diff options
| author | 2023-03-13 19:20:19 +0000 | |
|---|---|---|
| committer | 2023-03-13 19:20:19 +0000 | |
| commit | f21ef1de30b0bdcb2fd91ab7980ca287c65d25ea (patch) | |
| tree | 929214793f007be99fd1a1cba8e94738eec0db85 | |
| parent | dcf6cb5eacc34d9f34f3c1191fda4aa76c55076d (diff) | |
| parent | dc6745dff37fe635671088a3c6830906a6b4cbe5 (diff) | |
Merge "Further A11yMenuService tests. Buttons with known behavior (brightness, volume & intent execution) verify the result of being clicked. Global Action buttons simply verify that clicking results in the service attempting to perform the respective action." into udc-dev
4 files changed, 252 insertions, 24 deletions
diff --git a/packages/SystemUI/accessibility/accessibilitymenu/AndroidManifest.xml b/packages/SystemUI/accessibility/accessibilitymenu/AndroidManifest.xml index ca8426560ccc..440c6e58d581 100644 --- a/packages/SystemUI/accessibility/accessibilitymenu/AndroidManifest.xml +++ b/packages/SystemUI/accessibility/accessibilitymenu/AndroidManifest.xml @@ -58,5 +58,8 @@ <intent> <action android:name="android.intent.action.VOICE_COMMAND" /> </intent> + <!--intent> + <action android:name="android.settings.ACCESSIBILITY_SETTINGS" /> + </intent--> </queries> </manifest>
\ No newline at end of file diff --git a/packages/SystemUI/accessibility/accessibilitymenu/src/com/android/systemui/accessibility/accessibilitymenu/AccessibilityMenuService.java b/packages/SystemUI/accessibility/accessibilitymenu/src/com/android/systemui/accessibility/accessibilitymenu/AccessibilityMenuService.java index 8ca64d2505ce..96ea5b45282b 100644 --- a/packages/SystemUI/accessibility/accessibilitymenu/src/com/android/systemui/accessibility/accessibilitymenu/AccessibilityMenuService.java +++ b/packages/SystemUI/accessibility/accessibilitymenu/src/com/android/systemui/accessibility/accessibilitymenu/AccessibilityMenuService.java @@ -35,6 +35,7 @@ import android.os.Handler; import android.os.Looper; import android.os.SystemClock; import android.provider.Settings; +import android.util.Log; import android.view.Display; import android.view.KeyEvent; import android.view.MotionEvent; @@ -56,6 +57,8 @@ public class AccessibilityMenuService extends AccessibilityService public static final String PACKAGE_NAME = AccessibilityMenuService.class.getPackageName(); public static final String INTENT_TOGGLE_MENU = ".toggle_menu"; public static final String INTENT_HIDE_MENU = ".hide_menu"; + public static final String INTENT_GLOBAL_ACTION = ".global_action"; + public static final String INTENT_GLOBAL_ACTION_EXTRA = "GLOBAL_ACTION"; private static final String TAG = "A11yMenuService"; private static final long BUFFER_MILLISECONDS_TO_PREVENT_UPDATE_FAILURE = 100L; @@ -231,6 +234,22 @@ public class AccessibilityMenuService extends AccessibilityService } /** + * Performs global action and broadcasts an intent indicating the action was performed. + * This is unnecessary for any current functionality, but is used for testing. + * Refer to {@code performGlobalAction()}. + * + * @param globalAction Global action to be performed. + * @return {@code true} if successful, {@code false} otherwise. + */ + private boolean performGlobalActionInternal(int globalAction) { + Intent intent = new Intent(PACKAGE_NAME + INTENT_GLOBAL_ACTION); + intent.putExtra(INTENT_GLOBAL_ACTION_EXTRA, globalAction); + sendBroadcast(intent); + Log.i("A11yMenuService", "Broadcasting global action " + globalAction); + return performGlobalAction(globalAction); + } + + /** * Handles click events of shortcuts. * * @param view the shortcut button being clicked. @@ -249,17 +268,17 @@ public class AccessibilityMenuService extends AccessibilityService new Intent(Settings.ACTION_ACCESSIBILITY_SETTINGS), Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK); } else if (viewTag == ShortcutId.ID_POWER_VALUE.ordinal()) { - performGlobalAction(GLOBAL_ACTION_POWER_DIALOG); + performGlobalActionInternal(GLOBAL_ACTION_POWER_DIALOG); } else if (viewTag == ShortcutId.ID_RECENT_VALUE.ordinal()) { - performGlobalAction(GLOBAL_ACTION_RECENTS); + performGlobalActionInternal(GLOBAL_ACTION_RECENTS); } else if (viewTag == ShortcutId.ID_LOCKSCREEN_VALUE.ordinal()) { - performGlobalAction(GLOBAL_ACTION_LOCK_SCREEN); + performGlobalActionInternal(GLOBAL_ACTION_LOCK_SCREEN); } else if (viewTag == ShortcutId.ID_QUICKSETTING_VALUE.ordinal()) { - performGlobalAction(GLOBAL_ACTION_QUICK_SETTINGS); + performGlobalActionInternal(GLOBAL_ACTION_QUICK_SETTINGS); } else if (viewTag == ShortcutId.ID_NOTIFICATION_VALUE.ordinal()) { - performGlobalAction(GLOBAL_ACTION_NOTIFICATIONS); + performGlobalActionInternal(GLOBAL_ACTION_NOTIFICATIONS); } else if (viewTag == ShortcutId.ID_SCREENSHOT_VALUE.ordinal()) { - performGlobalAction(GLOBAL_ACTION_TAKE_SCREENSHOT); + performGlobalActionInternal(GLOBAL_ACTION_TAKE_SCREENSHOT); } else if (viewTag == ShortcutId.ID_BRIGHTNESS_UP_VALUE.ordinal()) { adjustBrightness(BRIGHTNESS_UP_INCREMENT_GAMMA); return; diff --git a/packages/SystemUI/accessibility/accessibilitymenu/tests/AndroidManifest.xml b/packages/SystemUI/accessibility/accessibilitymenu/tests/AndroidManifest.xml index 7be6ca742376..2be92450f207 100644 --- a/packages/SystemUI/accessibility/accessibilitymenu/tests/AndroidManifest.xml +++ b/packages/SystemUI/accessibility/accessibilitymenu/tests/AndroidManifest.xml @@ -29,4 +29,15 @@ android:targetPackage="com.android.systemui.accessibility.accessibilitymenu.tests" android:label="AccessibilityMenu Test Cases"> </instrumentation> + + <queries> + <intent> + <action android:name="android.intent.action.VIEW" /> + <category android:name="android.intent.category.BROWSABLE" /> + <data android:scheme="https" /> + </intent> + <intent> + <action android:name="android.intent.action.VOICE_COMMAND" /> + </intent> + </queries> </manifest>
\ No newline at end of file diff --git a/packages/SystemUI/accessibility/accessibilitymenu/tests/src/com/android/systemui/accessibility/accessibilitymenu/tests/AccessibilityMenuServiceTest.java b/packages/SystemUI/accessibility/accessibilitymenu/tests/src/com/android/systemui/accessibility/accessibilitymenu/tests/AccessibilityMenuServiceTest.java index 529a70c1ab18..0e89dcdaf142 100644 --- a/packages/SystemUI/accessibility/accessibilitymenu/tests/src/com/android/systemui/accessibility/accessibilitymenu/tests/AccessibilityMenuServiceTest.java +++ b/packages/SystemUI/accessibility/accessibilitymenu/tests/src/com/android/systemui/accessibility/accessibilitymenu/tests/AccessibilityMenuServiceTest.java @@ -16,6 +16,15 @@ package com.android.systemui.accessibility.accessibilitymenu.tests; +import static android.accessibilityservice.AccessibilityService.GLOBAL_ACTION_LOCK_SCREEN; +import static android.accessibilityservice.AccessibilityService.GLOBAL_ACTION_NOTIFICATIONS; +import static android.accessibilityservice.AccessibilityService.GLOBAL_ACTION_POWER_DIALOG; +import static android.accessibilityservice.AccessibilityService.GLOBAL_ACTION_QUICK_SETTINGS; +import static android.accessibilityservice.AccessibilityService.GLOBAL_ACTION_RECENTS; +import static android.accessibilityservice.AccessibilityService.GLOBAL_ACTION_TAKE_SCREENSHOT; + +import static com.android.systemui.accessibility.accessibilitymenu.AccessibilityMenuService.INTENT_GLOBAL_ACTION; +import static com.android.systemui.accessibility.accessibilitymenu.AccessibilityMenuService.INTENT_GLOBAL_ACTION_EXTRA; import static com.android.systemui.accessibility.accessibilitymenu.AccessibilityMenuService.INTENT_HIDE_MENU; import static com.android.systemui.accessibility.accessibilitymenu.AccessibilityMenuService.INTENT_TOGGLE_MENU; import static com.android.systemui.accessibility.accessibilitymenu.AccessibilityMenuService.PACKAGE_NAME; @@ -23,11 +32,15 @@ import static com.android.systemui.accessibility.accessibilitymenu.Accessibility import android.accessibilityservice.AccessibilityServiceInfo; import android.app.Instrumentation; import android.app.UiAutomation; +import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; +import android.content.IntentFilter; import android.hardware.display.BrightnessInfo; import android.hardware.display.DisplayManager; +import android.media.AudioManager; import android.provider.Settings; +import android.util.Log; import android.view.accessibility.AccessibilityManager; import android.view.accessibility.AccessibilityNodeInfo; @@ -37,22 +50,29 @@ import androidx.test.platform.app.InstrumentationRegistry; import com.android.compatibility.common.util.TestUtils; import com.android.systemui.accessibility.accessibilitymenu.model.A11yMenuShortcut.ShortcutId; +import org.junit.After; import org.junit.AfterClass; +import org.junit.Before; import org.junit.BeforeClass; import org.junit.Test; import org.junit.runner.RunWith; import java.util.List; +import java.util.concurrent.atomic.AtomicInteger; @RunWith(AndroidJUnit4.class) public class AccessibilityMenuServiceTest { private static final String TAG = "A11yMenuServiceTest"; + private static final int CLICK_ID = AccessibilityNodeInfo.ACTION_CLICK; private static final int TIMEOUT_SERVICE_STATUS_CHANGE_S = 5; - private static final int TIMEOUT_UI_CHANGE_S = 5; + private static final int TIMEOUT_UI_CHANGE_S = 10; + private static final int NO_GLOBAL_ACTION = -1; + private static final String INPUT_KEYEVENT_KEYCODE_BACK = "input keyevent KEYCODE_BACK"; private static Instrumentation sInstrumentation; private static UiAutomation sUiAutomation; + private static AtomicInteger sLastGlobalAction; private static AccessibilityManager sAccessibilityManager; @@ -62,7 +82,7 @@ public class AccessibilityMenuServiceTest { sInstrumentation = InstrumentationRegistry.getInstrumentation(); sUiAutomation = sInstrumentation.getUiAutomation( UiAutomation.FLAG_DONT_SUPPRESS_ACCESSIBILITY_SERVICES); - final Context context = sInstrumentation.getContext(); + final Context context = sInstrumentation.getTargetContext(); sAccessibilityManager = context.getSystemService(AccessibilityManager.class); // Disable all a11yServices if any are active. @@ -85,6 +105,17 @@ public class AccessibilityMenuServiceTest { () -> sAccessibilityManager.getEnabledAccessibilityServiceList( AccessibilityServiceInfo.FEEDBACK_ALL_MASK).stream().filter( info -> info.getId().contains(serviceName)).count() == 1); + + sLastGlobalAction = new AtomicInteger(NO_GLOBAL_ACTION); + context.registerReceiver(new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + Log.i(TAG, "Received global action intent."); + sLastGlobalAction.set( + intent.getIntExtra(INTENT_GLOBAL_ACTION_EXTRA, NO_GLOBAL_ACTION)); + }}, + new IntentFilter(PACKAGE_NAME + INTENT_GLOBAL_ACTION), + null, null, Context.RECEIVER_EXPORTED); } @AfterClass @@ -93,23 +124,39 @@ public class AccessibilityMenuServiceTest { Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES, ""); } - private boolean isMenuVisible() { - return sUiAutomation.getRootInActiveWindow() != null - && sUiAutomation.getRootInActiveWindow().getPackageName().toString().equals( - PACKAGE_NAME); + @Before + public void setup() throws Throwable { + openMenu(); } - private void openMenu() throws Throwable { - if (isMenuVisible()) { - return; - } + @After + public void tearDown() throws Throwable { + closeMenu(); + sLastGlobalAction.set(NO_GLOBAL_ACTION); + } + + private static boolean isMenuVisible() { + AccessibilityNodeInfo root = sUiAutomation.getRootInActiveWindow(); + return root != null && root.getPackageName().toString().equals(PACKAGE_NAME); + } + + private static void openMenu() throws Throwable { Intent intent = new Intent(PACKAGE_NAME + INTENT_TOGGLE_MENU); sInstrumentation.getContext().sendBroadcast(intent); + TestUtils.waitUntil("Timed out before menu could appear.", - TIMEOUT_UI_CHANGE_S, () -> isMenuVisible()); + TIMEOUT_UI_CHANGE_S, + () -> { + if (isMenuVisible()) { + return true; + } else { + sInstrumentation.getContext().sendBroadcast(intent); + return false; + } + }); } - private void closeMenu() throws Throwable { + private static void closeMenu() throws Throwable { if (!isMenuVisible()) { return; } @@ -119,11 +166,21 @@ public class AccessibilityMenuServiceTest { TIMEOUT_UI_CHANGE_S, () -> !isMenuVisible()); } + /** + * Provides list of all present shortcut buttons. + * @return List of shortcut buttons. + */ private List<AccessibilityNodeInfo> getGridButtonList() { return sUiAutomation.getRootInActiveWindow() .findAccessibilityNodeInfosByViewId(PACKAGE_NAME + ":id/shortcutIconBtn"); } + /** + * Returns the first button whose uniqueID matches the provided text. + * @param buttons List of buttons. + * @param text Text to match button's uniqueID to. + * @return Button whose uniqueID matches text, {@code null} otherwise. + */ private AccessibilityNodeInfo findGridButtonInfo( List<AccessibilityNodeInfo> buttons, String text) { for (AccessibilityNodeInfo button: buttons) { @@ -136,8 +193,6 @@ public class AccessibilityMenuServiceTest { @Test public void testAdjustBrightness() throws Throwable { - openMenu(); - Context context = sInstrumentation.getTargetContext(); DisplayManager displayManager = context.getSystemService( DisplayManager.class); @@ -149,7 +204,6 @@ public class AccessibilityMenuServiceTest { AccessibilityNodeInfo brightnessDownButton = findGridButtonInfo(buttons, String.valueOf(ShortcutId.ID_BRIGHTNESS_DOWN_VALUE.ordinal())); - int clickId = AccessibilityNodeInfo.AccessibilityAction.ACTION_CLICK.getId(); BrightnessInfo brightnessInfo = displayManager.getDisplay( context.getDisplayId()).getBrightnessInfo(); @@ -159,7 +213,7 @@ public class AccessibilityMenuServiceTest { TIMEOUT_UI_CHANGE_S, () -> displayManager.getBrightness(context.getDisplayId()) == brightnessInfo.brightnessMinimum); - brightnessUpButton.performAction(clickId); + brightnessUpButton.performAction(CLICK_ID); TestUtils.waitUntil("Did not detect an increase in brightness.", TIMEOUT_UI_CHANGE_S, () -> displayManager.getBrightness(context.getDisplayId()) @@ -170,14 +224,155 @@ public class AccessibilityMenuServiceTest { TIMEOUT_UI_CHANGE_S, () -> displayManager.getBrightness(context.getDisplayId()) == brightnessInfo.brightnessMaximum); - brightnessDownButton.performAction(clickId); + brightnessDownButton.performAction(CLICK_ID); TestUtils.waitUntil("Did not detect a decrease in brightness.", TIMEOUT_UI_CHANGE_S, () -> displayManager.getBrightness(context.getDisplayId()) < brightnessInfo.brightnessMaximum); } finally { displayManager.setBrightness(context.getDisplayId(), resetBrightness); - closeMenu(); } } + + @Test + public void testAdjustVolume() throws Throwable { + Context context = sInstrumentation.getTargetContext(); + AudioManager audioManager = context.getSystemService(AudioManager.class); + int resetVolume = audioManager.getStreamVolume(AudioManager.STREAM_MUSIC); + + List<AccessibilityNodeInfo> buttons = getGridButtonList(); + AccessibilityNodeInfo volumeUpButton = findGridButtonInfo(buttons, + String.valueOf(ShortcutId.ID_VOLUME_UP_VALUE.ordinal())); + AccessibilityNodeInfo volumeDownButton = findGridButtonInfo(buttons, + String.valueOf(ShortcutId.ID_VOLUME_DOWN_VALUE.ordinal())); + + try { + int min = audioManager.getStreamMinVolume(AudioManager.STREAM_MUSIC); + audioManager.setStreamVolume(AudioManager.STREAM_MUSIC, min, + AudioManager.FLAG_REMOVE_SOUND_AND_VIBRATE); + TestUtils.waitUntil("Could not change audio stream to minimum volume.", + TIMEOUT_UI_CHANGE_S, + () -> audioManager.getStreamVolume(AudioManager.STREAM_MUSIC) == min); + volumeUpButton.performAction(CLICK_ID); + TestUtils.waitUntil("Did not detect an increase in volume.", + TIMEOUT_UI_CHANGE_S, + () -> audioManager.getStreamVolume(AudioManager.STREAM_MUSIC) > min); + + int max = audioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC); + audioManager.setStreamVolume(AudioManager.STREAM_MUSIC, max, + AudioManager.FLAG_REMOVE_SOUND_AND_VIBRATE); + TestUtils.waitUntil("Could not change audio stream to maximum volume.", + TIMEOUT_UI_CHANGE_S, + () -> audioManager.getStreamVolume(AudioManager.STREAM_MUSIC) == max); + volumeDownButton.performAction(CLICK_ID); + TestUtils.waitUntil("Did not detect a decrease in volume.", + TIMEOUT_UI_CHANGE_S, + () -> audioManager.getStreamVolume(AudioManager.STREAM_MUSIC) < max); + } finally { + audioManager.setStreamVolume(AudioManager.STREAM_MUSIC, + resetVolume, AudioManager.FLAG_REMOVE_SOUND_AND_VIBRATE); + } + } + + @Test + public void testAssistantButton_opensVoiceAssistant() throws Throwable { + AccessibilityNodeInfo assistantButton = findGridButtonInfo(getGridButtonList(), + String.valueOf(ShortcutId.ID_ASSISTANT_VALUE.ordinal())); + Intent expectedIntent = new Intent(Intent.ACTION_VOICE_COMMAND); + String expectedPackage = expectedIntent.resolveActivity( + sInstrumentation.getContext().getPackageManager()).getPackageName(); + + sUiAutomation.executeAndWaitForEvent( + () -> assistantButton.performAction(CLICK_ID), + (event) -> expectedPackage.contains(event.getPackageName()), + TIMEOUT_UI_CHANGE_S * 1000 + ); + } + + @Test + public void testAccessibilitySettingsButton_opensAccessibilitySettings() throws Throwable { + AccessibilityNodeInfo settingsButton = findGridButtonInfo(getGridButtonList(), + String.valueOf(ShortcutId.ID_A11YSETTING_VALUE.ordinal())); + Intent expectedIntent = new Intent(Settings.ACTION_ACCESSIBILITY_SETTINGS); + String expectedPackage = expectedIntent.resolveActivity( + sInstrumentation.getContext().getPackageManager()).getPackageName(); + + sUiAutomation.executeAndWaitForEvent( + () -> settingsButton.performAction(CLICK_ID), + (event) -> expectedPackage.contains(event.getPackageName()), + TIMEOUT_UI_CHANGE_S * 1000 + ); + } + + @Test + public void testPowerButton_performsGlobalAction() throws Throwable { + AccessibilityNodeInfo button = findGridButtonInfo(getGridButtonList(), + String.valueOf(ShortcutId.ID_POWER_VALUE.ordinal())); + + button.performAction(CLICK_ID); + TestUtils.waitUntil("Did not detect Power action being performed.", + TIMEOUT_UI_CHANGE_S, + () -> sLastGlobalAction.compareAndSet( + GLOBAL_ACTION_POWER_DIALOG, NO_GLOBAL_ACTION)); + } + + @Test + public void testRecentButton_performsGlobalAction() throws Throwable { + AccessibilityNodeInfo button = findGridButtonInfo(getGridButtonList(), + String.valueOf(ShortcutId.ID_RECENT_VALUE.ordinal())); + + button.performAction(CLICK_ID); + TestUtils.waitUntil("Did not detect Recents action being performed.", + TIMEOUT_UI_CHANGE_S, + () -> sLastGlobalAction.compareAndSet( + GLOBAL_ACTION_RECENTS, NO_GLOBAL_ACTION)); + } + + @Test + public void testLockButton_performsGlobalAction() throws Throwable { + AccessibilityNodeInfo button = findGridButtonInfo(getGridButtonList(), + String.valueOf(ShortcutId.ID_LOCKSCREEN_VALUE.ordinal())); + + button.performAction(CLICK_ID); + TestUtils.waitUntil("Did not detect Lock action being performed.", + TIMEOUT_UI_CHANGE_S, + () -> sLastGlobalAction.compareAndSet( + GLOBAL_ACTION_LOCK_SCREEN, NO_GLOBAL_ACTION)); + } + + @Test + public void testQuickSettingsButton_performsGlobalAction() throws Throwable { + AccessibilityNodeInfo button = findGridButtonInfo(getGridButtonList(), + String.valueOf(ShortcutId.ID_QUICKSETTING_VALUE.ordinal())); + + button.performAction(CLICK_ID); + TestUtils.waitUntil("Did not detect Quick Settings action being performed.", + TIMEOUT_UI_CHANGE_S, + () -> sLastGlobalAction.compareAndSet( + GLOBAL_ACTION_QUICK_SETTINGS, NO_GLOBAL_ACTION)); + } + + @Test + public void testNotificationsButton_performsGlobalAction() throws Throwable { + AccessibilityNodeInfo button = findGridButtonInfo(getGridButtonList(), + String.valueOf(ShortcutId.ID_NOTIFICATION_VALUE.ordinal())); + + button.performAction(CLICK_ID); + TestUtils.waitUntil("Did not detect Notifications action being performed.", + TIMEOUT_UI_CHANGE_S, + () -> sLastGlobalAction.compareAndSet( + GLOBAL_ACTION_NOTIFICATIONS, NO_GLOBAL_ACTION)); + } + + @Test + public void testScreenshotButton_performsGlobalAction() throws Throwable { + AccessibilityNodeInfo button = findGridButtonInfo(getGridButtonList(), + String.valueOf(ShortcutId.ID_SCREENSHOT_VALUE.ordinal())); + + button.performAction(CLICK_ID); + TestUtils.waitUntil("Did not detect Screenshot action being performed.", + TIMEOUT_UI_CHANGE_S, + () -> sLastGlobalAction.compareAndSet( + GLOBAL_ACTION_TAKE_SCREENSHOT, NO_GLOBAL_ACTION)); + } } |