Web app: set a flag on the Intent if the icon was generated by Chromium.

This is in order to prevent Chromium to then re-use that icon for
anything related to web app branding.

BUG=546212

Review URL: https://codereview.chromium.org/1420743002

Cr-Commit-Position: refs/heads/master@{#355634}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ShortcutHelper.java b/chrome/android/java/src/org/chromium/chrome/browser/ShortcutHelper.java
index 15ba4ed..3df4198 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ShortcutHelper.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ShortcutHelper.java
@@ -64,17 +64,19 @@
     public static final String EXTRA_THEME_COLOR = "org.chromium.chrome.browser.theme_color";
     public static final String EXTRA_BACKGROUND_COLOR =
             "org.chromium.chrome.browser.background_color";
+    public static final String EXTRA_IS_ICON_GENERATED =
+            "org.chromium.chrome.browser.is_icon_generated";
     public static final String REUSE_URL_MATCHING_TAB_ELSE_NEW_TAB =
             "REUSE_URL_MATCHING_TAB_ELSE_NEW_TAB";
 
     // This value is equal to kInvalidOrMissingColor in the C++ content::Manifest struct.
     public static final long MANIFEST_COLOR_INVALID_OR_MISSING = ((long) Integer.MAX_VALUE) + 1;
 
-    private static final String TAG = "cr.Shortcuts";
+    private static final String TAG = "ShortcutHelper";
+
     // There is no public string defining this intent so if Home changes the value, we
     // have to update this string.
     private static final String INSTALL_SHORTCUT = "com.android.launcher.action.INSTALL_SHORTCUT";
-    private static final int DEFAULT_RGB_VALUE = 145;
     private static final int INSET_DIMENSION_FOR_TOUCHICON = 1;
     private static final int TOUCHICON_BORDER_RADII_DP = 4;
     private static final int GENERATED_ICON_SIZE_DP = 40;
@@ -120,7 +122,7 @@
     @CalledByNative
     private static void addShortcut(Context context, String id, String url, final String userTitle,
             String name, String shortName, Bitmap icon, boolean isWebappCapable, int orientation,
-            int source, long themeColor, long backgroundColor) {
+            int source, long themeColor, long backgroundColor, boolean isIconGenerated) {
         Intent shortcutIntent;
         if (isWebappCapable) {
             // Encode the icon as a base64 string (Launcher drops Bitmaps in the Intent).
@@ -128,16 +130,17 @@
 
             // Add the shortcut as a launcher icon for a full-screen Activity.
             shortcutIntent = new Intent();
-            shortcutIntent.setAction(sDelegate.getFullscreenAction());
-            shortcutIntent.putExtra(EXTRA_ICON, encodedIcon);
-            shortcutIntent.putExtra(EXTRA_ID, id);
-            shortcutIntent.putExtra(EXTRA_NAME, name);
-            shortcutIntent.putExtra(EXTRA_SHORT_NAME, shortName);
-            shortcutIntent.putExtra(EXTRA_URL, url);
-            shortcutIntent.putExtra(EXTRA_ORIENTATION, orientation);
-            shortcutIntent.putExtra(EXTRA_MAC, getEncodedMac(context, url));
-            shortcutIntent.putExtra(EXTRA_THEME_COLOR, themeColor);
-            shortcutIntent.putExtra(EXTRA_BACKGROUND_COLOR, backgroundColor);
+            shortcutIntent.setAction(sDelegate.getFullscreenAction())
+                    .putExtra(EXTRA_ICON, encodedIcon)
+                    .putExtra(EXTRA_ID, id)
+                    .putExtra(EXTRA_NAME, name)
+                    .putExtra(EXTRA_SHORT_NAME, shortName)
+                    .putExtra(EXTRA_URL, url)
+                    .putExtra(EXTRA_ORIENTATION, orientation)
+                    .putExtra(EXTRA_MAC, getEncodedMac(context, url))
+                    .putExtra(EXTRA_THEME_COLOR, themeColor)
+                    .putExtra(EXTRA_BACKGROUND_COLOR, backgroundColor)
+                    .putExtra(EXTRA_IS_ICON_GENERATED, isIconGenerated);
         } else {
             // Add the shortcut as a launcher icon to open in the browser Activity.
             shortcutIntent = createShortcutIntent(url);
@@ -232,17 +235,54 @@
     }
 
     /**
-     * Creates an icon to be associated with this shortcut. If available, the touch icon
-     * will be used, else we draw our own.
+     * Returns whether the given icon matches the size requirements to be used on the homescreen.
      * @param context Context used to create the intent.
      * @param icon Image representing the shortcut.
+     * @return whether the given icon matches the size requirements to be used on the homescreen.
+     */
+    @CalledByNative
+    public static boolean isIconLargeEnoughForLauncher(Context context, Bitmap icon) {
+        ActivityManager am = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
+        final int minimalSize = am.getLauncherLargeIconSize() / 2;
+        return icon.getWidth() >= minimalSize && icon.getHeight() >= minimalSize;
+    }
+
+    /**
+     * Returns the given icon after applying same changes to match the launcher design
+     * requirements.
+     * @param context Context used to create the intent.
+     * @param icon Image representing the shortcut.
+     * @return Bitmap Either the touch-icon or the newly created favicon.
+     */
+    @CalledByNative
+    public static Bitmap modifyIconForLauncher(Context context, Bitmap icon) {
+        assert isIconLargeEnoughForLauncher(context, icon);
+
+        Bitmap bitmap = null;
+        ActivityManager am = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
+        final int iconSize = am.getLauncherLargeIconSize();
+        try {
+            bitmap = Bitmap.createBitmap(iconSize, iconSize, Bitmap.Config.ARGB_8888);
+            Canvas canvas = new Canvas(bitmap);
+            drawTouchIconToCanvas(context, icon, canvas);
+            canvas.setBitmap(null);
+        } catch (OutOfMemoryError e) {
+            Log.w(TAG, "OutOfMemoryError while trying to draw bitmap on canvas.");
+        }
+        return bitmap;
+    }
+
+    /**
+     * Generates an icon to be used on the launcher.
+     * @param context Context used to create the intent.
      * @param url URL of the shortcut.
      * @param rValue Red component of the dominant icon color.
      * @param gValue Green component of the dominant icon color.
      * @param bValue Blue component of the dominant icon color.
      * @return Bitmap Either the touch-icon or the newly created favicon.
      */
-    public static Bitmap createLauncherIcon(Context context, Bitmap icon, String url, int rValue,
+    @CalledByNative
+    public static Bitmap generateLauncherIcon(Context context, String url, int rValue,
             int gValue, int bValue) {
         Bitmap bitmap = null;
         ActivityManager am = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
@@ -251,17 +291,8 @@
         try {
             bitmap = Bitmap.createBitmap(iconSize, iconSize, Bitmap.Config.ARGB_8888);
             Canvas canvas = new Canvas(bitmap);
-            if (icon == null) {
-                icon = getBitmapFromResourceId(context, R.drawable.globe_favicon, iconDensity);
-                rValue = gValue = bValue = DEFAULT_RGB_VALUE;
-            }
-            final int smallestSide = iconSize;
-            if (icon.getWidth() >= smallestSide / 2 && icon.getHeight() >= smallestSide / 2) {
-                drawTouchIconToCanvas(context, icon, canvas);
-            } else {
-                drawWidgetBackgroundToCanvas(context, canvas, iconDensity, url,
-                        Color.rgb(rValue, gValue, bValue));
-            }
+            drawWidgetBackgroundToCanvas(context, canvas, iconDensity, url,
+                    Color.rgb(rValue, gValue, bValue));
             canvas.setBitmap(null);
         } catch (OutOfMemoryError e) {
             Log.w(TAG, "OutOfMemoryError while trying to draw bitmap on canvas.");
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/bookmark/ShortcutActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/bookmark/ShortcutActivity.java
index 6c8bae6..b052e02 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/bookmark/ShortcutActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/bookmark/ShortcutActivity.java
@@ -71,9 +71,15 @@
 
     @Override
     public void onBookmarkSelected(String url, String title, Bitmap favicon) {
-        int dominantColor = FaviconHelper.getDominantColorForBitmap(favicon);
-        Bitmap launcherIcon = ShortcutHelper.createLauncherIcon(this, favicon, url,
-                Color.red(dominantColor), Color.green(dominantColor), Color.blue(dominantColor));
+        Bitmap launcherIcon;
+        if (ShortcutHelper.isIconLargeEnoughForLauncher(this, favicon)) {
+            launcherIcon = ShortcutHelper.modifyIconForLauncher(this, favicon);
+        } else {
+            int dominantColor = FaviconHelper.getDominantColorForBitmap(favicon);
+            launcherIcon = ShortcutHelper.generateLauncherIcon(this, url, Color.red(dominantColor),
+                    Color.green(dominantColor), Color.blue(dominantColor));
+        }
+
         Intent intent = ShortcutHelper.createAddToHomeIntent(url, title, launcherIcon);
         intent.putExtra(ShortcutHelper.EXTRA_SOURCE, ShortcutSource.BOOKMARK_SHORTCUT_WIDGET);
         setResult(RESULT_OK, intent);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/webapps/AddToHomescreenDialogHelper.java b/chrome/android/java/src/org/chromium/chrome/browser/webapps/AddToHomescreenDialogHelper.java
index e01ee23..6abd100e 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/webapps/AddToHomescreenDialogHelper.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/webapps/AddToHomescreenDialogHelper.java
@@ -7,9 +7,7 @@
 import android.content.Context;
 import android.graphics.Bitmap;
 
-import org.chromium.base.ApplicationStatus;
 import org.chromium.base.annotations.CalledByNative;
-import org.chromium.chrome.browser.ShortcutHelper;
 import org.chromium.chrome.browser.tab.Tab;
 import org.chromium.content_public.browser.WebContents;
 
@@ -87,16 +85,6 @@
         nativeAddShortcut(mNativeAddToHomescreenDialogHelper, userRequestedTitle);
     }
 
-    /**
-     * Creates an icon that is acceptable to show on the launcher.
-     */
-    @CalledByNative
-    private static Bitmap finalizeLauncherIcon(
-            String url, Bitmap icon, int red, int green, int blue) {
-        return ShortcutHelper.createLauncherIcon(
-                ApplicationStatus.getApplicationContext(), icon, url, red, green, blue);
-    }
-
     private native long nativeInitialize(WebContents webContents);
     private native void nativeAddShortcut(long nativeAddToHomescreenDialogHelper,
             String userRequestedTitle);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebappInfo.java b/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebappInfo.java
index 2c60f38..c34b6e3 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebappInfo.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebappInfo.java
@@ -29,6 +29,7 @@
     private int mSource;
     private long mThemeColor;
     private long mBackgroundColor;
+    private boolean mIsIconGenerated;
 
     public static WebappInfo createEmpty() {
         return new WebappInfo();
@@ -70,12 +71,14 @@
         long backgroundColor = IntentUtils.safeGetLongExtra(intent,
                 ShortcutHelper.EXTRA_BACKGROUND_COLOR,
                 ShortcutHelper.MANIFEST_COLOR_INVALID_OR_MISSING);
+        boolean isIconGenerated = IntentUtils.safeGetBooleanExtra(intent,
+                ShortcutHelper.EXTRA_IS_ICON_GENERATED, false);
 
         String name = nameFromIntent(intent);
         String shortName = shortNameFromIntent(intent);
 
         return create(id, url, icon, name, shortName, orientation, source,
-                themeColor, backgroundColor);
+                themeColor, backgroundColor, isIconGenerated);
     }
 
     /**
@@ -88,10 +91,11 @@
      * @param orientation Orientation of the webapp.
      * @param source Source where the webapp was added from.
      * @param themeColor The theme color of the webapp.
+     * @param isIconGenerated Whether the |icon| was generated by Chromium.
      */
     public static WebappInfo create(String id, String url, String icon, String name,
             String shortName, int orientation, int source, long themeColor,
-            long backgroundColor) {
+            long backgroundColor, boolean isIconGenerated) {
         if (id == null || url == null) {
             Log.e("WebappInfo", "Data passed in was incomplete: " + id + ", " + url);
             return null;
@@ -99,12 +103,12 @@
 
         Uri uri = Uri.parse(url);
         return new WebappInfo(id, uri, icon, name, shortName, orientation, source,
-                themeColor, backgroundColor);
+                themeColor, backgroundColor, isIconGenerated);
     }
 
     private WebappInfo(String id, Uri uri, String encodedIcon, String name,
             String shortName, int orientation, int source, long themeColor,
-            long backgroundColor) {
+            long backgroundColor, boolean isIconGenerated) {
         mEncodedIcon = encodedIcon;
         mId = id;
         mName = name;
@@ -114,6 +118,7 @@
         mSource = source;
         mThemeColor = themeColor;
         mBackgroundColor = backgroundColor;
+        mIsIconGenerated = isIconGenerated;
         mIsInitialized = mUri != null;
     }
 
@@ -136,6 +141,7 @@
         mSource = newInfo.mSource;
         mThemeColor = newInfo.mThemeColor;
         mBackgroundColor = newInfo.mBackgroundColor;
+        mIsIconGenerated = newInfo.mIsIconGenerated;
     }
 
     public boolean isInitialized() {
@@ -224,6 +230,13 @@
     }
 
     /**
+     * Returns whether the icon was generated by Chromium.
+     */
+    public boolean isIconGenerated() {
+        return mIsIconGenerated;
+    }
+
+    /**
      * Sets extras on an Intent that will launch a WebappActivity.
      * @param intent Intent that will be used to launch a WebappActivity.
      */
@@ -237,5 +250,6 @@
         intent.putExtra(ShortcutHelper.EXTRA_SOURCE, source());
         intent.putExtra(ShortcutHelper.EXTRA_THEME_COLOR, themeColor());
         intent.putExtra(ShortcutHelper.EXTRA_BACKGROUND_COLOR, backgroundColor());
+        intent.putExtra(ShortcutHelper.EXTRA_IS_ICON_GENERATED, isIconGenerated());
     }
 }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/WebappInfoTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/WebappInfoTest.java
index cacd1f1..b61974e 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/WebappInfoTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/WebappInfoTest.java
@@ -28,7 +28,7 @@
         WebappInfo info = WebappInfo.create(id, url, null, name, shortName,
                 ScreenOrientationValues.DEFAULT, ShortcutSource.UNKNOWN,
                 ShortcutHelper.MANIFEST_COLOR_INVALID_OR_MISSING,
-                ShortcutHelper.MANIFEST_COLOR_INVALID_OR_MISSING);
+                ShortcutHelper.MANIFEST_COLOR_INVALID_OR_MISSING, false);
         assertNotNull(info);
     }
 
@@ -43,7 +43,7 @@
         WebappInfo info = WebappInfo.create(id, url, null, name, shortName,
                 ScreenOrientationValues.DEFAULT, ShortcutSource.UNKNOWN,
                 ShortcutHelper.MANIFEST_COLOR_INVALID_OR_MISSING,
-                ShortcutHelper.MANIFEST_COLOR_INVALID_OR_MISSING);
+                ShortcutHelper.MANIFEST_COLOR_INVALID_OR_MISSING, false);
         assertNotNull(info);
     }
 
@@ -148,7 +148,7 @@
         WebappInfo info = WebappInfo.create(id, url, null, name, shortName,
                 ScreenOrientationValues.DEFAULT, ShortcutSource.UNKNOWN,
                 ShortcutHelper.MANIFEST_COLOR_INVALID_OR_MISSING,
-                ShortcutHelper.MANIFEST_COLOR_INVALID_OR_MISSING);
+                ShortcutHelper.MANIFEST_COLOR_INVALID_OR_MISSING, false);
         assertEquals(ScreenOrientationValues.DEFAULT, info.orientation());
         assertEquals(ShortcutSource.UNKNOWN, info.source());
     }
@@ -165,7 +165,7 @@
 
         WebappInfo info = WebappInfo.create(id, url, null, name, shortName,
                 ScreenOrientationValues.DEFAULT, ShortcutSource.UNKNOWN,
-                themeColor, backgroundColor);
+                themeColor, backgroundColor, false);
         assertEquals(info.themeColor(), themeColor);
         assertEquals(info.backgroundColor(), backgroundColor);
     }
@@ -181,7 +181,7 @@
         WebappInfo info = WebappInfo.create(id, url, null, name, shortName,
                 ScreenOrientationValues.DEFAULT, ShortcutSource.UNKNOWN,
                 ShortcutHelper.MANIFEST_COLOR_INVALID_OR_MISSING,
-                ShortcutHelper.MANIFEST_COLOR_INVALID_OR_MISSING);
+                ShortcutHelper.MANIFEST_COLOR_INVALID_OR_MISSING, false);
         assertEquals(info.themeColor(), ShortcutHelper.MANIFEST_COLOR_INVALID_OR_MISSING);
         assertEquals(info.backgroundColor(), ShortcutHelper.MANIFEST_COLOR_INVALID_OR_MISSING);
     }
@@ -204,4 +204,60 @@
         assertEquals(info.themeColor(), themeColor);
         assertEquals(info.backgroundColor(), backgroundColor);
     }
+
+    @SmallTest
+    @Feature({"Webapps"})
+    public void testIntentGeneratedIcon() {
+        String id = "webapp id";
+        String name = "longName";
+        String shortName = "name";
+        String url = "about:blank";
+
+        // Default value.
+        {
+            Intent intent = new Intent();
+            intent.putExtra(ShortcutHelper.EXTRA_ID, id);
+            intent.putExtra(ShortcutHelper.EXTRA_NAME, name);
+            intent.putExtra(ShortcutHelper.EXTRA_SHORT_NAME, shortName);
+            intent.putExtra(ShortcutHelper.EXTRA_URL, url);
+
+            assertFalse(name, WebappInfo.create(intent).isIconGenerated());
+        }
+
+        // Set to true.
+        {
+            Intent intent = new Intent();
+            intent.putExtra(ShortcutHelper.EXTRA_ID, id);
+            intent.putExtra(ShortcutHelper.EXTRA_NAME, name);
+            intent.putExtra(ShortcutHelper.EXTRA_SHORT_NAME, shortName);
+            intent.putExtra(ShortcutHelper.EXTRA_URL, url);
+            intent.putExtra(ShortcutHelper.EXTRA_IS_ICON_GENERATED, true);
+
+            assertTrue(name, WebappInfo.create(intent).isIconGenerated());
+        }
+
+        // Set to false.
+        {
+            Intent intent = new Intent();
+            intent.putExtra(ShortcutHelper.EXTRA_ID, id);
+            intent.putExtra(ShortcutHelper.EXTRA_NAME, name);
+            intent.putExtra(ShortcutHelper.EXTRA_SHORT_NAME, shortName);
+            intent.putExtra(ShortcutHelper.EXTRA_URL, url);
+            intent.putExtra(ShortcutHelper.EXTRA_IS_ICON_GENERATED, false);
+
+            assertFalse(name, WebappInfo.create(intent).isIconGenerated());
+        }
+
+        // Set to something else than a boolean.
+        {
+            Intent intent = new Intent();
+            intent.putExtra(ShortcutHelper.EXTRA_ID, id);
+            intent.putExtra(ShortcutHelper.EXTRA_NAME, name);
+            intent.putExtra(ShortcutHelper.EXTRA_SHORT_NAME, shortName);
+            intent.putExtra(ShortcutHelper.EXTRA_URL, url);
+            intent.putExtra(ShortcutHelper.EXTRA_IS_ICON_GENERATED, "true");
+
+            assertFalse(name, WebappInfo.create(intent).isIconGenerated());
+        }
+    }
 }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/WebappModeTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/WebappModeTest.java
index 6bfac0b8..f6f8fde08 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/WebappModeTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/WebappModeTest.java
@@ -100,7 +100,7 @@
         WebappInfo webappInfo = WebappInfo.create(id, url, icon, title, null,
                 ScreenOrientationValues.PORTRAIT, ShortcutSource.UNKNOWN,
                 ShortcutHelper.MANIFEST_COLOR_INVALID_OR_MISSING,
-                ShortcutHelper.MANIFEST_COLOR_INVALID_OR_MISSING);
+                ShortcutHelper.MANIFEST_COLOR_INVALID_OR_MISSING, false);
         webappInfo.setWebappIntentExtras(intent);
 
         getInstrumentation().getTargetContext().startActivity(intent);
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/WebappUrlBarTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/WebappUrlBarTest.java
index 48e9497..ca1aff6 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/WebappUrlBarTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/WebappUrlBarTest.java
@@ -27,7 +27,7 @@
         WebappInfo mockInfo = WebappInfo.create(WEBAPP_ID, WEBAPP_URL, null, null, null,
                 ScreenOrientationValues.DEFAULT, ShortcutSource.UNKNOWN,
                 ShortcutHelper.MANIFEST_COLOR_INVALID_OR_MISSING,
-                ShortcutHelper.MANIFEST_COLOR_INVALID_OR_MISSING);
+                ShortcutHelper.MANIFEST_COLOR_INVALID_OR_MISSING, false);
         getActivity().getWebappInfo().copy(mockInfo);
         mUrlBar = getActivity().getUrlBarForTests();
     }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/WebappVisibilityTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/WebappVisibilityTest.java
index 357ae464..5a678509 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/WebappVisibilityTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/WebappVisibilityTest.java
@@ -23,7 +23,7 @@
         WebappInfo mockInfo = WebappInfo.create(WEBAPP_ID, webappUrl, null,
                 null, null, ScreenOrientationValues.DEFAULT, ShortcutSource.UNKNOWN,
                 ShortcutHelper.MANIFEST_COLOR_INVALID_OR_MISSING,
-                ShortcutHelper.MANIFEST_COLOR_INVALID_OR_MISSING);
+                ShortcutHelper.MANIFEST_COLOR_INVALID_OR_MISSING, false);
         getActivity().getWebappInfo().copy(mockInfo);
 
         // Show top controls for out-of-domain URLs.
diff --git a/chrome/browser/android/shortcut_helper.cc b/chrome/browser/android/shortcut_helper.cc
index de75b8a..c39462a3 100644
--- a/chrome/browser/android/shortcut_helper.cc
+++ b/chrome/browser/android/shortcut_helper.cc
@@ -17,6 +17,7 @@
 #include "content/public/browser/web_contents.h"
 #include "jni/ShortcutHelper_jni.h"
 #include "ui/gfx/android/java_bitmap.h"
+#include "ui/gfx/color_analysis.h"
 #include "url/gurl.h"
 
 using content::Manifest;
@@ -28,6 +29,8 @@
 static int kIdealSplashImageSize = -1;
 static int kMinimumSplashImageSize = -1;
 
+static int kDefaultRGBIconValue = 145;
+
 // Retrieves and caches the ideal and minimum sizes of the Home screen icon
 // and the splash screen image.
 void GetHomescreenIconAndSplashImageSizes() {
@@ -91,7 +94,8 @@
       info.orientation,
       info.source,
       info.theme_color,
-      info.background_color);
+      info.background_color,
+      info.is_icon_generated);
 }
 
 int ShortcutHelper::GetIdealHomescreenIconSizeInDp() {
@@ -155,6 +159,44 @@
       java_splash_image.obj());
 }
 
+// static
+SkBitmap ShortcutHelper::FinalizeLauncherIcon(const SkBitmap& bitmap,
+                                              const GURL& url,
+                                              bool* is_generated) {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
+
+  JNIEnv* env = base::android::AttachCurrentThread();
+  ScopedJavaLocalRef<jobject> result;
+  *is_generated = false;
+
+  if (!bitmap.isNull()) {
+    ScopedJavaLocalRef<jobject> java_bitmap = gfx::ConvertToJavaBitmap(&bitmap);
+    if (Java_ShortcutHelper_isIconLargeEnoughForLauncher(
+        env, base::android::GetApplicationContext(), java_bitmap.obj())) {
+      result = Java_ShortcutHelper_modifyIconForLauncher(
+          env, base::android::GetApplicationContext(), java_bitmap.obj());
+    }
+  }
+
+  if (result.is_null()) {
+    ScopedJavaLocalRef<jstring> java_url =
+        base::android::ConvertUTF8ToJavaString(env, url.spec());
+    SkColor mean_color = SkColorSetRGB(
+        kDefaultRGBIconValue, kDefaultRGBIconValue, kDefaultRGBIconValue);
+
+    if (!bitmap.isNull())
+      mean_color = color_utils::CalculateKMeanColorOfBitmap(bitmap);
+
+    *is_generated = true;
+    result = Java_ShortcutHelper_generateLauncherIcon(
+        env, base::android::GetApplicationContext(), java_url.obj(),
+        SkColorGetR(mean_color), SkColorGetG(mean_color),
+        SkColorGetB(mean_color));
+  }
+
+  return gfx::CreateSkBitmapFromJavaBitmap(gfx::JavaBitmap(result.obj()));
+}
+
 bool ShortcutHelper::RegisterShortcutHelper(JNIEnv* env) {
   return RegisterNativesImpl(env);
 }
diff --git a/chrome/browser/android/shortcut_helper.h b/chrome/browser/android/shortcut_helper.h
index 12e4793..4dcbcb1 100644
--- a/chrome/browser/android/shortcut_helper.h
+++ b/chrome/browser/android/shortcut_helper.h
@@ -53,6 +53,13 @@
   static void StoreWebappData(const std::string& webapp_id,
                               const SkBitmap& splash_image);
 
+  // Modify the given icon to matche the launcher requirements, then returns the
+  // new icon. It might generate an entirely new icon, in which case,
+  // |is_generated| will be set to |true|.
+  static SkBitmap FinalizeLauncherIcon(const SkBitmap& icon,
+                                       const GURL& url,
+                                       bool* is_generated);
+
  private:
   ShortcutHelper() = delete;
   ~ShortcutHelper() = delete;
diff --git a/chrome/browser/android/shortcut_info.cc b/chrome/browser/android/shortcut_info.cc
index d9d6685..cf310eb 100644
--- a/chrome/browser/android/shortcut_info.cc
+++ b/chrome/browser/android/shortcut_info.cc
@@ -10,7 +10,8 @@
       orientation(blink::WebScreenOrientationLockDefault),
       source(SOURCE_ADD_TO_HOMESCREEN),
       theme_color(content::Manifest::kInvalidOrMissingColor),
-      background_color(content::Manifest::kInvalidOrMissingColor) {
+      background_color(content::Manifest::kInvalidOrMissingColor),
+      is_icon_generated(false) {
 }
 
 ShortcutInfo::~ShortcutInfo() {
diff --git a/chrome/browser/android/shortcut_info.h b/chrome/browser/android/shortcut_info.h
index d5db06b..e623932a 100644
--- a/chrome/browser/android/shortcut_info.h
+++ b/chrome/browser/android/shortcut_info.h
@@ -45,6 +45,7 @@
   Source source;
   int64_t theme_color;
   int64_t background_color;
+  bool is_icon_generated;
 };
 
 #endif  // CHROME_BROWSER_ANDROID_SHORTCUT_INFO_H_
diff --git a/chrome/browser/android/webapps/add_to_homescreen_data_fetcher.cc b/chrome/browser/android/webapps/add_to_homescreen_data_fetcher.cc
index 978053f..464e2f5e 100644
--- a/chrome/browser/android/webapps/add_to_homescreen_data_fetcher.cc
+++ b/chrome/browser/android/webapps/add_to_homescreen_data_fetcher.cc
@@ -235,9 +235,11 @@
                           &icon_bitmap);
   }
 
+  bool is_generated = false;
   if (weak_observer_) {
     icon_bitmap = weak_observer_->FinalizeLauncherIcon(icon_bitmap,
-                                                       shortcut_info_.url);
+                                                       shortcut_info_.url,
+                                                       &is_generated);
   }
 
   content::BrowserThread::PostTask(
@@ -245,7 +247,8 @@
       FROM_HERE,
       base::Bind(&AddToHomescreenDataFetcher::NotifyObserver,
                  this,
-                 icon_bitmap));
+                 icon_bitmap,
+                 is_generated));
 }
 
 void AddToHomescreenDataFetcher::OnManifestIconFetched(const SkBitmap& icon) {
@@ -253,16 +256,18 @@
     FetchFavicon();
     return;
   }
-  NotifyObserver(icon);
+  NotifyObserver(icon, false);
 }
 
-void AddToHomescreenDataFetcher::NotifyObserver(const SkBitmap& bitmap) {
+void AddToHomescreenDataFetcher::NotifyObserver(const SkBitmap& bitmap,
+                                                bool is_generated) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
   if (!web_contents() || !weak_observer_ || is_icon_saved_)
     return;
 
   is_icon_saved_ = true;
   shortcut_icon_ = bitmap;
+  shortcut_info_.is_icon_generated = is_generated;
   is_ready_ = true;
   weak_observer_->OnDataAvailable(shortcut_info_, shortcut_icon_);
 }
diff --git a/chrome/browser/android/webapps/add_to_homescreen_data_fetcher.h b/chrome/browser/android/webapps/add_to_homescreen_data_fetcher.h
index b3927ec..173b45f 100644
--- a/chrome/browser/android/webapps/add_to_homescreen_data_fetcher.h
+++ b/chrome/browser/android/webapps/add_to_homescreen_data_fetcher.h
@@ -41,8 +41,11 @@
     virtual void OnUserTitleAvailable(const base::string16& title) = 0;
 
     // Converts the icon into one that can be used on the Android Home screen.
+    // |is_generated| is an out-param that indicates whether the icon was
+    // generated by Chrome.
     virtual SkBitmap FinalizeLauncherIcon(const SkBitmap& icon,
-                                          const GURL& url) = 0;
+                                          const GURL& url,
+                                          bool* is_generated) = 0;
 
     // Called when all the data needed to create a shortcut is available.
     virtual void OnDataAvailable(const ShortcutInfo& info,
@@ -95,7 +98,7 @@
   void OnManifestIconFetched(const SkBitmap& icon);
 
   // Notifies the observer that the shortcut data is all available.
-  void NotifyObserver(const SkBitmap& icon);
+  void NotifyObserver(const SkBitmap& icon, bool is_generated);
 
   Observer* weak_observer_;
 
diff --git a/chrome/browser/android/webapps/add_to_homescreen_dialog_helper.cc b/chrome/browser/android/webapps/add_to_homescreen_dialog_helper.cc
index 15a2227..845d325a 100644
--- a/chrome/browser/android/webapps/add_to_homescreen_dialog_helper.cc
+++ b/chrome/browser/android/webapps/add_to_homescreen_dialog_helper.cc
@@ -85,32 +85,11 @@
 
 SkBitmap AddToHomescreenDialogHelper::FinalizeLauncherIcon(
       const SkBitmap& bitmap,
-      const GURL& url) {
+      const GURL& url,
+      bool* is_generated) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
 
-  // Determine a single color to use for the favicon if the favicon that is
-  // returned it is too low quality.
-  SkColor color = color_utils::CalculateKMeanColorOfBitmap(bitmap);
-  int dominant_red = SkColorGetR(color);
-  int dominant_green = SkColorGetG(color);
-  int dominant_blue = SkColorGetB(color);
-
-  // Make the icon acceptable for the Android launcher.
-  JNIEnv* env = base::android::AttachCurrentThread();
-  ScopedJavaLocalRef<jstring> java_url =
-      base::android::ConvertUTF8ToJavaString(env, url.spec());
-  ScopedJavaLocalRef<jobject> java_bitmap;
-  if (bitmap.getSize())
-    java_bitmap = gfx::ConvertToJavaBitmap(&bitmap);
-
-  base::android::ScopedJavaLocalRef<jobject> ref =
-      Java_AddToHomescreenDialogHelper_finalizeLauncherIcon(env,
-                                                      java_url.obj(),
-                                                      java_bitmap.obj(),
-                                                      dominant_red,
-                                                      dominant_green,
-                                                      dominant_blue);
-  return gfx::CreateSkBitmapFromJavaBitmap(gfx::JavaBitmap(ref.obj()));
+  return ShortcutHelper::FinalizeLauncherIcon(bitmap, url, is_generated);
 }
 
 void AddToHomescreenDialogHelper::AddShortcut(JNIEnv* env,
diff --git a/chrome/browser/android/webapps/add_to_homescreen_dialog_helper.h b/chrome/browser/android/webapps/add_to_homescreen_dialog_helper.h
index 448c5c12..5db54a7 100644
--- a/chrome/browser/android/webapps/add_to_homescreen_dialog_helper.h
+++ b/chrome/browser/android/webapps/add_to_homescreen_dialog_helper.h
@@ -45,7 +45,9 @@
   // AddToHomescreenDataFetcher::Observer
   void OnUserTitleAvailable(const base::string16& user_title) override;
   void OnDataAvailable(const ShortcutInfo& info, const SkBitmap& icon) override;
-  SkBitmap FinalizeLauncherIcon(const SkBitmap& icon, const GURL& url) override;
+  SkBitmap FinalizeLauncherIcon(const SkBitmap& icon,
+                                const GURL& url,
+                                bool* is_generated) override;
 
  private:
   virtual ~AddToHomescreenDialogHelper();