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

Commit 7e3fb8e7 authored by Xu Cao's avatar Xu Cao
Browse files

Launch all activities into the same display

When multiple activities are launched through a PendingIntent, all
activities need to be launched onto the same display. To ensure that,
all display-related information from the passed-in
SafeActivityOptions object are used to create a new
SafeActivityOptions object for bottom activities.

Bug: 225102873
Bug: 215308769

Test: atest
StartActivitiesTest#testStartActivities_shouldLaunchOnSameDisplay

Change-Id: Ie42913194847578972320a135ee753bffaa3f27d
parent de5f0ae8
Loading
Loading
Loading
Loading
+9 −1
Original line number Diff line number Diff line
@@ -384,6 +384,14 @@ public class ActivityStartController {
                callingUid, realCallingUid, UserHandle.USER_NULL);
        final SparseArray<String> startingUidPkgs = new SparseArray<>();
        final long origId = Binder.clearCallingIdentity();

        SafeActivityOptions bottomOptions = null;
        if (options != null) {
            // To ensure the first N-1 activities (N == total # of activities) are also launched
            // into the correct display, use a copy of the passed-in options (keeping only
            // display-related info) for these activities.
            bottomOptions = options.selectiveCloneDisplayOptions();
        }
        try {
            intents = ArrayUtils.filterNotNull(intents, Intent[]::new);
            final ActivityStarter[] starters = new ActivityStarter[intents.length];
@@ -432,7 +440,7 @@ public class ActivityStartController {
                final boolean top = i == intents.length - 1;
                final SafeActivityOptions checkedOptions = top
                        ? options
                        : null;
                        : bottomOptions;
                starters[i] = obtainStarter(intent, reason)
                        .setIntentGrants(intentGrants)
                        .setCaller(caller)
+28 −0
Original line number Diff line number Diff line
@@ -115,6 +115,34 @@ public class SafeActivityOptions {
        mOriginalOptions = options;
    }

    /**
     * To ensure that two activities, one using this object, and the other using the
     * SafeActivityOptions returned from this function, are launched into the same display through
     * ActivityStartController#startActivities, all display-related information, i.e.
     * displayAreaToken, launchDisplayId and callerDisplayId, are cloned.
     */
    @Nullable SafeActivityOptions selectiveCloneDisplayOptions() {
        final ActivityOptions options = cloneLaunchingDisplayOptions(mOriginalOptions);
        final ActivityOptions callerOptions = cloneLaunchingDisplayOptions(mCallerOptions);
        if (options == null && callerOptions == null) {
            return null;
        }

        final SafeActivityOptions safeOptions = new SafeActivityOptions(options,
                mOriginalCallingPid, mOriginalCallingUid);
        safeOptions.mCallerOptions = callerOptions;
        safeOptions.mRealCallingPid = mRealCallingPid;
        safeOptions.mRealCallingUid = mRealCallingUid;
        return safeOptions;
    }

    private ActivityOptions cloneLaunchingDisplayOptions(ActivityOptions options) {
        return options == null ? null : ActivityOptions.makeBasic()
                .setLaunchTaskDisplayArea(options.getLaunchTaskDisplayArea())
                .setLaunchDisplayId(options.getLaunchDisplayId())
                .setCallerDisplayId((options.getCallerDisplayId()));
    }

    /**
     * Overrides options with options from a caller and records {@link Binder#getCallingPid}/
     * {@link Binder#getCallingUid}. Thus, calling identity MUST NOT be cleared when calling this
+20 −0
Original line number Diff line number Diff line
@@ -17,9 +17,12 @@
package com.android.server.wm;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertSame;
import static org.mockito.Mockito.mock;

import android.app.ActivityOptions;
import android.platform.test.annotations.Presubmit;
import android.window.WindowContainerToken;

import androidx.test.filters.MediumTest;

@@ -43,4 +46,21 @@ public class SafeActivityOptionsTest {
        final ActivityOptions result = options.mergeActivityOptions(opts1, opts2);
        assertEquals(6, result.getLaunchDisplayId());
    }

    @Test
    public void test_selectiveCloneDisplayOptions() {
        final WindowContainerToken token = mock(WindowContainerToken.class);
        final int launchDisplayId = 5;
        final int callerDisplayId = 6;

        final SafeActivityOptions clone = new SafeActivityOptions(ActivityOptions.makeBasic()
                .setLaunchTaskDisplayArea(token)
                .setLaunchDisplayId(launchDisplayId)
                .setCallerDisplayId(callerDisplayId))
                .selectiveCloneDisplayOptions();

        assertSame(clone.getOriginalOptions().getLaunchTaskDisplayArea(), token);
        assertEquals(clone.getOriginalOptions().getLaunchDisplayId(), launchDisplayId);
        assertEquals(clone.getOriginalOptions().getCallerDisplayId(), callerDisplayId);
    }
}