Merge "Generalize change transition into WindowContainer" into rvc-dev am: 66279fe163
Change-Id: I18bd10524fe03ada89d179d3de9a087dc22f5112
This commit is contained in:
@@ -697,6 +697,12 @@
|
||||
"group": "WM_DEBUG_FOCUS_LIGHT",
|
||||
"at": "com\/android\/server\/wm\/RootWindowContainer.java"
|
||||
},
|
||||
"-668956537": {
|
||||
"message": " THUMBNAIL %s: CREATE",
|
||||
"level": "INFO",
|
||||
"group": "WM_SHOW_TRANSACTIONS",
|
||||
"at": "com\/android\/server\/wm\/SurfaceFreezer.java"
|
||||
},
|
||||
"-666510420": {
|
||||
"message": "With display frozen, orientationChangeComplete=%b",
|
||||
"level": "VERBOSE",
|
||||
|
||||
@@ -275,8 +275,9 @@ class ActivityMetricsLogger {
|
||||
}
|
||||
|
||||
/** @return {@code true} if the activity matches a launched activity in this transition. */
|
||||
boolean contains(ActivityRecord r) {
|
||||
return r == mLastLaunchedActivity || mPendingDrawActivities.contains(r);
|
||||
boolean contains(WindowContainer wc) {
|
||||
final ActivityRecord r = AppTransitionController.getAppFromContainer(wc);
|
||||
return r != null && (r == mLastLaunchedActivity || mPendingDrawActivities.contains(r));
|
||||
}
|
||||
|
||||
/** Called when the activity is drawn or won't be drawn. */
|
||||
@@ -435,10 +436,10 @@ class ActivityMetricsLogger {
|
||||
|
||||
/** @return Non-null {@link TransitionInfo} if the activity is found in an active transition. */
|
||||
@Nullable
|
||||
private TransitionInfo getActiveTransitionInfo(ActivityRecord r) {
|
||||
private TransitionInfo getActiveTransitionInfo(WindowContainer wc) {
|
||||
for (int i = mTransitionInfoList.size() - 1; i >= 0; i--) {
|
||||
final TransitionInfo info = mTransitionInfoList.get(i);
|
||||
if (info.contains(r)) {
|
||||
if (info.contains(wc)) {
|
||||
return info;
|
||||
}
|
||||
}
|
||||
@@ -623,19 +624,19 @@ class ActivityMetricsLogger {
|
||||
* @param activityToReason A map from activity to a reason integer, which must be on of
|
||||
* ActivityTaskManagerInternal.APP_TRANSITION_* reasons.
|
||||
*/
|
||||
void notifyTransitionStarting(ArrayMap<ActivityRecord, Integer> activityToReason) {
|
||||
void notifyTransitionStarting(ArrayMap<WindowContainer, Integer> activityToReason) {
|
||||
if (DEBUG_METRICS) Slog.i(TAG, "notifyTransitionStarting");
|
||||
|
||||
final long timestampNs = SystemClock.elapsedRealtimeNanos();
|
||||
for (int index = activityToReason.size() - 1; index >= 0; index--) {
|
||||
final ActivityRecord r = activityToReason.keyAt(index);
|
||||
final TransitionInfo info = getActiveTransitionInfo(r);
|
||||
final WindowContainer wc = activityToReason.keyAt(index);
|
||||
final TransitionInfo info = getActiveTransitionInfo(wc);
|
||||
if (info == null || info.mLoggedTransitionStarting) {
|
||||
// Ignore any subsequent notifyTransitionStarting.
|
||||
continue;
|
||||
}
|
||||
if (DEBUG_METRICS) {
|
||||
Slog.i(TAG, "notifyTransitionStarting activity=" + r + " info=" + info);
|
||||
Slog.i(TAG, "notifyTransitionStarting activity=" + wc + " info=" + info);
|
||||
}
|
||||
|
||||
info.mCurrentTransitionDelayMs = info.calculateDelay(timestampNs);
|
||||
|
||||
@@ -40,7 +40,6 @@ import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
|
||||
import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS;
|
||||
import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
|
||||
import static android.app.WindowConfiguration.ROTATION_UNDEFINED;
|
||||
import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
|
||||
import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
|
||||
import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
|
||||
import static android.app.WindowConfiguration.activityTypeToString;
|
||||
@@ -106,7 +105,6 @@ import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
|
||||
import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
|
||||
import static android.view.WindowManager.TRANSIT_ACTIVITY_CLOSE;
|
||||
import static android.view.WindowManager.TRANSIT_DOCK_TASK_FROM_RECENTS;
|
||||
import static android.view.WindowManager.TRANSIT_TASK_CHANGE_WINDOWING_MODE;
|
||||
import static android.view.WindowManager.TRANSIT_TASK_CLOSE;
|
||||
import static android.view.WindowManager.TRANSIT_TASK_OPEN_BEHIND;
|
||||
import static android.view.WindowManager.TRANSIT_UNSET;
|
||||
@@ -284,7 +282,6 @@ import android.view.DisplayInfo;
|
||||
import android.view.IAppTransitionAnimationSpecsFuture;
|
||||
import android.view.IApplicationToken;
|
||||
import android.view.InputApplicationHandle;
|
||||
import android.view.RemoteAnimationAdapter;
|
||||
import android.view.RemoteAnimationDefinition;
|
||||
import android.view.RemoteAnimationTarget;
|
||||
import android.view.SurfaceControl;
|
||||
@@ -577,12 +574,6 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
|
||||
*/
|
||||
private boolean mCurrentLaunchCanTurnScreenOn = true;
|
||||
|
||||
/**
|
||||
* This leash is used to "freeze" the app surface in place after the state change, but before
|
||||
* the animation is ready to start.
|
||||
*/
|
||||
private SurfaceControl mTransitChangeLeash = null;
|
||||
|
||||
/** Whether our surface was set to be showing in the last call to {@link #prepareSurfaces} */
|
||||
private boolean mLastSurfaceShowing = true;
|
||||
|
||||
@@ -1329,15 +1320,6 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
|
||||
mDisplayContent.executeAppTransition();
|
||||
}
|
||||
|
||||
if (prevDc.mChangingApps.remove(this)) {
|
||||
// This gets called *after* the ActivityRecord has been reparented to the new display.
|
||||
// That reparenting resulted in this window changing modes (eg. FREEFORM -> FULLSCREEN),
|
||||
// so this token is now "frozen" while waiting for the animation to start on prevDc
|
||||
// (which will be cancelled since the window is no-longer a child). However, since this
|
||||
// is no longer a child of prevDc, this won't be notified of the cancelled animation,
|
||||
// so we need to cancel the change transition here.
|
||||
clearChangeLeash(getPendingTransaction(), true /* cancel */);
|
||||
}
|
||||
prevDc.mClosingApps.remove(this);
|
||||
|
||||
if (prevDc.mFocusedApp == this) {
|
||||
@@ -3092,7 +3074,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
|
||||
commitVisibility(false /* visible */, true /* performLayout */);
|
||||
|
||||
getDisplayContent().mOpeningApps.remove(this);
|
||||
getDisplayContent().mChangingApps.remove(this);
|
||||
getDisplayContent().mChangingContainers.remove(this);
|
||||
getDisplayContent().mUnknownAppVisibilityController.appRemovedOrHidden(this);
|
||||
mWmService.mTaskSnapshotController.onAppRemoved(this);
|
||||
mStackSupervisor.getActivityMetricsLogger().notifyActivityRemoved(this);
|
||||
@@ -3995,13 +3977,11 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
|
||||
appToken, visible, appTransition, isVisible(), mVisibleRequested,
|
||||
Debug.getCallers(6));
|
||||
|
||||
onChildVisibilityRequested(visible);
|
||||
|
||||
final DisplayContent displayContent = getDisplayContent();
|
||||
displayContent.mOpeningApps.remove(this);
|
||||
displayContent.mClosingApps.remove(this);
|
||||
if (isInChangeTransition()) {
|
||||
clearChangeLeash(getPendingTransaction(), true /* cancel */);
|
||||
}
|
||||
displayContent.mChangingApps.remove(this);
|
||||
waitingToShow = false;
|
||||
mVisibleRequested = visible;
|
||||
mLastDeferHidingClient = deferHidingClient;
|
||||
@@ -5805,11 +5785,6 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
|
||||
return !isSplitScreenPrimary || allowSplitScreenPrimaryAnimation;
|
||||
}
|
||||
|
||||
@Override
|
||||
boolean isChangingAppTransition() {
|
||||
return task != null ? task.isChangingAppTransition() : super.isChangingAppTransition();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a layer to apply crop to an animation.
|
||||
*/
|
||||
@@ -5830,84 +5805,19 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
|
||||
this, endDeferFinishCallback);
|
||||
}
|
||||
|
||||
private boolean shouldStartChangeTransition(int prevWinMode, int newWinMode) {
|
||||
if (mWmService.mDisableTransitionAnimation
|
||||
|| !isVisible()
|
||||
|| getDisplayContent().mAppTransition.isTransitionSet()
|
||||
|| getSurfaceControl() == null) {
|
||||
return false;
|
||||
}
|
||||
// Only do an animation into and out-of freeform mode for now. Other mode
|
||||
// transition animations are currently handled by system-ui.
|
||||
return (prevWinMode == WINDOWING_MODE_FREEFORM) != (newWinMode == WINDOWING_MODE_FREEFORM);
|
||||
}
|
||||
|
||||
@Override
|
||||
boolean isWaitingForTransitionStart() {
|
||||
final DisplayContent dc = getDisplayContent();
|
||||
return dc != null && dc.mAppTransition.isTransitionSet()
|
||||
&& (dc.mOpeningApps.contains(this)
|
||||
|| dc.mClosingApps.contains(this)
|
||||
|| dc.mChangingApps.contains(this));
|
||||
|| dc.mChangingContainers.contains(this));
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes a change transition. Because the app is visible already, there is a small period
|
||||
* of time where the user can see the app content/window update before the transition starts.
|
||||
* To prevent this, we immediately take a snapshot and place the app/snapshot into a leash which
|
||||
* "freezes" the location/crop until the transition starts.
|
||||
* <p>
|
||||
* Here's a walk-through of the process:
|
||||
* 1. Create a temporary leash ("interim-change-leash") and reparent the app to it.
|
||||
* 2. Set the temporary leash's position/crop to the current state.
|
||||
* 3. Create a snapshot and place that at the top of the leash to cover up content changes.
|
||||
* 4. Once the transition is ready, it will reparent the app to the animation leash.
|
||||
* 5. Detach the interim-change-leash.
|
||||
*/
|
||||
private void initializeChangeTransition(Rect startBounds) {
|
||||
mDisplayContent.prepareAppTransition(TRANSIT_TASK_CHANGE_WINDOWING_MODE,
|
||||
false /* alwaysKeepCurrent */, 0, false /* forceOverride */);
|
||||
mDisplayContent.mChangingApps.add(this);
|
||||
mTransitStartRect.set(startBounds);
|
||||
|
||||
final SurfaceControl.Builder builder = makeAnimationLeash()
|
||||
.setParent(getAnimationLeashParent())
|
||||
.setName(getSurfaceControl() + " - interim-change-leash");
|
||||
mTransitChangeLeash = builder.build();
|
||||
Transaction t = getPendingTransaction();
|
||||
t.setWindowCrop(mTransitChangeLeash, startBounds.width(), startBounds.height());
|
||||
t.setPosition(mTransitChangeLeash, startBounds.left, startBounds.top);
|
||||
t.show(mTransitChangeLeash);
|
||||
t.reparent(getSurfaceControl(), mTransitChangeLeash);
|
||||
onAnimationLeashCreated(t, mTransitChangeLeash);
|
||||
|
||||
// Skip creating snapshot if this transition is controlled by a remote animator which
|
||||
// doesn't need it.
|
||||
ArraySet<Integer> activityTypes = new ArraySet<>();
|
||||
activityTypes.add(getActivityType());
|
||||
RemoteAnimationAdapter adapter =
|
||||
mDisplayContent.mAppTransitionController.getRemoteAnimationOverride(
|
||||
this, TRANSIT_TASK_CHANGE_WINDOWING_MODE, activityTypes);
|
||||
if (adapter != null && !adapter.getChangeNeedsSnapshot()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (mThumbnail == null && task != null && !hasCommittedReparentToAnimationLeash()) {
|
||||
SurfaceControl.ScreenshotGraphicBuffer snapshot =
|
||||
mWmService.mTaskSnapshotController.createTaskSnapshot(
|
||||
task, 1 /* scaleFraction */);
|
||||
if (snapshot != null) {
|
||||
mThumbnail = new WindowContainerThumbnail(mWmService.mSurfaceFactory, t, this,
|
||||
snapshot.getGraphicBuffer(), true /* relative */);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAnimationLeashCreated(Transaction t, SurfaceControl leash) {
|
||||
private int getAnimationLayer() {
|
||||
// The leash is parented to the animation layer. We need to preserve the z-order by using
|
||||
// the prefix order index, but we boost if necessary.
|
||||
int layer = 0;
|
||||
int layer;
|
||||
if (!inPinnedWindowingMode()) {
|
||||
layer = getPrefixOrderIndex();
|
||||
} else {
|
||||
@@ -5920,21 +5830,17 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
|
||||
if (mNeedsZBoost) {
|
||||
layer += Z_BOOST_BASE;
|
||||
}
|
||||
if (!mNeedsAnimationBoundsLayer) {
|
||||
t.setLayer(leash, layer);
|
||||
}
|
||||
return layer;
|
||||
}
|
||||
|
||||
final DisplayContent dc = getDisplayContent();
|
||||
dc.assignStackOrdering();
|
||||
|
||||
if (leash == mTransitChangeLeash) {
|
||||
// This is a temporary state so skip any animation notifications
|
||||
return;
|
||||
} else if (mTransitChangeLeash != null) {
|
||||
// unparent mTransitChangeLeash for clean-up
|
||||
clearChangeLeash(t, false /* cancel */);
|
||||
}
|
||||
@Override
|
||||
public void onAnimationLeashCreated(Transaction t, SurfaceControl leash) {
|
||||
t.setLayer(leash, getAnimationLayer());
|
||||
getDisplayContent().assignStackOrdering();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLeashAnimationStarting(Transaction t, SurfaceControl leash) {
|
||||
if (mAnimatingActivityRegistry != null) {
|
||||
mAnimatingActivityRegistry.notifyStarting(this);
|
||||
}
|
||||
@@ -5962,7 +5868,8 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
|
||||
// surface size has already same as the animating container.
|
||||
t.setWindowCrop(mAnimationBoundsLayer, mTmpRect);
|
||||
}
|
||||
t.setLayer(mAnimationBoundsLayer, layer);
|
||||
t.setLayer(leash, 0);
|
||||
t.setLayer(mAnimationBoundsLayer, getAnimationLayer());
|
||||
|
||||
// Reparent leash to animation bounds layer.
|
||||
t.reparent(leash, mAnimationBoundsLayer);
|
||||
@@ -5994,10 +5901,6 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
|
||||
return mLastSurfaceShowing;
|
||||
}
|
||||
|
||||
boolean isInChangeTransition() {
|
||||
return mTransitChangeLeash != null || AppTransition.isChangeTransit(mTransit);
|
||||
}
|
||||
|
||||
void attachThumbnailAnimation() {
|
||||
if (!isAnimating(PARENTS)) {
|
||||
return;
|
||||
@@ -6134,31 +6037,6 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
|
||||
Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param cancel {@code true} if clearing the leash due to cancelling instead of transferring
|
||||
* to another leash.
|
||||
*/
|
||||
private void clearChangeLeash(Transaction t, boolean cancel) {
|
||||
if (mTransitChangeLeash == null) {
|
||||
return;
|
||||
}
|
||||
if (cancel) {
|
||||
clearThumbnail();
|
||||
SurfaceControl sc = getSurfaceControl();
|
||||
SurfaceControl parentSc = getParentSurfaceControl();
|
||||
// Don't reparent if surface is getting destroyed
|
||||
if (parentSc != null && sc != null) {
|
||||
t.reparent(sc, getParentSurfaceControl());
|
||||
}
|
||||
}
|
||||
t.hide(mTransitChangeLeash);
|
||||
t.remove(mTransitChangeLeash);
|
||||
mTransitChangeLeash = null;
|
||||
if (cancel) {
|
||||
onAnimationLeashLost(t);
|
||||
}
|
||||
}
|
||||
|
||||
void clearAnimatingFlags() {
|
||||
boolean wallpaperMightChange = false;
|
||||
for (int i = mChildren.size() - 1; i >= 0; i--) {
|
||||
@@ -6174,7 +6052,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
|
||||
void cancelAnimation() {
|
||||
cancelAnimationOnly();
|
||||
clearThumbnail();
|
||||
clearChangeLeash(getPendingTransaction(), true /* cancel */);
|
||||
mSurfaceFreezer.unfreeze(getPendingTransaction());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -6219,6 +6097,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
|
||||
mRemoteAnimationDefinition = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
RemoteAnimationDefinition getRemoteAnimationDefinition() {
|
||||
return mRemoteAnimationDefinition;
|
||||
}
|
||||
@@ -6679,8 +6558,6 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
|
||||
return;
|
||||
}
|
||||
}
|
||||
final int prevWinMode = getWindowingMode();
|
||||
mTmpPrevBounds.set(getBounds());
|
||||
super.onConfigurationChanged(newParentConfig);
|
||||
|
||||
if (shouldUseSizeCompatMode()) {
|
||||
@@ -6705,12 +6582,6 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
|
||||
}
|
||||
}
|
||||
|
||||
final int newWinMode = getWindowingMode();
|
||||
if ((prevWinMode != newWinMode) && (mDisplayContent != null)
|
||||
&& shouldStartChangeTransition(prevWinMode, newWinMode)) {
|
||||
initializeChangeTransition(mTmpPrevBounds);
|
||||
}
|
||||
|
||||
// Configuration's equality doesn't consider seq so if only seq number changes in resolved
|
||||
// override configuration. Therefore ConfigurationContainer doesn't change merged override
|
||||
// configuration, but it's used to push configuration changes so explicitly update that.
|
||||
@@ -7595,6 +7466,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
void writeIdentifierToProto(ProtoOutputStream proto, long fieldId) {
|
||||
final long token = proto.start(fieldId);
|
||||
proto.write(HASH_CODE, System.identityHashCode(this));
|
||||
|
||||
@@ -2308,14 +2308,14 @@ public class AppTransition implements Dump {
|
||||
}
|
||||
notifyAppTransitionTimeoutLocked();
|
||||
if (isTransitionSet() || !dc.mOpeningApps.isEmpty() || !dc.mClosingApps.isEmpty()
|
||||
|| !dc.mChangingApps.isEmpty()) {
|
||||
|| !dc.mChangingContainers.isEmpty()) {
|
||||
ProtoLog.v(WM_DEBUG_APP_TRANSITIONS,
|
||||
"*** APP TRANSITION TIMEOUT. displayId=%d isTransitionSet()=%b "
|
||||
+ "mOpeningApps.size()=%d mClosingApps.size()=%d "
|
||||
+ "mChangingApps.size()=%d",
|
||||
dc.getDisplayId(), dc.mAppTransition.isTransitionSet(),
|
||||
dc.mOpeningApps.size(), dc.mClosingApps.size(),
|
||||
dc.mChangingApps.size());
|
||||
dc.mChangingContainers.size());
|
||||
|
||||
setTimeout();
|
||||
mService.mWindowPlacerLocked.performSurfacePlacement();
|
||||
|
||||
@@ -55,6 +55,7 @@ import static com.android.server.wm.WindowManagerDebugConfig.SHOW_LIGHT_TRANSACT
|
||||
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
|
||||
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.os.Trace;
|
||||
import android.util.ArrayMap;
|
||||
import android.util.ArraySet;
|
||||
@@ -86,7 +87,7 @@ public class AppTransitionController {
|
||||
private final WallpaperController mWallpaperControllerLocked;
|
||||
private RemoteAnimationDefinition mRemoteAnimationDefinition = null;
|
||||
|
||||
private final ArrayMap<ActivityRecord, Integer> mTempTransitionReasons = new ArrayMap<>();
|
||||
private final ArrayMap<WindowContainer, Integer> mTempTransitionReasons = new ArrayMap<>();
|
||||
|
||||
AppTransitionController(WindowManagerService service, DisplayContent displayContent) {
|
||||
mService = service;
|
||||
@@ -104,7 +105,8 @@ public class AppTransitionController {
|
||||
void handleAppTransitionReady() {
|
||||
mTempTransitionReasons.clear();
|
||||
if (!transitionGoodToGo(mDisplayContent.mOpeningApps, mTempTransitionReasons)
|
||||
|| !transitionGoodToGo(mDisplayContent.mChangingApps, mTempTransitionReasons)) {
|
||||
|| !transitionGoodToGo(mDisplayContent.mChangingContainers,
|
||||
mTempTransitionReasons)) {
|
||||
return;
|
||||
}
|
||||
Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "AppTransitionReady");
|
||||
@@ -130,17 +132,21 @@ public class AppTransitionController {
|
||||
// transition selection depends on wallpaper target visibility.
|
||||
mDisplayContent.mOpeningApps.valueAtUnchecked(i).clearAnimatingFlags();
|
||||
}
|
||||
appCount = mDisplayContent.mChangingApps.size();
|
||||
appCount = mDisplayContent.mChangingContainers.size();
|
||||
for (int i = 0; i < appCount; ++i) {
|
||||
// Clearing for same reason as above.
|
||||
mDisplayContent.mChangingApps.valueAtUnchecked(i).clearAnimatingFlags();
|
||||
final ActivityRecord activity = getAppFromContainer(
|
||||
mDisplayContent.mChangingContainers.valueAtUnchecked(i));
|
||||
if (activity != null) {
|
||||
activity.clearAnimatingFlags();
|
||||
}
|
||||
}
|
||||
|
||||
// Adjust wallpaper before we pull the lower/upper target, since pending changes
|
||||
// (like the clearAnimatingFlags() above) might affect wallpaper target result.
|
||||
// Or, the opening app window should be a wallpaper target.
|
||||
mWallpaperControllerLocked.adjustWallpaperWindowsForAppTransitionIfNeeded(
|
||||
mDisplayContent.mOpeningApps, mDisplayContent.mChangingApps);
|
||||
mDisplayContent.mOpeningApps);
|
||||
|
||||
// Determine if closing and opening app token sets are wallpaper targets, in which case
|
||||
// special animations are needed.
|
||||
@@ -159,7 +165,7 @@ public class AppTransitionController {
|
||||
// no need to do an animation. This is the case, for example, when this transition is being
|
||||
// done behind a dream window.
|
||||
final ArraySet<Integer> activityTypes = collectActivityTypes(mDisplayContent.mOpeningApps,
|
||||
mDisplayContent.mClosingApps, mDisplayContent.mChangingApps);
|
||||
mDisplayContent.mClosingApps, mDisplayContent.mChangingContainers);
|
||||
final boolean allowAnimations = mDisplayContent.getDisplayPolicy().allowAppAnimationsLw();
|
||||
final ActivityRecord animLpActivity = allowAnimations
|
||||
? findAnimLayoutParamsToken(transit, activityTypes)
|
||||
@@ -171,14 +177,13 @@ public class AppTransitionController {
|
||||
? getTopApp(mDisplayContent.mClosingApps, false /* ignoreHidden */)
|
||||
: null;
|
||||
final ActivityRecord topChangingApp = allowAnimations
|
||||
? getTopApp(mDisplayContent.mChangingApps, false /* ignoreHidden */)
|
||||
? getTopApp(mDisplayContent.mChangingContainers, false /* ignoreHidden */)
|
||||
: null;
|
||||
final WindowManager.LayoutParams animLp = getAnimLp(animLpActivity);
|
||||
overrideWithRemoteAnimationIfSet(animLpActivity, transit, activityTypes);
|
||||
|
||||
final boolean voiceInteraction = containsVoiceInteraction(mDisplayContent.mOpeningApps)
|
||||
|| containsVoiceInteraction(mDisplayContent.mOpeningApps)
|
||||
|| containsVoiceInteraction(mDisplayContent.mChangingApps);
|
||||
|| containsVoiceInteraction(mDisplayContent.mOpeningApps);
|
||||
|
||||
final int layoutRedo;
|
||||
mService.mSurfaceAnimationRunner.deferStartingAnimations();
|
||||
@@ -206,7 +211,7 @@ public class AppTransitionController {
|
||||
|
||||
mDisplayContent.mOpeningApps.clear();
|
||||
mDisplayContent.mClosingApps.clear();
|
||||
mDisplayContent.mChangingApps.clear();
|
||||
mDisplayContent.mChangingContainers.clear();
|
||||
mDisplayContent.mUnknownAppVisibilityController.clear();
|
||||
|
||||
// This has changed the visibility of windows, so perform
|
||||
@@ -235,9 +240,9 @@ public class AppTransitionController {
|
||||
return mainWindow != null ? mainWindow.mAttrs : null;
|
||||
}
|
||||
|
||||
RemoteAnimationAdapter getRemoteAnimationOverride(ActivityRecord animLpActivity,
|
||||
RemoteAnimationAdapter getRemoteAnimationOverride(@NonNull WindowContainer container,
|
||||
@TransitionType int transit, ArraySet<Integer> activityTypes) {
|
||||
final RemoteAnimationDefinition definition = animLpActivity.getRemoteAnimationDefinition();
|
||||
final RemoteAnimationDefinition definition = container.getRemoteAnimationDefinition();
|
||||
if (definition != null) {
|
||||
final RemoteAnimationAdapter adapter = definition.getAdapter(transit, activityTypes);
|
||||
if (adapter != null) {
|
||||
@@ -271,6 +276,11 @@ public class AppTransitionController {
|
||||
}
|
||||
}
|
||||
|
||||
static ActivityRecord getAppFromContainer(WindowContainer wc) {
|
||||
return wc.asTask() != null ? wc.asTask().getTopNonFinishingActivity()
|
||||
: wc.asActivityRecord();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The window token that determines the animation theme.
|
||||
*/
|
||||
@@ -279,14 +289,14 @@ public class AppTransitionController {
|
||||
ActivityRecord result;
|
||||
final ArraySet<ActivityRecord> closingApps = mDisplayContent.mClosingApps;
|
||||
final ArraySet<ActivityRecord> openingApps = mDisplayContent.mOpeningApps;
|
||||
final ArraySet<ActivityRecord> changingApps = mDisplayContent.mChangingApps;
|
||||
final ArraySet<WindowContainer> changingApps = mDisplayContent.mChangingContainers;
|
||||
|
||||
// Remote animations always win, but fullscreen tokens override non-fullscreen tokens.
|
||||
result = lookForHighestTokenWithFilter(closingApps, openingApps, changingApps,
|
||||
w -> w.getRemoteAnimationDefinition() != null
|
||||
&& w.getRemoteAnimationDefinition().hasTransition(transit, activityTypes));
|
||||
if (result != null) {
|
||||
return result;
|
||||
return getAppFromContainer(result);
|
||||
}
|
||||
result = lookForHighestTokenWithFilter(closingApps, openingApps, changingApps,
|
||||
w -> w.fillsParent() && w.findMainWindow() != null);
|
||||
@@ -302,7 +312,7 @@ public class AppTransitionController {
|
||||
* of apps in {@code array1}, {@code array2}, and {@code array3}.
|
||||
*/
|
||||
private static ArraySet<Integer> collectActivityTypes(ArraySet<ActivityRecord> array1,
|
||||
ArraySet<ActivityRecord> array2, ArraySet<ActivityRecord> array3) {
|
||||
ArraySet<ActivityRecord> array2, ArraySet<WindowContainer> array3) {
|
||||
final ArraySet<Integer> result = new ArraySet<>();
|
||||
for (int i = array1.size() - 1; i >= 0; i--) {
|
||||
result.add(array1.valueAt(i).getActivityType());
|
||||
@@ -317,7 +327,7 @@ public class AppTransitionController {
|
||||
}
|
||||
|
||||
private static ActivityRecord lookForHighestTokenWithFilter(ArraySet<ActivityRecord> array1,
|
||||
ArraySet<ActivityRecord> array2, ArraySet<ActivityRecord> array3,
|
||||
ArraySet<ActivityRecord> array2, ArraySet<WindowContainer> array3,
|
||||
Predicate<ActivityRecord> filter) {
|
||||
final int array2base = array1.size();
|
||||
final int array3base = array2.size() + array2base;
|
||||
@@ -325,15 +335,16 @@ public class AppTransitionController {
|
||||
int bestPrefixOrderIndex = Integer.MIN_VALUE;
|
||||
ActivityRecord bestToken = null;
|
||||
for (int i = 0; i < count; i++) {
|
||||
final ActivityRecord wtoken = i < array2base
|
||||
final WindowContainer wtoken = i < array2base
|
||||
? array1.valueAt(i)
|
||||
: (i < array3base
|
||||
? array2.valueAt(i - array2base)
|
||||
: array3.valueAt(i - array3base));
|
||||
final int prefixOrderIndex = wtoken.getPrefixOrderIndex();
|
||||
if (filter.test(wtoken) && prefixOrderIndex > bestPrefixOrderIndex) {
|
||||
final ActivityRecord r = getAppFromContainer(wtoken);
|
||||
if (r != null && filter.test(r) && prefixOrderIndex > bestPrefixOrderIndex) {
|
||||
bestPrefixOrderIndex = prefixOrderIndex;
|
||||
bestToken = wtoken;
|
||||
bestToken = r;
|
||||
}
|
||||
}
|
||||
return bestToken;
|
||||
@@ -589,21 +600,13 @@ public class AppTransitionController {
|
||||
}
|
||||
|
||||
private void handleChangingApps(@TransitionType int transit) {
|
||||
final ArraySet<ActivityRecord> apps = mDisplayContent.mChangingApps;
|
||||
final ArraySet<WindowContainer> apps = mDisplayContent.mChangingContainers;
|
||||
final int appsCount = apps.size();
|
||||
for (int i = 0; i < appsCount; i++) {
|
||||
ActivityRecord activity = apps.valueAt(i);
|
||||
ProtoLog.v(WM_DEBUG_APP_TRANSITIONS, "Now changing app %s", activity);
|
||||
activity.cancelAnimationOnly();
|
||||
activity.applyAnimation(null, transit, true, false,
|
||||
WindowContainer wc = apps.valueAt(i);
|
||||
ProtoLog.v(WM_DEBUG_APP_TRANSITIONS, "Now changing app %s", wc);
|
||||
wc.applyAnimation(null, transit, true, false,
|
||||
null /* animationFinishedCallback */);
|
||||
activity.updateReportedVisibilityLocked();
|
||||
mService.openSurfaceTransaction();
|
||||
try {
|
||||
activity.showAllWindowsLocked();
|
||||
} finally {
|
||||
mService.closeSurfaceTransaction("handleChangingApps");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -628,8 +631,8 @@ public class AppTransitionController {
|
||||
}
|
||||
}
|
||||
|
||||
private boolean transitionGoodToGo(ArraySet<ActivityRecord> apps,
|
||||
ArrayMap<ActivityRecord, Integer> outReasons) {
|
||||
private boolean transitionGoodToGo(ArraySet<? extends WindowContainer> apps,
|
||||
ArrayMap<WindowContainer, Integer> outReasons) {
|
||||
ProtoLog.v(WM_DEBUG_APP_TRANSITIONS,
|
||||
"Checking %d opening apps (frozen=%b timeout=%b)...", apps.size(),
|
||||
mService.mDisplayFrozen, mDisplayContent.mAppTransition.isTimeout());
|
||||
@@ -652,13 +655,17 @@ public class AppTransitionController {
|
||||
return false;
|
||||
}
|
||||
for (int i = 0; i < apps.size(); i++) {
|
||||
ActivityRecord activity = apps.valueAt(i);
|
||||
WindowContainer wc = apps.valueAt(i);
|
||||
final ActivityRecord activity = getAppFromContainer(wc);
|
||||
if (activity == null) {
|
||||
continue;
|
||||
}
|
||||
ProtoLog.v(WM_DEBUG_APP_TRANSITIONS,
|
||||
"Check opening app=%s: allDrawn=%b startingDisplayed=%b "
|
||||
+ "startingMoved=%b isRelaunching()=%b startingWindow=%s",
|
||||
activity, activity.allDrawn, activity.startingDisplayed,
|
||||
activity.startingMoved, activity.isRelaunching(),
|
||||
activity.startingWindow);
|
||||
"Check opening app=%s: allDrawn=%b startingDisplayed=%b "
|
||||
+ "startingMoved=%b isRelaunching()=%b startingWindow=%s",
|
||||
activity, activity.allDrawn, activity.startingDisplayed,
|
||||
activity.startingMoved, activity.isRelaunching(),
|
||||
activity.startingWindow);
|
||||
|
||||
|
||||
final boolean allDrawn = activity.allDrawn && !activity.isRelaunching();
|
||||
@@ -838,7 +845,7 @@ public class AppTransitionController {
|
||||
@VisibleForTesting
|
||||
boolean isTransitWithinTask(@TransitionType int transit, Task task) {
|
||||
if (task == null
|
||||
|| !mDisplayContent.mChangingApps.isEmpty()) {
|
||||
|| !mDisplayContent.mChangingContainers.isEmpty()) {
|
||||
// if there is no task, then we can't constrain to the task.
|
||||
// if anything is changing, it can animate outside its task.
|
||||
return false;
|
||||
@@ -882,12 +889,13 @@ public class AppTransitionController {
|
||||
* {@link ActivityRecord#isVisible}.
|
||||
* @return The top {@link ActivityRecord}.
|
||||
*/
|
||||
private ActivityRecord getTopApp(ArraySet<ActivityRecord> apps, boolean ignoreInvisible) {
|
||||
private ActivityRecord getTopApp(ArraySet<? extends WindowContainer> apps,
|
||||
boolean ignoreInvisible) {
|
||||
int topPrefixOrderIndex = Integer.MIN_VALUE;
|
||||
ActivityRecord topApp = null;
|
||||
for (int i = apps.size() - 1; i >= 0; i--) {
|
||||
final ActivityRecord app = apps.valueAt(i);
|
||||
if (ignoreInvisible && !app.isVisible()) {
|
||||
final ActivityRecord app = getAppFromContainer(apps.valueAt(i));
|
||||
if (app == null || ignoreInvisible && !app.isVisible()) {
|
||||
continue;
|
||||
}
|
||||
final int prefixOrderIndex = app.getPrefixOrderIndex();
|
||||
|
||||
@@ -91,7 +91,6 @@ import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_STATES;
|
||||
import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_TASKS;
|
||||
import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_STACK;
|
||||
import static com.android.server.wm.DisplayContentProto.APP_TRANSITION;
|
||||
import static com.android.server.wm.DisplayContentProto.CHANGING_APPS;
|
||||
import static com.android.server.wm.DisplayContentProto.CLOSING_APPS;
|
||||
import static com.android.server.wm.DisplayContentProto.DISPLAY_FRAMES;
|
||||
import static com.android.server.wm.DisplayContentProto.DISPLAY_INFO;
|
||||
@@ -314,7 +313,7 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
|
||||
|
||||
final ArraySet<ActivityRecord> mOpeningApps = new ArraySet<>();
|
||||
final ArraySet<ActivityRecord> mClosingApps = new ArraySet<>();
|
||||
final ArraySet<ActivityRecord> mChangingApps = new ArraySet<>();
|
||||
final ArraySet<WindowContainer> mChangingContainers = new ArraySet<>();
|
||||
final UnknownAppVisibilityController mUnknownAppVisibilityController;
|
||||
|
||||
private MetricsLogger mMetricsLogger;
|
||||
@@ -2695,7 +2694,7 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
|
||||
// Clear all transitions & screen frozen states when removing display.
|
||||
mOpeningApps.clear();
|
||||
mClosingApps.clear();
|
||||
mChangingApps.clear();
|
||||
mChangingContainers.clear();
|
||||
mUnknownAppVisibilityController.clear();
|
||||
mAppTransition.removeAppTransitionTimeoutCallbacks();
|
||||
handleAnimatingStoppedAndTransition();
|
||||
@@ -2916,9 +2915,6 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
|
||||
for (int i = mClosingApps.size() - 1; i >= 0; i--) {
|
||||
mClosingApps.valueAt(i).writeIdentifierToProto(proto, CLOSING_APPS);
|
||||
}
|
||||
for (int i = mChangingApps.size() - 1; i >= 0; i--) {
|
||||
mChangingApps.valueAt(i).writeIdentifierToProto(proto, CHANGING_APPS);
|
||||
}
|
||||
|
||||
proto.write(SINGLE_TASK_INSTANCE, mSingleTaskInstance);
|
||||
final ActivityStack focusedStack = getFocusedStack();
|
||||
@@ -3670,7 +3666,7 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
|
||||
}
|
||||
}
|
||||
|
||||
if (!mOpeningApps.isEmpty() || !mClosingApps.isEmpty() || !mChangingApps.isEmpty()) {
|
||||
if (!mOpeningApps.isEmpty() || !mClosingApps.isEmpty() || !mChangingContainers.isEmpty()) {
|
||||
pw.println();
|
||||
if (mOpeningApps.size() > 0) {
|
||||
pw.print(" mOpeningApps="); pw.println(mOpeningApps);
|
||||
@@ -3678,8 +3674,8 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
|
||||
if (mClosingApps.size() > 0) {
|
||||
pw.print(" mClosingApps="); pw.println(mClosingApps);
|
||||
}
|
||||
if (mChangingApps.size() > 0) {
|
||||
pw.print(" mChangingApps="); pw.println(mChangingApps);
|
||||
if (mChangingContainers.size() > 0) {
|
||||
pw.print(" mChangingApps="); pw.println(mChangingContainers);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -500,7 +500,7 @@ public class RecentsAnimationController implements DeathRecipient {
|
||||
}
|
||||
|
||||
if (mTargetActivityRecord != null) {
|
||||
final ArrayMap<ActivityRecord, Integer> reasons = new ArrayMap<>(1);
|
||||
final ArrayMap<WindowContainer, Integer> reasons = new ArrayMap<>(1);
|
||||
reasons.put(mTargetActivityRecord, APP_TRANSITION_RECENTS_ANIM);
|
||||
mService.mAtmService.mStackSupervisor.getActivityMetricsLogger()
|
||||
.notifyTransitionStarting(reasons);
|
||||
|
||||
@@ -387,7 +387,7 @@ class RemoteAnimationController implements DeathRecipient {
|
||||
final ActivityRecord topActivity = mWindowContainer.getTopMostActivity();
|
||||
if (dc.mOpeningApps.contains(topActivity)) {
|
||||
return RemoteAnimationTarget.MODE_OPENING;
|
||||
} else if (dc.mChangingApps.contains(topActivity)) {
|
||||
} else if (dc.mChangingContainers.contains(topActivity)) {
|
||||
return RemoteAnimationTarget.MODE_CHANGING;
|
||||
} else {
|
||||
return RemoteAnimationTarget.MODE_CLOSING;
|
||||
|
||||
@@ -128,7 +128,8 @@ class SurfaceAnimator {
|
||||
*/
|
||||
void startAnimation(Transaction t, AnimationAdapter anim, boolean hidden,
|
||||
@AnimationType int type,
|
||||
@Nullable OnAnimationFinishedCallback animationFinishedCallback) {
|
||||
@Nullable OnAnimationFinishedCallback animationFinishedCallback,
|
||||
@Nullable SurfaceFreezer freezer) {
|
||||
cancelAnimation(t, true /* restarting */, true /* forwardCancel */);
|
||||
mAnimation = anim;
|
||||
mAnimationType = type;
|
||||
@@ -139,9 +140,14 @@ class SurfaceAnimator {
|
||||
cancelAnimation();
|
||||
return;
|
||||
}
|
||||
mLeash = createAnimationLeash(surface, t,
|
||||
mAnimatable.getSurfaceWidth(), mAnimatable.getSurfaceHeight(), hidden);
|
||||
mAnimatable.onAnimationLeashCreated(t, mLeash);
|
||||
mLeash = freezer != null ? freezer.takeLeashForAnimation() : null;
|
||||
if (mLeash == null) {
|
||||
mLeash = createAnimationLeash(mAnimatable, surface, t,
|
||||
mAnimatable.getSurfaceWidth(), mAnimatable.getSurfaceHeight(), 0 /* x */,
|
||||
0 /* y */, hidden);
|
||||
mAnimatable.onAnimationLeashCreated(t, mLeash);
|
||||
}
|
||||
mAnimatable.onLeashAnimationStarting(t, mLeash);
|
||||
if (mAnimationStartDelayed) {
|
||||
if (DEBUG_ANIM) Slog.i(TAG, "Animation start delayed");
|
||||
return;
|
||||
@@ -149,6 +155,12 @@ class SurfaceAnimator {
|
||||
mAnimation.startAnimation(mLeash, t, type, mInnerAnimationFinishedCallback);
|
||||
}
|
||||
|
||||
void startAnimation(Transaction t, AnimationAdapter anim, boolean hidden,
|
||||
@AnimationType int type,
|
||||
@Nullable OnAnimationFinishedCallback animationFinishedCallback) {
|
||||
startAnimation(t, anim, hidden, type, animationFinishedCallback, null /* freezer */);
|
||||
}
|
||||
|
||||
void startAnimation(Transaction t, AnimationAdapter anim, boolean hidden,
|
||||
@AnimationType int type) {
|
||||
startAnimation(t, anim, hidden, type, null /* animationFinishedCallback */);
|
||||
@@ -311,15 +323,31 @@ class SurfaceAnimator {
|
||||
}
|
||||
|
||||
private void reset(Transaction t, boolean destroyLeash) {
|
||||
final SurfaceControl surface = mAnimatable.getSurfaceControl();
|
||||
final SurfaceControl parent = mAnimatable.getParentSurfaceControl();
|
||||
mService.mAnimationTransferMap.remove(mAnimation);
|
||||
mAnimation = null;
|
||||
mAnimationFinishedCallback = null;
|
||||
mAnimationType = ANIMATION_TYPE_NONE;
|
||||
if (mLeash == null) {
|
||||
return;
|
||||
}
|
||||
SurfaceControl leash = mLeash;
|
||||
mLeash = null;
|
||||
final boolean scheduleAnim = removeLeash(t, mAnimatable, leash, destroyLeash);
|
||||
if (scheduleAnim) {
|
||||
mService.scheduleAnimationLocked();
|
||||
}
|
||||
}
|
||||
|
||||
static boolean removeLeash(Transaction t, Animatable animatable, @NonNull SurfaceControl leash,
|
||||
boolean destroy) {
|
||||
boolean scheduleAnim = false;
|
||||
final SurfaceControl surface = animatable.getSurfaceControl();
|
||||
final SurfaceControl parent = animatable.getParentSurfaceControl();
|
||||
|
||||
// If the surface was destroyed or the leash is invalid, we don't care to reparent it back.
|
||||
// Note that we also set this variable to true even if the parent isn't valid anymore, in
|
||||
// order to ensure onAnimationLeashLost still gets called in this case.
|
||||
final boolean reparent = mLeash != null && surface != null;
|
||||
final boolean reparent = surface != null;
|
||||
if (reparent) {
|
||||
if (DEBUG_ANIM) Slog.i(TAG, "Reparenting to original parent: " + parent);
|
||||
// We shouldn't really need these isValid checks but we do
|
||||
@@ -329,40 +357,30 @@ class SurfaceAnimator {
|
||||
scheduleAnim = true;
|
||||
}
|
||||
}
|
||||
mService.mAnimationTransferMap.remove(mAnimation);
|
||||
if (mLeash != null && destroyLeash) {
|
||||
t.remove(mLeash);
|
||||
if (destroy) {
|
||||
t.remove(leash);
|
||||
scheduleAnim = true;
|
||||
}
|
||||
mLeash = null;
|
||||
mAnimation = null;
|
||||
mAnimationFinishedCallback = null;
|
||||
mAnimationType = ANIMATION_TYPE_NONE;
|
||||
|
||||
if (reparent) {
|
||||
// Make sure to inform the animatable after the surface was reparented (or reparent
|
||||
// wasn't possible, but we still need to invoke the callback)
|
||||
mAnimatable.onAnimationLeashLost(t);
|
||||
animatable.onAnimationLeashLost(t);
|
||||
scheduleAnim = true;
|
||||
}
|
||||
|
||||
if (scheduleAnim) {
|
||||
mService.scheduleAnimationLocked();
|
||||
}
|
||||
return scheduleAnim;
|
||||
}
|
||||
|
||||
private SurfaceControl createAnimationLeash(SurfaceControl surface, Transaction t, int width,
|
||||
int height, boolean hidden) {
|
||||
static SurfaceControl createAnimationLeash(Animatable animatable, SurfaceControl surface,
|
||||
Transaction t, int width, int height, int x, int y, boolean hidden) {
|
||||
if (DEBUG_ANIM) Slog.i(TAG, "Reparenting to leash");
|
||||
final SurfaceControl.Builder builder = mAnimatable.makeAnimationLeash()
|
||||
.setParent(mAnimatable.getAnimationLeashParent())
|
||||
final SurfaceControl.Builder builder = animatable.makeAnimationLeash()
|
||||
.setParent(animatable.getAnimationLeashParent())
|
||||
.setHidden(hidden)
|
||||
.setName(surface + " - animation-leash");
|
||||
final SurfaceControl leash = builder.build();
|
||||
t.setWindowCrop(leash, width, height);
|
||||
|
||||
// TODO: rely on builder.setHidden(hidden) instead of show and setAlpha when b/138459974 is
|
||||
// fixed.
|
||||
t.setPosition(leash, x, y);
|
||||
t.show(leash);
|
||||
t.setAlpha(leash, hidden ? 0 : 1);
|
||||
|
||||
@@ -489,13 +507,22 @@ class SurfaceAnimator {
|
||||
void commitPendingTransaction();
|
||||
|
||||
/**
|
||||
* Called when the was created.
|
||||
* Called when the animation leash is created. Note that this is also called by
|
||||
* {@link SurfaceFreezer}, so this doesn't mean we're about to start animating.
|
||||
*
|
||||
* @param t The transaction to use to apply any necessary changes.
|
||||
* @param leash The leash that was created.
|
||||
*/
|
||||
void onAnimationLeashCreated(Transaction t, SurfaceControl leash);
|
||||
|
||||
/**
|
||||
* Called when the animator is about to start animating the leash.
|
||||
*
|
||||
* @param t The transaction to use to apply any necessary changes.
|
||||
* @param leash The leash that was created.
|
||||
*/
|
||||
default void onLeashAnimationStarting(Transaction t, SurfaceControl leash) { }
|
||||
|
||||
/**
|
||||
* Called when the leash is being destroyed, or when the leash is being transferred to
|
||||
* another SurfaceAnimator.
|
||||
|
||||
245
services/core/java/com/android/server/wm/SurfaceFreezer.java
Normal file
245
services/core/java/com/android/server/wm/SurfaceFreezer.java
Normal file
@@ -0,0 +1,245 @@
|
||||
/*
|
||||
* Copyright (C) 2020 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.server.wm;
|
||||
|
||||
import static com.android.server.wm.ProtoLogGroup.WM_SHOW_TRANSACTIONS;
|
||||
import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_APP_TRANSITION;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.graphics.GraphicBuffer;
|
||||
import android.graphics.PixelFormat;
|
||||
import android.graphics.Rect;
|
||||
import android.view.Surface;
|
||||
import android.view.SurfaceControl;
|
||||
|
||||
import com.android.server.protolog.common.ProtoLog;
|
||||
|
||||
import java.util.function.Supplier;
|
||||
|
||||
/**
|
||||
* This class handles "freezing" of an Animatable. The Animatable in question should implement
|
||||
* Freezable.
|
||||
*
|
||||
* The point of this is to enable WindowContainers to each be capable of freezing themselves.
|
||||
* Freezing means taking a snapshot and placing it above everything in the sub-hierarchy.
|
||||
* The "placing above" requires that a parent surface be inserted above the target surface so that
|
||||
* the target surface and the snapshot are siblings.
|
||||
*
|
||||
* The overall flow for a transition using this would be:
|
||||
* 1. Set transition and record animatable in mChangingApps
|
||||
* 2. Call {@link #freeze} to set-up the leashes and cover with a snapshot.
|
||||
* 3. When transition participants are ready, start SurfaceAnimator with this as a parameter
|
||||
* 4. SurfaceAnimator will then {@link #takeLeashForAnimation} instead of creating another leash.
|
||||
* 5. The animation system should eventually clean this up via {@link #unfreeze}.
|
||||
*/
|
||||
class SurfaceFreezer {
|
||||
|
||||
private final Freezable mAnimatable;
|
||||
private final WindowManagerService mWmService;
|
||||
private SurfaceControl mLeash;
|
||||
Snapshot mSnapshot = null;
|
||||
final Rect mFreezeBounds = new Rect();
|
||||
|
||||
/**
|
||||
* @param animatable The object to animate.
|
||||
*/
|
||||
SurfaceFreezer(Freezable animatable, WindowManagerService service) {
|
||||
mAnimatable = animatable;
|
||||
mWmService = service;
|
||||
}
|
||||
|
||||
/**
|
||||
* Freeze the target surface. This is done by creating a leash (inserting a parent surface
|
||||
* above the target surface) and then taking a snapshot and placing it over the target surface.
|
||||
*
|
||||
* @param startBounds The original bounds (on screen) of the surface we are snapshotting.
|
||||
*/
|
||||
void freeze(SurfaceControl.Transaction t, Rect startBounds) {
|
||||
mFreezeBounds.set(startBounds);
|
||||
|
||||
mLeash = SurfaceAnimator.createAnimationLeash(mAnimatable, mAnimatable.getSurfaceControl(),
|
||||
t, startBounds.width(), startBounds.height(), startBounds.left, startBounds.top,
|
||||
false /* hidden */);
|
||||
mAnimatable.onAnimationLeashCreated(t, mLeash);
|
||||
|
||||
SurfaceControl freezeTarget = mAnimatable.getFreezeSnapshotTarget();
|
||||
if (freezeTarget != null) {
|
||||
GraphicBuffer snapshot = createSnapshotBuffer(freezeTarget, startBounds);
|
||||
if (snapshot != null) {
|
||||
mSnapshot = new Snapshot(mWmService.mSurfaceFactory, t, snapshot, mLeash);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Used by {@link SurfaceAnimator}. This "transfers" the leash to be used for animation.
|
||||
* By transferring the leash, this will no longer try to clean-up the leash when finished.
|
||||
*/
|
||||
SurfaceControl takeLeashForAnimation() {
|
||||
SurfaceControl out = mLeash;
|
||||
mLeash = null;
|
||||
return out;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clean-up the snapshot and remove leash. If the leash was taken, this just cleans-up the
|
||||
* snapshot.
|
||||
*/
|
||||
void unfreeze(SurfaceControl.Transaction t) {
|
||||
if (mSnapshot != null) {
|
||||
mSnapshot.destroy(t);
|
||||
}
|
||||
if (mLeash == null) {
|
||||
return;
|
||||
}
|
||||
SurfaceControl leash = mLeash;
|
||||
mLeash = null;
|
||||
final boolean scheduleAnim = SurfaceAnimator.removeLeash(t, mAnimatable, leash,
|
||||
false /* destroy */);
|
||||
if (scheduleAnim) {
|
||||
mWmService.scheduleAnimationLocked();
|
||||
}
|
||||
}
|
||||
|
||||
boolean hasLeash() {
|
||||
return mLeash != null;
|
||||
}
|
||||
|
||||
private static GraphicBuffer createSnapshotBuffer(@NonNull SurfaceControl target,
|
||||
@Nullable Rect bounds) {
|
||||
Rect cropBounds = null;
|
||||
if (bounds != null) {
|
||||
cropBounds = new Rect(bounds);
|
||||
cropBounds.offsetTo(0, 0);
|
||||
}
|
||||
final SurfaceControl.ScreenshotGraphicBuffer screenshotBuffer =
|
||||
SurfaceControl.captureLayers(
|
||||
target, cropBounds, 1.f /* frameScale */, PixelFormat.RGBA_8888);
|
||||
final GraphicBuffer buffer = screenshotBuffer != null ? screenshotBuffer.getGraphicBuffer()
|
||||
: null;
|
||||
if (buffer == null || buffer.getWidth() <= 1 || buffer.getHeight() <= 1) {
|
||||
return null;
|
||||
}
|
||||
return buffer;
|
||||
}
|
||||
|
||||
class Snapshot {
|
||||
private SurfaceControl mSurfaceControl;
|
||||
private AnimationAdapter mAnimation;
|
||||
private SurfaceAnimator.OnAnimationFinishedCallback mFinishedCallback;
|
||||
|
||||
/**
|
||||
* @param t Transaction to create the thumbnail in.
|
||||
* @param thumbnailHeader A thumbnail or placeholder for thumbnail to initialize with.
|
||||
*/
|
||||
Snapshot(Supplier<Surface> surfaceFactory, SurfaceControl.Transaction t,
|
||||
GraphicBuffer thumbnailHeader, SurfaceControl parent) {
|
||||
Surface drawSurface = surfaceFactory.get();
|
||||
// We can't use a delegating constructor since we need to
|
||||
// reference this::onAnimationFinished
|
||||
final int width = thumbnailHeader.getWidth();
|
||||
final int height = thumbnailHeader.getHeight();
|
||||
|
||||
mSurfaceControl = mAnimatable.makeAnimationLeash()
|
||||
.setName("snapshot anim: " + mAnimatable.toString())
|
||||
.setBufferSize(width, height)
|
||||
.setFormat(PixelFormat.TRANSLUCENT)
|
||||
.setParent(parent)
|
||||
.build();
|
||||
|
||||
ProtoLog.i(WM_SHOW_TRANSACTIONS, " THUMBNAIL %s: CREATE", mSurfaceControl);
|
||||
|
||||
// Transfer the thumbnail to the surface
|
||||
drawSurface.copyFrom(mSurfaceControl);
|
||||
drawSurface.attachAndQueueBuffer(thumbnailHeader);
|
||||
drawSurface.release();
|
||||
t.show(mSurfaceControl);
|
||||
|
||||
// We parent the thumbnail to the container, and just place it on top of anything else
|
||||
// in the container.
|
||||
t.setLayer(mSurfaceControl, Integer.MAX_VALUE);
|
||||
}
|
||||
|
||||
void destroy(SurfaceControl.Transaction t) {
|
||||
if (mSurfaceControl == null) {
|
||||
return;
|
||||
}
|
||||
t.remove(mSurfaceControl);
|
||||
mSurfaceControl = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts an animation.
|
||||
*
|
||||
* @param anim The object that bridges the controller, {@link SurfaceAnimator}, with the
|
||||
* component responsible for running the animation. It runs the animation with
|
||||
* {@link AnimationAdapter#startAnimation} once the hierarchy with
|
||||
* the Leash has been set up.
|
||||
* @param animationFinishedCallback The callback being triggered when the animation
|
||||
* finishes.
|
||||
*/
|
||||
void startAnimation(SurfaceControl.Transaction t, AnimationAdapter anim, int type,
|
||||
@Nullable SurfaceAnimator.OnAnimationFinishedCallback animationFinishedCallback) {
|
||||
cancelAnimation(t, true /* restarting */);
|
||||
mAnimation = anim;
|
||||
mFinishedCallback = animationFinishedCallback;
|
||||
if (mSurfaceControl == null) {
|
||||
cancelAnimation(t, false /* restarting */);
|
||||
return;
|
||||
}
|
||||
mAnimation.startAnimation(mSurfaceControl, t, type, animationFinishedCallback);
|
||||
}
|
||||
|
||||
/**
|
||||
* Cancels the animation, and resets the leash.
|
||||
*
|
||||
* @param t The transaction to use for all cancelling surface operations.
|
||||
* @param restarting Whether we are restarting the animation.
|
||||
*/
|
||||
private void cancelAnimation(SurfaceControl.Transaction t, boolean restarting) {
|
||||
final SurfaceControl leash = mSurfaceControl;
|
||||
final AnimationAdapter animation = mAnimation;
|
||||
final SurfaceAnimator.OnAnimationFinishedCallback animationFinishedCallback =
|
||||
mFinishedCallback;
|
||||
mAnimation = null;
|
||||
mFinishedCallback = null;
|
||||
if (animation != null) {
|
||||
animation.onAnimationCancelled(leash);
|
||||
if (!restarting) {
|
||||
if (animationFinishedCallback != null) {
|
||||
animationFinishedCallback.onAnimationFinished(
|
||||
ANIMATION_TYPE_APP_TRANSITION, animation);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!restarting) {
|
||||
// TODO: do we need to destroy?
|
||||
destroy(t);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** freezable */
|
||||
public interface Freezable extends SurfaceAnimator.Animatable {
|
||||
/**
|
||||
* @return The surface to take a snapshot of. If this returns {@code null}, no snapshot
|
||||
* will be generated (but the rest of the freezing logic will still happen).
|
||||
*/
|
||||
@Nullable SurfaceControl getFreezeSnapshotTarget();
|
||||
}
|
||||
}
|
||||
@@ -58,6 +58,7 @@ import static android.provider.Settings.Secure.USER_SETUP_COMPLETE;
|
||||
import static android.view.Display.DEFAULT_DISPLAY;
|
||||
import static android.view.Display.INVALID_DISPLAY;
|
||||
import static android.view.SurfaceControl.METADATA_TASK_ID;
|
||||
import static android.view.WindowManager.TRANSIT_TASK_CHANGE_WINDOWING_MODE;
|
||||
|
||||
import static com.android.internal.policy.DecorView.DECOR_SHADOW_FOCUSED_HEIGHT_IN_DIP;
|
||||
import static com.android.internal.policy.DecorView.DECOR_SHADOW_UNFOCUSED_HEIGHT_IN_DIP;
|
||||
@@ -78,6 +79,9 @@ import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_ATM;
|
||||
import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME;
|
||||
import static com.android.server.wm.ActivityTaskManagerService.TAG_STACK;
|
||||
import static com.android.server.wm.DragResizeMode.DRAG_RESIZE_MODE_DOCKED_DIVIDER;
|
||||
import static com.android.server.wm.IdentifierProto.HASH_CODE;
|
||||
import static com.android.server.wm.IdentifierProto.TITLE;
|
||||
import static com.android.server.wm.IdentifierProto.USER_ID;
|
||||
import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_ADD_REMOVE;
|
||||
import static com.android.server.wm.WindowContainer.AnimationFlags.CHILDREN;
|
||||
import static com.android.server.wm.WindowContainer.AnimationFlags.TRANSITION;
|
||||
@@ -119,10 +123,13 @@ import android.os.Trace;
|
||||
import android.os.UserHandle;
|
||||
import android.provider.Settings;
|
||||
import android.service.voice.IVoiceInteractionSession;
|
||||
import android.util.ArraySet;
|
||||
import android.util.DisplayMetrics;
|
||||
import android.util.Slog;
|
||||
import android.util.proto.ProtoOutputStream;
|
||||
import android.view.DisplayInfo;
|
||||
import android.view.ITaskOrganizer;
|
||||
import android.view.RemoteAnimationAdapter;
|
||||
import android.view.RemoteAnimationTarget;
|
||||
import android.view.Surface;
|
||||
import android.view.SurfaceControl;
|
||||
@@ -1884,6 +1891,8 @@ class Task extends WindowContainer<WindowContainer> {
|
||||
.setBounds(mLastNonFullscreenBounds);
|
||||
}
|
||||
|
||||
final int prevWinMode = getWindowingMode();
|
||||
mTmpPrevBounds.set(getBounds());
|
||||
final boolean wasInMultiWindowMode = inMultiWindowMode();
|
||||
super.onConfigurationChanged(newParentConfig);
|
||||
if (wasInMultiWindowMode != inMultiWindowMode()) {
|
||||
@@ -1891,6 +1900,12 @@ class Task extends WindowContainer<WindowContainer> {
|
||||
updateShadowsRadius(isFocused(), getPendingTransaction());
|
||||
}
|
||||
|
||||
final int newWinMode = getWindowingMode();
|
||||
if ((prevWinMode != newWinMode) && (mDisplayContent != null)
|
||||
&& shouldStartChangeTransition(prevWinMode, newWinMode)) {
|
||||
initializeChangeTransition(mTmpPrevBounds);
|
||||
}
|
||||
|
||||
// If the configuration supports persistent bounds (eg. Freeform), keep track of the
|
||||
// current (non-fullscreen) bounds for persistence.
|
||||
if (getWindowConfiguration().persistTaskBounds()) {
|
||||
@@ -1904,6 +1919,63 @@ class Task extends WindowContainer<WindowContainer> {
|
||||
saveLaunchingStateIfNeeded();
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes a change transition. See {@link SurfaceFreezer} for more information.
|
||||
*/
|
||||
private void initializeChangeTransition(Rect startBounds) {
|
||||
mDisplayContent.prepareAppTransition(TRANSIT_TASK_CHANGE_WINDOWING_MODE,
|
||||
false /* alwaysKeepCurrent */, 0, false /* forceOverride */);
|
||||
mDisplayContent.mChangingContainers.add(this);
|
||||
|
||||
mSurfaceFreezer.freeze(getPendingTransaction(), startBounds);
|
||||
}
|
||||
|
||||
private boolean shouldStartChangeTransition(int prevWinMode, int newWinMode) {
|
||||
if (mWmService.mDisableTransitionAnimation
|
||||
|| !isVisible()
|
||||
|| getDisplayContent().mAppTransition.isTransitionSet()
|
||||
|| getSurfaceControl() == null) {
|
||||
return false;
|
||||
}
|
||||
// Only do an animation into and out-of freeform mode for now. Other mode
|
||||
// transition animations are currently handled by system-ui.
|
||||
return (prevWinMode == WINDOWING_MODE_FREEFORM) != (newWinMode == WINDOWING_MODE_FREEFORM);
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
boolean isInChangeTransition() {
|
||||
return mSurfaceFreezer.hasLeash() || AppTransition.isChangeTransit(mTransit);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SurfaceControl getFreezeSnapshotTarget() {
|
||||
final int transit = mDisplayContent.mAppTransition.getAppTransition();
|
||||
if (!AppTransition.isChangeTransit(transit)) {
|
||||
return null;
|
||||
}
|
||||
// Skip creating snapshot if this transition is controlled by a remote animator which
|
||||
// doesn't need it.
|
||||
final ArraySet<Integer> activityTypes = new ArraySet<>();
|
||||
activityTypes.add(getActivityType());
|
||||
final RemoteAnimationAdapter adapter =
|
||||
mDisplayContent.mAppTransitionController.getRemoteAnimationOverride(
|
||||
this, transit, activityTypes);
|
||||
if (adapter != null && !adapter.getChangeNeedsSnapshot()) {
|
||||
return null;
|
||||
}
|
||||
return getSurfaceControl();
|
||||
}
|
||||
|
||||
@Override
|
||||
void writeIdentifierToProto(ProtoOutputStream proto, long fieldId) {
|
||||
final long token = proto.start(fieldId);
|
||||
proto.write(HASH_CODE, System.identityHashCode(this));
|
||||
proto.write(USER_ID, mUserId);
|
||||
proto.write(TITLE, intent != null && intent.getComponent() != null
|
||||
? intent.getComponent().flattenToShortString() : "Task");
|
||||
proto.end(token);
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves launching state if necessary so that we can launch the activity to its latest state.
|
||||
* It only saves state if this task has been shown to user and it's in fullscreen or freeform
|
||||
@@ -2614,12 +2686,22 @@ class Task extends WindowContainer<WindowContainer> {
|
||||
if (!isRootTask) {
|
||||
adjustBoundsForDisplayChangeIfNeeded(dc);
|
||||
}
|
||||
final DisplayContent prevDc = mDisplayContent;
|
||||
super.onDisplayChanged(dc);
|
||||
if (!isRootTask) {
|
||||
final int displayId = (dc != null) ? dc.getDisplayId() : INVALID_DISPLAY;
|
||||
mWmService.mAtmService.getTaskChangeNotificationController().notifyTaskDisplayChanged(
|
||||
mTaskId, displayId);
|
||||
}
|
||||
if (prevDc != null && prevDc.mChangingContainers.remove(this)) {
|
||||
// This gets called *after* this has been reparented to the new display.
|
||||
// That reparenting resulted in this window changing modes (eg. FREEFORM -> FULLSCREEN),
|
||||
// so this token is now "frozen" while waiting for the animation to start on prevDc
|
||||
// (which will be cancelled since the window is no-longer a child). However, since this
|
||||
// is no longer a child of prevDc, this won't be notified of the cancelled animation,
|
||||
// so we need to cancel the change transition here.
|
||||
mSurfaceFreezer.unfreeze(getPendingTransaction());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -3010,15 +3092,6 @@ class Task extends WindowContainer<WindowContainer> {
|
||||
return forAllTasks((t) -> { return t != this && t.isTaskAnimating(); });
|
||||
}
|
||||
|
||||
/**
|
||||
* @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) {
|
||||
|
||||
@@ -669,8 +669,7 @@ class WallpaperController {
|
||||
* Adjusts the wallpaper windows if the input display has a pending wallpaper layout or one of
|
||||
* the opening apps should be a wallpaper target.
|
||||
*/
|
||||
void adjustWallpaperWindowsForAppTransitionIfNeeded(ArraySet<ActivityRecord> openingApps,
|
||||
ArraySet<ActivityRecord> changingApps) {
|
||||
void adjustWallpaperWindowsForAppTransitionIfNeeded(ArraySet<ActivityRecord> openingApps) {
|
||||
boolean adjust = false;
|
||||
if ((mDisplayContent.pendingLayoutChanges & FINISH_LAYOUT_REDO_WALLPAPER) != 0) {
|
||||
adjust = true;
|
||||
@@ -682,15 +681,6 @@ class WallpaperController {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!adjust) {
|
||||
for (int i = changingApps.size() - 1; i >= 0; --i) {
|
||||
final ActivityRecord activity = changingApps.valueAt(i);
|
||||
if (activity.windowsCanBeWallpaperTarget()) {
|
||||
adjust = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (adjust) {
|
||||
|
||||
@@ -25,9 +25,13 @@ 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.os.UserHandle.USER_NULL;
|
||||
import static android.view.SurfaceControl.Transaction;
|
||||
|
||||
import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
|
||||
import static com.android.server.wm.IdentifierProto.HASH_CODE;
|
||||
import static com.android.server.wm.IdentifierProto.TITLE;
|
||||
import static com.android.server.wm.IdentifierProto.USER_ID;
|
||||
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.ProtoLogGroup.WM_DEBUG_ORIENTATION;
|
||||
@@ -64,6 +68,7 @@ import android.util.proto.ProtoOutputStream;
|
||||
import android.view.DisplayInfo;
|
||||
import android.view.IWindowContainer;
|
||||
import android.view.MagnificationSpec;
|
||||
import android.view.RemoteAnimationDefinition;
|
||||
import android.view.RemoteAnimationTarget;
|
||||
import android.view.SurfaceControl;
|
||||
import android.view.SurfaceControl.Builder;
|
||||
@@ -94,7 +99,7 @@ import java.util.function.Predicate;
|
||||
* changes are made to this class.
|
||||
*/
|
||||
class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<E>
|
||||
implements Comparable<WindowContainer>, Animatable,
|
||||
implements Comparable<WindowContainer>, Animatable, SurfaceFreezer.Freezable,
|
||||
BLASTSyncEngine.TransactionReadyListener {
|
||||
|
||||
private static final String TAG = TAG_WITH_CLASS_NAME ? "WindowContainer" : TAG_WM;
|
||||
@@ -169,6 +174,7 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<
|
||||
* Applied as part of the animation pass in "prepareSurfaces".
|
||||
*/
|
||||
protected final SurfaceAnimator mSurfaceAnimator;
|
||||
final SurfaceFreezer mSurfaceFreezer;
|
||||
protected final WindowManagerService mWmService;
|
||||
|
||||
private final Point mTmpPos = new Point();
|
||||
@@ -252,7 +258,6 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<
|
||||
* where it represents the starting-state snapshot.
|
||||
*/
|
||||
WindowContainerThumbnail mThumbnail;
|
||||
final Rect mTransitStartRect = new Rect();
|
||||
final Point mTmpPoint = new Point();
|
||||
protected final Rect mTmpRect = new Rect();
|
||||
final Rect mTmpPrevBounds = new Rect();
|
||||
@@ -277,6 +282,7 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<
|
||||
mWmService = wms;
|
||||
mPendingTransaction = wms.mTransactionFactory.get();
|
||||
mSurfaceAnimator = new SurfaceAnimator(this, this::onAnimationFinished, wms);
|
||||
mSurfaceFreezer = new SurfaceFreezer(this, wms);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -834,7 +840,7 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<
|
||||
* @return {@code true} if the container is in changing app transition.
|
||||
*/
|
||||
boolean isChangingAppTransition() {
|
||||
return false;
|
||||
return mDisplayContent != null && mDisplayContent.mChangingContainers.contains(this);
|
||||
}
|
||||
|
||||
void sendAppVisibilityToClients() {
|
||||
@@ -885,6 +891,31 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the visibility of a child is asked to change. This is before visibility actually
|
||||
* changes (eg. a transition animation might play out first).
|
||||
*/
|
||||
void onChildVisibilityRequested(boolean visible) {
|
||||
// If we are changing visibility, then a snapshot isn't necessary and we are no-longer
|
||||
// part of a change transition.
|
||||
mSurfaceFreezer.unfreeze(getPendingTransaction());
|
||||
if (mDisplayContent != null) {
|
||||
mDisplayContent.mChangingContainers.remove(this);
|
||||
}
|
||||
WindowContainer parent = getParent();
|
||||
if (parent != null) {
|
||||
parent.onChildVisibilityRequested(visible);
|
||||
}
|
||||
}
|
||||
|
||||
void writeIdentifierToProto(ProtoOutputStream proto, long fieldId) {
|
||||
final long token = proto.start(fieldId);
|
||||
proto.write(HASH_CODE, System.identityHashCode(this));
|
||||
proto.write(USER_ID, USER_NULL);
|
||||
proto.write(TITLE, "WindowContainer");
|
||||
proto.end(token);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@code true} if this container is focusable. Generally, if a parent is not focusable,
|
||||
* this will not be focusable either.
|
||||
@@ -1917,7 +1948,8 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<
|
||||
|
||||
// TODO: This should use isVisible() but because isVisible has a really weird meaning at
|
||||
// the moment this doesn't work for all animatable window containers.
|
||||
mSurfaceAnimator.startAnimation(t, anim, hidden, type, animationFinishedCallback);
|
||||
mSurfaceAnimator.startAnimation(t, anim, hidden, type, animationFinishedCallback,
|
||||
mSurfaceFreezer);
|
||||
}
|
||||
|
||||
void startAnimation(Transaction t, AnimationAdapter anim, boolean hidden,
|
||||
@@ -1933,6 +1965,11 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<
|
||||
mSurfaceAnimator.cancelAnimation();
|
||||
}
|
||||
|
||||
@Override
|
||||
public SurfaceControl getFreezeSnapshotTarget() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Builder makeAnimationLeash() {
|
||||
return makeSurface().setContainerLayer();
|
||||
@@ -2002,8 +2039,9 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<
|
||||
getDisplayContent().pendingLayoutChanges |= FINISH_LAYOUT_REDO_WALLPAPER;
|
||||
}
|
||||
if (thumbnailAdapter != null) {
|
||||
mThumbnail.startAnimation(
|
||||
getPendingTransaction(), thumbnailAdapter, !isVisible());
|
||||
mSurfaceFreezer.mSnapshot.startAnimation(getPendingTransaction(),
|
||||
thumbnailAdapter, ANIMATION_TYPE_APP_TRANSITION,
|
||||
(type, anim) -> { });
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@@ -2049,7 +2087,7 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<
|
||||
if (controller != null && !mSurfaceAnimator.isAnimationStartDelayed()) {
|
||||
final RemoteAnimationController.RemoteAnimationRecord adapters =
|
||||
controller.createRemoteAnimationRecord(this, mTmpPoint, mTmpRect,
|
||||
(isChanging ? mTransitStartRect : null));
|
||||
(isChanging ? mSurfaceFreezer.mFreezeBounds : null));
|
||||
resultAdapters = new Pair<>(adapters.mAdapter, adapters.mThumbnailAdapter);
|
||||
} else if (isChanging) {
|
||||
final float durationScale = mWmService.getTransitionAnimationScaleLocked();
|
||||
@@ -2057,14 +2095,15 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<
|
||||
mTmpRect.offsetTo(mTmpPoint.x, mTmpPoint.y);
|
||||
|
||||
final AnimationAdapter adapter = new LocalAnimationAdapter(
|
||||
new WindowChangeAnimationSpec(mTransitStartRect, mTmpRect, displayInfo,
|
||||
durationScale, true /* isAppAnimation */, false /* isThumbnail */),
|
||||
new WindowChangeAnimationSpec(mSurfaceFreezer.mFreezeBounds, mTmpRect,
|
||||
displayInfo, durationScale, true /* isAppAnimation */,
|
||||
false /* isThumbnail */),
|
||||
getSurfaceAnimationRunner());
|
||||
|
||||
final AnimationAdapter thumbnailAdapter = mThumbnail != null
|
||||
? new LocalAnimationAdapter(new WindowChangeAnimationSpec(mTransitStartRect,
|
||||
mTmpRect, displayInfo, durationScale, true /* isAppAnimation */,
|
||||
true /* isThumbnail */), getSurfaceAnimationRunner())
|
||||
final AnimationAdapter thumbnailAdapter = mSurfaceFreezer.mSnapshot != null
|
||||
? new LocalAnimationAdapter(new WindowChangeAnimationSpec(
|
||||
mSurfaceFreezer.mFreezeBounds, mTmpRect, displayInfo, durationScale,
|
||||
true /* isAppAnimation */, true /* isThumbnail */), getSurfaceAnimationRunner())
|
||||
: null;
|
||||
resultAdapters = new Pair<>(adapter, thumbnailAdapter);
|
||||
mTransit = transit;
|
||||
@@ -2182,6 +2221,7 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<
|
||||
@Override
|
||||
public void onAnimationLeashLost(Transaction t) {
|
||||
mLastLayer = -1;
|
||||
mSurfaceFreezer.unfreeze(t);
|
||||
reassignLayer(t);
|
||||
}
|
||||
|
||||
@@ -2322,6 +2362,10 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<
|
||||
mSurfaceControl = sc;
|
||||
}
|
||||
|
||||
RemoteAnimationDefinition getRemoteAnimationDefinition() {
|
||||
return null;
|
||||
}
|
||||
|
||||
/** Cheap way of doing cast and instanceof. */
|
||||
Task asTask() {
|
||||
return null;
|
||||
|
||||
@@ -255,7 +255,7 @@ public class ActivityMetricsLaunchObserverTests extends ActivityTestsBase {
|
||||
}
|
||||
|
||||
private void notifyTransitionStarting(ActivityRecord activity) {
|
||||
final ArrayMap<ActivityRecord, Integer> reasons = new ArrayMap<>();
|
||||
final ArrayMap<WindowContainer, Integer> reasons = new ArrayMap<>();
|
||||
reasons.put(activity, ActivityTaskManagerInternal.APP_TRANSITION_SPLASH_SCREEN);
|
||||
mActivityMetricsLogger.notifyTransitionStarting(reasons);
|
||||
}
|
||||
|
||||
@@ -103,12 +103,12 @@ public class AppChangeTransitionTests extends WindowTestsBase {
|
||||
setUpOnDisplay(mDisplayContent);
|
||||
|
||||
mTask.setWindowingMode(WINDOWING_MODE_FREEFORM);
|
||||
assertEquals(1, mDisplayContent.mChangingApps.size());
|
||||
assertEquals(1, mDisplayContent.mChangingContainers.size());
|
||||
|
||||
// Verify we are in a change transition, but without a snapshot.
|
||||
// Though, the test will actually have crashed by now if a snapshot is attempted.
|
||||
assertNull(mActivity.getThumbnail());
|
||||
assertTrue(mActivity.isInChangeTransition());
|
||||
assertNull(mTask.mSurfaceFreezer.mSnapshot);
|
||||
assertTrue(mTask.isInChangeTransition());
|
||||
|
||||
waitUntilHandlersIdle();
|
||||
mActivity.removeImmediately();
|
||||
@@ -121,14 +121,14 @@ public class AppChangeTransitionTests extends WindowTestsBase {
|
||||
setUpOnDisplay(mDisplayContent);
|
||||
|
||||
mTask.setWindowingMode(WINDOWING_MODE_FREEFORM);
|
||||
assertEquals(1, mDisplayContent.mChangingApps.size());
|
||||
assertTrue(mActivity.isInChangeTransition());
|
||||
assertEquals(1, mDisplayContent.mChangingContainers.size());
|
||||
assertTrue(mTask.isInChangeTransition());
|
||||
|
||||
// Removing the app-token from the display should clean-up the
|
||||
// the change leash.
|
||||
mDisplayContent.removeAppToken(mActivity.token);
|
||||
assertEquals(0, mDisplayContent.mChangingApps.size());
|
||||
assertFalse(mActivity.isInChangeTransition());
|
||||
assertEquals(0, mDisplayContent.mChangingContainers.size());
|
||||
assertFalse(mTask.isInChangeTransition());
|
||||
|
||||
waitUntilHandlersIdle();
|
||||
mActivity.removeImmediately();
|
||||
@@ -152,8 +152,8 @@ public class AppChangeTransitionTests extends WindowTestsBase {
|
||||
assertEquals(WINDOWING_MODE_FULLSCREEN, mTask.getWindowingMode());
|
||||
|
||||
// Make sure we're not waiting for a change animation (no leash)
|
||||
assertFalse(mActivity.isInChangeTransition());
|
||||
assertNull(mActivity.getThumbnail());
|
||||
assertFalse(mTask.isInChangeTransition());
|
||||
assertNull(mActivity.mSurfaceFreezer.mSnapshot);
|
||||
|
||||
waitUntilHandlersIdle();
|
||||
mActivity.removeImmediately();
|
||||
@@ -165,13 +165,13 @@ public class AppChangeTransitionTests extends WindowTestsBase {
|
||||
setUpOnDisplay(mDisplayContent);
|
||||
|
||||
mTask.setWindowingMode(WINDOWING_MODE_FREEFORM);
|
||||
assertEquals(1, mDisplayContent.mChangingApps.size());
|
||||
assertTrue(mActivity.isInChangeTransition());
|
||||
assertEquals(1, mDisplayContent.mChangingContainers.size());
|
||||
assertTrue(mTask.isInChangeTransition());
|
||||
|
||||
// Changing visibility should cancel the change transition and become closing
|
||||
mActivity.setVisibility(false, false);
|
||||
assertEquals(0, mDisplayContent.mChangingApps.size());
|
||||
assertFalse(mActivity.isInChangeTransition());
|
||||
assertEquals(0, mDisplayContent.mChangingContainers.size());
|
||||
assertFalse(mTask.isInChangeTransition());
|
||||
|
||||
waitUntilHandlersIdle();
|
||||
mActivity.removeImmediately();
|
||||
|
||||
@@ -247,7 +247,7 @@ public class RemoteAnimationControllerTest extends WindowTestsBase {
|
||||
@Test
|
||||
public void testChange() throws Exception {
|
||||
final WindowState win = createWindow(null /* parent */, TYPE_BASE_APPLICATION, "testWin");
|
||||
mDisplayContent.mChangingApps.add(win.mActivityRecord);
|
||||
mDisplayContent.mChangingContainers.add(win.mActivityRecord);
|
||||
try {
|
||||
final RemoteAnimationRecord record = mController.createRemoteAnimationRecord(
|
||||
win.mActivityRecord, new Point(50, 100), new Rect(50, 100, 150, 150),
|
||||
@@ -290,7 +290,7 @@ public class RemoteAnimationControllerTest extends WindowTestsBase {
|
||||
verify(mThumbnailFinishedCallback).onAnimationFinished(
|
||||
eq(ANIMATION_TYPE_WINDOW_ANIMATION), eq(record.mThumbnailAdapter));
|
||||
} finally {
|
||||
mDisplayContent.mChangingApps.clear();
|
||||
mDisplayContent.mChangingContainers.clear();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user