Loading core/java/android/window/WindowContainerTransaction.java +5 −0 Original line number Diff line number Diff line Loading @@ -360,6 +360,11 @@ public final class WindowContainerTransaction implements Parcelable { } } /** @hide */ public boolean isEmpty() { return mChanges.isEmpty() && mHierarchyOps.isEmpty(); } /** @hide */ public Map<IBinder, Change> getChanges() { return mChanges; Loading core/java/android/window/WindowOrganizer.java +3 −1 Original line number Diff line number Diff line Loading @@ -42,7 +42,9 @@ public class WindowOrganizer { @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_TASKS) public void applyTransaction(@NonNull WindowContainerTransaction t) { try { if (!t.isEmpty()) { getWindowOrganizerController().applyTransaction(t); } } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } Loading libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/MainStage.java +10 −6 Original line number Diff line number Diff line Loading @@ -51,8 +51,7 @@ class MainStage extends StageTaskListener { if (mIsActive) return; final WindowContainerToken rootToken = mRootTaskInfo.token; wct.setHidden(rootToken, false) .setBounds(rootToken, rootBounds) wct.setBounds(rootToken, rootBounds) .setLaunchRoot( rootToken, CONTROLLED_WINDOWING_MODES, Loading @@ -63,7 +62,7 @@ class MainStage extends StageTaskListener { CONTROLLED_WINDOWING_MODES, CONTROLLED_ACTIVITY_TYPES, true /* onTop */) // Moving the root task to top after the child tasks were repareted , or the root // Moving the root task to top after the child tasks were re-parented , or the root // task cannot be visible and focused. .reorder(rootToken, true /* onTop */); Loading @@ -71,13 +70,16 @@ class MainStage extends StageTaskListener { } void deactivate(WindowContainerTransaction wct) { deactivate(wct, false /* toTop */); } void deactivate(WindowContainerTransaction wct, boolean toTop) { if (!mIsActive) return; mIsActive = false; if (mRootTaskInfo == null) return; final WindowContainerToken rootToken = mRootTaskInfo.token; wct.setHidden(rootToken, true) .setLaunchRoot( wct.setLaunchRoot( rootToken, null, null) Loading @@ -86,7 +88,9 @@ class MainStage extends StageTaskListener { null /* newParent */, CONTROLLED_WINDOWING_MODES_WHEN_ACTIVE, CONTROLLED_ACTIVITY_TYPES, false /* onTop */) toTop) // We want this re-order to the bottom regardless since we are re-parenting // all its tasks. .reorder(rootToken, false /* onTop */); } Loading libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SideStage.java +2 −12 Original line number Diff line number Diff line Loading @@ -16,8 +16,6 @@ package com.android.wm.shell.splitscreen; import static android.app.ActivityTaskManager.INVALID_TASK_ID; import android.app.ActivityManager; import android.graphics.Rect; import android.window.WindowContainerToken; Loading Loading @@ -50,14 +48,14 @@ class SideStage extends StageTaskListener { .reorder(rootToken, true); } boolean removeAllTasks(WindowContainerTransaction wct) { boolean removeAllTasks(WindowContainerTransaction wct, boolean toTop) { if (mChildrenTaskInfo.size() == 0) return false; wct.reparentTasks( mRootTaskInfo.token, null /* newParent */, CONTROLLED_WINDOWING_MODES_WHEN_ACTIVE, CONTROLLED_ACTIVITY_TYPES, false /* onTop */); toTop); return true; } Loading @@ -70,12 +68,4 @@ class SideStage extends StageTaskListener { .reparent(task.token, newParent, false /* onTop */); return true; } int getTopVisibleTaskId() { for (int i = mChildrenTaskInfo.size() - 1; i >= 0; --i) { final ActivityManager.RunningTaskInfo task = mChildrenTaskInfo.valueAt(i); if (task.isVisible) return task.taskId; } return INVALID_TASK_ID; } } libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java +24 −30 Original line number Diff line number Diff line Loading @@ -146,10 +146,16 @@ class StageCoordinator implements SplitLayout.LayoutChangeListener, } void exitSplitScreen() { exitSplitScreen(null /* childrenToTop */); } private void exitSplitScreen(StageTaskListener childrenToTop) { final WindowContainerTransaction wct = new WindowContainerTransaction(); mSideStage.removeAllTasks(wct); mMainStage.deactivate(wct); mSideStage.removeAllTasks(wct, childrenToTop == mSideStage); mMainStage.deactivate(wct, childrenToTop == mMainStage); mTaskOrganizer.applyTransaction(wct); // Reset divider position. mSplitLayout.resetDividerPosition(); } void getStageBounds(Rect outTopOrLeftBounds, Rect outBottomOrRightBounds) { Loading Loading @@ -272,41 +278,29 @@ class StageCoordinator implements SplitLayout.LayoutChangeListener, } private void onStageHasChildrenChanged(StageListenerImpl stageListener) { if (stageListener == mSideStageListener) { final boolean hasChildren = stageListener.mHasChildren; final boolean isSideStage = stageListener == mSideStageListener; if (!hasChildren) { if (isSideStage && mMainStageListener.mVisible) { // Exit to main stage if side stage no longer has children. exitSplitScreen(mMainStage); } else if (!isSideStage && mSideStageListener.mVisible) { // Exit to side stage if main stage no longer has children. exitSplitScreen(mSideStage); } } else if (isSideStage) { final WindowContainerTransaction wct = new WindowContainerTransaction(); if (mSideStageListener.mHasChildren) { // Make sure the main stage is active. mMainStage.activate(getMainStageBounds(), wct); } else { // The side stage no long has children so we can deactivate the main stage. mMainStage.deactivate(wct); } mTaskOrganizer.applyTransaction(wct); } } @Override public void onSnappedToDismiss(boolean bottomOrRight) { if (mSideStagePosition == SIDE_STAGE_POSITION_BOTTOM_OR_RIGHT && bottomOrRight) { // Main stage was fully expanded...Just side side-stage. setSideStageVisibility(false); } else { // Side stage was fully expanded...Move its top task to the main stage // and hide side-stage. // TODO: Would UX prefer the side-stage go into fullscreen mode here? final int taskId = mSideStage.getTopVisibleTaskId(); if (taskId == INVALID_TASK_ID) { throw new IllegalStateException("Side stage doesn't have visible task? " + mSideStage); } final WindowContainerTransaction wct = new WindowContainerTransaction(); mSideStage.removeTask(taskId, mMainStage.mRootTaskInfo.getToken(), wct); mSideStage.setVisibility(false, wct); mTaskOrganizer.applyTransaction(wct); } // Reset divider position. mSplitLayout.resetDividerPosition(); final boolean mainStageToTop = bottomOrRight && mSideStagePosition == SIDE_STAGE_POSITION_BOTTOM_OR_RIGHT; exitSplitScreen(mainStageToTop ? mMainStage : mSideStage); } @Override Loading Loading
core/java/android/window/WindowContainerTransaction.java +5 −0 Original line number Diff line number Diff line Loading @@ -360,6 +360,11 @@ public final class WindowContainerTransaction implements Parcelable { } } /** @hide */ public boolean isEmpty() { return mChanges.isEmpty() && mHierarchyOps.isEmpty(); } /** @hide */ public Map<IBinder, Change> getChanges() { return mChanges; Loading
core/java/android/window/WindowOrganizer.java +3 −1 Original line number Diff line number Diff line Loading @@ -42,7 +42,9 @@ public class WindowOrganizer { @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_TASKS) public void applyTransaction(@NonNull WindowContainerTransaction t) { try { if (!t.isEmpty()) { getWindowOrganizerController().applyTransaction(t); } } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } Loading
libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/MainStage.java +10 −6 Original line number Diff line number Diff line Loading @@ -51,8 +51,7 @@ class MainStage extends StageTaskListener { if (mIsActive) return; final WindowContainerToken rootToken = mRootTaskInfo.token; wct.setHidden(rootToken, false) .setBounds(rootToken, rootBounds) wct.setBounds(rootToken, rootBounds) .setLaunchRoot( rootToken, CONTROLLED_WINDOWING_MODES, Loading @@ -63,7 +62,7 @@ class MainStage extends StageTaskListener { CONTROLLED_WINDOWING_MODES, CONTROLLED_ACTIVITY_TYPES, true /* onTop */) // Moving the root task to top after the child tasks were repareted , or the root // Moving the root task to top after the child tasks were re-parented , or the root // task cannot be visible and focused. .reorder(rootToken, true /* onTop */); Loading @@ -71,13 +70,16 @@ class MainStage extends StageTaskListener { } void deactivate(WindowContainerTransaction wct) { deactivate(wct, false /* toTop */); } void deactivate(WindowContainerTransaction wct, boolean toTop) { if (!mIsActive) return; mIsActive = false; if (mRootTaskInfo == null) return; final WindowContainerToken rootToken = mRootTaskInfo.token; wct.setHidden(rootToken, true) .setLaunchRoot( wct.setLaunchRoot( rootToken, null, null) Loading @@ -86,7 +88,9 @@ class MainStage extends StageTaskListener { null /* newParent */, CONTROLLED_WINDOWING_MODES_WHEN_ACTIVE, CONTROLLED_ACTIVITY_TYPES, false /* onTop */) toTop) // We want this re-order to the bottom regardless since we are re-parenting // all its tasks. .reorder(rootToken, false /* onTop */); } Loading
libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SideStage.java +2 −12 Original line number Diff line number Diff line Loading @@ -16,8 +16,6 @@ package com.android.wm.shell.splitscreen; import static android.app.ActivityTaskManager.INVALID_TASK_ID; import android.app.ActivityManager; import android.graphics.Rect; import android.window.WindowContainerToken; Loading Loading @@ -50,14 +48,14 @@ class SideStage extends StageTaskListener { .reorder(rootToken, true); } boolean removeAllTasks(WindowContainerTransaction wct) { boolean removeAllTasks(WindowContainerTransaction wct, boolean toTop) { if (mChildrenTaskInfo.size() == 0) return false; wct.reparentTasks( mRootTaskInfo.token, null /* newParent */, CONTROLLED_WINDOWING_MODES_WHEN_ACTIVE, CONTROLLED_ACTIVITY_TYPES, false /* onTop */); toTop); return true; } Loading @@ -70,12 +68,4 @@ class SideStage extends StageTaskListener { .reparent(task.token, newParent, false /* onTop */); return true; } int getTopVisibleTaskId() { for (int i = mChildrenTaskInfo.size() - 1; i >= 0; --i) { final ActivityManager.RunningTaskInfo task = mChildrenTaskInfo.valueAt(i); if (task.isVisible) return task.taskId; } return INVALID_TASK_ID; } }
libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java +24 −30 Original line number Diff line number Diff line Loading @@ -146,10 +146,16 @@ class StageCoordinator implements SplitLayout.LayoutChangeListener, } void exitSplitScreen() { exitSplitScreen(null /* childrenToTop */); } private void exitSplitScreen(StageTaskListener childrenToTop) { final WindowContainerTransaction wct = new WindowContainerTransaction(); mSideStage.removeAllTasks(wct); mMainStage.deactivate(wct); mSideStage.removeAllTasks(wct, childrenToTop == mSideStage); mMainStage.deactivate(wct, childrenToTop == mMainStage); mTaskOrganizer.applyTransaction(wct); // Reset divider position. mSplitLayout.resetDividerPosition(); } void getStageBounds(Rect outTopOrLeftBounds, Rect outBottomOrRightBounds) { Loading Loading @@ -272,41 +278,29 @@ class StageCoordinator implements SplitLayout.LayoutChangeListener, } private void onStageHasChildrenChanged(StageListenerImpl stageListener) { if (stageListener == mSideStageListener) { final boolean hasChildren = stageListener.mHasChildren; final boolean isSideStage = stageListener == mSideStageListener; if (!hasChildren) { if (isSideStage && mMainStageListener.mVisible) { // Exit to main stage if side stage no longer has children. exitSplitScreen(mMainStage); } else if (!isSideStage && mSideStageListener.mVisible) { // Exit to side stage if main stage no longer has children. exitSplitScreen(mSideStage); } } else if (isSideStage) { final WindowContainerTransaction wct = new WindowContainerTransaction(); if (mSideStageListener.mHasChildren) { // Make sure the main stage is active. mMainStage.activate(getMainStageBounds(), wct); } else { // The side stage no long has children so we can deactivate the main stage. mMainStage.deactivate(wct); } mTaskOrganizer.applyTransaction(wct); } } @Override public void onSnappedToDismiss(boolean bottomOrRight) { if (mSideStagePosition == SIDE_STAGE_POSITION_BOTTOM_OR_RIGHT && bottomOrRight) { // Main stage was fully expanded...Just side side-stage. setSideStageVisibility(false); } else { // Side stage was fully expanded...Move its top task to the main stage // and hide side-stage. // TODO: Would UX prefer the side-stage go into fullscreen mode here? final int taskId = mSideStage.getTopVisibleTaskId(); if (taskId == INVALID_TASK_ID) { throw new IllegalStateException("Side stage doesn't have visible task? " + mSideStage); } final WindowContainerTransaction wct = new WindowContainerTransaction(); mSideStage.removeTask(taskId, mMainStage.mRootTaskInfo.getToken(), wct); mSideStage.setVisibility(false, wct); mTaskOrganizer.applyTransaction(wct); } // Reset divider position. mSplitLayout.resetDividerPosition(); final boolean mainStageToTop = bottomOrRight && mSideStagePosition == SIDE_STAGE_POSITION_BOTTOM_OR_RIGHT; exitSplitScreen(mainStageToTop ? mMainStage : mSideStage); } @Override Loading