Commit cc374d11 authored by Peter Kotwicz's avatar Peter Kotwicz Committed by Commit Bot

[Android WebAPK] Don't inflate splash icon if we don't use it

New-style WebAPKs use splash screen screenshot from the WebAPK content
provider and don't use WebApkInfo#splashIcon().
This CL introduces WebappLazyIcon which postpones reading the bitmap
from resources till WebappLazyIcon#bitmap() is called.

This CL improves startup on an Android One device by ~20ms.

BUG=995168

Change-Id: I013afadb1a781837830fe1d2ff5ade56fbf83dec
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1759296
Commit-Queue: Peter Kotwicz <pkotwicz@chromium.org>
Reviewed-by: default avatarDominick Ng <dominickn@chromium.org>
Cr-Commit-Position: refs/heads/master@{#689465}
parent 8e902a99
......@@ -1738,6 +1738,7 @@ chrome_java_sources = [
"java/src/org/chromium/chrome/browser/webapps/WebappDelegateFactory.java",
"java/src/org/chromium/chrome/browser/webapps/WebappDirectoryManager.java",
"java/src/org/chromium/chrome/browser/webapps/WebappDisclosureSnackbarController.java",
"java/src/org/chromium/chrome/browser/webapps/WebappIcon.java",
"java/src/org/chromium/chrome/browser/webapps/WebappInfo.java",
"java/src/org/chromium/chrome/browser/webapps/WebappLauncherActivity.java",
"java/src/org/chromium/chrome/browser/webapps/WebappManagedActivity.java",
......
......@@ -11,8 +11,6 @@ import android.content.pm.PackageManager;
import android.content.pm.ProviderInfo;
import android.content.pm.ResolveInfo;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.drawable.BitmapDrawable;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
......@@ -48,7 +46,7 @@ import java.util.Map;
* Stores info for WebAPK.
*/
public class WebApkInfo extends WebappInfo {
// A class that stores share information from share intent.
/** A class that stores share information from share intent. */
public static class ShareData {
public String subject;
public String text;
......@@ -149,8 +147,8 @@ public class WebApkInfo extends WebappInfo {
private static final String TAG = "WebApkInfo";
private Icon mBadgeIcon;
private Icon mSplashIcon;
private WebappIcon mBadgeIcon;
private WebappIcon mSplashIcon;
private String mApkPackageName;
private int mShellApkVersion;
private String mManifestUrl;
......@@ -340,16 +338,11 @@ public class WebApkInfo extends WebappInfo {
int distributor = getDistributor(bundle, webApkPackageName);
int primaryIconId = IntentUtils.safeGetInt(bundle, WebApkMetaDataKeys.ICON_ID, 0);
Bitmap primaryIcon = decodeBitmapFromDrawable(res, primaryIconId);
boolean isPrimaryIconMaskable =
IntentUtils.safeGetBoolean(bundle, WebApkMetaDataKeys.IS_ICON_MASKABLE, false);
int badgeIconId = IntentUtils.safeGetInt(bundle, WebApkMetaDataKeys.BADGE_ICON_ID, 0);
Bitmap badgeIcon = decodeBitmapFromDrawable(res, badgeIconId);
int splashIconId = IntentUtils.safeGetInt(bundle, WebApkMetaDataKeys.SPLASH_ID, 0);
Bitmap splashIcon = decodeBitmapFromDrawable(res, splashIconId);
Pair<String, ShareTarget> shareTargetActivityNameAndData =
extractFirstShareTarget(webApkPackageName);
......@@ -360,10 +353,12 @@ public class WebApkInfo extends WebappInfo {
(canUseSplashFromContentProvider && Build.VERSION.SDK_INT >= Build.VERSION_CODES.N
&& hasContentProviderForSplash(webApkPackageName));
return create(url, scope, new Icon(primaryIcon), new Icon(badgeIcon), new Icon(splashIcon),
name, shortName, displayMode, orientation, source, themeColor, backgroundColor,
defaultBackgroundColor, isPrimaryIconMaskable, webApkPackageName, shellApkVersion,
manifestUrl, manifestStartUrl, distributor, iconUrlToMurmur2HashMap, shareTarget,
return create(url, scope, new WebappIcon(webApkPackageName, primaryIconId),
new WebappIcon(webApkPackageName, badgeIconId),
new WebappIcon(webApkPackageName, splashIconId), name, shortName, displayMode,
orientation, source, themeColor, backgroundColor, defaultBackgroundColor,
isPrimaryIconMaskable, webApkPackageName, shellApkVersion, manifestUrl,
manifestStartUrl, distributor, iconUrlToMurmur2HashMap, shareTarget,
shareTargetActivityName, forceNavigation, isSplashProvidedByWebApk, shareData,
apkVersion);
}
......@@ -405,13 +400,14 @@ public class WebApkInfo extends WebappInfo {
* @param shareData Shared information from the share intent.
* @param webApkVersionCode WebAPK's version code.
*/
public static WebApkInfo create(String url, String scope, Icon primaryIcon, Icon badgeIcon,
Icon splashIcon, String name, String shortName, @WebDisplayMode int displayMode,
int orientation, int source, long themeColor, long backgroundColor,
int defaultBackgroundColor, boolean isPrimaryIconMaskable, String webApkPackageName,
int shellApkVersion, String manifestUrl, String manifestStartUrl,
@WebApkDistributor int distributor, Map<String, String> iconUrlToMurmur2HashMap,
ShareTarget shareTarget, String shareTargetActivityName, boolean forceNavigation,
public static WebApkInfo create(String url, String scope, WebappIcon primaryIcon,
WebappIcon badgeIcon, WebappIcon splashIcon, String name, String shortName,
@WebDisplayMode int displayMode, int orientation, int source, long themeColor,
long backgroundColor, int defaultBackgroundColor, boolean isPrimaryIconMaskable,
String webApkPackageName, int shellApkVersion, String manifestUrl,
String manifestStartUrl, @WebApkDistributor int distributor,
Map<String, String> iconUrlToMurmur2HashMap, ShareTarget shareTarget,
String shareTargetActivityName, boolean forceNavigation,
boolean isSplashProvidedByWebApk, ShareData shareData, int webApkVersionCode) {
if (url == null || manifestStartUrl == null || webApkPackageName == null) {
Log.e(TAG,
......@@ -435,8 +431,8 @@ public class WebApkInfo extends WebappInfo {
webApkVersionCode);
}
protected WebApkInfo(String url, String scope, Icon primaryIcon, Icon badgeIcon,
Icon splashIcon, String name, String shortName, @WebDisplayMode int displayMode,
protected WebApkInfo(String url, String scope, WebappIcon primaryIcon, WebappIcon badgeIcon,
WebappIcon splashIcon, String name, String shortName, @WebDisplayMode int displayMode,
int orientation, int source, long themeColor, long backgroundColor,
int defaultBackgroundColor, boolean isPrimaryIconMaskable, String webApkPackageName,
int shellApkVersion, String manifestUrl, String manifestStartUrl,
......@@ -447,8 +443,8 @@ public class WebApkInfo extends WebappInfo {
shortName, displayMode, orientation, source, themeColor, backgroundColor,
defaultBackgroundColor, false /* isIconGenerated */,
isPrimaryIconMaskable /* isIconAdaptive */, forceNavigation);
mBadgeIcon = badgeIcon;
mSplashIcon = splashIcon;
mBadgeIcon = (badgeIcon != null) ? badgeIcon : new WebappIcon();
mSplashIcon = (splashIcon != null) ? splashIcon : new WebappIcon();
mApkPackageName = webApkPackageName;
mShellApkVersion = shellApkVersion;
mManifestUrl = manifestUrl;
......@@ -470,15 +466,15 @@ public class WebApkInfo extends WebappInfo {
/**
* Returns the badge icon in Bitmap form.
*/
public Bitmap badgeIcon() {
return (mBadgeIcon == null) ? null : mBadgeIcon.decoded();
public WebappIcon badgeIcon() {
return mBadgeIcon;
}
/**
* Returns the splash icon in Bitmap form.
*/
public Bitmap splashIcon() {
return (mSplashIcon == null) ? null : mSplashIcon.decoded();
public WebappIcon splashIcon() {
return mSplashIcon;
}
/** Returns data about the WebAPK's share intent handlers. */
......@@ -567,22 +563,6 @@ public class WebApkInfo extends WebappInfo {
}
}
/**
* Decodes bitmap drawable from WebAPK's resources. This should also be used for XML aliases.
*/
private static Bitmap decodeBitmapFromDrawable(Resources webApkResources, int resourceId) {
if (resourceId == 0) {
return null;
}
try {
BitmapDrawable bitmapDrawable =
(BitmapDrawable) ApiCompatibilityUtils.getDrawable(webApkResources, resourceId);
return bitmapDrawable != null ? bitmapDrawable.getBitmap() : null;
} catch (Resources.NotFoundException e) {
return null;
}
}
/**
* 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
......
......@@ -128,13 +128,13 @@ public class WebApkUpdateDataFetcher extends EmptyTabObserver {
int defaultBackgroundColor = SplashLayout.getDefaultBackgroundColor(appContext);
WebApkInfo info = WebApkInfo.create(mOldInfo.url(), scopeUrl,
new WebApkInfo.Icon(primaryIconBitmap), new WebApkInfo.Icon(badgeIconBitmap), null,
name, shortName, displayMode, orientation, mOldInfo.source(), themeColor,
backgroundColor, defaultBackgroundColor, isPrimaryIconMaskable,
mOldInfo.webApkPackageName(), mOldInfo.shellApkVersion(), mOldInfo.manifestUrl(),
manifestStartUrl, WebApkInfo.WebApkDistributor.BROWSER, iconUrlToMurmur2HashMap,
shareTarget, null, mOldInfo.shouldForceNavigation(),
mOldInfo.isSplashProvidedByWebApk(), null, mOldInfo.webApkVersionCode());
new WebappIcon(primaryIconBitmap), new WebappIcon(badgeIconBitmap), null, name,
shortName, displayMode, orientation, mOldInfo.source(), themeColor, backgroundColor,
defaultBackgroundColor, isPrimaryIconMaskable, mOldInfo.webApkPackageName(),
mOldInfo.shellApkVersion(), mOldInfo.manifestUrl(), manifestStartUrl,
WebApkInfo.WebApkDistributor.BROWSER, iconUrlToMurmur2HashMap, shareTarget, null,
mOldInfo.shouldForceNavigation(), mOldInfo.isSplashProvidedByWebApk(), null,
mOldInfo.webApkVersionCode());
mObserver.onGotManifestData(info, primaryIconUrl, badgeIconUrl);
}
......
......@@ -374,11 +374,12 @@ public class WebApkUpdateManager implements WebApkUpdateDataFetcher.Observer {
WebApkUpdateManagerJni.get().storeWebApkUpdateRequestToFile(updateRequestPath,
info.manifestStartUrl(), info.scopeUrl(), info.name(), info.shortName(),
primaryIconUrl, info.icon(), info.isIconAdaptive(), badgeIconUrl, info.badgeIcon(),
iconUrls, iconHashes, info.displayMode(), info.orientation(), info.themeColor(),
info.backgroundColor(), info.shareTarget().getAction(),
info.shareTarget().getParamTitle(), info.shareTarget().getParamText(),
info.shareTarget().getParamUrl(), info.shareTarget().isShareMethodPost(),
primaryIconUrl, info.icon().bitmap(), info.isIconAdaptive(), badgeIconUrl,
info.badgeIcon().bitmap(), iconUrls, iconHashes, info.displayMode(),
info.orientation(), info.themeColor(), info.backgroundColor(),
info.shareTarget().getAction(), info.shareTarget().getParamTitle(),
info.shareTarget().getParamText(), info.shareTarget().getParamUrl(),
info.shareTarget().isShareMethodPost(),
info.shareTarget().isShareEncTypeMultipart(), info.shareTarget().getFileNames(),
info.shareTarget().getFileAccepts(), info.manifestUrl(), info.webApkPackageName(),
versionCode, isManifestStale, updateReason, callback);
......
......@@ -715,7 +715,7 @@ public class WebappActivity extends SingleTabActivity {
Bitmap icon = null;
if (mWebappInfo.icon() != null) {
icon = mWebappInfo.icon();
icon = mWebappInfo.icon().bitmap();
} else if (getActivityTab() != null) {
icon = mLargestFavicon;
}
......
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package org.chromium.chrome.browser.webapps;
import android.content.pm.PackageManager;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.drawable.BitmapDrawable;
import org.chromium.base.ApiCompatibilityUtils;
import org.chromium.base.ContextUtils;
import org.chromium.chrome.browser.ShortcutHelper;
/** Represents bitmap icon. Lazily converts icon format. */
public class WebappIcon {
private String mEncoded;
private Bitmap mBitmap;
private String mWebApkPackageName;
private int mResourceId;
public WebappIcon() {}
public WebappIcon(String encoded) {
mEncoded = encoded;
}
public WebappIcon(Bitmap bitmap) {
mBitmap = bitmap;
}
public WebappIcon(String webApkPackageName, int resourceId) {
mWebApkPackageName = webApkPackageName;
mResourceId = resourceId;
}
public String encoded() {
if (mEncoded == null) {
mEncoded = ShortcutHelper.encodeBitmapAsString(bitmap());
}
return mEncoded;
}
public Bitmap bitmap() {
if (mBitmap == null) {
mBitmap = generateBitmap();
}
return mBitmap;
}
private Bitmap generateBitmap() {
if (mEncoded != null) {
return ShortcutHelper.decodeBitmapFromString(mEncoded);
}
if (mWebApkPackageName != null && mResourceId != 0) {
try {
PackageManager pm = ContextUtils.getApplicationContext().getPackageManager();
Resources res = pm.getResourcesForApplication(mWebApkPackageName);
BitmapDrawable bitmapDrawable =
(BitmapDrawable) ApiCompatibilityUtils.getDrawable(res, mResourceId);
return bitmapDrawable != null ? bitmapDrawable.getBitmap() : null;
} catch (Exception e) {
}
}
return null;
}
}
......@@ -5,7 +5,6 @@
package org.chromium.chrome.browser.webapps;
import android.content.Intent;
import android.graphics.Bitmap;
import android.text.TextUtils;
import org.chromium.base.ContextUtils;
......@@ -23,39 +22,8 @@ import org.chromium.webapk.lib.common.splash.SplashLayout;
public class WebappInfo {
private static final String TAG = "WebappInfo";
/**
* Parameter for {@link WebappInfo#create} method which allows either a Bitmap or a PNG
* encoded string to be passed as a parameter.
*/
public static class Icon {
private String mEncoded;
private Bitmap mDecoded;
public Icon(String encoded) {
mEncoded = encoded;
}
public Icon(Bitmap decoded) {
mDecoded = decoded;
}
public String encoded() {
if (mEncoded == null) {
mEncoded = ShortcutHelper.encodeBitmapAsString(mDecoded);
}
return mEncoded;
}
public Bitmap decoded() {
if (mDecoded == null) {
mDecoded = ShortcutHelper.decodeBitmapFromString(mEncoded);
}
return mDecoded;
}
}
private String mId;
private Icon mIcon;
private WebappIcon mIcon;
private String mUrl;
private String mScopeUrl;
private String mName;
......@@ -143,7 +111,7 @@ public class WebappInfo {
int defaultBackgroundColor =
SplashLayout.getDefaultBackgroundColor(ContextUtils.getApplicationContext());
return new WebappInfo(id, url, scope, new Icon(icon), name, shortName, displayMode,
return new WebappInfo(id, url, scope, new WebappIcon(icon), name, shortName, displayMode,
orientation, source, themeColor, backgroundColor, defaultBackgroundColor,
isIconGenerated, isIconAdaptive, forceNavigation);
}
......@@ -166,7 +134,7 @@ public class WebappInfo {
* @param forceNavigation Whether the webapp should navigate to {@link url} if the
* webapp is already open.
*/
protected WebappInfo(String id, String url, String scope, Icon icon, String name,
protected WebappInfo(String id, String url, String scope, WebappIcon icon, String name,
String shortName, @WebDisplayMode int displayMode, int orientation, int source,
long themeColor, long backgroundColor, int defaultBackgroundColor,
boolean isIconGenerated, boolean isIconAdaptive, boolean forceNavigation) {
......@@ -174,7 +142,7 @@ public class WebappInfo {
scope = ShortcutHelper.getScopeFromUrl(url);
}
mIcon = icon;
mIcon = (icon != null) ? icon : new WebappIcon();
mId = id;
mName = name;
mShortName = shortName;
......@@ -287,17 +255,11 @@ public class WebappInfo {
return hasValidBackgroundColor() ? (int) mBackgroundColor : mDefaultBackgroundColor;
}
// This is needed for clients that want to send the icon through an intent.
public String encodedIcon() {
return (mIcon == null) ? null : mIcon.encoded();
}
/**
* Returns the icon in Bitmap form.
* Returns the icon.
*/
public Bitmap icon() {
// TODO(yusufo) : Add a way to plumb this through for Trusted Web Activity.
return (mIcon == null) ? null : mIcon.decoded();
public WebappIcon icon() {
return mIcon;
}
/**
......@@ -331,7 +293,7 @@ public class WebappInfo {
intent.putExtra(ShortcutHelper.EXTRA_URL, url());
intent.putExtra(ShortcutHelper.EXTRA_FORCE_NAVIGATION, shouldForceNavigation());
intent.putExtra(ShortcutHelper.EXTRA_SCOPE, scopeUrl());
intent.putExtra(ShortcutHelper.EXTRA_ICON, encodedIcon());
intent.putExtra(ShortcutHelper.EXTRA_ICON, icon().encoded());
intent.putExtra(ShortcutHelper.EXTRA_VERSION, ShortcutHelper.WEBAPP_SHORTCUT_VERSION);
intent.putExtra(ShortcutHelper.EXTRA_NAME, name());
intent.putExtra(ShortcutHelper.EXTRA_SHORT_NAME, shortName());
......
......@@ -83,8 +83,8 @@ public class WebappSplashDelegate implements SplashDelegate {
splashScreen.setBackgroundColor(backgroundColor);
if (mWebappInfo.isForWebApk()) {
initializeWebApkInfoSplashLayout(
splashScreen, backgroundColor, ((WebApkInfo) mWebappInfo).splashIcon());
initializeWebApkInfoSplashLayout(splashScreen, backgroundColor,
((WebApkInfo) mWebappInfo).splashIcon().bitmap());
return splashScreen;
}
......@@ -114,7 +114,7 @@ public class WebappSplashDelegate implements SplashDelegate {
// TODO(crbug.com/977173): assign selectedIconAdaptive to correct value
boolean selectedIconAdaptive = false;
if (selectedIcon == null) {
selectedIcon = mWebappInfo.icon();
selectedIcon = mWebappInfo.icon().bitmap();
selectedIconGenerated = mWebappInfo.isIconGenerated();
selectedIconAdaptive = mWebappInfo.isIconAdaptive();
}
......
......@@ -171,9 +171,9 @@ public class WebApkInfoTest {
Assert.assertEquals(
(Build.VERSION.SDK_INT >= Build.VERSION_CODES.M), info.isSplashProvidedByWebApk());
Assert.assertEquals(null, info.icon());
Assert.assertEquals(null, info.badgeIcon());
Assert.assertEquals(null, info.splashIcon());
Assert.assertEquals(null, info.icon().bitmap());
Assert.assertEquals(null, info.badgeIcon().bitmap());
Assert.assertEquals(null, info.splashIcon().bitmap());
WebApkInfo.ShareTarget shareTarget = info.shareTarget();
Assert.assertNotNull(shareTarget);
......
......@@ -360,10 +360,9 @@ public class WebApkUpdateManagerUnitTest {
final String kPackageName = "org.random.webapk";
return WebApkInfo.create("", manifestData.scopeUrl,
new WebApkInfo.Icon(manifestData.primaryIcon),
new WebApkInfo.Icon(manifestData.badgeIcon), null, manifestData.name,
manifestData.shortName, manifestData.displayMode, manifestData.orientation, -1,
manifestData.themeColor, manifestData.backgroundColor,
new WebappIcon(manifestData.primaryIcon), new WebappIcon(manifestData.badgeIcon),
null, manifestData.name, manifestData.shortName, manifestData.displayMode,
manifestData.orientation, -1, manifestData.themeColor, manifestData.backgroundColor,
manifestData.defaultBackgroundColor, false /* isPrimaryIconMaskable */,
kPackageName, -1, WEB_MANIFEST_URL, manifestData.startUrl,
WebApkInfo.WebApkDistributor.BROWSER, manifestData.iconUrlToMurmur2HashMap,
......
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