Merge "Add rounded corners to TaskMenu Items" into sc-dev
diff --git a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
index 4d47ef1..d511e6d 100644
--- a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
+++ b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
@@ -230,6 +230,7 @@
 
     // Used to control launcher components throughout the swipe gesture.
     private AnimatorControllerWithResistance mLauncherTransitionController;
+    private boolean mHasEndedLauncherTransition;
 
     private AnimationFactory mAnimationFactory = (t) -> { };
 
@@ -603,11 +604,11 @@
 
     /**
      * We don't want to change mLauncherTransitionController if mGestureState.getEndTarget() == HOME
-     * (it has its own animation).
+     * (it has its own animation) or if we explicitly ended the controller already.
      * @return Whether we can create the launcher controller or update its progress.
      */
     private boolean canCreateNewOrUpdateExistingLauncherTransitionController() {
-        return mGestureState.getEndTarget() != HOME;
+        return mGestureState.getEndTarget() != HOME && !mHasEndedLauncherTransition;
     }
 
     @Override
@@ -1421,6 +1422,8 @@
     }
 
     private void endLauncherTransitionController() {
+        mHasEndedLauncherTransition = true;
+
         if (mLauncherTransitionController != null) {
             // End the animation, but stay at the same visual progress.
             mLauncherTransitionController.getNormalController().dispatchSetInterpolator(
diff --git a/quickstep/src/com/android/quickstep/TouchInteractionService.java b/quickstep/src/com/android/quickstep/TouchInteractionService.java
index c9b68df..84f7e83 100644
--- a/quickstep/src/com/android/quickstep/TouchInteractionService.java
+++ b/quickstep/src/com/android/quickstep/TouchInteractionService.java
@@ -64,6 +64,7 @@
 import android.view.accessibility.AccessibilityManager;
 
 import androidx.annotation.BinderThread;
+import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 import androidx.annotation.UiThread;
 import androidx.annotation.WorkerThread;
@@ -303,10 +304,10 @@
     private RecentsAnimationDeviceState mDeviceState;
     private TaskAnimationManager mTaskAnimationManager;
 
-    private InputConsumer mUncheckedConsumer = InputConsumer.NO_OP;
-    private InputConsumer mConsumer = InputConsumer.NO_OP;
+    private @NonNull InputConsumer mUncheckedConsumer = InputConsumer.NO_OP;
+    private @NonNull InputConsumer mConsumer = InputConsumer.NO_OP;
     private Choreographer mMainChoreographer;
-    private InputConsumer mResetGestureInputConsumer;
+    private @Nullable ResetGestureInputConsumer mResetGestureInputConsumer;
     private GestureState mGestureState = DEFAULT_STATE;
 
     private InputMonitorCompat mInputMonitorCompat;
@@ -635,7 +636,7 @@
                 // launched while device is locked even after exiting direct boot mode (e.g. camera).
                 return createDeviceLockedInputConsumer(newGestureState);
             } else {
-                return mResetGestureInputConsumer;
+                return getDefaultInputConsumer();
             }
         }
 
@@ -644,7 +645,7 @@
         InputConsumer base = canStartSystemGesture
                 || previousGestureState.isRecentsAnimationRunning()
                         ? newBaseConsumer(previousGestureState, newGestureState, event)
-                        : mResetGestureInputConsumer;
+                        : getDefaultInputConsumer();
         if (mDeviceState.isGesturalNavMode()) {
             handleOrientationSetup(base);
         }
@@ -698,7 +699,7 @@
             }
         } else {
             if (mDeviceState.isScreenPinningActive()) {
-                base = mResetGestureInputConsumer;
+                base = getDefaultInputConsumer();
             }
 
             if (mDeviceState.canTriggerOneHandedAction(event)) {
@@ -740,14 +741,14 @@
             return createOverviewInputConsumer(
                     previousGestureState, gestureState, event, forceOverviewInputConsumer);
         } else if (gestureState.getRunningTask() == null) {
-            return mResetGestureInputConsumer;
+            return getDefaultInputConsumer();
         } else if (previousGestureState.isRunningAnimationToLauncher()
                 || gestureState.getActivityInterface().isResumed()
                 || forceOverviewInputConsumer) {
             return createOverviewInputConsumer(
                     previousGestureState, gestureState, event, forceOverviewInputConsumer);
         } else if (mDeviceState.isGestureBlockedActivity(gestureState.getRunningTask())) {
-            return mResetGestureInputConsumer;
+            return getDefaultInputConsumer();
         } else {
             return createOtherActivityInputConsumer(gestureState, event);
         }
@@ -775,7 +776,7 @@
             return new DeviceLockedInputConsumer(this, mDeviceState, mTaskAnimationManager,
                     gestureState, mInputMonitorCompat);
         } else {
-            return mResetGestureInputConsumer;
+            return getDefaultInputConsumer();
         }
     }
 
@@ -784,7 +785,7 @@
             boolean forceOverviewInputConsumer) {
         StatefulActivity activity = gestureState.getActivityInterface().getCreatedActivity();
         if (activity == null) {
-            return mResetGestureInputConsumer;
+            return getDefaultInputConsumer();
         }
 
         if (activity.getRootView().hasWindowFocus()
@@ -813,13 +814,7 @@
     }
 
     private void reset() {
-        if (mResetGestureInputConsumer != null) {
-            mConsumer = mUncheckedConsumer = mResetGestureInputConsumer;
-        } else {
-            // mResetGestureInputConsumer isn't initialized until onUserUnlocked(), so reset to
-            // NO_OP until then (we never want these to be null).
-            mConsumer = mUncheckedConsumer = InputConsumer.NO_OP;
-        }
+        mConsumer = mUncheckedConsumer = getDefaultInputConsumer();
         mGestureState = DEFAULT_STATE;
         // By default, use batching of the input events, but check receiver before using in the rare
         // case that the monitor was disposed before the swipe settled
@@ -828,6 +823,19 @@
         }
     }
 
+    /**
+     * Returns the {@link ResetGestureInputConsumer} if user is unlocked, else NO_OP.
+     */
+    private @NonNull InputConsumer getDefaultInputConsumer() {
+        if (mResetGestureInputConsumer != null) {
+            return mResetGestureInputConsumer;
+        } else {
+            // mResetGestureInputConsumer isn't initialized until onUserUnlocked(), so reset to
+            // NO_OP until then (we never want these to be null).
+            return InputConsumer.NO_OP;
+        }
+    }
+
     private void preloadOverview(boolean fromInit) {
         if (!mDeviceState.isUserUnlocked()) {
             return;
diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java
index 000a95d..8b7af04 100644
--- a/quickstep/src/com/android/quickstep/views/RecentsView.java
+++ b/quickstep/src/com/android/quickstep/views/RecentsView.java
@@ -1251,7 +1251,9 @@
 
     private void updateOrientationHandler() {
         // Handle orientation changes.
+        PagedOrientationHandler oldOrientationHandler = mOrientationHandler;
         mOrientationHandler = mOrientationState.getOrientationHandler();
+
         mIsRtl = mOrientationHandler.getRecentsRtlSetting(getResources());
         setLayoutDirection(mIsRtl
                 ? View.LAYOUT_DIRECTION_RTL
@@ -1260,7 +1262,12 @@
                 ? View.LAYOUT_DIRECTION_LTR
                 : View.LAYOUT_DIRECTION_RTL);
         mClearAllButton.setRotation(mOrientationHandler.getDegreesRotated());
-        mActivity.getDragLayer().recreateControllers();
+
+        if (!mOrientationHandler.equals(oldOrientationHandler)) {
+            // Changed orientations, update controllers so they intercept accordingly.
+            mActivity.getDragLayer().recreateControllers();
+        }
+
         boolean isInLandscape = mOrientationState.getTouchRotation() != ROTATION_0
                 || mOrientationState.getRecentsActivityRotation() != ROTATION_0;
         mActionsView.updateHiddenFlags(HIDDEN_NON_ZERO_ROTATION,
diff --git a/src/com/android/launcher3/widget/WidgetsBottomSheet.java b/src/com/android/launcher3/widget/WidgetsBottomSheet.java
index d0e69fa..37b950d 100644
--- a/src/com/android/launcher3/widget/WidgetsBottomSheet.java
+++ b/src/com/android/launcher3/widget/WidgetsBottomSheet.java
@@ -23,6 +23,7 @@
 import android.graphics.Rect;
 import android.util.AttributeSet;
 import android.util.IntProperty;
+import android.util.Log;
 import android.util.Pair;
 import android.view.Gravity;
 import android.view.LayoutInflater;
@@ -35,6 +36,8 @@
 import android.widget.TableRow;
 import android.widget.TextView;
 
+import androidx.annotation.GuardedBy;
+
 import com.android.launcher3.DeviceProfile;
 import com.android.launcher3.Insettable;
 import com.android.launcher3.LauncherAppState;
@@ -51,6 +54,7 @@
  * Bottom sheet for the "Widgets" system shortcut in the long-press popup.
  */
 public class WidgetsBottomSheet extends BaseWidgetSheet implements Insettable {
+    private static final String TAG = "WidgetsBottomSheet";
 
     private static final IntProperty<View> PADDING_BOTTOM =
             new IntProperty<View>("paddingBottom") {
@@ -128,6 +132,32 @@
 
     @Override
     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+        if (doMeasure(widthMeasureSpec, heightMeasureSpec)) {
+            boolean hasUpdated = doMeasure(widthMeasureSpec, heightMeasureSpec);
+            if (hasUpdated) {
+                Log.w(TAG, "WidgetsBottomSheet dimension has been updated after a 2nd"
+                        + " measurement.");
+            }
+        }
+    }
+
+    /**
+     * Measures the dimension of this view and its children.
+     *
+     * <p>This function takes account of the following during measurement:
+     * <ol>
+     *     <li>status bar and system navigation bar insets</li>
+     *     <li>
+     *         number of spans that can fit in a row. This affects the number of widgets that can
+     *         fit in a row.
+     *     </li>
+     * </ol>
+     *
+     * @return {@code true} if the width or height of this view or its children have changed after
+     *          the measurement. Otherwise, returns {@code false}.
+     */
+    @GuardedBy("MainThread")
+    private boolean doMeasure(int widthMeasureSpec, int heightMeasureSpec) {
         DeviceProfile deviceProfile = mActivityContext.getDeviceProfile();
         int widthUsed;
         if (mInsets.bottom > 0) {
@@ -153,7 +183,9 @@
             // Ensure the table layout is showing widgets in the right column after measure.
             mMaxHorizontalSpan = maxHorizontalSpan;
             onWidgetsBound();
+            return true;
         }
+        return false;
     }
 
     @Override