Merge "Update some policy around multi-window windowing mode" into rvc-dev

This commit is contained in:
Winson Chung
2020-03-19 03:40:35 +00:00
committed by Android (Google) Code Review
8 changed files with 96 additions and 21 deletions

View File

@@ -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);
}

View File

@@ -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);
}

View File

@@ -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

View File

@@ -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.

View File

@@ -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);

View File

@@ -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) {

View File

@@ -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,

View File

@@ -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");