1 // Copyright 2012 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 package org.chromium.chrome.browser; 6 7 import android.app.ActivityManager; 8 import android.content.Context; 9 import android.content.Intent; 10 import android.graphics.Bitmap; 11 import android.graphics.Canvas; 12 import android.graphics.Color; 13 import android.graphics.Paint; 14 import android.graphics.Path; 15 import android.graphics.PorterDuff; 16 import android.graphics.PorterDuffColorFilter; 17 import android.graphics.PorterDuffXfermode; 18 import android.graphics.Rect; 19 import android.graphics.RectF; 20 import android.graphics.drawable.BitmapDrawable; 21 import android.graphics.drawable.Drawable; 22 import android.net.Uri; 23 import android.os.Build; 24 import android.util.Log; 25 import android.util.TypedValue; 26 27 import org.chromium.chrome.R; 28 29 /** 30 * Util class for bookmarks. 31 */ 32 public class BookmarkUtils { 33 34 // There is no public string defining this intent so if Home changes the value, we 35 // have to update this string. 36 private static final String INSTALL_SHORTCUT = "com.android.launcher.action.INSTALL_SHORTCUT"; 37 private static final int DEFAULT_RGB_VALUE = 145; 38 private static final String TAG = "BookmarkUtils"; 39 public static final String REUSE_URL_MATCHING_TAB_ELSE_NEW_TAB = 40 "REUSE_URL_MATCHING_TAB_ELSE_NEW_TAB"; 41 private static final int INSET_DIMENSION_FOR_TOUCHICON = 1; 42 private static final int TOUCHICON_BORDER_RADII = 10; 43 44 /** 45 * Creates an intent that will add a shortcut to the home screen. 46 * @param context Context used to create the intent. 47 * @param shortcutIntent Intent to fire when the shortcut is activated. 48 * @param title Title of the bookmark. 49 * @param favicon Bookmark favicon. 50 * @param rValue Red component of the dominant favicon color. 51 * @param gValue Green component of the dominant favicon color. 52 * @param bValue Blue component of the dominant favicon color. 53 * @return Intent for the shortcut. 54 */ createAddToHomeIntent(Context context, Intent shortcutIntent, String title, Bitmap favicon, int rValue, int gValue, int bValue)55 public static Intent createAddToHomeIntent(Context context, Intent shortcutIntent, String title, 56 Bitmap favicon, int rValue, int gValue, int bValue) { 57 Intent i = new Intent(INSTALL_SHORTCUT); 58 i.putExtra(Intent.EXTRA_SHORTCUT_INTENT, shortcutIntent); 59 i.putExtra(Intent.EXTRA_SHORTCUT_NAME, title); 60 i.putExtra(Intent.EXTRA_SHORTCUT_ICON, createIcon(context, favicon, rValue, 61 gValue, bValue)); 62 return i; 63 } 64 65 /** 66 * Creates an intent that will add a shortcut to the home screen. 67 * @param context Context used to create the intent. 68 * @param url Url of the bookmark. 69 * @param title Title of the bookmark. 70 * @param favicon Bookmark favicon. 71 * @param rValue Red component of the dominant favicon color. 72 * @param gValue Green component of the dominant favicon color. 73 * @param bValue Blue component of the dominant favicon color. 74 * @return Intent for the shortcut. 75 */ createAddToHomeIntent(Context context, String url, String title, Bitmap favicon, int rValue, int gValue, int bValue)76 public static Intent createAddToHomeIntent(Context context, String url, String title, 77 Bitmap favicon, int rValue, int gValue, int bValue) { 78 Intent shortcutIntent = createShortcutIntent(context, url); 79 return createAddToHomeIntent( 80 context, shortcutIntent, title, favicon, rValue, gValue, bValue); 81 } 82 83 /** 84 * Shortcut intent for icon on homescreen. 85 * @param context Context used to create the intent. 86 * @param url Url of the bookmark. 87 * @return Intent for onclick action of the shortcut. 88 */ createShortcutIntent(Context context, String url)89 public static Intent createShortcutIntent(Context context, String url) { 90 Intent shortcutIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(url)); 91 shortcutIntent.putExtra(REUSE_URL_MATCHING_TAB_ELSE_NEW_TAB, true); 92 return shortcutIntent; 93 } 94 95 /** 96 * Creates an icon to be associated with this bookmark. If available, the touch icon 97 * will be used, else we draw our own. 98 * @param context Context used to create the intent. 99 * @param favicon Bookmark favicon bitmap. 100 * @param rValue Red component of the dominant favicon color. 101 * @param gValue Green component of the dominant favicon color. 102 * @param bValue Blue component of the dominant favicon color. 103 * @return Bitmap Either the touch-icon or the newly created favicon. 104 */ createIcon(Context context, Bitmap favicon, int rValue, int gValue, int bValue)105 private static Bitmap createIcon(Context context, Bitmap favicon, int rValue, 106 int gValue, int bValue) { 107 Bitmap bitmap = null; 108 ActivityManager am = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE); 109 final int iconSize = am.getLauncherLargeIconSize(); 110 final int iconDensity = am.getLauncherLargeIconDensity(); 111 try { 112 bitmap = Bitmap.createBitmap(iconSize, iconSize, Bitmap.Config.ARGB_8888); 113 Canvas canvas = new Canvas(bitmap); 114 if (favicon == null) { 115 favicon = getBitmapFromResourceId(context, R.drawable.globe_favicon, iconDensity); 116 rValue = gValue = bValue = DEFAULT_RGB_VALUE; 117 } 118 final int smallestSide = iconSize; 119 if (favicon.getWidth() >= smallestSide / 2 && favicon.getHeight() >= smallestSide / 2) { 120 drawTouchIconToCanvas(context, favicon, canvas); 121 } else { 122 drawWidgetBackgroundToCanvas(context, canvas, iconDensity, 123 Color.rgb(rValue, gValue, bValue)); 124 drawFaviconToCanvas(context, favicon, canvas); 125 } 126 canvas.setBitmap(null); 127 } catch (OutOfMemoryError e) { 128 Log.w(TAG, "OutOfMemoryError while trying to draw bitmap on canvas."); 129 } 130 return bitmap; 131 } 132 getBitmapFromResourceId(Context context, int id, int density)133 private static Bitmap getBitmapFromResourceId(Context context, int id, int density) { 134 Drawable drawable = null; 135 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1) { 136 drawable = context.getResources().getDrawableForDensity(id, density); 137 } else { 138 drawable = context.getResources().getDrawable(id); 139 } 140 141 if (drawable instanceof BitmapDrawable) { 142 BitmapDrawable bd = (BitmapDrawable) drawable; 143 return bd.getBitmap(); 144 } 145 assert false : "The drawable was not a bitmap drawable as expected"; 146 return null; 147 } 148 149 /** 150 * Use touch-icon or higher-resolution favicon and round the corners. 151 * @param context Context used to get resources. 152 * @param touchIcon Touch icon bitmap. 153 * @param canvas Canvas that holds the touch icon. 154 */ drawTouchIconToCanvas( Context context, Bitmap touchIcon, Canvas canvas)155 private static void drawTouchIconToCanvas( 156 Context context, Bitmap touchIcon, Canvas canvas) { 157 Rect iconBounds = new Rect(0, 0, canvas.getWidth(), canvas.getHeight()); 158 Rect src = new Rect(0, 0, touchIcon.getWidth(), touchIcon.getHeight()); 159 Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG); 160 paint.setFilterBitmap(true); 161 canvas.drawBitmap(touchIcon, src, iconBounds, paint); 162 // Convert dp to px. 163 int borderRadii = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 164 TOUCHICON_BORDER_RADII, context.getResources().getDisplayMetrics()); 165 Path path = new Path(); 166 path.setFillType(Path.FillType.INVERSE_WINDING); 167 RectF rect = new RectF(iconBounds); 168 rect.inset(INSET_DIMENSION_FOR_TOUCHICON, INSET_DIMENSION_FOR_TOUCHICON); 169 path.addRoundRect(rect, borderRadii, borderRadii, Path.Direction.CW); 170 paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR)); 171 canvas.drawPath(path, paint); 172 } 173 174 /** 175 * Draw the favicon with dominant color. 176 * @param context Context used to create the intent. 177 * @param favicon favicon bitmap. 178 * @param canvas Canvas that holds the favicon. 179 */ drawFaviconToCanvas(Context context, Bitmap favicon, Canvas canvas)180 private static void drawFaviconToCanvas(Context context, Bitmap favicon, Canvas canvas) { 181 Rect iconBounds = new Rect(0, 0, canvas.getWidth(), canvas.getHeight()); 182 int faviconSize = iconBounds.width() / 3; 183 Bitmap scaledFavicon = Bitmap.createScaledBitmap(favicon, faviconSize, faviconSize, true); 184 canvas.drawBitmap(scaledFavicon, 185 iconBounds.exactCenterX() - scaledFavicon.getWidth() / 2.0f, 186 iconBounds.exactCenterY() - scaledFavicon.getHeight() / 2.0f, null); 187 } 188 189 /** 190 * Draw document icon to canvas. 191 * @param context Context used to get bitmap resources. 192 * @param canvas Canvas that holds the document icon. 193 * @param iconDensity Density information to get bitmap resources. 194 * @param color Color for the document icon's folding and the bottom strip. 195 */ drawWidgetBackgroundToCanvas( Context context, Canvas canvas, int iconDensity, int color)196 private static void drawWidgetBackgroundToCanvas( 197 Context context, Canvas canvas, int iconDensity, int color) { 198 Rect iconBounds = new Rect(0, 0, canvas.getWidth(), canvas.getHeight()); 199 Bitmap bookmarkWidgetBg = 200 getBitmapFromResourceId(context, R.mipmap.bookmark_widget_bg, iconDensity); 201 Bitmap bookmarkWidgetBgHighlights = getBitmapFromResourceId(context, 202 R.mipmap.bookmark_widget_bg_highlights, iconDensity); 203 if (bookmarkWidgetBg == null || bookmarkWidgetBgHighlights == null) { 204 Log.w(TAG, "Can't load R.mipmap.bookmark_widget_bg or " + 205 "R.mipmap.bookmark_widget_bg_highlights."); 206 return; 207 } 208 Paint paint = new Paint(Paint.FILTER_BITMAP_FLAG); 209 canvas.drawBitmap(bookmarkWidgetBg, null, iconBounds, paint); 210 211 // The following color filter will convert bookmark_widget_bg_highlights' white color to 212 // the 'color' variable when it is painted to 'canvas'. 213 paint.setColorFilter(new PorterDuffColorFilter(color, PorterDuff.Mode.SRC_IN)); 214 canvas.drawBitmap(bookmarkWidgetBgHighlights, null, iconBounds, paint); 215 } 216 } 217