Promote AppWindowToken.applyAnimationLocked() to the base class.
- Add WindowContainer#getAnimationAdapter for all window hierarchy.
- Extract logics related Remote animation / Local animation adapter
creation from applyAnimationLocked into WC#getAnimationAdapter.
- Make RemoteAnimationRecord can accept in each window hierarchy.
Bug: 142617871
Bug: 131661052
Test: Refactoring, existing tests pass.
Change-Id: If1c39d09966d82653faf7ebd975592eaeacd7c24
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 982ef53..8bb545a 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -214,10 +214,8 @@
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_NORMAL;
import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_WILL_PLACE_SURFACES;
-import static com.android.server.wm.WindowManagerService.logWithStack;
import static com.android.server.wm.WindowState.LEGACY_POLICY_VISIBILITY;
import static com.android.server.wm.WindowStateAnimator.HAS_DRAWN;
-import static com.android.server.wm.WindowStateAnimator.STACK_CLIP_AFTER_ANIM;
import static com.android.server.wm.WindowStateAnimator.STACK_CLIP_BEFORE_ANIM;
import static org.xmlpull.v1.XmlPullParser.END_DOCUMENT;
@@ -294,6 +292,7 @@
import android.view.InputApplicationHandle;
import android.view.RemoteAnimationAdapter;
import android.view.RemoteAnimationDefinition;
+import android.view.RemoteAnimationTarget;
import android.view.SurfaceControl;
import android.view.SurfaceControl.Transaction;
import android.view.WindowManager;
@@ -318,6 +317,7 @@
import com.android.server.wm.ActivityMetricsLogger.WindowingModeTransitionInfoSnapshot;
import com.android.server.wm.ActivityStack.ActivityState;
import com.android.server.wm.WindowManagerService.H;
+import com.android.server.wm.utils.InsetUtils;
import com.google.android.collect.Sets;
@@ -553,24 +553,6 @@
private boolean mCurrentLaunchCanTurnScreenOn = true;
/**
- * This gets used during some open/close transitions as well as during a change transition
- * where it represents the starting-state snapshot.
- */
- private AppWindowThumbnail mThumbnail;
- private final Rect mTransitStartRect = new Rect();
-
- /**
- * If we are running an animation, this determines the transition type. Must be one of
- * AppTransition.TRANSIT_* constants.
- */
- private int mTransit;
-
- /**
- * If we are running an animation, this determines the flags during this animation. Must be a
- * bitwise combination of AppTransition.TRANSIT_FLAG_* constants.
- */
- private int mTransitFlags;
- /**
* This leash is used to "freeze" the app surface in place after the state change, but before
* the animation is ready to start.
*/
@@ -666,7 +648,6 @@
// TODO: Have a WindowContainer state for tracking exiting/deferred removal.
boolean mIsExiting;
- boolean mLaunchTaskBehind;
boolean mEnteringAnimation;
boolean mAppStopped;
@@ -678,15 +659,6 @@
ArrayDeque<Rect> mFrozenBounds = new ArrayDeque<>();
ArrayDeque<Configuration> mFrozenMergedConfig = new ArrayDeque<>();
- /** Whether this token should be boosted at the top of all app window tokens. */
- @VisibleForTesting boolean mNeedsZBoost;
-
- /** Layer used to constrain the animation to a token's stack bounds. */
- SurfaceControl mAnimationBoundsLayer;
-
- /** Whether this token needs to create mAnimationBoundsLayer for cropping animations. */
- boolean mNeedsAnimationBoundsLayer;
-
private AppSaturationInfo mLastAppSaturationInfo;
private final ColorDisplayService.ColorTransformController mColorTransformController =
@@ -712,10 +684,6 @@
private final Configuration mTmpConfig = new Configuration();
private final Rect mTmpBounds = new Rect();
- private final Point mTmpPoint = new Point();
- private final Rect mTmpRect = new Rect();
- private final Rect mTmpPrevBounds = new Rect();
-
// Token for targeting this activity for assist purposes.
final Binder assistToken = new Binder();
@@ -4124,7 +4092,7 @@
if (transit != WindowManager.TRANSIT_UNSET) {
if (mUseTransferredAnimation) {
runningAppAnimation = isAnimating();
- } else if (applyAnimationLocked(lp, transit, visible, isVoiceInteraction)) {
+ } else if (applyAnimation(lp, transit, visible, isVoiceInteraction)) {
runningAppAnimation = true;
}
delayed = runningAppAnimation;
@@ -5701,28 +5669,44 @@
}
}
-
@VisibleForTesting
boolean shouldAnimate(int transit) {
+ final Task task = getTask();
+ if (task != null && !task.shouldAnimate()) {
+ return false;
+ }
final boolean isSplitScreenPrimary =
getWindowingMode() == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
final boolean allowSplitScreenPrimaryAnimation = transit != TRANSIT_WALLPAPER_OPEN;
- // Don't animate while the task runs recents animation but only if we are in the mode
- // where we cancel with deferred screenshot, which means that the controller has
- // transformed the task.
- final RecentsAnimationController controller = mWmService.getRecentsAnimationController();
- if (controller != null && controller.isAnimatingTask(getTask())
- && controller.shouldDeferCancelUntilNextTransition()) {
- return false;
- }
-
// We animate always if it's not split screen primary, and only some special cases in split
// screen primary because it causes issues with stack clipping when we run an un-minimize
// animation at the same time.
return !isSplitScreenPrimary || allowSplitScreenPrimaryAnimation;
}
+ @Override
+ boolean isChangingAppTransition() {
+ final Task task = getTask();
+ if (task != null) {
+ return task.isChangingAppTransition();
+ }
+ return super.isChangingAppTransition();
+ }
+
+ @Override
+ boolean applyAnimation(WindowManager.LayoutParams lp, int transit, boolean enter,
+ boolean isVoiceInteraction) {
+ if (mWmService.mDisableTransitionAnimation || !shouldAnimate(transit)) {
+ ProtoLog.v(WM_DEBUG_APP_TRANSITIONS_ANIM,
+ "applyAnimation: transition animation is disabled or skipped. "
+ + "container=%s", this);
+ cancelAnimation();
+ return false;
+ }
+ return super.applyAnimation(lp, transit, enter, isVoiceInteraction);
+ }
+
/**
* Creates a layer to apply crop to an animation.
*/
@@ -5736,171 +5720,6 @@
return boundsLayer;
}
- boolean applyAnimationLocked(WindowManager.LayoutParams lp, int transit, boolean enter,
- boolean isVoiceInteraction) {
-
- if (mWmService.mDisableTransitionAnimation || !shouldAnimate(transit)) {
- ProtoLog.v(WM_DEBUG_APP_TRANSITIONS_ANIM,
- "applyAnimation: transition animation is disabled or skipped. "
- + "atoken=%s", this);
- cancelAnimation();
- return false;
- }
-
- // Only apply an animation if the display isn't frozen. If it is frozen, there is no reason
- // to animate and it can cause strange artifacts when we unfreeze the display if some
- // different animation is running.
- Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "AWT#applyAnimationLocked");
- if (okToAnimate()) {
- final AnimationAdapter adapter;
- AnimationAdapter thumbnailAdapter = null;
-
- final int appStackClipMode =
- getDisplayContent().mAppTransition.getAppStackClipMode();
-
- // Separate position and size for use in animators.
- mTmpRect.set(getAnimationBounds(appStackClipMode));
- mTmpPoint.set(mTmpRect.left, mTmpRect.top);
- mTmpRect.offsetTo(0, 0);
-
- final boolean isChanging = AppTransition.isChangeTransit(transit) && enter
- && getDisplayContent().mChangingApps.contains(this);
-
- // Delaying animation start isn't compatible with remote animations at all.
- if (getDisplayContent().mAppTransition.getRemoteAnimationController() != null
- && !mSurfaceAnimator.isAnimationStartDelayed()) {
- RemoteAnimationController.RemoteAnimationRecord adapters =
- getDisplayContent().mAppTransition.getRemoteAnimationController()
- .createRemoteAnimationRecord(this, mTmpPoint, mTmpRect,
- (isChanging ? mTransitStartRect : null));
- adapter = adapters.mAdapter;
- thumbnailAdapter = adapters.mThumbnailAdapter;
- } else if (isChanging) {
- final float durationScale = mWmService.getTransitionAnimationScaleLocked();
- mTmpRect.offsetTo(mTmpPoint.x, mTmpPoint.y);
- adapter = new LocalAnimationAdapter(
- new WindowChangeAnimationSpec(mTransitStartRect, mTmpRect,
- getDisplayContent().getDisplayInfo(), durationScale,
- true /* isAppAnimation */, false /* isThumbnail */),
- mWmService.mSurfaceAnimationRunner);
- if (mThumbnail != null) {
- thumbnailAdapter = new LocalAnimationAdapter(
- new WindowChangeAnimationSpec(mTransitStartRect, mTmpRect,
- getDisplayContent().getDisplayInfo(), durationScale,
- true /* isAppAnimation */, true /* isThumbnail */),
- mWmService.mSurfaceAnimationRunner);
- }
- mTransit = transit;
- mTransitFlags = getDisplayContent().mAppTransition.getTransitFlags();
- } else {
- mNeedsAnimationBoundsLayer = (appStackClipMode == STACK_CLIP_AFTER_ANIM);
-
- final Animation a = loadAnimation(lp, transit, enter, isVoiceInteraction);
- if (a != null) {
- // Only apply corner radius to animation if we're not in multi window mode.
- // We don't want rounded corners when in pip or split screen.
- final float windowCornerRadius = !inMultiWindowMode()
- ? getDisplayContent().getWindowCornerRadius()
- : 0;
- adapter = new LocalAnimationAdapter(
- new WindowAnimationSpec(a, mTmpPoint, mTmpRect,
- getDisplayContent().mAppTransition.canSkipFirstFrame(),
- appStackClipMode,
- true /* isAppAnimation */,
- windowCornerRadius),
- mWmService.mSurfaceAnimationRunner);
- if (a.getZAdjustment() == Animation.ZORDER_TOP) {
- mNeedsZBoost = true;
- }
- mTransit = transit;
- mTransitFlags = getDisplayContent().mAppTransition.getTransitFlags();
- } else {
- adapter = null;
- }
- }
- if (adapter != null) {
- startAnimation(getPendingTransaction(), adapter, !isVisible());
- if (adapter.getShowWallpaper()) {
- mDisplayContent.pendingLayoutChanges |= FINISH_LAYOUT_REDO_WALLPAPER;
- }
- if (thumbnailAdapter != null) {
- mThumbnail.startAnimation(
- getPendingTransaction(), thumbnailAdapter, !isVisible());
- }
- }
- } else {
- cancelAnimation();
- }
- Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
-
- return isAnimating();
- }
-
- private Animation loadAnimation(WindowManager.LayoutParams lp, int transit, boolean enter,
- boolean isVoiceInteraction) {
- final DisplayContent displayContent = getTask().getDisplayContent();
- final DisplayInfo displayInfo = displayContent.getDisplayInfo();
- final int width = displayInfo.appWidth;
- final int height = displayInfo.appHeight;
- ProtoLog.v(WM_DEBUG_APP_TRANSITIONS_ANIM,
- "applyAnimation: atoken=%s", this);
-
- // Determine the visible rect to calculate the thumbnail clip
- final WindowState win = findMainWindow();
- final Rect frame = new Rect(0, 0, width, height);
- final Rect displayFrame = new Rect(0, 0,
- displayInfo.logicalWidth, displayInfo.logicalHeight);
- final Rect insets = new Rect();
- final Rect stableInsets = new Rect();
- Rect surfaceInsets = null;
- final boolean freeform = win != null && win.inFreeformWindowingMode();
- if (win != null) {
- // Containing frame will usually cover the whole screen, including dialog windows.
- // For freeform workspace windows it will not cover the whole screen and it also
- // won't exactly match the final freeform window frame (e.g. when overlapping with
- // the status bar). In that case we need to use the final frame.
- if (freeform) {
- frame.set(win.getFrameLw());
- } else if (win.isLetterboxedAppWindow()) {
- frame.set(getTask().getBounds());
- } else if (win.isDockedResizing()) {
- // If we are animating while docked resizing, then use the stack bounds as the
- // animation target (which will be different than the task bounds)
- frame.set(getTask().getParent().getBounds());
- } else {
- frame.set(win.getContainingFrame());
- }
- surfaceInsets = win.getAttrs().surfaceInsets;
- // XXX(b/72757033): These are insets relative to the window frame, but we're really
- // interested in the insets relative to the frame we chose in the if-blocks above.
- win.getContentInsets(insets);
- win.getStableInsets(stableInsets);
- }
-
- if (mLaunchTaskBehind) {
- // Differentiate the two animations. This one which is briefly on the screen
- // gets the !enter animation, and the other activity which remains on the
- // screen gets the enter animation. Both appear in the mOpeningApps set.
- enter = false;
- }
- ProtoLog.d(WM_DEBUG_APP_TRANSITIONS,
- "Loading animation for app transition. transit=%s enter=%b frame=%s insets=%s "
- + "surfaceInsets=%s",
- AppTransition.appTransitionToString(transit), enter, frame, insets, surfaceInsets);
- final Configuration displayConfig = displayContent.getConfiguration();
- final Animation a = getDisplayContent().mAppTransition.loadAnimation(lp, transit, enter,
- displayConfig.uiMode, displayConfig.orientation, frame, displayFrame, insets,
- surfaceInsets, stableInsets, isVoiceInteraction, freeform, getTask().mTaskId);
- if (a != null) {
- if (DEBUG_ANIM) logWithStack(TAG, "Loaded animation " + a + " for " + this);
- final int containingWidth = frame.width();
- final int containingHeight = frame.height();
- a.initialize(containingWidth, containingHeight, width, height);
- a.scaleCurrentDuration(mWmService.getTransitionAnimationScaleLocked());
- }
- return a;
- }
-
@Override
public boolean shouldDeferAnimationFinish(Runnable endDeferFinishCallback) {
return mAnimatingActivityRegistry != null
@@ -6080,11 +5899,10 @@
if (!isAnimating()) {
return;
}
- final int taskId = getTask().mTaskId;
final GraphicBuffer thumbnailHeader =
- getDisplayContent().mAppTransition.getAppTransitionThumbnailHeader(taskId);
+ getDisplayContent().mAppTransition.getAppTransitionThumbnailHeader(getTask());
if (thumbnailHeader == null) {
- ProtoLog.d(WM_DEBUG_APP_TRANSITIONS, "No thumbnail header bitmap for: %d", taskId);
+ ProtoLog.d(WM_DEBUG_APP_TRANSITIONS, "No thumbnail header bitmap for: %s", getTask());
return;
}
clearThumbnail();
@@ -6138,7 +5956,7 @@
final Rect insets = win != null ? win.getContentInsets() : null;
final Configuration displayConfig = mDisplayContent.getConfiguration();
return getDisplayContent().mAppTransition.createThumbnailAspectScaleAnimationLocked(
- appRect, insets, thumbnailHeader, getTask().mTaskId, displayConfig.uiMode,
+ appRect, insets, thumbnailHeader, getTask(), displayConfig.uiMode,
displayConfig.orientation);
}
@@ -6648,6 +6466,7 @@
}
@VisibleForTesting
+ @Override
Rect getAnimationBounds(int appStackClipMode) {
if (appStackClipMode == STACK_CLIP_BEFORE_ANIM && getStack() != null) {
// Using the stack bounds here effectively applies the clipping before animation.
@@ -7722,4 +7541,35 @@
System.arraycopy(translation, 0, mTranslation, 0, mTranslation.length);
}
}
+
+ @Override
+ RemoteAnimationTarget createRemoteAnimationTarget(
+ RemoteAnimationController.RemoteAnimationRecord record) {
+ final Task task = getTask();
+ final WindowState mainWindow = findMainWindow();
+ if (task == null || mainWindow == null) {
+ return null;
+ }
+ final Rect insets = new Rect();
+ mainWindow.getContentInsets(insets);
+ InsetUtils.addInsets(insets, getLetterboxInsets());
+ return new RemoteAnimationTarget(task.mTaskId, record.getMode(),
+ record.mAdapter.mCapturedLeash, !task.fillsParent(),
+ mainWindow.mWinAnimator.mLastClipRect, insets,
+ getPrefixOrderIndex(), record.mAdapter.mPosition,
+ record.mAdapter.mStackBounds, task.getWindowConfiguration(),
+ false /*isNotInRecents*/,
+ record.mThumbnailAdapter != null ? record.mThumbnailAdapter.mCapturedLeash : null,
+ record.mStartBounds);
+ }
+
+ @Override
+ void getAnimationFrames(Rect outFrame, Rect outInsets, Rect outStableInsets,
+ Rect outSurfaceInsets) {
+ final WindowState win = findMainWindow();
+ if (win == null) {
+ return;
+ }
+ win.getAnimationFrames(outFrame, outInsets, outStableInsets, outSurfaceInsets);
+ }
}
diff --git a/services/core/java/com/android/server/wm/AppTransition.java b/services/core/java/com/android/server/wm/AppTransition.java
index c1143c8..cb9a200 100644
--- a/services/core/java/com/android/server/wm/AppTransition.java
+++ b/services/core/java/com/android/server/wm/AppTransition.java
@@ -219,7 +219,7 @@
private int mNextAppTransitionExit;
private int mNextAppTransitionInPlace;
- // Keyed by task id.
+ // Keyed by WindowContainer hashCode.
private final SparseArray<AppTransitionAnimationSpec> mNextAppTransitionAnimationsSpecs
= new SparseArray<>();
private IAppTransitionAnimationSpecsFuture mNextAppTransitionAnimationsSpecsFuture;
@@ -372,8 +372,9 @@
setAppTransitionState(APP_STATE_TIMEOUT);
}
- GraphicBuffer getAppTransitionThumbnailHeader(int taskId) {
- AppTransitionAnimationSpec spec = mNextAppTransitionAnimationsSpecs.get(taskId);
+ GraphicBuffer getAppTransitionThumbnailHeader(WindowContainer container) {
+ AppTransitionAnimationSpec spec = mNextAppTransitionAnimationsSpecs.get(
+ container.hashCode());
if (spec == null) {
spec = mDefaultNextAppTransitionAnimationSpec;
}
@@ -789,14 +790,15 @@
}
}
- void getNextAppTransitionStartRect(int taskId, Rect rect) {
- AppTransitionAnimationSpec spec = mNextAppTransitionAnimationsSpecs.get(taskId);
+ void getNextAppTransitionStartRect(WindowContainer container, Rect rect) {
+ AppTransitionAnimationSpec spec = mNextAppTransitionAnimationsSpecs.get(
+ container.hashCode());
if (spec == null) {
spec = mDefaultNextAppTransitionAnimationSpec;
}
if (spec == null || spec.rect == null) {
- Slog.e(TAG, "Starting rect for task: " + taskId + " requested, but not available",
- new Throwable());
+ Slog.e(TAG, "Starting rect for container: " + container
+ + " requested, but not available", new Throwable());
rect.setEmpty();
} else {
rect.set(spec.rect);
@@ -1065,7 +1067,7 @@
* when a thumbnail is specified with the pending animation override.
*/
Animation createThumbnailAspectScaleAnimationLocked(Rect appRect, @Nullable Rect contentInsets,
- GraphicBuffer thumbnailHeader, final int taskId, int uiMode, int orientation) {
+ GraphicBuffer thumbnailHeader, WindowContainer container, int uiMode, int orientation) {
Animation a;
final int thumbWidthI = thumbnailHeader.getWidth();
final float thumbWidth = thumbWidthI > 0 ? thumbWidthI : 1;
@@ -1073,7 +1075,7 @@
final int appWidth = appRect.width();
float scaleW = appWidth / thumbWidth;
- getNextAppTransitionStartRect(taskId, mTmpRect);
+ getNextAppTransitionStartRect(container, mTmpRect);
final float fromX;
float fromY;
final float toX;
@@ -1226,7 +1228,7 @@
Animation createAspectScaledThumbnailEnterExitAnimationLocked(int thumbTransitState,
int uiMode, int orientation, int transit, Rect containingFrame, Rect contentInsets,
@Nullable Rect surfaceInsets, @Nullable Rect stableInsets, boolean freeform,
- int taskId) {
+ WindowContainer container) {
Animation a;
final int appWidth = containingFrame.width();
final int appHeight = containingFrame.height();
@@ -1244,10 +1246,10 @@
final boolean scaleUp = thumbTransitState == THUMBNAIL_TRANSITION_ENTER_SCALE_UP;
if (freeform && scaleUp) {
a = createAspectScaledThumbnailEnterFreeformAnimationLocked(
- containingFrame, surfaceInsets, taskId);
+ containingFrame, surfaceInsets, container);
} else if (freeform) {
a = createAspectScaledThumbnailExitFreeformAnimationLocked(
- containingFrame, surfaceInsets, taskId);
+ containingFrame, surfaceInsets, container);
} else {
AnimationSet set = new AnimationSet(true);
@@ -1359,15 +1361,15 @@
}
private Animation createAspectScaledThumbnailEnterFreeformAnimationLocked(Rect frame,
- @Nullable Rect surfaceInsets, int taskId) {
- getNextAppTransitionStartRect(taskId, mTmpRect);
+ @Nullable Rect surfaceInsets, WindowContainer container) {
+ getNextAppTransitionStartRect(container, mTmpRect);
return createAspectScaledThumbnailFreeformAnimationLocked(mTmpRect, frame, surfaceInsets,
true);
}
private Animation createAspectScaledThumbnailExitFreeformAnimationLocked(Rect frame,
- @Nullable Rect surfaceInsets, int taskId) {
- getNextAppTransitionStartRect(taskId, mTmpRect);
+ @Nullable Rect surfaceInsets, WindowContainer container) {
+ getNextAppTransitionStartRect(container, mTmpRect);
return createAspectScaledThumbnailFreeformAnimationLocked(frame, mTmpRect, surfaceInsets,
false);
}
@@ -1469,10 +1471,10 @@
* leaving, and the activity that is entering.
*/
Animation createThumbnailEnterExitAnimationLocked(int thumbTransitState, Rect containingFrame,
- int transit, int taskId) {
+ int transit, WindowContainer container) {
final int appWidth = containingFrame.width();
final int appHeight = containingFrame.height();
- final GraphicBuffer thumbnailHeader = getAppTransitionThumbnailHeader(taskId);
+ final GraphicBuffer thumbnailHeader = getAppTransitionThumbnailHeader(container);
Animation a;
getDefaultNextAppTransitionStartRect(mTmpRect);
final int thumbWidthI = thumbnailHeader != null ? thumbnailHeader.getWidth() : appWidth;
@@ -1615,7 +1617,7 @@
Animation loadAnimation(LayoutParams lp, int transit, boolean enter, int uiMode,
int orientation, Rect frame, Rect displayFrame, Rect insets,
@Nullable Rect surfaceInsets, @Nullable Rect stableInsets, boolean isVoiceInteraction,
- boolean freeform, int taskId) {
+ boolean freeform, WindowContainer container) {
Animation a;
if (isKeyguardGoingAwayTransit(transit) && enter) {
a = loadKeyguardExitAnimation(transit);
@@ -1679,7 +1681,7 @@
mNextAppTransitionScaleUp =
(mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_UP);
a = createThumbnailEnterExitAnimationLocked(getThumbnailTransitionState(enter),
- frame, transit, taskId);
+ frame, transit, container);
ProtoLog.v(WM_DEBUG_APP_TRANSITIONS_ANIM,
"applyAnimation: anim=%s nextAppTransition=%s transit=%s isEntrance=%b "
+ "Callers=%s",
@@ -1692,7 +1694,7 @@
(mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_UP);
a = createAspectScaledThumbnailEnterExitAnimationLocked(
getThumbnailTransitionState(enter), uiMode, orientation, transit, frame,
- insets, surfaceInsets, stableInsets, freeform, taskId);
+ insets, surfaceInsets, stableInsets, freeform, container);
ProtoLog.v(WM_DEBUG_APP_TRANSITIONS_ANIM,
"applyAnimation: anim=%s nextAppTransition=%s transit=%s isEntrance=%b "
+ "Callers=%s",
@@ -1895,7 +1897,11 @@
for (int i = 0; i < specs.length; i++) {
AppTransitionAnimationSpec spec = specs[i];
if (spec != null) {
- mNextAppTransitionAnimationsSpecs.put(spec.taskId, spec);
+ final WindowContainer container = findTask(spec.taskId);
+ if (container == null) {
+ continue;
+ }
+ mNextAppTransitionAnimationsSpecs.put(container.hashCode(), spec);
if (i == 0) {
// In full screen mode, the transition code depends on the default spec
// to be set.
@@ -1912,6 +1918,19 @@
}
}
+ private Task findTask(int taskId) {
+ if (taskId < 0) {
+ return null;
+ }
+ ArrayList<Task> tasks = new ArrayList<>();
+ mDisplayContent.forAllTasks(task -> {
+ if (task.mTaskId == taskId) {
+ tasks.add(task);
+ }
+ });
+ return tasks.size() == 1 ? tasks.get(0) : null;
+ }
+
void overridePendingAppTransitionMultiThumbFuture(
IAppTransitionAnimationSpecsFuture specsFuture, IRemoteCallback callback,
boolean scaleUp) {
diff --git a/services/core/java/com/android/server/wm/AppTransitionController.java b/services/core/java/com/android/server/wm/AppTransitionController.java
index 3bda0c2..bef6af3 100644
--- a/services/core/java/com/android/server/wm/AppTransitionController.java
+++ b/services/core/java/com/android/server/wm/AppTransitionController.java
@@ -410,7 +410,7 @@
ActivityRecord activity = apps.valueAt(i);
ProtoLog.v(WM_DEBUG_APP_TRANSITIONS, "Now changing app %s", activity);
activity.cancelAnimationOnly();
- activity.applyAnimationLocked(null, transit, true, false);
+ activity.applyAnimation(null, transit, true, false);
activity.updateReportedVisibilityLocked();
mService.openSurfaceTransaction();
try {
diff --git a/services/core/java/com/android/server/wm/RemoteAnimationController.java b/services/core/java/com/android/server/wm/RemoteAnimationController.java
index c23ffd9..efd1241 100644
--- a/services/core/java/com/android/server/wm/RemoteAnimationController.java
+++ b/services/core/java/com/android/server/wm/RemoteAnimationController.java
@@ -41,7 +41,6 @@
import com.android.server.protolog.ProtoLogImpl;
import com.android.server.protolog.common.ProtoLog;
import com.android.server.wm.SurfaceAnimator.OnAnimationFinishedCallback;
-import com.android.server.wm.utils.InsetUtils;
import java.io.PrintWriter;
import java.io.StringWriter;
@@ -76,20 +75,20 @@
}
/**
- * Creates an animation record for each individual {@link ActivityRecord}.
+ * Creates an animation record for each individual {@link WindowContainer}.
*
- * @param activity The app to animate.
+ * @param windowContainer The windows to animate.
* @param position The position app bounds, in screen coordinates.
* @param stackBounds The stack bounds of the app relative to position.
* @param startBounds The stack bounds before the transition, in screen coordinates
* @return The record representing animation(s) to run on the app.
*/
- RemoteAnimationRecord createRemoteAnimationRecord(ActivityRecord activity, Point position,
- Rect stackBounds, Rect startBounds) {
- ProtoLog.d(WM_DEBUG_REMOTE_ANIMATIONS, "createAnimationAdapter(): token=%s",
- activity);
+ RemoteAnimationRecord createRemoteAnimationRecord(WindowContainer windowContainer,
+ Point position, Rect stackBounds, Rect startBounds) {
+ ProtoLog.d(WM_DEBUG_REMOTE_ANIMATIONS, "createAnimationAdapter(): container=%s",
+ windowContainer);
final RemoteAnimationRecord adapters =
- new RemoteAnimationRecord(activity, position, stackBounds, startBounds);
+ new RemoteAnimationRecord(windowContainer, position, stackBounds, startBounds);
mPendingAnimations.add(adapters);
return adapters;
}
@@ -169,11 +168,12 @@
final RemoteAnimationRecord wrappers = mPendingAnimations.get(i);
final RemoteAnimationTarget target = wrappers.createRemoteAnimationTarget();
if (target != null) {
- ProtoLog.d(WM_DEBUG_REMOTE_ANIMATIONS, "\tAdd token=%s", wrappers.mActivityRecord);
+ ProtoLog.d(WM_DEBUG_REMOTE_ANIMATIONS, "\tAdd container=%s",
+ wrappers.mWindowContainer);
targets.add(target);
} else {
- ProtoLog.d(WM_DEBUG_REMOTE_ANIMATIONS, "\tRemove token=%s",
- wrappers.mActivityRecord);
+ ProtoLog.d(WM_DEBUG_REMOTE_ANIMATIONS, "\tRemove container=%s",
+ wrappers.mWindowContainer);
// We can't really start an animation but we still need to make sure to finish the
// pending animation that was started by SurfaceAnimator
@@ -228,7 +228,8 @@
.onAnimationFinished(adapters.mThumbnailAdapter);
}
mPendingAnimations.remove(i);
- ProtoLog.d(WM_DEBUG_REMOTE_ANIMATIONS, "\tapp=%s", adapters.mActivityRecord);
+ ProtoLog.d(WM_DEBUG_REMOTE_ANIMATIONS, "\tcontainer=%s",
+ adapters.mWindowContainer);
}
for (int i = mPendingWallpaperAnimations.size() - 1; i >= 0; i--) {
@@ -332,7 +333,7 @@
};
/**
- * Contains information about a remote-animation for one AppWindowToken. This keeps track of,
+ * Contains information about a remote-animation for one WindowContainer. This keeps track of,
* potentially, multiple animating surfaces (AdapterWrappers) associated with one
* Window/Transition. For example, a change transition has an adapter controller for the
* main window and an adapter controlling the start-state snapshot.
@@ -345,12 +346,12 @@
RemoteAnimationAdapterWrapper mAdapter;
RemoteAnimationAdapterWrapper mThumbnailAdapter = null;
RemoteAnimationTarget mTarget;
- final ActivityRecord mActivityRecord;
+ final WindowContainer mWindowContainer;
final Rect mStartBounds;
- RemoteAnimationRecord(ActivityRecord activityRecord, Point endPos, Rect endBounds,
+ RemoteAnimationRecord(WindowContainer windowContainer, Point endPos, Rect endBounds,
Rect startBounds) {
- mActivityRecord = activityRecord;
+ mWindowContainer = windowContainer;
mAdapter = new RemoteAnimationAdapterWrapper(this, endPos, endBounds);
if (startBounds != null) {
mStartBounds = new Rect(startBounds);
@@ -366,31 +367,20 @@
}
RemoteAnimationTarget createRemoteAnimationTarget() {
- final Task task = mActivityRecord.getTask();
- final WindowState mainWindow = mActivityRecord.findMainWindow();
- if (task == null || mainWindow == null || mAdapter == null
+ if (mAdapter == null
|| mAdapter.mCapturedFinishCallback == null
|| mAdapter.mCapturedLeash == null) {
return null;
}
- final Rect insets = new Rect();
- mainWindow.getContentInsets(insets);
- InsetUtils.addInsets(insets, mActivityRecord.getLetterboxInsets());
- mTarget = new RemoteAnimationTarget(task.mTaskId, getMode(),
- mAdapter.mCapturedLeash, !mActivityRecord.fillsParent(),
- mainWindow.mWinAnimator.mLastClipRect, insets,
- mActivityRecord.getPrefixOrderIndex(), mAdapter.mPosition,
- mAdapter.mStackBounds, task.getWindowConfiguration(), false /*isNotInRecents*/,
- mThumbnailAdapter != null ? mThumbnailAdapter.mCapturedLeash : null,
- mStartBounds);
+ mTarget = mWindowContainer.createRemoteAnimationTarget(this);
return mTarget;
}
- private int getMode() {
- final DisplayContent dc = mActivityRecord.getDisplayContent();
- if (dc.mOpeningApps.contains(mActivityRecord)) {
+ int getMode() {
+ final DisplayContent dc = mWindowContainer.getDisplayContent();
+ if (dc.mOpeningApps.contains(mWindowContainer)) {
return RemoteAnimationTarget.MODE_OPENING;
- } else if (dc.mChangingApps.contains(mActivityRecord)) {
+ } else if (dc.mChangingApps.contains(mWindowContainer)) {
return RemoteAnimationTarget.MODE_CHANGING;
} else {
return RemoteAnimationTarget.MODE_CLOSING;
@@ -398,12 +388,12 @@
}
}
- private class RemoteAnimationAdapterWrapper implements AnimationAdapter {
+ class RemoteAnimationAdapterWrapper implements AnimationAdapter {
private final RemoteAnimationRecord mRecord;
SurfaceControl mCapturedLeash;
private OnAnimationFinishedCallback mCapturedFinishCallback;
- private final Point mPosition = new Point();
- private final Rect mStackBounds = new Rect();
+ final Point mPosition = new Point();
+ final Rect mStackBounds = new Rect();
RemoteAnimationAdapterWrapper(RemoteAnimationRecord record, Point position,
Rect stackBounds) {
@@ -423,7 +413,7 @@
ProtoLog.d(WM_DEBUG_REMOTE_ANIMATIONS, "startAnimation");
// Restore z-layering, position and stack crop until client has a chance to modify it.
- t.setLayer(animationLeash, mRecord.mActivityRecord.getPrefixOrderIndex());
+ t.setLayer(animationLeash, mRecord.mWindowContainer.getPrefixOrderIndex());
if (mRecord.mStartBounds != null) {
t.setPosition(animationLeash, mRecord.mStartBounds.left, mRecord.mStartBounds.top);
t.setWindowCrop(animationLeash, mRecord.mStartBounds.width(),
@@ -464,7 +454,7 @@
@Override
public void dump(PrintWriter pw, String prefix) {
- pw.print(prefix); pw.print("token="); pw.println(mRecord.mActivityRecord);
+ pw.print(prefix); pw.print("container="); pw.println(mRecord.mWindowContainer);
if (mRecord.mTarget != null) {
pw.print(prefix); pw.println("Target:");
mRecord.mTarget.dump(pw, prefix + " ");
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index 8c03db5..92ff2dc 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -51,6 +51,7 @@
import android.util.Slog;
import android.util.proto.ProtoOutputStream;
import android.view.Display;
+import android.view.RemoteAnimationTarget;
import android.view.Surface;
import android.view.SurfaceControl;
@@ -646,6 +647,18 @@
return getAppAnimationLayer(ANIMATION_LAYER_HOME);
}
+ boolean shouldAnimate() {
+ // Don't animate while the task runs recents animation but only if we are in the mode
+ // where we cancel with deferred screenshot, which means that the controller has
+ // transformed the task.
+ final RecentsAnimationController controller = mWmService.getRecentsAnimationController();
+ if (controller != null && controller.isAnimatingTask(this)
+ && controller.shouldDeferCancelUntilNextTransition()) {
+ return false;
+ }
+ return true;
+ }
+
@Override
SurfaceControl.Builder makeSurface() {
return super.makeSurface().setMetadata(METADATA_TASK_ID, mTaskId);
@@ -661,6 +674,22 @@
return false;
}
+ /**
+ * @return {@code true} if changing app transition is running.
+ */
+ @Override
+ boolean isChangingAppTransition() {
+ final ActivityRecord activity = getTopVisibleActivity();
+ return activity != null && getDisplayContent().mChangingApps.contains(activity);
+ }
+
+ @Override
+ RemoteAnimationTarget createRemoteAnimationTarget(
+ RemoteAnimationController.RemoteAnimationRecord record) {
+ final ActivityRecord activity = getTopVisibleActivity();
+ return activity != null ? activity.createRemoteAnimationTarget(record) : null;
+ }
+
WindowState getTopVisibleAppMainWindow() {
final ActivityRecord activity = getTopVisibleActivity();
return activity != null ? activity.findMainWindow() : null;
diff --git a/services/core/java/com/android/server/wm/TaskStack.java b/services/core/java/com/android/server/wm/TaskStack.java
index ca41bc5..8f8c7e7 100644
--- a/services/core/java/com/android/server/wm/TaskStack.java
+++ b/services/core/java/com/android/server/wm/TaskStack.java
@@ -71,6 +71,7 @@
import android.util.proto.ProtoOutputStream;
import android.view.DisplayCutout;
import android.view.DisplayInfo;
+import android.view.RemoteAnimationTarget;
import android.view.SurfaceControl;
import com.android.internal.annotations.VisibleForTesting;
@@ -1868,4 +1869,11 @@
AnimatingActivityRegistry getAnimatingActivityRegistry() {
return mAnimatingActivityRegistry;
}
+
+ @Override
+ RemoteAnimationTarget createRemoteAnimationTarget(
+ RemoteAnimationController.RemoteAnimationRecord record) {
+ final Task task = getTopChild();
+ return task != null ? task.createRemoteAnimationTarget(record) : null;
+ }
}
diff --git a/services/core/java/com/android/server/wm/WallpaperController.java b/services/core/java/com/android/server/wm/WallpaperController.java
index 3142da5..3632284 100644
--- a/services/core/java/com/android/server/wm/WallpaperController.java
+++ b/services/core/java/com/android/server/wm/WallpaperController.java
@@ -162,7 +162,8 @@
final RecentsAnimationController recentsAnimationController =
mService.getRecentsAnimationController();
- final boolean animationWallpaper = w.mActivityRecord != null && w.mActivityRecord.getAnimation() != null
+ final boolean animationWallpaper = w.mActivityRecord != null
+ && w.mActivityRecord.getAnimation() != null
&& w.mActivityRecord.getAnimation().getShowWallpaper();
final boolean hasWallpaper = (w.mAttrs.flags & FLAG_SHOW_WALLPAPER) != 0
|| animationWallpaper;
diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java
index ac4f7b6..7ce2b5e 100644
--- a/services/core/java/com/android/server/wm/WindowContainer.java
+++ b/services/core/java/com/android/server/wm/WindowContainer.java
@@ -24,8 +24,12 @@
import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
import static android.content.res.Configuration.ORIENTATION_UNDEFINED;
+import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
import static android.view.SurfaceControl.Transaction;
+import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
+import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_APP_TRANSITIONS;
+import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_APP_TRANSITIONS_ANIM;
import static com.android.server.wm.WindowContainer.AnimationFlags.CHILDREN;
import static com.android.server.wm.WindowContainer.AnimationFlags.PARENTS;
import static com.android.server.wm.WindowContainer.AnimationFlags.TRANSITION;
@@ -36,7 +40,9 @@
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ANIM;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
+import static com.android.server.wm.WindowManagerService.logWithStack;
import static com.android.server.wm.WindowStateAnimator.DRAW_PENDING;
+import static com.android.server.wm.WindowStateAnimator.STACK_CLIP_AFTER_ANIM;
import android.annotation.CallSuper;
import android.annotation.IntDef;
@@ -48,17 +54,24 @@
import android.graphics.Rect;
import android.os.Debug;
import android.os.IBinder;
+import android.os.Trace;
+import android.util.Pair;
import android.util.Pools;
import android.util.Slog;
import android.util.proto.ProtoOutputStream;
+import android.view.DisplayInfo;
import android.view.MagnificationSpec;
+import android.view.RemoteAnimationTarget;
import android.view.SurfaceControl;
import android.view.SurfaceControl.Builder;
import android.view.SurfaceSession;
+import android.view.WindowManager;
+import android.view.animation.Animation;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.ToBooleanFunction;
import com.android.server.policy.WindowManagerPolicy;
+import com.android.server.protolog.common.ProtoLog;
import com.android.server.wm.SurfaceAnimator.Animatable;
import java.io.PrintWriter;
@@ -189,6 +202,47 @@
void onPreAssignChildLayers();
}
+ /**
+ * True if this an AppWindowToken and the activity which created this was launched with
+ * ActivityOptions.setLaunchTaskBehind.
+ *
+ * TODO(b/142617871): We run a special animation when the activity was launched with that
+ * flag, but it's not necessary anymore. Keep the window invisible until the task is explicitly
+ * selected to suppress an animation, and remove this flag.
+ */
+ boolean mLaunchTaskBehind;
+
+ /**
+ * If we are running an animation, this determines the transition type. Must be one of
+ * {@link AppTransition#TransitionFlags}.
+ */
+ int mTransit;
+
+ /**
+ * If we are running an animation, this determines the flags during this animation. Must be a
+ * bitwise combination of AppTransition.TRANSIT_FLAG_* constants.
+ */
+ int mTransitFlags;
+
+ /** Whether this container should be boosted at the top of all its siblings. */
+ @VisibleForTesting boolean mNeedsZBoost;
+
+ /** Layer used to constrain the animation to a container's stack bounds. */
+ SurfaceControl mAnimationBoundsLayer;
+
+ /** Whether this container needs to create mAnimationBoundsLayer for cropping animations. */
+ boolean mNeedsAnimationBoundsLayer;
+
+ /**
+ * This gets used during some open/close transitions as well as during a change transition
+ * where it represents the starting-state snapshot.
+ */
+ AppWindowThumbnail mThumbnail;
+ final Rect mTransitStartRect = new Rect();
+ final Point mTmpPoint = new Point();
+ protected final Rect mTmpRect = new Rect();
+ final Rect mTmpPrevBounds = new Rect();
+
WindowContainer(WindowManagerService wms) {
mWmService = wms;
mPendingTransaction = wms.mTransactionFactory.get();
@@ -735,6 +789,13 @@
return isAnimating(0 /* self only */);
}
+ /**
+ * @return {@code true} if the container is in changing app transition.
+ */
+ boolean isChangingAppTransition() {
+ return false;
+ }
+
void sendAppVisibilityToClients() {
for (int i = mChildren.size() - 1; i >= 0; --i) {
final WindowContainer wc = mChildren.get(i);
@@ -1423,6 +1484,203 @@
return null;
}
+ // TODO: Remove this and use #getBounds() instead once we set an app transition animation
+ // on TaskStack.
+ Rect getAnimationBounds(int appStackClipMode) {
+ return getBounds();
+ }
+
+ /**
+ * Applies the app transition animation according the given the layout properties in the
+ * window hierarchy.
+ *
+ * @param lp The layout parameters of the window.
+ * @param transit The app transition type indicates what kind of transition to be applied.
+ * @param enter Whether the app transition is entering transition or not.
+ * @param isVoiceInteraction Whether the container is participating in voice interaction or not.
+ *
+ * @return {@code true} when the container applied the app transition, {@code false} if the
+ * app transition is disabled or skipped.
+ *
+ * @see #getAnimationAdapter
+ */
+ boolean applyAnimation(WindowManager.LayoutParams lp, int transit, boolean enter,
+ boolean isVoiceInteraction) {
+ if (mWmService.mDisableTransitionAnimation) {
+ ProtoLog.v(WM_DEBUG_APP_TRANSITIONS_ANIM,
+ "applyAnimation: transition animation is disabled or skipped. "
+ + "container=%s", this);
+ cancelAnimation();
+ return false;
+ }
+
+ // Only apply an animation if the display isn't frozen. If it is frozen, there is no reason
+ // to animate and it can cause strange artifacts when we unfreeze the display if some
+ // different animation is running.
+ try {
+ Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "WC#applyAnimation");
+ if (okToAnimate()) {
+ Pair<AnimationAdapter, AnimationAdapter> adapters = getAnimationAdapter(lp, transit,
+ enter, isVoiceInteraction);
+ AnimationAdapter adapter = adapters.first;
+ AnimationAdapter thumbnailAdapter = adapters.second;
+ if (adapter != null) {
+ startAnimation(getPendingTransaction(), adapter, !isVisible());
+ if (adapter.getShowWallpaper()) {
+ mDisplayContent.pendingLayoutChanges |= FINISH_LAYOUT_REDO_WALLPAPER;
+ }
+ if (thumbnailAdapter != null) {
+ mThumbnail.startAnimation(
+ getPendingTransaction(), thumbnailAdapter, !isVisible());
+ }
+ }
+ } else {
+ cancelAnimation();
+ }
+ } finally {
+ Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
+ }
+
+ return isAnimating();
+ }
+
+ /**
+ * Gets the {@link AnimationAdapter} according the given window layout properties in the window
+ * hierarchy.
+ *
+ * @return The return value will always contain two elements, one for normal animations and the
+ * other for thumbnail animation, both can be {@code null}.
+ *
+ * @See com.android.server.wm.RemoteAnimationController.RemoteAnimationRecord
+ * @See LocalAnimationAdapter
+ */
+ Pair<AnimationAdapter, AnimationAdapter> getAnimationAdapter(WindowManager.LayoutParams lp,
+ int transit, boolean enter, boolean isVoiceInteraction) {
+ final Pair<AnimationAdapter, AnimationAdapter> resultAdapters;
+ final int appStackClipMode = getDisplayContent().mAppTransition.getAppStackClipMode();
+
+ // Separate position and size for use in animators.
+ mTmpRect.set(getAnimationBounds(appStackClipMode));
+ mTmpPoint.set(mTmpRect.left, mTmpRect.top);
+ mTmpRect.offsetTo(0, 0);
+
+ final RemoteAnimationController controller =
+ getDisplayContent().mAppTransition.getRemoteAnimationController();
+ final boolean isChanging = AppTransition.isChangeTransit(transit) && enter
+ && isChangingAppTransition();
+
+ // Delaying animation start isn't compatible with remote animations at all.
+ if (controller != null && !mSurfaceAnimator.isAnimationStartDelayed()) {
+ final RemoteAnimationController.RemoteAnimationRecord adapters =
+ controller.createRemoteAnimationRecord(this, mTmpPoint, mTmpRect,
+ (isChanging ? mTransitStartRect : null));
+ resultAdapters = new Pair<>(adapters.mAdapter, adapters.mThumbnailAdapter);
+ } else if (isChanging) {
+ final float durationScale = mWmService.getTransitionAnimationScaleLocked();
+ final DisplayInfo displayInfo = getDisplayContent().getDisplayInfo();
+ mTmpRect.offsetTo(mTmpPoint.x, mTmpPoint.y);
+
+ AnimationAdapter adapter = new LocalAnimationAdapter(
+ new WindowChangeAnimationSpec(mTransitStartRect, mTmpRect, displayInfo,
+ durationScale, true /* isAppAnimation */, false /* isThumbnail */),
+ getSurfaceAnimationRunner());
+
+ AnimationAdapter thumbnailAdapter = null;
+ if (mThumbnail != null) {
+ thumbnailAdapter = new LocalAnimationAdapter(
+ new WindowChangeAnimationSpec(mTransitStartRect, mTmpRect, displayInfo,
+ durationScale, true /* isAppAnimation */, true /* isThumbnail */),
+ getSurfaceAnimationRunner());
+ }
+ resultAdapters = new Pair<>(adapter, thumbnailAdapter);
+ mTransit = transit;
+ mTransitFlags = getDisplayContent().mAppTransition.getTransitFlags();
+ } else {
+ mNeedsAnimationBoundsLayer = (appStackClipMode == STACK_CLIP_AFTER_ANIM);
+ final Animation a = loadAnimation(lp, transit, enter, isVoiceInteraction);
+
+ if (a != null) {
+ // Only apply corner radius to animation if we're not in multi window mode.
+ // We don't want rounded corners when in pip or split screen.
+ final float windowCornerRadius = !inMultiWindowMode()
+ ? getDisplayContent().getWindowCornerRadius()
+ : 0;
+ AnimationAdapter adapter = new LocalAnimationAdapter(
+ new WindowAnimationSpec(a, mTmpPoint, mTmpRect,
+ getDisplayContent().mAppTransition.canSkipFirstFrame(),
+ appStackClipMode, true /* isAppAnimation */, windowCornerRadius),
+ getSurfaceAnimationRunner());
+
+ resultAdapters = new Pair<>(adapter, null);
+ mNeedsZBoost = a.getZAdjustment() == Animation.ZORDER_TOP;
+ mTransit = transit;
+ mTransitFlags = getDisplayContent().mAppTransition.getTransitFlags();
+ } else {
+ resultAdapters = new Pair<>(null, null);
+ }
+ }
+ return resultAdapters;
+ }
+
+ final SurfaceAnimationRunner getSurfaceAnimationRunner() {
+ return mWmService.mSurfaceAnimationRunner;
+ }
+
+ private Animation loadAnimation(WindowManager.LayoutParams lp, int transit, boolean enter,
+ boolean isVoiceInteraction) {
+ final DisplayContent displayContent = getDisplayContent();
+ final DisplayInfo displayInfo = displayContent.getDisplayInfo();
+ final int width = displayInfo.appWidth;
+ final int height = displayInfo.appHeight;
+ ProtoLog.v(WM_DEBUG_APP_TRANSITIONS_ANIM, "applyAnimation: container=%s", this);
+
+ // Determine the visible rect to calculate the thumbnail clip with
+ // getAnimationFrames.
+ final Rect frame = new Rect(0, 0, width, height);
+ final Rect displayFrame = new Rect(0, 0,
+ displayInfo.logicalWidth, displayInfo.logicalHeight);
+ final Rect insets = new Rect();
+ final Rect stableInsets = new Rect();
+ final Rect surfaceInsets = new Rect();
+ getAnimationFrames(frame, insets, stableInsets, surfaceInsets);
+
+ if (mLaunchTaskBehind) {
+ // Differentiate the two animations. This one which is briefly on the screen
+ // gets the !enter animation, and the other one which remains on the
+ // screen gets the enter animation. Both appear in the mOpeningApps set.
+ enter = false;
+ }
+ ProtoLog.d(WM_DEBUG_APP_TRANSITIONS,
+ "Loading animation for app transition. transit=%s enter=%b frame=%s insets=%s "
+ + "surfaceInsets=%s",
+ AppTransition.appTransitionToString(transit), enter, frame, insets, surfaceInsets);
+ final Configuration displayConfig = displayContent.getConfiguration();
+ final Animation a = getDisplayContent().mAppTransition.loadAnimation(lp, transit, enter,
+ displayConfig.uiMode, displayConfig.orientation, frame, displayFrame, insets,
+ surfaceInsets, stableInsets, isVoiceInteraction, inFreeformWindowingMode(), this);
+ if (a != null) {
+ if (DEBUG_ANIM) logWithStack(TAG, "Loaded animation " + a + " for " + this);
+ final int containingWidth = frame.width();
+ final int containingHeight = frame.height();
+ a.initialize(containingWidth, containingHeight, width, height);
+ a.scaleCurrentDuration(mWmService.getTransitionAnimationScaleLocked());
+ }
+ return a;
+ }
+
+ RemoteAnimationTarget createRemoteAnimationTarget(
+ RemoteAnimationController.RemoteAnimationRecord record) {
+ return null;
+ }
+
+ boolean okToDisplay() {
+ return mDisplayContent != null && mDisplayContent.okToDisplay();
+ }
+
+ boolean okToAnimate() {
+ return mDisplayContent != null && mDisplayContent.okToAnimate();
+ }
+
@Override
public void commitPendingTransaction() {
scheduleAnimation();
@@ -1522,6 +1780,26 @@
return getBounds();
}
+ /**
+ * The {@code outFrame} retrieved by this method specifies where the animation will finish
+ * the entrance animation, as the next frame will display the window at these coordinates. In
+ * case of exit animation, this is where the animation will start, as the frame before the
+ * animation is displaying the window at these bounds.
+ *
+ * @param outFrame The bounds where entrance animation finishes or exit animation starts.
+ * @param outInsets Insets that are covered by system windows.
+ * @param outStableInsets Insets that determine the area covered by the stable system windows.
+ * @param outSurfaceInsets Positive insets between the drawing surface and window content.
+ */
+ void getAnimationFrames(Rect outFrame, Rect outInsets, Rect outStableInsets,
+ Rect outSurfaceInsets) {
+ final DisplayInfo displayInfo = getDisplayContent().getDisplayInfo();
+ outFrame.set(0, 0, displayInfo.appWidth, displayInfo.appHeight);
+ outInsets.setEmpty();
+ outStableInsets.setEmpty();
+ outSurfaceInsets.setEmpty();
+ }
+
void getRelativeDisplayedPosition(Point outPos) {
final Rect dispBounds = getDisplayedBounds();
outPos.set(dispBounds.left, dispBounds.top);
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index d87c5bb..f7402e1 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -5404,4 +5404,29 @@
}
return mKeyInterceptionInfo;
}
+
+ @Override
+ void getAnimationFrames(Rect outFrame, Rect outInsets, Rect outStableInsets,
+ Rect outSurfaceInsets) {
+ // Containing frame will usually cover the whole screen, including dialog windows.
+ // For freeform workspace windows it will not cover the whole screen and it also
+ // won't exactly match the final freeform window frame (e.g. when overlapping with
+ // the status bar). In that case we need to use the final frame.
+ if (inFreeformWindowingMode()) {
+ outFrame.set(getFrameLw());
+ } else if (isLetterboxedAppWindow()) {
+ outFrame.set(getTask().getBounds());
+ } else if (isDockedResizing()) {
+ // If we are animating while docked resizing, then use the stack bounds as the
+ // animation target (which will be different than the task bounds)
+ outFrame.set(getTask().getParent().getBounds());
+ } else {
+ outFrame.set(getContainingFrame());
+ }
+ outSurfaceInsets.set(getAttrs().surfaceInsets);
+ // TODO(b/72757033): These are insets relative to the window frame, but we're really
+ // interested in the insets relative to the frame we chose in the if-blocks above.
+ getContentInsets(outInsets);
+ getStableInsets(outStableInsets);
+ }
}
diff --git a/services/core/java/com/android/server/wm/WindowToken.java b/services/core/java/com/android/server/wm/WindowToken.java
index dda2a2d..88a1458 100644
--- a/services/core/java/com/android/server/wm/WindowToken.java
+++ b/services/core/java/com/android/server/wm/WindowToken.java
@@ -321,14 +321,6 @@
return toString();
}
- boolean okToDisplay() {
- return mDisplayContent != null && mDisplayContent.okToDisplay();
- }
-
- boolean okToAnimate() {
- return mDisplayContent != null && mDisplayContent.okToAnimate();
- }
-
/**
* Return whether windows from this token can layer above the
* system bars, or in other words extend outside of the "Decor Frame"