Support launching home activity on secondary display
- Add a new flag indicating that the display should show
system decorations, such as status bar, nav bar, home and IME.
- Automatically launches home activity on secondary display
if the display support system decorations and home
activity has multiple instances supports.
- Remove ActivityStackSupervisor#mHomeStack and move several
home stack related methods to ActivityDisplay.
Bug: 111363427
Test: atest ActivityManagerMultiDisplayTests
atest com.android.server.am
Manual test on virtual display and chromecast
Change-Id: I48fe245ad12965a19a6768f5dbb4e974ce94b01a
diff --git a/core/java/android/hardware/display/DisplayManager.java b/core/java/android/hardware/display/DisplayManager.java
index e8fb287..09113e5 100644
--- a/core/java/android/hardware/display/DisplayManager.java
+++ b/core/java/android/hardware/display/DisplayManager.java
@@ -297,6 +297,15 @@
*/
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 4d96fc3..719a401 100644
--- a/core/java/android/view/Display.java
+++ b/core/java/android/view/Display.java
@@ -221,6 +221,18 @@
public static final int FLAG_CAN_SHOW_WITH_INSECURE_KEYGUARD = 1 << 5;
/**
+ * Display flag: Indicates that the display should show system decorations.
+ * <p>
+ * This flag identifies secondary displays that should show system decorations, such as status
+ * bar, navigation bar, home activity or IME.
+ * </p>
+ *
+ * @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
* devices with smaller physicals screens while preserving density.
@@ -874,6 +886,16 @@
}
/**
+ * 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.
*
* @see #isHdr()
diff --git a/services/core/java/com/android/server/am/ActivityDisplay.java b/services/core/java/com/android/server/am/ActivityDisplay.java
index fab967c..6012823 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.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 @@
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 @@
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<TaskRecord> tasks = mHomeStack.getAllTasks();
+ for (int taskNdx = tasks.size() - 1; taskNdx >= 0; --taskNdx) {
+ final TaskRecord task = tasks.get(taskNdx);
+ if (!task.isActivityTypeHome()) {
+ continue;
+ }
+
+ final ArrayList<ActivityRecord> 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 aa14da0..6ffa4c0 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.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 @@
}
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 @@
// 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 @@
? 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 29b04cc..2ab9388 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 @@
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 @@
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 @@
final String myReason = reason + " adjustFocus";
if (next == r) {
- mStackSupervisor.moveFocusableActivityStackToFrontLocked(
- mStackSupervisor.topRunningActivityLocked(), myReason);
+ mStackSupervisor.moveFocusableActivityToTop(mStackSupervisor.topRunningActivityLocked(),
+ myReason);
return;
}
@@ -3482,7 +3479,7 @@
}
// Whatever...go home.
- mStackSupervisor.moveHomeStackTaskToTop(myReason);
+ getDisplay().moveHomeActivityToTop(myReason);
}
/**
@@ -3511,7 +3508,7 @@
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 @@
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 @@
// 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 @@
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 8ff55f6..7f1e149 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_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 @@
/** 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 @@
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 @@
if (focusCandidate == null) {
Slog.w(TAG,
"setFocusStackUnchecked: No focusable stack found, focus home as default");
- focusCandidate = mHomeStack;
+ focusCandidate = getDefaultDisplay().getHomeStack();
}
}
@@ -803,10 +802,6 @@
}
}
- 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 @@
}
}
- /** 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 @@
*/
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 @@
*/
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 @@
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 @@
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 @@
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 @@
return null;
}
- ActivityRecord getHomeActivity() {
- return getHomeActivityForUser(mCurrentUser);
+ ActivityRecord getDefaultDisplayHomeActivity() {
+ return getDefaultDisplayHomeActivityForUser(mCurrentUser);
}
- ActivityRecord getHomeActivityForUser(int userId) {
- final ArrayList<TaskRecord> tasks = mHomeStack.getAllTasks();
- for (int taskNdx = tasks.size() - 1; taskNdx >= 0; --taskNdx) {
- final TaskRecord task = tasks.get(taskNdx);
- if (task.isActivityTypeHome()) {
- final ArrayList<ActivityRecord> 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 @@
}
/** 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 @@
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 @@
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 @@
private void handleDisplayAdded(int displayId) {
synchronized (mService.mGlobalLock) {
getActivityDisplayOrCreateLocked(displayId);
+ mService.mAm.startHomeActivityLocked(mCurrentUser, "displayAdded", displayId);
}
}
@@ -4838,7 +4845,8 @@
// 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 @@
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 6e3a79c..5e73bc3 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 @@
/** 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 @@
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 1fb8f87..4789ff3 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 @@
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 8236bd0..de3b9cf 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 @@
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 @@
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 @@
&& 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 @@
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 36261b5..bb940cb 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 @@
return;
}
final ActivityRecord r = stack.topRunningActivityLocked();
- if (mStackSupervisor.moveFocusableActivityStackToFrontLocked(
- r, "setFocusedStack")) {
+ if (mStackSupervisor.moveFocusableActivityToTop(r, "setFocusedStack")) {
mStackSupervisor.resumeFocusedStacksTopActivitiesLocked();
}
}
@@ -1714,7 +1713,7 @@
return;
}
final ActivityRecord r = task.topRunningActivityLocked();
- if (mStackSupervisor.moveFocusableActivityStackToFrontLocked(r, "setFocusedTask")) {
+ if (mStackSupervisor.moveFocusableActivityToTop(r, "setFocusedTask")) {
mStackSupervisor.resumeFocusedStacksTopActivitiesLocked();
}
}
@@ -5263,7 +5262,8 @@
@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 @@
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 bd0eca8..4d0b1da 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_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 @@
*/
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 @@
}
// 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 512e851..c51dc52 100644
--- a/services/core/java/com/android/server/display/DisplayDeviceInfo.java
+++ b/services/core/java/com/android/server/display/DisplayDeviceInfo.java
@@ -110,6 +110,13 @@
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.
*/
public static final int TOUCH_NONE = 0;
diff --git a/services/core/java/com/android/server/display/LogicalDisplay.java b/services/core/java/com/android/server/display/LogicalDisplay.java
index 5b7c520..6f726e6 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 @@
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 @@
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 244c764..5aa585f 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 @@
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 22add01..20088619 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 @@
// 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 @@
// 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 @@
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 70cfad1..1276f65 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 @@
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 @@
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 @@
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 @@
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 @@
@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 @@
mRunningTasks = new TestRunningTasks();
return mRunningTasks;
}
-
- void setHomeStack(ActivityStack stack) {
- mHomeStack = stack;
- }
}
private class MyTestActivityStack extends TestActivityStack {