Loading services/core/java/com/android/server/wm/ActivityRecord.java +79 −29 Original line number Diff line number Diff line Loading @@ -330,8 +330,6 @@ import com.android.internal.policy.AttributeCache; import com.android.internal.protolog.common.ProtoLog; import com.android.internal.util.ToBooleanFunction; import com.android.internal.util.XmlUtils; import com.android.internal.util.function.pooled.PooledFunction; import com.android.internal.util.function.pooled.PooledLambda; import com.android.server.LocalServices; import com.android.server.am.AppTimeTracker; import com.android.server.am.PendingIntentRecord; Loading Loading @@ -746,6 +744,13 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A boolean startingDisplayed; boolean startingMoved; /** * 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; Loading Loading @@ -1085,6 +1090,9 @@ 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) { pw.print(prefix); pw.print("startingWindow="); pw.print(mStartingWindow); Loading Loading @@ -1379,9 +1387,11 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A } @Override void onParentChanged(ConfigurationContainer newParent, ConfigurationContainer oldParent) { final Task oldTask = oldParent != null ? ((TaskFragment) oldParent).getTask() : null; final Task newTask = newParent != null ? ((TaskFragment) newParent).getTask() : null; void onParentChanged(ConfigurationContainer rawNewParent, ConfigurationContainer rawOldParent) { final TaskFragment oldParent = (TaskFragment) rawOldParent; final TaskFragment newParent = (TaskFragment) rawNewParent; final Task oldTask = oldParent != null ? oldParent.getTask() : null; final Task newTask = newParent != null ? newParent.getTask() : null; this.task = newTask; super.onParentChanged(newParent, oldParent); Loading Loading @@ -1440,11 +1450,18 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A updateColorTransform(); if (oldParent != null) { ((TaskFragment) oldParent).cleanUpActivityReferences(this); oldParent.cleanUpActivityReferences(this); } if (newParent != null && isState(RESUMED)) { ((TaskFragment) newParent).setResumedActivity(this, "onParentChanged"); newParent.setResumedActivity(this, "onParentChanged"); if (mStartingWindow != null && mStartingData != null && mStartingData.mAssociatedTask == null && newParent.isEmbedded()) { // The starting window should keep covering its task when the activity is // reparented to a task fragment that may not fill the task bounds. associateStartingDataWithTask(); overrideConfigurationPropagation(mStartingWindow, task); } } if (rootTask != null && rootTask.topRunningActivity() == this) { Loading Loading @@ -2005,7 +2022,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A @VisibleForTesting boolean addStartingWindow(String pkg, int resolvedTheme, CompatibilityInfo compatInfo, CharSequence nonLocalizedLabel, int labelRes, int icon, int logo, int windowFlags, IBinder transferFrom, boolean newTask, boolean taskSwitch, boolean processRunning, ActivityRecord from, boolean newTask, boolean taskSwitch, boolean processRunning, boolean allowTaskSnapshot, boolean activityCreated, boolean useEmpty) { // If the display is frozen, we won't do anything until the actual window is // displayed so there is no reason to put in the starting window. Loading Loading @@ -2064,7 +2081,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A } applyStartingWindowTheme(pkg, resolvedTheme); if (transferStartingWindow(transferFrom)) { if (from != null && transferStartingWindow(from)) { return true; } Loading @@ -2089,6 +2106,11 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A ProtoLog.v(WM_DEBUG_STARTING_WINDOW, "Creating SnapshotStartingData"); mStartingData = new SnapshotStartingData(mWmService, snapshot, typeParams); if (task.forAllLeafTaskFragments(TaskFragment::isEmbedded)) { // Associate with the task so if this activity is resized by task fragment later, the // starting window can keep the same bounds as the task. associateStartingDataWithTask(); } scheduleAddStartingWindow(); return true; } Loading Loading @@ -2337,6 +2359,23 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A } } void attachStartingWindow(@NonNull WindowState startingWindow) { mStartingWindow = startingWindow; if (mStartingData != null && mStartingData.mAssociatedTask != null) { // Associate the configuration of starting window with the task. overrideConfigurationPropagation(startingWindow, mStartingData.mAssociatedTask); } } private void associateStartingDataWithTask() { mStartingData.mAssociatedTask = task; task.forAllActivities(r -> { if (r.mVisibleRequested && !r.firstWindowDrawn) { r.mSharedStartingData = mStartingData; } }); } void removeStartingWindow() { if (transferSplashScreenIfNeeded()) { return; Loading @@ -2346,6 +2385,11 @@ 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 (mStartingWindow == null) { if (mStartingData != null) { // Starting window has not been added yet, but it is scheduled to be added. Loading Loading @@ -3864,12 +3908,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A } } boolean transferStartingWindow(IBinder transferFrom) { final ActivityRecord fromActivity = getDisplayContent().getActivityRecord(transferFrom); if (fromActivity == null) { return false; } private boolean transferStartingWindow(@NonNull ActivityRecord fromActivity) { final WindowState tStartingWindow = fromActivity.mStartingWindow; if (tStartingWindow != null && fromActivity.mStartingSurface != null) { // In this case, the starting icon has already been displayed, so start Loading @@ -3890,6 +3929,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; Loading Loading @@ -3952,6 +3992,7 @@ 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(); Loading @@ -3970,16 +4011,10 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A * immediately finishes after, so we have to transfer T to M. */ void transferStartingWindowFromHiddenAboveTokenIfNeeded() { final PooledFunction p = PooledLambda.obtainFunction(ActivityRecord::transferStartingWindow, this, PooledLambda.__(ActivityRecord.class)); task.forAllActivities(p); p.recycle(); } private boolean transferStartingWindow(ActivityRecord fromActivity) { task.forAllActivities(fromActivity -> { if (fromActivity == this) return true; return !fromActivity.mVisibleRequested && transferStartingWindow(fromActivity.token); return !fromActivity.mVisibleRequested && transferStartingWindow(fromActivity); }); } void checkKeyguardFlagsChanged() { Loading Loading @@ -5160,6 +5195,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A void notifyAppStopped() { ProtoLog.v(WM_DEBUG_ADD_REMOVE, "notifyAppStopped: %s", this); mAppStopped = true; firstWindowDrawn = false; // This is to fix the edge case that auto-enter-pip is finished in Launcher but app calls // setAutoEnterEnabled(false) and transitions to STOPPED state, see b/191930787. // Clear any surface transactions and content overlay in this case. Loading Loading @@ -5923,7 +5959,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A } } void onFirstWindowDrawn(WindowState win, WindowStateAnimator winAnimator) { void onFirstWindowDrawn(WindowState win) { firstWindowDrawn = true; // stop tracking mSplashScreenStyleEmpty = true; Loading @@ -5939,7 +5975,22 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A // own stuff. win.cancelAnimation(); } // 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; if (associatedTask == null) { removeStartingWindow(); } 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) { r.removeStartingWindow(); } } updateReportedVisibilityLocked(); } Loading Loading @@ -6510,8 +6561,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A final boolean scheduled = addStartingWindow(packageName, resolvedTheme, compatInfo, nonLocalizedLabel, labelRes, icon, logo, windowFlags, prev != null ? prev.appToken : null, newTask || newSingleActivity, taskSwitch, isProcessRunning(), prev, newTask || newSingleActivity, taskSwitch, isProcessRunning(), allowTaskSnapshot(), activityCreated, mSplashScreenStyleEmpty); if (DEBUG_STARTING_WINDOW_VERBOSE && scheduled) { Slog.d(TAG, "Scheduled starting window for " + this); Loading services/core/java/com/android/server/wm/StartingData.java +6 −0 Original line number Diff line number Diff line Loading @@ -32,6 +32,12 @@ public abstract class StartingData { */ boolean mIsTransitionForward; /** * Non-null if the starting window should cover the bounds of associated task. It is assigned * when the parent activity of starting window may be put in a partial area of the task. */ Task mAssociatedTask; protected StartingData(WindowManagerService service, int typeParams) { mService = service; mTypeParams = typeParams; Loading services/core/java/com/android/server/wm/Task.java +18 −22 Original line number Diff line number Diff line Loading @@ -628,7 +628,7 @@ class Task extends TaskFragment { IVoiceInteractionSession _voiceSession, IVoiceInteractor _voiceInteractor, boolean _createdByOrganizer, IBinder _launchCookie, boolean _deferTaskAppear, boolean _removeWithTaskOrganizer) { super(atmService, null /* fragmentToken */, _createdByOrganizer); super(atmService, null /* fragmentToken */, _createdByOrganizer, false /* isEmbedded */); mTaskId = _taskId; mUserId = _userId; Loading Loading @@ -707,13 +707,13 @@ class Task extends TaskFragment { return this; } private void cleanUpResourcesForDestroy(ConfigurationContainer oldParent) { private void cleanUpResourcesForDestroy(WindowContainer<?> oldParent) { if (hasChild()) { return; } // This task is going away, so save the last state if necessary. saveLaunchingStateIfNeeded(((WindowContainer) oldParent).getDisplayContent()); saveLaunchingStateIfNeeded(oldParent.getDisplayContent()); // TODO: VI what about activity? final boolean isVoiceSession = voiceSession != null; Loading Loading @@ -1144,11 +1144,11 @@ class Task extends TaskFragment { } @Override void onParentChanged(ConfigurationContainer newParent, ConfigurationContainer oldParent) { final DisplayContent display = newParent != null ? ((WindowContainer) newParent).getDisplayContent() : null; final DisplayContent oldDisplay = oldParent != null ? ((WindowContainer) oldParent).getDisplayContent() : null; void onParentChanged(ConfigurationContainer rawNewParent, ConfigurationContainer rawOldParent) { final WindowContainer<?> newParent = (WindowContainer<?>) rawNewParent; final WindowContainer<?> oldParent = (WindowContainer<?>) rawOldParent; final DisplayContent display = newParent != null ? newParent.getDisplayContent() : null; final DisplayContent oldDisplay = oldParent != null ? oldParent.getDisplayContent() : null; mPrevDisplayId = (oldDisplay != null) ? oldDisplay.mDisplayId : INVALID_DISPLAY; Loading Loading @@ -1189,7 +1189,7 @@ class Task extends TaskFragment { } if (oldParent != null) { final Task oldParentTask = ((WindowContainer) oldParent).asTask(); final Task oldParentTask = oldParent.asTask(); if (oldParentTask != null) { final PooledConsumer c = PooledLambda.obtainConsumer( Task::cleanUpActivityReferences, oldParentTask, Loading Loading @@ -5164,21 +5164,17 @@ class Task extends TaskFragment { // "has the same starting icon" as the next one. This allows the // window manager to keep the previous window it had previously // created, if it still had one. Task prevTask = r.getTask(); ActivityRecord prev = prevTask.getActivity( a -> a.mStartingData != null && a.okToShowLocked()); if (prev != null) { // We don't want to reuse the previous starting preview if: // (1) The current activity is in a different task. if (prev.getTask() != prevTask) { prev = null; } // (2) The current activity is already displayed. else if (prev.nowVisible) { prev = null; } Task baseTask = r.getTask(); if (baseTask.isEmbedded()) { // If the task is embedded in a task fragment, there may have an existing // starting window in the parent task. This allows the embedded activities // to share the starting window and make sure that the window can have top // z-order by transferring to the top activity. baseTask = baseTask.getParent().asTaskFragment().getTask(); } final ActivityRecord prev = baseTask.getActivity( a -> a.mStartingData != null && a.okToShowLocked()); r.showStartingWindow(prev, newTask, isTaskSwitch, true /* startActivity */, sourceRecord); } Loading services/core/java/com/android/server/wm/TaskFragment.java +22 −0 Original line number Diff line number Diff line Loading @@ -207,6 +207,9 @@ class TaskFragment extends WindowContainer<WindowContainer> { @VisibleForTesting boolean mCreatedByOrganizer; /** Whether this TaskFragment is embedded in a task. */ private final boolean mIsEmbedded; /** Organizer that organizing this TaskFragment. */ @Nullable private ITaskFragmentOrganizer mTaskFragmentOrganizer; Loading Loading @@ -269,14 +272,21 @@ class TaskFragment extends WindowContainer<WindowContainer> { } } /** Creates an embedded task fragment. */ TaskFragment(ActivityTaskManagerService atmService, IBinder fragmentToken, boolean createdByOrganizer) { this(atmService, fragmentToken, createdByOrganizer, true /* isEmbedded */); } TaskFragment(ActivityTaskManagerService atmService, IBinder fragmentToken, boolean createdByOrganizer, boolean isEmbedded) { super(atmService.mWindowManager); mAtmService = atmService; mTaskSupervisor = mAtmService.mTaskSupervisor; mRootWindowContainer = mAtmService.mRootWindowContainer; mCreatedByOrganizer = createdByOrganizer; mIsEmbedded = isEmbedded; mTaskFragmentOrganizerController = mAtmService.mWindowOrganizerController.mTaskFragmentOrganizerController; mFragmentToken = fragmentToken; Loading Loading @@ -389,6 +399,18 @@ class TaskFragment extends WindowContainer<WindowContainer> { return this; } /** Returns {@code true} if this is a container for embedded activities or tasks. */ boolean isEmbedded() { if (mIsEmbedded) { return true; } final WindowContainer<?> parent = getParent(); if (parent != null) { final TaskFragment taskFragment = parent.asTaskFragment(); return taskFragment != null && taskFragment.isEmbedded(); } return false; } /** * Simply check and give warning logs if this is not operated on leaf {@link TaskFragment}. Loading services/core/java/com/android/server/wm/WindowContainer.java +23 −0 Original line number Diff line number Diff line Loading @@ -3399,6 +3399,29 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer< unregisterConfigurationChangeListener(listener); } /** * Forces the receiver container to always use the configuration of the supplier container as * its requested override configuration. It allows to propagate configuration without changing * the relationship between child and parent. */ static void overrideConfigurationPropagation(WindowContainer<?> receiver, WindowContainer<?> supplier) { final ConfigurationContainerListener listener = new ConfigurationContainerListener() { @Override public void onMergedOverrideConfigurationChanged(Configuration mergedOverrideConfig) { receiver.onRequestedOverrideConfigurationChanged(supplier.getConfiguration()); } }; supplier.registerConfigurationChangeListener(listener); receiver.registerWindowContainerListener(new WindowContainerListener() { @Override public void onRemoved() { receiver.unregisterWindowContainerListener(this); supplier.unregisterConfigurationChangeListener(listener); } }); } /** * Returns the {@link WindowManager.LayoutParams.WindowType}. */ Loading Loading
services/core/java/com/android/server/wm/ActivityRecord.java +79 −29 Original line number Diff line number Diff line Loading @@ -330,8 +330,6 @@ import com.android.internal.policy.AttributeCache; import com.android.internal.protolog.common.ProtoLog; import com.android.internal.util.ToBooleanFunction; import com.android.internal.util.XmlUtils; import com.android.internal.util.function.pooled.PooledFunction; import com.android.internal.util.function.pooled.PooledLambda; import com.android.server.LocalServices; import com.android.server.am.AppTimeTracker; import com.android.server.am.PendingIntentRecord; Loading Loading @@ -746,6 +744,13 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A boolean startingDisplayed; boolean startingMoved; /** * 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; Loading Loading @@ -1085,6 +1090,9 @@ 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) { pw.print(prefix); pw.print("startingWindow="); pw.print(mStartingWindow); Loading Loading @@ -1379,9 +1387,11 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A } @Override void onParentChanged(ConfigurationContainer newParent, ConfigurationContainer oldParent) { final Task oldTask = oldParent != null ? ((TaskFragment) oldParent).getTask() : null; final Task newTask = newParent != null ? ((TaskFragment) newParent).getTask() : null; void onParentChanged(ConfigurationContainer rawNewParent, ConfigurationContainer rawOldParent) { final TaskFragment oldParent = (TaskFragment) rawOldParent; final TaskFragment newParent = (TaskFragment) rawNewParent; final Task oldTask = oldParent != null ? oldParent.getTask() : null; final Task newTask = newParent != null ? newParent.getTask() : null; this.task = newTask; super.onParentChanged(newParent, oldParent); Loading Loading @@ -1440,11 +1450,18 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A updateColorTransform(); if (oldParent != null) { ((TaskFragment) oldParent).cleanUpActivityReferences(this); oldParent.cleanUpActivityReferences(this); } if (newParent != null && isState(RESUMED)) { ((TaskFragment) newParent).setResumedActivity(this, "onParentChanged"); newParent.setResumedActivity(this, "onParentChanged"); if (mStartingWindow != null && mStartingData != null && mStartingData.mAssociatedTask == null && newParent.isEmbedded()) { // The starting window should keep covering its task when the activity is // reparented to a task fragment that may not fill the task bounds. associateStartingDataWithTask(); overrideConfigurationPropagation(mStartingWindow, task); } } if (rootTask != null && rootTask.topRunningActivity() == this) { Loading Loading @@ -2005,7 +2022,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A @VisibleForTesting boolean addStartingWindow(String pkg, int resolvedTheme, CompatibilityInfo compatInfo, CharSequence nonLocalizedLabel, int labelRes, int icon, int logo, int windowFlags, IBinder transferFrom, boolean newTask, boolean taskSwitch, boolean processRunning, ActivityRecord from, boolean newTask, boolean taskSwitch, boolean processRunning, boolean allowTaskSnapshot, boolean activityCreated, boolean useEmpty) { // If the display is frozen, we won't do anything until the actual window is // displayed so there is no reason to put in the starting window. Loading Loading @@ -2064,7 +2081,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A } applyStartingWindowTheme(pkg, resolvedTheme); if (transferStartingWindow(transferFrom)) { if (from != null && transferStartingWindow(from)) { return true; } Loading @@ -2089,6 +2106,11 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A ProtoLog.v(WM_DEBUG_STARTING_WINDOW, "Creating SnapshotStartingData"); mStartingData = new SnapshotStartingData(mWmService, snapshot, typeParams); if (task.forAllLeafTaskFragments(TaskFragment::isEmbedded)) { // Associate with the task so if this activity is resized by task fragment later, the // starting window can keep the same bounds as the task. associateStartingDataWithTask(); } scheduleAddStartingWindow(); return true; } Loading Loading @@ -2337,6 +2359,23 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A } } void attachStartingWindow(@NonNull WindowState startingWindow) { mStartingWindow = startingWindow; if (mStartingData != null && mStartingData.mAssociatedTask != null) { // Associate the configuration of starting window with the task. overrideConfigurationPropagation(startingWindow, mStartingData.mAssociatedTask); } } private void associateStartingDataWithTask() { mStartingData.mAssociatedTask = task; task.forAllActivities(r -> { if (r.mVisibleRequested && !r.firstWindowDrawn) { r.mSharedStartingData = mStartingData; } }); } void removeStartingWindow() { if (transferSplashScreenIfNeeded()) { return; Loading @@ -2346,6 +2385,11 @@ 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 (mStartingWindow == null) { if (mStartingData != null) { // Starting window has not been added yet, but it is scheduled to be added. Loading Loading @@ -3864,12 +3908,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A } } boolean transferStartingWindow(IBinder transferFrom) { final ActivityRecord fromActivity = getDisplayContent().getActivityRecord(transferFrom); if (fromActivity == null) { return false; } private boolean transferStartingWindow(@NonNull ActivityRecord fromActivity) { final WindowState tStartingWindow = fromActivity.mStartingWindow; if (tStartingWindow != null && fromActivity.mStartingSurface != null) { // In this case, the starting icon has already been displayed, so start Loading @@ -3890,6 +3929,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; Loading Loading @@ -3952,6 +3992,7 @@ 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(); Loading @@ -3970,16 +4011,10 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A * immediately finishes after, so we have to transfer T to M. */ void transferStartingWindowFromHiddenAboveTokenIfNeeded() { final PooledFunction p = PooledLambda.obtainFunction(ActivityRecord::transferStartingWindow, this, PooledLambda.__(ActivityRecord.class)); task.forAllActivities(p); p.recycle(); } private boolean transferStartingWindow(ActivityRecord fromActivity) { task.forAllActivities(fromActivity -> { if (fromActivity == this) return true; return !fromActivity.mVisibleRequested && transferStartingWindow(fromActivity.token); return !fromActivity.mVisibleRequested && transferStartingWindow(fromActivity); }); } void checkKeyguardFlagsChanged() { Loading Loading @@ -5160,6 +5195,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A void notifyAppStopped() { ProtoLog.v(WM_DEBUG_ADD_REMOVE, "notifyAppStopped: %s", this); mAppStopped = true; firstWindowDrawn = false; // This is to fix the edge case that auto-enter-pip is finished in Launcher but app calls // setAutoEnterEnabled(false) and transitions to STOPPED state, see b/191930787. // Clear any surface transactions and content overlay in this case. Loading Loading @@ -5923,7 +5959,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A } } void onFirstWindowDrawn(WindowState win, WindowStateAnimator winAnimator) { void onFirstWindowDrawn(WindowState win) { firstWindowDrawn = true; // stop tracking mSplashScreenStyleEmpty = true; Loading @@ -5939,7 +5975,22 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A // own stuff. win.cancelAnimation(); } // 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; if (associatedTask == null) { removeStartingWindow(); } 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) { r.removeStartingWindow(); } } updateReportedVisibilityLocked(); } Loading Loading @@ -6510,8 +6561,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A final boolean scheduled = addStartingWindow(packageName, resolvedTheme, compatInfo, nonLocalizedLabel, labelRes, icon, logo, windowFlags, prev != null ? prev.appToken : null, newTask || newSingleActivity, taskSwitch, isProcessRunning(), prev, newTask || newSingleActivity, taskSwitch, isProcessRunning(), allowTaskSnapshot(), activityCreated, mSplashScreenStyleEmpty); if (DEBUG_STARTING_WINDOW_VERBOSE && scheduled) { Slog.d(TAG, "Scheduled starting window for " + this); Loading
services/core/java/com/android/server/wm/StartingData.java +6 −0 Original line number Diff line number Diff line Loading @@ -32,6 +32,12 @@ public abstract class StartingData { */ boolean mIsTransitionForward; /** * Non-null if the starting window should cover the bounds of associated task. It is assigned * when the parent activity of starting window may be put in a partial area of the task. */ Task mAssociatedTask; protected StartingData(WindowManagerService service, int typeParams) { mService = service; mTypeParams = typeParams; Loading
services/core/java/com/android/server/wm/Task.java +18 −22 Original line number Diff line number Diff line Loading @@ -628,7 +628,7 @@ class Task extends TaskFragment { IVoiceInteractionSession _voiceSession, IVoiceInteractor _voiceInteractor, boolean _createdByOrganizer, IBinder _launchCookie, boolean _deferTaskAppear, boolean _removeWithTaskOrganizer) { super(atmService, null /* fragmentToken */, _createdByOrganizer); super(atmService, null /* fragmentToken */, _createdByOrganizer, false /* isEmbedded */); mTaskId = _taskId; mUserId = _userId; Loading Loading @@ -707,13 +707,13 @@ class Task extends TaskFragment { return this; } private void cleanUpResourcesForDestroy(ConfigurationContainer oldParent) { private void cleanUpResourcesForDestroy(WindowContainer<?> oldParent) { if (hasChild()) { return; } // This task is going away, so save the last state if necessary. saveLaunchingStateIfNeeded(((WindowContainer) oldParent).getDisplayContent()); saveLaunchingStateIfNeeded(oldParent.getDisplayContent()); // TODO: VI what about activity? final boolean isVoiceSession = voiceSession != null; Loading Loading @@ -1144,11 +1144,11 @@ class Task extends TaskFragment { } @Override void onParentChanged(ConfigurationContainer newParent, ConfigurationContainer oldParent) { final DisplayContent display = newParent != null ? ((WindowContainer) newParent).getDisplayContent() : null; final DisplayContent oldDisplay = oldParent != null ? ((WindowContainer) oldParent).getDisplayContent() : null; void onParentChanged(ConfigurationContainer rawNewParent, ConfigurationContainer rawOldParent) { final WindowContainer<?> newParent = (WindowContainer<?>) rawNewParent; final WindowContainer<?> oldParent = (WindowContainer<?>) rawOldParent; final DisplayContent display = newParent != null ? newParent.getDisplayContent() : null; final DisplayContent oldDisplay = oldParent != null ? oldParent.getDisplayContent() : null; mPrevDisplayId = (oldDisplay != null) ? oldDisplay.mDisplayId : INVALID_DISPLAY; Loading Loading @@ -1189,7 +1189,7 @@ class Task extends TaskFragment { } if (oldParent != null) { final Task oldParentTask = ((WindowContainer) oldParent).asTask(); final Task oldParentTask = oldParent.asTask(); if (oldParentTask != null) { final PooledConsumer c = PooledLambda.obtainConsumer( Task::cleanUpActivityReferences, oldParentTask, Loading Loading @@ -5164,21 +5164,17 @@ class Task extends TaskFragment { // "has the same starting icon" as the next one. This allows the // window manager to keep the previous window it had previously // created, if it still had one. Task prevTask = r.getTask(); ActivityRecord prev = prevTask.getActivity( a -> a.mStartingData != null && a.okToShowLocked()); if (prev != null) { // We don't want to reuse the previous starting preview if: // (1) The current activity is in a different task. if (prev.getTask() != prevTask) { prev = null; } // (2) The current activity is already displayed. else if (prev.nowVisible) { prev = null; } Task baseTask = r.getTask(); if (baseTask.isEmbedded()) { // If the task is embedded in a task fragment, there may have an existing // starting window in the parent task. This allows the embedded activities // to share the starting window and make sure that the window can have top // z-order by transferring to the top activity. baseTask = baseTask.getParent().asTaskFragment().getTask(); } final ActivityRecord prev = baseTask.getActivity( a -> a.mStartingData != null && a.okToShowLocked()); r.showStartingWindow(prev, newTask, isTaskSwitch, true /* startActivity */, sourceRecord); } Loading
services/core/java/com/android/server/wm/TaskFragment.java +22 −0 Original line number Diff line number Diff line Loading @@ -207,6 +207,9 @@ class TaskFragment extends WindowContainer<WindowContainer> { @VisibleForTesting boolean mCreatedByOrganizer; /** Whether this TaskFragment is embedded in a task. */ private final boolean mIsEmbedded; /** Organizer that organizing this TaskFragment. */ @Nullable private ITaskFragmentOrganizer mTaskFragmentOrganizer; Loading Loading @@ -269,14 +272,21 @@ class TaskFragment extends WindowContainer<WindowContainer> { } } /** Creates an embedded task fragment. */ TaskFragment(ActivityTaskManagerService atmService, IBinder fragmentToken, boolean createdByOrganizer) { this(atmService, fragmentToken, createdByOrganizer, true /* isEmbedded */); } TaskFragment(ActivityTaskManagerService atmService, IBinder fragmentToken, boolean createdByOrganizer, boolean isEmbedded) { super(atmService.mWindowManager); mAtmService = atmService; mTaskSupervisor = mAtmService.mTaskSupervisor; mRootWindowContainer = mAtmService.mRootWindowContainer; mCreatedByOrganizer = createdByOrganizer; mIsEmbedded = isEmbedded; mTaskFragmentOrganizerController = mAtmService.mWindowOrganizerController.mTaskFragmentOrganizerController; mFragmentToken = fragmentToken; Loading Loading @@ -389,6 +399,18 @@ class TaskFragment extends WindowContainer<WindowContainer> { return this; } /** Returns {@code true} if this is a container for embedded activities or tasks. */ boolean isEmbedded() { if (mIsEmbedded) { return true; } final WindowContainer<?> parent = getParent(); if (parent != null) { final TaskFragment taskFragment = parent.asTaskFragment(); return taskFragment != null && taskFragment.isEmbedded(); } return false; } /** * Simply check and give warning logs if this is not operated on leaf {@link TaskFragment}. Loading
services/core/java/com/android/server/wm/WindowContainer.java +23 −0 Original line number Diff line number Diff line Loading @@ -3399,6 +3399,29 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer< unregisterConfigurationChangeListener(listener); } /** * Forces the receiver container to always use the configuration of the supplier container as * its requested override configuration. It allows to propagate configuration without changing * the relationship between child and parent. */ static void overrideConfigurationPropagation(WindowContainer<?> receiver, WindowContainer<?> supplier) { final ConfigurationContainerListener listener = new ConfigurationContainerListener() { @Override public void onMergedOverrideConfigurationChanged(Configuration mergedOverrideConfig) { receiver.onRequestedOverrideConfigurationChanged(supplier.getConfiguration()); } }; supplier.registerConfigurationChangeListener(listener); receiver.registerWindowContainerListener(new WindowContainerListener() { @Override public void onRemoved() { receiver.unregisterWindowContainerListener(this); supplier.unregisterConfigurationChangeListener(listener); } }); } /** * Returns the {@link WindowManager.LayoutParams.WindowType}. */ Loading