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

Commit d58b2734 authored by Vladimir Komsiyski's avatar Vladimir Komsiyski Committed by Android (Google) Code Review
Browse files

Merge "Intercept HOME intents for secondary home displays." into main

parents 12666090 a4269d0b
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -2929,7 +2929,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
        reparent(newTaskFrag, position);
    }

    private boolean isHomeIntent(Intent intent) {
    static boolean isHomeIntent(Intent intent) {
        return ACTION_MAIN.equals(intent.getAction())
                && (intent.hasCategory(CATEGORY_HOME)
                || intent.hasCategory(CATEGORY_SECONDARY_HOME))
+59 −6
Original line number Diff line number Diff line
@@ -55,6 +55,7 @@ import android.os.IBinder;
import android.os.RemoteException;
import android.os.UserHandle;
import android.os.UserManager;
import android.util.Pair;
import android.util.SparseArray;

import com.android.internal.annotations.VisibleForTesting;
@@ -77,7 +78,6 @@ class ActivityStartInterceptor {

    private final ActivityTaskManagerService mService;
    private final ActivityTaskSupervisor mSupervisor;
    private final RootWindowContainer mRootWindowContainer;
    private final Context mServiceContext;

    // UserManager cannot be final as it's not ready when this class is instantiated during boot
@@ -110,17 +110,23 @@ class ActivityStartInterceptor {
    TaskFragment mInTaskFragment;
    ActivityOptions mActivityOptions;

    /*
     * Note that this is just a hint of what the launch display area will be as it is
     * based only on the information at the early pre-interception stage of starting the
     * intent. The real launch display area calculated later may be different from this one.
     */
    TaskDisplayArea mPresumableLaunchDisplayArea;

    ActivityStartInterceptor(
            ActivityTaskManagerService service, ActivityTaskSupervisor supervisor) {
        this(service, supervisor, service.mRootWindowContainer, service.mContext);
        this(service, supervisor, service.mContext);
    }

    @VisibleForTesting
    ActivityStartInterceptor(ActivityTaskManagerService service, ActivityTaskSupervisor supervisor,
            RootWindowContainer root, Context context) {
            Context context) {
        mService = service;
        mSupervisor = supervisor;
        mRootWindowContainer = root;
        mServiceContext = context;
    }

@@ -162,7 +168,7 @@ class ActivityStartInterceptor {
    /**
     * A helper function to obtain the targeted {@link TaskFragment} during
     * {@link #intercept(Intent, ResolveInfo, ActivityInfo, String, Task, TaskFragment, int, int,
     * ActivityOptions)} if any.
     * ActivityOptions, TaskDisplayArea)} if any.
     */
    @Nullable
    private TaskFragment getLaunchTaskFragment() {
@@ -187,7 +193,7 @@ class ActivityStartInterceptor {
     */
    boolean intercept(Intent intent, ResolveInfo rInfo, ActivityInfo aInfo, String resolvedType,
            Task inTask, TaskFragment inTaskFragment, int callingPid, int callingUid,
            ActivityOptions activityOptions) {
            ActivityOptions activityOptions, TaskDisplayArea presumableLaunchDisplayArea) {
        mUserManager = UserManager.get(mServiceContext);

        mIntent = intent;
@@ -199,6 +205,7 @@ class ActivityStartInterceptor {
        mInTask = inTask;
        mInTaskFragment = inTaskFragment;
        mActivityOptions = activityOptions;
        mPresumableLaunchDisplayArea = presumableLaunchDisplayArea;

        if (interceptQuietProfileIfNeeded()) {
            // If work profile is turned off, skip the work challenge since the profile can only
@@ -221,6 +228,11 @@ class ActivityStartInterceptor {
        if (interceptLockedManagedProfileIfNeeded()) {
            return true;
        }
        if (interceptHomeIfNeeded()) {
            // Replace primary home intents directed at displays that do not support primary home
            // but support secondary home with the relevant secondary home activity.
            return true;
        }

        final SparseArray<ActivityInterceptorCallback> callbacks =
                mService.getActivityInterceptorCallbacks();
@@ -470,6 +482,47 @@ class ActivityStartInterceptor {
        return true;
    }

    private boolean interceptHomeIfNeeded() {
        if (mPresumableLaunchDisplayArea == null || mService.mRootWindowContainer == null) {
            return false;
        }
        if (!ActivityRecord.isHomeIntent(mIntent)) {
            return false;
        }
        if (!mIntent.hasCategory(Intent.CATEGORY_HOME)) {
            // Already a secondary home intent, leave it alone.
            return false;
        }
        if (mService.mRootWindowContainer.shouldPlacePrimaryHomeOnDisplay(
                mPresumableLaunchDisplayArea.getDisplayId())) {
            // Primary home can be launched to the display area.
            return false;
        }
        if (!mService.mRootWindowContainer.shouldPlaceSecondaryHomeOnDisplayArea(
                mPresumableLaunchDisplayArea)) {
            // Secondary home cannot be launched on the display area.
            return false;
        }

        // At this point we have a primary home intent for a display that does not support primary
        // home activity but it supports secondary home one. So replace it with secondary home.
        Pair<ActivityInfo, Intent> info = mService.mRootWindowContainer
                .resolveSecondaryHomeActivity(mUserId, mPresumableLaunchDisplayArea);
        mIntent = info.second;
        // The new task flag is needed because the home activity should already be in the root task
        // and should not be moved to the caller's task. Also, activities cannot change their type,
        // e.g. a standard activity cannot become a home activity.
        mIntent.addFlags(FLAG_ACTIVITY_NEW_TASK);
        mCallingPid = mRealCallingPid;
        mCallingUid = mRealCallingUid;
        mResolvedType = null;

        mRInfo = mSupervisor.resolveIntent(mIntent, mResolvedType, mUserId, /* flags= */ 0,
                mRealCallingUid, mRealCallingPid);
        mAInfo = mSupervisor.resolveActivity(mIntent, mRInfo, mStartFlags, /*profilerInfo=*/ null);
        return true;
    }

    private boolean isPackageSuspended() {
        return mAInfo != null && mAInfo.applicationInfo != null
                && (mAInfo.applicationInfo.flags & FLAG_SUSPENDED) != 0;
+12 −1
Original line number Diff line number Diff line
@@ -1154,10 +1154,12 @@ class ActivityStarter {
            }
        }

        final TaskDisplayArea suggestedLaunchDisplayArea =
                computeSuggestedLaunchDisplayArea(inTask, sourceRecord, checkedOptions);
        mInterceptor.setStates(userId, realCallingPid, realCallingUid, startFlags, callingPackage,
                callingFeatureId);
        if (mInterceptor.intercept(intent, rInfo, aInfo, resolvedType, inTask, inTaskFragment,
                callingPid, callingUid, checkedOptions)) {
                callingPid, callingUid, checkedOptions, suggestedLaunchDisplayArea)) {
            // activity start was intercepted, e.g. because the target user is currently in quiet
            // mode (turn off work) or the target application is suspended
            intent = mInterceptor.mIntent;
@@ -1890,6 +1892,15 @@ class ActivityStarter {
        mPreferredWindowingMode = mLaunchParams.mWindowingMode;
    }

    private TaskDisplayArea computeSuggestedLaunchDisplayArea(
            Task task, ActivityRecord source, ActivityOptions options) {
        mSupervisor.getLaunchParamsController().calculate(task, /*layout=*/null,
                /*activity=*/ null, source, options, mRequest, PHASE_DISPLAY, mLaunchParams);
        return mLaunchParams.hasPreferredTaskDisplayArea()
                ? mLaunchParams.mPreferredTaskDisplayArea
                : mRootWindowContainer.getDefaultTaskDisplayArea();
    }

    @VisibleForTesting
    int isAllowedToStart(ActivityRecord r, boolean newTask, Task targetTask) {
        if (r.packageName == null) {
+14 −4
Original line number Diff line number Diff line
@@ -1607,6 +1607,19 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
                false /* allowInstrumenting */, false /* fromHomeKey */);
    }

    /**
     * Check if the display is valid for primary home activity.
     *
     * @param displayId The target display ID
     * @return {@code true} if allowed to launch, {@code false} otherwise.
     */
    boolean shouldPlacePrimaryHomeOnDisplay(int displayId) {
        // No restrictions to default display, vr 2d display or main display for visible users.
        return displayId == DEFAULT_DISPLAY || (displayId != INVALID_DISPLAY
                && (displayId == mService.mVr2dDisplayId
                || mWmService.shouldPlacePrimaryHomeOnDisplay(displayId)));
    }

    /**
     * Check if the display area is valid for secondary home activity.
     *
@@ -1680,10 +1693,7 @@ class RootWindowContainer extends WindowContainer<DisplayContent>

        final int displayId = taskDisplayArea != null ? taskDisplayArea.getDisplayId()
                : INVALID_DISPLAY;
        if (displayId == DEFAULT_DISPLAY || (displayId != INVALID_DISPLAY
                && (displayId == mService.mVr2dDisplayId
                || mWmService.shouldPlacePrimaryHomeOnDisplay(displayId)))) {
            // No restrictions to default display, vr 2d display or main display for visible users.
        if (shouldPlacePrimaryHomeOnDisplay(displayId)) {
            return true;
        }

+57 −30
Original line number Diff line number Diff line
@@ -118,12 +118,14 @@ class TaskLaunchParamsModifier implements LaunchParamsModifier {
            root = activity;
        }

        if (root == null) {
        if (root == null && phase != PHASE_DISPLAY) {
            // There is a case that can lead us here. The caller is moving the top activity that is
            // in a task that has multiple activities to PIP mode. For that the caller is creating a
            // new task to host the activity so that we only move the top activity to PIP mode and
            // keep other activities in the previous task. There is no point to apply the launch
            // logic in this case.
            // However, for PHASE_DISPLAY the root may be null, but we still want to get a hint of
            // what the suggested launch display area would be.
            return RESULT_SKIP;
        }

@@ -395,8 +397,9 @@ class TaskLaunchParamsModifier implements LaunchParamsModifier {
    }

    private TaskDisplayArea getPreferredLaunchTaskDisplayArea(@Nullable Task task,
            @Nullable ActivityOptions options, ActivityRecord source, LaunchParams currentParams,
            @NonNull ActivityRecord activityRecord, @Nullable Request request) {
            @Nullable ActivityOptions options, @Nullable ActivityRecord source,
            @Nullable LaunchParams currentParams, @Nullable ActivityRecord activityRecord,
            @Nullable Request request) {
        TaskDisplayArea taskDisplayArea = null;

        final WindowContainerToken optionLaunchTaskDisplayAreaToken = options != null
@@ -438,8 +441,7 @@ class TaskLaunchParamsModifier implements LaunchParamsModifier {

        // If the source activity is a no-display activity, pass on the launch display area token
        // from source activity as currently preferred.
        if (taskDisplayArea == null && source != null
                && source.noDisplay) {
        if (taskDisplayArea == null && source != null && source.noDisplay) {
            taskDisplayArea = source.mHandoverTaskDisplayArea;
            if (taskDisplayArea != null) {
                if (DEBUG) appendLog("display-area-from-no-display-source=" + taskDisplayArea);
@@ -478,21 +480,24 @@ class TaskLaunchParamsModifier implements LaunchParamsModifier {
            }
        }

        if (taskDisplayArea == null) {
        if (taskDisplayArea == null && currentParams != null) {
            taskDisplayArea = currentParams.mPreferredTaskDisplayArea;
            if (DEBUG) appendLog("display-area-from-current-params=" + taskDisplayArea);
        }

        // Re-route to default display if the device didn't declare support for multi-display
        if (taskDisplayArea != null && !mSupervisor.mService.mSupportsMultiDisplay
                && taskDisplayArea.getDisplayId() != DEFAULT_DISPLAY) {
            taskDisplayArea = mSupervisor.mRootWindowContainer.getDefaultTaskDisplayArea();
            if (DEBUG) appendLog("display-area-from-no-multidisplay=" + taskDisplayArea);
        }

        // Re-route to default display if the home activity doesn't support multi-display
        if (taskDisplayArea != null && activityRecord.isActivityTypeHome()
        if (taskDisplayArea != null && activityRecord != null && activityRecord.isActivityTypeHome()
                && !mSupervisor.mRootWindowContainer.canStartHomeOnDisplayArea(activityRecord.info,
                        taskDisplayArea, false /* allowInstrumenting */)) {
            taskDisplayArea = mSupervisor.mRootWindowContainer.getDefaultTaskDisplayArea();
            if (DEBUG) appendLog("display-area-from-home=" + taskDisplayArea);
        }

        return (taskDisplayArea != null)
@@ -516,34 +521,56 @@ class TaskLaunchParamsModifier implements LaunchParamsModifier {
     * @return {@link TaskDisplayArea} to house the task
     */
    private TaskDisplayArea getFallbackDisplayAreaForActivity(
            @NonNull ActivityRecord activityRecord, @Nullable Request request) {

        WindowProcessController controllerFromLaunchingRecord = mSupervisor.mService
                .getProcessController(activityRecord.launchedFromPid,
                        activityRecord.launchedFromUid);
        final TaskDisplayArea displayAreaForLaunchingRecord = controllerFromLaunchingRecord == null
                ? null : controllerFromLaunchingRecord.getTopActivityDisplayArea();
        if (displayAreaForLaunchingRecord != null) {
            return displayAreaForLaunchingRecord;
            @Nullable ActivityRecord activityRecord, @Nullable Request request) {
        if (activityRecord != null) {
            WindowProcessController controllerFromLaunchingRecord =
                    mSupervisor.mService.getProcessController(
                            activityRecord.launchedFromPid, activityRecord.launchedFromUid);
            if (controllerFromLaunchingRecord != null) {
                final TaskDisplayArea taskDisplayAreaForLaunchingRecord =
                        controllerFromLaunchingRecord.getTopActivityDisplayArea();
                if (taskDisplayAreaForLaunchingRecord != null) {
                    if (DEBUG) {
                        appendLog("display-area-for-launching-record="
                                + taskDisplayAreaForLaunchingRecord);
                    }
                    return taskDisplayAreaForLaunchingRecord;
                }
            }

        WindowProcessController controllerFromProcess = mSupervisor.mService.getProcessController(
            WindowProcessController controllerFromProcess =
                    mSupervisor.mService.getProcessController(
                            activityRecord.getProcessName(), activityRecord.getUid());
        final TaskDisplayArea displayAreaForRecord = controllerFromProcess == null ? null
                : controllerFromProcess.getTopActivityDisplayArea();
            if (controllerFromProcess != null) {
                final TaskDisplayArea displayAreaForRecord =
                        controllerFromProcess.getTopActivityDisplayArea();
                if (displayAreaForRecord != null) {
                    if (DEBUG) appendLog("display-area-for-record=" + displayAreaForRecord);
                    return displayAreaForRecord;
                }
            }
        }

        WindowProcessController controllerFromRequest = request == null ? null : mSupervisor
                .mService.getProcessController(request.realCallingPid, request.realCallingUid);
        final TaskDisplayArea displayAreaFromSourceProcess = controllerFromRequest == null ? null
                : controllerFromRequest.getTopActivityDisplayArea();
        if (request != null) {
            WindowProcessController controllerFromRequest =
                    mSupervisor.mService.getProcessController(
                            request.realCallingPid, request.realCallingUid);
            if (controllerFromRequest != null) {
                final TaskDisplayArea displayAreaFromSourceProcess =
                            controllerFromRequest.getTopActivityDisplayArea();
                if (displayAreaFromSourceProcess != null) {
                    if (DEBUG) {
                        appendLog("display-area-source-process=" + displayAreaFromSourceProcess);
                    }
                    return displayAreaFromSourceProcess;
                }
            }
        }

        return mSupervisor.mRootWindowContainer.getDefaultTaskDisplayArea();
        final TaskDisplayArea defaultTaskDisplayArea =
                mSupervisor.mRootWindowContainer.getDefaultTaskDisplayArea();
        if (DEBUG) appendLog("display-area-from-default-fallback=" + defaultTaskDisplayArea);
        return defaultTaskDisplayArea;
    }

    private boolean canInheritWindowingModeFromSource(@NonNull DisplayContent display,
Loading