Loading src/com/android/settings/accessibility/AccessibilityUtil.java +54 −1 Original line number Diff line number Diff line Loading @@ -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}. Loading @@ -33,4 +65,25 @@ public class AccessibilityUtil { : 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; } } tests/robotests/src/com/android/settings/accessibility/AccessibilityUtilTest.java +75 −1 Original line number Diff line number Diff line Loading @@ -18,7 +18,13 @@ package com.android.settings.accessibility; 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; Loading @@ -28,12 +34,18 @@ import org.junit.Test; 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 Loading Loading @@ -68,4 +80,66 @@ public class AccessibilityUtilTest { 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; } } Loading
src/com/android/settings/accessibility/AccessibilityUtil.java +54 −1 Original line number Diff line number Diff line Loading @@ -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}. Loading @@ -33,4 +65,25 @@ public class AccessibilityUtil { : 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; } }
tests/robotests/src/com/android/settings/accessibility/AccessibilityUtilTest.java +75 −1 Original line number Diff line number Diff line Loading @@ -18,7 +18,13 @@ package com.android.settings.accessibility; 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; Loading @@ -28,12 +34,18 @@ import org.junit.Test; 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 Loading Loading @@ -68,4 +80,66 @@ public class AccessibilityUtilTest { 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; } }