diff options
| author | 2022-08-02 11:05:44 +0000 | |
|---|---|---|
| committer | 2022-08-02 11:05:44 +0000 | |
| commit | 3b93fd5831313ff185b27950ca1080b8991eb3fc (patch) | |
| tree | c9a8b0154c0d9e5e3f4d0304024f6962d0e56bd2 | |
| parent | 3459f452d80d02d5d1384e1694fdc58102876477 (diff) | |
| parent | 95a0aa965f41f3d034d56c2111f9a09bd37941dd (diff) | |
Merge "Pass LetterboxDetails to SysUI" into tm-qpr-dev am: 95a0aa965f
Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/19377725
Change-Id: Id26c6d726541d47ce5668a80e5e0ac8d862a582d
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
4 files changed, 171 insertions, 2 deletions
diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java index 693f9c460ee6..7aa05412ec88 100644 --- a/services/core/java/com/android/server/wm/DisplayPolicy.java +++ b/services/core/java/com/android/server/wm/DisplayPolicy.java @@ -318,12 +318,19 @@ public class DisplayPolicy { */ private final ArrayList<WindowState> mStatusBarBackgroundWindows = new ArrayList<>(); + /** + * A collection of {@link LetterboxDetails} of all visible activities to be sent to SysUI in + * order to determine status bar appearance + */ + private final ArrayList<LetterboxDetails> mLetterboxDetails = new ArrayList<>(); + private String mFocusedApp; private int mLastDisableFlags; private int mLastAppearance; private int mLastBehavior; private InsetsVisibilities mRequestedVisibilities = new InsetsVisibilities(); private AppearanceRegion[] mLastStatusBarAppearanceRegions; + private LetterboxDetails[] mLastLetterboxDetails; /** The union of checked bounds while building {@link #mStatusBarAppearanceRegionList}. */ private final Rect mStatusBarColorCheckedBounds = new Rect(); @@ -1638,6 +1645,7 @@ public class DisplayPolicy { mNavBarColorWindowCandidate = null; mNavBarBackgroundWindow = null; mStatusBarAppearanceRegionList.clear(); + mLetterboxDetails.clear(); mStatusBarBackgroundWindows.clear(); mStatusBarColorCheckedBounds.setEmpty(); mStatusBarBackgroundCheckedBounds.setEmpty(); @@ -1717,6 +1725,16 @@ public class DisplayPolicy { win.mAttrs.insetsFlags.appearance & APPEARANCE_LIGHT_STATUS_BARS, new Rect(win.getFrame()))); mStatusBarColorCheckedBounds.union(sTmpRect); + // Check if current activity is letterboxed in order create a LetterboxDetails + // component to be passed to SysUI for status bar treatment + final ActivityRecord currentActivity = win.getActivityRecord(); + if (currentActivity != null) { + final LetterboxDetails currentLetterboxDetails = currentActivity + .mLetterboxUiController.getLetterboxDetails(); + if (currentLetterboxDetails != null) { + mLetterboxDetails.add(currentLetterboxDetails); + } + } } } @@ -2404,12 +2422,15 @@ public class DisplayPolicy { callStatusBarSafely(statusBar -> statusBar.setDisableFlags(displayId, disableFlags, cause)); } + final LetterboxDetails[] letterboxDetails = new LetterboxDetails[mLetterboxDetails.size()]; + mLetterboxDetails.toArray(letterboxDetails); if (mLastAppearance == appearance && mLastBehavior == behavior && mRequestedVisibilities.equals(win.getRequestedVisibilities()) && Objects.equals(mFocusedApp, focusedApp) && mLastFocusIsFullscreen == isFullscreen - && Arrays.equals(mLastStatusBarAppearanceRegions, statusBarAppearanceRegions)) { + && Arrays.equals(mLastStatusBarAppearanceRegions, statusBarAppearanceRegions) + && Arrays.equals(mLastLetterboxDetails, letterboxDetails)) { return; } if (mDisplayContent.isDefaultDisplay && mLastFocusIsFullscreen != isFullscreen @@ -2425,9 +2446,10 @@ public class DisplayPolicy { mFocusedApp = focusedApp; mLastFocusIsFullscreen = isFullscreen; mLastStatusBarAppearanceRegions = statusBarAppearanceRegions; + mLastLetterboxDetails = letterboxDetails; callStatusBarSafely(statusBar -> statusBar.onSystemBarAttributesChanged(displayId, appearance, statusBarAppearanceRegions, isNavbarColorManagedByIme, behavior, - requestedVisibilities, focusedApp, new LetterboxDetails[]{})); + requestedVisibilities, focusedApp, letterboxDetails)); } private void callStatusBarSafely(Consumer<StatusBarManagerInternal> consumer) { @@ -2841,6 +2863,12 @@ public class DisplayPolicy { pw.print(prefixInner); pw.println(mLastStatusBarAppearanceRegions[i]); } } + if (mLastLetterboxDetails != null) { + pw.print(prefix); pw.println("mLastLetterboxDetails="); + for (int i = mLastLetterboxDetails.length - 1; i >= 0; i--) { + pw.print(prefixInner); pw.println(mLastLetterboxDetails[i]); + } + } if (!mStatusBarBackgroundWindows.isEmpty()) { pw.print(prefix); pw.println("mStatusBarBackgroundWindows="); for (int i = mStatusBarBackgroundWindows.size() - 1; i >= 0; i--) { diff --git a/services/core/java/com/android/server/wm/Letterbox.java b/services/core/java/com/android/server/wm/Letterbox.java index b5eff41d4f62..df3109ad33c7 100644 --- a/services/core/java/com/android/server/wm/Letterbox.java +++ b/services/core/java/com/android/server/wm/Letterbox.java @@ -138,6 +138,11 @@ public class Letterbox { return mInner; } + /** @return The frame that contains the inner frame and the insets. */ + Rect getOuterFrame() { + return mOuter; + } + /** * Returns {@code true} if the letterbox does not overlap with the bar, or the letterbox can * fully cover the window frame. diff --git a/services/core/java/com/android/server/wm/LetterboxUiController.java b/services/core/java/com/android/server/wm/LetterboxUiController.java index d65276793700..ec9ee29679a4 100644 --- a/services/core/java/com/android/server/wm/LetterboxUiController.java +++ b/services/core/java/com/android/server/wm/LetterboxUiController.java @@ -68,6 +68,7 @@ import android.view.WindowManager; import com.android.internal.R; import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.statusbar.LetterboxDetails; import com.android.server.wm.LetterboxConfiguration.LetterboxBackgroundType; import java.io.PrintWriter; @@ -141,6 +142,15 @@ final class LetterboxUiController { } } + /** Gets the outer bounds of letterbox. The bounds will be empty if there is no letterbox. */ + private void getLetterboxOuterBounds(Rect outBounds) { + if (mLetterbox != null) { + outBounds.set(mLetterbox.getOuterFrame()); + } else { + outBounds.setEmpty(); + } + } + /** * @return {@code true} if bar shown within a given rectangle is allowed to be fully transparent * when the current activity is displayed. @@ -683,4 +693,26 @@ final class LetterboxUiController { mActivityRecord.mTaskSupervisor.getActivityMetricsLogger() .logLetterboxPositionChange(mActivityRecord, letterboxPositionChange); } + + @Nullable + LetterboxDetails getLetterboxDetails() { + final WindowState w = mActivityRecord.findMainWindow(); + if (mLetterbox == null || w == null || w.isLetterboxedForDisplayCutout()) { + return null; + } + Rect letterboxInnerBounds = new Rect(); + Rect letterboxOuterBounds = new Rect(); + getLetterboxInnerBounds(letterboxInnerBounds); + getLetterboxOuterBounds(letterboxOuterBounds); + + if (letterboxInnerBounds.isEmpty() || letterboxOuterBounds.isEmpty()) { + return null; + } + + return new LetterboxDetails( + letterboxInnerBounds, + letterboxOuterBounds, + w.mAttrs.insetsFlags.appearance + ); + } } diff --git a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java index 324e244c46f5..21839aac4ec5 100644 --- a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java @@ -61,8 +61,10 @@ import static org.junit.Assert.assertNotEquals; import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyBoolean; +import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.argThat; +import static org.mockito.ArgumentMatchers.isNull; import static org.mockito.ArgumentMatchers.same; import static org.mockito.Mockito.atLeastOnce; import static org.mockito.Mockito.clearInvocations; @@ -82,11 +84,14 @@ import android.os.UserHandle; import android.platform.test.annotations.Presubmit; import android.provider.DeviceConfig; import android.provider.DeviceConfig.Properties; +import android.view.InsetsVisibilities; import android.view.WindowManager; import androidx.test.filters.MediumTest; import com.android.internal.policy.SystemBarUtils; +import com.android.internal.statusbar.LetterboxDetails; +import com.android.server.statusbar.StatusBarManagerInternal; import libcore.junit.util.compat.CoreCompatChangeRule.DisableCompatChanges; import libcore.junit.util.compat.CoreCompatChangeRule.EnableCompatChanges; @@ -97,6 +102,7 @@ import org.junit.Rule; import org.junit.Test; import org.junit.rules.TestRule; import org.junit.runner.RunWith; +import org.mockito.Mockito; /** * Tests for Size Compatibility mode. @@ -2113,6 +2119,104 @@ public class SizeCompatTests extends WindowTestsBase { assertLetterboxSurfacesDrawnBetweenActivityAndParentBounds(organizer.mPrimary.getBounds()); } + @Test + public void testLetterboxDetailsForStatusBar_noLetterbox() { + setUpDisplaySizeWithApp(2800, 1000); + addStatusBar(mActivity.mDisplayContent); + addWindowToActivity(mActivity); // Add a window to the activity so that we can get an + // appearance inside letterboxDetails + + DisplayPolicy displayPolicy = mActivity.getDisplayContent().getDisplayPolicy(); + StatusBarManagerInternal statusBar = displayPolicy.getStatusBarManagerInternal(); + // We should get a null LetterboxDetails object as there is no letterboxed activity, so + // nothing will get passed to SysUI + verify(statusBar, never()).onSystemBarAttributesChanged(anyInt(), anyInt(), + any(), anyBoolean(), anyInt(), + any(InsetsVisibilities.class), isNull(), isNull()); + + } + + @Test + public void testLetterboxDetailsForStatusBar_letterboxedForMaxAspectRatio() { + setUpDisplaySizeWithApp(2800, 1000); + addStatusBar(mActivity.mDisplayContent); + addWindowToActivity(mActivity); // Add a window to the activity so that we can get an + // appearance inside letterboxDetails + // Prepare unresizable activity with max aspect ratio + prepareUnresizable(mActivity, /* maxAspect */ 1.1f, SCREEN_ORIENTATION_UNSPECIFIED); + // Refresh the letterbox + mActivity.mRootWindowContainer.performSurfacePlacement(); + + Rect mBounds = new Rect(mActivity.getWindowConfiguration().getBounds()); + assertEquals(mBounds, new Rect(850, 0, 1950, 1000)); + + DisplayPolicy displayPolicy = mActivity.getDisplayContent().getDisplayPolicy(); + LetterboxDetails[] expectedLetterboxDetails = {new LetterboxDetails( + mBounds, + mActivity.getDisplayContent().getBounds(), + mActivity.findMainWindow().mAttrs.insetsFlags.appearance + )}; + + // Check that letterboxDetails actually gets passed to SysUI + StatusBarManagerInternal statusBar = displayPolicy.getStatusBarManagerInternal(); + verify(statusBar).onSystemBarAttributesChanged(anyInt(), anyInt(), + any(), anyBoolean(), anyInt(), + any(InsetsVisibilities.class), isNull(), eq(expectedLetterboxDetails)); + } + + @Test + public void testSplitScreenLetterboxDetailsForStatusBar_twoLetterboxedApps() { + mAtm.mDevEnableNonResizableMultiWindow = true; + setUpDisplaySizeWithApp(2800, 1000); + addStatusBar(mActivity.mDisplayContent); + // Create another task for the second activity + final Task newTask = new TaskBuilder(mSupervisor).setDisplay(mActivity.getDisplayContent()) + .setCreateActivity(true).build(); + ActivityRecord newActivity = newTask.getTopNonFinishingActivity(); + + final TestSplitOrganizer organizer = + new TestSplitOrganizer(mAtm, mActivity.getDisplayContent()); + + // Move first activity to split screen which takes half of the screen. + organizer.mPrimary.setBounds(0, 0, 1400, 1000); + organizer.putTaskToPrimary(mTask, true); + // Move second activity to split screen which takes half of the screen. + organizer.mSecondary.setBounds(1400, 0, 2800, 1000); + organizer.putTaskToSecondary(newTask, true); + + addWindowToActivity(mActivity); // Add a window to the activity so that we can get an + // appearance inside letterboxDetails + // Prepare unresizable activity with max aspect ratio + prepareUnresizable(mActivity, /* maxAspect */ 1.1f, SCREEN_ORIENTATION_UNSPECIFIED); + addWindowToActivity(newActivity); + prepareUnresizable(newActivity, /* maxAspect */ 1.1f, SCREEN_ORIENTATION_UNSPECIFIED); + + // Refresh the letterboxes + newActivity.mRootWindowContainer.performSurfacePlacement(); + + Rect mBounds = new Rect(mActivity.getWindowConfiguration().getBounds()); + assertEquals(mBounds, new Rect(150, 0, 1250, 1000)); + final Rect newBounds = new Rect(newActivity.getWindowConfiguration().getBounds()); + assertEquals(newBounds, new Rect(1550, 0, 2650, 1000)); + + DisplayPolicy displayPolicy = mActivity.getDisplayContent().getDisplayPolicy(); + LetterboxDetails[] expectedLetterboxDetails = { new LetterboxDetails( + mBounds, + organizer.mPrimary.getBounds(), + mActivity.findMainWindow().mAttrs.insetsFlags.appearance + ), new LetterboxDetails( + newBounds, + organizer.mSecondary.getBounds(), + newActivity.findMainWindow().mAttrs.insetsFlags.appearance + )}; + + // Check that letterboxDetails actually gets passed to SysUI + StatusBarManagerInternal statusBar = displayPolicy.getStatusBarManagerInternal(); + verify(statusBar).onSystemBarAttributesChanged(anyInt(), anyInt(), + any(), anyBoolean(), anyInt(), + any(InsetsVisibilities.class), isNull(), eq(expectedLetterboxDetails)); + } + private void recomputeNaturalConfigurationOfUnresizableActivity() { // Recompute the natural configuration of the non-resizable activity and the split screen. mActivity.clearSizeCompatMode(); |