Merge "Implement split resize shell transition" into tm-qpr-dev

This commit is contained in:
Tony Huang
2022-12-07 03:43:13 +00:00
committed by Android (Google) Code Review
5 changed files with 160 additions and 30 deletions

View File

@@ -51,8 +51,6 @@ import com.android.wm.shell.R;
import com.android.wm.shell.common.ScreenshotUtils;
import com.android.wm.shell.common.SurfaceUtils;
import java.util.function.Consumer;
/**
* Handles split decor like showing resizing hint for a specific split.
*/
@@ -72,17 +70,18 @@ public class SplitDecorManager extends WindowlessWindowManager {
private SurfaceControl mIconLeash;
private SurfaceControl mBackgroundLeash;
private SurfaceControl mGapBackgroundLeash;
private SurfaceControl mScreenshot;
private boolean mShown;
private boolean mIsResizing;
private final Rect mBounds = new Rect();
private final Rect mResizingBounds = new Rect();
private final Rect mTempRect = new Rect();
private ValueAnimator mFadeAnimator;
private int mIconSize;
private int mOffsetX;
private int mOffsetY;
private int mRunningAnimationCount = 0;
public SplitDecorManager(Configuration configuration, IconProvider iconProvider,
SurfaceSession surfaceSession) {
@@ -173,7 +172,6 @@ public class SplitDecorManager extends WindowlessWindowManager {
mIsResizing = true;
mBounds.set(newBounds);
}
mResizingBounds.set(newBounds);
mOffsetX = offsetX;
mOffsetY = offsetY;
@@ -227,33 +225,41 @@ public class SplitDecorManager extends WindowlessWindowManager {
t.setVisibility(mBackgroundLeash, show);
t.setVisibility(mIconLeash, show);
} else {
startFadeAnimation(show, null /* finishedConsumer */);
startFadeAnimation(show, false, null);
}
mShown = show;
}
}
/** Stops showing resizing hint. */
public void onResized(SurfaceControl.Transaction t) {
if (!mShown && mIsResizing) {
mTempRect.set(mResizingBounds);
mTempRect.offsetTo(-mOffsetX, -mOffsetY);
final SurfaceControl screenshot = ScreenshotUtils.takeScreenshot(t,
mHostLeash, mTempRect, Integer.MAX_VALUE - 1);
public void onResized(SurfaceControl.Transaction t, Runnable animFinishedCallback) {
if (mScreenshot != null) {
t.setPosition(mScreenshot, mOffsetX, mOffsetY);
final SurfaceControl.Transaction animT = new SurfaceControl.Transaction();
final ValueAnimator va = ValueAnimator.ofFloat(1, 0);
va.addUpdateListener(valueAnimator -> {
final float progress = (float) valueAnimator.getAnimatedValue();
animT.setAlpha(screenshot, progress);
animT.setAlpha(mScreenshot, progress);
animT.apply();
});
va.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationStart(Animator animation) {
mRunningAnimationCount++;
}
@Override
public void onAnimationEnd(@androidx.annotation.NonNull Animator animation) {
animT.remove(screenshot);
mRunningAnimationCount--;
animT.remove(mScreenshot);
animT.apply();
animT.close();
mScreenshot = null;
if (mRunningAnimationCount == 0 && animFinishedCallback != null) {
animFinishedCallback.run();
}
}
});
va.start();
@@ -285,10 +291,34 @@ public class SplitDecorManager extends WindowlessWindowManager {
mFadeAnimator.cancel();
}
if (mShown) {
fadeOutDecor(null /* finishedCallback */);
fadeOutDecor(animFinishedCallback);
} else {
// Decor surface is hidden so release it directly.
releaseDecor(t);
if (mRunningAnimationCount == 0 && animFinishedCallback != null) {
animFinishedCallback.run();
}
}
}
/** Screenshot host leash and attach on it if meet some conditions */
public void screenshotIfNeeded(SurfaceControl.Transaction t) {
if (!mShown && mIsResizing) {
mTempRect.set(mBounds);
mTempRect.offsetTo(0, 0);
mScreenshot = ScreenshotUtils.takeScreenshot(t, mHostLeash, mTempRect,
Integer.MAX_VALUE - 1);
}
}
/** Set screenshot and attach on host leash it if meet some conditions */
public void setScreenshotIfNeeded(SurfaceControl screenshot, SurfaceControl.Transaction t) {
if (screenshot == null || !screenshot.isValid()) return;
if (!mShown && mIsResizing) {
mScreenshot = screenshot;
t.reparent(screenshot, mHostLeash);
t.setLayer(screenshot, Integer.MAX_VALUE - 1);
}
}
@@ -296,18 +326,15 @@ public class SplitDecorManager extends WindowlessWindowManager {
* directly. */
public void fadeOutDecor(Runnable finishedCallback) {
if (mShown) {
startFadeAnimation(false /* show */, transaction -> {
releaseDecor(transaction);
if (finishedCallback != null) finishedCallback.run();
});
startFadeAnimation(false /* show */, true, finishedCallback);
mShown = false;
} else {
if (finishedCallback != null) finishedCallback.run();
}
}
private void startFadeAnimation(boolean show,
Consumer<SurfaceControl.Transaction> finishedConsumer) {
private void startFadeAnimation(boolean show, boolean releaseSurface,
Runnable finishedCallback) {
final SurfaceControl.Transaction animT = new SurfaceControl.Transaction();
mFadeAnimator = ValueAnimator.ofFloat(0f, 1f);
mFadeAnimator.setDuration(FADE_DURATION);
@@ -324,6 +351,7 @@ public class SplitDecorManager extends WindowlessWindowManager {
mFadeAnimator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationStart(@NonNull Animator animation) {
mRunningAnimationCount++;
if (show) {
animT.show(mBackgroundLeash).show(mIconLeash);
}
@@ -335,6 +363,7 @@ public class SplitDecorManager extends WindowlessWindowManager {
@Override
public void onAnimationEnd(@NonNull Animator animation) {
mRunningAnimationCount--;
if (!show) {
if (mBackgroundLeash != null) {
animT.hide(mBackgroundLeash);
@@ -343,11 +372,15 @@ public class SplitDecorManager extends WindowlessWindowManager {
animT.hide(mIconLeash);
}
}
if (finishedConsumer != null) {
finishedConsumer.accept(animT);
if (releaseSurface) {
releaseDecor(animT);
}
animT.apply();
animT.close();
if (mRunningAnimationCount == 0 && finishedCallback != null) {
finishedCallback.run();
}
}
});
mFadeAnimator.start();

View File

@@ -47,6 +47,7 @@ import android.window.WindowContainerTransactionCallback;
import com.android.internal.protolog.common.ProtoLog;
import com.android.wm.shell.common.TransactionPool;
import com.android.wm.shell.common.split.SplitDecorManager;
import com.android.wm.shell.protolog.ShellProtoLogGroup;
import com.android.wm.shell.transition.OneShotRemoteHandler;
import com.android.wm.shell.transition.Transitions;
@@ -64,6 +65,7 @@ class SplitScreenTransitions {
DismissTransition mPendingDismiss = null;
TransitSession mPendingEnter = null;
TransitSession mPendingRecent = null;
TransitSession mPendingResize = null;
private IBinder mAnimatingTransition = null;
OneShotRemoteHandler mPendingRemoteHandler = null;
@@ -177,6 +179,43 @@ class SplitScreenTransitions {
onFinish(null /* wct */, null /* wctCB */);
}
void applyResizeTransition(@NonNull IBinder transition, @NonNull TransitionInfo info,
@NonNull SurfaceControl.Transaction startTransaction,
@NonNull SurfaceControl.Transaction finishTransaction,
@NonNull Transitions.TransitionFinishCallback finishCallback,
@NonNull WindowContainerToken mainRoot, @NonNull WindowContainerToken sideRoot,
@NonNull SplitDecorManager mainDecor, @NonNull SplitDecorManager sideDecor) {
mFinishCallback = finishCallback;
mAnimatingTransition = transition;
mFinishTransaction = finishTransaction;
for (int i = info.getChanges().size() - 1; i >= 0; --i) {
final TransitionInfo.Change change = info.getChanges().get(i);
if (mainRoot.equals(change.getContainer()) || sideRoot.equals(change.getContainer())) {
final SurfaceControl leash = change.getLeash();
startTransaction.setPosition(leash, change.getEndAbsBounds().left,
change.getEndAbsBounds().top);
startTransaction.setWindowCrop(leash, change.getEndAbsBounds().width(),
change.getEndAbsBounds().height());
SplitDecorManager decor = mainRoot.equals(change.getContainer())
? mainDecor : sideDecor;
ValueAnimator va = new ValueAnimator();
mAnimations.add(va);
decor.setScreenshotIfNeeded(change.getSnapshot(), startTransaction);
decor.onResized(startTransaction, () -> {
mTransitions.getMainExecutor().execute(() -> {
mAnimations.remove(va);
onFinish(null /* wct */, null /* wctCB */);
});
});
}
}
startTransaction.apply();
onFinish(null /* wct */, null /* wctCB */);
}
boolean isPendingTransition(IBinder transition) {
return getPendingTransition(transition) != null;
}
@@ -193,6 +232,10 @@ class SplitScreenTransitions {
return mPendingDismiss != null && mPendingDismiss.mTransition == transition;
}
boolean isPendingResize(IBinder transition) {
return mPendingResize != null && mPendingResize.mTransition == transition;
}
@Nullable
private TransitSession getPendingTransition(IBinder transition) {
if (isPendingEnter(transition)) {
@@ -201,11 +244,14 @@ class SplitScreenTransitions {
return mPendingRecent;
} else if (isPendingDismiss(transition)) {
return mPendingDismiss;
} else if (isPendingResize(transition)) {
return mPendingResize;
}
return null;
}
/** Starts a transition to enter split with a remote transition animator. */
IBinder startEnterTransition(
@WindowManager.TransitionType int transitType,
@@ -258,6 +304,21 @@ class SplitScreenTransitions {
exitReasonToString(reason), stageTypeToString(dismissTop));
}
IBinder startResizeTransition(WindowContainerTransaction wct,
Transitions.TransitionHandler handler,
@Nullable TransitionFinishedCallback finishCallback) {
IBinder transition = mTransitions.startTransition(TRANSIT_CHANGE, wct, handler);
setResizeTransition(transition, finishCallback);
return transition;
}
void setResizeTransition(@NonNull IBinder transition,
@Nullable TransitionFinishedCallback finishCallback) {
mPendingResize = new TransitSession(transition, null /* consumedCb */, finishCallback);
ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, " splitTransition "
+ " deduced Resize split screen");
}
void setRecentTransition(@NonNull IBinder transition,
@Nullable RemoteTransition remoteTransition,
@Nullable TransitionFinishedCallback finishCallback) {
@@ -324,6 +385,9 @@ class SplitScreenTransitions {
mPendingRecent.onConsumed(aborted);
mPendingRecent = null;
mPendingRemoteHandler = null;
} else if (isPendingResize(transition)) {
mPendingResize.onConsumed(aborted);
mPendingResize = null;
}
}
@@ -340,6 +404,9 @@ class SplitScreenTransitions {
} else if (isPendingDismiss(mAnimatingTransition)) {
mPendingDismiss.onFinished(wct, mFinishTransaction);
mPendingDismiss = null;
} else if (isPendingResize(mAnimatingTransition)) {
mPendingResize.onFinished(wct, mFinishTransaction);
mPendingResize = null;
}
mPendingRemoteHandler = null;

View File

@@ -1667,15 +1667,29 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
public void onLayoutSizeChanged(SplitLayout layout) {
// Reset this flag every time onLayoutSizeChanged.
mShowDecorImmediately = false;
if (!ENABLE_SHELL_TRANSITIONS) {
// Only need screenshot for legacy case because shell transition should screenshot
// itself during transition.
final SurfaceControl.Transaction startT = mTransactionPool.acquire();
mMainStage.screenshotIfNeeded(startT);
mSideStage.screenshotIfNeeded(startT);
mTransactionPool.release(startT);
}
final WindowContainerTransaction wct = new WindowContainerTransaction();
updateWindowBounds(layout, wct);
sendOnBoundsChanged();
mSyncQueue.queue(wct);
mSyncQueue.runInSync(t -> {
updateSurfaceBounds(layout, t, false /* applyResizingOffset */);
mMainStage.onResized(t);
mSideStage.onResized(t);
});
if (ENABLE_SHELL_TRANSITIONS) {
mSplitTransitions.startResizeTransition(wct, this, null /* callback */);
} else {
mSyncQueue.queue(wct);
mSyncQueue.runInSync(t -> {
updateSurfaceBounds(layout, t, false /* applyResizingOffset */);
mMainStage.onResized(t);
mSideStage.onResized(t);
});
}
mLogger.logResize(mSplitLayout.getDividerPositionAsFraction());
}
@@ -2029,6 +2043,12 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
} else if (mSplitTransitions.isPendingDismiss(transition)) {
shouldAnimate = startPendingDismissAnimation(
mSplitTransitions.mPendingDismiss, info, startTransaction, finishTransaction);
} else if (mSplitTransitions.isPendingResize(transition)) {
mSplitTransitions.applyResizeTransition(transition, info, startTransaction,
finishTransaction, finishCallback, mMainStage.mRootTaskInfo.token,
mSideStage.mRootTaskInfo.token, mMainStage.getSplitDecorManager(),
mSideStage.getSplitDecorManager());
return true;
}
if (!shouldAnimate) return false;

View File

@@ -292,7 +292,13 @@ class StageTaskListener implements ShellTaskOrganizer.TaskListener {
void onResized(SurfaceControl.Transaction t) {
if (mSplitDecorManager != null) {
mSplitDecorManager.onResized(t);
mSplitDecorManager.onResized(t, null);
}
}
void screenshotIfNeeded(SurfaceControl.Transaction t) {
if (mSplitDecorManager != null) {
mSplitDecorManager.screenshotIfNeeded(t);
}
}
@@ -304,6 +310,10 @@ class StageTaskListener implements ShellTaskOrganizer.TaskListener {
}
}
SplitDecorManager getSplitDecorManager() {
return mSplitDecorManager;
}
void addTask(ActivityManager.RunningTaskInfo task, WindowContainerTransaction wct) {
// Clear overridden bounds and windowing mode to make sure the child task can inherit
// windowing mode and bounds from split root.

View File

@@ -2183,7 +2183,7 @@ class Task extends TaskFragment {
}
private boolean shouldStartChangeTransition(int prevWinMode, @NonNull Rect prevBounds) {
if (!isLeafTask() || !canStartChangeTransition()) {
if (!(isLeafTask() || mCreatedByOrganizer) || !canStartChangeTransition()) {
return false;
}
final int newWinMode = getWindowingMode();