| 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);
|
| }
|
|
|