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

Commit 799700f6 authored by Riddle Hsu's avatar Riddle Hsu Committed by android-build-merger
Browse files

Merge "Add support to preload recents activity in background" into qt-r1-dev am: 6a6d1c38

am: da7d338b

Change-Id: I25955d55a6936b64d591a660e42a9c196232cb5d
parents b397107e da7d338b
Loading
Loading
Loading
Loading
+8 −14
Original line number Diff line number Diff line
@@ -3160,7 +3160,7 @@ final class ActivityRecord extends ConfigurationContainer {

    boolean ensureActivityConfiguration(int globalChanges, boolean preserveWindow) {
        return ensureActivityConfiguration(globalChanges, preserveWindow,
                false /* ignoreStopState */);
                false /* ignoreVisibility */);
    }

    /**
@@ -3170,15 +3170,15 @@ final class ActivityRecord extends ConfigurationContainer {
     * @param globalChanges The changes to the global configuration.
     * @param preserveWindow If the activity window should be preserved on screen if the activity
     *                       is relaunched.
     * @param ignoreStopState If we should try to relaunch the activity even if it is in the stopped
     *                        state. This is useful for the case where we know the activity will be
     *                        visible soon and we want to ensure its configuration before we make it
     *                        visible.
     * @param ignoreVisibility If we should try to relaunch the activity even if it is invisible
     *                         (stopped state). This is useful for the case where we know the
     *                         activity will be visible soon and we want to ensure its configuration
     *                         before we make it visible.
     * @return False if the activity was relaunched and true if it wasn't relaunched because we
     *         can't or the app handles the specific configuration that is changing.
     */
    boolean ensureActivityConfiguration(int globalChanges, boolean preserveWindow,
            boolean ignoreStopState) {
            boolean ignoreVisibility) {
        final ActivityStack stack = getActivityStack();
        if (stack.mConfigWillChange) {
            if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION,
@@ -3194,15 +3194,9 @@ final class ActivityRecord extends ConfigurationContainer {
            return true;
        }

        if (!ignoreStopState && (mState == STOPPING || mState == STOPPED)) {
        if (!ignoreVisibility && (mState == STOPPING || mState == STOPPED || !shouldBeVisible())) {
            if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION,
                    "Skipping config check stopped or stopping: " + this);
            return true;
        }

        if (!shouldBeVisible()) {
            if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION,
                    "Skipping config check invisible stack: " + this);
                    "Skipping config check invisible: " + this);
            return true;
        }

+8 −5
Original line number Diff line number Diff line
@@ -1880,8 +1880,7 @@ class ActivityStack extends ConfigurationContainer {
        mRootActivityContainer.ensureActivitiesVisible(resuming, 0, !PRESERVE_WINDOWS);
    }

    private void addToStopping(ActivityRecord r, boolean scheduleIdle, boolean idleDelayed,
            String reason) {
    void addToStopping(ActivityRecord r, boolean scheduleIdle, boolean idleDelayed, String reason) {
        if (!mStackSupervisor.mStoppingActivities.contains(r)) {
            EventLog.writeEvent(EventLogTags.AM_ADD_TO_STOPPING, r.mUserId,
                    System.identityHashCode(r), r.shortComponentName, reason);
@@ -2176,7 +2175,7 @@ class ActivityStack extends ConfigurationContainer {
                        // sure it matches the current configuration.
                        if (r != starting && notifyClients) {
                            r.ensureActivityConfiguration(0 /* globalChanges */, preserveWindows,
                                    true /* ignoreStopState */);
                                    true /* ignoreVisibility */);
                        }

                        if (!r.attachedToProcess()) {
@@ -3145,8 +3144,10 @@ class ActivityStack extends ConfigurationContainer {
            boolean newTask, boolean keepCurTransition, ActivityOptions options) {
        TaskRecord rTask = r.getTaskRecord();
        final int taskId = rTask.taskId;
        final boolean allowMoveToFront = options == null || !options.getAvoidMoveToFront();
        // mLaunchTaskBehind tasks get placed at the back of the task stack.
        if (!r.mLaunchTaskBehind && (taskForIdLocked(taskId) == null || newTask)) {
        if (!r.mLaunchTaskBehind && allowMoveToFront
                && (taskForIdLocked(taskId) == null || newTask)) {
            // Last activity in task had been removed or ActivityManagerService is reusing task.
            // Insert or replace.
            // Might not even be in.
@@ -3205,7 +3206,9 @@ class ActivityStack extends ConfigurationContainer {

        task.setFrontOfTask();

        if (!isHomeOrRecentsStack() || numActivities() > 0) {
        // The transition animation and starting window are not needed if {@code allowMoveToFront}
        // is false, because the activity won't be visible.
        if ((!isHomeOrRecentsStack() || numActivities() > 0) && allowMoveToFront) {
            final DisplayContent dc = getDisplay().mDisplayContent;
            if (DEBUG_TRANSITION) Slog.v(TAG_TRANSITION,
                    "Prepare open transition: starting " + r);
+2 −2
Original line number Diff line number Diff line
@@ -2307,12 +2307,12 @@ class ActivityStarter {
        // isLockTaskModeViolation fails below.

        if (mReuseTask == null) {
            final boolean toTop = !mLaunchTaskBehind && !mAvoidMoveToFront;
            final TaskRecord task = mTargetStack.createTaskRecord(
                    mSupervisor.getNextTaskIdForUserLocked(mStartActivity.mUserId),
                    mNewTaskInfo != null ? mNewTaskInfo : mStartActivity.info,
                    mNewTaskIntent != null ? mNewTaskIntent : mIntent, mVoiceSession,
                    mVoiceInteractor, !mLaunchTaskBehind /* toTop */, mStartActivity, mSourceRecord,
                    mOptions);
                    mVoiceInteractor, toTop, mStartActivity, mSourceRecord, mOptions);
            addOrReparentStartingActivity(task, "setTaskFromReuseOrCreateNewTask - mReuseTask");
            updateBounds(mStartActivity.getTaskRecord(), mLaunchParams.mBounds);

+15 −5
Original line number Diff line number Diff line
@@ -1447,9 +1447,15 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
                .execute();
    }

    /**
     * Start the recents activity to perform the recents animation.
     *
     * @param intent The intent to start the recents activity.
     * @param recentsAnimationRunner Pass {@code null} to only preload the activity.
     */
    @Override
    public void startRecentsActivity(Intent intent, IAssistDataReceiver assistDataReceiver,
            IRecentsAnimationRunner recentsAnimationRunner) {
    public void startRecentsActivity(Intent intent, @Deprecated IAssistDataReceiver unused,
            @Nullable IRecentsAnimationRunner recentsAnimationRunner) {
        enforceCallerIsRecentsOrHasPermission(MANAGE_ACTIVITY_STACKS, "startRecentsActivity()");
        final int callingPid = Binder.getCallingPid();
        final long origId = Binder.clearCallingIdentity();
@@ -1460,9 +1466,13 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {

                // Start a new recents animation
                final RecentsAnimation anim = new RecentsAnimation(this, mStackSupervisor,
                        getActivityStartController(), mWindowManager, callingPid);
                anim.startRecentsActivity(intent, recentsAnimationRunner, recentsComponent,
                        recentsUid, assistDataReceiver);
                        getActivityStartController(), mWindowManager, intent, recentsComponent,
                        recentsUid, callingPid);
                if (recentsAnimationRunner == null) {
                    anim.preloadRecentsActivity();
                } else {
                    anim.startRecentsActivity(recentsAnimationRunner);
                }
            }
        } finally {
            Binder.restoreCallingIdentity(origId);
+98 −33
Original line number Diff line number Diff line
@@ -34,7 +34,6 @@ import static com.android.server.wm.RecentsAnimationController.REORDER_MOVE_TO_T
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_RECENTS_ANIMATIONS;

import android.app.ActivityOptions;
import android.app.IAssistDataReceiver;
import android.content.ComponentName;
import android.content.Intent;
import android.os.RemoteException;
@@ -58,7 +57,12 @@ class RecentsAnimation implements RecentsAnimationCallbacks,
    private final ActivityStartController mActivityStartController;
    private final WindowManagerService mWindowManager;
    private final ActivityDisplay mDefaultDisplay;
    private final Intent mTargetIntent;
    private final ComponentName mRecentsComponent;
    private final int mRecentsUid;
    private final int mCallingPid;
    private final int mUserId;
    private final int mTargetActivityType;

    /**
     * The activity which has been launched behind. We need to remember the activity because the
@@ -66,27 +70,90 @@ class RecentsAnimation implements RecentsAnimationCallbacks,
     * for the exact activity.
     */
    private ActivityRecord mLaunchedTargetActivity;
    private int mTargetActivityType;

    // The stack to restore the target stack behind when the animation is finished
    private ActivityStack mRestoreTargetBehindStack;

    RecentsAnimation(ActivityTaskManagerService atm, ActivityStackSupervisor stackSupervisor,
            ActivityStartController activityStartController, WindowManagerService wm,
            int callingPid) {
            Intent targetIntent, ComponentName recentsComponent, int recentsUid, int callingPid) {
        mService = atm;
        mStackSupervisor = stackSupervisor;
        mDefaultDisplay = mService.mRootActivityContainer.getDefaultDisplay();
        mActivityStartController = activityStartController;
        mWindowManager = wm;
        mTargetIntent = targetIntent;
        mRecentsComponent = recentsComponent;
        mRecentsUid = recentsUid;
        mCallingPid = callingPid;
        mUserId = atm.getCurrentUserId();
        mTargetActivityType = targetIntent.getComponent() != null
                && recentsComponent.equals(targetIntent.getComponent())
                        ? ACTIVITY_TYPE_RECENTS
                        : ACTIVITY_TYPE_HOME;
    }

    /**
     * Starts the recents activity in background without animation if the record doesn't exist or
     * the client isn't launched. If the recents activity is already alive, ensure its configuration
     * is updated to the current one.
     */
    void preloadRecentsActivity() {
        if (DEBUG) Slog.d(TAG, "Preload recents with " + mTargetIntent);
        ActivityStack targetStack = mDefaultDisplay.getStack(WINDOWING_MODE_UNDEFINED,
                mTargetActivityType);
        ActivityRecord targetActivity = getTargetActivity(targetStack);
        if (targetActivity != null) {
            if (targetActivity.visible || targetActivity.isTopRunningActivity()) {
                // The activity is ready.
                return;
            }
            if (targetActivity.attachedToProcess()) {
                // The activity may be relaunched if it cannot handle the current configuration
                // changes. The activity will be paused state if it is relaunched, otherwise it
                // keeps the original stopped state.
                targetActivity.ensureActivityConfiguration(0 /* globalChanges */,
                        false /* preserveWindow */, true /* ignoreVisibility */);
                if (DEBUG) Slog.d(TAG, "Updated config=" + targetActivity.getConfiguration());
            }
        } else {
            // Create the activity record. Because the activity is invisible, this doesn't really
            // start the client.
            startRecentsActivityInBackground("preloadRecents");
            targetStack = mDefaultDisplay.getStack(WINDOWING_MODE_UNDEFINED, mTargetActivityType);
            targetActivity = getTargetActivity(targetStack);
            if (targetActivity == null) {
                Slog.w(TAG, "Cannot start " + mTargetIntent);
                return;
            }
        }

        if (!targetActivity.attachedToProcess()) {
            if (DEBUG) Slog.d(TAG, "Real start recents");
            mStackSupervisor.startSpecificActivityLocked(targetActivity, false /* andResume */,
                    false /* checkConfig */);
            // Make sure the activity won't be involved in transition.
            if (targetActivity.mAppWindowToken != null) {
                targetActivity.mAppWindowToken.getDisplayContent().mUnknownAppVisibilityController
                        .appRemovedOrHidden(targetActivity.mAppWindowToken);
            }
        }

    void startRecentsActivity(Intent intent, IRecentsAnimationRunner recentsAnimationRunner,
            ComponentName recentsComponent, int recentsUid,
            @Deprecated IAssistDataReceiver assistDataReceiver) {
        if (DEBUG) Slog.d(TAG, "startRecentsActivity(): intent=" + intent
                + " assistDataReceiver=" + assistDataReceiver);
        // Invisible activity should be stopped. If the recents activity is alive and its doesn't
        // need to relaunch by current configuration, then it may be already in stopped state.
        if (!targetActivity.isState(ActivityStack.ActivityState.STOPPING,
                ActivityStack.ActivityState.STOPPED)) {
            // Add to stopping instead of stop immediately. So the client has the chance to perform
            // traversal in non-stopped state (ViewRootImpl.mStopped) that would initialize more
            // things (e.g. the measure can be done earlier). The actual stop will be performed when
            // it reports idle.
            targetStack.addToStopping(targetActivity, true /* scheduleIdle */,
                    true /* idleDelayed */, "preloadRecents");
        }
    }

    void startRecentsActivity(IRecentsAnimationRunner recentsAnimationRunner) {
        if (DEBUG) Slog.d(TAG, "startRecentsActivity(): intent=" + mTargetIntent);
        Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "RecentsAnimation#startRecentsActivity");

        // TODO(multi-display) currently only support recents animation in default display.
@@ -100,15 +167,9 @@ class RecentsAnimation implements RecentsAnimationCallbacks,
        }

        // If the activity is associated with the recents stack, then try and get that first
        final int userId = mService.getCurrentUserId();
        mTargetActivityType = intent.getComponent() != null
                && recentsComponent.equals(intent.getComponent())
                        ? ACTIVITY_TYPE_RECENTS
                        : ACTIVITY_TYPE_HOME;
        ActivityStack targetStack = mDefaultDisplay.getStack(WINDOWING_MODE_UNDEFINED,
                mTargetActivityType);
        ActivityRecord targetActivity = getTargetActivity(targetStack, intent.getComponent(),
                userId);
        ActivityRecord targetActivity = getTargetActivity(targetStack);
        final boolean hasExistingActivity = targetActivity != null;
        if (hasExistingActivity) {
            final ActivityDisplay display = targetActivity.getDisplay();
@@ -127,7 +188,7 @@ class RecentsAnimation implements RecentsAnimationCallbacks,
                    true /* forceSend */, targetActivity);
        }

        mStackSupervisor.getActivityMetricsLogger().notifyActivityLaunching(intent);
        mStackSupervisor.getActivityMetricsLogger().notifyActivityLaunching(mTargetIntent);

        mService.mH.post(() -> mService.mAmInternal.setRunningRemoteAnimation(mCallingPid, true));

@@ -148,23 +209,12 @@ class RecentsAnimation implements RecentsAnimationCallbacks,
                }
            } else {
                // No recents activity, create the new recents activity bottom most
                ActivityOptions options = ActivityOptions.makeBasic();
                options.setLaunchActivityType(mTargetActivityType);
                options.setAvoidMoveToFront();
                intent.addFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_NO_ANIMATION);

                mActivityStartController
                        .obtainStarter(intent, "startRecentsActivity_noTargetActivity")
                        .setCallingUid(recentsUid)
                        .setCallingPackage(recentsComponent.getPackageName())
                        .setActivityOptions(SafeActivityOptions.fromBundle(options.toBundle()))
                        .setMayWait(userId)
                        .execute();
                startRecentsActivityInBackground("startRecentsActivity_noTargetActivity");

                // Move the recents activity into place for the animation
                targetStack = mDefaultDisplay.getStack(WINDOWING_MODE_UNDEFINED,
                        mTargetActivityType);
                targetActivity = getTargetActivity(targetStack, intent.getComponent(), userId);
                targetActivity = getTargetActivity(targetStack);
                mDefaultDisplay.moveStackBehindBottomMostVisibleStack(targetStack);
                if (DEBUG) {
                    Slog.d(TAG, "Moved stack=" + targetStack + " behind stack="
@@ -176,7 +226,7 @@ class RecentsAnimation implements RecentsAnimationCallbacks,

                // TODO: Maybe wait for app to draw in this particular case?

                if (DEBUG) Slog.d(TAG, "Started intent=" + intent);
                if (DEBUG) Slog.d(TAG, "Started intent=" + mTargetIntent);
            }

            // Mark the target activity as launch-behind to bump its visibility for the
@@ -383,6 +433,21 @@ class RecentsAnimation implements RecentsAnimationCallbacks,
        }
    }

    private void startRecentsActivityInBackground(String reason) {
        final ActivityOptions options = ActivityOptions.makeBasic();
        options.setLaunchActivityType(mTargetActivityType);
        options.setAvoidMoveToFront();
        mTargetIntent.addFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_NO_ANIMATION);

        mActivityStartController
                .obtainStarter(mTargetIntent, reason)
                .setCallingUid(mRecentsUid)
                .setCallingPackage(mRecentsComponent.getPackageName())
                .setActivityOptions(new SafeActivityOptions(options))
                .setMayWait(mUserId)
                .execute();
    }

    /**
     * Called only when the animation should be canceled prior to starting.
     */
@@ -412,15 +477,15 @@ class RecentsAnimation implements RecentsAnimationCallbacks,
     * @return the top activity in the {@param targetStack} matching the {@param component}, or just
     * the top activity of the top task if no task matches the component.
     */
    private ActivityRecord getTargetActivity(ActivityStack targetStack, ComponentName component,
            int userId) {
    private ActivityRecord getTargetActivity(ActivityStack targetStack) {
        if (targetStack == null) {
            return null;
        }

        for (int i = targetStack.getChildCount() - 1; i >= 0; i--) {
            final TaskRecord task = targetStack.getChildAt(i);
            if (task.userId == userId && task.getBaseIntent().getComponent().equals(component)) {
            if (task.userId == mUserId
                    && task.getBaseIntent().getComponent().equals(mTargetIntent.getComponent())) {
                return task.getTopActivity();
            }
        }
Loading