Commit 74c4a854 authored by Rayan Kanso's avatar Rayan Kanso Committed by Commit Bot

[Shortcuts] Populate WebApkInfo with shortcut values.

The information is extracted from the shortcuts.xml resource if present
in the WebAPK.

This is needed to diff with a new WebApkInfo generated from the web app
manifest for update decisions.

Bug: 1045588
Change-Id: Ibe5284d22799e5d5d5c37e53da3da95c6903a5ca
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2027417
Commit-Queue: Rayan Kanso <rayankans@chromium.org>
Reviewed-by: default avatarPeter Kotwicz <pkotwicz@chromium.org>
Cr-Commit-Position: refs/heads/master@{#737907}
parent 5bf17cd5
...@@ -7,6 +7,8 @@ package org.chromium.chrome.browser.webapps; ...@@ -7,6 +7,8 @@ package org.chromium.chrome.browser.webapps;
import org.chromium.chrome.browser.webapps.WebApkInfo.ShareData; import org.chromium.chrome.browser.webapps.WebApkInfo.ShareData;
import org.chromium.chrome.browser.webapps.WebApkInfo.ShareTarget; import org.chromium.chrome.browser.webapps.WebApkInfo.ShareTarget;
import java.util.ArrayList;
import java.util.List;
import java.util.Map; import java.util.Map;
/** /**
...@@ -78,25 +80,46 @@ public class WebApkExtras { ...@@ -78,25 +80,46 @@ public class WebApkExtras {
*/ */
public final ShareData shareData; public final ShareData shareData;
/**
* The list of the WebAPK's shortcuts.
*/
public final List<ShortcutItem> shortcutItems;
/** /**
* WebAPK's version code. * WebAPK's version code.
*/ */
public final int webApkVersionCode; public final int webApkVersionCode;
/** A class that stores information from shortcut items. */
public static class ShortcutItem {
public String name;
public String shortName;
public String launchUrl;
public String iconHash;
public ShortcutItem(String name, String shortName, String launchUrl, String iconHash) {
this.name = name;
this.shortName = shortName;
this.launchUrl = launchUrl;
this.iconHash = iconHash;
}
}
public static WebApkExtras createEmpty() { public static WebApkExtras createEmpty() {
return new WebApkExtras(null /* webApkPackageName */, new WebappIcon(), new WebappIcon(), return new WebApkExtras(null /* webApkPackageName */, new WebappIcon(), new WebappIcon(),
false /* isSplashIconMaskable */, 0 /* shellApkVersion */, null /* manifestUrl */, false /* isSplashIconMaskable */, 0 /* shellApkVersion */, null /* manifestUrl */,
null /* manifestStartUrl */, WebApkDistributor.OTHER, null /* manifestStartUrl */, WebApkDistributor.OTHER,
null /* iconUrlToMurmur2HashMap */, new ShareTarget(), null /* iconUrlToMurmur2HashMap */, new ShareTarget(),
false /* isSplashProvidedByWebApk */, null /* shareData */, false /* isSplashProvidedByWebApk */, null /* shareData */,
0 /* webApkVersionCode */); new ArrayList<>() /* shortcutItems */, 0 /* webApkVersionCode */);
} }
public WebApkExtras(String webApkPackageName, WebappIcon badgeIcon, WebappIcon splashIcon, public WebApkExtras(String webApkPackageName, WebappIcon badgeIcon, WebappIcon splashIcon,
boolean isSplashIconMaskable, int shellApkVersion, String manifestUrl, boolean isSplashIconMaskable, int shellApkVersion, String manifestUrl,
String manifestStartUrl, @WebApkDistributor int distributor, String manifestStartUrl, @WebApkDistributor int distributor,
Map<String, String> iconUrlToMurmur2HashMap, ShareTarget shareTarget, Map<String, String> iconUrlToMurmur2HashMap, ShareTarget shareTarget,
boolean isSplashProvidedByWebApk, ShareData shareData, int webApkVersionCode) { boolean isSplashProvidedByWebApk, ShareData shareData, List<ShortcutItem> shortcutItems,
int webApkVersionCode) {
this.webApkPackageName = webApkPackageName; this.webApkPackageName = webApkPackageName;
this.badgeIcon = badgeIcon; this.badgeIcon = badgeIcon;
this.splashIcon = splashIcon; this.splashIcon = splashIcon;
...@@ -109,6 +132,7 @@ public class WebApkExtras { ...@@ -109,6 +132,7 @@ public class WebApkExtras {
this.shareTarget = shareTarget; this.shareTarget = shareTarget;
this.isSplashProvidedByWebApk = isSplashProvidedByWebApk; this.isSplashProvidedByWebApk = isSplashProvidedByWebApk;
this.shareData = shareData; this.shareData = shareData;
this.shortcutItems = shortcutItems;
this.webApkVersionCode = webApkVersionCode; this.webApkVersionCode = webApkVersionCode;
} }
} }
...@@ -12,10 +12,12 @@ import androidx.annotation.Nullable; ...@@ -12,10 +12,12 @@ import androidx.annotation.Nullable;
import org.chromium.chrome.browser.ShortcutHelper; import org.chromium.chrome.browser.ShortcutHelper;
import org.chromium.chrome.browser.browserservices.BrowserServicesIntentDataProvider; import org.chromium.chrome.browser.browserservices.BrowserServicesIntentDataProvider;
import org.chromium.chrome.browser.webapps.WebApkExtras.ShortcutItem;
import org.chromium.webapk.lib.common.WebApkConstants; import org.chromium.webapk.lib.common.WebApkConstants;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.List;
import java.util.Map; import java.util.Map;
/** /**
...@@ -179,13 +181,14 @@ public class WebApkInfo extends WebappInfo { ...@@ -179,13 +181,14 @@ public class WebApkInfo extends WebappInfo {
String manifestUrl, String manifestStartUrl, @WebApkDistributor int distributor, String manifestUrl, String manifestStartUrl, @WebApkDistributor int distributor,
Map<String, String> iconUrlToMurmur2HashMap, ShareTarget shareTarget, Map<String, String> iconUrlToMurmur2HashMap, ShareTarget shareTarget,
boolean forceNavigation, boolean isSplashProvidedByWebApk, ShareData shareData, boolean forceNavigation, boolean isSplashProvidedByWebApk, ShareData shareData,
int webApkVersionCode) { List<ShortcutItem> shortcutItems, int webApkVersionCode) {
return create(WebApkIntentDataProviderFactory.create(url, scope, primaryIcon, badgeIcon, return create(WebApkIntentDataProviderFactory.create(url, scope, primaryIcon, badgeIcon,
splashIcon, name, shortName, displayMode, orientation, source, themeColor, splashIcon, name, shortName, displayMode, orientation, source, themeColor,
backgroundColor, defaultBackgroundColor, isPrimaryIconMaskable, backgroundColor, defaultBackgroundColor, isPrimaryIconMaskable,
isSplashIconMaskable, webApkPackageName, shellApkVersion, manifestUrl, isSplashIconMaskable, webApkPackageName, shellApkVersion, manifestUrl,
manifestStartUrl, distributor, iconUrlToMurmur2HashMap, shareTarget, manifestStartUrl, distributor, iconUrlToMurmur2HashMap, shareTarget,
forceNavigation, isSplashProvidedByWebApk, shareData, webApkVersionCode)); forceNavigation, isSplashProvidedByWebApk, shareData, shortcutItems,
webApkVersionCode));
} }
private static WebApkInfo create(@Nullable BrowserServicesIntentDataProvider provider) { private static WebApkInfo create(@Nullable BrowserServicesIntentDataProvider provider) {
...@@ -265,6 +268,10 @@ public class WebApkInfo extends WebappInfo { ...@@ -265,6 +268,10 @@ public class WebApkInfo extends WebappInfo {
return getWebApkExtras().shareData; return getWebApkExtras().shareData;
} }
public List<ShortcutItem> shortcutItems() {
return getWebApkExtras().shortcutItems;
}
private WebApkExtras getWebApkExtras() { private WebApkExtras getWebApkExtras() {
WebApkExtras extras = mProvider.getWebApkExtras(); WebApkExtras extras = mProvider.getWebApkExtras();
assert extras != null; assert extras != null;
......
...@@ -11,12 +11,15 @@ import android.content.pm.PackageManager; ...@@ -11,12 +11,15 @@ import android.content.pm.PackageManager;
import android.content.pm.ProviderInfo; import android.content.pm.ProviderInfo;
import android.content.pm.ResolveInfo; import android.content.pm.ResolveInfo;
import android.content.res.Resources; import android.content.res.Resources;
import android.content.res.XmlResourceParser;
import android.net.Uri; import android.net.Uri;
import android.os.Build; import android.os.Build;
import android.os.Bundle; import android.os.Bundle;
import android.text.TextUtils; import android.text.TextUtils;
import android.util.Pair; import android.util.Pair;
import org.xmlpull.v1.XmlPullParser;
import org.chromium.base.ApiCompatibilityUtils; import org.chromium.base.ApiCompatibilityUtils;
import org.chromium.base.ContextUtils; import org.chromium.base.ContextUtils;
import org.chromium.base.Log; import org.chromium.base.Log;
...@@ -26,6 +29,7 @@ import org.chromium.chrome.browser.ShortcutHelper; ...@@ -26,6 +29,7 @@ import org.chromium.chrome.browser.ShortcutHelper;
import org.chromium.chrome.browser.ShortcutSource; import org.chromium.chrome.browser.ShortcutSource;
import org.chromium.chrome.browser.browserservices.BrowserServicesIntentDataProvider; import org.chromium.chrome.browser.browserservices.BrowserServicesIntentDataProvider;
import org.chromium.chrome.browser.util.IntentUtils; import org.chromium.chrome.browser.util.IntentUtils;
import org.chromium.chrome.browser.webapps.WebApkExtras.ShortcutItem;
import org.chromium.chrome.browser.webapps.WebApkInfo.ShareData; import org.chromium.chrome.browser.webapps.WebApkInfo.ShareData;
import org.chromium.chrome.browser.webapps.WebApkInfo.ShareTarget; import org.chromium.chrome.browser.webapps.WebApkInfo.ShareTarget;
import org.chromium.content_public.common.ScreenOrientationValues; import org.chromium.content_public.common.ScreenOrientationValues;
...@@ -47,7 +51,18 @@ import java.util.Map; ...@@ -47,7 +51,18 @@ import java.util.Map;
public class WebApkIntentDataProviderFactory { public class WebApkIntentDataProviderFactory {
public static final String RESOURCE_NAME = "name"; public static final String RESOURCE_NAME = "name";
public static final String RESOURCE_SHORT_NAME = "short_name"; public static final String RESOURCE_SHORT_NAME = "short_name";
public static final String RESOURCE_SHORTCUTS = "shortcuts";
public static final String RESOURCE_STRING_TYPE = "string"; public static final String RESOURCE_STRING_TYPE = "string";
public static final String RESOURCE_XML_TYPE = "xml";
private static final String SHORTCUT_ATTRIBUTE_NAMESPACE =
"http://schemas.android.com/apk/res/android";
private static final String SHORTCUT_TAG_NAME = "shortcut";
private static final String SHORTCUT_INTENT_TAG_NAME = "intent";
private static final String SHORTCUT_NAME_ATTRIBUTE = "shortcutLongLabel";
private static final String SHORTCUT_SHORT_NAME_ATTRIBUTE = "shortcutShortLabel";
private static final String SHORTCUT_ICON_HASH_ATTRIBUTE = "iconHash";
private static final String SHORTCUT_INTENT_LAUNCH_URL_ATTRIBUTE = "data";
private static final String TAG = "WebApkInfo"; private static final String TAG = "WebApkInfo";
...@@ -128,6 +143,54 @@ public class WebApkIntentDataProviderFactory { ...@@ -128,6 +143,54 @@ public class WebApkIntentDataProviderFactory {
: WebApkDistributor.OTHER; : WebApkDistributor.OTHER;
} }
/**
* @param webApkPackageName
* @param resources
* @return A list of shortcut items derived from the parser.
*/
private static List<ShortcutItem> parseShortcutItems(String webApkPackageName, Resources res) {
int shortcutsResId =
res.getIdentifier(RESOURCE_SHORTCUTS, RESOURCE_XML_TYPE, webApkPackageName);
if (shortcutsResId == 0) {
return new ArrayList<>();
}
XmlResourceParser parser = res.getXml(shortcutsResId);
List<ShortcutItem> shortcuts = new ArrayList<>();
try {
int eventType = parser.getEventType();
while (eventType != XmlPullParser.END_DOCUMENT) {
if (eventType == XmlPullParser.START_TAG
&& TextUtils.equals(parser.getName(), SHORTCUT_TAG_NAME)) {
int nameResId = parser.getAttributeResourceValue(
SHORTCUT_ATTRIBUTE_NAMESPACE, SHORTCUT_NAME_ATTRIBUTE, 0);
int shortNameResId = parser.getAttributeResourceValue(
SHORTCUT_ATTRIBUTE_NAMESPACE, SHORTCUT_SHORT_NAME_ATTRIBUTE, 0);
String iconHash = parser.getAttributeValue(null, SHORTCUT_ICON_HASH_ATTRIBUTE);
eventType = parser.next();
if (eventType != XmlPullParser.START_TAG
&& !TextUtils.equals(parser.getName(), SHORTCUT_INTENT_TAG_NAME)) {
// shortcuts.xml is malformed for some reason. Bail out.
return new ArrayList<>();
}
String launchUrl = parser.getAttributeValue(
SHORTCUT_ATTRIBUTE_NAMESPACE, SHORTCUT_INTENT_LAUNCH_URL_ATTRIBUTE);
shortcuts.add(new ShortcutItem(nameResId != 0 ? res.getString(nameResId) : null,
shortNameResId != 0 ? res.getString(shortNameResId) : null,
launchUrl != null ? launchUrl : null, iconHash));
}
eventType = parser.next();
}
} catch (Exception e) {
return new ArrayList<>();
}
return shortcuts;
}
/** /**
* Constructs a BrowserServicesIntentDataProvider from the passed in parameters and <meta-data> * Constructs a BrowserServicesIntentDataProvider from the passed in parameters and <meta-data>
* in the WebAPK's Android manifest. * in the WebAPK's Android manifest.
...@@ -261,7 +324,8 @@ public class WebApkIntentDataProviderFactory { ...@@ -261,7 +324,8 @@ public class WebApkIntentDataProviderFactory {
orientation, source, themeColor, backgroundColor, defaultBackgroundColor, orientation, source, themeColor, backgroundColor, defaultBackgroundColor,
isPrimaryIconMaskable, isSplashIconMaskable, webApkPackageName, shellApkVersion, isPrimaryIconMaskable, isSplashIconMaskable, webApkPackageName, shellApkVersion,
manifestUrl, manifestStartUrl, distributor, iconUrlToMurmur2HashMap, shareTarget, manifestUrl, manifestStartUrl, distributor, iconUrlToMurmur2HashMap, shareTarget,
forceNavigation, isSplashProvidedByWebApk, shareData, apkVersion); forceNavigation, isSplashProvidedByWebApk, shareData,
parseShortcutItems(webApkPackageName, res), apkVersion);
} }
/** /**
...@@ -298,6 +362,7 @@ public class WebApkIntentDataProviderFactory { ...@@ -298,6 +362,7 @@ public class WebApkIntentDataProviderFactory {
* display the splash screen and (2) has a content provider * display the splash screen and (2) has a content provider
* which provides a screenshot of the splash screen. * which provides a screenshot of the splash screen.
* @param shareData Shared information from the share intent. * @param shareData Shared information from the share intent.
* @param shortcutItems A list of shortcut items.
* @param webApkVersionCode WebAPK's version code. * @param webApkVersionCode WebAPK's version code.
*/ */
public static BrowserServicesIntentDataProvider create(String url, String scope, public static BrowserServicesIntentDataProvider create(String url, String scope,
...@@ -308,7 +373,7 @@ public class WebApkIntentDataProviderFactory { ...@@ -308,7 +373,7 @@ public class WebApkIntentDataProviderFactory {
int shellApkVersion, String manifestUrl, String manifestStartUrl, int shellApkVersion, String manifestUrl, String manifestStartUrl,
@WebApkDistributor int distributor, Map<String, String> iconUrlToMurmur2HashMap, @WebApkDistributor int distributor, Map<String, String> iconUrlToMurmur2HashMap,
ShareTarget shareTarget, boolean forceNavigation, boolean isSplashProvidedByWebApk, ShareTarget shareTarget, boolean forceNavigation, boolean isSplashProvidedByWebApk,
ShareData shareData, int webApkVersionCode) { ShareData shareData, List<ShortcutItem> shortcutItems, int webApkVersionCode) {
if (manifestStartUrl == null || webApkPackageName == null) { if (manifestStartUrl == null || webApkPackageName == null) {
Log.e(TAG, "Incomplete data provided: " + manifestStartUrl + ", " + webApkPackageName); Log.e(TAG, "Incomplete data provided: " + manifestStartUrl + ", " + webApkPackageName);
return null; return null;
...@@ -349,7 +414,7 @@ public class WebApkIntentDataProviderFactory { ...@@ -349,7 +414,7 @@ public class WebApkIntentDataProviderFactory {
WebApkExtras webApkExtras = new WebApkExtras(webApkPackageName, badgeIcon, splashIcon, WebApkExtras webApkExtras = new WebApkExtras(webApkPackageName, badgeIcon, splashIcon,
isSplashIconMaskable, shellApkVersion, manifestUrl, manifestStartUrl, distributor, isSplashIconMaskable, shellApkVersion, manifestUrl, manifestStartUrl, distributor,
iconUrlToMurmur2HashMap, shareTarget, isSplashProvidedByWebApk, shareData, iconUrlToMurmur2HashMap, shareTarget, isSplashProvidedByWebApk, shareData,
webApkVersionCode); shortcutItems, webApkVersionCode);
boolean hasCustomToolbarColor = WebappIntentUtils.isLongColorValid(themeColor); boolean hasCustomToolbarColor = WebappIntentUtils.isLongColorValid(themeColor);
int toolbarColor = hasCustomToolbarColor int toolbarColor = hasCustomToolbarColor
? (int) themeColor ? (int) themeColor
......
...@@ -137,7 +137,7 @@ public class WebApkUpdateDataFetcher extends EmptyTabObserver { ...@@ -137,7 +137,7 @@ public class WebApkUpdateDataFetcher extends EmptyTabObserver {
mOldInfo.webApkPackageName(), mOldInfo.shellApkVersion(), mOldInfo.manifestUrl(), mOldInfo.webApkPackageName(), mOldInfo.shellApkVersion(), mOldInfo.manifestUrl(),
manifestStartUrl, WebApkDistributor.BROWSER, iconUrlToMurmur2HashMap, shareTarget, manifestStartUrl, WebApkDistributor.BROWSER, iconUrlToMurmur2HashMap, shareTarget,
mOldInfo.shouldForceNavigation(), mOldInfo.isSplashProvidedByWebApk(), null, mOldInfo.shouldForceNavigation(), mOldInfo.isSplashProvidedByWebApk(), null,
mOldInfo.webApkVersionCode()); mOldInfo.shortcutItems(), mOldInfo.webApkVersionCode());
mObserver.onGotManifestData(info, primaryIconUrl, badgeIconUrl); mObserver.onGotManifestData(info, primaryIconUrl, badgeIconUrl);
} }
......
...@@ -33,6 +33,7 @@ import org.chromium.content_public.common.ScreenOrientationValues; ...@@ -33,6 +33,7 @@ import org.chromium.content_public.common.ScreenOrientationValues;
import org.chromium.net.test.EmbeddedTestServerRule; import org.chromium.net.test.EmbeddedTestServerRule;
import org.chromium.webapk.lib.client.WebApkVersion; import org.chromium.webapk.lib.client.WebApkVersion;
import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
...@@ -167,18 +168,16 @@ public class WebApkUpdateManagerTest { ...@@ -167,18 +168,16 @@ public class WebApkUpdateManagerTest {
TestThreadUtils.runOnUiThreadBlocking(() -> { TestThreadUtils.runOnUiThreadBlocking(() -> {
WebappDataStorage storage = WebappDataStorage storage =
WebappRegistry.getInstance().getWebappDataStorage(WEBAPK_ID); WebappRegistry.getInstance().getWebappDataStorage(WEBAPK_ID);
WebApkInfo info = WebApkInfo.create( WebApkInfo info = WebApkInfo.create("", creationData.scope, null, null, null,
"", creationData.scope, null, null, null, creationData.name, creationData.name, creationData.shortName, creationData.displayMode,
creationData.shortName, creationData.displayMode, creationData.orientation, 0, creationData.orientation, 0, creationData.themeColor,
creationData.themeColor, creationData.backgroundColor, 0, creationData.backgroundColor, 0, creationData.isPrimaryIconMaskable,
creationData.isPrimaryIconMaskable, false /* isSplashIconMaskable */, "", false /* isSplashIconMaskable */, "",
WebApkVersion.REQUEST_UPDATE_FOR_SHELL_APK_VERSION, creationData.manifestUrl, WebApkVersion.REQUEST_UPDATE_FOR_SHELL_APK_VERSION, creationData.manifestUrl,
creationData.startUrl, WebApkDistributor.BROWSER, creationData.startUrl, WebApkDistributor.BROWSER,
creationData.iconUrlToMurmur2HashMap, null, false /* forceNavigation */, creationData.iconUrlToMurmur2HashMap, null, false /* forceNavigation */,
false /* isSplashProvidedByWebApk */, null /* shareData */, false /* isSplashProvidedByWebApk */, null /* shareData */,
1 /* webApkVersionCode */ new ArrayList<>() /* shortcutItems */, 1 /* webApkVersionCode */);
);
updateManager.updateIfNeeded(storage, info); updateManager.updateIfNeeded(storage, info);
}); });
waiter.waitForCallback(0); waiter.waitForCallback(0);
......
...@@ -7,6 +7,7 @@ package org.chromium.chrome.browser.webapps; ...@@ -7,6 +7,7 @@ package org.chromium.chrome.browser.webapps;
import android.content.Intent; import android.content.Intent;
import android.content.res.AssetManager; import android.content.res.AssetManager;
import android.content.res.Resources; import android.content.res.Resources;
import android.content.res.XmlResourceParser;
import android.net.Uri; import android.net.Uri;
import android.os.Build; import android.os.Build;
import android.os.Bundle; import android.os.Bundle;
...@@ -17,7 +18,10 @@ import org.junit.Assert; ...@@ -17,7 +18,10 @@ import org.junit.Assert;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import org.robolectric.RuntimeEnvironment; import org.robolectric.RuntimeEnvironment;
import org.robolectric.android.XmlResourceParserImpl;
import org.robolectric.annotation.Config; import org.robolectric.annotation.Config;
import org.robolectric.res.ResourceTable;
import org.w3c.dom.Document;
import org.chromium.base.test.BaseRobolectricTestRunner; import org.chromium.base.test.BaseRobolectricTestRunner;
import org.chromium.chrome.browser.ShortcutHelper; import org.chromium.chrome.browser.ShortcutHelper;
...@@ -28,10 +32,14 @@ import org.chromium.webapk.lib.common.WebApkMetaDataKeys; ...@@ -28,10 +32,14 @@ import org.chromium.webapk.lib.common.WebApkMetaDataKeys;
import org.chromium.webapk.lib.common.splash.SplashLayout; import org.chromium.webapk.lib.common.splash.SplashLayout;
import org.chromium.webapk.test.WebApkTestHelper; import org.chromium.webapk.test.WebApkTestHelper;
import java.io.ByteArrayInputStream;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
/** /**
* Tests WebApkInfo. * Tests WebApkInfo.
*/ */
...@@ -60,6 +68,28 @@ public class WebApkInfoTest { ...@@ -60,6 +68,28 @@ public class WebApkInfoTest {
private static class FakeResources extends Resources { private static class FakeResources extends Resources {
private final Map<String, Integer> mStringIdMap; private final Map<String, Integer> mStringIdMap;
private final Map<Integer, String> mIdValueMap; private final Map<Integer, String> mIdValueMap;
private String mShortcutsXmlContents;
private class MockXmlResourceParserImpl extends XmlResourceParserImpl {
String mPackageName;
public MockXmlResourceParserImpl(Document document, String fileName, String packageName,
String applicationPackageName, ResourceTable resourceTable) {
super(document, fileName, packageName, applicationPackageName, resourceTable);
mPackageName = packageName;
}
@Override
public int getAttributeResourceValue(
String namespace, String attribute, int defaultValue) {
// Remove the trailing '@'.
String attributeValue = getAttributeValue(namespace, attribute).substring(1);
if (mStringIdMap.containsKey(attributeValue)) {
return mStringIdMap.get(attributeValue);
}
return defaultValue;
}
}
// Do not warn about deprecated call to Resources(); the documentation says code is not // Do not warn about deprecated call to Resources(); the documentation says code is not
// supposed to create its own Resources object, but we are using it to fake out the // supposed to create its own Resources object, but we are using it to fake out the
...@@ -91,9 +121,33 @@ public class WebApkInfoTest { ...@@ -91,9 +121,33 @@ public class WebApkInfoTest {
return Integer.parseInt(getString(id)); return Integer.parseInt(getString(id));
} }
@Override
public XmlResourceParser getXml(int id) {
try {
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setNamespaceAware(true);
factory.setIgnoringComments(true);
factory.setIgnoringElementContentWhitespace(true);
DocumentBuilder documentBuilder = factory.newDocumentBuilder();
Document document = documentBuilder.parse(
new ByteArrayInputStream(mShortcutsXmlContents.getBytes()));
return new MockXmlResourceParserImpl(
document, "file", WEBAPK_PACKAGE_NAME, WEBAPK_PACKAGE_NAME, null);
} catch (Exception e) {
Assert.fail("Failed to create XmlResourceParser");
return null;
}
}
void setShortcutsXmlContent(String content) {
mShortcutsXmlContents = content;
}
public void addStringForTesting( public void addStringForTesting(
String name, String defType, String defPackage, int identifier, String value) { String name, String defType, String defPackage, int identifier, String value) {
String key = getKey(name, defType, defPackage); String key = getKey(name, defType, defPackage);
mStringIdMap.put(key, identifier); mStringIdMap.put(key, identifier);
mIdValueMap.put(identifier, value); mIdValueMap.put(identifier, value);
} }
...@@ -632,4 +686,92 @@ public class WebApkInfoTest { ...@@ -632,4 +686,92 @@ public class WebApkInfoTest {
Assert.assertEquals( Assert.assertEquals(
defaultBackgroundColorInWebApk, info.backgroundColorFallbackToDefault()); defaultBackgroundColorInWebApk, info.backgroundColorFallbackToDefault());
} }
/**
* Test that shortcut items are properly parsed.
*/
@Test
public void testShortcutItemsFromWebApkStrings() {
Bundle bundle = new Bundle();
bundle.putString(WebApkMetaDataKeys.START_URL, START_URL);
WebApkTestHelper.registerWebApkWithMetaData(
WEBAPK_PACKAGE_NAME, bundle, null /* shareTargetMetaData */);
FakeResources res = new FakeResources();
res.addStringForTesting(WebApkIntentDataProviderFactory.RESOURCE_SHORTCUTS,
WebApkIntentDataProviderFactory.RESOURCE_XML_TYPE, WEBAPK_PACKAGE_NAME, 1, null);
res.addStringForTesting("shortcut_1_short_name",
WebApkIntentDataProviderFactory.RESOURCE_STRING_TYPE, WEBAPK_PACKAGE_NAME, 2,
"short name1");
res.addStringForTesting("shortcut_1_name",
WebApkIntentDataProviderFactory.RESOURCE_STRING_TYPE, WEBAPK_PACKAGE_NAME, 3,
"name1");
res.addStringForTesting("shortcut_2_short_name",
WebApkIntentDataProviderFactory.RESOURCE_STRING_TYPE, WEBAPK_PACKAGE_NAME, 4,
"short name2");
res.addStringForTesting("shortcut_2_name",
WebApkIntentDataProviderFactory.RESOURCE_STRING_TYPE, WEBAPK_PACKAGE_NAME, 5,
"name2");
WebApkTestHelper.setResource(WEBAPK_PACKAGE_NAME, res);
Intent intent = createMinimalWebApkIntent(WEBAPK_PACKAGE_NAME, START_URL);
// No shortcuts case.
res.setShortcutsXmlContent(
"<shortcuts xmlns:android='http://schemas.android.com/apk/res/android'/>");
WebApkInfo info = WebApkInfo.create(intent);
Assert.assertEquals(info.shortcutItems().size(), 0);
// One shortcut case.
String oneShortcut =
"<shortcuts xmlns:android='http://schemas.android.com/apk/res/android'>"
+ " <shortcut"
+ " android:shortcutId='shortcut_1'"
+ " android:icon='@drawable/shortcut_1_icon'"
+ " iconHash='1234'"
+ " android:shortcutShortLabel='@string/shortcut_1_short_name'"
+ " android:shortcutLongLabel='@string/shortcut_1_name'>"
+ " <intent android:data='https://example.com/launch1' />"
+ " </shortcut>"
+ "</shortcuts>";
res.setShortcutsXmlContent(oneShortcut);
info = WebApkInfo.create(intent);
Assert.assertEquals(info.shortcutItems().size(), 1);
WebApkExtras.ShortcutItem item = info.shortcutItems().get(0);
Assert.assertEquals(item.name, "name1");
Assert.assertEquals(item.shortName, "short name1");
Assert.assertEquals(item.launchUrl, "https://example.com/launch1");
Assert.assertEquals(item.iconHash, "1234");
// Multiple shortcuts case.
String twoShortcuts =
"<shortcuts xmlns:android='http://schemas.android.com/apk/res/android'>"
+ " <shortcut"
+ " android:shortcutId='shortcut_1'"
+ " android:icon='@drawable/shortcut_1_icon'"
+ " iconHash='1234'"
+ " android:shortcutShortLabel='@string/shortcut_1_short_name'"
+ " android:shortcutLongLabel='@string/shortcut_1_name'>"
+ " <intent android:data='https://example.com/launch1' />"
+ " </shortcut>"
+ " <shortcut"
+ " android:shortcutId='shortcut_2'"
+ " android:icon='@drawable/shortcut_2_icon'"
+ " iconHash='2345'"
+ " android:shortcutShortLabel='@string/shortcut_2_short_name'"
+ " android:shortcutLongLabel='@string/shortcut_2_name'>"
+ " <intent android:data='https://example.com/launch2' />"
+ " </shortcut>"
+ "</shortcuts>";
res.setShortcutsXmlContent(twoShortcuts);
info = WebApkInfo.create(intent);
Assert.assertEquals(info.shortcutItems().size(), 2);
item = info.shortcutItems().get(1);
Assert.assertEquals(item.name, "name2");
Assert.assertEquals(item.shortName, "short name2");
Assert.assertEquals(item.launchUrl, "https://example.com/launch2");
Assert.assertEquals(item.iconHash, "2345");
}
} }
...@@ -53,6 +53,7 @@ import org.chromium.webapk.test.WebApkTestHelper; ...@@ -53,6 +53,7 @@ import org.chromium.webapk.test.WebApkTestHelper;
import java.io.File; import java.io.File;
import java.io.FileOutputStream; import java.io.FileOutputStream;
import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
...@@ -393,7 +394,8 @@ public class WebApkUpdateManagerUnitTest { ...@@ -393,7 +394,8 @@ public class WebApkUpdateManagerUnitTest {
SHARE_TARGET_ENC_TYPE_MULTIPART), SHARE_TARGET_ENC_TYPE_MULTIPART),
manifestData.shareTargetFileNames, manifestData.shareTargetFileAccepts), manifestData.shareTargetFileNames, manifestData.shareTargetFileAccepts),
false /* forceNavigation */, false /* isSplashProvidedByWebApk */, false /* forceNavigation */, false /* isSplashProvidedByWebApk */,
null /* shareData */, 1 /* webApkVersionCode */); null /* shareData */, new ArrayList<>() /* shortcutItems */,
1 /* webApkVersionCode */);
} }
/** /**
......
...@@ -13,6 +13,7 @@ import org.chromium.chrome.browser.webapps.WebApkInfo; ...@@ -13,6 +13,7 @@ import org.chromium.chrome.browser.webapps.WebApkInfo;
import org.chromium.chrome.browser.webapps.WebDisplayMode; import org.chromium.chrome.browser.webapps.WebDisplayMode;
import org.chromium.content_public.common.ScreenOrientationValues; import org.chromium.content_public.common.ScreenOrientationValues;
import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
/** Builder class for {@link WebApkInfo} objects. */ /** Builder class for {@link WebApkInfo} objects. */
...@@ -58,6 +59,6 @@ public class WebApkInfoBuilder { ...@@ -58,6 +59,6 @@ public class WebApkInfoBuilder {
WebApkDistributor.BROWSER, WebApkDistributor.BROWSER,
new HashMap<String, String>() /* iconUrlToMurmur2HashMap */, null, new HashMap<String, String>() /* iconUrlToMurmur2HashMap */, null,
false /* forceNavigation */, false /* isSplashProvidedByWebApk */, null, false /* forceNavigation */, false /* isSplashProvidedByWebApk */, null,
mWebApkVersionCode); new ArrayList<>() /* shortcutItems */, mWebApkVersionCode);
} }
} }
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment