1// Copyright 2014 The Chromium Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5package org.chromium.chrome.browser.util; 6 7import android.annotation.SuppressLint; 8import android.annotation.TargetApi; 9import android.content.Context; 10import android.content.Intent; 11import android.content.pm.PackageManager; 12import android.content.pm.ResolveInfo; 13import android.os.Build; 14import android.os.Bundle; 15import android.os.UserManager; 16import android.speech.RecognizerIntent; 17 18import com.google.common.annotations.VisibleForTesting; 19 20import org.chromium.base.ThreadUtils; 21import org.chromium.sync.signin.AccountManagerHelper; 22 23import java.util.List; 24 25/** 26 * A utility {@code class} meant to help determine whether or not certain features are supported by 27 * this device. 28 */ 29public class FeatureUtilities { 30 private static Boolean sHasGoogleAccountAuthenticator; 31 private static Boolean sHasRecognitionIntentHandler; 32 33 /** 34 * Determines whether or not the {@link RecognizerIntent#ACTION_WEB_SEARCH} {@link Intent} 35 * is handled by any {@link android.app.Activity}s in the system. The result will be cached for 36 * future calls. Passing {@code false} to {@code useCachedValue} will force it to re-query any 37 * {@link android.app.Activity}s that can process the {@link Intent}. 38 * @param context The {@link Context} to use to check to see if the {@link Intent} will 39 * be handled. 40 * @param useCachedValue Whether or not to use the cached value from a previous result. 41 * @return {@code true} if recognition is supported. {@code false} otherwise. 42 */ 43 public static boolean isRecognitionIntentPresent(Context context, boolean useCachedValue) { 44 ThreadUtils.assertOnUiThread(); 45 if (sHasRecognitionIntentHandler == null || !useCachedValue) { 46 PackageManager pm = context.getPackageManager(); 47 List<ResolveInfo> activities = pm.queryIntentActivities( 48 new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH), 0); 49 sHasRecognitionIntentHandler = activities.size() > 0; 50 } 51 52 return sHasRecognitionIntentHandler; 53 } 54 55 /** 56 * Determines whether or not the user has a Google account (so we can sync) or can add one. 57 * @param context The {@link Context} that we should check accounts under. 58 * @return Whether or not sync is allowed on this device. 59 */ 60 public static boolean canAllowSync(Context context) { 61 return (hasGoogleAccountAuthenticator(context) && hasSyncPermissions(context)) || 62 hasGoogleAccounts(context); 63 } 64 65 @VisibleForTesting 66 static boolean hasGoogleAccountAuthenticator(Context context) { 67 if (sHasGoogleAccountAuthenticator == null) { 68 AccountManagerHelper accountHelper = AccountManagerHelper.get(context); 69 sHasGoogleAccountAuthenticator = accountHelper.hasGoogleAccountAuthenticator(); 70 } 71 return sHasGoogleAccountAuthenticator; 72 } 73 74 @VisibleForTesting 75 static boolean hasGoogleAccounts(Context context) { 76 return AccountManagerHelper.get(context).hasGoogleAccounts(); 77 } 78 79 @SuppressLint("InlinedApi") 80 @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR2) 81 private static boolean hasSyncPermissions(Context context) { 82 if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR2) return true; 83 84 UserManager manager = (UserManager) context.getSystemService(Context.USER_SERVICE); 85 Bundle userRestrictions = manager.getUserRestrictions(); 86 return !userRestrictions.getBoolean(UserManager.DISALLOW_MODIFY_ACCOUNTS, false); 87 } 88} 89