diff options
| author | 2021-05-05 23:43:12 +0000 | |
|---|---|---|
| committer | 2021-05-05 23:43:12 +0000 | |
| commit | f94486117fce311d92e37d38e7a639f8ecc67ad3 (patch) | |
| tree | d9d0bce790336d2569e037fd4b1c7a7a174ac730 | |
| parent | 720add59c72eb78316de87fa75d20fcd561dce37 (diff) | |
| parent | eb9b719bc5d8119cf027165cf88a8954efc96b5b (diff) | |
Merge changes from topic "ohm-shortcut" into sc-dev
* changes:
3/ Listen ONE_HANDED_MODE_ACTIVATED for A11y shortcut action
2/ Implement Shortcut for One Handed mode feature
9 files changed, 208 insertions, 3 deletions
diff --git a/core/java/com/android/internal/accessibility/AccessibilityShortcutController.java b/core/java/com/android/internal/accessibility/AccessibilityShortcutController.java index 2b4e09d66851..83def0cc1fd6 100644 --- a/core/java/com/android/internal/accessibility/AccessibilityShortcutController.java +++ b/core/java/com/android/internal/accessibility/AccessibilityShortcutController.java @@ -80,6 +80,8 @@ public class AccessibilityShortcutController { "com.android.server.accessibility.MagnificationController"; public static final ComponentName MAGNIFICATION_COMPONENT_NAME = new ComponentName("com.android.server.accessibility", "Magnification"); + public static final ComponentName ONE_HANDED_COMPONENT_NAME = + new ComponentName("com.android.server.accessibility", "OneHandedMode"); public static final ComponentName REDUCE_BRIGHT_COLORS_COMPONENT_NAME = new ComponentName("com.android.server.accessibility", "ReduceBrightColors"); @@ -117,7 +119,7 @@ public class AccessibilityShortcutController { public static Map<ComponentName, ToggleableFrameworkFeatureInfo> getFrameworkShortcutFeaturesMap() { if (sFrameworkShortcutFeaturesMap == null) { - Map<ComponentName, ToggleableFrameworkFeatureInfo> featuresMap = new ArrayMap<>(2); + Map<ComponentName, ToggleableFrameworkFeatureInfo> featuresMap = new ArrayMap<>(4); featuresMap.put(COLOR_INVERSION_COMPONENT_NAME, new ToggleableFrameworkFeatureInfo( Settings.Secure.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED, @@ -128,6 +130,11 @@ public class AccessibilityShortcutController { Settings.Secure.ACCESSIBILITY_DISPLAY_DALTONIZER_ENABLED, "1" /* Value to enable */, "0" /* Value to disable */, R.string.color_correction_feature_name)); + featuresMap.put(ONE_HANDED_COMPONENT_NAME, + new ToggleableFrameworkFeatureInfo( + Settings.Secure.ONE_HANDED_MODE_ACTIVATED, + "1" /* Value to enable */, "0" /* Value to disable */, + R.string.one_handed_mode_feature_name)); featuresMap.put(REDUCE_BRIGHT_COLORS_COMPONENT_NAME, new ToggleableFrameworkFeatureInfo( Settings.Secure.REDUCE_BRIGHT_COLORS_ACTIVATED, diff --git a/core/java/com/android/internal/accessibility/dialog/AccessibilityTargetHelper.java b/core/java/com/android/internal/accessibility/dialog/AccessibilityTargetHelper.java index f2d91ba30842..4a20ad0f33f5 100644 --- a/core/java/com/android/internal/accessibility/dialog/AccessibilityTargetHelper.java +++ b/core/java/com/android/internal/accessibility/dialog/AccessibilityTargetHelper.java @@ -21,6 +21,7 @@ import static android.view.accessibility.AccessibilityManager.ACCESSIBILITY_BUTT import static com.android.internal.accessibility.AccessibilityShortcutController.COLOR_INVERSION_COMPONENT_NAME; import static com.android.internal.accessibility.AccessibilityShortcutController.DALTONIZER_COMPONENT_NAME; import static com.android.internal.accessibility.AccessibilityShortcutController.MAGNIFICATION_CONTROLLER_NAME; +import static com.android.internal.accessibility.AccessibilityShortcutController.ONE_HANDED_COMPONENT_NAME; import static com.android.internal.accessibility.AccessibilityShortcutController.REDUCE_BRIGHT_COLORS_COMPONENT_NAME; import static com.android.internal.accessibility.util.AccessibilityUtils.getAccessibilityServiceFragmentType; import static com.android.internal.accessibility.util.ShortcutUtils.isShortcutContained; @@ -230,6 +231,16 @@ public final class AccessibilityTargetHelper { context.getDrawable(R.drawable.ic_accessibility_color_inversion), Settings.Secure.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED); + final ToggleAllowListingFeatureTarget oneHandedMode = + new ToggleAllowListingFeatureTarget(context, + shortcutType, + isShortcutContained(context, shortcutType, + ONE_HANDED_COMPONENT_NAME.flattenToString()), + ONE_HANDED_COMPONENT_NAME.flattenToString(), + context.getString(R.string.one_handed_mode_feature_name), + context.getDrawable(R.drawable.ic_accessibility_one_handed), + Settings.Secure.ONE_HANDED_MODE_ACTIVATED); + final ToggleAllowListingFeatureTarget reduceBrightColors = new ToggleAllowListingFeatureTarget(context, shortcutType, @@ -243,6 +254,7 @@ public final class AccessibilityTargetHelper { targets.add(magnification); targets.add(daltonizer); targets.add(colorInversion); + targets.add(oneHandedMode); targets.add(reduceBrightColors); return targets; diff --git a/core/res/res/drawable/ic_accessibility_one_handed.xml b/core/res/res/drawable/ic_accessibility_one_handed.xml new file mode 100644 index 000000000000..0a469ba731ee --- /dev/null +++ b/core/res/res/drawable/ic_accessibility_one_handed.xml @@ -0,0 +1,25 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + Copyright (C) 2021 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> + +<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android"> +<background android:drawable="@color/accessibility_feature_background" /> +<foreground> + <inset + android:drawable="@drawable/ic_accessibility_one_handed_foreground" + android:inset="@dimen/accessibility_icon_foreground_padding_ratio" /> +</foreground> +</adaptive-icon>
\ No newline at end of file diff --git a/core/res/res/drawable/ic_accessibility_one_handed_foreground.xml b/core/res/res/drawable/ic_accessibility_one_handed_foreground.xml new file mode 100644 index 000000000000..18e56187efb3 --- /dev/null +++ b/core/res/res/drawable/ic_accessibility_one_handed_foreground.xml @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + Copyright (C) 2021 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> + +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="18dp" + android:height="18dp" + android:viewportWidth="24" + android:viewportHeight="24"> + + <path android:fillColor="@android:color/white" + android:pathData="M4.64169 3C3.88567 3 3.27271 3.61296 3.27271 4.36898V18.4011C3.27271 19.154 3.88875 19.7701 4.64169 19.7701H12.5339C12.5339 19.7701 12.5425 18.0588 11.2324 18.0588H6.01067C5.44597 18.0588 4.98393 17.5968 4.98393 17.0321V5.73797C4.98393 5.17326 5.44597 4.71123 6.01067 4.71123H15.9358C16.5005 4.71123 16.9625 5.17326 16.9625 5.73797V9.84492C16.9625 10.9651 16.4899 12.5952 15.5936 13.2674L9.77538 9.16043C8.58505 10.425 8.88177 11.705 10.1176 12.9251L13.1978 16.0053C13.1978 16.0053 13.3231 17.4572 13.5401 18.0588C14.2034 19.8984 16.2781 20.7968 16.2781 20.7968H19.231H19.2967C20.0835 20.7968 20.7273 20.153 20.7273 19.3662V12.2543L18.9441 4.06781C18.7662 3.23718 18.4068 3 17.8729 3H4.64169Z"/> +</vector>
\ No newline at end of file diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml index a0c6f451f14e..4cbfc69527ef 100644 --- a/core/res/res/values/strings.xml +++ b/core/res/res/values/strings.xml @@ -4636,6 +4636,9 @@ shown in the warning dialog about the accessibility shortcut. --> <string name="color_correction_feature_name">Color Correction</string> + <!-- Title of One Handed Mode feature, shown in the system gestures of the accessibility shortcut. [CHAR LIMIT=none] --> + <string name="one_handed_mode_feature_name">One-Handed mode</string> + <!-- Title of Reduce Brightness feature, shown in the warning dialog about the accessibility shortcut. [CHAR LIMIT=none] --> <string name="reduce_bright_colors_feature_name">Extra dim</string> diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index 5019ccadd353..3a22efce70fc 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -3410,9 +3410,12 @@ <java-symbol type="drawable" name="ic_accessibility_color_correction" /> <java-symbol type="drawable" name="ic_accessibility_magnification" /> <java-symbol type="drawable" name="ic_accessibility_reduce_bright_colors" /> + <java-symbol type="drawable" name="ic_accessibility_one_handed" /> <java-symbol type="string" name="reduce_bright_colors_feature_name" /> + <java-symbol type="string" name="one_handed_mode_feature_name" /> + <!-- com.android.internal.widget.RecyclerView --> <java-symbol type="id" name="item_touch_helper_previous_elevation"/> <java-symbol type="dimen" name="item_touch_helper_max_drag_scroll_per_frame"/> diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedController.java index ae7ab528ed0a..ce57638f16f4 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedController.java @@ -135,6 +135,7 @@ public class OneHandedController implements RemoteCallable<OneHandedController> } }; + private final ContentObserver mActivatedObserver; private final ContentObserver mEnabledObserver; private final ContentObserver mTimeoutObserver; private final ContentObserver mTaskChangeExitObserver; @@ -170,11 +171,13 @@ public class OneHandedController implements RemoteCallable<OneHandedController> @Override public void onStartFinished(Rect bounds) { mState.setState(STATE_ACTIVE); + notifyShortcutState(STATE_ACTIVE); } @Override public void onStopFinished(Rect bounds) { mState.setState(STATE_NONE); + notifyShortcutState(STATE_NONE); } }; @@ -287,6 +290,7 @@ public class OneHandedController implements RemoteCallable<OneHandedController> context.getContentResolver(), mUserId); mTimeoutHandler = timeoutHandler; + mActivatedObserver = getObserver(this::onActivatedActionChanged); mEnabledObserver = getObserver(this::onEnabledSettingChanged); mTimeoutObserver = getObserver(this::onTimeoutSettingChanged); mTaskChangeExitObserver = getObserver(this::onTaskChangeExitSettingChanged); @@ -348,6 +352,12 @@ public class OneHandedController implements RemoteCallable<OneHandedController> } @VisibleForTesting + void notifyShortcutState(@OneHandedState.State int state) { + mOneHandedSettingsUtil.setOneHandedModeActivated( + mContext.getContentResolver(), state == STATE_ACTIVE ? 1 : 0, mUserId); + } + + @VisibleForTesting void startOneHanded() { if (isLockedDisabled()) { Slog.d(TAG, "Temporary lock disabled"); @@ -416,6 +426,9 @@ public class OneHandedController implements RemoteCallable<OneHandedController> } private void registerSettingObservers(int newUserId) { + mOneHandedSettingsUtil.registerSettingsKeyObserver( + Settings.Secure.ONE_HANDED_MODE_ACTIVATED, + mContext.getContentResolver(), mActivatedObserver, newUserId); mOneHandedSettingsUtil.registerSettingsKeyObserver(Settings.Secure.ONE_HANDED_MODE_ENABLED, mContext.getContentResolver(), mEnabledObserver, newUserId); mOneHandedSettingsUtil.registerSettingsKeyObserver(Settings.Secure.ONE_HANDED_MODE_TIMEOUT, @@ -466,6 +479,26 @@ public class OneHandedController implements RemoteCallable<OneHandedController> } @VisibleForTesting + void onActivatedActionChanged() { + if (mState.isTransitioning() || !isOneHandedEnabled()) { + return; + } + + final boolean isActivated = mState.getState() == STATE_ACTIVE; + final boolean requestActivated = mOneHandedSettingsUtil.getOneHandedModeActivated( + mContext.getContentResolver(), mUserId); + // When gesture trigger action, we will update settings and introduce observer callback + // again, then the following logic will just ignore the second redundant callback. + if (isActivated ^ requestActivated) { + if (requestActivated) { + startOneHanded(); + } else { + stopOneHanded(); + } + } + } + + @VisibleForTesting void onEnabledSettingChanged() { final boolean enabled = mOneHandedSettingsUtil.getSettingsOneHandedModeEnabled( mContext.getContentResolver(), mUserId); @@ -544,6 +577,11 @@ public class OneHandedController implements RemoteCallable<OneHandedController> return mLockedDisabled; } + @VisibleForTesting + boolean isOneHandedEnabled() { + return mIsOneHandedEnabled; + } + private void updateOneHandedEnabled() { if (mState.getState() == STATE_ENTERING || mState.getState() == STATE_ACTIVE) { mMainExecutor.execute(() -> stopOneHanded()); diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedSettingsUtil.java b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedSettingsUtil.java index 2ab51f3f1313..bb68224b0a87 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedSettingsUtil.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedSettingsUtil.java @@ -131,8 +131,28 @@ public final class OneHandedSettingsUtil { * Returns whether swipe bottom to notification gesture enabled or not. */ public boolean getSettingsSwipeToNotificationEnabled(ContentResolver resolver, int userId) { - return Settings.Secure.getInt(resolver, - Settings.Secure.SWIPE_BOTTOM_TO_NOTIFICATION_ENABLED, 0 /* Default OFF */) == 1; + return Settings.Secure.getIntForUser(resolver, + Settings.Secure.SWIPE_BOTTOM_TO_NOTIFICATION_ENABLED, 0, userId) == 1; + } + + /** + * Sets one handed activated or not to notify state for shortcut + * + * @return activated or not + */ + public boolean getOneHandedModeActivated(ContentResolver resolver, int userId) { + return Settings.Secure.getIntForUser(resolver, + Settings.Secure.ONE_HANDED_MODE_ACTIVATED, 0, userId) == 1; + } + + /** + * Sets one handed activated or not to notify state for shortcut + * + * @return activated or not + */ + public boolean setOneHandedModeActivated(ContentResolver resolver, int state, int userId) { + return Settings.Secure.putIntForUser(resolver, + Settings.Secure.ONE_HANDED_MODE_ACTIVATED, state, userId); } void dump(PrintWriter pw, String prefix, ContentResolver resolver, @@ -145,6 +165,8 @@ public final class OneHandedSettingsUtil { pw.println(getSettingsOneHandedModeTimeout(resolver, userId)); pw.print(innerPrefix + "tapsAppToExit="); pw.println(getSettingsTapsAppToExit(resolver, userId)); + pw.print(innerPrefix + "shortcutActivated="); + pw.println(getOneHandedModeActivated(resolver, userId)); } public OneHandedSettingsUtil() { diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedControllerTest.java index c1282c9d7b12..99342f02463a 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedControllerTest.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedControllerTest.java @@ -16,7 +16,9 @@ package com.android.wm.shell.onehanded; +import static com.android.wm.shell.onehanded.OneHandedState.STATE_ACTIVE; import static com.android.wm.shell.onehanded.OneHandedState.STATE_ENTERING; +import static com.android.wm.shell.onehanded.OneHandedState.STATE_EXITING; import static com.android.wm.shell.onehanded.OneHandedState.STATE_NONE; import static com.google.common.truth.Truth.assertThat; @@ -360,4 +362,71 @@ public class OneHandedControllerTest extends OneHandedTestCase { verify(mMockGestureHandler).onGestureEnabled(isOneHandedEnabled); } + + @Test + public void testStateActive_shortcutRequestActivate_skipActions() { + when(mSpiedTransitionState.getState()).thenReturn(STATE_ACTIVE); + when(mSpiedTransitionState.isTransitioning()).thenReturn(false); + when(mMockSettingsUitl.getOneHandedModeActivated(any(), anyInt())).thenReturn(true); + mSpiedOneHandedController.onActivatedActionChanged(); + + verify(mSpiedOneHandedController, never()).startOneHanded(); + verify(mSpiedOneHandedController, never()).stopOneHanded(); + } + + @Test + public void testStateNotActive_shortcutRequestInActivate_skipAction() { + when(mSpiedTransitionState.getState()).thenReturn(STATE_NONE); + when(mSpiedTransitionState.isTransitioning()).thenReturn(false); + when(mMockSettingsUitl.getOneHandedModeActivated(any(), anyInt())).thenReturn(false); + mSpiedOneHandedController.onActivatedActionChanged(); + + verify(mSpiedOneHandedController, never()).startOneHanded(); + verify(mSpiedOneHandedController, never()).stopOneHanded(); + } + + @Test + public void testStateNotActive_shortcutRequestActivate_doAction() { + when(mSpiedTransitionState.getState()).thenReturn(STATE_NONE); + when(mSpiedTransitionState.isTransitioning()).thenReturn(false); + when(mMockSettingsUitl.getOneHandedModeActivated(any(), anyInt())).thenReturn(true); + mSpiedOneHandedController.onActivatedActionChanged(); + + verify(mSpiedOneHandedController).startOneHanded(); + verify(mSpiedOneHandedController, never()).stopOneHanded(); + } + + @Test + public void testEnteringTransition_shortcutRequestActivate_skipActions() { + when(mSpiedTransitionState.getState()).thenReturn(STATE_ENTERING); + when(mSpiedTransitionState.isTransitioning()).thenReturn(true); + when(mMockSettingsUitl.getOneHandedModeActivated(any(), anyInt())).thenReturn(true); + mSpiedOneHandedController.onActivatedActionChanged(); + + verify(mSpiedOneHandedController, never()).startOneHanded(); + verify(mSpiedOneHandedController, never()).stopOneHanded(); + } + + @Test + public void testExitingTransition_shortcutRequestActivate_skipActions() { + when(mSpiedTransitionState.getState()).thenReturn(STATE_EXITING); + when(mSpiedTransitionState.isTransitioning()).thenReturn(true); + when(mMockSettingsUitl.getOneHandedModeActivated(any(), anyInt())).thenReturn(true); + mSpiedOneHandedController.onActivatedActionChanged(); + + verify(mSpiedOneHandedController, never()).startOneHanded(); + verify(mSpiedOneHandedController, never()).stopOneHanded(); + } + + @Test + public void testOneHandedDisabled_shortcutEnabled_skipActions() { + when(mSpiedOneHandedController.isOneHandedEnabled()).thenReturn(false); + when(mSpiedTransitionState.getState()).thenReturn(STATE_NONE); + when(mSpiedTransitionState.isTransitioning()).thenReturn(false); + when(mMockSettingsUitl.getOneHandedModeActivated(any(), anyInt())).thenReturn(true); + mSpiedOneHandedController.onActivatedActionChanged(); + + verify(mSpiedOneHandedController, never()).startOneHanded(); + verify(mSpiedOneHandedController, never()).stopOneHanded(); + } } |