Fix Talk back announces "Exit one handed mode" on every orientation

change though one-handed mode is off

Add more condition check when Talk back announce one-handed mode
related.

Bug: 182475904
Test: manual
Test: atest WMShellUnitTests
Change-Id: I0644146eaa6d7d6701af94fe6caceee5e6c3be8b
This commit is contained in:
Jason Chang
2021-03-27 00:38:02 +08:00
parent befdba3764
commit 327e463a30
7 changed files with 135 additions and 29 deletions

View File

@@ -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);
}
}

View File

@@ -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) {

View File

@@ -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();

View File

@@ -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.

View File

@@ -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();
}

View File

@@ -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,

View File

@@ -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,