diff options
| author | 2021-05-06 14:13:30 +0800 | |
|---|---|---|
| committer | 2021-05-07 12:26:12 +0800 | |
| commit | 64049c4e0079e2401d7c0a5d21729cfb7e882b99 (patch) | |
| tree | 6b3f3c4be3597051ce21345f200de444af20c218 | |
| parent | 5d2533cdfc9152204511518fcf5e72738166fd8b (diff) | |
Adjust split layout with IME animation in split (4/N)
Update split surface dim value to match IME animation.
Bug: 179262787
Test: atest WMShellUnitTests
Test: manual checks split surface dim properly with IME animation.
Change-Id: I17c03def1a7e19d6bdbfc44fa846da4b1efa3275
3 files changed, 121 insertions, 71 deletions
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/apppairs/AppPair.java b/libs/WindowManager/Shell/src/com/android/wm/shell/apppairs/AppPair.java index abcde34ed5bb..af65d36da473 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/apppairs/AppPair.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/apppairs/AppPair.java @@ -291,40 +291,16 @@ class AppPair implements ShellTaskOrganizer.TaskListener, SplitLayout.SplitLayou @Override public void onBoundsChanging(SplitLayout layout) { - final SurfaceControl dividerLeash = mSplitLayout.getDividerLeash(); - if (dividerLeash == null) return; - final Rect dividerBounds = layout.getDividerBounds(); - final Rect bounds1 = layout.getBounds1(); - final Rect bounds2 = layout.getBounds2(); - mSyncQueue.runInSync(t -> t - .setPosition(dividerLeash, dividerBounds.left, dividerBounds.top) - .setPosition(mTaskLeash1, bounds1.left, bounds1.top) - .setPosition(mTaskLeash2, bounds2.left, bounds2.top) - // Sets crop to prevent visible region of tasks overlap with each other when - // re-positioning surfaces while resizing. - .setWindowCrop(mTaskLeash1, bounds1.width(), bounds1.height()) - .setWindowCrop(mTaskLeash2, bounds2.width(), bounds2.height())); + mSyncQueue.runInSync(t -> + layout.applySurfaceChanges(t, mTaskLeash1, mTaskLeash2, mDimLayer1, mDimLayer2)); } @Override public void onBoundsChanged(SplitLayout layout) { - final SurfaceControl dividerLeash = mSplitLayout.getDividerLeash(); - if (dividerLeash == null) return; - final Rect dividerBounds = layout.getDividerBounds(); - final Rect bounds1 = layout.getBounds1(); - final Rect bounds2 = layout.getBounds2(); final WindowContainerTransaction wct = new WindowContainerTransaction(); - wct.setBounds(mTaskInfo1.token, bounds1) - .setBounds(mTaskInfo2.token, bounds2); - mController.getTaskOrganizer().applyTransaction(wct); - mSyncQueue.runInSync(t -> t - // Resets layer of divider bar to make sure it is always on top. - .setLayer(dividerLeash, Integer.MAX_VALUE) - .setPosition(dividerLeash, dividerBounds.left, dividerBounds.top) - .setPosition(mTaskLeash1, bounds1.left, bounds1.top) - .setPosition(mTaskLeash2, bounds2.left, bounds2.top) - // Resets crop to apply new surface bounds directly. - .setWindowCrop(mTaskLeash1, null) - .setWindowCrop(mTaskLeash2, null)); + layout.applyTaskChanges(wct, mTaskInfo1, mTaskInfo2); + mSyncQueue.queue(wct); + mSyncQueue.runInSync(t -> + layout.applySurfaceChanges(t, mTaskLeash1, mTaskLeash2, mDimLayer1, mDimLayer2)); } } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java index c1ba6a5356fa..310e4791ddd3 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java @@ -26,6 +26,7 @@ import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.animation.ValueAnimator; import android.annotation.IntDef; +import android.app.ActivityManager; import android.content.Context; import android.content.res.Configuration; import android.content.res.Resources; @@ -34,6 +35,7 @@ import android.view.SurfaceControl; import android.view.WindowInsets; import android.view.WindowManager; import android.window.WindowContainerToken; +import android.window.WindowContainerTransaction; import androidx.annotation.Nullable; @@ -197,6 +199,7 @@ public final class SplitLayout { mInitialized = false; mSplitWindowManager.release(); mDisplayImeController.removePositionProcessor(mImePositionProcessor); + mImePositionProcessor.reset(); } /** @@ -302,8 +305,35 @@ public final class SplitLayout { return bounds.width() > bounds.height(); } + /** Apply recorded surface layout to the {@link SurfaceControl.Transaction}. */ + public void applySurfaceChanges(SurfaceControl.Transaction t, SurfaceControl leash1, + SurfaceControl leash2, SurfaceControl dimLayer1, SurfaceControl dimLayer2) { + final SurfaceControl dividerLeash = getDividerLeash(); + if (dividerLeash != null) { + t.setPosition(dividerLeash, mDividerBounds.left, mDividerBounds.top) + // Resets layer of divider bar to make sure it is always on top. + .setLayer(dividerLeash, Integer.MAX_VALUE); + } + + t.setPosition(leash1, mBounds1.left, mBounds1.top) + .setWindowCrop(leash1, mBounds1.width(), mBounds1.height()); + + t.setPosition(leash2, mBounds2.left, mBounds2.top) + .setWindowCrop(leash2, mBounds2.width(), mBounds2.height()); + + mImePositionProcessor.applySurfaceDimValues(t, dimLayer1, dimLayer2); + } + + /** Apply recorded task layout to the {@link WindowContainerTransaction}. */ + public void applyTaskChanges(WindowContainerTransaction wct, + ActivityManager.RunningTaskInfo task1, ActivityManager.RunningTaskInfo task2) { + wct.setBounds(task1.token, mBounds1) + .setBounds(task2.token, mBounds2); + } + /** Handles layout change event. */ public interface SplitLayoutHandler { + /** Calls when dismissing split. */ void onSnappedToDismiss(boolean snappedToEnd); @@ -324,9 +354,26 @@ public final class SplitLayout { /** Records IME top offset changes and updates SplitLayout correspondingly. */ private class ImePositionProcessor implements DisplayImeController.ImePositionProcessor { + /** + * Maximum size of an adjusted split bounds relative to original stack bounds. Used to + * restrict IME adjustment so that a min portion of top split remains visible. + */ + private static final float ADJUSTED_SPLIT_FRACTION_MAX = 0.7f; + private static final float ADJUSTED_NONFOCUS_DIM = 0.3f; private final int mDisplayId; + private float mDimValue1; + private float mDimValue2; + + private int mStartImeTop; + private int mEndImeTop; + + private float mTargetDim1; + private float mTargetDim2; + private float mLastDim1; + private float mLastDim2; + private ImePositionProcessor(int displayId) { mDisplayId = displayId; } @@ -337,6 +384,16 @@ public final class SplitLayout { if (displayId != mDisplayId) return 0; final int imeTargetPosition = getImeTargetPosition(); if (!mInitialized || imeTargetPosition == SPLIT_POSITION_UNDEFINED) return 0; + mStartImeTop = showing ? hiddenTop : shownTop; + mEndImeTop = showing ? shownTop : hiddenTop; + + // Update target dim values + mLastDim1 = mDimValue1; + mTargetDim1 = imeTargetPosition == SPLIT_POSITION_BOTTOM_OR_RIGHT && showing + ? ADJUSTED_NONFOCUS_DIM : 0.0f; + mLastDim2 = mDimValue2; + mTargetDim2 = imeTargetPosition == SPLIT_POSITION_TOP_OR_LEFT && showing + ? ADJUSTED_NONFOCUS_DIM : 0.0f; // Make {@link DividerView} non-interactive while IME showing in split mode. Listen to // ImePositionProcessor#onImeVisibilityChanged directly in DividerView is not enough @@ -348,10 +405,48 @@ public final class SplitLayout { return 0; } + @Override + public void onImePositionChanged(int displayId, int imeTop, SurfaceControl.Transaction t) { + if (displayId != mDisplayId) return; + onProgress(getProgress(imeTop)); + mSplitLayoutHandler.onBoundsChanging(SplitLayout.this); + } + + @Override + public void onImeEndPositioning(int displayId, boolean cancel, + SurfaceControl.Transaction t) { + if (displayId != mDisplayId || cancel) return; + onProgress(1.0f); + mSplitLayoutHandler.onBoundsChanging(SplitLayout.this); + } + @SplitPosition private int getImeTargetPosition() { final WindowContainerToken token = mTaskOrganizer.getImeTarget(mDisplayId); return mSplitLayoutHandler.getSplitItemPosition(token); } + + private float getProgress(int currImeTop) { + return ((float) currImeTop - mStartImeTop) / (mEndImeTop - mStartImeTop); + } + + private void onProgress(float progress) { + mDimValue1 = getProgressValue(mLastDim1, mTargetDim1, progress); + mDimValue2 = getProgressValue(mLastDim2, mTargetDim2, progress); + } + + private float getProgressValue(float start, float end, float progress) { + return start + (end - start) * progress; + } + + private void reset() { + mDimValue1 = mDimValue2 = 0.0f; + } + + private void applySurfaceDimValues(SurfaceControl.Transaction t, SurfaceControl dimLayer1, + SurfaceControl dimLayer2) { + t.setAlpha(dimLayer1, mDimValue1).setVisibility(dimLayer1, mDimValue1 > 0.001f); + t.setAlpha(dimLayer2, mDimValue2).setVisibility(dimLayer2, mDimValue2 > 0.001f); + } } } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java index e1799d28e423..7b788543c0b2 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java @@ -515,55 +515,34 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler, } @Override - public void onBoundsChanging(SplitLayout layout) { - final SurfaceControl dividerLeash = mSplitLayout.getDividerLeash(); - if (dividerLeash == null) return; - final Rect mainStageBounds = getMainStageBounds(); - final Rect sideStageBounds = getSideStageBounds(); - - mSyncQueue.runInSync(t -> t - .setPosition(dividerLeash, - mSplitLayout.getDividerBounds().left, mSplitLayout.getDividerBounds().top) - .setPosition(mMainStage.mRootLeash, mainStageBounds.left, mainStageBounds.top) - .setPosition(mSideStage.mRootLeash, sideStageBounds.left, sideStageBounds.top) - // Sets crop to prevent visible region of tasks overlap with each other when - // re-positioning surfaces while resizing. - .setWindowCrop(mMainStage.mRootLeash, - mainStageBounds.width(), mainStageBounds.height()) - .setWindowCrop(mSideStage.mRootLeash, - sideStageBounds.width(), sideStageBounds.height())); - - } - - @Override public void onDoubleTappedDivider() { setSideStagePosition(mSideStagePosition == SPLIT_POSITION_TOP_OR_LEFT ? SPLIT_POSITION_BOTTOM_OR_RIGHT : SPLIT_POSITION_TOP_OR_LEFT); } @Override + public void onBoundsChanging(SplitLayout layout) { + final StageTaskListener topLeftStage = + mSideStagePosition == SPLIT_POSITION_TOP_OR_LEFT ? mSideStage : mMainStage; + final StageTaskListener bottomRightStage = + mSideStagePosition == SPLIT_POSITION_TOP_OR_LEFT ? mMainStage : mSideStage; + + mSyncQueue.runInSync(t -> layout.applySurfaceChanges(t, topLeftStage.mRootLeash, + bottomRightStage.mRootLeash, topLeftStage.mDimLayer, bottomRightStage.mDimLayer)); + } + + @Override public void onBoundsChanged(SplitLayout layout) { - final SurfaceControl dividerLeash = mSplitLayout.getDividerLeash(); - if (dividerLeash == null) return; - final Rect mainStageBounds = getMainStageBounds(); - final Rect sideStageBounds = getSideStageBounds(); - final WindowContainerTransaction wct = new WindowContainerTransaction(); - mMainStage.setBounds(mainStageBounds, wct); - mSideStage.setBounds(sideStageBounds, wct); - mTaskOrganizer.applyTransaction(wct); + final StageTaskListener topLeftStage = + mSideStagePosition == SPLIT_POSITION_TOP_OR_LEFT ? mSideStage : mMainStage; + final StageTaskListener bottomRightStage = + mSideStagePosition == SPLIT_POSITION_TOP_OR_LEFT ? mMainStage : mSideStage; - mSyncQueue.runInSync(t -> t - // Resets layer of divider bar to make sure it is always on top. - .setLayer(dividerLeash, Integer.MAX_VALUE) - .setPosition(dividerLeash, - mSplitLayout.getDividerBounds().left, mSplitLayout.getDividerBounds().top) - .setPosition(mMainStage.mRootLeash, - mainStageBounds.left, mainStageBounds.top) - .setPosition(mSideStage.mRootLeash, - sideStageBounds.left, sideStageBounds.top) - // Resets crop to apply new surface bounds directly. - .setWindowCrop(mMainStage.mRootLeash, null) - .setWindowCrop(mSideStage.mRootLeash, null)); + final WindowContainerTransaction wct = new WindowContainerTransaction(); + layout.applyTaskChanges(wct, topLeftStage.mRootTaskInfo, bottomRightStage.mRootTaskInfo); + mSyncQueue.queue(wct); + mSyncQueue.runInSync(t -> layout.applySurfaceChanges(t, topLeftStage.mRootLeash, + bottomRightStage.mRootLeash, topLeftStage.mDimLayer, bottomRightStage.mDimLayer)); } @Override |