[Toast] Introduce SysUI's animation library to the transition manager.
Bug: 250588519
Test: manual, see videos in bug
Change-Id: Iccc440c95ecc14d39e35d911798e239b698b950a
diff --git a/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java b/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
index 7948ca4..b880a7e 100644
--- a/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
+++ b/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
@@ -89,6 +89,7 @@
import android.util.Pair;
import android.util.Size;
import android.view.CrossWindowBlurListeners;
+import android.view.IRemoteAnimationFinishedCallback;
import android.view.RemoteAnimationAdapter;
import android.view.RemoteAnimationDefinition;
import android.view.RemoteAnimationTarget;
@@ -114,6 +115,7 @@
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.dragndrop.DragLayer;
import com.android.launcher3.icons.FastBitmapDrawable;
+import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.shortcuts.DeepShortcutView;
import com.android.launcher3.statehandlers.DepthController;
import com.android.launcher3.taskbar.LauncherTaskbarUIController;
@@ -143,6 +145,9 @@
import com.android.quickstep.util.WorkspaceRevealAnim;
import com.android.quickstep.views.FloatingWidgetView;
import com.android.quickstep.views.RecentsView;
+import com.android.systemui.animation.ActivityLaunchAnimator;
+import com.android.systemui.animation.DelegateLaunchAnimatorController;
+import com.android.systemui.animation.RemoteAnimationDelegate;
import com.android.systemui.shared.system.BlurUtils;
import com.android.systemui.shared.system.InteractionJankMonitorWrapper;
import com.android.systemui.shared.system.QuickStepContract;
@@ -222,7 +227,6 @@
private RemoteAnimationProvider mRemoteAnimationProvider;
// Strong refs to runners which are cleared when the launcher activity is destroyed
private RemoteAnimationFactory mWallpaperOpenRunner;
- private RemoteAnimationFactory mAppLaunchRunner;
private RemoteAnimationFactory mKeyguardGoingAwayRunner;
private RemoteAnimationFactory mWallpaperOpenTransitionRunner;
@@ -291,9 +295,18 @@
public ActivityOptionsWrapper getActivityLaunchOptions(View v) {
boolean fromRecents = isLaunchingFromRecents(v, null /* targets */);
RunnableList onEndCallback = new RunnableList();
- mAppLaunchRunner = new AppLaunchAnimationRunner(v, onEndCallback);
+
+ RemoteAnimationFactory delegateRunner = new AppLaunchAnimationRunner(v, onEndCallback);
+ ItemInfo tag = (ItemInfo) v.getTag();
+ if (tag != null && tag.shouldUseBackgroundAnimation()) {
+ ContainerAnimationRunner containerAnimationRunner =
+ ContainerAnimationRunner.from(v, mStartingWindowListener);
+ if (containerAnimationRunner != null) {
+ delegateRunner = containerAnimationRunner;
+ }
+ }
RemoteAnimationRunnerCompat runner = new LauncherAnimationRunner(
- mHandler, mAppLaunchRunner, true /* startAtFrontOfQueue */);
+ mHandler, delegateRunner, true /* startAtFrontOfQueue */);
// Note that this duration is a guess as we do not know if the animation will be a
// recents launch or not for sure until we know the opening app targets.
@@ -1160,7 +1173,6 @@
// Also clear strong references to the runners registered with the remote animation
// definition so we don't have to wait for the system gc
mWallpaperOpenRunner = null;
- mAppLaunchRunner = null;
mKeyguardGoingAwayRunner = null;
}
}
@@ -1754,6 +1766,79 @@
}
}
+ /** Remote animation runner to launch an app using System UI's animation library. */
+ private static class ContainerAnimationRunner implements RemoteAnimationFactory {
+
+ /** The delegate runner that handles the actual animation. */
+ private final RemoteAnimationDelegate<IRemoteAnimationFinishedCallback> mDelegate;
+
+ private ContainerAnimationRunner(
+ RemoteAnimationDelegate<IRemoteAnimationFinishedCallback> delegate) {
+ mDelegate = delegate;
+ }
+
+ @Nullable
+ private static ContainerAnimationRunner from(
+ View v, StartingWindowListener startingWindowListener) {
+ View viewToUse = findViewWithBackground(v);
+ if (viewToUse == null) {
+ viewToUse = v;
+ }
+
+ // TODO(b/265134143): create a CUJ type for interaction jank monitoring.
+ ActivityLaunchAnimator.Controller controllerDelegate =
+ ActivityLaunchAnimator.Controller.fromView(viewToUse, null /* cujType */);
+
+ if (controllerDelegate == null) {
+ return null;
+ }
+
+ // This wrapper allows us to override the default value, telling the controller that the
+ // current window is below the animating window.
+ ActivityLaunchAnimator.Controller controller =
+ new DelegateLaunchAnimatorController(controllerDelegate) {
+ @Override
+ public boolean isBelowAnimatingWindow() {
+ return true;
+ }
+ };
+
+ ActivityLaunchAnimator.Callback callback = task -> ColorUtils.setAlphaComponent(
+ startingWindowListener.getBackgroundColor(), 255);
+
+ return new ContainerAnimationRunner(
+ new ActivityLaunchAnimator.AnimationDelegate(controller, callback));
+ }
+
+ /** Finds the closest parent of [view] (inclusive) with a background drawable. */
+ @Nullable
+ private static View findViewWithBackground(View view) {
+ View current = view;
+ while (current.getBackground() == null) {
+ if (!(current.getParent() instanceof View)) {
+ return null;
+ }
+
+ current = (View) view.getParent();
+ }
+
+ return current;
+ }
+
+ @Override
+ public void onAnimationStart(int transit, RemoteAnimationTarget[] appTargets,
+ RemoteAnimationTarget[] wallpaperTargets, RemoteAnimationTarget[] nonAppTargets,
+ LauncherAnimationRunner.AnimationResult result) {
+ mDelegate.onAnimationStart(
+ transit, appTargets, wallpaperTargets, nonAppTargets, result);
+ }
+
+ @Override
+ public void onAnimationCancelled(boolean isKeyguardOccluded) {
+ mDelegate.onAnimationCancelled(isKeyguardOccluded);
+ }
+ }
+
/**
* Class that holds all the variables for the app open animation.
*/
@@ -1822,8 +1907,9 @@
}
}
- private static class StartingWindowListener extends IStartingWindowListener.Stub {
+ private class StartingWindowListener extends IStartingWindowListener.Stub {
private QuickstepTransitionManager mTransitionManager;
+ private int mBackgroundColor;
public void setTransitionManager(QuickstepTransitionManager transitionManager) {
mTransitionManager = transitionManager;
@@ -1832,6 +1918,13 @@
@Override
public void onTaskLaunching(int taskId, int supportedType, int color) {
mTransitionManager.mTaskStartParams.put(taskId, Pair.create(supportedType, color));
+ mBackgroundColor = color;
+ }
+
+ public int getBackgroundColor() {
+ return mBackgroundColor == Color.TRANSPARENT
+ ? mLauncher.getScrimView().getBackgroundColor()
+ : mBackgroundColor;
}
}
diff --git a/src/com/android/launcher3/LauncherSettings.java b/src/com/android/launcher3/LauncherSettings.java
index 6ea331d..66ea616 100644
--- a/src/com/android/launcher3/LauncherSettings.java
+++ b/src/com/android/launcher3/LauncherSettings.java
@@ -30,6 +30,20 @@
public class LauncherSettings {
/**
+ * Types of animations.
+ */
+ public static final class Animation {
+ /**
+ * The default animation for a given view/item info type.
+ */
+ public static final int DEFAULT = 0;
+ /**
+ * An animation using the view's background.
+ */
+ public static final int VIEW_BACKGROUND = 1;
+ }
+
+ /**
* Favorites.
*/
public static final class Favorites implements BaseColumns {
diff --git a/src/com/android/launcher3/config/FeatureFlags.java b/src/com/android/launcher3/config/FeatureFlags.java
index c90c6bf..2841129 100644
--- a/src/com/android/launcher3/config/FeatureFlags.java
+++ b/src/com/android/launcher3/config/FeatureFlags.java
@@ -272,7 +272,7 @@
public static final BooleanFlag ENABLE_SEARCH_RESULT_LAUNCH_TRANSITION = new DeviceFlag(
"ENABLE_SEARCH_RESULT_LAUNCH_TRANSITION", false,
- "Enable option to launch search results using the new standardized transitions");
+ "Enable option to launch search results using the new view container transitions");
public static final BooleanFlag TWO_PREDICTED_ROWS_ALL_APPS_SEARCH = new DeviceFlag(
"TWO_PREDICTED_ROWS_ALL_APPS_SEARCH", false,
diff --git a/src/com/android/launcher3/model/data/ItemInfo.java b/src/com/android/launcher3/model/data/ItemInfo.java
index 2dd44a4..4eb2e9e 100644
--- a/src/com/android/launcher3/model/data/ItemInfo.java
+++ b/src/com/android/launcher3/model/data/ItemInfo.java
@@ -47,8 +47,10 @@
import androidx.annotation.Nullable;
import com.android.launcher3.LauncherSettings;
+import com.android.launcher3.LauncherSettings.Animation;
import com.android.launcher3.LauncherSettings.Favorites;
import com.android.launcher3.Workspace;
+import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.logger.LauncherAtom;
import com.android.launcher3.logger.LauncherAtom.AllAppsContainer;
import com.android.launcher3.logger.LauncherAtom.ContainerInfo;
@@ -94,6 +96,12 @@
public int itemType;
/**
+ * One of {@link Animation#DEFAULT},
+ * {@link Animation#VIEW_BACKGROUND}.
+ */
+ public int animationType = Animation.DEFAULT;
+
+ /**
* The id of the container that holds this item. For the desktop, this will be
* {@link Favorites#CONTAINER_DESKTOP}. For the all applications folder it
* will be {@link #NO_ID} (since it is not stored in the settings DB). For user folders
@@ -185,6 +193,7 @@
rank = info.rank;
screenId = info.screenId;
itemType = info.itemType;
+ animationType = info.animationType;
container = info.container;
user = info.user;
contentDescription = info.contentDescription;
@@ -298,6 +307,15 @@
}
/**
+ * Returns whether this item should use the background animation.
+ */
+ public boolean shouldUseBackgroundAnimation() {
+ return animationType == LauncherSettings.Animation.VIEW_BACKGROUND
+ && FeatureFlags.ENABLE_SEARCH_RESULT_BACKGROUND_DRAWABLES.get()
+ && FeatureFlags.ENABLE_SEARCH_RESULT_LAUNCH_TRANSITION.get();
+ }
+
+ /**
* Creates {@link LauncherAtom.ItemInfo} with important fields and parent container info.
*/
@NonNull
diff --git a/src/com/android/launcher3/touch/ItemClickHandler.java b/src/com/android/launcher3/touch/ItemClickHandler.java
index 64951ca..790c226 100644
--- a/src/com/android/launcher3/touch/ItemClickHandler.java
+++ b/src/com/android/launcher3/touch/ItemClickHandler.java
@@ -343,7 +343,8 @@
return;
}
}
- if (v != null && launcher.supportsAdaptiveIconAnimation(v)) {
+ if (v != null && launcher.supportsAdaptiveIconAnimation(v)
+ && !item.shouldUseBackgroundAnimation()) {
// Preload the icon to reduce latency b/w swapping the floating view with the original.
FloatingIconView.fetchIcon(launcher, v, item, true /* isOpening */);
}
diff --git a/src/com/android/launcher3/views/ActivityContext.java b/src/com/android/launcher3/views/ActivityContext.java
index 79b4cb4..36f5f4d 100644
--- a/src/com/android/launcher3/views/ActivityContext.java
+++ b/src/com/android/launcher3/views/ActivityContext.java
@@ -23,6 +23,7 @@
import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
import android.app.ActivityOptions;
+import android.app.PendingIntent;
import android.content.ActivityNotFoundException;
import android.content.Context;
import android.content.ContextWrapper;
@@ -45,6 +46,7 @@
import android.view.inputmethod.InputMethodManager;
import android.widget.Toast;
+import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.android.launcher3.BubbleTextView;
@@ -270,6 +272,29 @@
}
}
+
+ /**
+ * Sends a pending intent animating from a view.
+ *
+ * @param v View to animate.
+ * @param intent The pending intent being launched.
+ * @param item Item associated with the view.
+ * @return {@code true} if the intent is sent successfully.
+ */
+ default boolean sendPendingIntentWithAnimation(
+ @NonNull View v, PendingIntent intent, @Nullable ItemInfo item) {
+ Bundle optsBundle = getActivityLaunchOptions(v, item).toBundle();
+ try {
+ intent.send(null, 0, null, null, null, null, optsBundle);
+ return true;
+ } catch (PendingIntent.CanceledException e) {
+ Toast.makeText(v.getContext(),
+ v.getContext().getResources().getText(R.string.shortcut_not_available),
+ Toast.LENGTH_SHORT).show();
+ }
+ return false;
+ }
+
/**
* Safely starts an activity.
*
diff --git a/src/com/android/launcher3/views/ScrimView.java b/src/com/android/launcher3/views/ScrimView.java
index 870ff12..ca80c51 100644
--- a/src/com/android/launcher3/views/ScrimView.java
+++ b/src/com/android/launcher3/views/ScrimView.java
@@ -77,6 +77,10 @@
super.setBackgroundColor(color);
}
+ public int getBackgroundColor() {
+ return mBackgroundColor;
+ }
+
@Override
public void onVisibilityAggregated(boolean isVisible) {
super.onVisibilityAggregated(isVisible);