diff options
28 files changed, 346 insertions, 153 deletions
diff --git a/api/test-current.txt b/api/test-current.txt index 38b15b418a4a..f10e3d679e08 100644 --- a/api/test-current.txt +++ b/api/test-current.txt @@ -3866,7 +3866,9 @@ package android.app { method public void removeOnUidImportanceListener(android.app.ActivityManager.OnUidImportanceListener); method public void removeStacksInWindowingModes(int[]) throws java.lang.SecurityException; method public void removeStacksWithActivityTypes(int[]) throws java.lang.SecurityException; + method public void resizeStack(int, android.graphics.Rect) throws java.lang.SecurityException; method public deprecated void restartPackage(java.lang.String); + method public void setTaskWindowingMode(int, int, boolean) throws java.lang.SecurityException; method public static void setVrThread(int); method public void setWatchHeapLimit(long); method public static boolean supportsMultiWindow(android.content.Context); @@ -4019,11 +4021,7 @@ package android.app { } public static class ActivityManager.StackId { - field public static final int DOCKED_STACK_ID = 3; // 0x3 - field public static final int FREEFORM_WORKSPACE_STACK_ID = 2; // 0x2 - field public static final int FULLSCREEN_WORKSPACE_STACK_ID = 1; // 0x1 field public static final int INVALID_STACK_ID = -1; // 0xffffffff - field public static final int PINNED_STACK_ID = 4; // 0x4 } public static class ActivityManager.TaskDescription implements android.os.Parcelable { diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java index 26f96fbeede1..5e61727fc1c3 100644 --- a/core/java/android/app/ActivityManager.java +++ b/core/java/android/app/ActivityManager.java @@ -16,10 +16,10 @@ package android.app; -import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY; import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM; import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; 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; @@ -674,16 +674,20 @@ public class ActivityManager { * @hide */ private static final int FIRST_STATIC_STACK_ID = 0; - /** ID of stack where fullscreen activities are normally launched into. */ + /** ID of stack where fullscreen activities are normally launched into. + * @hide */ public static final int FULLSCREEN_WORKSPACE_STACK_ID = 1; - /** ID of stack where freeform/resized activities are normally launched into. */ + /** ID of stack where freeform/resized activities are normally launched into. + * @hide */ public static final int FREEFORM_WORKSPACE_STACK_ID = FULLSCREEN_WORKSPACE_STACK_ID + 1; - /** ID of stack that occupies a dedicated region of the screen. */ + /** ID of stack that occupies a dedicated region of the screen. + * @hide */ public static final int DOCKED_STACK_ID = FREEFORM_WORKSPACE_STACK_ID + 1; - /** ID of stack that always on top (always visible) when it exist. */ + /** ID of stack that always on top (always visible) when it exist. + * @hide */ public static final int PINNED_STACK_ID = DOCKED_STACK_ID + 1; /** Last static stack stack ID. @@ -1531,6 +1535,12 @@ public class ActivityManager { */ public int resizeMode; + /** + * The current configuration this task is in. + * @hide + */ + final public Configuration configuration = new Configuration(); + public RecentTaskInfo() { } @@ -1576,6 +1586,7 @@ public class ActivityManager { } dest.writeInt(supportsSplitScreenMultiWindow ? 1 : 0); dest.writeInt(resizeMode); + configuration.writeToParcel(dest, flags); } public void readFromParcel(Parcel source) { @@ -1600,6 +1611,7 @@ public class ActivityManager { Rect.CREATOR.createFromParcel(source) : null; supportsSplitScreenMultiWindow = source.readInt() == 1; resizeMode = source.readInt(); + configuration.readFromParcel(source); } public static final Creator<RecentTaskInfo> CREATOR @@ -1798,7 +1810,7 @@ public class ActivityManager { * The full configuration the task is currently running in. * @hide */ - public Configuration configuration = new Configuration(); + final public Configuration configuration = new Configuration(); public RunningTaskInfo() { } @@ -2025,12 +2037,49 @@ public class ActivityManager { } /** + * Sets the windowing mode for a specific task. Only works on tasks of type + * {@link WindowConfiguration#ACTIVITY_TYPE_STANDARD} + * @param taskId The id of the task to set the windowing mode for. + * @param windowingMode The windowing mode to set for the task. + * @param toTop If the task should be moved to the top once the windowing mode changes. + * @hide + */ + @TestApi + @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) + public void setTaskWindowingMode(int taskId, int windowingMode, boolean toTop) + throws SecurityException { + try { + getService().setTaskWindowingMode(taskId, windowingMode, toTop); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * Resizes the input stack id to the given bounds. + * @param stackId Id of the stack to resize. + * @param bounds Bounds to resize the stack to or {@code null} for fullscreen. + * @hide + */ + @TestApi + @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) + public void resizeStack(int stackId, Rect bounds) throws SecurityException { + try { + getService().resizeStack(stackId, bounds, false /* allowResizeInDockedMode */, + false /* preserveWindows */, false /* animate */, -1 /* animationDuration */); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** * Removes stacks in the windowing modes from the system if they are of activity type * ACTIVITY_TYPE_STANDARD or ACTIVITY_TYPE_UNDEFINED * * @hide */ @TestApi + @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) public void removeStacksInWindowingModes(int[] windowingModes) throws SecurityException { try { getService().removeStacksInWindowingModes(windowingModes); @@ -2045,6 +2094,7 @@ public class ActivityManager { * @hide */ @TestApi + @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS) public void removeStacksWithActivityTypes(int[] activityTypes) throws SecurityException { try { getService().removeStacksWithActivityTypes(activityTypes); @@ -2535,7 +2585,7 @@ public class ActivityManager { * The full configuration the stack is currently running in. * @hide */ - public Configuration configuration = new Configuration(); + final public Configuration configuration = new Configuration(); @Override public int describeContents() { diff --git a/core/java/android/app/IActivityManager.aidl b/core/java/android/app/IActivityManager.aidl index 955b46300ea0..f03951607678 100644 --- a/core/java/android/app/IActivityManager.aidl +++ b/core/java/android/app/IActivityManager.aidl @@ -361,6 +361,15 @@ interface IActivityManager { void killUid(int appId, int userId, in String reason); void setUserIsMonkey(boolean monkey); void hang(in IBinder who, boolean allowRestart); + + /** + * Sets the windowing mode for a specific task. Only works on tasks of type + * {@link WindowConfiguration#ACTIVITY_TYPE_STANDARD} + * @param taskId The id of the task to set the windowing mode for. + * @param windowingMode The windowing mode to set for the task. + * @param toTop If the task should be moved to the top once the windowing mode changes. + */ + void setTaskWindowingMode(int taskId, int windowingMode, boolean toTop); void moveTaskToStack(int taskId, int stackId, boolean toTop); /** * Resizes the input stack id to the given bounds. @@ -490,6 +499,18 @@ interface IActivityManager { in int[] verticalSizeConfigurations, in int[] smallestWidthConfigurations); boolean moveTaskToDockedStack(int taskId, int createMode, boolean toTop, boolean animate, in Rect initialBounds); + /** + * Dismisses split-screen multi-window mode. + * {@param toTop} If true the current primary split-screen stack will be placed or left on top. + */ + void dismissSplitScreenMode(boolean toTop); + /** + * Dismisses PiP + * @param animate True if the dismissal should be animated. + * @param animationDuration The duration of the resize animation in milliseconds or -1 if the + * default animation duration should be used. + */ + void dismissPip(boolean animate, int animationDuration); void suppressResizeConfigChanges(boolean suppress); void moveTasksToFullscreenStack(int fromStackId, boolean onTop); boolean moveTopActivityToPinnedStack(int stackId, in Rect bounds); diff --git a/core/java/android/app/ITaskStackListener.aidl b/core/java/android/app/ITaskStackListener.aidl index a56965bdbd4d..2e1e9889eadc 100644 --- a/core/java/android/app/ITaskStackListener.aidl +++ b/core/java/android/app/ITaskStackListener.aidl @@ -30,7 +30,7 @@ oneway interface ITaskStackListener { void onTaskStackChanged(); /** Called whenever an Activity is moved to the pinned stack from another stack. */ - void onActivityPinned(String packageName, int userId, int taskId); + void onActivityPinned(String packageName, int userId, int taskId, int stackId); /** Called whenever an Activity is moved from the pinned stack to another stack. */ void onActivityUnpinned(); diff --git a/core/java/android/app/TaskStackListener.java b/core/java/android/app/TaskStackListener.java index 4674c9cd2389..402e2095a749 100644 --- a/core/java/android/app/TaskStackListener.java +++ b/core/java/android/app/TaskStackListener.java @@ -31,7 +31,7 @@ public abstract class TaskStackListener extends ITaskStackListener.Stub { } @Override - public void onActivityPinned(String packageName, int userId, int taskId) + public void onActivityPinned(String packageName, int userId, int taskId, int stackId) throws RemoteException { } diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java index 58243b487d64..f8996aae9a20 100644 --- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java +++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java @@ -16,7 +16,6 @@ package com.android.systemui.pip.phone; -import static android.app.ActivityManager.StackId.PINNED_STACK_ID; import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED; import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED; import static android.view.Display.DEFAULT_DISPLAY; @@ -73,7 +72,7 @@ public class PipManager implements BasePipManager { */ TaskStackListener mTaskStackListener = new TaskStackListener() { @Override - public void onActivityPinned(String packageName, int userId, int taskId) { + public void onActivityPinned(String packageName, int userId, int taskId, int stackId) { mTouchHandler.onActivityPinned(); mMediaController.onActivityPinned(); mMenuController.onActivityPinned(); diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivityController.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivityController.java index d71d4def576c..9fb201b82d8c 100644 --- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivityController.java +++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivityController.java @@ -16,7 +16,6 @@ package com.android.systemui.pip.phone; -import static android.app.ActivityManager.StackId.PINNED_STACK_ID; import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED; import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED; diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java index eef0e7d46943..21a836c030cb 100644 --- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java +++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java @@ -16,7 +16,7 @@ package com.android.systemui.pip.phone; -import static android.app.ActivityManager.StackId.PINNED_STACK_ID; +import static android.app.ActivityManager.StackId.INVALID_STACK_ID; import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED; import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED; @@ -161,13 +161,7 @@ public class PipMotionHelper implements Handler.Callback { mMenuController.hideMenuWithoutResize(); mHandler.post(() -> { try { - if (skipAnimation) { - mActivityManager.moveTasksToFullscreenStack(PINNED_STACK_ID, true /* onTop */); - } else { - mActivityManager.resizeStack(PINNED_STACK_ID, null /* bounds */, - true /* allowResizeInDockedMode */, true /* preserveWindows */, - true /* animate */, EXPAND_STACK_TO_FULLSCREEN_DURATION); - } + mActivityManager.dismissPip(!skipAnimation, EXPAND_STACK_TO_FULLSCREEN_DURATION); } catch (RemoteException e) { Log.e(TAG, "Error expanding PiP activity", e); } @@ -185,7 +179,7 @@ public class PipMotionHelper implements Handler.Callback { mMenuController.hideMenuWithoutResize(); mHandler.post(() -> { try { - mActivityManager.removeStack(PINNED_STACK_ID); + mActivityManager.removeStacksInWindowingModes(new int[]{ WINDOWING_MODE_PINNED }); } catch (RemoteException e) { Log.e(TAG, "Failed to remove PiP", e); } @@ -540,7 +534,7 @@ public class PipMotionHelper implements Handler.Callback { return true; } - mActivityManager.resizeStack(PINNED_STACK_ID, toBounds, + mActivityManager.resizeStack(stackInfo.stackId, toBounds, false /* allowResizeInDockedMode */, true /* preserveWindows */, true /* animate */, duration); mBounds.set(toBounds); diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipUtils.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipUtils.java index 84410f2fdb1d..2f53de96db2d 100644 --- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipUtils.java +++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipUtils.java @@ -16,7 +16,6 @@ package com.android.systemui.pip.phone; -import static android.app.ActivityManager.StackId.PINNED_STACK_ID; import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED; import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED; diff --git a/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java b/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java index 6e8554901f45..e0445c16b50c 100644 --- a/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java +++ b/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java @@ -53,7 +53,7 @@ import java.io.PrintWriter; import java.util.ArrayList; import java.util.List; -import static android.app.ActivityManager.StackId.PINNED_STACK_ID; +import static android.app.ActivityManager.StackId.INVALID_STACK_ID; import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED; import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED; import static android.view.Display.DEFAULT_DISPLAY; @@ -123,6 +123,7 @@ public class PipManager implements BasePipManager { private int mLastOrientation = Configuration.ORIENTATION_UNDEFINED; private boolean mInitialized; private int mPipTaskId = TASK_ID_NO_PIP; + private int mPinnedStackId = INVALID_STACK_ID; private ComponentName mPipComponentName; private MediaController mPipMediaController; private String[] mLastPackagesResourceGranted; @@ -338,9 +339,11 @@ public class PipManager implements BasePipManager { mMediaSessionManager.removeOnActiveSessionsChangedListener(mActiveMediaSessionListener); if (removePipStack) { try { - mActivityManager.removeStack(PINNED_STACK_ID); + mActivityManager.removeStack(mPinnedStackId); } catch (RemoteException e) { Log.e(TAG, "removeStack failed", e); + } finally { + mPinnedStackId = INVALID_STACK_ID; } } for (int i = mListeners.size() - 1; i >= 0; --i) { @@ -426,7 +429,7 @@ public class PipManager implements BasePipManager { } try { int animationDurationMs = -1; - mActivityManager.resizeStack(PINNED_STACK_ID, mCurrentPipBounds, + mActivityManager.resizeStack(mPinnedStackId, mCurrentPipBounds, true, true, true, animationDurationMs); } catch (RemoteException e) { Log.e(TAG, "resizeStack failed", e); @@ -657,7 +660,7 @@ public class PipManager implements BasePipManager { } @Override - public void onActivityPinned(String packageName, int userId, int taskId) { + public void onActivityPinned(String packageName, int userId, int taskId, int stackId) { if (DEBUG) Log.d(TAG, "onActivityPinned()"); if (!checkCurrentUserId(mContext, DEBUG)) { return; @@ -668,6 +671,7 @@ public class PipManager implements BasePipManager { return; } if (DEBUG) Log.d(TAG, "PINNED_STACK:" + stackInfo); + mPinnedStackId = stackInfo.stackId; mPipTaskId = stackInfo.taskIds[stackInfo.taskIds.length - 1]; mPipComponentName = ComponentName.unflattenFromString( stackInfo.taskNames[stackInfo.taskNames.length - 1]); diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java index dc83333da2e8..3e2a5f3f2043 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java +++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java @@ -16,9 +16,9 @@ package com.android.systemui.recents; -import static android.app.ActivityManager.StackId.FREEFORM_WORKSPACE_STACK_ID; import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME; import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS; +import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM; import static android.view.View.MeasureSpec; import android.app.ActivityManager; @@ -173,7 +173,7 @@ public class RecentsImpl implements ActivityOptions.OnAnimationFinishedListener } @Override - public void onActivityPinned(String packageName, int userId, int taskId) { + public void onActivityPinned(String packageName, int userId, int taskId, int stackId) { // Check this is for the right user if (!checkCurrentUserId(mContext, false /* debug */)) { return; @@ -873,7 +873,9 @@ public class RecentsImpl implements ActivityOptions.OnAnimationFinishedListener getThumbnailTransitionActivityOptions(ActivityManager.RunningTaskInfo runningTask, Rect windowOverrideRect) { final boolean isLowRamDevice = Recents.getConfiguration().isLowRamDevice; - if (runningTask != null && runningTask.stackId == FREEFORM_WORKSPACE_STACK_ID) { + if (runningTask != null + && runningTask.configuration.windowConfiguration.getWindowingMode() + == WINDOWING_MODE_FREEFORM) { ArrayList<AppTransitionAnimationSpec> specs = new ArrayList<>(); ArrayList<Task> tasks = mDummyStackView.getStack().getStackTasks(); TaskStackLayoutAlgorithm stackLayout = mDummyStackView.getStackAlgorithm(); diff --git a/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java b/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java index 4580b1f5c1a3..bddf9a5983db 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java +++ b/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java @@ -16,8 +16,6 @@ package com.android.systemui.recents.misc; -import static android.app.ActivityManager.StackId.DOCKED_STACK_ID; -import static android.app.ActivityManager.StackId.FREEFORM_WORKSPACE_STACK_ID; import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME; import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS; import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD; @@ -177,7 +175,7 @@ public class SystemServicesProxy { public void onTaskStackChangedBackground() { } public void onTaskStackChanged() { } public void onTaskSnapshotChanged(int taskId, TaskSnapshot snapshot) { } - public void onActivityPinned(String packageName, int userId, int taskId) { } + public void onActivityPinned(String packageName, int userId, int taskId, int stackId) { } public void onActivityUnpinned() { } public void onPinnedActivityRestartAttempt(boolean clearedTask) { } public void onPinnedStackAnimationStarted() { } @@ -232,10 +230,11 @@ public class SystemServicesProxy { } @Override - public void onActivityPinned(String packageName, int userId, int taskId) + public void onActivityPinned(String packageName, int userId, int taskId, int stackId) throws RemoteException { mHandler.removeMessages(H.ON_ACTIVITY_PINNED); - mHandler.obtainMessage(H.ON_ACTIVITY_PINNED, userId, taskId, packageName).sendToTarget(); + mHandler.obtainMessage(H.ON_ACTIVITY_PINNED, + new PinnedActivityInfo(packageName, userId, taskId, stackId)).sendToTarget(); } @Override @@ -618,13 +617,6 @@ public class SystemServicesProxy { } /** - * Returns whether the given stack id is the freeform workspace stack id. - */ - public static boolean isFreeformStack(int stackId) { - return stackId == FREEFORM_WORKSPACE_STACK_ID; - } - - /** * @return whether there are any docked tasks for the current user. */ public boolean hasDockedTask() { @@ -734,14 +726,12 @@ public class SystemServicesProxy { } } - /** - * Moves a task into another stack. - */ - public void moveTaskToStack(int taskId, int stackId) { + /** Set the task's windowing mode. */ + public void setTaskWindowingMode(int taskId, int windowingMode) { if (mIam == null) return; try { - mIam.positionTaskInStack(taskId, stackId, 0); + mIam.setTaskWindowingMode(taskId, windowingMode, false /* onTop */); } catch (RemoteException | IllegalArgumentException e) { e.printStackTrace(); } @@ -1132,7 +1122,7 @@ public class SystemServicesProxy { if (mIam == null) { return; } - if (taskKey.stackId == DOCKED_STACK_ID) { + if (taskKey.windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) { // We show non-visible docked tasks in Recents, but we always want to launch // them in the fullscreen stack. if (options == null) { @@ -1314,6 +1304,20 @@ public class SystemServicesProxy { void onStartActivityResult(boolean succeeded); } + private class PinnedActivityInfo { + final String mPackageName; + final int mUserId; + final int mTaskId; + final int mStackId; + + PinnedActivityInfo(String packageName, int userId, int taskId, int stackId) { + mPackageName = packageName; + mUserId = userId; + mTaskId = taskId; + mStackId = stackId; + } + } + private final class H extends Handler { private static final int ON_TASK_STACK_CHANGED = 1; private static final int ON_TASK_SNAPSHOT_CHANGED = 2; @@ -1349,9 +1353,10 @@ public class SystemServicesProxy { break; } case ON_ACTIVITY_PINNED: { + final PinnedActivityInfo info = (PinnedActivityInfo) msg.obj; for (int i = mTaskStackListeners.size() - 1; i >= 0; i--) { - mTaskStackListeners.get(i).onActivityPinned((String) msg.obj, msg.arg1, - msg.arg2); + mTaskStackListeners.get(i).onActivityPinned( + info.mPackageName, info.mUserId, info.mTaskId, info.mStackId); } break; } diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/HighResThumbnailLoader.java b/packages/SystemUI/src/com/android/systemui/recents/model/HighResThumbnailLoader.java index 48fa6c3c053b..6414ea1e9783 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/model/HighResThumbnailLoader.java +++ b/packages/SystemUI/src/com/android/systemui/recents/model/HighResThumbnailLoader.java @@ -187,7 +187,7 @@ public class HighResThumbnailLoader implements TaskCallbacks { } @Override - public void onTaskStackIdChanged() { + public void onTaskWindowingModeChanged() { } private final Runnable mLoader = new Runnable() { diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoadPlan.java b/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoadPlan.java index 8d31730d8602..d5e031355810 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoadPlan.java +++ b/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoadPlan.java @@ -16,6 +16,8 @@ package com.android.systemui.recents.model; +import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM; + import android.app.ActivityManager; import android.content.Context; import android.content.pm.ActivityInfo; @@ -155,12 +157,13 @@ public class RecentsTaskLoadPlan { ActivityManager.RecentTaskInfo t = mRawTasks.get(i); // Compose the task key - Task.TaskKey taskKey = new Task.TaskKey(t.persistentId, t.stackId, t.baseIntent, + final int windowingMode = t.configuration.windowConfiguration.getWindowingMode(); + Task.TaskKey taskKey = new Task.TaskKey(t.persistentId, windowingMode, t.baseIntent, t.userId, t.firstActiveTime, t.lastActiveTime); // This task is only shown in the stack if it satisfies the historical time or min // number of tasks constraints. Freeform tasks are also always shown. - boolean isFreeformTask = SystemServicesProxy.isFreeformStack(t.stackId); + boolean isFreeformTask = windowingMode == WINDOWING_MODE_FREEFORM; boolean isStackTask; if (Recents.getConfiguration().isGridEnabled) { // When grid layout is enabled, we only show the first diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/Task.java b/packages/SystemUI/src/com/android/systemui/recents/model/Task.java index 9e6bf85445a0..abdb5cb8c2e3 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/model/Task.java +++ b/packages/SystemUI/src/com/android/systemui/recents/model/Task.java @@ -16,6 +16,8 @@ package com.android.systemui.recents.model; +import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM; + import android.app.ActivityManager; import android.content.ComponentName; import android.content.Intent; @@ -46,8 +48,8 @@ public class Task { public void onTaskDataLoaded(Task task, ThumbnailData thumbnailData); /* Notifies when a task has been unbound */ public void onTaskDataUnloaded(); - /* Notifies when a task's stack id has changed. */ - public void onTaskStackIdChanged(); + /* Notifies when a task's windowing mode has changed. */ + public void onTaskWindowingModeChanged(); } /* The Task Key represents the unique primary key for the task */ @@ -55,7 +57,7 @@ public class Task { @ViewDebug.ExportedProperty(category="recents") public final int id; @ViewDebug.ExportedProperty(category="recents") - public int stackId; + public int windowingMode; @ViewDebug.ExportedProperty(category="recents") public final Intent baseIntent; @ViewDebug.ExportedProperty(category="recents") @@ -67,10 +69,10 @@ public class Task { private int mHashCode; - public TaskKey(int id, int stackId, Intent intent, int userId, long firstActiveTime, + public TaskKey(int id, int windowingMode, Intent intent, int userId, long firstActiveTime, long lastActiveTime) { this.id = id; - this.stackId = stackId; + this.windowingMode = windowingMode; this.baseIntent = intent; this.userId = userId; this.firstActiveTime = firstActiveTime; @@ -78,8 +80,8 @@ public class Task { updateHashCode(); } - public void setStackId(int stackId) { - this.stackId = stackId; + public void setWindowingMode(int windowingMode) { + this.windowingMode = windowingMode; updateHashCode(); } @@ -93,7 +95,9 @@ public class Task { return false; } TaskKey otherKey = (TaskKey) o; - return id == otherKey.id && stackId == otherKey.stackId && userId == otherKey.userId; + return id == otherKey.id + && windowingMode == otherKey.windowingMode + && userId == otherKey.userId; } @Override @@ -103,12 +107,12 @@ public class Task { @Override public String toString() { - return "id=" + id + " stackId=" + stackId + " user=" + userId + " lastActiveTime=" + - lastActiveTime; + return "id=" + id + " windowingMode=" + windowingMode + " user=" + userId + + " lastActiveTime=" + lastActiveTime; } private void updateHashCode() { - mHashCode = Objects.hash(id, stackId, userId); + mHashCode = Objects.hash(id, windowingMode, userId); } } @@ -277,14 +281,12 @@ public class Task { this.group = group; } - /** - * Updates the stack id of this task. - */ - public void setStackId(int stackId) { - key.setStackId(stackId); + /** Updates the task's windowing mode. */ + public void setWindowingMode(int windowingMode) { + key.setWindowingMode(windowingMode); int callbackCount = mCallbacks.size(); for (int i = 0; i < callbackCount; i++) { - mCallbacks.get(i).onTaskStackIdChanged(); + mCallbacks.get(i).onTaskWindowingModeChanged(); } } @@ -293,7 +295,7 @@ public class Task { */ public boolean isFreeformTask() { SystemServicesProxy ssp = Recents.getSystemServices(); - return ssp.hasFreeformWorkspaceSupport() && ssp.isFreeformStack(key.stackId); + return ssp.hasFreeformWorkspaceSupport() && key.windowingMode == WINDOWING_MODE_FREEFORM; } /** Notifies the callback listeners that this task has been loaded */ diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/TaskKeyCache.java b/packages/SystemUI/src/com/android/systemui/recents/model/TaskKeyCache.java index be99f93028dc..247a654207c8 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/model/TaskKeyCache.java +++ b/packages/SystemUI/src/com/android/systemui/recents/model/TaskKeyCache.java @@ -45,7 +45,7 @@ public abstract class TaskKeyCache<V> { final V getAndInvalidateIfModified(Task.TaskKey key) { Task.TaskKey lastKey = mKeys.get(key.id); if (lastKey != null) { - if ((lastKey.stackId != key.stackId) || + if ((lastKey.windowingMode != key.windowingMode) || (lastKey.lastActiveTime != key.lastActiveTime)) { // The task has updated (been made active since the last time it was put into the // LRU cache) or the stack id for the task has changed, invalidate that cache item diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java b/packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java index 6e3be09b2ae9..fdae917cf1ab 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java +++ b/packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java @@ -18,8 +18,8 @@ package com.android.systemui.recents.model; import static android.app.ActivityManager.DOCKED_STACK_CREATE_MODE_BOTTOM_OR_RIGHT; import static android.app.ActivityManager.DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT; -import static android.app.ActivityManager.StackId.FREEFORM_WORKSPACE_STACK_ID; -import static android.app.ActivityManager.StackId.FULLSCREEN_WORKSPACE_STACK_ID; +import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM; +import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; import static android.view.WindowManager.DOCKED_BOTTOM; import static android.view.WindowManager.DOCKED_INVALID; import static android.view.WindowManager.DOCKED_LEFT; @@ -115,7 +115,7 @@ class FilteredTaskList { /** * Moves the given task. */ - public void moveTaskToStack(Task task, int insertIndex, int newStackId) { + public void setTaskWindowingMode(Task task, int insertIndex, int windowingMode) { int taskIndex = indexOf(task); if (taskIndex != insertIndex) { mTasks.remove(taskIndex); @@ -127,7 +127,7 @@ class FilteredTaskList { // Update the stack id now, after we've moved the task, and before we update the // filtered tasks - task.setStackId(newStackId); + task.setWindowingMode(windowingMode); updateFilteredTasks(); } @@ -590,17 +590,15 @@ public class TaskStack { mCb = cb; } - /** - * Moves the given task to either the front of the freeform workspace or the stack. - */ - public void moveTaskToStack(Task task, int newStackId) { + /** Sets the windowing mode for a given task. */ + public void setTaskWindowingMode(Task task, int windowingMode) { // Find the index to insert into ArrayList<Task> taskList = mStackTaskList.getTasks(); int taskCount = taskList.size(); - if (!task.isFreeformTask() && (newStackId == FREEFORM_WORKSPACE_STACK_ID)) { + if (!task.isFreeformTask() && (windowingMode == WINDOWING_MODE_FREEFORM)) { // Insert freeform tasks at the front - mStackTaskList.moveTaskToStack(task, taskCount, newStackId); - } else if (task.isFreeformTask() && (newStackId == FULLSCREEN_WORKSPACE_STACK_ID)) { + mStackTaskList.setTaskWindowingMode(task, taskCount, windowingMode); + } else if (task.isFreeformTask() && (windowingMode == WINDOWING_MODE_FULLSCREEN)) { // Insert after the first stacked task int insertIndex = 0; for (int i = taskCount - 1; i >= 0; i--) { @@ -609,7 +607,7 @@ public class TaskStack { break; } } - mStackTaskList.moveTaskToStack(task, insertIndex, newStackId); + mStackTaskList.setTaskWindowingMode(task, insertIndex, windowingMode); } } diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java index 7ede0c5d08c8..3160ee0ee8df 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java +++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java @@ -16,9 +16,8 @@ package com.android.systemui.recents.views; -import static android.app.ActivityManager.StackId.FREEFORM_WORKSPACE_STACK_ID; -import static android.app.ActivityManager.StackId.FULLSCREEN_WORKSPACE_STACK_ID; -import static android.app.ActivityManager.StackId.INVALID_STACK_ID; +import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM; +import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; import android.animation.Animator; import android.animation.AnimatorListenerAdapter; @@ -2094,18 +2093,18 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal } boolean isFreeformTask = event.task.isFreeformTask(); - boolean hasChangedStacks = + boolean hasChangedWindowingMode = (!isFreeformTask && event.dropTarget == mFreeformWorkspaceDropTarget) || (isFreeformTask && event.dropTarget == mStackDropTarget); - if (hasChangedStacks) { + if (hasChangedWindowingMode) { // Move the task to the right position in the stack (ie. the front of the stack if // freeform or the front of the stack if fullscreen). Note, we MUST move the tasks // before we update their stack ids, otherwise, the keys will have changed. if (event.dropTarget == mFreeformWorkspaceDropTarget) { - mStack.moveTaskToStack(event.task, FREEFORM_WORKSPACE_STACK_ID); + mStack.setTaskWindowingMode(event.task, WINDOWING_MODE_FREEFORM); } else if (event.dropTarget == mStackDropTarget) { - mStack.moveTaskToStack(event.task, FULLSCREEN_WORKSPACE_STACK_ID); + mStack.setTaskWindowingMode(event.task, WINDOWING_MODE_FULLSCREEN); } updateLayoutAlgorithm(true /* boundScroll */); @@ -2114,7 +2113,7 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal @Override public void run() { SystemServicesProxy ssp = Recents.getSystemServices(); - ssp.moveTaskToStack(event.task.key.id, event.task.key.stackId); + ssp.setTaskWindowingMode(event.task.key.id, event.task.key.windowingMode); } }); } diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java index c64f6dfcea4a..9d639647acdb 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java +++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java @@ -647,7 +647,7 @@ public class TaskView extends FixedSizeFrameLayout implements Task.TaskCallbacks } @Override - public void onTaskStackIdChanged() { + public void onTaskWindowingModeChanged() { // Force rebind the header, the thumbnail does not change due to stack changes mHeaderView.bindToTask(mTask, mTouchExplorationEnabled, mIsDisabledInSafeMode); mHeaderView.onTaskDataLoaded(); diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/WindowManagerProxy.java b/packages/SystemUI/src/com/android/systemui/stackdivider/WindowManagerProxy.java index f7c04116c767..85a60624c275 100644 --- a/packages/SystemUI/src/com/android/systemui/stackdivider/WindowManagerProxy.java +++ b/packages/SystemUI/src/com/android/systemui/stackdivider/WindowManagerProxy.java @@ -16,7 +16,6 @@ package com.android.systemui.stackdivider; -import static android.app.ActivityManager.StackId.DOCKED_STACK_ID; import static android.view.WindowManager.DOCKED_INVALID; import android.app.ActivityManager; @@ -88,8 +87,7 @@ public class WindowManagerProxy { @Override public void run() { try { - ActivityManager.getService().moveTasksToFullscreenStack( - DOCKED_STACK_ID, false /* onTop */); + ActivityManager.getService().dismissSplitScreenMode(false /* onTop */); } catch (RemoteException e) { Log.w(TAG, "Failed to remove stack: " + e); } @@ -100,8 +98,7 @@ public class WindowManagerProxy { @Override public void run() { try { - ActivityManager.getService().resizeStack( - DOCKED_STACK_ID, null, true, true, false, -1); + ActivityManager.getService().dismissSplitScreenMode(true /* onTop */); } catch (RemoteException e) { Log.w(TAG, "Failed to resize stack: " + e); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java index 561fbb2b4aba..6cfd42fa00eb 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java @@ -43,6 +43,7 @@ import android.util.FloatProperty; import android.util.Log; import android.util.Property; import android.util.TypedValue; +import android.view.View; import android.view.ViewDebug; import android.view.accessibility.AccessibilityEvent; import android.view.animation.Interpolator; @@ -142,6 +143,7 @@ public class StatusBarIconView extends AnimatedImageView { private float[] mMatrix; private ColorMatrixColorFilter mMatrixColorFilter; private boolean mIsInShelf; + private Runnable mLayoutRunnable; public StatusBarIconView(Context context, String slot, StatusBarNotification sbn) { this(context, slot, sbn, false); @@ -822,6 +824,19 @@ public class StatusBarIconView extends AnimatedImageView { return mIsInShelf; } + @Override + protected void onLayout(boolean changed, int left, int top, int right, int bottom) { + super.onLayout(changed, left, top, right, bottom); + if (mLayoutRunnable != null) { + mLayoutRunnable.run(); + mLayoutRunnable = null; + } + } + + public void executeOnLayout(Runnable runnable) { + mLayoutRunnable = runnable; + } + public interface OnVisibilityChangedListener { void onVisibilityChanged(int newVisibility); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java index 41a69b4ba557..40fe50fb9325 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java @@ -4,10 +4,8 @@ import android.content.Context; import android.content.res.Resources; import android.graphics.Color; import android.graphics.Rect; -import android.graphics.drawable.Icon; import android.support.annotation.NonNull; import android.support.v4.util.ArrayMap; -import android.support.v4.util.ArraySet; import android.view.LayoutInflater; import android.view.View; import android.widget.FrameLayout; @@ -269,18 +267,26 @@ public class NotificationIconAreaController implements DarkReceiver { */ private void applyNotificationIconsTint() { for (int i = 0; i < mNotificationIcons.getChildCount(); i++) { - StatusBarIconView v = (StatusBarIconView) mNotificationIcons.getChildAt(i); - boolean isPreL = Boolean.TRUE.equals(v.getTag(R.id.icon_is_pre_L)); - int color = StatusBarIconView.NO_COLOR; - boolean colorize = !isPreL || NotificationUtils.isGrayscale(v, mNotificationColorUtil); - if (colorize) { - color = DarkIconDispatcher.getTint(mTintArea, v, mIconTint); + final StatusBarIconView iv = (StatusBarIconView) mNotificationIcons.getChildAt(i); + if (iv.getWidth() != 0) { + updateTintForIcon(iv); + } else { + iv.executeOnLayout(() -> updateTintForIcon(iv)); } - v.setStaticDrawableColor(color); - v.setDecorColor(mIconTint); } } + private void updateTintForIcon(StatusBarIconView v) { + boolean isPreL = Boolean.TRUE.equals(v.getTag(R.id.icon_is_pre_L)); + int color = StatusBarIconView.NO_COLOR; + boolean colorize = !isPreL || NotificationUtils.isGrayscale(v, mNotificationColorUtil); + if (colorize) { + color = DarkIconDispatcher.getTint(mTintArea, v, mIconTint); + } + v.setStaticDrawableColor(color); + v.setDecorColor(mIconTint); + } + public void setDark(boolean dark) { mNotificationIcons.setDark(dark, false, 0); mShelfIcons.setDark(dark, false, 0); diff --git a/packages/SystemUI/tests/src/com/android/systemui/recents/model/HighResThumbnailLoaderTest.java b/packages/SystemUI/tests/src/com/android/systemui/recents/model/HighResThumbnailLoaderTest.java index 5a8c6dd97908..767e1246e45b 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/recents/model/HighResThumbnailLoaderTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/recents/model/HighResThumbnailLoaderTest.java @@ -16,6 +16,7 @@ package com.android.systemui.recents.model; +import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import static org.mockito.Mockito.anyBoolean; @@ -59,7 +60,7 @@ public class HighResThumbnailLoaderTest extends SysuiTestCase { MockitoAnnotations.initMocks(this); mLoader = new HighResThumbnailLoader(mMockSystemServicesProxy, Looper.getMainLooper(), false); - mTask.key = new TaskKey(0, 0, null, 0, 0, 0); + mTask.key = new TaskKey(0, WINDOWING_MODE_UNDEFINED, null, 0, 0, 0); when(mMockSystemServicesProxy.getTaskThumbnail(anyInt(), anyBoolean())) .thenReturn(mThumbnailData); mLoader.setVisible(true); diff --git a/packages/VpnDialogs/res/values-cs/strings.xml b/packages/VpnDialogs/res/values-cs/strings.xml index 7a3d515877fa..47d950ff8cdb 100644 --- a/packages/VpnDialogs/res/values-cs/strings.xml +++ b/packages/VpnDialogs/res/values-cs/strings.xml @@ -31,6 +31,6 @@ <string name="always_on_disconnected_message_settings_link" msgid="6172280302829992412">"Změnit nastavení VPN"</string> <string name="configure" msgid="4905518375574791375">"Konfigurovat"</string> <string name="disconnect" msgid="971412338304200056">"Odpojit"</string> - <string name="open_app" msgid="3717639178595958667">"Spustit aplikaci"</string> + <string name="open_app" msgid="3717639178595958667">"Do aplikace"</string> <string name="dismiss" msgid="6192859333764711227">"Zavřít"</string> </resources> diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index 5160474f091a..e6fe620485da 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -38,6 +38,7 @@ import static android.app.ActivityManager.StackId.isStaticStack; import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD; import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM; import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; +import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY; import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED; import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY; import static android.content.pm.PackageManager.FEATURE_ACTIVITIES_ON_SECONDARY_DISPLAYS; @@ -3243,7 +3244,8 @@ public class ActivityManagerService extends IActivityManager.Stub if (r.requestedVrComponent != null && r.getStackId() >= FIRST_DYNAMIC_STACK_ID) { Slog.i(TAG, "Moving " + r.shortComponentName + " from stack " + r.getStackId() + " to main stack for VR"); - moveTaskToStack(r.getTask().taskId, FULLSCREEN_WORKSPACE_STACK_ID, true /* toTop */); + setTaskWindowingMode(r.getTask().taskId, + WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY, true /* toTop */); } mHandler.sendMessage( mHandler.obtainMessage(VR_MODE_CHANGE_MSG, 0, 0, r)); @@ -9877,6 +9879,7 @@ public class ActivityManagerService extends IActivityManager.Stub } rti.supportsSplitScreenMultiWindow = tr.supportsSplitScreenWindowingMode(); rti.resizeMode = tr.mResizeMode; + rti.configuration.setTo(tr.getConfiguration()); ActivityRecord base = null; ActivityRecord top = null; @@ -10625,6 +10628,42 @@ public class ActivityManagerService extends IActivityManager.Stub } @Override + public void setTaskWindowingMode(int taskId, int windowingMode, boolean toTop) { + enforceCallingPermission(MANAGE_ACTIVITY_STACKS, "setTaskWindowingMode()"); + synchronized (this) { + final long ident = Binder.clearCallingIdentity(); + try { + final TaskRecord task = mStackSupervisor.anyTaskForIdLocked(taskId); + if (task == null) { + Slog.w(TAG, "setTaskWindowingMode: No task for id=" + taskId); + return; + } + + if (DEBUG_STACK) Slog.d(TAG_STACK, "setTaskWindowingMode: moving task=" + taskId + + " to windowingMode=" + windowingMode + " toTop=" + toTop); + if (windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) { + mWindowManager.setDockedStackCreateState(DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT, + null /* initialBounds */); + } + + if (!task.isActivityTypeStandardOrUndefined()) { + throw new IllegalArgumentException("setTaskWindowingMode: Attempt to move task " + + taskId + " to non-standard windowin mode=" + windowingMode); + } + final ActivityDisplay display = task.getStack().getDisplay(); + final ActivityStack stack = display.getOrCreateStack(windowingMode, + task.getStack().getActivityType(), toTop); + // TODO: We should just change the windowing mode for the task vs. creating and + // moving it to a stack. + task.reparent(stack, toTop, REPARENT_KEEP_STACK_AT_FRONT, ANIMATE, !DEFER_RESUME, + "moveTaskToStack"); + } finally { + Binder.restoreCallingIdentity(ident); + } + } + } + + @Override public void moveTaskToStack(int taskId, int stackId, boolean toTop) { enforceCallingPermission(MANAGE_ACTIVITY_STACKS, "moveTaskToStack()"); synchronized (this) { @@ -10718,6 +10757,66 @@ public class ActivityManagerService extends IActivityManager.Stub } /** + * Dismisses split-screen multi-window mode. + * @param toTop If true the current primary split-screen stack will be placed or left on top. + */ + @Override + public void dismissSplitScreenMode(boolean toTop) { + enforceCallingPermission(MANAGE_ACTIVITY_STACKS, "dismissSplitScreenMode()"); + final long ident = Binder.clearCallingIdentity(); + try { + synchronized (this) { + final ActivityStack stack = + mStackSupervisor.getDefaultDisplay().getSplitScreenStack(); + if (toTop) { + mStackSupervisor.resizeStackLocked(stack.mStackId, null /* destBounds */, + null /* tempTaskBounds */, null /* tempTaskInsetBounds */, + true /* preserveWindows */, true /* allowResizeInDockedMode */, + !DEFER_RESUME); + } else { + mStackSupervisor.moveTasksToFullscreenStackLocked(stack, false /* onTop */); + } + } + } finally { + Binder.restoreCallingIdentity(ident); + } + } + + /** + * Dismisses Pip + * @param animate True if the dismissal should be animated. + * @param animationDuration The duration of the resize animation in milliseconds or -1 if the + * default animation duration should be used. + */ + @Override + public void dismissPip(boolean animate, int animationDuration) { + enforceCallingPermission(MANAGE_ACTIVITY_STACKS, "dismissPip()"); + final long ident = Binder.clearCallingIdentity(); + try { + synchronized (this) { + final PinnedActivityStack stack = + mStackSupervisor.getDefaultDisplay().getPinnedStack(); + + if (stack == null) { + return; + } + if (stack.getWindowingMode() != WINDOWING_MODE_PINNED) { + throw new IllegalArgumentException("Stack: " + stack + + " doesn't support animated resize."); + } + if (animate) { + stack.animateResizePinnedStack(null /* sourceHintBounds */, + null /* destBounds */, animationDuration, false /* fromFullscreen */); + } else { + mStackSupervisor.moveTasksToFullscreenStackLocked(stack, true /* onTop */); + } + } + } finally { + Binder.restoreCallingIdentity(ident); + } + } + + /** * Moves the top activity in the input stackId to the pinned stack. * * @param stackId Id of stack to move the top activity to pinned stack. diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java index 34eaab234381..1940ca2b4c31 100644 --- a/services/core/java/com/android/server/am/ActivityStack.java +++ b/services/core/java/com/android/server/am/ActivityStack.java @@ -4900,7 +4900,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai ci.numRunning = numRunning; ci.supportsSplitScreenMultiWindow = task.supportsSplitScreenWindowingMode(); ci.resizeMode = task.mResizeMode; - ci.configuration = task.getConfiguration(); + ci.configuration.setTo(task.getConfiguration()); list.add(ci); } } @@ -5089,7 +5089,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai if (isAttached()) { getDisplay().positionChildAtBottom(this); } - if (!isHomeOrRecentsStack()) { + if (!isActivityTypeHome()) { remove(); } } diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java index 42f3550da8b9..da2827a6aedc 100644 --- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java +++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java @@ -2625,38 +2625,41 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D // the picture-in-picture mode. final boolean schedulePictureInPictureModeChange = inPinnedWindowingMode; final ArrayList<TaskRecord> tasks = fromStack.getAllTasks(); - final int size = tasks.size(); - final ActivityStack fullscreenStack = toDisplay.getOrCreateStack( - WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, onTop); - if (onTop) { - final int returnToType = - toDisplay.getTopVisibleStackActivityType(WINDOWING_MODE_PINNED); - for (int i = 0; i < size; i++) { - final TaskRecord task = tasks.get(i); - final boolean isTopTask = i == (size - 1); - if (inPinnedWindowingMode) { - // Update the return-to to reflect where the pinned stack task was moved - // from so that we retain the stack that was previously visible if the - // pinned stack is recreated. See moveActivityToPinnedStackLocked(). - task.setTaskToReturnTo(returnToType); + if (!tasks.isEmpty()) { + final int size = tasks.size(); + final ActivityStack fullscreenStack = toDisplay.getOrCreateStack( + WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, onTop); + + if (onTop) { + final int returnToType = + toDisplay.getTopVisibleStackActivityType(WINDOWING_MODE_PINNED); + for (int i = 0; i < size; i++) { + final TaskRecord task = tasks.get(i); + final boolean isTopTask = i == (size - 1); + if (inPinnedWindowingMode) { + // Update the return-to to reflect where the pinned stack task was moved + // from so that we retain the stack that was previously visible if the + // pinned stack is recreated. See moveActivityToPinnedStackLocked(). + task.setTaskToReturnTo(returnToType); + } + // Defer resume until all the tasks have been moved to the fullscreen stack + task.reparent(fullscreenStack, ON_TOP, REPARENT_MOVE_STACK_TO_FRONT, + isTopTask /* animate */, DEFER_RESUME, + schedulePictureInPictureModeChange, + "moveTasksToFullscreenStack - onTop"); + } + } else { + for (int i = 0; i < size; i++) { + final TaskRecord task = tasks.get(i); + // Position the tasks in the fullscreen stack in order at the bottom of the + // stack. Also defer resume until all the tasks have been moved to the + // fullscreen stack. + task.reparent(fullscreenStack, i /* position */, + REPARENT_LEAVE_STACK_IN_PLACE, !ANIMATE, DEFER_RESUME, + schedulePictureInPictureModeChange, + "moveTasksToFullscreenStack - NOT_onTop"); } - // Defer resume until all the tasks have been moved to the fullscreen stack - task.reparent(fullscreenStack, ON_TOP, REPARENT_MOVE_STACK_TO_FRONT, - isTopTask /* animate */, DEFER_RESUME, - schedulePictureInPictureModeChange, - "moveTasksToFullscreenStack - onTop"); - } - } else { - for (int i = 0; i < size; i++) { - final TaskRecord task = tasks.get(i); - // Position the tasks in the fullscreen stack in order at the bottom of the - // stack. Also defer resume until all the tasks have been moved to the - // fullscreen stack. - task.reparent(fullscreenStack, i /* position */, - REPARENT_LEAVE_STACK_IN_PLACE, !ANIMATE, DEFER_RESUME, - schedulePictureInPictureModeChange, - "moveTasksToFullscreenStack - NOT_onTop"); } } @@ -3216,8 +3219,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS); resumeFocusedStackTopActivityLocked(); - mService.mTaskChangeNotificationController.notifyActivityPinned(r.packageName, r.userId, - r.getTask().taskId); + mService.mTaskChangeNotificationController.notifyActivityPinned(r); } /** Move activity with its stack to front and make the stack focused. */ diff --git a/services/core/java/com/android/server/am/TaskChangeNotificationController.java b/services/core/java/com/android/server/am/TaskChangeNotificationController.java index 6a986bb8a684..5a7e7ced930c 100644 --- a/services/core/java/com/android/server/am/TaskChangeNotificationController.java +++ b/services/core/java/com/android/server/am/TaskChangeNotificationController.java @@ -95,7 +95,8 @@ class TaskChangeNotificationController { }; private final TaskStackConsumer mNotifyActivityPinned = (l, m) -> { - l.onActivityPinned((String) m.obj, m.arg1, m.arg2); + final ActivityRecord r = (ActivityRecord) m.obj; + l.onActivityPinned(r.packageName, r.userId, r.getTask().taskId, r.getStackId()); }; private final TaskStackConsumer mNotifyActivityUnpinned = (l, m) -> { @@ -278,10 +279,9 @@ class TaskChangeNotificationController { } /** Notifies all listeners when an Activity is pinned. */ - void notifyActivityPinned(String packageName, int userId, int taskId) { + void notifyActivityPinned(ActivityRecord r) { mHandler.removeMessages(NOTIFY_ACTIVITY_PINNED_LISTENERS_MSG); - final Message msg = mHandler.obtainMessage(NOTIFY_ACTIVITY_PINNED_LISTENERS_MSG, - userId, taskId, packageName); + final Message msg = mHandler.obtainMessage(NOTIFY_ACTIVITY_PINNED_LISTENERS_MSG, r); forAllLocalListeners(mNotifyActivityPinned, msg); msg.sendToTarget(); } |