Loading packages/SystemUI/accessibility/accessibilitymenu/src/com/android/systemui/accessibility/accessibilitymenu/AccessibilityMenuService.java +16 −6 Original line number Diff line number Diff line Loading @@ -56,10 +56,12 @@ public class AccessibilityMenuService extends AccessibilityService implements View.OnTouchListener { public static final String PACKAGE_NAME = AccessibilityMenuService.class.getPackageName(); public static final String PACKAGE_TESTS = ".tests"; 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"; public static final String INTENT_OPEN_BLOCKED = "OPEN_BLOCKED"; private static final String TAG = "A11yMenuService"; private static final long BUFFER_MILLISECONDS_TO_PREVENT_UPDATE_FAILURE = 100L; Loading Loading @@ -192,7 +194,7 @@ public class AccessibilityMenuService extends AccessibilityService IntentFilter hideMenuFilter = new IntentFilter(); hideMenuFilter.addAction(Intent.ACTION_SCREEN_OFF); hideMenuFilter.addAction(PACKAGE_NAME + INTENT_HIDE_MENU); hideMenuFilter.addAction(INTENT_HIDE_MENU); // Including WRITE_SECURE_SETTINGS enforces that we only listen to apps // with the restricted WRITE_SECURE_SETTINGS permission who broadcast this intent. Loading @@ -200,7 +202,7 @@ public class AccessibilityMenuService extends AccessibilityService Manifest.permission.WRITE_SECURE_SETTINGS, null, Context.RECEIVER_EXPORTED); registerReceiver(mToggleMenuReceiver, new IntentFilter(PACKAGE_NAME + INTENT_TOGGLE_MENU), new IntentFilter(INTENT_TOGGLE_MENU), Manifest.permission.WRITE_SECURE_SETTINGS, null, Context.RECEIVER_EXPORTED); Loading Loading @@ -245,8 +247,9 @@ public class AccessibilityMenuService extends AccessibilityService * @return {@code true} if successful, {@code false} otherwise. */ private boolean performGlobalActionInternal(int globalAction) { Intent intent = new Intent(PACKAGE_NAME + INTENT_GLOBAL_ACTION); Intent intent = new Intent(INTENT_GLOBAL_ACTION); intent.putExtra(INTENT_GLOBAL_ACTION_EXTRA, globalAction); intent.setPackage(PACKAGE_NAME + PACKAGE_TESTS); sendBroadcast(intent); Log.i("A11yMenuService", "Broadcasting global action " + globalAction); return performGlobalAction(globalAction); Loading Loading @@ -410,9 +413,16 @@ public class AccessibilityMenuService extends AccessibilityService private void toggleVisibility() { boolean locked = mKeyguardManager != null && mKeyguardManager.isKeyguardLocked(); if (!locked && SystemClock.uptimeMillis() - mLastTimeTouchedOutside if (!locked) { if (SystemClock.uptimeMillis() - mLastTimeTouchedOutside > BUTTON_CLICK_TIMEOUT) { mA11yMenuLayout.toggleVisibility(); } } else { // Broadcast for testing. Intent intent = new Intent(INTENT_OPEN_BLOCKED); intent.setPackage(PACKAGE_NAME + PACKAGE_TESTS); sendBroadcast(intent); } } } packages/SystemUI/accessibility/accessibilitymenu/tests/src/com/android/systemui/accessibility/accessibilitymenu/tests/AccessibilityMenuServiceTest.java +34 −31 Original line number Diff line number Diff line Loading @@ -23,6 +23,7 @@ import static android.accessibilityservice.AccessibilityService.GLOBAL_ACTION_QU 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_OPEN_BLOCKED; 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; Loading Loading @@ -65,6 +66,7 @@ import org.junit.Test; import org.junit.runner.RunWith; import java.util.List; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; @RunWith(AndroidJUnit4.class) Loading @@ -75,12 +77,11 @@ public class AccessibilityMenuServiceTest { private static final int TIMEOUT_SERVICE_STATUS_CHANGE_S = 5; private static final int TIMEOUT_UI_CHANGE_S = 5; private static final int NO_GLOBAL_ACTION = -1; private static final String INPUT_KEYEVENT_KEYCODE_BACK = "input keyevent KEYCODE_BACK"; private static final String TEST_PIN = "1234"; private static Instrumentation sInstrumentation; private static UiAutomation sUiAutomation; private static AtomicInteger sLastGlobalAction; private static final AtomicInteger sLastGlobalAction = new AtomicInteger(NO_GLOBAL_ACTION); private static final AtomicBoolean sOpenBlocked = new AtomicBoolean(false); private static AccessibilityManager sAccessibilityManager; private static PowerManager sPowerManager; Loading Loading @@ -122,8 +123,6 @@ 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) { Loading @@ -131,20 +130,28 @@ public class AccessibilityMenuServiceTest { sLastGlobalAction.set( intent.getIntExtra(INTENT_GLOBAL_ACTION_EXTRA, NO_GLOBAL_ACTION)); }}, new IntentFilter(PACKAGE_NAME + INTENT_GLOBAL_ACTION), new IntentFilter(INTENT_GLOBAL_ACTION), null, null, Context.RECEIVER_EXPORTED); context.registerReceiver(new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { Log.i(TAG, "Received notification that menu cannot be opened."); sOpenBlocked.set(true); }}, new IntentFilter(INTENT_OPEN_BLOCKED), null, null, Context.RECEIVER_EXPORTED); } @AfterClass public static void classTeardown() throws Throwable { clearPin(); public static void classTeardown() { Settings.Secure.putString(sInstrumentation.getTargetContext().getContentResolver(), Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES, ""); } @Before public void setup() throws Throwable { clearPin(); sOpenBlocked.set(false); wakeUpScreen(); sUiAutomation.executeShellCommand("input keyevent KEYCODE_MENU"); openMenu(); Loading @@ -154,20 +161,8 @@ public class AccessibilityMenuServiceTest { public void tearDown() throws Throwable { closeMenu(); sLastGlobalAction.set(NO_GLOBAL_ACTION); } private static void clearPin() throws Throwable { sUiAutomation.executeShellCommand("locksettings clear --old " + TEST_PIN); TestUtils.waitUntil("Device did not register as unlocked & insecure.", TIMEOUT_SERVICE_STATUS_CHANGE_S, () -> !sKeyguardManager.isDeviceSecure()); } private static void setPin() throws Throwable { sUiAutomation.executeShellCommand("locksettings set-pin " + TEST_PIN); TestUtils.waitUntil("Device did not recognize as locked & secure.", TIMEOUT_SERVICE_STATUS_CHANGE_S, () -> sKeyguardManager.isDeviceSecure()); // dismisses screenshot popup if present. sUiAutomation.executeShellCommand("input keyevent KEYCODE_BACK"); } private static boolean isMenuVisible() { Loading @@ -184,7 +179,6 @@ public class AccessibilityMenuServiceTest { private static void closeScreen() throws Throwable { Display display = sDisplayManager.getDisplay(Display.DEFAULT_DISPLAY); setPin(); sUiAutomation.performGlobalAction(GLOBAL_ACTION_LOCK_SCREEN); TestUtils.waitUntil("Screen did not close.", TIMEOUT_UI_CHANGE_S, Loading @@ -194,12 +188,20 @@ public class AccessibilityMenuServiceTest { } private static void openMenu() throws Throwable { Intent intent = new Intent(PACKAGE_NAME + INTENT_TOGGLE_MENU); openMenu(false); } private static void openMenu(boolean abandonOnBlock) throws Throwable { Intent intent = new Intent(INTENT_TOGGLE_MENU); intent.setPackage(PACKAGE_NAME); sInstrumentation.getContext().sendBroadcast(intent); TestUtils.waitUntil("Timed out before menu could appear.", TIMEOUT_UI_CHANGE_S, () -> { if (sOpenBlocked.get() && abandonOnBlock) { throw new IllegalStateException(); } if (isMenuVisible()) { return true; } else { Loading @@ -213,7 +215,8 @@ public class AccessibilityMenuServiceTest { if (!isMenuVisible()) { return; } Intent intent = new Intent(PACKAGE_NAME + INTENT_HIDE_MENU); Intent intent = new Intent(INTENT_HIDE_MENU); intent.setPackage(PACKAGE_NAME); sInstrumentation.getContext().sendBroadcast(intent); TestUtils.waitUntil("Timed out before menu could close.", TIMEOUT_UI_CHANGE_S, () -> !isMenuVisible()); Loading Loading @@ -444,13 +447,13 @@ public class AccessibilityMenuServiceTest { closeScreen(); wakeUpScreen(); boolean timedOut = false; boolean blocked = false; try { openMenu(); } catch (AssertionError e) { openMenu(true); } catch (IllegalStateException e) { // Expected timedOut = true; blocked = true; } assertThat(timedOut).isTrue(); assertThat(blocked).isTrue(); } } Loading
packages/SystemUI/accessibility/accessibilitymenu/src/com/android/systemui/accessibility/accessibilitymenu/AccessibilityMenuService.java +16 −6 Original line number Diff line number Diff line Loading @@ -56,10 +56,12 @@ public class AccessibilityMenuService extends AccessibilityService implements View.OnTouchListener { public static final String PACKAGE_NAME = AccessibilityMenuService.class.getPackageName(); public static final String PACKAGE_TESTS = ".tests"; 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"; public static final String INTENT_OPEN_BLOCKED = "OPEN_BLOCKED"; private static final String TAG = "A11yMenuService"; private static final long BUFFER_MILLISECONDS_TO_PREVENT_UPDATE_FAILURE = 100L; Loading Loading @@ -192,7 +194,7 @@ public class AccessibilityMenuService extends AccessibilityService IntentFilter hideMenuFilter = new IntentFilter(); hideMenuFilter.addAction(Intent.ACTION_SCREEN_OFF); hideMenuFilter.addAction(PACKAGE_NAME + INTENT_HIDE_MENU); hideMenuFilter.addAction(INTENT_HIDE_MENU); // Including WRITE_SECURE_SETTINGS enforces that we only listen to apps // with the restricted WRITE_SECURE_SETTINGS permission who broadcast this intent. Loading @@ -200,7 +202,7 @@ public class AccessibilityMenuService extends AccessibilityService Manifest.permission.WRITE_SECURE_SETTINGS, null, Context.RECEIVER_EXPORTED); registerReceiver(mToggleMenuReceiver, new IntentFilter(PACKAGE_NAME + INTENT_TOGGLE_MENU), new IntentFilter(INTENT_TOGGLE_MENU), Manifest.permission.WRITE_SECURE_SETTINGS, null, Context.RECEIVER_EXPORTED); Loading Loading @@ -245,8 +247,9 @@ public class AccessibilityMenuService extends AccessibilityService * @return {@code true} if successful, {@code false} otherwise. */ private boolean performGlobalActionInternal(int globalAction) { Intent intent = new Intent(PACKAGE_NAME + INTENT_GLOBAL_ACTION); Intent intent = new Intent(INTENT_GLOBAL_ACTION); intent.putExtra(INTENT_GLOBAL_ACTION_EXTRA, globalAction); intent.setPackage(PACKAGE_NAME + PACKAGE_TESTS); sendBroadcast(intent); Log.i("A11yMenuService", "Broadcasting global action " + globalAction); return performGlobalAction(globalAction); Loading Loading @@ -410,9 +413,16 @@ public class AccessibilityMenuService extends AccessibilityService private void toggleVisibility() { boolean locked = mKeyguardManager != null && mKeyguardManager.isKeyguardLocked(); if (!locked && SystemClock.uptimeMillis() - mLastTimeTouchedOutside if (!locked) { if (SystemClock.uptimeMillis() - mLastTimeTouchedOutside > BUTTON_CLICK_TIMEOUT) { mA11yMenuLayout.toggleVisibility(); } } else { // Broadcast for testing. Intent intent = new Intent(INTENT_OPEN_BLOCKED); intent.setPackage(PACKAGE_NAME + PACKAGE_TESTS); sendBroadcast(intent); } } }
packages/SystemUI/accessibility/accessibilitymenu/tests/src/com/android/systemui/accessibility/accessibilitymenu/tests/AccessibilityMenuServiceTest.java +34 −31 Original line number Diff line number Diff line Loading @@ -23,6 +23,7 @@ import static android.accessibilityservice.AccessibilityService.GLOBAL_ACTION_QU 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_OPEN_BLOCKED; 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; Loading Loading @@ -65,6 +66,7 @@ import org.junit.Test; import org.junit.runner.RunWith; import java.util.List; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; @RunWith(AndroidJUnit4.class) Loading @@ -75,12 +77,11 @@ public class AccessibilityMenuServiceTest { private static final int TIMEOUT_SERVICE_STATUS_CHANGE_S = 5; private static final int TIMEOUT_UI_CHANGE_S = 5; private static final int NO_GLOBAL_ACTION = -1; private static final String INPUT_KEYEVENT_KEYCODE_BACK = "input keyevent KEYCODE_BACK"; private static final String TEST_PIN = "1234"; private static Instrumentation sInstrumentation; private static UiAutomation sUiAutomation; private static AtomicInteger sLastGlobalAction; private static final AtomicInteger sLastGlobalAction = new AtomicInteger(NO_GLOBAL_ACTION); private static final AtomicBoolean sOpenBlocked = new AtomicBoolean(false); private static AccessibilityManager sAccessibilityManager; private static PowerManager sPowerManager; Loading Loading @@ -122,8 +123,6 @@ 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) { Loading @@ -131,20 +130,28 @@ public class AccessibilityMenuServiceTest { sLastGlobalAction.set( intent.getIntExtra(INTENT_GLOBAL_ACTION_EXTRA, NO_GLOBAL_ACTION)); }}, new IntentFilter(PACKAGE_NAME + INTENT_GLOBAL_ACTION), new IntentFilter(INTENT_GLOBAL_ACTION), null, null, Context.RECEIVER_EXPORTED); context.registerReceiver(new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { Log.i(TAG, "Received notification that menu cannot be opened."); sOpenBlocked.set(true); }}, new IntentFilter(INTENT_OPEN_BLOCKED), null, null, Context.RECEIVER_EXPORTED); } @AfterClass public static void classTeardown() throws Throwable { clearPin(); public static void classTeardown() { Settings.Secure.putString(sInstrumentation.getTargetContext().getContentResolver(), Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES, ""); } @Before public void setup() throws Throwable { clearPin(); sOpenBlocked.set(false); wakeUpScreen(); sUiAutomation.executeShellCommand("input keyevent KEYCODE_MENU"); openMenu(); Loading @@ -154,20 +161,8 @@ public class AccessibilityMenuServiceTest { public void tearDown() throws Throwable { closeMenu(); sLastGlobalAction.set(NO_GLOBAL_ACTION); } private static void clearPin() throws Throwable { sUiAutomation.executeShellCommand("locksettings clear --old " + TEST_PIN); TestUtils.waitUntil("Device did not register as unlocked & insecure.", TIMEOUT_SERVICE_STATUS_CHANGE_S, () -> !sKeyguardManager.isDeviceSecure()); } private static void setPin() throws Throwable { sUiAutomation.executeShellCommand("locksettings set-pin " + TEST_PIN); TestUtils.waitUntil("Device did not recognize as locked & secure.", TIMEOUT_SERVICE_STATUS_CHANGE_S, () -> sKeyguardManager.isDeviceSecure()); // dismisses screenshot popup if present. sUiAutomation.executeShellCommand("input keyevent KEYCODE_BACK"); } private static boolean isMenuVisible() { Loading @@ -184,7 +179,6 @@ public class AccessibilityMenuServiceTest { private static void closeScreen() throws Throwable { Display display = sDisplayManager.getDisplay(Display.DEFAULT_DISPLAY); setPin(); sUiAutomation.performGlobalAction(GLOBAL_ACTION_LOCK_SCREEN); TestUtils.waitUntil("Screen did not close.", TIMEOUT_UI_CHANGE_S, Loading @@ -194,12 +188,20 @@ public class AccessibilityMenuServiceTest { } private static void openMenu() throws Throwable { Intent intent = new Intent(PACKAGE_NAME + INTENT_TOGGLE_MENU); openMenu(false); } private static void openMenu(boolean abandonOnBlock) throws Throwable { Intent intent = new Intent(INTENT_TOGGLE_MENU); intent.setPackage(PACKAGE_NAME); sInstrumentation.getContext().sendBroadcast(intent); TestUtils.waitUntil("Timed out before menu could appear.", TIMEOUT_UI_CHANGE_S, () -> { if (sOpenBlocked.get() && abandonOnBlock) { throw new IllegalStateException(); } if (isMenuVisible()) { return true; } else { Loading @@ -213,7 +215,8 @@ public class AccessibilityMenuServiceTest { if (!isMenuVisible()) { return; } Intent intent = new Intent(PACKAGE_NAME + INTENT_HIDE_MENU); Intent intent = new Intent(INTENT_HIDE_MENU); intent.setPackage(PACKAGE_NAME); sInstrumentation.getContext().sendBroadcast(intent); TestUtils.waitUntil("Timed out before menu could close.", TIMEOUT_UI_CHANGE_S, () -> !isMenuVisible()); Loading Loading @@ -444,13 +447,13 @@ public class AccessibilityMenuServiceTest { closeScreen(); wakeUpScreen(); boolean timedOut = false; boolean blocked = false; try { openMenu(); } catch (AssertionError e) { openMenu(true); } catch (IllegalStateException e) { // Expected timedOut = true; blocked = true; } assertThat(timedOut).isTrue(); assertThat(blocked).isTrue(); } }