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;