Restructure a11y shortcut settings

Separating the shortcut on/off from the shortcut service.
Enabling the shortcut to work from the lock screen if the
user wants it to.

Bug: 35872328
Bug: 35219988
Bug: 35443593
Test: Adjusted tests for shortcut controller, manually
activated shortcut in a variety of conditions.
Change-Id: Id39d33ec62eb5f11b76b2972089167dc7d4c625b
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 146d2d3..58043a2 100755
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -5482,6 +5482,20 @@
         public static final String ACCESSIBILITY_ENABLED = "accessibility_enabled";
 
         /**
+         * Setting specifying if the accessibility shortcut is enabled.
+         * @hide
+         */
+        public static final String ACCESSIBILITY_SHORTCUT_ENABLED =
+                "accessibility_shortcut_enabled";
+
+        /**
+         * Setting specifying if the accessibility shortcut is enabled.
+         * @hide
+         */
+        public static final String ACCESSIBILITY_SHORTCUT_ON_LOCK_SCREEN =
+                "accessibility_shortcut_on_lock_screen";
+
+        /**
          * Setting specifying if the accessibility shortcut dialog has been shown to this user.
          * @hide
          */
@@ -5489,7 +5503,7 @@
                 "accessibility_shortcut_dialog_shown";
 
         /**
-         * Setting specifying the the accessibility service to be toggled via the accessibility
+         * Setting specifying the accessibility service to be toggled via the accessibility
          * shortcut. Must be its flattened {@link ComponentName}.
          * @hide
          */
@@ -6984,6 +6998,8 @@
             ACCESSIBILITY_ENABLED,
             ACCESSIBILITY_SHORTCUT_TARGET_SERVICE,
             ACCESSIBILITY_SHORTCUT_DIALOG_SHOWN,
+            ACCESSIBILITY_SHORTCUT_ENABLED,
+            ACCESSIBILITY_SHORTCUT_ON_LOCK_SCREEN,
             ACCESSIBILITY_SPEAK_PASSWORD,
             ACCESSIBILITY_HIGH_TEXT_CONTRAST_ENABLED,
             ACCESSIBILITY_CAPTIONING_PRESET,
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index d4db258..c28ba35 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -3928,22 +3928,24 @@
 
     <!-- Dialog title for dialog shown when the accessibility shortcut is activated, and we want
      to confirm that the user understands what's going to happen-->
-    <string name="accessibility_shortcut_warning_dialog_title">Accessibility Shortcut is ON</string>
+    <string name="accessibility_shortcut_warning_dialog_title">Use Accessibility Shortcut?</string>
 
     <!-- Message shown in dialog when user is in the process of enabling the accessibility
     service via the volume buttons shortcut for the first time. [CHAR LIMIT=none] -->
     <string name="accessibility_shortcut_toogle_warning">
-        Turn <xliff:g id="service_name" example="TalkBack">%1$s</xliff:g> on or off by holding down
-        both volume buttons for 3 seconds.\n\nYou can change the service in
-        Settings > Accessibility.
+        When the shortcut is on, pressing both volume buttons for 3 seconds will start an
+        accessibility feature.\n\n
+        Current accessibility feature:\n
+        <xliff:g id="service_name" example="TalkBack">%1$s</xliff:g>\n\n
+        You can change the feature in Settings > Accessibility.
     </string>
 
     <!-- Text in button that turns off the accessibility shortcut -->
-    <string name="disable_accessibility_shortcut">Turn Off Shortcut</string>
+    <string name="disable_accessibility_shortcut">Turn off Shortcut</string>
 
     <!-- Text in button that closes the warning dialog about the accessibility shortcut, leaving the
     shortcut enabled.-->
-    <string name="leave_accessibility_shortcut_on">Leave on</string>
+    <string name="leave_accessibility_shortcut_on">Use Shortcut</string>
 
     <!-- Text in toast to alert the user that the accessibility shortcut turned on an accessibility
     service.-->
diff --git a/packages/SettingsLib/src/com/android/settingslib/accessibility/AccessibilityUtils.java b/packages/SettingsLib/src/com/android/settingslib/accessibility/AccessibilityUtils.java
index 9bb3c36..350b648 100644
--- a/packages/SettingsLib/src/com/android/settingslib/accessibility/AccessibilityUtils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/accessibility/AccessibilityUtils.java
@@ -169,6 +169,19 @@
         return context.getString(R.string.config_defaultAccessibilityService);
     }
 
+    /**
+     * Check if the accessibility shortcut is enabled for a user
+     *
+     * @param context A valid context
+     * @param userId The user of interest
+     * @return {@code true} if the shortcut is enabled for the user. {@code false} otherwise.
+     *         Note that the shortcut may be enabled, but no action associated with it.
+     */
+    public static boolean isShortcutEnabled(Context context, int userId) {
+        return Settings.Secure.getIntForUser(context.getContentResolver(),
+                Settings.Secure.ACCESSIBILITY_SHORTCUT_ENABLED, 1, userId) == 1;
+    }
+
     private static Set<ComponentName> getInstalledServices(Context context) {
         final Set<ComponentName> installedServices = new HashSet<>();
         installedServices.clear();
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index 397938a..3666763 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -1920,7 +1920,8 @@
         }
         ComponentName componentNameToEnable =
             ComponentName.unflattenFromString(componentNameToEnableString);
-        if (componentNameToEnable.equals(userState.mServiceToEnableWithShortcut)) {
+        if ((componentNameToEnable != null)
+                && componentNameToEnable.equals(userState.mServiceToEnableWithShortcut)) {
             return false;
         }
         userState.mServiceToEnableWithShortcut = componentNameToEnable;
@@ -1948,7 +1949,9 @@
         if (!shortcutServiceIsInstalled) {
             userState.mServiceToEnableWithShortcut = null;
             Settings.Secure.putStringForUser(mContext.getContentResolver(),
-                    Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE, "", userState.mUserId);
+                    Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE, null, userState.mUserId);
+            Settings.Secure.putIntForUser(mContext.getContentResolver(),
+                    Settings.Secure.ACCESSIBILITY_SHORTCUT_ENABLED, 0, userState.mUserId);
         }
     }
 
diff --git a/services/core/java/com/android/server/policy/AccessibilityShortcutController.java b/services/core/java/com/android/server/policy/AccessibilityShortcutController.java
index cd55f50..7d53310 100644
--- a/services/core/java/com/android/server/policy/AccessibilityShortcutController.java
+++ b/services/core/java/com/android/server/policy/AccessibilityShortcutController.java
@@ -27,6 +27,7 @@
 import android.media.AudioAttributes;
 import android.media.Ringtone;
 import android.media.RingtoneManager;
+import android.net.Uri;
 import android.os.Handler;
 import android.os.UserHandle;
 import android.os.Vibrator;
@@ -58,6 +59,9 @@
     private final Context mContext;
     private AlertDialog mAlertDialog;
     private boolean mIsShortcutEnabled;
+    private boolean mEnabledOnLockScreen;
+    private int mUserId;
+
     // Visible for testing
     public FrameworkObjectProvider mFrameworkObjectProvider = new FrameworkObjectProvider();
 
@@ -72,29 +76,55 @@
         return context.getString(R.string.config_defaultAccessibilityService);
     }
 
-    public AccessibilityShortcutController(Context context, Handler handler) {
+    public AccessibilityShortcutController(Context context, Handler handler, int initialUserId) {
         mContext = context;
 
-        // Keep track of state of shortcut
+        // Keep track of state of shortcut settings
+        final ContentObserver co = new ContentObserver(handler) {
+            @Override
+            public void onChange(boolean selfChange, Uri uri, int userId) {
+                if (userId == mUserId) {
+                    onSettingsChanged();
+                }
+            }
+        };
         mContext.getContentResolver().registerContentObserver(
                 Settings.Secure.getUriFor(Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE),
-                false,
-                new ContentObserver(handler) {
-                    @Override
-                    public void onChange(boolean selfChange) {
-                        onSettingsChanged();
-                    }
-                },
-                UserHandle.USER_ALL);
-        updateShortcutEnabled();
+                false, co, UserHandle.USER_ALL);
+        mContext.getContentResolver().registerContentObserver(
+                Settings.Secure.getUriFor(Settings.Secure.ACCESSIBILITY_SHORTCUT_ENABLED),
+                false, co, UserHandle.USER_ALL);
+        mContext.getContentResolver().registerContentObserver(
+                Settings.Secure.getUriFor(Settings.Secure.ACCESSIBILITY_SHORTCUT_ON_LOCK_SCREEN),
+                false, co, UserHandle.USER_ALL);
+        setCurrentUser(mUserId);
     }
 
-    public boolean isAccessibilityShortcutAvailable() {
-        return mIsShortcutEnabled;
+    public void setCurrentUser(int currentUserId) {
+        mUserId = currentUserId;
+        onSettingsChanged();
+    }
+
+    /**
+     * Check if the shortcut is available.
+     *
+     * @param onLockScreen Whether or not the phone is currently locked.
+     *
+     * @return {@code true} if the shortcut is available
+     */
+    public boolean isAccessibilityShortcutAvailable(boolean phoneLocked) {
+        return mIsShortcutEnabled && (!phoneLocked || mEnabledOnLockScreen);
     }
 
     public void onSettingsChanged() {
-        updateShortcutEnabled();
+        final boolean haveValidService =
+                !TextUtils.isEmpty(getTargetServiceComponentNameString(mContext, mUserId));
+        final ContentResolver cr = mContext.getContentResolver();
+        final boolean enabled = Settings.Secure.getIntForUser(
+                cr, Settings.Secure.ACCESSIBILITY_SHORTCUT_ENABLED, 1, mUserId) == 1;
+        mEnabledOnLockScreen = Settings.Secure.getIntForUser(
+                cr, Settings.Secure.ACCESSIBILITY_SHORTCUT_ON_LOCK_SCREEN, 0, mUserId) == 1;
+        mIsShortcutEnabled = enabled && haveValidService;
     }
 
     /**
@@ -171,11 +201,6 @@
         }
     }
 
-    private void updateShortcutEnabled() {
-        mIsShortcutEnabled = !TextUtils.isEmpty(getTargetServiceComponentNameString(
-                mContext, UserHandle.myUserId()));
-    }
-
     private AlertDialog createShortcutWarningDialog(int userId) {
         final AccessibilityServiceInfo serviceInfo = getInfoForTargetService();
 
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 31e22b9..52f6955 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -1547,7 +1547,7 @@
     }
 
     private void interceptAccessibilityShortcutChord() {
-        if (mAccessibilityShortcutController.isAccessibilityShortcutAvailable()
+        if (mAccessibilityShortcutController.isAccessibilityShortcutAvailable(isKeyguardLocked())
                 && mScreenshotChordVolumeDownKeyTriggered && mA11yShortcutChordVolumeUpKeyTriggered
                 && !mScreenshotChordPowerKeyTriggered) {
             final long now = SystemClock.uptimeMillis();
@@ -1771,7 +1771,7 @@
         mHasFeatureWatch = mContext.getPackageManager().hasSystemFeature(FEATURE_WATCH);
         mHasFeatureLeanback = mContext.getPackageManager().hasSystemFeature(FEATURE_LEANBACK);
         mAccessibilityShortcutController =
-                new AccessibilityShortcutController(mContext, new Handler());
+                new AccessibilityShortcutController(mContext, new Handler(), mCurrentUserId);
         // Init display burn-in protection
         boolean burnInProtectionEnabled = context.getResources().getBoolean(
                 com.android.internal.R.bool.config_enableBurnInProtection);
@@ -3243,7 +3243,7 @@
 
         // If an accessibility shortcut might be partially complete, hold off dispatching until we
         // know if it is complete or not
-        if (mAccessibilityShortcutController.isAccessibilityShortcutAvailable()
+        if (mAccessibilityShortcutController.isAccessibilityShortcutAvailable(false)
                 && (flags & KeyEvent.FLAG_FALLBACK) == 0) {
             if (mScreenshotChordVolumeDownKeyTriggered ^ mA11yShortcutChordVolumeUpKeyTriggered) {
                 final long now = SystemClock.uptimeMillis();
@@ -5823,9 +5823,7 @@
                             mScreenshotChordVolumeDownKeyConsumed = false;
                             cancelPendingPowerKeyAction();
                             interceptScreenshotChord();
-                            if (!isKeyguardLocked()) {
-                                interceptAccessibilityShortcutChord();
-                            }
+                            interceptAccessibilityShortcutChord();
                         }
                     } else {
                         mScreenshotChordVolumeDownKeyTriggered = false;
@@ -5841,9 +5839,7 @@
                             mA11yShortcutChordVolumeUpKeyConsumed = false;
                             cancelPendingPowerKeyAction();
                             cancelPendingScreenshotChordAction();
-                            if (!isKeyguardLocked()) {
-                                interceptAccessibilityShortcutChord();
-                            }
+                            interceptAccessibilityShortcutChord();
                         }
                     } else {
                         mA11yShortcutChordVolumeUpKeyTriggered = false;
@@ -7945,6 +7941,9 @@
         if (mKeyguardDelegate != null) {
             mKeyguardDelegate.setCurrentUser(newUserId);
         }
+        if (mAccessibilityShortcutController != null) {
+            mAccessibilityShortcutController.setCurrentUser(newUserId);
+        }
         StatusBarManagerInternal statusBar = getStatusBarManagerInternal();
         if (statusBar != null) {
             statusBar.setCurrentUser(newUserId);
diff --git a/services/tests/servicestests/src/com/android/server/policy/AccessibilityShortcutControllerTest.java b/services/tests/servicestests/src/com/android/server/policy/AccessibilityShortcutControllerTest.java
index 4d5f783..a4e3988 100644
--- a/services/tests/servicestests/src/com/android/server/policy/AccessibilityShortcutControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/policy/AccessibilityShortcutControllerTest.java
@@ -52,6 +52,8 @@
 import java.util.Collections;
 
 import static android.provider.Settings.Secure.ACCESSIBILITY_SHORTCUT_DIALOG_SHOWN;
+import static android.provider.Settings.Secure.ACCESSIBILITY_SHORTCUT_ENABLED;
+import static android.provider.Settings.Secure.ACCESSIBILITY_SHORTCUT_ON_LOCK_SCREEN;
 import static android.provider.Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE;
 import static junit.framework.Assert.assertEquals;
 import static junit.framework.Assert.assertFalse;
@@ -76,6 +78,12 @@
             (int) VIBRATOR_PATTERN_2};
     private static final long[] VIBRATOR_PATTERN_LONG = {VIBRATOR_PATTERN_1, VIBRATOR_PATTERN_2};
 
+    // Convenience values for enabling/disabling to make code more readable
+    private static final int DISABLED = 0;
+    private static final int ENABLED_EXCEPT_LOCK_SCREEN = 1;
+    private static final int ENABLED_INCLUDING_LOCK_SCREEN = 2;
+    private static final int DISABLED_BUT_LOCK_SCREEN_ON = 3;
+
     private @Mock Context mContext;
     private @Mock FrameworkObjectProvider mFrameworkObjectProvider;
     private @Mock IAccessibilityManager mAccessibilityManagerService;
@@ -158,38 +166,103 @@
     }
 
     @Test
-    public void testShortcutAvailable_withNullServiceIdWhenCreated_shouldReturnFalse() {
-        configureShortcutDisabled();
-        assertFalse(getController().isAccessibilityShortcutAvailable());
+    public void testShortcutAvailable_enabledButNoServiceWhenCreated_shouldReturnFalse() {
+        configureNoShortcutService();
+        configureShortcutEnabled(ENABLED_EXCEPT_LOCK_SCREEN);
+        assertFalse(getController().isAccessibilityShortcutAvailable(false));
     }
 
     @Test
-    public void testShortcutAvailable_withNonNullServiceIdWhenCreated_shouldReturnTrue() {
-        configureShortcutEnabled();
-        assertTrue(getController().isAccessibilityShortcutAvailable());
+    public void testShortcutAvailable_enabledWithValidServiceWhenCreated_shouldReturnTrue() {
+        configureValidShortcutService();
+        configureShortcutEnabled(ENABLED_EXCEPT_LOCK_SCREEN);
+        assertTrue(getController().isAccessibilityShortcutAvailable(false));
+    }
+
+    @Test
+    public void testShortcutAvailable_disabledWithValidServiceWhenCreated_shouldReturnFalse() {
+        configureValidShortcutService();
+        configureShortcutEnabled(DISABLED_BUT_LOCK_SCREEN_ON);
+        assertFalse(getController().isAccessibilityShortcutAvailable(false));
+    }
+
+    @Test
+    public void testShortcutAvailable_onLockScreenButDisabledThere_shouldReturnFalse() {
+        configureValidShortcutService();
+        configureShortcutEnabled(ENABLED_EXCEPT_LOCK_SCREEN);
+        assertFalse(getController().isAccessibilityShortcutAvailable(true));
+    }
+
+    @Test
+    public void testShortcutAvailable_onLockScreenAndEnabledThere_shouldReturnTrue() {
+        configureValidShortcutService();
+        configureShortcutEnabled(ENABLED_INCLUDING_LOCK_SCREEN);
+        assertTrue(getController().isAccessibilityShortcutAvailable(true));
     }
 
     @Test
     public void testShortcutAvailable_whenServiceIdBecomesNull_shouldReturnFalse() {
-        configureShortcutEnabled();
+        configureShortcutEnabled(ENABLED_EXCEPT_LOCK_SCREEN);
+        configureValidShortcutService();
         AccessibilityShortcutController accessibilityShortcutController = getController();
         Settings.Secure.putString(mContentResolver, ACCESSIBILITY_SHORTCUT_TARGET_SERVICE, "");
         accessibilityShortcutController.onSettingsChanged();
-        assertFalse(accessibilityShortcutController.isAccessibilityShortcutAvailable());
+        assertFalse(accessibilityShortcutController.isAccessibilityShortcutAvailable(false));
     }
 
     @Test
     public void testShortcutAvailable_whenServiceIdBecomesNonNull_shouldReturnTrue() {
-        configureShortcutDisabled();
+        configureShortcutEnabled(ENABLED_EXCEPT_LOCK_SCREEN);
+        configureNoShortcutService();
         AccessibilityShortcutController accessibilityShortcutController = getController();
-        configureShortcutEnabled();
+        configureValidShortcutService();
         accessibilityShortcutController.onSettingsChanged();
-        assertTrue(accessibilityShortcutController.isAccessibilityShortcutAvailable());
+        assertTrue(accessibilityShortcutController.isAccessibilityShortcutAvailable(false));
+    }
+
+    @Test
+    public void testShortcutAvailable_whenShortcutBecomesDisabled_shouldReturnFalse() {
+        configureShortcutEnabled(ENABLED_EXCEPT_LOCK_SCREEN);
+        configureValidShortcutService();
+        AccessibilityShortcutController accessibilityShortcutController = getController();
+        configureShortcutEnabled(DISABLED);
+        accessibilityShortcutController.onSettingsChanged();
+        assertFalse(accessibilityShortcutController.isAccessibilityShortcutAvailable(false));
+    }
+
+    @Test
+    public void testShortcutAvailable_whenShortcutBecomesEnabled_shouldReturnTrue() {
+        configureShortcutEnabled(DISABLED);
+        configureValidShortcutService();
+        AccessibilityShortcutController accessibilityShortcutController = getController();
+        configureShortcutEnabled(ENABLED_EXCEPT_LOCK_SCREEN);
+        accessibilityShortcutController.onSettingsChanged();
+        assertTrue(accessibilityShortcutController.isAccessibilityShortcutAvailable(false));
+    }
+
+    @Test
+    public void testShortcutAvailable_whenLockscreenBecomesDisabled_shouldReturnFalse() {
+        configureShortcutEnabled(ENABLED_INCLUDING_LOCK_SCREEN);
+        configureValidShortcutService();
+        AccessibilityShortcutController accessibilityShortcutController = getController();
+        configureShortcutEnabled(ENABLED_EXCEPT_LOCK_SCREEN);
+        accessibilityShortcutController.onSettingsChanged();
+        assertFalse(accessibilityShortcutController.isAccessibilityShortcutAvailable(true));
+    }
+
+    @Test
+    public void testShortcutAvailable_whenLockscreenBecomesEnabled_shouldReturnTrue() {
+        configureShortcutEnabled(ENABLED_EXCEPT_LOCK_SCREEN);
+        configureValidShortcutService();
+        AccessibilityShortcutController accessibilityShortcutController = getController();
+        configureShortcutEnabled(ENABLED_INCLUDING_LOCK_SCREEN);
+        accessibilityShortcutController.onSettingsChanged();
+        assertTrue(accessibilityShortcutController.isAccessibilityShortcutAvailable(true));
     }
 
     @Test
     public void testOnAccessibilityShortcut_vibrates() {
-        configureShortcutEnabled();
+        configureShortcutEnabled(ENABLED_EXCEPT_LOCK_SCREEN);
         AccessibilityShortcutController accessibilityShortcutController = getController();
         accessibilityShortcutController.performAccessibilityShortcut();
         verify(mVibrator).vibrate(aryEq(VIBRATOR_PATTERN_LONG), eq(-1), anyObject());
@@ -198,7 +271,8 @@
     @Test
     public void testOnAccessibilityShortcut_firstTime_showsWarningDialog()
             throws Exception {
-        configureShortcutEnabled();
+        configureShortcutEnabled(ENABLED_EXCEPT_LOCK_SCREEN);
+        configureValidShortcutService();
         AccessibilityShortcutController accessibilityShortcutController = getController();
         Settings.Secure.putInt(mContentResolver, ACCESSIBILITY_SHORTCUT_DIALOG_SHOWN, 0);
         accessibilityShortcutController.performAccessibilityShortcut();
@@ -214,7 +288,8 @@
     @Test
     public void testOnAccessibilityShortcut_withDialogShowing_callsServer()
         throws Exception {
-        configureShortcutEnabled();
+        configureShortcutEnabled(ENABLED_EXCEPT_LOCK_SCREEN);
+        configureValidShortcutService();
         AccessibilityShortcutController accessibilityShortcutController = getController();
         Settings.Secure.putInt(mContentResolver, ACCESSIBILITY_SHORTCUT_DIALOG_SHOWN, 0);
         accessibilityShortcutController.performAccessibilityShortcut();
@@ -229,7 +304,8 @@
     @Test
     public void testOnAccessibilityShortcut_ifCanceledFirstTime_showsWarningDialog()
         throws Exception {
-        configureShortcutEnabled();
+        configureShortcutEnabled(ENABLED_EXCEPT_LOCK_SCREEN);
+        configureValidShortcutService();
         AccessibilityShortcutController accessibilityShortcutController = getController();
         Settings.Secure.putInt(mContentResolver, ACCESSIBILITY_SHORTCUT_DIALOG_SHOWN, 0);
         accessibilityShortcutController.performAccessibilityShortcut();
@@ -245,7 +321,8 @@
 
     @Test
     public void testClickingDisableButtonInDialog_shouldClearShortcutId() {
-        configureShortcutEnabled();
+        configureShortcutEnabled(ENABLED_EXCEPT_LOCK_SCREEN);
+        configureValidShortcutService();
         Settings.Secure.putInt(mContentResolver, ACCESSIBILITY_SHORTCUT_DIALOG_SHOWN, 0);
         getController().performAccessibilityShortcut();
 
@@ -261,7 +338,8 @@
 
     @Test
     public void testClickingLeaveOnButtonInDialog_shouldLeaveShortcutReady() throws Exception {
-        configureShortcutEnabled();
+        configureShortcutEnabled(ENABLED_EXCEPT_LOCK_SCREEN);
+        configureValidShortcutService();
         Settings.Secure.putInt(mContentResolver, ACCESSIBILITY_SHORTCUT_DIALOG_SHOWN, 0);
         getController().performAccessibilityShortcut();
 
@@ -281,7 +359,8 @@
 
     @Test
     public void testOnAccessibilityShortcut_afterDialogShown_shouldCallServer() throws Exception {
-        configureShortcutEnabled();
+        configureShortcutEnabled(ENABLED_EXCEPT_LOCK_SCREEN);
+        configureValidShortcutService();
         Settings.Secure.putInt(mContentResolver, ACCESSIBILITY_SHORTCUT_DIALOG_SHOWN, 1);
         getController().performAccessibilityShortcut();
 
@@ -290,18 +369,48 @@
         verify(mAccessibilityManagerService).performAccessibilityShortcut();
     }
 
-    private void configureShortcutDisabled() {
+    private void configureNoShortcutService() {
         Settings.Secure.putString(mContentResolver, ACCESSIBILITY_SHORTCUT_TARGET_SERVICE, "");
     }
 
-    private void configureShortcutEnabled() {
+    private void configureValidShortcutService() {
         Settings.Secure.putString(
                 mContentResolver, ACCESSIBILITY_SHORTCUT_TARGET_SERVICE, SERVICE_NAME_STRING);
     }
 
+    private void configureShortcutEnabled(int enabledValue) {
+        final boolean enabled;
+        final boolean lockscreen;
+
+        switch (enabledValue) {
+            case DISABLED:
+                enabled = false;
+                lockscreen = false;
+                break;
+            case DISABLED_BUT_LOCK_SCREEN_ON:
+                enabled = false;
+                lockscreen = true;
+                break;
+            case ENABLED_INCLUDING_LOCK_SCREEN:
+                enabled = true;
+                lockscreen = true;
+                break;
+            case ENABLED_EXCEPT_LOCK_SCREEN:
+                enabled = true;
+                lockscreen = false;
+                break;
+            default:
+                throw new IllegalArgumentException();
+        }
+
+        Settings.Secure.putInt(mContentResolver, ACCESSIBILITY_SHORTCUT_ENABLED, enabled ? 1 : 0);
+        Settings.Secure.putInt(
+                mContentResolver, ACCESSIBILITY_SHORTCUT_ON_LOCK_SCREEN, lockscreen ? 1 : 0);
+    }
+
     private AccessibilityShortcutController getController() {
         AccessibilityShortcutController accessibilityShortcutController =
-                new AccessibilityShortcutController(mContext, mHandler);
+                new AccessibilityShortcutController(mContext, mHandler, 0);
         accessibilityShortcutController.mFrameworkObjectProvider = mFrameworkObjectProvider;
         return accessibilityShortcutController;
     }