Each displays can have individual app transition.
Include below refectoring items to support per display AppTransition:
WMS / AM refectoring parts:
- Move AppTransition related stuff from WMS into DisplayContent.
- Move WMS.prepareAppTransition into DisplayWindowController.
- Move WMS.executeAppTransition to DisplayWindowController.
- Move ATM.isNextTransitionForward to DisplayWindowController.
- Move WMS.getPendingAppTransition to DisplayWindowController.
- Move WMS.overrideAppTransition like APIs to DisplayWindowController.
- Move ActivityRecord.applyOptionsLocked to AppContainerController.
- Support tracing all display's AppTransition status for
DisplayContent.pendingLayoutChanges & window hierachy update.
- Modify logics for AppTransition related caller parts.
- Move WindowSurfacePlacer.handleAppTransitionReadyLocked related
stuffs into added class AppTransitionController.
WM unit test parts:
- Add test case for verifying app transition state per display:
- AppTransitionTests.testAppTransitionStateForMultiDisplay
- AppTransitionTests.testCleanAppTransitionWhenTaskStackReparent
- Rename WindowSurfacePlacerTest to AppTransitionControllerTest since
the test is related handle AppTransition flow.
Bug: 111362605
Test: go/wm-smoke
Test: atest ActivityManagerTransitionSelectionTests
Test: atest ActivityManagerMultiDisplayTests
Test: atest FrameworksServicesTests for DisplayContent / AppTransition
related tests.
Change-Id: Ic1793aa794eb161bec31fda57847a6ba2ff4f84f
diff --git a/config/boot-image-profile.txt b/config/boot-image-profile.txt
index 2d51038..c312aa9 100644
--- a/config/boot-image-profile.txt
+++ b/config/boot-image-profile.txt
@@ -13145,7 +13145,7 @@
HSPLandroid/app/ActivityManagerInternal;->notifyAppTransitionFinished()V
HSPLandroid/app/ActivityManagerInternal;->notifyAppTransitionStarting(Landroid/util/SparseIntArray;J)V
HSPLandroid/app/ActivityManagerInternal;->notifyDockedStackMinimizedChanged(Z)V
-HSPLandroid/app/ActivityManagerInternal;->notifyKeyguardFlagsChanged(Ljava/lang/Runnable;)V
+HSPLandroid/app/ActivityManagerInternal;->notifyKeyguardFlagsChanged(Ljava/lang/Runnable;I)V
HSPLandroid/app/ActivityManagerInternal;->notifyKeyguardTrustedChanged()V
HSPLandroid/app/ActivityManagerInternal;->notifyNetworkPolicyRulesUpdated(IJ)V
HSPLandroid/app/ActivityManagerInternal;->onLocalVoiceInteractionStarted(Landroid/os/IBinder;Landroid/service/voice/IVoiceInteractionSession;Lcom/android/internal/app/IVoiceInteractor;)V
@@ -32750,15 +32750,8 @@
HSPLandroid/view/IWindowManager;->isWindowTraceEnabled()Z
HSPLandroid/view/IWindowManager;->lockNow(Landroid/os/Bundle;)V
HSPLandroid/view/IWindowManager;->openSession(Landroid/view/IWindowSessionCallback;Lcom/android/internal/view/IInputMethodClient;Lcom/android/internal/view/IInputContext;)Landroid/view/IWindowSession;
-HSPLandroid/view/IWindowManager;->overridePendingAppTransition(Ljava/lang/String;IILandroid/os/IRemoteCallback;)V
-HSPLandroid/view/IWindowManager;->overridePendingAppTransitionAspectScaledThumb(Landroid/graphics/GraphicBuffer;IIIILandroid/os/IRemoteCallback;Z)V
-HSPLandroid/view/IWindowManager;->overridePendingAppTransitionClipReveal(IIII)V
-HSPLandroid/view/IWindowManager;->overridePendingAppTransitionInPlace(Ljava/lang/String;I)V
-HSPLandroid/view/IWindowManager;->overridePendingAppTransitionMultiThumb([Landroid/view/AppTransitionAnimationSpec;Landroid/os/IRemoteCallback;Landroid/os/IRemoteCallback;Z)V
HSPLandroid/view/IWindowManager;->overridePendingAppTransitionMultiThumbFuture(Landroid/view/IAppTransitionAnimationSpecsFuture;Landroid/os/IRemoteCallback;Z)V
HSPLandroid/view/IWindowManager;->overridePendingAppTransitionRemote(Landroid/view/RemoteAnimationAdapter;)V
-HSPLandroid/view/IWindowManager;->overridePendingAppTransitionScaleUp(IIII)V
-HSPLandroid/view/IWindowManager;->overridePendingAppTransitionThumb(Landroid/graphics/GraphicBuffer;IILandroid/os/IRemoteCallback;Z)V
HSPLandroid/view/IWindowManager;->prepareAppTransition(IZ)V
HSPLandroid/view/IWindowManager;->reenableKeyguard(Landroid/os/IBinder;)V
HSPLandroid/view/IWindowManager;->refreshScreenCaptureDisabled(I)V
diff --git a/config/hiddenapi-light-greylist.txt b/config/hiddenapi-light-greylist.txt
index bbc3f35..e6257b3 100644
--- a/config/hiddenapi-light-greylist.txt
+++ b/config/hiddenapi-light-greylist.txt
@@ -1418,7 +1418,6 @@
Landroid/view/IWindowManager;->getDockedStackSide()I
Landroid/view/IWindowManager;->getInitialDisplayDensity(I)I
Landroid/view/IWindowManager;->getInitialDisplaySize(ILandroid/graphics/Point;)V
-Landroid/view/IWindowManager;->getPendingAppTransition()I
Landroid/view/IWindowManager;->hasNavigationBar()Z
Landroid/view/IWindowManager;->isKeyguardLocked()Z
Landroid/view/IWindowManager;->isKeyguardSecure()Z
diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl
index 0c3a295..f8bdfe2 100644
--- a/core/java/android/view/IWindowManager.aidl
+++ b/core/java/android/view/IWindowManager.aidl
@@ -88,29 +88,6 @@
void addWindowToken(IBinder token, int type, int displayId);
void removeWindowToken(IBinder token, int displayId);
void prepareAppTransition(int transit, boolean alwaysKeepCurrent);
- int getPendingAppTransition();
- void overridePendingAppTransition(String packageName, int enterAnim, int exitAnim,
- IRemoteCallback startedCallback);
- void overridePendingAppTransitionScaleUp(int startX, int startY, int startWidth,
- int startHeight);
- void overridePendingAppTransitionClipReveal(int startX, int startY,
- int startWidth, int startHeight);
- void overridePendingAppTransitionThumb(in GraphicBuffer srcThumb, int startX, int startY,
- IRemoteCallback startedCallback, boolean scaleUp);
- void overridePendingAppTransitionAspectScaledThumb(in GraphicBuffer srcThumb, int startX,
- int startY, int targetWidth, int targetHeight, IRemoteCallback startedCallback,
- boolean scaleUp);
- /**
- * Overrides animation for app transition that exits from an application to a multi-window
- * environment and allows specifying transition animation parameters for each window.
- *
- * @param specs Array of transition animation descriptions for entering windows.
- *
- * @hide
- */
- void overridePendingAppTransitionMultiThumb(in AppTransitionAnimationSpec[] specs,
- IRemoteCallback startedCallback, IRemoteCallback finishedCallback, boolean scaleUp);
- void overridePendingAppTransitionInPlace(String packageName, int anim);
/**
* Like overridePendingAppTransitionMultiThumb, but uses a future to supply the specs. This is
diff --git a/core/proto/android/server/windowmanagerservice.proto b/core/proto/android/server/windowmanagerservice.proto
index c1c86f0..b0dbaa0 100644
--- a/core/proto/android/server/windowmanagerservice.proto
+++ b/core/proto/android/server/windowmanagerservice.proto
@@ -45,7 +45,6 @@
optional bool display_frozen = 6;
optional int32 rotation = 7;
optional int32 last_orientation = 8;
- optional AppTransitionProto app_transition = 9;
}
/* represents RootWindowContainer object */
@@ -159,6 +158,7 @@
optional DisplayFramesProto display_frames = 13;
optional int32 surface_size = 14;
optional string focused_app = 15;
+ optional AppTransitionProto app_transition = 16;
}
/* represents DisplayFrames */
diff --git a/services/core/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java
index 865c774..47b4f47 100644
--- a/services/core/java/com/android/server/am/ActivityRecord.java
+++ b/services/core/java/com/android/server/am/ActivityRecord.java
@@ -18,16 +18,7 @@
import static android.app.ActivityManager.LOCK_TASK_MODE_NONE;
import static android.app.ActivityManager.TaskDescription.ATTR_TASKDESCRIPTION_PREFIX;
-import static android.app.ActivityOptions.ANIM_CLIP_REVEAL;
-import static android.app.ActivityOptions.ANIM_CUSTOM;
-import static android.app.ActivityOptions.ANIM_OPEN_CROSS_PROFILE_APPS;
-import static android.app.ActivityOptions.ANIM_REMOTE_ANIMATION;
-import static android.app.ActivityOptions.ANIM_SCALE_UP;
import static android.app.ActivityOptions.ANIM_SCENE_TRANSITION;
-import static android.app.ActivityOptions.ANIM_THUMBNAIL_ASPECT_SCALE_DOWN;
-import static android.app.ActivityOptions.ANIM_THUMBNAIL_ASPECT_SCALE_UP;
-import static android.app.ActivityOptions.ANIM_THUMBNAIL_SCALE_DOWN;
-import static android.app.ActivityOptions.ANIM_THUMBNAIL_SCALE_UP;
import static android.app.ActivityTaskManager.INVALID_STACK_ID;
import static android.app.AppOpsManager.MODE_ALLOWED;
import static android.app.AppOpsManager.OP_PICTURE_IN_PICTURE;
@@ -156,7 +147,6 @@
import android.content.res.CompatibilityInfo;
import android.content.res.Configuration;
import android.graphics.Bitmap;
-import android.graphics.GraphicBuffer;
import android.graphics.Rect;
import android.os.Binder;
import android.os.Build;
@@ -177,8 +167,6 @@
import android.util.Slog;
import android.util.TimeUtils;
import android.util.proto.ProtoOutputStream;
-import android.view.AppTransitionAnimationSpec;
-import android.view.IAppTransitionAnimationSpecsFuture;
import android.view.IApplicationToken;
import android.view.RemoteAnimationDefinition;
import android.view.WindowManager.LayoutParams;
@@ -1502,93 +1490,7 @@
void applyOptionsLocked() {
if (pendingOptions != null
&& pendingOptions.getAnimationType() != ANIM_SCENE_TRANSITION) {
- final int animationType = pendingOptions.getAnimationType();
- switch (animationType) {
- case ANIM_CUSTOM:
- service.mWindowManager.overridePendingAppTransition(
- pendingOptions.getPackageName(),
- pendingOptions.getCustomEnterResId(),
- pendingOptions.getCustomExitResId(),
- pendingOptions.getOnAnimationStartListener());
- break;
- case ANIM_CLIP_REVEAL:
- service.mWindowManager.overridePendingAppTransitionClipReveal(
- pendingOptions.getStartX(), pendingOptions.getStartY(),
- pendingOptions.getWidth(), pendingOptions.getHeight());
- if (intent.getSourceBounds() == null) {
- intent.setSourceBounds(new Rect(pendingOptions.getStartX(),
- pendingOptions.getStartY(),
- pendingOptions.getStartX()+pendingOptions.getWidth(),
- pendingOptions.getStartY()+pendingOptions.getHeight()));
- }
- break;
- case ANIM_SCALE_UP:
- service.mWindowManager.overridePendingAppTransitionScaleUp(
- pendingOptions.getStartX(), pendingOptions.getStartY(),
- pendingOptions.getWidth(), pendingOptions.getHeight());
- if (intent.getSourceBounds() == null) {
- intent.setSourceBounds(new Rect(pendingOptions.getStartX(),
- pendingOptions.getStartY(),
- pendingOptions.getStartX()+pendingOptions.getWidth(),
- pendingOptions.getStartY()+pendingOptions.getHeight()));
- }
- break;
- case ANIM_THUMBNAIL_SCALE_UP:
- case ANIM_THUMBNAIL_SCALE_DOWN:
- final boolean scaleUp = (animationType == ANIM_THUMBNAIL_SCALE_UP);
- final GraphicBuffer buffer = pendingOptions.getThumbnail();
- service.mWindowManager.overridePendingAppTransitionThumb(buffer,
- pendingOptions.getStartX(), pendingOptions.getStartY(),
- pendingOptions.getOnAnimationStartListener(),
- scaleUp);
- if (intent.getSourceBounds() == null && buffer != null) {
- intent.setSourceBounds(new Rect(pendingOptions.getStartX(),
- pendingOptions.getStartY(),
- pendingOptions.getStartX() + buffer.getWidth(),
- pendingOptions.getStartY() + buffer.getHeight()));
- }
- break;
- case ANIM_THUMBNAIL_ASPECT_SCALE_UP:
- case ANIM_THUMBNAIL_ASPECT_SCALE_DOWN:
- final AppTransitionAnimationSpec[] specs = pendingOptions.getAnimSpecs();
- final IAppTransitionAnimationSpecsFuture specsFuture =
- pendingOptions.getSpecsFuture();
- if (specsFuture != null) {
- service.mWindowManager.overridePendingAppTransitionMultiThumbFuture(
- specsFuture, pendingOptions.getOnAnimationStartListener(),
- animationType == ANIM_THUMBNAIL_ASPECT_SCALE_UP);
- } else if (animationType == ANIM_THUMBNAIL_ASPECT_SCALE_DOWN
- && specs != null) {
- service.mWindowManager.overridePendingAppTransitionMultiThumb(
- specs, pendingOptions.getOnAnimationStartListener(),
- pendingOptions.getAnimationFinishedListener(), false);
- } else {
- service.mWindowManager.overridePendingAppTransitionAspectScaledThumb(
- pendingOptions.getThumbnail(),
- pendingOptions.getStartX(), pendingOptions.getStartY(),
- pendingOptions.getWidth(), pendingOptions.getHeight(),
- pendingOptions.getOnAnimationStartListener(),
- (animationType == ANIM_THUMBNAIL_ASPECT_SCALE_UP));
- if (intent.getSourceBounds() == null) {
- intent.setSourceBounds(new Rect(pendingOptions.getStartX(),
- pendingOptions.getStartY(),
- pendingOptions.getStartX() + pendingOptions.getWidth(),
- pendingOptions.getStartY() + pendingOptions.getHeight()));
- }
- }
- break;
- case ANIM_OPEN_CROSS_PROFILE_APPS:
- service.mWindowManager.overridePendingAppTransitionStartCrossProfileApps();
- break;
- case ANIM_REMOTE_ANIMATION:
- service.mWindowManager.overridePendingAppTransitionRemote(
- pendingOptions.getRemoteAnimationAdapter());
- break;
- default:
- Slog.e(TAG, "applyOptionsLocked: Unknown animationType=" + animationType);
- break;
- }
-
+ mWindowContainerController.applyOptionsLocked(pendingOptions, intent);
if (task == null) {
clearOptionsLocked(false /* withAbort */);
} else {
@@ -2768,7 +2670,8 @@
preserveWindow);
final ActivityLifecycleItem lifecycleItem;
if (andResume) {
- lifecycleItem = ResumeActivityItem.obtain(service.isNextTransitionForward());
+ lifecycleItem = ResumeActivityItem.obtain(
+ getDisplay().getWindowContainerController().isNextTransitionForward());
} else {
lifecycleItem = PauseActivityItem.obtain();
}
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index 026c5cc..b8d85a9 100644
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -156,6 +156,7 @@
import com.android.server.Watchdog;
import com.android.server.am.ActivityManagerService.ItemMatcher;
import com.android.server.wm.ConfigurationContainer;
+import com.android.server.wm.DisplayWindowController;
import com.android.server.wm.StackWindowController;
import com.android.server.wm.StackWindowListener;
import com.android.server.wm.WindowManagerService;
@@ -2615,17 +2616,18 @@
// that the previous one will be hidden soon. This way it can know
// to ignore it when computing the desired screen orientation.
boolean anim = true;
+ final DisplayWindowController dwc = getDisplay().getWindowContainerController();
if (prev != null) {
if (prev.finishing) {
if (DEBUG_TRANSITION) Slog.v(TAG_TRANSITION,
"Prepare close transition: prev=" + prev);
if (mStackSupervisor.mNoAnimActivities.contains(prev)) {
anim = false;
- mWindowManager.prepareAppTransition(TRANSIT_NONE, false);
+ dwc.prepareAppTransition(TRANSIT_NONE, false);
} else {
- mWindowManager.prepareAppTransition(prev.getTask() == next.getTask()
- ? TRANSIT_ACTIVITY_CLOSE
- : TRANSIT_TASK_CLOSE, false);
+ dwc.prepareAppTransition(
+ prev.getTask() == next.getTask() ? TRANSIT_ACTIVITY_CLOSE
+ : TRANSIT_TASK_CLOSE, false);
}
prev.setVisibility(false);
} else {
@@ -2633,22 +2635,21 @@
"Prepare open transition: prev=" + prev);
if (mStackSupervisor.mNoAnimActivities.contains(next)) {
anim = false;
- mWindowManager.prepareAppTransition(TRANSIT_NONE, false);
+ dwc.prepareAppTransition(TRANSIT_NONE, false);
} else {
- mWindowManager.prepareAppTransition(prev.getTask() == next.getTask()
- ? TRANSIT_ACTIVITY_OPEN
- : next.mLaunchTaskBehind
- ? TRANSIT_TASK_OPEN_BEHIND
- : TRANSIT_TASK_OPEN, false);
+ dwc.prepareAppTransition(
+ prev.getTask() == next.getTask() ? TRANSIT_ACTIVITY_OPEN
+ : next.mLaunchTaskBehind ? TRANSIT_TASK_OPEN_BEHIND
+ : TRANSIT_TASK_OPEN, false);
}
}
} else {
if (DEBUG_TRANSITION) Slog.v(TAG_TRANSITION, "Prepare open transition: no previous");
if (mStackSupervisor.mNoAnimActivities.contains(next)) {
anim = false;
- mWindowManager.prepareAppTransition(TRANSIT_NONE, false);
+ dwc.prepareAppTransition(TRANSIT_NONE, false);
} else {
- mWindowManager.prepareAppTransition(TRANSIT_ACTIVITY_OPEN, false);
+ dwc.prepareAppTransition(TRANSIT_ACTIVITY_OPEN, false);
}
}
@@ -2777,7 +2778,8 @@
next.clearOptionsLocked();
transaction.setLifecycleStateRequest(
ResumeActivityItem.obtain(next.app.getReportedProcState(),
- mService.isNextTransitionForward()));
+ getDisplay().getWindowContainerController()
+ .isNextTransitionForward()));
mService.getLifecycleManager().scheduleTransaction(transaction);
if (DEBUG_STATES) Slog.d(TAG_STATES, "resumeTopActivityLocked: Resumed "
@@ -2984,10 +2986,11 @@
task.setFrontOfTask();
if (!isHomeOrRecentsStack() || numActivities() > 0) {
+ final DisplayWindowController dwc = getDisplay().getWindowContainerController();
if (DEBUG_TRANSITION) Slog.v(TAG_TRANSITION,
"Prepare open transition: starting " + r);
if ((r.intent.getFlags() & Intent.FLAG_ACTIVITY_NO_ANIMATION) != 0) {
- mWindowManager.prepareAppTransition(TRANSIT_NONE, keepCurTransition);
+ dwc.prepareAppTransition(TRANSIT_NONE, keepCurTransition);
mStackSupervisor.mNoAnimActivities.add(r);
} else {
int transit = TRANSIT_ACTIVITY_OPEN;
@@ -3006,7 +3009,7 @@
transit = TRANSIT_TASK_OPEN;
}
}
- mWindowManager.prepareAppTransition(transit, keepCurTransition);
+ dwc.prepareAppTransition(transit, keepCurTransition);
mStackSupervisor.mNoAnimActivities.remove(r);
}
boolean doShow = true;
@@ -3635,8 +3638,8 @@
int taskNdx = mTaskHistory.indexOf(finishedTask);
final TaskRecord task = finishedTask;
int activityNdx = task.mActivities.indexOf(r);
- mWindowManager.prepareAppTransition(TRANSIT_CRASHING_ACTIVITY_CLOSE,
- false /* alwaysKeepCurrent */);
+ getDisplay().getWindowContainerController().prepareAppTransition(
+ TRANSIT_CRASHING_ACTIVITY_CLOSE, false /* alwaysKeepCurrent */);
finishActivityLocked(r, Activity.RESULT_CANCELED, null, reason, false);
finishedTask = task;
// Also terminate any activities below it that aren't yet
@@ -3801,7 +3804,7 @@
mService.getTaskChangeNotificationController().notifyTaskRemovalStarted(
task.taskId);
}
- mWindowManager.prepareAppTransition(transit, false);
+ getDisplay().getWindowContainerController().prepareAppTransition(transit, false);
// Tell window manager to prepare for this one to be removed.
r.setVisibility(false);
@@ -3856,9 +3859,10 @@
}
private void prepareActivityHideTransitionAnimation(ActivityRecord r, int transit) {
- mWindowManager.prepareAppTransition(transit, false);
+ final DisplayWindowController dwc = getDisplay().getWindowContainerController();
+ dwc.prepareAppTransition(transit, false);
r.setVisibility(false);
- mWindowManager.executeAppTransition();
+ dwc.executeAppTransition();
if (!mStackSupervisor.mActivitiesWaitingForVisibleActivity.contains(r)) {
mStackSupervisor.mActivitiesWaitingForVisibleActivity.add(r);
}
@@ -4602,7 +4606,7 @@
ActivityOptions.abort(options);
}
}
- mWindowManager.prepareAppTransition(transit, false);
+ getDisplay().getWindowContainerController().prepareAppTransition(transit, false);
}
private void updateTaskMovement(TaskRecord task, boolean toFront) {
@@ -4671,7 +4675,8 @@
if (DEBUG_TRANSITION) Slog.v(TAG_TRANSITION, "Prepare to front transition: task=" + tr);
if (noAnimation) {
- mWindowManager.prepareAppTransition(TRANSIT_NONE, false);
+ getDisplay().getWindowContainerController().prepareAppTransition(
+ TRANSIT_NONE, false);
if (r != null) {
mStackSupervisor.mNoAnimActivities.add(r);
}
@@ -4753,7 +4758,8 @@
mTaskHistory.add(0, tr);
updateTaskMovement(tr, false);
- mWindowManager.prepareAppTransition(TRANSIT_TASK_TO_BACK, false);
+ getDisplay().getWindowContainerController().prepareAppTransition(
+ TRANSIT_TASK_TO_BACK, false);
moveToBack("moveTaskToBackLocked", tr);
if (inPinnedWindowingMode()) {
@@ -5077,8 +5083,8 @@
+ r.intent.getComponent().flattenToShortString());
// Force the destroy to skip right to removal.
r.app = null;
- mWindowManager.prepareAppTransition(TRANSIT_CRASHING_ACTIVITY_CLOSE,
- false /* alwaysKeepCurrent */);
+ getDisplay().getWindowContainerController().prepareAppTransition(
+ TRANSIT_CRASHING_ACTIVITY_CLOSE, false /* alwaysKeepCurrent */);
finishCurrentActivityLocked(r, FINISH_IMMEDIATELY, false,
"handleAppCrashedLocked");
}
@@ -5410,7 +5416,7 @@
}
void executeAppTransition(ActivityOptions options) {
- mWindowManager.executeAppTransition();
+ getDisplay().getWindowContainerController().executeAppTransition();
ActivityOptions.abort(options);
}
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index 17454b4..8f5e02d 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -1072,6 +1072,13 @@
return foundResumed;
}
+ private void executeAppTransitionForAllDisplay() {
+ for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
+ final ActivityDisplay display = mActivityDisplays.get(displayNdx);
+ display.getWindowContainerController().executeAppTransition();
+ }
+ }
+
/**
* Pause all activities in either all of the stacks or just the back stacks.
* @param userLeaving Passed to pauseActivity() to indicate whether to call onUserLeaving().
@@ -1421,6 +1428,8 @@
// Create activity launch transaction.
final ClientTransaction clientTransaction = ClientTransaction.obtain(
proc.getThread(), r.appToken);
+
+ final DisplayWindowController dwc = r.getDisplay().getWindowContainerController();
clientTransaction.addCallback(LaunchActivityItem.obtain(new Intent(r.intent),
System.identityHashCode(r), r.info,
// TODO: Have this take the merged configuration instead of separate global
@@ -1429,12 +1438,12 @@
mergedConfiguration.getOverrideConfiguration(), r.compat,
r.launchedFromPackage, task.voiceInteractor, proc.getReportedProcState(),
r.icicle, r.persistentState, results, newIntents,
- mService.isNextTransitionForward(), profilerInfo));
+ dwc.isNextTransitionForward(), profilerInfo));
// Set desired final state.
final ActivityLifecycleItem lifecycleItem;
if (andResume) {
- lifecycleItem = ResumeActivityItem.obtain(mService.isNextTransitionForward());
+ lifecycleItem = ResumeActivityItem.obtain(dwc.isNextTransitionForward());
} else {
lifecycleItem = PauseActivityItem.obtain();
}
@@ -3520,7 +3529,9 @@
}
if (stack.getDisplay().allResumedActivitiesComplete()) {
ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
- mWindowManager.executeAppTransition();
+ // Make sure activity & window visibility should be identical
+ // for all displays in this stage.
+ executeAppTransitionForAllDisplay();
return true;
}
return false;
@@ -4618,6 +4629,7 @@
// not run into issues where we still need to draw the task in recents but the
// docked stack is already created.
deferUpdateRecentsHomeStackBounds();
+ // TODO(multi-display): currently recents animation only support default display.
mWindowManager.prepareAppTransition(TRANSIT_DOCK_TASK_FROM_RECENTS, false);
}
diff --git a/services/core/java/com/android/server/am/ActivityStarter.java b/services/core/java/com/android/server/am/ActivityStarter.java
index fa227a2..37ddaf9 100644
--- a/services/core/java/com/android/server/am/ActivityStarter.java
+++ b/services/core/java/com/android/server/am/ActivityStarter.java
@@ -1502,7 +1502,7 @@
mTargetStack.ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
// Go ahead and tell window manager to execute app transition for this activity
// since the app transition will not be triggered through the resume channel.
- mService.mWindowManager.executeAppTransition();
+ mTargetStack.getDisplay().getWindowContainerController().executeAppTransition();
} else {
// If the target stack was not previously focusable (previous top running activity
// on that stack was not visible) then any prior calls to move the stack to the
diff --git a/services/core/java/com/android/server/am/ActivityTaskManagerService.java b/services/core/java/com/android/server/am/ActivityTaskManagerService.java
index 5b0a4a9..078ed0e 100644
--- a/services/core/java/com/android/server/am/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityTaskManagerService.java
@@ -65,11 +65,8 @@
import static android.service.voice.VoiceInteractionSession.SHOW_SOURCE_APPLICATION;
import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.Display.INVALID_DISPLAY;
-import static android.view.WindowManager.TRANSIT_ACTIVITY_OPEN;
import static android.view.WindowManager.TRANSIT_NONE;
import static android.view.WindowManager.TRANSIT_TASK_IN_PLACE;
-import static android.view.WindowManager.TRANSIT_TASK_OPEN;
-import static android.view.WindowManager.TRANSIT_TASK_TO_FRONT;
import static com.android.server.am.ActivityManagerService.ANR_TRACE_DIR;
import static com.android.server.am.ActivityManagerService.MY_PID;
@@ -259,6 +256,7 @@
import com.android.server.uri.UriGrantsManagerInternal;
import com.android.server.vr.VrManagerInternal;
import com.android.server.wm.ActivityTaskManagerInternal;
+import com.android.server.wm.DisplayWindowController;
import com.android.server.wm.PinnedStackWindowController;
import com.android.server.wm.WindowManagerService;
@@ -1622,8 +1620,8 @@
if (self.isState(
ActivityStack.ActivityState.RESUMED, ActivityStack.ActivityState.PAUSING)) {
- mWindowManager.overridePendingAppTransition(packageName,
- enterAnim, exitAnim, null);
+ self.getDisplay().getWindowContainerController().overridePendingAppTransition(
+ packageName, enterAnim, exitAnim, null);
}
Binder.restoreCallingIdentity(origId);
@@ -2941,10 +2939,16 @@
throw new IllegalArgumentException("Expected in-place ActivityOption " +
"with valid animation");
}
- mWindowManager.prepareAppTransition(TRANSIT_TASK_IN_PLACE, false);
- mWindowManager.overridePendingAppTransitionInPlace(activityOptions.getPackageName(),
- activityOptions.getCustomInPlaceResId());
- mWindowManager.executeAppTransition();
+ // Get top display of front most application.
+ final ActivityStack focusedStack = getTopDisplayFocusedStack();
+ if (focusedStack != null) {
+ final DisplayWindowController dwc =
+ focusedStack.getDisplay().getWindowContainerController();
+ dwc.prepareAppTransition(TRANSIT_TASK_IN_PLACE, false);
+ dwc.overridePendingAppTransitionInPlace(activityOptions.getPackageName(),
+ activityOptions.getCustomInPlaceResId());
+ dwc.executeAppTransition();
+ }
}
@Override
@@ -4384,13 +4388,6 @@
return mKeyguardController.isKeyguardLocked();
}
- boolean isNextTransitionForward() {
- int transit = mWindowManager.getPendingAppTransition();
- return transit == TRANSIT_ACTIVITY_OPEN
- || transit == TRANSIT_TASK_OPEN
- || transit == TRANSIT_TASK_TO_FRONT;
- }
-
void dumpLastANRLocked(PrintWriter pw) {
pw.println("ACTIVITY MANAGER LAST ANR (dumpsys activity lastanr)");
if (mLastANRState == null) {
@@ -5701,23 +5698,23 @@
}
@Override
- public void notifyKeyguardFlagsChanged(@Nullable Runnable callback) {
+ public void notifyKeyguardFlagsChanged(@Nullable Runnable callback, int displayId) {
synchronized (mGlobalLock) {
// We might change the visibilities here, so prepare an empty app transition which
// might be overridden later if we actually change visibilities.
- final boolean wasTransitionSet =
- mWindowManager.getPendingAppTransition() != TRANSIT_NONE;
+ final DisplayWindowController dwc = mStackSupervisor.getActivityDisplay(displayId)
+ .getWindowContainerController();
+ final boolean wasTransitionSet = dwc.getPendingAppTransition() != TRANSIT_NONE;
if (!wasTransitionSet) {
- mWindowManager.prepareAppTransition(TRANSIT_NONE,
- false /* alwaysKeepCurrent */);
+ dwc.prepareAppTransition(TRANSIT_NONE, false /* alwaysKeepCurrent */);
}
mStackSupervisor.ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
// If there was a transition set already we don't want to interfere with it as we
// might be starting it too early.
if (!wasTransitionSet) {
- mWindowManager.executeAppTransition();
+ dwc.executeAppTransition();
}
}
if (callback != null) {
diff --git a/services/core/java/com/android/server/am/KeyguardController.java b/services/core/java/com/android/server/am/KeyguardController.java
index 28b2a42..9c41c77 100644
--- a/services/core/java/com/android/server/am/KeyguardController.java
+++ b/services/core/java/com/android/server/am/KeyguardController.java
@@ -48,6 +48,7 @@
import com.android.internal.policy.IKeyguardDismissCallback;
import com.android.server.policy.WindowManagerPolicy;
import com.android.server.wm.ActivityTaskManagerInternal.SleepToken;
+import com.android.server.wm.DisplayWindowController;
import com.android.server.wm.WindowManagerService;
import java.io.PrintWriter;
@@ -160,9 +161,10 @@
mWindowManager.deferSurfaceLayout();
try {
setKeyguardGoingAway(true);
- mWindowManager.prepareAppTransition(TRANSIT_KEYGUARD_GOING_AWAY,
- false /* alwaysKeepCurrent */, convertTransitFlags(flags),
- false /* forceOverride */);
+ mStackSupervisor.getDefaultDisplay().getWindowContainerController()
+ .prepareAppTransition(TRANSIT_KEYGUARD_GOING_AWAY,
+ false /* alwaysKeepCurrent */, convertTransitFlags(flags),
+ false /* forceOverride */);
updateKeyguardSleepToken();
// Some stack visibility might change (e.g. docked stack)
@@ -285,8 +287,10 @@
if (isKeyguardLocked()) {
mWindowManager.deferSurfaceLayout();
try {
- mWindowManager.prepareAppTransition(resolveOccludeTransit(),
- false /* alwaysKeepCurrent */, 0 /* flags */, true /* forceOverride */);
+ mStackSupervisor.getDefaultDisplay().getWindowContainerController()
+ .prepareAppTransition(resolveOccludeTransit(),
+ false /* alwaysKeepCurrent */, 0 /* flags */,
+ true /* forceOverride */);
updateKeyguardSleepToken();
mStackSupervisor.ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
mWindowManager.executeAppTransition();
@@ -310,10 +314,12 @@
// If we are about to unocclude the Keyguard, but we can dismiss it without security,
// we immediately dismiss the Keyguard so the activity gets shown without a flicker.
+ final DisplayWindowController dwc =
+ mStackSupervisor.getDefaultDisplay().getWindowContainerController();
if (mKeyguardShowing && canDismissKeyguard()
- && mWindowManager.getPendingAppTransition() == TRANSIT_KEYGUARD_UNOCCLUDE) {
- mWindowManager.prepareAppTransition(mBeforeUnoccludeTransit,
- false /* alwaysKeepCurrent */, 0 /* flags */, true /* forceOverride */);
+ && dwc.getPendingAppTransition() == TRANSIT_KEYGUARD_UNOCCLUDE) {
+ dwc.prepareAppTransition(mBeforeUnoccludeTransit, false /* alwaysKeepCurrent */,
+ 0 /* flags */, true /* forceOverride */);
mStackSupervisor.ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
mWindowManager.executeAppTransition();
}
@@ -332,8 +338,10 @@
}
private int resolveOccludeTransit() {
+ final DisplayWindowController dwc =
+ mStackSupervisor.getDefaultDisplay().getWindowContainerController();
if (mBeforeUnoccludeTransit != TRANSIT_UNSET
- && mWindowManager.getPendingAppTransition() == TRANSIT_KEYGUARD_UNOCCLUDE
+ && dwc.getPendingAppTransition() == TRANSIT_KEYGUARD_UNOCCLUDE
// TODO(b/113840485): Handle app transition for individual display.
&& isDisplayOccluded(DEFAULT_DISPLAY)) {
@@ -344,7 +352,7 @@
} else if (!isDisplayOccluded(DEFAULT_DISPLAY)) {
// Save transit in case we dismiss/occlude Keyguard shortly after.
- mBeforeUnoccludeTransit = mWindowManager.getPendingAppTransition();
+ mBeforeUnoccludeTransit = dwc.getPendingAppTransition();
return TRANSIT_KEYGUARD_UNOCCLUDE;
} else {
return TRANSIT_KEYGUARD_OCCLUDE;
diff --git a/services/core/java/com/android/server/am/LockTaskController.java b/services/core/java/com/android/server/am/LockTaskController.java
index d5f2d34..bcebaaa 100644
--- a/services/core/java/com/android/server/am/LockTaskController.java
+++ b/services/core/java/com/android/server/am/LockTaskController.java
@@ -580,7 +580,10 @@
mSupervisor.findTaskToMoveToFront(task, 0, null, reason,
lockTaskModeState != LOCK_TASK_MODE_NONE);
mSupervisor.resumeFocusedStacksTopActivitiesLocked();
- mWindowManager.executeAppTransition();
+ final ActivityStack stack = task.getStack();
+ if (stack != null) {
+ stack.getDisplay().getWindowContainerController().executeAppTransition();
+ }
} else if (lockTaskModeState != LOCK_TASK_MODE_NONE) {
mSupervisor.handleNonResizableTaskIfNeeded(task, WINDOWING_MODE_UNDEFINED,
DEFAULT_DISPLAY, task.getStack(), true /* forceNonResizable */);
diff --git a/services/core/java/com/android/server/am/RecentsAnimation.java b/services/core/java/com/android/server/am/RecentsAnimation.java
index c5586bb..41d488ba 100644
--- a/services/core/java/com/android/server/am/RecentsAnimation.java
+++ b/services/core/java/com/android/server/am/RecentsAnimation.java
@@ -41,6 +41,8 @@
import android.os.Trace;
import android.util.Slog;
import android.view.IRecentsAnimationRunner;
+
+import com.android.server.wm.DisplayWindowController;
import com.android.server.wm.RecentsAnimationController;
import com.android.server.wm.RecentsAnimationController.RecentsAnimationCallbacks;
import com.android.server.wm.WindowManagerService;
@@ -85,10 +87,13 @@
+ " assistDataReceiver=" + assistDataReceiver);
Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "RecentsAnimation#startRecentsActivity");
+ // TODO(multi-display) currently only support recents animation in default display.
+ final DisplayWindowController dwc =
+ mStackSupervisor.getDefaultDisplay().getWindowContainerController();
if (!mWindowManager.canStartRecentsAnimation()) {
notifyAnimationCancelBeforeStart(recentsAnimationRunner);
if (DEBUG) Slog.d(TAG, "Can't start recents animation, nextAppTransition="
- + mWindowManager.getPendingAppTransition());
+ + dwc.getPendingAppTransition());
return;
}
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java b/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
index b011da6..ae47c27 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
@@ -229,8 +229,9 @@
* @param callback Callback to run after activity visibilities have been reevaluated. This can
* be used from window manager so that when the callback is called, it's
* guaranteed that all apps have their visibility updated accordingly.
+ * @param displayId The id of the display where the keyguard flags changed.
*/
- public abstract void notifyKeyguardFlagsChanged(@Nullable Runnable callback);
+ public abstract void notifyKeyguardFlagsChanged(@Nullable Runnable callback, int displayId);
/**
* Called when the trusted state of Keyguard has changed.
diff --git a/services/core/java/com/android/server/wm/AppTransition.java b/services/core/java/com/android/server/wm/AppTransition.java
index a9d0978..10a1be5 100644
--- a/services/core/java/com/android/server/wm/AppTransition.java
+++ b/services/core/java/com/android/server/wm/AppTransition.java
@@ -166,6 +166,7 @@
private final Context mContext;
private final WindowManagerService mService;
+ private final DisplayContent mDisplayContent;
private @TransitionType int mNextAppTransition = TRANSIT_UNSET;
private @TransitionFlags int mNextAppTransitionFlags = 0;
@@ -257,10 +258,11 @@
final Handler mHandler;
final Runnable mHandleAppTransitionTimeoutRunnable = () -> handleAppTransitionTimeout();
- AppTransition(Context context, WindowManagerService service) {
+ AppTransition(Context context, WindowManagerService service, DisplayContent displayContent) {
mContext = context;
mService = service;
mHandler = new Handler(service.mH.getLooper());
+ mDisplayContent = displayContent;
mLinearOutSlowInInterpolator = AnimationUtils.loadInterpolator(context,
com.android.internal.R.interpolator.linear_out_slow_in);
mFastOutLinearInInterpolator = AnimationUtils.loadInterpolator(context,
@@ -426,7 +428,7 @@
? topOpeningAnim.getStatusBarTransitionsStartTime()
: SystemClock.uptimeMillis(),
AnimationAdapter.STATUS_BAR_TRANSITION_DURATION);
- mService.getDefaultDisplayContentLocked().getDockedDividerController()
+ mDisplayContent.getDockedDividerController()
.notifyAppTransitionStarting(openingApps, transit);
if (mRemoteAnimationController != null) {
@@ -2142,7 +2144,8 @@
+ " transit=" + appTransitionToString(transit)
+ " " + this
+ " alwaysKeepCurrent=" + alwaysKeepCurrent
- + " Callers=" + Debug.getCallers(3));
+ + " displayId=" + mDisplayContent.getDisplayId()
+ + " Callers=" + Debug.getCallers(5));
final boolean allowSetCrashing = !isKeyguardTransit(mNextAppTransition)
&& transit == TRANSIT_CRASHING_ACTIVITY_CLOSE;
if (forceOverride || isKeyguardTransit(transit) || !isTransitionSet()
@@ -2218,14 +2221,18 @@
private void handleAppTransitionTimeout() {
synchronized (mService.mWindowMap) {
- if (isTransitionSet() || !mService.mOpeningApps.isEmpty()
- || !mService.mClosingApps.isEmpty()) {
+ final DisplayContent dc = mDisplayContent;
+ if (dc == null) {
+ return;
+ }
+ if (isTransitionSet() || !dc.mOpeningApps.isEmpty() || !dc.mClosingApps.isEmpty()) {
if (DEBUG_APP_TRANSITIONS) {
Slog.v(TAG_WM, "*** APP TRANSITION TIMEOUT."
+ + " displayId=" + dc.getDisplayId()
+ " isTransitionSet()="
- + mService.mAppTransition.isTransitionSet()
- + " mOpeningApps.size()=" + mService.mOpeningApps.size()
- + " mClosingApps.size()=" + mService.mClosingApps.size());
+ + dc.mAppTransition.isTransitionSet()
+ + " mOpeningApps.size()=" + dc.mOpeningApps.size()
+ + " mClosingApps.size()=" + dc.mClosingApps.size());
}
setTimeout();
mService.mWindowPlacerLocked.performSurfacePlacement();
diff --git a/services/core/java/com/android/server/wm/AppTransitionController.java b/services/core/java/com/android/server/wm/AppTransitionController.java
new file mode 100644
index 0000000..94a47dd
--- /dev/null
+++ b/services/core/java/com/android/server/wm/AppTransitionController.java
@@ -0,0 +1,631 @@
+/*
+ * Copyright (C) 2018 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 android.view.WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
+import static android.view.WindowManager.TRANSIT_ACTIVITY_CLOSE;
+import static android.view.WindowManager.TRANSIT_ACTIVITY_OPEN;
+import static android.view.WindowManager.TRANSIT_CRASHING_ACTIVITY_CLOSE;
+import static android.view.WindowManager.TRANSIT_DOCK_TASK_FROM_RECENTS;
+import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_NO_ANIMATION;
+import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_TO_SHADE;
+import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_WITH_WALLPAPER;
+import static android.view.WindowManager.TRANSIT_KEYGUARD_GOING_AWAY;
+import static android.view.WindowManager.TRANSIT_KEYGUARD_GOING_AWAY_ON_WALLPAPER;
+import static android.view.WindowManager.TRANSIT_NONE;
+import static android.view.WindowManager.TRANSIT_TASK_CLOSE;
+import static android.view.WindowManager.TRANSIT_TASK_IN_PLACE;
+import static android.view.WindowManager.TRANSIT_TASK_OPEN;
+import static android.view.WindowManager.TRANSIT_TASK_TO_BACK;
+import static android.view.WindowManager.TRANSIT_TASK_TO_FRONT;
+import static android.view.WindowManager.TRANSIT_TRANSLUCENT_ACTIVITY_CLOSE;
+import static android.view.WindowManager.TRANSIT_TRANSLUCENT_ACTIVITY_OPEN;
+import static android.view.WindowManager.TRANSIT_WALLPAPER_CLOSE;
+import static android.view.WindowManager.TRANSIT_WALLPAPER_INTRA_CLOSE;
+import static android.view.WindowManager.TRANSIT_WALLPAPER_INTRA_OPEN;
+import static android.view.WindowManager.TRANSIT_WALLPAPER_OPEN;
+
+import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_CONFIG;
+import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT;
+import static com.android.server.wm.ActivityTaskManagerInternal.APP_TRANSITION_SNAPSHOT;
+import static com.android.server.wm.ActivityTaskManagerInternal.APP_TRANSITION_SPLASH_SCREEN;
+import static com.android.server.wm.ActivityTaskManagerInternal.APP_TRANSITION_WINDOWS_DRAWN;
+import static com.android.server.wm.AppTransition.isKeyguardGoingAwayTransit;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_APP_TRANSITIONS;
+import static com.android.server.wm.WindowManagerDebugConfig.SHOW_LIGHT_TRANSACTIONS;
+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.H.NOTIFY_APP_TRANSITION_STARTING;
+
+import android.app.WindowConfiguration;
+import android.os.Trace;
+import android.util.ArraySet;
+import android.util.Slog;
+import android.util.SparseIntArray;
+import android.view.Display;
+import android.view.RemoteAnimationAdapter;
+import android.view.RemoteAnimationDefinition;
+import android.view.WindowManager;
+import android.view.WindowManager.LayoutParams;
+import android.view.animation.Animation;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+import java.util.function.Predicate;
+
+
+/**
+ * Checks for app transition readiness, resolves animation attributes and performs visibility
+ * change for apps that animate as part of an app transition.
+ */
+public class AppTransitionController {
+ private static final String TAG = TAG_WITH_CLASS_NAME ? "AppTransitionController" : TAG_WM;
+ private final WindowManagerService mService;
+ private final DisplayContent mDisplayContent;
+ private final WallpaperController mWallpaperControllerLocked;
+
+ private final SparseIntArray mTempTransitionReasons = new SparseIntArray();
+
+ AppTransitionController(WindowManagerService service, DisplayContent displayContent) {
+ mService = service;
+ mDisplayContent = displayContent;
+ mWallpaperControllerLocked = new WallpaperController(mService);
+ }
+
+ /**
+ * Handle application transition for given display.
+ */
+ void handleAppTransitionReady() {
+ final int appsCount = mDisplayContent.mOpeningApps.size();
+ if (!transitionGoodToGo(appsCount, mTempTransitionReasons)) {
+ return;
+ }
+ Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "AppTransitionReady");
+
+ if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "**** GOOD TO GO");
+ int transit = mDisplayContent.mAppTransition.getAppTransition();
+ if (mDisplayContent.mSkipAppTransitionAnimation && !isKeyguardGoingAwayTransit(transit)) {
+ transit = WindowManager.TRANSIT_UNSET;
+ }
+ mDisplayContent.mSkipAppTransitionAnimation = false;
+ mDisplayContent.mNoAnimationNotifyOnTransitionFinished.clear();
+
+ mDisplayContent.mAppTransition.removeAppTransitionTimeoutCallbacks();
+
+ mService.mRoot.mWallpaperMayChange = false;
+
+ int i;
+ for (i = 0; i < appsCount; i++) {
+ final AppWindowToken wtoken = mDisplayContent.mOpeningApps.valueAt(i);
+ // Clearing the mAnimatingExit flag before entering animation. It's set to true if app
+ // window is removed, or window relayout to invisible. This also affects window
+ // visibility. We need to clear it *before* maybeUpdateTransitToWallpaper() as the
+ // transition selection depends on wallpaper target visibility.
+ wtoken.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,
+ mDisplayContent.mOpeningApps);
+
+ // Determine if closing and opening app token sets are wallpaper targets, in which case
+ // special animations are needed.
+ final boolean hasWallpaperTarget = mWallpaperControllerLocked.getWallpaperTarget() != null;
+ final boolean openingAppHasWallpaper = canBeWallpaperTarget(mDisplayContent.mOpeningApps)
+ && hasWallpaperTarget;
+ final boolean closingAppHasWallpaper = canBeWallpaperTarget(mDisplayContent.mClosingApps)
+ && hasWallpaperTarget;
+
+ transit = maybeUpdateTransitToTranslucentAnim(transit);
+ transit = maybeUpdateTransitToWallpaper(transit, openingAppHasWallpaper,
+ closingAppHasWallpaper);
+
+ // Find the layout params of the top-most application window in the tokens, which is
+ // what will control the animation theme. If all closing windows are obscured, then there is
+ // 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);
+ final boolean allowAnimations = mService.mPolicy.allowAppAnimationsLw();
+ final AppWindowToken animLpToken = allowAnimations
+ ? findAnimLayoutParamsToken(transit, activityTypes)
+ : null;
+ final AppWindowToken topOpeningApp = allowAnimations
+ ? getTopApp(mDisplayContent.mOpeningApps, false /* ignoreHidden */)
+ : null;
+ final AppWindowToken topClosingApp = allowAnimations
+ ? getTopApp(mDisplayContent.mClosingApps, false /* ignoreHidden */)
+ : null;
+ final WindowManager.LayoutParams animLp = getAnimLp(animLpToken);
+ overrideWithRemoteAnimationIfSet(animLpToken, transit, activityTypes);
+
+ final boolean voiceInteraction = containsVoiceInteraction(mDisplayContent.mOpeningApps)
+ || containsVoiceInteraction(mDisplayContent.mOpeningApps);
+
+ final int layoutRedo;
+ mService.mSurfaceAnimationRunner.deferStartingAnimations();
+ try {
+ processApplicationsAnimatingInPlace(transit);
+
+ handleClosingApps(transit, animLp, voiceInteraction);
+ handleOpeningApps(transit, animLp, voiceInteraction);
+
+ mDisplayContent.mAppTransition.setLastAppTransition(transit, topOpeningApp,
+ topClosingApp);
+
+ final int flags = mDisplayContent.mAppTransition.getTransitFlags();
+ layoutRedo = mDisplayContent.mAppTransition.goodToGo(transit, topOpeningApp,
+ topClosingApp, mDisplayContent.mOpeningApps, mDisplayContent.mClosingApps);
+ handleNonAppWindowsInTransition(transit, flags);
+ mDisplayContent.mAppTransition.postAnimationCallback();
+ mDisplayContent.mAppTransition.clear();
+ } finally {
+ mService.mSurfaceAnimationRunner.continueStartingAnimations();
+ }
+
+ mService.mTaskSnapshotController.onTransitionStarting(mDisplayContent);
+
+ mDisplayContent.mOpeningApps.clear();
+ mDisplayContent.mClosingApps.clear();
+ mDisplayContent.mUnknownAppVisibilityController.clear();
+
+ // This has changed the visibility of windows, so perform
+ // a new layout to get them all up-to-date.
+ mDisplayContent.setLayoutNeeded();
+
+ mDisplayContent.computeImeTarget(true /* updateImeTarget */);
+
+ mService.mH.obtainMessage(NOTIFY_APP_TRANSITION_STARTING,
+ mTempTransitionReasons.clone()).sendToTarget();
+
+ Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
+
+ mDisplayContent.pendingLayoutChanges |=
+ layoutRedo | FINISH_LAYOUT_REDO_LAYOUT | FINISH_LAYOUT_REDO_CONFIG;
+ }
+
+ private static WindowManager.LayoutParams getAnimLp(AppWindowToken wtoken) {
+ final WindowState mainWindow = wtoken != null ? wtoken.findMainWindow() : null;
+ return mainWindow != null ? mainWindow.mAttrs : null;
+ }
+
+ /**
+ * Overrides the pending transition with the remote animation defined for the transition in the
+ * set of defined remote animations in the app window token.
+ */
+ private void overrideWithRemoteAnimationIfSet(AppWindowToken animLpToken, int transit,
+ ArraySet<Integer> activityTypes) {
+ if (transit == TRANSIT_CRASHING_ACTIVITY_CLOSE) {
+ // The crash transition has higher priority than any involved remote animations.
+ return;
+ }
+ if (animLpToken == null) {
+ return;
+ }
+ final RemoteAnimationDefinition definition = animLpToken.getRemoteAnimationDefinition();
+ if (definition == null) {
+ return;
+ }
+ final RemoteAnimationAdapter adapter = definition.getAdapter(transit, activityTypes);
+ if (adapter != null) {
+ animLpToken.getDisplayContent().mAppTransition.overridePendingAppTransitionRemote(
+ adapter);
+ }
+ }
+
+ /**
+ * @return The window token that determines the animation theme.
+ */
+ private AppWindowToken findAnimLayoutParamsToken(@WindowManager.TransitionType int transit,
+ ArraySet<Integer> activityTypes) {
+ AppWindowToken result;
+ final ArraySet<AppWindowToken> closingApps = mDisplayContent.mClosingApps;
+ final ArraySet<AppWindowToken> openingApps = mDisplayContent.mOpeningApps;
+
+ // Remote animations always win, but fullscreen tokens override non-fullscreen tokens.
+ result = lookForHighestTokenWithFilter(closingApps, openingApps,
+ w -> w.getRemoteAnimationDefinition() != null
+ && w.getRemoteAnimationDefinition().hasTransition(transit, activityTypes));
+ if (result != null) {
+ return result;
+ }
+ result = lookForHighestTokenWithFilter(closingApps, openingApps,
+ w -> w.fillsParent() && w.findMainWindow() != null);
+ if (result != null) {
+ return result;
+ }
+ return lookForHighestTokenWithFilter(closingApps, openingApps,
+ w -> w.findMainWindow() != null);
+ }
+
+ /**
+ * @return The set of {@link WindowConfiguration.ActivityType}s contained in the set of apps in
+ * {@code array1} and {@code array2}.
+ */
+ private static ArraySet<Integer> collectActivityTypes(ArraySet<AppWindowToken> array1,
+ ArraySet<AppWindowToken> array2) {
+ final ArraySet<Integer> result = new ArraySet<>();
+ for (int i = array1.size() - 1; i >= 0; i--) {
+ result.add(array1.valueAt(i).getActivityType());
+ }
+ for (int i = array2.size() - 1; i >= 0; i--) {
+ result.add(array2.valueAt(i).getActivityType());
+ }
+ return result;
+ }
+
+ private static AppWindowToken lookForHighestTokenWithFilter(ArraySet<AppWindowToken> array1,
+ ArraySet<AppWindowToken> array2, Predicate<AppWindowToken> filter) {
+ final int array1count = array1.size();
+ final int count = array1count + array2.size();
+ int bestPrefixOrderIndex = Integer.MIN_VALUE;
+ AppWindowToken bestToken = null;
+ for (int i = 0; i < count; i++) {
+ final AppWindowToken wtoken = i < array1count
+ ? array1.valueAt(i)
+ : array2.valueAt(i - array1count);
+ final int prefixOrderIndex = wtoken.getPrefixOrderIndex();
+ if (filter.test(wtoken) && prefixOrderIndex > bestPrefixOrderIndex) {
+ bestPrefixOrderIndex = prefixOrderIndex;
+ bestToken = wtoken;
+ }
+ }
+ return bestToken;
+ }
+
+ private boolean containsVoiceInteraction(ArraySet<AppWindowToken> apps) {
+ for (int i = apps.size() - 1; i >= 0; i--) {
+ if (apps.valueAt(i).mVoiceInteraction) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private void handleOpeningApps(int transit, LayoutParams animLp, boolean voiceInteraction) {
+ final ArraySet<AppWindowToken> openingApps = mDisplayContent.mOpeningApps;
+ final int appsCount = openingApps.size();
+ for (int i = 0; i < appsCount; i++) {
+ AppWindowToken wtoken = openingApps.valueAt(i);
+ if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "Now opening app" + wtoken);
+
+ if (!wtoken.setVisibility(animLp, true, transit, false, voiceInteraction)) {
+ // This token isn't going to be animating. Add it to the list of tokens to
+ // be notified of app transition complete since the notification will not be
+ // sent be the app window animator.
+ mDisplayContent.mNoAnimationNotifyOnTransitionFinished.add(wtoken.token);
+ }
+ wtoken.updateReportedVisibilityLocked();
+ wtoken.waitingToShow = false;
+ if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG,
+ ">>> OPEN TRANSACTION handleAppTransitionReady()");
+ mService.openSurfaceTransaction();
+ try {
+ wtoken.showAllWindowsLocked();
+ } finally {
+ mService.closeSurfaceTransaction("handleAppTransitionReady");
+ if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG,
+ "<<< CLOSE TRANSACTION handleAppTransitionReady()");
+ }
+
+ if (mDisplayContent.mAppTransition.isNextAppTransitionThumbnailUp()) {
+ wtoken.attachThumbnailAnimation();
+ } else if (mDisplayContent.mAppTransition.isNextAppTransitionOpenCrossProfileApps()) {
+ wtoken.attachCrossProfileAppsThumbnailAnimation();
+ }
+ }
+ }
+
+ private void handleClosingApps(int transit, LayoutParams animLp, boolean voiceInteraction) {
+ final ArraySet<AppWindowToken> closingApps = mDisplayContent.mClosingApps;
+ final int appsCount = closingApps.size();
+ for (int i = 0; i < appsCount; i++) {
+ AppWindowToken wtoken = closingApps.valueAt(i);
+
+ if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "Now closing app " + wtoken);
+ // TODO: Do we need to add to mNoAnimationNotifyOnTransitionFinished like above if not
+ // animating?
+ wtoken.setVisibility(animLp, false, transit, false, voiceInteraction);
+ wtoken.updateReportedVisibilityLocked();
+ // Force the allDrawn flag, because we want to start
+ // this guy's animations regardless of whether it's
+ // gotten drawn.
+ wtoken.allDrawn = true;
+ wtoken.deferClearAllDrawn = false;
+ // Ensure that apps that are mid-starting are also scheduled to have their
+ // starting windows removed after the animation is complete
+ if (wtoken.startingWindow != null && !wtoken.startingWindow.mAnimatingExit
+ && wtoken.getController() != null) {
+ wtoken.getController().removeStartingWindow();
+ }
+
+ if (mDisplayContent.mAppTransition.isNextAppTransitionThumbnailDown()) {
+ wtoken.attachThumbnailAnimation();
+ }
+ }
+ }
+
+ private void handleNonAppWindowsInTransition(int transit, int flags) {
+ if (transit == TRANSIT_KEYGUARD_GOING_AWAY) {
+ if ((flags & TRANSIT_FLAG_KEYGUARD_GOING_AWAY_WITH_WALLPAPER) != 0
+ && (flags & TRANSIT_FLAG_KEYGUARD_GOING_AWAY_NO_ANIMATION) == 0) {
+ Animation anim = mService.mPolicy.createKeyguardWallpaperExit(
+ (flags & TRANSIT_FLAG_KEYGUARD_GOING_AWAY_TO_SHADE) != 0);
+ if (anim != null) {
+ mDisplayContent.mWallpaperController.startWallpaperAnimation(anim);
+ }
+ }
+ }
+ if (transit == TRANSIT_KEYGUARD_GOING_AWAY
+ || transit == TRANSIT_KEYGUARD_GOING_AWAY_ON_WALLPAPER) {
+ mDisplayContent.startKeyguardExitOnNonAppWindows(
+ transit == TRANSIT_KEYGUARD_GOING_AWAY_ON_WALLPAPER,
+ (flags & TRANSIT_FLAG_KEYGUARD_GOING_AWAY_TO_SHADE) != 0);
+ }
+ }
+
+ private boolean transitionGoodToGo(int appsCount, SparseIntArray outReasons) {
+ if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
+ "Checking " + appsCount + " opening apps (frozen="
+ + mService.mDisplayFrozen + " timeout="
+ + mDisplayContent.mAppTransition.isTimeout() + ")...");
+ final ScreenRotationAnimation screenRotationAnimation =
+ mService.mAnimator.getScreenRotationAnimationLocked(
+ Display.DEFAULT_DISPLAY);
+
+ outReasons.clear();
+ if (!mDisplayContent.mAppTransition.isTimeout()) {
+ // Imagine the case where we are changing orientation due to an app transition, but a
+ // previous orientation change is still in progress. We won't process the orientation
+ // change for our transition because we need to wait for the rotation animation to
+ // finish.
+ // If we start the app transition at this point, we will interrupt it halfway with a
+ // new rotation animation after the old one finally finishes. It's better to defer the
+ // app transition.
+ if (screenRotationAnimation != null && screenRotationAnimation.isAnimating() &&
+ mService.getDefaultDisplayContentLocked().rotationNeedsUpdate()) {
+ if (DEBUG_APP_TRANSITIONS) {
+ Slog.v(TAG, "Delaying app transition for screen rotation animation to finish");
+ }
+ return false;
+ }
+ for (int i = 0; i < appsCount; i++) {
+ AppWindowToken wtoken = mDisplayContent.mOpeningApps.valueAt(i);
+ if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
+ "Check opening app=" + wtoken + ": allDrawn="
+ + wtoken.allDrawn + " startingDisplayed="
+ + wtoken.startingDisplayed + " startingMoved="
+ + wtoken.startingMoved + " isRelaunching()="
+ + wtoken.isRelaunching() + " startingWindow="
+ + wtoken.startingWindow);
+
+
+ final boolean allDrawn = wtoken.allDrawn && !wtoken.isRelaunching();
+ if (!allDrawn && !wtoken.startingDisplayed && !wtoken.startingMoved) {
+ return false;
+ }
+ final int windowingMode = wtoken.getWindowingMode();
+ if (allDrawn) {
+ outReasons.put(windowingMode, APP_TRANSITION_WINDOWS_DRAWN);
+ } else {
+ outReasons.put(windowingMode,
+ wtoken.startingData instanceof SplashScreenStartingData
+ ? APP_TRANSITION_SPLASH_SCREEN
+ : APP_TRANSITION_SNAPSHOT);
+ }
+ }
+
+ // We also need to wait for the specs to be fetched, if needed.
+ if (mDisplayContent.mAppTransition.isFetchingAppTransitionsSpecs()) {
+ if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "isFetchingAppTransitionSpecs=true");
+ return false;
+ }
+
+ if (!mDisplayContent.mUnknownAppVisibilityController.allResolved()) {
+ if (DEBUG_APP_TRANSITIONS) {
+ Slog.v(TAG, "unknownApps is not empty: "
+ + mDisplayContent.mUnknownAppVisibilityController.getDebugMessage());
+ }
+ return false;
+ }
+
+ // If the wallpaper is visible, we need to check it's ready too.
+ boolean wallpaperReady = !mWallpaperControllerLocked.isWallpaperVisible() ||
+ mWallpaperControllerLocked.wallpaperTransitionReady();
+ if (wallpaperReady) {
+ return true;
+ }
+ return false;
+ }
+ return true;
+ }
+
+ private int maybeUpdateTransitToWallpaper(int transit, boolean openingAppHasWallpaper,
+ boolean closingAppHasWallpaper) {
+ // Given no app transition pass it through instead of a wallpaper transition.
+ // Never convert the crashing transition.
+ // Never update the transition for the wallpaper if we are just docking from recents
+ if (transit == TRANSIT_NONE || transit == TRANSIT_CRASHING_ACTIVITY_CLOSE
+ || transit == TRANSIT_DOCK_TASK_FROM_RECENTS) {
+ return transit;
+ }
+
+ final WindowState wallpaperTarget = mWallpaperControllerLocked.getWallpaperTarget();
+ final boolean showWallpaper = wallpaperTarget != null
+ && (wallpaperTarget.mAttrs.flags & FLAG_SHOW_WALLPAPER) != 0;
+ // If wallpaper is animating or wallpaperTarget doesn't have SHOW_WALLPAPER flag set,
+ // don't consider upgrading to wallpaper transition.
+ final WindowState oldWallpaper =
+ (mWallpaperControllerLocked.isWallpaperTargetAnimating() || !showWallpaper)
+ ? null
+ : wallpaperTarget;
+ final ArraySet<AppWindowToken> openingApps = mDisplayContent.mOpeningApps;
+ final ArraySet<AppWindowToken> closingApps = mDisplayContent.mClosingApps;
+ final AppWindowToken topOpeningApp = getTopApp(mDisplayContent.mOpeningApps,
+ false /* ignoreHidden */);
+ final AppWindowToken topClosingApp = getTopApp(mDisplayContent.mClosingApps,
+ true /* ignoreHidden */);
+
+ boolean openingCanBeWallpaperTarget = canBeWallpaperTarget(openingApps);
+ if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
+ "New wallpaper target=" + wallpaperTarget
+ + ", oldWallpaper=" + oldWallpaper
+ + ", openingApps=" + openingApps
+ + ", closingApps=" + closingApps);
+
+ if (openingCanBeWallpaperTarget && transit == TRANSIT_KEYGUARD_GOING_AWAY) {
+ transit = TRANSIT_KEYGUARD_GOING_AWAY_ON_WALLPAPER;
+ if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
+ "New transit: " + AppTransition.appTransitionToString(transit));
+ }
+ // We never want to change from a Keyguard transit to a non-Keyguard transit, as our logic
+ // relies on the fact that we always execute a Keyguard transition after preparing one.
+ else if (!isKeyguardGoingAwayTransit(transit)) {
+ if (closingAppHasWallpaper && openingAppHasWallpaper) {
+ if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "Wallpaper animation!");
+ switch (transit) {
+ case TRANSIT_ACTIVITY_OPEN:
+ case TRANSIT_TASK_OPEN:
+ case TRANSIT_TASK_TO_FRONT:
+ transit = TRANSIT_WALLPAPER_INTRA_OPEN;
+ break;
+ case TRANSIT_ACTIVITY_CLOSE:
+ case TRANSIT_TASK_CLOSE:
+ case TRANSIT_TASK_TO_BACK:
+ transit = TRANSIT_WALLPAPER_INTRA_CLOSE;
+ break;
+ }
+ if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
+ "New transit: " + AppTransition.appTransitionToString(transit));
+ } else if (oldWallpaper != null && !mDisplayContent.mOpeningApps.isEmpty()
+ && !openingApps.contains(oldWallpaper.mAppToken)
+ && closingApps.contains(oldWallpaper.mAppToken)
+ && topClosingApp == oldWallpaper.mAppToken) {
+ // We are transitioning from an activity with a wallpaper to one without.
+ transit = TRANSIT_WALLPAPER_CLOSE;
+ if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "New transit away from wallpaper: "
+ + AppTransition.appTransitionToString(transit));
+ } else if (wallpaperTarget != null && wallpaperTarget.isVisibleLw()
+ && openingApps.contains(wallpaperTarget.mAppToken)
+ && topOpeningApp == wallpaperTarget.mAppToken
+ && transit != TRANSIT_TRANSLUCENT_ACTIVITY_CLOSE) {
+ // We are transitioning from an activity without
+ // a wallpaper to now showing the wallpaper
+ transit = TRANSIT_WALLPAPER_OPEN;
+ if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "New transit into wallpaper: "
+ + AppTransition.appTransitionToString(transit));
+ }
+ }
+ return transit;
+ }
+
+ /**
+ * There are cases where we open/close a new task/activity, but in reality only a translucent
+ * activity on top of existing activities is opening/closing. For that one, we have a different
+ * animation because non of the task/activity animations actually work well with translucent
+ * apps.
+ *
+ * @param transit The current transition type.
+ * @return The current transition type or
+ * {@link WindowManager#TRANSIT_TRANSLUCENT_ACTIVITY_CLOSE}/
+ * {@link WindowManager#TRANSIT_TRANSLUCENT_ACTIVITY_OPEN} if appropriate for the
+ * situation.
+ */
+ @VisibleForTesting
+ int maybeUpdateTransitToTranslucentAnim(int transit) {
+ final boolean taskOrActivity = AppTransition.isTaskTransit(transit)
+ || AppTransition.isActivityTransit(transit);
+ boolean allOpeningVisible = true;
+ boolean allTranslucentOpeningApps = !mDisplayContent.mOpeningApps.isEmpty();
+ for (int i = mDisplayContent.mOpeningApps.size() - 1; i >= 0; i--) {
+ final AppWindowToken token = mDisplayContent.mOpeningApps.valueAt(i);
+ if (!token.isVisible()) {
+ allOpeningVisible = false;
+ if (token.fillsParent()) {
+ allTranslucentOpeningApps = false;
+ }
+ }
+ }
+ boolean allTranslucentClosingApps = !mDisplayContent.mClosingApps.isEmpty();
+ for (int i = mDisplayContent.mClosingApps.size() - 1; i >= 0; i--) {
+ if (mDisplayContent.mClosingApps.valueAt(i).fillsParent()) {
+ allTranslucentClosingApps = false;
+ break;
+ }
+ }
+
+ if (taskOrActivity && allTranslucentClosingApps && allOpeningVisible) {
+ return TRANSIT_TRANSLUCENT_ACTIVITY_CLOSE;
+ }
+ if (taskOrActivity && allTranslucentOpeningApps && mDisplayContent.mClosingApps.isEmpty()) {
+ return TRANSIT_TRANSLUCENT_ACTIVITY_OPEN;
+ }
+ return transit;
+ }
+
+ private boolean canBeWallpaperTarget(ArraySet<AppWindowToken> apps) {
+ for (int i = apps.size() - 1; i >= 0; i--) {
+ if (apps.valueAt(i).windowsCanBeWallpaperTarget()) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Finds the top app in a list of apps, using its {@link AppWindowToken#getPrefixOrderIndex} to
+ * compare z-order.
+ *
+ * @param apps The list of apps to search.
+ * @param ignoreHidden If set to true, ignores apps that are {@link AppWindowToken#isHidden}.
+ * @return The top {@link AppWindowToken}.
+ */
+ private AppWindowToken getTopApp(ArraySet<AppWindowToken> apps, boolean ignoreHidden) {
+ int topPrefixOrderIndex = Integer.MIN_VALUE;
+ AppWindowToken topApp = null;
+ for (int i = apps.size() - 1; i >= 0; i--) {
+ final AppWindowToken app = apps.valueAt(i);
+ if (ignoreHidden && app.isHidden()) {
+ continue;
+ }
+ final int prefixOrderIndex = app.getPrefixOrderIndex();
+ if (prefixOrderIndex > topPrefixOrderIndex) {
+ topPrefixOrderIndex = prefixOrderIndex;
+ topApp = app;
+ }
+ }
+ return topApp;
+ }
+
+ private void processApplicationsAnimatingInPlace(int transit) {
+ if (transit == TRANSIT_TASK_IN_PLACE) {
+ // Find the focused window
+ final WindowState win = mDisplayContent.findFocusedWindow();
+ if (win != null) {
+ final AppWindowToken wtoken = win.mAppToken;
+ if (DEBUG_APP_TRANSITIONS)
+ Slog.v(TAG, "Now animating app in place " + wtoken);
+ wtoken.cancelAnimation();
+ wtoken.applyAnimationLocked(null, transit, false, false);
+ wtoken.updateReportedVisibilityLocked();
+ wtoken.showAllWindowsLocked();
+ }
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/wm/AppWindowContainerController.java b/services/core/java/com/android/server/wm/AppWindowContainerController.java
index 330c54c..7435ea5 100644
--- a/services/core/java/com/android/server/wm/AppWindowContainerController.java
+++ b/services/core/java/com/android/server/wm/AppWindowContainerController.java
@@ -16,6 +16,15 @@
package com.android.server.wm;
+import static android.app.ActivityOptions.ANIM_CLIP_REVEAL;
+import static android.app.ActivityOptions.ANIM_CUSTOM;
+import static android.app.ActivityOptions.ANIM_OPEN_CROSS_PROFILE_APPS;
+import static android.app.ActivityOptions.ANIM_REMOTE_ANIMATION;
+import static android.app.ActivityOptions.ANIM_SCALE_UP;
+import static android.app.ActivityOptions.ANIM_THUMBNAIL_ASPECT_SCALE_DOWN;
+import static android.app.ActivityOptions.ANIM_THUMBNAIL_ASPECT_SCALE_UP;
+import static android.app.ActivityOptions.ANIM_THUMBNAIL_SCALE_DOWN;
+import static android.app.ActivityOptions.ANIM_THUMBNAIL_SCALE_UP;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
@@ -30,14 +39,20 @@
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
import android.app.ActivityManager.TaskSnapshot;
+import android.app.ActivityOptions;
+import android.content.Intent;
import android.content.res.CompatibilityInfo;
import android.content.res.Configuration;
+import android.graphics.GraphicBuffer;
+import android.graphics.Rect;
import android.os.Debug;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
import android.util.Slog;
+import android.view.AppTransitionAnimationSpec;
+import android.view.IAppTransitionAnimationSpecsFuture;
import android.view.IApplicationToken;
import android.view.RemoteAnimationDefinition;
import android.view.WindowManager;
@@ -324,6 +339,7 @@
}
final AppWindowToken wtoken = mContainer;
+ final AppTransition appTransition = mContainer.getDisplayContent().mAppTransition;
// Don't set visibility to false if we were already not visible. This prevents WM from
// adding the app to the closing app list which doesn't make sense for something that is
@@ -344,12 +360,13 @@
}
if (DEBUG_APP_TRANSITIONS || DEBUG_ORIENTATION) Slog.v(TAG_WM, "setAppVisibility("
- + mToken + ", visible=" + visible + "): " + mService.mAppTransition
+ + mToken + ", visible=" + visible + "): " + appTransition
+ " hidden=" + wtoken.isHidden() + " hiddenRequested="
+ wtoken.hiddenRequested + " Callers=" + Debug.getCallers(6));
- mService.mOpeningApps.remove(wtoken);
- mService.mClosingApps.remove(wtoken);
+ final DisplayContent displayContent = mContainer.getDisplayContent();
+ displayContent.mOpeningApps.remove(wtoken);
+ displayContent.mClosingApps.remove(wtoken);
wtoken.waitingToShow = false;
wtoken.hiddenRequested = !visible;
wtoken.mDeferHidingClient = deferHidingClient;
@@ -360,12 +377,12 @@
// if made visible again.
wtoken.removeDeadWindows();
} else {
- if (!mService.mAppTransition.isTransitionSet()
- && mService.mAppTransition.isReady()) {
+ if (!appTransition.isTransitionSet()
+ && appTransition.isReady()) {
// Add the app mOpeningApps if transition is unset but ready. This means
// we're doing a screen freeze, and the unfreeze will wait for all opening
// apps to be ready.
- mService.mOpeningApps.add(wtoken);
+ displayContent.mOpeningApps.add(wtoken);
}
wtoken.startingMoved = false;
// If the token is currently hidden (should be the common case), or has been
@@ -395,16 +412,16 @@
// If we are preparing an app transition, then delay changing
// the visibility of this token until we execute that transition.
- if (wtoken.okToAnimate() && mService.mAppTransition.isTransitionSet()) {
+ if (wtoken.okToAnimate() && appTransition.isTransitionSet()) {
wtoken.inPendingTransaction = true;
if (visible) {
- mService.mOpeningApps.add(wtoken);
+ displayContent.mOpeningApps.add(wtoken);
wtoken.mEnteringAnimation = true;
} else {
- mService.mClosingApps.add(wtoken);
+ displayContent.mClosingApps.add(wtoken);
wtoken.mEnteringAnimation = false;
}
- if (mService.mAppTransition.getAppTransition()
+ if (appTransition.getAppTransition()
== WindowManager.TRANSIT_TASK_OPEN_BEHIND) {
// We're launchingBehind, add the launching activity to mOpeningApps.
final WindowState win = mContainer.getDisplayContent().findFocusedWindow();
@@ -415,7 +432,7 @@
+ " adding " + focusedToken + " to mOpeningApps");
// Force animation to be loaded.
focusedToken.setHidden(true);
- mService.mOpeningApps.add(focusedToken);
+ displayContent.mOpeningApps.add(focusedToken);
}
}
}
@@ -434,7 +451,8 @@
public void notifyUnknownVisibilityLaunched() {
synchronized(mWindowMap) {
if (mContainer != null) {
- mService.mUnknownAppVisibilityController.notifyLaunched(mContainer);
+ mContainer.getDisplayContent().mUnknownAppVisibilityController.notifyLaunched(
+ mContainer);
}
}
}
@@ -547,7 +565,8 @@
private int getStartingWindowType(boolean newTask, boolean taskSwitch, boolean processRunning,
boolean allowTaskSnapshot, boolean activityCreated, boolean fromRecents,
TaskSnapshot snapshot) {
- if (mService.mAppTransition.getAppTransition() == TRANSIT_DOCK_TASK_FROM_RECENTS) {
+ if (mContainer.getDisplayContent().mAppTransition.getAppTransition()
+ == TRANSIT_DOCK_TASK_FROM_RECENTS) {
// TODO(b/34099271): Remove this statement to add back the starting window and figure
// out why it causes flickering, the starting window appears over the thumbnail while
// the docked from recents transition occurs
@@ -753,6 +772,104 @@
}
/**
+ * Apply override app transition base on options & animation type.
+ */
+ public void applyOptionsLocked(ActivityOptions pendingOptions, Intent intent) {
+ synchronized (mWindowMap) {
+ final int animationType = pendingOptions.getAnimationType();
+ final DisplayContent displayContent = mContainer.getDisplayContent();
+ switch (animationType) {
+ case ANIM_CUSTOM:
+ displayContent.mAppTransition.overridePendingAppTransition(
+ pendingOptions.getPackageName(),
+ pendingOptions.getCustomEnterResId(),
+ pendingOptions.getCustomExitResId(),
+ pendingOptions.getOnAnimationStartListener());
+ break;
+ case ANIM_CLIP_REVEAL:
+ displayContent.mAppTransition.overridePendingAppTransitionClipReveal(
+ pendingOptions.getStartX(), pendingOptions.getStartY(),
+ pendingOptions.getWidth(), pendingOptions.getHeight());
+ if (intent.getSourceBounds() == null) {
+ intent.setSourceBounds(new Rect(pendingOptions.getStartX(),
+ pendingOptions.getStartY(),
+ pendingOptions.getStartX() + pendingOptions.getWidth(),
+ pendingOptions.getStartY() + pendingOptions.getHeight()));
+ }
+ break;
+ case ANIM_SCALE_UP:
+ displayContent.mAppTransition.overridePendingAppTransitionScaleUp(
+ pendingOptions.getStartX(), pendingOptions.getStartY(),
+ pendingOptions.getWidth(), pendingOptions.getHeight());
+ if (intent.getSourceBounds() == null) {
+ intent.setSourceBounds(new Rect(pendingOptions.getStartX(),
+ pendingOptions.getStartY(),
+ pendingOptions.getStartX() + pendingOptions.getWidth(),
+ pendingOptions.getStartY() + pendingOptions.getHeight()));
+ }
+ break;
+ case ANIM_THUMBNAIL_SCALE_UP:
+ case ANIM_THUMBNAIL_SCALE_DOWN:
+ final boolean scaleUp = (animationType == ANIM_THUMBNAIL_SCALE_UP);
+ final GraphicBuffer buffer = pendingOptions.getThumbnail();
+ displayContent.mAppTransition.overridePendingAppTransitionThumb(buffer,
+ pendingOptions.getStartX(), pendingOptions.getStartY(),
+ pendingOptions.getOnAnimationStartListener(),
+ scaleUp);
+ if (intent.getSourceBounds() == null && buffer != null) {
+ intent.setSourceBounds(new Rect(pendingOptions.getStartX(),
+ pendingOptions.getStartY(),
+ pendingOptions.getStartX() + buffer.getWidth(),
+ pendingOptions.getStartY() + buffer.getHeight()));
+ }
+ break;
+ case ANIM_THUMBNAIL_ASPECT_SCALE_UP:
+ case ANIM_THUMBNAIL_ASPECT_SCALE_DOWN:
+ final AppTransitionAnimationSpec[] specs = pendingOptions.getAnimSpecs();
+ final IAppTransitionAnimationSpecsFuture specsFuture =
+ pendingOptions.getSpecsFuture();
+ if (specsFuture != null) {
+ // TODO(multidisplay): Shouldn't be really used anymore from next CL.
+ displayContent.mAppTransition.overridePendingAppTransitionMultiThumbFuture(
+ specsFuture, pendingOptions.getOnAnimationStartListener(),
+ animationType == ANIM_THUMBNAIL_ASPECT_SCALE_UP);
+ } else if (animationType == ANIM_THUMBNAIL_ASPECT_SCALE_DOWN
+ && specs != null) {
+ displayContent.mAppTransition.overridePendingAppTransitionMultiThumb(
+ specs, pendingOptions.getOnAnimationStartListener(),
+ pendingOptions.getAnimationFinishedListener(), false);
+ } else {
+ displayContent.mAppTransition.overridePendingAppTransitionAspectScaledThumb(
+ pendingOptions.getThumbnail(),
+ pendingOptions.getStartX(), pendingOptions.getStartY(),
+ pendingOptions.getWidth(), pendingOptions.getHeight(),
+ pendingOptions.getOnAnimationStartListener(),
+ (animationType == ANIM_THUMBNAIL_ASPECT_SCALE_UP));
+ if (intent.getSourceBounds() == null) {
+ intent.setSourceBounds(new Rect(pendingOptions.getStartX(),
+ pendingOptions.getStartY(),
+ pendingOptions.getStartX() + pendingOptions.getWidth(),
+ pendingOptions.getStartY() + pendingOptions.getHeight()));
+ }
+ }
+ break;
+ case ANIM_OPEN_CROSS_PROFILE_APPS:
+ displayContent.mAppTransition
+ .overridePendingAppTransitionStartCrossProfileApps();
+ break;
+ case ANIM_REMOTE_ANIMATION:
+ // TODO(multidisplay): Will pass displayId and adjust dependencies from next CL.
+ displayContent.mAppTransition.overridePendingAppTransitionRemote(
+ pendingOptions.getRemoteAnimationAdapter());
+ break;
+ default:
+ Slog.e(TAG_WM, "applyOptionsLocked: Unknown animationType=" + animationType);
+ break;
+ }
+ }
+ }
+
+ /**
* Notifies AWT that this app is waiting to pause in order to determine if it will enter PIP.
* This information helps AWT know that the app is in the process of pausing before it gets the
* signal on the WM side.
diff --git a/services/core/java/com/android/server/wm/AppWindowThumbnail.java b/services/core/java/com/android/server/wm/AppWindowThumbnail.java
index ad92f81..729f89b 100644
--- a/services/core/java/com/android/server/wm/AppWindowThumbnail.java
+++ b/services/core/java/com/android/server/wm/AppWindowThumbnail.java
@@ -96,7 +96,7 @@
anim.scaleCurrentDuration(mAppToken.mService.getTransitionAnimationScaleLocked());
mSurfaceAnimator.startAnimation(t, new LocalAnimationAdapter(
new WindowAnimationSpec(anim, position,
- mAppToken.mService.mAppTransition.canSkipFirstFrame()),
+ mAppToken.getDisplayContent().mAppTransition.canSkipFirstFrame()),
mAppToken.mService.mSurfaceAnimationRunner), false /* hidden */);
}
diff --git a/services/core/java/com/android/server/wm/AppWindowToken.java b/services/core/java/com/android/server/wm/AppWindowToken.java
index e38e229..9baafcb 100644
--- a/services/core/java/com/android/server/wm/AppWindowToken.java
+++ b/services/core/java/com/android/server/wm/AppWindowToken.java
@@ -111,6 +111,7 @@
import java.io.PrintWriter;
import java.util.ArrayDeque;
import java.util.ArrayList;
+import java.util.function.Consumer;
class AppTokenList extends ArrayList<AppWindowToken> {
}
@@ -500,14 +501,14 @@
setClientHidden(!visible);
}
- if (!mService.mClosingApps.contains(this) && !mService.mOpeningApps.contains(this)) {
+ if (!getDisplayContent().mClosingApps.contains(this)
+ && !getDisplayContent().mOpeningApps.contains(this)) {
// The token is not closing nor opening, so even if there is an animation set, that
// doesn't mean that it goes through the normal app transition cycle so we have
// to inform the docked controller about visibility change.
// TODO(multi-display): notify docked divider on all displays where visibility was
// affected.
- mService.getDefaultDisplayContentLocked().getDockedDividerController()
- .notifyAppVisibilityChanged();
+ getDisplayContent().getDockedDividerController().notifyAppVisibilityChanged();
// Take the screenshot before possibly hiding the WSA, otherwise the screenshot
// will not be taken.
@@ -524,7 +525,7 @@
// no animation but there will still be a transition set.
// We still need to delay hiding the surface such that it
// can be synchronized with showing the next surface in the transition.
- if (isHidden() && !delayed && !mService.mAppTransition.isTransitionSet()) {
+ if (isHidden() && !delayed && !getDisplayContent().mAppTransition.isTransitionSet()) {
SurfaceControl.openTransaction();
for (int i = mChildren.size() - 1; i >= 0; i--) {
mChildren.get(i).mWinAnimator.hide("immediately hidden");
@@ -630,14 +631,14 @@
boolean delayed = setVisibility(null, false, TRANSIT_UNSET, true, mVoiceInteraction);
- mService.mOpeningApps.remove(this);
- mService.mUnknownAppVisibilityController.appRemovedOrHidden(this);
+ getDisplayContent().mOpeningApps.remove(this);
+ getDisplayContent().mUnknownAppVisibilityController.appRemovedOrHidden(this);
mService.mTaskSnapshotController.onAppRemoved(this);
waitingToShow = false;
- if (mService.mClosingApps.contains(this)) {
+ if (getDisplayContent().mClosingApps.contains(this)) {
delayed = true;
- } else if (mService.mAppTransition.isTransitionSet()) {
- mService.mClosingApps.add(this);
+ } else if (getDisplayContent().mAppTransition.isTransitionSet()) {
+ getDisplayContent().mClosingApps.add(this);
delayed = true;
}
@@ -652,10 +653,10 @@
}
// If this window was animating, then we need to ensure that the app transition notifies
- // that animations have completed in WMS.handleAnimatingStoppedAndTransitionLocked(), so
- // add to that list now
+ // that animations have completed in DisplayContent.handleAnimatingStoppedAndTransition(),
+ // so add to that list now
if (isSelfAnimating()) {
- mService.mNoAnimationNotifyOnTransitionFinished.add(token);
+ getDisplayContent().mNoAnimationNotifyOnTransitionFinished.add(token);
}
final TaskStack stack = getStack();
@@ -795,7 +796,7 @@
if (task == null) {
// It is possible we have been marked as a closing app earlier. We must remove ourselves
// from this list so we do not participate in any future animations.
- mService.mClosingApps.remove(this);
+ getDisplayContent().mClosingApps.remove(this);
} else if (mLastParent != null && mLastParent.mStack != null) {
task.mStack.mExitingAppTokens.remove(this);
}
@@ -1219,7 +1220,7 @@
if (tStartingWindow != null && fromToken.startingSurface != null) {
// In this case, the starting icon has already been displayed, so start
// letting windows get shown immediately without any more transitions.
- mService.mSkipAppTransitionAnimation = true;
+ getDisplayContent().mSkipAppTransitionAnimation = true;
if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Moving existing starting " + tStartingWindow
+ " from " + fromToken + " to " + this);
@@ -1269,7 +1270,7 @@
// When transferring an animation, we no longer need to apply an animation to the
// the token we transfer the animation over. Thus, remove the animation from
// pending opening apps.
- mService.mOpeningApps.remove(this);
+ getDisplayContent().mOpeningApps.remove(this);
mService.updateFocusedWindowLocked(
UPDATE_FOCUS_WILL_PLACE_SURFACES, true /*updateInputWindows*/);
@@ -1323,8 +1324,8 @@
// The {@link AppWindowToken} should only specify an orientation when it is not closing or
// going to the bottom. Allowing closing {@link AppWindowToken} to participate can lead to
// an Activity in another task being started in the wrong orientation during the transition.
- if (!(sendingToBottom || mService.mClosingApps.contains(this))
- && (isVisible() || mService.mOpeningApps.contains(this))) {
+ if (!(sendingToBottom || getDisplayContent().mClosingApps.contains(this))
+ && (isVisible() || getDisplayContent().mOpeningApps.contains(this))) {
return mOrientation;
}
@@ -1398,7 +1399,7 @@
setAppLayoutChanges(FINISH_LAYOUT_REDO_ANIM, "checkAppWindowsReadyToShow");
// We can now show all of the drawn windows!
- if (!mService.mOpeningApps.contains(this) && canShowWindows()) {
+ if (!getDisplayContent().mOpeningApps.contains(this) && canShowWindows()) {
showAllWindowsLocked();
}
}
@@ -1572,6 +1573,11 @@
return forAllWindowsUnchecked(callback, traverseTopToBottom);
}
+ @Override
+ void forAllAppWindows(Consumer<AppWindowToken> callback) {
+ callback.accept(this);
+ }
+
boolean forAllWindowsUnchecked(ToBooleanFunction<WindowState> callback,
boolean traverseTopToBottom) {
return super.forAllWindows(callback, traverseTopToBottom);
@@ -1629,7 +1635,8 @@
final boolean containsShowWhenLocked = containsShowWhenLockedWindow();
if (containsDismissKeyguard != mLastContainsDismissKeyguardWindow
|| containsShowWhenLocked != mLastContainsShowWhenLockedWindow) {
- mService.notifyKeyguardFlagsChanged(null /* callback */);
+ mService.notifyKeyguardFlagsChanged(null /* callback */,
+ getDisplayContent().getDisplayId());
}
mLastContainsDismissKeyguardWindow = containsDismissKeyguard;
mLastContainsShowWhenLockedWindow = containsShowWhenLocked;
@@ -1787,19 +1794,20 @@
getAnimationBounds(mTmpPoint, mTmpRect);
// Delaying animation start isn't compatible with remote animations at all.
- if (mService.mAppTransition.getRemoteAnimationController() != null
+ if (getDisplayContent().mAppTransition.getRemoteAnimationController() != null
&& !mSurfaceAnimator.isAnimationStartDelayed()) {
- adapter = mService.mAppTransition.getRemoteAnimationController()
+ adapter = getDisplayContent().mAppTransition.getRemoteAnimationController()
.createAnimationAdapter(this, mTmpPoint, mTmpRect);
} else {
- final int appStackClipMode = mService.mAppTransition.getAppStackClipMode();
+ final int appStackClipMode =
+ getDisplayContent().mAppTransition.getAppStackClipMode();
mNeedsAnimationBoundsLayer = (appStackClipMode == STACK_CLIP_AFTER_ANIM);
final Animation a = loadAnimation(lp, transit, enter, isVoiceInteraction);
if (a != null) {
adapter = new LocalAnimationAdapter(
new WindowAnimationSpec(a, mTmpPoint, mTmpRect,
- mService.mAppTransition.canSkipFirstFrame(),
+ getDisplayContent().mAppTransition.canSkipFirstFrame(),
appStackClipMode,
true /* isAppAnimation */),
mService.mSurfaceAnimationRunner);
@@ -1807,7 +1815,7 @@
mNeedsZBoost = true;
}
mTransit = transit;
- mTransitFlags = mService.mAppTransition.getTransitFlags();
+ mTransitFlags = getDisplayContent().mAppTransition.getTransitFlags();
} else {
adapter = null;
}
@@ -1877,7 +1885,7 @@
+ " transit=" + AppTransition.appTransitionToString(transit) + " enter=" + enter
+ " frame=" + frame + " insets=" + insets + " surfaceInsets=" + surfaceInsets);
final Configuration displayConfig = displayContent.getConfiguration();
- final Animation a = mService.mAppTransition.loadAnimation(lp, transit, enter,
+ 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) {
@@ -2017,7 +2025,7 @@
final ArrayList<WindowState> children = new ArrayList<>(mChildren);
children.forEach(WindowState::onExitAnimationDone);
- mService.mAppTransition.notifyAppTransitionFinishedLocked(token);
+ getDisplayContent().mAppTransition.notifyAppTransitionFinishedLocked(token);
scheduleAnimation();
}
@@ -2048,8 +2056,9 @@
}
boolean isWaitingForTransitionStart() {
- return mService.mAppTransition.isTransitionSet()
- && (mService.mOpeningApps.contains(this) || mService.mClosingApps.contains(this));
+ return getDisplayContent().mAppTransition.isTransitionSet()
+ && (getDisplayContent().mOpeningApps.contains(this)
+ || getDisplayContent().mClosingApps.contains(this));
}
public int getTransit() {
@@ -2066,7 +2075,7 @@
}
final int taskId = getTask().mTaskId;
final GraphicBuffer thumbnailHeader =
- mService.mAppTransition.getAppTransitionThumbnailHeader(taskId);
+ getDisplayContent().mAppTransition.getAppTransitionThumbnailHeader(taskId);
if (thumbnailHeader == null) {
if (DEBUG_APP_TRANSITIONS) Slog.d(TAG, "No thumbnail header bitmap for: " + taskId);
return;
@@ -2095,14 +2104,14 @@
? R.drawable.ic_account_circle
: R.drawable.ic_corp_badge;
final GraphicBuffer thumbnail =
- mService.mAppTransition
+ getDisplayContent().mAppTransition
.createCrossProfileAppsThumbnail(thumbnailDrawableRes, frame);
if (thumbnail == null) {
return;
}
mThumbnail = new AppWindowThumbnail(getPendingTransaction(), this, thumbnail);
final Animation animation =
- mService.mAppTransition.createCrossProfileAppsThumbnailAnimationLocked(
+ getDisplayContent().mAppTransition.createCrossProfileAppsThumbnailAnimationLocked(
win.getFrameLw());
mThumbnail.startAnimation(getPendingTransaction(), animation, new Point(frame.left,
frame.top));
@@ -2119,7 +2128,7 @@
new Rect(0, 0, displayInfo.appWidth, displayInfo.appHeight);
final Rect insets = win != null ? win.getContentInsets() : null;
final Configuration displayConfig = mDisplayContent.getConfiguration();
- return mService.mAppTransition.createThumbnailAspectScaleAnimationLocked(
+ return getDisplayContent().mAppTransition.createThumbnailAspectScaleAnimationLocked(
appRect, insets, thumbnailHeader, getTask().mTaskId, displayConfig.uiMode,
displayConfig.orientation);
}
@@ -2357,4 +2366,11 @@
return forAllWindows(ws -> ws.mAttrs.getColorMode() != COLOR_MODE_DEFAULT,
true /* topToBottom */);
}
+
+ void removeFromPendingTransition() {
+ if (isWaitingForTransitionStart() && mDisplayContent != null) {
+ mDisplayContent.mOpeningApps.remove(this);
+ mDisplayContent.mClosingApps.remove(this);
+ }
+ }
}
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index fa9ae52..ba03034 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -65,6 +65,7 @@
import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT;
import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
import static com.android.server.wm.DisplayContentProto.ABOVE_APP_WINDOWS;
+import static com.android.server.wm.DisplayContentProto.APP_TRANSITION;
import static com.android.server.wm.DisplayContentProto.BELOW_APP_WINDOWS;
import static com.android.server.wm.DisplayContentProto.DISPLAY_FRAMES;
import static com.android.server.wm.DisplayContentProto.DISPLAY_INFO;
@@ -80,6 +81,7 @@
import static com.android.server.wm.DisplayContentProto.SURFACE_SIZE;
import static com.android.server.wm.DisplayContentProto.WINDOW_CONTAINER;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ADD_REMOVE;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_APP_TRANSITIONS;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_BOOT;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_DISPLAY;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_FOCUS;
@@ -119,6 +121,7 @@
import static com.android.server.wm.WindowStateAnimator.DRAW_PENDING;
import static com.android.server.wm.WindowStateAnimator.READY_TO_SHOW;
+import android.animation.AnimationHandler;
import android.annotation.CallSuper;
import android.annotation.IntDef;
import android.annotation.NonNull;
@@ -155,6 +158,7 @@
import android.view.SurfaceControl.Transaction;
import android.view.SurfaceSession;
import android.view.WindowManagerPolicyConstants.PointerEventListener;
+import android.view.WindowManager;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.ToBooleanFunction;
@@ -228,6 +232,21 @@
private boolean mTmpInitial;
private int mMaxUiWidth;
+ final AppTransition mAppTransition;
+ final AppTransitionController mAppTransitionController;
+ boolean mSkipAppTransitionAnimation = false;
+
+ final ArraySet<AppWindowToken> mOpeningApps = new ArraySet<>();
+ final ArraySet<AppWindowToken> mClosingApps = new ArraySet<>();
+ final UnknownAppVisibilityController mUnknownAppVisibilityController;
+ BoundsAnimationController mBoundsAnimationController;
+
+ /**
+ * List of clients without a transtiton animation that we notify once we are done
+ * transitioning since they won't be notified through the app window animator.
+ */
+ final List<IBinder> mNoAnimationNotifyOnTransitionFinished = new ArrayList<>();
+
// Mapping from a token IBinder to a WindowToken object on this display.
private final HashMap<IBinder, WindowToken> mTokenMap = new HashMap();
@@ -821,6 +840,15 @@
mDividerControllerLocked = new DockedStackDividerController(service, this);
mPinnedStackControllerLocked = new PinnedStackController(service, this);
+ mAppTransition = new AppTransition(service.mContext, service, this);
+ mAppTransition.registerListenerLocked(service.mActivityManagerAppTransitionNotifier);
+ mAppTransitionController = new AppTransitionController(service, this);
+ mUnknownAppVisibilityController = new UnknownAppVisibilityController(service, this);
+
+ AnimationHandler animationHandler = new AnimationHandler();
+ mBoundsAnimationController = new BoundsAnimationController(service.mContext,
+ mAppTransition, SurfaceAnimationThread.getHandler(), animationHandler);
+
// We use this as our arbitrary surface size for buffer-less parents
// that don't impose cropping on their children. It may need to be larger
// than the display size because fullscreen windows can be shifted offscreen
@@ -2135,6 +2163,9 @@
+ " to its current displayId=" + mDisplayId);
}
+ // Clean up all pending transitions when stack reparent to another display.
+ stack.forAllAppWindows(AppWindowToken::removeFromPendingTransition);
+
prevDc.mTaskStackContainers.removeChild(stack);
mTaskStackContainers.addStackToDisplay(stack, onTop);
}
@@ -2294,6 +2325,13 @@
void removeImmediately() {
mRemovingDisplay = true;
try {
+ // Clear all transitions & screen frozen states when removing display.
+ mOpeningApps.clear();
+ mClosingApps.clear();
+ mUnknownAppVisibilityController.clear();
+ mAppTransition.removeAppTransitionTimeoutCallbacks();
+ handleAnimatingStoppedAndTransition();
+ mService.stopFreezingDisplayLocked();
super.removeImmediately();
if (DEBUG_DISPLAY) Slog.v(TAG_WM, "Removing display=" + this);
if (mPointerEventDispatcher != null && mTapDetector != null) {
@@ -2514,6 +2552,7 @@
screenRotationAnimation.writeToProto(proto, SCREEN_ROTATION_ANIMATION);
}
mDisplayFrames.writeToProto(proto, DISPLAY_FRAMES);
+ mAppTransition.writeToProto(proto, APP_TRANSITION);
proto.write(SURFACE_SIZE, mSurfaceSize);
if (mFocusedApp != null) {
mFocusedApp.writeNameToProto(proto, FOCUSED_APP);
@@ -2998,11 +3037,10 @@
}
if (highestTarget != null) {
- final AppTransition appTransition = mService.mAppTransition;
- if (DEBUG_INPUT_METHOD) Slog.v(TAG_WM, appTransition + " " + highestTarget
+ if (DEBUG_INPUT_METHOD) Slog.v(TAG_WM, mAppTransition + " " + highestTarget
+ " animating=" + highestTarget.isAnimating());
- if (appTransition.isTransitionSet()) {
+ if (mAppTransition.isTransitionSet()) {
// If we are currently setting up for an animation, hold everything until we
// can find out what will happen.
setInputMethodTarget(highestTarget, true);
@@ -3093,6 +3131,18 @@
pw.println();
}
}
+
+ if (!mOpeningApps.isEmpty() || !mClosingApps.isEmpty()) {
+ pw.println();
+ if (mOpeningApps.size() > 0) {
+ pw.print(" mOpeningApps="); pw.println(mOpeningApps);
+ }
+ if (mClosingApps.size() > 0) {
+ pw.print(" mClosingApps="); pw.println(mClosingApps);
+ }
+ }
+
+ mUnknownAppVisibilityController.dump(pw, " ");
}
void dumpWindowAnimators(PrintWriter pw, String subPrefix) {
@@ -3989,7 +4039,7 @@
final AppTokenList appTokens = mChildren.get(i).mExitingAppTokens;
for (int j = appTokens.size() - 1; j >= 0; --j) {
final AppWindowToken token = appTokens.get(j);
- if (!token.hasVisible && !mService.mClosingApps.contains(token)
+ if (!token.hasVisible && !mClosingApps.contains(token)
&& (!token.mIsExiting || token.isEmpty())) {
// Make sure there is no animation running on this token, so any windows
// associated with it will be removed as soon as their animations are
@@ -4287,8 +4337,8 @@
// Only allow force setting the orientation when all unknown visibilities have been
// resolved, as otherwise we just may be starting another occluding activity.
final boolean isUnoccluding =
- mService.mAppTransition.getAppTransition() == TRANSIT_KEYGUARD_UNOCCLUDE
- && mService.mUnknownAppVisibilityController.allResolved();
+ mAppTransition.getAppTransition() == TRANSIT_KEYGUARD_UNOCCLUDE
+ && mUnknownAppVisibilityController.allResolved();
if (policy.isKeyguardShowingAndNotOccluded() || isUnoccluding) {
return mLastKeyguardForcedOrientation;
}
@@ -4528,4 +4578,56 @@
mPointerEventDispatcher.unregisterInputEventListener(listener);
}
}
+
+ void prepareAppTransition(@WindowManager.TransitionType int transit,
+ boolean alwaysKeepCurrent, @WindowManager.TransitionFlags int flags,
+ boolean forceOverride) {
+ final boolean prepared = mAppTransition.prepareAppTransitionLocked(
+ transit, alwaysKeepCurrent, flags, forceOverride);
+ if (prepared && okToAnimate()) {
+ mSkipAppTransitionAnimation = false;
+ }
+ }
+
+ void executeAppTransition() {
+ if (mAppTransition.isTransitionSet()) {
+ if (DEBUG_APP_TRANSITIONS) {
+ Slog.w(TAG_WM, "Execute app transition: " + mAppTransition + ", displayId: "
+ + mDisplayId + " Callers=" + Debug.getCallers(5));
+ }
+ mAppTransition.setReady();
+ mService.mWindowPlacerLocked.requestTraversal();
+ }
+ }
+
+ /**
+ * Update pendingLayoutChanges after app transition has finished.
+ */
+ void handleAnimatingStoppedAndTransition() {
+ int changes = 0;
+
+ mAppTransition.setIdle();
+
+ for (int i = mNoAnimationNotifyOnTransitionFinished.size() - 1; i >= 0; i--) {
+ final IBinder token = mNoAnimationNotifyOnTransitionFinished.get(i);
+ mAppTransition.notifyAppTransitionFinishedLocked(token);
+ }
+ mNoAnimationNotifyOnTransitionFinished.clear();
+
+ mWallpaperController.hideDeferredWallpapersIfNeeded();
+
+ onAppTransitionDone();
+
+ changes |= FINISH_LAYOUT_REDO_LAYOUT;
+ if (DEBUG_WALLPAPER_LIGHT) {
+ Slog.v(TAG_WM, "Wallpaper layer changed: assigning layers + relayout");
+ }
+ computeImeTarget(true /* updateImeTarget */);
+ mService.mRoot.mWallpaperMayChange = true;
+ // Since the window list has been rebuilt, focus might have to be recomputed since the
+ // actual order of windows might have changed again.
+ mService.mFocusMayChange = true;
+
+ pendingLayoutChanges |= changes;
+ }
}
diff --git a/services/core/java/com/android/server/wm/DisplayWindowController.java b/services/core/java/com/android/server/wm/DisplayWindowController.java
index 3282b1c..01d556a 100644
--- a/services/core/java/com/android/server/wm/DisplayWindowController.java
+++ b/services/core/java/com/android/server/wm/DisplayWindowController.java
@@ -16,6 +16,10 @@
package com.android.server.wm;
+import static android.view.WindowManager.TRANSIT_ACTIVITY_OPEN;
+import static android.view.WindowManager.TRANSIT_TASK_OPEN;
+import static android.view.WindowManager.TRANSIT_TASK_TO_FRONT;
+
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_DISPLAY;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_FOCUS_LIGHT;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STACK;
@@ -23,10 +27,17 @@
import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_NORMAL;
import android.content.res.Configuration;
+import android.graphics.GraphicBuffer;
import android.os.Binder;
import android.os.IBinder;
+import android.os.IRemoteCallback;
import android.util.Slog;
+import android.view.AppTransitionAnimationSpec;
import android.view.Display;
+import android.view.WindowManager;
+import android.view.WindowManager.TransitionType;
+
+import com.android.internal.annotations.VisibleForTesting;
/**
* Controller for the display container. This is created by activity manager to link activity
@@ -56,6 +67,12 @@
}
}
+ @VisibleForTesting
+ public DisplayWindowController(Display display, WindowManagerService service) {
+ super(null, service);
+ mDisplayId = display.getDisplayId();
+ }
+
@Override
public void removeContainer() {
synchronized (mWindowMap) {
@@ -179,6 +196,124 @@
}
}
+ public void prepareAppTransition(@WindowManager.TransitionType int transit,
+ boolean alwaysKeepCurrent) {
+ prepareAppTransition(transit, alwaysKeepCurrent, 0 /* flags */, false /* forceOverride */);
+ }
+
+ /**
+ * @param transit What kind of transition is happening. Use one of the constants
+ * AppTransition.TRANSIT_*.
+ * @param alwaysKeepCurrent If true and a transition is already set, new transition will NOT
+ * be set.
+ * @param flags Additional flags for the app transition, Use a combination of the constants
+ * AppTransition.TRANSIT_FLAG_*.
+ * @param forceOverride Always override the transit, not matter what was set previously.
+ */
+ public void prepareAppTransition(@WindowManager.TransitionType int transit,
+ boolean alwaysKeepCurrent, @WindowManager.TransitionFlags int flags,
+ boolean forceOverride) {
+ synchronized (mWindowMap) {
+ mRoot.getDisplayContent(mDisplayId).prepareAppTransition(transit, alwaysKeepCurrent,
+ flags, forceOverride);
+ }
+ }
+
+ public void executeAppTransition() {
+ synchronized (mWindowMap) {
+ mRoot.getDisplayContent(mDisplayId).executeAppTransition();
+ }
+ }
+
+ public void overridePendingAppTransition(String packageName,
+ int enterAnim, int exitAnim, IRemoteCallback startedCallback) {
+ synchronized (mWindowMap) {
+ mRoot.getDisplayContent(mDisplayId).mAppTransition.overridePendingAppTransition(
+ packageName, enterAnim, exitAnim, startedCallback);
+ }
+ }
+
+ public void overridePendingAppTransitionScaleUp(int startX, int startY, int startWidth,
+ int startHeight) {
+ synchronized (mWindowMap) {
+ mRoot.getDisplayContent(mDisplayId).mAppTransition.overridePendingAppTransitionScaleUp(
+ startX, startY, startWidth, startHeight);
+ }
+ }
+
+ public void overridePendingAppTransitionClipReveal(int startX, int startY,
+ int startWidth, int startHeight) {
+ synchronized (mWindowMap) {
+ mRoot.getDisplayContent(mDisplayId)
+ .mAppTransition.overridePendingAppTransitionClipReveal(startX, startY,
+ startWidth, startHeight);
+ }
+ }
+
+ public void overridePendingAppTransitionThumb(GraphicBuffer srcThumb, int startX,
+ int startY, IRemoteCallback startedCallback, boolean scaleUp) {
+ synchronized (mWindowMap) {
+ mRoot.getDisplayContent(mDisplayId)
+ .mAppTransition.overridePendingAppTransitionThumb(srcThumb, startX, startY,
+ startedCallback, scaleUp);
+ }
+ }
+
+ public void overridePendingAppTransitionAspectScaledThumb(GraphicBuffer srcThumb, int startX,
+ int startY, int targetWidth, int targetHeight, IRemoteCallback startedCallback,
+ boolean scaleUp) {
+ synchronized (mWindowMap) {
+ mRoot.getDisplayContent(mDisplayId)
+ .mAppTransition.overridePendingAppTransitionAspectScaledThumb(srcThumb, startX,
+ startY, targetWidth, targetHeight, startedCallback, scaleUp);
+ }
+ }
+
+ public void overridePendingAppTransitionMultiThumb(AppTransitionAnimationSpec[] specs,
+ IRemoteCallback onAnimationStartedCallback, IRemoteCallback onAnimationFinishedCallback,
+ boolean scaleUp) {
+ synchronized (mWindowMap) {
+ mRoot.getDisplayContent(mDisplayId)
+ .mAppTransition.overridePendingAppTransitionMultiThumb(specs,
+ onAnimationStartedCallback, onAnimationFinishedCallback, scaleUp);
+ }
+ }
+
+ public void overridePendingAppTransitionStartCrossProfileApps() {
+ synchronized (mWindowMap) {
+ mRoot.getDisplayContent(mDisplayId)
+ .mAppTransition.overridePendingAppTransitionStartCrossProfileApps();
+ }
+ }
+
+ public void overridePendingAppTransitionInPlace(String packageName, int anim) {
+ synchronized (mWindowMap) {
+ mRoot.getDisplayContent(mDisplayId)
+ .mAppTransition.overrideInPlaceAppTransition(packageName, anim);
+ }
+ }
+
+ /**
+ * Get Pending App transition of display.
+ *
+ * @return The pending app transition of the display.
+ */
+ public @TransitionType int getPendingAppTransition() {
+ synchronized (mWindowMap) {
+ return mRoot.getDisplayContent(mDisplayId).mAppTransition.getAppTransition();
+ }
+ }
+
+ /**
+ * Check if pending app transition is for activity / task launch.
+ */
+ public boolean isNextTransitionForward() {
+ final int transit = getPendingAppTransition();
+ return transit == TRANSIT_ACTIVITY_OPEN
+ || transit == TRANSIT_TASK_OPEN
+ || transit == TRANSIT_TASK_TO_FRONT;
+ }
+
@Override
public String toString() {
return "{DisplayWindowController displayId=" + mDisplayId + "}";
diff --git a/services/core/java/com/android/server/wm/DockedStackDividerController.java b/services/core/java/com/android/server/wm/DockedStackDividerController.java
index ac93848..8ed29a9 100644
--- a/services/core/java/com/android/server/wm/DockedStackDividerController.java
+++ b/services/core/java/com/android/server/wm/DockedStackDividerController.java
@@ -531,7 +531,7 @@
final TaskStack stack =
mDisplayContent.getSplitScreenPrimaryStackIgnoringVisibility();
final long transitionDuration = isAnimationMaximizing()
- ? mService.mAppTransition.getLastClipRevealTransitionDuration()
+ ? mDisplayContent.mAppTransition.getLastClipRevealTransitionDuration()
: DEFAULT_APP_TRANSITION_DURATION;
mAnimationDuration = (long)
(transitionDuration * mService.getTransitionAnimationScaleLocked());
@@ -950,7 +950,7 @@
return naturalAmount;
}
final int minimizeDistance = stack.getMinimizeDistance();
- float startPrime = mService.mAppTransition.getLastClipRevealMaxTranslation()
+ final float startPrime = mDisplayContent.mAppTransition.getLastClipRevealMaxTranslation()
/ (float) minimizeDistance;
final float amountPrime = t * mAnimationTarget + (1 - t) * startPrime;
final float t2 = Math.min(t / mMaximizeMeetFraction, 1);
@@ -963,12 +963,12 @@
*/
private float getClipRevealMeetFraction(TaskStack stack) {
if (!isAnimationMaximizing() || stack == null ||
- !mService.mAppTransition.hadClipRevealAnimation()) {
+ !mDisplayContent.mAppTransition.hadClipRevealAnimation()) {
return 1f;
}
final int minimizeDistance = stack.getMinimizeDistance();
- final float fraction = Math.abs(mService.mAppTransition.getLastClipRevealMaxTranslation())
- / (float) minimizeDistance;
+ final float fraction = Math.abs(mDisplayContent.mAppTransition
+ .getLastClipRevealMaxTranslation()) / (float) minimizeDistance;
final float t = Math.max(0, Math.min(1, (fraction - CLIP_REVEAL_MEET_FRACTION_MIN)
/ (CLIP_REVEAL_MEET_FRACTION_MAX - CLIP_REVEAL_MEET_FRACTION_MIN)));
return CLIP_REVEAL_MEET_EARLIEST
diff --git a/services/core/java/com/android/server/wm/PinnedStackWindowController.java b/services/core/java/com/android/server/wm/PinnedStackWindowController.java
index 02fbfba..1807eeb 100644
--- a/services/core/java/com/android/server/wm/PinnedStackWindowController.java
+++ b/services/core/java/com/android/server/wm/PinnedStackWindowController.java
@@ -117,11 +117,12 @@
final Rect finalToBounds = toBounds;
final @SchedulePipModeChangedState int finalSchedulePipModeChangedState =
schedulePipModeChangedState;
- mService.mBoundsAnimationController.getHandler().post(() -> {
+ final DisplayContent displayContent = mContainer.getDisplayContent();
+ displayContent.mBoundsAnimationController.getHandler().post(() -> {
if (mContainer == null) {
return;
}
- mService.mBoundsAnimationController.animateBounds(mContainer, fromBounds,
+ displayContent.mBoundsAnimationController.animateBounds(mContainer, fromBounds,
finalToBounds, animationDuration, finalSchedulePipModeChangedState,
fromFullscreen, toFullscreen);
});
diff --git a/services/core/java/com/android/server/wm/RecentsAnimationController.java b/services/core/java/com/android/server/wm/RecentsAnimationController.java
index 5c80759..c4fbee9 100644
--- a/services/core/java/com/android/server/wm/RecentsAnimationController.java
+++ b/services/core/java/com/android/server/wm/RecentsAnimationController.java
@@ -467,7 +467,8 @@
// so if we are actually transitioning there, notify again here
if (mTargetAppToken != null) {
if (reorderMode == REORDER_MOVE_TO_TOP || reorderMode == REORDER_KEEP_IN_PLACE) {
- mService.mAppTransition.notifyAppTransitionFinishedLocked(mTargetAppToken.token);
+ mService.mRoot.getDisplayContent(mDisplayId)
+ .mAppTransition.notifyAppTransitionFinishedLocked(mTargetAppToken.token);
}
}
}
diff --git a/services/core/java/com/android/server/wm/RemoteAnimationController.java b/services/core/java/com/android/server/wm/RemoteAnimationController.java
index 8ec0a01..0ec4baf 100644
--- a/services/core/java/com/android/server/wm/RemoteAnimationController.java
+++ b/services/core/java/com/android/server/wm/RemoteAnimationController.java
@@ -317,7 +317,7 @@
}
private int getMode() {
- if (mService.mOpeningApps.contains(mAppWindowToken)) {
+ if (mAppWindowToken.getDisplayContent().mOpeningApps.contains(mAppWindowToken)) {
return RemoteAnimationTarget.MODE_OPENING;
} else {
return RemoteAnimationTarget.MODE_CLOSING;
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index c8977be..62078f7 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -576,17 +576,15 @@
mSustainedPerformanceModeCurrent = false;
mService.mTransactionSequence++;
- // TODO(multi-display):
+ // TODO(multi-display): recents animation & wallpaper need support multi-display.
final DisplayContent defaultDisplay = mService.getDefaultDisplayContentLocked();
- final DisplayInfo defaultInfo = defaultDisplay.getDisplayInfo();
- final int defaultDw = defaultInfo.logicalWidth;
- final int defaultDh = defaultInfo.logicalHeight;
+ final WindowSurfacePlacer surfacePlacer = mService.mWindowPlacerLocked;
if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG,
">>> OPEN TRANSACTION performLayoutAndPlaceSurfaces");
mService.openSurfaceTransaction();
try {
- applySurfaceChangesTransaction(recoveringMemory, defaultDw, defaultDh);
+ applySurfaceChangesTransaction(recoveringMemory);
} catch (RuntimeException e) {
Slog.wtf(TAG, "Unhandled exception in Window Manager", e);
} finally {
@@ -594,39 +592,13 @@
if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG,
"<<< CLOSE TRANSACTION performLayoutAndPlaceSurfaces");
}
-
mService.mAnimator.executeAfterPrepareSurfacesRunnables();
- final WindowSurfacePlacer surfacePlacer = mService.mWindowPlacerLocked;
-
- // If we are ready to perform an app transition, check through all of the app tokens to be
- // shown and see if they are ready to go.
- if (mService.mAppTransition.isReady()) {
- // This needs to be split into two expressions, as handleAppTransitionReadyLocked may
- // modify dc.pendingLayoutChanges, which would get lost when writing
- // defaultDisplay.pendingLayoutChanges |= handleAppTransitionReadyLocked()
- final int layoutChanges = surfacePlacer.handleAppTransitionReadyLocked();
- defaultDisplay.pendingLayoutChanges |= layoutChanges;
- if (DEBUG_LAYOUT_REPEATS)
- surfacePlacer.debugLayoutRepeats("after handleAppTransitionReadyLocked",
- defaultDisplay.pendingLayoutChanges);
- }
-
- if (!isAppAnimating() && mService.mAppTransition.isRunning()) {
- // We have finished the animation of an app transition. To do this, we have delayed a
- // lot of operations like showing and hiding apps, moving apps in Z-order, etc. The app
- // token list reflects the correct Z-order, but the window list may now be out of sync
- // with it. So here we will just rebuild the entire app window list. Fun!
- defaultDisplay.pendingLayoutChanges |=
- mService.handleAnimatingStoppedAndTransitionLocked();
- if (DEBUG_LAYOUT_REPEATS)
- surfacePlacer.debugLayoutRepeats("after handleAnimStopAndXitionLock",
- defaultDisplay.pendingLayoutChanges);
- }
+ checkAppTransitionReady(surfacePlacer);
// Defer starting the recents animation until the wallpaper has drawn
final RecentsAnimationController recentsAnimationController =
- mService.getRecentsAnimationController();
+ mService.getRecentsAnimationController();
if (recentsAnimationController != null) {
recentsAnimationController.checkAnimationReady(mWallpaperController);
}
@@ -732,8 +704,8 @@
mUpdateRotation = updateRotationUnchecked();
}
- if (mService.mWaitingForDrawnCallback != null ||
- (mOrientationChangeComplete && !defaultDisplay.isLayoutNeeded()
+ if (mService.mWaitingForDrawnCallback != null
+ || (mOrientationChangeComplete && !isLayoutNeeded()
&& !mUpdateRotation)) {
mService.checkDrawnWindowsLocked();
}
@@ -741,7 +713,7 @@
final int N = mService.mPendingRemove.size();
if (N > 0) {
if (mService.mPendingRemoveTmp.length < N) {
- mService.mPendingRemoveTmp = new WindowState[N+10];
+ mService.mPendingRemoveTmp = new WindowState[N + 10];
}
mService.mPendingRemove.toArray(mService.mPendingRemoveTmp);
mService.mPendingRemove.clear();
@@ -783,12 +755,47 @@
"performSurfacePlacementInner exit: animating=" + mService.mAnimator.isAnimating());
}
- private void applySurfaceChangesTransaction(boolean recoveringMemory, int defaultDw,
- int defaultDh) {
+ private void checkAppTransitionReady(WindowSurfacePlacer surfacePlacer) {
+ // Trace all displays app transition by Z-order for pending layout change.
+ for (int i = mChildren.size() - 1; i >= 0; --i) {
+ final DisplayContent curDisplay = mChildren.get(i);
+
+ // If we are ready to perform an app transition, check through all of the app tokens
+ // to be shown and see if they are ready to go.
+ if (curDisplay.mAppTransition.isReady()) {
+ // handleAppTransitionReady may modify curDisplay.pendingLayoutChanges.
+ curDisplay.mAppTransitionController.handleAppTransitionReady();
+ if (DEBUG_LAYOUT_REPEATS) {
+ surfacePlacer.debugLayoutRepeats("after handleAppTransitionReady",
+ curDisplay.pendingLayoutChanges);
+ }
+ }
+
+ if (!curDisplay.isAppAnimating() && curDisplay.mAppTransition.isRunning()) {
+ // We have finished the animation of an app transition. To do this, we have
+ // delayed a lot of operations like showing and hiding apps, moving apps in
+ // Z-order, etc.
+ // The app token list reflects the correct Z-order, but the window list may now
+ // be out of sync with it. So here we will just rebuild the entire app window
+ // list. Fun!
+ curDisplay.handleAnimatingStoppedAndTransition();
+ if (DEBUG_LAYOUT_REPEATS) {
+ surfacePlacer.debugLayoutRepeats("after handleAnimStopAndXitionLock",
+ curDisplay.pendingLayoutChanges);
+ }
+ }
+ }
+ }
+
+ private void applySurfaceChangesTransaction(boolean recoveringMemory) {
mHoldScreenWindow = null;
mObscuringWindow = null;
// TODO(multi-display): Support these features on secondary screens.
+ final DisplayContent defaultDc = mService.getDefaultDisplayContentLocked();
+ final DisplayInfo defaultInfo = defaultDc.getDisplayInfo();
+ final int defaultDw = defaultInfo.logicalWidth;
+ final int defaultDh = defaultInfo.logicalHeight;
if (mService.mWatermark != null) {
mService.mWatermark.positionSurface(defaultDw, defaultDh);
}
diff --git a/services/core/java/com/android/server/wm/StackWindowController.java b/services/core/java/com/android/server/wm/StackWindowController.java
index 1fd2c0f..6ac63a1 100644
--- a/services/core/java/com/android/server/wm/StackWindowController.java
+++ b/services/core/java/com/android/server/wm/StackWindowController.java
@@ -140,10 +140,11 @@
}
mContainer.positionChildAt(POSITION_TOP, childTask, includingParents);
- if (mService.mAppTransition.isTransitionSet()) {
+ final DisplayContent displayContent = mContainer.getDisplayContent();
+ if (displayContent.mAppTransition.isTransitionSet()) {
childTask.setSendingToBottom(false);
}
- mContainer.getDisplayContent().layoutAndAssignWindowLayersIfNeeded();
+ displayContent.layoutAndAssignWindowLayersIfNeeded();
}
}
@@ -162,7 +163,7 @@
}
mContainer.positionChildAt(POSITION_BOTTOM, childTask, includingParents);
- if (mService.mAppTransition.isTransitionSet()) {
+ if (mContainer.getDisplayContent().mAppTransition.isTransitionSet()) {
childTask.setSendingToBottom(true);
}
mContainer.getDisplayContent().layoutAndAssignWindowLayersIfNeeded();
diff --git a/services/core/java/com/android/server/wm/TaskSnapshotController.java b/services/core/java/com/android/server/wm/TaskSnapshotController.java
index ef63b9b..0d5469b 100644
--- a/services/core/java/com/android/server/wm/TaskSnapshotController.java
+++ b/services/core/java/com/android/server/wm/TaskSnapshotController.java
@@ -129,8 +129,8 @@
mPersister.start();
}
- void onTransitionStarting() {
- handleClosingApps(mService.mClosingApps);
+ void onTransitionStarting(DisplayContent displayContent) {
+ handleClosingApps(displayContent.mClosingApps);
}
/**
diff --git a/services/core/java/com/android/server/wm/TaskStack.java b/services/core/java/com/android/server/wm/TaskStack.java
index 00caceb..81507fa 100644
--- a/services/core/java/com/android/server/wm/TaskStack.java
+++ b/services/core/java/com/android/server/wm/TaskStack.java
@@ -1638,7 +1638,7 @@
return;
}
- mService.mBoundsAnimationController.onAllWindowsDrawn();
+ getDisplayContent().mBoundsAnimationController.onAllWindowsDrawn();
}
@Override // AnimatesBounds
diff --git a/services/core/java/com/android/server/wm/UnknownAppVisibilityController.java b/services/core/java/com/android/server/wm/UnknownAppVisibilityController.java
index eb751fa..01abcab 100644
--- a/services/core/java/com/android/server/wm/UnknownAppVisibilityController.java
+++ b/services/core/java/com/android/server/wm/UnknownAppVisibilityController.java
@@ -60,8 +60,11 @@
private final WindowManagerService mService;
- UnknownAppVisibilityController(WindowManagerService service) {
+ private final DisplayContent mDisplayContent;
+
+ UnknownAppVisibilityController(WindowManagerService service, DisplayContent displayContent) {
mService = service;
+ mDisplayContent = displayContent;
}
boolean allResolved() {
@@ -128,7 +131,8 @@
int state = mUnknownApps.get(appWindow);
if (state == UNKNOWN_STATE_WAITING_RELAYOUT) {
mUnknownApps.put(appWindow, UNKNOWN_STATE_WAITING_VISIBILITY_UPDATE);
- mService.notifyKeyguardFlagsChanged(this::notifyVisibilitiesUpdated);
+ mService.notifyKeyguardFlagsChanged(this::notifyVisibilitiesUpdated,
+ appWindow.getDisplayContent().getDisplayId());
}
}
diff --git a/services/core/java/com/android/server/wm/WallpaperController.java b/services/core/java/com/android/server/wm/WallpaperController.java
index a448f97..942cdb9 100644
--- a/services/core/java/com/android/server/wm/WallpaperController.java
+++ b/services/core/java/com/android/server/wm/WallpaperController.java
@@ -16,16 +16,14 @@
package com.android.server.wm;
-import com.android.internal.util.ToBooleanFunction;
-
import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED;
import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
+import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_WITH_WALLPAPER;
import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
-import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_WITH_WALLPAPER;
import static com.android.server.wm.RecentsAnimationController.REORDER_MOVE_TO_ORIGINAL_POSITION;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_APP_TRANSITIONS;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_SCREENSHOT;
@@ -50,6 +48,8 @@
import android.view.WindowManager;
import android.view.animation.Animation;
+import com.android.internal.util.ToBooleanFunction;
+
import java.io.PrintWriter;
import java.util.ArrayList;
@@ -263,7 +263,8 @@
&& (mWallpaperTarget != winGoingAway || mPrevWallpaperTarget != null)) {
return;
}
- if (mService.mAppTransition.isRunning()) {
+ if (mWallpaperTarget != null
+ && mWallpaperTarget.getDisplayContent().mAppTransition.isRunning()) {
// Defer hiding the wallpaper when app transition is running until the animations
// are done.
mDeferredHideWallpaper = winGoingAway;
@@ -549,9 +550,9 @@
// is not. If they're both hidden, still use the new target.
mWallpaperTarget = prevWallpaperTarget;
} else if (newTargetHidden == oldTargetHidden
- && !mService.mOpeningApps.contains(wallpaperTarget.mAppToken)
- && (mService.mOpeningApps.contains(prevWallpaperTarget.mAppToken)
- || mService.mClosingApps.contains(prevWallpaperTarget.mAppToken))) {
+ && !dc.mOpeningApps.contains(wallpaperTarget.mAppToken)
+ && (dc.mOpeningApps.contains(prevWallpaperTarget.mAppToken)
+ || dc.mClosingApps.contains(prevWallpaperTarget.mAppToken))) {
// If they're both hidden (or both not hidden), prefer the one that's currently in
// opening or closing app list, this allows transition selection logic to better
// determine the wallpaper status of opening/closing apps.
diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java
index 46999a2..abc3826 100644
--- a/services/core/java/com/android/server/wm/WindowContainer.java
+++ b/services/core/java/com/android/server/wm/WindowContainer.java
@@ -826,6 +826,12 @@
wrapper.release();
}
+ void forAllAppWindows(Consumer<AppWindowToken> callback) {
+ for (int i = mChildren.size() - 1; i >= 0; --i) {
+ mChildren.get(i).forAllAppWindows(callback);
+ }
+ }
+
/**
* For all tasks at or below this container call the callback.
*
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 3aad73c..96fc2e2 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -67,12 +67,10 @@
import static com.android.internal.util.LatencyTracker.ACTION_ROTATE_SCREEN;
import static com.android.server.LockGuard.INDEX_WINDOW;
import static com.android.server.LockGuard.installLock;
-import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT;
import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
import static com.android.server.wm.KeyguardDisableHandler.KEYGUARD_POLICY_CHANGED;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ADD_REMOVE;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_APP_TRANSITIONS;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_BOOT;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_CONFIGURATION;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_DISPLAY;
@@ -86,7 +84,6 @@
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_SCREEN_ON;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STARTING_WINDOW;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_VISIBILITY;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WALLPAPER_LIGHT;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WINDOW_MOVEMENT;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WINDOW_TRACE;
import static com.android.server.wm.WindowManagerDebugConfig.SHOW_LIGHT_TRANSACTIONS;
@@ -96,7 +93,6 @@
import static com.android.server.wm.WindowManagerDebugConfig.TAG_KEEP_SCREEN_ON;
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.WindowManagerServiceDumpProto.APP_TRANSITION;
import static com.android.server.wm.WindowManagerServiceDumpProto.DISPLAY_FROZEN;
import static com.android.server.wm.WindowManagerServiceDumpProto.FOCUSED_APP;
import static com.android.server.wm.WindowManagerServiceDumpProto.FOCUSED_WINDOW;
@@ -108,7 +104,6 @@
import android.Manifest;
import android.Manifest.permission;
-import android.animation.AnimationHandler;
import android.animation.ValueAnimator;
import android.annotation.IntDef;
import android.annotation.NonNull;
@@ -134,7 +129,6 @@
import android.content.res.Configuration;
import android.database.ContentObserver;
import android.graphics.Bitmap;
-import android.graphics.GraphicBuffer;
import android.graphics.Matrix;
import android.graphics.Point;
import android.graphics.Rect;
@@ -188,7 +182,6 @@
import android.util.TimeUtils;
import android.util.TypedValue;
import android.util.proto.ProtoOutputStream;
-import android.view.AppTransitionAnimationSpec;
import android.view.Display;
import android.view.DisplayCutout;
import android.view.DisplayInfo;
@@ -221,7 +214,6 @@
import android.view.WindowContentFrameStats;
import android.view.WindowManager;
import android.view.WindowManager.LayoutParams;
-import android.view.WindowManager.TransitionFlags;
import android.view.WindowManager.TransitionType;
import android.view.WindowManagerGlobal;
import android.view.WindowManagerPolicyConstants.PointerEventListener;
@@ -266,7 +258,6 @@
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
-import java.util.List;
/** {@hide} */
public class WindowManagerService extends IWindowManager.Stub
@@ -612,14 +603,6 @@
// changes the orientation.
private final PowerManager.WakeLock mScreenFrozenLock;
- final AppTransition mAppTransition;
- boolean mSkipAppTransitionAnimation = false;
-
- final ArraySet<AppWindowToken> mOpeningApps = new ArraySet<>();
- final ArraySet<AppWindowToken> mClosingApps = new ArraySet<>();
-
- final UnknownAppVisibilityController mUnknownAppVisibilityController =
- new UnknownAppVisibilityController(this);
final TaskSnapshotController mTaskSnapshotController;
boolean mIsTouchDevice;
@@ -751,7 +734,6 @@
* up when the animation finishes.
*/
final ArrayMap<AnimationAdapter, SurfaceAnimator> mAnimationTransferMap = new ArrayMap<>();
- final BoundsAnimationController mBoundsAnimationController;
private WindowContentFrameStats mTempWindowRenderStats;
@@ -779,10 +761,6 @@
// For example, when this flag is true, there will be no wallpaper service.
final boolean mOnlyCore;
- // List of clients without a transtiton animation that we notify once we are done transitioning
- // since they won't be notified through the app window animator.
- final List<IBinder> mNoAnimationNotifyOnTransitionFinished = new ArrayList<>();
-
static WindowManagerThreadPriorityBooster sThreadPriorityBooster =
new WindowManagerThreadPriorityBooster();
@@ -975,13 +953,6 @@
PowerManager.PARTIAL_WAKE_LOCK, "SCREEN_FROZEN");
mScreenFrozenLock.setReferenceCounted(false);
- mAppTransition = new AppTransition(context, this);
- mAppTransition.registerListenerLocked(mActivityManagerAppTransitionNotifier);
-
- final AnimationHandler animationHandler = new AnimationHandler();
- mBoundsAnimationController = new BoundsAnimationController(context, mAppTransition,
- AnimationThread.getHandler(), animationHandler);
-
mActivityManager = ActivityManager.getService();
mActivityTaskManager = ActivityTaskManager.getService();
mAmInternal = LocalServices.getService(ActivityManagerInternal.class);
@@ -1577,11 +1548,13 @@
Rect frame = replacedWindow.getVisibleFrameLw();
// We treat this as if this activity was opening, so we can trigger the app transition
// animation and piggy-back on existing transition animation infrastructure.
- mOpeningApps.add(atoken);
- prepareAppTransition(WindowManager.TRANSIT_ACTIVITY_RELAUNCH, ALWAYS_KEEP_CURRENT);
- mAppTransition.overridePendingAppTransitionClipReveal(frame.left, frame.top,
+ final DisplayContent dc = atoken.getDisplayContent();
+ dc.mOpeningApps.add(atoken);
+ dc.prepareAppTransition(WindowManager.TRANSIT_ACTIVITY_RELAUNCH, ALWAYS_KEEP_CURRENT,
+ 0 /* flags */, false /* forceOverride */);
+ dc.mAppTransition.overridePendingAppTransitionClipReveal(frame.left, frame.top,
frame.width(), frame.height());
- executeAppTransition();
+ dc.executeAppTransition();
return true;
}
@@ -1590,10 +1563,12 @@
// unfreeze wait for the apps to be drawn.
// Note that if the display unfroze already because app unfreeze timed out,
// we don't set up the transition anymore and just let it go.
- if (mDisplayFrozen && !mOpeningApps.contains(atoken) && atoken.isRelaunching()) {
- mOpeningApps.add(atoken);
- prepareAppTransition(WindowManager.TRANSIT_NONE, !ALWAYS_KEEP_CURRENT);
- executeAppTransition();
+ final DisplayContent dc = atoken.getDisplayContent();
+ if (mDisplayFrozen && !dc.mOpeningApps.contains(atoken) && atoken.isRelaunching()) {
+ dc.mOpeningApps.add(atoken);
+ dc.prepareAppTransition(WindowManager.TRANSIT_NONE, !ALWAYS_KEEP_CURRENT, 0 /* flags */,
+ false /* forceOverride */);
+ dc.executeAppTransition();
}
}
@@ -2087,7 +2062,7 @@
}
if (win.mAppToken != null) {
- mUnknownAppVisibilityController.notifyRelayouted(win.mAppToken);
+ dc.mUnknownAppVisibilityController.notifyRelayouted(win.mAppToken);
}
Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER,
@@ -2445,6 +2420,9 @@
long ident = Binder.clearCallingIdentity();
try {
final DisplayContent dc = mRoot.getDisplayContent(displayId);
+ if (dc == null) {
+ return false;
+ }
final int req = dc.getOrientation();
if (req != dc.getLastOrientation() || forceUpdate) {
dc.setLastOrientation(req);
@@ -2475,109 +2453,15 @@
}
}
+ // TODO(multi-display): remove when no default display use case.
+ // (i.e. KeyguardController / RecentsAnimation)
@Override
public void prepareAppTransition(@TransitionType int transit, boolean alwaysKeepCurrent) {
- prepareAppTransition(transit, alwaysKeepCurrent, 0 /* flags */, false /* forceOverride */);
- }
-
- /**
- * @param transit What kind of transition is happening. Use one of the constants
- * AppTransition.TRANSIT_*.
- * @param alwaysKeepCurrent If true and a transition is already set, new transition will NOT
- * be set.
- * @param flags Additional flags for the app transition, Use a combination of the constants
- * AppTransition.TRANSIT_FLAG_*.
- * @param forceOverride Always override the transit, not matter what was set previously.
- */
- public void prepareAppTransition(@TransitionType int transit, boolean alwaysKeepCurrent,
- @TransitionFlags int flags, boolean forceOverride) {
if (!checkCallingPermission(MANAGE_APP_TOKENS, "prepareAppTransition()")) {
throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
}
- synchronized(mWindowMap) {
- boolean prepared = mAppTransition.prepareAppTransitionLocked(transit, alwaysKeepCurrent,
- flags, forceOverride);
- // TODO (multidisplay): associate app transitions with displays
- final DisplayContent dc = mRoot.getDisplayContent(DEFAULT_DISPLAY);
- if (prepared && dc != null && dc.okToAnimate()) {
- mSkipAppTransitionAnimation = false;
- }
- }
- }
-
- @Override
- public @TransitionType int getPendingAppTransition() {
- return mAppTransition.getAppTransition();
- }
-
- @Override
- public void overridePendingAppTransition(String packageName,
- int enterAnim, int exitAnim, IRemoteCallback startedCallback) {
- synchronized(mWindowMap) {
- mAppTransition.overridePendingAppTransition(packageName, enterAnim, exitAnim,
- startedCallback);
- }
- }
-
- @Override
- public void overridePendingAppTransitionScaleUp(int startX, int startY, int startWidth,
- int startHeight) {
- synchronized(mWindowMap) {
- mAppTransition.overridePendingAppTransitionScaleUp(startX, startY, startWidth,
- startHeight);
- }
- }
-
- @Override
- public void overridePendingAppTransitionClipReveal(int startX, int startY,
- int startWidth, int startHeight) {
- synchronized(mWindowMap) {
- mAppTransition.overridePendingAppTransitionClipReveal(startX, startY, startWidth,
- startHeight);
- }
- }
-
- @Override
- public void overridePendingAppTransitionThumb(GraphicBuffer srcThumb, int startX,
- int startY, IRemoteCallback startedCallback, boolean scaleUp) {
- synchronized(mWindowMap) {
- mAppTransition.overridePendingAppTransitionThumb(srcThumb, startX, startY,
- startedCallback, scaleUp);
- }
- }
-
- @Override
- public void overridePendingAppTransitionAspectScaledThumb(GraphicBuffer srcThumb, int startX,
- int startY, int targetWidth, int targetHeight, IRemoteCallback startedCallback,
- boolean scaleUp) {
- synchronized(mWindowMap) {
- mAppTransition.overridePendingAppTransitionAspectScaledThumb(srcThumb, startX, startY,
- targetWidth, targetHeight, startedCallback, scaleUp);
- }
- }
-
- @Override
- public void overridePendingAppTransitionMultiThumb(AppTransitionAnimationSpec[] specs,
- IRemoteCallback onAnimationStartedCallback, IRemoteCallback onAnimationFinishedCallback,
- boolean scaleUp) {
- synchronized (mWindowMap) {
- mAppTransition.overridePendingAppTransitionMultiThumb(specs, onAnimationStartedCallback,
- onAnimationFinishedCallback, scaleUp);
-
- }
- }
-
- public void overridePendingAppTransitionStartCrossProfileApps() {
- synchronized (mWindowMap) {
- mAppTransition.overridePendingAppTransitionStartCrossProfileApps();
- }
- }
-
- @Override
- public void overridePendingAppTransitionInPlace(String packageName, int anim) {
- synchronized(mWindowMap) {
- mAppTransition.overrideInPlaceAppTransition(packageName, anim);
- }
+ getDefaultDisplayContentLocked().prepareAppTransition(transit,
+ alwaysKeepCurrent, 0 /* flags */, false /* forceOverride */);
}
@Override
@@ -2585,8 +2469,10 @@
IAppTransitionAnimationSpecsFuture specsFuture, IRemoteCallback callback,
boolean scaleUp) {
synchronized(mWindowMap) {
- mAppTransition.overridePendingAppTransitionMultiThumbFuture(specsFuture, callback,
- scaleUp);
+ // TODO(multi-display): sysui using this api only support default display.
+ mRoot.getDisplayContent(DEFAULT_DISPLAY)
+ .mAppTransition.overridePendingAppTransitionMultiThumbFuture(specsFuture,
+ callback, scaleUp);
}
}
@@ -2598,7 +2484,9 @@
"Requires CONTROL_REMOTE_APP_TRANSITION_ANIMATIONS permission");
}
synchronized (mWindowMap) {
- mAppTransition.overridePendingAppTransitionRemote(remoteAnimationAdapter);
+ // TODO(multi-display): sysui using this api only support default display.
+ mRoot.getDisplayContent(DEFAULT_DISPLAY)
+ .mAppTransition.overridePendingAppTransitionRemote(remoteAnimationAdapter);
}
}
@@ -2607,20 +2495,14 @@
// TODO: Remove once clients are updated.
}
+ // TODO(multi-display): remove when no default display use case.
+ // (i.e. KeyguardController / RecentsAnimation)
@Override
public void executeAppTransition() {
if (!checkCallingPermission(MANAGE_APP_TOKENS, "executeAppTransition()")) {
throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
}
-
- synchronized(mWindowMap) {
- if (DEBUG_APP_TRANSITIONS) Slog.w(TAG_WM, "Execute app transition: " + mAppTransition
- + " Callers=" + Debug.getCallers(5));
- if (mAppTransition.isTransitionSet()) {
- mAppTransition.setReady();
- mWindowPlacerLocked.requestTraversal();
- }
- }
+ getDefaultDisplayContentLocked().executeAppTransition();
}
public void initializeRecentsAnimation(int targetActivityType,
@@ -2630,7 +2512,7 @@
synchronized (mWindowMap) {
mRecentsAnimationController = new RecentsAnimationController(this,
recentsAnimationRunner, callbacks, displayId);
- mAppTransition.updateBooster();
+ mRoot.getDisplayContent(displayId).mAppTransition.updateBooster();
mRecentsAnimationController.initialize(targetActivityType, recentTaskIds);
}
}
@@ -2650,7 +2532,8 @@
*/
public boolean canStartRecentsAnimation() {
synchronized (mWindowMap) {
- if (mAppTransition.isTransitionSet()) {
+ // TODO(multi-display): currently only default display support recent activity
+ if (getDefaultDisplayContentLocked().mAppTransition.isTransitionSet()) {
return false;
}
return true;
@@ -2677,7 +2560,8 @@
final RecentsAnimationController controller = mRecentsAnimationController;
mRecentsAnimationController = null;
controller.cleanupAnimation(reorderMode);
- mAppTransition.updateBooster();
+ // TODO(mult-display): currently only default display support recents animation.
+ getDefaultDisplayContentLocked().mAppTransition.updateBooster();
}
}
}
@@ -2747,7 +2631,8 @@
@Override
public void notifyShowingDreamChanged() {
- notifyKeyguardFlagsChanged(null /* callback */);
+ // TODO(multi-display): support show dream in multi-display.
+ notifyKeyguardFlagsChanged(null /* callback */, DEFAULT_DISPLAY);
}
@Override
@@ -2822,11 +2707,12 @@
* reevaluate the visibilities of the activities.
* @param callback Runnable to be called when activity manager is done reevaluating visibilities
*/
- void notifyKeyguardFlagsChanged(@Nullable Runnable callback) {
+ void notifyKeyguardFlagsChanged(@Nullable Runnable callback, int displayId) {
final Runnable wrappedCallback = callback != null
? () -> { synchronized (mWindowMap) { callback.run(); } }
: null;
- mH.obtainMessage(H.NOTIFY_KEYGUARD_FLAGS_CHANGED, wrappedCallback).sendToTarget();
+ mH.obtainMessage(H.NOTIFY_KEYGUARD_FLAGS_CHANGED, displayId, 0,
+ wrappedCallback).sendToTarget();
}
public boolean isKeyguardTrusted() {
@@ -3215,7 +3101,6 @@
synchronized (mWindowMap) {
mCurrentUserId = newUserId;
mCurrentProfileIds = currentProfileIds;
- mAppTransition.setCurrentUser(newUserId);
mPolicy.setCurrentUserLw(newUserId);
// If keyguard was disabled, re-enable it
@@ -3234,6 +3119,8 @@
displayContent.mDividerControllerLocked.notifyDockedStackExistsChanged(
stack != null && stack.hasTaskForUser(newUserId));
+ mRoot.forAllDisplays(dc -> dc.mAppTransition.setCurrentUser(newUserId));
+
// If the display is already prepared, update the density.
// Otherwise, we'll update it when it's prepared.
if (mDisplayReady) {
@@ -4895,7 +4782,7 @@
}
break;
case NOTIFY_KEYGUARD_FLAGS_CHANGED: {
- mAtmInternal.notifyKeyguardFlagsChanged((Runnable) msg.obj);
+ mAtmInternal.notifyKeyguardFlagsChanged((Runnable) msg.obj, msg.arg1);
}
break;
case NOTIFY_KEYGUARD_TRUSTED_CHANGED: {
@@ -5314,39 +5201,6 @@
}
}
- /**
- * @return bitmap indicating if another pass through layout must be made.
- */
- int handleAnimatingStoppedAndTransitionLocked() {
- int changes = 0;
-
- mAppTransition.setIdle();
-
- for (int i = mNoAnimationNotifyOnTransitionFinished.size() - 1; i >= 0; i--) {
- final IBinder token = mNoAnimationNotifyOnTransitionFinished.get(i);
- mAppTransition.notifyAppTransitionFinishedLocked(token);
- }
- mNoAnimationNotifyOnTransitionFinished.clear();
-
- // TODO: multi-display.
- final DisplayContent dc = getDefaultDisplayContentLocked();
-
- dc.mWallpaperController.hideDeferredWallpapersIfNeeded();
-
- dc.onAppTransitionDone();
-
- changes |= FINISH_LAYOUT_REDO_LAYOUT;
- if (DEBUG_WALLPAPER_LIGHT) Slog.v(TAG_WM,
- "Wallpaper layer changed: assigning layers + relayout");
- dc.computeImeTarget(true /* updateImeTarget */);
- mRoot.mWallpaperMayChange = true;
- // Since the window list has been rebuilt, focus might have to be recomputed since the
- // actual order of windows might have changed again.
- mFocusMayChange = true;
-
- return changes;
- }
-
void checkDrawnWindowsLocked() {
if (mWaitingForDrawn.isEmpty() || mWaitingForDrawnCallback == null) {
return;
@@ -5459,8 +5313,8 @@
mInputManagerCallback.freezeInputDispatchingLw();
- if (mAppTransition.isTransitionSet()) {
- mAppTransition.freeze();
+ if (displayContent.mAppTransition.isTransitionSet()) {
+ displayContent.mAppTransition.freeze();
}
if (PROFILE_ORIENTATION) {
@@ -5495,15 +5349,16 @@
return;
}
+ final DisplayContent dc = mRoot.getDisplayContent(mFrozenDisplayId);
if (mWaitingForConfig || mAppsFreezingScreen > 0
|| mWindowsFreezingScreen == WINDOWS_FREEZING_SCREENS_ACTIVE
- || mClientFreezingScreen || !mOpeningApps.isEmpty()) {
+ || mClientFreezingScreen || (dc != null && !dc.mOpeningApps.isEmpty())) {
if (DEBUG_ORIENTATION) Slog.d(TAG_WM,
"stopFreezingDisplayLocked: Returning mWaitingForConfig=" + mWaitingForConfig
+ ", mAppsFreezingScreen=" + mAppsFreezingScreen
+ ", mWindowsFreezingScreen=" + mWindowsFreezingScreen
+ ", mClientFreezingScreen=" + mClientFreezingScreen
- + ", mOpeningApps.size()=" + mOpeningApps.size());
+ + ", mOpeningApps.size()=" + (dc != null ? dc.mOpeningApps.size() : 0));
return;
}
@@ -5583,7 +5438,7 @@
mScreenFrozenLock.release();
- if (updateRotation) {
+ if (updateRotation && displayContent != null && updateRotation) {
if (DEBUG_ORIENTATION) Slog.d(TAG_WM, "Performing post-rotate rotation");
configChanged |= displayContent.updateRotationUnchecked();
}
@@ -5909,7 +5764,8 @@
synchronized (mWindowMap) {
final AppWindowToken appWindow = mRoot.getAppWindowToken(token);
if (appWindow != null) {
- mUnknownAppVisibilityController.notifyAppResumedFinished(appWindow);
+ appWindow.getDisplayContent().mUnknownAppVisibilityController
+ .notifyAppResumedFinished(appWindow);
}
}
}
@@ -5955,15 +5811,6 @@
private void dumpTokensLocked(PrintWriter pw, boolean dumpAll) {
pw.println("WINDOW MANAGER TOKENS (dumpsys window tokens)");
mRoot.dumpTokens(pw, dumpAll);
- if (!mOpeningApps.isEmpty() || !mClosingApps.isEmpty()) {
- pw.println();
- if (mOpeningApps.size() > 0) {
- pw.print(" mOpeningApps="); pw.println(mOpeningApps);
- }
- if (mClosingApps.size() > 0) {
- pw.print(" mClosingApps="); pw.println(mClosingApps);
- }
- }
}
private void dumpSessionsLocked(PrintWriter pw, boolean dumpAll) {
@@ -6000,7 +5847,6 @@
final DisplayContent defaultDisplayContent = getDefaultDisplayContentLocked();
proto.write(ROTATION, defaultDisplayContent.getRotation());
proto.write(LAST_ORIENTATION, defaultDisplayContent.getLastOrientation());
- mAppTransition.writeToProto(proto, APP_TRANSITION);
}
void traceStateLocked(String where) {
@@ -6133,7 +5979,6 @@
pw.println();
mInputManagerCallback.dump(pw, " ");
- mUnknownAppVisibilityController.dump(pw, " ");
mTaskSnapshotController.dump(pw, " ");
if (dumpAll) {
@@ -6172,9 +6017,6 @@
pw.print(" window="); pw.print(mWindowAnimationScaleSetting);
pw.print(" transition="); pw.print(mTransitionAnimationScaleSetting);
pw.print(" animator="); pw.println(mAnimatorDurationScaleSetting);
- pw.print(" mSkipAppTransitionAnimation=");pw.println(mSkipAppTransitionAnimation);
- pw.println(" mLayoutToAnim:");
- mAppTransition.dump(pw, " ");
if (mRecentsAnimationController != null) {
pw.print(" mRecentsAnimationController="); pw.println(mRecentsAnimationController);
mRecentsAnimationController.dump(pw, " ");
@@ -7024,10 +6866,12 @@
}
}
+ // TODO(multi-display): currently only used by PWM to notify keyguard transitions as well
+ // forwarding it to SystemUI for synchronizing status and navigation bar animations.
@Override
public void registerAppTransitionListener(AppTransitionListener listener) {
synchronized (mWindowMap) {
- mAppTransition.registerListenerLocked(listener);
+ getDefaultDisplayContentLocked().mAppTransition.registerListenerLocked(listener);
}
}
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 2f89d5c..9dc7721 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -1364,7 +1364,7 @@
@Override
boolean hasContentToDisplay() {
if (!mAppFreezing && isDrawnLw() && (mViewVisibility == View.VISIBLE
- || (isAnimating() && !mService.mAppTransition.isTransitionSet()))) {
+ || (isAnimating() && !getDisplayContent().mAppTransition.isTransitionSet()))) {
return true;
}
@@ -1473,7 +1473,7 @@
* of a transition that has not yet been started.
*/
boolean isReadyForDisplay() {
- if (mToken.waitingToShow && mService.mAppTransition.isTransitionSet()) {
+ if (mToken.waitingToShow && getDisplayContent().mAppTransition.isTransitionSet()) {
return false;
}
final boolean parentAndClientVisible = !isParentWindowHidden()
diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
index 2beb788..838d2a1 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -1364,7 +1364,8 @@
break;
}
if (attr >= 0) {
- a = mService.mAppTransition.loadAnimationAttr(mWin.mAttrs, attr, TRANSIT_NONE);
+ a = mWin.getDisplayContent().mAppTransition.loadAnimationAttr(
+ mWin.mAttrs, attr, TRANSIT_NONE);
}
}
if (DEBUG_ANIM) Slog.v(TAG,
diff --git a/services/core/java/com/android/server/wm/WindowSurfacePlacer.java b/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
index e13a70a..e82ffe8 100644
--- a/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
+++ b/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
@@ -16,62 +16,18 @@
package com.android.server.wm;
-import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
-import static android.view.WindowManager.TRANSIT_ACTIVITY_CLOSE;
-import static android.view.WindowManager.TRANSIT_ACTIVITY_OPEN;
-import static android.view.WindowManager.TRANSIT_CRASHING_ACTIVITY_CLOSE;
-import static android.view.WindowManager.TRANSIT_DOCK_TASK_FROM_RECENTS;
-import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_NO_ANIMATION;
-import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_TO_SHADE;
-import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_WITH_WALLPAPER;
-import static android.view.WindowManager.TRANSIT_KEYGUARD_GOING_AWAY;
-import static android.view.WindowManager.TRANSIT_KEYGUARD_GOING_AWAY_ON_WALLPAPER;
-import static android.view.WindowManager.TRANSIT_NONE;
-import static android.view.WindowManager.TRANSIT_TASK_CLOSE;
-import static android.view.WindowManager.TRANSIT_TASK_IN_PLACE;
-import static android.view.WindowManager.TRANSIT_TASK_OPEN;
-import static android.view.WindowManager.TRANSIT_TASK_TO_BACK;
-import static android.view.WindowManager.TRANSIT_TASK_TO_FRONT;
-import static android.view.WindowManager.TRANSIT_TRANSLUCENT_ACTIVITY_CLOSE;
-import static android.view.WindowManager.TRANSIT_TRANSLUCENT_ACTIVITY_OPEN;
-import static android.view.WindowManager.TRANSIT_WALLPAPER_CLOSE;
-import static android.view.WindowManager.TRANSIT_WALLPAPER_INTRA_CLOSE;
-import static android.view.WindowManager.TRANSIT_WALLPAPER_INTRA_OPEN;
-import static android.view.WindowManager.TRANSIT_WALLPAPER_OPEN;
-import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_CONFIG;
-import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT;
-import static com.android.server.wm.ActivityTaskManagerInternal.APP_TRANSITION_SNAPSHOT;
-import static com.android.server.wm.ActivityTaskManagerInternal.APP_TRANSITION_SPLASH_SCREEN;
-import static com.android.server.wm.ActivityTaskManagerInternal.APP_TRANSITION_WINDOWS_DRAWN;
-import static com.android.server.wm.AppTransition.isKeyguardGoingAwayTransit;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_APP_TRANSITIONS;
-import static com.android.server.wm.WindowManagerDebugConfig.SHOW_LIGHT_TRANSACTIONS;
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.H.NOTIFY_APP_TRANSITION_STARTING;
import static com.android.server.wm.WindowManagerService.H.REPORT_WINDOWS_CHANGE;
import static com.android.server.wm.WindowManagerService.LAYOUT_REPEAT_THRESHOLD;
-import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_PLACING_SURFACES;
-import android.app.WindowConfiguration;
import android.os.Debug;
import android.os.Trace;
-import android.util.ArraySet;
import android.util.Slog;
import android.util.SparseIntArray;
-import android.view.Display;
-import android.view.RemoteAnimationAdapter;
-import android.view.RemoteAnimationDefinition;
-import android.view.WindowManager;
-import android.view.WindowManager.LayoutParams;
-import android.view.WindowManager.TransitionType;
-import android.view.animation.Animation;
-
-import com.android.internal.annotations.VisibleForTesting;
import java.io.PrintWriter;
-import java.util.function.Predicate;
/**
* Positions windows and their surfaces.
@@ -233,550 +189,6 @@
return mInLayout;
}
- /**
- * @return bitmap indicating if another pass through layout must be made.
- */
- int handleAppTransitionReadyLocked() {
- int appsCount = mService.mOpeningApps.size();
- if (!transitionGoodToGo(appsCount, mTempTransitionReasons)) {
- return 0;
- }
- Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "AppTransitionReady");
-
- if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "**** GOOD TO GO");
- int transit = mService.mAppTransition.getAppTransition();
- if (mService.mSkipAppTransitionAnimation && !isKeyguardGoingAwayTransit(transit)) {
- transit = WindowManager.TRANSIT_UNSET;
- }
- mService.mSkipAppTransitionAnimation = false;
- mService.mNoAnimationNotifyOnTransitionFinished.clear();
-
- mService.mAppTransition.removeAppTransitionTimeoutCallbacks();
-
- final DisplayContent displayContent = mService.getDefaultDisplayContentLocked();
-
- mService.mRoot.mWallpaperMayChange = false;
-
- int i;
- for (i = 0; i < appsCount; i++) {
- final AppWindowToken wtoken = mService.mOpeningApps.valueAt(i);
- // Clearing the mAnimatingExit flag before entering animation. It's set to true if app
- // window is removed, or window relayout to invisible. This also affects window
- // visibility. We need to clear it *before* maybeUpdateTransitToWallpaper() as the
- // transition selection depends on wallpaper target visibility.
- wtoken.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(displayContent,
- mService.mOpeningApps);
-
- // Determine if closing and opening app token sets are wallpaper targets, in which case
- // special animations are needed.
- final boolean hasWallpaperTarget = mWallpaperControllerLocked.getWallpaperTarget() != null;
- final boolean openingAppHasWallpaper = canBeWallpaperTarget(mService.mOpeningApps)
- && hasWallpaperTarget;
- final boolean closingAppHasWallpaper = canBeWallpaperTarget(mService.mClosingApps)
- && hasWallpaperTarget;
-
- transit = maybeUpdateTransitToTranslucentAnim(transit);
- transit = maybeUpdateTransitToWallpaper(transit, openingAppHasWallpaper,
- closingAppHasWallpaper);
-
- // Find the layout params of the top-most application window in the tokens, which is
- // what will control the animation theme. If all closing windows are obscured, then there is
- // 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(mService.mOpeningApps,
- mService.mClosingApps);
- final boolean allowAnimations = mService.mPolicy.allowAppAnimationsLw();
- final AppWindowToken animLpToken = allowAnimations
- ? findAnimLayoutParamsToken(transit, activityTypes)
- : null;
- final AppWindowToken topOpeningApp = allowAnimations
- ? getTopApp(mService.mOpeningApps, false /* ignoreHidden */)
- : null;
- final AppWindowToken topClosingApp = allowAnimations
- ? getTopApp(mService.mClosingApps, false /* ignoreHidden */)
- : null;
- final LayoutParams animLp = getAnimLp(animLpToken);
- overrideWithRemoteAnimationIfSet(animLpToken, transit, activityTypes);
-
- final boolean voiceInteraction = containsVoiceInteraction(mService.mOpeningApps)
- || containsVoiceInteraction(mService.mOpeningApps);
-
- final int layoutRedo;
- mService.mSurfaceAnimationRunner.deferStartingAnimations();
- try {
- processApplicationsAnimatingInPlace(transit);
-
- handleClosingApps(transit, animLp, voiceInteraction);
- handleOpeningApps(transit, animLp, voiceInteraction);
-
- mService.mAppTransition.setLastAppTransition(transit, topOpeningApp, topClosingApp);
-
- final int flags = mService.mAppTransition.getTransitFlags();
- layoutRedo = mService.mAppTransition.goodToGo(transit, topOpeningApp, topClosingApp,
- mService.mOpeningApps, mService.mClosingApps);
- handleNonAppWindowsInTransition(transit, flags);
- mService.mAppTransition.postAnimationCallback();
- mService.mAppTransition.clear();
- } finally {
- mService.mSurfaceAnimationRunner.continueStartingAnimations();
- }
-
- mService.mTaskSnapshotController.onTransitionStarting();
-
- mService.mOpeningApps.clear();
- mService.mClosingApps.clear();
- mService.mUnknownAppVisibilityController.clear();
-
- // This has changed the visibility of windows, so perform
- // a new layout to get them all up-to-date.
- displayContent.setLayoutNeeded();
-
- // TODO(multidisplay): IMEs are only supported on the default display.
- final DisplayContent dc = mService.getDefaultDisplayContentLocked();
- dc.computeImeTarget(true /* updateImeTarget */);
- mService.updateFocusedWindowLocked(UPDATE_FOCUS_PLACING_SURFACES,
- true /*updateInputWindows*/);
- mService.mFocusMayChange = false;
-
- mService.mH.obtainMessage(NOTIFY_APP_TRANSITION_STARTING,
- mTempTransitionReasons.clone()).sendToTarget();
-
- Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
-
- return layoutRedo | FINISH_LAYOUT_REDO_LAYOUT | FINISH_LAYOUT_REDO_CONFIG;
- }
-
- private static LayoutParams getAnimLp(AppWindowToken wtoken) {
- final WindowState mainWindow = wtoken != null ? wtoken.findMainWindow() : null;
- return mainWindow != null ? mainWindow.mAttrs : null;
- }
-
- /**
- * Overrides the pending transition with the remote animation defined for the transition in the
- * set of defined remote animations in the app window token.
- */
- private void overrideWithRemoteAnimationIfSet(AppWindowToken animLpToken, int transit,
- ArraySet<Integer> activityTypes) {
- if (transit == TRANSIT_CRASHING_ACTIVITY_CLOSE) {
- // The crash transition has higher priority than any involved remote animations.
- return;
- }
- if (animLpToken == null) {
- return;
- }
- final RemoteAnimationDefinition definition = animLpToken.getRemoteAnimationDefinition();
- if (definition != null) {
- final RemoteAnimationAdapter adapter = definition.getAdapter(transit, activityTypes);
- if (adapter != null) {
- mService.mAppTransition.overridePendingAppTransitionRemote(adapter);
- }
- }
- }
-
- /**
- * @return The window token that determines the animation theme.
- */
- private AppWindowToken findAnimLayoutParamsToken(@TransitionType int transit,
- ArraySet<Integer> activityTypes) {
- AppWindowToken result;
-
- // Remote animations always win, but fullscreen tokens override non-fullscreen tokens.
- result = lookForHighestTokenWithFilter(mService.mClosingApps, mService.mOpeningApps,
- w -> w.getRemoteAnimationDefinition() != null
- && w.getRemoteAnimationDefinition().hasTransition(transit, activityTypes));
- if (result != null) {
- return result;
- }
- result = lookForHighestTokenWithFilter(mService.mClosingApps, mService.mOpeningApps,
- w -> w.fillsParent() && w.findMainWindow() != null);
- if (result != null) {
- return result;
- }
- return lookForHighestTokenWithFilter(mService.mClosingApps, mService.mOpeningApps,
- w -> w.findMainWindow() != null);
- }
-
- /**
- * @return The set of {@link WindowConfiguration.ActivityType}s contained in the set of apps in
- * {@code array1} and {@code array2}.
- */
- private ArraySet<Integer> collectActivityTypes(ArraySet<AppWindowToken> array1,
- ArraySet<AppWindowToken> array2) {
- final ArraySet<Integer> result = new ArraySet<>();
- for (int i = array1.size() - 1; i >= 0; i--) {
- result.add(array1.valueAt(i).getActivityType());
- }
- for (int i = array2.size() - 1; i >= 0; i--) {
- result.add(array2.valueAt(i).getActivityType());
- }
- return result;
- }
-
- private AppWindowToken lookForHighestTokenWithFilter(ArraySet<AppWindowToken> array1,
- ArraySet<AppWindowToken> array2, Predicate<AppWindowToken> filter) {
- final int array1count = array1.size();
- final int count = array1count + array2.size();
- int bestPrefixOrderIndex = Integer.MIN_VALUE;
- AppWindowToken bestToken = null;
- for (int i = 0; i < count; i++) {
- final AppWindowToken wtoken = i < array1count
- ? array1.valueAt(i)
- : array2.valueAt(i - array1count);
- final int prefixOrderIndex = wtoken.getPrefixOrderIndex();
- if (filter.test(wtoken) && prefixOrderIndex > bestPrefixOrderIndex) {
- bestPrefixOrderIndex = prefixOrderIndex;
- bestToken = wtoken;
- }
- }
- return bestToken;
- }
-
- private boolean containsVoiceInteraction(ArraySet<AppWindowToken> apps) {
- for (int i = apps.size() - 1; i >= 0; i--) {
- if (apps.valueAt(i).mVoiceInteraction) {
- return true;
- }
- }
- return false;
- }
-
- private void handleOpeningApps(int transit, LayoutParams animLp, boolean voiceInteraction) {
- final int appsCount = mService.mOpeningApps.size();
- for (int i = 0; i < appsCount; i++) {
- AppWindowToken wtoken = mService.mOpeningApps.valueAt(i);
- if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "Now opening app" + wtoken);
-
- if (!wtoken.setVisibility(animLp, true, transit, false, voiceInteraction)) {
- // This token isn't going to be animating. Add it to the list of tokens to
- // be notified of app transition complete since the notification will not be
- // sent be the app window animator.
- mService.mNoAnimationNotifyOnTransitionFinished.add(wtoken.token);
- }
- wtoken.updateReportedVisibilityLocked();
- wtoken.waitingToShow = false;
- if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG,
- ">>> OPEN TRANSACTION handleAppTransitionReadyLocked()");
- mService.openSurfaceTransaction();
- try {
- wtoken.showAllWindowsLocked();
- } finally {
- mService.closeSurfaceTransaction("handleAppTransitionReadyLocked");
- if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG,
- "<<< CLOSE TRANSACTION handleAppTransitionReadyLocked()");
- }
-
- if (mService.mAppTransition.isNextAppTransitionThumbnailUp()) {
- wtoken.attachThumbnailAnimation();
- } else if (mService.mAppTransition.isNextAppTransitionOpenCrossProfileApps()) {
- wtoken.attachCrossProfileAppsThumbnailAnimation();
- }
- }
- }
-
- private void handleClosingApps(int transit, LayoutParams animLp, boolean voiceInteraction) {
- final int appsCount;
- appsCount = mService.mClosingApps.size();
- for (int i = 0; i < appsCount; i++) {
- AppWindowToken wtoken = mService.mClosingApps.valueAt(i);
-
- if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "Now closing app " + wtoken);
- // TODO: Do we need to add to mNoAnimationNotifyOnTransitionFinished like above if not
- // animating?
- wtoken.setVisibility(animLp, false, transit, false, voiceInteraction);
- wtoken.updateReportedVisibilityLocked();
- // Force the allDrawn flag, because we want to start
- // this guy's animations regardless of whether it's
- // gotten drawn.
- wtoken.allDrawn = true;
- wtoken.deferClearAllDrawn = false;
- // Ensure that apps that are mid-starting are also scheduled to have their
- // starting windows removed after the animation is complete
- if (wtoken.startingWindow != null && !wtoken.startingWindow.mAnimatingExit
- && wtoken.getController() != null) {
- wtoken.getController().removeStartingWindow();
- }
-
- if (mService.mAppTransition.isNextAppTransitionThumbnailDown()) {
- wtoken.attachThumbnailAnimation();
- }
- }
- }
-
- private void handleNonAppWindowsInTransition(int transit, int flags) {
- if (transit == TRANSIT_KEYGUARD_GOING_AWAY) {
- if ((flags & TRANSIT_FLAG_KEYGUARD_GOING_AWAY_WITH_WALLPAPER) != 0
- && (flags & TRANSIT_FLAG_KEYGUARD_GOING_AWAY_NO_ANIMATION) == 0) {
- Animation anim = mService.mPolicy.createKeyguardWallpaperExit(
- (flags & TRANSIT_FLAG_KEYGUARD_GOING_AWAY_TO_SHADE) != 0);
- if (anim != null) {
- mService.getDefaultDisplayContentLocked().mWallpaperController
- .startWallpaperAnimation(anim);
- }
- }
- }
- if (transit == TRANSIT_KEYGUARD_GOING_AWAY
- || transit == TRANSIT_KEYGUARD_GOING_AWAY_ON_WALLPAPER) {
- mService.getDefaultDisplayContentLocked().startKeyguardExitOnNonAppWindows(
- transit == TRANSIT_KEYGUARD_GOING_AWAY_ON_WALLPAPER,
- (flags & TRANSIT_FLAG_KEYGUARD_GOING_AWAY_TO_SHADE) != 0);
- }
- }
-
- private boolean transitionGoodToGo(int appsCount, SparseIntArray outReasons) {
- if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
- "Checking " + appsCount + " opening apps (frozen="
- + mService.mDisplayFrozen + " timeout="
- + mService.mAppTransition.isTimeout() + ")...");
- final ScreenRotationAnimation screenRotationAnimation =
- mService.mAnimator.getScreenRotationAnimationLocked(
- Display.DEFAULT_DISPLAY);
-
- outReasons.clear();
- if (!mService.mAppTransition.isTimeout()) {
- // Imagine the case where we are changing orientation due to an app transition, but a previous
- // orientation change is still in progress. We won't process the orientation change
- // for our transition because we need to wait for the rotation animation to finish.
- // If we start the app transition at this point, we will interrupt it halfway with a new rotation
- // animation after the old one finally finishes. It's better to defer the
- // app transition.
- if (screenRotationAnimation != null && screenRotationAnimation.isAnimating() &&
- mService.getDefaultDisplayContentLocked().rotationNeedsUpdate()) {
- if (DEBUG_APP_TRANSITIONS) {
- Slog.v(TAG, "Delaying app transition for screen rotation animation to finish");
- }
- return false;
- }
- for (int i = 0; i < appsCount; i++) {
- AppWindowToken wtoken = mService.mOpeningApps.valueAt(i);
- if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
- "Check opening app=" + wtoken + ": allDrawn="
- + wtoken.allDrawn + " startingDisplayed="
- + wtoken.startingDisplayed + " startingMoved="
- + wtoken.startingMoved + " isRelaunching()="
- + wtoken.isRelaunching() + " startingWindow="
- + wtoken.startingWindow);
-
-
- final boolean allDrawn = wtoken.allDrawn && !wtoken.isRelaunching();
- if (!allDrawn && !wtoken.startingDisplayed && !wtoken.startingMoved) {
- return false;
- }
- final int windowingMode = wtoken.getWindowingMode();
- if (allDrawn) {
- outReasons.put(windowingMode, APP_TRANSITION_WINDOWS_DRAWN);
- } else {
- outReasons.put(windowingMode,
- wtoken.startingData instanceof SplashScreenStartingData
- ? APP_TRANSITION_SPLASH_SCREEN
- : APP_TRANSITION_SNAPSHOT);
- }
- }
-
- // We also need to wait for the specs to be fetched, if needed.
- if (mService.mAppTransition.isFetchingAppTransitionsSpecs()) {
- if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "isFetchingAppTransitionSpecs=true");
- return false;
- }
-
- if (!mService.mUnknownAppVisibilityController.allResolved()) {
- if (DEBUG_APP_TRANSITIONS) {
- Slog.v(TAG, "unknownApps is not empty: "
- + mService.mUnknownAppVisibilityController.getDebugMessage());
- }
- return false;
- }
-
- // If the wallpaper is visible, we need to check it's ready too.
- boolean wallpaperReady = !mWallpaperControllerLocked.isWallpaperVisible() ||
- mWallpaperControllerLocked.wallpaperTransitionReady();
- if (wallpaperReady) {
- return true;
- }
- return false;
- }
- return true;
- }
-
- private int maybeUpdateTransitToWallpaper(int transit, boolean openingAppHasWallpaper,
- boolean closingAppHasWallpaper) {
- // Given no app transition pass it through instead of a wallpaper transition.
- // Never convert the crashing transition.
- // Never update the transition for the wallpaper if we are just docking from recents
- if (transit == TRANSIT_NONE || transit == TRANSIT_CRASHING_ACTIVITY_CLOSE
- || transit == TRANSIT_DOCK_TASK_FROM_RECENTS) {
- return transit;
- }
-
- final WindowState wallpaperTarget = mWallpaperControllerLocked.getWallpaperTarget();
- final boolean showWallpaper = wallpaperTarget != null
- && (wallpaperTarget.mAttrs.flags & FLAG_SHOW_WALLPAPER) != 0;
- // If wallpaper is animating or wallpaperTarget doesn't have SHOW_WALLPAPER flag set,
- // don't consider upgrading to wallpaper transition.
- final WindowState oldWallpaper =
- (mWallpaperControllerLocked.isWallpaperTargetAnimating() || !showWallpaper)
- ? null
- : wallpaperTarget;
- final ArraySet<AppWindowToken> openingApps = mService.mOpeningApps;
- final ArraySet<AppWindowToken> closingApps = mService.mClosingApps;
- final AppWindowToken topOpeningApp = getTopApp(mService.mOpeningApps,
- false /* ignoreHidden */);
- final AppWindowToken topClosingApp = getTopApp(mService.mClosingApps,
- true /* ignoreHidden */);
-
- boolean openingCanBeWallpaperTarget = canBeWallpaperTarget(openingApps);
- if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
- "New wallpaper target=" + wallpaperTarget
- + ", oldWallpaper=" + oldWallpaper
- + ", openingApps=" + openingApps
- + ", closingApps=" + closingApps);
-
- if (openingCanBeWallpaperTarget && transit == TRANSIT_KEYGUARD_GOING_AWAY) {
- transit = TRANSIT_KEYGUARD_GOING_AWAY_ON_WALLPAPER;
- if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
- "New transit: " + AppTransition.appTransitionToString(transit));
- }
- // We never want to change from a Keyguard transit to a non-Keyguard transit, as our logic
- // relies on the fact that we always execute a Keyguard transition after preparing one.
- else if (!isKeyguardGoingAwayTransit(transit)) {
- if (closingAppHasWallpaper && openingAppHasWallpaper) {
- if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "Wallpaper animation!");
- switch (transit) {
- case TRANSIT_ACTIVITY_OPEN:
- case TRANSIT_TASK_OPEN:
- case TRANSIT_TASK_TO_FRONT:
- transit = TRANSIT_WALLPAPER_INTRA_OPEN;
- break;
- case TRANSIT_ACTIVITY_CLOSE:
- case TRANSIT_TASK_CLOSE:
- case TRANSIT_TASK_TO_BACK:
- transit = TRANSIT_WALLPAPER_INTRA_CLOSE;
- break;
- }
- if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
- "New transit: " + AppTransition.appTransitionToString(transit));
- } else if (oldWallpaper != null && !mService.mOpeningApps.isEmpty()
- && !openingApps.contains(oldWallpaper.mAppToken)
- && closingApps.contains(oldWallpaper.mAppToken)
- && topClosingApp == oldWallpaper.mAppToken) {
- // We are transitioning from an activity with a wallpaper to one without.
- transit = TRANSIT_WALLPAPER_CLOSE;
- if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "New transit away from wallpaper: "
- + AppTransition.appTransitionToString(transit));
- } else if (wallpaperTarget != null && wallpaperTarget.isVisibleLw()
- && openingApps.contains(wallpaperTarget.mAppToken)
- && topOpeningApp == wallpaperTarget.mAppToken
- && transit != TRANSIT_TRANSLUCENT_ACTIVITY_CLOSE) {
- // We are transitioning from an activity without
- // a wallpaper to now showing the wallpaper
- transit = TRANSIT_WALLPAPER_OPEN;
- if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "New transit into wallpaper: "
- + AppTransition.appTransitionToString(transit));
- }
- }
- return transit;
- }
-
- /**
- * There are cases where we open/close a new task/activity, but in reality only a translucent
- * activity on top of existing activities is opening/closing. For that one, we have a different
- * animation because non of the task/activity animations actually work well with translucent
- * apps.
- *
- * @param transit The current transition type.
- * @return The current transition type or
- * {@link WindowManager#TRANSIT_TRANSLUCENT_ACTIVITY_CLOSE}/
- * {@link WindowManager#TRANSIT_TRANSLUCENT_ACTIVITY_OPEN} if appropriate for the
- * situation.
- */
- @VisibleForTesting
- int maybeUpdateTransitToTranslucentAnim(int transit) {
- final boolean taskOrActivity = AppTransition.isTaskTransit(transit)
- || AppTransition.isActivityTransit(transit);
- boolean allOpeningVisible = true;
- boolean allTranslucentOpeningApps = !mService.mOpeningApps.isEmpty();
- for (int i = mService.mOpeningApps.size() - 1; i >= 0; i--) {
- final AppWindowToken token = mService.mOpeningApps.valueAt(i);
- if (!token.isVisible()) {
- allOpeningVisible = false;
- if (token.fillsParent()) {
- allTranslucentOpeningApps = false;
- }
- }
- }
- boolean allTranslucentClosingApps = !mService.mClosingApps.isEmpty();
- for (int i = mService.mClosingApps.size() - 1; i >= 0; i--) {
- if (mService.mClosingApps.valueAt(i).fillsParent()) {
- allTranslucentClosingApps = false;
- break;
- }
- }
-
- if (taskOrActivity && allTranslucentClosingApps && allOpeningVisible) {
- return TRANSIT_TRANSLUCENT_ACTIVITY_CLOSE;
- }
- if (taskOrActivity && allTranslucentOpeningApps && mService.mClosingApps.isEmpty()) {
- return TRANSIT_TRANSLUCENT_ACTIVITY_OPEN;
- }
- return transit;
- }
-
- private boolean canBeWallpaperTarget(ArraySet<AppWindowToken> apps) {
- for (int i = apps.size() - 1; i >= 0; i--) {
- if (apps.valueAt(i).windowsCanBeWallpaperTarget()) {
- return true;
- }
- }
- return false;
- }
-
- /**
- * Finds the top app in a list of apps, using its {@link AppWindowToken#getPrefixOrderIndex} to
- * compare z-order.
- *
- * @param apps The list of apps to search.
- * @param ignoreHidden If set to true, ignores apps that are {@link AppWindowToken#isHidden}.
- * @return The top {@link AppWindowToken}.
- */
- private AppWindowToken getTopApp(ArraySet<AppWindowToken> apps, boolean ignoreHidden) {
- int topPrefixOrderIndex = Integer.MIN_VALUE;
- AppWindowToken topApp = null;
- for (int i = apps.size() - 1; i >= 0; i--) {
- final AppWindowToken app = apps.valueAt(i);
- if (ignoreHidden && app.isHidden()) {
- continue;
- }
- final int prefixOrderIndex = app.getPrefixOrderIndex();
- if (prefixOrderIndex > topPrefixOrderIndex) {
- topPrefixOrderIndex = prefixOrderIndex;
- topApp = app;
- }
- }
- return topApp;
- }
-
- private void processApplicationsAnimatingInPlace(int transit) {
- if (transit == TRANSIT_TASK_IN_PLACE) {
- // TODO (b/111362605): non-default-display transition.
- // Find the focused window
- final WindowState win = mService.getDefaultDisplayContentLocked().findFocusedWindow();
- if (win != null) {
- final AppWindowToken wtoken = win.mAppToken;
- if (DEBUG_APP_TRANSITIONS)
- Slog.v(TAG, "Now animating app in place " + wtoken);
- wtoken.cancelAnimation();
- wtoken.applyAnimationLocked(null, transit, false, false);
- wtoken.updateReportedVisibilityLocked();
- wtoken.showAllWindowsLocked();
- }
- }
- }
-
void requestTraversal() {
if (!mTraversalScheduled) {
mTraversalScheduled = true;
diff --git a/services/tests/servicestests/src/com/android/server/wm/WindowSurfacePlacerTest.java b/services/tests/servicestests/src/com/android/server/wm/AppTransitionControllerTest.java
similarity index 79%
rename from services/tests/servicestests/src/com/android/server/wm/WindowSurfacePlacerTest.java
rename to services/tests/servicestests/src/com/android/server/wm/AppTransitionControllerTest.java
index 057f047..aa495f7 100644
--- a/services/tests/servicestests/src/com/android/server/wm/WindowSurfacePlacerTest.java
+++ b/services/tests/servicestests/src/com/android/server/wm/AppTransitionControllerTest.java
@@ -36,14 +36,14 @@
@SmallTest
@Presubmit
@RunWith(AndroidJUnit4.class)
-public class WindowSurfacePlacerTest extends WindowTestsBase {
+public class AppTransitionControllerTest extends WindowTestsBase {
- private WindowSurfacePlacer mWindowSurfacePlacer;
+ private AppTransitionController mAppTransitionController;
@Before
public void setUp() throws Exception {
super.setUp();
- mWindowSurfacePlacer = new WindowSurfacePlacer(sWm);
+ mAppTransitionController = new AppTransitionController(sWm, mDisplayContent);
}
@Test
@@ -55,10 +55,11 @@
WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD);
translucentOpening.setFillsParent(false);
translucentOpening.setHidden(true);
- sWm.mOpeningApps.add(behind);
- sWm.mOpeningApps.add(translucentOpening);
+ mDisplayContent.mOpeningApps.add(behind);
+ mDisplayContent.mOpeningApps.add(translucentOpening);
assertEquals(WindowManager.TRANSIT_TRANSLUCENT_ACTIVITY_OPEN,
- mWindowSurfacePlacer.maybeUpdateTransitToTranslucentAnim(TRANSIT_TASK_OPEN));
+ mAppTransitionController.maybeUpdateTransitToTranslucentAnim(
+ TRANSIT_TASK_OPEN));
}
}
@@ -70,9 +71,10 @@
final AppWindowToken translucentClosing = createAppWindowToken(mDisplayContent,
WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD);
translucentClosing.setFillsParent(false);
- sWm.mClosingApps.add(translucentClosing);
+ mDisplayContent.mClosingApps.add(translucentClosing);
assertEquals(WindowManager.TRANSIT_TRANSLUCENT_ACTIVITY_CLOSE,
- mWindowSurfacePlacer.maybeUpdateTransitToTranslucentAnim(TRANSIT_TASK_CLOSE));
+ mAppTransitionController.maybeUpdateTransitToTranslucentAnim(
+ TRANSIT_TASK_CLOSE));
}
}
}
diff --git a/services/tests/servicestests/src/com/android/server/wm/AppTransitionTests.java b/services/tests/servicestests/src/com/android/server/wm/AppTransitionTests.java
index 3053c41..ee6fbac 100644
--- a/services/tests/servicestests/src/com/android/server/wm/AppTransitionTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/AppTransitionTests.java
@@ -16,22 +16,33 @@
package com.android.server.wm;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
+import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
+import static android.view.WindowManager.TRANSIT_ACTIVITY_CLOSE;
import static android.view.WindowManager.TRANSIT_ACTIVITY_OPEN;
import static android.view.WindowManager.TRANSIT_CRASHING_ACTIVITY_CLOSE;
import static android.view.WindowManager.TRANSIT_KEYGUARD_GOING_AWAY;
import static android.view.WindowManager.TRANSIT_KEYGUARD_UNOCCLUDE;
+import static junit.framework.Assert.assertFalse;
+import static junit.framework.Assert.assertTrue;
+
import static org.junit.Assert.assertEquals;
+import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.spy;
import android.content.Context;
+import android.graphics.Rect;
import android.platform.test.annotations.Presubmit;
+import android.view.Display;
+import android.view.IApplicationToken;
import androidx.test.InstrumentationRegistry;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
import org.junit.Before;
-import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -43,51 +54,142 @@
@SmallTest
@Presubmit
@RunWith(AndroidJUnit4.class)
-public class AppTransitionTests {
+public class AppTransitionTests extends WindowTestsBase {
- @Rule
- public final WindowManagerServiceRule mRule = new WindowManagerServiceRule();
- private WindowManagerService mWm;
+ private DisplayContent mDc;
@Before
public void setUp() throws Exception {
+ super.setUp();
final Context context = InstrumentationRegistry.getTargetContext();
- mWm = mRule.getWindowManagerService();
+ mDc = sWm.getDefaultDisplayContentLocked();
+ // For unit test, we don't need to test performSurfacePlacement to prevent some
+ // abnormal interaction with surfaceflinger native side.
+ sWm.mRoot = spy(sWm.mRoot);
+ doNothing().when(sWm.mRoot).performSurfacePlacement(anyBoolean());
}
@Test
public void testKeyguardOverride() throws Exception {
- mWm.prepareAppTransition(TRANSIT_ACTIVITY_OPEN, false /* alwaysKeepCurrent */);
- mWm.prepareAppTransition(TRANSIT_KEYGUARD_GOING_AWAY, false /* alwaysKeepCurrent */);
- assertEquals(TRANSIT_KEYGUARD_GOING_AWAY, mWm.mAppTransition.getAppTransition());
+ sWm.prepareAppTransition(TRANSIT_ACTIVITY_OPEN, false /* alwaysKeepCurrent */);
+ sWm.prepareAppTransition(TRANSIT_KEYGUARD_GOING_AWAY, false /* alwaysKeepCurrent */);
+ assertEquals(TRANSIT_KEYGUARD_GOING_AWAY, mDc.mAppTransition.getAppTransition());
}
@Test
public void testKeyguardKeep() throws Exception {
- mWm.prepareAppTransition(TRANSIT_KEYGUARD_GOING_AWAY, false /* alwaysKeepCurrent */);
- mWm.prepareAppTransition(TRANSIT_ACTIVITY_OPEN, false /* alwaysKeepCurrent */);
- assertEquals(TRANSIT_KEYGUARD_GOING_AWAY, mWm.mAppTransition.getAppTransition());
+ sWm.prepareAppTransition(TRANSIT_KEYGUARD_GOING_AWAY, false /* alwaysKeepCurrent */);
+ sWm.prepareAppTransition(TRANSIT_ACTIVITY_OPEN, false /* alwaysKeepCurrent */);
+ assertEquals(TRANSIT_KEYGUARD_GOING_AWAY, mDc.mAppTransition.getAppTransition());
}
@Test
public void testForceOverride() throws Exception {
- mWm.prepareAppTransition(TRANSIT_KEYGUARD_UNOCCLUDE, false /* alwaysKeepCurrent */);
- mWm.prepareAppTransition(TRANSIT_ACTIVITY_OPEN, false /* alwaysKeepCurrent */,
- 0 /* flags */, true /* forceOverride */);
- assertEquals(TRANSIT_ACTIVITY_OPEN, mWm.mAppTransition.getAppTransition());
+ sWm.prepareAppTransition(TRANSIT_KEYGUARD_UNOCCLUDE, false /* alwaysKeepCurrent */);
+ mDc.getController().prepareAppTransition(TRANSIT_ACTIVITY_OPEN,
+ false /* alwaysKeepCurrent */, 0 /* flags */, true /* forceOverride */);
+ assertEquals(TRANSIT_ACTIVITY_OPEN, mDc.mAppTransition.getAppTransition());
}
@Test
public void testCrashing() throws Exception {
- mWm.prepareAppTransition(TRANSIT_ACTIVITY_OPEN, false /* alwaysKeepCurrent */);
- mWm.prepareAppTransition(TRANSIT_CRASHING_ACTIVITY_CLOSE, false /* alwaysKeepCurrent */);
- assertEquals(TRANSIT_CRASHING_ACTIVITY_CLOSE, mWm.mAppTransition.getAppTransition());
+ sWm.prepareAppTransition(TRANSIT_ACTIVITY_OPEN, false /* alwaysKeepCurrent */);
+ sWm.prepareAppTransition(TRANSIT_CRASHING_ACTIVITY_CLOSE, false /* alwaysKeepCurrent */);
+ assertEquals(TRANSIT_CRASHING_ACTIVITY_CLOSE, mDc.mAppTransition.getAppTransition());
}
@Test
public void testKeepKeyguard_withCrashing() throws Exception {
- mWm.prepareAppTransition(TRANSIT_KEYGUARD_GOING_AWAY, false /* alwaysKeepCurrent */);
- mWm.prepareAppTransition(TRANSIT_CRASHING_ACTIVITY_CLOSE, false /* alwaysKeepCurrent */);
- assertEquals(TRANSIT_KEYGUARD_GOING_AWAY, mWm.mAppTransition.getAppTransition());
+ sWm.prepareAppTransition(TRANSIT_KEYGUARD_GOING_AWAY, false /* alwaysKeepCurrent */);
+ sWm.prepareAppTransition(TRANSIT_CRASHING_ACTIVITY_CLOSE, false /* alwaysKeepCurrent */);
+ assertEquals(TRANSIT_KEYGUARD_GOING_AWAY, mDc.mAppTransition.getAppTransition());
+ }
+
+ @Test
+ public void testAppTransitionStateForMultiDisplay() throws Exception {
+ // Create 2 displays & presume both display the state is ON for ready to display & animate.
+ final DisplayContent dc1 = createNewDisplayWithController(Display.STATE_ON);
+ final DisplayContent dc2 = createNewDisplayWithController(Display.STATE_ON);
+
+ // Create 2 app window tokens to represent 2 activity window.
+ final WindowTestUtils.TestAppWindowToken token1 = createTestAppWindowToken(dc1,
+ WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD);
+ final WindowTestUtils.TestAppWindowToken token2 = createTestAppWindowToken(dc2,
+ WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD);
+
+ // Set TestAppWindowContainerController & assign first app token state to be good to go.
+ final WindowTestUtils.TestAppWindowContainerController controller1 =
+ createAppWindowController(dc1, token1.appToken);
+ final WindowTestUtils.TestAppWindowContainerController controller2 =
+ createAppWindowController(dc1, token2.appToken);
+ controller1.setContainer(token1);
+ token1.allDrawn = true;
+ token1.startingDisplayed = true;
+ token1.startingMoved = true;
+ controller2.setContainer(token2);
+
+ // Simulate activity resume / finish flows to prepare app transition & set visibility,
+ // make sure transition is set as expected for each display.
+ dc1.getController().prepareAppTransition(TRANSIT_ACTIVITY_OPEN,
+ false /* alwaysKeepCurrent */, 0 /* flags */, false /* forceOverride */);
+ assertEquals(TRANSIT_ACTIVITY_OPEN, dc1.mAppTransition.getAppTransition());
+ dc2.getController().prepareAppTransition(TRANSIT_ACTIVITY_CLOSE,
+ false /* alwaysKeepCurrent */, 0 /* flags */, false /* forceOverride */);
+ assertEquals(TRANSIT_ACTIVITY_CLOSE, dc2.mAppTransition.getAppTransition());
+ // One activity window is visible for resuming & the other activity window is invisible
+ // for finishing in different display.
+ controller1.setVisibility(true, false);
+ controller2.setVisibility(false, false);
+
+ // Make sure each display is in animating stage.
+ assertTrue(dc1.mOpeningApps.size() > 0);
+ assertTrue(dc2.mClosingApps.size() > 0);
+ assertTrue(dc1.isAppAnimating());
+ assertTrue(dc2.isAppAnimating());
+ }
+
+ @Test
+ public void testCleanAppTransitionWhenTaskStackReparent() throws Exception {
+ // Create 2 displays & presume both display the state is ON for ready to display & animate.
+ final DisplayContent dc1 = createNewDisplayWithController(Display.STATE_ON);
+ final DisplayContent dc2 = createNewDisplayWithController(Display.STATE_ON);
+
+ final TaskStack stack1 = createTaskStackOnDisplay(dc1);
+ final Task task1 = createTaskInStack(stack1, 0 /* userId */);
+ final WindowTestUtils.TestAppWindowToken token1 =
+ WindowTestUtils.createTestAppWindowToken(dc1);
+ task1.addChild(token1, 0);
+
+ // Simulate same app is during opening / closing transition set stage.
+ dc1.mClosingApps.add(token1);
+ assertTrue(dc1.mClosingApps.size() > 0);
+
+ dc1.getController().prepareAppTransition(TRANSIT_ACTIVITY_OPEN,
+ false /* alwaysKeepCurrent */, 0 /* flags */, false /* forceOverride */);
+ assertEquals(TRANSIT_ACTIVITY_OPEN, dc1.mAppTransition.getAppTransition());
+ assertTrue(dc1.mAppTransition.isTransitionSet());
+
+ dc1.mOpeningApps.add(token1);
+ assertTrue(dc1.mOpeningApps.size() > 0);
+
+ // Move stack to another display.
+ stack1.getController().reparent(dc2.getDisplayId(), new Rect(), true);
+
+ // Verify if token are cleared from both pending transition list in former display.
+ assertFalse(dc1.mOpeningApps.contains(token1));
+ assertFalse(dc1.mOpeningApps.contains(token1));
+ }
+
+ private WindowTestUtils.TestAppWindowContainerController createAppWindowController(
+ DisplayContent dc, IApplicationToken token) {
+ return createAppWindowController(
+ new WindowTestUtils.TestTaskWindowContainerController(
+ createStackControllerOnDisplay(dc)), token);
+ }
+
+ private WindowTestUtils.TestAppWindowContainerController createAppWindowController(
+ WindowTestUtils.TestTaskWindowContainerController taskController,
+ IApplicationToken token) {
+ return new WindowTestUtils.TestAppWindowContainerController(taskController, token);
}
}
diff --git a/services/tests/servicestests/src/com/android/server/wm/BoundsAnimationControllerTests.java b/services/tests/servicestests/src/com/android/server/wm/BoundsAnimationControllerTests.java
index e6e08bb..d65055c 100644
--- a/services/tests/servicestests/src/com/android/server/wm/BoundsAnimationControllerTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/BoundsAnimationControllerTests.java
@@ -16,6 +16,8 @@
package com.android.server.wm;
+import static android.view.Display.DEFAULT_DISPLAY;
+
import static com.android.server.wm.BoundsAnimationController.NO_PIP_MODE_CHANGED_CALLBACKS;
import static com.android.server.wm.BoundsAnimationController.SCHEDULE_PIP_MODE_CHANGED_ON_END;
import static com.android.server.wm.BoundsAnimationController.SCHEDULE_PIP_MODE_CHANGED_ON_START;
@@ -90,7 +92,7 @@
private AppTransitionListener mListener;
MockAppTransition(Context context) {
- super(context, sWm);
+ super(context, sWm, mDisplayContent);
}
@Override
diff --git a/services/tests/servicestests/src/com/android/server/wm/RemoteAnimationControllerTest.java b/services/tests/servicestests/src/com/android/server/wm/RemoteAnimationControllerTest.java
index 7d19baa..ae92984 100644
--- a/services/tests/servicestests/src/com/android/server/wm/RemoteAnimationControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/wm/RemoteAnimationControllerTest.java
@@ -85,7 +85,7 @@
@Test
public void testRun() throws Exception {
final WindowState win = createWindow(null /* parent */, TYPE_BASE_APPLICATION, "testWin");
- sWm.mOpeningApps.add(win.mAppToken);
+ mDisplayContent.mOpeningApps.add(win.mAppToken);
try {
final AnimationAdapter adapter = mController.createAnimationAdapter(win.mAppToken,
new Point(50, 100), new Rect(50, 100, 150, 150));
@@ -113,7 +113,7 @@
finishedCaptor.getValue().onAnimationFinished();
verify(mFinishedCallback).onAnimationFinished(eq(adapter));
} finally {
- sWm.mOpeningApps.clear();
+ mDisplayContent.mOpeningApps.clear();
}
}
diff --git a/services/tests/servicestests/src/com/android/server/wm/TaskStackTests.java b/services/tests/servicestests/src/com/android/server/wm/TaskStackTests.java
index 53a1185..cb5c1cd 100644
--- a/services/tests/servicestests/src/com/android/server/wm/TaskStackTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/TaskStackTests.java
@@ -74,7 +74,7 @@
appWindowToken2.setOrientation(SCREEN_ORIENTATION_PORTRAIT);
assertEquals(SCREEN_ORIENTATION_PORTRAIT, stack.getOrientation());
- sWm.mClosingApps.add(appWindowToken2);
+ mDisplayContent.mClosingApps.add(appWindowToken2);
assertEquals(SCREEN_ORIENTATION_LANDSCAPE, stack.getOrientation());
}
diff --git a/services/tests/servicestests/src/com/android/server/wm/UnknownAppVisibilityControllerTest.java b/services/tests/servicestests/src/com/android/server/wm/UnknownAppVisibilityControllerTest.java
index 3ac97027..54456fb 100644
--- a/services/tests/servicestests/src/com/android/server/wm/UnknownAppVisibilityControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/wm/UnknownAppVisibilityControllerTest.java
@@ -40,50 +40,50 @@
@Before
public void setUp() throws Exception {
super.setUp();
- sWm.mUnknownAppVisibilityController.clear();
+ mDisplayContent.mUnknownAppVisibilityController.clear();
}
@Test
public void testFlow() throws Exception {
final AppWindowToken token = WindowTestUtils.createTestAppWindowToken(mDisplayContent);
- sWm.mUnknownAppVisibilityController.notifyLaunched(token);
- sWm.mUnknownAppVisibilityController.notifyAppResumedFinished(token);
- sWm.mUnknownAppVisibilityController.notifyRelayouted(token);
+ mDisplayContent.mUnknownAppVisibilityController.notifyLaunched(token);
+ mDisplayContent.mUnknownAppVisibilityController.notifyAppResumedFinished(token);
+ mDisplayContent.mUnknownAppVisibilityController.notifyRelayouted(token);
// Make sure our handler processed the message.
Thread.sleep(100);
- assertTrue(sWm.mUnknownAppVisibilityController.allResolved());
+ assertTrue(mDisplayContent.mUnknownAppVisibilityController.allResolved());
}
@Test
public void testMultiple() throws Exception {
final AppWindowToken token1 = WindowTestUtils.createTestAppWindowToken(mDisplayContent);
final AppWindowToken token2 = WindowTestUtils.createTestAppWindowToken(mDisplayContent);
- sWm.mUnknownAppVisibilityController.notifyLaunched(token1);
- sWm.mUnknownAppVisibilityController.notifyAppResumedFinished(token1);
- sWm.mUnknownAppVisibilityController.notifyLaunched(token2);
- sWm.mUnknownAppVisibilityController.notifyRelayouted(token1);
- sWm.mUnknownAppVisibilityController.notifyAppResumedFinished(token2);
- sWm.mUnknownAppVisibilityController.notifyRelayouted(token2);
+ mDisplayContent.mUnknownAppVisibilityController.notifyLaunched(token1);
+ mDisplayContent.mUnknownAppVisibilityController.notifyAppResumedFinished(token1);
+ mDisplayContent.mUnknownAppVisibilityController.notifyLaunched(token2);
+ mDisplayContent.mUnknownAppVisibilityController.notifyRelayouted(token1);
+ mDisplayContent.mUnknownAppVisibilityController.notifyAppResumedFinished(token2);
+ mDisplayContent.mUnknownAppVisibilityController.notifyRelayouted(token2);
// Make sure our handler processed the message.
Thread.sleep(100);
- assertTrue(sWm.mUnknownAppVisibilityController.allResolved());
+ assertTrue(mDisplayContent.mUnknownAppVisibilityController.allResolved());
}
@Test
public void testClear() throws Exception {
final AppWindowToken token = WindowTestUtils.createTestAppWindowToken(mDisplayContent);
- sWm.mUnknownAppVisibilityController.notifyLaunched(token);
- sWm.mUnknownAppVisibilityController.clear();;
- assertTrue(sWm.mUnknownAppVisibilityController.allResolved());
+ mDisplayContent.mUnknownAppVisibilityController.notifyLaunched(token);
+ mDisplayContent.mUnknownAppVisibilityController.clear();;
+ assertTrue(mDisplayContent.mUnknownAppVisibilityController.allResolved());
}
@Test
public void testAppRemoved() throws Exception {
final AppWindowToken token = WindowTestUtils.createTestAppWindowToken(mDisplayContent);
- sWm.mUnknownAppVisibilityController.notifyLaunched(token);
- sWm.mUnknownAppVisibilityController.appRemovedOrHidden(token);
- assertTrue(sWm.mUnknownAppVisibilityController.allResolved());
+ mDisplayContent.mUnknownAppVisibilityController.notifyLaunched(token);
+ mDisplayContent.mUnknownAppVisibilityController.appRemovedOrHidden(token);
+ assertTrue(mDisplayContent.mUnknownAppVisibilityController.allResolved());
}
}
diff --git a/services/tests/servicestests/src/com/android/server/wm/WindowManagerServiceRule.java b/services/tests/servicestests/src/com/android/server/wm/WindowManagerServiceRule.java
index 389eba5..012c4be 100644
--- a/services/tests/servicestests/src/com/android/server/wm/WindowManagerServiceRule.java
+++ b/services/tests/servicestests/src/com/android/server/wm/WindowManagerServiceRule.java
@@ -33,6 +33,7 @@
import android.hardware.display.DisplayManagerInternal;
import android.os.PowerManagerInternal;
import android.os.PowerSaveState;
+import android.view.Display;
import android.view.InputChannel;
import android.view.SurfaceControl;
import android.view.SurfaceControl.Transaction;
@@ -114,7 +115,7 @@
runnable.run();
}
return null;
- }).when(atm).notifyKeyguardFlagsChanged(any());
+ }).when(atm).notifyKeyguardFlagsChanged(any(), anyInt());
InputManagerService ims = mock(InputManagerService.class);
// InputChannel is final and can't be mocked.
@@ -142,11 +143,11 @@
mService.onInitReady();
+ final Display display = mService.mDisplayManager.getDisplay(DEFAULT_DISPLAY);
+ final DisplayWindowController dcw = new DisplayWindowController(display, mService);
// Display creation is driven by the ActivityManagerService via ActivityStackSupervisor.
// We emulate those steps here.
- mService.mRoot.createDisplayContent(
- mService.mDisplayManager.getDisplay(DEFAULT_DISPLAY),
- mock(DisplayWindowController.class));
+ mService.mRoot.createDisplayContent(display, dcw);
}
private void removeServices() {
diff --git a/services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java b/services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java
index d0a81b2..dcfe556 100644
--- a/services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java
+++ b/services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java
@@ -181,9 +181,12 @@
displayContent.removeImmediately();
}
}
+ // Remove app transition & window freeze timeout callbacks to prevent unnecessary
+ // actions after test.
+ sWm.getDefaultDisplayContentLocked().mAppTransition
+ .removeAppTransitionTimeoutCallbacks();
+ sWm.mH.removeMessages(WindowManagerService.H.WINDOW_FREEZE_TIMEOUT);
sWm.mInputMethodTarget = null;
- sWm.mClosingApps.clear();
- sWm.mOpeningApps.clear();
}
// Wait until everything is really cleaned up.
@@ -354,6 +357,32 @@
}
}
+ /**
+ * Creates a {@link DisplayContent} with given display state and adds it to the system.
+ *
+ * Unlike {@link #createNewDisplay()} that uses a mock {@link DisplayWindowController} to
+ * initialize {@link DisplayContent}, this method used real controller object when the test
+ * need to verify its related flows.
+ *
+ * @param displayState For initializing the state of the display. See
+ * {@link Display#getState()}.
+ */
+ DisplayContent createNewDisplayWithController(int displayState) {
+ // Leverage main display info & initialize it with display state for given displayId.
+ DisplayInfo displayInfo = new DisplayInfo();
+ displayInfo.copyFrom(mDisplayInfo);
+ displayInfo.state = displayState;
+ final int displayId = sNextDisplayId++;
+ final Display display = new Display(DisplayManagerGlobal.getInstance(), displayId,
+ displayInfo, DEFAULT_DISPLAY_ADJUSTMENTS);
+ final DisplayWindowController dcw = new DisplayWindowController(display, sWm);
+ synchronized (sWm.mWindowMap) {
+ // Display creation is driven by DisplayWindowController via ActivityStackSupervisor.
+ // We skip those steps here.
+ return sWm.mRoot.createDisplayContent(display, dcw);
+ }
+ }
+
/** Creates a {@link com.android.server.wm.WindowTestUtils.TestWindowState} */
WindowTestUtils.TestWindowState createWindowState(WindowManager.LayoutParams attrs,
WindowToken token) {