Merge "Fix Talk back announces "Exit one handed mode" on every orientation change though one-handed mode is off" into sc-dev
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 0000000..1302461
--- /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 38cf9e6..19098fd 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 @@
     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 @@
             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 @@
         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 @@
             OneHandedTutorialHandler tutorialHandler,
             OneHandedGestureHandler gestureHandler,
             OneHandedSettingsUtil settingsUtil,
+            OneHandedAccessibilityUtil oneHandedAccessibilityUtil,
             OneHandedTimeoutHandler timeoutHandler,
             OneHandedUiEventLogger uiEventsLogger,
             IOverlayManager overlayManager,
@@ -234,6 +238,7 @@
             Handler mainHandler) {
         mContext = context;
         mOneHandedSettingsUtil = settingsUtil;
+        mOneHandedAccessibilityUtil = oneHandedAccessibilityUtil;
         mBackgroundPanelOrganizer = backgroundPanelOrganizer;
         mDisplayAreaOrganizer = displayAreaOrganizer;
         mDisplayController = displayController;
@@ -334,6 +339,8 @@
         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 @@
     @VisibleForTesting
     void stopOneHanded() {
         if (mDisplayAreaOrganizer.isInOneHanded()) {
+            mOneHandedAccessibilityUtil.announcementForScreenReader(
+                    mOneHandedAccessibilityUtil.getOneHandedStopDescription());
             mDisplayAreaOrganizer.scheduleOffset(0, 0);
             mTimeoutHandler.removeTimer();
         }
@@ -352,6 +361,8 @@
 
     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 @@
             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 682c9a3f..d1b3f1a 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 @@
 
     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 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 @@
         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 d539835..b445917 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.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 @@
             "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 @@
     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 @@
         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 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 @@
                 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 e309f96..105bd82 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 @@
 
     Display mDisplay;
     DisplayLayout mDisplayLayout;
+    OneHandedAccessibilityUtil mOneHandedAccessibilityUtil;
     OneHandedController mSpiedOneHandedController;
     OneHandedTimeoutHandler mSpiedTimeoutHandler;
 
@@ -116,6 +117,7 @@
                 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 @@
                 mMockTutorialHandler,
                 mMockGestureHandler,
                 mMockSettingsUitl,
+                mOneHandedAccessibilityUtil,
                 mSpiedTimeoutHandler,
                 mMockUiEventLogger,
                 mMockOverlayManager,
@@ -139,8 +142,8 @@
         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 f654bb5..eb731d2 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 @@
     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 @@
         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 2886bb1..06a6671 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 @@
     OneHandedUiEventLogger mMockUiEventLogger;
     @Mock
     OneHandedSettingsUtil mMockSettingsUtil;
+    @Mock
+    OneHandedAccessibilityUtil mMockAccessibilityUtil;
 
     @Before
     public void setUp() {
@@ -82,6 +84,7 @@
                 mMockTutorialHandler,
                 mMockGestureHandler,
                 mMockSettingsUtil,
+                mMockAccessibilityUtil,
                 mTimeoutHandler,
                 mMockUiEventLogger,
                 mMockOverlayManager,