Merge "Accessibility shortcut primary action - method to check shortcut type"
diff --git a/src/com/android/settings/accessibility/AccessibilityUtil.java b/src/com/android/settings/accessibility/AccessibilityUtil.java
index 1cb5ffb..ac9cd09 100644
--- a/src/com/android/settings/accessibility/AccessibilityUtil.java
+++ b/src/com/android/settings/accessibility/AccessibilityUtil.java
@@ -16,12 +16,44 @@
 
 package com.android.settings.accessibility;
 
+import android.accessibilityservice.AccessibilityServiceInfo;
 import android.content.Context;
+import android.os.Build;
 import android.provider.Settings;
 
+import androidx.annotation.IntDef;
+
 import com.android.settings.R;
 
-public class AccessibilityUtil {
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/** Provides utility methods to accessibility settings only. */
+final class AccessibilityUtil {
+
+    private AccessibilityUtil(){}
+
+    /**
+     * Annotation for different accessibilityService fragment UI type.
+     *
+     * {@code LEGACY} for displaying appearance aligned with sdk version Q accessibility service
+     * page, but only hardware shortcut allowed.
+     * {@code HEADLESS} for displaying appearance without switch bar.
+     * {@code INTUITIVE} for displaying appearance with new design.
+     */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef({
+            AccessibilityServiceFragmentType.LEGACY,
+            AccessibilityServiceFragmentType.HEADLESS,
+            AccessibilityServiceFragmentType.INTUITIVE,
+    })
+
+    public @interface AccessibilityServiceFragmentType {
+        int LEGACY = 0;
+        int HEADLESS = 1;
+        int INTUITIVE = 2;
+    }
+
     /**
      * Return On/Off string according to the setting which specifies the integer value 1 or 0. This
      * setting is defined in the secure system settings {@link android.provider.Settings.Secure}.
@@ -33,4 +65,25 @@
                 : R.string.accessibility_feature_state_off;
         return context.getResources().getText(resId);
     }
+
+    /**
+     * Gets the corresponding fragment type of a given accessibility service
+     *
+     * @param accessibilityServiceInfo The accessibilityService's info
+     * @return int from {@link AccessibilityServiceFragmentType}
+     */
+    static @AccessibilityServiceFragmentType int getAccessibilityServiceFragmentType(
+            AccessibilityServiceInfo accessibilityServiceInfo) {
+        final int targetSdk = accessibilityServiceInfo.getResolveInfo()
+                .serviceInfo.applicationInfo.targetSdkVersion;
+        final boolean requestA11yButton = (accessibilityServiceInfo.flags
+                & AccessibilityServiceInfo.FLAG_REQUEST_ACCESSIBILITY_BUTTON) != 0;
+
+        if (targetSdk <= Build.VERSION_CODES.Q) {
+            return AccessibilityServiceFragmentType.LEGACY;
+        }
+        return requestA11yButton
+                ? AccessibilityServiceFragmentType.HEADLESS
+                : AccessibilityServiceFragmentType.INTUITIVE;
+    }
 }
diff --git a/tests/robotests/src/com/android/settings/accessibility/AccessibilityUtilTest.java b/tests/robotests/src/com/android/settings/accessibility/AccessibilityUtilTest.java
index 70d86d0..c4d8ead 100644
--- a/tests/robotests/src/com/android/settings/accessibility/AccessibilityUtilTest.java
+++ b/tests/robotests/src/com/android/settings/accessibility/AccessibilityUtilTest.java
@@ -18,7 +18,13 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
+import android.accessibilityservice.AccessibilityServiceInfo;
+import android.content.ComponentName;
 import android.content.Context;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.ResolveInfo;
+import android.content.pm.ServiceInfo;
+import android.os.Build;
 import android.provider.Settings;
 
 import com.android.settings.R;
@@ -28,12 +34,18 @@
 import org.junit.runner.RunWith;
 import org.robolectric.RobolectricTestRunner;
 import org.robolectric.RuntimeEnvironment;
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.IOException;
 
 @RunWith(RobolectricTestRunner.class)
-public class AccessibilityUtilTest {
+public final class AccessibilityUtilTest {
     private static final int ON = 1;
     private static final int OFF = 0;
     private static final String SECURE_TEST_KEY = "secure_test_key";
+    private static final String DUMMY_PACKAGE_NAME = "com.dummy.example";
+    private static final String DUMMY_CLASS_NAME = DUMMY_PACKAGE_NAME + ".dummy_a11y_service";
+    private static final String DUMMY_COMPONENT_NAME = DUMMY_PACKAGE_NAME + "/" + DUMMY_CLASS_NAME;
     private Context mContext;
 
     @Before
@@ -68,4 +80,66 @@
         assertThat(result)
                 .isEqualTo(mContext.getText(R.string.accessibility_feature_state_off));
     }
+
+    @Test
+    public void getAccessibilityServiceFragmentType_targetSdkQ_legacyType() {
+        final AccessibilityServiceInfo info = getMockAccessibilityServiceInfo();
+
+        info.getResolveInfo().serviceInfo.applicationInfo.targetSdkVersion = Build.VERSION_CODES.Q;
+        info.flags |= AccessibilityServiceInfo.FLAG_REQUEST_ACCESSIBILITY_BUTTON;
+
+        assertThat(AccessibilityUtil.getAccessibilityServiceFragmentType(info)).isEqualTo(
+                AccessibilityUtil.AccessibilityServiceFragmentType.LEGACY);
+
+    }
+
+    @Test
+    public void getAccessibilityServiceFragmentType_targetSdkR_HaveA11yButton_headlessType() {
+        final AccessibilityServiceInfo info = getMockAccessibilityServiceInfo();
+
+        info.getResolveInfo().serviceInfo.applicationInfo.targetSdkVersion = Build.VERSION_CODES.R;
+        info.flags |= AccessibilityServiceInfo.FLAG_REQUEST_ACCESSIBILITY_BUTTON;
+
+        assertThat(AccessibilityUtil.getAccessibilityServiceFragmentType(info)).isEqualTo(
+                AccessibilityUtil.AccessibilityServiceFragmentType.HEADLESS);
+
+    }
+
+    @Test
+    public void getAccessibilityServiceFragmentType_targetSdkR_NoA11yButton_intuitiveType() {
+        final AccessibilityServiceInfo info = getMockAccessibilityServiceInfo();
+
+        info.getResolveInfo().serviceInfo.applicationInfo.targetSdkVersion = Build.VERSION_CODES.R;
+        info.flags |= ~AccessibilityServiceInfo.FLAG_REQUEST_ACCESSIBILITY_BUTTON;
+
+        assertThat(AccessibilityUtil.getAccessibilityServiceFragmentType(info)).isEqualTo(
+                AccessibilityUtil.AccessibilityServiceFragmentType.INTUITIVE);
+
+    }
+
+
+    private AccessibilityServiceInfo getMockAccessibilityServiceInfo() {
+        final ApplicationInfo applicationInfo = new ApplicationInfo();
+        final ServiceInfo serviceInfo = new ServiceInfo();
+        applicationInfo.packageName = DUMMY_PACKAGE_NAME;
+        serviceInfo.packageName = DUMMY_PACKAGE_NAME;
+        serviceInfo.name = DUMMY_CLASS_NAME;
+        serviceInfo.applicationInfo = applicationInfo;
+
+        final ResolveInfo resolveInfo = new ResolveInfo();
+        resolveInfo.serviceInfo = serviceInfo;
+
+        try {
+            final AccessibilityServiceInfo info = new AccessibilityServiceInfo(resolveInfo,
+                    mContext);
+            final ComponentName componentName = ComponentName.unflattenFromString(
+                    DUMMY_COMPONENT_NAME);
+            info.setComponentName(componentName);
+            return info;
+        } catch (XmlPullParserException | IOException e) {
+            // Do nothing
+        }
+
+        return null;
+    }
 }