From 9f06168692271d808ff0358a6fc8e8135e6eecd5 Mon Sep 17 00:00:00 2001 From: Cyrus Boadway Date: Mon, 7 Jun 2021 20:56:37 +0000 Subject: [PATCH 1/3] Use the splash screen background color as the fallback background color For the widget transition animation fallback background color, use either the splash screen background color if a task is starting or the task description-attached background color. With a background in place, allow the window to fully fade out before fading in the widget, by moving the window alpha math into an animation factory-specific implementation. Bug: 187706750 Test: Manual Change-Id: I2b5a7783b0585d447ad60534bc48d2e2176877ed --- .../launcher3/QuickstepTransitionManager.java | 48 +++++++++++-------- .../android/quickstep/AbsSwipeUpHandler.java | 5 +- .../quickstep/FallbackSwipeHandler.java | 3 +- .../quickstep/LauncherSwipeHandlerV2.java | 37 ++++++++++---- .../quickstep/RemoteAnimationTargets.java | 11 +++++ .../quickstep/SwipeUpAnimationLogic.java | 38 +++++++-------- .../views/FloatingWidgetBackgroundView.java | 6 +-- .../quickstep/views/FloatingWidgetView.java | 23 +++++++-- src/com/android/launcher3/Utilities.java | 7 +++ 9 files changed, 118 insertions(+), 60 deletions(-) diff --git a/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java b/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java index 36322ce439..26d407fb96 100644 --- a/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java +++ b/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java @@ -214,8 +214,9 @@ public class QuickstepTransitionManager implements OnDeviceProfileChangeListener } }; + // Pairs of window starting type and starting window background color for starting tasks // Will never be larger than MAX_NUM_TASKS - private LinkedHashMap mTypeForTaskId; + private LinkedHashMap> mTaskStartParams; public QuickstepTransitionManager(Context context) { mLauncher = Launcher.cast(Launcher.getLauncher(context)); @@ -232,9 +233,9 @@ public class QuickstepTransitionManager implements OnDeviceProfileChangeListener mLauncher.addOnDeviceProfileChangeListener(this); if (supportsSSplashScreen()) { - mTypeForTaskId = new LinkedHashMap(MAX_NUM_TASKS) { + mTaskStartParams = new LinkedHashMap>(MAX_NUM_TASKS) { @Override - protected boolean removeEldestEntry(Entry entry) { + protected boolean removeEldestEntry(Entry> entry) { return size() > MAX_NUM_TASKS; } }; @@ -420,15 +421,6 @@ public class QuickstepTransitionManager implements OnDeviceProfileChangeListener return bounds; } - private int getOpeningTaskId(RemoteAnimationTargetCompat[] appTargets) { - for (RemoteAnimationTargetCompat target : appTargets) { - if (target.mode == MODE_OPENING) { - return target.taskId; - } - } - return -1; - } - public void setRemoteAnimationProvider(final RemoteAnimationProvider animationProvider, CancellationSignal cancellationSignal) { mRemoteAnimationProvider = animationProvider; @@ -595,10 +587,12 @@ public class QuickstepTransitionManager implements OnDeviceProfileChangeListener final boolean hasSplashScreen; if (supportsSSplashScreen()) { - int taskId = getOpeningTaskId(appTargets); - int type = mTypeForTaskId.getOrDefault(taskId, STARTING_WINDOW_TYPE_NONE); - mTypeForTaskId.remove(taskId); - hasSplashScreen = type == STARTING_WINDOW_TYPE_SPLASH_SCREEN; + int taskId = openingTargets.getFirstAppTargetTaskId(); + Pair defaultParams = Pair.create(STARTING_WINDOW_TYPE_NONE, 0); + Pair taskParams = + mTaskStartParams.getOrDefault(taskId, defaultParams); + mTaskStartParams.remove(taskId); + hasSplashScreen = taskParams.first == STARTING_WINDOW_TYPE_SPLASH_SCREEN; } else { hasSplashScreen = false; } @@ -799,18 +793,30 @@ public class QuickstepTransitionManager implements OnDeviceProfileChangeListener final RectF widgetBackgroundBounds = new RectF(); final Rect appWindowCrop = new Rect(); final Matrix matrix = new Matrix(); + RemoteAnimationTargets openingTargets = new RemoteAnimationTargets(appTargets, + wallpaperTargets, nonAppTargets, MODE_OPENING); + + RemoteAnimationTargetCompat openingTarget = openingTargets.getFirstAppTarget(); + int fallbackBackgroundColor = 0; + if (openingTarget != null && supportsSSplashScreen()) { + fallbackBackgroundColor = mTaskStartParams.containsKey(openingTarget.taskId) + ? mTaskStartParams.get(openingTarget.taskId).second : 0; + mTaskStartParams.remove(openingTarget.taskId); + } + if (fallbackBackgroundColor == 0) { + fallbackBackgroundColor = + FloatingWidgetView.getDefaultBackgroundColor(mLauncher, openingTarget); + } final float finalWindowRadius = mDeviceProfile.isMultiWindowMode ? 0 : getWindowCornerRadius(mLauncher.getResources()); final FloatingWidgetView floatingView = FloatingWidgetView.getFloatingWidgetView(mLauncher, v, widgetBackgroundBounds, new Size(windowTargetBounds.width(), windowTargetBounds.height()), - finalWindowRadius, appTargetsAreTranslucent); + finalWindowRadius, appTargetsAreTranslucent, fallbackBackgroundColor); final float initialWindowRadius = supportsRoundedCornersOnWindows(mLauncher.getResources()) ? floatingView.getInitialCornerRadius() : 0; - RemoteAnimationTargets openingTargets = new RemoteAnimationTargets(appTargets, - wallpaperTargets, nonAppTargets, MODE_OPENING); SurfaceTransactionApplier surfaceApplier = new SurfaceTransactionApplier(floatingView); openingTargets.addReleaseCheck(surfaceApplier); @@ -1434,8 +1440,8 @@ public class QuickstepTransitionManager implements OnDeviceProfileChangeListener } @Override - public void onTaskLaunching(int taskId, int supportedType) { - mTransitionManager.mTypeForTaskId.put(taskId, supportedType); + public void onTaskLaunching(int taskId, int supportedType, int color) { + mTransitionManager.mTaskStartParams.put(taskId, Pair.create(supportedType, color)); } } } diff --git a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java index 88db2741ab..52f34d90e0 100644 --- a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java +++ b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java @@ -1071,7 +1071,8 @@ public abstract class AbsSwipeUpHandler, } protected abstract HomeAnimationFactory createHomeAnimationFactory( - ArrayList launchCookies, long duration, boolean isTargetTranslucent); + ArrayList launchCookies, long duration, boolean isTargetTranslucent, + RemoteAnimationTargetCompat runningTaskTarget); private final TaskStackChangeListener mActivityRestartListener = new TaskStackChangeListener() { @Override @@ -1117,7 +1118,7 @@ public abstract class AbsSwipeUpHandler, : new ArrayList<>(); boolean isTranslucent = runningTaskTarget != null && runningTaskTarget.isTranslucent; HomeAnimationFactory homeAnimFactory = - createHomeAnimationFactory(cookies, duration, isTranslucent); + createHomeAnimationFactory(cookies, duration, isTranslucent, runningTaskTarget); mIsSwipingPipToHome = homeAnimFactory.supportSwipePipToHome() && runningTaskTarget != null && runningTaskTarget.taskInfo.pictureInPictureParams != null diff --git a/quickstep/src/com/android/quickstep/FallbackSwipeHandler.java b/quickstep/src/com/android/quickstep/FallbackSwipeHandler.java index 2d81429a94..7290ff6a41 100644 --- a/quickstep/src/com/android/quickstep/FallbackSwipeHandler.java +++ b/quickstep/src/com/android/quickstep/FallbackSwipeHandler.java @@ -129,7 +129,8 @@ public class FallbackSwipeHandler extends @Override protected HomeAnimationFactory createHomeAnimationFactory(ArrayList launchCookies, - long duration, boolean isTargetTranslucent) { + long duration, boolean isTargetTranslucent, + RemoteAnimationTargetCompat runningTaskTarget) { mActiveAnimationFactory = new FallbackHomeAnimationFactory(duration); ActivityOptions options = ActivityOptions.makeCustomAnimation(mContext, 0, 0); Intent intent = new Intent(mGestureState.getHomeIntent()); diff --git a/quickstep/src/com/android/quickstep/LauncherSwipeHandlerV2.java b/quickstep/src/com/android/quickstep/LauncherSwipeHandlerV2.java index 1bae1c5f6b..40741e4945 100644 --- a/quickstep/src/com/android/quickstep/LauncherSwipeHandlerV2.java +++ b/quickstep/src/com/android/quickstep/LauncherSwipeHandlerV2.java @@ -20,6 +20,9 @@ import static com.android.launcher3.LauncherAnimUtils.VIEW_TRANSLATE_Y; import static com.android.launcher3.LauncherState.NORMAL; import static com.android.launcher3.Utilities.boundToRange; import static com.android.launcher3.Utilities.dpToPx; +import static com.android.launcher3.Utilities.mapBoundToRange; +import static com.android.launcher3.anim.Interpolators.EXAGGERATED_EASE; +import static com.android.launcher3.anim.Interpolators.LINEAR; import static com.android.launcher3.config.FeatureFlags.PROTOTYPE_APP_CLOSE; import static com.android.launcher3.model.data.ItemInfo.NO_MATCHING_ID; import static com.android.launcher3.views.FloatingIconView.SHAPE_PROGRESS_DURATION; @@ -65,6 +68,7 @@ import com.android.quickstep.views.RecentsView; import com.android.quickstep.views.TaskView; import com.android.systemui.plugins.ResourceProvider; import com.android.systemui.shared.system.InputConsumerController; +import com.android.systemui.shared.system.RemoteAnimationTargetCompat; import java.util.ArrayList; @@ -84,7 +88,8 @@ public class LauncherSwipeHandlerV2 extends @Override protected HomeAnimationFactory createHomeAnimationFactory(ArrayList launchCookies, - long duration, boolean isTargetTranslucent) { + long duration, boolean isTargetTranslucent, + RemoteAnimationTargetCompat runningTaskTarget) { if (mActivity == null) { mStateCallback.addChangeListener(STATE_LAUNCHER_PRESENT | STATE_HANDLER_INVALIDATED, isPresent -> mRecentsView.startHome()); @@ -108,7 +113,7 @@ public class LauncherSwipeHandlerV2 extends } if (workspaceView instanceof LauncherAppWidgetHostView) { return createWidgetHomeAnimationFactory((LauncherAppWidgetHostView) workspaceView, - isTargetTranslucent); + isTargetTranslucent, runningTaskTarget); } return createIconHomeAnimationFactory(workspaceView); } @@ -169,15 +174,19 @@ public class LauncherSwipeHandlerV2 extends } private HomeAnimationFactory createWidgetHomeAnimationFactory( - LauncherAppWidgetHostView hostView, boolean isTargetTranslucent) { - + LauncherAppWidgetHostView hostView, boolean isTargetTranslucent, + RemoteAnimationTargetCompat runningTaskTarget) { + final float floatingWidgetAlpha = isTargetTranslucent ? 0 : 1; RectF backgroundLocation = new RectF(); Rect crop = new Rect(); mTaskViewSimulator.getCurrentCropRect().roundOut(crop); Size windowSize = new Size(crop.width(), crop.height()); + int fallbackBackgroundColor = + FloatingWidgetView.getDefaultBackgroundColor(mContext, runningTaskTarget); FloatingWidgetView floatingWidgetView = FloatingWidgetView.getFloatingWidgetView(mActivity, hostView, backgroundLocation, windowSize, - mTaskViewSimulator.getCurrentCornerRadius(), isTargetTranslucent); + mTaskViewSimulator.getCurrentCornerRadius(), isTargetTranslucent, + fallbackBackgroundColor); return new FloatingViewHomeAnimationFactory(floatingWidgetView) { @@ -207,12 +216,20 @@ public class LauncherSwipeHandlerV2 extends } @Override - public void update(@Nullable AppCloseConfig config, RectF currentRect, - float progress, float radius) { + public void update(@Nullable AppCloseConfig config, RectF currentRect, float progress, + float radius) { super.update(config, currentRect, progress, radius); - floatingWidgetView.update(currentRect, 1 /* floatingWidgetAlpha */, - config != null ? config.getFgAlpha() : 1f /* foregroundAlpha */, - 0 /* fallbackBackgroundAlpha */, 1 - progress); + final float fallbackBackgroundAlpha = + 1 - mapBoundToRange(progress, 0.8f, 1, 0, 1, EXAGGERATED_EASE); + final float foregroundAlpha = + mapBoundToRange(progress, 0.5f, 1, 0, 1, EXAGGERATED_EASE); + floatingWidgetView.update(currentRect, floatingWidgetAlpha, foregroundAlpha, + fallbackBackgroundAlpha, 1 - progress); + } + + @Override + protected float getWindowAlpha(float progress) { + return 1 - mapBoundToRange(progress, 0, 0.5f, 0, 1, LINEAR); } }; } diff --git a/quickstep/src/com/android/quickstep/RemoteAnimationTargets.java b/quickstep/src/com/android/quickstep/RemoteAnimationTargets.java index edc3ab22f3..c032889db5 100644 --- a/quickstep/src/com/android/quickstep/RemoteAnimationTargets.java +++ b/quickstep/src/com/android/quickstep/RemoteAnimationTargets.java @@ -85,6 +85,17 @@ public class RemoteAnimationTargets { return null; } + /** Returns the first opening app target. */ + public RemoteAnimationTargetCompat getFirstAppTarget() { + return apps.length > 0 ? apps[0] : null; + } + + /** Returns the task id of the first opening app target, or -1 if none is found. */ + public int getFirstAppTargetTaskId() { + RemoteAnimationTargetCompat target = getFirstAppTarget(); + return target == null ? -1 : target.taskId; + } + public boolean isAnimatingHome() { for (RemoteAnimationTargetCompat target : unfilteredApps) { if (target.activityType == RemoteAnimationTargetCompat.ACTIVITY_TYPE_HOME) { diff --git a/quickstep/src/com/android/quickstep/SwipeUpAnimationLogic.java b/quickstep/src/com/android/quickstep/SwipeUpAnimationLogic.java index b79e9344bf..44954555b0 100644 --- a/quickstep/src/com/android/quickstep/SwipeUpAnimationLogic.java +++ b/quickstep/src/com/android/quickstep/SwipeUpAnimationLogic.java @@ -181,6 +181,24 @@ public abstract class SwipeUpAnimationLogic { public boolean supportSwipePipToHome() { return false; } + + /** + * @param progress The progress of the animation to the home screen. + * @return The current alpha to set on the animating app window. + */ + protected float getWindowAlpha(float progress) { + // Alpha interpolates between [1, 0] between progress values [start, end] + final float start = 0f; + final float end = 0.85f; + + if (progress <= start) { + return 1f; + } + if (progress >= end) { + return 0f; + } + return Utilities.mapToRange(progress, start, end, 1, 0, ACCEL_1_5); + } } /** @@ -236,24 +254,6 @@ public abstract class SwipeUpAnimationLogic { return anim; } - /** - * @param progress The progress of the animation to the home screen. - * @return The current alpha to set on the animating app window. - */ - protected float getWindowAlpha(float progress) { - // Alpha interpolates between [1, 0] between progress values [start, end] - final float start = 0f; - final float end = 0.85f; - - if (progress <= start) { - return 1f; - } - if (progress >= end) { - return 0f; - } - return Utilities.mapToRange(progress, start, end, 1, 0, ACCEL_1_5); - } - protected class SpringAnimationRunner extends AnimationSuccessListener implements RectFSpringAnim.OnUpdateListener, BuilderProxy { @@ -292,7 +292,7 @@ public abstract class SwipeUpAnimationLogic { mMatrix.setRectToRect(mCropRectF, mWindowCurrentRect, ScaleToFit.FILL); float cornerRadius = Utilities.mapRange(progress, mStartRadius, mEndRadius); - float alpha = getWindowAlpha(progress); + float alpha = mAnimationFactory.getWindowAlpha(progress); if (config != null && PROTOTYPE_APP_CLOSE.get()) { alpha = config.getWindowAlpha(); cornerRadius = config.getCornerRadius(); diff --git a/quickstep/src/com/android/quickstep/views/FloatingWidgetBackgroundView.java b/quickstep/src/com/android/quickstep/views/FloatingWidgetBackgroundView.java index 9ea2369836..65dba338f8 100644 --- a/quickstep/src/com/android/quickstep/views/FloatingWidgetBackgroundView.java +++ b/quickstep/src/com/android/quickstep/views/FloatingWidgetBackgroundView.java @@ -27,7 +27,6 @@ import android.view.View; import android.view.ViewOutlineProvider; import android.widget.RemoteViews.RemoteViewOutlineProvider; -import com.android.launcher3.util.Themes; import com.android.launcher3.widget.LauncherAppWidgetHostView; import com.android.launcher3.widget.RoundedCornerEnforcement; @@ -62,7 +61,8 @@ final class FloatingWidgetBackgroundView extends View { setClipToOutline(true); } - void init(LauncherAppWidgetHostView hostView, View backgroundView, float finalRadius) { + void init(LauncherAppWidgetHostView hostView, View backgroundView, float finalRadius, + int fallbackBackgroundColor) { mFinalRadius = finalRadius; mSourceView = backgroundView; mInitialOutlineRadius = getOutlineRadius(hostView, backgroundView); @@ -81,7 +81,7 @@ final class FloatingWidgetBackgroundView extends View { setBackground(mBackgroundProperties.mDrawable); mSourceView.setBackground(null); } else if (mOriginalForeground == null) { - mFallbackDrawable.setColor(Themes.getColorBackground(backgroundView.getContext())); + mFallbackDrawable.setColor(fallbackBackgroundColor); setBackground(mFallbackDrawable); mIsUsingFallback = true; } diff --git a/quickstep/src/com/android/quickstep/views/FloatingWidgetView.java b/quickstep/src/com/android/quickstep/views/FloatingWidgetView.java index 0012dd805d..22ce9421f7 100644 --- a/quickstep/src/com/android/quickstep/views/FloatingWidgetView.java +++ b/quickstep/src/com/android/quickstep/views/FloatingWidgetView.java @@ -34,10 +34,12 @@ import com.android.launcher3.Launcher; import com.android.launcher3.R; import com.android.launcher3.Utilities; import com.android.launcher3.dragndrop.DragLayer; +import com.android.launcher3.util.Themes; import com.android.launcher3.views.FloatingView; import com.android.launcher3.views.ListenerView; import com.android.launcher3.widget.LauncherAppWidgetHostView; import com.android.launcher3.widget.RoundedCornerEnforcement; +import com.android.systemui.shared.system.RemoteAnimationTargetCompat; /** A view that mimics an App Widget through a launch animation. */ @TargetApi(Build.VERSION_CODES.S) @@ -148,7 +150,7 @@ public class FloatingWidgetView extends FrameLayout implements AnimatorListener, private void init(DragLayer dragLayer, LauncherAppWidgetHostView originalView, RectF widgetBackgroundPosition, Size windowSize, float windowCornerRadius, - boolean appTargetIsTranslucent) { + boolean appTargetIsTranslucent, int fallbackBackgroundColor) { mAppWidgetView = originalView; mAppWidgetView.beginDeferringUpdates(); mBackgroundPosition = widgetBackgroundPosition; @@ -163,7 +165,8 @@ public class FloatingWidgetView extends FrameLayout implements AnimatorListener, getRelativePosition(mAppWidgetBackgroundView, dragLayer, mBackgroundPosition); getRelativePosition(mAppWidgetBackgroundView, mAppWidgetView, mBackgroundOffset); if (!mAppTargetIsTranslucent) { - mBackgroundView.init(mAppWidgetView, mAppWidgetBackgroundView, windowCornerRadius); + mBackgroundView.init(mAppWidgetView, mAppWidgetBackgroundView, windowCornerRadius, + fallbackBackgroundColor); // Layout call before GhostView creation so that the overlaid view isn't clipped layout(0, 0, windowSize.getWidth(), windowSize.getHeight()); mForegroundOverlayView = GhostView.addGhost(mAppWidgetView, this); @@ -274,7 +277,8 @@ public class FloatingWidgetView extends FrameLayout implements AnimatorListener, */ public static FloatingWidgetView getFloatingWidgetView(Launcher launcher, LauncherAppWidgetHostView originalView, RectF widgetBackgroundPosition, - Size windowSize, float windowCornerRadius, boolean appTargetsAreTranslucent) { + Size windowSize, float windowCornerRadius, boolean appTargetsAreTranslucent, + int fallbackBackgroundColor) { final DragLayer dragLayer = launcher.getDragLayer(); ViewGroup parent = (ViewGroup) dragLayer.getParent(); FloatingWidgetView floatingView = @@ -282,11 +286,22 @@ public class FloatingWidgetView extends FrameLayout implements AnimatorListener, floatingView.recycle(); floatingView.init(dragLayer, originalView, widgetBackgroundPosition, windowSize, - windowCornerRadius, appTargetsAreTranslucent); + windowCornerRadius, appTargetsAreTranslucent, fallbackBackgroundColor); parent.addView(floatingView); return floatingView; } + /** + * Extract a background color from a target's task description, or fall back to the given + * context's theme background color. + */ + public static int getDefaultBackgroundColor( + Context context, RemoteAnimationTargetCompat target) { + return (target != null && target.taskInfo.taskDescription != null) + ? target.taskInfo.taskDescription.getBackgroundColor() + : Themes.getColorBackground(context); + } + private static void getRelativePosition(View descendant, View ancestor, RectF position) { float[] points = new float[]{0, 0, descendant.getWidth(), descendant.getHeight()}; Utilities.getDescendantCoordRelativeToAncestor(descendant, ancestor, points, diff --git a/src/com/android/launcher3/Utilities.java b/src/com/android/launcher3/Utilities.java index cb9e1f3a5c..a2d86bc7fa 100644 --- a/src/com/android/launcher3/Utilities.java +++ b/src/com/android/launcher3/Utilities.java @@ -397,6 +397,13 @@ public final class Utilities { return mapRange(interpolator.getInterpolation(progress), toMin, toMax); } + /** Bounds t between a lower and upper bound and maps the result to a range. */ + public static float mapBoundToRange(float t, float lowerBound, float upperBound, + float toMin, float toMax, Interpolator interpolator) { + return mapToRange(boundToRange(t, lowerBound, upperBound), lowerBound, upperBound, + toMin, toMax, interpolator); + } + public static float getProgress(float current, float min, float max) { return Math.abs(current - min) / Math.abs(max - min); } From 2668e731a0b79cf94b6962ec4c75a506e163c3d2 Mon Sep 17 00:00:00 2001 From: Cyrus Boadway Date: Tue, 18 May 2021 16:16:14 +0000 Subject: [PATCH 2/3] Add activity-start/return animation to widget configuration When launching the configuration activity for a widget, use the activity transition animation. Test: manual Bug: 190487998 Change-Id: Ife84e86eec74f81fecddce07c833356a7962fd4b --- .../widget/LauncherAppWidgetHost.java | 30 +++++++++++++++++-- 1 file changed, 27 insertions(+), 3 deletions(-) diff --git a/src/com/android/launcher3/widget/LauncherAppWidgetHost.java b/src/com/android/launcher3/widget/LauncherAppWidgetHost.java index d745754497..6dc69712dc 100644 --- a/src/com/android/launcher3/widget/LauncherAppWidgetHost.java +++ b/src/com/android/launcher3/widget/LauncherAppWidgetHost.java @@ -25,15 +25,20 @@ import android.appwidget.AppWidgetProviderInfo; import android.content.ActivityNotFoundException; import android.content.Context; import android.content.Intent; +import android.os.Bundle; import android.os.Handler; import android.util.SparseArray; import android.widget.Toast; +import androidx.annotation.Nullable; + import com.android.launcher3.BaseActivity; +import com.android.launcher3.BaseDraggingActivity; import com.android.launcher3.LauncherAppState; import com.android.launcher3.R; import com.android.launcher3.Utilities; import com.android.launcher3.model.WidgetsModel; +import com.android.launcher3.model.data.ItemInfo; import com.android.launcher3.testing.TestLogging; import com.android.launcher3.testing.TestProtocol; import com.android.launcher3.widget.custom.CustomWidgetManager; @@ -292,8 +297,13 @@ public class LauncherAppWidgetHost extends AppWidgetHost { activity.startActivityForResult(intent, requestCode); } - - public void startConfigActivity(BaseActivity activity, int widgetId, int requestCode) { + /** + * Launches an app widget's configuration activity. + * @param activity The activity from which to launch the configuration activity + * @param widgetId The id of the bound app widget to be configured + * @param requestCode An optional request code to be returned with the result + */ + public void startConfigActivity(BaseDraggingActivity activity, int widgetId, int requestCode) { if (WidgetsModel.GO_DISABLE_WIDGETS) { sendActionCancelled(activity, requestCode); return; @@ -301,13 +311,27 @@ public class LauncherAppWidgetHost extends AppWidgetHost { try { TestLogging.recordEvent(TestProtocol.SEQUENCE_MAIN, "start: startConfigActivity"); - startAppWidgetConfigureActivityForResult(activity, widgetId, 0, requestCode, null); + startAppWidgetConfigureActivityForResult(activity, widgetId, 0, requestCode, + getConfigurationActivityOptions(activity, widgetId)); } catch (ActivityNotFoundException | SecurityException e) { Toast.makeText(activity, R.string.activity_not_found, Toast.LENGTH_SHORT).show(); sendActionCancelled(activity, requestCode); } } + /** + * Returns an {@link android.app.ActivityOptions} bundle from the {code activity} for launching + * the configuration of the {@code widgetId} app widget, or null of options cannot be produced. + */ + @Nullable + private Bundle getConfigurationActivityOptions(BaseDraggingActivity activity, int widgetId) { + LauncherAppWidgetHostView view = mViews.get(widgetId); + if (view == null) return null; + Object tag = view.getTag(); + if (!(tag instanceof ItemInfo)) return null; + return activity.getActivityLaunchOptions(view, (ItemInfo) tag).toBundle(); + } + private void sendActionCancelled(final BaseActivity activity, final int requestCode) { new Handler().post(() -> activity.onActivityResult(requestCode, RESULT_CANCELED, null)); } From 77a1393c4484a78da20cc3943ed3221976e68a93 Mon Sep 17 00:00:00 2001 From: Steven Ng Date: Fri, 11 Jun 2021 20:17:02 +0100 Subject: [PATCH 3/3] Fix CellLayout cast exception when drag is canceled Test: Long press a widget and then release when the resize frame is shown. Then, click the content of the widget to launch the widget's activity. Go back to home screen and then immediately long press the same widget again. No crash was observed. Bug: 189814379 Change-Id: I4232ecf9d9d9efaba817b7777314f0814bb7ef21 --- src/com/android/launcher3/Workspace.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java index 17c8edce6e..2e1cc58aa0 100644 --- a/src/com/android/launcher3/Workspace.java +++ b/src/com/android/launcher3/Workspace.java @@ -1922,6 +1922,11 @@ public class Workspace extends PagedView CellLayout layout = (CellLayout) cell.getParent().getParent(); layout.markCellsAsOccupiedForView(cell); } + } else { + // When drag is cancelled, reattach content view back to its original parent. + if (mDragInfo.cell instanceof LauncherAppWidgetHostView) { + d.dragView.detachContentView(/* reattachToPreviousParent= */ true); + } } final CellLayout parent = (CellLayout) cell.getParent().getParent();