diff options
author | 2024-06-20 17:03:11 +0000 | |
---|---|---|
committer | 2024-06-20 17:03:11 +0000 | |
commit | cf7ffed6d71761d02f8ea18f2657410b9eee286e (patch) | |
tree | a90a9f7158bbcad3fa35d6589bf166ab78b9a26d | |
parent | 40d3c7fd8fd6aa7f7eaa033ff7ea434a5441b1b1 (diff) | |
parent | a67233312eea0ad0445edbfd368b369aa06e4e88 (diff) |
Merge "Add menu and media play/pause global actions [1/2]" into main
8 files changed, 154 insertions, 1 deletions
diff --git a/core/api/current.txt b/core/api/current.txt index 2866e71dce91..d64593854749 100644 --- a/core/api/current.txt +++ b/core/api/current.txt @@ -3454,6 +3454,8 @@ package android.accessibilityservice { field public static final int GLOBAL_ACTION_HOME = 2; // 0x2 field public static final int GLOBAL_ACTION_KEYCODE_HEADSETHOOK = 10; // 0xa field public static final int GLOBAL_ACTION_LOCK_SCREEN = 8; // 0x8 + field @FlaggedApi("android.view.accessibility.global_action_media_play_pause") public static final int GLOBAL_ACTION_MEDIA_PLAY_PAUSE = 22; // 0x16 + field @FlaggedApi("android.view.accessibility.global_action_menu") public static final int GLOBAL_ACTION_MENU = 21; // 0x15 field public static final int GLOBAL_ACTION_NOTIFICATIONS = 4; // 0x4 field public static final int GLOBAL_ACTION_POWER_DIALOG = 6; // 0x6 field public static final int GLOBAL_ACTION_QUICK_SETTINGS = 5; // 0x5 diff --git a/core/java/android/accessibilityservice/AccessibilityService.java b/core/java/android/accessibilityservice/AccessibilityService.java index d70fa19a4468..81cc6742fb17 100644 --- a/core/java/android/accessibilityservice/AccessibilityService.java +++ b/core/java/android/accessibilityservice/AccessibilityService.java @@ -67,6 +67,7 @@ import android.view.accessibility.AccessibilityInteractionClient; import android.view.accessibility.AccessibilityNodeInfo; import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction; import android.view.accessibility.AccessibilityWindowInfo; +import android.view.accessibility.Flags; import android.view.inputmethod.EditorInfo; import com.android.internal.annotations.VisibleForTesting; @@ -625,6 +626,18 @@ public abstract class AccessibilityService extends Service { */ public static final int GLOBAL_ACTION_DPAD_CENTER = 20; + /** + * Action to trigger menu key event. + */ + @FlaggedApi(Flags.FLAG_GLOBAL_ACTION_MENU) + public static final int GLOBAL_ACTION_MENU = 21; + + /** + * Action to trigger media play/pause key event. + */ + @FlaggedApi(Flags.FLAG_GLOBAL_ACTION_MEDIA_PLAY_PAUSE) + public static final int GLOBAL_ACTION_MEDIA_PLAY_PAUSE = 22; + private static final String LOG_TAG = "AccessibilityService"; /** diff --git a/core/java/android/view/accessibility/flags/accessibility_flags.aconfig b/core/java/android/view/accessibility/flags/accessibility_flags.aconfig index 685654a781dd..a62efdf37665 100644 --- a/core/java/android/view/accessibility/flags/accessibility_flags.aconfig +++ b/core/java/android/view/accessibility/flags/accessibility_flags.aconfig @@ -82,6 +82,20 @@ flag { flag { namespace: "accessibility" + name: "global_action_menu" + description: "Allow AccessibilityService to perform GLOBAL_ACTION_MENU" + bug: "334954140" +} + +flag { + namespace: "accessibility" + name: "global_action_media_play_pause" + description: "Allow AccessibilityService to perform GLOBAL_ACTION_MEDIA_PLAY_PAUSE" + bug: "334954140" +} + +flag { + namespace: "accessibility" name: "granular_scrolling" description: "Allow the use of granular scrolling. This allows scrollable nodes to scroll by increments other than a full screen" bug: "302376158" diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml index 59066eb83f1c..0b9bde835b99 100644 --- a/core/res/res/values/strings.xml +++ b/core/res/res/values/strings.xml @@ -5937,6 +5937,10 @@ <string name="accessibility_system_action_hardware_a11y_shortcut_label">Accessibility Shortcut</string> <!-- Label for dismissing the notification shade [CHAR LIMIT=NONE] --> <string name="accessibility_system_action_dismiss_notification_shade">Dismiss Notification Shade</string> + <!-- Label for menu action [CHAR LIMIT=NONE] --> + <string name="accessibility_system_action_menu_label">Menu</string> + <!-- Label for media play/pause action [CHAR LIMIT=NONE] --> + <string name="accessibility_system_action_media_play_pause_label">Media Play/Pause</string> <!-- Label for Dpad up action [CHAR LIMIT=NONE] --> <string name="accessibility_system_action_dpad_up_label">Dpad Up</string> <!-- Label for Dpad down action [CHAR LIMIT=NONE] --> diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index 54ab1470dea7..8b13a11eb46f 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -4433,6 +4433,8 @@ <java-symbol type="string" name="accessibility_system_action_on_screen_a11y_shortcut_chooser_label" /> <java-symbol type="string" name="accessibility_system_action_hardware_a11y_shortcut_label" /> <java-symbol type="string" name="accessibility_system_action_dismiss_notification_shade" /> + <java-symbol type="string" name="accessibility_system_action_menu_label" /> + <java-symbol type="string" name="accessibility_system_action_media_play_pause_label" /> <java-symbol type="string" name="accessibility_system_action_dpad_up_label" /> <java-symbol type="string" name="accessibility_system_action_dpad_down_label" /> <java-symbol type="string" name="accessibility_system_action_dpad_left_label" /> diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/SystemActions.java b/packages/SystemUI/src/com/android/systemui/accessibility/SystemActions.java index da49201db808..5c5ff1e793df 100644 --- a/packages/SystemUI/src/com/android/systemui/accessibility/SystemActions.java +++ b/packages/SystemUI/src/com/android/systemui/accessibility/SystemActions.java @@ -42,6 +42,7 @@ import android.view.KeyCharacterMap; import android.view.KeyEvent; import android.view.WindowManagerGlobal; import android.view.accessibility.AccessibilityManager; +import android.view.accessibility.Flags; import com.android.internal.R; import com.android.internal.accessibility.dialog.AccessibilityButtonChooserActivity; @@ -178,6 +179,18 @@ public class SystemActions implements CoreStartable, ConfigurationController.Con private static final int SYSTEM_ACTION_ID_DPAD_CENTER = AccessibilityService.GLOBAL_ACTION_DPAD_CENTER; // 20 + /** + * Action ID to trigger menu key event. + */ + private static final int SYSTEM_ACTION_ID_MENU = + AccessibilityService.GLOBAL_ACTION_MENU; // 21 + + /** + * Action ID to trigger media play/pause key event. + */ + private static final int SYSTEM_ACTION_ID_MEDIA_PLAY_PAUSE = + AccessibilityService.GLOBAL_ACTION_MEDIA_PLAY_PAUSE; // 22 + private static final String PERMISSION_SELF = "com.android.systemui.permission.SELF"; private final SystemActionsBroadcastReceiver mReceiver; @@ -305,6 +318,14 @@ public class SystemActions implements CoreStartable, ConfigurationController.Con R.string.accessibility_system_action_dpad_center_label, SystemActionsBroadcastReceiver.INTENT_ACTION_DPAD_CENTER); + RemoteAction actionMenu = createRemoteAction( + R.string.accessibility_system_action_menu_label, + SystemActionsBroadcastReceiver.INTENT_ACTION_MENU); + + RemoteAction actionMediaPlayPause = createRemoteAction( + R.string.accessibility_system_action_media_play_pause_label, + SystemActionsBroadcastReceiver.INTENT_ACTION_MEDIA_PLAY_PAUSE); + mA11yManager.registerSystemAction(actionBack, SYSTEM_ACTION_ID_BACK); mA11yManager.registerSystemAction(actionHome, SYSTEM_ACTION_ID_HOME); mA11yManager.registerSystemAction(actionRecents, SYSTEM_ACTION_ID_RECENTS); @@ -324,6 +345,8 @@ public class SystemActions implements CoreStartable, ConfigurationController.Con mA11yManager.registerSystemAction(actionDpadLeft, SYSTEM_ACTION_ID_DPAD_LEFT); mA11yManager.registerSystemAction(actionDpadRight, SYSTEM_ACTION_ID_DPAD_RIGHT); mA11yManager.registerSystemAction(actionDpadCenter, SYSTEM_ACTION_ID_DPAD_CENTER); + mA11yManager.registerSystemAction(actionMenu, SYSTEM_ACTION_ID_MENU); + mA11yManager.registerSystemAction(actionMediaPlayPause, SYSTEM_ACTION_ID_MEDIA_PLAY_PAUSE); registerOrUnregisterDismissNotificationShadeAction(); } @@ -433,6 +456,14 @@ public class SystemActions implements CoreStartable, ConfigurationController.Con labelId = R.string.accessibility_system_action_dpad_center_label; intent = SystemActionsBroadcastReceiver.INTENT_ACTION_DPAD_CENTER; break; + case SYSTEM_ACTION_ID_MENU: + labelId = R.string.accessibility_system_action_menu_label; + intent = SystemActionsBroadcastReceiver.INTENT_ACTION_MENU; + break; + case SYSTEM_ACTION_ID_MEDIA_PLAY_PAUSE: + labelId = R.string.accessibility_system_action_media_play_pause_label; + intent = SystemActionsBroadcastReceiver.INTENT_ACTION_MEDIA_PLAY_PAUSE; + break; default: return; } @@ -569,6 +600,16 @@ public class SystemActions implements CoreStartable, ConfigurationController.Con sendDownAndUpKeyEvents(KeyEvent.KEYCODE_DPAD_CENTER); } + @VisibleForTesting + void handleMenu() { + sendDownAndUpKeyEvents(KeyEvent.KEYCODE_MENU); + } + + @VisibleForTesting + void handleMediaPlayPause() { + sendDownAndUpKeyEvents(KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE); + } + private class SystemActionsBroadcastReceiver extends BroadcastReceiver { private static final String INTENT_ACTION_BACK = "SYSTEM_ACTION_BACK"; private static final String INTENT_ACTION_HOME = "SYSTEM_ACTION_HOME"; @@ -592,6 +633,9 @@ public class SystemActions implements CoreStartable, ConfigurationController.Con private static final String INTENT_ACTION_DPAD_LEFT = "SYSTEM_ACTION_DPAD_LEFT"; private static final String INTENT_ACTION_DPAD_RIGHT = "SYSTEM_ACTION_DPAD_RIGHT"; private static final String INTENT_ACTION_DPAD_CENTER = "SYSTEM_ACTION_DPAD_CENTER"; + private static final String INTENT_ACTION_MENU = "SYSTEM_ACTION_MENU"; + private static final String INTENT_ACTION_MEDIA_PLAY_PAUSE = + "SYSTEM_ACTION_MEDIA_PLAY_PAUSE"; private PendingIntent createPendingIntent(Context context, String intentAction) { switch (intentAction) { @@ -612,7 +656,9 @@ public class SystemActions implements CoreStartable, ConfigurationController.Con case INTENT_ACTION_DPAD_DOWN: case INTENT_ACTION_DPAD_LEFT: case INTENT_ACTION_DPAD_RIGHT: - case INTENT_ACTION_DPAD_CENTER: { + case INTENT_ACTION_DPAD_CENTER: + case INTENT_ACTION_MENU: + case INTENT_ACTION_MEDIA_PLAY_PAUSE: { Intent intent = new Intent(intentAction); intent.setPackage(context.getPackageName()); intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND); @@ -645,6 +691,8 @@ public class SystemActions implements CoreStartable, ConfigurationController.Con intentFilter.addAction(INTENT_ACTION_DPAD_LEFT); intentFilter.addAction(INTENT_ACTION_DPAD_RIGHT); intentFilter.addAction(INTENT_ACTION_DPAD_CENTER); + intentFilter.addAction(INTENT_ACTION_MENU); + intentFilter.addAction(INTENT_ACTION_MEDIA_PLAY_PAUSE); return intentFilter; } @@ -724,6 +772,18 @@ public class SystemActions implements CoreStartable, ConfigurationController.Con handleDpadCenter(); break; } + case INTENT_ACTION_MENU: { + if (Flags.globalActionMenu()) { + handleMenu(); + } + break; + } + case INTENT_ACTION_MEDIA_PLAY_PAUSE: { + if (Flags.globalActionMediaPlayPause()) { + handleMediaPlayPause(); + } + break; + } default: break; } diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/SystemActionsTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/SystemActionsTest.java index b478d5cc9d50..da3e4871d21f 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/SystemActionsTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/SystemActionsTest.java @@ -17,6 +17,7 @@ package com.android.systemui.accessibility; import static com.google.common.truth.Truth.assertThat; + import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.Mockito.doAnswer; @@ -25,11 +26,15 @@ import static org.mockito.Mockito.when; import android.hardware.input.InputManager; import android.os.RemoteException; +import android.platform.test.annotations.RequiresFlagsEnabled; +import android.platform.test.flag.junit.CheckFlagsRule; +import android.platform.test.flag.junit.DeviceFlagsValueProvider; import android.telecom.TelecomManager; import android.telephony.TelephonyManager; import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; import android.view.KeyEvent; +import android.view.accessibility.Flags; import androidx.test.filters.SmallTest; @@ -43,6 +48,7 @@ import com.android.systemui.statusbar.NotificationShadeWindowController; import com.android.systemui.statusbar.policy.KeyguardStateController; import org.junit.Before; +import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; @@ -76,6 +82,9 @@ public class SystemActionsTest extends SysuiTestCase { private SystemActions mSystemActions; + @Rule + public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule(); + @Before public void setUp() throws RemoteException { MockitoAnnotations.initMocks(this); @@ -130,4 +139,40 @@ public class SystemActionsTest extends SysuiTestCase { verify(mTelecomManager).endCall(); } + + @Test + @RequiresFlagsEnabled(Flags.FLAG_GLOBAL_ACTION_MENU) + public void handleMenu_injectsKeyEvents() { + final List<KeyEvent> keyEvents = new ArrayList<>(); + doAnswer(invocation -> { + keyEvents.add(new KeyEvent(invocation.getArgument(0))); + return null; + }).when(mInputManager).injectInputEvent(any(), anyInt()); + + mSystemActions.handleMenu(); + + assertThat(keyEvents.size()).isEqualTo(2); + assertThat(keyEvents.get(0).getKeyCode()).isEqualTo(KeyEvent.KEYCODE_MENU); + assertThat(keyEvents.get(0).getAction()).isEqualTo(KeyEvent.ACTION_DOWN); + assertThat(keyEvents.get(1).getKeyCode()).isEqualTo(KeyEvent.KEYCODE_MENU); + assertThat(keyEvents.get(1).getAction()).isEqualTo(KeyEvent.ACTION_UP); + } + + @Test + @RequiresFlagsEnabled(Flags.FLAG_GLOBAL_ACTION_MEDIA_PLAY_PAUSE) + public void handleMediaPlayPause_injectsKeyEvents() { + final List<KeyEvent> keyEvents = new ArrayList<>(); + doAnswer(invocation -> { + keyEvents.add(new KeyEvent(invocation.getArgument(0))); + return null; + }).when(mInputManager).injectInputEvent(any(), anyInt()); + + mSystemActions.handleMediaPlayPause(); + + assertThat(keyEvents.size()).isEqualTo(2); + assertThat(keyEvents.get(0).getKeyCode()).isEqualTo(KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE); + assertThat(keyEvents.get(0).getAction()).isEqualTo(KeyEvent.ACTION_DOWN); + assertThat(keyEvents.get(1).getKeyCode()).isEqualTo(KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE); + assertThat(keyEvents.get(1).getAction()).isEqualTo(KeyEvent.ACTION_UP); + } } diff --git a/services/accessibility/java/com/android/server/accessibility/SystemActionPerformer.java b/services/accessibility/java/com/android/server/accessibility/SystemActionPerformer.java index 9747579fa231..2945af507d51 100644 --- a/services/accessibility/java/com/android/server/accessibility/SystemActionPerformer.java +++ b/services/accessibility/java/com/android/server/accessibility/SystemActionPerformer.java @@ -34,6 +34,7 @@ import android.view.KeyCharacterMap; import android.view.KeyEvent; import android.view.WindowManager; import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction; +import android.view.accessibility.Flags; import com.android.internal.R; import com.android.internal.accessibility.util.AccessibilityUtils; @@ -328,6 +329,18 @@ public class SystemActionPerformer { sendDownAndUpKeyEvents(KeyEvent.KEYCODE_DPAD_CENTER, InputDevice.SOURCE_KEYBOARD | InputDevice.SOURCE_DPAD); return true; + case AccessibilityService.GLOBAL_ACTION_MENU: + if (Flags.globalActionMenu()) { + sendDownAndUpKeyEvents(KeyEvent.KEYCODE_MENU, + InputDevice.SOURCE_KEYBOARD); + } + return true; + case AccessibilityService.GLOBAL_ACTION_MEDIA_PLAY_PAUSE: + if (Flags.globalActionMediaPlayPause()) { + sendDownAndUpKeyEvents(KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE, + InputDevice.SOURCE_KEYBOARD); + } + return true; default: Slog.e(TAG, "Invalid action id: " + actionId); return false; |