release-request-276f9f52-87fd-4915-bd79-9a2f0ee77433-for-git_oc-release-4090213 snap-temp-L31600000073091223

Change-Id: I9888956d3dbb66f8de012ef2e61395075ff4fa72
diff --git a/AndroidManifest-common.xml b/AndroidManifest-common.xml
index 3a60a98..ab582fe 100644
--- a/AndroidManifest-common.xml
+++ b/AndroidManifest-common.xml
@@ -82,7 +82,8 @@
 
         <service android:name="com.android.launcher3.dynamicui.ColorExtractionService"
             android:exported="false"
-            android:process=":wallpaper_chooser">
+            android:process=":wallpaper_chooser"
+            android:permission="android.permission.BIND_JOB_SERVICE">
         </service>
 
         <service android:name="com.android.launcher3.notification.NotificationListener"
diff --git a/res/values-ja/strings.xml b/res/values-ja/strings.xml
index 0d491ac..6182eb5 100644
--- a/res/values-ja/strings.xml
+++ b/res/values-ja/strings.xml
@@ -120,7 +120,7 @@
     <string name="widget_resized" msgid="9130327887929620">"ウィジェットのサイズを幅<xliff:g id="NUMBER_0">%1$s</xliff:g>、高さ<xliff:g id="NUMBER_1">%2$s</xliff:g>に変更しました"</string>
     <string name="action_deep_shortcut" msgid="2864038805849372848">"ショートカット"</string>
     <string name="shortcuts_menu_description" msgid="406159963824238648">"<xliff:g id="APP_NAME">%2$s</xliff:g>用の <xliff:g id="NUMBER_OF_SHORTCUTS">%1$d</xliff:g> 件のショートカット"</string>
-    <string name="shortcuts_menu_with_notifications_description" msgid="8985659504915468840">"<xliff:g id="APP_NAME">%3$s</xliff:g>: <xliff:g id="NUMBER_OF_SHORTCUTS">%1$d</xliff:g> 件のショートカットと <xliff:g id="NUMBER_OF_NOTIFICATIONS">%2$d</xliff:g> 件の通知"</string>
+    <string name="shortcuts_menu_with_notifications_description" msgid="8985659504915468840">"<xliff:g id="APP_NAME">%3$s</xliff:g>: <xliff:g id="NUMBER_OF_SHORTCUTS">%1$d</xliff:g> 個のショートカットと <xliff:g id="NUMBER_OF_NOTIFICATIONS">%2$d</xliff:g> 件の通知"</string>
     <string name="action_dismiss_notification" msgid="5909461085055959187">"表示しない"</string>
     <string name="notification_dismissed" msgid="6002233469409822874">"通知を非表示にしました"</string>
 </resources>
diff --git a/res/values/colors.xml b/res/values/colors.xml
index 2589308..67a7544 100644
--- a/res/values/colors.xml
+++ b/res/values/colors.xml
@@ -42,6 +42,7 @@
     <color name="notification_color_beneath">#E0E0E0</color> <!-- Gray 300 -->
 
     <color name="badge_color">#1DE9B6</color> <!-- Teal A400 -->
+    <color name="folder_badge_color">#1DE9B6</color> <!-- Teal A400 -->
 
     <!-- System shortcuts -->
     <color name="system_shortcuts_icon_color">@android:color/tertiary_text_light</color>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 1fe33ae..ecc537d 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -172,12 +172,12 @@
     <string name="allow_rotation_desc">When phone is rotated</string>
     <!-- Text explaining that rotation is disabled in Display settings. 'Display' refers to the Display section in system settings [CHAR LIMIT=100] -->
     <string name="allow_rotation_blocked_desc">Current Display setting doesn\'t permit rotation</string>
-    <!-- Title for Icon Badging setting. Tapping this will link to the system Notifications Settings screen where the user can turn off badging globally. [CHAR LIMIT=50] -->
-    <string name="icon_badging_title">Icon badging</string>
+    <!-- Title for Notification dots setting. Tapping this will link to the system Notifications settings screen where the user can turn off notification dots globally. [CHAR LIMIT=50] -->
+    <string name="icon_badging_title">Notification dots</string>
     <!-- Text to indicate that the system icon badging setting is on [CHAR LIMIT=100] -->
-    <string name="icon_badging_desc_on">On for all apps</string>
+    <string name="icon_badging_desc_on">On</string>
     <!-- Text to indicate that the system icon badging setting is off [CHAR LIMIT=100] -->
-    <string name="icon_badging_desc_off">Off for all apps</string>
+    <string name="icon_badging_desc_off">Off</string>
 
     <!-- Label for the setting that allows the automatic placement of launcher shortcuts for applications and games installed on the device [CHAR LIMIT=40] -->
     <string name="auto_add_shortcuts_label">Add icon to Home screen</string>
diff --git a/src/com/android/launcher3/BubbleTextView.java b/src/com/android/launcher3/BubbleTextView.java
index 94c7e07..3c3e224 100644
--- a/src/com/android/launcher3/BubbleTextView.java
+++ b/src/com/android/launcher3/BubbleTextView.java
@@ -96,7 +96,7 @@
 
     private BadgeInfo mBadgeInfo;
     private BadgeRenderer mBadgeRenderer;
-    private IconPalette mIconPalette;
+    private IconPalette mBadgePalette;
     private float mBadgeScale;
     private boolean mForceHideBadge;
     private Point mTempSpaceForBadgeOffset = new Point();
@@ -453,7 +453,7 @@
             final int scrollX = getScrollX();
             final int scrollY = getScrollY();
             canvas.translate(scrollX, scrollY);
-            mBadgeRenderer.draw(canvas, mBadgeInfo, mTempIconBounds, mBadgeScale,
+            mBadgeRenderer.draw(canvas, mBadgePalette, mBadgeInfo, mTempIconBounds, mBadgeScale,
                     mTempSpaceForBadgeOffset);
             canvas.translate(-scrollX, -scrollY);
         }
@@ -578,7 +578,10 @@
             float newBadgeScale = isBadged ? 1f : 0;
             mBadgeRenderer = mLauncher.getDeviceProfile().mBadgeRenderer;
             if (wasBadged || isBadged) {
-                mIconPalette = ((FastBitmapDrawable) mIcon).getIconPalette();
+                mBadgePalette = IconPalette.getBadgePalette(getResources());
+                if (mBadgePalette == null) {
+                    mBadgePalette = ((FastBitmapDrawable) mIcon).getIconPalette();
+                }
                 // Animate when a badge is first added or when it is removed.
                 if (animate && (wasBadged ^ isBadged) && isShown()) {
                     ObjectAnimator.ofFloat(this, BADGE_SCALE_PROPERTY, newBadgeScale).start();
@@ -590,6 +593,10 @@
         }
     }
 
+    public IconPalette getBadgePalette() {
+        return mBadgePalette;
+    }
+
     /**
      * Sets the icon for this view based on the layout direction.
      */
diff --git a/src/com/android/launcher3/FastBitmapDrawable.java b/src/com/android/launcher3/FastBitmapDrawable.java
index a096a1d..199baaf 100644
--- a/src/com/android/launcher3/FastBitmapDrawable.java
+++ b/src/com/android/launcher3/FastBitmapDrawable.java
@@ -124,7 +124,7 @@
     public IconPalette getIconPalette() {
         if (mIconPalette == null) {
             mIconPalette = IconPalette.fromDominantColor(Utilities
-                    .findDominantColorByHue(mBitmap, 20));
+                    .findDominantColorByHue(mBitmap, 20), true /* desaturateBackground */);
         }
         return mIconPalette;
     }
diff --git a/src/com/android/launcher3/Utilities.java b/src/com/android/launcher3/Utilities.java
index 207a7d4..b5c44bb 100644
--- a/src/com/android/launcher3/Utilities.java
+++ b/src/com/android/launcher3/Utilities.java
@@ -61,7 +61,6 @@
 import java.util.Collection;
 import java.util.HashSet;
 import java.util.Locale;
-import java.util.Set;
 import java.util.concurrent.Executor;
 import java.util.concurrent.LinkedBlockingQueue;
 import java.util.concurrent.ThreadPoolExecutor;
@@ -110,6 +109,8 @@
     // An intent extra to indicate the horizontal scroll of the wallpaper.
     public static final String EXTRA_WALLPAPER_OFFSET = "com.android.launcher3.WALLPAPER_OFFSET";
 
+    public static final int COLOR_EXTRACTION_JOB_ID = 1;
+
     // These values are same as that in {@link AsyncTask}.
     private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors();
     private static final int CORE_POOL_SIZE = CPU_COUNT + 1;
diff --git a/src/com/android/launcher3/badge/BadgeRenderer.java b/src/com/android/launcher3/badge/BadgeRenderer.java
index adde4a2..ba1977a 100644
--- a/src/com/android/launcher3/badge/BadgeRenderer.java
+++ b/src/com/android/launcher3/badge/BadgeRenderer.java
@@ -63,7 +63,6 @@
     private final Paint mBackgroundPaint = new Paint(Paint.ANTI_ALIAS_FLAG
             | Paint.FILTER_BITMAP_FLAG);
     private final SparseArray<Bitmap> mBackgroundsWithShadow;
-    private final IconPalette mIconPalette;
 
     public BadgeRenderer(Context context, int iconSizePx) {
         mContext = context;
@@ -83,25 +82,24 @@
         mTextHeight = tempTextHeight.height();
 
         mBackgroundsWithShadow = new SparseArray<>(3);
-
-        mIconPalette = IconPalette.fromDominantColor(context.getColor(R.color.badge_color));
     }
 
     /**
      * Draw a circle in the top right corner of the given bounds, and draw
      * {@link BadgeInfo#getNotificationCount()} on top of the circle.
+     * @param palette The colors (based on the icon) to use for the badge.
      * @param badgeInfo Contains data to draw on the badge. Could be null if we are animating out.
      * @param iconBounds The bounds of the icon being badged.
      * @param badgeScale The progress of the animation, from 0 to 1.
      * @param spaceForOffset How much space is available to offset the badge up and to the right.
      */
-    public void draw(Canvas canvas, @Nullable BadgeInfo badgeInfo,
+    public void draw(Canvas canvas, IconPalette palette, @Nullable BadgeInfo badgeInfo,
             Rect iconBounds, float badgeScale, Point spaceForOffset) {
-        mTextPaint.setColor(mIconPalette.textColor);
+        mTextPaint.setColor(palette.textColor);
         IconDrawer iconDrawer = badgeInfo != null && badgeInfo.isIconLarge()
                 ? mLargeIconDrawer : mSmallIconDrawer;
         Shader icon = badgeInfo == null ? null : badgeInfo.getNotificationIconForBadge(
-                mContext, mIconPalette.backgroundColor, mSize, iconDrawer.mPadding);
+                mContext, palette.backgroundColor, mSize, iconDrawer.mPadding);
         String notificationCount = badgeInfo == null ? "0"
                 : String.valueOf(badgeInfo.getNotificationCount());
         int numChars = notificationCount.length();
@@ -127,7 +125,7 @@
         canvas.translate(badgeCenterX + offsetX, badgeCenterY - offsetY);
         canvas.scale(badgeScale, badgeScale);
         // Prepare the background and shadow and possible stacking effect.
-        mBackgroundPaint.setColorFilter(mIconPalette.backgroundColorMatrixFilter);
+        mBackgroundPaint.setColorFilter(palette.backgroundColorMatrixFilter);
         int backgroundWithShadowSize = backgroundWithShadow.getHeight(); // Same as width.
         boolean shouldStack = !isDot && badgeInfo != null
                 && badgeInfo.getNotificationKeys().size() > 1;
@@ -149,7 +147,7 @@
                     -backgroundWithShadowSize / 2, mBackgroundPaint);
             iconDrawer.drawIcon(icon, canvas);
         } else if (isDot) {
-            mBackgroundPaint.setColorFilter(mIconPalette.saturatedBackgroundColorMatrixFilter);
+            mBackgroundPaint.setColorFilter(palette.saturatedBackgroundColorMatrixFilter);
             canvas.drawBitmap(backgroundWithShadow, -backgroundWithShadowSize / 2,
                     -backgroundWithShadowSize / 2, mBackgroundPaint);
         }
diff --git a/src/com/android/launcher3/dynamicui/ColorExtractionService.java b/src/com/android/launcher3/dynamicui/ColorExtractionService.java
index f94d442..a2e118e 100644
--- a/src/com/android/launcher3/dynamicui/ColorExtractionService.java
+++ b/src/com/android/launcher3/dynamicui/ColorExtractionService.java
@@ -17,15 +17,17 @@
 package com.android.launcher3.dynamicui;
 
 import android.annotation.TargetApi;
-import android.app.IntentService;
 import android.app.WallpaperManager;
-import android.content.Intent;
+import android.app.job.JobParameters;
+import android.app.job.JobService;
 import android.graphics.Bitmap;
 import android.graphics.BitmapRegionDecoder;
 import android.graphics.Rect;
 import android.graphics.drawable.BitmapDrawable;
 import android.os.Build;
 import android.os.Bundle;
+import android.os.Handler;
+import android.os.HandlerThread;
 import android.os.ParcelFileDescriptor;
 import android.support.v7.graphics.Palette;
 import android.util.Log;
@@ -41,45 +43,76 @@
 /**
  * Extracts colors from the wallpaper, and saves results to {@link LauncherProvider}.
  */
-public class ColorExtractionService extends IntentService {
+public class ColorExtractionService extends JobService {
 
     private static final String TAG = "ColorExtractionService";
+    private static final boolean DEBUG = false;
 
     /** The fraction of the wallpaper to extract colors for use on the hotseat. */
     private static final float HOTSEAT_FRACTION = 1f / 4;
 
-    public ColorExtractionService() {
-        super("ColorExtractionService");
+    private HandlerThread mWorkerThread;
+    private Handler mWorkerHandler;
+
+    @Override
+    public void onCreate() {
+        super.onCreate();
+        mWorkerThread = new HandlerThread("ColorExtractionService");
+        mWorkerThread.start();
+        mWorkerHandler = new Handler(mWorkerThread.getLooper());
     }
 
     @Override
-    protected void onHandleIntent(Intent intent) {
-        WallpaperManager wallpaperManager = WallpaperManager.getInstance(this);
-        int wallpaperId = ExtractionUtils.getWallpaperId(wallpaperManager);
+    public void onDestroy() {
+        super.onDestroy();
+        mWorkerThread.quit();
+    }
 
-        ExtractedColors extractedColors = new ExtractedColors();
-        if (wallpaperManager.getWallpaperInfo() != null) {
-            // We can't extract colors from live wallpapers, so just use the default color always.
-            extractedColors.updateHotseatPalette(null);
-        } else {
-            // We extract colors for the hotseat and status bar separately,
-            // since they only consider part of the wallpaper.
-            extractedColors.updateHotseatPalette(getHotseatPalette());
+    @Override
+    public boolean onStartJob(final JobParameters jobParameters) {
+        if (DEBUG) Log.d(TAG, "onStartJob");
+        mWorkerHandler.post(new Runnable() {
+            @Override
+            public void run() {
+                WallpaperManager wallpaperManager = WallpaperManager.getInstance(
+                        ColorExtractionService.this);
+                int wallpaperId = ExtractionUtils.getWallpaperId(wallpaperManager);
 
-            if (FeatureFlags.LIGHT_STATUS_BAR) {
-                extractedColors.updateStatusBarPalette(getStatusBarPalette());
+                ExtractedColors extractedColors = new ExtractedColors();
+                if (wallpaperManager.getWallpaperInfo() != null) {
+                    // We can't extract colors from live wallpapers; always use the default color.
+                    extractedColors.updateHotseatPalette(null);
+                } else {
+                    // We extract colors for the hotseat and status bar separately,
+                    // since they only consider part of the wallpaper.
+                    extractedColors.updateHotseatPalette(getHotseatPalette());
+
+                    if (FeatureFlags.LIGHT_STATUS_BAR) {
+                        extractedColors.updateStatusBarPalette(getStatusBarPalette());
+                    }
+                }
+
+                // Save the extracted colors and wallpaper id to LauncherProvider.
+                String colorsString = extractedColors.encodeAsString();
+                Bundle extras = new Bundle();
+                extras.putInt(LauncherSettings.Settings.EXTRA_WALLPAPER_ID, wallpaperId);
+                extras.putString(LauncherSettings.Settings.EXTRA_EXTRACTED_COLORS, colorsString);
+                getContentResolver().call(
+                        LauncherSettings.Settings.CONTENT_URI,
+                        LauncherSettings.Settings.METHOD_SET_EXTRACTED_COLORS_AND_WALLPAPER_ID,
+                        null, extras);
+                jobFinished(jobParameters, false /* needsReschedule */);
+                if (DEBUG) Log.d(TAG, "job finished!");
             }
-        }
+        });
+        return true;
+    }
 
-        // Save the extracted colors and wallpaper id to LauncherProvider.
-        String colorsString = extractedColors.encodeAsString();
-        Bundle extras = new Bundle();
-        extras.putInt(LauncherSettings.Settings.EXTRA_WALLPAPER_ID, wallpaperId);
-        extras.putString(LauncherSettings.Settings.EXTRA_EXTRACTED_COLORS, colorsString);
-        getContentResolver().call(
-                LauncherSettings.Settings.CONTENT_URI,
-                LauncherSettings.Settings.METHOD_SET_EXTRACTED_COLORS_AND_WALLPAPER_ID,
-                null, extras);
+    @Override
+    public boolean onStopJob(JobParameters jobParameters) {
+        if (DEBUG) Log.d(TAG, "onStopJob");
+        mWorkerHandler.removeCallbacksAndMessages(null);
+        return true;
     }
 
     @TargetApi(Build.VERSION_CODES.N)
diff --git a/src/com/android/launcher3/dynamicui/ExtractionUtils.java b/src/com/android/launcher3/dynamicui/ExtractionUtils.java
index 1cf5d55..92cb5dc 100644
--- a/src/com/android/launcher3/dynamicui/ExtractionUtils.java
+++ b/src/com/android/launcher3/dynamicui/ExtractionUtils.java
@@ -18,8 +18,10 @@
 
 import android.annotation.TargetApi;
 import android.app.WallpaperManager;
+import android.app.job.JobInfo;
+import android.app.job.JobScheduler;
+import android.content.ComponentName;
 import android.content.Context;
-import android.content.Intent;
 import android.content.SharedPreferences;
 import android.graphics.Color;
 import android.os.Build;
@@ -58,7 +60,11 @@
 
     /** Starts the {@link ColorExtractionService} without checking the wallpaper id */
     public static void startColorExtractionService(Context context) {
-        context.startService(new Intent(context, ColorExtractionService.class));
+        JobScheduler jobScheduler = (JobScheduler) context.getSystemService(
+                Context.JOB_SCHEDULER_SERVICE);
+        jobScheduler.schedule(new JobInfo.Builder(Utilities.COLOR_EXTRACTION_JOB_ID,
+                new ComponentName(context, ColorExtractionService.class))
+                .setMinimumLatency(0).build());
     }
 
     private static boolean hasWallpaperIdChanged(Context context) {
diff --git a/src/com/android/launcher3/folder/FolderIcon.java b/src/com/android/launcher3/folder/FolderIcon.java
index 0b356b5..8d58fef 100644
--- a/src/com/android/launcher3/folder/FolderIcon.java
+++ b/src/com/android/launcher3/folder/FolderIcon.java
@@ -75,6 +75,7 @@
 import com.android.launcher3.config.FeatureFlags;
 import com.android.launcher3.dragndrop.DragLayer;
 import com.android.launcher3.dragndrop.DragView;
+import com.android.launcher3.graphics.IconPalette;
 import com.android.launcher3.util.Thunk;
 
 import java.util.ArrayList;
@@ -885,7 +886,8 @@
             // If we are animating to the accepting state, animate the badge out.
             float badgeScale = Math.max(0, mBadgeScale - mBackground.getScaleProgress());
             mTempSpaceForBadgeOffset.set(getWidth() - mTempBounds.right, mTempBounds.top);
-            mBadgeRenderer.draw(canvas, mBadgeInfo, mTempBounds,
+            IconPalette badgePalette = IconPalette.getFolderBadgePalette(getResources());
+            mBadgeRenderer.draw(canvas, badgePalette, mBadgeInfo, mTempBounds,
                     badgeScale, mTempSpaceForBadgeOffset);
         }
     }
diff --git a/src/com/android/launcher3/graphics/IconPalette.java b/src/com/android/launcher3/graphics/IconPalette.java
index 60ca7b2..a17ceeb 100644
--- a/src/com/android/launcher3/graphics/IconPalette.java
+++ b/src/com/android/launcher3/graphics/IconPalette.java
@@ -18,9 +18,12 @@
 
 import android.app.Notification;
 import android.content.Context;
+import android.content.res.Resources;
 import android.graphics.Color;
 import android.graphics.ColorMatrix;
 import android.graphics.ColorMatrixColorFilter;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
 import android.support.v4.graphics.ColorUtils;
 import android.util.Log;
 
@@ -35,11 +38,12 @@
     private static final boolean DEBUG = false;
     private static final String TAG = "IconPalette";
 
-    public static final IconPalette FOLDER_ICON_PALETTE = new IconPalette(Color.parseColor("#BDC1C6"));
-
     private static final float MIN_PRELOAD_COLOR_SATURATION = 0.2f;
     private static final float MIN_PRELOAD_COLOR_LIGHTNESS = 0.6f;
 
+    private static IconPalette sBadgePalette;
+    private static IconPalette sFolderBadgePalette;
+
     public final int dominantColor;
     public final int backgroundColor;
     public final ColorMatrixColorFilter backgroundColorMatrixFilter;
@@ -47,15 +51,19 @@
     public final int textColor;
     public final int secondaryColor;
 
-    private IconPalette(int color) {
+    private IconPalette(int color, boolean desaturateBackground) {
         dominantColor = color;
-        backgroundColor = dominantColor;
+        backgroundColor = desaturateBackground ? getMutedColor(dominantColor, 0.87f) : dominantColor;
         ColorMatrix backgroundColorMatrix = new ColorMatrix();
         Themes.setColorScaleOnMatrix(backgroundColor, backgroundColorMatrix);
         backgroundColorMatrixFilter = new ColorMatrixColorFilter(backgroundColorMatrix);
-        // Get slightly more saturated background color.
-        Themes.setColorScaleOnMatrix(getMutedColor(dominantColor, 0.54f), backgroundColorMatrix);
-        saturatedBackgroundColorMatrixFilter = new ColorMatrixColorFilter(backgroundColorMatrix);
+        if (!desaturateBackground) {
+            saturatedBackgroundColorMatrixFilter = backgroundColorMatrixFilter;
+        } else {
+            // Get slightly more saturated background color.
+            Themes.setColorScaleOnMatrix(getMutedColor(dominantColor, 0.54f), backgroundColorMatrix);
+            saturatedBackgroundColorMatrixFilter = new ColorMatrixColorFilter(backgroundColorMatrix);
+        }
         textColor = getTextColorForBackground(backgroundColor);
         secondaryColor = getLowContrastColor(backgroundColor);
     }
@@ -78,8 +86,35 @@
         return result;
     }
 
-    public static IconPalette fromDominantColor(int dominantColor) {
-        return new IconPalette(dominantColor);
+    public static IconPalette fromDominantColor(int dominantColor, boolean desaturateBackground) {
+        return new IconPalette(dominantColor, desaturateBackground);
+    }
+
+    /**
+     * Returns an IconPalette based on the badge_color in colors.xml.
+     * If that color is Color.TRANSPARENT, then returns null instead.
+     */
+    public static @Nullable IconPalette getBadgePalette(Resources resources) {
+        int badgeColor = resources.getColor(R.color.badge_color);
+        if (badgeColor == Color.TRANSPARENT) {
+            // Colors will be extracted per app icon, so a static palette won't work.
+            return null;
+        }
+        if (sBadgePalette == null) {
+            sBadgePalette = fromDominantColor(badgeColor, false);
+        }
+        return sBadgePalette;
+    }
+
+    /**
+     * Returns an IconPalette based on the folder_badge_color in colors.xml.
+     */
+    public static @NonNull IconPalette getFolderBadgePalette(Resources resources) {
+        if (sFolderBadgePalette == null) {
+            int badgeColor = resources.getColor(R.color.folder_badge_color);
+            sFolderBadgePalette = fromDominantColor(badgeColor, false);
+        }
+        return sFolderBadgePalette;
     }
 
     /**
diff --git a/src/com/android/launcher3/graphics/LauncherIcons.java b/src/com/android/launcher3/graphics/LauncherIcons.java
index 53521f2..19e5702 100644
--- a/src/com/android/launcher3/graphics/LauncherIcons.java
+++ b/src/com/android/launcher3/graphics/LauncherIcons.java
@@ -266,9 +266,10 @@
 
             sOldBounds.set(icon.getBounds());
             if (Utilities.isAtLeastO() && icon instanceof AdaptiveIconDrawable) {
-                int offset = Math.min(left, top);
+                int offset = Math.max((int)(ShadowGenerator.BLUR_FACTOR * iconBitmapSize),
+                        Math.min(left, top));
                 int size = Math.max(width, height);
-                icon.setBounds(offset, offset, offset + size, offset + size);
+                icon.setBounds(offset, offset, size, size);
             } else {
                 icon.setBounds(left, top, left+width, top+height);
             }
diff --git a/src/com/android/launcher3/graphics/ShadowGenerator.java b/src/com/android/launcher3/graphics/ShadowGenerator.java
index 469fe34..5d8cca8 100644
--- a/src/com/android/launcher3/graphics/ShadowGenerator.java
+++ b/src/com/android/launcher3/graphics/ShadowGenerator.java
@@ -35,7 +35,7 @@
 
     // Percent of actual icon size
     private static final float HALF_DISTANCE = 0.5f;
-    private static final float BLUR_FACTOR = 0.5f/48;
+    public static final float BLUR_FACTOR = 0.5f/48;
 
     // Percent of actual icon size
     private static final float KEY_SHADOW_DISTANCE = 1f/48;
diff --git a/src/com/android/launcher3/popup/PopupContainerWithArrow.java b/src/com/android/launcher3/popup/PopupContainerWithArrow.java
index ccead37..4488f66 100644
--- a/src/com/android/launcher3/popup/PopupContainerWithArrow.java
+++ b/src/com/android/launcher3/popup/PopupContainerWithArrow.java
@@ -47,7 +47,6 @@
 import com.android.launcher3.BubbleTextView;
 import com.android.launcher3.DragSource;
 import com.android.launcher3.DropTarget;
-import com.android.launcher3.FastBitmapDrawable;
 import com.android.launcher3.ItemInfo;
 import com.android.launcher3.Launcher;
 import com.android.launcher3.LauncherAnimUtils;
@@ -579,9 +578,7 @@
         ItemInfo itemInfo = (ItemInfo) mOriginalIcon.getTag();
         BadgeInfo badgeInfo = mLauncher.getPopupDataProvider().getBadgeInfoForItem(itemInfo);
         if (mNotificationItemView != null && badgeInfo != null) {
-            IconPalette palette = mOriginalIcon.getIcon() instanceof FastBitmapDrawable
-                    ? ((FastBitmapDrawable) mOriginalIcon.getIcon()).getIconPalette()
-                    : null;
+            IconPalette palette = mOriginalIcon.getBadgePalette();
             mNotificationItemView.updateHeader(badgeInfo.getNotificationCount(), palette);
         }
     }