Deferring add splash screen window when launch with startActivities
There should only need to create one splash screen window for the top activity when launch with startActivities, but there would create starting window for each activities and make extra calls to WMShell, which is not necessary, so we can queueing the status and activities while startActivities, and use the status to create a starting window to the top-most activity. This also fix the other limitation that ActivityOptions can only apply to the top activity. Bug: 194367428 Bug: 203497083 Test: atest ActivityRecordTests ActivityStarterTests Test: atest SplashscreenTests Test: verify launch app with startActivities and WMShell should only receive one addStartingWindow request. Change-Id: I759da20e585f54a6e86e20153c2b4aa35017c1f6
This commit is contained in:
@@ -2134,7 +2134,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
|
||||
return activityInfo != null ? activityInfo.applicationInfo : null;
|
||||
});
|
||||
|
||||
final int typeParameter = mWmService.mStartingSurfaceController
|
||||
final int typeParameter = StartingSurfaceController
|
||||
.makeStartingWindowTypeParameter(newTask, taskSwitch, processRunning,
|
||||
allowTaskSnapshot, activityCreated, useEmpty, useLegacy, activityAllDrawn);
|
||||
|
||||
@@ -6617,13 +6617,20 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
|
||||
return splashScreenThemeResId;
|
||||
}
|
||||
|
||||
void showStartingWindow(ActivityRecord prev, boolean newTask, boolean taskSwitch,
|
||||
boolean startActivity, ActivityRecord sourceRecord) {
|
||||
showStartingWindow(prev, newTask, taskSwitch, isProcessRunning(), startActivity,
|
||||
sourceRecord);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param prev Previous activity which contains a starting window.
|
||||
* @param processRunning Whether the client process is running.
|
||||
* @param startActivity Whether this activity is just created from starter.
|
||||
* @param sourceRecord The source activity which start this activity.
|
||||
*/
|
||||
void showStartingWindow(ActivityRecord prev, boolean newTask, boolean taskSwitch,
|
||||
boolean startActivity, ActivityRecord sourceRecord) {
|
||||
boolean processRunning, boolean startActivity, ActivityRecord sourceRecord) {
|
||||
if (mTaskOverlay) {
|
||||
// We don't show starting window for overlay activities.
|
||||
return;
|
||||
@@ -6648,7 +6655,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
|
||||
&& task.getActivity((r) -> !r.finishing && r != this) == null;
|
||||
|
||||
final boolean scheduled = addStartingWindow(packageName, resolvedTheme,
|
||||
prev, newTask || newSingleActivity, taskSwitch, isProcessRunning(),
|
||||
prev, newTask || newSingleActivity, taskSwitch, processRunning,
|
||||
allowTaskSnapshot(), activityCreated, mSplashScreenStyleEmpty, allDrawn);
|
||||
if (DEBUG_STARTING_WINDOW_VERBOSE && scheduled) {
|
||||
Slog.d(TAG, "Scheduled starting window for " + this);
|
||||
|
||||
@@ -455,6 +455,10 @@ public class ActivityStartController {
|
||||
// Lock the loop to ensure the activities launched in a sequence.
|
||||
synchronized (mService.mGlobalLock) {
|
||||
mService.deferWindowLayout();
|
||||
// To avoid creating multiple starting window when creating starting multiples
|
||||
// activities, we defer the creation of the starting window once all start request
|
||||
// are processed
|
||||
mService.mWindowManager.mStartingSurfaceController.beginDeferAddStartingWindow();
|
||||
try {
|
||||
for (int i = 0; i < starters.length; i++) {
|
||||
final int startResult = starters[i].setResultTo(resultTo)
|
||||
@@ -480,6 +484,7 @@ public class ActivityStartController {
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
mService.mWindowManager.mStartingSurfaceController.endDeferAddStartingWindow();
|
||||
mService.continueWindowLayout();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,6 +34,7 @@ import android.content.pm.ApplicationInfo;
|
||||
import android.util.Slog;
|
||||
import android.window.TaskSnapshot;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
/**
|
||||
@@ -45,6 +46,14 @@ public class StartingSurfaceController {
|
||||
private final WindowManagerService mService;
|
||||
private final SplashScreenExceptionList mSplashScreenExceptionsList;
|
||||
|
||||
// Cache status while deferring add starting window
|
||||
boolean mInitProcessRunning;
|
||||
boolean mInitNewTask;
|
||||
boolean mInitTaskSwitch;
|
||||
private final ArrayList<DeferringStartingWindowRecord> mDeferringAddStartActivities =
|
||||
new ArrayList<>();
|
||||
private boolean mDeferringAddStartingWindow;
|
||||
|
||||
public StartingSurfaceController(WindowManagerService wm) {
|
||||
mService = wm;
|
||||
mSplashScreenExceptionsList = new SplashScreenExceptionList(wm.mContext.getMainExecutor());
|
||||
@@ -70,7 +79,7 @@ public class StartingSurfaceController {
|
||||
return mSplashScreenExceptionsList.isException(packageName, targetSdk, infoProvider);
|
||||
}
|
||||
|
||||
int makeStartingWindowTypeParameter(boolean newTask, boolean taskSwitch,
|
||||
static int makeStartingWindowTypeParameter(boolean newTask, boolean taskSwitch,
|
||||
boolean processRunning, boolean allowTaskSnapshot, boolean activityCreated,
|
||||
boolean useEmpty, boolean useLegacy, boolean activityDrawn) {
|
||||
int parameter = 0;
|
||||
@@ -142,6 +151,82 @@ public class StartingSurfaceController {
|
||||
}
|
||||
}
|
||||
|
||||
private static final class DeferringStartingWindowRecord {
|
||||
final ActivityRecord mDeferring;
|
||||
final ActivityRecord mPrev;
|
||||
final ActivityRecord mSource;
|
||||
|
||||
DeferringStartingWindowRecord(ActivityRecord deferring, ActivityRecord prev,
|
||||
ActivityRecord source) {
|
||||
mDeferring = deferring;
|
||||
mPrev = prev;
|
||||
mSource = source;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows a starting window while starting a new activity. Do not use this method to create a
|
||||
* starting window for an existing activity.
|
||||
*/
|
||||
void showStartingWindow(ActivityRecord target, ActivityRecord prev,
|
||||
boolean newTask, boolean isTaskSwitch, ActivityRecord source) {
|
||||
if (mDeferringAddStartingWindow) {
|
||||
addDeferringRecord(target, prev, newTask, isTaskSwitch, source);
|
||||
} else {
|
||||
target.showStartingWindow(prev, newTask, isTaskSwitch, true /* startActivity */,
|
||||
source);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Queueing the starting activity status while deferring add starting window.
|
||||
* @see Task#startActivityLocked
|
||||
*/
|
||||
private void addDeferringRecord(ActivityRecord deferring, ActivityRecord prev,
|
||||
boolean newTask, boolean isTaskSwitch, ActivityRecord source) {
|
||||
// Set newTask, taskSwitch, processRunning form first activity because those can change
|
||||
// after first activity started.
|
||||
if (mDeferringAddStartActivities.isEmpty()) {
|
||||
mInitProcessRunning = deferring.isProcessRunning();
|
||||
mInitNewTask = newTask;
|
||||
mInitTaskSwitch = isTaskSwitch;
|
||||
}
|
||||
mDeferringAddStartActivities.add(new DeferringStartingWindowRecord(
|
||||
deferring, prev, source));
|
||||
}
|
||||
|
||||
private void showStartingWindowFromDeferringActivities() {
|
||||
// Attempt to add starting window from the top-most activity.
|
||||
for (int i = mDeferringAddStartActivities.size() - 1; i >= 0; --i) {
|
||||
final DeferringStartingWindowRecord next = mDeferringAddStartActivities.get(i);
|
||||
next.mDeferring.showStartingWindow(next.mPrev, mInitNewTask, mInitTaskSwitch,
|
||||
mInitProcessRunning, true /* startActivity */, next.mSource);
|
||||
// If one succeeds, it is done.
|
||||
if (next.mDeferring.mStartingData != null) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
mDeferringAddStartActivities.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* Begin deferring add starting window in one pass.
|
||||
* This is used to deferring add starting window while starting multiples activities because
|
||||
* system only need to provide a starting window to the top-visible activity.
|
||||
* Most call {@link #endDeferAddStartingWindow} when starting activities process finished.
|
||||
* @see #endDeferAddStartingWindow()
|
||||
*/
|
||||
void beginDeferAddStartingWindow() {
|
||||
mDeferringAddStartingWindow = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* End deferring add starting window.
|
||||
*/
|
||||
void endDeferAddStartingWindow() {
|
||||
mDeferringAddStartingWindow = false;
|
||||
showStartingWindowFromDeferringActivities();
|
||||
}
|
||||
|
||||
final class StartingSurface {
|
||||
private final Task mTask;
|
||||
|
||||
@@ -5151,8 +5151,8 @@ class Task extends TaskFragment {
|
||||
|
||||
final ActivityRecord prev = baseTask.getActivity(
|
||||
a -> a.mStartingData != null && a.showToCurrentUser());
|
||||
r.showStartingWindow(prev, newTask, isTaskSwitch,
|
||||
true /* startActivity */, sourceRecord);
|
||||
mWmService.mStartingSurfaceController.showStartingWindow(r, prev, newTask,
|
||||
isTaskSwitch, sourceRecord);
|
||||
}
|
||||
} else {
|
||||
// If this is the first activity, don't do any fancy animations,
|
||||
|
||||
Reference in New Issue
Block a user