| Index: chrome/android/java/src/org/chromium/chrome/browser/webapps/WebApkInfo.java
|
| diff --git a/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebApkInfo.java b/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebApkInfo.java
|
| index 825830b628684d0fd71a2eedff0395bca0327514..2a6cf5d038ef803eca0c7ff86461ac49b7021424 100644
|
| --- a/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebApkInfo.java
|
| +++ b/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebApkInfo.java
|
| @@ -5,11 +5,25 @@
|
| package org.chromium.chrome.browser.webapps;
|
|
|
| import android.content.Intent;
|
| +import android.content.pm.ApplicationInfo;
|
| +import android.content.pm.PackageManager;
|
| +import android.content.res.Resources;
|
| +import android.graphics.Bitmap;
|
| +import android.graphics.BitmapFactory;
|
| +import android.os.Bundle;
|
| import android.text.TextUtils;
|
|
|
| +import org.chromium.base.ContextUtils;
|
| import org.chromium.base.Log;
|
| +import org.chromium.blink_public.platform.WebDisplayMode;
|
| import org.chromium.chrome.browser.ShortcutHelper;
|
| import org.chromium.chrome.browser.util.IntentUtils;
|
| +import org.chromium.content_public.common.ScreenOrientationValues;
|
| +import org.chromium.webapk.lib.common.WebApkConstants;
|
| +import org.chromium.webapk.lib.common.WebApkMetaDataKeys;
|
| +
|
| +import java.util.HashMap;
|
| +import java.util.Map;
|
|
|
| /**
|
| * Stores info for WebAPK.
|
| @@ -18,6 +32,10 @@ public class WebApkInfo extends WebappInfo {
|
| private static final String TAG = "WebApkInfo";
|
|
|
| private String mWebApkPackageName;
|
| + private int mShellApkVersion;
|
| + private String mManifestUrl;
|
| + private String mManifestStartUrl;
|
| + private Map<String, String> mIconUrlToMurmur2HashMap;
|
|
|
| public static WebApkInfo createEmpty() {
|
| return new WebApkInfo();
|
| @@ -42,43 +60,89 @@ public class WebApkInfo extends WebappInfo {
|
| // intent with a valid start URL and arbitrary other data. Only use the start URL, the
|
| // package name and the ShortcutSource from the launch intent and extract the remaining data
|
| // from the <meta-data> in the WebAPK's Android manifest.
|
| - return WebApkMetaDataUtils.extractWebappInfoFromWebApk(webApkPackageName, url, source);
|
| +
|
| + Bundle bundle = extractWebApkMetaData(webApkPackageName);
|
| + if (bundle == null) {
|
| + return null;
|
| + }
|
| +
|
| + String name = IntentUtils.safeGetString(bundle, WebApkMetaDataKeys.NAME);
|
| + String shortName = IntentUtils.safeGetString(bundle, WebApkMetaDataKeys.SHORT_NAME);
|
| + String scope = IntentUtils.safeGetString(bundle, WebApkMetaDataKeys.SCOPE);
|
| +
|
| + int displayMode = displayModeFromString(
|
| + IntentUtils.safeGetString(bundle, WebApkMetaDataKeys.DISPLAY_MODE));
|
| + int orientation = orientationFromString(
|
| + IntentUtils.safeGetString(bundle, WebApkMetaDataKeys.ORIENTATION));
|
| + long themeColor = getLongFromMetaData(bundle, WebApkMetaDataKeys.THEME_COLOR,
|
| + ShortcutHelper.MANIFEST_COLOR_INVALID_OR_MISSING);
|
| + long backgroundColor = getLongFromMetaData(bundle, WebApkMetaDataKeys.BACKGROUND_COLOR,
|
| + ShortcutHelper.MANIFEST_COLOR_INVALID_OR_MISSING);
|
| +
|
| + int shellApkVersion =
|
| + IntentUtils.safeGetInt(bundle, WebApkMetaDataKeys.SHELL_APK_VERSION, 0);
|
| +
|
| + String manifestUrl = IntentUtils.safeGetString(bundle, WebApkMetaDataKeys.WEB_MANIFEST_URL);
|
| + String manifestStartUrl = IntentUtils.safeGetString(bundle, WebApkMetaDataKeys.START_URL);
|
| + Map<String, String> iconUrlToMurmur2HashMap = getIconUrlAndIconMurmur2HashMap(bundle);
|
| +
|
| + int iconId = IntentUtils.safeGetInt(bundle, WebApkMetaDataKeys.ICON_ID, 0);
|
| + Bitmap icon = decodeImageResource(webApkPackageName, iconId);
|
| +
|
| + return create(WebApkConstants.WEBAPK_ID_PREFIX + webApkPackageName, url, scope,
|
| + new Icon(icon), name, shortName, displayMode, orientation, source, themeColor,
|
| + backgroundColor, webApkPackageName, shellApkVersion, manifestUrl, manifestStartUrl,
|
| + iconUrlToMurmur2HashMap);
|
| }
|
|
|
| /**
|
| * Construct a {@link WebApkInfo} instance.
|
| *
|
| - * @param id ID for the webapp.
|
| - * @param url URL for the webapp.
|
| - * @param scope Scope for the webapp.
|
| - * @param encodedIcon Icon to show for the webapp.
|
| - * @param name Name of the webapp.
|
| - * @param shortName The short name of the webapp.
|
| - * @param displayMode Display mode of the webapp.
|
| - * @param orientation Orientation of the webapp.
|
| - * @param source Source where the webapp was added from.
|
| - * @param themeColor The theme color of the webapp.
|
| - * @param backgroundColor The background color of the webapp.
|
| - * @param webApkPackageName The package of the WebAPK associated with the webapp.
|
| + * @param id ID for the WebAPK.
|
| + * @param url URL that the WebAPK should navigate to when launched.
|
| + * @param scope Scope for the WebAPK.
|
| + * @param icon Icon to show for the WebAPK.
|
| + * @param name Name of the WebAPK.
|
| + * @param shortName The short name of the WebAPK.
|
| + * @param displayMode Display mode of the WebAPK.
|
| + * @param orientation Orientation of the WebAPK.
|
| + * @param source Source that the WebAPK was launched from.
|
| + * @param themeColor The theme color of the WebAPK.
|
| + * @param backgroundColor The background color of the WebAPK.
|
| + * @param webApkPackageName The package of the WebAPK.
|
| + * @param shellApkVersion Version of the code in //chrome/android/webapk/shell_apk.
|
| + * @param manifestUrl URL of the Web Manifest.
|
| + * @param manifestStartUrl URL that the WebAPK should navigate to when launched from the
|
| + * homescreen. Different from the {@link url} parameter if the
|
| + * WebAPK is launched from a deep link.
|
| + * @param iconUrlToMurmur2HashMap Map of the WebAPK's icon URLs to Murmur2 hashes of the
|
| + * icon untransformed bytes.
|
| */
|
| - public static WebApkInfo create(String id, String url, String scope, String encodedIcon,
|
| - String name, String shortName, int displayMode, int orientation, int source,
|
| - long themeColor, long backgroundColor, String webApkPackageName) {
|
| + public static WebApkInfo create(String id, String url, String scope, Icon icon, String name,
|
| + String shortName, int displayMode, int orientation, int source, long themeColor,
|
| + long backgroundColor, String webApkPackageName, int shellApkVersion, String manifestUrl,
|
| + String manifestStartUrl, Map<String, String> iconUrlToMurmur2HashMap) {
|
| if (id == null || url == null || webApkPackageName == null) {
|
| Log.e(TAG, "Incomplete data provided: " + id + ", " + url + ", " + webApkPackageName);
|
| return null;
|
| }
|
|
|
| - return new WebApkInfo(id, url, scope, encodedIcon, name, shortName, displayMode,
|
| - orientation, source, themeColor, backgroundColor, webApkPackageName);
|
| + return new WebApkInfo(id, url, scope, icon, name, shortName, displayMode,
|
| + orientation, source, themeColor, backgroundColor, webApkPackageName,
|
| + shellApkVersion, manifestUrl, manifestStartUrl, iconUrlToMurmur2HashMap);
|
| }
|
|
|
| - protected WebApkInfo(String id, String url, String scope, String encodedIcon, String name,
|
| + protected WebApkInfo(String id, String url, String scope, Icon icon, String name,
|
| String shortName, int displayMode, int orientation, int source, long themeColor,
|
| - long backgroundColor, String webApkPackageName) {
|
| - super(id, url, scope, encodedIcon, name, shortName, displayMode, orientation, source,
|
| - themeColor, backgroundColor, false);
|
| + long backgroundColor, String webApkPackageName, int shellApkVersion, String manifestUrl,
|
| + String manifestStartUrl, Map<String, String> iconUrlToMurmur2HashMap) {
|
| + super(id, url, scope, icon, name, shortName, displayMode, orientation, source, themeColor,
|
| + backgroundColor, false);
|
| mWebApkPackageName = webApkPackageName;
|
| + mShellApkVersion = shellApkVersion;
|
| + mManifestUrl = manifestUrl;
|
| + mManifestStartUrl = manifestStartUrl;
|
| + mIconUrlToMurmur2HashMap = iconUrlToMurmur2HashMap;
|
| }
|
|
|
| protected WebApkInfo() {}
|
| @@ -88,6 +152,22 @@ public class WebApkInfo extends WebappInfo {
|
| return mWebApkPackageName;
|
| }
|
|
|
| + public int shellApkVersion() {
|
| + return mShellApkVersion;
|
| + }
|
| +
|
| + public String manifestUrl() {
|
| + return mManifestUrl;
|
| + }
|
| +
|
| + public String manifestStartUrl() {
|
| + return mManifestStartUrl;
|
| + }
|
| +
|
| + public Map<String, String> iconUrlToMurmur2HashMap() {
|
| + return mIconUrlToMurmur2HashMap;
|
| + }
|
| +
|
| @Override
|
| public void setWebappIntentExtras(Intent intent) {
|
| // For launching a {@link WebApkActivity}.
|
| @@ -96,4 +176,164 @@ public class WebApkInfo extends WebappInfo {
|
| intent.putExtra(ShortcutHelper.EXTRA_WEBAPK_PACKAGE_NAME, webApkPackageName());
|
| }
|
|
|
| + /**
|
| + * Extracts meta data from a WebAPK's Android Manifest.
|
| + * @param webApkPackageName WebAPK's package name.
|
| + * @return Bundle with the extracted meta data.
|
| + */
|
| + private static Bundle extractWebApkMetaData(String webApkPackageName) {
|
| + PackageManager packageManager = ContextUtils.getApplicationContext().getPackageManager();
|
| + try {
|
| + ApplicationInfo appInfo = packageManager.getApplicationInfo(
|
| + webApkPackageName, PackageManager.GET_META_DATA);
|
| + return appInfo.metaData;
|
| + } catch (PackageManager.NameNotFoundException e) {
|
| + return null;
|
| + }
|
| + }
|
| +
|
| + /** Decodes bitmap from WebAPK's resources. */
|
| + private static Bitmap decodeImageResource(String webApkPackageName, int resourceId) {
|
| + PackageManager packageManager = ContextUtils.getApplicationContext().getPackageManager();
|
| + try {
|
| + Resources resources = packageManager.getResourcesForApplication(webApkPackageName);
|
| + return BitmapFactory.decodeResource(resources, resourceId);
|
| + } catch (PackageManager.NameNotFoundException e) {
|
| + return null;
|
| + }
|
| + }
|
| +
|
| + /**
|
| + * Extracts long value from the WebAPK's meta data.
|
| + * @param metaData WebAPK meta data to extract the long from.
|
| + * @param name Name of the <meta-data> tag to extract the value from.
|
| + * @param defaultValue Value to return if long value could not be extracted.
|
| + * @return long value.
|
| + */
|
| + private static long getLongFromMetaData(Bundle metaData, String name, long defaultValue) {
|
| + String value = metaData.getString(name);
|
| +
|
| + // The value should be terminated with 'L' to force the value to be a string. According to
|
| + // https://developer.android.com/guide/topics/manifest/meta-data-element.html numeric
|
| + // meta data values can only be retrieved via {@link Bundle#getInt()} and
|
| + // {@link Bundle#getFloat()}. We cannot use {@link Bundle#getFloat()} due to loss of
|
| + // precision.
|
| + if (value == null || !value.endsWith("L")) {
|
| + return defaultValue;
|
| + }
|
| + try {
|
| + return Long.parseLong(value.substring(0, value.length() - 1));
|
| + } catch (NumberFormatException e) {
|
| + }
|
| + return defaultValue;
|
| + }
|
| +
|
| + /**
|
| + * Extract the icon URLs and icon hashes from the WebAPK's meta data, and returns a map of these
|
| + * {URL, hash} pairs. The icon URLs/icon hashes are stored in a single meta data tag in the
|
| + * WebAPK's AndroidManifest.xml as following:
|
| + * "URL1 hash1 URL2 hash2 URL3 hash3..."
|
| + */
|
| + private static Map<String, String> getIconUrlAndIconMurmur2HashMap(Bundle metaData) {
|
| + Map<String, String> iconUrlAndIconMurmur2HashMap = new HashMap<String, String>();
|
| + String iconUrlsAndIconMurmur2Hashes = metaData.getString(
|
| + WebApkMetaDataKeys.ICON_URLS_AND_ICON_MURMUR2_HASHES);
|
| + if (TextUtils.isEmpty(iconUrlsAndIconMurmur2Hashes)) {
|
| + // Open old WebAPKs which support single icon only.
|
| + // TODO(hanxi): crbug.com/665549. Clean up the following code after all the old WebAPKs
|
| + // are updated.
|
| + String iconUrl = metaData.getString(WebApkMetaDataKeys.ICON_URL);
|
| + if (TextUtils.isEmpty(iconUrl)) {
|
| + return iconUrlAndIconMurmur2HashMap;
|
| + }
|
| + iconUrlAndIconMurmur2HashMap.put(iconUrl, getIconMurmur2HashFromMetaData(metaData));
|
| + return iconUrlAndIconMurmur2HashMap;
|
| + }
|
| +
|
| + // Parse the metadata tag which contains "URL1 hash1 URL2 hash2 URL3 hash3..." pairs and
|
| + // create a hash map.
|
| + // TODO(hanxi): crbug.com/666349. Add a test to verify that the icon URLs in WebAPKs'
|
| + // AndroidManifest.xml don't contain space.
|
| + String[] urlsAndHashes = iconUrlsAndIconMurmur2Hashes.split("[ ]+");
|
| + if (urlsAndHashes.length % 2 != 0) {
|
| + Log.e(TAG, "The icon URLs and icon murmur2 hashes don't come in pairs.");
|
| + return iconUrlAndIconMurmur2HashMap;
|
| + }
|
| + for (int i = 0; i < urlsAndHashes.length; i += 2) {
|
| + iconUrlAndIconMurmur2HashMap.put(urlsAndHashes[i], urlsAndHashes[i + 1]);
|
| + }
|
| + return iconUrlAndIconMurmur2HashMap;
|
| + }
|
| +
|
| + /**
|
| + * Extracts icon murmur2 hash from the WebAPK's meta data. Return value is a string because the
|
| + * hash can take values up to 2^64-1 which is greater than {@link Long#MAX_VALUE}.
|
| + * Note: keep this function for supporting old WebAPKs which have single icon only.
|
| + * @param metaData WebAPK meta data to extract the hash from.
|
| + * @return The hash. An empty string if the hash could not be extracted.
|
| + */
|
| + private static String getIconMurmur2HashFromMetaData(Bundle metaData) {
|
| + String value = metaData.getString(WebApkMetaDataKeys.ICON_MURMUR2_HASH);
|
| +
|
| + // The value should be terminated with 'L' to force the value to be a string.
|
| + if (value == null || !value.endsWith("L")) {
|
| + return "";
|
| + }
|
| + return value.substring(0, value.length() - 1);
|
| + }
|
| +
|
| + /**
|
| + * Returns the WebDisplayMode which matches {@link displayMode}.
|
| + * @param displayMode One of https://www.w3.org/TR/appmanifest/#dfn-display-modes-values
|
| + * @return The matching WebDisplayMode. {@link WebDisplayMode#Undefined} if there is no match.
|
| + */
|
| + private static int displayModeFromString(String displayMode) {
|
| + if (displayMode == null) {
|
| + return WebDisplayMode.Undefined;
|
| + }
|
| +
|
| + if (displayMode.equals("fullscreen")) {
|
| + return WebDisplayMode.Fullscreen;
|
| + } else if (displayMode.equals("standalone")) {
|
| + return WebDisplayMode.Standalone;
|
| + } else if (displayMode.equals("minimal-ui")) {
|
| + return WebDisplayMode.MinimalUi;
|
| + } else if (displayMode.equals("browser")) {
|
| + return WebDisplayMode.Browser;
|
| + } else {
|
| + return WebDisplayMode.Undefined;
|
| + }
|
| + }
|
| +
|
| + /**
|
| + * Returns the ScreenOrientationValue which matches {@link orientation}.
|
| + * @param orientation One of https://w3c.github.io/screen-orientation/#orientationlocktype-enum
|
| + * @return The matching ScreenOrientationValue. {@link ScreenOrientationValues#DEFAULT} if there
|
| + * is no match.
|
| + */
|
| + private static int orientationFromString(String orientation) {
|
| + if (orientation == null) {
|
| + return ScreenOrientationValues.DEFAULT;
|
| + }
|
| +
|
| + if (orientation.equals("any")) {
|
| + return ScreenOrientationValues.ANY;
|
| + } else if (orientation.equals("natural")) {
|
| + return ScreenOrientationValues.NATURAL;
|
| + } else if (orientation.equals("landscape")) {
|
| + return ScreenOrientationValues.LANDSCAPE;
|
| + } else if (orientation.equals("landscape-primary")) {
|
| + return ScreenOrientationValues.LANDSCAPE_PRIMARY;
|
| + } else if (orientation.equals("landscape-secondary")) {
|
| + return ScreenOrientationValues.LANDSCAPE_SECONDARY;
|
| + } else if (orientation.equals("portrait")) {
|
| + return ScreenOrientationValues.PORTRAIT;
|
| + } else if (orientation.equals("portrait-primary")) {
|
| + return ScreenOrientationValues.PORTRAIT_PRIMARY;
|
| + } else if (orientation.equals("portrait-secondary")) {
|
| + return ScreenOrientationValues.PORTRAIT_SECONDARY;
|
| + } else {
|
| + return ScreenOrientationValues.DEFAULT;
|
| + }
|
| + }
|
| }
|
|
|