Index: chrome/android/java/src/org/chromium/chrome/browser/ShortcutHelper.java |
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 ec1ffdabc0c7d2dde778cf21628f575e05dc5f3c..ecb2acdea553ba595f9bc8bddd9d754555f935c8 100644 |
--- a/chrome/android/java/src/org/chromium/chrome/browser/ShortcutHelper.java |
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ShortcutHelper.java |
@@ -4,24 +4,42 @@ |
package org.chromium.chrome.browser; |
+import android.app.ActivityManager; |
import android.content.Context; |
import android.content.Intent; |
+import android.content.pm.PackageManager; |
+import android.content.pm.ResolveInfo; |
import android.graphics.Bitmap; |
+import android.graphics.Canvas; |
+import android.graphics.Color; |
+import android.graphics.Paint; |
+import android.graphics.Path; |
+import android.graphics.PorterDuff; |
+import android.graphics.PorterDuffXfermode; |
+import android.graphics.Rect; |
+import android.graphics.RectF; |
+import android.graphics.drawable.BitmapDrawable; |
+import android.graphics.drawable.Drawable; |
+import android.net.Uri; |
import android.os.Handler; |
import android.os.Looper; |
import android.util.Base64; |
+import android.util.DisplayMetrics; |
+import android.util.TypedValue; |
+import org.chromium.base.ApiCompatibilityUtils; |
import org.chromium.base.ApplicationStatus; |
+import org.chromium.base.Log; |
import org.chromium.base.VisibleForTesting; |
import org.chromium.base.annotations.CalledByNative; |
import org.chromium.chrome.R; |
-import org.chromium.chrome.browser.tab.Tab; |
import org.chromium.chrome.browser.webapps.WebappLauncherActivity; |
-import org.chromium.content_public.browser.WebContents; |
+import org.chromium.chrome.browser.widget.RoundedIconGenerator; |
import org.chromium.content_public.common.ScreenOrientationConstants; |
import org.chromium.ui.widget.Toast; |
import java.io.ByteArrayOutputStream; |
+import java.util.List; |
import java.util.UUID; |
/** |
@@ -41,18 +59,22 @@ public class ShortcutHelper { |
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 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; |
- /** Observes the data fetching pipeline. */ |
- public interface ShortcutHelperObserver { |
- /** Called when the title of the page is available. */ |
- void onUserTitleAvailable(String title); |
- |
- /** Called when the icon to use in the launcher is available. */ |
- void onIconAvailable(Bitmap icon); |
- } |
+ private static final String TAG = "cr.Shortcuts"; |
+ // 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; |
+ private static final int GENERATED_ICON_ROUNDED_CORNERS_DP = 2; |
+ private static final int GENERATED_ICON_FONT_SIZE_DP = 16; |
/** Broadcasts Intents out Android for adding the shortcut. */ |
public static class Delegate { |
@@ -75,47 +97,6 @@ public class ShortcutHelper { |
private static Delegate sDelegate = new Delegate(); |
- private final Context mAppContext; |
- private final Tab mTab; |
- |
- private ShortcutHelperObserver mObserver; |
- private boolean mIsInitialized; |
- private long mNativeShortcutHelper; |
- |
- public ShortcutHelper(Context appContext, Tab tab) { |
- mAppContext = appContext; |
- mTab = tab; |
- } |
- |
- /** |
- * Gets all the information required to initialize the UI. The observer will be notified as |
- * information required for the shortcut become available. |
- * @param observer Observer to notify. |
- */ |
- public void initialize(ShortcutHelperObserver observer) { |
- mObserver = observer; |
- mNativeShortcutHelper = nativeInitialize(mTab.getWebContents()); |
- } |
- |
- /** |
- * Returns whether the object is initialized. |
- */ |
- public boolean isInitialized() { |
- return mIsInitialized; |
- } |
- |
- /** |
- * Puts the object in a state where it is safe to be destroyed. |
- */ |
- public void destroy() { |
- nativeDestroy(mNativeShortcutHelper); |
- |
- // Make sure the callback isn't run if the tear down happens before |
- // onInitialized() is called. |
- mObserver = null; |
- mNativeShortcutHelper = 0; |
- } |
- |
/** |
* Sets the delegate to use. |
*/ |
@@ -124,35 +105,6 @@ public class ShortcutHelper { |
sDelegate = delegate; |
} |
- @CalledByNative |
- private void onUserTitleAvailable(String title) { |
- mObserver.onUserTitleAvailable(title); |
- } |
- |
- @CalledByNative |
- private void onIconAvailable(Bitmap icon) { |
- mObserver.onIconAvailable(icon); |
- mIsInitialized = true; |
- } |
- |
- /** |
- * Adds a shortcut for the current Tab. |
- * @param userRequestedTitle Updated title for the shortcut. |
- */ |
- public void addShortcut(String userRequestedTitle) { |
- nativeAddShortcut(mNativeShortcutHelper, 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 BookmarkUtils.createLauncherIcon( |
- ApplicationStatus.getApplicationContext(), icon, url, red, green, blue); |
- } |
- |
/** |
* Called when we have to fire an Intent to add a shortcut to the homescreen. |
* If the webpage indicated that it was capable of functioning as a webapp, it is added as a |
@@ -189,7 +141,7 @@ public class ShortcutHelper { |
shortcutIntent.putExtra(EXTRA_BACKGROUND_COLOR, backgroundColor); |
} else { |
// Add the shortcut as a launcher icon to open in the browser Activity. |
- shortcutIntent = BookmarkUtils.createShortcutIntent(url); |
+ shortcutIntent = createShortcutIntent(url); |
} |
// Always attach a source (one of add to homescreen menu item, app banner, or unknown) to |
@@ -197,7 +149,7 @@ public class ShortcutHelper { |
shortcutIntent.putExtra(EXTRA_SOURCE, source); |
shortcutIntent.setPackage(context.getPackageName()); |
sDelegate.sendBroadcast( |
- context, BookmarkUtils.createAddToHomeIntent(shortcutIntent, userTitle, icon, url)); |
+ context, createAddToHomeIntent(url, userTitle, icon, shortcutIntent)); |
// Alert the user about adding the shortcut. |
final String shortUrl = UrlUtilities.getDomainAndRegistry(url, true); |
@@ -215,6 +167,163 @@ public class ShortcutHelper { |
} |
/** |
+ * Creates an intent that will add a shortcut to the home screen. |
+ * @param shortcutIntent Intent to fire when the shortcut is activated. |
+ * @param url URL of the shortcut. |
+ * @param title Title of the shortcut. |
+ * @param icon Image that represents the shortcut. |
+ * @return Intent for the shortcut. |
+ */ |
+ public static Intent createAddToHomeIntent(String url, String title, |
+ Bitmap icon, Intent shortcutIntent) { |
+ Intent i = new Intent(INSTALL_SHORTCUT); |
+ i.putExtra(Intent.EXTRA_SHORTCUT_INTENT, shortcutIntent); |
+ i.putExtra(Intent.EXTRA_SHORTCUT_NAME, title); |
+ i.putExtra(Intent.EXTRA_SHORTCUT_ICON, icon); |
+ return i; |
+ } |
+ |
+ /** |
+ * Creates an intent that will add a shortcut to the home screen. |
+ * @param url Url of the shortcut. |
+ * @param title Title of the shortcut. |
+ * @param icon Image that represents the shortcut. |
+ * @return Intent for the shortcut. |
+ */ |
+ public static Intent createAddToHomeIntent(String url, String title, Bitmap icon) { |
+ Intent shortcutIntent = createShortcutIntent(url); |
+ return createAddToHomeIntent(url, title, icon, shortcutIntent); |
+ } |
+ |
+ /** |
+ * Shortcut intent for icon on homescreen. |
+ * @param url Url of the shortcut. |
+ * @return Intent for onclick action of the shortcut. |
+ */ |
+ public static Intent createShortcutIntent(String url) { |
+ Intent shortcutIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(url)); |
+ shortcutIntent.putExtra(REUSE_URL_MATCHING_TAB_ELSE_NEW_TAB, true); |
+ return shortcutIntent; |
+ } |
+ |
+ /** |
+ * Utility method to check if a shortcut can be added to the homescreen. |
+ * @param context Context used to get the package manager. |
+ * @return if a shortcut can be added to the homescreen under the current profile. |
+ */ |
+ public static boolean isAddToHomeIntentSupported(Context context) { |
+ PackageManager pm = context.getPackageManager(); |
+ Intent i = new Intent(INSTALL_SHORTCUT); |
+ List<ResolveInfo> receivers = pm.queryBroadcastReceivers( |
+ i, PackageManager.GET_INTENT_FILTERS); |
+ return !receivers.isEmpty(); |
+ } |
+ |
+ /** |
+ * Creates an icon to be associated with this shortcut. If available, the touch icon |
+ * will be used, else we draw our own. |
+ * @param context Context used to create the intent. |
+ * @param icon Image representing the shortcut. |
+ * @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, |
+ int gValue, int bValue) { |
+ Bitmap bitmap = null; |
+ ActivityManager am = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE); |
+ final int iconSize = am.getLauncherLargeIconSize(); |
+ final int iconDensity = am.getLauncherLargeIconDensity(); |
+ 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)); |
+ } |
+ canvas.setBitmap(null); |
+ } catch (OutOfMemoryError e) { |
+ Log.w(TAG, "OutOfMemoryError while trying to draw bitmap on canvas."); |
+ } |
+ return bitmap; |
+ } |
+ |
+ private static Bitmap getBitmapFromResourceId(Context context, int id, int density) { |
+ Drawable drawable = ApiCompatibilityUtils.getDrawableForDensity( |
+ context.getResources(), id, density); |
+ |
+ if (drawable instanceof BitmapDrawable) { |
+ BitmapDrawable bd = (BitmapDrawable) drawable; |
+ return bd.getBitmap(); |
+ } |
+ assert false : "The drawable was not a bitmap drawable as expected"; |
+ return null; |
+ } |
+ |
+ /** |
+ * Use touch-icon or higher-resolution favicon and round the corners. |
+ * @param context Context used to get resources. |
+ * @param touchIcon Touch icon bitmap. |
+ * @param canvas Canvas that holds the touch icon. |
+ */ |
+ private static void drawTouchIconToCanvas(Context context, Bitmap touchIcon, Canvas canvas) { |
+ Rect iconBounds = new Rect(0, 0, canvas.getWidth(), canvas.getHeight()); |
+ Rect src = new Rect(0, 0, touchIcon.getWidth(), touchIcon.getHeight()); |
+ Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG); |
+ paint.setFilterBitmap(true); |
+ canvas.drawBitmap(touchIcon, src, iconBounds, paint); |
+ // Convert dp to px. |
+ int borderRadii = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, |
+ TOUCHICON_BORDER_RADII_DP, context.getResources().getDisplayMetrics()); |
+ Path path = new Path(); |
+ path.setFillType(Path.FillType.INVERSE_WINDING); |
+ RectF rect = new RectF(iconBounds); |
+ rect.inset(INSET_DIMENSION_FOR_TOUCHICON, INSET_DIMENSION_FOR_TOUCHICON); |
+ path.addRoundRect(rect, borderRadii, borderRadii, Path.Direction.CW); |
+ paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR)); |
+ canvas.drawPath(path, paint); |
+ } |
+ |
+ /** |
+ * Draw document icon to canvas. |
+ * @param context Context used to get bitmap resources. |
+ * @param canvas Canvas that holds the document icon. |
+ * @param iconDensity Density information to get bitmap resources. |
+ * @param url URL of the shortcut. |
+ * @param color Color for the document icon's folding and the bottom strip. |
+ */ |
+ private static void drawWidgetBackgroundToCanvas( |
+ Context context, Canvas canvas, int iconDensity, String url, int color) { |
+ Rect iconBounds = new Rect(0, 0, canvas.getWidth(), canvas.getHeight()); |
+ Bitmap bookmarkWidgetBg = |
+ getBitmapFromResourceId(context, R.mipmap.bookmark_widget_bg, iconDensity); |
+ |
+ Paint paint = new Paint(Paint.FILTER_BITMAP_FLAG); |
+ canvas.drawBitmap(bookmarkWidgetBg, null, iconBounds, paint); |
+ |
+ float density = (float) iconDensity / DisplayMetrics.DENSITY_MEDIUM; |
+ int iconSize = (int) (GENERATED_ICON_SIZE_DP * density); |
+ int iconRoundedEdge = (int) (GENERATED_ICON_ROUNDED_CORNERS_DP * density); |
+ int iconFontSize = (int) (GENERATED_ICON_FONT_SIZE_DP * density); |
+ |
+ RoundedIconGenerator generator = new RoundedIconGenerator( |
+ iconSize, iconSize, iconRoundedEdge, color, iconFontSize); |
+ Bitmap icon = generator.generateIconForUrl(url); |
+ if (icon == null) return; // Bookmark URL does not have a domain. |
+ canvas.drawBitmap(icon, iconBounds.exactCenterX() - icon.getWidth() / 2.0f, |
+ iconBounds.exactCenterY() - icon.getHeight() / 2.0f, null); |
+ } |
+ |
+ /** |
* @return String that can be used to verify that a WebappActivity is being started by Chrome. |
*/ |
public static String getEncodedMac(Context context, String url) { |
@@ -224,8 +333,4 @@ public class ShortcutHelper { |
byte[] mac = WebappAuthenticator.getMacForUrl(context, url); |
return Base64.encodeToString(mac, Base64.DEFAULT); |
} |
- |
- private native long nativeInitialize(WebContents webContents); |
- private native void nativeAddShortcut(long nativeShortcutHelper, String userRequestedTitle); |
- private native void nativeDestroy(long nativeShortcutHelper); |
} |