Loading libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java +18 −2 Original line number Diff line number Diff line Loading @@ -180,8 +180,6 @@ public final class SplitLayout implements DisplayInsetsController.OnInsetsChange /** Applies new configuration, returns {@code false} if there's no effect to the layout. */ public boolean updateConfiguration(Configuration configuration) { boolean affectsLayout = false; // Update the split bounds when necessary. Besides root bounds changed, split bounds need to // be updated when the rotation changed to cover the case that users rotated the screen 180 // degrees. Loading Loading @@ -214,6 +212,24 @@ public final class SplitLayout implements DisplayInsetsController.OnInsetsChange return true; } /** Rotate the layout to specific rotation and assume its new bounds. */ public void rotateTo(int newRotation) { final int rotationDelta = (newRotation - mRotation + 4) % 4; final boolean changeOrient = (rotationDelta % 2) != 0; mRotation = newRotation; Rect tmpRect = new Rect(mRootBounds); if (changeOrient) { tmpRect.set(mRootBounds.top, mRootBounds.left, mRootBounds.bottom, mRootBounds.right); } final Configuration config = new Configuration(); config.setTo(mContext.getResources().getConfiguration()); config.orientation = mOrientation; config.windowConfiguration.setBounds(tmpRect); updateConfiguration(config); } private void initDividerPosition(Rect oldBounds) { final float snapRatio = (float) mDividePosition / (float) (isLandscape(oldBounds) ? oldBounds.width() : oldBounds.height()); Loading libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java +2 −1 Original line number Diff line number Diff line Loading @@ -161,13 +161,14 @@ public class WMShellModule { SyncTransactionQueue syncQueue, Context context, RootTaskDisplayAreaOrganizer rootTaskDisplayAreaOrganizer, @ShellMainThread ShellExecutor mainExecutor, DisplayController displayController, DisplayImeController displayImeController, DisplayInsetsController displayInsetsController, Transitions transitions, TransactionPool transactionPool, IconProvider iconProvider, Optional<RecentTasksController> recentTasks, Provider<Optional<StageTaskUnfoldController>> stageTaskUnfoldControllerProvider) { return new SplitScreenController(shellTaskOrganizer, syncQueue, context, rootTaskDisplayAreaOrganizer, mainExecutor, displayImeController, rootTaskDisplayAreaOrganizer, mainExecutor, displayController, displayImeController, displayInsetsController, transitions, transactionPool, iconProvider, recentTasks, stageTaskUnfoldControllerProvider); } Loading libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java +6 −2 Original line number Diff line number Diff line Loading @@ -58,6 +58,7 @@ import com.android.internal.logging.InstanceId; import com.android.launcher3.icons.IconProvider; import com.android.wm.shell.RootTaskDisplayAreaOrganizer; import com.android.wm.shell.ShellTaskOrganizer; import com.android.wm.shell.common.DisplayController; import com.android.wm.shell.common.DisplayImeController; import com.android.wm.shell.common.DisplayInsetsController; import com.android.wm.shell.common.RemoteCallable; Loading Loading @@ -124,6 +125,7 @@ public class SplitScreenController implements DragAndDropPolicy.Starter, private final RootTaskDisplayAreaOrganizer mRootTDAOrganizer; private final ShellExecutor mMainExecutor; private final SplitScreenImpl mImpl = new SplitScreenImpl(); private final DisplayController mDisplayController; private final DisplayImeController mDisplayImeController; private final DisplayInsetsController mDisplayInsetsController; private final Transitions mTransitions; Loading @@ -138,7 +140,8 @@ public class SplitScreenController implements DragAndDropPolicy.Starter, public SplitScreenController(ShellTaskOrganizer shellTaskOrganizer, SyncTransactionQueue syncQueue, Context context, RootTaskDisplayAreaOrganizer rootTDAOrganizer, ShellExecutor mainExecutor, DisplayImeController displayImeController, ShellExecutor mainExecutor, DisplayController displayController, DisplayImeController displayImeController, DisplayInsetsController displayInsetsController, Transitions transitions, TransactionPool transactionPool, IconProvider iconProvider, Optional<RecentTasksController> recentTasks, Loading @@ -148,6 +151,7 @@ public class SplitScreenController implements DragAndDropPolicy.Starter, mContext = context; mRootTDAOrganizer = rootTDAOrganizer; mMainExecutor = mainExecutor; mDisplayController = displayController; mDisplayImeController = displayImeController; mDisplayInsetsController = displayInsetsController; mTransitions = transitions; Loading Loading @@ -176,7 +180,7 @@ public class SplitScreenController implements DragAndDropPolicy.Starter, if (mStageCoordinator == null) { // TODO: Multi-display mStageCoordinator = new StageCoordinator(mContext, DEFAULT_DISPLAY, mSyncQueue, mRootTDAOrganizer, mTaskOrganizer, mDisplayImeController, mRootTDAOrganizer, mTaskOrganizer, mDisplayController, mDisplayImeController, mDisplayInsetsController, mTransitions, mTransactionPool, mLogger, mIconProvider, mRecentTasksOptional, mUnfoldControllerProvider); } Loading libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenTransitions.java +3 −2 Original line number Diff line number Diff line Loading @@ -144,8 +144,9 @@ class SplitScreenTransitions { if (transition == mPendingEnter && (mainRoot.equals(change.getContainer()) || sideRoot.equals(change.getContainer()))) { t.setWindowCrop(leash, change.getStartAbsBounds().width(), change.getStartAbsBounds().height()); t.setPosition(leash, change.getEndAbsBounds().left, change.getEndAbsBounds().top); t.setWindowCrop(leash, change.getEndAbsBounds().width(), change.getEndAbsBounds().height()); } boolean isOpening = isOpeningType(info.getType()); if (isOpening && (mode == TRANSIT_OPEN || mode == TRANSIT_TO_FRONT)) { Loading libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java +78 −32 Original line number Diff line number Diff line Loading @@ -21,7 +21,9 @@ import static android.app.ActivityTaskManager.INVALID_TASK_ID; import static android.app.WindowConfiguration.ACTIVITY_TYPE_ASSISTANT; import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME; import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; import static android.view.Display.DEFAULT_DISPLAY; import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER; import static android.view.WindowManager.TRANSIT_CHANGE; import static android.view.WindowManager.TRANSIT_TO_BACK; import static android.view.WindowManager.TRANSIT_TO_FRONT; import static android.view.WindowManager.transitTypeToString; Loading Loading @@ -83,6 +85,7 @@ import com.android.internal.protolog.common.ProtoLog; import com.android.launcher3.icons.IconProvider; import com.android.wm.shell.RootTaskDisplayAreaOrganizer; import com.android.wm.shell.ShellTaskOrganizer; import com.android.wm.shell.common.DisplayController; import com.android.wm.shell.common.DisplayImeController; import com.android.wm.shell.common.DisplayInsetsController; import com.android.wm.shell.common.SyncTransactionQueue; Loading Loading @@ -118,7 +121,8 @@ import javax.inject.Provider; * {@link #onStageHasChildrenChanged(StageListenerImpl).} */ class StageCoordinator implements SplitLayout.SplitLayoutHandler, RootTaskDisplayAreaOrganizer.RootTaskDisplayAreaListener, Transitions.TransitionHandler { RootTaskDisplayAreaOrganizer.RootTaskDisplayAreaListener, DisplayController.OnDisplaysChangedListener, Transitions.TransitionHandler { private static final String TAG = StageCoordinator.class.getSimpleName(); Loading @@ -142,8 +146,10 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler, private DisplayAreaInfo mDisplayAreaInfo; private final Context mContext; private final List<SplitScreen.SplitScreenListener> mListeners = new ArrayList<>(); private final DisplayController mDisplayController; private final DisplayImeController mDisplayImeController; private final DisplayInsetsController mDisplayInsetsController; private final TransactionPool mTransactionPool; private final SplitScreenTransitions mSplitTransitions; private final SplitscreenEventLogger mLogger; private final Optional<RecentTasksController> mRecentTasks; Loading @@ -163,7 +169,7 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler, if (!isSplitScreenVisible()) { // Update divider state after animation so that it is still around and positioned // properly for the animation itself. setDividerVisibility(false); mSplitLayout.release(); mSplitLayout.resetDividerPosition(); } }; Loading @@ -183,6 +189,7 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler, StageCoordinator(Context context, int displayId, SyncTransactionQueue syncQueue, RootTaskDisplayAreaOrganizer rootTDAOrganizer, ShellTaskOrganizer taskOrganizer, DisplayController displayController, DisplayImeController displayImeController, DisplayInsetsController displayInsetsController, Transitions transitions, TransactionPool transactionPool, SplitscreenEventLogger logger, Loading Loading @@ -217,8 +224,10 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler, mSurfaceSession, iconProvider, mSideUnfoldController); mDisplayController = displayController; mDisplayImeController = displayImeController; mDisplayInsetsController = displayInsetsController; mTransactionPool = transactionPool; mRootTDAOrganizer.registerListener(displayId, this); final DeviceStateManager deviceStateManager = mContext.getSystemService(DeviceStateManager.class); Loading @@ -226,13 +235,15 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler, new DeviceStateManager.FoldStateListener(mContext, this::onFoldedStateChanged)); mSplitTransitions = new SplitScreenTransitions(transactionPool, transitions, mOnTransitionAnimationComplete); mDisplayController.addDisplayWindowListener(this); transitions.addHandler(this); } @VisibleForTesting StageCoordinator(Context context, int displayId, SyncTransactionQueue syncQueue, RootTaskDisplayAreaOrganizer rootTDAOrganizer, ShellTaskOrganizer taskOrganizer, MainStage mainStage, SideStage sideStage, DisplayImeController displayImeController, MainStage mainStage, SideStage sideStage, DisplayController displayController, DisplayImeController displayImeController, DisplayInsetsController displayInsetsController, SplitLayout splitLayout, Transitions transitions, TransactionPool transactionPool, SplitscreenEventLogger logger, Loading @@ -245,8 +256,10 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler, mTaskOrganizer = taskOrganizer; mMainStage = mainStage; mSideStage = sideStage; mDisplayController = displayController; mDisplayImeController = displayImeController; mDisplayInsetsController = displayInsetsController; mTransactionPool = transactionPool; mRootTDAOrganizer.registerListener(displayId, this); mSplitLayout = splitLayout; mSplitTransitions = new SplitScreenTransitions(transactionPool, transitions, Loading @@ -255,6 +268,7 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler, mSideUnfoldController = unfoldControllerProvider.get().orElse(null); mLogger = logger; mRecentTasks = recentTasks; mDisplayController.addDisplayWindowListener(this); transitions.addHandler(this); } Loading Loading @@ -630,8 +644,8 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler, .setWindowCrop(mSideStage.mRootLeash, null)); // Hide divider and reset its position. setDividerVisibility(false); mSplitLayout.resetDividerPosition(); mSplitLayout.release(); mTopStageAfterFoldDismiss = STAGE_TYPE_UNDEFINED; Slog.i(TAG, "applyExitSplitScreen, reason = " + exitReasonToString(exitReason)); // Log the exit Loading Loading @@ -811,29 +825,12 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler, } } private void setDividerVisibility(boolean visible) { if (mDividerVisible == visible) return; mDividerVisible = visible; if (visible) { mSplitLayout.init(); updateUnfoldBounds(); } else { mSplitLayout.release(); } sendSplitVisibilityChanged(); } private void onStageVisibilityChanged(StageListenerImpl stageListener) { final boolean sideStageVisible = mSideStageListener.mVisible; final boolean mainStageVisible = mMainStageListener.mVisible; final boolean bothStageVisible = sideStageVisible && mainStageVisible; final boolean bothStageInvisible = !sideStageVisible && !mainStageVisible; final boolean sameVisibility = sideStageVisible == mainStageVisible; // Only add or remove divider when both visible or both invisible to avoid sometimes we only // got one stage visibility changed for a moment and it will cause flicker. if (sameVisibility) { setDividerVisibility(bothStageVisible); } if (bothStageInvisible) { if (mExitSplitScreenOnHide Loading @@ -854,11 +851,21 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler, if (sameVisibility) { t.setVisibility(mSideStage.mRootLeash, bothStageVisible) .setVisibility(mMainStage.mRootLeash, bothStageVisible); applyDividerVisibility(t); setDividerVisibility(bothStageVisible, t); } }); } private void setDividerVisibility(boolean visible, @Nullable SurfaceControl.Transaction t) { mDividerVisible = visible; sendSplitVisibilityChanged(); if (t != null) { applyDividerVisibility(t); } else { mSyncQueue.runInSync(transaction -> applyDividerVisibility(transaction)); } } private void applyDividerVisibility(SurfaceControl.Transaction t) { final SurfaceControl dividerLeash = mSplitLayout.getDividerLeash(); if (dividerLeash == null) { Loading @@ -866,11 +873,10 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler, } if (mDividerVisible) { t.show(dividerLeash) .setLayer(dividerLeash, SPLIT_DIVIDER_LAYER) .setPosition(dividerLeash, mSplitLayout.getDividerBounds().left, mSplitLayout.getDividerBounds().top); t.show(dividerLeash); t.setLayer(dividerLeash, SPLIT_DIVIDER_LAYER); t.setPosition(dividerLeash, mSplitLayout.getDividerBounds().left, mSplitLayout.getDividerBounds().top); } else { t.hide(dividerLeash); } Loading Loading @@ -1050,10 +1056,39 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler, if (mSplitLayout != null && mSplitLayout.updateConfiguration(mDisplayAreaInfo.configuration) && mMainStage.isActive()) { // TODO(b/204925795): With Shell transition, We are handle roation case for apply split // bounds at onRotateDisplay. But still need to handle unfold case. if (ENABLE_SHELL_TRANSITIONS) { updateUnfoldBounds(); return; } onLayoutSizeChanged(mSplitLayout); } } @Override public void onDisplayAdded(int displayId) { if (displayId != DEFAULT_DISPLAY) { return; } mDisplayController.addDisplayChangingController(this::onRotateDisplay); } private void onRotateDisplay(int displayId, int fromRotation, int toRotation, WindowContainerTransaction wct) { if (!mMainStage.isActive()) return; // Only do this when shell transition if (!ENABLE_SHELL_TRANSITIONS) return; final SurfaceControl.Transaction t = mTransactionPool.acquire(); setDividerVisibility(false, t); mSplitLayout.rotateTo(toRotation); updateWindowBounds(mSplitLayout, wct); updateUnfoldBounds(); t.apply(); mTransactionPool.release(t); } private void onFoldedStateChanged(boolean folded) { mTopStageAfterFoldDismiss = STAGE_TYPE_UNDEFINED; if (!folded) return; Loading Loading @@ -1192,6 +1227,10 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler, Log.w(TAG, "Expected onTaskVanished on " + stage + " to have been called" + " with " + taskInfo.taskId + " before startAnimation()."); } } else if (info.getType() == TRANSIT_CHANGE && change.getStartRotation() != change.getEndRotation()) { // Show the divider after transition finished. setDividerVisibility(true, finishTransaction); } } if (mMainStage.getChildCount() == 0 || mSideStage.getChildCount() == 0) { Loading @@ -1216,7 +1255,7 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler, } else if (mSplitTransitions.mPendingDismiss != null && mSplitTransitions.mPendingDismiss.mTransition == transition) { shouldAnimate = startPendingDismissAnimation( mSplitTransitions.mPendingDismiss, info, startTransaction); mSplitTransitions.mPendingDismiss, info, startTransaction, finishTransaction); } if (!shouldAnimate) return false; Loading Loading @@ -1249,7 +1288,8 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler, } // Update local states (before animating). setDividerVisibility(true); mSplitLayout.init(); setDividerVisibility(true, t); setSplitsVisible(true); addDividerBarToTransition(info, t, true /* show */); Loading Loading @@ -1286,7 +1326,8 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler, private boolean startPendingDismissAnimation( @NonNull SplitScreenTransitions.DismissTransition dismissTransition, @NonNull TransitionInfo info, @NonNull SurfaceControl.Transaction t) { @NonNull TransitionInfo info, @NonNull SurfaceControl.Transaction t, @NonNull SurfaceControl.Transaction finishT) { // Make some noise if things aren't totally expected. These states shouldn't effect // transitions locally, but remotes (like Launcher) may get confused if they were // depending on listener callbacks. This can happen because task-organizer callbacks Loading Loading @@ -1343,8 +1384,8 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler, logExit(dismissTransition.mReason); // TODO: Have a proper remote for this. Until then, though, reset state and use the // normal animation stuff (which falls back to the normal launcher remote). t.hide(mSplitLayout.getDividerLeash()); setDividerVisibility(false); setDividerVisibility(false, t); mSplitLayout.release(); mSplitTransitions.mPendingDismiss = null; return false; } else { Loading @@ -1356,6 +1397,11 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler, // We're dismissing split by moving the other one to fullscreen. // Since we don't have any animations for this yet, just use the internal example // animations. // Hide divider and dim layer on transition finished. setDividerVisibility(false, finishT); finishT.hide(mMainStage.mDimLayer); finishT.hide(mSideStage.mDimLayer); return true; } Loading Loading
libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java +18 −2 Original line number Diff line number Diff line Loading @@ -180,8 +180,6 @@ public final class SplitLayout implements DisplayInsetsController.OnInsetsChange /** Applies new configuration, returns {@code false} if there's no effect to the layout. */ public boolean updateConfiguration(Configuration configuration) { boolean affectsLayout = false; // Update the split bounds when necessary. Besides root bounds changed, split bounds need to // be updated when the rotation changed to cover the case that users rotated the screen 180 // degrees. Loading Loading @@ -214,6 +212,24 @@ public final class SplitLayout implements DisplayInsetsController.OnInsetsChange return true; } /** Rotate the layout to specific rotation and assume its new bounds. */ public void rotateTo(int newRotation) { final int rotationDelta = (newRotation - mRotation + 4) % 4; final boolean changeOrient = (rotationDelta % 2) != 0; mRotation = newRotation; Rect tmpRect = new Rect(mRootBounds); if (changeOrient) { tmpRect.set(mRootBounds.top, mRootBounds.left, mRootBounds.bottom, mRootBounds.right); } final Configuration config = new Configuration(); config.setTo(mContext.getResources().getConfiguration()); config.orientation = mOrientation; config.windowConfiguration.setBounds(tmpRect); updateConfiguration(config); } private void initDividerPosition(Rect oldBounds) { final float snapRatio = (float) mDividePosition / (float) (isLandscape(oldBounds) ? oldBounds.width() : oldBounds.height()); Loading
libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java +2 −1 Original line number Diff line number Diff line Loading @@ -161,13 +161,14 @@ public class WMShellModule { SyncTransactionQueue syncQueue, Context context, RootTaskDisplayAreaOrganizer rootTaskDisplayAreaOrganizer, @ShellMainThread ShellExecutor mainExecutor, DisplayController displayController, DisplayImeController displayImeController, DisplayInsetsController displayInsetsController, Transitions transitions, TransactionPool transactionPool, IconProvider iconProvider, Optional<RecentTasksController> recentTasks, Provider<Optional<StageTaskUnfoldController>> stageTaskUnfoldControllerProvider) { return new SplitScreenController(shellTaskOrganizer, syncQueue, context, rootTaskDisplayAreaOrganizer, mainExecutor, displayImeController, rootTaskDisplayAreaOrganizer, mainExecutor, displayController, displayImeController, displayInsetsController, transitions, transactionPool, iconProvider, recentTasks, stageTaskUnfoldControllerProvider); } Loading
libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java +6 −2 Original line number Diff line number Diff line Loading @@ -58,6 +58,7 @@ import com.android.internal.logging.InstanceId; import com.android.launcher3.icons.IconProvider; import com.android.wm.shell.RootTaskDisplayAreaOrganizer; import com.android.wm.shell.ShellTaskOrganizer; import com.android.wm.shell.common.DisplayController; import com.android.wm.shell.common.DisplayImeController; import com.android.wm.shell.common.DisplayInsetsController; import com.android.wm.shell.common.RemoteCallable; Loading Loading @@ -124,6 +125,7 @@ public class SplitScreenController implements DragAndDropPolicy.Starter, private final RootTaskDisplayAreaOrganizer mRootTDAOrganizer; private final ShellExecutor mMainExecutor; private final SplitScreenImpl mImpl = new SplitScreenImpl(); private final DisplayController mDisplayController; private final DisplayImeController mDisplayImeController; private final DisplayInsetsController mDisplayInsetsController; private final Transitions mTransitions; Loading @@ -138,7 +140,8 @@ public class SplitScreenController implements DragAndDropPolicy.Starter, public SplitScreenController(ShellTaskOrganizer shellTaskOrganizer, SyncTransactionQueue syncQueue, Context context, RootTaskDisplayAreaOrganizer rootTDAOrganizer, ShellExecutor mainExecutor, DisplayImeController displayImeController, ShellExecutor mainExecutor, DisplayController displayController, DisplayImeController displayImeController, DisplayInsetsController displayInsetsController, Transitions transitions, TransactionPool transactionPool, IconProvider iconProvider, Optional<RecentTasksController> recentTasks, Loading @@ -148,6 +151,7 @@ public class SplitScreenController implements DragAndDropPolicy.Starter, mContext = context; mRootTDAOrganizer = rootTDAOrganizer; mMainExecutor = mainExecutor; mDisplayController = displayController; mDisplayImeController = displayImeController; mDisplayInsetsController = displayInsetsController; mTransitions = transitions; Loading Loading @@ -176,7 +180,7 @@ public class SplitScreenController implements DragAndDropPolicy.Starter, if (mStageCoordinator == null) { // TODO: Multi-display mStageCoordinator = new StageCoordinator(mContext, DEFAULT_DISPLAY, mSyncQueue, mRootTDAOrganizer, mTaskOrganizer, mDisplayImeController, mRootTDAOrganizer, mTaskOrganizer, mDisplayController, mDisplayImeController, mDisplayInsetsController, mTransitions, mTransactionPool, mLogger, mIconProvider, mRecentTasksOptional, mUnfoldControllerProvider); } Loading
libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenTransitions.java +3 −2 Original line number Diff line number Diff line Loading @@ -144,8 +144,9 @@ class SplitScreenTransitions { if (transition == mPendingEnter && (mainRoot.equals(change.getContainer()) || sideRoot.equals(change.getContainer()))) { t.setWindowCrop(leash, change.getStartAbsBounds().width(), change.getStartAbsBounds().height()); t.setPosition(leash, change.getEndAbsBounds().left, change.getEndAbsBounds().top); t.setWindowCrop(leash, change.getEndAbsBounds().width(), change.getEndAbsBounds().height()); } boolean isOpening = isOpeningType(info.getType()); if (isOpening && (mode == TRANSIT_OPEN || mode == TRANSIT_TO_FRONT)) { Loading
libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java +78 −32 Original line number Diff line number Diff line Loading @@ -21,7 +21,9 @@ import static android.app.ActivityTaskManager.INVALID_TASK_ID; import static android.app.WindowConfiguration.ACTIVITY_TYPE_ASSISTANT; import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME; import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; import static android.view.Display.DEFAULT_DISPLAY; import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER; import static android.view.WindowManager.TRANSIT_CHANGE; import static android.view.WindowManager.TRANSIT_TO_BACK; import static android.view.WindowManager.TRANSIT_TO_FRONT; import static android.view.WindowManager.transitTypeToString; Loading Loading @@ -83,6 +85,7 @@ import com.android.internal.protolog.common.ProtoLog; import com.android.launcher3.icons.IconProvider; import com.android.wm.shell.RootTaskDisplayAreaOrganizer; import com.android.wm.shell.ShellTaskOrganizer; import com.android.wm.shell.common.DisplayController; import com.android.wm.shell.common.DisplayImeController; import com.android.wm.shell.common.DisplayInsetsController; import com.android.wm.shell.common.SyncTransactionQueue; Loading Loading @@ -118,7 +121,8 @@ import javax.inject.Provider; * {@link #onStageHasChildrenChanged(StageListenerImpl).} */ class StageCoordinator implements SplitLayout.SplitLayoutHandler, RootTaskDisplayAreaOrganizer.RootTaskDisplayAreaListener, Transitions.TransitionHandler { RootTaskDisplayAreaOrganizer.RootTaskDisplayAreaListener, DisplayController.OnDisplaysChangedListener, Transitions.TransitionHandler { private static final String TAG = StageCoordinator.class.getSimpleName(); Loading @@ -142,8 +146,10 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler, private DisplayAreaInfo mDisplayAreaInfo; private final Context mContext; private final List<SplitScreen.SplitScreenListener> mListeners = new ArrayList<>(); private final DisplayController mDisplayController; private final DisplayImeController mDisplayImeController; private final DisplayInsetsController mDisplayInsetsController; private final TransactionPool mTransactionPool; private final SplitScreenTransitions mSplitTransitions; private final SplitscreenEventLogger mLogger; private final Optional<RecentTasksController> mRecentTasks; Loading @@ -163,7 +169,7 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler, if (!isSplitScreenVisible()) { // Update divider state after animation so that it is still around and positioned // properly for the animation itself. setDividerVisibility(false); mSplitLayout.release(); mSplitLayout.resetDividerPosition(); } }; Loading @@ -183,6 +189,7 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler, StageCoordinator(Context context, int displayId, SyncTransactionQueue syncQueue, RootTaskDisplayAreaOrganizer rootTDAOrganizer, ShellTaskOrganizer taskOrganizer, DisplayController displayController, DisplayImeController displayImeController, DisplayInsetsController displayInsetsController, Transitions transitions, TransactionPool transactionPool, SplitscreenEventLogger logger, Loading Loading @@ -217,8 +224,10 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler, mSurfaceSession, iconProvider, mSideUnfoldController); mDisplayController = displayController; mDisplayImeController = displayImeController; mDisplayInsetsController = displayInsetsController; mTransactionPool = transactionPool; mRootTDAOrganizer.registerListener(displayId, this); final DeviceStateManager deviceStateManager = mContext.getSystemService(DeviceStateManager.class); Loading @@ -226,13 +235,15 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler, new DeviceStateManager.FoldStateListener(mContext, this::onFoldedStateChanged)); mSplitTransitions = new SplitScreenTransitions(transactionPool, transitions, mOnTransitionAnimationComplete); mDisplayController.addDisplayWindowListener(this); transitions.addHandler(this); } @VisibleForTesting StageCoordinator(Context context, int displayId, SyncTransactionQueue syncQueue, RootTaskDisplayAreaOrganizer rootTDAOrganizer, ShellTaskOrganizer taskOrganizer, MainStage mainStage, SideStage sideStage, DisplayImeController displayImeController, MainStage mainStage, SideStage sideStage, DisplayController displayController, DisplayImeController displayImeController, DisplayInsetsController displayInsetsController, SplitLayout splitLayout, Transitions transitions, TransactionPool transactionPool, SplitscreenEventLogger logger, Loading @@ -245,8 +256,10 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler, mTaskOrganizer = taskOrganizer; mMainStage = mainStage; mSideStage = sideStage; mDisplayController = displayController; mDisplayImeController = displayImeController; mDisplayInsetsController = displayInsetsController; mTransactionPool = transactionPool; mRootTDAOrganizer.registerListener(displayId, this); mSplitLayout = splitLayout; mSplitTransitions = new SplitScreenTransitions(transactionPool, transitions, Loading @@ -255,6 +268,7 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler, mSideUnfoldController = unfoldControllerProvider.get().orElse(null); mLogger = logger; mRecentTasks = recentTasks; mDisplayController.addDisplayWindowListener(this); transitions.addHandler(this); } Loading Loading @@ -630,8 +644,8 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler, .setWindowCrop(mSideStage.mRootLeash, null)); // Hide divider and reset its position. setDividerVisibility(false); mSplitLayout.resetDividerPosition(); mSplitLayout.release(); mTopStageAfterFoldDismiss = STAGE_TYPE_UNDEFINED; Slog.i(TAG, "applyExitSplitScreen, reason = " + exitReasonToString(exitReason)); // Log the exit Loading Loading @@ -811,29 +825,12 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler, } } private void setDividerVisibility(boolean visible) { if (mDividerVisible == visible) return; mDividerVisible = visible; if (visible) { mSplitLayout.init(); updateUnfoldBounds(); } else { mSplitLayout.release(); } sendSplitVisibilityChanged(); } private void onStageVisibilityChanged(StageListenerImpl stageListener) { final boolean sideStageVisible = mSideStageListener.mVisible; final boolean mainStageVisible = mMainStageListener.mVisible; final boolean bothStageVisible = sideStageVisible && mainStageVisible; final boolean bothStageInvisible = !sideStageVisible && !mainStageVisible; final boolean sameVisibility = sideStageVisible == mainStageVisible; // Only add or remove divider when both visible or both invisible to avoid sometimes we only // got one stage visibility changed for a moment and it will cause flicker. if (sameVisibility) { setDividerVisibility(bothStageVisible); } if (bothStageInvisible) { if (mExitSplitScreenOnHide Loading @@ -854,11 +851,21 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler, if (sameVisibility) { t.setVisibility(mSideStage.mRootLeash, bothStageVisible) .setVisibility(mMainStage.mRootLeash, bothStageVisible); applyDividerVisibility(t); setDividerVisibility(bothStageVisible, t); } }); } private void setDividerVisibility(boolean visible, @Nullable SurfaceControl.Transaction t) { mDividerVisible = visible; sendSplitVisibilityChanged(); if (t != null) { applyDividerVisibility(t); } else { mSyncQueue.runInSync(transaction -> applyDividerVisibility(transaction)); } } private void applyDividerVisibility(SurfaceControl.Transaction t) { final SurfaceControl dividerLeash = mSplitLayout.getDividerLeash(); if (dividerLeash == null) { Loading @@ -866,11 +873,10 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler, } if (mDividerVisible) { t.show(dividerLeash) .setLayer(dividerLeash, SPLIT_DIVIDER_LAYER) .setPosition(dividerLeash, mSplitLayout.getDividerBounds().left, mSplitLayout.getDividerBounds().top); t.show(dividerLeash); t.setLayer(dividerLeash, SPLIT_DIVIDER_LAYER); t.setPosition(dividerLeash, mSplitLayout.getDividerBounds().left, mSplitLayout.getDividerBounds().top); } else { t.hide(dividerLeash); } Loading Loading @@ -1050,10 +1056,39 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler, if (mSplitLayout != null && mSplitLayout.updateConfiguration(mDisplayAreaInfo.configuration) && mMainStage.isActive()) { // TODO(b/204925795): With Shell transition, We are handle roation case for apply split // bounds at onRotateDisplay. But still need to handle unfold case. if (ENABLE_SHELL_TRANSITIONS) { updateUnfoldBounds(); return; } onLayoutSizeChanged(mSplitLayout); } } @Override public void onDisplayAdded(int displayId) { if (displayId != DEFAULT_DISPLAY) { return; } mDisplayController.addDisplayChangingController(this::onRotateDisplay); } private void onRotateDisplay(int displayId, int fromRotation, int toRotation, WindowContainerTransaction wct) { if (!mMainStage.isActive()) return; // Only do this when shell transition if (!ENABLE_SHELL_TRANSITIONS) return; final SurfaceControl.Transaction t = mTransactionPool.acquire(); setDividerVisibility(false, t); mSplitLayout.rotateTo(toRotation); updateWindowBounds(mSplitLayout, wct); updateUnfoldBounds(); t.apply(); mTransactionPool.release(t); } private void onFoldedStateChanged(boolean folded) { mTopStageAfterFoldDismiss = STAGE_TYPE_UNDEFINED; if (!folded) return; Loading Loading @@ -1192,6 +1227,10 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler, Log.w(TAG, "Expected onTaskVanished on " + stage + " to have been called" + " with " + taskInfo.taskId + " before startAnimation()."); } } else if (info.getType() == TRANSIT_CHANGE && change.getStartRotation() != change.getEndRotation()) { // Show the divider after transition finished. setDividerVisibility(true, finishTransaction); } } if (mMainStage.getChildCount() == 0 || mSideStage.getChildCount() == 0) { Loading @@ -1216,7 +1255,7 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler, } else if (mSplitTransitions.mPendingDismiss != null && mSplitTransitions.mPendingDismiss.mTransition == transition) { shouldAnimate = startPendingDismissAnimation( mSplitTransitions.mPendingDismiss, info, startTransaction); mSplitTransitions.mPendingDismiss, info, startTransaction, finishTransaction); } if (!shouldAnimate) return false; Loading Loading @@ -1249,7 +1288,8 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler, } // Update local states (before animating). setDividerVisibility(true); mSplitLayout.init(); setDividerVisibility(true, t); setSplitsVisible(true); addDividerBarToTransition(info, t, true /* show */); Loading Loading @@ -1286,7 +1326,8 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler, private boolean startPendingDismissAnimation( @NonNull SplitScreenTransitions.DismissTransition dismissTransition, @NonNull TransitionInfo info, @NonNull SurfaceControl.Transaction t) { @NonNull TransitionInfo info, @NonNull SurfaceControl.Transaction t, @NonNull SurfaceControl.Transaction finishT) { // Make some noise if things aren't totally expected. These states shouldn't effect // transitions locally, but remotes (like Launcher) may get confused if they were // depending on listener callbacks. This can happen because task-organizer callbacks Loading Loading @@ -1343,8 +1384,8 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler, logExit(dismissTransition.mReason); // TODO: Have a proper remote for this. Until then, though, reset state and use the // normal animation stuff (which falls back to the normal launcher remote). t.hide(mSplitLayout.getDividerLeash()); setDividerVisibility(false); setDividerVisibility(false, t); mSplitLayout.release(); mSplitTransitions.mPendingDismiss = null; return false; } else { Loading @@ -1356,6 +1397,11 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler, // We're dismissing split by moving the other one to fullscreen. // Since we don't have any animations for this yet, just use the internal example // animations. // Hide divider and dim layer on transition finished. setDividerVisibility(false, finishT); finishT.hide(mMainStage.mDimLayer); finishT.hide(mSideStage.mDimLayer); return true; } Loading