Changed createRootTask task to be completely async

Currently some of the information about a task created by createRootTask
is returned with the method and the rest like leash is return in
onTaskAppear. Mixing both async and sync infromation return styles
complicates the mental model for this. So, we will have this be
completely aync for now.

Also, fixed an issue where the windowing mode for organizer created
task was not set correctly before the organizer gets the first task
appear signal.

Bug: 169266958
Test: Split-screen works!
Change-Id: Ia4180d5a42838bf566fbf75f40466dfd8237e0f1
This commit is contained in:
Wale Ogunwale
2020-10-23 13:45:54 -07:00
parent 6a6ce5e698
commit 188d801038
20 changed files with 211 additions and 111 deletions

View File

@@ -2375,7 +2375,7 @@ package android.window {
public class TaskOrganizer extends android.window.WindowOrganizer {
ctor public TaskOrganizer();
method @Nullable @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) public android.app.ActivityManager.RunningTaskInfo createRootTask(int, int);
method @Nullable @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) public void createRootTask(int, int, @Nullable android.os.IBinder);
method @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) public boolean deleteRootTask(@NonNull android.window.WindowContainerToken);
method @Nullable @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) public java.util.List<android.app.ActivityManager.RunningTaskInfo> getChildTasks(@NonNull android.window.WindowContainerToken, @NonNull int[]);
method @Nullable @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) public android.window.WindowContainerToken getImeTarget(int);

View File

@@ -241,6 +241,7 @@ public class TaskInfo {
/** @hide */
public void addLaunchCookie(IBinder cookie) {
if (cookie == null || launchCookies.contains(cookie)) return;
launchCookies.add(cookie);
}

View File

@@ -40,7 +40,7 @@ interface ITaskOrganizerController {
void unregisterTaskOrganizer(ITaskOrganizer organizer);
/** Creates a persistent root task in WM for a particular windowing-mode. */
ActivityManager.RunningTaskInfo createRootTask(int displayId, int windowingMode);
void createRootTask(int displayId, int windowingMode, IBinder launchCookie);
/** Deletes a persistent root task in WM */
boolean deleteRootTask(in WindowContainerToken task);

View File

@@ -23,6 +23,7 @@ import android.annotation.Nullable;
import android.annotation.RequiresPermission;
import android.annotation.TestApi;
import android.app.ActivityManager;
import android.os.IBinder;
import android.os.RemoteException;
import android.view.SurfaceControl;
@@ -101,12 +102,18 @@ public class TaskOrganizer extends WindowOrganizer {
@BinderThread
public void onBackPressedOnTaskRoot(@NonNull ActivityManager.RunningTaskInfo taskInfo) {}
/** Creates a persistent root task in WM for a particular windowing-mode. */
/**
* Creates a persistent root task in WM for a particular windowing-mode.
* @param displayId The display to create the root task on.
* @param windowingMode Windowing mode to put the root task in.
* @param launchCookie Launch cookie to associate with the task so that is can be identified
* when the {@link ITaskOrganizer#onTaskAppeared} callback is called.
*/
@RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS)
@Nullable
public ActivityManager.RunningTaskInfo createRootTask(int displayId, int windowingMode) {
public void createRootTask(int displayId, int windowingMode, @Nullable IBinder launchCookie) {
try {
return mTaskOrganizerController.createRootTask(displayId, windowingMode);
mTaskOrganizerController.createRootTask(displayId, windowingMode, launchCookie);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}

View File

@@ -2923,6 +2923,12 @@
"group": "WM_DEBUG_ORIENTATION",
"at": "com\/android\/server\/wm\/TaskDisplayArea.java"
},
"1396893178": {
"message": "createRootTask unknown displayId=%d",
"level": "ERROR",
"group": "WM_DEBUG_WINDOW_ORGANIZER",
"at": "com\/android\/server\/wm\/TaskOrganizerController.java"
},
"1401295262": {
"message": "Mode default, asking user",
"level": "WARN",

View File

@@ -37,6 +37,18 @@
"group": "WM_SHELL_TASK_ORG",
"at": "com\/android\/wm\/shell\/ShellTaskOrganizer.java"
},
"-1325223370": {
"message": "Task appeared taskId=%d listener=%s",
"level": "VERBOSE",
"group": "WM_SHELL_TASK_ORG",
"at": "com\/android\/wm\/shell\/ShellTaskOrganizer.java"
},
"-1312360667": {
"message": "createRootTask() displayId=%d winMode=%d listener=%s",
"level": "VERBOSE",
"group": "WM_SHELL_TASK_ORG",
"at": "com\/android\/wm\/shell\/ShellTaskOrganizer.java"
},
"-1006733970": {
"message": "Display added: %d",
"level": "VERBOSE",
@@ -61,6 +73,12 @@
"group": "WM_SHELL_TASK_ORG",
"at": "com\/android\/wm\/shell\/LetterboxTaskListener.java"
},
"-842742255": {
"message": "%s onTaskAppeared unknown taskId=%d winMode=%d",
"level": "VERBOSE",
"group": "WM_SHELL_TASK_ORG",
"at": "com\/android\/wm\/shell\/splitscreen\/SplitScreenTaskListener.java"
},
"-712674749": {
"message": "Clip description: %s",
"level": "VERBOSE",
@@ -73,11 +91,11 @@
"group": "WM_SHELL_DRAG_AND_DROP",
"at": "com\/android\/wm\/shell\/draganddrop\/DragLayout.java"
},
"-460572385": {
"message": "Task appeared taskId=%d",
"-679492476": {
"message": "%s onTaskAppeared Primary taskId=%d",
"level": "VERBOSE",
"group": "WM_SHELL_TASK_ORG",
"at": "com\/android\/wm\/shell\/ShellTaskOrganizer.java"
"at": "com\/android\/wm\/shell\/splitscreen\/SplitScreenTaskListener.java"
},
"-191422040": {
"message": "Transition animations finished, notifying core %s",
@@ -85,6 +103,12 @@
"group": "WM_SHELL_TRANSITIONS",
"at": "com\/android\/wm\/shell\/Transitions.java"
},
"154313206": {
"message": "%s onTaskAppeared Secondary taskId=%d",
"level": "VERBOSE",
"group": "WM_SHELL_TASK_ORG",
"at": "com\/android\/wm\/shell\/splitscreen\/SplitScreenTaskListener.java"
},
"157713005": {
"message": "Task info changed taskId=%d",
"level": "VERBOSE",
@@ -162,6 +186,12 @@
"level": "VERBOSE",
"group": "WM_SHELL_DRAG_AND_DROP",
"at": "com\/android\/wm\/shell\/draganddrop\/DragAndDropController.java"
},
"2135461748": {
"message": "%s onTaskAppeared Supported",
"level": "VERBOSE",
"group": "WM_SHELL_TASK_ORG",
"at": "com\/android\/wm\/shell\/splitscreen\/SplitScreenTaskListener.java"
}
},
"groups": {

View File

@@ -20,8 +20,6 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
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;
import static com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_TASK_ORG;
@@ -29,6 +27,7 @@ import static com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_TASK_ORG
import android.annotation.IntDef;
import android.app.ActivityManager.RunningTaskInfo;
import android.app.WindowConfiguration.WindowingMode;
import android.os.Binder;
import android.os.IBinder;
import android.util.ArrayMap;
import android.util.Log;
@@ -63,15 +62,13 @@ public class ShellTaskOrganizer extends TaskOrganizer {
public static final int TASK_LISTENER_TYPE_FULLSCREEN = -2;
public static final int TASK_LISTENER_TYPE_MULTI_WINDOW = -3;
public static final int TASK_LISTENER_TYPE_PIP = -4;
public static final int TASK_LISTENER_TYPE_SPLIT_SCREEN = -5;
public static final int TASK_LISTENER_TYPE_LETTERBOX = -6;
public static final int TASK_LISTENER_TYPE_LETTERBOX = -5;
@IntDef(prefix = {"TASK_LISTENER_TYPE_"}, value = {
TASK_LISTENER_TYPE_UNDEFINED,
TASK_LISTENER_TYPE_FULLSCREEN,
TASK_LISTENER_TYPE_MULTI_WINDOW,
TASK_LISTENER_TYPE_PIP,
TASK_LISTENER_TYPE_SPLIT_SCREEN,
TASK_LISTENER_TYPE_LETTERBOX,
})
public @interface TaskListenerType {}
@@ -139,6 +136,14 @@ public class ShellTaskOrganizer extends TaskOrganizer {
}
}
public void createRootTask(int displayId, int windowingMode, TaskListener listener) {
ProtoLog.v(WM_SHELL_TASK_ORG, "createRootTask() displayId=%d winMode=%d listener=%s",
displayId, windowingMode, listener.toString());
final IBinder cookie = new Binder();
setPendingLaunchCookieListener(cookie, listener);
super.createRootTask(displayId, windowingMode, cookie);
}
/**
* Adds a listener for a specific task id.
*/
@@ -238,10 +243,10 @@ public class ShellTaskOrganizer extends TaskOrganizer {
private void onTaskAppeared(TaskAppearedInfo info) {
final int taskId = info.getTaskInfo().taskId;
ProtoLog.v(WM_SHELL_TASK_ORG, "Task appeared taskId=%d", taskId);
mTasks.put(taskId, info);
final TaskListener listener =
getTaskListener(info.getTaskInfo(), true /*removeLaunchCookieIfNeeded*/);
ProtoLog.v(WM_SHELL_TASK_ORG, "Task appeared taskId=%d listener=%s", taskId, listener);
if (listener != null) {
listener.onTaskAppeared(info.getTaskInfo(), info.getLeash());
}
@@ -336,7 +341,7 @@ public class ShellTaskOrganizer extends TaskOrganizer {
}
@WindowingMode
private static int getWindowingMode(RunningTaskInfo taskInfo) {
public static int getWindowingMode(RunningTaskInfo taskInfo) {
return taskInfo.configuration.windowConfiguration.getWindowingMode();
}
@@ -350,9 +355,6 @@ public class ShellTaskOrganizer extends TaskOrganizer {
: TASK_LISTENER_TYPE_FULLSCREEN;
case WINDOWING_MODE_MULTI_WINDOW:
return TASK_LISTENER_TYPE_MULTI_WINDOW;
case WINDOWING_MODE_SPLIT_SCREEN_PRIMARY:
case WINDOWING_MODE_SPLIT_SCREEN_SECONDARY:
return TASK_LISTENER_TYPE_SPLIT_SCREEN;
case WINDOWING_MODE_PINNED:
return TASK_LISTENER_TYPE_PIP;
case WINDOWING_MODE_FREEFORM:
@@ -370,8 +372,6 @@ public class ShellTaskOrganizer extends TaskOrganizer {
return "TASK_LISTENER_TYPE_LETTERBOX";
case TASK_LISTENER_TYPE_MULTI_WINDOW:
return "TASK_LISTENER_TYPE_MULTI_WINDOW";
case TASK_LISTENER_TYPE_SPLIT_SCREEN:
return "TASK_LISTENER_TYPE_SPLIT_SCREEN";
case TASK_LISTENER_TYPE_PIP:
return "TASK_LISTENER_TYPE_PIP";
case TASK_LISTENER_TYPE_UNDEFINED:

View File

@@ -40,7 +40,7 @@ class DividerImeController implements DisplayImeController.ImePositionProcessor
private static final float ADJUSTED_NONFOCUS_DIM = 0.3f;
private final SplitScreenTaskOrganizer mSplits;
private final SplitScreenTaskListener mSplits;
private final TransactionPool mTransactionPool;
private final Handler mHandler;
private final TaskOrganizer mTaskOrganizer;
@@ -92,7 +92,7 @@ class DividerImeController implements DisplayImeController.ImePositionProcessor
private boolean mPausedTargetAdjusted = false;
private boolean mAdjustedWhileHidden = false;
DividerImeController(SplitScreenTaskOrganizer splits, TransactionPool pool, Handler handler,
DividerImeController(SplitScreenTaskListener splits, TransactionPool pool, Handler handler,
TaskOrganizer taskOrganizer) {
mSplits = splits;
mTransactionPool = pool;

View File

@@ -155,7 +155,7 @@ public class DividerView extends FrameLayout implements OnTouchListener,
private boolean mAdjustedForIme;
private DividerState mState;
private SplitScreenTaskOrganizer mTiles;
private SplitScreenTaskListener mTiles;
boolean mFirstLayout = true;
int mDividerPositionX;
int mDividerPositionY;
@@ -354,7 +354,7 @@ public class DividerView extends FrameLayout implements OnTouchListener,
void injectDependencies(SplitScreenController splitScreenController,
DividerWindowManager windowManager, DividerState dividerState,
DividerCallbacks callback, SplitScreenTaskOrganizer tiles, SplitDisplayLayout sdl,
DividerCallbacks callback, SplitScreenTaskListener tiles, SplitDisplayLayout sdl,
DividerImeController imeController, WindowManagerProxy wmProxy) {
mSplitScreenController = splitScreenController;
mWindowManager = windowManager;

View File

@@ -47,7 +47,7 @@ public class SplitDisplayLayout {
private static final int DIVIDER_WIDTH_INACTIVE_DP = 4;
SplitScreenTaskOrganizer mTiles;
SplitScreenTaskListener mTiles;
DisplayLayout mDisplayLayout;
Context mContext;
@@ -62,7 +62,7 @@ public class SplitDisplayLayout {
Rect mAdjustedPrimary = null;
Rect mAdjustedSecondary = null;
public SplitDisplayLayout(Context ctx, DisplayLayout dl, SplitScreenTaskOrganizer taskTiles) {
public SplitDisplayLayout(Context ctx, DisplayLayout dl, SplitScreenTaskListener taskTiles) {
mTiles = taskTiles;
mDisplayLayout = dl;
mContext = ctx;

View File

@@ -75,7 +75,7 @@ public class SplitScreenController implements SplitScreen,
private final DividerState mDividerState = new DividerState();
private final ForcedResizableInfoActivityController mForcedResizableController;
private final Handler mHandler;
private final SplitScreenTaskOrganizer mSplits;
private final SplitScreenTaskListener mSplits;
private final SystemWindows mSystemWindows;
final TransactionPool mTransactionPool;
private final WindowManagerProxy mWindowManagerProxy;
@@ -117,7 +117,7 @@ public class SplitScreenController implements SplitScreen,
mTransactionPool = transactionPool;
mWindowManagerProxy = new WindowManagerProxy(syncQueue, shellTaskOrganizer);
mTaskOrganizer = shellTaskOrganizer;
mSplits = new SplitScreenTaskOrganizer(this, shellTaskOrganizer);
mSplits = new SplitScreenTaskListener(this, shellTaskOrganizer);
mImePositionProcessor = new DividerImeController(mSplits, mTransactionPool, mHandler,
shellTaskOrganizer);
mRotationController =
@@ -164,6 +164,14 @@ public class SplitScreenController implements SplitScreen,
// Don't initialize the divider or anything until we get the default display.
}
void onSplitScreenSupported() {
// Set starting tile bounds based on middle target
final WindowContainerTransaction tct = new WindowContainerTransaction();
int midPos = mSplitLayout.getSnapAlgorithm().getMiddleTarget().position;
mSplitLayout.resizeSplits(midPos, tct);
mTaskOrganizer.applyTransaction(tct);
}
@Override
public boolean isSplitScreenSupported() {
return mSplits.isSplitScreenSupported();
@@ -196,11 +204,6 @@ public class SplitScreenController implements SplitScreen,
}
try {
mSplits.init();
// Set starting tile bounds based on middle target
final WindowContainerTransaction tct = new WindowContainerTransaction();
int midPos = mSplitLayout.getSnapAlgorithm().getMiddleTarget().position;
mSplitLayout.resizeSplits(midPos, tct);
mTaskOrganizer.applyTransaction(tct);
} catch (Exception e) {
Slog.e(TAG, "Failed to register docked stack listener", e);
removeDivider();

View File

@@ -23,25 +23,24 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMAR
import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
import static android.view.Display.DEFAULT_DISPLAY;
import static com.android.wm.shell.ShellTaskOrganizer.TASK_LISTENER_TYPE_SPLIT_SCREEN;
import static com.android.wm.shell.ShellTaskOrganizer.taskListenerTypeToString;
import static com.android.wm.shell.ShellTaskOrganizer.getWindowingMode;
import static com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_TASK_ORG;
import android.app.ActivityManager.RunningTaskInfo;
import android.graphics.Rect;
import android.os.RemoteException;
import android.util.Log;
import android.view.Display;
import android.view.SurfaceControl;
import android.view.SurfaceSession;
import androidx.annotation.NonNull;
import com.android.internal.protolog.common.ProtoLog;
import com.android.wm.shell.ShellTaskOrganizer;
import java.io.PrintWriter;
class SplitScreenTaskOrganizer implements ShellTaskOrganizer.TaskListener {
private static final String TAG = "SplitScreenTaskOrg";
class SplitScreenTaskListener implements ShellTaskOrganizer.TaskListener {
private static final String TAG = "SplitScreenTaskListener";
private static final boolean DEBUG = SplitScreenController.DEBUG;
private final ShellTaskOrganizer mTaskOrganizer;
@@ -58,20 +57,19 @@ class SplitScreenTaskOrganizer implements ShellTaskOrganizer.TaskListener {
final SurfaceSession mSurfaceSession = new SurfaceSession();
SplitScreenTaskOrganizer(SplitScreenController splitScreenController,
SplitScreenTaskListener(SplitScreenController splitScreenController,
ShellTaskOrganizer shellTaskOrganizer) {
mSplitScreenController = splitScreenController;
mTaskOrganizer = shellTaskOrganizer;
mTaskOrganizer.addListenerForType(this, TASK_LISTENER_TYPE_SPLIT_SCREEN);
}
void init() throws RemoteException {
void init() {
synchronized (this) {
try {
mPrimary = mTaskOrganizer.createRootTask(Display.DEFAULT_DISPLAY,
WINDOWING_MODE_SPLIT_SCREEN_PRIMARY);
mSecondary = mTaskOrganizer.createRootTask(Display.DEFAULT_DISPLAY,
WINDOWING_MODE_SPLIT_SCREEN_SECONDARY);
mTaskOrganizer.createRootTask(
DEFAULT_DISPLAY, WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, this);
mTaskOrganizer.createRootTask(
DEFAULT_DISPLAY, WINDOWING_MODE_SPLIT_SCREEN_SECONDARY, this);
} catch (Exception e) {
// teardown to prevent callbacks
mTaskOrganizer.removeListener(this);
@@ -95,19 +93,26 @@ class SplitScreenTaskOrganizer implements ShellTaskOrganizer.TaskListener {
@Override
public void onTaskAppeared(RunningTaskInfo taskInfo, SurfaceControl leash) {
synchronized (this) {
if (mPrimary == null || mSecondary == null) {
Log.w(TAG, "Received onTaskAppeared before creating root tasks " + taskInfo);
return;
}
if (taskInfo.token.equals(mPrimary.token)) {
final int winMode = getWindowingMode(taskInfo);
if (winMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) {
ProtoLog.v(WM_SHELL_TASK_ORG,
"%s onTaskAppeared Primary taskId=%d", TAG, taskInfo.taskId);
mPrimary = taskInfo;
mPrimarySurface = leash;
} else if (taskInfo.token.equals(mSecondary.token)) {
} else if (winMode == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY) {
ProtoLog.v(WM_SHELL_TASK_ORG,
"%s onTaskAppeared Secondary taskId=%d", TAG, taskInfo.taskId);
mSecondary = taskInfo;
mSecondarySurface = leash;
} else {
ProtoLog.v(WM_SHELL_TASK_ORG, "%s onTaskAppeared unknown taskId=%d winMode=%d",
TAG, taskInfo.taskId, winMode);
}
if (!mSplitScreenSupported && mPrimarySurface != null && mSecondarySurface != null) {
mSplitScreenSupported = true;
mSplitScreenController.onSplitScreenSupported();
ProtoLog.v(WM_SHELL_TASK_ORG, "%s onTaskAppeared Supported", TAG);
// Initialize dim surfaces:
mPrimaryDim = new SurfaceControl.Builder(mSurfaceSession)
@@ -240,10 +245,13 @@ class SplitScreenTaskOrganizer implements ShellTaskOrganizer.TaskListener {
final String innerPrefix = prefix + " ";
final String childPrefix = innerPrefix + " ";
pw.println(prefix + this);
pw.println(innerPrefix + "mSplitScreenSupported=" + mSplitScreenSupported);
if (mPrimary != null) pw.println(innerPrefix + "mPrimary.taskId=" + mPrimary.taskId);
if (mSecondary != null) pw.println(innerPrefix + "mSecondary.taskId=" + mSecondary.taskId);
}
@Override
public String toString() {
return TAG + ":" + taskListenerTypeToString(TASK_LISTENER_TYPE_SPLIT_SCREEN);
return TAG;
}
}

View File

@@ -88,7 +88,7 @@ class WindowManagerProxy {
mTaskOrganizer = taskOrganizer;
}
void dismissOrMaximizeDocked(final SplitScreenTaskOrganizer tiles, SplitDisplayLayout layout,
void dismissOrMaximizeDocked(final SplitScreenTaskListener tiles, SplitDisplayLayout layout,
final boolean dismissOrMaximize) {
mExecutor.execute(() -> applyDismissSplit(tiles, layout, dismissOrMaximize));
}
@@ -189,7 +189,7 @@ class WindowManagerProxy {
*
* @return whether the home stack is resizable
*/
boolean applyEnterSplit(SplitScreenTaskOrganizer tiles, SplitDisplayLayout layout) {
boolean applyEnterSplit(SplitScreenTaskListener tiles, SplitDisplayLayout layout) {
// Set launchtile first so that any stack created after
// getAllRootTaskInfos and before reparent (even if unlikely) are placed
// correctly.
@@ -242,7 +242,7 @@ class WindowManagerProxy {
* split (thus resulting in the top of the secondary split becoming
* fullscreen. {@code false} resolves the other way.
*/
void applyDismissSplit(SplitScreenTaskOrganizer tiles, SplitDisplayLayout layout,
void applyDismissSplit(SplitScreenTaskListener tiles, SplitDisplayLayout layout,
boolean dismissOrMaximize) {
// Set launch root first so that any task created after getChildContainers and
// before reparent (pretty unlikely) are put into fullscreen.

View File

@@ -795,6 +795,10 @@ class Task extends WindowContainer<WindowContainer> {
*/
boolean mTaskAppearedSent;
// If the sending of the task appear signal should be deferred until this flag is set back to
// false.
private boolean mDeferTaskAppear;
/**
* This task was created by the task organizer which has the following implementations.
* <ul>
@@ -807,14 +811,20 @@ class Task extends WindowContainer<WindowContainer> {
@VisibleForTesting
boolean mCreatedByOrganizer;
// Tracking cookie for the creation of this task.
IBinder mLaunchCookie;
/**
* Don't use constructor directly. Use {@link TaskDisplayArea#createStackUnchecked()} instead.
*/
Task(ActivityTaskManagerService atmService, int id, int activityType,
ActivityInfo info, Intent intent, boolean createdByOrganizer) {
Task(ActivityTaskManagerService atmService, int id, int activityType, ActivityInfo info,
Intent intent, boolean createdByOrganizer, boolean deferTaskAppear,
IBinder launchCookie) {
this(atmService, id, info, intent, null /*voiceSession*/, null /*voiceInteractor*/,
null /*taskDescription*/, null /*stack*/);
mCreatedByOrganizer = createdByOrganizer;
mLaunchCookie = launchCookie;
mDeferTaskAppear = deferTaskAppear;
setActivityType(activityType);
}
@@ -4088,6 +4098,7 @@ class Task extends WindowContainer<WindowContainer> {
info.topActivityInfo = mReuseActivitiesReport.top != null
? mReuseActivitiesReport.top.info
: null;
info.addLaunchCookie(mLaunchCookie);
forAllActivities(r -> {
info.addLaunchCookie(r.mLaunchCookie);
});
@@ -4857,6 +4868,13 @@ class Task extends WindowContainer<WindowContainer> {
return mHasBeenVisible;
}
void setDeferTaskAppear(boolean deferTaskAppear) {
mDeferTaskAppear = deferTaskAppear;
if (!mDeferTaskAppear) {
sendTaskAppeared();
}
}
/** In the case that these conditions are true, we want to send the Task to the organizer:
* 1. An organizer has been set
* 2. The Task was created by the organizer
@@ -4871,6 +4889,10 @@ class Task extends WindowContainer<WindowContainer> {
return false;
}
if (mDeferTaskAppear) {
return false;
}
if (mCreatedByOrganizer) {
return true;
}

View File

@@ -50,6 +50,7 @@ import android.app.WindowConfiguration;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
import android.os.IBinder;
import android.os.UserHandle;
import android.util.IntArray;
import android.util.Slog;
@@ -996,6 +997,13 @@ final class TaskDisplayArea extends DisplayArea<Task> {
false /* createdByOrganizer */);
}
Task createStack(int windowingMode, int activityType, boolean onTop, ActivityInfo info,
Intent intent, boolean createdByOrganizer) {
return createStack(windowingMode, activityType, onTop, null /* info */, null /* intent */,
false /* createdByOrganizer */ , false /* deferTaskAppear */,
null /* launchCookie */);
}
/**
* Creates a stack matching the input windowing mode and activity type on this display.
*
@@ -1013,10 +1021,14 @@ final class TaskDisplayArea extends DisplayArea<Task> {
* @param intent The intent that started this task.
* @param createdByOrganizer @{code true} if this is created by task organizer, @{code false}
* otherwise.
* @param deferTaskAppear @{code true} if the task appeared signal should be deferred.
* @param launchCookie Launch cookie used for tracking/association of the task we are
* creating.
* @return The newly created stack.
*/
Task createStack(int windowingMode, int activityType, boolean onTop, ActivityInfo info,
Intent intent, boolean createdByOrganizer) {
Intent intent, boolean createdByOrganizer, boolean deferTaskAppear,
IBinder launchCookie) {
if (activityType == ACTIVITY_TYPE_UNDEFINED && !createdByOrganizer) {
// Can't have an undefined stack type yet...so re-map to standard. Anyone that wants
// anything else should be passing it in anyways...except for the task organizer.
@@ -1048,7 +1060,7 @@ final class TaskDisplayArea extends DisplayArea<Task> {
final int stackId = getNextStackId();
return createStackUnchecked(windowingMode, activityType, stackId, onTop, info, intent,
createdByOrganizer);
createdByOrganizer, deferTaskAppear, launchCookie);
}
/** @return the root task to create the next task in. */
@@ -1078,8 +1090,9 @@ final class TaskDisplayArea extends DisplayArea<Task> {
}
@VisibleForTesting
Task createStackUnchecked(int windowingMode, int activityType, int stackId,
boolean onTop, ActivityInfo info, Intent intent, boolean createdByOrganizer) {
Task createStackUnchecked(int windowingMode, int activityType, int stackId, boolean onTop,
ActivityInfo info, Intent intent, boolean createdByOrganizer, boolean deferTaskAppear,
IBinder launchCookie) {
if (windowingMode == WINDOWING_MODE_PINNED && activityType != ACTIVITY_TYPE_STANDARD) {
throw new IllegalArgumentException("Stack with windowing mode cannot with non standard "
+ "activity type.");
@@ -1097,7 +1110,7 @@ final class TaskDisplayArea extends DisplayArea<Task> {
}
final Task stack = new Task(mAtmService, stackId, activityType,
info, intent, createdByOrganizer);
info, intent, createdByOrganizer, deferTaskAppear, launchCookie);
if (launchRootTask != null) {
launchRootTask.addChild(stack, onTop ? POSITION_TOP : POSITION_BOTTOM);
if (onTop) {

View File

@@ -156,9 +156,8 @@ class TaskOrganizerController extends ITaskOrganizerController.Stub {
}
void onTaskInfoChanged(Task task, ActivityManager.RunningTaskInfo taskInfo) {
if (!task.mCreatedByOrganizer && !task.mTaskAppearedSent) {
// Skip if the task has not yet received taskAppeared(), except for tasks created
// by the organizer that don't receive that signal
if (!task.mTaskAppearedSent) {
// Skip if the task has not yet received taskAppeared().
return;
}
ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "Task info changed taskId=%d", task.mTaskId);
@@ -179,9 +178,8 @@ class TaskOrganizerController extends ITaskOrganizerController.Stub {
void onBackPressedOnTaskRoot(Task task) {
ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "Task back pressed on root taskId=%d",
task.mTaskId);
if (!task.mCreatedByOrganizer && !task.mTaskAppearedSent) {
// Skip if the task has not yet received taskAppeared(), except for tasks created
// by the organizer that don't receive that signal
if (!task.mTaskAppearedSent) {
// Skip if the task has not yet received taskAppeared().
return;
}
if (!task.isOrganized()) {
@@ -402,30 +400,39 @@ class TaskOrganizerController extends ITaskOrganizerController.Stub {
}
@Override
public RunningTaskInfo createRootTask(int displayId, int windowingMode) {
public void createRootTask(int displayId, int windowingMode, @Nullable IBinder launchCookie) {
enforceStackPermission("createRootTask()");
final long origId = Binder.clearCallingIdentity();
try {
synchronized (mGlobalLock) {
DisplayContent display = mService.mRootWindowContainer.getDisplayContent(displayId);
if (display == null) {
return null;
ProtoLog.e(WM_DEBUG_WINDOW_ORGANIZER,
"createRootTask unknown displayId=%d", displayId);
return;
}
ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "Create root task displayId=%d winMode=%d",
displayId, windowingMode);
final Task task = display.getDefaultTaskDisplayArea().createStack(windowingMode,
ACTIVITY_TYPE_UNDEFINED, false /* onTop */, null /* info */, new Intent(),
true /* createdByOrganizer */);
RunningTaskInfo out = task.getTaskInfo();
mLastSentTaskInfos.put(task, out);
return out;
createRootTask(display, windowingMode, launchCookie);
}
} finally {
Binder.restoreCallingIdentity(origId);
}
}
@VisibleForTesting
Task createRootTask(DisplayContent display, int windowingMode, @Nullable IBinder launchCookie) {
ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "Create root task displayId=%d winMode=%d",
display.mDisplayId, windowingMode);
// We want to defer the task appear signal until the task is fully created and attached to
// to the hierarchy so that the complete starting configuration is in the task info we send
// over to the organizer.
final Task task = display.getDefaultTaskDisplayArea().createStack(windowingMode,
ACTIVITY_TYPE_UNDEFINED, false /* onTop */, null /* info */, new Intent(),
true /* createdByOrganizer */, true /* deferTaskAppear */, launchCookie);
task.setDeferTaskAppear(false /* deferTaskAppear */);
return task;
}
@Override
public boolean deleteRootTask(WindowContainerToken token) {
enforceStackPermission("deleteRootTask()");

View File

@@ -245,9 +245,8 @@ public class ActivityStackTests extends WindowTestsBase {
.setStack(rootHomeTask)
.setCreateTask(true)
.build();
final Task secondaryStack = (Task) WindowContainer.fromBinder(
mAtm.mTaskOrganizerController.createRootTask(rootHomeTask.getDisplayId(),
WINDOWING_MODE_SPLIT_SCREEN_SECONDARY).token.asBinder());
final Task secondaryStack = mAtm.mTaskOrganizerController.createRootTask(
rootHomeTask.getDisplayContent(), WINDOWING_MODE_SPLIT_SCREEN_SECONDARY, null);
rootHomeTask.reparent(secondaryStack, POSITION_TOP);
assertEquals(secondaryStack, rootHomeTask.getParent());

View File

@@ -1022,7 +1022,7 @@ public class ActivityStarterTests extends WindowTestsBase {
assertThat(outActivity[0].inSplitScreenWindowingMode()).isFalse();
// Move activity to split-screen-primary stack and make sure it has the focus.
TestSplitOrganizer splitOrg = new TestSplitOrganizer(mAtm, top.getDisplayId());
TestSplitOrganizer splitOrg = new TestSplitOrganizer(mAtm, top.getDisplayContent());
top.getRootTask().reparent(splitOrg.mPrimary, POSITION_BOTTOM);
top.getRootTask().moveToFront("testWindowingModeOptionsLaunchAdjacent");

View File

@@ -479,21 +479,22 @@ public class WindowOrganizerTests extends WindowTestsBase {
@Test
public void testCreateDeleteRootTasks() {
RunningTaskInfo info1 = mWm.mAtmService.mTaskOrganizerController.createRootTask(
Display.DEFAULT_DISPLAY,
WINDOWING_MODE_SPLIT_SCREEN_PRIMARY);
DisplayContent dc = mWm.mRoot.getDisplayContent(Display.DEFAULT_DISPLAY);
Task task1 = mWm.mAtmService.mTaskOrganizerController.createRootTask(
dc, WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, null);
RunningTaskInfo info1 = task1.getTaskInfo();
assertEquals(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY,
info1.configuration.windowConfiguration.getWindowingMode());
assertEquals(ACTIVITY_TYPE_UNDEFINED, info1.topActivityType);
RunningTaskInfo info2 = mWm.mAtmService.mTaskOrganizerController.createRootTask(
Display.DEFAULT_DISPLAY,
WINDOWING_MODE_SPLIT_SCREEN_SECONDARY);
Task task2 = mWm.mAtmService.mTaskOrganizerController.createRootTask(
dc, WINDOWING_MODE_SPLIT_SCREEN_SECONDARY, null);
RunningTaskInfo info2 = task2.getTaskInfo();
assertEquals(WINDOWING_MODE_SPLIT_SCREEN_SECONDARY,
info2.configuration.windowConfiguration.getWindowingMode());
assertEquals(ACTIVITY_TYPE_UNDEFINED, info2.topActivityType);
DisplayContent dc = mWm.mRoot.getDisplayContent(Display.DEFAULT_DISPLAY);
List<Task> infos = getTasksCreatedByOrganizer(dc);
assertEquals(2, infos.size());
@@ -521,8 +522,9 @@ public class WindowOrganizerTests extends WindowTestsBase {
}
};
mWm.mAtmService.mTaskOrganizerController.registerTaskOrganizer(listener);
RunningTaskInfo info1 = mWm.mAtmService.mTaskOrganizerController.createRootTask(
mDisplayContent.mDisplayId, WINDOWING_MODE_SPLIT_SCREEN_SECONDARY);
Task task = mWm.mAtmService.mTaskOrganizerController.createRootTask(
mDisplayContent, WINDOWING_MODE_SPLIT_SCREEN_SECONDARY, null);
RunningTaskInfo info1 = task.getTaskInfo();
final Task stack = createTaskStackOnDisplay(
WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_STANDARD, mDisplayContent);
@@ -579,8 +581,9 @@ public class WindowOrganizerTests extends WindowTestsBase {
}
};
mWm.mAtmService.mTaskOrganizerController.registerTaskOrganizer(listener);
RunningTaskInfo info1 = mWm.mAtmService.mTaskOrganizerController.createRootTask(
mDisplayContent.mDisplayId, WINDOWING_MODE_SPLIT_SCREEN_SECONDARY);
Task task = mWm.mAtmService.mTaskOrganizerController.createRootTask(
mDisplayContent, WINDOWING_MODE_SPLIT_SCREEN_SECONDARY, null);
RunningTaskInfo info1 = task.getTaskInfo();
lastReportedTiles.clear();
called[0] = false;
@@ -640,10 +643,13 @@ public class WindowOrganizerTests extends WindowTestsBase {
}
};
mWm.mAtmService.mTaskOrganizerController.registerTaskOrganizer(listener);
RunningTaskInfo info1 = mWm.mAtmService.mTaskOrganizerController.createRootTask(
mDisplayContent.mDisplayId, WINDOWING_MODE_SPLIT_SCREEN_PRIMARY);
RunningTaskInfo info2 = mWm.mAtmService.mTaskOrganizerController.createRootTask(
mDisplayContent.mDisplayId, WINDOWING_MODE_SPLIT_SCREEN_SECONDARY);
Task task1 = mWm.mAtmService.mTaskOrganizerController.createRootTask(
mDisplayContent, WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, null);
RunningTaskInfo info1 = task1.getTaskInfo();
Task task2 = mWm.mAtmService.mTaskOrganizerController.createRootTask(
mDisplayContent, WINDOWING_MODE_SPLIT_SCREEN_SECONDARY, null);
RunningTaskInfo info2 = task2.getTaskInfo();
final int initialRootTaskCount = mWm.mAtmService.mTaskOrganizerController.getRootTasks(
mDisplayContent.mDisplayId, null /* activityTypes */).size();

View File

@@ -973,8 +973,9 @@ class WindowTestsBase extends SystemServiceTestsBase {
final int taskId = mTaskId >= 0 ? mTaskId : mTaskDisplayArea.getNextStackId();
if (mParentTask == null) {
task = mTaskDisplayArea.createStackUnchecked(
mWindowingMode, mActivityType, taskId, mOnTop, mActivityInfo,
mIntent, false /* createdByOrganizer */);
mWindowingMode, mActivityType, taskId, mOnTop, mActivityInfo, mIntent,
false /* createdByOrganizer */, false /* deferTaskAppear */,
null /* launchCookie */);
} else {
task = new Task(mSupervisor.mService, taskId, mActivityInfo,
mIntent /*intent*/, mVoiceSession, null /*_voiceInteractor*/,
@@ -1016,20 +1017,17 @@ class WindowTestsBase extends SystemServiceTestsBase {
// moves everything to secondary. Most tests expect this since sysui usually does it.
boolean mMoveToSecondaryOnEnter = true;
int mDisplayId;
TestSplitOrganizer(ActivityTaskManagerService service, int displayId) {
TestSplitOrganizer(ActivityTaskManagerService service, DisplayContent display) {
mService = service;
mDisplayId = displayId;
mDisplayId = display.mDisplayId;
mService.mTaskOrganizerController.registerTaskOrganizer(this);
WindowContainerToken primary = mService.mTaskOrganizerController.createRootTask(
displayId, WINDOWING_MODE_SPLIT_SCREEN_PRIMARY).token;
mPrimary = WindowContainer.fromBinder(primary.asBinder()).asTask();
WindowContainerToken secondary = mService.mTaskOrganizerController.createRootTask(
displayId, WINDOWING_MODE_SPLIT_SCREEN_SECONDARY).token;
mSecondary = WindowContainer.fromBinder(secondary.asBinder()).asTask();
mPrimary = mService.mTaskOrganizerController.createRootTask(
display, WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, null);
mSecondary = mService.mTaskOrganizerController.createRootTask(
display, WINDOWING_MODE_SPLIT_SCREEN_SECONDARY, null);;
}
TestSplitOrganizer(ActivityTaskManagerService service) {
this(service,
service.mStackSupervisor.mRootWindowContainer.getDefaultDisplay().mDisplayId);
this(service, service.mStackSupervisor.mRootWindowContainer.getDefaultDisplay());
}
public void setMoveToSecondaryOnEnter(boolean move) {
mMoveToSecondaryOnEnter = move;