Infer launcher rotation when initializing RecentsOrientedState

fixes: 154776599
Change-Id: I9b95f7f96836a974be0fd1236547efb4b405fda5
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/util/TaskViewSimulator.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/util/TaskViewSimulator.java
index 832f0e2..391dcaf 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/util/TaskViewSimulator.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/util/TaskViewSimulator.java
@@ -88,9 +88,6 @@
         mSizeStrategy = sizeStrategy;
 
         mOrientationState = new RecentsOrientedState(context, sizeStrategy, i -> { });
-        // We do not need to attach listeners as the simulator is created just for the gesture
-        // duration, and any settings are unlikely to change during this
-        mOrientationState.initWithoutListeners();
 
         mCurrentFullscreenParams = new FullscreenDrawParams(context);
         mPageSpacing = context.getResources().getDimensionPixelSize(R.dimen.recents_page_spacing);
@@ -109,15 +106,7 @@
      * @see com.android.quickstep.views.RecentsView#setLayoutRotation(int, int)
      */
     public void setLayoutRotation(int touchRotation, int displayRotation) {
-        int launcherRotation;
-        if (!mOrientationState.isMultipleOrientationSupportedByDevice()
-                || mOrientationState.isHomeRotationAllowed()) {
-            launcherRotation = displayRotation;
-        } else {
-            launcherRotation = ROTATION_0;
-        }
-
-        mOrientationState.update(touchRotation, displayRotation, launcherRotation);
+        mOrientationState.update(touchRotation, displayRotation);
         mLayoutValid = false;
     }
 
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/RecentsView.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/RecentsView.java
index 49aca30..31fc2fd 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/RecentsView.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/RecentsView.java
@@ -16,6 +16,7 @@
 
 package com.android.quickstep.views;
 
+import static android.view.Surface.ROTATION_0;
 import static com.android.launcher3.BaseActivity.STATE_HANDLER_INVISIBILITY_FLAGS;
 import static com.android.launcher3.InvariantDeviceProfile.CHANGE_FLAG_ICON_PARAMS;
 import static com.android.launcher3.LauncherAnimUtils.SCALE_PROPERTY;
@@ -55,7 +56,6 @@
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
-import android.content.res.Configuration;
 import android.graphics.Canvas;
 import android.graphics.Point;
 import android.graphics.PointF;
@@ -509,7 +509,7 @@
         mIPinnedStackAnimationListener.setActivity(mActivity);
         SystemUiProxy.INSTANCE.get(getContext()).setPinnedStackAnimationListener(
                 mIPinnedStackAnimationListener);
-        mOrientationState.init();
+        mOrientationState.initListeners();
     }
 
     @Override
@@ -524,7 +524,7 @@
         mIdp.removeOnChangeListener(this);
         SystemUiProxy.INSTANCE.get(getContext()).setPinnedStackAnimationListener(null);
         mIPinnedStackAnimationListener.setActivity(null);
-        mOrientationState.destroy();
+        mOrientationState.destroyListeners();
     }
 
     @Override
@@ -617,15 +617,6 @@
     }
 
     @Override
-    protected void onConfigurationChanged(Configuration newConfig) {
-        super.onConfigurationChanged(newConfig);
-        int windowConfigurationRotation = ConfigurationCompat
-                .getWindowConfigurationRotation(getResources().getConfiguration());
-        setLayoutInternal(mOrientationState.getTouchRotation(),
-                mOrientationState.getDisplayRotation(), windowConfigurationRotation);
-    }
-
-    @Override
     public boolean onTouchEvent(MotionEvent ev) {
         super.onTouchEvent(ev);
         final int x = (int) ev.getX();
@@ -1594,19 +1585,14 @@
     }
 
     public void setLayoutRotation(int touchRotation, int displayRotation) {
-        int launcherRotation = mOrientationState.getLauncherRotation();
-        setLayoutInternal(touchRotation, displayRotation, launcherRotation);
-    }
-
-    private void setLayoutInternal(int touchRotation, int displayRotation, int launcherRotation) {
-        if (mOrientationState.update(touchRotation, displayRotation, launcherRotation)) {
+        if (mOrientationState.update(touchRotation, displayRotation)) {
             mOrientationHandler = mOrientationState.getOrientationHandler();
             mIsRtl = mOrientationHandler.getRecentsRtlSetting(getResources());
             setLayoutDirection(mIsRtl ? View.LAYOUT_DIRECTION_RTL : View.LAYOUT_DIRECTION_LTR);
             mClearAllButton.setRotation(mOrientationHandler.getDegreesRotated());
             mActivity.getDragLayer().recreateControllers();
             mActionsView.updateHiddenFlags(HIDDEN_NON_ZERO_ROTATION,
-                    touchRotation != 0 || launcherRotation != 0);
+                    touchRotation != 0 || mOrientationState.getLauncherRotation() != ROTATION_0);
             requestLayout();
         }
     }
diff --git a/quickstep/src/com/android/quickstep/util/RecentsOrientedState.java b/quickstep/src/com/android/quickstep/util/RecentsOrientedState.java
index f6c4e66..1336561 100644
--- a/quickstep/src/com/android/quickstep/util/RecentsOrientedState.java
+++ b/quickstep/src/com/android/quickstep/util/RecentsOrientedState.java
@@ -23,6 +23,7 @@
 import static android.view.Surface.ROTATION_270;
 import static android.view.Surface.ROTATION_90;
 
+import static com.android.launcher3.logging.LoggerUtils.extractObjectNameAndAddress;
 import static com.android.launcher3.states.RotationHelper.ALLOW_ROTATION_PREFERENCE_KEY;
 import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
 
@@ -84,7 +85,7 @@
 
     private @SurfaceRotation int mTouchRotation = ROTATION_0;
     private @SurfaceRotation int mDisplayRotation = ROTATION_0;
-    private @SurfaceRotation int mLauncherRotation = Surface.ROTATION_0;
+    private @SurfaceRotation int mLauncherRotation = ROTATION_0;
 
     // Launcher activity supports multiple orientation, but fallback activity does not
     private static final int FLAG_MULTIPLE_ORIENTATION_SUPPORTED_BY_ACTIVITY = 1 << 0;
@@ -102,6 +103,8 @@
     private static final int FLAG_ROTATION_WATCHER_SUPPORTED = 1 << 6;
     // Whether to enable rotation watcher when multi-rotation is supported
     private static final int FLAG_ROTATION_WATCHER_ENABLED = 1 << 7;
+    // Enable home rotation for UI tests, ignoring home rotation value from prefs
+    private static final int FLAG_HOME_ROTATION_FORCE_ENABLED_FOR_TESTING = 1 << 8;
 
     private static final int MASK_MULTIPLE_ORIENTATION_SUPPORTED_BY_DEVICE =
             FLAG_MULTIPLE_ORIENTATION_SUPPORTED_BY_ACTIVITY
@@ -163,6 +166,10 @@
         if (mOrientationListener.canDetectOrientation()) {
             mFlags |= FLAG_ROTATION_WATCHER_SUPPORTED;
         }
+
+        // initialize external flags
+        updateAutoRotateSetting();
+        updateHomeRotationSetting();
     }
 
     /**
@@ -181,13 +188,15 @@
      *         false otherwise
      */
     public boolean update(
-            @SurfaceRotation int touchRotation, @SurfaceRotation int displayRotation,
-            @SurfaceRotation int launcherRotation) {
+            @SurfaceRotation int touchRotation, @SurfaceRotation int displayRotation) {
         if (!isMultipleOrientationSupportedByDevice()) {
             return false;
         }
-        if (mDisplayRotation == displayRotation && mTouchRotation == touchRotation
-                && launcherRotation == mLauncherRotation) {
+
+        int launcherRotation = inferLauncherRotation(displayRotation);
+        if (mDisplayRotation == displayRotation
+                && mTouchRotation == touchRotation
+                && mLauncherRotation == launcherRotation) {
             return false;
         }
 
@@ -195,11 +204,10 @@
         mDisplayRotation = displayRotation;
         mTouchRotation = touchRotation;
 
-        if (canLauncherRotate() || mLauncherRotation == mTouchRotation) {
-            // TODO(b/153476489) Need to determine when launcher is rotated
+        if (mLauncherRotation == mTouchRotation) {
             mOrientationHandler = PagedOrientationHandler.HOME_ROTATED;
             if (DEBUG) {
-                Log.d(TAG, "Set Orientation Handler: " + mOrientationHandler);
+                Log.d(TAG, "current RecentsOrientedState: " + this);
             }
             return true;
         }
@@ -212,11 +220,20 @@
             mOrientationHandler = PagedOrientationHandler.PORTRAIT;
         }
         if (DEBUG) {
-            Log.d(TAG, "Set Orientation Handler: " + mOrientationHandler);
+            Log.d(TAG, "current RecentsOrientedState: " + this);
         }
         return true;
     }
 
+    @SurfaceRotation
+    private int inferLauncherRotation(@SurfaceRotation int displayRotation) {
+        if (!isMultipleOrientationSupportedByDevice() || isHomeRotationAllowed()) {
+            return displayRotation;
+        } else {
+            return ROTATION_0;
+        }
+    }
+
     private void setFlag(int mask, boolean enabled) {
         boolean wasRotationEnabled = !TestProtocol.sDisableSensorRotation
                 && mFlags == VALUE_ROTATION_WATCHER_ENABLED;
@@ -241,7 +258,9 @@
 
     @Override
     public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String s) {
-        updateHomeRotationSetting();
+        if (ALLOW_ROTATION_PREFERENCE_KEY.equals(s)) {
+            updateHomeRotationSetting();
+        }
     }
 
     private void updateAutoRotateSetting() {
@@ -255,23 +274,24 @@
     }
 
     /**
-     * Initializes aany system values and registers corresponding change listeners. It must be
-     * paired with {@link #destroy()} call
+     * Initializes any system values and registers corresponding change listeners. It must be
+     * paired with {@link #destroyListeners()} call
      */
-    public void init() {
+    public void initListeners() {
         if (isMultipleOrientationSupportedByDevice()) {
             mSharedPrefs.registerOnSharedPreferenceChangeListener(this);
             mContentResolver.registerContentObserver(
                     Settings.System.getUriFor(Settings.System.ACCELEROMETER_ROTATION),
                     false, mSystemAutoRotateObserver);
         }
-        initWithoutListeners();
+        updateAutoRotateSetting();
+        updateHomeRotationSetting();
     }
 
     /**
      * Unregisters any previously registered listeners.
      */
-    public void destroy() {
+    public void destroyListeners() {
         if (isMultipleOrientationSupportedByDevice()) {
             mSharedPrefs.unregisterOnSharedPreferenceChangeListener(this);
             mContentResolver.unregisterContentObserver(mSystemAutoRotateObserver);
@@ -279,13 +299,8 @@
         setRotationWatcherEnabled(false);
     }
 
-    /**
-     * Initializes the OrientationState without attaching any listeners. This can be used when
-     * the object is short lived.
-     */
-    public void initWithoutListeners() {
-        updateAutoRotateSetting();
-        updateHomeRotationSetting();
+    public void forceAllowRotationForTesting(boolean forceAllow) {
+        setFlag(FLAG_HOME_ROTATION_FORCE_ENABLED_FOR_TESTING, forceAllow);
     }
 
     @SurfaceRotation
@@ -310,7 +325,8 @@
 
     public boolean isHomeRotationAllowed() {
         return (mFlags & (FLAG_HOME_ROTATION_ALLOWED_IN_PREFS | FLAG_MULTIWINDOW_ROTATION_ALLOWED))
-                != 0;
+                != 0 ||
+                (mFlags & FLAG_HOME_ROTATION_FORCE_ENABLED_FOR_TESTING) != 0;
     }
 
     public boolean canLauncherRotate() {
@@ -440,9 +456,13 @@
                 if (degrees < (90 - threshold)) {
                     return ROTATION_0;
                 }
-                if (degrees > (90 + threshold)) {
+                if (degrees > (90 + threshold) && degrees < 180) {
                     return ROTATION_180;
                 }
+                // flip from seascape to landscape
+                if (degrees > (180 + threshold) && degrees < 360) {
+                    return ROTATION_90;
+                }
                 break;
             case ROTATION_180:
                 if (degrees < (180 - threshold)) {
@@ -453,12 +473,16 @@
                 }
                 break;
             case ROTATION_90:
-                if (degrees < (270 - threshold)) {
+                if (degrees < (270 - threshold) && degrees > 90) {
                     return ROTATION_180;
                 }
-                if (degrees > (270 + threshold)) {
+                if (degrees > (270 + threshold) && degrees < 360) {
                     return ROTATION_0;
                 }
+                // flip from landscape to seascape
+                if (degrees > threshold && degrees < 180) {
+                    return ROTATION_270;
+                }
                 break;
         }
 
@@ -506,13 +530,15 @@
     public String toString() {
         boolean systemRotationOn = (mFlags & FLAG_SYSTEM_ROTATION_ALLOWED) != 0;
         return "["
-                + "mDisplayRotation=" + mDisplayRotation
+                + "this=" + extractObjectNameAndAddress(super.toString())
+                + " mOrientationHandler=" +
+                    extractObjectNameAndAddress(mOrientationHandler.toString())
+                + " mDisplayRotation=" + mDisplayRotation
                 + " mTouchRotation=" + mTouchRotation
                 + " mLauncherRotation=" + mLauncherRotation
                 + " mHomeRotation=" + isHomeRotationAllowed()
                 + " mSystemRotation=" + systemRotationOn
                 + " mFlags=" + mFlags
-                + " mOrientationHandler=" + mOrientationHandler
                 + "]";
     }
 }
diff --git a/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java b/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java
index 75fcfe2..bf093fd 100644
--- a/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java
+++ b/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java
@@ -42,6 +42,7 @@
 import com.android.quickstep.NavigationModeSwitchRule.NavigationModeSwitch;
 import com.android.quickstep.views.RecentsView;
 
+import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -53,6 +54,18 @@
     public void setUp() throws Exception {
         super.setUp();
         TaplTestsLauncher3.initialize(this);
+        executeOnLauncher(launcher -> {
+            RecentsView recentsView = launcher.getOverviewPanel();
+            recentsView.getPagedViewOrientedState().forceAllowRotationForTesting(true);
+        });
+    }
+
+    @After
+    public void tearDown() {
+        executeOnLauncher(launcher -> {
+            RecentsView recentsView = launcher.getOverviewPanel();
+            recentsView.getPagedViewOrientedState().forceAllowRotationForTesting(false);
+        });
     }
 
     private void startTestApps() throws Exception {
diff --git a/src/com/android/launcher3/logging/LoggerUtils.java b/src/com/android/launcher3/logging/LoggerUtils.java
index 0f79bd6..cd4f034 100644
--- a/src/com/android/launcher3/logging/LoggerUtils.java
+++ b/src/com/android/launcher3/logging/LoggerUtils.java
@@ -41,6 +41,7 @@
     private static final ArrayMap<Class, SparseArray<String>> sNameCache = new ArrayMap<>();
     private static final String UNKNOWN = "UNKNOWN";
     private static final int DEFAULT_PREDICTED_RANK = 10000;
+    private static final String DELIMITER_DOT = "\\.";
 
     public static String getFieldName(int value, Class c) {
         SparseArray<String> cache;
@@ -173,4 +174,17 @@
         targets.toArray(targetsArray);
         return newLauncherEvent(action, targetsArray);
     }
+
+    /**
+     * String conversion for only the helpful parts of {@link Object#toString()} method
+     * @param stringToExtract "foo.bar.baz.MyObject@1234"
+     * @return "MyObject@1234"
+     */
+    public static String extractObjectNameAndAddress(String stringToExtract) {
+        String[] superStringParts = stringToExtract.split(DELIMITER_DOT);
+        if (superStringParts.length == 0) {
+            return "";
+        }
+        return superStringParts[superStringParts.length - 1];
+    }
 }