Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 0b9d5851 authored by Riddle Hsu's avatar Riddle Hsu Committed by Automerger Merge Worker
Browse files

Merge "Associate starting window in task fragment with base task" into sc-v2-dev am: 25f50a91

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/15371455

Change-Id: I813776a9f0e4b0ebf6fcb6a0cf5c515cf0e8cf37
parents 15d4c60b 25f50a91
Loading
Loading
Loading
Loading
+79 −29
Original line number Diff line number Diff line
@@ -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;
@@ -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;
@@ -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);
@@ -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);
@@ -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) {
@@ -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.
@@ -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;
        }

@@ -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;
    }
@@ -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;
@@ -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.
@@ -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
@@ -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;
@@ -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();
@@ -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() {
@@ -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.
@@ -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;
@@ -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();
    }

@@ -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);
+6 −0
Original line number Diff line number Diff line
@@ -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;
+18 −22
Original line number Diff line number Diff line
@@ -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;
@@ -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;
@@ -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;

@@ -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,
@@ -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);
            }
+22 −0
Original line number Diff line number Diff line
@@ -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;
@@ -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;
@@ -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}.
+23 −0
Original line number Diff line number Diff line
@@ -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