Fix the content of the bottom split being truncated while showing IME
Freeze the configuration size when shifting split layout so that client apps can calculate insets properly and won't get config or relaunch. Fix: 192410210 Test: atest WMShellUnitTests Test: verified the content of the bottom split won't be truncated when adjusting split layout with IME and won't get relaunch. Change-Id: I38da063ffacc19b691c14b74d118949293414492
This commit is contained in:
@@ -215,7 +215,7 @@ class AppPair implements ShellTaskOrganizer.TaskListener, SplitLayout.SplitLayou
|
||||
|
||||
if (mSplitLayout != null) {
|
||||
if (mSplitLayout.updateConfiguration(mRootTaskInfo.configuration)) {
|
||||
onBoundsChanged(mSplitLayout);
|
||||
onLayoutChanged(mSplitLayout);
|
||||
}
|
||||
// updateConfiguration re-inits the dividerbar, so show it now
|
||||
mSyncQueue.runInSync(t -> t.show(mSplitLayout.getDividerLeash()));
|
||||
@@ -299,17 +299,24 @@ class AppPair implements ShellTaskOrganizer.TaskListener, SplitLayout.SplitLayou
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBoundsChanging(SplitLayout layout) {
|
||||
public void onLayoutChanging(SplitLayout layout) {
|
||||
mSyncQueue.runInSync(t ->
|
||||
layout.applySurfaceChanges(t, mTaskLeash1, mTaskLeash2, mDimLayer1, mDimLayer2));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBoundsChanged(SplitLayout layout) {
|
||||
public void onLayoutChanged(SplitLayout layout) {
|
||||
final WindowContainerTransaction wct = new WindowContainerTransaction();
|
||||
layout.applyTaskChanges(wct, mTaskInfo1, mTaskInfo2);
|
||||
mSyncQueue.queue(wct);
|
||||
mSyncQueue.runInSync(t ->
|
||||
layout.applySurfaceChanges(t, mTaskLeash1, mTaskLeash2, mDimLayer1, mDimLayer2));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLayoutShifted(int offsetX, int offsetY, SplitLayout layout) {
|
||||
final WindowContainerTransaction wct = new WindowContainerTransaction();
|
||||
layout.applyLayoutShifted(wct, offsetX, offsetY, mTaskInfo1, mTaskInfo2);
|
||||
mController.getTaskOrganizer().applyTransaction(wct);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,6 +16,8 @@
|
||||
|
||||
package com.android.wm.shell.common.split;
|
||||
|
||||
import static android.content.res.Configuration.SCREEN_HEIGHT_DP_UNDEFINED;
|
||||
import static android.content.res.Configuration.SCREEN_WIDTH_DP_UNDEFINED;
|
||||
import static android.view.WindowManager.DOCKED_LEFT;
|
||||
import static android.view.WindowManager.DOCKED_TOP;
|
||||
|
||||
@@ -224,13 +226,13 @@ public final class SplitLayout {
|
||||
void updateDivideBounds(int position) {
|
||||
updateBounds(position);
|
||||
mSplitWindowManager.setResizingSplits(true);
|
||||
mSplitLayoutHandler.onBoundsChanging(this);
|
||||
mSplitLayoutHandler.onLayoutChanging(this);
|
||||
}
|
||||
|
||||
void setDividePosition(int position) {
|
||||
mDividePosition = position;
|
||||
updateBounds(mDividePosition);
|
||||
mSplitLayoutHandler.onBoundsChanged(this);
|
||||
mSplitLayoutHandler.onLayoutChanged(this);
|
||||
mSplitWindowManager.setResizingSplits(false);
|
||||
}
|
||||
|
||||
@@ -352,6 +354,46 @@ public final class SplitLayout {
|
||||
.setBounds(task2.token, mImePositionProcessor.adjustForIme(mBounds2));
|
||||
}
|
||||
|
||||
/**
|
||||
* Shift configuration bounds to prevent client apps get configuration changed or relaunch. And
|
||||
* restore shifted configuration bounds if it's no longer shifted.
|
||||
*/
|
||||
public void applyLayoutShifted(WindowContainerTransaction wct, int offsetX, int offsetY,
|
||||
ActivityManager.RunningTaskInfo taskInfo1, ActivityManager.RunningTaskInfo taskInfo2) {
|
||||
if (offsetX == 0 && offsetY == 0) {
|
||||
wct.setBounds(taskInfo1.token, mBounds1);
|
||||
wct.setAppBounds(taskInfo1.token, null);
|
||||
wct.setScreenSizeDp(taskInfo1.token,
|
||||
SCREEN_WIDTH_DP_UNDEFINED, SCREEN_HEIGHT_DP_UNDEFINED);
|
||||
|
||||
wct.setBounds(taskInfo2.token, mBounds2);
|
||||
wct.setAppBounds(taskInfo2.token, null);
|
||||
wct.setScreenSizeDp(taskInfo2.token,
|
||||
SCREEN_WIDTH_DP_UNDEFINED, SCREEN_HEIGHT_DP_UNDEFINED);
|
||||
} else {
|
||||
final Rect bounds = new Rect();
|
||||
bounds.set(taskInfo1.configuration.windowConfiguration.getBounds());
|
||||
bounds.offset(offsetX, offsetY);
|
||||
wct.setBounds(taskInfo1.token, bounds);
|
||||
bounds.set(taskInfo1.configuration.windowConfiguration.getAppBounds());
|
||||
bounds.offset(offsetX, offsetY);
|
||||
wct.setAppBounds(taskInfo1.token, bounds);
|
||||
wct.setScreenSizeDp(taskInfo1.token,
|
||||
taskInfo1.configuration.screenWidthDp,
|
||||
taskInfo1.configuration.screenHeightDp);
|
||||
|
||||
bounds.set(taskInfo2.configuration.windowConfiguration.getBounds());
|
||||
bounds.offset(offsetX, offsetY);
|
||||
wct.setBounds(taskInfo2.token, bounds);
|
||||
bounds.set(taskInfo2.configuration.windowConfiguration.getAppBounds());
|
||||
bounds.offset(offsetX, offsetY);
|
||||
wct.setAppBounds(taskInfo2.token, bounds);
|
||||
wct.setScreenSizeDp(taskInfo2.token,
|
||||
taskInfo2.configuration.screenWidthDp,
|
||||
taskInfo2.configuration.screenHeightDp);
|
||||
}
|
||||
}
|
||||
|
||||
/** Handles layout change event. */
|
||||
public interface SplitLayoutHandler {
|
||||
|
||||
@@ -359,10 +401,18 @@ public final class SplitLayout {
|
||||
void onSnappedToDismiss(boolean snappedToEnd);
|
||||
|
||||
/** Calls when the bounds is changing due to animation or dragging divider bar. */
|
||||
void onBoundsChanging(SplitLayout layout);
|
||||
void onLayoutChanging(SplitLayout layout);
|
||||
|
||||
/** Calls when the target bounds changed. */
|
||||
void onBoundsChanged(SplitLayout layout);
|
||||
void onLayoutChanged(SplitLayout layout);
|
||||
|
||||
/**
|
||||
* Notifies when the layout shifted. So the layout handler can shift configuration
|
||||
* bounds correspondingly to make sure client apps won't get configuration changed or
|
||||
* relaunch. If the layout is no longer shifted, layout handler should restore shifted
|
||||
* configuration bounds.
|
||||
*/
|
||||
void onLayoutShifted(int offsetX, int offsetY, SplitLayout layout);
|
||||
|
||||
/** Calls when user double tapped on the divider bar. */
|
||||
default void onDoubleTappedDivider() {
|
||||
@@ -427,6 +477,18 @@ public final class SplitLayout {
|
||||
&& !isFloating && !isLandscape(mRootBounds) && showing;
|
||||
mTargetYOffset = needOffset ? getTargetYOffset() : 0;
|
||||
|
||||
if (mTargetYOffset != mLastYOffset) {
|
||||
// Freeze the configuration size with offset to prevent app get a configuration
|
||||
// changed or relaunch. This is required to make sure client apps will calculate
|
||||
// insets properly after layout shifted.
|
||||
if (mTargetYOffset == 0) {
|
||||
mSplitLayoutHandler.onLayoutShifted(0, 0, SplitLayout.this);
|
||||
} else {
|
||||
mSplitLayoutHandler.onLayoutShifted(0, mTargetYOffset - mLastYOffset,
|
||||
SplitLayout.this);
|
||||
}
|
||||
}
|
||||
|
||||
// Make {@link DividerView} non-interactive while IME showing in split mode. Listen to
|
||||
// ImePositionProcessor#onImeVisibilityChanged directly in DividerView is not enough
|
||||
// because DividerView won't receive onImeVisibilityChanged callback after it being
|
||||
@@ -441,7 +503,7 @@ public final class SplitLayout {
|
||||
public void onImePositionChanged(int displayId, int imeTop, SurfaceControl.Transaction t) {
|
||||
if (displayId != mDisplayId) return;
|
||||
onProgress(getProgress(imeTop));
|
||||
mSplitLayoutHandler.onBoundsChanging(SplitLayout.this);
|
||||
mSplitLayoutHandler.onLayoutChanging(SplitLayout.this);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -449,7 +511,7 @@ public final class SplitLayout {
|
||||
SurfaceControl.Transaction t) {
|
||||
if (displayId != mDisplayId || cancel) return;
|
||||
onProgress(1.0f);
|
||||
mSplitLayoutHandler.onBoundsChanging(SplitLayout.this);
|
||||
mSplitLayoutHandler.onLayoutChanging(SplitLayout.this);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -459,7 +521,7 @@ public final class SplitLayout {
|
||||
if (!controlling && mImeShown) {
|
||||
reset();
|
||||
mSplitWindowManager.setInteractive(true);
|
||||
mSplitLayoutHandler.onBoundsChanging(SplitLayout.this);
|
||||
mSplitLayoutHandler.onLayoutChanging(SplitLayout.this);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -422,7 +422,7 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler,
|
||||
if (mSideStageListener.mVisible && updateBounds) {
|
||||
if (wct == null) {
|
||||
// onBoundsChanged builds/applies a wct with the contents of updateWindowBounds.
|
||||
onBoundsChanged(mSplitLayout);
|
||||
onLayoutChanged(mSplitLayout);
|
||||
} else {
|
||||
updateWindowBounds(mSplitLayout, wct);
|
||||
}
|
||||
@@ -732,12 +732,12 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler,
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBoundsChanging(SplitLayout layout) {
|
||||
public void onLayoutChanging(SplitLayout layout) {
|
||||
mSyncQueue.runInSync(t -> updateSurfaceBounds(layout, t));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBoundsChanged(SplitLayout layout) {
|
||||
public void onLayoutChanged(SplitLayout layout) {
|
||||
final WindowContainerTransaction wct = new WindowContainerTransaction();
|
||||
updateWindowBounds(layout, wct);
|
||||
mSyncQueue.queue(wct);
|
||||
@@ -780,6 +780,18 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler,
|
||||
return SPLIT_POSITION_UNDEFINED;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLayoutShifted(int offsetX, int offsetY, SplitLayout layout) {
|
||||
final StageTaskListener topLeftStage =
|
||||
mSideStagePosition == SPLIT_POSITION_TOP_OR_LEFT ? mSideStage : mMainStage;
|
||||
final StageTaskListener bottomRightStage =
|
||||
mSideStagePosition == SPLIT_POSITION_TOP_OR_LEFT ? mMainStage : mSideStage;
|
||||
final WindowContainerTransaction wct = new WindowContainerTransaction();
|
||||
layout.applyLayoutShifted(wct, offsetX, offsetY, topLeftStage.mRootTaskInfo,
|
||||
bottomRightStage.mRootTaskInfo);
|
||||
mTaskOrganizer.applyTransaction(wct);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDisplayAreaAppeared(DisplayAreaInfo displayAreaInfo) {
|
||||
mDisplayAreaInfo = displayAreaInfo;
|
||||
@@ -802,7 +814,7 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler,
|
||||
if (mSplitLayout != null
|
||||
&& mSplitLayout.updateConfiguration(mDisplayAreaInfo.configuration)
|
||||
&& mMainStage.isActive()) {
|
||||
onBoundsChanged(mSplitLayout);
|
||||
onLayoutChanged(mSplitLayout);
|
||||
mSyncQueue.runInSync(t -> applyDividerVisibility(t));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -92,13 +92,13 @@ public class SplitLayoutTests extends ShellTestCase {
|
||||
@Test
|
||||
public void testUpdateDivideBounds() {
|
||||
mSplitLayout.updateDivideBounds(anyInt());
|
||||
verify(mSplitLayoutHandler).onBoundsChanging(any(SplitLayout.class));
|
||||
verify(mSplitLayoutHandler).onLayoutChanging(any(SplitLayout.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSetDividePosition() {
|
||||
mSplitLayout.setDividePosition(anyInt());
|
||||
verify(mSplitLayoutHandler).onBoundsChanged(any(SplitLayout.class));
|
||||
verify(mSplitLayoutHandler).onLayoutChanged(any(SplitLayout.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
Reference in New Issue
Block a user