146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)// Copyright 2014 The Chromium Authors. All rights reserved.
246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)// found in the LICENSE file.
446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)package org.chromium.chrome.browser.util;
646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)import android.annotation.SuppressLint;
846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)import android.annotation.TargetApi;
946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)import android.content.Context;
1046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)import android.content.Intent;
1146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)import android.content.pm.PackageManager;
1246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)import android.content.pm.ResolveInfo;
1346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)import android.os.Build;
1446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)import android.os.Bundle;
1546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)import android.os.UserManager;
1646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)import android.speech.RecognizerIntent;
1746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
1846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)import com.google.common.annotations.VisibleForTesting;
1946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
2046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)import org.chromium.base.ThreadUtils;
2146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)import org.chromium.sync.signin.AccountManagerHelper;
2246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
2346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)import java.util.List;
2446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
2546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)/**
2646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) * A utility {@code class} meant to help determine whether or not certain features are supported by
2746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) * this device.
2846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) */
2946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)public class FeatureUtilities {
3046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    private static Boolean sHasGoogleAccountAuthenticator;
3146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    private static Boolean sHasRecognitionIntentHandler;
3246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
3346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    /**
3446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)     * Determines whether or not the {@link RecognizerIntent#ACTION_WEB_SEARCH} {@link Intent}
3546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)     * is handled by any {@link android.app.Activity}s in the system.  The result will be cached for
3646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)     * future calls.  Passing {@code false} to {@code useCachedValue} will force it to re-query any
3746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)     * {@link android.app.Activity}s that can process the {@link Intent}.
3846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)     * @param context        The {@link Context} to use to check to see if the {@link Intent} will
3946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)     *                       be handled.
4046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)     * @param useCachedValue Whether or not to use the cached value from a previous result.
4146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)     * @return {@code true} if recognition is supported.  {@code false} otherwise.
4246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)     */
4346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    public static boolean isRecognitionIntentPresent(Context context, boolean useCachedValue) {
4446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)        ThreadUtils.assertOnUiThread();
4546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)        if (sHasRecognitionIntentHandler == null || !useCachedValue) {
4646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)            PackageManager pm = context.getPackageManager();
4746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)            List<ResolveInfo> activities = pm.queryIntentActivities(
4846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                    new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH), 0);
4946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)            sHasRecognitionIntentHandler = activities.size() > 0;
5046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)        }
5146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
5246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)        return sHasRecognitionIntentHandler;
5346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    }
5446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
5546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    /**
5646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)     * Determines whether or not the user has a Google account (so we can sync) or can add one.
5746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)     * @param context The {@link Context} that we should check accounts under.
5846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)     * @return Whether or not sync is allowed on this device.
5946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)     */
6046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    public static boolean canAllowSync(Context context) {
6146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)        return (hasGoogleAccountAuthenticator(context) && hasSyncPermissions(context)) ||
6246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                hasGoogleAccounts(context);
6346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    }
6446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
6546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    @VisibleForTesting
6646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    static boolean hasGoogleAccountAuthenticator(Context context) {
6746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)        if (sHasGoogleAccountAuthenticator == null) {
6846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)            AccountManagerHelper accountHelper = AccountManagerHelper.get(context);
6946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)            sHasGoogleAccountAuthenticator = accountHelper.hasGoogleAccountAuthenticator();
7046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)        }
7146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)        return sHasGoogleAccountAuthenticator;
7246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    }
7346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
7446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    @VisibleForTesting
7546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    static boolean hasGoogleAccounts(Context context) {
7646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)        return AccountManagerHelper.get(context).hasGoogleAccounts();
7746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    }
7846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
7946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    @SuppressLint("InlinedApi")
8046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR2)
8146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    private static boolean hasSyncPermissions(Context context) {
8246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR2) return true;
8346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
8446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)        UserManager manager = (UserManager) context.getSystemService(Context.USER_SERVICE);
8546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)        Bundle userRestrictions = manager.getUserRestrictions();
8646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)        return !userRestrictions.getBoolean(UserManager.DISALLOW_MODIFY_ACCOUNTS, false);
8746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    }
8846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)}
89