Fixing various system UI flags not getting updated properly on theme changes.

SystemUiController manages various system UI flags in priorty order and merges
all the states before applying the syste flags.
Fixing WallpaperColors when it was not handing wallpaper change properly in
some cases

Change-Id: I915442818e7888c97c81f63c8ea9f3c13053eb2c
diff --git a/src/com/android/launcher3/BaseActivity.java b/src/com/android/launcher3/BaseActivity.java
index 08cd955..2b59ede 100644
--- a/src/com/android/launcher3/BaseActivity.java
+++ b/src/com/android/launcher3/BaseActivity.java
@@ -22,11 +22,13 @@
 import android.view.View.AccessibilityDelegate;
 
 import com.android.launcher3.logging.UserEventDispatcher;
+import com.android.launcher3.util.SystemUiController;
 
 public abstract class BaseActivity extends Activity {
 
     protected DeviceProfile mDeviceProfile;
     protected UserEventDispatcher mUserEventDispatcher;
+    protected SystemUiController mSystemUiController;
 
     public DeviceProfile getDeviceProfile() {
         return mDeviceProfile;
@@ -54,4 +56,11 @@
         }
         return ((BaseActivity) ((ContextWrapper) context).getBaseContext());
     }
+
+    public SystemUiController getSystemUiController() {
+        if (mSystemUiController == null) {
+            mSystemUiController = new SystemUiController(getWindow());
+        }
+        return mSystemUiController;
+    }
 }
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index bb32a45..66aab43 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -126,6 +126,7 @@
 import com.android.launcher3.util.PackageManagerHelper;
 import com.android.launcher3.util.PackageUserKey;
 import com.android.launcher3.util.PendingRequestArgs;
+import com.android.launcher3.util.SystemUiController;
 import com.android.launcher3.util.TestingUtils;
 import com.android.launcher3.util.Themes;
 import com.android.launcher3.util.Thunk;
@@ -470,9 +471,8 @@
         // Listen for broadcasts screen off
         registerReceiver(mReceiver, new IntentFilter(Intent.ACTION_SCREEN_OFF));
 
-        if (Themes.getAttrBoolean(this, R.attr.isWorkspaceDarkText)) {
-            activateLightSystemBars(true, true, true);
-        }
+        getSystemUiController().updateUiState(SystemUiController.UI_STATE_BASE_WINDOW,
+                Themes.getAttrBoolean(this, R.attr.isWorkspaceDarkText));
     }
 
     @Override
@@ -519,36 +519,6 @@
         }
     }
 
-    /**
-     * Sets the status and/or nav bar to be light or not. Light status bar means dark icons.
-     * @param isLight make sure the system bar is light.
-     * @param statusBar if true, make the status bar theme match the isLight param.
-     * @param navBar if true, make the nav bar theme match the isLight param.
-     */
-    public void activateLightSystemBars(boolean isLight, boolean statusBar, boolean navBar) {
-        int oldSystemUiFlags = getWindow().getDecorView().getSystemUiVisibility();
-        int newSystemUiFlags = oldSystemUiFlags;
-        if (isLight) {
-            if (statusBar) {
-                newSystemUiFlags |= View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR;
-            }
-            if (navBar && Utilities.isAtLeastO()) {
-                newSystemUiFlags |= View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR;
-            }
-        } else {
-            if (statusBar) {
-                newSystemUiFlags &= ~(View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR);
-            }
-            if (navBar && Utilities.isAtLeastO()) {
-                newSystemUiFlags &= ~(View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR);
-            }
-        }
-
-        if (newSystemUiFlags != oldSystemUiFlags) {
-            getWindow().getDecorView().setSystemUiVisibility(newSystemUiFlags);
-        }
-    }
-
     private LauncherCallbacks mLauncherCallbacks;
 
     public void onPostCreate(Bundle savedInstanceState) {
diff --git a/src/com/android/launcher3/allapps/AllAppsTransitionController.java b/src/com/android/launcher3/allapps/AllAppsTransitionController.java
index 2d8310b..faadce4 100644
--- a/src/com/android/launcher3/allapps/AllAppsTransitionController.java
+++ b/src/com/android/launcher3/allapps/AllAppsTransitionController.java
@@ -28,6 +28,7 @@
 import com.android.launcher3.graphics.ScrimView;
 import com.android.launcher3.userevent.nano.LauncherLogProto.Action;
 import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType;
+import com.android.launcher3.util.SystemUiController;
 import com.android.launcher3.util.Themes;
 import com.android.launcher3.util.TouchController;
 
@@ -71,7 +72,6 @@
     private final VerticalPullDetector mDetector;
     private final ArgbEvaluator mEvaluator;
     private final boolean mIsDarkTheme;
-    private final boolean mIsWorkspaceDarkText;
 
     // Animation in this class is controlled by a single variable {@link mProgress}.
     // Visually, it represents top y coordinate of the all apps container if multiplied with
@@ -114,7 +114,6 @@
         mEvaluator = new ArgbEvaluator();
         mAllAppsBackgroundColor = Themes.getAttrColor(l, android.R.attr.colorPrimary);
         mIsDarkTheme = Themes.getAttrBoolean(mLauncher, R.attr.isMainColorDark);
-        mIsWorkspaceDarkText = Themes.getAttrBoolean(mLauncher, R.attr.isWorkspaceDarkText);
     }
 
     @Override
@@ -278,15 +277,21 @@
     }
 
     private void updateLightStatusBar(float shift) {
-        // Do not modify status bar in dark theme or on landscape as all apps is not full bleed.
-        if (mIsDarkTheme || mIsWorkspaceDarkText || (!FeatureFlags.LAUNCHER3_GRADIENT_ALL_APPS
-                && mLauncher.getDeviceProfile().isVerticalBarLayout())) {
+        // Do not modify status bar on landscape as all apps is not full bleed.
+        if (!FeatureFlags.LAUNCHER3_GRADIENT_ALL_APPS
+                && mLauncher.getDeviceProfile().isVerticalBarLayout()) {
             return;
         }
-        // Use a light status bar (dark icons) if all apps is behind at least half of the status
-        // bar. If the status bar is already light due to wallpaper extraction, keep it that way.
-        boolean forceLight = shift <= mStatusBarHeight / 2;
-        mLauncher.activateLightSystemBars(forceLight, true /* statusBar */, true /* navBar */);
+
+        // Use a light system UI (dark icons) if all apps is behind at least half of the status bar.
+        boolean forceChange = shift <= mStatusBarHeight / 2;
+        if (forceChange) {
+            mLauncher.getSystemUiController().updateUiState(
+                    SystemUiController.UI_STATE_ALL_APPS, !mIsDarkTheme);
+        } else {
+            mLauncher.getSystemUiController().updateUiState(
+                    SystemUiController.UI_STATE_ALL_APPS, 0);
+        }
     }
 
     private void updateAllAppsBg(float progress) {
diff --git a/src/com/android/launcher3/dynamicui/WallpaperColorInfo.java b/src/com/android/launcher3/dynamicui/WallpaperColorInfo.java
index 856a26c..512e89a 100644
--- a/src/com/android/launcher3/dynamicui/WallpaperColorInfo.java
+++ b/src/com/android/launcher3/dynamicui/WallpaperColorInfo.java
@@ -61,7 +61,7 @@
 
     @Override
     public void onColorsChanged(WallpaperColorsCompat colors, int which) {
-        if (which == FLAG_SYSTEM) {
+        if ((which & FLAG_SYSTEM) != 0) {
             boolean wasDarkTheme = mIsDark;
             boolean didSupportDarkText = mSupportsDarkText;
             update(colors);
diff --git a/src/com/android/launcher3/util/SystemUiController.java b/src/com/android/launcher3/util/SystemUiController.java
new file mode 100644
index 0000000..6b5b095
--- /dev/null
+++ b/src/com/android/launcher3/util/SystemUiController.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.util;
+
+import android.view.View;
+import android.view.Window;
+
+import com.android.launcher3.Utilities;
+
+/**
+ * Utility class to manage various window flags to control system UI.
+ */
+public class SystemUiController {
+
+    // Various UI states in increasing order of priority
+    public static final int UI_STATE_BASE_WINDOW = 0;
+    public static final int UI_STATE_ALL_APPS = 1;
+    public static final int UI_STATE_WIDGET_BOTTOM_SHEET = 2;
+
+    public static final int FLAG_LIGHT_NAV = 1 << 0;
+    public static final int FLAG_DARK_NAV = 1 << 1;
+    public static final int FLAG_LIGHT_STATUS = 1 << 2;
+    public static final int FLAG_DARK_STATUS = 1 << 3;
+
+    private final Window mWindow;
+    private final int[] mStates = new int[3];
+
+    public SystemUiController(Window window) {
+        mWindow = window;
+    }
+
+    public void updateUiState(int uiState, boolean isLight) {
+        updateUiState(uiState, isLight
+                ? (FLAG_LIGHT_NAV | FLAG_LIGHT_STATUS) : (FLAG_DARK_NAV | FLAG_DARK_STATUS));
+    }
+
+    public void updateUiState(int uiState, int flags) {
+        if (mStates[uiState] == flags) {
+            return;
+        }
+        mStates[uiState] = flags;
+
+        int oldFlags = mWindow.getDecorView().getSystemUiVisibility();
+        // Apply the state flags in priority order
+        int newFlags = oldFlags;
+        for (int stateFlag : mStates) {
+            if (Utilities.isAtLeastO()) {
+                if ((stateFlag & FLAG_LIGHT_NAV) != 0) {
+                    newFlags |= View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR;
+                } else if ((stateFlag & FLAG_DARK_NAV) != 0) {
+                    newFlags &= ~(View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR);
+                }
+            }
+
+            if ((stateFlag & FLAG_LIGHT_STATUS) != 0) {
+                newFlags |= View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR;
+            } else if ((stateFlag & FLAG_DARK_STATUS) != 0) {
+                newFlags &= ~(View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR);
+            }
+        }
+        if (newFlags != oldFlags) {
+            mWindow.getDecorView().setSystemUiVisibility(newFlags);
+        }
+    }
+}
diff --git a/src/com/android/launcher3/widget/WidgetsBottomSheet.java b/src/com/android/launcher3/widget/WidgetsBottomSheet.java
index 5fe00c2..cea58b9 100644
--- a/src/com/android/launcher3/widget/WidgetsBottomSheet.java
+++ b/src/com/android/launcher3/widget/WidgetsBottomSheet.java
@@ -48,6 +48,7 @@
 import com.android.launcher3.model.WidgetItem;
 import com.android.launcher3.userevent.nano.LauncherLogProto;
 import com.android.launcher3.util.PackageUserKey;
+import com.android.launcher3.util.SystemUiController;
 import com.android.launcher3.util.TouchController;
 
 import java.util.List;
@@ -69,7 +70,6 @@
     private Interpolator mFastOutSlowInInterpolator;
     private VerticalPullDetector.ScrollInterpolator mScrollInterpolator;
     private Rect mInsets;
-    private boolean mWasNavBarLight;
     private VerticalPullDetector mVerticalPullDetector;
 
     public WidgetsBottomSheet(Context context, AttributeSet attrs) {
@@ -103,8 +103,6 @@
 
         onWidgetsBound();
 
-        mWasNavBarLight = (mLauncher.getWindow().getDecorView().getSystemUiVisibility()
-                & View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR) != 0;
         mLauncher.getDragLayer().addView(this);
         measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED);
         setTranslationY(mTranslationYClosed);
@@ -180,7 +178,8 @@
             return;
         }
         mIsOpen = true;
-        setLightNavBar(true);
+        mLauncher.getSystemUiController().updateUiState(
+                SystemUiController.UI_STATE_WIDGET_BOTTOM_SHEET, SystemUiController.FLAG_LIGHT_NAV);
         if (animate) {
             mOpenCloseAnimator.setValues(new PropertyListBuilder()
                     .translationY(mTranslationYOpen).build());
@@ -211,7 +210,8 @@
                     mIsOpen = false;
                     mVerticalPullDetector.finishedScrolling();
                     ((ViewGroup) getParent()).removeView(WidgetsBottomSheet.this);
-                    setLightNavBar(mWasNavBarLight);
+                    mLauncher.getSystemUiController().updateUiState(
+                            SystemUiController.UI_STATE_WIDGET_BOTTOM_SHEET, 0);
                 }
             });
             mOpenCloseAnimator.setInterpolator(mVerticalPullDetector.isIdleState()
@@ -219,15 +219,12 @@
             mOpenCloseAnimator.start();
         } else {
             setTranslationY(mTranslationYClosed);
-            setLightNavBar(mWasNavBarLight);
+            mLauncher.getSystemUiController().updateUiState(
+                    SystemUiController.UI_STATE_WIDGET_BOTTOM_SHEET, 0);
             mIsOpen = false;
         }
     }
 
-    private void setLightNavBar(boolean lightNavBar) {
-        mLauncher.activateLightSystemBars(lightNavBar, false /* statusBar */, true /* navBar */);
-    }
-
     @Override
     protected boolean isOfType(@FloatingViewType int type) {
         return (type & TYPE_WIDGETS_BOTTOM_SHEET) != 0;