Merge "Improve drag divider dismiss transition." into udc-dev
This commit is contained in:
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user