Merge "Improve drag divider dismiss transition." into udc-dev

This commit is contained in:
Tony Huang
2023-05-23 05:21:43 +00:00
committed by Android (Google) Code Review
7 changed files with 94 additions and 15 deletions

View File

@@ -293,6 +293,9 @@ public class SplitDecorManager extends WindowlessWindowManager {
}
if (mResizingIconView == null) {
if (mRunningAnimationCount == 0 && animFinishedCallback != null) {
animFinishedCallback.accept(false);
}
return;
}
@@ -311,6 +314,9 @@ public class SplitDecorManager extends WindowlessWindowManager {
releaseDecor(finishT);
finishT.apply();
finishT.close();
if (mRunningAnimationCount == 0 && animFinishedCallback != null) {
animFinishedCallback.accept(true);
}
}
});
return;

View File

@@ -87,6 +87,14 @@ class SplitScreenTransitions {
mStageCoordinator = stageCoordinator;
}
private void initTransition(@NonNull IBinder transition,
@NonNull SurfaceControl.Transaction finishTransaction,
@NonNull Transitions.TransitionFinishCallback finishCallback) {
mAnimatingTransition = transition;
mFinishTransaction = finishTransaction;
mFinishCallback = finishCallback;
}
/** Play animation for enter transition or dismiss transition. */
void playAnimation(@NonNull IBinder transition, @NonNull TransitionInfo info,
@NonNull SurfaceControl.Transaction startTransaction,
@@ -94,9 +102,7 @@ class SplitScreenTransitions {
@NonNull Transitions.TransitionFinishCallback finishCallback,
@NonNull WindowContainerToken mainRoot, @NonNull WindowContainerToken sideRoot,
@NonNull WindowContainerToken topRoot) {
mFinishCallback = finishCallback;
mAnimatingTransition = transition;
mFinishTransaction = finishTransaction;
initTransition(transition, finishTransaction, finishCallback);
final TransitSession pendingTransition = getPendingTransition(transition);
if (pendingTransition != null) {
@@ -220,6 +226,45 @@ class SplitScreenTransitions {
onFinish(null /* wct */, null /* wctCB */);
}
/** Play animation for drag divider dismiss transition. */
void playDragDismissAnimation(@NonNull IBinder transition, @NonNull TransitionInfo info,
@NonNull SurfaceControl.Transaction startTransaction,
@NonNull SurfaceControl.Transaction finishTransaction,
@NonNull Transitions.TransitionFinishCallback finishCallback,
@NonNull WindowContainerToken toTopRoot, @NonNull SplitDecorManager toTopDecor,
@NonNull WindowContainerToken topRoot) {
initTransition(transition, finishTransaction, finishCallback);
for (int i = info.getChanges().size() - 1; i >= 0; --i) {
final TransitionInfo.Change change = info.getChanges().get(i);
final SurfaceControl leash = change.getLeash();
if (toTopRoot.equals(change.getContainer())) {
startTransaction.setAlpha(leash, 1.f);
startTransaction.show(leash);
ValueAnimator va = new ValueAnimator();
mAnimations.add(va);
toTopDecor.onResized(startTransaction, animated -> {
mAnimations.remove(va);
if (animated) {
mTransitions.getMainExecutor().execute(() -> {
onFinish(null /* wct */, null /* wctCB */);
});
}
});
} else if (topRoot.equals(change.getContainer())) {
// Ensure it on top of all changes in transition.
startTransaction.setLayer(leash, Integer.MAX_VALUE);
startTransaction.setAlpha(leash, 1.f);
startTransaction.show(leash);
}
}
startTransaction.apply();
onFinish(null /* wct */, null /* wctCB */);
}
/** Play animation for resize transition. */
void playResizeAnimation(@NonNull IBinder transition, @NonNull TransitionInfo info,
@NonNull SurfaceControl.Transaction startTransaction,
@@ -227,9 +272,7 @@ class SplitScreenTransitions {
@NonNull Transitions.TransitionFinishCallback finishCallback,
@NonNull WindowContainerToken mainRoot, @NonNull WindowContainerToken sideRoot,
@NonNull SplitDecorManager mainDecor, @NonNull SplitDecorManager sideDecor) {
mFinishCallback = finishCallback;
mAnimatingTransition = transition;
mFinishTransaction = finishTransaction;
initTransition(transition, finishTransaction, finishCallback);
for (int i = info.getChanges().size() - 1; i >= 0; --i) {
final TransitionInfo.Change change = info.getChanges().get(i);

View File

@@ -1328,8 +1328,6 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
mIsExiting = true;
childrenToTop.resetBounds(wct);
wct.reorder(childrenToTop.mRootTaskInfo.token, true);
wct.setSmallestScreenWidthDp(childrenToTop.mRootTaskInfo.token,
SMALLEST_SCREEN_WIDTH_DP_UNDEFINED);
}
wct.setReparentLeafTaskIfRelaunch(mRootTaskInfo.token,
false /* reparentLeafTaskIfRelaunch */);
@@ -1517,6 +1515,10 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
void finishEnterSplitScreen(SurfaceControl.Transaction t) {
mSplitLayout.update(t);
mMainStage.getSplitDecorManager().inflate(mContext, mMainStage.mRootLeash,
getMainStageBounds());
mSideStage.getSplitDecorManager().inflate(mContext, mSideStage.mRootLeash,
getSideStageBounds());
setDividerVisibility(true, t);
// Ensure divider surface are re-parented back into the hierarchy at the end of the
// transition. See Transition#buildFinishTransaction for more detail.
@@ -1989,13 +1991,15 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
final boolean mainStageToTop =
bottomOrRight ? mSideStagePosition == SPLIT_POSITION_BOTTOM_OR_RIGHT
: mSideStagePosition == SPLIT_POSITION_TOP_OR_LEFT;
final StageTaskListener toTopStage = mainStageToTop ? mMainStage : mSideStage;
if (!ENABLE_SHELL_TRANSITIONS) {
exitSplitScreen(mainStageToTop ? mMainStage : mSideStage, reason);
exitSplitScreen(toTopStage, reason);
return;
}
final int dismissTop = mainStageToTop ? STAGE_TYPE_MAIN : STAGE_TYPE_SIDE;
final WindowContainerTransaction wct = new WindowContainerTransaction();
toTopStage.resetBounds(wct);
prepareExitSplitScreen(dismissTop, wct);
if (mRootTaskInfo != null) {
wct.setDoNotPip(mRootTaskInfo.token);
@@ -2531,8 +2535,17 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
shouldAnimate = startPendingEnterAnimation(
mSplitTransitions.mPendingEnter, info, startTransaction, finishTransaction);
} else if (mSplitTransitions.isPendingDismiss(transition)) {
final SplitScreenTransitions.DismissSession dismiss = mSplitTransitions.mPendingDismiss;
shouldAnimate = startPendingDismissAnimation(
mSplitTransitions.mPendingDismiss, info, startTransaction, finishTransaction);
dismiss, info, startTransaction, finishTransaction);
if (shouldAnimate && dismiss.mReason == EXIT_REASON_DRAG_DIVIDER) {
final StageTaskListener toTopStage =
dismiss.mDismissTop == STAGE_TYPE_MAIN ? mMainStage : mSideStage;
mSplitTransitions.playDragDismissAnimation(transition, info, startTransaction,
finishTransaction, finishCallback, toTopStage.mRootTaskInfo.token,
toTopStage.getSplitDecorManager(), mRootTaskInfo.token);
return true;
}
} else if (mSplitTransitions.isPendingResize(transition)) {
mSplitTransitions.playResizeAnimation(transition, info, startTransaction,
finishTransaction, finishCallback, mMainStage.mRootTaskInfo.token,
@@ -2787,6 +2800,10 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
mSplitTransitions.mPendingDismiss = null;
return false;
}
dismissTransition.setFinishedCallback((callbackWct, callbackT) -> {
mMainStage.getSplitDecorManager().release(callbackT);
mSideStage.getSplitDecorManager().release(callbackT);
});
addDividerBarToTransition(info, false /* show */);
return true;

View File

@@ -19,6 +19,7 @@ package com.android.wm.shell.splitscreen;
import static android.app.ActivityTaskManager.INVALID_TASK_ID;
import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
import static android.content.res.Configuration.SMALLEST_SCREEN_WIDTH_DP_UNDEFINED;
import static android.view.RemoteAnimationTarget.MODE_OPENING;
import static com.android.wm.shell.common.split.SplitScreenConstants.CONTROLLED_ACTIVITY_TYPES;
@@ -201,7 +202,7 @@ class StageTaskListener implements ShellTaskOrganizer.TaskListener {
public void onTaskInfoChanged(ActivityManager.RunningTaskInfo taskInfo) {
if (mRootTaskInfo.taskId == taskInfo.taskId) {
// Inflates split decor view only when the root task is visible.
if (mRootTaskInfo.isVisible != taskInfo.isVisible) {
if (!ENABLE_SHELL_TRANSITIONS && mRootTaskInfo.isVisible != taskInfo.isVisible) {
if (taskInfo.isVisible) {
mSplitDecorManager.inflate(mContext, mRootLeash,
taskInfo.configuration.windowConfiguration.getBounds());
@@ -385,6 +386,7 @@ class StageTaskListener implements ShellTaskOrganizer.TaskListener {
void resetBounds(WindowContainerTransaction wct) {
wct.setBounds(mRootTaskInfo.token, null);
wct.setAppBounds(mRootTaskInfo.token, null);
wct.setSmallestScreenWidthDp(mRootTaskInfo.token, SMALLEST_SCREEN_WIDTH_DP_UNDEFINED);
}
void onSplitScreenListenerRegistered(SplitScreen.SplitScreenListener listener,

View File

@@ -44,11 +44,15 @@ public class SplitTestUtils {
static SplitLayout createMockSplitLayout() {
final Rect dividerBounds = new Rect(48, 0, 52, 100);
final Rect bounds1 = new Rect(0, 0, 40, 100);
final Rect bounds2 = new Rect(60, 0, 100, 100);
final SurfaceControl leash = createMockSurface();
SplitLayout out = mock(SplitLayout.class);
doReturn(dividerBounds).when(out).getDividerBounds();
doReturn(dividerBounds).when(out).getRefDividerBounds();
doReturn(leash).when(out).getDividerLeash();
doReturn(bounds1).when(out).getBounds1();
doReturn(bounds2).when(out).getBounds2();
return out;
}

View File

@@ -42,6 +42,7 @@ import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
import android.annotation.NonNull;
import android.app.ActivityManager;
@@ -72,6 +73,7 @@ import com.android.wm.shell.common.DisplayInsetsController;
import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.common.SyncTransactionQueue;
import com.android.wm.shell.common.TransactionPool;
import com.android.wm.shell.common.split.SplitDecorManager;
import com.android.wm.shell.common.split.SplitLayout;
import com.android.wm.shell.transition.Transitions;
@@ -117,13 +119,13 @@ public class SplitTransitionTests extends ShellTestCase {
doReturn(mockExecutor).when(mTransitions).getAnimExecutor();
doReturn(mock(SurfaceControl.Transaction.class)).when(mTransactionPool).acquire();
mSplitLayout = SplitTestUtils.createMockSplitLayout();
mMainStage = new MainStage(mContext, mTaskOrganizer, DEFAULT_DISPLAY, mock(
mMainStage = spy(new MainStage(mContext, mTaskOrganizer, DEFAULT_DISPLAY, mock(
StageTaskListener.StageListenerCallbacks.class), mSyncQueue, mSurfaceSession,
mIconProvider);
mIconProvider));
mMainStage.onTaskAppeared(new TestRunningTaskInfoBuilder().build(), createMockSurface());
mSideStage = new SideStage(mContext, mTaskOrganizer, DEFAULT_DISPLAY, mock(
mSideStage = spy(new SideStage(mContext, mTaskOrganizer, DEFAULT_DISPLAY, mock(
StageTaskListener.StageListenerCallbacks.class), mSyncQueue, mSurfaceSession,
mIconProvider);
mIconProvider));
mSideStage.onTaskAppeared(new TestRunningTaskInfoBuilder().build(), createMockSurface());
mStageCoordinator = new SplitTestUtils.TestStageCoordinator(mContext, DEFAULT_DISPLAY,
mSyncQueue, mTaskOrganizer, mMainStage, mSideStage, mDisplayController,
@@ -137,6 +139,8 @@ public class SplitTransitionTests extends ShellTestCase {
.setParentTaskId(mMainStage.mRootTaskInfo.taskId).build();
mSideChild = new TestRunningTaskInfoBuilder()
.setParentTaskId(mSideStage.mRootTaskInfo.taskId).build();
doReturn(mock(SplitDecorManager.class)).when(mMainStage).getSplitDecorManager();
doReturn(mock(SplitDecorManager.class)).when(mSideStage).getSplitDecorManager();
}
@Test

View File

@@ -68,6 +68,7 @@ import com.android.wm.shell.common.DisplayInsetsController;
import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.common.SyncTransactionQueue;
import com.android.wm.shell.common.TransactionPool;
import com.android.wm.shell.common.split.SplitDecorManager;
import com.android.wm.shell.common.split.SplitLayout;
import com.android.wm.shell.splitscreen.SplitScreen.SplitScreenListener;
import com.android.wm.shell.sysui.ShellController;
@@ -145,6 +146,8 @@ public class StageCoordinatorTests extends ShellTestCase {
mSideStage.mRootTaskInfo = new TestRunningTaskInfoBuilder().build();
mMainStage.mRootTaskInfo = new TestRunningTaskInfoBuilder().build();
doReturn(mock(SplitDecorManager.class)).when(mMainStage).getSplitDecorManager();
doReturn(mock(SplitDecorManager.class)).when(mSideStage).getSplitDecorManager();
}
@Test