Respect light nav bar flag set by IME on keyguard

Currently LightBarController takes care of both ScrimBehind alpha and
ScrimInFront text color when finally deciding whether light navigation
bar mode should be enabled or not.

When IME is shown on the keyguard, however, light navigation bar flag
explicitly set by the IME actually needs to be used because
ScrimController does not put anything over the IME layer in that
state.

This CL addresses the above corner case, by also forwarding ScrimState
from ScrimController to LightBarController so that LightBarController
can change the behavior when scrim UI is in bouncer mode.

Test: atest CtsInputMethodTestCases
Test: atest com.android.server.policy.PhoneWindowManagerTest
Test: atest SystemUITests:com.android.systemui.statusbar.phone.ScrimControllerTest
Test: Manually tested Manually tested with ThemedNavBarKeyboard sample
  1. make -j ThemedNavBarKeyboard
  2. adb install -r $OUT/system/app/ThemedNavBarKeyboard/ThemedNavBarKeyboard.apk
  3. adb shell ime enable com.example.android.themednavbarkeyboard/.ThemedNavBarKeyboard
  4. adb shell ime set com.example.android.themednavbarkeyboard/.ThemedNavBarKeyboard
  5. Open Dialer app
  6. Focus in the top edit field.
  7. Tap "EXTENDED LIGHT NAVIGARION BAR" mode
  8. Make sure that the navigation button color is optimized for light navigation bar
  9. Swipe down the notification shade.
 10. Make sure that the navigation button color is inverted.
Fixes: 72940586
Change-Id: I7a9001888f9b2d74c84c384b6302706da7a2b4b2
diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java b/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
index c01cafa..ef11c42 100644
--- a/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
+++ b/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
@@ -24,6 +24,7 @@
 import android.view.ViewGroup;
 
 import com.android.internal.logging.MetricsLogger;
+import com.android.internal.util.function.TriConsumer;
 import com.android.internal.widget.LockPatternUtils;
 import com.android.internal.colorextraction.ColorExtractor.GradientColors;
 import com.android.keyguard.ViewMediatorCallback;
@@ -52,6 +53,7 @@
 import com.android.systemui.statusbar.phone.NotificationGroupManager;
 import com.android.systemui.statusbar.phone.NotificationIconAreaController;
 import com.android.systemui.statusbar.phone.ScrimController;
+import com.android.systemui.statusbar.phone.ScrimState;
 import com.android.systemui.statusbar.phone.StatusBar;
 import com.android.systemui.statusbar.phone.StatusBarIconController;
 import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
@@ -103,12 +105,12 @@
     }
 
     public ScrimController createScrimController(ScrimView scrimBehind, ScrimView scrimInFront,
-            LockscreenWallpaper lockscreenWallpaper, Consumer<Float> scrimBehindAlphaListener,
-            Consumer<GradientColors> scrimInFrontColorListener,
+            LockscreenWallpaper lockscreenWallpaper,
+            TriConsumer<ScrimState, Float, GradientColors> scrimStateListener,
             Consumer<Integer> scrimVisibleListener, DozeParameters dozeParameters,
             AlarmManager alarmManager) {
-        return new ScrimController(scrimBehind, scrimInFront, scrimBehindAlphaListener,
-                scrimInFrontColorListener, scrimVisibleListener, dozeParameters, alarmManager);
+        return new ScrimController(scrimBehind, scrimInFront, scrimStateListener,
+                scrimVisibleListener, dozeParameters, alarmManager);
     }
 
     public NotificationIconAreaController createNotificationIconAreaController(Context context,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarController.java
index d61d6e2..8b8cbfe 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarController.java
@@ -66,9 +66,12 @@
      * scrim alpha yet.
      */
     private boolean mHasLightNavigationBar;
-    private boolean mScrimAlphaBelowThreshold;
-    private boolean mInvertLightNavBarWithScrim;
-    private float mScrimAlpha;
+
+    /**
+     * {@code true} if {@link #mHasLightNavigationBar} should be ignored and forcefully make
+     * {@link #mNavigationLight} {@code false}.
+     */
+    private boolean mForceDarkForScrim;
 
     private final Rect mLastFullscreenBounds = new Rect();
     private final Rect mLastDockedBounds = new Rect();
@@ -129,9 +132,7 @@
             boolean last = mNavigationLight;
             mHasLightNavigationBar = isLight(vis, navigationBarMode,
                     View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR);
-            mNavigationLight = mHasLightNavigationBar
-                    && (mScrimAlphaBelowThreshold || !mInvertLightNavBarWithScrim)
-                    && !mQsCustomizing;
+            mNavigationLight = mHasLightNavigationBar && !mForceDarkForScrim && !mQsCustomizing;
             if (mNavigationLight != last) {
                 updateNavigation();
             }
@@ -154,20 +155,17 @@
         reevaluate();
     }
 
-    public void setScrimAlpha(float alpha) {
-        mScrimAlpha = alpha;
-        boolean belowThresholdBefore = mScrimAlphaBelowThreshold;
-        mScrimAlphaBelowThreshold = mScrimAlpha < NAV_BAR_INVERSION_SCRIM_ALPHA_THRESHOLD;
-        if (mHasLightNavigationBar && belowThresholdBefore != mScrimAlphaBelowThreshold) {
-            reevaluate();
-        }
-    }
-
-    public void setScrimColor(GradientColors colors) {
-        boolean invertLightNavBarWithScrimBefore = mInvertLightNavBarWithScrim;
-        mInvertLightNavBarWithScrim = !colors.supportsDarkText();
-        if (mHasLightNavigationBar
-                && invertLightNavBarWithScrimBefore != mInvertLightNavBarWithScrim) {
+    public void setScrimState(ScrimState scrimState, float scrimBehindAlpha,
+            GradientColors scrimInFrontColor) {
+        boolean forceDarkForScrimLast = mForceDarkForScrim;
+        // For BOUNCER/BOUNCER_SCRIMMED cases, we assume that alpha is always below threshold.
+        // This enables IMEs to control the navigation bar color.
+        // For other cases, scrim should be able to veto the light navigation bar.
+        mForceDarkForScrim = scrimState != ScrimState.BOUNCER
+                && scrimState != ScrimState.BOUNCER_SCRIMMED
+                && scrimBehindAlpha >= NAV_BAR_INVERSION_SCRIM_ALPHA_THRESHOLD
+                && !scrimInFrontColor.supportsDarkText();
+        if (mHasLightNavigationBar && (mForceDarkForScrim != forceDarkForScrimLast)) {
             reevaluate();
         }
     }
@@ -257,8 +255,9 @@
         pw.print(" mLastStatusBarMode="); pw.print(mLastStatusBarMode);
         pw.print(" mLastNavigationBarMode="); pw.println(mLastNavigationBarMode);
 
-        pw.print(" mScrimAlpha="); pw.print(mScrimAlpha);
-        pw.print(" mScrimAlphaBelowThreshold="); pw.println(mScrimAlphaBelowThreshold);
+        pw.print(" mForceDarkForScrim="); pw.print(mForceDarkForScrim);
+        pw.print(" mQsCustomizing="); pw.println(mQsCustomizing);
+
         pw.println();
 
         LightBarTransitionsController transitionsController =
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
index cc143bb..4e8003e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
@@ -41,6 +41,7 @@
 import com.android.internal.colorextraction.ColorExtractor.GradientColors;
 import com.android.internal.colorextraction.ColorExtractor.OnColorsChangedListener;
 import com.android.internal.graphics.ColorUtils;
+import com.android.internal.util.function.TriConsumer;
 import com.android.keyguard.KeyguardUpdateMonitor;
 import com.android.systemui.Dependency;
 import com.android.systemui.Dumpable;
@@ -144,8 +145,7 @@
     private int mCurrentBehindTint;
     private boolean mWallpaperVisibilityTimedOut;
     private int mScrimsVisibility;
-    private final Consumer<GradientColors> mScrimInFrontColorListener;
-    private final Consumer<Float> mScrimBehindAlphaListener;
+    private final TriConsumer<ScrimState, Float, GradientColors> mScrimStateListener;
     private final Consumer<Integer> mScrimVisibleListener;
     private boolean mBlankScreen;
     private boolean mScreenBlankingCallbackCalled;
@@ -163,14 +163,12 @@
     private boolean mKeyguardOccluded;
 
     public ScrimController(ScrimView scrimBehind, ScrimView scrimInFront,
-            Consumer<Float> scrimBehindAlphaListener,
-            Consumer<GradientColors> scrimInFrontColorListener,
+            TriConsumer<ScrimState, Float, GradientColors> scrimStateListener,
             Consumer<Integer> scrimVisibleListener, DozeParameters dozeParameters,
             AlarmManager alarmManager) {
         mScrimBehind = scrimBehind;
         mScrimInFront = scrimInFront;
-        mScrimBehindAlphaListener = scrimBehindAlphaListener;
-        mScrimInFrontColorListener = scrimInFrontColorListener;
+        mScrimStateListener = scrimStateListener;
         mScrimVisibleListener = scrimVisibleListener;
         mContext = scrimBehind.getContext();
         mUnlockMethodCache = UnlockMethodCache.getInstance(mContext);
@@ -300,6 +298,8 @@
         } else {
             scheduleUpdate();
         }
+
+        dispatchScrimState(mScrimBehind.getViewAlpha());
     }
 
     public ScrimState getState() {
@@ -375,7 +375,7 @@
             setOrAdaptCurrentAnimation(mScrimBehind);
             setOrAdaptCurrentAnimation(mScrimInFront);
 
-            mScrimBehindAlphaListener.accept(mScrimBehind.getViewAlpha());
+            dispatchScrimState(mScrimBehind.getViewAlpha());
         }
     }
 
@@ -484,7 +484,7 @@
             float minOpacity = ColorUtils.calculateMinimumBackgroundAlpha(textColor, mainColor,
                     4.5f /* minimumContrast */) / 255f;
             mScrimBehindAlpha = Math.max(mScrimBehindAlphaResValue, minOpacity);
-            mScrimInFrontColorListener.accept(mScrimInFront.getColors());
+            dispatchScrimState(mScrimBehind.getViewAlpha());
         }
 
         // We want to override the back scrim opacity for the AOD state
@@ -503,6 +503,10 @@
         dispatchScrimsVisible();
     }
 
+    private void dispatchScrimState(float alpha) {
+        mScrimStateListener.accept(mState, alpha, mScrimInFront.getColors());
+    }
+
     private void dispatchScrimsVisible() {
         final int currentScrimVisibility;
         if (mScrimInFront.getViewAlpha() == 1 || mScrimBehind.getViewAlpha() == 1) {
@@ -712,7 +716,7 @@
         }
 
         if (scrim == mScrimBehind) {
-            mScrimBehindAlphaListener.accept(alpha);
+            dispatchScrimState(alpha);
         }
 
         final boolean wantsAlphaUpdate = alpha != currentAlpha;
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 4b2bc45..ee1f02d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -918,12 +918,7 @@
         ScrimView scrimInFront = mStatusBarWindow.findViewById(R.id.scrim_in_front);
         mScrimController = SystemUIFactory.getInstance().createScrimController(
                 scrimBehind, scrimInFront, mLockscreenWallpaper,
-                scrimBehindAlpha -> {
-                    mLightBarController.setScrimAlpha(scrimBehindAlpha);
-                },
-                scrimInFrontColor -> {
-                    mLightBarController.setScrimColor(scrimInFrontColor);
-                },
+                (state, alpha, color) -> mLightBarController.setScrimState(state, alpha, color),
                 scrimsVisible -> {
                     if (mStatusBarWindowManager != null) {
                         mStatusBarWindowManager.setScrimsVisibility(scrimsVisible);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
index 0416232..69508ac 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
@@ -43,6 +43,7 @@
 import android.view.View;
 
 import com.android.internal.colorextraction.ColorExtractor.GradientColors;
+import com.android.internal.util.function.TriConsumer;
 import com.android.keyguard.KeyguardUpdateMonitor;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.statusbar.ScrimView;
@@ -66,9 +67,7 @@
     private SynchronousScrimController mScrimController;
     private ScrimView mScrimBehind;
     private ScrimView mScrimInFront;
-    private Consumer<Float> mScrimBehindAlphaCallback;
-    private Consumer<GradientColors> mScrimInFrontColorCallback;
-    private Consumer<Integer> mScrimVisibilityCallback;
+    private ScrimState mScrimState;
     private float mScrimBehindAlpha;
     private GradientColors mScrimInFrontColor;
     private int mScrimVisibility;
@@ -77,6 +76,7 @@
     private boolean mAlwaysOnEnabled;
     private AlarmManager mAlarmManager;
 
+
     @Before
     public void setup() {
         mScrimBehind = spy(new ScrimView(getContext()));
@@ -84,15 +84,16 @@
         mWakeLock = mock(WakeLock.class);
         mAlarmManager = mock(AlarmManager.class);
         mAlwaysOnEnabled = true;
-        mScrimBehindAlphaCallback = (Float alpha) -> mScrimBehindAlpha = alpha;
-        mScrimInFrontColorCallback = (GradientColors color) -> mScrimInFrontColor = color;
-        mScrimVisibilityCallback = (Integer visible) -> mScrimVisibility = visible;
         mDozeParamenters = mock(DozeParameters.class);
         when(mDozeParamenters.getAlwaysOn()).thenAnswer(invocation -> mAlwaysOnEnabled);
         when(mDozeParamenters.getDisplayNeedsBlanking()).thenReturn(true);
         mScrimController = new SynchronousScrimController(mScrimBehind, mScrimInFront,
-                mScrimBehindAlphaCallback, mScrimInFrontColorCallback, mScrimVisibilityCallback,
-                mDozeParamenters, mAlarmManager);
+                (scrimState, scrimBehindAlpha, scrimInFrontColor) -> {
+                    mScrimState = scrimState;
+                    mScrimBehindAlpha = scrimBehindAlpha;
+                    mScrimInFrontColor = scrimInFrontColor;
+                },
+                visible -> mScrimVisibility = visible, mDozeParamenters, mAlarmManager);
     }
 
     @Test
@@ -211,6 +212,21 @@
     }
 
     @Test
+    public void scrimStateCallback() {
+        mScrimController.transitionTo(ScrimState.UNLOCKED);
+        mScrimController.finishAnimationsImmediately();
+        Assert.assertEquals(mScrimState, ScrimState.UNLOCKED);
+
+        mScrimController.transitionTo(ScrimState.BOUNCER);
+        mScrimController.finishAnimationsImmediately();
+        Assert.assertEquals(mScrimState, ScrimState.BOUNCER);
+
+        mScrimController.transitionTo(ScrimState.BOUNCER_SCRIMMED);
+        mScrimController.finishAnimationsImmediately();
+        Assert.assertEquals(mScrimState, ScrimState.BOUNCER_SCRIMMED);
+    }
+
+    @Test
     public void panelExpansion() {
         mScrimController.setPanelExpansion(0f);
         mScrimController.setPanelExpansion(0.5f);
@@ -559,12 +575,11 @@
         boolean mOnPreDrawCalled;
 
         SynchronousScrimController(ScrimView scrimBehind, ScrimView scrimInFront,
-                Consumer<Float> scrimBehindAlphaListener,
-                Consumer<GradientColors> scrimInFrontColorListener,
+                TriConsumer<ScrimState, Float, GradientColors> scrimStateListener,
                 Consumer<Integer> scrimVisibleListener, DozeParameters dozeParameters,
                 AlarmManager alarmManager) {
-            super(scrimBehind, scrimInFront, scrimBehindAlphaListener, scrimInFrontColorListener,
-                    scrimVisibleListener, dozeParameters, alarmManager);
+            super(scrimBehind, scrimInFront, scrimStateListener, scrimVisibleListener,
+                    dozeParameters, alarmManager);
             mHandler = new FakeHandler(Looper.myLooper());
         }