Merge "Update some policy around multi-window windowing mode" into rvc-dev
This commit is contained in:
@@ -111,6 +111,7 @@ package android.app {
|
||||
method public void setLaunchActivityType(int);
|
||||
method public void setLaunchTaskId(int);
|
||||
method public void setLaunchWindowingMode(int);
|
||||
method public void setTaskAlwaysOnTop(boolean);
|
||||
method public void setTaskOverlay(boolean, boolean);
|
||||
}
|
||||
|
||||
|
||||
@@ -208,6 +208,12 @@ public class ActivityOptions {
|
||||
private static final String KEY_PENDING_INTENT_LAUNCH_FLAGS =
|
||||
"android.activity.pendingIntentLaunchFlags";
|
||||
|
||||
/**
|
||||
* See {@link #setTaskAlwaysOnTop}.
|
||||
* @hide
|
||||
*/
|
||||
private static final String KEY_TASK_ALWAYS_ON_TOP = "android.activity.alwaysOnTop";
|
||||
|
||||
/**
|
||||
* See {@link #setTaskOverlay}.
|
||||
* @hide
|
||||
@@ -337,6 +343,7 @@ public class ActivityOptions {
|
||||
private int mSplitScreenCreateMode = SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT;
|
||||
private boolean mLockTaskMode = false;
|
||||
private boolean mDisallowEnterPictureInPictureWhileLaunching;
|
||||
private boolean mTaskAlwaysOnTop;
|
||||
private boolean mTaskOverlay;
|
||||
private boolean mTaskOverlayCanResume;
|
||||
private boolean mAvoidMoveToFront;
|
||||
@@ -971,6 +978,7 @@ public class ActivityOptions {
|
||||
mLaunchActivityType = opts.getInt(KEY_LAUNCH_ACTIVITY_TYPE, ACTIVITY_TYPE_UNDEFINED);
|
||||
mLaunchTaskId = opts.getInt(KEY_LAUNCH_TASK_ID, -1);
|
||||
mPendingIntentLaunchFlags = opts.getInt(KEY_PENDING_INTENT_LAUNCH_FLAGS, 0);
|
||||
mTaskAlwaysOnTop = opts.getBoolean(KEY_TASK_ALWAYS_ON_TOP, false);
|
||||
mTaskOverlay = opts.getBoolean(KEY_TASK_OVERLAY, false);
|
||||
mTaskOverlayCanResume = opts.getBoolean(KEY_TASK_OVERLAY_CAN_RESUME, false);
|
||||
mAvoidMoveToFront = opts.getBoolean(KEY_AVOID_MOVE_TO_FRONT, false);
|
||||
@@ -1299,6 +1307,22 @@ public class ActivityOptions {
|
||||
return mPendingIntentLaunchFlags;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set's whether the task for the activity launched with this option should always be on top.
|
||||
* @hide
|
||||
*/
|
||||
@TestApi
|
||||
public void setTaskAlwaysOnTop(boolean alwaysOnTop) {
|
||||
mTaskAlwaysOnTop = alwaysOnTop;
|
||||
}
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public boolean getTaskAlwaysOnTop() {
|
||||
return mTaskAlwaysOnTop;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set's whether the activity launched with this option should be a task overlay. That is the
|
||||
* activity will always be the top activity of the task.
|
||||
@@ -1556,6 +1580,9 @@ public class ActivityOptions {
|
||||
if (mPendingIntentLaunchFlags != 0) {
|
||||
b.putInt(KEY_PENDING_INTENT_LAUNCH_FLAGS, mPendingIntentLaunchFlags);
|
||||
}
|
||||
if (mTaskAlwaysOnTop) {
|
||||
b.putBoolean(KEY_TASK_ALWAYS_ON_TOP, mTaskAlwaysOnTop);
|
||||
}
|
||||
if (mTaskOverlay) {
|
||||
b.putBoolean(KEY_TASK_OVERLAY, mTaskOverlay);
|
||||
}
|
||||
|
||||
@@ -31,6 +31,11 @@ interface ITaskOrganizerController {
|
||||
*/
|
||||
void registerTaskOrganizer(ITaskOrganizer organizer, int windowingMode);
|
||||
|
||||
/**
|
||||
* Unregisters a previously registered task organizer.
|
||||
*/
|
||||
void unregisterTaskOrganizer(ITaskOrganizer organizer);
|
||||
|
||||
/**
|
||||
* Apply multiple WindowContainer operations at once.
|
||||
* @param organizer If non-null this transaction will use the synchronization
|
||||
|
||||
@@ -27,8 +27,10 @@ import static android.app.ActivityManager.START_RETURN_INTENT_TO_CALLER;
|
||||
import static android.app.ActivityManager.START_RETURN_LOCK_TASK_MODE_VIOLATION;
|
||||
import static android.app.ActivityManager.START_SUCCESS;
|
||||
import static android.app.ActivityManager.START_TASK_TO_FRONT;
|
||||
import static android.app.ActivityTaskManager.INVALID_TASK_ID;
|
||||
import static android.app.WaitResult.LAUNCH_STATE_COLD;
|
||||
import static android.app.WaitResult.LAUNCH_STATE_HOT;
|
||||
import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
|
||||
import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
|
||||
import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
|
||||
import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
|
||||
@@ -167,6 +169,8 @@ class ActivityStarter {
|
||||
|
||||
// The display to launch the activity onto, barring any strong reason to do otherwise.
|
||||
private int mPreferredDisplayId;
|
||||
// The windowing mode to apply to the root task, if possible
|
||||
private int mPreferredWindowingMode;
|
||||
|
||||
private Task mInTask;
|
||||
@VisibleForTesting
|
||||
@@ -538,6 +542,7 @@ class ActivityStarter {
|
||||
mStartFlags = starter.mStartFlags;
|
||||
mSourceRecord = starter.mSourceRecord;
|
||||
mPreferredDisplayId = starter.mPreferredDisplayId;
|
||||
mPreferredWindowingMode = starter.mPreferredWindowingMode;
|
||||
|
||||
mInTask = starter.mInTask;
|
||||
mAddingToTask = starter.mAddingToTask;
|
||||
@@ -1493,8 +1498,6 @@ class ActivityStarter {
|
||||
setInitialState(r, options, inTask, doResume, startFlags, sourceRecord, voiceSession,
|
||||
voiceInteractor, restrictedBgActivity);
|
||||
|
||||
final int preferredWindowingMode = mLaunchParams.mWindowingMode;
|
||||
|
||||
computeLaunchingTaskFlags();
|
||||
|
||||
computeSourceStack();
|
||||
@@ -1564,6 +1567,14 @@ class ActivityStarter {
|
||||
|
||||
if (!mAvoidMoveToFront && mDoResume) {
|
||||
mTargetStack.moveToFront("reuseOrNewTask");
|
||||
if (mOptions != null) {
|
||||
if (mPreferredWindowingMode != WINDOWING_MODE_UNDEFINED) {
|
||||
mTargetStack.setWindowingMode(mPreferredWindowingMode);
|
||||
}
|
||||
if (mOptions.getTaskAlwaysOnTop()) {
|
||||
mTargetStack.setAlwaysOnTop(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mService.mUgmInternal.grantUriPermissionFromIntent(mCallingUid, mStartActivity.packageName,
|
||||
@@ -1627,7 +1638,7 @@ class ActivityStarter {
|
||||
// Update the recent tasks list immediately when the activity starts
|
||||
mSupervisor.mRecentTasks.add(mStartActivity.getTask());
|
||||
mSupervisor.handleNonResizableTaskIfNeeded(mStartActivity.getTask(),
|
||||
preferredWindowingMode, mPreferredDisplayId, mTargetStack);
|
||||
mPreferredWindowingMode, mPreferredDisplayId, mTargetStack);
|
||||
|
||||
return START_SUCCESS;
|
||||
}
|
||||
@@ -1680,9 +1691,10 @@ class ActivityStarter {
|
||||
|
||||
mSupervisor.getLaunchParamsController().calculate(targetTask, r.info.windowLayout, r,
|
||||
sourceRecord, mOptions, PHASE_BOUNDS, mLaunchParams);
|
||||
mPreferredDisplayId =
|
||||
mLaunchParams.hasPreferredDisplay() ? mLaunchParams.mPreferredDisplayId
|
||||
: DEFAULT_DISPLAY;
|
||||
mPreferredDisplayId = mLaunchParams.hasPreferredDisplay()
|
||||
? mLaunchParams.mPreferredDisplayId
|
||||
: DEFAULT_DISPLAY;
|
||||
mPreferredWindowingMode = mLaunchParams.mWindowingMode;
|
||||
}
|
||||
|
||||
private int isAllowedToStart(ActivityRecord r, boolean newTask, Task targetTask) {
|
||||
@@ -2006,6 +2018,7 @@ class ActivityStarter {
|
||||
mStartFlags = 0;
|
||||
mSourceRecord = null;
|
||||
mPreferredDisplayId = INVALID_DISPLAY;
|
||||
mPreferredWindowingMode = WINDOWING_MODE_UNDEFINED;
|
||||
|
||||
mInTask = null;
|
||||
mAddingToTask = false;
|
||||
@@ -2054,9 +2067,10 @@ class ActivityStarter {
|
||||
// after we located a reusable task (which might be resided in another display).
|
||||
mSupervisor.getLaunchParamsController().calculate(inTask, r.info.windowLayout, r,
|
||||
sourceRecord, options, PHASE_DISPLAY, mLaunchParams);
|
||||
mPreferredDisplayId =
|
||||
mLaunchParams.hasPreferredDisplay() ? mLaunchParams.mPreferredDisplayId
|
||||
: DEFAULT_DISPLAY;
|
||||
mPreferredDisplayId = mLaunchParams.hasPreferredDisplay()
|
||||
? mLaunchParams.mPreferredDisplayId
|
||||
: DEFAULT_DISPLAY;
|
||||
mPreferredWindowingMode = mLaunchParams.mWindowingMode;
|
||||
|
||||
mLaunchMode = r.launchMode;
|
||||
|
||||
@@ -2098,7 +2112,7 @@ class ActivityStarter {
|
||||
}
|
||||
|
||||
if (mOptions != null) {
|
||||
if (mOptions.getLaunchTaskId() != -1 && mOptions.getTaskOverlay()) {
|
||||
if (mOptions.getLaunchTaskId() != INVALID_TASK_ID && mOptions.getTaskOverlay()) {
|
||||
r.setTaskOverlay(true);
|
||||
if (!mOptions.canTaskOverlayResume()) {
|
||||
final Task task = mRootWindowContainer.anyTaskForId(
|
||||
@@ -2291,6 +2305,15 @@ class ActivityStarter {
|
||||
* if not or an ActivityRecord with the task into which the new activity should be added.
|
||||
*/
|
||||
private Task getReusableTask() {
|
||||
// If a target task is specified, try to reuse that one
|
||||
if (mOptions != null && mOptions.getLaunchTaskId() != INVALID_TASK_ID) {
|
||||
Task launchTask = mRootWindowContainer.anyTaskForId(mOptions.getLaunchTaskId());
|
||||
if (launchTask != null) {
|
||||
return launchTask;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
// We may want to try to place the new activity in to an existing task. We always
|
||||
// do this if the target activity is singleTask or singleInstance; we will also do
|
||||
// this if NEW_TASK has been requested, and there is not an additional qualifier telling
|
||||
@@ -2304,12 +2327,7 @@ class ActivityStarter {
|
||||
// same component, then instead of launching bring that one to the front.
|
||||
putIntoExistingTask &= mInTask == null && mStartActivity.resultTo == null;
|
||||
ActivityRecord intentActivity = null;
|
||||
if (mOptions != null && mOptions.getLaunchTaskId() != -1) {
|
||||
Task launchTask = mRootWindowContainer.anyTaskForId(mOptions.getLaunchTaskId());
|
||||
if (launchTask != null) {
|
||||
return launchTask;
|
||||
}
|
||||
} else if (putIntoExistingTask) {
|
||||
if (putIntoExistingTask) {
|
||||
if (LAUNCH_SINGLE_INSTANCE == mLaunchMode) {
|
||||
// There can be one and only one instance of single instance activity in the
|
||||
// history, and it is always in its own unique task, so we do a special search.
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
package com.android.server.wm;
|
||||
|
||||
import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
|
||||
import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
|
||||
import static android.view.InsetsState.ITYPE_CAPTION_BAR;
|
||||
import static android.view.InsetsState.ITYPE_IME;
|
||||
@@ -87,7 +88,8 @@ class InsetsStateController {
|
||||
final InsetsSourceProvider provider = target.getControllableInsetProvider();
|
||||
final @InternalInsetsType int type = provider != null
|
||||
? provider.getSource().getType() : ITYPE_INVALID;
|
||||
return getInsetsForTypeAndWindowingMode(type, target.getWindowingMode());
|
||||
return getInsetsForTypeAndWindowingMode(type, target.getWindowingMode(),
|
||||
target.isAlwaysOnTop());
|
||||
}
|
||||
|
||||
InsetsState getInsetsForWindowMetrics(@NonNull WindowManager.LayoutParams attrs) {
|
||||
@@ -95,7 +97,9 @@ class InsetsStateController {
|
||||
final WindowToken token = mDisplayContent.getWindowToken(attrs.token);
|
||||
final @WindowingMode int windowingMode = token != null
|
||||
? token.getWindowingMode() : WINDOWING_MODE_UNDEFINED;
|
||||
return getInsetsForTypeAndWindowingMode(type, windowingMode);
|
||||
final boolean alwaysOnTop = token != null
|
||||
? token.isAlwaysOnTop() : false;
|
||||
return getInsetsForTypeAndWindowingMode(type, windowingMode, alwaysOnTop);
|
||||
}
|
||||
|
||||
private static @InternalInsetsType int getInsetsTypeForWindowType(int type) {
|
||||
@@ -113,7 +117,7 @@ class InsetsStateController {
|
||||
|
||||
/** @see #getInsetsForDispatch */
|
||||
private InsetsState getInsetsForTypeAndWindowingMode(@InternalInsetsType int type,
|
||||
@WindowingMode int windowingMode) {
|
||||
@WindowingMode int windowingMode, boolean isAlwaysOnTop) {
|
||||
InsetsState state = mState;
|
||||
|
||||
if (type != ITYPE_INVALID) {
|
||||
@@ -147,7 +151,8 @@ class InsetsStateController {
|
||||
}
|
||||
}
|
||||
|
||||
if (WindowConfiguration.isFloating(windowingMode)) {
|
||||
if (WindowConfiguration.isFloating(windowingMode)
|
||||
|| (windowingMode == WINDOWING_MODE_MULTI_WINDOW && isAlwaysOnTop)) {
|
||||
state = new InsetsState(state);
|
||||
state.removeSource(ITYPE_STATUS_BAR);
|
||||
state.removeSource(ITYPE_NAVIGATION_BAR);
|
||||
|
||||
@@ -231,7 +231,8 @@ class TaskOrganizerController extends ITaskOrganizerController.Stub
|
||||
}
|
||||
}
|
||||
|
||||
void unregisterTaskOrganizer(ITaskOrganizer organizer) {
|
||||
@Override
|
||||
public void unregisterTaskOrganizer(ITaskOrganizer organizer) {
|
||||
final TaskOrganizerState state = mTaskOrganizerStates.get(organizer.asBinder());
|
||||
state.unlinkDeath();
|
||||
if (mTaskOrganizersForWindowingMode.get(state.mWindowingMode) == state) {
|
||||
|
||||
@@ -51,6 +51,7 @@ public class ActivityOptionsTest {
|
||||
opts.setLaunchTaskId(Integer.MAX_VALUE);
|
||||
opts.setLockTaskEnabled(true);
|
||||
opts.setRotationAnimationHint(ROTATION_ANIMATION_ROTATE);
|
||||
opts.setTaskAlwaysOnTop(true);
|
||||
opts.setTaskOverlay(true, true);
|
||||
opts.setSplitScreenCreateMode(SPLIT_SCREEN_CREATE_MODE_BOTTOM_OR_RIGHT);
|
||||
Bundle optsBundle = opts.toBundle();
|
||||
@@ -67,6 +68,7 @@ public class ActivityOptionsTest {
|
||||
assertEquals(Integer.MAX_VALUE, restoredOpts.getLaunchTaskId());
|
||||
assertTrue(restoredOpts.getLockTaskMode());
|
||||
assertEquals(ROTATION_ANIMATION_ROTATE, restoredOpts.getRotationAnimationHint());
|
||||
assertTrue(restoredOpts.getTaskAlwaysOnTop());
|
||||
assertTrue(restoredOpts.getTaskOverlay());
|
||||
assertTrue(restoredOpts.canTaskOverlayResume());
|
||||
assertEquals(SPLIT_SCREEN_CREATE_MODE_BOTTOM_OR_RIGHT,
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
package com.android.server.wm;
|
||||
|
||||
import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
|
||||
import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
|
||||
import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
|
||||
import static android.view.InsetsState.ITYPE_IME;
|
||||
import static android.view.InsetsState.ITYPE_NAVIGATION_BAR;
|
||||
@@ -130,6 +131,21 @@ public class InsetsStateControllerTest extends WindowTestsBase {
|
||||
assertNull(getController().getInsetsForDispatch(app).peekSource(ITYPE_NAVIGATION_BAR));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testStripForDispatch_multiwindow_alwaysOnTop() {
|
||||
final WindowState statusBar = createWindow(null, TYPE_APPLICATION, "statusBar");
|
||||
final WindowState navBar = createWindow(null, TYPE_APPLICATION, "navBar");
|
||||
final WindowState app = createWindow(null, TYPE_APPLICATION, "app");
|
||||
|
||||
getController().getSourceProvider(ITYPE_STATUS_BAR).setWindow(statusBar, null, null);
|
||||
getController().getSourceProvider(ITYPE_NAVIGATION_BAR).setWindow(navBar, null, null);
|
||||
app.setWindowingMode(WINDOWING_MODE_MULTI_WINDOW);
|
||||
app.setAlwaysOnTop(true);
|
||||
|
||||
assertNull(getController().getInsetsForDispatch(app).peekSource(ITYPE_STATUS_BAR));
|
||||
assertNull(getController().getInsetsForDispatch(app).peekSource(ITYPE_NAVIGATION_BAR));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testImeForDispatch() {
|
||||
final WindowState statusBar = createWindow(null, TYPE_APPLICATION, "statusBar");
|
||||
|
||||
Reference in New Issue
Block a user