зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1258450 - Add GeckoInterface.createShortcut. r=snorp
This moves some Fennec-specific home-screen icon manipulations out of GeckoAppShell. A GeckoView interface can follow. MozReview-Commit-ID: 7OhRAT9Agdh --HG-- extra : rebase_source : e09513eb2f922a06b931005eea1151b2365fd990 extra : histedit_source : 82c1feda1c8b504de99e0010bee99b4b264d84c0
This commit is contained in:
Родитель
e3b1bc2e68
Коммит
1ed9735c87
|
@ -140,4 +140,9 @@ public class BaseGeckoInterface implements GeckoAppShell.GeckoInterface {
|
|||
// Bug 908792: Implement this
|
||||
@Override
|
||||
public void invalidateOptionsMenu() {}
|
||||
|
||||
@Override
|
||||
public void createShortcut(String title, String URI) {
|
||||
// By default, do nothing.
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,12 +5,15 @@
|
|||
|
||||
package org.mozilla.gecko;
|
||||
|
||||
import android.content.ContentResolver;
|
||||
import android.widget.AdapterView;
|
||||
import android.widget.Button;
|
||||
import org.mozilla.gecko.AppConstants.Versions;
|
||||
import org.mozilla.gecko.GeckoProfileDirectories.NoMozillaDirectoryException;
|
||||
import org.mozilla.gecko.db.BrowserDB;
|
||||
import org.mozilla.gecko.db.URLMetadataTable;
|
||||
import org.mozilla.gecko.favicons.Favicons;
|
||||
import org.mozilla.gecko.favicons.OnFaviconLoadedListener;
|
||||
import org.mozilla.gecko.gfx.BitmapUtils;
|
||||
import org.mozilla.gecko.gfx.FullScreenState;
|
||||
import org.mozilla.gecko.gfx.Layer;
|
||||
|
@ -111,6 +114,7 @@ import java.io.IOException;
|
|||
import java.io.InputStream;
|
||||
import java.net.URL;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
|
@ -1818,6 +1822,66 @@ public abstract class GeckoApp
|
|||
AppConstants.USER_AGENT_FENNEC_MOBILE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void createShortcut(final String title, final String URI) {
|
||||
ThreadUtils.assertOnBackgroundThread();
|
||||
final BrowserDB db = GeckoProfile.get(getApplicationContext()).getDB();
|
||||
|
||||
final ContentResolver cr = getContext().getContentResolver();
|
||||
final Map<String, Map<String, Object>> metadata = db.getURLMetadata().getForURLs(cr,
|
||||
Collections.singletonList(URI),
|
||||
Collections.singletonList(URLMetadataTable.TOUCH_ICON_COLUMN)
|
||||
);
|
||||
|
||||
final Map<String, Object> row = metadata.get(URI);
|
||||
|
||||
String touchIconURL = null;
|
||||
|
||||
if (row != null) {
|
||||
touchIconURL = (String) row.get(URLMetadataTable.TOUCH_ICON_COLUMN);
|
||||
}
|
||||
|
||||
OnFaviconLoadedListener listener = new OnFaviconLoadedListener() {
|
||||
@Override
|
||||
public void onFaviconLoaded(String url, String faviconURL, Bitmap favicon) {
|
||||
doCreateShortcut(title, url, favicon);
|
||||
}
|
||||
};
|
||||
|
||||
// Retrieve the icon while bypassing the cache. Homescreen icon creation is a one-off event, hence it isn't
|
||||
// useful to cache these icons. (Android takes care of storing homescreen icons after a shortcut
|
||||
// has been created.)
|
||||
// The cache is also (currently) limited to 32dp, hence we explicitly need to avoid accessing those icons.
|
||||
// If touchIconURL is null, then Favicons falls back to finding the best possible favicon for
|
||||
// the site URI, hence we can use this call even when there is no touchIcon defined.
|
||||
Favicons.getPreferredSizeFaviconForPage(getApplicationContext(), URI, touchIconURL, listener);
|
||||
}
|
||||
|
||||
private void doCreateShortcut(final String aTitle, final String aURI, final Bitmap aIcon) {
|
||||
// The intent to be launched by the shortcut.
|
||||
Intent shortcutIntent = new Intent();
|
||||
shortcutIntent.setAction(GeckoApp.ACTION_HOMESCREEN_SHORTCUT);
|
||||
shortcutIntent.setData(Uri.parse(aURI));
|
||||
shortcutIntent.setClassName(AppConstants.ANDROID_PACKAGE_NAME,
|
||||
AppConstants.MOZ_ANDROID_BROWSER_INTENT_CLASS);
|
||||
|
||||
Intent intent = new Intent();
|
||||
intent.putExtra(Intent.EXTRA_SHORTCUT_INTENT, shortcutIntent);
|
||||
intent.putExtra(Intent.EXTRA_SHORTCUT_ICON, BitmapUtils.getLauncherIcon(getApplicationContext(), aIcon, GeckoAppShell.getPreferredIconSize()));
|
||||
|
||||
if (aTitle != null) {
|
||||
intent.putExtra(Intent.EXTRA_SHORTCUT_NAME, aTitle);
|
||||
} else {
|
||||
intent.putExtra(Intent.EXTRA_SHORTCUT_NAME, aURI);
|
||||
}
|
||||
|
||||
// Do not allow duplicate items.
|
||||
intent.putExtra("duplicate", false);
|
||||
|
||||
intent.setAction("com.android.launcher.action.INSTALL_SHORTCUT");
|
||||
getApplicationContext().sendBroadcast(intent);
|
||||
}
|
||||
|
||||
private void processAlertCallback(SafeIntent intent) {
|
||||
String alertName = "";
|
||||
String alertCookie = "";
|
||||
|
|
|
@ -22,7 +22,6 @@ import java.net.URL;
|
|||
import java.net.URLConnection;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
@ -32,15 +31,11 @@ import java.util.TreeMap;
|
|||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.content.ContentResolver;
|
||||
import org.mozilla.gecko.annotation.JNITarget;
|
||||
import org.mozilla.gecko.annotation.RobocopTarget;
|
||||
import org.mozilla.gecko.annotation.WrapForJNI;
|
||||
import org.mozilla.gecko.AppConstants.Versions;
|
||||
import org.mozilla.gecko.db.BrowserDB;
|
||||
import org.mozilla.gecko.db.URLMetadataTable;
|
||||
import org.mozilla.gecko.favicons.Favicons;
|
||||
import org.mozilla.gecko.favicons.OnFaviconLoadedListener;
|
||||
import org.mozilla.gecko.gfx.BitmapUtils;
|
||||
import org.mozilla.gecko.gfx.LayerView;
|
||||
import org.mozilla.gecko.gfx.PanZoomController;
|
||||
|
@ -78,10 +73,7 @@ import android.content.pm.ServiceInfo;
|
|||
import android.content.pm.Signature;
|
||||
import android.content.res.TypedArray;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.ImageFormat;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.PixelFormat;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.RectF;
|
||||
|
@ -213,9 +205,6 @@ public class GeckoAppShell
|
|||
static private int sDensityDpi;
|
||||
static private int sScreenDepth;
|
||||
|
||||
/* Default colors. */
|
||||
private static final float[] DEFAULT_LAUNCHER_ICON_HSV = { 32.0f, 1.0f, 1.0f };
|
||||
|
||||
/* Is the value in sVibrationEndTime valid? */
|
||||
private static boolean sVibrationMaybePlaying;
|
||||
|
||||
|
@ -833,62 +822,11 @@ public class GeckoAppShell
|
|||
// This is the entry point from nsIShellService.
|
||||
@WrapForJNI
|
||||
public static void createShortcut(final String aTitle, final String aURI) {
|
||||
ThreadUtils.assertOnBackgroundThread();
|
||||
final BrowserDB db = GeckoProfile.get(getApplicationContext()).getDB();
|
||||
|
||||
final ContentResolver cr = getContext().getContentResolver();
|
||||
final Map<String, Map<String, Object>> metadata = db.getURLMetadata().getForURLs(cr,
|
||||
Collections.singletonList(aURI),
|
||||
Collections.singletonList(URLMetadataTable.TOUCH_ICON_COLUMN)
|
||||
);
|
||||
|
||||
final Map<String, Object> row = metadata.get(aURI);
|
||||
|
||||
String touchIconURL = null;
|
||||
|
||||
if (row != null) {
|
||||
touchIconURL = (String) row.get(URLMetadataTable.TOUCH_ICON_COLUMN);
|
||||
final GeckoInterface geckoInterface = getGeckoInterface();
|
||||
if (geckoInterface == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
OnFaviconLoadedListener listener = new OnFaviconLoadedListener() {
|
||||
@Override
|
||||
public void onFaviconLoaded(String url, String faviconURL, Bitmap favicon) {
|
||||
doCreateShortcut(aTitle, url, favicon);
|
||||
}
|
||||
};
|
||||
|
||||
// Retrieve the icon while bypassing the cache. Homescreen icon creation is a one-off event, hence it isn't
|
||||
// useful to cache these icons. (Android takes care of storing homescreen icons after a shortcut
|
||||
// has been created.)
|
||||
// The cache is also (currently) limited to 32dp, hence we explicitly need to avoid accessing those icons.
|
||||
// If touchIconURL is null, then Favicons falls back to finding the best possible favicon for
|
||||
// the site URI, hence we can use this call even when there is no touchIcon defined.
|
||||
Favicons.getPreferredSizeFaviconForPage(getApplicationContext(), aURI, touchIconURL, listener);
|
||||
}
|
||||
|
||||
private static void doCreateShortcut(final String aTitle, final String aURI, final Bitmap aIcon) {
|
||||
// The intent to be launched by the shortcut.
|
||||
Intent shortcutIntent = new Intent();
|
||||
shortcutIntent.setAction(GeckoApp.ACTION_HOMESCREEN_SHORTCUT);
|
||||
shortcutIntent.setData(Uri.parse(aURI));
|
||||
shortcutIntent.setClassName(AppConstants.ANDROID_PACKAGE_NAME,
|
||||
AppConstants.MOZ_ANDROID_BROWSER_INTENT_CLASS);
|
||||
|
||||
Intent intent = new Intent();
|
||||
intent.putExtra(Intent.EXTRA_SHORTCUT_INTENT, shortcutIntent);
|
||||
intent.putExtra(Intent.EXTRA_SHORTCUT_ICON, getLauncherIcon(aIcon));
|
||||
|
||||
if (aTitle != null) {
|
||||
intent.putExtra(Intent.EXTRA_SHORTCUT_NAME, aTitle);
|
||||
} else {
|
||||
intent.putExtra(Intent.EXTRA_SHORTCUT_NAME, aURI);
|
||||
}
|
||||
|
||||
// Do not allow duplicate items.
|
||||
intent.putExtra("duplicate", false);
|
||||
|
||||
intent.setAction("com.android.launcher.action.INSTALL_SHORTCUT");
|
||||
getApplicationContext().sendBroadcast(intent);
|
||||
geckoInterface.createShortcut(aTitle, aURI);
|
||||
}
|
||||
|
||||
@JNITarget
|
||||
|
@ -910,60 +848,6 @@ public class GeckoAppShell
|
|||
}
|
||||
}
|
||||
|
||||
static private Bitmap getLauncherIcon(Bitmap aSource) {
|
||||
final int kOffset = 6;
|
||||
final int kRadius = 5;
|
||||
int size = getPreferredIconSize();
|
||||
int insetSize = aSource != null ? size * 2 / 3 : size;
|
||||
|
||||
Bitmap bitmap = Bitmap.createBitmap(size, size, Bitmap.Config.ARGB_8888);
|
||||
Canvas canvas = new Canvas(bitmap);
|
||||
|
||||
|
||||
// draw a base color
|
||||
Paint paint = new Paint();
|
||||
if (aSource == null) {
|
||||
// If we aren't drawing a favicon, just use an orange color.
|
||||
paint.setColor(Color.HSVToColor(DEFAULT_LAUNCHER_ICON_HSV));
|
||||
canvas.drawRoundRect(new RectF(kOffset, kOffset, size - kOffset, size - kOffset), kRadius, kRadius, paint);
|
||||
} else if (aSource.getWidth() >= insetSize || aSource.getHeight() >= insetSize) {
|
||||
// Otherwise, if the icon is large enough, just draw it.
|
||||
Rect iconBounds = new Rect(0, 0, size, size);
|
||||
canvas.drawBitmap(aSource, null, iconBounds, null);
|
||||
return bitmap;
|
||||
} 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, size - kOffset, size - kOffset), kRadius, kRadius, paint);
|
||||
paint.setColor(Color.argb(100, 255, 255, 255));
|
||||
canvas.drawRoundRect(new RectF(kOffset, kOffset, size - kOffset, size - kOffset), kRadius, kRadius, paint);
|
||||
}
|
||||
|
||||
// draw the overlay
|
||||
Bitmap overlay = BitmapUtils.decodeResource(getApplicationContext(), R.drawable.home_bg);
|
||||
canvas.drawBitmap(overlay, null, new Rect(0, 0, size, size), null);
|
||||
|
||||
// draw the favicon
|
||||
if (aSource == null)
|
||||
aSource = BitmapUtils.decodeResource(getApplicationContext(), R.drawable.home_star);
|
||||
|
||||
// by default, we scale the icon to this size
|
||||
int sWidth = insetSize / 2;
|
||||
int sHeight = sWidth;
|
||||
|
||||
int halfSize = size / 2;
|
||||
canvas.drawBitmap(aSource,
|
||||
null,
|
||||
new Rect(halfSize - sWidth,
|
||||
halfSize - sHeight,
|
||||
halfSize + sWidth,
|
||||
halfSize + sHeight),
|
||||
null);
|
||||
|
||||
return bitmap;
|
||||
}
|
||||
|
||||
@WrapForJNI(stubName = "GetHandlersForMimeTypeWrapper")
|
||||
static String[] getHandlersForMimeType(String aMimeType, String aAction) {
|
||||
Intent intent = getIntentForActionString(aAction);
|
||||
|
@ -2209,6 +2093,13 @@ public class GeckoAppShell
|
|||
public AbsoluteLayout getPluginContainer();
|
||||
public void notifyCheckUpdateResult(String result);
|
||||
public void invalidateOptionsMenu();
|
||||
|
||||
/**
|
||||
* Create a shortcut -- generally a home-screen icon -- linking the given title to the given URI.
|
||||
* @param title of URI to link to.
|
||||
* @param URI to link to.
|
||||
*/
|
||||
public void createShortcut(String title, String URI);
|
||||
};
|
||||
|
||||
private static GeckoInterface sGeckoInterface;
|
||||
|
|
|
@ -26,6 +26,9 @@ import android.graphics.Bitmap;
|
|||
import android.graphics.BitmapFactory;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.RectF;
|
||||
import android.graphics.drawable.BitmapDrawable;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.net.Uri;
|
||||
|
@ -34,6 +37,9 @@ import android.util.Base64;
|
|||
import android.util.Log;
|
||||
|
||||
public final class BitmapUtils {
|
||||
/* Default colors. */
|
||||
private static final float[] DEFAULT_LAUNCHER_ICON_HSV = { 32.0f, 1.0f, 1.0f };
|
||||
|
||||
private static final String LOGTAG = "GeckoBitmapUtils";
|
||||
|
||||
private BitmapUtils() {}
|
||||
|
@ -429,5 +435,57 @@ public final class BitmapUtils {
|
|||
}
|
||||
return icon;
|
||||
}
|
||||
}
|
||||
|
||||
public static Bitmap getLauncherIcon(Context context, Bitmap aSource, int size) {
|
||||
final int kOffset = 6;
|
||||
final int kRadius = 5;
|
||||
int insetSize = aSource != null ? size * 2 / 3 : size;
|
||||
|
||||
Bitmap bitmap = Bitmap.createBitmap(size, size, Bitmap.Config.ARGB_8888);
|
||||
Canvas canvas = new Canvas(bitmap);
|
||||
|
||||
|
||||
// draw a base color
|
||||
Paint paint = new Paint();
|
||||
if (aSource == null) {
|
||||
// If we aren't drawing a favicon, just use an orange color.
|
||||
paint.setColor(Color.HSVToColor(DEFAULT_LAUNCHER_ICON_HSV));
|
||||
canvas.drawRoundRect(new RectF(kOffset, kOffset, size - kOffset, size - kOffset), kRadius, kRadius, paint);
|
||||
} else if (aSource.getWidth() >= insetSize || aSource.getHeight() >= insetSize) {
|
||||
// Otherwise, if the icon is large enough, just draw it.
|
||||
Rect iconBounds = new Rect(0, 0, size, size);
|
||||
canvas.drawBitmap(aSource, null, iconBounds, null);
|
||||
return bitmap;
|
||||
} 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, size - kOffset, size - kOffset), kRadius, kRadius, paint);
|
||||
paint.setColor(Color.argb(100, 255, 255, 255));
|
||||
canvas.drawRoundRect(new RectF(kOffset, kOffset, size - kOffset, size - kOffset), kRadius, kRadius, paint);
|
||||
}
|
||||
|
||||
// draw the overlay
|
||||
Bitmap overlay = BitmapUtils.decodeResource(context, R.drawable.home_bg);
|
||||
canvas.drawBitmap(overlay, null, new Rect(0, 0, size, size), null);
|
||||
|
||||
// draw the favicon
|
||||
if (aSource == null)
|
||||
aSource = BitmapUtils.decodeResource(context, R.drawable.home_star);
|
||||
|
||||
// by default, we scale the icon to this size
|
||||
int sWidth = insetSize / 2;
|
||||
int sHeight = sWidth;
|
||||
|
||||
int halfSize = size / 2;
|
||||
canvas.drawBitmap(aSource,
|
||||
null,
|
||||
new Rect(halfSize - sWidth,
|
||||
halfSize - sHeight,
|
||||
halfSize + sWidth,
|
||||
halfSize + sHeight),
|
||||
null);
|
||||
|
||||
return bitmap;
|
||||
}
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче