Implement ActivityEmbedding Shell transition animation with showBackdrop
Refactor background color handling from DefaultTransitionHandler to a helper class, so that we can reuse it for ActivityEmbedding as well. Bug: 207070762 Test: manual Change-Id: I6034ddd1928184a969848f0be496247032763b40
This commit is contained in:
@@ -20,6 +20,9 @@ import static android.view.WindowManager.TRANSIT_CHANGE;
|
||||
import static android.view.WindowManagerPolicyConstants.TYPE_LAYER_OFFSET;
|
||||
import static android.window.TransitionInfo.FLAG_IS_BEHIND_STARTING_WINDOW;
|
||||
|
||||
import static com.android.wm.shell.transition.TransitionAnimationHelper.addBackgroundToTransition;
|
||||
import static com.android.wm.shell.transition.TransitionAnimationHelper.getTransitionBackgroundColorIfSet;
|
||||
|
||||
import android.animation.Animator;
|
||||
import android.animation.ValueAnimator;
|
||||
import android.content.Context;
|
||||
@@ -42,7 +45,6 @@ import com.android.wm.shell.transition.Transitions;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.function.BiFunction;
|
||||
|
||||
/** To run the ActivityEmbedding animations. */
|
||||
class ActivityEmbeddingAnimationRunner {
|
||||
@@ -85,7 +87,7 @@ class ActivityEmbeddingAnimationRunner {
|
||||
@NonNull SurfaceControl.Transaction finishTransaction,
|
||||
@NonNull Runnable animationFinishCallback) {
|
||||
final List<ActivityEmbeddingAnimationAdapter> adapters =
|
||||
createAnimationAdapters(info, startTransaction);
|
||||
createAnimationAdapters(info, startTransaction, finishTransaction);
|
||||
long duration = 0;
|
||||
for (ActivityEmbeddingAnimationAdapter adapter : adapters) {
|
||||
duration = Math.max(duration, adapter.getDurationHint());
|
||||
@@ -129,7 +131,8 @@ class ActivityEmbeddingAnimationRunner {
|
||||
*/
|
||||
@NonNull
|
||||
private List<ActivityEmbeddingAnimationAdapter> createAnimationAdapters(
|
||||
@NonNull TransitionInfo info, @NonNull SurfaceControl.Transaction startTransaction) {
|
||||
@NonNull TransitionInfo info, @NonNull SurfaceControl.Transaction startTransaction,
|
||||
@NonNull SurfaceControl.Transaction finishTransaction) {
|
||||
boolean isChangeTransition = false;
|
||||
for (TransitionInfo.Change change : info.getChanges()) {
|
||||
if (change.hasFlags(FLAG_IS_BEHIND_STARTING_WINDOW)) {
|
||||
@@ -145,23 +148,25 @@ class ActivityEmbeddingAnimationRunner {
|
||||
return createChangeAnimationAdapters(info, startTransaction);
|
||||
}
|
||||
if (Transitions.isClosingType(info.getType())) {
|
||||
return createCloseAnimationAdapters(info);
|
||||
return createCloseAnimationAdapters(info, startTransaction, finishTransaction);
|
||||
}
|
||||
return createOpenAnimationAdapters(info);
|
||||
return createOpenAnimationAdapters(info, startTransaction, finishTransaction);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
private List<ActivityEmbeddingAnimationAdapter> createOpenAnimationAdapters(
|
||||
@NonNull TransitionInfo info) {
|
||||
return createOpenCloseAnimationAdapters(info, true /* isOpening */,
|
||||
mAnimationSpec::loadOpenAnimation);
|
||||
@NonNull TransitionInfo info, @NonNull SurfaceControl.Transaction startTransaction,
|
||||
@NonNull SurfaceControl.Transaction finishTransaction) {
|
||||
return createOpenCloseAnimationAdapters(info, startTransaction, finishTransaction,
|
||||
true /* isOpening */, mAnimationSpec::loadOpenAnimation);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
private List<ActivityEmbeddingAnimationAdapter> createCloseAnimationAdapters(
|
||||
@NonNull TransitionInfo info) {
|
||||
return createOpenCloseAnimationAdapters(info, false /* isOpening */,
|
||||
mAnimationSpec::loadCloseAnimation);
|
||||
@NonNull TransitionInfo info, @NonNull SurfaceControl.Transaction startTransaction,
|
||||
@NonNull SurfaceControl.Transaction finishTransaction) {
|
||||
return createOpenCloseAnimationAdapters(info, startTransaction, finishTransaction,
|
||||
false /* isOpening */, mAnimationSpec::loadCloseAnimation);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -170,8 +175,9 @@ class ActivityEmbeddingAnimationRunner {
|
||||
*/
|
||||
@NonNull
|
||||
private List<ActivityEmbeddingAnimationAdapter> createOpenCloseAnimationAdapters(
|
||||
@NonNull TransitionInfo info, boolean isOpening,
|
||||
@NonNull BiFunction<TransitionInfo.Change, Rect, Animation> animationProvider) {
|
||||
@NonNull TransitionInfo info, @NonNull SurfaceControl.Transaction startTransaction,
|
||||
@NonNull SurfaceControl.Transaction finishTransaction, boolean isOpening,
|
||||
@NonNull AnimationProvider animationProvider) {
|
||||
// We need to know if the change window is only a partial of the whole animation screen.
|
||||
// If so, we will need to adjust it to make the whole animation screen looks like one.
|
||||
final List<TransitionInfo.Change> openingChanges = new ArrayList<>();
|
||||
@@ -194,7 +200,8 @@ class ActivityEmbeddingAnimationRunner {
|
||||
final List<ActivityEmbeddingAnimationAdapter> adapters = new ArrayList<>();
|
||||
for (TransitionInfo.Change change : openingChanges) {
|
||||
final ActivityEmbeddingAnimationAdapter adapter = createOpenCloseAnimationAdapter(
|
||||
change, animationProvider, openingWholeScreenBounds);
|
||||
info, change, startTransaction, finishTransaction, animationProvider,
|
||||
openingWholeScreenBounds);
|
||||
if (isOpening) {
|
||||
adapter.overrideLayer(offsetLayer++);
|
||||
}
|
||||
@@ -202,7 +209,8 @@ class ActivityEmbeddingAnimationRunner {
|
||||
}
|
||||
for (TransitionInfo.Change change : closingChanges) {
|
||||
final ActivityEmbeddingAnimationAdapter adapter = createOpenCloseAnimationAdapter(
|
||||
change, animationProvider, closingWholeScreenBounds);
|
||||
info, change, startTransaction, finishTransaction, animationProvider,
|
||||
closingWholeScreenBounds);
|
||||
if (!isOpening) {
|
||||
adapter.overrideLayer(offsetLayer++);
|
||||
}
|
||||
@@ -213,10 +221,18 @@ class ActivityEmbeddingAnimationRunner {
|
||||
|
||||
@NonNull
|
||||
private ActivityEmbeddingAnimationAdapter createOpenCloseAnimationAdapter(
|
||||
@NonNull TransitionInfo.Change change,
|
||||
@NonNull BiFunction<TransitionInfo.Change, Rect, Animation> animationProvider,
|
||||
@NonNull Rect wholeAnimationBounds) {
|
||||
final Animation animation = animationProvider.apply(change, wholeAnimationBounds);
|
||||
@NonNull TransitionInfo info, @NonNull TransitionInfo.Change change,
|
||||
@NonNull SurfaceControl.Transaction startTransaction,
|
||||
@NonNull SurfaceControl.Transaction finishTransaction,
|
||||
@NonNull AnimationProvider animationProvider, @NonNull Rect wholeAnimationBounds) {
|
||||
final Animation animation = animationProvider.get(info, change, wholeAnimationBounds);
|
||||
// We may want to show a background color for open/close transition.
|
||||
final int backgroundColor = getTransitionBackgroundColorIfSet(info, change, animation,
|
||||
0 /* defaultColor */);
|
||||
if (backgroundColor != 0) {
|
||||
addBackgroundToTransition(info.getRootLeash(), backgroundColor, startTransaction,
|
||||
finishTransaction);
|
||||
}
|
||||
return new ActivityEmbeddingAnimationAdapter(animation, change, change.getLeash(),
|
||||
wholeAnimationBounds);
|
||||
}
|
||||
@@ -322,4 +338,10 @@ class ActivityEmbeddingAnimationRunner {
|
||||
return ScreenshotUtils.takeScreenshot(t, screenshotChange.getLeash(),
|
||||
animationChange.getLeash(), cropBounds, Integer.MAX_VALUE);
|
||||
}
|
||||
|
||||
/** To provide an {@link Animation} based on the transition infos. */
|
||||
private interface AnimationProvider {
|
||||
Animation get(@NonNull TransitionInfo info, @NonNull TransitionInfo.Change change,
|
||||
@NonNull Rect animationBounds);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,6 +17,9 @@
|
||||
package com.android.wm.shell.activityembedding;
|
||||
|
||||
|
||||
import static com.android.internal.policy.TransitionAnimation.WALLPAPER_TRANSITION_NONE;
|
||||
import static com.android.wm.shell.transition.TransitionAnimationHelper.loadAttributeAnimation;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.Point;
|
||||
import android.graphics.Rect;
|
||||
@@ -33,7 +36,6 @@ import android.window.TransitionInfo;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import com.android.internal.R;
|
||||
import com.android.internal.policy.TransitionAnimation;
|
||||
import com.android.wm.shell.transition.Transitions;
|
||||
|
||||
@@ -175,16 +177,20 @@ class ActivityEmbeddingAnimationSpec {
|
||||
}
|
||||
|
||||
@NonNull
|
||||
Animation loadOpenAnimation(@NonNull TransitionInfo.Change change,
|
||||
@NonNull Rect wholeAnimationBounds) {
|
||||
Animation loadOpenAnimation(@NonNull TransitionInfo info,
|
||||
@NonNull TransitionInfo.Change change, @NonNull Rect wholeAnimationBounds) {
|
||||
final boolean isEnter = Transitions.isOpeningType(change.getMode());
|
||||
final Animation animation;
|
||||
// TODO(b/207070762):
|
||||
// 1. Implement clearTop version: R.anim.task_fragment_clear_top_close_enter/exit
|
||||
// 2. Implement edgeExtension version
|
||||
animation = mTransitionAnimation.loadDefaultAnimationRes(isEnter
|
||||
? R.anim.task_fragment_open_enter
|
||||
: R.anim.task_fragment_open_exit);
|
||||
// TODO(b/207070762): Implement edgeExtension version
|
||||
if (shouldShowBackdrop(info, change)) {
|
||||
animation = mTransitionAnimation.loadDefaultAnimationRes(isEnter
|
||||
? com.android.internal.R.anim.task_fragment_clear_top_open_enter
|
||||
: com.android.internal.R.anim.task_fragment_clear_top_open_exit);
|
||||
} else {
|
||||
animation = mTransitionAnimation.loadDefaultAnimationRes(isEnter
|
||||
? com.android.internal.R.anim.task_fragment_open_enter
|
||||
: com.android.internal.R.anim.task_fragment_open_exit);
|
||||
}
|
||||
// Use the whole animation bounds instead of the change bounds, so that when multiple change
|
||||
// targets are opening at the same time, the animation applied to each will be the same.
|
||||
// Otherwise, we may see gap between the activities that are launching together.
|
||||
@@ -195,16 +201,20 @@ class ActivityEmbeddingAnimationSpec {
|
||||
}
|
||||
|
||||
@NonNull
|
||||
Animation loadCloseAnimation(@NonNull TransitionInfo.Change change,
|
||||
@NonNull Rect wholeAnimationBounds) {
|
||||
Animation loadCloseAnimation(@NonNull TransitionInfo info,
|
||||
@NonNull TransitionInfo.Change change, @NonNull Rect wholeAnimationBounds) {
|
||||
final boolean isEnter = Transitions.isOpeningType(change.getMode());
|
||||
final Animation animation;
|
||||
// TODO(b/207070762):
|
||||
// 1. Implement clearTop version: R.anim.task_fragment_clear_top_close_enter/exit
|
||||
// 2. Implement edgeExtension version
|
||||
animation = mTransitionAnimation.loadDefaultAnimationRes(isEnter
|
||||
? R.anim.task_fragment_close_enter
|
||||
: R.anim.task_fragment_close_exit);
|
||||
// TODO(b/207070762): Implement edgeExtension version
|
||||
if (shouldShowBackdrop(info, change)) {
|
||||
animation = mTransitionAnimation.loadDefaultAnimationRes(isEnter
|
||||
? com.android.internal.R.anim.task_fragment_clear_top_close_enter
|
||||
: com.android.internal.R.anim.task_fragment_clear_top_close_exit);
|
||||
} else {
|
||||
animation = mTransitionAnimation.loadDefaultAnimationRes(isEnter
|
||||
? com.android.internal.R.anim.task_fragment_close_enter
|
||||
: com.android.internal.R.anim.task_fragment_close_exit);
|
||||
}
|
||||
// Use the whole animation bounds instead of the change bounds, so that when multiple change
|
||||
// targets are closing at the same time, the animation applied to each will be the same.
|
||||
// Otherwise, we may see gap between the activities that are finishing together.
|
||||
@@ -213,4 +223,11 @@ class ActivityEmbeddingAnimationSpec {
|
||||
animation.scaleCurrentDuration(mTransitionAnimationScaleSetting);
|
||||
return animation;
|
||||
}
|
||||
|
||||
private boolean shouldShowBackdrop(@NonNull TransitionInfo info,
|
||||
@NonNull TransitionInfo.Change change) {
|
||||
final Animation a = loadAttributeAnimation(info, change, WALLPAPER_TRANSITION_NONE,
|
||||
mTransitionAnimation);
|
||||
return a != null && a.getShowBackdrop();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,13 +18,11 @@ package com.android.wm.shell.transition;
|
||||
|
||||
import static android.app.ActivityOptions.ANIM_CLIP_REVEAL;
|
||||
import static android.app.ActivityOptions.ANIM_CUSTOM;
|
||||
import static android.app.ActivityOptions.ANIM_FROM_STYLE;
|
||||
import static android.app.ActivityOptions.ANIM_NONE;
|
||||
import static android.app.ActivityOptions.ANIM_OPEN_CROSS_PROFILE_APPS;
|
||||
import static android.app.ActivityOptions.ANIM_SCALE_UP;
|
||||
import static android.app.ActivityOptions.ANIM_THUMBNAIL_SCALE_DOWN;
|
||||
import static android.app.ActivityOptions.ANIM_THUMBNAIL_SCALE_UP;
|
||||
import static android.app.WindowConfiguration.ACTIVITY_TYPE_DREAM;
|
||||
import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
|
||||
import static android.app.admin.DevicePolicyManager.ACTION_DEVICE_POLICY_RESOURCE_UPDATED;
|
||||
import static android.app.admin.DevicePolicyManager.EXTRA_RESOURCE_TYPE;
|
||||
@@ -43,7 +41,6 @@ import static android.view.WindowManager.TRANSIT_OPEN;
|
||||
import static android.view.WindowManager.TRANSIT_RELAUNCH;
|
||||
import static android.view.WindowManager.TRANSIT_TO_BACK;
|
||||
import static android.view.WindowManager.TRANSIT_TO_FRONT;
|
||||
import static android.view.WindowManager.transitTypeToString;
|
||||
import static android.window.TransitionInfo.FLAG_CROSS_PROFILE_OWNER_THUMBNAIL;
|
||||
import static android.window.TransitionInfo.FLAG_CROSS_PROFILE_WORK_THUMBNAIL;
|
||||
import static android.window.TransitionInfo.FLAG_DISPLAY_HAS_ALERT_WINDOWS;
|
||||
@@ -59,6 +56,10 @@ import static com.android.internal.policy.TransitionAnimation.WALLPAPER_TRANSITI
|
||||
import static com.android.internal.policy.TransitionAnimation.WALLPAPER_TRANSITION_INTRA_OPEN;
|
||||
import static com.android.internal.policy.TransitionAnimation.WALLPAPER_TRANSITION_NONE;
|
||||
import static com.android.internal.policy.TransitionAnimation.WALLPAPER_TRANSITION_OPEN;
|
||||
import static com.android.wm.shell.transition.TransitionAnimationHelper.addBackgroundToTransition;
|
||||
import static com.android.wm.shell.transition.TransitionAnimationHelper.getTransitionBackgroundColorIfSet;
|
||||
import static com.android.wm.shell.transition.TransitionAnimationHelper.loadAttributeAnimation;
|
||||
import static com.android.wm.shell.transition.TransitionAnimationHelper.sDisableCustomTaskAnimationProperty;
|
||||
|
||||
import android.animation.Animator;
|
||||
import android.animation.AnimatorListenerAdapter;
|
||||
@@ -74,7 +75,6 @@ import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.Insets;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.PixelFormat;
|
||||
@@ -84,7 +84,6 @@ import android.graphics.drawable.Drawable;
|
||||
import android.hardware.HardwareBuffer;
|
||||
import android.os.Handler;
|
||||
import android.os.IBinder;
|
||||
import android.os.SystemProperties;
|
||||
import android.os.UserHandle;
|
||||
import android.util.ArrayMap;
|
||||
import android.view.Choreographer;
|
||||
@@ -122,21 +121,6 @@ import java.util.function.Consumer;
|
||||
public class DefaultTransitionHandler implements Transitions.TransitionHandler {
|
||||
private static final int MAX_ANIMATION_DURATION = 3000;
|
||||
|
||||
/**
|
||||
* Restrict ability of activities overriding transition animation in a way such that
|
||||
* an activity can do it only when the transition happens within a same task.
|
||||
*
|
||||
* @see android.app.Activity#overridePendingTransition(int, int)
|
||||
*/
|
||||
private static final String DISABLE_CUSTOM_TASK_ANIMATION_PROPERTY =
|
||||
"persist.wm.disable_custom_task_animation";
|
||||
|
||||
/**
|
||||
* @see #DISABLE_CUSTOM_TASK_ANIMATION_PROPERTY
|
||||
*/
|
||||
static boolean sDisableCustomTaskAnimationProperty =
|
||||
SystemProperties.getBoolean(DISABLE_CUSTOM_TASK_ANIMATION_PROPERTY, true);
|
||||
|
||||
private final TransactionPool mTransactionPool;
|
||||
private final DisplayController mDisplayController;
|
||||
private final Context mContext;
|
||||
@@ -431,22 +415,8 @@ public class DefaultTransitionHandler implements Transitions.TransitionHandler {
|
||||
cornerRadius = 0;
|
||||
}
|
||||
|
||||
if (a.getShowBackdrop()) {
|
||||
if (info.getAnimationOptions().getBackgroundColor() != 0) {
|
||||
// If available use the background color provided through AnimationOptions
|
||||
backgroundColorForTransition =
|
||||
info.getAnimationOptions().getBackgroundColor();
|
||||
} else if (a.getBackdropColor() != 0) {
|
||||
// Otherwise fallback on the background color provided through the animation
|
||||
// definition.
|
||||
backgroundColorForTransition = a.getBackdropColor();
|
||||
} else if (change.getBackgroundColor() != 0) {
|
||||
// Otherwise default to the window's background color if provided through
|
||||
// the theme as the background color for the animation - the top most window
|
||||
// with a valid background color and showBackground set takes precedence.
|
||||
backgroundColorForTransition = change.getBackgroundColor();
|
||||
}
|
||||
}
|
||||
backgroundColorForTransition = getTransitionBackgroundColorIfSet(info, change, a,
|
||||
backgroundColorForTransition);
|
||||
|
||||
boolean delayedEdgeExtension = false;
|
||||
if (!isTask && a.hasExtension()) {
|
||||
@@ -668,29 +638,6 @@ public class DefaultTransitionHandler implements Transitions.TransitionHandler {
|
||||
return edgeExtensionLayer;
|
||||
}
|
||||
|
||||
private void addBackgroundToTransition(
|
||||
@NonNull SurfaceControl rootLeash,
|
||||
@ColorInt int color,
|
||||
@NonNull SurfaceControl.Transaction startTransaction,
|
||||
@NonNull SurfaceControl.Transaction finishTransaction
|
||||
) {
|
||||
final Color bgColor = Color.valueOf(color);
|
||||
final float[] colorArray = new float[] { bgColor.red(), bgColor.green(), bgColor.blue() };
|
||||
|
||||
final SurfaceControl animationBackgroundSurface = new SurfaceControl.Builder()
|
||||
.setName("Animation Background")
|
||||
.setParent(rootLeash)
|
||||
.setColorLayer()
|
||||
.setOpaque(true)
|
||||
.build();
|
||||
|
||||
startTransaction
|
||||
.setLayer(animationBackgroundSurface, Integer.MIN_VALUE)
|
||||
.setColor(animationBackgroundSurface, colorArray)
|
||||
.show(animationBackgroundSurface);
|
||||
finishTransaction.remove(animationBackgroundSurface);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public WindowContainerTransaction handleRequest(@NonNull IBinder transition,
|
||||
@@ -704,9 +651,9 @@ public class DefaultTransitionHandler implements Transitions.TransitionHandler {
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private Animation loadAnimation(TransitionInfo info, TransitionInfo.Change change,
|
||||
int wallpaperTransit) {
|
||||
Animation a = null;
|
||||
private Animation loadAnimation(@NonNull TransitionInfo info,
|
||||
@NonNull TransitionInfo.Change change, int wallpaperTransit) {
|
||||
Animation a;
|
||||
|
||||
final int type = info.getType();
|
||||
final int flags = info.getFlags();
|
||||
@@ -717,12 +664,10 @@ public class DefaultTransitionHandler implements Transitions.TransitionHandler {
|
||||
final boolean isTask = change.getTaskInfo() != null;
|
||||
final TransitionInfo.AnimationOptions options = info.getAnimationOptions();
|
||||
final int overrideType = options != null ? options.getType() : ANIM_NONE;
|
||||
final boolean canCustomContainer = isTask ? !sDisableCustomTaskAnimationProperty : true;
|
||||
final boolean canCustomContainer = !isTask || !sDisableCustomTaskAnimationProperty;
|
||||
final Rect endBounds = Transitions.isClosingType(changeMode)
|
||||
? mRotator.getEndBoundsInStartRotation(change)
|
||||
: change.getEndAbsBounds();
|
||||
final boolean isDream =
|
||||
isTask && change.getTaskInfo().topActivityType == ACTIVITY_TYPE_DREAM;
|
||||
|
||||
if (info.isKeyguardGoingAway()) {
|
||||
a = mTransitionAnimation.loadKeyguardExitAnimation(flags,
|
||||
@@ -763,87 +708,7 @@ public class DefaultTransitionHandler implements Transitions.TransitionHandler {
|
||||
// This received a transferred starting window, so don't animate
|
||||
return null;
|
||||
} else {
|
||||
int animAttr = 0;
|
||||
boolean translucent = false;
|
||||
if (isDream) {
|
||||
if (type == TRANSIT_OPEN) {
|
||||
animAttr = enter
|
||||
? R.styleable.WindowAnimation_dreamActivityOpenEnterAnimation
|
||||
: R.styleable.WindowAnimation_dreamActivityOpenExitAnimation;
|
||||
} else if (type == TRANSIT_CLOSE) {
|
||||
animAttr = enter
|
||||
? 0
|
||||
: R.styleable.WindowAnimation_dreamActivityCloseExitAnimation;
|
||||
}
|
||||
} else if (wallpaperTransit == WALLPAPER_TRANSITION_INTRA_OPEN) {
|
||||
animAttr = enter
|
||||
? R.styleable.WindowAnimation_wallpaperIntraOpenEnterAnimation
|
||||
: R.styleable.WindowAnimation_wallpaperIntraOpenExitAnimation;
|
||||
} else if (wallpaperTransit == WALLPAPER_TRANSITION_INTRA_CLOSE) {
|
||||
animAttr = enter
|
||||
? R.styleable.WindowAnimation_wallpaperIntraCloseEnterAnimation
|
||||
: R.styleable.WindowAnimation_wallpaperIntraCloseExitAnimation;
|
||||
} else if (wallpaperTransit == WALLPAPER_TRANSITION_OPEN) {
|
||||
animAttr = enter
|
||||
? R.styleable.WindowAnimation_wallpaperOpenEnterAnimation
|
||||
: R.styleable.WindowAnimation_wallpaperOpenExitAnimation;
|
||||
} else if (wallpaperTransit == WALLPAPER_TRANSITION_CLOSE) {
|
||||
animAttr = enter
|
||||
? R.styleable.WindowAnimation_wallpaperCloseEnterAnimation
|
||||
: R.styleable.WindowAnimation_wallpaperCloseExitAnimation;
|
||||
} else if (type == TRANSIT_OPEN) {
|
||||
// We will translucent open animation for translucent activities and tasks. Choose
|
||||
// WindowAnimation_activityOpenEnterAnimation and set translucent here, then
|
||||
// TransitionAnimation loads appropriate animation later.
|
||||
if ((changeFlags & FLAG_TRANSLUCENT) != 0 && enter) {
|
||||
translucent = true;
|
||||
}
|
||||
if (isTask && !translucent) {
|
||||
animAttr = enter
|
||||
? R.styleable.WindowAnimation_taskOpenEnterAnimation
|
||||
: R.styleable.WindowAnimation_taskOpenExitAnimation;
|
||||
} else {
|
||||
animAttr = enter
|
||||
? R.styleable.WindowAnimation_activityOpenEnterAnimation
|
||||
: R.styleable.WindowAnimation_activityOpenExitAnimation;
|
||||
}
|
||||
} else if (type == TRANSIT_TO_FRONT) {
|
||||
animAttr = enter
|
||||
? R.styleable.WindowAnimation_taskToFrontEnterAnimation
|
||||
: R.styleable.WindowAnimation_taskToFrontExitAnimation;
|
||||
} else if (type == TRANSIT_CLOSE) {
|
||||
if (isTask) {
|
||||
animAttr = enter
|
||||
? R.styleable.WindowAnimation_taskCloseEnterAnimation
|
||||
: R.styleable.WindowAnimation_taskCloseExitAnimation;
|
||||
} else {
|
||||
if ((changeFlags & FLAG_TRANSLUCENT) != 0 && !enter) {
|
||||
translucent = true;
|
||||
}
|
||||
animAttr = enter
|
||||
? R.styleable.WindowAnimation_activityCloseEnterAnimation
|
||||
: R.styleable.WindowAnimation_activityCloseExitAnimation;
|
||||
}
|
||||
} else if (type == TRANSIT_TO_BACK) {
|
||||
animAttr = enter
|
||||
? R.styleable.WindowAnimation_taskToBackEnterAnimation
|
||||
: R.styleable.WindowAnimation_taskToBackExitAnimation;
|
||||
}
|
||||
|
||||
if (animAttr != 0) {
|
||||
if (overrideType == ANIM_FROM_STYLE && canCustomContainer) {
|
||||
a = mTransitionAnimation
|
||||
.loadAnimationAttr(options.getPackageName(), options.getAnimations(),
|
||||
animAttr, translucent);
|
||||
} else {
|
||||
a = mTransitionAnimation.loadDefaultAnimationAttr(animAttr, translucent);
|
||||
}
|
||||
}
|
||||
|
||||
ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS,
|
||||
"loadAnimation: anim=%s animAttr=0x%x type=%s isEntrance=%b", a, animAttr,
|
||||
transitTypeToString(type),
|
||||
enter);
|
||||
a = loadAttributeAnimation(info, change, wallpaperTransit, mTransitionAnimation);
|
||||
}
|
||||
|
||||
if (a != null) {
|
||||
|
||||
@@ -0,0 +1,220 @@
|
||||
/*
|
||||
* Copyright (C) 2022 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.wm.shell.transition;
|
||||
|
||||
import static android.app.ActivityOptions.ANIM_FROM_STYLE;
|
||||
import static android.app.ActivityOptions.ANIM_NONE;
|
||||
import static android.app.WindowConfiguration.ACTIVITY_TYPE_DREAM;
|
||||
import static android.view.WindowManager.TRANSIT_CLOSE;
|
||||
import static android.view.WindowManager.TRANSIT_OPEN;
|
||||
import static android.view.WindowManager.TRANSIT_TO_BACK;
|
||||
import static android.view.WindowManager.TRANSIT_TO_FRONT;
|
||||
import static android.view.WindowManager.transitTypeToString;
|
||||
import static android.window.TransitionInfo.FLAG_TRANSLUCENT;
|
||||
|
||||
import static com.android.internal.policy.TransitionAnimation.WALLPAPER_TRANSITION_CLOSE;
|
||||
import static com.android.internal.policy.TransitionAnimation.WALLPAPER_TRANSITION_INTRA_CLOSE;
|
||||
import static com.android.internal.policy.TransitionAnimation.WALLPAPER_TRANSITION_INTRA_OPEN;
|
||||
import static com.android.internal.policy.TransitionAnimation.WALLPAPER_TRANSITION_OPEN;
|
||||
|
||||
import android.annotation.ColorInt;
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.graphics.Color;
|
||||
import android.os.SystemProperties;
|
||||
import android.view.SurfaceControl;
|
||||
import android.view.animation.Animation;
|
||||
import android.window.TransitionInfo;
|
||||
|
||||
import com.android.internal.R;
|
||||
import com.android.internal.policy.TransitionAnimation;
|
||||
import com.android.internal.protolog.common.ProtoLog;
|
||||
import com.android.wm.shell.protolog.ShellProtoLogGroup;
|
||||
|
||||
/** The helper class that provides methods for adding styles to transition animations. */
|
||||
public class TransitionAnimationHelper {
|
||||
|
||||
/**
|
||||
* Restrict ability of activities overriding transition animation in a way such that
|
||||
* an activity can do it only when the transition happens within a same task.
|
||||
*
|
||||
* @see android.app.Activity#overridePendingTransition(int, int)
|
||||
*/
|
||||
private static final String DISABLE_CUSTOM_TASK_ANIMATION_PROPERTY =
|
||||
"persist.wm.disable_custom_task_animation";
|
||||
|
||||
/**
|
||||
* @see #DISABLE_CUSTOM_TASK_ANIMATION_PROPERTY
|
||||
*/
|
||||
static final boolean sDisableCustomTaskAnimationProperty =
|
||||
SystemProperties.getBoolean(DISABLE_CUSTOM_TASK_ANIMATION_PROPERTY, true);
|
||||
|
||||
/** Loads the animation that is defined through attribute id for the given transition. */
|
||||
@Nullable
|
||||
public static Animation loadAttributeAnimation(@NonNull TransitionInfo info,
|
||||
@NonNull TransitionInfo.Change change, int wallpaperTransit,
|
||||
@NonNull TransitionAnimation transitionAnimation) {
|
||||
final int type = info.getType();
|
||||
final int changeMode = change.getMode();
|
||||
final int changeFlags = change.getFlags();
|
||||
final boolean enter = Transitions.isOpeningType(changeMode);
|
||||
final boolean isTask = change.getTaskInfo() != null;
|
||||
final TransitionInfo.AnimationOptions options = info.getAnimationOptions();
|
||||
final int overrideType = options != null ? options.getType() : ANIM_NONE;
|
||||
final boolean canCustomContainer = !isTask || !sDisableCustomTaskAnimationProperty;
|
||||
final boolean isDream =
|
||||
isTask && change.getTaskInfo().topActivityType == ACTIVITY_TYPE_DREAM;
|
||||
int animAttr = 0;
|
||||
boolean translucent = false;
|
||||
if (isDream) {
|
||||
if (type == TRANSIT_OPEN) {
|
||||
animAttr = enter
|
||||
? R.styleable.WindowAnimation_dreamActivityOpenEnterAnimation
|
||||
: R.styleable.WindowAnimation_dreamActivityOpenExitAnimation;
|
||||
} else if (type == TRANSIT_CLOSE) {
|
||||
animAttr = enter
|
||||
? 0
|
||||
: R.styleable.WindowAnimation_dreamActivityCloseExitAnimation;
|
||||
}
|
||||
} else if (wallpaperTransit == WALLPAPER_TRANSITION_INTRA_OPEN) {
|
||||
animAttr = enter
|
||||
? R.styleable.WindowAnimation_wallpaperIntraOpenEnterAnimation
|
||||
: R.styleable.WindowAnimation_wallpaperIntraOpenExitAnimation;
|
||||
} else if (wallpaperTransit == WALLPAPER_TRANSITION_INTRA_CLOSE) {
|
||||
animAttr = enter
|
||||
? R.styleable.WindowAnimation_wallpaperIntraCloseEnterAnimation
|
||||
: R.styleable.WindowAnimation_wallpaperIntraCloseExitAnimation;
|
||||
} else if (wallpaperTransit == WALLPAPER_TRANSITION_OPEN) {
|
||||
animAttr = enter
|
||||
? R.styleable.WindowAnimation_wallpaperOpenEnterAnimation
|
||||
: R.styleable.WindowAnimation_wallpaperOpenExitAnimation;
|
||||
} else if (wallpaperTransit == WALLPAPER_TRANSITION_CLOSE) {
|
||||
animAttr = enter
|
||||
? R.styleable.WindowAnimation_wallpaperCloseEnterAnimation
|
||||
: R.styleable.WindowAnimation_wallpaperCloseExitAnimation;
|
||||
} else if (type == TRANSIT_OPEN) {
|
||||
// We will translucent open animation for translucent activities and tasks. Choose
|
||||
// WindowAnimation_activityOpenEnterAnimation and set translucent here, then
|
||||
// TransitionAnimation loads appropriate animation later.
|
||||
if ((changeFlags & FLAG_TRANSLUCENT) != 0 && enter) {
|
||||
translucent = true;
|
||||
}
|
||||
if (isTask && !translucent) {
|
||||
animAttr = enter
|
||||
? R.styleable.WindowAnimation_taskOpenEnterAnimation
|
||||
: R.styleable.WindowAnimation_taskOpenExitAnimation;
|
||||
} else {
|
||||
animAttr = enter
|
||||
? R.styleable.WindowAnimation_activityOpenEnterAnimation
|
||||
: R.styleable.WindowAnimation_activityOpenExitAnimation;
|
||||
}
|
||||
} else if (type == TRANSIT_TO_FRONT) {
|
||||
animAttr = enter
|
||||
? R.styleable.WindowAnimation_taskToFrontEnterAnimation
|
||||
: R.styleable.WindowAnimation_taskToFrontExitAnimation;
|
||||
} else if (type == TRANSIT_CLOSE) {
|
||||
if (isTask) {
|
||||
animAttr = enter
|
||||
? R.styleable.WindowAnimation_taskCloseEnterAnimation
|
||||
: R.styleable.WindowAnimation_taskCloseExitAnimation;
|
||||
} else {
|
||||
if ((changeFlags & FLAG_TRANSLUCENT) != 0 && !enter) {
|
||||
translucent = true;
|
||||
}
|
||||
animAttr = enter
|
||||
? R.styleable.WindowAnimation_activityCloseEnterAnimation
|
||||
: R.styleable.WindowAnimation_activityCloseExitAnimation;
|
||||
}
|
||||
} else if (type == TRANSIT_TO_BACK) {
|
||||
animAttr = enter
|
||||
? R.styleable.WindowAnimation_taskToBackEnterAnimation
|
||||
: R.styleable.WindowAnimation_taskToBackExitAnimation;
|
||||
}
|
||||
|
||||
Animation a = null;
|
||||
if (animAttr != 0) {
|
||||
if (overrideType == ANIM_FROM_STYLE && canCustomContainer) {
|
||||
a = transitionAnimation
|
||||
.loadAnimationAttr(options.getPackageName(), options.getAnimations(),
|
||||
animAttr, translucent);
|
||||
} else {
|
||||
a = transitionAnimation.loadDefaultAnimationAttr(animAttr, translucent);
|
||||
}
|
||||
}
|
||||
|
||||
ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS,
|
||||
"loadAnimation: anim=%s animAttr=0x%x type=%s isEntrance=%b", a, animAttr,
|
||||
transitTypeToString(type),
|
||||
enter);
|
||||
return a;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the background {@link ColorInt} for the given transition animation if it is set.
|
||||
*
|
||||
* @param defaultColor {@link ColorInt} to return if there is no background color specified by
|
||||
* the given transition animation.
|
||||
*/
|
||||
@ColorInt
|
||||
public static int getTransitionBackgroundColorIfSet(@NonNull TransitionInfo info,
|
||||
@NonNull TransitionInfo.Change change, @NonNull Animation a,
|
||||
@ColorInt int defaultColor) {
|
||||
if (!a.getShowBackdrop()) {
|
||||
return defaultColor;
|
||||
}
|
||||
if (info.getAnimationOptions() != null
|
||||
&& info.getAnimationOptions().getBackgroundColor() != 0) {
|
||||
// If available use the background color provided through AnimationOptions
|
||||
return info.getAnimationOptions().getBackgroundColor();
|
||||
} else if (a.getBackdropColor() != 0) {
|
||||
// Otherwise fallback on the background color provided through the animation
|
||||
// definition.
|
||||
return a.getBackdropColor();
|
||||
} else if (change.getBackgroundColor() != 0) {
|
||||
// Otherwise default to the window's background color if provided through
|
||||
// the theme as the background color for the animation - the top most window
|
||||
// with a valid background color and showBackground set takes precedence.
|
||||
return change.getBackgroundColor();
|
||||
}
|
||||
return defaultColor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the given {@code backgroundColor} as the background color to the transition animation.
|
||||
*/
|
||||
public static void addBackgroundToTransition(@NonNull SurfaceControl rootLeash,
|
||||
@ColorInt int backgroundColor, @NonNull SurfaceControl.Transaction startTransaction,
|
||||
@NonNull SurfaceControl.Transaction finishTransaction) {
|
||||
if (backgroundColor == 0) {
|
||||
// No background color.
|
||||
return;
|
||||
}
|
||||
final Color bgColor = Color.valueOf(backgroundColor);
|
||||
final float[] colorArray = new float[] { bgColor.red(), bgColor.green(), bgColor.blue() };
|
||||
final SurfaceControl animationBackgroundSurface = new SurfaceControl.Builder()
|
||||
.setName("Animation Background")
|
||||
.setParent(rootLeash)
|
||||
.setColorLayer()
|
||||
.setOpaque(true)
|
||||
.build();
|
||||
startTransaction
|
||||
.setLayer(animationBackgroundSurface, Integer.MIN_VALUE)
|
||||
.setColor(animationBackgroundSurface, colorArray)
|
||||
.show(animationBackgroundSurface);
|
||||
finishTransaction.remove(animationBackgroundSurface);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user