Merge "Settings enable a11y shortcut framework features"
diff --git a/src/com/android/settings/accessibility/AccessibilityShortcutPreferenceFragment.java b/src/com/android/settings/accessibility/AccessibilityShortcutPreferenceFragment.java
index db121e2..d321783 100644
--- a/src/com/android/settings/accessibility/AccessibilityShortcutPreferenceFragment.java
+++ b/src/com/android/settings/accessibility/AccessibilityShortcutPreferenceFragment.java
@@ -16,6 +16,7 @@
 package com.android.settings.accessibility;
 
 import android.accessibilityservice.AccessibilityServiceInfo;
+import android.annotation.Nullable;
 import android.content.ComponentName;
 import android.content.ContentResolver;
 import android.content.Context;
@@ -27,6 +28,7 @@
 import android.view.accessibility.AccessibilityManager;
 import android.widget.Switch;
 
+import com.android.internal.accessibility.AccessibilityShortcutController;
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.settings.R;
 import com.android.settings.search.BaseSearchIndexProvider;
@@ -87,7 +89,7 @@
         super.onInstallSwitchBarToggleSwitch();
         mSwitchBar.addOnSwitchChangeListener((Switch switchView, boolean enabled) -> {
             Context context = getContext();
-            if (enabled && (getServiceInfo(context) == null)) {
+            if (enabled && !shortcutFeatureAvailable(context)) {
                 // If no service is configured, we'll disable the shortcut shortly. Give the
                 // user a chance to select a service. We'll update the preferences when we resume.
                 Settings.Secure.putInt(
@@ -110,7 +112,7 @@
         ContentResolver cr = getContentResolver();
         Context context = getContext();
         mServicePreference.setSummary(getServiceName(context));
-        if (getServiceInfo(context) == null) {
+        if (!shortcutFeatureAvailable(context)) {
             // If no service is configured, make sure the overall shortcut is turned off
             Settings.Secure.putInt(
                     getContentResolver(), Settings.Secure.ACCESSIBILITY_SHORTCUT_ENABLED, 0);
@@ -132,19 +134,38 @@
      * @return The name of the service or a string saying that none is selected.
      */
     public static CharSequence getServiceName(Context context) {
+        if (!shortcutFeatureAvailable(context)) {
+            return context.getString(R.string.accessibility_no_service_selected);
+        }
         AccessibilityServiceInfo shortcutServiceInfo = getServiceInfo(context);
         if (shortcutServiceInfo != null) {
             return shortcutServiceInfo.getResolveInfo().loadLabel(context.getPackageManager());
         }
-        return context.getString(R.string.accessibility_no_service_selected);
+        return AccessibilityShortcutController.getFrameworkShortcutFeaturesMap()
+                .get(getShortcutComponent(context)).getLabel(context);
     }
 
     private static AccessibilityServiceInfo getServiceInfo(Context context) {
-        ComponentName shortcutServiceName = ComponentName.unflattenFromString(
-                AccessibilityUtils.getShortcutTargetServiceComponentNameString(
-                        context, UserHandle.myUserId()));
         return AccessibilityManager.getInstance(context)
-                .getInstalledServiceInfoWithComponentName(shortcutServiceName);
+                .getInstalledServiceInfoWithComponentName(getShortcutComponent(context));
+    }
+
+    private static boolean shortcutFeatureAvailable(Context context) {
+        ComponentName shortcutFeature = getShortcutComponent(context);
+        if (shortcutFeature == null) return false;
+
+        if (AccessibilityShortcutController.getFrameworkShortcutFeaturesMap()
+                .containsKey(shortcutFeature)) {
+            return true;
+        }
+        return getServiceInfo(context) != null;
+    }
+
+    private static @Nullable ComponentName getShortcutComponent(Context context) {
+        String componentNameString = AccessibilityUtils.getShortcutTargetServiceComponentNameString(
+                context, UserHandle.myUserId());
+        if (componentNameString == null) return null;
+        return ComponentName.unflattenFromString(componentNameString);
     }
 
     public static final SearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
diff --git a/src/com/android/settings/accessibility/ShortcutServicePickerFragment.java b/src/com/android/settings/accessibility/ShortcutServicePickerFragment.java
index 5b0e76d..e0c41be 100644
--- a/src/com/android/settings/accessibility/ShortcutServicePickerFragment.java
+++ b/src/com/android/settings/accessibility/ShortcutServicePickerFragment.java
@@ -25,29 +25,40 @@
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.DialogInterface;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.ComponentInfo;
+import android.content.pm.PackageManager;
+import android.graphics.drawable.Drawable;
 import android.os.Binder;
 import android.os.Bundle;
 import android.os.IBinder;
 import android.os.UserHandle;
 import android.provider.Settings;
 import android.text.TextUtils;
+import android.util.IconDrawableFactory;
 import android.view.accessibility.AccessibilityManager;
 
+import com.android.internal.accessibility.AccessibilityShortcutController;
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+import com.android.internal.accessibility.AccessibilityShortcutController.ToggleableFrameworkFeatureInfo;
 import com.android.settings.R;
 import com.android.settings.applications.defaultapps.DefaultAppInfo;
 import com.android.settings.applications.defaultapps.DefaultAppPickerFragment;
 import com.android.settings.core.instrumentation.InstrumentedDialogFragment;
+import com.android.settings.widget.RadioButtonPickerFragment;
 import com.android.settings.widget.RadioButtonPreference;
+import com.android.settings.wrapper.IPackageManagerWrapper;
 import com.android.settingslib.accessibility.AccessibilityUtils;
+import com.android.settingslib.wrapper.PackageManagerWrapper;
 
 import java.util.ArrayList;
 import java.util.List;
+import java.util.Map;
 
 /**
  * Fragment for picking accessibility shortcut service
  */
-public class ShortcutServicePickerFragment extends DefaultAppPickerFragment {
+public class ShortcutServicePickerFragment extends RadioButtonPickerFragment {
 
     @Override
     public int getMetricsCategory() {
@@ -60,22 +71,29 @@
     }
 
     @Override
-    protected List<? extends DefaultAppInfo> getCandidates() {
+    protected List<? extends CandidateInfo> getCandidates() {
         final Context context = getContext();
+        final PackageManager pm = context.getPackageManager();
         final AccessibilityManager accessibilityManager = context
                 .getSystemService(AccessibilityManager.class);
         final List<AccessibilityServiceInfo> installedServices =
                 accessibilityManager.getInstalledAccessibilityServiceList();
         final int numInstalledServices = installedServices.size();
+        final PackageManagerWrapper pmw = new PackageManagerWrapper(context.getPackageManager());
 
-        List<DefaultAppInfo> candidates = new ArrayList<>(numInstalledServices);
+        final List<CandidateInfo> candidates = new ArrayList<>(numInstalledServices);
+        Map<ComponentName, ToggleableFrameworkFeatureInfo> frameworkFeatureInfoMap =
+                AccessibilityShortcutController.getFrameworkShortcutFeaturesMap();
+        for (ComponentName componentName : frameworkFeatureInfoMap.keySet()) {
+            // Lookup icon
+            candidates.add(new FrameworkCandidateInfo(frameworkFeatureInfoMap.get(componentName),
+                    R.drawable.empty_icon, componentName.flattenToString()));
+        }
         for (int i = 0; i < numInstalledServices; i++) {
-            AccessibilityServiceInfo installedServiceInfo = installedServices.get(i);
-            candidates.add(new DefaultAppInfo(context, mPm,
-                    UserHandle.myUserId(),
+            final AccessibilityServiceInfo installedServiceInfo = installedServices.get(i);
+            candidates.add(new DefaultAppInfo(context, pmw, UserHandle.myUserId(),
                     installedServiceInfo.getComponentName(),
-                    (String) installedServiceInfo.loadSummary(mPm.getPackageManager()),
-                    true /* enabled */));
+                    (String) installedServiceInfo.loadSummary(pm), true /* enabled */));
         }
 
         return candidates;
@@ -105,13 +123,21 @@
     public void onRadioButtonClicked(RadioButtonPreference selected) {
         final String selectedKey = selected.getKey();
 
-        final Activity activity = getActivity();
         if (TextUtils.isEmpty(selectedKey)) {
             super.onRadioButtonClicked(selected);
-        } else if (activity != null) {
-            final DialogFragment fragment = ConfirmationDialogFragment.newInstance(
-                    this, selectedKey);
-            fragment.show(activity.getFragmentManager(), ConfirmationDialogFragment.TAG);
+        } else {
+            final ComponentName selectedComponent = ComponentName.unflattenFromString(selectedKey);
+            if (AccessibilityShortcutController.getFrameworkShortcutFeaturesMap()
+                    .containsKey(selectedComponent)) {
+                // This is a framework feature. It doesn't need to be confirmed.
+                onRadioButtonConfirmed(selectedKey);
+            } else {
+                final Activity activity = getActivity();
+                if (activity != null) {
+                    ConfirmationDialogFragment.newInstance(this, selectedKey)
+                            .show(activity.getFragmentManager(), ConfirmationDialogFragment.TAG);
+                }
+            }
         }
     }
 
@@ -156,11 +182,40 @@
         @Override
         public void onClick(DialogInterface dialog, int which) {
             final Fragment fragment = getTargetFragment();
-            if ((which == BUTTON_POSITIVE) && (fragment instanceof DefaultAppPickerFragment)) {
+            if ((which == BUTTON_POSITIVE) && (fragment instanceof ShortcutServicePickerFragment)) {
                 final Bundle bundle = getArguments();
                 ((ShortcutServicePickerFragment) fragment).onServiceConfirmed(
                         bundle.getString(EXTRA_KEY));
             }
         }
     }
+
+    private class FrameworkCandidateInfo extends CandidateInfo {
+        ToggleableFrameworkFeatureInfo mToggleableFrameworkFeatureInfo;
+        int mIconResId;
+        String mKey;
+
+        public FrameworkCandidateInfo(
+                ToggleableFrameworkFeatureInfo frameworkFeatureInfo, int iconResId, String key) {
+            super(true /* enabled */);
+            mToggleableFrameworkFeatureInfo = frameworkFeatureInfo;
+            mIconResId = iconResId;
+            mKey = key;
+        }
+
+        @Override
+        public CharSequence loadLabel() {
+            return mToggleableFrameworkFeatureInfo.getLabel(getContext());
+        }
+
+        @Override
+        public Drawable loadIcon() {
+            return getContext().getDrawable(mIconResId);
+        }
+
+        @Override
+        public String getKey() {
+            return mKey;
+        }
+    }
 }