diff options
7 files changed, 135 insertions, 29 deletions
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedAccessibilityUtil.java b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedAccessibilityUtil.java new file mode 100644 index 000000000000..130246177fdc --- /dev/null +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedAccessibilityUtil.java @@ -0,0 +1,91 @@ +/* + * 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. + */ + +package com.android.wm.shell.onehanded; + +import android.content.Context; +import android.view.accessibility.AccessibilityEvent; +import android.view.accessibility.AccessibilityManager; + +import androidx.annotation.NonNull; + +import com.android.wm.shell.R; + +import java.io.PrintWriter; + +/** + * The util for handling A11y events. + */ +public final class OneHandedAccessibilityUtil { + private static final String TAG = "OneHandedAccessibilityUtil"; + + private final AccessibilityManager mAccessibilityManager; + private final String mStartOneHandedDescription; + private final String mStopOneHandedDescription; + private final String mPackageName; + + private String mDescription; + + public OneHandedAccessibilityUtil(Context context) { + mAccessibilityManager = AccessibilityManager.getInstance(context); + mPackageName = context.getPackageName(); + mStartOneHandedDescription = context.getResources().getString( + R.string.accessibility_action_start_one_handed); + mStopOneHandedDescription = context.getResources().getString( + R.string.accessibility_action_stop_one_handed); + } + + /** + * Gets One-Handed start description. + * @return text of start description. + */ + public String getOneHandedStartDescription() { + return mStartOneHandedDescription; + } + + /** + * Gets One-Handed stop description. + * @return text of stop description. + */ + public String getOneHandedStopDescription() { + return mStopOneHandedDescription; + } + + /** + * Announcement of A11y Events + * @param description for accessibility announcement text + */ + public void announcementForScreenReader(String description) { + if (!mAccessibilityManager.isTouchExplorationEnabled()) { + return; + } + mDescription = description; + final AccessibilityEvent event = AccessibilityEvent.obtain(); + event.setPackageName(mPackageName); + event.setEventType(AccessibilityEvent.TYPE_ANNOUNCEMENT); + event.getText().add(mDescription); + mAccessibilityManager.sendAccessibilityEvent(event); + } + + public void dump(@NonNull PrintWriter pw) { + final String innerPrefix = " "; + pw.println(TAG + "States: "); + pw.print(innerPrefix + "mPackageName="); + pw.println(mPackageName); + pw.print(innerPrefix + "mDescription="); + pw.println(mDescription); + } +} 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 38cf9e6183b4..19098fdd5220 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 @@ -83,6 +83,7 @@ public class OneHandedController implements RemoteCallable<OneHandedController> private final AccessibilityManager mAccessibilityManager; private final DisplayController mDisplayController; private final OneHandedSettingsUtil mOneHandedSettingsUtil; + private final OneHandedAccessibilityUtil mOneHandedAccessibilityUtil; private final OneHandedTimeoutHandler mTimeoutHandler; private final OneHandedTouchHandler mTouchHandler; private final OneHandedTutorialHandler mTutorialHandler; @@ -193,6 +194,8 @@ public class OneHandedController implements RemoteCallable<OneHandedController> return null; } + OneHandedSettingsUtil settingsUtil = new OneHandedSettingsUtil(); + OneHandedAccessibilityUtil accessibilityUtil = new OneHandedAccessibilityUtil(context); OneHandedTimeoutHandler timeoutHandler = new OneHandedTimeoutHandler(mainExecutor); OneHandedTutorialHandler tutorialHandler = new OneHandedTutorialHandler(context, windowManager, mainExecutor); @@ -205,16 +208,16 @@ public class OneHandedController implements RemoteCallable<OneHandedController> OneHandedBackgroundPanelOrganizer oneHandedBackgroundPanelOrganizer = new OneHandedBackgroundPanelOrganizer(context, displayLayout, mainExecutor); OneHandedDisplayAreaOrganizer organizer = new OneHandedDisplayAreaOrganizer( - context, displayLayout, animationController, tutorialHandler, + context, displayLayout, settingsUtil, animationController, tutorialHandler, oneHandedBackgroundPanelOrganizer, mainExecutor); - OneHandedSettingsUtil settingsUtil = new OneHandedSettingsUtil(); OneHandedUiEventLogger oneHandedUiEventsLogger = new OneHandedUiEventLogger(uiEventLogger); IOverlayManager overlayManager = IOverlayManager.Stub.asInterface( ServiceManager.getService(Context.OVERLAY_SERVICE)); return new OneHandedController(context, displayController, oneHandedBackgroundPanelOrganizer, organizer, touchHandler, tutorialHandler, - gestureHandler, settingsUtil, timeoutHandler, oneHandedUiEventsLogger, - overlayManager, taskStackListener, mainExecutor, mainHandler); + gestureHandler, settingsUtil, accessibilityUtil, timeoutHandler, + oneHandedUiEventsLogger, overlayManager, taskStackListener, mainExecutor, + mainHandler); } @VisibleForTesting @@ -226,6 +229,7 @@ public class OneHandedController implements RemoteCallable<OneHandedController> OneHandedTutorialHandler tutorialHandler, OneHandedGestureHandler gestureHandler, OneHandedSettingsUtil settingsUtil, + OneHandedAccessibilityUtil oneHandedAccessibilityUtil, OneHandedTimeoutHandler timeoutHandler, OneHandedUiEventLogger uiEventsLogger, IOverlayManager overlayManager, @@ -234,6 +238,7 @@ public class OneHandedController implements RemoteCallable<OneHandedController> Handler mainHandler) { mContext = context; mOneHandedSettingsUtil = settingsUtil; + mOneHandedAccessibilityUtil = oneHandedAccessibilityUtil; mBackgroundPanelOrganizer = backgroundPanelOrganizer; mDisplayAreaOrganizer = displayAreaOrganizer; mDisplayController = displayController; @@ -334,6 +339,8 @@ public class OneHandedController implements RemoteCallable<OneHandedController> if (!mDisplayAreaOrganizer.isInOneHanded()) { final int yOffSet = Math.round( mDisplayAreaOrganizer.getDisplayLayout().height() * mOffSetFraction); + mOneHandedAccessibilityUtil.announcementForScreenReader( + mOneHandedAccessibilityUtil.getOneHandedStartDescription()); mDisplayAreaOrganizer.scheduleOffset(0, yOffSet); mTimeoutHandler.resetTimer(); @@ -345,6 +352,8 @@ public class OneHandedController implements RemoteCallable<OneHandedController> @VisibleForTesting void stopOneHanded() { if (mDisplayAreaOrganizer.isInOneHanded()) { + mOneHandedAccessibilityUtil.announcementForScreenReader( + mOneHandedAccessibilityUtil.getOneHandedStopDescription()); mDisplayAreaOrganizer.scheduleOffset(0, 0); mTimeoutHandler.removeTimer(); } @@ -352,6 +361,8 @@ public class OneHandedController implements RemoteCallable<OneHandedController> private void stopOneHanded(int uiEvent) { if (mDisplayAreaOrganizer.isInOneHanded()) { + mOneHandedAccessibilityUtil.announcementForScreenReader( + mOneHandedAccessibilityUtil.getOneHandedStopDescription()); mDisplayAreaOrganizer.scheduleOffset(0, 0); mTimeoutHandler.removeTimer(); mOneHandedUiEventLogger.writeEvent(uiEvent); @@ -629,6 +640,10 @@ public class OneHandedController implements RemoteCallable<OneHandedController> mTutorialHandler.dump(pw); } + if (mOneHandedAccessibilityUtil != null) { + mOneHandedAccessibilityUtil.dump(pw); + } + mOneHandedSettingsUtil.dump(pw, innerPrefix, mContext.getContentResolver(), mUserId); if (mOverlayManager != null) { diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedDisplayAreaOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedDisplayAreaOrganizer.java index 682c9a3f0d62..d1b3f1a2e8a5 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedDisplayAreaOrganizer.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedDisplayAreaOrganizer.java @@ -16,6 +16,8 @@ package com.android.wm.shell.onehanded; +import static android.os.UserHandle.myUserId; + import static com.android.wm.shell.onehanded.OneHandedAnimationController.TRANSITION_DIRECTION_EXIT; import static com.android.wm.shell.onehanded.OneHandedAnimationController.TRANSITION_DIRECTION_TRIGGER; @@ -61,6 +63,7 @@ public class OneHandedDisplayAreaOrganizer extends DisplayAreaOrganizer { private final Rect mLastVisualDisplayBounds = new Rect(); private final Rect mDefaultDisplayBounds = new Rect(); + private final OneHandedSettingsUtil mOneHandedSettingsUtil; private boolean mIsInOneHanded; private int mEnterExitAnimationDurationMs; @@ -109,12 +112,14 @@ public class OneHandedDisplayAreaOrganizer extends DisplayAreaOrganizer { */ public OneHandedDisplayAreaOrganizer(Context context, DisplayLayout displayLayout, + OneHandedSettingsUtil oneHandedSettingsUtil, OneHandedAnimationController animationController, OneHandedTutorialHandler tutorialHandler, OneHandedBackgroundPanelOrganizer oneHandedBackgroundGradientOrganizer, ShellExecutor mainExecutor) { super(mainExecutor); mDisplayLayout.set(displayLayout); + mOneHandedSettingsUtil = oneHandedSettingsUtil; updateDisplayBounds(); mAnimationController = animationController; final int animationDurationConfig = context.getResources().getInteger( @@ -168,6 +173,11 @@ public class OneHandedDisplayAreaOrganizer extends DisplayAreaOrganizer { if (mDisplayLayout.rotation() == toRotation) { return; } + + if (!mOneHandedSettingsUtil.getSettingsOneHandedModeEnabled(context.getContentResolver(), + myUserId())) { + return; + } mDisplayLayout.rotateTo(context.getResources(), toRotation); resetWindowsOffset(wct); updateDisplayBounds(); diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedTutorialHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedTutorialHandler.java index d539835da764..b445917fb90c 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedTutorialHandler.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedTutorialHandler.java @@ -28,8 +28,6 @@ import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.view.WindowManager; -import android.view.accessibility.AccessibilityEvent; -import android.view.accessibility.AccessibilityManager; import android.widget.FrameLayout; import androidx.annotation.NonNull; @@ -51,7 +49,6 @@ public class OneHandedTutorialHandler implements OneHandedTransitionCallback { "persist.debug.one_handed_offset_percentage"; private static final int MAX_TUTORIAL_SHOW_COUNT = 2; private final WindowManager mWindowManager; - private final AccessibilityManager mAccessibilityManager; private final String mPackageName; private final Rect mDisplaySize; @@ -59,8 +56,6 @@ public class OneHandedTutorialHandler implements OneHandedTransitionCallback { private View mTutorialView; private ContentResolver mContentResolver; private boolean mCanShowTutorial; - private String mStartOneHandedDescription; - private String mStopOneHandedDescription; private boolean mIsOneHandedMode; private enum ONE_HANDED_TRIGGER_STATE { @@ -106,11 +101,6 @@ public class OneHandedTutorialHandler implements OneHandedTransitionCallback { mDisplaySize = windowManager.getCurrentWindowMetrics().getBounds(); mPackageName = context.getPackageName(); mContentResolver = context.getContentResolver(); - mAccessibilityManager = AccessibilityManager.getInstance(context); - mStartOneHandedDescription = context.getResources().getString( - R.string.accessibility_action_start_one_handed); - mStopOneHandedDescription = context.getResources().getString( - R.string.accessibility_action_stop_one_handed); mCanShowTutorial = (Settings.Secure.getInt(mContentResolver, Settings.Secure.ONE_HANDED_TUTORIAL_SHOW_COUNT, 0) >= MAX_TUTORIAL_SHOW_COUNT) ? false : true; @@ -131,14 +121,12 @@ public class OneHandedTutorialHandler implements OneHandedTransitionCallback { public void onStartFinished(Rect bounds) { updateFinished(View.VISIBLE, 0f); updateTutorialCount(); - announcementForScreenReader(true); mTriggerState = ONE_HANDED_TRIGGER_STATE.UNSET; } @Override public void onStopFinished(Rect bounds) { updateFinished(View.INVISIBLE, -mTargetViewContainer.getHeight()); - announcementForScreenReader(false); removeTutorialFromWindowManager(); mTriggerState = ONE_HANDED_TRIGGER_STATE.UNSET; } @@ -170,17 +158,6 @@ public class OneHandedTutorialHandler implements OneHandedTransitionCallback { Settings.Secure.ONE_HANDED_TUTORIAL_SHOW_COUNT, showCount); } - private void announcementForScreenReader(boolean isStartOneHanded) { - if (mAccessibilityManager.isTouchExplorationEnabled()) { - final AccessibilityEvent event = AccessibilityEvent.obtain(); - event.setPackageName(mPackageName); - event.setEventType(AccessibilityEvent.TYPE_ANNOUNCEMENT); - event.getText().add(isStartOneHanded - ? mStartOneHandedDescription : mStopOneHandedDescription); - mAccessibilityManager.sendAccessibilityEvent(event); - } - } - /** * Adds the tutorial target view to the WindowManager and update its layout, so it's ready * to be animated in. 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 e309f9659338..105bd828aa9e 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 @@ -58,6 +58,7 @@ public class OneHandedControllerTest extends OneHandedTestCase { Display mDisplay; DisplayLayout mDisplayLayout; + OneHandedAccessibilityUtil mOneHandedAccessibilityUtil; OneHandedController mSpiedOneHandedController; OneHandedTimeoutHandler mSpiedTimeoutHandler; @@ -116,6 +117,7 @@ public class OneHandedControllerTest extends OneHandedTestCase { new Rect(0, 0, mDisplayLayout.width(), mDisplayLayout.height())); when(mMockDisplayAreaOrganizer.getDisplayLayout()).thenReturn(mDisplayLayout); + mOneHandedAccessibilityUtil = new OneHandedAccessibilityUtil(mContext); mSpiedOneHandedController = spy(new OneHandedController( mContext, mMockDisplayController, @@ -125,6 +127,7 @@ public class OneHandedControllerTest extends OneHandedTestCase { mMockTutorialHandler, mMockGestureHandler, mMockSettingsUitl, + mOneHandedAccessibilityUtil, mSpiedTimeoutHandler, mMockUiEventLogger, mMockOverlayManager, @@ -139,8 +142,8 @@ public class OneHandedControllerTest extends OneHandedTestCase { final OneHandedAnimationController animationController = new OneHandedAnimationController( mContext); OneHandedDisplayAreaOrganizer displayAreaOrganizer = new OneHandedDisplayAreaOrganizer( - mContext, mDisplayLayout, animationController, mMockTutorialHandler, - mMockBackgroundOrganizer, mMockShellMainExecutor); + mContext, mDisplayLayout, mMockSettingsUitl, animationController, + mMockTutorialHandler, mMockBackgroundOrganizer, mMockShellMainExecutor); assertThat(displayAreaOrganizer.isInOneHanded()).isFalse(); } diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedDisplayAreaOrganizerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedDisplayAreaOrganizerTest.java index f654bb59ef0c..eb731d2c674d 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedDisplayAreaOrganizerTest.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedDisplayAreaOrganizerTest.java @@ -97,9 +97,13 @@ public class OneHandedDisplayAreaOrganizerTest extends OneHandedTestCase { OneHandedBackgroundPanelOrganizer mMockBackgroundOrganizer; @Mock ShellExecutor mMockShellMainExecutor; + @Mock + OneHandedSettingsUtil mMockSettingsUitl; List<DisplayAreaAppearedInfo> mDisplayAreaAppearedInfoList = new ArrayList<>(); + final boolean mDefaultEnabled = true; + @Before public void setUp() throws Exception { MockitoAnnotations.initMocks(this); @@ -126,9 +130,12 @@ public class OneHandedDisplayAreaOrganizerTest extends OneHandedTestCase { when(mMockAnimator.setTransitionDirection(anyInt())).thenReturn(mFakeAnimator); when(mMockLeash.getWidth()).thenReturn(DISPLAY_WIDTH); when(mMockLeash.getHeight()).thenReturn(DISPLAY_HEIGHT); + when(mMockSettingsUitl.getSettingsOneHandedModeEnabled(any(), anyInt())).thenReturn( + mDefaultEnabled); mSpiedDisplayAreaOrganizer = spy(new OneHandedDisplayAreaOrganizer(mContext, mDisplayLayout, + mMockSettingsUitl, mMockAnimationController, mTutorialHandler, mMockBackgroundOrganizer, diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedTutorialHandlerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedTutorialHandlerTest.java index 2886bb1e905a..06a66717ed31 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedTutorialHandlerTest.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedTutorialHandlerTest.java @@ -66,6 +66,8 @@ public class OneHandedTutorialHandlerTest extends OneHandedTestCase { OneHandedUiEventLogger mMockUiEventLogger; @Mock OneHandedSettingsUtil mMockSettingsUtil; + @Mock + OneHandedAccessibilityUtil mMockAccessibilityUtil; @Before public void setUp() { @@ -82,6 +84,7 @@ public class OneHandedTutorialHandlerTest extends OneHandedTestCase { mMockTutorialHandler, mMockGestureHandler, mMockSettingsUtil, + mMockAccessibilityUtil, mTimeoutHandler, mMockUiEventLogger, mMockOverlayManager, |