diff options
9 files changed, 88 insertions, 40 deletions
diff --git a/core/java/android/view/InsetsFlags.java b/core/java/android/view/InsetsFlags.java index a334907c04bc..3355252c4372 100644 --- a/core/java/android/view/InsetsFlags.java +++ b/core/java/android/view/InsetsFlags.java @@ -21,6 +21,8 @@ import static android.view.WindowInsetsController.APPEARANCE_LIGHT_STATUS_BARS; import static android.view.WindowInsetsController.APPEARANCE_LOW_PROFILE_BARS; import static android.view.WindowInsetsController.APPEARANCE_OPAQUE_NAVIGATION_BARS; import static android.view.WindowInsetsController.APPEARANCE_OPAQUE_STATUS_BARS; +import static android.view.WindowInsetsController.APPEARANCE_SEMI_TRANSPARENT_NAVIGATION_BARS; +import static android.view.WindowInsetsController.APPEARANCE_SEMI_TRANSPARENT_STATUS_BARS; import static android.view.WindowInsetsController.BEHAVIOR_DEFAULT; import static android.view.WindowInsetsController.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE; @@ -54,7 +56,15 @@ public class InsetsFlags { @ViewDebug.FlagToString( mask = APPEARANCE_LIGHT_NAVIGATION_BARS, equals = APPEARANCE_LIGHT_NAVIGATION_BARS, - name = "LIGHT_NAVIGATION_BARS") + name = "LIGHT_NAVIGATION_BARS"), + @ViewDebug.FlagToString( + mask = APPEARANCE_SEMI_TRANSPARENT_STATUS_BARS, + equals = APPEARANCE_SEMI_TRANSPARENT_STATUS_BARS, + name = "SEMI_TRANSPARENT_STATUS_BARS"), + @ViewDebug.FlagToString( + mask = APPEARANCE_SEMI_TRANSPARENT_NAVIGATION_BARS, + equals = APPEARANCE_SEMI_TRANSPARENT_NAVIGATION_BARS, + name = "SEMI_TRANSPARENT_NAVIGATION_BARS") }) public @Appearance int appearance; diff --git a/core/java/android/view/WindowInsetsController.java b/core/java/android/view/WindowInsetsController.java index 991ed5518003..227b9f402bba 100644 --- a/core/java/android/view/WindowInsetsController.java +++ b/core/java/android/view/WindowInsetsController.java @@ -67,13 +67,26 @@ public interface WindowInsetsController { int APPEARANCE_LIGHT_NAVIGATION_BARS = 1 << 4; /** + * Makes status bars semi-transparent with dark background and light foreground. + * @hide + */ + int APPEARANCE_SEMI_TRANSPARENT_STATUS_BARS = 1 << 5; + + /** + * Makes navigation bars semi-transparent with dark background and light foreground. + * @hide + */ + int APPEARANCE_SEMI_TRANSPARENT_NAVIGATION_BARS = 1 << 6; + + /** * Determines the appearance of system bars. * @hide */ @Retention(RetentionPolicy.SOURCE) @IntDef(flag = true, value = {APPEARANCE_OPAQUE_STATUS_BARS, APPEARANCE_OPAQUE_NAVIGATION_BARS, APPEARANCE_LOW_PROFILE_BARS, APPEARANCE_LIGHT_STATUS_BARS, - APPEARANCE_LIGHT_NAVIGATION_BARS}) + APPEARANCE_LIGHT_NAVIGATION_BARS, APPEARANCE_SEMI_TRANSPARENT_STATUS_BARS, + APPEARANCE_SEMI_TRANSPARENT_NAVIGATION_BARS}) @interface Appearance { } diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java index 34d1f6e1789c..fcb5da3f8c52 100644 --- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java +++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java @@ -28,6 +28,7 @@ import static android.view.InsetsState.ITYPE_NAVIGATION_BAR; import static android.view.InsetsState.containsType; import static android.view.WindowInsetsController.APPEARANCE_LOW_PROFILE_BARS; import static android.view.WindowInsetsController.APPEARANCE_OPAQUE_NAVIGATION_BARS; +import static android.view.WindowInsetsController.APPEARANCE_SEMI_TRANSPARENT_NAVIGATION_BARS; import static android.view.WindowInsetsController.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE; import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_NO_MOVE_ANIMATION; import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_3BUTTON; @@ -994,6 +995,8 @@ public class NavigationBar implements View.OnAttachStateChangeListener, return MODE_LIGHTS_OUT_TRANSPARENT; } else if ((appearance & APPEARANCE_OPAQUE_NAVIGATION_BARS) != 0) { return MODE_OPAQUE; + } else if ((appearance & APPEARANCE_SEMI_TRANSPARENT_NAVIGATION_BARS) != 0) { + return MODE_SEMI_TRANSPARENT; } else { return MODE_TRANSPARENT; } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java index e08224c84813..83651398be43 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java @@ -26,6 +26,7 @@ import static android.view.InsetsState.ITYPE_STATUS_BAR; import static android.view.InsetsState.containsType; import static android.view.WindowInsetsController.APPEARANCE_LOW_PROFILE_BARS; import static android.view.WindowInsetsController.APPEARANCE_OPAQUE_STATUS_BARS; +import static android.view.WindowInsetsController.APPEARANCE_SEMI_TRANSPARENT_STATUS_BARS; import static androidx.lifecycle.Lifecycle.State.RESUMED; @@ -2430,6 +2431,8 @@ public class StatusBar extends SystemUI implements DemoMode, return MODE_LIGHTS_OUT_TRANSPARENT; } else if ((appearance & APPEARANCE_OPAQUE_STATUS_BARS) != 0) { return MODE_OPAQUE; + } else if ((appearance & APPEARANCE_SEMI_TRANSPARENT_STATUS_BARS) != 0) { + return MODE_SEMI_TRANSPARENT; } else { return MODE_TRANSPARENT; } diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java index 4b4b2b65b8fc..b1da2f0fe888 100644 --- a/services/core/java/com/android/server/wm/ActivityRecord.java +++ b/services/core/java/com/android/server/wm/ActivityRecord.java @@ -1431,14 +1431,11 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A } /** - * @return {@code true} if bar shown within a given rectangle is allowed to be transparent + * @return {@code true} if bar shown within a given rectangle is allowed to be fully transparent * when the current activity is displayed. */ - boolean isTransparentBarAllowed(Rect rect) { - // TODO(b/175482966): Allow status and navigation bars to be semi-transparent black - // in letterbox mode. - return mLetterbox == null || mLetterbox.notIntersectsOrFullyContains(rect) - || mWmService.isLetterboxActivityCornersRounded(); + boolean isFullyTransparentBarAllowed(Rect rect) { + return mLetterbox == null || mLetterbox.notIntersectsOrFullyContains(rect); } /** diff --git a/services/core/java/com/android/server/wm/BarController.java b/services/core/java/com/android/server/wm/BarController.java index eee27c72e583..3c8cf4edf733 100644 --- a/services/core/java/com/android/server/wm/BarController.java +++ b/services/core/java/com/android/server/wm/BarController.java @@ -52,10 +52,19 @@ public class BarController { return !win.isLetterboxedOverlappingWith(getContentFrame(win)); } - boolean isTransparentAllowed(WindowState win) { + /** + * @return {@code true} if bar is allowed to be fully transparent when given window is show. + * + * <p>Prevents showing a transparent bar over a letterboxed activity which can make + * notification icons or navigation buttons unreadable due to contrast between letterbox + * background and an activity. For instance, this happens when letterbox background is solid + * black while activity is white. To resolve this, only semi-transparent bars are allowed to + * be drawn over letterboxed activity. + */ + boolean isFullyTransparentAllowed(WindowState win) { if (win == null) { return true; } - return win.isTransparentBarAllowed(getContentFrame(win)); + return win.isFullyTransparentBarAllowed(getContentFrame(win)); } } diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java index a7db9d624b7e..f52cb09bc201 100644 --- a/services/core/java/com/android/server/wm/DisplayPolicy.java +++ b/services/core/java/com/android/server/wm/DisplayPolicy.java @@ -42,6 +42,8 @@ import static android.view.WindowInsetsController.APPEARANCE_LIGHT_STATUS_BARS; import static android.view.WindowInsetsController.APPEARANCE_LOW_PROFILE_BARS; import static android.view.WindowInsetsController.APPEARANCE_OPAQUE_NAVIGATION_BARS; import static android.view.WindowInsetsController.APPEARANCE_OPAQUE_STATUS_BARS; +import static android.view.WindowInsetsController.APPEARANCE_SEMI_TRANSPARENT_NAVIGATION_BARS; +import static android.view.WindowInsetsController.APPEARANCE_SEMI_TRANSPARENT_STATUS_BARS; import static android.view.WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW; import static android.view.WindowManager.LayoutParams.FIRST_SYSTEM_WINDOW; import static android.view.WindowManager.LayoutParams.FLAG_ALLOW_LOCK_WHILE_SCREEN_ON; @@ -2693,34 +2695,17 @@ public class DisplayPolicy { private int updateSystemBarsLw(WindowState win, int disableFlags) { final boolean dockedRootTaskVisible = mDisplayContent.getDefaultTaskDisplayArea() .isRootTaskVisible(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY); - final boolean freeformRootTaskVisible = mDisplayContent.getDefaultTaskDisplayArea() - .isRootTaskVisible(WINDOWING_MODE_FREEFORM); final boolean resizing = mDisplayContent.getDockedDividerController().isResizing(); // We need to force system bars when the docked root task is visible, when the freeform // root task is focused but also when we are resizing for the transitions when docked // root task visibility changes. mForceShowSystemBars = dockedRootTaskVisible || win.inFreeformWindowingMode() || resizing; - final boolean forceOpaqueStatusBar = mForceShowSystemBars && !isKeyguardShowing(); - - final boolean fullscreenDrawsStatusBarBackground = - drawsStatusBarBackground(mTopFullscreenOpaqueWindowState); - final boolean dockedDrawsStatusBarBackground = - drawsStatusBarBackground(mTopDockedOpaqueWindowState); - final boolean fullscreenDrawsNavBarBackground = - drawsNavigationBarBackground(mTopFullscreenOpaqueWindowState); - final boolean dockedDrawsNavigationBarBackground = - drawsNavigationBarBackground(mTopDockedOpaqueWindowState); int appearance = APPEARANCE_OPAQUE_NAVIGATION_BARS | APPEARANCE_OPAQUE_STATUS_BARS; - if (fullscreenDrawsStatusBarBackground && dockedDrawsStatusBarBackground) { - appearance &= ~APPEARANCE_OPAQUE_STATUS_BARS; - } - - appearance = configureNavBarOpacity(appearance, dockedRootTaskVisible, - freeformRootTaskVisible, resizing, fullscreenDrawsNavBarBackground, - dockedDrawsNavigationBarBackground); + appearance = configureStatusBarOpacity(appearance); + appearance = configureNavBarOpacity(appearance, dockedRootTaskVisible, resizing); final boolean requestHideNavBar = !win.getRequestedVisibility(ITYPE_NAVIGATION_BAR); final long now = SystemClock.uptimeMillis(); @@ -2755,9 +2740,6 @@ public class DisplayPolicy { } private boolean drawsBarBackground(WindowState win, BarController controller) { - if (!controller.isTransparentAllowed(win)) { - return false; - } if (win == null) { return true; } @@ -2778,15 +2760,40 @@ public class DisplayPolicy { return drawsBarBackground(win, mNavigationBarController); } + /** @return the current visibility flags with the status bar opacity related flags toggled. */ + private int configureStatusBarOpacity(int appearance) { + final boolean fullscreenDrawsBackground = + drawsStatusBarBackground(mTopFullscreenOpaqueWindowState); + final boolean dockedDrawsBackground = + drawsStatusBarBackground(mTopDockedOpaqueWindowState); + + if (fullscreenDrawsBackground && dockedDrawsBackground) { + appearance &= ~APPEARANCE_OPAQUE_STATUS_BARS; + } + + if (!mStatusBarController.isFullyTransparentAllowed(mTopFullscreenOpaqueWindowState) + || !mStatusBarController.isFullyTransparentAllowed(mTopDockedOpaqueWindowState)) { + appearance |= APPEARANCE_SEMI_TRANSPARENT_STATUS_BARS; + } + + return appearance; + } + /** * @return the current visibility flags with the nav-bar opacity related flags toggled based * on the nav bar opacity rules chosen by {@link #mNavBarOpacityMode}. */ private int configureNavBarOpacity(int appearance, boolean dockedRootTaskVisible, - boolean freeformRootTaskVisible, boolean isDockedDividerResizing, - boolean fullscreenDrawsBackground, boolean dockedDrawsNavigationBarBackground) { + boolean isDockedDividerResizing) { + final boolean freeformRootTaskVisible = mDisplayContent.getDefaultTaskDisplayArea() + .isRootTaskVisible(WINDOWING_MODE_FREEFORM); + final boolean fullscreenDrawsBackground = + drawsNavigationBarBackground(mTopFullscreenOpaqueWindowState); + final boolean dockedDrawsBackground = + drawsNavigationBarBackground(mTopDockedOpaqueWindowState); + if (mNavBarOpacityMode == NAV_BAR_FORCE_TRANSPARENT) { - if (fullscreenDrawsBackground && dockedDrawsNavigationBarBackground) { + if (fullscreenDrawsBackground && dockedDrawsBackground) { appearance = clearNavBarOpaqueFlag(appearance); } else if (dockedRootTaskVisible) { appearance = setNavBarOpaqueFlag(appearance); @@ -2811,6 +2818,12 @@ public class DisplayPolicy { } } + if (!mNavigationBarController.isFullyTransparentAllowed(mTopFullscreenOpaqueWindowState) + || !mNavigationBarController.isFullyTransparentAllowed( + mTopDockedOpaqueWindowState)) { + appearance |= APPEARANCE_SEMI_TRANSPARENT_NAVIGATION_BARS; + } + return appearance; } diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java index 9a7823e35a01..159760491ff1 100644 --- a/services/core/java/com/android/server/wm/WindowState.java +++ b/services/core/java/com/android/server/wm/WindowState.java @@ -3846,11 +3846,11 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP } /** - * @return {@code true} if bar shown within a given frame is allowed to be transparent + * @return {@code true} if bar shown within a given frame is allowed to be fully transparent * when the current window is displayed. */ - boolean isTransparentBarAllowed(Rect frame) { - return mActivityRecord == null || mActivityRecord.isTransparentBarAllowed(frame); + boolean isFullyTransparentBarAllowed(Rect frame) { + return mActivityRecord == null || mActivityRecord.isFullyTransparentBarAllowed(frame); } public boolean isLetterboxedOverlappingWith(Rect rect) { 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 942e1c91989c..d0d612fc8dda 100644 --- a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java @@ -607,7 +607,7 @@ public class SizeCompatTests extends WindowTestsBase { // The activity doesn't fill the display, so the letterbox of the rotated activity is // overlapped with the rotated content frame of status bar. Hence the status bar shouldn't // be transparent. - assertFalse(statusBarController.isTransparentAllowed(w)); + assertFalse(statusBarController.isFullyTransparentAllowed(w)); // Make the activity fill the display. prepareUnresizable(mActivity, 10 /* maxAspect */, SCREEN_ORIENTATION_LANDSCAPE); @@ -617,7 +617,7 @@ public class SizeCompatTests extends WindowTestsBase { // The letterbox should only cover the notch area, so status bar can be transparent. assertEquals(new Rect(notchHeight, 0, 0, 0), mActivity.getLetterboxInsets()); - assertTrue(statusBarController.isTransparentAllowed(w)); + assertTrue(statusBarController.isFullyTransparentAllowed(w)); } @Test |