Loading libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenTransitions.java +17 −6 Original line number Diff line number Diff line Loading @@ -68,6 +68,7 @@ class SplitScreenTransitions { private IBinder mAnimatingTransition = null; OneShotRemoteHandler mPendingRemoteHandler = null; private OneShotRemoteHandler mActiveRemoteHandler = null; private boolean mEnterTransitionMerged; private final Transitions.TransitionFinishCallback mRemoteFinishCB = this::onFinish; Loading Loading @@ -229,6 +230,18 @@ class SplitScreenTransitions { } } void onTransitionMerged(@NonNull IBinder transition) { // Once a pending enter transition got merged, make sure to append the reset of finishing // operations to the finish transition. if (transition == mPendingEnter) { mFinishTransaction = mTransactionPool.acquire(); mStageCoordinator.finishEnterSplitScreen(mFinishTransaction); mPendingEnter = null; mPendingRemoteHandler = null; mEnterTransitionMerged = true; } } void onFinish(WindowContainerTransaction wct, WindowContainerTransactionCallback wctCB) { if (!mAnimations.isEmpty()) return; if (mAnimatingTransition == mPendingEnter) { Loading @@ -238,18 +251,16 @@ class SplitScreenTransitions { mPendingDismiss = null; } if (mAnimatingTransition == mPendingRecent) { // If the clean-up wct is null when finishing recent transition, it indicates it's // returning to home and thus no need to reorder tasks. final boolean returnToHome = wct == null; if (returnToHome) { wct = new WindowContainerTransaction(); if (!mEnterTransitionMerged) { if (wct == null) wct = new WindowContainerTransaction(); mStageCoordinator.onRecentTransitionFinished(wct, mFinishTransaction); } mStageCoordinator.onRecentTransitionFinished(returnToHome, wct, mFinishTransaction); mPendingRecent = null; } mPendingRemoteHandler = null; mActiveRemoteHandler = null; mAnimatingTransition = null; mEnterTransitionMerged = false; mOnFinish.run(); if (mFinishTransaction != null) { Loading libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java +27 −30 Original line number Diff line number Diff line Loading @@ -30,6 +30,7 @@ import static android.view.WindowManager.TRANSIT_TO_FRONT; import static android.view.WindowManager.transitTypeToString; import static android.window.TransitionInfo.FLAG_FIRST_CUSTOM; import static android.window.TransitionInfo.FLAG_IS_DISPLAY; import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_REORDER; import static com.android.wm.shell.common.split.SplitLayout.PARALLAX_ALIGN_CENTER; import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_BOTTOM_OR_RIGHT; Loading Loading @@ -369,10 +370,15 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, sideOptions = sideOptions != null ? sideOptions : new Bundle(); setSideStagePosition(sidePosition, wct); mSplitLayout.setDivideRatio(splitRatio); if (mMainStage.isActive()) { mMainStage.evictAllChildren(wct); mSideStage.evictAllChildren(wct); } else { // Build a request WCT that will launch both apps such that task 0 is on the main stage // while task 1 is on the side stage. mMainStage.activate(wct, false /* reparent */); } mSplitLayout.setDivideRatio(splitRatio); updateWindowBounds(mSplitLayout, wct); wct.reorder(mRootTaskInfo.token, true); Loading Loading @@ -1507,16 +1513,7 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, @Override public void onTransitionMerged(@NonNull IBinder transition) { // Once the pending enter transition got merged, make sure to bring divider bar visible and // clear the pending transition from cache to prevent mess-up the following state. if (transition == mSplitTransitions.mPendingEnter) { final SurfaceControl.Transaction t = mTransactionPool.acquire(); finishEnterSplitScreen(t); mSplitTransitions.mPendingEnter = null; mSplitTransitions.mPendingRemoteHandler = null; t.apply(); mTransactionPool.release(t); } mSplitTransitions.onTransitionMerged(transition); } @Override Loading Loading @@ -1748,26 +1745,26 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, return true; } void onRecentTransitionFinished(boolean returnToHome, WindowContainerTransaction wct, void onRecentTransitionFinished(WindowContainerTransaction wct, SurfaceControl.Transaction finishT) { // Exclude the case that the split screen has been dismissed already. if (!mMainStage.isActive()) { // The latest split dismissing transition might be a no-op transition and thus won't // callback startAnimation, update split visibility here to cover this kind of no-op // transition case. setSplitsVisible(false); // Check if the recent transition is finished by returning to the current split so we can // restore the divider bar. for (int i = 0; i < wct.getHierarchyOps().size(); ++i) { final WindowContainerTransaction.HierarchyOp op = wct.getHierarchyOps().get(i); final IBinder container = op.getContainer(); if (op.getType() == HIERARCHY_OP_TYPE_REORDER && op.getToTop() && (mMainStage.containsContainer(container) || mSideStage.containsContainer(container))) { setDividerVisibility(true, finishT); return; } } if (returnToHome) { // When returning to home from recent apps, the splitting tasks are already hidden, so // append the reset of dismissing operations into the clean-up wct. // Dismiss the split screen is it's not returning to split. prepareExitSplitScreen(STAGE_TYPE_UNDEFINED, wct); setSplitsVisible(false); logExit(EXIT_REASON_RETURN_HOME); } else { setDividerVisibility(true, finishT); } setDividerVisibility(false, finishT); logExit(EXIT_REASON_UNKNOWN); } private void addDividerBarToTransition(@NonNull TransitionInfo info, Loading libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java +25 −33 Original line number Diff line number Diff line Loading @@ -31,6 +31,7 @@ import android.app.ActivityManager; import android.content.Context; import android.graphics.Point; import android.graphics.Rect; import android.os.IBinder; import android.util.SparseArray; import android.view.SurfaceControl; import android.view.SurfaceSession; Loading @@ -47,6 +48,7 @@ import com.android.wm.shell.common.split.SplitDecorManager; import com.android.wm.shell.splitscreen.SplitScreen.StageType; import java.io.PrintWriter; import java.util.function.Predicate; /** * Base class that handle common task org. related for split-screen stages. Loading Loading @@ -119,63 +121,53 @@ class StageTaskListener implements ShellTaskOrganizer.TaskListener { } boolean containsToken(WindowContainerToken token) { if (token.equals(mRootTaskInfo.token)) { return true; return contains(t -> t.token.equals(token)); } for (int i = mChildrenTaskInfo.size() - 1; i >= 0; --i) { if (token.equals(mChildrenTaskInfo.valueAt(i).token)) { return true; } } return false; boolean containsContainer(IBinder binder) { return contains(t -> t.token.asBinder() == binder); } /** * Returns the top visible child task's id. */ int getTopVisibleChildTaskId() { for (int i = mChildrenTaskInfo.size() - 1; i >= 0; --i) { final ActivityManager.RunningTaskInfo info = mChildrenTaskInfo.valueAt(i); if (info.isVisible) { return info.taskId; } } return INVALID_TASK_ID; final ActivityManager.RunningTaskInfo taskInfo = getChildTaskInfo(t -> t.isVisible); return taskInfo != null ? taskInfo.taskId : INVALID_TASK_ID; } /** * Returns the top activity uid for the top child task. */ int getTopChildTaskUid() { for (int i = mChildrenTaskInfo.size() - 1; i >= 0; --i) { final ActivityManager.RunningTaskInfo info = mChildrenTaskInfo.valueAt(i); if (info.topActivityInfo == null) { continue; } return info.topActivityInfo.applicationInfo.uid; } return 0; final ActivityManager.RunningTaskInfo taskInfo = getChildTaskInfo(t -> t.topActivityInfo != null); return taskInfo != null ? taskInfo.topActivityInfo.applicationInfo.uid : 0; } /** @return {@code true} if this listener contains the currently focused task. */ boolean isFocused() { if (mRootTaskInfo == null) { return false; return contains(t -> t.isFocused); } if (mRootTaskInfo.isFocused) { private boolean contains(Predicate<ActivityManager.RunningTaskInfo> predicate) { if (mRootTaskInfo != null && predicate.test(mRootTaskInfo)) { return true; } return getChildTaskInfo(predicate) != null; } @Nullable private ActivityManager.RunningTaskInfo getChildTaskInfo( Predicate<ActivityManager.RunningTaskInfo> predicate) { for (int i = mChildrenTaskInfo.size() - 1; i >= 0; --i) { if (mChildrenTaskInfo.valueAt(i).isFocused) { return true; final ActivityManager.RunningTaskInfo taskInfo = mChildrenTaskInfo.valueAt(i); if (predicate.test(taskInfo)) { return taskInfo; } } return false; return null; } @Override Loading Loading
libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenTransitions.java +17 −6 Original line number Diff line number Diff line Loading @@ -68,6 +68,7 @@ class SplitScreenTransitions { private IBinder mAnimatingTransition = null; OneShotRemoteHandler mPendingRemoteHandler = null; private OneShotRemoteHandler mActiveRemoteHandler = null; private boolean mEnterTransitionMerged; private final Transitions.TransitionFinishCallback mRemoteFinishCB = this::onFinish; Loading Loading @@ -229,6 +230,18 @@ class SplitScreenTransitions { } } void onTransitionMerged(@NonNull IBinder transition) { // Once a pending enter transition got merged, make sure to append the reset of finishing // operations to the finish transition. if (transition == mPendingEnter) { mFinishTransaction = mTransactionPool.acquire(); mStageCoordinator.finishEnterSplitScreen(mFinishTransaction); mPendingEnter = null; mPendingRemoteHandler = null; mEnterTransitionMerged = true; } } void onFinish(WindowContainerTransaction wct, WindowContainerTransactionCallback wctCB) { if (!mAnimations.isEmpty()) return; if (mAnimatingTransition == mPendingEnter) { Loading @@ -238,18 +251,16 @@ class SplitScreenTransitions { mPendingDismiss = null; } if (mAnimatingTransition == mPendingRecent) { // If the clean-up wct is null when finishing recent transition, it indicates it's // returning to home and thus no need to reorder tasks. final boolean returnToHome = wct == null; if (returnToHome) { wct = new WindowContainerTransaction(); if (!mEnterTransitionMerged) { if (wct == null) wct = new WindowContainerTransaction(); mStageCoordinator.onRecentTransitionFinished(wct, mFinishTransaction); } mStageCoordinator.onRecentTransitionFinished(returnToHome, wct, mFinishTransaction); mPendingRecent = null; } mPendingRemoteHandler = null; mActiveRemoteHandler = null; mAnimatingTransition = null; mEnterTransitionMerged = false; mOnFinish.run(); if (mFinishTransaction != null) { Loading
libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java +27 −30 Original line number Diff line number Diff line Loading @@ -30,6 +30,7 @@ import static android.view.WindowManager.TRANSIT_TO_FRONT; import static android.view.WindowManager.transitTypeToString; import static android.window.TransitionInfo.FLAG_FIRST_CUSTOM; import static android.window.TransitionInfo.FLAG_IS_DISPLAY; import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_REORDER; import static com.android.wm.shell.common.split.SplitLayout.PARALLAX_ALIGN_CENTER; import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_BOTTOM_OR_RIGHT; Loading Loading @@ -369,10 +370,15 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, sideOptions = sideOptions != null ? sideOptions : new Bundle(); setSideStagePosition(sidePosition, wct); mSplitLayout.setDivideRatio(splitRatio); if (mMainStage.isActive()) { mMainStage.evictAllChildren(wct); mSideStage.evictAllChildren(wct); } else { // Build a request WCT that will launch both apps such that task 0 is on the main stage // while task 1 is on the side stage. mMainStage.activate(wct, false /* reparent */); } mSplitLayout.setDivideRatio(splitRatio); updateWindowBounds(mSplitLayout, wct); wct.reorder(mRootTaskInfo.token, true); Loading Loading @@ -1507,16 +1513,7 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, @Override public void onTransitionMerged(@NonNull IBinder transition) { // Once the pending enter transition got merged, make sure to bring divider bar visible and // clear the pending transition from cache to prevent mess-up the following state. if (transition == mSplitTransitions.mPendingEnter) { final SurfaceControl.Transaction t = mTransactionPool.acquire(); finishEnterSplitScreen(t); mSplitTransitions.mPendingEnter = null; mSplitTransitions.mPendingRemoteHandler = null; t.apply(); mTransactionPool.release(t); } mSplitTransitions.onTransitionMerged(transition); } @Override Loading Loading @@ -1748,26 +1745,26 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, return true; } void onRecentTransitionFinished(boolean returnToHome, WindowContainerTransaction wct, void onRecentTransitionFinished(WindowContainerTransaction wct, SurfaceControl.Transaction finishT) { // Exclude the case that the split screen has been dismissed already. if (!mMainStage.isActive()) { // The latest split dismissing transition might be a no-op transition and thus won't // callback startAnimation, update split visibility here to cover this kind of no-op // transition case. setSplitsVisible(false); // Check if the recent transition is finished by returning to the current split so we can // restore the divider bar. for (int i = 0; i < wct.getHierarchyOps().size(); ++i) { final WindowContainerTransaction.HierarchyOp op = wct.getHierarchyOps().get(i); final IBinder container = op.getContainer(); if (op.getType() == HIERARCHY_OP_TYPE_REORDER && op.getToTop() && (mMainStage.containsContainer(container) || mSideStage.containsContainer(container))) { setDividerVisibility(true, finishT); return; } } if (returnToHome) { // When returning to home from recent apps, the splitting tasks are already hidden, so // append the reset of dismissing operations into the clean-up wct. // Dismiss the split screen is it's not returning to split. prepareExitSplitScreen(STAGE_TYPE_UNDEFINED, wct); setSplitsVisible(false); logExit(EXIT_REASON_RETURN_HOME); } else { setDividerVisibility(true, finishT); } setDividerVisibility(false, finishT); logExit(EXIT_REASON_UNKNOWN); } private void addDividerBarToTransition(@NonNull TransitionInfo info, Loading
libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java +25 −33 Original line number Diff line number Diff line Loading @@ -31,6 +31,7 @@ import android.app.ActivityManager; import android.content.Context; import android.graphics.Point; import android.graphics.Rect; import android.os.IBinder; import android.util.SparseArray; import android.view.SurfaceControl; import android.view.SurfaceSession; Loading @@ -47,6 +48,7 @@ import com.android.wm.shell.common.split.SplitDecorManager; import com.android.wm.shell.splitscreen.SplitScreen.StageType; import java.io.PrintWriter; import java.util.function.Predicate; /** * Base class that handle common task org. related for split-screen stages. Loading Loading @@ -119,63 +121,53 @@ class StageTaskListener implements ShellTaskOrganizer.TaskListener { } boolean containsToken(WindowContainerToken token) { if (token.equals(mRootTaskInfo.token)) { return true; return contains(t -> t.token.equals(token)); } for (int i = mChildrenTaskInfo.size() - 1; i >= 0; --i) { if (token.equals(mChildrenTaskInfo.valueAt(i).token)) { return true; } } return false; boolean containsContainer(IBinder binder) { return contains(t -> t.token.asBinder() == binder); } /** * Returns the top visible child task's id. */ int getTopVisibleChildTaskId() { for (int i = mChildrenTaskInfo.size() - 1; i >= 0; --i) { final ActivityManager.RunningTaskInfo info = mChildrenTaskInfo.valueAt(i); if (info.isVisible) { return info.taskId; } } return INVALID_TASK_ID; final ActivityManager.RunningTaskInfo taskInfo = getChildTaskInfo(t -> t.isVisible); return taskInfo != null ? taskInfo.taskId : INVALID_TASK_ID; } /** * Returns the top activity uid for the top child task. */ int getTopChildTaskUid() { for (int i = mChildrenTaskInfo.size() - 1; i >= 0; --i) { final ActivityManager.RunningTaskInfo info = mChildrenTaskInfo.valueAt(i); if (info.topActivityInfo == null) { continue; } return info.topActivityInfo.applicationInfo.uid; } return 0; final ActivityManager.RunningTaskInfo taskInfo = getChildTaskInfo(t -> t.topActivityInfo != null); return taskInfo != null ? taskInfo.topActivityInfo.applicationInfo.uid : 0; } /** @return {@code true} if this listener contains the currently focused task. */ boolean isFocused() { if (mRootTaskInfo == null) { return false; return contains(t -> t.isFocused); } if (mRootTaskInfo.isFocused) { private boolean contains(Predicate<ActivityManager.RunningTaskInfo> predicate) { if (mRootTaskInfo != null && predicate.test(mRootTaskInfo)) { return true; } return getChildTaskInfo(predicate) != null; } @Nullable private ActivityManager.RunningTaskInfo getChildTaskInfo( Predicate<ActivityManager.RunningTaskInfo> predicate) { for (int i = mChildrenTaskInfo.size() - 1; i >= 0; --i) { if (mChildrenTaskInfo.valueAt(i).isFocused) { return true; final ActivityManager.RunningTaskInfo taskInfo = mChildrenTaskInfo.valueAt(i); if (predicate.test(taskInfo)) { return taskInfo; } } return false; return null; } @Override Loading