diff --git a/core/java/android/hardware/display/DisplayManager.java b/core/java/android/hardware/display/DisplayManager.java index e8fb287795635..09113e5d175df 100644 --- a/core/java/android/hardware/display/DisplayManager.java +++ b/core/java/android/hardware/display/DisplayManager.java @@ -297,6 +297,15 @@ public final class DisplayManager { */ public static final int VIRTUAL_DISPLAY_FLAG_DESTROY_CONTENT_ON_REMOVAL = 1 << 8; + /** + * Virtual display flag: Indicates that the display should support system decorations. Virtual + * displays without this flag shouldn't show home, IME or any other system decorations. + * + * @see #createVirtualDisplay + * @hide + */ + public static final int VIRTUAL_DISPLAY_FLAG_SHOULD_SHOW_SYSTEM_DECORATIONS = 1 << 9; + /** @hide */ public DisplayManager(Context context) { mContext = context; diff --git a/core/java/android/view/Display.java b/core/java/android/view/Display.java index 4d96fc3175cd9..719a401ce0cf9 100644 --- a/core/java/android/view/Display.java +++ b/core/java/android/view/Display.java @@ -220,6 +220,18 @@ public final class Display { */ public static final int FLAG_CAN_SHOW_WITH_INSECURE_KEYGUARD = 1 << 5; + /** + * Display flag: Indicates that the display should show system decorations. + *

+ * This flag identifies secondary displays that should show system decorations, such as status + * bar, navigation bar, home activity or IME. + *

+ * + * @see #supportsSystemDecorations + * @hide + */ + public static final int FLAG_SHOULD_SHOW_SYSTEM_DECORATIONS = 1 << 6; + /** * Display flag: Indicates that the contents of the display should not be scaled * to fit the physical screen dimensions. Used for development only to emulate @@ -873,6 +885,16 @@ public final class Display { return mDisplayInfo.removeMode; } + /** + * Returns whether this display should support showing system decorations. + * + * @see #FLAG_SHOULD_SHOW_SYSTEM_DECORATIONS + * @hide + */ + public boolean supportsSystemDecorations() { + return (mDisplayInfo.flags & FLAG_SHOULD_SHOW_SYSTEM_DECORATIONS) != 0; + } + /** * Returns the display's HDR capabilities. * diff --git a/services/core/java/com/android/server/am/ActivityDisplay.java b/services/core/java/com/android/server/am/ActivityDisplay.java index fab967c01086e..601282326b9fb 100644 --- a/services/core/java/com/android/server/am/ActivityDisplay.java +++ b/services/core/java/com/android/server/am/ActivityDisplay.java @@ -51,6 +51,7 @@ import android.annotation.Nullable; import android.app.ActivityOptions; import android.app.WindowConfiguration; import android.graphics.Point; +import android.os.UserHandle; import android.util.IntArray; import android.util.Slog; import android.util.proto.ProtoOutputStream; @@ -911,6 +912,13 @@ class ActivityDisplay extends ConfigurationContainer return mDisplayAccessUIDs; } + /** + * @see Display#FLAG_SHOULD_SHOW_SYSTEM_DECORATIONS + */ + boolean supportsSystemDecorations() { + return mDisplay.supportsSystemDecorations(); + } + private boolean shouldDestroyContentOnRemove() { return mDisplay.getRemoveMode() == REMOVE_MODE_DESTROY_CONTENT; } @@ -981,6 +989,57 @@ class ActivityDisplay extends ConfigurationContainer positionChildAt(stack, Math.max(0, insertIndex)); } + void moveHomeStackToFront(String reason) { + if (mHomeStack != null) { + mHomeStack.moveToFront(reason); + } + } + + /** Returns true if the focus activity was adjusted to the home stack top activity. */ + boolean moveHomeActivityToTop(String reason) { + final ActivityRecord top = getHomeActivity(); + if (top == null) { + return false; + } + mSupervisor.moveFocusableActivityToTop(top, reason); + return true; + } + + @Nullable + ActivityStack getHomeStack() { + return mHomeStack; + } + + @Nullable + ActivityRecord getHomeActivity() { + return getHomeActivityForUser(mSupervisor.mCurrentUser); + } + + @Nullable + ActivityRecord getHomeActivityForUser(int userId) { + if (mHomeStack == null) { + return null; + } + + final ArrayList tasks = mHomeStack.getAllTasks(); + for (int taskNdx = tasks.size() - 1; taskNdx >= 0; --taskNdx) { + final TaskRecord task = tasks.get(taskNdx); + if (!task.isActivityTypeHome()) { + continue; + } + + final ArrayList activities = task.mActivities; + for (int activityNdx = activities.size() - 1; activityNdx >= 0; --activityNdx) { + final ActivityRecord r = activities.get(activityNdx); + if (r.isActivityTypeHome() + && ((userId == UserHandle.USER_ALL) || (r.userId == userId))) { + return r; + } + } + } + return null; + } + boolean isSleeping() { return mSleeping; } diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index aa14da0ad70a4..6ffa4c08bd300 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -90,6 +90,7 @@ import static android.provider.Settings.Global.DEBUG_APP; import static android.provider.Settings.Global.NETWORK_ACCESS_TIMEOUT_MS; import static android.provider.Settings.Global.WAIT_FOR_DEBUGGER; import static android.text.format.DateUtils.DAY_IN_MILLIS; +import static android.view.Display.DEFAULT_DISPLAY; import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_ALL; import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_ANR; @@ -3725,6 +3726,14 @@ public class ActivityManagerService extends IActivityManager.Stub } boolean startHomeActivityLocked(int userId, String reason) { + return startHomeActivityLocked(userId, reason, DEFAULT_DISPLAY); + } + + /** + * This starts home activity on displays that can have system decorations and only if the + * home activity can have multiple instances. + */ + boolean startHomeActivityLocked(int userId, String reason, int displayId) { if (mFactoryTest == FactoryTest.FACTORY_TEST_LOW_LEVEL && mTopAction == null) { // We are running in factory test mode, but unable to find @@ -3748,7 +3757,8 @@ public class ActivityManagerService extends IActivityManager.Stub // For ANR debugging to verify if the user activity is the one that actually // launched. final String myReason = reason + ":" + userId + ":" + resolvedUserId; - mActivityTaskManager.getActivityStartController().startHomeActivity(intent, aInfo, myReason); + mActivityTaskManager.getActivityStartController().startHomeActivity(intent, aInfo, + myReason, displayId); } } else { Slog.wtf(TAG, "No home screen found for " + intent, new Throwable()); @@ -8817,7 +8827,7 @@ public class ActivityManagerService extends IActivityManager.Stub ? new ActivityOptions(options) : ActivityOptions.makeBasic(); activityOptions.setLaunchTaskId( - mStackSupervisor.getHomeActivity().getTask().taskId); + mStackSupervisor.getDefaultDisplayHomeActivity().getTask().taskId); mContext.startActivityAsUser(intent, activityOptions.toBundle(), UserHandle.CURRENT); } finally { diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java index 29b04ccdab08d..2ab938880ac78 100644 --- a/services/core/java/com/android/server/am/ActivityStack.java +++ b/services/core/java/com/android/server/am/ActivityStack.java @@ -1102,8 +1102,7 @@ class ActivityStack extends ConfigurationContai if (!isActivityTypeHome() && returnsToHomeStack()) { // Make sure the home stack is behind this stack since that is where we should return to // when this stack is no longer visible. - // TODO(b/111541062): Move home stack on the current display - mStackSupervisor.moveHomeStackToFront(reason + " returnToHome"); + display.moveHomeStackToFront(reason + " returnToHome"); } display.positionChildAtTop(this, true /* includingParents */); @@ -2854,9 +2853,7 @@ class ActivityStack extends ConfigurationContai if (DEBUG_STATES) Slog.d(TAG_STATES, "resumeTopActivityInNextFocusableStack: " + reason + ", go home"); if (DEBUG_STACK) mStackSupervisor.validateTopActivitiesLocked(); - // Only resume home if on home display - return isOnHomeDisplay() && - mStackSupervisor.resumeHomeStackTask(prev, reason); + return mStackSupervisor.resumeHomeActivity(prev, reason, mDisplayId); } /** Returns the position the input task should be placed in this stack. */ @@ -3450,8 +3447,8 @@ class ActivityStack extends ConfigurationContai final String myReason = reason + " adjustFocus"; if (next == r) { - mStackSupervisor.moveFocusableActivityStackToFrontLocked( - mStackSupervisor.topRunningActivityLocked(), myReason); + mStackSupervisor.moveFocusableActivityToTop(mStackSupervisor.topRunningActivityLocked(), + myReason); return; } @@ -3482,7 +3479,7 @@ class ActivityStack extends ConfigurationContai } // Whatever...go home. - mStackSupervisor.moveHomeStackTaskToTop(myReason); + getDisplay().moveHomeActivityToTop(myReason); } /** @@ -3511,7 +3508,7 @@ class ActivityStack extends ConfigurationContai if (stack.isActivityTypeHome() && (top == null || !top.visible)) { // If we will be focusing on the home stack next and its current top activity isn't // visible, then use the move the home stack task to top to make the activity visible. - mStackSupervisor.moveHomeStackTaskToTop(reason); + stack.getDisplay().moveHomeActivityToTop(reason); return stack; } @@ -4619,22 +4616,6 @@ class ActivityStack extends ConfigurationContai mStackSupervisor.invalidateTaskLayers(); } - void moveHomeStackTaskToTop() { - if (!isActivityTypeHome()) { - throw new IllegalStateException("Calling moveHomeStackTaskToTop() on non-home stack: " - + this); - } - final int top = mTaskHistory.size() - 1; - if (top >= 0) { - final TaskRecord task = mTaskHistory.get(top); - if (DEBUG_TASKS || DEBUG_STACK) Slog.d(TAG_STACK, - "moveHomeStackTaskToTop: moving " + task); - mTaskHistory.remove(top); - mTaskHistory.add(top, task); - updateTaskMovement(task, true); - } - } - final void moveTaskToFrontLocked(TaskRecord tr, boolean noAnimation, ActivityOptions options, AppTimeTracker timeTracker, String reason) { if (DEBUG_SWITCH) Slog.v(TAG_SWITCH, "moveTaskToFront: " + tr); @@ -4682,7 +4663,7 @@ class ActivityStack extends ConfigurationContai // Set focus to the top running activity of this stack. final ActivityRecord r = topRunningActivityLocked(); - mStackSupervisor.moveFocusableActivityStackToFrontLocked(r, reason); + mStackSupervisor.moveFocusableActivityToTop(r, reason); if (DEBUG_TRANSITION) Slog.v(TAG_TRANSITION, "Prepare to front transition: task=" + tr); if (noAnimation) { @@ -5223,11 +5204,11 @@ class ActivityStack extends ConfigurationContai if (DEBUG_STACK) Slog.i(TAG_STACK, "removeTask: removing stack=" + this); // We only need to adjust focused stack if this stack is in focus and we are not in the // process of moving the task to the top of the stack that will be focused. - if (isOnHomeDisplay() && mode != REMOVE_TASK_MODE_MOVING_TO_TOP + if (mode != REMOVE_TASK_MODE_MOVING_TO_TOP && mStackSupervisor.isTopDisplayFocusedStack(this)) { String myReason = reason + " leftTaskHistoryEmpty"; if (!inMultiWindowMode() || adjustFocusToNextFocusableStack(myReason) == null) { - mStackSupervisor.moveHomeStackToFront(myReason); + getDisplay().moveHomeStackToFront(myReason); } } if (isAttached()) { diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java index 8ff55f6ebba87..7f1e149838f81 100644 --- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java +++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java @@ -40,6 +40,8 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECOND import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED; import static android.app.WindowConfiguration.activityTypeToString; import static android.app.WindowConfiguration.windowingModeToString; +import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_INSTANCE; +import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_TASK; import static android.content.pm.PackageManager.PERMISSION_DENIED; import static android.content.pm.PackageManager.PERMISSION_GRANTED; import static android.graphics.Rect.copyOrNull; @@ -335,10 +337,6 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D /** The current user */ int mCurrentUser; - /** The stack containing the launcher app. Assumed to always be attached to - * Display.DEFAULT_DISPLAY. */ - ActivityStack mHomeStack; - /** If this is the same as mFocusedStack then the activity on the top of the focused stack has * been resumed. If stacks are changing position this will hold the old stack until the new * stack becomes resumed after which it will be set to mFocusedStack. */ @@ -693,7 +691,8 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D calculateDefaultMinimalSizeOfResizeableTasks(); final ActivityDisplay defaultDisplay = getDefaultDisplay(); - mHomeStack = mLastFocusedStack = defaultDisplay.getOrCreateStack( + + mLastFocusedStack = defaultDisplay.getOrCreateStack( WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME, ON_TOP); positionChildAt(defaultDisplay, ActivityDisplay.POSITION_TOP); } @@ -782,7 +781,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D if (focusCandidate == null) { Slog.w(TAG, "setFocusStackUnchecked: No focusable stack found, focus home as default"); - focusCandidate = mHomeStack; + focusCandidate = getDefaultDisplay().getHomeStack(); } } @@ -803,10 +802,6 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D } } - void moveHomeStackToFront(String reason) { - mHomeStack.moveToFront(reason); - } - void moveRecentsStackToFront(String reason) { final ActivityStack recentsStack = getDefaultDisplay().getStack( WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_RECENTS); @@ -815,34 +810,47 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D } } - /** Returns true if the focus activity was adjusted to the home stack top activity. */ - boolean moveHomeStackTaskToTop(String reason) { - mHomeStack.moveHomeStackTaskToTop(); - - final ActivityRecord top = getHomeActivity(); - if (top == null) { - return false; - } - moveFocusableActivityStackToFrontLocked(top, reason); - return true; - } - - boolean resumeHomeStackTask(ActivityRecord prev, String reason) { + boolean resumeHomeActivity(ActivityRecord prev, String reason, int displayId) { if (!mService.isBooting() && !mService.isBooted()) { // Not ready yet! return false; } - mHomeStack.moveHomeStackTaskToTop(); - ActivityRecord r = getHomeActivity(); - final String myReason = reason + " resumeHomeStackTask"; + if (displayId == INVALID_DISPLAY) { + displayId = DEFAULT_DISPLAY; + } + + final ActivityRecord r = getActivityDisplay(displayId).getHomeActivity(); + final String myReason = reason + " resumeHomeActivity"; // Only resume home activity if isn't finishing. if (r != null && !r.finishing) { - moveFocusableActivityStackToFrontLocked(r, myReason); - return resumeFocusedStacksTopActivitiesLocked(mHomeStack, prev, null); + moveFocusableActivityToTop(r, myReason); + return resumeFocusedStacksTopActivitiesLocked(r.getStack(), prev, null); } - return mService.mAm.startHomeActivityLocked(mCurrentUser, myReason); + return mService.mAm.startHomeActivityLocked(mCurrentUser, myReason, displayId); + } + + boolean canStartHomeOnDisplay(ActivityInfo homeActivity, int displayId) { + if (displayId == DEFAULT_DISPLAY) { + // No restrictions to default display. + return true; + } + + final ActivityDisplay display = getActivityDisplay(displayId); + if (display == null || display.isRemoved() || !display.supportsSystemDecorations()) { + // Can't launch home on display that doesn't support system decorations. + return false; + } + + final boolean supportMultipleInstance = homeActivity.launchMode != LAUNCH_SINGLE_TASK + && homeActivity.launchMode != LAUNCH_SINGLE_INSTANCE; + if (!supportMultipleInstance) { + // Can't launch home on other displays if it requested to be single instance. + return false; + } + + return true; } TaskRecord anyTaskForIdLocked(int id) { @@ -2206,7 +2214,8 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D */ void updateUserStackLocked(int userId, ActivityStack stack) { if (userId != mCurrentUser) { - mUserStackInFront.put(userId, stack != null ? stack.getStackId() : mHomeStack.mStackId); + mUserStackInFront.put(userId, stack != null ? stack.getStackId() + : getDefaultDisplay().getHomeStack().mStackId); } } @@ -2348,7 +2357,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D */ void findTaskToMoveToFront(TaskRecord task, int flags, ActivityOptions options, String reason, boolean forceNonResizeable) { - final ActivityStack currentStack = task.getStack(); + ActivityStack currentStack = task.getStack(); if (currentStack == null) { Slog.e(TAG, "findTaskToMoveToFront: can't move task=" + task + " to front. Stack is null"); @@ -2359,13 +2368,15 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D mUserLeaving = true; } + // TODO(b/111363427): The moving-to-top task may not be on the top display, so it could be + // different from where the prev activity stays on. final ActivityRecord prev = topRunningActivityLocked(); if ((flags & ActivityManager.MOVE_TASK_WITH_HOME) != 0 || (prev != null && prev.isActivityTypeRecents())) { // Caller wants the home activity moved with it or the previous task is recents in which // case we always return home from the task we are moving to the front. - moveHomeStackToFront("findTaskToMoveToFront"); + currentStack.getDisplay().moveHomeStackToFront("findTaskToMoveToFront"); } if (task.isResizeable() && canUseActivityOptionsLaunchBounds(options)) { @@ -2377,7 +2388,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D if (stack != currentStack) { task.reparent(stack, ON_TOP, REPARENT_KEEP_STACK_AT_FRONT, !ANIMATE, DEFER_RESUME, "findTaskToMoveToFront"); - stack = currentStack; + currentStack = stack; // moveTaskToStackUncheckedLocked() should already placed the task on top, // still need moveTaskToFrontLocked() below for any transition settings. } @@ -2644,6 +2655,12 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D if (preferredFocusableStack != null) { return preferredFocusableStack; } + if (preferredDisplay.supportsSystemDecorations()) { + // Stop looking for focusable stack on other displays because the preferred display + // supports system decorations. Home activity would be launched on the same display if + // no focusable stack found. + return null; + } // Now look through all displays for (int i = mActivityDisplays.size() - 1; i >= 0; --i) { @@ -2687,25 +2704,12 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D return null; } - ActivityRecord getHomeActivity() { - return getHomeActivityForUser(mCurrentUser); + ActivityRecord getDefaultDisplayHomeActivity() { + return getDefaultDisplayHomeActivityForUser(mCurrentUser); } - ActivityRecord getHomeActivityForUser(int userId) { - final ArrayList tasks = mHomeStack.getAllTasks(); - for (int taskNdx = tasks.size() - 1; taskNdx >= 0; --taskNdx) { - final TaskRecord task = tasks.get(taskNdx); - if (task.isActivityTypeHome()) { - final ArrayList activities = task.mActivities; - for (int activityNdx = activities.size() - 1; activityNdx >= 0; --activityNdx) { - final ActivityRecord r = activities.get(activityNdx); - if (r.isActivityTypeHome() - && ((userId == UserHandle.USER_ALL) || (r.userId == userId))) { - return r; - } - } - } - } + ActivityRecord getDefaultDisplayHomeActivityForUser(int userId) { + getActivityDisplay(DEFAULT_DISPLAY).getHomeActivityForUser(userId); return null; } @@ -3419,7 +3423,8 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D } /** Move activity with its stack to front and make the stack focused. */ - boolean moveFocusableActivityStackToFrontLocked(ActivityRecord r, String reason) { + // TODO(b/111363427): Move this method to ActivityRecord. + boolean moveFocusableActivityToTop(ActivityRecord r, String reason) { if (r == null || !r.isFocusable()) { if (DEBUG_FOCUS) Slog.d(TAG_FOCUS, "moveActivityStackToFront: unfocusable r=" + r); @@ -3828,7 +3833,8 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D removeStacksInWindowingModes(WINDOWING_MODE_PINNED); mUserStackInFront.put(mCurrentUser, focusStackId); - final int restoreStackId = mUserStackInFront.get(userId, mHomeStack.mStackId); + final int restoreStackId = + mUserStackInFront.get(userId, getDefaultDisplay().getHomeStack().mStackId); mCurrentUser = userId; mStartingUsers.add(uss); @@ -3846,14 +3852,14 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D ActivityStack stack = getStack(restoreStackId); if (stack == null) { - stack = mHomeStack; + stack = getDefaultDisplay().getHomeStack(); } final boolean homeInFront = stack.isActivityTypeHome(); if (stack.isOnHomeDisplay()) { stack.moveToFront("switchUserOnHomeDisplay"); } else { // Stack was moved to another display while user was swapped out. - resumeHomeStackTask(null, "switchUserOnOtherDisplay"); + resumeHomeActivity(null, "switchUserOnOtherDisplay", DEFAULT_DISPLAY); } return homeInFront; } @@ -4273,6 +4279,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D private void handleDisplayAdded(int displayId) { synchronized (mService.mGlobalLock) { getActivityDisplayOrCreateLocked(displayId); + mService.mAm.startHomeActivityLocked(mCurrentUser, "displayAdded", displayId); } } @@ -4838,7 +4845,8 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D // We always want to return to the home activity instead of the recents activity // from whatever is started from the recents activity, so move the home stack // forward. - moveHomeStackToFront("startActivityFromRecents"); + // TODO (b/115289124): Multi-display supports for recents. + getDefaultDisplay().moveHomeStackToFront("startActivityFromRecents"); } // If the user must confirm credentials (e.g. when first launching a work app and the @@ -4881,12 +4889,13 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D final ActivityStack topSecondaryStack = display.getTopStackInWindowingMode(WINDOWING_MODE_SPLIT_SCREEN_SECONDARY); if (topSecondaryStack.isActivityTypeHome()) { - // If the home activity if the top split-screen secondary stack, then the + // If the home activity is the top split-screen secondary stack, then the // primary split-screen stack is in the minimized mode which means it can't // receive input keys, so we should move the focused app to the home app so that // window manager can correctly calculate the focus window that can receive // input keys. - moveHomeStackToFront("startActivityFromRecents: homeVisibleInSplitScreen"); + display.moveHomeStackToFront( + "startActivityFromRecents: homeVisibleInSplitScreen"); // Immediately update the minimized docked stack mode, the upcoming animation // for the docked activity (WMS.overridePendingAppTransitionMultiThumbFuture) diff --git a/services/core/java/com/android/server/am/ActivityStartController.java b/services/core/java/com/android/server/am/ActivityStartController.java index 6e3a79c3aa952..5e73bc3a22594 100644 --- a/services/core/java/com/android/server/am/ActivityStartController.java +++ b/services/core/java/com/android/server/am/ActivityStartController.java @@ -17,12 +17,14 @@ package com.android.server.am; import static android.app.ActivityManager.START_SUCCESS; +import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME; +import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK; import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM; import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME; -import static android.app.ActivityManagerInternal.ALLOW_FULL_ONLY; +import android.app.ActivityOptions; import android.app.IApplicationThread; import android.content.ComponentName; import android.content.ContentResolver; @@ -75,7 +77,7 @@ public class ActivityStartController { /** Temporary array to capture start activity results */ private ActivityRecord[] tmpOutRecord = new ActivityRecord[1]; - /**The result of the last home activity we attempted to start. */ + /** The result of the last home activity we attempted to start. */ private int mLastHomeActivityStartResult; /** A list of activities that are waiting to launch. */ @@ -161,13 +163,20 @@ public class ActivityStartController { mLastStarter.postStartActivityProcessing(r, result, targetStack); } - void startHomeActivity(Intent intent, ActivityInfo aInfo, String reason) { - mSupervisor.moveHomeStackTaskToTop(reason); + void startHomeActivity(Intent intent, ActivityInfo aInfo, String reason, int displayId) { + if (!mSupervisor.canStartHomeOnDisplay(aInfo, displayId)) { + return; + } + final ActivityOptions options = ActivityOptions.makeBasic(); + options.setLaunchWindowingMode(WINDOWING_MODE_FULLSCREEN); + options.setLaunchActivityType(ACTIVITY_TYPE_HOME); + options.setLaunchDisplayId(displayId); mLastHomeActivityStartResult = obtainStarter(intent, "startHomeActivity: " + reason) .setOutActivity(tmpOutRecord) .setCallingUid(0) .setActivityInfo(aInfo) + .setActivityOptions(options.toBundle()) .execute(); mLastHomeActivityStartRecord = tmpOutRecord[0]; if (mSupervisor.inResumeTopActivity) { diff --git a/services/core/java/com/android/server/am/ActivityStartInterceptor.java b/services/core/java/com/android/server/am/ActivityStartInterceptor.java index 1fb8f871efcd3..4789ff3343981 100644 --- a/services/core/java/com/android/server/am/ActivityStartInterceptor.java +++ b/services/core/java/com/android/server/am/ActivityStartInterceptor.java @@ -277,7 +277,7 @@ class ActivityStartInterceptor { mActivityOptions = ActivityOptions.makeBasic(); } - ActivityRecord homeActivityRecord = mSupervisor.getHomeActivity(); + ActivityRecord homeActivityRecord = mSupervisor.getDefaultDisplayHomeActivity(); if (homeActivityRecord != null && homeActivityRecord.getTask() != null) { // Showing credential confirmation activity in home task to avoid stopping multi-windowed // mode after showing the full-screen credential confirmation activity. diff --git a/services/core/java/com/android/server/am/ActivityStarter.java b/services/core/java/com/android/server/am/ActivityStarter.java index 8236bd0e763ec..de3b9cf3ccdea 100644 --- a/services/core/java/com/android/server/am/ActivityStarter.java +++ b/services/core/java/com/android/server/am/ActivityStarter.java @@ -975,7 +975,8 @@ class ActivityStarter { clearedTask); break; case WINDOWING_MODE_SPLIT_SCREEN_PRIMARY: - final ActivityStack homeStack = mSupervisor.mHomeStack; + final ActivityStack homeStack = + startedActivityStack.getDisplay().getHomeStack(); if (homeStack != null && homeStack.shouldBeVisible(null /* starting */)) { mService.mWindowManager.showRecentApps(); } @@ -1280,6 +1281,15 @@ class ActivityStarter { setInitialState(r, options, inTask, doResume, startFlags, sourceRecord, voiceSession, voiceInteractor); + // Do not start home activity if it cannot be launched on preferred display. We are not + // doing this in ActivityStackSupervisor#canPlaceEntityOnDisplay because it might + // fallback to launch on other displays. + if (r.isActivityTypeHome() + && !mSupervisor.canStartHomeOnDisplay(r.info, mPreferredDisplayId)) { + Slog.w(TAG, "Cannot launch home on display " + mPreferredDisplayId); + return START_CANCELED; + } + computeLaunchingTaskFlags(); computeSourceStack(); @@ -1430,7 +1440,11 @@ class ActivityStarter { && top.userId == mStartActivity.userId && top.attachedToProcess() && ((mLaunchFlags & FLAG_ACTIVITY_SINGLE_TOP) != 0 - || isLaunchModeOneOf(LAUNCH_SINGLE_TOP, LAUNCH_SINGLE_TASK)); + || isLaunchModeOneOf(LAUNCH_SINGLE_TOP, LAUNCH_SINGLE_TASK)) + // This allows home activity to automatically launch on secondary display when + // display added, if home was the top activity on default display, instead of + // sending new intent to the home activity on default display. + && (!top.isActivityTypeHome() || top.getDisplayId() == mPreferredDisplayId); if (dontStart) { // For paranoia, make sure we have correctly resumed the top activity. topStack.mLastPausedActivity = null; @@ -1858,6 +1872,13 @@ class ActivityStarter { intentActivity = mSupervisor.findTaskLocked(mStartActivity, mPreferredDisplayId); } } + + if (mStartActivity.isActivityTypeHome() && intentActivity != null + && intentActivity.getDisplayId() != mPreferredDisplayId) { + // Do not reuse home activity on other displays. + intentActivity = null; + } + return intentActivity; } diff --git a/services/core/java/com/android/server/am/ActivityTaskManagerService.java b/services/core/java/com/android/server/am/ActivityTaskManagerService.java index 36261b505a942..bb940cb308816 100644 --- a/services/core/java/com/android/server/am/ActivityTaskManagerService.java +++ b/services/core/java/com/android/server/am/ActivityTaskManagerService.java @@ -1692,8 +1692,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { return; } final ActivityRecord r = stack.topRunningActivityLocked(); - if (mStackSupervisor.moveFocusableActivityStackToFrontLocked( - r, "setFocusedStack")) { + if (mStackSupervisor.moveFocusableActivityToTop(r, "setFocusedStack")) { mStackSupervisor.resumeFocusedStacksTopActivitiesLocked(); } } @@ -1714,7 +1713,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { return; } final ActivityRecord r = task.topRunningActivityLocked(); - if (mStackSupervisor.moveFocusableActivityStackToFrontLocked(r, "setFocusedTask")) { + if (mStackSupervisor.moveFocusableActivityToTop(r, "setFocusedTask")) { mStackSupervisor.resumeFocusedStacksTopActivitiesLocked(); } } @@ -5263,7 +5262,8 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { @Override public ComponentName getHomeActivityForUser(int userId) { synchronized (mGlobalLock) { - ActivityRecord homeActivity = mStackSupervisor.getHomeActivityForUser(userId); + ActivityRecord homeActivity = + mStackSupervisor.getDefaultDisplayHomeActivityForUser(userId); return homeActivity == null ? null : homeActivity.realActivity; } } @@ -5437,8 +5437,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { throw new IllegalArgumentException( "setFocusedActivity: No activity record matching token=" + token); } - if (mStackSupervisor.moveFocusableActivityStackToFrontLocked( - r, "setFocusedActivity")) { + if (mStackSupervisor.moveFocusableActivityToTop(r, "setFocusedActivity")) { mStackSupervisor.resumeFocusedStacksTopActivitiesLocked(); } } diff --git a/services/core/java/com/android/server/am/RecentTasks.java b/services/core/java/com/android/server/am/RecentTasks.java index bd0eca8820e50..4d0b1da98fde9 100644 --- a/services/core/java/com/android/server/am/RecentTasks.java +++ b/services/core/java/com/android/server/am/RecentTasks.java @@ -31,6 +31,8 @@ import static android.content.Intent.FLAG_ACTIVITY_MULTIPLE_TASK; import static android.content.Intent.FLAG_ACTIVITY_NEW_DOCUMENT; import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK; import static android.os.Process.SYSTEM_UID; +import static android.view.Display.DEFAULT_DISPLAY; + import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_RECENTS; import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_RECENTS_TRIM_TASKS; import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_TASKS; @@ -1242,7 +1244,6 @@ class RecentTasks { */ protected boolean isTrimmable(TaskRecord task) { final ActivityStack stack = task.getStack(); - final ActivityStack homeStack = mSupervisor.mHomeStack; // No stack for task, just trim it if (stack == null) { @@ -1250,13 +1251,14 @@ class RecentTasks { } // Ignore tasks from different displays - if (stack.getDisplay() != homeStack.getDisplay()) { + // TODO (b/115289124): No Recents on non-default displays. + if (stack.mDisplayId != DEFAULT_DISPLAY) { return false; } // Trim tasks that are in stacks that are behind the home stack final ActivityDisplay display = stack.getDisplay(); - return display.getIndexOf(stack) < display.getIndexOf(homeStack); + return display.getIndexOf(stack) < display.getIndexOf(display.getHomeStack()); } /** diff --git a/services/core/java/com/android/server/display/DisplayDeviceInfo.java b/services/core/java/com/android/server/display/DisplayDeviceInfo.java index 512e85192d36f..c51dc52b0515d 100644 --- a/services/core/java/com/android/server/display/DisplayDeviceInfo.java +++ b/services/core/java/com/android/server/display/DisplayDeviceInfo.java @@ -109,6 +109,13 @@ final class DisplayDeviceInfo { */ public static final int FLAG_MASK_DISPLAY_CUTOUT = 1 << 11; + /** + * Flag: This flag identifies secondary displays that should show system decorations, such as + * status bar, navigation bar, home activity or IME. + * @hide + */ + public static final int FLAG_SHOULD_SHOW_SYSTEM_DECORATIONS = 1 << 12; + /** * Touch attachment: Display does not receive touch. */ diff --git a/services/core/java/com/android/server/display/LogicalDisplay.java b/services/core/java/com/android/server/display/LogicalDisplay.java index 5b7c5205ce3a7..6f726e605d5e9 100644 --- a/services/core/java/com/android/server/display/LogicalDisplay.java +++ b/services/core/java/com/android/server/display/LogicalDisplay.java @@ -18,7 +18,6 @@ package com.android.server.display; import android.graphics.Rect; import android.hardware.display.DisplayManagerInternal; -import android.os.SystemProperties; import android.view.Display; import android.view.DisplayInfo; import android.view.Surface; @@ -256,6 +255,9 @@ final class LogicalDisplay { if ((deviceInfo.flags & DisplayDeviceInfo.FLAG_CAN_SHOW_WITH_INSECURE_KEYGUARD) != 0) { mBaseDisplayInfo.flags |= Display.FLAG_CAN_SHOW_WITH_INSECURE_KEYGUARD; } + if ((deviceInfo.flags & DisplayDeviceInfo.FLAG_SHOULD_SHOW_SYSTEM_DECORATIONS) != 0) { + mBaseDisplayInfo.flags |= Display.FLAG_SHOULD_SHOW_SYSTEM_DECORATIONS; + } Rect maskingInsets = getMaskingInsets(deviceInfo); int maskedWidth = deviceInfo.width - maskingInsets.left - maskingInsets.right; int maskedHeight = deviceInfo.height - maskingInsets.top - maskingInsets.bottom; diff --git a/services/core/java/com/android/server/display/VirtualDisplayAdapter.java b/services/core/java/com/android/server/display/VirtualDisplayAdapter.java index 244c764ff2156..5aa585fcad754 100644 --- a/services/core/java/com/android/server/display/VirtualDisplayAdapter.java +++ b/services/core/java/com/android/server/display/VirtualDisplayAdapter.java @@ -17,14 +17,13 @@ package com.android.server.display; import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR; -import static android.hardware.display.DisplayManager - .VIRTUAL_DISPLAY_FLAG_CAN_SHOW_WITH_INSECURE_KEYGUARD; -import static android.hardware.display.DisplayManager - .VIRTUAL_DISPLAY_FLAG_DESTROY_CONTENT_ON_REMOVAL; +import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_CAN_SHOW_WITH_INSECURE_KEYGUARD; +import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_DESTROY_CONTENT_ON_REMOVAL; import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_PRESENTATION; import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC; import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_ROTATES_WITH_CONTENT; import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_SECURE; +import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_SHOULD_SHOW_SYSTEM_DECORATIONS; import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_SUPPORTS_TOUCH; import android.content.Context; @@ -367,7 +366,10 @@ public class VirtualDisplayAdapter extends DisplayAdapter { mInfo.flags |= DisplayDeviceInfo.FLAG_ROTATES_WITH_CONTENT; } if ((mFlags & VIRTUAL_DISPLAY_FLAG_DESTROY_CONTENT_ON_REMOVAL) != 0) { - mInfo.flags |= DisplayDeviceInfo.FLAG_DESTROY_CONTENT_ON_REMOVAL; + mInfo.flags |= DisplayDeviceInfo.FLAG_DESTROY_CONTENT_ON_REMOVAL; + } + if ((mFlags & VIRTUAL_DISPLAY_FLAG_SHOULD_SHOW_SYSTEM_DECORATIONS) != 0) { + mInfo.flags |= DisplayDeviceInfo.FLAG_SHOULD_SHOW_SYSTEM_DECORATIONS; } mInfo.type = Display.TYPE_VIRTUAL; diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityTestsBase.java b/services/tests/servicestests/src/com/android/server/am/ActivityTestsBase.java index 22add018f5702..2008861907a69 100644 --- a/services/tests/servicestests/src/com/android/server/am/ActivityTestsBase.java +++ b/services/tests/servicestests/src/com/android/server/am/ActivityTestsBase.java @@ -168,6 +168,9 @@ public class ActivityTestsBase { // Makes sure the supervisor is using with the spy object. atm.mStackSupervisor.setService(atm); doReturn(mock(IPackageManager.class)).when(am).getPackageManager(); + PackageManagerInternal mockPackageManager = mock(PackageManagerInternal.class); + doReturn(mockPackageManager).when(am).getPackageManagerInternalLocked(); + doReturn(null).when(mockPackageManager).getDefaultHomeActivity(anyInt()); doNothing().when(am).grantEphemeralAccessLocked(anyInt(), any(), anyInt(), anyInt()); am.mWindowManager = prepareMockWindowManager(); atm.setWindowManager(am.mWindowManager); @@ -175,10 +178,9 @@ public class ActivityTestsBase { // Put a home stack on the default display, so that we'll always have something focusable. final TestActivityStackSupervisor supervisor = (TestActivityStackSupervisor) atm.mStackSupervisor; - supervisor.mHomeStack = supervisor.mDisplay.createStack(WINDOWING_MODE_FULLSCREEN, - ACTIVITY_TYPE_HOME, ON_TOP); + supervisor.mDisplay.createStack(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME, ON_TOP); final TaskRecord task = new TaskBuilder(atm.mStackSupervisor) - .setStack(supervisor.mHomeStack).build(); + .setStack(supervisor.getDefaultDisplay().getHomeStack()).build(); new ActivityBuilder(atm).setTask(task).build(); } @@ -447,9 +449,6 @@ public class ActivityTestsBase { final ActivityStackSupervisor supervisor = spy(createTestSupervisor()); final KeyguardController keyguardController = mock(KeyguardController.class); - // No home stack is set. - doNothing().when(supervisor).moveHomeStackToFront(any()); - doReturn(true).when(supervisor).moveHomeStackTaskToTop(any()); // Invoked during {@link ActivityStack} creation. doNothing().when(supervisor).updateUIDsPresentOnDisplay(); // Always keep things awake. diff --git a/services/tests/servicestests/src/com/android/server/am/RecentTasksTest.java b/services/tests/servicestests/src/com/android/server/am/RecentTasksTest.java index 70cfad1d0f2f4..1276f656f9142 100644 --- a/services/tests/servicestests/src/com/android/server/am/RecentTasksTest.java +++ b/services/tests/servicestests/src/com/android/server/am/RecentTasksTest.java @@ -125,7 +125,6 @@ public class RecentTasksTest extends ActivityTestsBase { WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME, true /* onTop */); mStack = mService.mStackSupervisor.getDefaultDisplay().createStack( WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */); - ((MyTestActivityStackSupervisor) mService.mStackSupervisor).setHomeStack(mHomeStack); mCallbacksRecorder = new CallbacksRecorder(); mRecentTasks.registerCallback(mCallbacksRecorder); QUIET_USER_INFO.flags = UserInfo.FLAG_MANAGED_PROFILE | UserInfo.FLAG_QUIET_MODE; @@ -558,9 +557,8 @@ public class RecentTasksTest extends ActivityTestsBase { final MyTestActivityStackSupervisor supervisor = (MyTestActivityStackSupervisor) mService.mStackSupervisor; - final ActivityStack homeStack = new MyTestActivityStack(mDisplay, supervisor); + final ActivityStack homeStack = mDisplay.getHomeStack(); final ActivityStack aboveHomeStack = new MyTestActivityStack(mDisplay, supervisor); - supervisor.setHomeStack(homeStack); // Add a number of tasks (beyond the max) but ensure that nothing is trimmed because all // the tasks belong in stacks above the home stack @@ -579,9 +577,8 @@ public class RecentTasksTest extends ActivityTestsBase { final MyTestActivityStackSupervisor supervisor = (MyTestActivityStackSupervisor) mService.mStackSupervisor; final ActivityStack behindHomeStack = new MyTestActivityStack(mDisplay, supervisor); - final ActivityStack homeStack = new MyTestActivityStack(mDisplay, supervisor); + final ActivityStack homeStack = mDisplay.getHomeStack(); final ActivityStack aboveHomeStack = new MyTestActivityStack(mDisplay, supervisor); - supervisor.setHomeStack(homeStack); // Add a number of tasks (beyond the max) but ensure that only the task in the stack behind // the home stack is trimmed once a new task is added @@ -601,9 +598,8 @@ public class RecentTasksTest extends ActivityTestsBase { final MyTestActivityStackSupervisor supervisor = (MyTestActivityStackSupervisor) mService.mStackSupervisor; - final ActivityStack homeStack = new MyTestActivityStack(mDisplay, supervisor); + final ActivityStack homeStack = mDisplay.getHomeStack(); final ActivityStack otherDisplayStack = new MyTestActivityStack(mOtherDisplay, supervisor); - supervisor.setHomeStack(homeStack); // Add a number of tasks (beyond the max) on each display, ensure that the tasks are not // removed @@ -870,7 +866,7 @@ public class RecentTasksTest extends ActivityTestsBase { @Override public void initialize() { super.initialize(); - mDisplay = TestActivityDisplay.create(this, DEFAULT_DISPLAY); + mDisplay = getActivityDisplay(DEFAULT_DISPLAY); mOtherDisplay = TestActivityDisplay.create(this, DEFAULT_DISPLAY + 1); addChild(mOtherDisplay, ActivityDisplay.POSITION_TOP); addChild(mDisplay, ActivityDisplay.POSITION_TOP); @@ -881,10 +877,6 @@ public class RecentTasksTest extends ActivityTestsBase { mRunningTasks = new TestRunningTasks(); return mRunningTasks; } - - void setHomeStack(ActivityStack stack) { - mHomeStack = stack; - } } private class MyTestActivityStack extends TestActivityStack {