Merge changes from topic 'am-fbc85c75-5d3b-419b-8eda-1fbdb126a8a7' into ub-launcher3-master

* changes:
  [DO NOT MERGE] Making various icon shape options as non-translatable skipped: 1f5a264fac
  [DO NOT MERGE] Making various icon shape options as non-translatable
diff --git a/res/values-bn/config.xml b/res/values-bn/config.xml
deleted file mode 100644
index 7ee78d0..0000000
--- a/res/values-bn/config.xml
+++ /dev/null
@@ -1,12 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-  <string-array name="icon_shape_override_paths_values">
-    <item msgid="6640290598899495380"></item>
-    <item msgid="4009824731445917273">"M50,0L100,0 100,100 0,100 0,0z"</item>
-    <item msgid="1832340187106991439">"M50,0 C10,0 0,10 0,50 0,90 10,100 50,100 90,100 100,90 100,50 100,10 90,0 50,0 Z"</item>
-    <item msgid="8549745892733419075">"M50 0A50 50,0,1,1,50 100A50 50,0,1,1,50 0"</item>
-    <item msgid="7298209005825805703">"M50,0A50,50,0,0 1 100,50 L100,85 A15,15,0,0 1 85,100 L50,100 A50,50,0,0 1 50,0z"</item>
-  </string-array>
-    <!-- no translation found for icon_shape_override_paths_names:0 (4837899951986816538) -->
-</resources>
diff --git a/res/values-gu/config.xml b/res/values-gu/config.xml
deleted file mode 100644
index 7ee78d0..0000000
--- a/res/values-gu/config.xml
+++ /dev/null
@@ -1,12 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-  <string-array name="icon_shape_override_paths_values">
-    <item msgid="6640290598899495380"></item>
-    <item msgid="4009824731445917273">"M50,0L100,0 100,100 0,100 0,0z"</item>
-    <item msgid="1832340187106991439">"M50,0 C10,0 0,10 0,50 0,90 10,100 50,100 90,100 100,90 100,50 100,10 90,0 50,0 Z"</item>
-    <item msgid="8549745892733419075">"M50 0A50 50,0,1,1,50 100A50 50,0,1,1,50 0"</item>
-    <item msgid="7298209005825805703">"M50,0A50,50,0,0 1 100,50 L100,85 A15,15,0,0 1 85,100 L50,100 A50,50,0,0 1 50,0z"</item>
-  </string-array>
-    <!-- no translation found for icon_shape_override_paths_names:0 (4837899951986816538) -->
-</resources>
diff --git a/res/values-kn/config.xml b/res/values-kn/config.xml
deleted file mode 100644
index 7ee78d0..0000000
--- a/res/values-kn/config.xml
+++ /dev/null
@@ -1,12 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-  <string-array name="icon_shape_override_paths_values">
-    <item msgid="6640290598899495380"></item>
-    <item msgid="4009824731445917273">"M50,0L100,0 100,100 0,100 0,0z"</item>
-    <item msgid="1832340187106991439">"M50,0 C10,0 0,10 0,50 0,90 10,100 50,100 90,100 100,90 100,50 100,10 90,0 50,0 Z"</item>
-    <item msgid="8549745892733419075">"M50 0A50 50,0,1,1,50 100A50 50,0,1,1,50 0"</item>
-    <item msgid="7298209005825805703">"M50,0A50,50,0,0 1 100,50 L100,85 A15,15,0,0 1 85,100 L50,100 A50,50,0,0 1 50,0z"</item>
-  </string-array>
-    <!-- no translation found for icon_shape_override_paths_names:0 (4837899951986816538) -->
-</resources>
diff --git a/res/values-ml/config.xml b/res/values-ml/config.xml
deleted file mode 100644
index 7ee78d0..0000000
--- a/res/values-ml/config.xml
+++ /dev/null
@@ -1,12 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-  <string-array name="icon_shape_override_paths_values">
-    <item msgid="6640290598899495380"></item>
-    <item msgid="4009824731445917273">"M50,0L100,0 100,100 0,100 0,0z"</item>
-    <item msgid="1832340187106991439">"M50,0 C10,0 0,10 0,50 0,90 10,100 50,100 90,100 100,90 100,50 100,10 90,0 50,0 Z"</item>
-    <item msgid="8549745892733419075">"M50 0A50 50,0,1,1,50 100A50 50,0,1,1,50 0"</item>
-    <item msgid="7298209005825805703">"M50,0A50,50,0,0 1 100,50 L100,85 A15,15,0,0 1 85,100 L50,100 A50,50,0,0 1 50,0z"</item>
-  </string-array>
-    <!-- no translation found for icon_shape_override_paths_names:0 (4837899951986816538) -->
-</resources>
diff --git a/res/values-mr/config.xml b/res/values-mr/config.xml
deleted file mode 100644
index 7ee78d0..0000000
--- a/res/values-mr/config.xml
+++ /dev/null
@@ -1,12 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-  <string-array name="icon_shape_override_paths_values">
-    <item msgid="6640290598899495380"></item>
-    <item msgid="4009824731445917273">"M50,0L100,0 100,100 0,100 0,0z"</item>
-    <item msgid="1832340187106991439">"M50,0 C10,0 0,10 0,50 0,90 10,100 50,100 90,100 100,90 100,50 100,10 90,0 50,0 Z"</item>
-    <item msgid="8549745892733419075">"M50 0A50 50,0,1,1,50 100A50 50,0,1,1,50 0"</item>
-    <item msgid="7298209005825805703">"M50,0A50,50,0,0 1 100,50 L100,85 A15,15,0,0 1 85,100 L50,100 A50,50,0,0 1 50,0z"</item>
-  </string-array>
-    <!-- no translation found for icon_shape_override_paths_names:0 (4837899951986816538) -->
-</resources>
diff --git a/res/values-ne/config.xml b/res/values-ne/config.xml
deleted file mode 100644
index 7ee78d0..0000000
--- a/res/values-ne/config.xml
+++ /dev/null
@@ -1,12 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-  <string-array name="icon_shape_override_paths_values">
-    <item msgid="6640290598899495380"></item>
-    <item msgid="4009824731445917273">"M50,0L100,0 100,100 0,100 0,0z"</item>
-    <item msgid="1832340187106991439">"M50,0 C10,0 0,10 0,50 0,90 10,100 50,100 90,100 100,90 100,50 100,10 90,0 50,0 Z"</item>
-    <item msgid="8549745892733419075">"M50 0A50 50,0,1,1,50 100A50 50,0,1,1,50 0"</item>
-    <item msgid="7298209005825805703">"M50,0A50,50,0,0 1 100,50 L100,85 A15,15,0,0 1 85,100 L50,100 A50,50,0,0 1 50,0z"</item>
-  </string-array>
-    <!-- no translation found for icon_shape_override_paths_names:0 (4837899951986816538) -->
-</resources>
diff --git a/res/values-pa/config.xml b/res/values-pa/config.xml
deleted file mode 100644
index 7ee78d0..0000000
--- a/res/values-pa/config.xml
+++ /dev/null
@@ -1,12 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-  <string-array name="icon_shape_override_paths_values">
-    <item msgid="6640290598899495380"></item>
-    <item msgid="4009824731445917273">"M50,0L100,0 100,100 0,100 0,0z"</item>
-    <item msgid="1832340187106991439">"M50,0 C10,0 0,10 0,50 0,90 10,100 50,100 90,100 100,90 100,50 100,10 90,0 50,0 Z"</item>
-    <item msgid="8549745892733419075">"M50 0A50 50,0,1,1,50 100A50 50,0,1,1,50 0"</item>
-    <item msgid="7298209005825805703">"M50,0A50,50,0,0 1 100,50 L100,85 A15,15,0,0 1 85,100 L50,100 A50,50,0,0 1 50,0z"</item>
-  </string-array>
-    <!-- no translation found for icon_shape_override_paths_names:0 (4837899951986816538) -->
-</resources>
diff --git a/res/values-te/config.xml b/res/values-te/config.xml
deleted file mode 100644
index 7ee78d0..0000000
--- a/res/values-te/config.xml
+++ /dev/null
@@ -1,12 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-  <string-array name="icon_shape_override_paths_values">
-    <item msgid="6640290598899495380"></item>
-    <item msgid="4009824731445917273">"M50,0L100,0 100,100 0,100 0,0z"</item>
-    <item msgid="1832340187106991439">"M50,0 C10,0 0,10 0,50 0,90 10,100 50,100 90,100 100,90 100,50 100,10 90,0 50,0 Z"</item>
-    <item msgid="8549745892733419075">"M50 0A50 50,0,1,1,50 100A50 50,0,1,1,50 0"</item>
-    <item msgid="7298209005825805703">"M50,0A50,50,0,0 1 100,50 L100,85 A15,15,0,0 1 85,100 L50,100 A50,50,0,0 1 50,0z"</item>
-  </string-array>
-    <!-- no translation found for icon_shape_override_paths_names:0 (4837899951986816538) -->
-</resources>
diff --git a/res/values-ur/config.xml b/res/values-ur/config.xml
deleted file mode 100644
index 7ee78d0..0000000
--- a/res/values-ur/config.xml
+++ /dev/null
@@ -1,12 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-  <string-array name="icon_shape_override_paths_values">
-    <item msgid="6640290598899495380"></item>
-    <item msgid="4009824731445917273">"M50,0L100,0 100,100 0,100 0,0z"</item>
-    <item msgid="1832340187106991439">"M50,0 C10,0 0,10 0,50 0,90 10,100 50,100 90,100 100,90 100,50 100,10 90,0 50,0 Z"</item>
-    <item msgid="8549745892733419075">"M50 0A50 50,0,1,1,50 100A50 50,0,1,1,50 0"</item>
-    <item msgid="7298209005825805703">"M50,0A50,50,0,0 1 100,50 L100,85 A15,15,0,0 1 85,100 L50,100 A50,50,0,0 1 50,0z"</item>
-  </string-array>
-    <!-- no translation found for icon_shape_override_paths_names:0 (4837899951986816538) -->
-</resources>
diff --git a/res/values/config.xml b/res/values/config.xml
index 8f2590a..a467a5c 100644
--- a/res/values/config.xml
+++ b/res/values/config.xml
@@ -19,22 +19,23 @@
 
     <!-- Values for icon shape overrides. These should correspond to entries defined
      in icon_shape_override_paths_names -->
-    <string-array name="icon_shape_override_paths_values">
+    <string-array translatable="false" name="icon_shape_override_paths_values">
         <item></item>
-        <item translatable="false">M50,0L100,0 100,100 0,100 0,0z</item>
-        <item translatable="false">M50,0 C10,0 0,10 0,50 0,90 10,100 50,100 90,100 100,90 100,50 100,10 90,0 50,0 Z</item>
-        <item translatable="false">M50 0A50 50,0,1,1,50 100A50 50,0,1,1,50 0</item>
-        <item translatable="false">M50,0A50,50,0,0 1 100,50 L100,85 A15,15,0,0 1 85,100 L50,100 A50,50,0,0 1 50,0z</item>
+        <item>M50,0L100,0 100,100 0,100 0,0z</item>
+        <item>M50,0 C10,0 0,10 0,50 0,90 10,100 50,100 90,100 100,90 100,50 100,10 90,0 50,0 Z</item>
+        <item>M50 0A50 50,0,1,1,50 100A50 50,0,1,1,50 0</item>
+        <item>M50,0A50,50,0,0 1 100,50 L100,85 A15,15,0,0 1 85,100 L50,100 A50,50,0,0 1 50,0z</item>
     </string-array>
 
-    <string-array name="icon_shape_override_paths_names">
+    <string-array translatable="false" name="icon_shape_override_paths_names">
         <!-- Option to not change the icon shape on home screen. [CHAR LIMIT=50] -->
         <item>@string/icon_shape_system_default</item>
-        <item translatable="false">Square</item>
-        <item translatable="false">Squircle</item>
-        <item translatable="false">Circle</item>
-        <item translatable="false">Teardrop</item>
+        <item>@string/icon_shape_square</item>
+        <item>@string/icon_shape_squircle</item>
+        <item>@string/icon_shape_circle</item>
+        <item>@string/icon_shape_teardrop</item>
     </string-array>
+
 <!-- DragController -->
     <item type="id" name="drag_event_parity" />
 
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 3648e15..24a7b88 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -188,6 +188,15 @@
     <string name="icon_shape_override_label">Change icon shape</string>
     <!-- Option to not change the icon shape on home screen and use the system default setting instead. [CHAR LIMIT=50] -->
     <string name="icon_shape_system_default">Use system default</string>
+    <!-- Option to change the shape of the home screen icons to a square. [CHAR LIMIT=50] -->
+    <string name="icon_shape_square">Square</string>
+    <!-- Option to change the shape of the home screen icons to a squircle. This represents the name of the shape somewhere between a circle and a square. [CHAR LIMIT=50] -->
+    <string name="icon_shape_squircle">Squircle</string>
+    <!-- Option to change the shape of the home screen icons to a circle. [CHAR LIMIT=50] -->
+    <string name="icon_shape_circle">Circle</string>
+    <!-- Option to change the shape of the home screen icons to a teardrop. This represents the name of the shape similar to a circle with with the bottom right corner pushed out like a square [CHAR LIMIT=50] -->
+    <string name="icon_shape_teardrop">Teardrop</string>
+
     <!-- Message shown in the progress dialog when the icon shape override is being applied [CHAR LIMIT=100]-->
     <string name="icon_shape_override_progress">Applying icon shape changes</string>
 
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index 22aff64..ff7ca81 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -99,6 +99,7 @@
 import com.android.launcher3.dragndrop.DragView;
 import com.android.launcher3.dragndrop.PinItemDragListener;
 import com.android.launcher3.dynamicui.ExtractedColors;
+import com.android.launcher3.dynamicui.WallpaperColorInfo;
 import com.android.launcher3.folder.Folder;
 import com.android.launcher3.folder.FolderIcon;
 import com.android.launcher3.keyboard.CustomActionsPopup;
@@ -149,7 +150,8 @@
 public class Launcher extends BaseActivity
         implements LauncherExterns, View.OnClickListener, OnLongClickListener,
                    LauncherModel.Callbacks, View.OnTouchListener, LauncherProviderChangeListener,
-                   AccessibilityManager.AccessibilityStateChangeListener {
+                   AccessibilityManager.AccessibilityStateChangeListener,
+                   WallpaperColorInfo.OnThemeChangeListener {
     public static final String TAG = "Launcher";
     static final boolean LOGD = false;
 
@@ -365,6 +367,10 @@
             mLauncherCallbacks.preOnCreate();
         }
 
+        WallpaperColorInfo wallpaperColorInfo = WallpaperColorInfo.getInstance(this);
+        wallpaperColorInfo.setOnThemeChangeListener(this);
+        overrideTheme(wallpaperColorInfo.isDark());
+
         super.onCreate(savedInstanceState);
 
         LauncherAppState app = LauncherAppState.getInstance(this);
@@ -464,6 +470,17 @@
     }
 
     @Override
+    public void onThemeChanged() {
+        recreate();
+    }
+
+    protected void overrideTheme(boolean isDark) {
+        if (isDark) {
+            setTheme(R.style.LauncherThemeDark);
+        }
+    }
+
+    @Override
     public View findViewById(int id) {
         return mLauncherView.findViewById(id);
     }
@@ -494,9 +511,6 @@
         }
     }
 
-    // TODO: use platform flag on API >= 26
-    private static final int SYSTEM_UI_FLAG_LIGHT_NAV_BAR = 0x10;
-
     /**
      * 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.
@@ -511,14 +525,14 @@
                 newSystemUiFlags |= View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR;
             }
             if (navBar && Utilities.isAtLeastO()) {
-                newSystemUiFlags |= SYSTEM_UI_FLAG_LIGHT_NAV_BAR;
+                newSystemUiFlags |= View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR;
             }
         } else {
             if (statusBar) {
                 newSystemUiFlags &= ~(View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR);
             }
             if (navBar && Utilities.isAtLeastO()) {
-                newSystemUiFlags &= ~(SYSTEM_UI_FLAG_LIGHT_NAV_BAR);
+                newSystemUiFlags &= ~(View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR);
             }
         }
 
@@ -1859,6 +1873,8 @@
         ((AccessibilityManager) getSystemService(ACCESSIBILITY_SERVICE))
                 .removeAccessibilityStateChangeListener(this);
 
+        WallpaperColorInfo.getInstance(this).setOnThemeChangeListener(null);
+
         LauncherAnimUtils.onDestroyActivity();
 
         if (mLauncherCallbacks != null) {
diff --git a/src/com/android/launcher3/allapps/AllAppsTransitionController.java b/src/com/android/launcher3/allapps/AllAppsTransitionController.java
index 4f2e3d7..77bc8cb 100644
--- a/src/com/android/launcher3/allapps/AllAppsTransitionController.java
+++ b/src/com/android/launcher3/allapps/AllAppsTransitionController.java
@@ -24,7 +24,6 @@
 import com.android.launcher3.Workspace;
 import com.android.launcher3.anim.SpringAnimationHandler;
 import com.android.launcher3.config.FeatureFlags;
-import com.android.launcher3.dynamicui.ExtractedColors;
 import com.android.launcher3.graphics.GradientView;
 import com.android.launcher3.graphics.ScrimView;
 import com.android.launcher3.userevent.nano.LauncherLogProto.Action;
@@ -43,7 +42,7 @@
  * closer to top or closer to the page indicator.
  */
 public class AllAppsTransitionController implements TouchController, VerticalPullDetector.Listener,
-         ExtractedColors.OnChangeListener, SearchUiManager.OnScrollRangeChangeListener {
+         SearchUiManager.OnScrollRangeChangeListener {
 
     private static final String TAG = "AllAppsTrans";
     private static final boolean DBG = false;
@@ -112,7 +111,6 @@
 
         mEvaluator = new ArgbEvaluator();
         mAllAppsBackgroundColor = Themes.getAttrColor(l, android.R.attr.colorPrimary);
-        mLauncher.getExtractedColors().addOnChangeListener(this);
         mIsDarkTheme = Themes.getAttrBoolean(mLauncher, R.attr.isPrimaryColorDark);
     }
 
@@ -293,7 +291,6 @@
         if (mGradientView == null) {
             mGradientView = (GradientView) mLauncher.findViewById(R.id.gradient_bg);
             mGradientView.setVisibility(View.VISIBLE);
-            onExtractedColorsChanged();
         }
         mGradientView.setProgress(progress);
 
@@ -305,20 +302,6 @@
         mScrimView.setProgress(progress);
     }
 
-    @Override
-    public void onExtractedColorsChanged() {
-        if (FeatureFlags.LAUNCHER3_GRADIENT_ALL_APPS) {
-            if (mGradientView != null) {
-                int color1 = mLauncher.getExtractedColors()
-                        .getColor(ExtractedColors.ALLAPPS_GRADIENT_MAIN_INDEX);
-                int color2 = mLauncher.getExtractedColors()
-                        .getColor(ExtractedColors.ALLAPPS_GRADIENT_SECONDARY_INDEX);
-                mGradientView.onExtractedColorsChanged(color1, color2);
-                mGradientView.requestLayout();
-            }
-        }
-    }
-
     /**
      * @param progress       value between 0 and 1, 0 shows all apps and 1 shows workspace
      */
diff --git a/src/com/android/launcher3/dynamicui/ColorExtractionService.java b/src/com/android/launcher3/dynamicui/ColorExtractionService.java
index 349b4ff..06a4dab 100644
--- a/src/com/android/launcher3/dynamicui/ColorExtractionService.java
+++ b/src/com/android/launcher3/dynamicui/ColorExtractionService.java
@@ -65,9 +65,6 @@
 
             if (FeatureFlags.QSB_IN_HOTSEAT || FeatureFlags.LAUNCHER3_GRADIENT_ALL_APPS) {
                 extractedColors.updateWallpaperThemePalette(null);
-                if (FeatureFlags.LAUNCHER3_GRADIENT_ALL_APPS) {
-                    extractedColors.updateAllAppsGradientPalette(this);
-                }
             }
         } else {
             // We extract colors for the hotseat and status bar separately,
@@ -80,9 +77,6 @@
 
             if (FeatureFlags.QSB_IN_HOTSEAT || FeatureFlags.LAUNCHER3_GRADIENT_ALL_APPS) {
                 extractedColors.updateWallpaperThemePalette(getWallpaperPalette());
-                if (FeatureFlags.LAUNCHER3_GRADIENT_ALL_APPS) {
-                    extractedColors.updateAllAppsGradientPalette(this);
-                }
             }
         }
 
diff --git a/src/com/android/launcher3/dynamicui/ExtractedColors.java b/src/com/android/launcher3/dynamicui/ExtractedColors.java
index 96fe31a..2d8bb86 100644
--- a/src/com/android/launcher3/dynamicui/ExtractedColors.java
+++ b/src/com/android/launcher3/dynamicui/ExtractedColors.java
@@ -26,7 +26,6 @@
 
 import com.android.launcher3.Utilities;
 import com.android.launcher3.config.FeatureFlags;
-import com.android.launcher3.dynamicui.colorextraction.ColorExtractor;
 
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -165,20 +164,6 @@
                 ? defaultColor : wallpaperPalette.getVibrantColor(defaultColor));
     }
 
-    public void updateAllAppsGradientPalette(Context context) {
-        // TODO use isAtLeastO when available
-        try {
-            WallpaperManager.class.getDeclaredMethod("getWallpaperColors", int.class);
-            ColorExtractor extractor = new ColorExtractor(context);
-            ColorExtractor.GradientColors colors = extractor.getColors();
-            setColorAtIndex(ALLAPPS_GRADIENT_MAIN_INDEX, colors.getMainColor());
-            setColorAtIndex(ALLAPPS_GRADIENT_SECONDARY_INDEX, colors.getSecondaryColor());
-        } catch (NoSuchMethodException e) {
-            setColorAtIndex(ALLAPPS_GRADIENT_MAIN_INDEX, Color.WHITE);
-            setColorAtIndex(ALLAPPS_GRADIENT_SECONDARY_INDEX, Color.WHITE);
-        }
-    }
-
     public void addOnChangeListener(OnChangeListener listener) {
         mListeners.add(listener);
     }
diff --git a/src/com/android/launcher3/dynamicui/WallpaperColorInfo.java b/src/com/android/launcher3/dynamicui/WallpaperColorInfo.java
new file mode 100644
index 0000000..20fc424
--- /dev/null
+++ b/src/com/android/launcher3/dynamicui/WallpaperColorInfo.java
@@ -0,0 +1,113 @@
+package com.android.launcher3.dynamicui;
+
+import android.content.Context;
+import android.graphics.Color;
+import android.support.v4.graphics.ColorUtils;
+import android.util.Pair;
+
+import com.android.launcher3.compat.WallpaperColorsCompat;
+import com.android.launcher3.compat.WallpaperManagerCompat;
+import com.android.launcher3.dynamicui.colorextraction.types.ExtractionType;
+import com.android.launcher3.dynamicui.colorextraction.types.Tonal;
+
+import java.util.ArrayList;
+
+import static android.app.WallpaperManager.FLAG_SYSTEM;
+
+public class WallpaperColorInfo implements WallpaperManagerCompat.OnColorsChangedListenerCompat {
+
+    private static final int FALLBACK_COLOR = Color.WHITE;
+    private static final Object sInstanceLock = new Object();
+    private static WallpaperColorInfo sInstance;
+
+    public static WallpaperColorInfo getInstance(Context context) {
+        synchronized (sInstanceLock) {
+            if (sInstance == null) {
+                sInstance = new WallpaperColorInfo(context.getApplicationContext());
+            }
+            return sInstance;
+        }
+    }
+
+    private final ArrayList<OnChangeListener> mListeners = new ArrayList<>();
+    private final WallpaperManagerCompat mWallpaperManager;
+    private final ExtractionType mExtractionType;
+    private int mMainColor;
+    private int mSecondaryColor;
+    private boolean mIsDark;
+    private OnThemeChangeListener mOnThemeChangeListener;
+
+    private WallpaperColorInfo(Context context) {
+        mWallpaperManager = WallpaperManagerCompat.getInstance(context);
+        mWallpaperManager.addOnColorsChangedListener(this);
+        mExtractionType = new Tonal(); // TODO create and use DefaultExtractionLogic
+        update(mWallpaperManager.getWallpaperColors(FLAG_SYSTEM));
+    }
+
+    public int getMainColor() {
+        return mMainColor;
+    }
+
+    public int getSecondaryColor() {
+        return mSecondaryColor;
+    }
+
+    public boolean isDark() {
+        return mIsDark;
+    }
+
+    @Override
+    public void onColorsChanged(WallpaperColorsCompat colors, int which) {
+        if (which == FLAG_SYSTEM) {
+            boolean wasDarkTheme = mIsDark;
+            update(colors);
+            notifyChange(wasDarkTheme != mIsDark);
+        }
+    }
+
+    private void update(WallpaperColorsCompat wallpaperColors) {
+        Pair<Integer, Integer> colors = mExtractionType.extractInto(wallpaperColors);
+        if (colors != null) {
+            mMainColor = colors.first;
+            mSecondaryColor = colors.second;
+        } else {
+            mMainColor = FALLBACK_COLOR;
+            mSecondaryColor = FALLBACK_COLOR;
+        }
+        float[] hsl = new float[3];
+        ColorUtils.colorToHSL(mMainColor, hsl);
+        mIsDark = hsl[2] < 0.2f;
+    }
+
+    public void setOnThemeChangeListener(OnThemeChangeListener onThemeChangeListener) {
+        this.mOnThemeChangeListener = onThemeChangeListener;
+    }
+
+    public void addOnChangeListener(OnChangeListener listener) {
+        mListeners.add(listener);
+    }
+
+    public void removeOnChangeListener(OnChangeListener listener) {
+        mListeners.remove(listener);
+    }
+
+    public void notifyChange(boolean themeChanged) {
+        if (themeChanged) {
+            if (mOnThemeChangeListener != null) {
+                mOnThemeChangeListener.onThemeChanged();
+            }
+        } else {
+            for (OnChangeListener listener : mListeners) {
+                listener.onExtractedColorsChanged(this);
+            }
+        }
+    }
+
+    public interface OnChangeListener {
+        void onExtractedColorsChanged(WallpaperColorInfo wallpaperColorInfo);
+    }
+
+    public interface OnThemeChangeListener {
+        void onThemeChanged();
+    }
+}
diff --git a/src/com/android/launcher3/dynamicui/colorextraction/ColorExtractor.java b/src/com/android/launcher3/dynamicui/colorextraction/ColorExtractor.java
deleted file mode 100644
index 9855867..0000000
--- a/src/com/android/launcher3/dynamicui/colorextraction/ColorExtractor.java
+++ /dev/null
@@ -1,108 +0,0 @@
-package com.android.launcher3.dynamicui.colorextraction;
-
-import static android.app.WallpaperManager.FLAG_SYSTEM;
-
-import android.content.Context;
-import android.graphics.Color;
-
-import com.android.launcher3.compat.WallpaperColorsCompat;
-import com.android.launcher3.compat.WallpaperManagerCompat;
-import com.android.launcher3.dynamicui.colorextraction.types.ExtractionType;
-import com.android.launcher3.dynamicui.colorextraction.types.Tonal;
-
-
-/**
- * Class to process wallpaper colors and generate a tonal palette based on them.
- *
- * TODO remove this class if available by platform
- */
-public class ColorExtractor {
-    private static final int FALLBACK_COLOR = Color.WHITE;
-
-    private final Context mContext;
-    private int mMainFallbackColor = FALLBACK_COLOR;
-    private int mSecondaryFallbackColor = FALLBACK_COLOR;
-    private final GradientColors mSystemColors;
-    private final ExtractionType mExtractionType;
-
-    public ColorExtractor(Context context) {
-        mContext = context;
-        mSystemColors = new GradientColors();
-        mExtractionType = new Tonal();
-
-        extractFrom(WallpaperManagerCompat.getInstance(context).getWallpaperColors(FLAG_SYSTEM));
-    }
-
-    public GradientColors getColors() {
-        return mSystemColors;
-    }
-
-    private void extractFrom(WallpaperColorsCompat inWallpaperColors) {
-        applyFallback(mSystemColors);
-        if (inWallpaperColors == null) {
-            return;
-        }
-        mExtractionType.extractInto(inWallpaperColors, mSystemColors);
-    }
-
-    private void applyFallback(GradientColors outGradientColors) {
-        outGradientColors.setMainColor(mMainFallbackColor);
-        outGradientColors.setSecondaryColor(mSecondaryFallbackColor);
-    }
-
-    public static class GradientColors {
-        private int mMainColor = FALLBACK_COLOR;
-        private int mSecondaryColor = FALLBACK_COLOR;
-        private boolean mSupportsDarkText;
-
-        public void setMainColor(int mainColor) {
-            mMainColor = mainColor;
-        }
-
-        public void setSecondaryColor(int secondaryColor) {
-            mSecondaryColor = secondaryColor;
-        }
-
-        public void setSupportsDarkText(boolean supportsDarkText) {
-            mSupportsDarkText = supportsDarkText;
-        }
-
-        public void set(GradientColors other) {
-            mMainColor = other.mMainColor;
-            mSecondaryColor = other.mSecondaryColor;
-            mSupportsDarkText = other.mSupportsDarkText;
-        }
-
-        public int getMainColor() {
-            return mMainColor;
-        }
-
-        public int getSecondaryColor() {
-            return mSecondaryColor;
-        }
-
-        public boolean supportsDarkText() {
-            return mSupportsDarkText;
-        }
-
-        @Override
-        public boolean equals(Object o) {
-            if (o == null || o.getClass() != getClass()) {
-                return false;
-            }
-            GradientColors other = (GradientColors) o;
-            return other.mMainColor == mMainColor &&
-                    other.mSecondaryColor == mSecondaryColor &&
-                    other.mSupportsDarkText == mSupportsDarkText;
-        }
-
-        @Override
-        public int hashCode() {
-            int code = mMainColor;
-            code = 31 * code + mSecondaryColor;
-            code = 31 * code + (mSupportsDarkText ? 0 : 1);
-            return code;
-        }
-    }
-}
-
diff --git a/src/com/android/launcher3/dynamicui/colorextraction/types/ExtractionType.java b/src/com/android/launcher3/dynamicui/colorextraction/types/ExtractionType.java
index 88958a4..ba7408f 100644
--- a/src/com/android/launcher3/dynamicui/colorextraction/types/ExtractionType.java
+++ b/src/com/android/launcher3/dynamicui/colorextraction/types/ExtractionType.java
@@ -1,23 +1,22 @@
 package com.android.launcher3.dynamicui.colorextraction.types;
 
+import android.support.annotation.Nullable;
+import android.util.Pair;
+
 import com.android.launcher3.compat.WallpaperColorsCompat;
-import com.android.launcher3.dynamicui.colorextraction.ColorExtractor;
 
 
 /**
  * Interface to allow various color extraction implementations.
- *
- * TODO remove this class if available by platform
  */
 public interface ExtractionType {
 
     /**
      * Executes color extraction by reading WallpaperColors and setting
-     * main and secondary colors on GradientColors.
+     * main and secondary colors.
      *
-     * @param inWallpaperColors where to read from
-     * @param outGradientColors object that should receive the colors
+     * @param wallpaperColors where to read from
+     * @return a pair of main and secondary color
      */
-    void extractInto(WallpaperColorsCompat inWallpaperColors,
-                     ColorExtractor.GradientColors outGradientColors);
+    @Nullable Pair<Integer, Integer> extractInto(WallpaperColorsCompat wallpaperColors);
 }
diff --git a/src/com/android/launcher3/dynamicui/colorextraction/types/Tonal.java b/src/com/android/launcher3/dynamicui/colorextraction/types/Tonal.java
index 800dcd2..7c131f1 100644
--- a/src/com/android/launcher3/dynamicui/colorextraction/types/Tonal.java
+++ b/src/com/android/launcher3/dynamicui/colorextraction/types/Tonal.java
@@ -9,7 +9,6 @@
 import android.util.SparseIntArray;
 
 import com.android.launcher3.compat.WallpaperColorsCompat;
-import com.android.launcher3.dynamicui.colorextraction.ColorExtractor;
 
 import java.util.ArrayList;
 import java.util.Collections;
@@ -33,11 +32,13 @@
     private static final float MIN_COLOR_OCCURRENCE = 0.1f;
     private static final float MIN_LUMINOSITY = 0.5f;
 
-    public void extractInto(
-            WallpaperColorsCompat wallpaperColors, ColorExtractor.GradientColors gradientColors) {
+    public @Nullable Pair<Integer, Integer> extractInto(WallpaperColorsCompat wallpaperColors) {
+        if (wallpaperColors == null) {
+            return null;
+        }
         SparseIntArray colorsArray = wallpaperColors.getColors();
         if (colorsArray.size() == 0) {
-            return;
+            return null;
         }
         // Tonal is not really a sort, it takes a color from the extracted
         // palette and finds a best fit amongst a collection of pre-defined
@@ -91,13 +92,13 @@
         // Fall back to population sort if we couldn't find a tonal palette
         if (palette == null) {
             Log.w(TAG, "Could not find a tonal palette!");
-            return;
+            return null;
         }
 
         int fitIndex = bestFit(palette, hsl[0], hsl[1], hsl[2]);
         if (fitIndex == -1) {
             Log.w(TAG, "Could not find best fit!");
-            return;
+            return null;
         }
         float[] h = fit(palette.h, hsl[0], fitIndex,
                 Float.NEGATIVE_INFINITY, Float.POSITIVE_INFINITY);
@@ -108,12 +109,13 @@
         hsl[0] = fract(h[0]) * 360.0f;
         hsl[1] = s[0];
         hsl[2] = l[0];
-        gradientColors.setMainColor(ColorUtils.HSLToColor(hsl));
+        int mainColor = ColorUtils.HSLToColor(hsl);
 
         hsl[0] = fract(h[1]) * 360.0f;
         hsl[1] = s[1];
         hsl[2] = l[1];
-        gradientColors.setSecondaryColor(ColorUtils.HSLToColor(hsl));
+        int secondaryColor = ColorUtils.HSLToColor(hsl);
+        return new Pair<>(mainColor, secondaryColor);
     }
 
     private static void populationSort(@NonNull List<Pair<Integer, Integer>> wallpaperColors) {
diff --git a/src/com/android/launcher3/graphics/GradientView.java b/src/com/android/launcher3/graphics/GradientView.java
index 8f9f871..9dd9504 100644
--- a/src/com/android/launcher3/graphics/GradientView.java
+++ b/src/com/android/launcher3/graphics/GradientView.java
@@ -33,20 +33,20 @@
 import com.android.launcher3.Launcher;
 import com.android.launcher3.R;
 import com.android.launcher3.Utilities;
+import com.android.launcher3.dynamicui.WallpaperColorInfo;
 
 /**
  * Draws a translucent radial gradient background from an initial state with progress 0.0 to a
  * final state with progress 1.0;
  */
-public class GradientView extends View {
+public class GradientView extends View implements WallpaperColorInfo.OnChangeListener {
 
     private static final int DEFAULT_COLOR = Color.WHITE;
     private static final float GRADIENT_ALPHA_MASK_LENGTH_DP = 300;
-    private static final int FINAL_GRADIENT_ALPHA = 0xBF;
     private static final boolean DEBUG = false;
 
-    private static Bitmap sFinalGradientMask;
-    private static Bitmap sAlphaGradientMask;
+    private final Bitmap mFinalGradientMask;
+    private final Bitmap mAlphaGradientMask;
 
     private int mColor1 = DEFAULT_COLOR;
     private int mColor2 = DEFAULT_COLOR;
@@ -61,30 +61,48 @@
     private final Paint mDebugPaint = DEBUG ? new Paint() : null;
     private final Interpolator mAccelerator = new AccelerateInterpolator();
     private final float mAlphaStart;
+    private final WallpaperColorInfo mWallpaperColorInfo;
 
     public GradientView(Context context, AttributeSet attrs) {
         super(context, attrs);
         this.mAppContext = context.getApplicationContext();
         this.mMaskHeight = Utilities.pxFromDp(GRADIENT_ALPHA_MASK_LENGTH_DP,
                 mAppContext.getResources().getDisplayMetrics());
-        this.mAlphaStart = Launcher.getLauncher(context)
-                .getDeviceProfile().isVerticalBarLayout() ? 0 : 100;
+        Launcher launcher = Launcher.getLauncher(context);
+        this.mAlphaStart = launcher.getDeviceProfile().isVerticalBarLayout() ? 0 : 100;
+        this.mWallpaperColorInfo = WallpaperColorInfo.getInstance(launcher);
+        updateColors();
 
-        if (sFinalGradientMask == null) {
-            sFinalGradientMask = Utilities.convertToAlphaMask(
-                    Utilities.createOnePixBitmap(), FINAL_GRADIENT_ALPHA);
-        }
-        if (sAlphaGradientMask == null) {
-            Bitmap alphaMaskFromResource = BitmapFactory.decodeResource(context.getResources(),
-                    R.drawable.all_apps_alpha_mask);
-            sAlphaGradientMask = Utilities.convertToAlphaMask(
-                    alphaMaskFromResource, FINAL_GRADIENT_ALPHA);
-        }
+        int finalAlpha = 0xBF;
+        mFinalGradientMask = Utilities.convertToAlphaMask(
+                Utilities.createOnePixBitmap(), finalAlpha);
+        Bitmap alphaMaskFromResource = BitmapFactory.decodeResource(context.getResources(),
+                R.drawable.all_apps_alpha_mask);
+        mAlphaGradientMask = Utilities.convertToAlphaMask(
+                alphaMaskFromResource, finalAlpha);
     }
 
-    public void onExtractedColorsChanged(int color1, int color2) {
-        this.mColor1 = color1;
-        this.mColor2 = color2;
+    @Override
+    protected void onAttachedToWindow() {
+        super.onAttachedToWindow();
+        mWallpaperColorInfo.addOnChangeListener(this);
+    }
+
+    @Override
+    protected void onDetachedFromWindow() {
+        super.onDetachedFromWindow();
+        mWallpaperColorInfo.removeOnChangeListener(this);
+    }
+
+    @Override
+    public void onExtractedColorsChanged(WallpaperColorInfo info) {
+        updateColors();
+        invalidate();
+    }
+
+    private void updateColors() {
+        this.mColor1 = mWallpaperColorInfo.getMainColor();
+        this.mColor2 = mWallpaperColorInfo.getSecondaryColor();
         if (mWidth + mHeight > 0) {
             createRadialShader();
         }
@@ -130,8 +148,8 @@
         mPaint.setAlpha((int) (mAlphaStart + interpolatedAlpha));
         mAlphaMaskRect.set(0, startMaskY, mWidth, startMaskY + mMaskHeight);
         mFinalMaskRect.set(0, startMaskY + mMaskHeight, mWidth, mHeight);
-        canvas.drawBitmap(sAlphaGradientMask, null, mAlphaMaskRect, mPaint);
-        canvas.drawBitmap(sFinalGradientMask, null, mFinalMaskRect, mPaint);
+        canvas.drawBitmap(mAlphaGradientMask, null, mAlphaMaskRect, mPaint);
+        canvas.drawBitmap(mFinalGradientMask, null, mFinalMaskRect, mPaint);
 
         if (DEBUG) {
             mDebugPaint.setColor(0xFF00FF00);
@@ -139,5 +157,4 @@
             canvas.drawLine(0, startMaskY + mMaskHeight, mWidth, startMaskY + mMaskHeight, mDebugPaint);
         }
     }
-
 }
\ No newline at end of file
diff --git a/src/com/android/launcher3/graphics/ScrimView.java b/src/com/android/launcher3/graphics/ScrimView.java
index 2c5b9ed..6d1f30a 100644
--- a/src/com/android/launcher3/graphics/ScrimView.java
+++ b/src/com/android/launcher3/graphics/ScrimView.java
@@ -42,8 +42,8 @@
     private static final float MASK_START_LENGTH_FACTOR = 1f;
     private static final boolean APPLY_ALPHA = true;
 
-    private static Bitmap sFinalScrimMask;
-    private static Bitmap sAlphaScrimMask;
+    private final Bitmap mFinalScrimMask;
+    private final Bitmap mAlphaScrimMask;
 
     private final int mMaskHeight;
     private int mVisibleHeight;
@@ -67,15 +67,11 @@
         int scrimColor = Themes.getAttrColor(context, R.attr.allAppsScrimColor);
         int scrimAlpha = Color.alpha(scrimColor);
         mPaint.setColor(scrimColor);
-        if (sFinalScrimMask == null) {
-            sFinalScrimMask = Utilities.convertToAlphaMask(
-                    Utilities.createOnePixBitmap(), scrimAlpha);
-        }
-        if (sAlphaScrimMask == null) {
-            Bitmap alphaMaskFromResource = BitmapFactory.decodeResource(getResources(),
-                    R.drawable.all_apps_alpha_mask);
-            sAlphaScrimMask = Utilities.convertToAlphaMask(alphaMaskFromResource, scrimAlpha);
-        }
+        mFinalScrimMask = Utilities.convertToAlphaMask(
+                Utilities.createOnePixBitmap(), scrimAlpha);
+        Bitmap alphaMaskFromResource = BitmapFactory.decodeResource(getResources(),
+                R.drawable.all_apps_alpha_mask);
+        mAlphaScrimMask = Utilities.convertToAlphaMask(alphaMaskFromResource, scrimAlpha);
     }
 
     @Override
@@ -106,8 +102,8 @@
     protected void onDraw(Canvas canvas) {
         mAlphaMaskRect.set(0, 0, getWidth(), mMaskHeight);
         mFinalMaskRect.set(0, mMaskHeight, getWidth(), getHeight());
-        canvas.drawBitmap(sAlphaScrimMask, null, mAlphaMaskRect, mPaint);
-        canvas.drawBitmap(sFinalScrimMask, null, mFinalMaskRect, mPaint);
+        canvas.drawBitmap(mAlphaScrimMask, null, mAlphaMaskRect, mPaint);
+        canvas.drawBitmap(mFinalScrimMask, null, mFinalMaskRect, mPaint);
 
         if (DEBUG) {
             mDebugPaint.setColor(0xFF0000FF);
diff --git a/src/com/android/launcher3/logging/UserEventDispatcher.java b/src/com/android/launcher3/logging/UserEventDispatcher.java
index 7585be6..edbb88c 100644
--- a/src/com/android/launcher3/logging/UserEventDispatcher.java
+++ b/src/com/android/launcher3/logging/UserEventDispatcher.java
@@ -21,6 +21,7 @@
 import android.content.Context;
 import android.content.Intent;
 import android.os.SystemClock;
+import android.support.annotation.Nullable;
 import android.util.Log;
 import android.view.View;
 import android.view.ViewParent;
@@ -90,7 +91,7 @@
     /**
      * Recursively finds the parent of the given child which implements IconLogInfoProvider
      */
-    public static LogContainerProvider getLaunchProviderRecursive(View v) {
+    public static LogContainerProvider getLaunchProviderRecursive(@Nullable View v) {
         ViewParent parent;
         if (v != null) {
             parent = v.getParent();
@@ -147,7 +148,11 @@
         return event;
     }
 
-    public boolean fillInLogContainerData(LauncherEvent event, View v) {
+    /**
+     * Fills in the container data on the given event if the given view is not null.
+     * @return whether container data was added.
+     */
+    private boolean fillInLogContainerData(LauncherEvent event, @Nullable View v) {
         // Fill in grid(x,y), pageIndex of the child and container type of the parent
         LogContainerProvider provider = getLaunchProviderRecursive(v);
         if (v == null || !(v.getTag() instanceof ItemInfo) || provider == null) {
@@ -203,9 +208,16 @@
     }
 
     public void logActionOnControl(int action, int controlType) {
-        LauncherEvent event = newLauncherEvent(
-                newTouchAction(action), newTarget(Target.Type.CONTROL));
+        logActionOnControl(action, controlType, null);
+    }
+
+    public void logActionOnControl(int action, int controlType, @Nullable View controlInContainer) {
+        final LauncherEvent event = controlInContainer == null
+                ? newLauncherEvent(newTouchAction(action), newTarget(Target.Type.CONTROL))
+                : newLauncherEvent(newTouchAction(action), newTarget(Target.Type.CONTROL),
+                        newTarget(Target.Type.CONTAINER));
         event.srcTarget[0].controlType = controlType;
+        fillInLogContainerData(event, controlInContainer);
         dispatchUserEvent(event, null);
     }
 
diff --git a/src/com/android/launcher3/popup/SystemShortcut.java b/src/com/android/launcher3/popup/SystemShortcut.java
index a52d1d4..6254d2d 100644
--- a/src/com/android/launcher3/popup/SystemShortcut.java
+++ b/src/com/android/launcher3/popup/SystemShortcut.java
@@ -13,18 +13,20 @@
 import com.android.launcher3.R;
 import com.android.launcher3.model.WidgetItem;
 import com.android.launcher3.util.PackageUserKey;
-import com.android.launcher3.util.Themes;
 import com.android.launcher3.widget.WidgetsBottomSheet;
 
 import java.util.List;
 
+import static com.android.launcher3.userevent.nano.LauncherLogProto.Action;
+import static com.android.launcher3.userevent.nano.LauncherLogProto.ControlType;
+
 /**
  * Represents a system shortcut for a given app. The shortcut should have a static label and
  * icon, and an onClickListener that depends on the item that the shortcut services.
  *
  * Example system shortcuts, defined as inner classes, include Widgets and AppInfo.
  */
-public abstract class SystemShortcut {
+public abstract class SystemShortcut extends ItemInfo {
     private final int mIconResId;
     private final int mLabelResId;
 
@@ -66,6 +68,8 @@
                             (WidgetsBottomSheet) launcher.getLayoutInflater().inflate(
                                     R.layout.widgets_bottom_sheet, launcher.getDragLayer(), false);
                     widgetsBottomSheet.populateAndShow(itemInfo);
+                    launcher.getUserEventDispatcher().logActionOnControl(Action.Touch.TAP,
+                            ControlType.WIDGETS_BUTTON, view);
                 }
             };
         }
@@ -85,6 +89,8 @@
                     Rect sourceBounds = launcher.getViewBounds(view);
                     Bundle opts = launcher.getActivityLaunchOptions(view);
                     InfoDropTarget.startDetailsActivityForInfo(itemInfo, launcher, null, sourceBounds, opts);
+                    launcher.getUserEventDispatcher().logActionOnControl(Action.Touch.TAP,
+                            ControlType.APPINFO_TARGET, view);
                 }
             };
         }