Preserve the controlling state of appearance and behavior

Make sure the appearance or the behavior controlled by the new APIs
won't be affected by setting new LayoutParams.

This CL also makes ViewRootImpl#setLayoutParams won't modify the
caller's LayoutParams.

Fix: 175169461
Test: atest ViewRootImplTest
Change-Id: I4cdd846e8638f9813146e6461134e4dd1606bd50
This commit is contained in:
Tiger Huang
2021-01-06 19:10:02 +08:00
parent f749076910
commit 7dbb0540c0
2 changed files with 32 additions and 13 deletions

View File

@@ -1389,7 +1389,8 @@ public final class ViewRootImpl implements ViewParent,
return mLocation;
}
void setLayoutParams(WindowManager.LayoutParams attrs, boolean newView) {
@VisibleForTesting
public void setLayoutParams(WindowManager.LayoutParams attrs, boolean newView) {
synchronized (this) {
final int oldInsetLeft = mWindowAttributes.surfaceInsets.left;
final int oldInsetTop = mWindowAttributes.surfaceInsets.top;
@@ -1411,13 +1412,15 @@ public final class ViewRootImpl implements ViewParent,
final int compatibleWindowFlag = mWindowAttributes.privateFlags
& WindowManager.LayoutParams.PRIVATE_FLAG_COMPATIBLE_WINDOW;
// Transfer over system UI visibility values as they carry current state.
attrs.systemUiVisibility = mWindowAttributes.systemUiVisibility;
attrs.subtreeSystemUiVisibility = mWindowAttributes.subtreeSystemUiVisibility;
// Preserve system UI visibility.
final int systemUiVisibility = mWindowAttributes.systemUiVisibility;
final int subtreeSystemUiVisibility = mWindowAttributes.subtreeSystemUiVisibility;
// Transfer over appearance and behavior values as they carry current state.
attrs.insetsFlags.appearance = mWindowAttributes.insetsFlags.appearance;
attrs.insetsFlags.behavior = mWindowAttributes.insetsFlags.behavior;
// Preserve appearance and behavior.
final int appearance = mWindowAttributes.insetsFlags.appearance;
final int behavior = mWindowAttributes.insetsFlags.behavior;
final int appearanceAndBehaviorPrivateFlags = mWindowAttributes.privateFlags
& (PRIVATE_FLAG_APPEARANCE_CONTROLLED | PRIVATE_FLAG_BEHAVIOR_CONTROLLED);
final int changes = mWindowAttributes.copyFrom(attrs);
if ((changes & WindowManager.LayoutParams.TRANSLUCENT_FLAGS_CHANGED) != 0) {
@@ -1431,10 +1434,15 @@ public final class ViewRootImpl implements ViewParent,
if (mWindowAttributes.packageName == null) {
mWindowAttributes.packageName = mBasePackageName;
}
mWindowAttributes.privateFlags |= compatibleWindowFlag;
mWindowAttributes.privateFlags |=
WindowManager.LayoutParams.PRIVATE_FLAG_USE_BLAST;
// Restore preserved flags.
mWindowAttributes.systemUiVisibility = systemUiVisibility;
mWindowAttributes.subtreeSystemUiVisibility = subtreeSystemUiVisibility;
mWindowAttributes.insetsFlags.appearance = appearance;
mWindowAttributes.insetsFlags.behavior = behavior;
mWindowAttributes.privateFlags |= compatibleWindowFlag
| appearanceAndBehaviorPrivateFlags
| WindowManager.LayoutParams.PRIVATE_FLAG_USE_BLAST;
if (mWindowAttributes.preservePreviousSurfaceInsets) {
// Restore old surface insets.

View File

@@ -22,7 +22,8 @@ import static android.view.View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION;
import static android.view.View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR;
import static android.view.View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR;
import static android.view.View.SYSTEM_UI_FLAG_LOW_PROFILE;
import static android.view.WindowInsetsController.BEHAVIOR_SHOW_BARS_BY_TOUCH;
import static android.view.WindowInsetsController.APPEARANCE_OPAQUE_STATUS_BARS;
import static android.view.WindowInsetsController.BEHAVIOR_SHOW_BARS_BY_SWIPE;
import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;
import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
@@ -153,7 +154,7 @@ public class ViewRootImplTest {
public void adjustLayoutParamsForCompatibility_noAdjustAppearance() {
final WindowInsetsController controller = mViewRootImpl.getInsetsController();
final WindowManager.LayoutParams attrs = mViewRootImpl.mWindowAttributes;
final int appearance = 0;
final int appearance = APPEARANCE_OPAQUE_STATUS_BARS;
controller.setSystemBarsAppearance(appearance, 0xffffffff);
attrs.systemUiVisibility = SYSTEM_UI_FLAG_LOW_PROFILE
| SYSTEM_UI_FLAG_LIGHT_STATUS_BAR
@@ -163,13 +164,18 @@ public class ViewRootImplTest {
// Appearance must not be adjusted due to legacy system UI visibility after calling
// setSystemBarsAppearance.
assertEquals(appearance, controller.getSystemBarsAppearance());
mViewRootImpl.setLayoutParams(new WindowManager.LayoutParams(), false);
// Appearance must not be adjusted due to setting new LayoutParams.
assertEquals(appearance, controller.getSystemBarsAppearance());
}
@Test
public void adjustLayoutParamsForCompatibility_noAdjustBehavior() {
final WindowInsetsController controller = mViewRootImpl.getInsetsController();
final WindowManager.LayoutParams attrs = mViewRootImpl.mWindowAttributes;
final int behavior = BEHAVIOR_SHOW_BARS_BY_TOUCH;
final int behavior = BEHAVIOR_SHOW_BARS_BY_SWIPE;
controller.setSystemBarsBehavior(behavior);
attrs.systemUiVisibility = SYSTEM_UI_FLAG_IMMERSIVE_STICKY;
ViewRootImpl.adjustLayoutParamsForCompatibility(attrs);
@@ -177,5 +183,10 @@ public class ViewRootImplTest {
// Behavior must not be adjusted due to legacy system UI visibility after calling
// setSystemBarsBehavior.
assertEquals(behavior, controller.getSystemBarsBehavior());
mViewRootImpl.setLayoutParams(new WindowManager.LayoutParams(), false);
// Behavior must not be adjusted due to setting new LayoutParams.
assertEquals(behavior, controller.getSystemBarsBehavior());
}
}