Updating color extraction to include wallpaper theme color.
Also adding mathods and callbacks to pass the related data to the callbacks.

Bug: 37616877
Change-Id: I7512cac7a603e8e5a05ec3a360c9eec493344b00
diff --git a/src/com/android/launcher3/Hotseat.java b/src/com/android/launcher3/Hotseat.java
index 47052a7..128d956 100644
--- a/src/com/android/launcher3/Hotseat.java
+++ b/src/com/android/launcher3/Hotseat.java
@@ -180,7 +180,7 @@
 
     public void updateColor(ExtractedColors extractedColors, boolean animate) {
         if (!mHasVerticalHotseat) {
-            int color = extractedColors.getColor(ExtractedColors.HOTSEAT_INDEX, Color.TRANSPARENT);
+            int color = extractedColors.getColor(ExtractedColors.HOTSEAT_INDEX);
             if (mBackgroundColorAnimator != null) {
                 mBackgroundColorAnimator.cancel();
             }
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index a8d3d15..da52b4f 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -466,6 +466,14 @@
     @Override
     public void onExtractedColorsChanged() {
         loadExtractedColorsAndColorItems();
+
+        if (mLauncherCallbacks != null) {
+            mLauncherCallbacks.onExtractedColorsChanged();
+        }
+    }
+
+    public ExtractedColors getExtractedColors() {
+        return mExtractedColors;
     }
 
     @Override
@@ -481,9 +489,9 @@
             mExtractedColors.load(this);
             mHotseat.updateColor(mExtractedColors, !mPaused);
             mWorkspace.getPageIndicator().updateColor(mExtractedColors);
-            boolean lightStatusBar = (FeatureFlags.LIGHT_STATUS_BAR
-                    && mExtractedColors.getColor(ExtractedColors.STATUS_BAR_INDEX,
-                    ExtractedColors.DEFAULT_DARK) == ExtractedColors.DEFAULT_LIGHT);
+            boolean lightStatusBar = (FeatureFlags.LIGHT_STATUS_BAR &&
+                    mExtractedColors.getColor(ExtractedColors.STATUS_BAR_INDEX) ==
+                            ExtractedColors.DEFAULT_LIGHT);
             // It's possible that All Apps is visible when this is run,
             // so always use light status bar in that case. Only change nav bar color to status bar
             // color when All Apps is visible.
diff --git a/src/com/android/launcher3/LauncherCallbacks.java b/src/com/android/launcher3/LauncherCallbacks.java
index ff037b8..32f179f 100644
--- a/src/com/android/launcher3/LauncherCallbacks.java
+++ b/src/com/android/launcher3/LauncherCallbacks.java
@@ -107,4 +107,6 @@
     void setLauncherSearchCallback(Object callbacks);
 
     boolean shouldShowDiscoveryBounce();
+
+    void onExtractedColorsChanged();
 }
diff --git a/src/com/android/launcher3/dynamicui/ColorExtractionService.java b/src/com/android/launcher3/dynamicui/ColorExtractionService.java
index f94d442..9379a72 100644
--- a/src/com/android/launcher3/dynamicui/ColorExtractionService.java
+++ b/src/com/android/launcher3/dynamicui/ColorExtractionService.java
@@ -21,6 +21,7 @@
 import android.app.WallpaperManager;
 import android.content.Intent;
 import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
 import android.graphics.BitmapRegionDecoder;
 import android.graphics.Rect;
 import android.graphics.drawable.BitmapDrawable;
@@ -61,6 +62,10 @@
         if (wallpaperManager.getWallpaperInfo() != null) {
             // We can't extract colors from live wallpapers, so just use the default color always.
             extractedColors.updateHotseatPalette(null);
+
+            if (FeatureFlags.QSB_IN_HOTSEAT) {
+                extractedColors.updateWallpaperThemePalette(null);
+            }
         } else {
             // We extract colors for the hotseat and status bar separately,
             // since they only consider part of the wallpaper.
@@ -69,6 +74,10 @@
             if (FeatureFlags.LIGHT_STATUS_BAR) {
                 extractedColors.updateStatusBarPalette(getStatusBarPalette());
             }
+
+            if (FeatureFlags.QSB_IN_HOTSEAT) {
+                extractedColors.updateWallpaperThemePalette(getWallpaperPalette());
+            }
         }
 
         // Save the extracted colors and wallpaper id to LauncherProvider.
@@ -140,4 +149,23 @@
                 .clearFilters()
                 .generate();
     }
+
+    @TargetApi(Build.VERSION_CODES.N)
+    private Palette getWallpaperPalette() {
+        WallpaperManager wallpaperManager = WallpaperManager.getInstance(this);
+        if (Utilities.ATLEAST_NOUGAT) {
+            try (ParcelFileDescriptor fd = wallpaperManager
+                    .getWallpaperFile(WallpaperManager.FLAG_SYSTEM)) {
+                Bitmap bitmap = BitmapFactory.decodeFileDescriptor(fd.getFileDescriptor());
+                if (bitmap != null) {
+                    return Palette.from(bitmap).clearFilters().generate();
+                }
+            } catch (IOException | NullPointerException e) {
+                Log.e(TAG, "Fetching partial bitmap failed, trying old method", e);
+            }
+        }
+
+        Bitmap wallpaper = ((BitmapDrawable) wallpaperManager.getDrawable()).getBitmap();
+        return Palette.from(wallpaper).clearFilters().generate();
+    }
 }
diff --git a/src/com/android/launcher3/dynamicui/ExtractedColors.java b/src/com/android/launcher3/dynamicui/ExtractedColors.java
index 711508e..2e52a0b 100644
--- a/src/com/android/launcher3/dynamicui/ExtractedColors.java
+++ b/src/com/android/launcher3/dynamicui/ExtractedColors.java
@@ -23,6 +23,9 @@
 import android.util.Log;
 
 import com.android.launcher3.Utilities;
+import com.android.launcher3.config.FeatureFlags;
+
+import java.util.Arrays;
 
 /**
  * Saves and loads colors extracted from the wallpaper, as well as the associated wallpaper id.
@@ -32,31 +35,43 @@
 
     public static final int DEFAULT_LIGHT = Color.WHITE;
     public static final int DEFAULT_DARK = Color.BLACK;
-    public static final int DEFAULT_COLOR = DEFAULT_LIGHT;
 
     // These color profile indices should NOT be changed, since they are used when saving and
     // loading extracted colors. New colors should always be added at the end.
     public static final int VERSION_INDEX = 0;
     public static final int HOTSEAT_INDEX = 1;
     public static final int STATUS_BAR_INDEX = 2;
-    // public static final int VIBRANT_INDEX = 2;
-    // public static final int VIBRANT_DARK_INDEX = 3;
-    // public static final int VIBRANT_LIGHT_INDEX = 4;
-    // public static final int MUTED_INDEX = 5;
-    // public static final int MUTED_DARK_INDEX = 6;
-    // public static final int MUTED_LIGHT_INDEX = 7;
+    public static final int WALLPAPER_VIBRANT_INDEX = 3;
 
-    public static final int NUM_COLOR_PROFILES = 2;
-    private static final int VERSION = 1;
+    private static final int VERSION;
+    private static final int[] DEFAULT_VALUES;
+
+    static {
+        if (FeatureFlags.QSB_IN_HOTSEAT) {
+            VERSION = 2;
+            DEFAULT_VALUES = new int[] {
+                    VERSION,            // VERSION_INDEX
+                    0x40FFFFFF,         // HOTSEAT_INDEX: White with 25% alpha
+                    DEFAULT_DARK,       // STATUS_BAR_INDEX
+                    0xFFCCCCCC,         // WALLPAPER_VIBRANT_INDEX
+            };
+        } else {
+            VERSION = 1;
+            DEFAULT_VALUES = new int[] {
+                    VERSION,            // VERSION_INDEX
+                    0x40FFFFFF,         // HOTSEAT_INDEX: White with 25% alpha
+                    DEFAULT_DARK,       // STATUS_BAR_INDEX
+            };
+        }
+    }
 
     private static final String COLOR_SEPARATOR = ",";
 
-    private int[] mColors;
+    private final int[] mColors;
 
     public ExtractedColors() {
         // The first entry is reserved for the version number.
-        mColors = new int[NUM_COLOR_PROFILES + 1];
-        mColors[VERSION_INDEX] = VERSION;
+        mColors = Arrays.copyOf(DEFAULT_VALUES, DEFAULT_VALUES.length);
     }
 
     public void setColorAtIndex(int index, int color) {
@@ -79,17 +94,6 @@
     }
 
     /**
-     * Decodes a comma-separated String into {@link #mColors}.
-     */
-    void decodeFromString(String colorsString) {
-        String[] splitColorsString = colorsString.split(COLOR_SEPARATOR);
-        mColors = new int[splitColorsString.length];
-        for (int i = 0; i < mColors.length; i++) {
-            mColors[i] = Integer.parseInt(splitColorsString[i]);
-        }
-    }
-
-    /**
      * Loads colors and wallpaper id from {@link Utilities#getPrefs(Context)}.
      * These were saved there in {@link ColorExtractionService}.
      */
@@ -97,19 +101,22 @@
         String encodedString = Utilities.getPrefs(context).getString(
                 ExtractionUtils.EXTRACTED_COLORS_PREFERENCE_KEY, VERSION + "");
 
-        decodeFromString(encodedString);
-
-        if (mColors[VERSION_INDEX] != VERSION) {
+        String[] splitColorsString = encodedString.split(COLOR_SEPARATOR);
+        if (splitColorsString.length == DEFAULT_VALUES.length &&
+                Integer.parseInt(splitColorsString[VERSION_INDEX]) == VERSION) {
+            // Parse and apply the saved values.
+            for (int i = 0; i < mColors.length; i++) {
+                mColors[i] = Integer.parseInt(splitColorsString[i]);
+            }
+        } else {
+            // Leave the values as default values as the saved values may not be compatible.
             ExtractionUtils.startColorExtractionService(context);
         }
     }
 
     /** @param index must be one of the index values defined at the top of this class. */
-    public int getColor(int index, int defaultColor) {
-        if (index > VERSION_INDEX && index < mColors.length) {
-            return mColors[index];
-        }
-        return defaultColor;
+    public int getColor(int index) {
+        return mColors[index];
     }
 
     /**
@@ -125,7 +132,7 @@
         } else if (hotseatPalette != null && ExtractionUtils.isSuperDark(hotseatPalette)) {
             hotseatColor = ColorUtils.setAlphaComponent(Color.WHITE, (int) (0.18f * 255));
         } else {
-            hotseatColor = ColorUtils.setAlphaComponent(Color.WHITE, (int) (0.25f * 255));
+            hotseatColor = DEFAULT_VALUES[HOTSEAT_INDEX];
         }
         setColorAtIndex(HOTSEAT_INDEX, hotseatColor);
     }
@@ -134,4 +141,10 @@
         setColorAtIndex(STATUS_BAR_INDEX, ExtractionUtils.isSuperLight(statusBarPalette) ?
                 DEFAULT_LIGHT : DEFAULT_DARK);
     }
+
+    public void updateWallpaperThemePalette(Palette wallpaperPalette) {
+        int defaultColor = DEFAULT_VALUES[WALLPAPER_VIBRANT_INDEX];
+        setColorAtIndex(WALLPAPER_VIBRANT_INDEX, wallpaperPalette == null
+                ? defaultColor : wallpaperPalette.getVibrantColor(defaultColor));
+    }
 }
diff --git a/src/com/android/launcher3/pageindicators/PageIndicatorLineCaret.java b/src/com/android/launcher3/pageindicators/PageIndicatorLineCaret.java
index 3ceba84..91fc1f0 100644
--- a/src/com/android/launcher3/pageindicators/PageIndicatorLineCaret.java
+++ b/src/com/android/launcher3/pageindicators/PageIndicatorLineCaret.java
@@ -221,7 +221,7 @@
      */
     public void updateColor(ExtractedColors extractedColors) {
         int originalLineAlpha = mLinePaint.getAlpha();
-        int color = extractedColors.getColor(ExtractedColors.HOTSEAT_INDEX, Color.TRANSPARENT);
+        int color = extractedColors.getColor(ExtractedColors.HOTSEAT_INDEX);
         if (color != Color.TRANSPARENT) {
             color = ColorUtils.setAlphaComponent(color, 255);
             if (color == Color.BLACK) {
diff --git a/src/com/android/launcher3/testing/LauncherExtension.java b/src/com/android/launcher3/testing/LauncherExtension.java
index 12f3b84..031da20 100644
--- a/src/com/android/launcher3/testing/LauncherExtension.java
+++ b/src/com/android/launcher3/testing/LauncherExtension.java
@@ -230,5 +230,8 @@
         public boolean shouldShowDiscoveryBounce() {
             return false;
         }
+
+        @Override
+        public void onExtractedColorsChanged() { }
     }
 }