Loading core/java/android/view/accessibility/AccessibilityManager.java +10 −5 Original line number Diff line number Diff line Loading @@ -19,6 +19,8 @@ package android.view.accessibility; import static android.accessibilityservice.AccessibilityServiceInfo.FLAG_ENABLE_ACCESSIBILITY_VOLUME; import static android.annotation.SystemApi.Client.MODULE_LIBRARIES; import static com.android.internal.accessibility.common.ShortcutConstants.UserShortcutType.HARDWARE; import android.Manifest; import android.accessibilityservice.AccessibilityService; import android.accessibilityservice.AccessibilityServiceInfo; Loading Loading @@ -62,6 +64,7 @@ import android.os.UserHandle; import android.util.ArrayMap; import android.util.Log; import android.util.SparseArray; import android.view.Display; import android.view.IWindow; import android.view.SurfaceControl; import android.view.View; Loading @@ -69,6 +72,7 @@ import android.view.accessibility.AccessibilityEvent.EventType; import com.android.internal.R; import com.android.internal.accessibility.common.ShortcutConstants; import com.android.internal.accessibility.common.ShortcutConstants.UserShortcutType; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.IntPair; Loading Loading @@ -1565,7 +1569,7 @@ public final class AccessibilityManager { @SystemApi @RequiresPermission(Manifest.permission.MANAGE_ACCESSIBILITY) public void performAccessibilityShortcut() { performAccessibilityShortcut(null); performAccessibilityShortcut(Display.DEFAULT_DISPLAY, HARDWARE, null); } /** Loading @@ -1577,7 +1581,8 @@ public final class AccessibilityManager { * @hide */ @RequiresPermission(Manifest.permission.MANAGE_ACCESSIBILITY) public void performAccessibilityShortcut(@Nullable String targetName) { public void performAccessibilityShortcut( int displayId, @UserShortcutType int shortcutType, @Nullable String targetName) { final IAccessibilityManager service; synchronized (mLock) { service = getServiceLocked(); Loading @@ -1586,7 +1591,7 @@ public final class AccessibilityManager { } } try { service.performAccessibilityShortcut(targetName); service.performAccessibilityShortcut(displayId, shortcutType, targetName); } catch (RemoteException re) { Log.e(LOG_TAG, "Error performing accessibility shortcut. ", re); } Loading @@ -1602,7 +1607,7 @@ public final class AccessibilityManager { */ @RequiresPermission(Manifest.permission.MANAGE_ACCESSIBILITY) public void enableShortcutsForTargets(boolean enable, @ShortcutConstants.UserShortcutType int shortcutTypes, @NonNull Set<String> targets, @UserShortcutType int shortcutTypes, @NonNull Set<String> targets, @UserIdInt int userId) { final IAccessibilityManager service; synchronized (mLock) { Loading Loading @@ -1817,7 +1822,7 @@ public final class AccessibilityManager { @RequiresPermission(Manifest.permission.MANAGE_ACCESSIBILITY) @NonNull public List<String> getAccessibilityShortcutTargets( @ShortcutConstants.UserShortcutType int shortcutType) { @UserShortcutType int shortcutType) { final IAccessibilityManager service; synchronized (mLock) { service = getServiceLocked(); Loading core/java/android/view/accessibility/IAccessibilityManager.aidl +1 −1 Original line number Diff line number Diff line Loading @@ -92,7 +92,7 @@ interface IAccessibilityManager { void notifyAccessibilityButtonVisibilityChanged(boolean available); @EnforcePermission("MANAGE_ACCESSIBILITY") void performAccessibilityShortcut(String targetName); void performAccessibilityShortcut(int displayId, int shortcutType, String targetName); @EnforcePermission("MANAGE_ACCESSIBILITY") List<String> getAccessibilityShortcutTargets(int shortcutType); Loading core/java/com/android/internal/accessibility/dialog/AccessibilityTarget.java +20 −9 Original line number Diff line number Diff line Loading @@ -36,6 +36,7 @@ import com.android.internal.accessibility.common.ShortcutConstants; import com.android.internal.accessibility.common.ShortcutConstants.AccessibilityFragmentType; import com.android.internal.accessibility.common.ShortcutConstants.UserShortcutType; import com.android.internal.accessibility.dialog.TargetAdapter.ViewHolder; import com.android.internal.accessibility.util.ShortcutUtils; import com.android.internal.annotations.VisibleForTesting; import java.util.Set; Loading Loading @@ -67,6 +68,10 @@ public abstract class AccessibilityTarget implements TargetOperations, OnTargetS public AccessibilityTarget(Context context, @UserShortcutType int shortcutType, @AccessibilityFragmentType int fragmentType, boolean isShortcutSwitched, String id, int uid, CharSequence label, Drawable icon, String key) { if (!isRecognizedShortcutType(shortcutType)) { throw new IllegalArgumentException( "Unexpected shortcut type " + ShortcutUtils.convertToKey(shortcutType)); } mContext = context; mShortcutType = shortcutType; mFragmentType = fragmentType; Loading Loading @@ -97,20 +102,15 @@ public abstract class AccessibilityTarget implements TargetOperations, OnTargetS holder.mStatusView.setVisibility(View.GONE); } @SuppressLint("MissingPermission") @Override public void onSelected() { final AccessibilityManager am = getContext().getSystemService(AccessibilityManager.class); switch (getShortcutType()) { case SOFTWARE: am.notifyAccessibilityButtonClicked(getContext().getDisplayId(), getId()); if (am == null) { return; case HARDWARE: am.performAccessibilityShortcut(getId()); return; default: throw new IllegalStateException("Unexpected shortcut type"); } am.performAccessibilityShortcut(getContext().getDisplayId(), mShortcutType, getId()); } @SuppressLint("MissingPermission") Loading Loading @@ -188,4 +188,15 @@ public abstract class AccessibilityTarget implements TargetOperations, OnTargetS public String getKey() { return mKey; } /** * Determines if the provided shortcut type is valid for use with AccessibilityTargets. * @param shortcutType shortcut type to check. * @return {@code true} if the shortcut type can be used, {@code false} otherwise. */ @VisibleForTesting public static boolean isRecognizedShortcutType(@UserShortcutType int shortcutType) { int mask = SOFTWARE | HARDWARE; return (shortcutType != 0 && (shortcutType & mask) == shortcutType); } } core/java/com/android/internal/accessibility/dialog/AccessibilityTargetHelper.java +21 −9 Original line number Diff line number Diff line Loading @@ -41,6 +41,7 @@ import android.view.accessibility.AccessibilityManager; import com.android.internal.R; import com.android.internal.accessibility.common.ShortcutConstants.AccessibilityFragmentType; import com.android.internal.accessibility.common.ShortcutConstants.UserShortcutType; import com.android.internal.annotations.VisibleForTesting; import java.util.ArrayList; import java.util.Collections; Loading Loading @@ -159,21 +160,32 @@ public final class AccessibilityTargetHelper { final List<AccessibilityTarget> targets = new ArrayList<>(installedServices.size()); for (AccessibilityServiceInfo info : installedServices) { final int targetSdk = info.getResolveInfo().serviceInfo.applicationInfo.targetSdkVersion; final boolean hasRequestAccessibilityButtonFlag = (info.flags & AccessibilityServiceInfo.FLAG_REQUEST_ACCESSIBILITY_BUTTON) != 0; if ((targetSdk <= Build.VERSION_CODES.Q) && !hasRequestAccessibilityButtonFlag && (shortcutType == SOFTWARE)) { continue; } if (isValidServiceTarget(info, shortcutType)) { targets.add(createAccessibilityServiceTarget(context, shortcutType, info)); } } return targets; } /** * Check for maintaining compatibility on prior versions. * Determines if a given service should be accumulated in a list of installed services. * @param info service info to check. * @param shortcutType type of shortcut to accumulate a list for. * @return {@code true} if the service should be added (always true past version Q), * otherwise {@code false}. */ @VisibleForTesting public static boolean isValidServiceTarget( AccessibilityServiceInfo info, @UserShortcutType int shortcutType) { final boolean hasRequestAccessibilityButtonFlag = (info.flags & AccessibilityServiceInfo.FLAG_REQUEST_ACCESSIBILITY_BUTTON) != 0; return (info.getResolveInfo().serviceInfo.applicationInfo.targetSdkVersion > Build.VERSION_CODES.Q) || hasRequestAccessibilityButtonFlag || shortcutType != SOFTWARE; } private static List<AccessibilityTarget> getAccessibilityActivityTargets(Context context, @UserShortcutType int shortcutType) { final AccessibilityManager am = (AccessibilityManager) context.getSystemService( Loading core/tests/coretests/src/android/view/accessibility/AccessibilityManagerTest.java +31 −2 Original line number Diff line number Diff line Loading @@ -20,6 +20,7 @@ import static com.android.internal.accessibility.AccessibilityShortcutController import static com.android.internal.accessibility.AccessibilityShortcutController.COLOR_INVERSION_TILE_COMPONENT_NAME; import static com.android.internal.accessibility.AccessibilityShortcutController.DALTONIZER_COMPONENT_NAME; import static com.android.internal.accessibility.AccessibilityShortcutController.DALTONIZER_TILE_COMPONENT_NAME; import static com.android.internal.accessibility.common.ShortcutConstants.UserShortcutType.HARDWARE; import static com.google.common.truth.Truth.assertThat; Loading @@ -31,6 +32,8 @@ import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.anyList; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.ArgumentMatchers.isNull; import static org.mockito.Matchers.any; import static org.mockito.Matchers.anyInt; import static org.mockito.Mockito.doThrow; Loading @@ -48,12 +51,14 @@ import android.graphics.drawable.Icon; import android.os.Bundle; import android.os.RemoteException; import android.os.UserHandle; import android.view.Display; import androidx.annotation.NonNull; import androidx.test.InstrumentationRegistry; import androidx.test.runner.AndroidJUnit4; import com.android.internal.R; import com.android.internal.accessibility.common.ShortcutConstants; import com.android.internal.accessibility.common.ShortcutConstants.UserShortcutType; import com.android.internal.util.IntPair; import com.android.server.accessibility.test.MessageCapturingHandler; Loading Loading @@ -321,7 +326,7 @@ public class AccessibilityManagerTest { Throwable rethrownException = assertThrows(RuntimeException.class, () -> manager.enableShortcutsForTargets( /* enable= */ false, UserShortcutType.HARDWARE, HARDWARE, Set.of(DALTONIZER_COMPONENT_NAME.flattenToString()), UserHandle.USER_CURRENT )); Loading @@ -331,7 +336,7 @@ public class AccessibilityManagerTest { @Test public void enableShortcutsForTargets_verifyServiceMethodCalled() throws Exception { AccessibilityManager manager = createManager(WITH_A11Y_ENABLED); int shortcutTypes = UserShortcutType.HARDWARE | UserShortcutType.TRIPLETAP; int shortcutTypes = HARDWARE | UserShortcutType.TRIPLETAP; manager.enableShortcutsForTargets( /* enable= */ false, Loading @@ -348,6 +353,30 @@ public class AccessibilityManagerTest { ); } @Test public void performAccessibilityShortcut_callToService_defaultTypeIsHardware() throws Exception { AccessibilityManager manager = createManager(WITH_A11Y_ENABLED); manager.performAccessibilityShortcut(); verify(mMockService).performAccessibilityShortcut( eq(Display.DEFAULT_DISPLAY), eq(HARDWARE), isNull()); } @Test public void performAccessibilityShortcut_callToService_typeParameterMatches() throws Exception { AccessibilityManager manager = createManager(WITH_A11Y_ENABLED); int display = Display.DEFAULT_DISPLAY; String name = LABEL; for (int type: ShortcutConstants.USER_SHORTCUT_TYPES) { manager.performAccessibilityShortcut(display, type, name); verify(mMockService).performAccessibilityShortcut(display, type, name); } } private class MyAccessibilityProxy extends AccessibilityDisplayProxy { MyAccessibilityProxy(int displayId, @NonNull List<AccessibilityServiceInfo> serviceInfos) { Loading Loading
core/java/android/view/accessibility/AccessibilityManager.java +10 −5 Original line number Diff line number Diff line Loading @@ -19,6 +19,8 @@ package android.view.accessibility; import static android.accessibilityservice.AccessibilityServiceInfo.FLAG_ENABLE_ACCESSIBILITY_VOLUME; import static android.annotation.SystemApi.Client.MODULE_LIBRARIES; import static com.android.internal.accessibility.common.ShortcutConstants.UserShortcutType.HARDWARE; import android.Manifest; import android.accessibilityservice.AccessibilityService; import android.accessibilityservice.AccessibilityServiceInfo; Loading Loading @@ -62,6 +64,7 @@ import android.os.UserHandle; import android.util.ArrayMap; import android.util.Log; import android.util.SparseArray; import android.view.Display; import android.view.IWindow; import android.view.SurfaceControl; import android.view.View; Loading @@ -69,6 +72,7 @@ import android.view.accessibility.AccessibilityEvent.EventType; import com.android.internal.R; import com.android.internal.accessibility.common.ShortcutConstants; import com.android.internal.accessibility.common.ShortcutConstants.UserShortcutType; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.IntPair; Loading Loading @@ -1565,7 +1569,7 @@ public final class AccessibilityManager { @SystemApi @RequiresPermission(Manifest.permission.MANAGE_ACCESSIBILITY) public void performAccessibilityShortcut() { performAccessibilityShortcut(null); performAccessibilityShortcut(Display.DEFAULT_DISPLAY, HARDWARE, null); } /** Loading @@ -1577,7 +1581,8 @@ public final class AccessibilityManager { * @hide */ @RequiresPermission(Manifest.permission.MANAGE_ACCESSIBILITY) public void performAccessibilityShortcut(@Nullable String targetName) { public void performAccessibilityShortcut( int displayId, @UserShortcutType int shortcutType, @Nullable String targetName) { final IAccessibilityManager service; synchronized (mLock) { service = getServiceLocked(); Loading @@ -1586,7 +1591,7 @@ public final class AccessibilityManager { } } try { service.performAccessibilityShortcut(targetName); service.performAccessibilityShortcut(displayId, shortcutType, targetName); } catch (RemoteException re) { Log.e(LOG_TAG, "Error performing accessibility shortcut. ", re); } Loading @@ -1602,7 +1607,7 @@ public final class AccessibilityManager { */ @RequiresPermission(Manifest.permission.MANAGE_ACCESSIBILITY) public void enableShortcutsForTargets(boolean enable, @ShortcutConstants.UserShortcutType int shortcutTypes, @NonNull Set<String> targets, @UserShortcutType int shortcutTypes, @NonNull Set<String> targets, @UserIdInt int userId) { final IAccessibilityManager service; synchronized (mLock) { Loading Loading @@ -1817,7 +1822,7 @@ public final class AccessibilityManager { @RequiresPermission(Manifest.permission.MANAGE_ACCESSIBILITY) @NonNull public List<String> getAccessibilityShortcutTargets( @ShortcutConstants.UserShortcutType int shortcutType) { @UserShortcutType int shortcutType) { final IAccessibilityManager service; synchronized (mLock) { service = getServiceLocked(); Loading
core/java/android/view/accessibility/IAccessibilityManager.aidl +1 −1 Original line number Diff line number Diff line Loading @@ -92,7 +92,7 @@ interface IAccessibilityManager { void notifyAccessibilityButtonVisibilityChanged(boolean available); @EnforcePermission("MANAGE_ACCESSIBILITY") void performAccessibilityShortcut(String targetName); void performAccessibilityShortcut(int displayId, int shortcutType, String targetName); @EnforcePermission("MANAGE_ACCESSIBILITY") List<String> getAccessibilityShortcutTargets(int shortcutType); Loading
core/java/com/android/internal/accessibility/dialog/AccessibilityTarget.java +20 −9 Original line number Diff line number Diff line Loading @@ -36,6 +36,7 @@ import com.android.internal.accessibility.common.ShortcutConstants; import com.android.internal.accessibility.common.ShortcutConstants.AccessibilityFragmentType; import com.android.internal.accessibility.common.ShortcutConstants.UserShortcutType; import com.android.internal.accessibility.dialog.TargetAdapter.ViewHolder; import com.android.internal.accessibility.util.ShortcutUtils; import com.android.internal.annotations.VisibleForTesting; import java.util.Set; Loading Loading @@ -67,6 +68,10 @@ public abstract class AccessibilityTarget implements TargetOperations, OnTargetS public AccessibilityTarget(Context context, @UserShortcutType int shortcutType, @AccessibilityFragmentType int fragmentType, boolean isShortcutSwitched, String id, int uid, CharSequence label, Drawable icon, String key) { if (!isRecognizedShortcutType(shortcutType)) { throw new IllegalArgumentException( "Unexpected shortcut type " + ShortcutUtils.convertToKey(shortcutType)); } mContext = context; mShortcutType = shortcutType; mFragmentType = fragmentType; Loading Loading @@ -97,20 +102,15 @@ public abstract class AccessibilityTarget implements TargetOperations, OnTargetS holder.mStatusView.setVisibility(View.GONE); } @SuppressLint("MissingPermission") @Override public void onSelected() { final AccessibilityManager am = getContext().getSystemService(AccessibilityManager.class); switch (getShortcutType()) { case SOFTWARE: am.notifyAccessibilityButtonClicked(getContext().getDisplayId(), getId()); if (am == null) { return; case HARDWARE: am.performAccessibilityShortcut(getId()); return; default: throw new IllegalStateException("Unexpected shortcut type"); } am.performAccessibilityShortcut(getContext().getDisplayId(), mShortcutType, getId()); } @SuppressLint("MissingPermission") Loading Loading @@ -188,4 +188,15 @@ public abstract class AccessibilityTarget implements TargetOperations, OnTargetS public String getKey() { return mKey; } /** * Determines if the provided shortcut type is valid for use with AccessibilityTargets. * @param shortcutType shortcut type to check. * @return {@code true} if the shortcut type can be used, {@code false} otherwise. */ @VisibleForTesting public static boolean isRecognizedShortcutType(@UserShortcutType int shortcutType) { int mask = SOFTWARE | HARDWARE; return (shortcutType != 0 && (shortcutType & mask) == shortcutType); } }
core/java/com/android/internal/accessibility/dialog/AccessibilityTargetHelper.java +21 −9 Original line number Diff line number Diff line Loading @@ -41,6 +41,7 @@ import android.view.accessibility.AccessibilityManager; import com.android.internal.R; import com.android.internal.accessibility.common.ShortcutConstants.AccessibilityFragmentType; import com.android.internal.accessibility.common.ShortcutConstants.UserShortcutType; import com.android.internal.annotations.VisibleForTesting; import java.util.ArrayList; import java.util.Collections; Loading Loading @@ -159,21 +160,32 @@ public final class AccessibilityTargetHelper { final List<AccessibilityTarget> targets = new ArrayList<>(installedServices.size()); for (AccessibilityServiceInfo info : installedServices) { final int targetSdk = info.getResolveInfo().serviceInfo.applicationInfo.targetSdkVersion; final boolean hasRequestAccessibilityButtonFlag = (info.flags & AccessibilityServiceInfo.FLAG_REQUEST_ACCESSIBILITY_BUTTON) != 0; if ((targetSdk <= Build.VERSION_CODES.Q) && !hasRequestAccessibilityButtonFlag && (shortcutType == SOFTWARE)) { continue; } if (isValidServiceTarget(info, shortcutType)) { targets.add(createAccessibilityServiceTarget(context, shortcutType, info)); } } return targets; } /** * Check for maintaining compatibility on prior versions. * Determines if a given service should be accumulated in a list of installed services. * @param info service info to check. * @param shortcutType type of shortcut to accumulate a list for. * @return {@code true} if the service should be added (always true past version Q), * otherwise {@code false}. */ @VisibleForTesting public static boolean isValidServiceTarget( AccessibilityServiceInfo info, @UserShortcutType int shortcutType) { final boolean hasRequestAccessibilityButtonFlag = (info.flags & AccessibilityServiceInfo.FLAG_REQUEST_ACCESSIBILITY_BUTTON) != 0; return (info.getResolveInfo().serviceInfo.applicationInfo.targetSdkVersion > Build.VERSION_CODES.Q) || hasRequestAccessibilityButtonFlag || shortcutType != SOFTWARE; } private static List<AccessibilityTarget> getAccessibilityActivityTargets(Context context, @UserShortcutType int shortcutType) { final AccessibilityManager am = (AccessibilityManager) context.getSystemService( Loading
core/tests/coretests/src/android/view/accessibility/AccessibilityManagerTest.java +31 −2 Original line number Diff line number Diff line Loading @@ -20,6 +20,7 @@ import static com.android.internal.accessibility.AccessibilityShortcutController import static com.android.internal.accessibility.AccessibilityShortcutController.COLOR_INVERSION_TILE_COMPONENT_NAME; import static com.android.internal.accessibility.AccessibilityShortcutController.DALTONIZER_COMPONENT_NAME; import static com.android.internal.accessibility.AccessibilityShortcutController.DALTONIZER_TILE_COMPONENT_NAME; import static com.android.internal.accessibility.common.ShortcutConstants.UserShortcutType.HARDWARE; import static com.google.common.truth.Truth.assertThat; Loading @@ -31,6 +32,8 @@ import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.anyList; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.ArgumentMatchers.isNull; import static org.mockito.Matchers.any; import static org.mockito.Matchers.anyInt; import static org.mockito.Mockito.doThrow; Loading @@ -48,12 +51,14 @@ import android.graphics.drawable.Icon; import android.os.Bundle; import android.os.RemoteException; import android.os.UserHandle; import android.view.Display; import androidx.annotation.NonNull; import androidx.test.InstrumentationRegistry; import androidx.test.runner.AndroidJUnit4; import com.android.internal.R; import com.android.internal.accessibility.common.ShortcutConstants; import com.android.internal.accessibility.common.ShortcutConstants.UserShortcutType; import com.android.internal.util.IntPair; import com.android.server.accessibility.test.MessageCapturingHandler; Loading Loading @@ -321,7 +326,7 @@ public class AccessibilityManagerTest { Throwable rethrownException = assertThrows(RuntimeException.class, () -> manager.enableShortcutsForTargets( /* enable= */ false, UserShortcutType.HARDWARE, HARDWARE, Set.of(DALTONIZER_COMPONENT_NAME.flattenToString()), UserHandle.USER_CURRENT )); Loading @@ -331,7 +336,7 @@ public class AccessibilityManagerTest { @Test public void enableShortcutsForTargets_verifyServiceMethodCalled() throws Exception { AccessibilityManager manager = createManager(WITH_A11Y_ENABLED); int shortcutTypes = UserShortcutType.HARDWARE | UserShortcutType.TRIPLETAP; int shortcutTypes = HARDWARE | UserShortcutType.TRIPLETAP; manager.enableShortcutsForTargets( /* enable= */ false, Loading @@ -348,6 +353,30 @@ public class AccessibilityManagerTest { ); } @Test public void performAccessibilityShortcut_callToService_defaultTypeIsHardware() throws Exception { AccessibilityManager manager = createManager(WITH_A11Y_ENABLED); manager.performAccessibilityShortcut(); verify(mMockService).performAccessibilityShortcut( eq(Display.DEFAULT_DISPLAY), eq(HARDWARE), isNull()); } @Test public void performAccessibilityShortcut_callToService_typeParameterMatches() throws Exception { AccessibilityManager manager = createManager(WITH_A11Y_ENABLED); int display = Display.DEFAULT_DISPLAY; String name = LABEL; for (int type: ShortcutConstants.USER_SHORTCUT_TYPES) { manager.performAccessibilityShortcut(display, type, name); verify(mMockService).performAccessibilityShortcut(display, type, name); } } private class MyAccessibilityProxy extends AccessibilityDisplayProxy { MyAccessibilityProxy(int displayId, @NonNull List<AccessibilityServiceInfo> serviceInfos) { Loading