summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Riddle Hsu <riddlehsu@google.com> 2022-10-26 18:42:22 +0800
committer Riddle Hsu <riddlehsu@google.com> 2022-11-02 16:21:26 +0800
commit286bf02f2f93c28159c1317a4c65312e34fdb306 (patch)
tree8b928a106908dee235f0f7566b55e1e8b8e02c20
parent8a283d04f02dc11e41e795b50b194b3fc2f7f382 (diff)
Simplify the association of shared starting window
The issue case is launching an existing embedded activity with clear-task and then a new activity is started in a new task fragment. E.g. resume left panel -> finish right panel -> create right panel. And the transition starts until the right panel is drawn instead of the drawn starting window. That would feel a noticeable delay. This is mainly for showing starting window on a task with embedded activities, but also generalizes the common cases. 1. Move mSharedStartingData from ActivityRecord to Task. So if there is a new embedded activity launched in the task, it doesn't need to take care whether/when to assign the field. And no need to traverse all embedded activities in the task to make sure the shared starting data is up to date. 2. Move startingDisplayed from ActivityRecord to StartingData. The state of flag startingDisplayed is covered by the lifetime of StartingData. So it no longer needs to reset the flag. This also provides the ability to know whether the starting window is drawn or not without based on an activity or window. With above changes, any activity without owned starting window can know if the shared starting window is ready to execute transition. Also use a non-empty reference activity in createRemoteAnimationTarget, so the OPENING transition animation won't be skipped (the right panel is the top non-finishing activity but it hasn't a child window yet). Bug: 255688302 Test: atest ActivityRecordTests#testStartingWindowInTaskFragment Change-Id: I7adeed8801ea3a837afa3d46f1975cf6c5b3f99a
-rw-r--r--services/core/java/com/android/server/wm/ActivityRecord.java71
-rw-r--r--services/core/java/com/android/server/wm/AppTransitionController.java4
-rw-r--r--services/core/java/com/android/server/wm/StartingData.java3
-rw-r--r--services/core/java/com/android/server/wm/Task.java10
-rw-r--r--services/core/java/com/android/server/wm/TaskFragment.java8
-rw-r--r--services/core/java/com/android/server/wm/WindowState.java4
-rw-r--r--services/core/java/com/android/server/wm/WindowStateAnimator.java7
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java7
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java2
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java1
10 files changed, 55 insertions, 62 deletions
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 2eb2cf643c42..e86f34bb5d84 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -812,7 +812,6 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
StartingData mStartingData;
WindowState mStartingWindow;
StartingSurfaceController.StartingSurface mStartingSurface;
- boolean startingDisplayed;
boolean startingMoved;
/** The last set {@link DropInputMode} for this activity surface. */
@@ -821,13 +820,6 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
/** Whether the input to this activity will be dropped during the current playing animation. */
private boolean mIsInputDroppedForAnimation;
- /**
- * If it is non-null, it requires all activities who have the same starting data to be drawn
- * to remove the starting window.
- * TODO(b/189385912): Remove starting window related fields after migrating them to task.
- */
- private StartingData mSharedStartingData;
-
boolean mHandleExitSplashScreen;
@TransferSplashScreenState
int mTransferringSplashScreenState = TRANSFER_SPLASH_SCREEN_IDLE;
@@ -1200,14 +1192,11 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
pw.print(" firstWindowDrawn="); pw.print(firstWindowDrawn);
pw.print(" mIsExiting="); pw.println(mIsExiting);
}
- if (mSharedStartingData != null) {
- pw.println(prefix + "mSharedStartingData=" + mSharedStartingData);
- }
- if (mStartingWindow != null || mStartingSurface != null
- || startingDisplayed || startingMoved || mVisibleSetFromTransferredStartingWindow) {
+ if (mStartingWindow != null || mStartingData != null || mStartingSurface != null
+ || startingMoved || mVisibleSetFromTransferredStartingWindow) {
pw.print(prefix); pw.print("startingWindow="); pw.print(mStartingWindow);
pw.print(" startingSurface="); pw.print(mStartingSurface);
- pw.print(" startingDisplayed="); pw.print(startingDisplayed);
+ pw.print(" startingDisplayed="); pw.print(isStartingWindowDisplayed());
pw.print(" startingMoved="); pw.print(startingMoved);
pw.println(" mVisibleSetFromTransferredStartingWindow="
+ mVisibleSetFromTransferredStartingWindow);
@@ -2690,13 +2679,23 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
}
}
+ boolean isStartingWindowDisplayed() {
+ final StartingData data = mStartingData != null ? mStartingData : task != null
+ ? task.mSharedStartingData : null;
+ return data != null && data.mIsDisplayed;
+ }
+
/** Called when the starting window is added to this activity. */
void attachStartingWindow(@NonNull WindowState startingWindow) {
startingWindow.mStartingData = mStartingData;
mStartingWindow = startingWindow;
- // The snapshot type may have called associateStartingDataWithTask().
- if (mStartingData != null && mStartingData.mAssociatedTask != null) {
- attachStartingSurfaceToAssociatedTask();
+ if (mStartingData != null) {
+ if (mStartingData.mAssociatedTask != null) {
+ // The snapshot type may have called associateStartingDataWithTask().
+ attachStartingSurfaceToAssociatedTask();
+ } else if (isEmbedded()) {
+ associateStartingWindowWithTaskIfNeeded();
+ }
}
}
@@ -2711,11 +2710,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
/** Called when the starting window is not added yet but its data is known to fill the task. */
private void associateStartingDataWithTask() {
mStartingData.mAssociatedTask = task;
- task.forAllActivities(r -> {
- if (r.mVisibleRequested && !r.firstWindowDrawn) {
- r.mSharedStartingData = mStartingData;
- }
- });
+ task.mSharedStartingData = mStartingData;
}
/** Associates and attaches an added starting window to the current task. */
@@ -2746,10 +2741,8 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
void removeStartingWindowAnimation(boolean prepareAnimation) {
mTransferringSplashScreenState = TRANSFER_SPLASH_SCREEN_IDLE;
- if (mSharedStartingData != null) {
- mSharedStartingData.mAssociatedTask.forAllActivities(r -> {
- r.mSharedStartingData = null;
- });
+ if (task != null) {
+ task.mSharedStartingData = null;
}
if (mStartingWindow == null) {
if (mStartingData != null) {
@@ -2772,7 +2765,6 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
mStartingData = null;
mStartingSurface = null;
mStartingWindow = null;
- startingDisplayed = false;
if (surface == null) {
ProtoLog.v(WM_DEBUG_STARTING_WINDOW, "startingWindow was set but "
+ "startingSurface==null, couldn't remove");
@@ -4257,7 +4249,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
* @return {@code true} if starting window is in app's hierarchy.
*/
boolean hasStartingWindow() {
- if (startingDisplayed || mStartingData != null) {
+ if (mStartingData != null) {
return true;
}
for (int i = mChildren.size() - 1; i >= 0; i--) {
@@ -4355,10 +4347,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
// Transfer the starting window over to the new token.
mStartingData = fromActivity.mStartingData;
- mSharedStartingData = fromActivity.mSharedStartingData;
mStartingSurface = fromActivity.mStartingSurface;
- startingDisplayed = fromActivity.startingDisplayed;
- fromActivity.startingDisplayed = false;
mStartingWindow = tStartingWindow;
reportedVisible = fromActivity.reportedVisible;
fromActivity.mStartingData = null;
@@ -4424,7 +4413,6 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
ProtoLog.v(WM_DEBUG_STARTING_WINDOW,
"Moving pending starting from %s to %s", fromActivity, this);
mStartingData = fromActivity.mStartingData;
- mSharedStartingData = fromActivity.mSharedStartingData;
fromActivity.mStartingData = null;
fromActivity.startingMoved = true;
scheduleAddStartingWindow();
@@ -6534,14 +6522,11 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
// Remove starting window directly if is in a pure task. Otherwise if it is associated with
// a task (e.g. nested task fragment), then remove only if all visible windows in the task
// are drawn.
- final Task associatedTask =
- mSharedStartingData != null ? mSharedStartingData.mAssociatedTask : null;
+ final Task associatedTask = task.mSharedStartingData != null ? task : null;
if (associatedTask == null) {
removeStartingWindow();
- } else if (associatedTask.getActivity(r -> r.mVisibleRequested && !r.firstWindowDrawn
- // Don't block starting window removal if an Activity can't be a starting window
- // target.
- && r.mSharedStartingData != null) == null) {
+ } else if (associatedTask.getActivity(
+ r -> r.mVisibleRequested && !r.firstWindowDrawn) == null) {
// The last drawn activity may not be the one that owns the starting window.
final ActivityRecord r = associatedTask.topActivityContainsStartingWindow();
if (r != null) {
@@ -6756,7 +6741,6 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
if (mLastTransactionSequence != mWmService.mTransactionSequence) {
mLastTransactionSequence = mWmService.mTransactionSequence;
mNumDrawnWindows = 0;
- startingDisplayed = false;
// There is the main base application window, even if it is exiting, wait for it
mNumInterestingWindows = findMainWindow(false /* includeStartingApp */) != null ? 1 : 0;
@@ -6800,9 +6784,9 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
isInterestingAndDrawn = true;
}
}
- } else if (w.isDrawn()) {
+ } else if (mStartingData != null && w.isDrawn()) {
// The starting window for this container is drawn.
- startingDisplayed = true;
+ mStartingData.mIsDisplayed = true;
}
}
@@ -7550,7 +7534,8 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
ProtoLog.v(WM_DEBUG_ANIM, "Animation done in %s"
+ ": reportedVisible=%b okToDisplay=%b okToAnimate=%b startingDisplayed=%b",
- this, reportedVisible, okToDisplay(), okToAnimate(), startingDisplayed);
+ this, reportedVisible, okToDisplay(), okToAnimate(),
+ isStartingWindowDisplayed());
// clean up thumbnail window
if (mThumbnail != null) {
@@ -9649,7 +9634,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
if (mStartingWindow != null) {
mStartingWindow.writeIdentifierToProto(proto, STARTING_WINDOW);
}
- proto.write(STARTING_DISPLAYED, startingDisplayed);
+ proto.write(STARTING_DISPLAYED, isStartingWindowDisplayed());
proto.write(STARTING_MOVED, startingMoved);
proto.write(VISIBLE_SET_FROM_TRANSFERRED_STARTING_WINDOW,
mVisibleSetFromTransferredStartingWindow);
diff --git a/services/core/java/com/android/server/wm/AppTransitionController.java b/services/core/java/com/android/server/wm/AppTransitionController.java
index 9c95e31cc5f5..671524b39bc1 100644
--- a/services/core/java/com/android/server/wm/AppTransitionController.java
+++ b/services/core/java/com/android/server/wm/AppTransitionController.java
@@ -1229,11 +1229,11 @@ public class AppTransitionController {
ProtoLog.v(WM_DEBUG_APP_TRANSITIONS,
"Check opening app=%s: allDrawn=%b startingDisplayed=%b "
+ "startingMoved=%b isRelaunching()=%b startingWindow=%s",
- activity, activity.allDrawn, activity.startingDisplayed,
+ activity, activity.allDrawn, activity.isStartingWindowDisplayed(),
activity.startingMoved, activity.isRelaunching(),
activity.mStartingWindow);
final boolean allDrawn = activity.allDrawn && !activity.isRelaunching();
- if (!allDrawn && !activity.startingDisplayed && !activity.startingMoved) {
+ if (!allDrawn && !activity.isStartingWindowDisplayed() && !activity.startingMoved) {
return false;
}
if (allDrawn) {
diff --git a/services/core/java/com/android/server/wm/StartingData.java b/services/core/java/com/android/server/wm/StartingData.java
index fbee343f09b5..300a894d15c9 100644
--- a/services/core/java/com/android/server/wm/StartingData.java
+++ b/services/core/java/com/android/server/wm/StartingData.java
@@ -38,6 +38,9 @@ public abstract class StartingData {
*/
Task mAssociatedTask;
+ /** Whether the starting window is drawn. */
+ boolean mIsDisplayed;
+
protected StartingData(WindowManagerService service, int typeParams) {
mService = service;
mTypeParams = typeParams;
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index eba49bbc7301..66d7af9b4f6c 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -358,6 +358,13 @@ class Task extends TaskFragment {
int mLockTaskUid = -1; // The uid of the application that called startLockTask().
+ /**
+ * If non-null, the starting window should cover the associated task. It is assigned when the
+ * parent activity of starting window is put in a partial area of the task. This field will be
+ * cleared when all visible activities in this task are drawn.
+ */
+ StartingData mSharedStartingData;
+
/** The process that had previously hosted the root activity of this task.
* Used to know that we should try harder to keep this process around, in case the
* user wants to return to it. */
@@ -3688,6 +3695,9 @@ class Task extends TaskFragment {
if (mRootProcess != null) {
pw.print(prefix); pw.print("mRootProcess="); pw.println(mRootProcess);
}
+ if (mSharedStartingData != null) {
+ pw.println(prefix + "mSharedStartingData=" + mSharedStartingData);
+ }
pw.print(prefix); pw.print("taskId=" + mTaskId);
pw.println(" rootTaskId=" + getRootTaskId());
pw.print(prefix); pw.println("hasChildPipActivity=" + (mChildPipActivity != null));
diff --git a/services/core/java/com/android/server/wm/TaskFragment.java b/services/core/java/com/android/server/wm/TaskFragment.java
index d17867673474..879c7e2d75dc 100644
--- a/services/core/java/com/android/server/wm/TaskFragment.java
+++ b/services/core/java/com/android/server/wm/TaskFragment.java
@@ -1890,10 +1890,10 @@ class TaskFragment extends WindowContainer<WindowContainer> {
RemoteAnimationTarget createRemoteAnimationTarget(
RemoteAnimationController.RemoteAnimationRecord record) {
final ActivityRecord activity = record.getMode() == RemoteAnimationTarget.MODE_OPENING
- // There may be a trampoline activity without window on top of the existing task
- // which is moving to front. Exclude the finishing activity so the window of next
- // activity can be chosen to create the animation target.
- ? getTopNonFinishingActivity()
+ // There may be a launching (e.g. trampoline or embedded) activity without a window
+ // on top of the existing task which is moving to front. Exclude finishing activity
+ // so the window of next activity can be chosen to create the animation target.
+ ? getActivity(r -> !r.finishing && r.hasChild())
: getTopMostActivity();
return activity != null ? activity.createRemoteAnimationTarget(record) : null;
}
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index c161a9b26f59..1b5177154664 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -1842,8 +1842,8 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
* @return {@code true} if one or more windows have been displayed, else false.
*/
boolean hasAppShownWindows() {
- return mActivityRecord != null
- && (mActivityRecord.firstWindowDrawn || mActivityRecord.startingDisplayed);
+ return mActivityRecord != null && (mActivityRecord.firstWindowDrawn
+ || mActivityRecord.isStartingWindowDisplayed());
}
@Override
diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
index 5c0557f2d1f4..a82a8180259d 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -374,13 +374,6 @@ class WindowStateAnimator {
}
void destroySurfaceLocked(SurfaceControl.Transaction t) {
- final ActivityRecord activity = mWin.mActivityRecord;
- if (activity != null) {
- if (mWin == activity.mStartingWindow) {
- activity.startingDisplayed = false;
- }
- }
-
if (mSurfaceController == null) {
return;
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
index 462957a88a6c..8a0a4f7c82b7 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
@@ -2886,6 +2886,7 @@ public class ActivityRecordTests extends WindowTestsBase {
fragmentSetup.accept(taskFragment1, new Rect(0, 0, width / 2, height));
task.addChild(taskFragment1, POSITION_TOP);
assertEquals(task, activity1.mStartingData.mAssociatedTask);
+ assertEquals(activity1.mStartingData, task.mSharedStartingData);
final TaskFragment taskFragment2 = new TaskFragment(
mAtm, null /* fragmentToken */, false /* createdByOrganizer */);
@@ -2905,7 +2906,6 @@ public class ActivityRecordTests extends WindowTestsBase {
verify(activity1.getSyncTransaction()).reparent(eq(startingWindow.mSurfaceControl),
eq(task.mSurfaceControl));
- assertEquals(activity1.mStartingData, startingWindow.mStartingData);
assertEquals(task.mSurfaceControl, startingWindow.getAnimationLeashParent());
assertEquals(taskFragment1.getBounds(), activity1.getBounds());
// The activity was resized by task fragment, but starting window must still cover the task.
@@ -2916,6 +2916,7 @@ public class ActivityRecordTests extends WindowTestsBase {
activity1.onFirstWindowDrawn(activityWindow);
activity2.onFirstWindowDrawn(activityWindow);
assertNull(activity1.mStartingWindow);
+ assertNull(task.mSharedStartingData);
}
@Test
@@ -2991,10 +2992,10 @@ public class ActivityRecordTests extends WindowTestsBase {
final WindowManager.LayoutParams attrs =
new WindowManager.LayoutParams(TYPE_APPLICATION_STARTING);
final TestWindowState startingWindow = createWindowState(attrs, activity);
- activity.startingDisplayed = true;
+ activity.mStartingData = mock(StartingData.class);
activity.addWindow(startingWindow);
assertTrue("Starting window should be present", activity.hasStartingWindow());
- activity.startingDisplayed = false;
+ activity.mStartingData = null;
assertTrue("Starting window should be present", activity.hasStartingWindow());
activity.removeChild(startingWindow);
diff --git a/services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java
index 513791d2b8a5..0332c4b4597b 100644
--- a/services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java
@@ -1300,6 +1300,8 @@ public class AppTransitionControllerTest extends WindowTestsBase {
activity.allDrawn = true;
// Skip manipulate the SurfaceControl.
doNothing().when(activity).setDropInputMode(anyInt());
+ // Assume the activity contains a window.
+ doReturn(true).when(activity).hasChild();
// Make sure activity can create remote animation target.
doReturn(mock(RemoteAnimationTarget.class)).when(activity).createRemoteAnimationTarget(
any());
diff --git a/services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java b/services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java
index f61effa284ef..d55e53cca8a6 100644
--- a/services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java
@@ -321,7 +321,6 @@ public class AppTransitionTests extends WindowTestsBase {
final ActivityRecord activity2 = createActivityRecord(dc2);
activity1.allDrawn = true;
- activity1.startingDisplayed = true;
activity1.startingMoved = true;
// Simulate activity resume / finish flows to prepare app transition & set visibility,