Snap for 7365855 from 37b3752a864fc5c54930012c7446ba9a5dc70a64 to sc-v2-release

Change-Id: Ifba7ffc2abc0c62558b0689712d5cd47b4007c4a
diff --git a/protos/launcher_atom.proto b/protos/launcher_atom.proto
index fb47b0a..475b5be 100644
--- a/protos/launcher_atom.proto
+++ b/protos/launcher_atom.proto
@@ -162,6 +162,7 @@
   optional int32 app_widget_id = 3;
   optional string package_name = 4; // only populated during snapshot if from workspace
   optional string component_name = 5; // only populated during snapshot if from workspace
+  optional int32 widget_features = 6;
 }
 
 // Tasks handled by PackageManager
diff --git a/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java b/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
index de9b361..275dfda 100644
--- a/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
+++ b/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
@@ -1260,7 +1260,8 @@
             if (launchingFromWidget) {
                 composeWidgetLaunchAnimator(anim, (LauncherAppWidgetHostView) mV, appTargets,
                         wallpaperTargets, nonAppTargets);
-                // TODO(b/169042867): jank monitoring instrumentation
+                addCujInstrumentation(
+                        anim, InteractionJankMonitorWrapper.CUJ_APP_LAUNCH_FROM_WIDGET);
             } else if (launchingFromRecents) {
                 composeRecentsLaunchAnimator(anim, mV, appTargets, wallpaperTargets, nonAppTargets,
                         launcherClosing);
diff --git a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
index 2242168..63646d0 100644
--- a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
+++ b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
@@ -1514,10 +1514,12 @@
         if (mIsSwipingPipToHome && mSwipePipToHomeAnimator != null) {
             SystemUiProxy.INSTANCE.get(mContext).stopSwipePipToHome(
                     mSwipePipToHomeAnimator.getComponentName(),
-                    mSwipePipToHomeAnimator.getDestinationBounds());
+                    mSwipePipToHomeAnimator.getDestinationBounds(),
+                    mSwipePipToHomeAnimator.getContentOverlay());
             mRecentsAnimationController.setFinishTaskTransaction(
                     mSwipePipToHomeAnimator.getTaskId(),
-                    mSwipePipToHomeAnimator.getFinishTransaction());
+                    mSwipePipToHomeAnimator.getFinishTransaction(),
+                    mSwipePipToHomeAnimator.getContentOverlay());
             mIsSwipingPipToHome = false;
         }
     }
diff --git a/quickstep/src/com/android/quickstep/RecentsAnimationController.java b/quickstep/src/com/android/quickstep/RecentsAnimationController.java
index 78da311..f2bd916 100644
--- a/quickstep/src/com/android/quickstep/RecentsAnimationController.java
+++ b/quickstep/src/com/android/quickstep/RecentsAnimationController.java
@@ -19,6 +19,7 @@
 import static com.android.launcher3.util.Executors.THREAD_POOL_EXECUTOR;
 import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
 
+import android.view.SurfaceControl;
 import android.window.PictureInPictureSurfaceTransaction;
 
 import androidx.annotation.NonNull;
@@ -159,12 +160,15 @@
      * that animating Activity to PiP has completed and the associated task surface should be
      * updated accordingly. This should be called before `finish`
      * @param taskId for which the leash should be updated
-     * @param finishTransaction leash operations for the final transform.
+     * @param finishTransaction the transaction to transfer to the task surface control after the
+     *                          leash is removed
+     * @param overlay the surface control for an overlay being shown above the pip (can be null)
      */
     public void setFinishTaskTransaction(int taskId,
-            PictureInPictureSurfaceTransaction finishTransaction) {
+            PictureInPictureSurfaceTransaction finishTransaction,
+            SurfaceControl overlay) {
         UI_HELPER_EXECUTOR.execute(
-                () -> mController.setFinishTaskTransaction(taskId, finishTransaction));
+                () -> mController.setFinishTaskTransaction(taskId, finishTransaction, overlay));
     }
 
     /**
diff --git a/quickstep/src/com/android/quickstep/SystemUiProxy.java b/quickstep/src/com/android/quickstep/SystemUiProxy.java
index 39d8888..6fb938a 100644
--- a/quickstep/src/com/android/quickstep/SystemUiProxy.java
+++ b/quickstep/src/com/android/quickstep/SystemUiProxy.java
@@ -33,6 +33,7 @@
 import android.os.UserHandle;
 import android.util.Log;
 import android.view.MotionEvent;
+import android.view.SurfaceControl;
 
 import com.android.launcher3.util.MainThreadInitializedObject;
 import com.android.launcher3.util.SplitConfigurationOptions;
@@ -427,10 +428,11 @@
         return null;
     }
 
-    public void stopSwipePipToHome(ComponentName componentName, Rect destinationBounds) {
+    public void stopSwipePipToHome(ComponentName componentName, Rect destinationBounds,
+            SurfaceControl overlay) {
         if (mPip != null) {
             try {
-                mPip.stopSwipePipToHome(componentName, destinationBounds);
+                mPip.stopSwipePipToHome(componentName, destinationBounds, overlay);
             } catch (RemoteException e) {
                 Log.w(TAG, "Failed call stopSwipePipToHome");
             }
diff --git a/quickstep/src/com/android/quickstep/logging/StatsLogCompatManager.java b/quickstep/src/com/android/quickstep/logging/StatsLogCompatManager.java
index 3b26108..719cb0a 100644
--- a/quickstep/src/com/android/quickstep/logging/StatsLogCompatManager.java
+++ b/quickstep/src/com/android/quickstep/logging/StatsLogCompatManager.java
@@ -354,6 +354,10 @@
     }
 
     private static int getCardinality(LauncherAtom.ItemInfo info) {
+        // TODO(b/187734511): Implement a unified solution for 1x1 widgets in folders/hotseat.
+        if (info.getItemCase().equals(LauncherAtom.ItemInfo.ItemCase.WIDGET)) {
+            return info.getWidget().getWidgetFeatures();
+        }
         switch (info.getContainerInfo().getContainerCase()) {
             case PREDICTED_HOTSEAT_CONTAINER:
                 return info.getContainerInfo().getPredictedHotseatContainer().getCardinality();
diff --git a/quickstep/src/com/android/quickstep/util/SwipePipToHomeAnimator.java b/quickstep/src/com/android/quickstep/util/SwipePipToHomeAnimator.java
index b5570a7..3631130 100644
--- a/quickstep/src/com/android/quickstep/util/SwipePipToHomeAnimator.java
+++ b/quickstep/src/com/android/quickstep/util/SwipePipToHomeAnimator.java
@@ -22,19 +22,24 @@
 import android.animation.RectEvaluator;
 import android.animation.ValueAnimator;
 import android.content.ComponentName;
+import android.graphics.Color;
 import android.graphics.Matrix;
 import android.graphics.Rect;
 import android.graphics.RectF;
 import android.util.Log;
 import android.view.Surface;
 import android.view.SurfaceControl;
+import android.view.SurfaceSession;
 import android.view.View;
 import android.window.PictureInPictureSurfaceTransaction;
 
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 
+import com.android.launcher3.Utilities;
 import com.android.launcher3.anim.AnimationSuccessListener;
+import com.android.launcher3.anim.Interpolators;
+import com.android.launcher3.util.Themes;
 import com.android.systemui.shared.pip.PipSurfaceTransactionHelper;
 import com.android.systemui.shared.system.InteractionJankMonitorWrapper;
 
@@ -79,6 +84,12 @@
     private boolean mHasAnimationEnded;
 
     /**
+     * An overlay used to mask changes in content when entering PiP for apps that aren't seamless.
+     */
+    @Nullable
+    private SurfaceControl mContentOverlay;
+
+    /**
      * @param taskId Task id associated with this animator, see also {@link #getTaskId()}
      * @param componentName Component associated with this animator,
      *                      see also {@link #getComponentName()}
@@ -112,6 +123,33 @@
 
         if (sourceRectHint == null) {
             mSourceHintRectInsets = null;
+
+            // Create a new overlay layer
+            SurfaceSession session = new SurfaceSession();
+            mContentOverlay = new SurfaceControl.Builder(session)
+                    .setCallsite("SwipePipToHomeAnimator")
+                    .setName("PipContentOverlay")
+                    .setColorLayer()
+                    .build();
+            SurfaceControl.Transaction t = new SurfaceControl.Transaction();
+            t.show(mContentOverlay);
+            t.setLayer(mContentOverlay, Integer.MAX_VALUE);
+            int color = Themes.getColorBackground(view.getContext());
+            float[] bgColor = new float[] {Color.red(color) / 255f, Color.green(color) / 255f,
+                    Color.blue(color) / 255f};
+            t.setColor(mContentOverlay, bgColor);
+            t.setAlpha(mContentOverlay, 0f);
+            t.reparent(mContentOverlay, mLeash);
+            t.apply();
+
+            addUpdateListener(valueAnimator -> {
+                float alpha = valueAnimator.getAnimatedFraction() < 0.5f
+                        ? 0
+                        : Utilities.mapToRange(valueAnimator.getAnimatedFraction(), 0.5f, 1f,
+                                0f, 1f, Interpolators.FAST_OUT_SLOW_IN);
+                t.setAlpha(mContentOverlay, alpha);
+                t.apply();
+            });
         } else {
             mSourceHintRectInsets = new Rect(sourceRectHint.left - appBounds.left,
                     sourceRectHint.top - appBounds.top,
@@ -234,6 +272,11 @@
         return mDestinationBounds;
     }
 
+    @Nullable
+    public SurfaceControl getContentOverlay() {
+        return mContentOverlay;
+    }
+
     /** @return {@link PictureInPictureSurfaceTransaction} for the final leash transaction. */
     public PictureInPictureSurfaceTransaction getFinishTransaction() {
         // get the final leash operations but do not apply to the leash.
diff --git a/quickstep/src/com/android/quickstep/views/TaskThumbnailView.java b/quickstep/src/com/android/quickstep/views/TaskThumbnailView.java
index 5b8d4ce..02888a1 100644
--- a/quickstep/src/com/android/quickstep/views/TaskThumbnailView.java
+++ b/quickstep/src/com/android/quickstep/views/TaskThumbnailView.java
@@ -335,16 +335,13 @@
     public void setOverlayEnabled(boolean overlayEnabled) {
         if (mOverlayEnabled != overlayEnabled) {
             mOverlayEnabled = overlayEnabled;
-            updateOverlay();
-        }
-    }
 
-    private void updateOverlay() {
-        if (mOverlayEnabled) {
-            getTaskOverlay().initOverlay(mTask, mThumbnailData, mPreviewPositionHelper.mMatrix,
-                    mPreviewPositionHelper.mIsOrientationChanged);
-        } else {
-            getTaskOverlay().reset();
+            if (mOverlayEnabled) {
+                getTaskOverlay().initOverlay(mTask, mThumbnailData, mPreviewPositionHelper.mMatrix,
+                        mPreviewPositionHelper.mIsOrientationChanged);
+            } else {
+                getTaskOverlay().reset();
+            }
         }
     }
 
@@ -379,10 +376,6 @@
         }
         getTaskView().updateCurrentFullscreenParams(mPreviewPositionHelper);
         invalidate();
-
-        // Update can be called from {@link #onSizeChanged} during layout, post handling of overlay
-        // as overlay could modify the views in the overlay as a side effect of its update.
-        post(this::updateOverlay);
     }
 
     @Override
diff --git a/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java b/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java
index cabbe93..a5038a1 100644
--- a/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java
+++ b/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java
@@ -17,14 +17,13 @@
 package com.android.quickstep;
 
 import static com.android.launcher3.ui.TaplTestsLauncher3.getAppPackageName;
-import static com.android.launcher3.util.rule.TestStabilityRule.LOCAL;
-import static com.android.launcher3.util.rule.TestStabilityRule.UNBUNDLED_POSTSUBMIT;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertTrue;
 
 import android.content.Intent;
+import android.util.Log;
 
 import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
@@ -38,8 +37,8 @@
 import com.android.launcher3.tapl.Overview;
 import com.android.launcher3.tapl.OverviewActions;
 import com.android.launcher3.tapl.OverviewTask;
+import com.android.launcher3.testing.TestProtocol;
 import com.android.launcher3.ui.TaplTestsLauncher3;
-import com.android.launcher3.util.rule.TestStabilityRule.Stability;
 import com.android.quickstep.NavigationModeSwitchRule.NavigationModeSwitch;
 import com.android.quickstep.views.RecentsView;
 
@@ -95,7 +94,6 @@
 
     @Test
     @PortraitLandscape
-    @Stability(flavors = LOCAL | UNBUNDLED_POSTSUBMIT) // b/187899876
     public void testOverview() throws Exception {
         startTestAppsWithCheck();
         // mLauncher.pressHome() also tests an important case of pressing home while in background.
@@ -165,7 +163,6 @@
     @Test
     @NavigationModeSwitch
     @PortraitLandscape
-    @Stability(flavors = LOCAL | UNBUNDLED_POSTSUBMIT) // b/187899876
     public void testOverviewActions() throws Exception {
         // Experimenting for b/165029151:
         final Overview overview = mLauncher.pressHome().switchToOverview();
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index 7b67807..16ffd7a 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -1307,8 +1307,15 @@
             appWidgetInfo = mAppWidgetManager.getLauncherAppWidgetInfo(appWidgetId);
         }
 
+        if (hostView == null) {
+            // Perform actual inflation because we're live
+            hostView = mAppWidgetHost.createView(this, appWidgetId, appWidgetInfo);
+        }
+
         LauncherAppWidgetInfo launcherInfo;
-        launcherInfo = new LauncherAppWidgetInfo(appWidgetId, appWidgetInfo.provider);
+        launcherInfo =
+                new LauncherAppWidgetInfo(
+                        appWidgetId, appWidgetInfo.provider, appWidgetInfo, hostView);
         launcherInfo.spanX = itemInfo.spanX;
         launcherInfo.spanY = itemInfo.spanY;
         launcherInfo.minSpanX = itemInfo.minSpanX;
@@ -1318,10 +1325,6 @@
         getModelWriter().addItemToDatabase(launcherInfo,
                 itemInfo.container, itemInfo.screenId, itemInfo.cellX, itemInfo.cellY);
 
-        if (hostView == null) {
-            // Perform actual inflation because we're live
-            hostView = mAppWidgetHost.createView(this, appWidgetId, appWidgetInfo);
-        }
         hostView.setVisibility(View.VISIBLE);
         prepareAppWidget(hostView, launcherInfo);
         mWorkspace.addInScreen(hostView, launcherInfo);
diff --git a/src/com/android/launcher3/anim/AnimatorListeners.java b/src/com/android/launcher3/anim/AnimatorListeners.java
index 57c2f8d..d9046b9 100644
--- a/src/com/android/launcher3/anim/AnimatorListeners.java
+++ b/src/com/android/launcher3/anim/AnimatorListeners.java
@@ -50,7 +50,7 @@
     public static AnimatorListener forEndCallback(Runnable callback) {
         return new AnimatorListenerAdapter() {
             @Override
-            public void onAnimationEnd(Animator animation, boolean isReverse) {
+            public void onAnimationEnd(Animator animation) {
                 callback.run();
             }
         };
diff --git a/src/com/android/launcher3/model/data/LauncherAppWidgetInfo.java b/src/com/android/launcher3/model/data/LauncherAppWidgetInfo.java
index c04b7f0..003b3bd 100644
--- a/src/com/android/launcher3/model/data/LauncherAppWidgetInfo.java
+++ b/src/com/android/launcher3/model/data/LauncherAppWidgetInfo.java
@@ -16,9 +16,12 @@
 
 package com.android.launcher3.model.data;
 
+import static com.android.launcher3.Utilities.ATLEAST_S;
+
 import android.appwidget.AppWidgetHostView;
 import android.content.ComponentName;
 import android.content.Intent;
+import android.content.res.Resources;
 import android.os.Process;
 
 import androidx.annotation.Nullable;
@@ -26,7 +29,10 @@
 import com.android.launcher3.AppWidgetResizeFrame;
 import com.android.launcher3.Launcher;
 import com.android.launcher3.LauncherSettings;
+import com.android.launcher3.logger.LauncherAtom;
 import com.android.launcher3.util.ContentWriter;
+import com.android.launcher3.widget.LauncherAppWidgetHostView;
+import com.android.launcher3.widget.LauncherAppWidgetProviderInfo;
 
 /**
  * Represents a widget (either instantiated or about to be) in the Launcher.
@@ -81,6 +87,18 @@
     public static final int CUSTOM_WIDGET_ID = -100;
 
     /**
+     * Flags for recording all the features that a widget has enabled.
+     * @see widgetFeatures
+     */
+    public static final int FEATURE_RECONFIGURABLE = 1;
+    public static final int FEATURE_OPTIONAL_CONFIGURATION = 1 << 1;
+    public static final int FEATURE_PREVIEW_LAYOUT = 1 << 2;
+    public static final int FEATURE_TARGET_CELL_SIZE = 1 << 3;
+    public static final int FEATURE_MIN_SIZE = 1 << 4;
+    public static final int FEATURE_MAX_SIZE = 1 << 5;
+    public static final int FEATURE_ROUNDED_CORNERS = 1 << 6;
+
+    /**
      * Identifier for this widget when talking with
      * {@link android.appwidget.AppWidgetManager} for updates.
      */
@@ -113,6 +131,12 @@
      */
     public PackageItemInfo pendingItemInfo;
 
+    /**
+     * Contains a binary representation indicating which widget features are enabled. This value is
+     * -1 if widget features could not be identified.
+     */
+    private int widgetFeatures;
+
     private boolean mHasNotifiedInitialWidgetSizeChanged;
 
     public LauncherAppWidgetInfo(int appWidgetId, ComponentName providerName) {
@@ -129,11 +153,18 @@
         // to indicate that they should be calculated based on the layout and minWidth/minHeight
         spanX = -1;
         spanY = -1;
+        widgetFeatures = -1;
         // We only support app widgets on current user.
         user = Process.myUserHandle();
         restoreStatus = RESTORE_COMPLETED;
     }
 
+    public LauncherAppWidgetInfo(int appWidgetId, ComponentName providerName,
+            LauncherAppWidgetProviderInfo providerInfo, AppWidgetHostView hostView) {
+        this(appWidgetId, providerName);
+        widgetFeatures = computeWidgetFeatures(providerInfo, hostView);
+    }
+
     /** Used for testing **/
     public LauncherAppWidgetInfo() {
         itemType = LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET;
@@ -194,4 +225,41 @@
     public final boolean hasOptionFlag(int option) {
         return (options & option) != 0;
     }
+
+    @SuppressWarnings("NewApi")
+    private static int computeWidgetFeatures(
+            LauncherAppWidgetProviderInfo providerInfo, AppWidgetHostView hostView) {
+        int widgetFeatures = 0;
+        if (providerInfo.isReconfigurable()) {
+            widgetFeatures |= FEATURE_RECONFIGURABLE;
+        }
+        if (providerInfo.isConfigurationOptional()) {
+            widgetFeatures |= FEATURE_OPTIONAL_CONFIGURATION;
+        }
+        if (ATLEAST_S && providerInfo.previewLayout != Resources.ID_NULL) {
+            widgetFeatures |= FEATURE_PREVIEW_LAYOUT;
+        }
+        if (ATLEAST_S && providerInfo.targetCellWidth > 0 || providerInfo.targetCellHeight > 0) {
+            widgetFeatures |= FEATURE_TARGET_CELL_SIZE;
+        }
+        if (providerInfo.minResizeWidth > 0 || providerInfo.minResizeHeight > 0) {
+            widgetFeatures |= FEATURE_MIN_SIZE;
+        }
+        if (ATLEAST_S && providerInfo.maxResizeWidth > 0 || providerInfo.maxResizeHeight > 0) {
+            widgetFeatures |= FEATURE_MAX_SIZE;
+        }
+        if (hostView instanceof LauncherAppWidgetHostView &&
+                ((LauncherAppWidgetHostView) hostView).hasEnforcedCornerRadius()) {
+            widgetFeatures |= FEATURE_ROUNDED_CORNERS;
+        }
+        return widgetFeatures;
+    }
+
+    @Override
+    public LauncherAtom.ItemInfo buildProto(FolderInfo folderInfo) {
+        LauncherAtom.ItemInfo info = super.buildProto(folderInfo);
+        return info.toBuilder()
+                .setWidget(info.getWidget().toBuilder().setWidgetFeatures(widgetFeatures))
+                .build();
+    }
 }
diff --git a/src/com/android/launcher3/util/Themes.java b/src/com/android/launcher3/util/Themes.java
index 06cac08..8243dd4 100644
--- a/src/com/android/launcher3/util/Themes.java
+++ b/src/com/android/launcher3/util/Themes.java
@@ -92,7 +92,7 @@
         return getAttrColor(context, android.R.attr.colorAccent);
     }
 
-    /** Returns the floating background color attribute. */
+    /** Returns the background color attribute. */
     public static int getColorBackground(Context context) {
         return getAttrColor(context, android.R.attr.colorBackground);
     }
diff --git a/src/com/android/launcher3/widget/LauncherAppWidgetProviderInfo.java b/src/com/android/launcher3/widget/LauncherAppWidgetProviderInfo.java
index de511cd..53b5fec 100644
--- a/src/com/android/launcher3/widget/LauncherAppWidgetProviderInfo.java
+++ b/src/com/android/launcher3/widget/LauncherAppWidgetProviderInfo.java
@@ -149,6 +149,12 @@
         return configure != null && (getWidgetFeatures() & WIDGET_FEATURE_RECONFIGURABLE) != 0;
     }
 
+    public boolean isConfigurationOptional() {
+        return ATLEAST_S
+                && isReconfigurable()
+                && (getWidgetFeatures() & WIDGET_FEATURE_CONFIGURATION_OPTIONAL) != 0;
+    }
+
     @Override
     public final ComponentName getComponent() {
         return provider;