From a95bd4a83cabc12ecfe5e11f9d7848eee3f12ad4 Mon Sep 17 00:00:00 2001 From: Riddle Hsu Date: Wed, 27 Apr 2022 17:17:04 +0800 Subject: [PATCH] Attempt to use snapshot starting window for task trampoline When launching a singleTask activity, it may find an existing task to add. If the app uses it as trampoline/splash activity (finished after redirecting to main), then it will still be created every time. For example: (A and B are in the same task) First launch: Launch A from launcher, A starts B, A finished. Second launch: Launch A from launcher, A finished, resume B. Because it satisfies task-switch and activity-creation, by default there will be a splash screen activity. But because the new activity will finish itself immediately, it may be weird to see the splash screen starting window at the second launch. This approach infers that if the launching activity is the one that started the task with other existing activities, it is usually a temporal trampoline activity. So if the original top activity of the task matches the existing snapshot, then use snapshot starting window to make the visual result more continuous. Bug: 229959739 Test: Second launch an app which declares singleTask for its trampoline and main activity. There should not show a splash screen starting window. Change-Id: Ib0a39545e5b354fdb61d1cc0cb259900dba35a12 --- .../java/com/android/server/wm/ActivityRecord.java | 12 ++++++++++++ .../android/server/wm/StartingSurfaceController.java | 10 +++++----- services/core/java/com/android/server/wm/Task.java | 12 ++++++++---- 3 files changed, 25 insertions(+), 9 deletions(-) diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java index b6a1784839dee..50a09a307de61 100644 --- a/services/core/java/com/android/server/wm/ActivityRecord.java +++ b/services/core/java/com/android/server/wm/ActivityRecord.java @@ -2436,6 +2436,18 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A private int getStartingWindowType(boolean newTask, boolean taskSwitch, boolean processRunning, boolean allowTaskSnapshot, boolean activityCreated, boolean activityAllDrawn, TaskSnapshot snapshot) { + // A special case that a new activity is launching to an existing task which is moving to + // front. If the launching activity is the one that started the task, it could be a + // trampoline that will be always created and finished immediately. Then give a chance to + // see if the snapshot is usable for the current running activity so the transition will + // look smoother, instead of showing a splash screen on the second launch. + if (!newTask && taskSwitch && processRunning && !activityCreated && task.intent != null + && mActivityComponent.equals(task.intent.getComponent())) { + final ActivityRecord topAttached = task.getActivity(ActivityRecord::attachedToProcess); + if (topAttached != null && topAttached.isSnapshotCompatible(snapshot)) { + return STARTING_WINDOW_TYPE_SNAPSHOT; + } + } final boolean isActivityHome = isActivityTypeHome(); if ((newTask || !processRunning || (taskSwitch && !activityCreated)) && !isActivityHome) { diff --git a/services/core/java/com/android/server/wm/StartingSurfaceController.java b/services/core/java/com/android/server/wm/StartingSurfaceController.java index 813e06fecf486..ccd018faf075d 100644 --- a/services/core/java/com/android/server/wm/StartingSurfaceController.java +++ b/services/core/java/com/android/server/wm/StartingSurfaceController.java @@ -26,6 +26,7 @@ import static android.window.StartingWindowInfo.TYPE_PARAMETER_PROCESS_RUNNING; import static android.window.StartingWindowInfo.TYPE_PARAMETER_TASK_SWITCH; import static android.window.StartingWindowInfo.TYPE_PARAMETER_USE_SOLID_COLOR_SPLASH_SCREEN; +import static com.android.server.wm.ActivityRecord.STARTING_WINDOW_TYPE_SNAPSHOT; import static com.android.server.wm.ActivityRecord.STARTING_WINDOW_TYPE_SPLASH_SCREEN; import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME; import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; @@ -114,7 +115,7 @@ public class StartingSurfaceController { if (allowTaskSnapshot) { parameter |= TYPE_PARAMETER_ALLOW_TASK_SNAPSHOT; } - if (activityCreated) { + if (activityCreated || startingWindowType == STARTING_WINDOW_TYPE_SNAPSHOT) { parameter |= TYPE_PARAMETER_ACTIVITY_CREATED; } if (isSolidColor) { @@ -138,7 +139,6 @@ public class StartingSurfaceController { final WindowState topFullscreenOpaqueWindow; final Task task; synchronized (mService.mGlobalLock) { - final WindowState mainWindow = activity.findMainWindow(); task = activity.getTask(); if (task == null) { Slog.w(TAG, "TaskSnapshotSurface.create: Failed to find task for activity=" @@ -153,9 +153,9 @@ public class StartingSurfaceController { return null; } topFullscreenOpaqueWindow = topFullscreenActivity.getTopFullscreenOpaqueWindow(); - if (mainWindow == null || topFullscreenOpaqueWindow == null) { - Slog.w(TAG, "TaskSnapshotSurface.create: Failed to find main window for activity=" - + activity); + if (topFullscreenOpaqueWindow == null) { + Slog.w(TAG, "TaskSnapshotSurface.create: no opaque window in " + + topFullscreenActivity); return null; } if (topFullscreenActivity.getWindowConfiguration().getRotation() diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java index f97f768872fdd..0a3ce7497e23a 100644 --- a/services/core/java/com/android/server/wm/Task.java +++ b/services/core/java/com/android/server/wm/Task.java @@ -56,6 +56,7 @@ import static android.view.SurfaceControl.METADATA_TASK_ID; import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS; import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES; import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING; +import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION; import static android.view.WindowManager.TRANSIT_CHANGE; import static android.view.WindowManager.TRANSIT_CLOSE; import static android.view.WindowManager.TRANSIT_FLAG_APP_CRASHED; @@ -3525,10 +3526,13 @@ class Task extends TaskFragment { mAtmService.mKeyguardController.isDisplayOccluded(DEFAULT_DISPLAY); info.startingWindowTypeParameter = activity.mStartingData.mTypeParams; - final WindowState mainWindow = activity.findMainWindow(); - if (mainWindow != null) { - info.mainWindowLayoutParams = mainWindow.getAttrs(); - info.requestedVisibilities.set(mainWindow.getRequestedVisibilities()); + if ((info.startingWindowTypeParameter + & StartingWindowInfo.TYPE_PARAMETER_ACTIVITY_CREATED) != 0) { + final WindowState topMainWin = getWindow(w -> w.mAttrs.type == TYPE_BASE_APPLICATION); + if (topMainWin != null) { + info.mainWindowLayoutParams = topMainWin.getAttrs(); + info.requestedVisibilities.set(topMainWin.getRequestedVisibilities()); + } } // If the developer has persist a different configuration, we need to override it to the // starting window because persisted configuration does not effect to Task.