Bug 783921 - Fix homescreen icon scaling. r=mfinkle a=akeybl
authorWes Johnston <wjohnston@mozilla.com>
Wed, 12 Sep 2012 11:32:05 -0700
changeset 109789 974494c2de324139b23603303e2b23cc53dfd516
parent 109788 46c7396b16225d69e450b349f9c35a2de8e15cc6
child 109790 1f82974dc08c381e63b73db36b045c5ef5e6cdf2
push id214
push userakeybl@mozilla.com
push dateWed, 14 Nov 2012 20:38:59 +0000
treeherdermozilla-release@c8b08ec8e1aa [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmfinkle, akeybl
bugs783921
milestone17.0a2
Bug 783921 - Fix homescreen icon scaling. r=mfinkle a=akeybl
mobile/android/base/GeckoAppShell.java
mobile/android/chrome/content/browser.js
--- a/mobile/android/base/GeckoAppShell.java
+++ b/mobile/android/base/GeckoAppShell.java
@@ -833,19 +833,17 @@ public class GeckoAppShell
 
     // "Installs" an application by creating a shortcut
     // This is the entry point from AndroidBridge.h
     static void createShortcut(String aTitle, String aURI, String aIconData, String aType) {
         if ("webapp".equals(aType)) {
             Log.e(LOGTAG, "createShortcut with no unique URI should not be used for aType = webapp!");
         }
 
-        byte[] raw = Base64.decode(aIconData.substring(22), Base64.DEFAULT);
-        Bitmap bitmap = BitmapFactory.decodeByteArray(raw, 0, raw.length);
-        createShortcut(aTitle, aURI, aURI, bitmap, aType);
+        createShortcut(aTitle, aURI, aURI, aIconData, aType);
     }
 
     // internal, for non-webapps
     static void createShortcut(String aTitle, String aURI, Bitmap aBitmap, String aType) {
         createShortcut(aTitle, aURI, aURI, aBitmap, aType);
     }
 
     // internal, for webapps
@@ -952,88 +950,95 @@ public class GeckoAppShell
                 }
 
                 // then nuke the profile
                 GeckoProfile.removeProfile(GeckoApp.mAppContext, "webapp" + index);
             }
         });
     }
 
+    static public int getPreferredIconSize() {
+        if (android.os.Build.VERSION.SDK_INT >= 11) {
+            ActivityManager am = (ActivityManager)GeckoApp.mAppContext.getSystemService(Context.ACTIVITY_SERVICE);
+            return am.getLauncherLargeIconSize();
+        } else {
+            switch (getDpi()) {
+                case DisplayMetrics.DENSITY_MEDIUM:
+                    return 48;
+                case DisplayMetrics.DENSITY_XHIGH:
+                    return 96;
+                case DisplayMetrics.DENSITY_HIGH:
+                default:
+                    return 72;
+            }
+        }
+    }
+
     static private Bitmap getLauncherIcon(Bitmap aSource, String aType) {
         final int kOffset = 6;
         final int kRadius = 5;
-        int kIconSize;
-        int kOverlaySize;
-        switch (getDpi()) {
-            case DisplayMetrics.DENSITY_MEDIUM:
-                kIconSize = 48;
-                kOverlaySize = 32;
-                break;
-            case DisplayMetrics.DENSITY_XHIGH:
-                kIconSize = 96;
-                kOverlaySize = 48;
-                break;
-            case DisplayMetrics.DENSITY_HIGH:
-            default:
-                kIconSize = 72;
-                kOverlaySize = 32;
-        }
+        int size = getPreferredIconSize();
+        int insetSize = aSource != null ? size*2/3 : size;
 
-        Bitmap bitmap = Bitmap.createBitmap(kIconSize, kIconSize, Bitmap.Config.ARGB_8888);
+        Bitmap bitmap = Bitmap.createBitmap(size, size, Bitmap.Config.ARGB_8888);
         Canvas canvas = new Canvas(bitmap);
 
         if (aType.equalsIgnoreCase(SHORTCUT_TYPE_WEBAPP)) {
-            Rect iconBounds = new Rect(0, 0, bitmap.getWidth(), bitmap.getHeight());
+            Rect iconBounds = new Rect(0, 0, size, size);
             canvas.drawBitmap(aSource, null, iconBounds, null);
             return bitmap;
         }
 
         // draw a base color
         Paint paint = new Paint();
         if (aSource == null) {
+            // if we aren't drawing a favicon, just use an orange color
             float[] hsv = new float[3];
             hsv[0] = 32.0f;
             hsv[1] = 1.0f;
             hsv[2] = 1.0f;
             paint.setColor(Color.HSVToColor(hsv));
-            canvas.drawRoundRect(new RectF(kOffset, kOffset, kIconSize - kOffset, kIconSize - kOffset), kRadius, kRadius, paint);
+            canvas.drawRoundRect(new RectF(kOffset, kOffset, size - kOffset, size - kOffset), kRadius, kRadius, paint);
         } else {
+            // otherwise use the dominant color from the icon + a layer of transparent white to lighten it somewhat
             int color = BitmapUtils.getDominantColor(aSource);
             paint.setColor(color);
-            canvas.drawRoundRect(new RectF(kOffset, kOffset, kIconSize - kOffset, kIconSize - kOffset), kRadius, kRadius, paint);
+            canvas.drawRoundRect(new RectF(kOffset, kOffset, size - kOffset, size - kOffset), kRadius, kRadius, paint);
             paint.setColor(Color.argb(100, 255, 255, 255));
-            canvas.drawRoundRect(new RectF(kOffset, kOffset, kIconSize - kOffset, kIconSize - kOffset), kRadius, kRadius, paint);
+            canvas.drawRoundRect(new RectF(kOffset, kOffset, size - kOffset, size - kOffset), kRadius, kRadius, paint);
         }
 
         // draw the overlay
         Bitmap overlay = BitmapFactory.decodeResource(GeckoApp.mAppContext.getResources(), R.drawable.home_bg);
-        canvas.drawBitmap(overlay, null, new Rect(0, 0, kIconSize, kIconSize), null);
+        canvas.drawBitmap(overlay, null, new Rect(0, 0, size, size), null);
 
-        // draw the bitmap
+        // draw the favicon
         if (aSource == null)
             aSource = BitmapFactory.decodeResource(GeckoApp.mAppContext.getResources(), R.drawable.home_star);
 
-        if (aSource.getWidth() < kOverlaySize || aSource.getHeight() < kOverlaySize) {
-            canvas.drawBitmap(aSource,
-                              null,
-                              new Rect(kIconSize/2 - kOverlaySize/2,
-                                       kIconSize/2 - kOverlaySize/2,
-                                       kIconSize/2 + kOverlaySize/2,
-                                       kIconSize/2 + kOverlaySize/2),
-                              null);
-        } else {
-            canvas.drawBitmap(aSource,
-                              null,
-                              new Rect(kIconSize/2 - aSource.getWidth()/2,
-                                       kIconSize/2 - aSource.getHeight()/2,
-                                       kIconSize/2 + aSource.getWidth()/2,
-                                       kIconSize/2 + aSource.getHeight()/2),
-                              null);
+        // by default, we scale the icon to this size
+        int sWidth = insetSize/2;
+        int sHeight = sWidth;
+
+        if (aSource.getWidth() > insetSize || aSource.getHeight() > insetSize) {
+            // however, if the icon is larger than our minimum, we allow it to be drawn slightly larger
+            // (but not necessarily at its full resolution)
+            sWidth = Math.min(size/3, aSource.getWidth()/2);
+            sHeight = Math.min(size/3, aSource.getHeight()/2);
         }
 
+        int halfSize = size/2;
+        canvas.drawBitmap(aSource,
+                          null,
+                          new Rect(halfSize - sWidth,
+                                   halfSize - sHeight,
+                                   halfSize + sWidth,
+                                   halfSize + sHeight),
+                          null);
+
         return bitmap;
     }
 
     static String[] getHandlersForMimeType(String aMimeType, String aAction) {
         Intent intent = getIntentForActionString(aAction);
         if (aMimeType != null && aMimeType.length() > 0)
             intent.setType(aMimeType);
         return getHandlersForIntent(intent);
--- a/mobile/android/chrome/content/browser.js
+++ b/mobile/android/chrome/content/browser.js
@@ -6321,28 +6321,42 @@ var WebappsUI = {
       gecko: {
         type: "WebApps:Open",
         uri: aURI,
         origin: aOrigin
       }
     });
   },
 
+  get iconSize() {
+    let iconSize = 64;
+    try {
+      Cu.import("resource://gre/modules/JNI.jsm");
+      let jni = new JNI();
+      let cls = jni.findClass("org.mozilla.gecko.GeckoAppShell");
+      let method = jni.getStaticMethodID(cls, "getPreferredIconSize", "()I");
+      iconSize = jni.callStaticIntMethod(cls, method, null);
+      jni.close();
+    } catch(ex) {
+      console.log(ex);
+    }
+
+    delete this.iconSize;
+    return this.iconSize = iconSize;
+  },
+
   makeBase64Icon: function loadAndMakeBase64Icon(aIconURL, aCallbackFunction) {
-    // The images are 64px, but Android will resize as needed.
-    // Bigger is better than too small.
-    const kIconSize = 64;
+    let size = this.iconSize;
 
     let canvas = document.createElementNS("http://www.w3.org/1999/xhtml", "canvas");
-
-    canvas.width = canvas.height = kIconSize;
+    canvas.width = canvas.height = size;
     let ctx = canvas.getContext("2d");
     let favicon = new Image();
     favicon.onload = function() {
-      ctx.drawImage(favicon, 0, 0, kIconSize, kIconSize);
+      ctx.drawImage(favicon, 0, 0, size, size);
       let base64icon = canvas.toDataURL("image/png", "");
       canvas = null;
       aCallbackFunction.call(null, base64icon);
     };
     favicon.onerror = function() {
       Cu.reportError("CreateShortcut: favicon image load error");
 
       // if the image failed to load, and it was not our default icon, attempt to