From a8f0672b9a96618b1ca8c3ee68a0b6aff68a2b3e Mon Sep 17 00:00:00 2001 From: shawnlin Date: Wed, 23 Jun 2021 15:29:41 +0800 Subject: [PATCH] Updating the display bounds when it changes In previous design, we only get the display bounds once when the first time the hide cutout is enabled. But if user selects "Hide" first and then switch to "Render apps below cutout area", the display bounds we get will be incorrect. Add a listener to monitor and update the display size. Bug: 191273507 Test: atest HideDisplayCutoutTest Test: manual - 1. select "Hide" 2. select "Render apps below cutout area" 3. observe the result Change-Id: I0ff1c4b822615d6bd43adb2e9e9d17d6bd9b91a8 --- .../HideDisplayCutoutOrganizer.java | 78 ++++++++++++------- .../HideDisplayCutoutOrganizerTest.java | 28 ++++++- 2 files changed, 74 insertions(+), 32 deletions(-) diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/hidedisplaycutout/HideDisplayCutoutOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/hidedisplaycutout/HideDisplayCutoutOrganizer.java index 53dd391a01af0..75a1ddeccb221 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/hidedisplaycutout/HideDisplayCutoutOrganizer.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/hidedisplaycutout/HideDisplayCutoutOrganizer.java @@ -19,8 +19,8 @@ package com.android.wm.shell.hidedisplaycutout; import static android.view.Display.DEFAULT_DISPLAY; import android.content.Context; +import android.content.res.Configuration; import android.graphics.Insets; -import android.graphics.Point; import android.graphics.Rect; import android.util.ArrayMap; import android.util.Log; @@ -40,13 +40,12 @@ import androidx.annotation.NonNull; import androidx.annotation.VisibleForTesting; import com.android.internal.R; -import com.android.wm.shell.common.DisplayChangeController; import com.android.wm.shell.common.DisplayController; +import com.android.wm.shell.common.DisplayLayout; import com.android.wm.shell.common.ShellExecutor; import java.io.PrintWriter; import java.util.List; -import java.util.concurrent.Executor; /** * Manages the display areas of hide display cutout feature. @@ -76,19 +75,29 @@ class HideDisplayCutoutOrganizer extends DisplayAreaOrganizer { @VisibleForTesting int mRotation; - /** - * Handles rotation based on OnDisplayChangingListener callback. - */ - private final DisplayChangeController.OnDisplayChangingListener mRotationController = - (display, fromRotation, toRotation, wct) -> { - mRotation = toRotation; - updateBoundsAndOffsets(true /* enable */); - final SurfaceControl.Transaction t = new SurfaceControl.Transaction(); - applyAllBoundsAndOffsets(wct, t); - // Only apply t here since the server will do the wct.apply when the method - // finishes. - t.apply(); - }; + private final DisplayController.OnDisplaysChangedListener mListener = + new DisplayController.OnDisplaysChangedListener() { + @Override + public void onDisplayConfigurationChanged(int displayId, Configuration newConfig) { + if (displayId != DEFAULT_DISPLAY) { + return; + } + DisplayLayout displayLayout = + mDisplayController.getDisplayLayout(DEFAULT_DISPLAY); + if (displayLayout == null) { + return; + } + final boolean rotationChanged = mRotation != displayLayout.rotation(); + mRotation = displayLayout.rotation(); + if (rotationChanged || isDisplayBoundsChanged()) { + updateBoundsAndOffsets(true /* enabled */); + final WindowContainerTransaction wct = new WindowContainerTransaction(); + final SurfaceControl.Transaction t = new SurfaceControl.Transaction(); + applyAllBoundsAndOffsets(wct, t); + applyTransaction(wct, t); + } + } + }; HideDisplayCutoutOrganizer(Context context, DisplayController displayController, ShellExecutor mainExecutor) { @@ -154,10 +163,10 @@ class HideDisplayCutoutOrganizer extends DisplayAreaOrganizer { * Enables hide display cutout. */ void enableHideDisplayCutout() { - mDisplayController.addDisplayChangingController(mRotationController); - final Display display = mDisplayController.getDisplay(DEFAULT_DISPLAY); - if (display != null) { - mRotation = display.getRotation(); + mDisplayController.addDisplayWindowListener(mListener); + final DisplayLayout displayLayout = mDisplayController.getDisplayLayout(DEFAULT_DISPLAY); + if (displayLayout != null) { + mRotation = displayLayout.rotation(); } final List displayAreaInfos = registerOrganizer(DisplayAreaOrganizer.FEATURE_HIDE_DISPLAY_CUTOUT); @@ -174,7 +183,7 @@ class HideDisplayCutoutOrganizer extends DisplayAreaOrganizer { */ void disableHideDisplayCutout() { updateBoundsAndOffsets(false /* enabled */); - mDisplayController.removeDisplayChangingController(mRotationController); + mDisplayController.removeDisplayWindowListener(mListener); unregisterOrganizer(); } @@ -193,23 +202,35 @@ class HideDisplayCutoutOrganizer extends DisplayAreaOrganizer { @VisibleForTesting Rect getDisplayBoundsOfNaturalOrientation() { - Point realSize = new Point(0, 0); - final Display display = mDisplayController.getDisplay(DEFAULT_DISPLAY); - if (display != null) { - display.getRealSize(realSize); + final DisplayLayout displayLayout = mDisplayController.getDisplayLayout(DEFAULT_DISPLAY); + if (displayLayout == null) { + return new Rect(); } final boolean isDisplaySizeFlipped = isDisplaySizeFlipped(); return new Rect( 0, 0, - isDisplaySizeFlipped ? realSize.y : realSize.x, - isDisplaySizeFlipped ? realSize.x : realSize.y); + isDisplaySizeFlipped ? displayLayout.height() : displayLayout.width(), + isDisplaySizeFlipped ? displayLayout.width() : displayLayout.height()); } private boolean isDisplaySizeFlipped() { return mRotation == Surface.ROTATION_90 || mRotation == Surface.ROTATION_270; } + private boolean isDisplayBoundsChanged() { + final DisplayLayout displayLayout = mDisplayController.getDisplayLayout(DEFAULT_DISPLAY); + if (displayLayout == null) { + return false; + } + final boolean isDisplaySizeFlipped = isDisplaySizeFlipped(); + final int width = isDisplaySizeFlipped ? displayLayout.height() : displayLayout.width(); + final int height = isDisplaySizeFlipped ? displayLayout.width() : displayLayout.height(); + return mDefaultDisplayBounds.isEmpty() + || mDefaultDisplayBounds.width() != width + || mDefaultDisplayBounds.height() != height; + } + /** * Updates bounds and offsets according to current state. * @@ -237,7 +258,6 @@ class HideDisplayCutoutOrganizer extends DisplayAreaOrganizer { mCurrentDisplayBounds.right); } mCurrentDisplayBounds.inset(mCurrentCutoutInsets); - // Replace the top bound with the max(status bar height, cutout height) if there is // cutout on the top side. mStatusBarHeight = getStatusBarHeight(); @@ -256,7 +276,7 @@ class HideDisplayCutoutOrganizer extends DisplayAreaOrganizer { } private void initDefaultValuesIfNeeded() { - if (!mDefaultDisplayBounds.isEmpty()) { + if (!isDisplayBoundsChanged()) { return; } mDefaultDisplayBounds.set(getDisplayBoundsOfNaturalOrientation()); diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/hidedisplaycutout/HideDisplayCutoutOrganizerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/hidedisplaycutout/HideDisplayCutoutOrganizerTest.java index 9637570454530..3c124bafc18a7 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/hidedisplaycutout/HideDisplayCutoutOrganizerTest.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/hidedisplaycutout/HideDisplayCutoutOrganizerTest.java @@ -50,6 +50,7 @@ import androidx.test.filters.SmallTest; import com.android.internal.R; import com.android.wm.shell.common.DisplayController; +import com.android.wm.shell.common.DisplayLayout; import com.android.wm.shell.common.ShellExecutor; import org.junit.Before; @@ -82,6 +83,8 @@ public class HideDisplayCutoutOrganizerTest { @Mock private Display mDisplay; @Mock + private DisplayLayout mDisplayLayout; + @Mock private IWindowContainerToken mMockRealToken; private WindowContainerToken mToken; @@ -95,6 +98,7 @@ public class HideDisplayCutoutOrganizerTest { MockitoAnnotations.initMocks(this); when(mMockDisplayController.getDisplay(anyInt())).thenReturn(mDisplay); + when(mMockDisplayController.getDisplayLayout(anyInt())).thenReturn(mDisplayLayout); HideDisplayCutoutOrganizer organizer = new HideDisplayCutoutOrganizer( mContext, mMockDisplayController, mMockMainExecutor); @@ -152,7 +156,7 @@ public class HideDisplayCutoutOrganizerTest { .getDisplayCutoutInsetsOfNaturalOrientation(); mContext.getOrCreateTestableResources().addOverride( R.dimen.status_bar_height_portrait, mFakeStatusBarHeightPortrait); - doReturn(Surface.ROTATION_0).when(mDisplay).getRotation(); + doReturn(Surface.ROTATION_0).when(mDisplayLayout).rotation(); mOrganizer.enableHideDisplayCutout(); verify(mOrganizer).registerOrganizer(DisplayAreaOrganizer.FEATURE_HIDE_DISPLAY_CUTOUT); @@ -171,7 +175,7 @@ public class HideDisplayCutoutOrganizerTest { .getDisplayCutoutInsetsOfNaturalOrientation(); mContext.getOrCreateTestableResources().addOverride( R.dimen.status_bar_height_landscape, mFakeStatusBarHeightLandscape); - doReturn(Surface.ROTATION_90).when(mDisplay).getRotation(); + doReturn(Surface.ROTATION_90).when(mDisplayLayout).rotation(); mOrganizer.enableHideDisplayCutout(); verify(mOrganizer).registerOrganizer(DisplayAreaOrganizer.FEATURE_HIDE_DISPLAY_CUTOUT); @@ -190,7 +194,7 @@ public class HideDisplayCutoutOrganizerTest { .getDisplayCutoutInsetsOfNaturalOrientation(); mContext.getOrCreateTestableResources().addOverride( R.dimen.status_bar_height_landscape, mFakeStatusBarHeightLandscape); - doReturn(Surface.ROTATION_270).when(mDisplay).getRotation(); + doReturn(Surface.ROTATION_270).when(mDisplayLayout).rotation(); mOrganizer.enableHideDisplayCutout(); verify(mOrganizer).registerOrganizer(DisplayAreaOrganizer.FEATURE_HIDE_DISPLAY_CUTOUT); @@ -219,4 +223,22 @@ public class HideDisplayCutoutOrganizerTest { assertThat(mOrganizer.mOffsetX).isEqualTo(0); assertThat(mOrganizer.mOffsetY).isEqualTo(0); } + + @Test + public void testDisplaySizeChange() { + doReturn(100).when(mDisplayLayout).width(); + doReturn(200).when(mDisplayLayout).height(); + doReturn(mFakeDefaultCutoutInsets).when(mOrganizer) + .getDisplayCutoutInsetsOfNaturalOrientation(); + mContext.getOrCreateTestableResources().addOverride( + R.dimen.status_bar_height_portrait, mFakeStatusBarHeightPortrait); + doReturn(Surface.ROTATION_0).when(mDisplayLayout).rotation(); + mOrganizer.enableHideDisplayCutout(); + assertThat(mOrganizer.mCurrentDisplayBounds).isEqualTo(new Rect(0, 15, 100, 200)); + + doReturn(200).when(mDisplayLayout).width(); + doReturn(400).when(mDisplayLayout).height(); + mOrganizer.updateBoundsAndOffsets(true); + assertThat(mOrganizer.mCurrentDisplayBounds).isEqualTo(new Rect(0, 15, 200, 400)); + } }