Revert "Fix jank when switching themes"
am: 6498f96283

Change-Id: I7e833b282939153d63fc2ffbeb8d5cb77923b62d
diff --git a/core/java/com/android/internal/colorextraction/ColorExtractor.java b/core/java/com/android/internal/colorextraction/ColorExtractor.java
index 477285e63..68cf5cd 100644
--- a/core/java/com/android/internal/colorextraction/ColorExtractor.java
+++ b/core/java/com/android/internal/colorextraction/ColorExtractor.java
@@ -29,9 +29,7 @@
 import com.android.internal.colorextraction.types.ExtractionType;
 import com.android.internal.colorextraction.types.Tonal;
 
-import java.lang.ref.WeakReference;
 import java.util.ArrayList;
-import java.util.Iterator;
 
 /**
  * Class to process wallpaper colors and generate a tonal palette based on them.
@@ -46,7 +44,7 @@
     private static final String TAG = "ColorExtractor";
 
     private final SparseArray<GradientColors[]> mGradientColors;
-    private final ArrayList<WeakReference<OnColorsChangedListener>> mOnColorsChangedListeners;
+    private final ArrayList<OnColorsChangedListener> mOnColorsChangedListeners;
     private final Context mContext;
     private final ExtractionType mExtractionType;
     private WallpaperColors mSystemColors;
@@ -169,17 +167,8 @@
     }
 
     protected void triggerColorsChanged(int which) {
-        ArrayList<WeakReference<OnColorsChangedListener>> references =
-                new ArrayList<>(mOnColorsChangedListeners);
-        final int size = references.size();
-        for (int i = 0; i < size; i++) {
-            final WeakReference<OnColorsChangedListener> weakReference = references.get(i);
-            final OnColorsChangedListener listener = weakReference.get();
-            if (listener == null) {
-                mOnColorsChangedListeners.remove(weakReference);
-            } else {
-                listener.onColorsChanged(this, which);
-            }
+        for (OnColorsChangedListener listener: mOnColorsChangedListeners) {
+            listener.onColorsChanged(this, which);
         }
     }
 
@@ -198,20 +187,11 @@
     }
 
     public void addOnColorsChangedListener(@NonNull OnColorsChangedListener listener) {
-        mOnColorsChangedListeners.add(new WeakReference<>(listener));
+        mOnColorsChangedListeners.add(listener);
     }
 
     public void removeOnColorsChangedListener(@NonNull OnColorsChangedListener listener) {
-        ArrayList<WeakReference<OnColorsChangedListener>> references =
-                new ArrayList<>(mOnColorsChangedListeners);
-        final int size = references.size();
-        for (int i = 0; i < size; i++) {
-            final WeakReference<OnColorsChangedListener> weakReference = references.get(i);
-            if (weakReference.get() == listener) {
-                mOnColorsChangedListeners.remove(weakReference);
-                break;
-            }
-        }
+        mOnColorsChangedListeners.remove(listener);
     }
 
     public static class GradientColors {
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index 47ffa5c..e322acc 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -208,7 +208,7 @@
         android:icon="@drawable/icon"
         android:process="com.android.systemui"
         android:supportsRtl="true"
-        android:theme="@style/Theme.SystemUI"
+        android:theme="@style/systemui_theme"
         android:defaultToDeviceProtectedStorage="true"
         android:directBootAware="true">
         <!-- Keep theme in sync with SystemUIApplication.onCreate().
diff --git a/packages/SystemUI/res-keyguard/layout/keyguard_password_view.xml b/packages/SystemUI/res-keyguard/layout/keyguard_password_view.xml
index 9fdb00e..b821e7e 100644
--- a/packages/SystemUI/res-keyguard/layout/keyguard_password_view.xml
+++ b/packages/SystemUI/res-keyguard/layout/keyguard_password_view.xml
@@ -43,7 +43,7 @@
          android:layout_height="wrap_content"
          android:layout_width="280dp"
          android:layout_gravity="center_horizontal"
-         android:theme="?attr/passwordStyle"
+         android:theme="@style/PasswordTheme"
          >
 
          <EditText android:id="@+id/passwordEntry"
diff --git a/packages/SystemUI/res-keyguard/values/attrs.xml b/packages/SystemUI/res-keyguard/values/attrs.xml
index e2ce210..802bd30 100644
--- a/packages/SystemUI/res-keyguard/values/attrs.xml
+++ b/packages/SystemUI/res-keyguard/values/attrs.xml
@@ -41,6 +41,4 @@
     <declare-styleable name="CarrierText">
         <attr name="allCaps" format="boolean" />
     </declare-styleable>
-
-    <attr name="passwordStyle" format="reference" />
 </resources>
diff --git a/packages/SystemUI/res-keyguard/values/styles.xml b/packages/SystemUI/res-keyguard/values/styles.xml
index c6f9423..ea867ee 100644
--- a/packages/SystemUI/res-keyguard/values/styles.xml
+++ b/packages/SystemUI/res-keyguard/values/styles.xml
@@ -60,13 +60,7 @@
         <item name="android:layout_gravity">center_horizontal|bottom</item>
     </style>
 
-    <style name="PasswordTheme" parent="Theme.SystemUI">
-        <item name="android:textColor">?attr/wallpaperTextColor</item>
-        <item name="android:colorControlNormal">?attr/wallpaperTextColor</item>
-        <item name="android:colorControlActivated">?attr/wallpaperTextColor</item>
-    </style>
-
-    <style name="PasswordTheme.Light" parent="Theme.SystemUI.Light">
+    <style name="PasswordTheme" parent="systemui_theme">
         <item name="android:textColor">?attr/wallpaperTextColor</item>
         <item name="android:colorControlNormal">?attr/wallpaperTextColor</item>
         <item name="android:colorControlActivated">?attr/wallpaperTextColor</item>
diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index 27e067a..daed847 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -16,7 +16,7 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android">
 
-    <style name="RecentsTheme" parent="@android:style/Theme.Material">
+    <style name="RecentsTheme" parent="RecentsBase">
         <!-- NoTitle -->
         <item name="android:windowNoTitle">true</item>
         <!-- Misc -->
@@ -27,6 +27,13 @@
         <item name="android:ambientShadowAlpha">0.35</item>
     </style>
 
+    <!-- OverlayManager might replace this style entirely, use RecentsTheme to set a property
+    that should exist in both light and dark versions of Recents -->
+    <style name="RecentsBase" parent="@android:style/Theme.Material">
+        <item name="android:textColorPrimaryInverse">@*android:color/primary_text_material_dark</item>
+        <item name="android:textColorSecondaryInverse">@*android:color/secondary_text_material_dark</item>
+    </style>
+
     <!-- Recents theme -->
     <style name="RecentsTheme.Wallpaper">
         <item name="android:windowBackground">@*android:color/transparent</item>
@@ -34,13 +41,8 @@
         <item name="android:windowShowWallpaper">true</item>
         <item name="android:windowDisablePreview">true</item>
         <item name="clearAllStyle">@style/ClearAllButtonDefaultMargins</item>
-        <item name="wallpaperTextColor">@*android:color/primary_text_material_dark</item>
-        <item name="wallpaperTextColorSecondary">@*android:color/secondary_text_material_dark</item>
-    </style>
-
-    <style name="RecentsTheme.Wallpaper.Light">
-        <item name="wallpaperTextColor">@*android:color/primary_text_material_light</item>
-        <item name="wallpaperTextColorSecondary">@*android:color/secondary_text_material_light</item>
+        <item name="wallpaperTextColor">?android:attr/textColorPrimaryInverse</item>
+        <item name="wallpaperTextColorSecondary">?android:attr/textColorSecondaryInverse</item>
     </style>
 
     <style name="ClearAllButtonDefaultMargins">
@@ -298,27 +300,22 @@
     <style name="Animation.StatusBar">
     </style>
 
-    <style name="Theme.SystemUI" parent="@*android:style/Theme.DeviceDefault.QuickSettings">
+    <!-- Overlay manager may replace this theme -->
+    <style name="systemui_base" parent="@*android:style/Theme.DeviceDefault.QuickSettings" />
+
+    <style name="systemui_theme" parent="systemui_base">
         <item name="lightIconTheme">@style/DualToneLightTheme</item>
         <item name="darkIconTheme">@style/DualToneDarkTheme</item>
-        <item name="wallpaperTextColor">@*android:color/primary_text_material_dark</item>
-        <item name="wallpaperTextColorSecondary">@*android:color/secondary_text_material_dark</item>
-        <item name="android:colorControlHighlight">@*android:color/primary_text_material_dark</item>
+        <item name="wallpaperTextColor">?android:attr/textColorPrimaryInverse</item>
+        <item name="wallpaperTextColorSecondary">?android:attr/textColorSecondaryInverse</item>
+        <item name="android:colorControlHighlight">?android:attr/textColorSecondaryInverse</item>
         <item name="*android:lockPatternStyle">@style/LockPatternStyle</item>
-        <item name="passwordStyle">@style/PasswordTheme</item>
-    </style>
-
-    <style name="Theme.SystemUI.Light" parent="@*android:style/Theme.DeviceDefault.QuickSettings">
-        <item name="wallpaperTextColor">@*android:color/primary_text_material_light</item>
-        <item name="wallpaperTextColorSecondary">@*android:color/secondary_text_material_light</item>
-        <item name="android:colorControlHighlight">@*android:color/primary_text_material_light</item>
-        <item name="passwordStyle">@style/PasswordTheme.Light</item>
     </style>
 
     <style name="LockPatternStyle">
-        <item name="*android:regularColor">?attr/wallpaperTextColor</item>
-        <item name="*android:successColor">?attr/wallpaperTextColor</item>
-        <item name="*android:errorColor">?attr/colorError</item>
+        <item name="*android:regularColor">?android:attr/textColorPrimaryInverse</item>
+        <item name="*android:successColor">?android:attr/textColorPrimaryInverse</item>
+        <item name="*android:errorColor">?android:attr/colorError</item>
     </style>
 
     <!-- Overlay manager may replace this theme -->
diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java b/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
index 9f2dcd9..fe6eb4b 100644
--- a/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
+++ b/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
@@ -116,7 +116,7 @@
         // Set the application theme that is inherited by all services. Note that setting the
         // application theme in the manifest does only work for activities. Keep this in sync with
         // the theme set there.
-        setTheme(R.style.Theme_SystemUI);
+        setTheme(R.style.systemui_theme);
 
         SystemUIFactory.createFromConfig(this);
 
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
index c0550b5..f2ea6a6 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
@@ -20,11 +20,11 @@
 import android.app.ActivityManager;
 import android.app.ActivityOptions;
 import android.app.TaskStackBuilder;
-import android.app.WallpaperManager;
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
+import android.content.pm.ActivityInfo;
 import android.content.res.Configuration;
 import android.net.Uri;
 import android.os.Bundle;
@@ -41,15 +41,12 @@
 import android.view.WindowManager;
 import android.view.WindowManager.LayoutParams;
 
-import com.android.internal.colorextraction.ColorExtractor;
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.keyguard.LatencyTracker;
 import com.android.systemui.DejankUtils;
-import com.android.systemui.Dependency;
 import com.android.systemui.Interpolators;
 import com.android.systemui.R;
-import com.android.systemui.colorextraction.SysuiColorExtractor;
 import com.android.systemui.recents.events.EventBus;
 import com.android.systemui.recents.events.activity.CancelEnterRecentsWindowAnimationEvent;
 import com.android.systemui.recents.events.activity.ConfigurationChangedEvent;
@@ -103,8 +100,7 @@
 /**
  * The main Recents activity that is started from RecentsComponent.
  */
-public class RecentsActivity extends Activity implements ViewTreeObserver.OnPreDrawListener,
-        ColorExtractor.OnColorsChangedListener {
+public class RecentsActivity extends Activity implements ViewTreeObserver.OnPreDrawListener {
 
     private final static String TAG = "RecentsActivity";
     private final static boolean DEBUG = false;
@@ -133,10 +129,6 @@
     private DozeTrigger mIterateTrigger;
     private final UserInteractionEvent mUserInteractionEvent = new UserInteractionEvent();
 
-    // Theme and colors
-    private SysuiColorExtractor mColorExtractor;
-    private boolean mUsingDarkText;
-
     /**
      * A common Runnable to finish Recents by launching Home with an animation depending on the
      * last activity launch state. Generally we always launch home when we exit Recents rather than
@@ -337,14 +329,6 @@
         mPackageMonitor = new RecentsPackageMonitor();
         mPackageMonitor.register(this);
 
-        // Select theme based on wallpaper colors
-        mColorExtractor = Dependency.get(SysuiColorExtractor.class);
-        mColorExtractor.addOnColorsChangedListener(this);
-        mUsingDarkText = mColorExtractor.getColors(ColorExtractor.TYPE_DARK,
-                WallpaperManager.FLAG_SYSTEM, true).supportsDarkText();
-        setTheme(mUsingDarkText ? R.style.RecentsTheme_Wallpaper_Light
-                : R.style.RecentsTheme_Wallpaper);
-
         // Set the Recents layout
         setContentView(R.layout.recents);
         takeKeyEvents(true);
@@ -391,37 +375,13 @@
         EventBus.getDefault().send(new RecentsVisibilityChangedEvent(this, true));
         MetricsLogger.visible(this, MetricsEvent.OVERVIEW_ACTIVITY);
 
-        // Getting system scrim colors ignoring wallpaper visibility since it should never be grey.
-        ColorExtractor.GradientColors systemColors = mColorExtractor.getColors(
-                ColorExtractor.TYPE_DARK, WallpaperManager.FLAG_SYSTEM, true);
-        // We don't want to interpolate colors because we're defining the initial state.
-        // Gradient should be set/ready when you open "Recents".
-        mRecentsView.setScrimColors(systemColors, false);
-
+        // Make sure we have the right gradient and we're listening for update events
+        mRecentsView.onStart();
         // Notify of the next draw
         mRecentsView.getViewTreeObserver().addOnPreDrawListener(mRecentsDrawnEventListener);
     }
 
     @Override
-    public void onColorsChanged(ColorExtractor colorExtractor, int which) {
-        if ((which & WallpaperManager.FLAG_SYSTEM) != 0) {
-            // Recents doesn't care about the wallpaper being visible or not, it always
-            // wants to scrim with wallpaper colors
-            ColorExtractor.GradientColors colors = mColorExtractor.getColors(
-                    WallpaperManager.FLAG_SYSTEM,
-                    ColorExtractor.TYPE_DARK, true /* ignoreVis */);
-            boolean darkText = colors.supportsDarkText();
-            if (darkText != mUsingDarkText) {
-                mUsingDarkText = darkText;
-                setTheme(mUsingDarkText ? R.style.RecentsTheme_Wallpaper_Light
-                        : R.style.RecentsTheme_Wallpaper);
-                mRecentsView.reevaluateStyles();
-            }
-            mRecentsView.setScrimColors(colors, true /* animated */);
-        }
-    }
-
-    @Override
     protected void onNewIntent(Intent intent) {
         super.onNewIntent(intent);
 
@@ -523,7 +483,12 @@
                 mLastConfig.orientation != newDeviceConfiguration.orientation,
                 mLastConfig.densityDpi != newDeviceConfiguration.densityDpi, numStackTasks > 0));
 
-        mLastConfig.updateFrom(newDeviceConfiguration);
+        int configDiff = mLastConfig.updateFrom(newDeviceConfiguration);
+
+        // Recreate activity if an overlay was enabled/disabled
+        if ((configDiff & ActivityInfo.CONFIG_ASSETS_PATHS) != 0) {
+            recreate();
+        }
     }
 
     @Override
@@ -543,6 +508,9 @@
         MetricsLogger.hidden(this, MetricsEvent.OVERVIEW_ACTIVITY);
         Recents.getTaskLoader().getHighResThumbnailLoader().setVisible(false);
 
+        // We don't need to update the gradient when we're not visible
+        mRecentsView.onStop();
+
         if (!isChangingConfigurations()) {
             // Workaround for b/22542869, if the RecentsActivity is started again, but without going
             // through SystemUI, we need to reset the config launch flags to ensure that we do not
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
index 8e09481..fd37b17 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
@@ -21,12 +21,13 @@
 import android.animation.Animator;
 import android.animation.ObjectAnimator;
 import android.app.ActivityOptions.OnAnimationStartedListener;
+import android.app.WallpaperColors;
+import android.app.WallpaperManager;
 import android.content.Context;
-import android.content.res.ColorStateList;
 import android.graphics.Canvas;
 import android.graphics.Color;
-import android.graphics.PointF;
 import android.graphics.Rect;
+import android.graphics.drawable.ColorDrawable;
 import android.graphics.drawable.Drawable;
 import android.util.ArraySet;
 import android.util.AttributeSet;
@@ -42,12 +43,12 @@
 import android.widget.TextView;
 
 import com.android.internal.colorextraction.ColorExtractor;
-import com.android.internal.colorextraction.drawable.GradientDrawable;
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
-import com.android.settingslib.Utils;
+import com.android.systemui.Dependency;
 import com.android.systemui.Interpolators;
 import com.android.systemui.R;
+import com.android.systemui.colorextraction.SysuiColorExtractor;
 import com.android.systemui.recents.Recents;
 import com.android.systemui.recents.RecentsActivity;
 import com.android.systemui.recents.RecentsActivityLaunchState;
@@ -82,6 +83,8 @@
 import com.android.systemui.statusbar.FlingAnimationUtils;
 import com.android.systemui.statusbar.phone.ScrimController;
 
+import com.android.internal.colorextraction.drawable.GradientDrawable;
+
 import java.io.PrintWriter;
 import java.util.ArrayList;
 import java.util.List;
@@ -90,7 +93,7 @@
  * This view is the the top level layout that contains TaskStacks (which are laid out according
  * to their SpaceNode bounds.
  */
-public class RecentsView extends FrameLayout {
+public class RecentsView extends FrameLayout implements ColorExtractor.OnColorsChangedListener {
 
     private static final String TAG = "RecentsView";
 
@@ -104,9 +107,6 @@
     private TaskStackView mTaskStackView;
     private TextView mStackActionButton;
     private TextView mEmptyView;
-    private final float mStackButtonShadowRadius;
-    private final PointF mStackButtonShadowDistance;
-    private final int mStackButtonShadowColor;
 
     private boolean mAwaitingFirstLayout = true;
     private boolean mLastTaskLaunchedWasFreeform;
@@ -117,6 +117,7 @@
 
     private float mBusynessFactor;
     private GradientDrawable mBackgroundScrim;
+    private final SysuiColorExtractor mColorExtractor;
     private Animator mBackgroundScrimAnimator;
 
     private RecentsTransitionHelper mTransitionHelper;
@@ -147,51 +148,29 @@
         mFlingAnimationUtils = new FlingAnimationUtils(context, 0.3f);
         mBackgroundScrim = new GradientDrawable(context);
         mBackgroundScrim.setCallback(this);
-
-        boolean usingDarkText = Color.luminance(
-                Utils.getColorAttr(mContext, R.attr.wallpaperTextColor)) < 0.5f;
+        mColorExtractor = Dependency.get(SysuiColorExtractor.class);
 
         LayoutInflater inflater = LayoutInflater.from(context);
+
         mEmptyView = (TextView) inflater.inflate(R.layout.recents_empty, this, false);
         addView(mEmptyView);
 
+        boolean usingDarkText =
+                Color.luminance(mEmptyView.getTextColors().getDefaultColor()) < 0.5f;
         if (RecentsDebugFlags.Static.EnableStackActionButton) {
-            if (mStackActionButton != null) {
-                removeView(mStackActionButton);
-            }
             mStackActionButton = (TextView) inflater.inflate(R.layout.recents_stack_action_button,
                     this, false);
-            mStackActionButton.setOnClickListener(
-                    v -> EventBus.getDefault().send(new DismissAllTaskViewsEvent()));
-
-            mStackButtonShadowRadius = mStackActionButton.getShadowRadius();
-            mStackButtonShadowDistance = new PointF(mStackActionButton.getShadowDx(),
-                    mStackActionButton.getShadowDy());
-            mStackButtonShadowColor = mStackActionButton.getShadowColor();
-            addView(mStackActionButton);
-        }
-
-        reevaluateStyles();
-    }
-
-    public void reevaluateStyles() {
-        int textColor = Utils.getColorAttr(mContext, R.attr.wallpaperTextColor);
-        boolean usingDarkText = Color.luminance(textColor) < 0.5f;
-
-        mEmptyView.setTextColor(textColor);
-        mEmptyView.setCompoundDrawableTintList(new ColorStateList(new int[][]{
-                {android.R.attr.state_enabled}}, new int[]{textColor}));
-
-        if (mStackActionButton != null) {
-            mStackActionButton.setTextColor(textColor);
-            // Enable/disable shadow if text color is already dark.
+            mStackActionButton.setOnClickListener(new View.OnClickListener() {
+                @Override
+                public void onClick(View v) {
+                    EventBus.getDefault().send(new DismissAllTaskViewsEvent());
+                }
+            });
+            // Disable black shadow if text color is already dark.
             if (usingDarkText) {
                 mStackActionButton.setShadowLayer(0, 0, 0, 0);
-            } else {
-                mStackActionButton.setShadowLayer(mStackButtonShadowRadius,
-                        mStackButtonShadowDistance.x, mStackButtonShadowDistance.y,
-                        mStackButtonShadowColor);
             }
+            addView(mStackActionButton);
         }
 
         // Let's also require dark status and nav bars if the text is dark
@@ -390,16 +369,6 @@
         }
     }
 
-    /**
-     * Set the color of the scrim.
-     *
-     * @param scrimColors Colors to use.
-     * @param animated Interpolate colors if true.
-     */
-    public void setScrimColors(ColorExtractor.GradientColors scrimColors, boolean animated) {
-        mBackgroundScrim.setColors(scrimColors, animated);
-    }
-
     @Override
     protected void onAttachedToWindow() {
         EventBus.getDefault().register(this, RecentsActivity.EVENT_BUS_PRIORITY + 1);
@@ -919,4 +888,29 @@
             mTaskStackView.dump(innerPrefix, writer);
         }
     }
+
+    @Override
+    public void onColorsChanged(ColorExtractor colorExtractor, int which) {
+        if ((which & WallpaperManager.FLAG_SYSTEM) != 0) {
+            // Recents doesn't care about the wallpaper being visible or not, it always
+            // wants to scrim with wallpaper colors
+            mBackgroundScrim.setColors(
+                    mColorExtractor.getColors(WallpaperManager.FLAG_SYSTEM,
+                            ColorExtractor.TYPE_DARK, true));
+        }
+    }
+
+    public void onStart() {
+        mColorExtractor.addOnColorsChangedListener(this);
+        // Getting system scrim colors ignoring wallpaper visibility since it should never be grey.
+        ColorExtractor.GradientColors systemColors = mColorExtractor.getColors(
+                ColorExtractor.TYPE_DARK, WallpaperManager.FLAG_SYSTEM, true);
+        // We don't want to interpolate colors because we're defining the initial state.
+        // Gradient should be set/ready when you open "Recents".
+        mBackgroundScrim.setColors(systemColors, false);
+    }
+
+    public void onStop() {
+        mColorExtractor.removeOnColorsChangedListener(this);
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/DismissView.java b/packages/SystemUI/src/com/android/systemui/statusbar/DismissView.java
index d7c6443..5436664 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/DismissView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/DismissView.java
@@ -16,7 +16,6 @@
 
 package com.android.systemui.statusbar;
 
-import android.annotation.ColorInt;
 import android.content.Context;
 import android.content.res.Configuration;
 import android.util.AttributeSet;
@@ -47,10 +46,6 @@
         mDismissButton = (DismissViewButton) findContentView();
     }
 
-    public void setTextColor(@ColorInt int color) {
-        mDismissButton.setTextColor(color);
-    }
-
     public void setOnButtonClickListener(OnClickListener listener) {
         mContent.setOnClickListener(listener);
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/EmptyShadeView.java b/packages/SystemUI/src/com/android/systemui/statusbar/EmptyShadeView.java
index 58adde2..92b0890 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/EmptyShadeView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/EmptyShadeView.java
@@ -16,7 +16,6 @@
 
 package com.android.systemui.statusbar;
 
-import android.annotation.ColorInt;
 import android.content.Context;
 import android.content.res.Configuration;
 import android.util.AttributeSet;
@@ -46,10 +45,6 @@
         return findViewById(R.id.no_notifications);
     }
 
-    public void setTextColor(@ColorInt int color) {
-        mEmptyText.setTextColor(color);
-    }
-
     @Override
     protected void onFinishInflate() {
         super.onFinishInflate();
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 bc37d83..75a2768 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -978,6 +978,9 @@
         Dependency.get(ActivityStarterDelegate.class).setActivityStarterImpl(this);
 
         Dependency.get(ConfigurationController.class).addCallback(this);
+
+        // Make sure that we're using the correct theme
+        onOverlayChanged();
     }
 
     protected void createIconController() {
@@ -990,7 +993,6 @@
         final Context context = mContext;
         updateDisplaySize(); // populates mDisplayMetrics
         updateResources();
-        updateTheme();
 
         inflateStatusBarWindow(context);
         mStatusBarWindow.setService(this);
@@ -1198,6 +1200,7 @@
             });
         }
 
+
         PowerManager pm = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
         if (!pm.isScreenOn()) {
             mBroadcastReceiver.onReceive(mContext, new Intent(Intent.ACTION_SCREEN_OFF));
@@ -1302,14 +1305,14 @@
         reevaluateStyles();
     }
 
-    private void reinflateViews() {
+    public void onOverlayChanged() {
         reevaluateStyles();
 
         // Clock and bottom icons
         mNotificationPanel.onOverlayChanged();
-        // The status bar on the keyguard is a special layout.
-        mKeyguardStatusBar.onOverlayChanged();
+
         // Recreate Indication controller because internal references changed
+        // TODO: unregister callbacks before recreating
         mKeyguardIndicationController =
                 SystemUIFactory.getInstance().createKeyguardIndicationController(mContext,
                         mStatusBarWindow.findViewById(R.id.keyguard_indication_area),
@@ -2854,6 +2857,17 @@
         updateTheme();
     }
 
+    public boolean isUsingDarkText() {
+        OverlayInfo themeInfo = null;
+        try {
+            themeInfo = mOverlayManager.getOverlayInfo("com.android.systemui.theme.lightwallpaper",
+                    mCurrentUserId);
+        } catch (RemoteException e) {
+            e.printStackTrace();
+        }
+        return themeInfo != null && themeInfo.isEnabled();
+    }
+
     public boolean isUsingDarkTheme() {
         OverlayInfo themeInfo = null;
         try {
@@ -4552,13 +4566,24 @@
      * Switches theme from light to dark and vice-versa.
      */
     private void updateTheme() {
-        final boolean inflated = mStackScroller != null;
 
-        // The system wallpaper defines if QS should be light or dark.
+        int which;
+        if (mState == StatusBarState.KEYGUARD || mState == StatusBarState.SHADE_LOCKED) {
+            which = WallpaperManager.FLAG_LOCK;
+        } else {
+            which = WallpaperManager.FLAG_SYSTEM;
+        }
+
+        // Gradient defines if text color should be light or dark.
+        final boolean useDarkText = mColorExtractor.getColors(which, true /* ignoreVisibility */)
+                .supportsDarkText();
+        // And wallpaper defines if QS should be light or dark.
         WallpaperColors systemColors = mColorExtractor
                 .getWallpaperColors(WallpaperManager.FLAG_SYSTEM);
         final boolean useDarkTheme = systemColors != null
                 && (systemColors.getColorHints() & WallpaperColors.HINT_SUPPORTS_DARK_THEME) != 0;
+
+        // Enable/disable dark UI.
         if (isUsingDarkTheme() != useDarkTheme) {
             try {
                 mOverlayManager.setEnabled("com.android.systemui.theme.dark",
@@ -4567,33 +4592,18 @@
                 Log.w(TAG, "Can't change theme", e);
             }
         }
-
-        // Lock wallpaper defines the color of the majority of the views, hence we'll use it
-        // to set our default theme.
-        final boolean lockDarkText = mColorExtractor.getColors(WallpaperManager.FLAG_LOCK, true
-                /* ignoreVisibility */).supportsDarkText();
-        final int themeResId = lockDarkText ? R.style.Theme_SystemUI_Light : R.style.Theme_SystemUI;
-        if (mContext.getThemeResId() != themeResId) {
-            mContext.setTheme(themeResId);
-            if (inflated) {
-                reinflateViews();
+        // Enable/disable dark text overlay.
+        if (isUsingDarkText() != useDarkText) {
+            try {
+                mOverlayManager.setEnabled("com.android.systemui.theme.lightwallpaper",
+                        useDarkText, mCurrentUserId);
+            } catch (RemoteException e) {
+                Log.w(TAG, "Can't change theme", e);
             }
         }
 
-        if (inflated) {
-            int which;
-            if (mState == StatusBarState.KEYGUARD || mState == StatusBarState.SHADE_LOCKED) {
-                which = WallpaperManager.FLAG_LOCK;
-            } else {
-                which = WallpaperManager.FLAG_SYSTEM;
-            }
-            final boolean useDarkText = mColorExtractor.getColors(which,
-                    true /* ignoreVisibility */).supportsDarkText();
-            mStackScroller.updateDecorViews(useDarkText);
-
-            // Make sure we have the correct navbar/statusbar colors.
-            mStatusBarWindowManager.setKeyguardDark(useDarkText);
-        }
+        // Make sure we have the correct navbar/statusbar colors.
+        mStatusBarWindowManager.setKeyguardDark(useDarkText);
     }
 
     private void updateDozingState() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
index 4bbe895..42cebe2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
@@ -23,7 +23,6 @@
 import android.animation.TimeAnimator;
 import android.animation.ValueAnimator;
 import android.animation.ValueAnimator.AnimatorUpdateListener;
-import android.annotation.ColorInt;
 import android.annotation.FloatRange;
 import android.annotation.Nullable;
 import android.content.Context;
@@ -45,7 +44,6 @@
 import android.util.Log;
 import android.util.Pair;
 import android.util.Property;
-import android.view.ContextThemeWrapper;
 import android.view.InputDevice;
 import android.view.MotionEvent;
 import android.view.VelocityTracker;
@@ -63,7 +61,6 @@
 
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
-import com.android.settingslib.Utils;
 import com.android.systemui.ExpandHelper;
 import com.android.systemui.Interpolators;
 import com.android.systemui.R;
@@ -366,7 +363,6 @@
                     return object.getBackgroundFadeAmount();
                 }
             };
-    private boolean mUsingLightTheme;
     private boolean mQsExpanded;
     private boolean mForwardScrollable;
     private boolean mBackwardScrollable;
@@ -3657,23 +3653,6 @@
         mTmpSortedChildren.clear();
     }
 
-    /**
-     * Update colors of "dismiss" and "empty shade" views.
-     *
-     * @param lightTheme True if light theme should be used.
-     */
-    public void updateDecorViews(boolean lightTheme) {
-        if (lightTheme == mUsingLightTheme) {
-            return;
-        }
-        mUsingLightTheme = lightTheme;
-        Context context = new ContextThemeWrapper(mContext,
-                lightTheme ? R.style.Theme_SystemUI_Light : R.style.Theme_SystemUI);
-        final int textColor = Utils.getColorAttr(context, R.attr.wallpaperTextColor);
-        mDismissView.setTextColor(textColor);
-        mEmptyShadeView.setTextColor(textColor);
-    }
-
     public void goToFullShade(long delay) {
         if (mDismissView != null) {
             mDismissView.setInvisible();
diff --git a/packages/overlays/SysuiLightWallpaperThemeOverlay/Android.mk b/packages/overlays/SysuiLightWallpaperThemeOverlay/Android.mk
new file mode 100644
index 0000000..4782a16
--- /dev/null
+++ b/packages/overlays/SysuiLightWallpaperThemeOverlay/Android.mk
@@ -0,0 +1,13 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_RRO_THEME := SysuiLightWallpaperTheme
+LOCAL_CERTIFICATE := platform
+
+LOCAL_SRC_FILES := $(call all-subdir-java-files)
+
+LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
+
+LOCAL_PACKAGE_NAME := SysuiLightWallpaperThemeOverlay
+
+include $(BUILD_RRO_PACKAGE)
diff --git a/packages/overlays/SysuiLightWallpaperThemeOverlay/AndroidManifest.xml b/packages/overlays/SysuiLightWallpaperThemeOverlay/AndroidManifest.xml
new file mode 100644
index 0000000..0a8749c
--- /dev/null
+++ b/packages/overlays/SysuiLightWallpaperThemeOverlay/AndroidManifest.xml
@@ -0,0 +1,8 @@
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.android.systemui.theme.lightwallpaper"
+    android:versionCode="1"
+    android:versionName="1.0">
+    <overlay android:targetPackage="com.android.systemui" android:priority="2"/>
+
+    <application android:label="@string/sysui_overlay_light" android:hasCode="false"/>
+</manifest>
diff --git a/packages/overlays/SysuiLightWallpaperThemeOverlay/res/values/strings.xml b/packages/overlays/SysuiLightWallpaperThemeOverlay/res/values/strings.xml
new file mode 100644
index 0000000..acc3d16
--- /dev/null
+++ b/packages/overlays/SysuiLightWallpaperThemeOverlay/res/values/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * 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.
+ */
+-->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+
+    <string name="sysui_overlay_light">Light</string>
+
+</resources>
+
diff --git a/packages/overlays/SysuiLightWallpaperThemeOverlay/res/values/styles.xml b/packages/overlays/SysuiLightWallpaperThemeOverlay/res/values/styles.xml
new file mode 100644
index 0000000..53912b5
--- /dev/null
+++ b/packages/overlays/SysuiLightWallpaperThemeOverlay/res/values/styles.xml
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+    <style name="systemui_base" parent="@*android:style/Theme.DeviceDefault.QuickSettings">
+        <item name="android:textColorPrimaryInverse">@*android:color/primary_text_material_light</item>
+        <item name="android:textColorSecondaryInverse">@*android:color/secondary_text_material_light</item>
+    </style>
+
+    <style name="RecentsBase" parent="@android:style/Theme.Material">
+        <item name="android:textColorPrimaryInverse">@*android:color/primary_text_material_light</item>
+        <item name="android:textColorSecondaryInverse">@*android:color/secondary_text_material_light</item>
+    </style>
+</resources>
\ No newline at end of file
diff --git a/tests/Internal/src/com/android/internal/colorextraction/ColorExtractorTest.java b/tests/Internal/src/com/android/internal/colorextraction/ColorExtractorTest.java
index cb6a83d..0060901 100644
--- a/tests/Internal/src/com/android/internal/colorextraction/ColorExtractorTest.java
+++ b/tests/Internal/src/com/android/internal/colorextraction/ColorExtractorTest.java
@@ -16,14 +16,12 @@
 package com.android.internal.colorextraction;
 
 import static org.junit.Assert.assertEquals;
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.eq;
+import static org.junit.Assert.assertFalse;
+import static org.mockito.Mockito.any;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyNoMoreInteractions;
 
-import android.app.WallpaperColors;
 import android.app.WallpaperManager;
 import android.content.Context;
 import android.graphics.Color;
@@ -31,6 +29,7 @@
 import android.support.test.filters.SmallTest;
 import android.support.test.runner.AndroidJUnit4;
 
+import com.android.internal.colorextraction.ColorExtractor;
 import com.android.internal.colorextraction.ColorExtractor.GradientColors;
 import com.android.internal.colorextraction.types.ExtractionType;
 import com.android.internal.colorextraction.types.Tonal;
@@ -79,10 +78,10 @@
         ExtractionType type =
                 (inWallpaperColors, outGradientColorsNormal, outGradientColorsDark,
                         outGradientColorsExtraDark) -> {
-                    outGradientColorsNormal.set(colorsExpectedNormal);
-                    outGradientColorsDark.set(colorsExpectedDark);
-                    outGradientColorsExtraDark.set(colorsExpectedExtraDark);
-                };
+            outGradientColorsNormal.set(colorsExpectedNormal);
+            outGradientColorsDark.set(colorsExpectedDark);
+            outGradientColorsExtraDark.set(colorsExpectedExtraDark);
+        };
         ColorExtractor extractor = new ColorExtractor(mContext, type);
 
         GradientColors colors = extractor.getColors(WallpaperManager.FLAG_SYSTEM,
@@ -93,22 +92,4 @@
         colors = extractor.getColors(WallpaperManager.FLAG_SYSTEM, ColorExtractor.TYPE_EXTRA_DARK);
         assertEquals("Extracted colors not being used!", colors, colorsExpectedExtraDark);
     }
-
-    @Test
-    public void addOnColorsChangedListener_invokesListener() {
-        ColorExtractor.OnColorsChangedListener mockedListeners =
-                mock(ColorExtractor.OnColorsChangedListener.class);
-        ColorExtractor extractor = new ColorExtractor(mContext, new Tonal(mContext));
-        extractor.addOnColorsChangedListener(mockedListeners);
-
-        extractor.onColorsChanged(new WallpaperColors(Color.valueOf(Color.RED), null, null),
-                WallpaperManager.FLAG_LOCK);
-        verify(mockedListeners, times(1)).onColorsChanged(any(),
-                eq(WallpaperManager.FLAG_LOCK));
-
-        extractor.removeOnColorsChangedListener(mockedListeners);
-        extractor.onColorsChanged(new WallpaperColors(Color.valueOf(Color.RED), null, null),
-                WallpaperManager.FLAG_LOCK);
-        verifyNoMoreInteractions(mockedListeners);
-    }
 }