Commit 0c3be6d9 authored by Peter E Conn's avatar Peter E Conn Committed by Commit Bot

👹 Prefer maskable icons in InstallableManager when supported.

Web App Manifests allow icons to be specified with the "maskable"
purpose [1]. These icons are designed with enough space on the sides
to allow the user agent to mask them (eg, cut the icon into a circle).

On devices that support this, attempt to load a maskable icon.

[1] https://w3c.github.io/manifest/#purpose-member

Bug: 904354
Change-Id: I08c404d7b956e678b37f995e9ae0d3f13a5a49fe
Reviewed-on: https://chromium-review.googlesource.com/c/1333778
Commit-Queue: Peter Conn <peconn@chromium.org>
Reviewed-by: default avatarDominick Ng <dominickn@chromium.org>
Reviewed-by: default avatarMatt Giuca <mgiuca@chromium.org>
Cr-Commit-Position: refs/heads/master@{#608758}
parent 95012fbd
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
#include <vector> #include <vector>
#include "base/android/build_info.h"
#include "base/bind.h" #include "base/bind.h"
#include "base/location.h" #include "base/location.h"
#include "base/metrics/histogram_macros.h" #include "base/metrics/histogram_macros.h"
...@@ -44,9 +45,17 @@ GURL GetShortcutUrl(const content::WebContents* web_contents) { ...@@ -44,9 +45,17 @@ GURL GetShortcutUrl(const content::WebContents* web_contents) {
web_contents->GetVisibleURL()); web_contents->GetVisibleURL());
} }
bool DoesAndroidSupportMaskableIcons() {
// TODO(peconn): Enable once Chrome on Android correctly handles maskable
// icons (https://crbug.com/904354).
return base::android::BuildInfo::GetInstance()->sdk_int() >=
base::android::SDK_VERSION_OREO && false;
}
InstallableParams ParamsToPerformManifestAndIconFetch() { InstallableParams ParamsToPerformManifestAndIconFetch() {
InstallableParams params; InstallableParams params;
params.valid_primary_icon = true; params.valid_primary_icon = true;
params.prefer_maskable_icon = DoesAndroidSupportMaskableIcons();
params.valid_badge_icon = true; params.valid_badge_icon = true;
params.wait_for_worker = true; params.wait_for_worker = true;
return params; return params;
...@@ -58,6 +67,7 @@ InstallableParams ParamsToPerformInstallableCheck() { ...@@ -58,6 +67,7 @@ InstallableParams ParamsToPerformInstallableCheck() {
params.valid_manifest = true; params.valid_manifest = true;
params.has_worker = true; params.has_worker = true;
params.valid_primary_icon = true; params.valid_primary_icon = true;
params.prefer_maskable_icon = DoesAndroidSupportMaskableIcons();
params.wait_for_worker = true; params.wait_for_worker = true;
return params; return params;
} }
......
...@@ -170,6 +170,7 @@ class TestInstallableManager : public InstallableManager { ...@@ -170,6 +170,7 @@ class TestInstallableManager : public InstallableManager {
callback.Run({code, GURL(kDefaultManifestUrl), &manifest_, callback.Run({code, GURL(kDefaultManifestUrl), &manifest_,
params.valid_primary_icon ? primary_icon_url_ : GURL(), params.valid_primary_icon ? primary_icon_url_ : GURL(),
params.valid_primary_icon ? primary_icon_.get() : nullptr, params.valid_primary_icon ? primary_icon_.get() : nullptr,
params.prefer_maskable_icon,
params.valid_badge_icon ? badge_icon_url_ : GURL(), params.valid_badge_icon ? badge_icon_url_ : GURL(),
params.valid_badge_icon ? badge_icon_.get() : nullptr, params.valid_badge_icon ? badge_icon_.get() : nullptr,
params.valid_manifest ? is_installable : false, params.valid_manifest ? is_installable : false,
......
...@@ -145,6 +145,7 @@ class TestBookmarkAppHelper : public BookmarkAppHelper { ...@@ -145,6 +145,7 @@ class TestBookmarkAppHelper : public BookmarkAppHelper {
&manifest, &manifest,
GURL(kAppIconURL1), GURL(kAppIconURL1),
&bitmap_, &bitmap_,
false,
GURL(), GURL(),
nullptr, nullptr,
installable, installable,
......
...@@ -52,7 +52,8 @@ FakeInstallableManager::CreateForWebContentsWithManifest( ...@@ -52,7 +52,8 @@ FakeInstallableManager::CreateForWebContentsWithManifest(
auto installable_data = std::make_unique<InstallableData>( auto installable_data = std::make_unique<InstallableData>(
installable_code, manifest_url, installable_manager->manifest_.get(), installable_code, manifest_url, installable_manager->manifest_.get(),
icon_url, icon.get(), icon_url, icon.get(), valid_manifest, has_worker); icon_url, icon.get(), false, icon_url, icon.get(), valid_manifest,
has_worker);
installable_manager->data_ = std::move(installable_data); installable_manager->data_ = std::move(installable_data);
......
...@@ -9,6 +9,7 @@ InstallableData::InstallableData(InstallableStatusCode error_code, ...@@ -9,6 +9,7 @@ InstallableData::InstallableData(InstallableStatusCode error_code,
const blink::Manifest* manifest, const blink::Manifest* manifest,
GURL primary_icon_url, GURL primary_icon_url,
const SkBitmap* primary_icon, const SkBitmap* primary_icon,
bool has_maskable_primary_icon,
GURL badge_icon_url, GURL badge_icon_url,
const SkBitmap* badge_icon, const SkBitmap* badge_icon,
bool valid_manifest, bool valid_manifest,
...@@ -18,6 +19,7 @@ InstallableData::InstallableData(InstallableStatusCode error_code, ...@@ -18,6 +19,7 @@ InstallableData::InstallableData(InstallableStatusCode error_code,
manifest(manifest), manifest(manifest),
primary_icon_url(primary_icon_url), primary_icon_url(primary_icon_url),
primary_icon(primary_icon), primary_icon(primary_icon),
has_maskable_primary_icon(has_maskable_primary_icon),
badge_icon_url(badge_icon_url), badge_icon_url(badge_icon_url),
badge_icon(badge_icon), badge_icon(badge_icon),
valid_manifest(valid_manifest), valid_manifest(valid_manifest),
......
...@@ -20,6 +20,7 @@ struct InstallableData { ...@@ -20,6 +20,7 @@ struct InstallableData {
const blink::Manifest* manifest, const blink::Manifest* manifest,
GURL primary_icon_url, GURL primary_icon_url,
const SkBitmap* primary_icon, const SkBitmap* primary_icon,
bool has_maskable_primary_icon,
GURL badge_icon_url, GURL badge_icon_url,
const SkBitmap* badge_icon, const SkBitmap* badge_icon,
bool valid_manifest, bool valid_manifest,
...@@ -46,6 +47,10 @@ struct InstallableData { ...@@ -46,6 +47,10 @@ struct InstallableData {
// reason will be in error_code. // reason will be in error_code.
const SkBitmap* primary_icon; const SkBitmap* primary_icon;
// Whether the primary icon had the 'maskable' purpose, meaningless if no
// primary_icon was requested.
const bool has_maskable_primary_icon;
// Empty if no badge_icon was requested. // Empty if no badge_icon was requested.
const GURL badge_icon_url; const GURL badge_icon_url;
......
...@@ -63,6 +63,8 @@ int GetIdealBadgeIconSizeInPx() { ...@@ -63,6 +63,8 @@ int GetIdealBadgeIconSizeInPx() {
#endif #endif
} }
using IconPurpose = blink::Manifest::ImageResource::Purpose;
// Returns true if the overall security state of |web_contents| is sufficient to // Returns true if the overall security state of |web_contents| is sufficient to
// be considered installable. // be considered installable.
bool IsContentSecure(content::WebContents* web_contents) { bool IsContentSecure(content::WebContents* web_contents) {
...@@ -221,10 +223,33 @@ bool InstallableManager::IsIconFetched(const IconPurpose purpose) const { ...@@ -221,10 +223,33 @@ bool InstallableManager::IsIconFetched(const IconPurpose purpose) const {
return it != icons_.end() && it->second.fetched; return it != icons_.end() && it->second.fetched;
} }
bool InstallableManager::IsPrimaryIconFetched(
const InstallableParams& params) const {
return IsIconFetched(GetPrimaryIconPurpose(params));
}
void InstallableManager::SetIconFetched(const IconPurpose purpose) { void InstallableManager::SetIconFetched(const IconPurpose purpose) {
icons_[purpose].fetched = true; icons_[purpose].fetched = true;
} }
IconPurpose InstallableManager::GetPrimaryIconPurpose(
const InstallableParams& params) const {
if (params.prefer_maskable_icon) {
const auto it = icons_.find(IconPurpose::MASKABLE);
// If we haven't attempted fetching the maskable icon yet, we still plan
// to use that one for primary.
if (it == icons_.end() || !it->second.fetched)
return IconPurpose::MASKABLE;
// If fetching was successful, use MASKABLE.
if (it->second.error == NO_ERROR_DETECTED)
return IconPurpose::MASKABLE;
}
// Otherwise fall back to ANY.
return IconPurpose::ANY;
}
InstallableStatusCode InstallableManager::GetErrorCode( InstallableStatusCode InstallableManager::GetErrorCode(
const InstallableParams& params) { const InstallableParams& params) {
if (params.check_eligibility && eligibility_->error != NO_ERROR_DETECTED) if (params.check_eligibility && eligibility_->error != NO_ERROR_DETECTED)
...@@ -240,7 +265,7 @@ InstallableStatusCode InstallableManager::GetErrorCode( ...@@ -240,7 +265,7 @@ InstallableStatusCode InstallableManager::GetErrorCode(
return worker_->error; return worker_->error;
if (params.valid_primary_icon) { if (params.valid_primary_icon) {
IconProperty& icon = icons_[IconPurpose::ANY]; IconProperty& icon = icons_[GetPrimaryIconPurpose(params)];
if (icon.error != NO_ERROR_DETECTED) if (icon.error != NO_ERROR_DETECTED)
return icon.error; return icon.error;
} }
...@@ -307,7 +332,7 @@ bool InstallableManager::IsComplete(const InstallableParams& params) const { ...@@ -307,7 +332,7 @@ bool InstallableManager::IsComplete(const InstallableParams& params) const {
manifest_->fetched && manifest_->fetched &&
(!params.valid_manifest || valid_manifest_->fetched) && (!params.valid_manifest || valid_manifest_->fetched) &&
(!params.has_worker || worker_->fetched) && (!params.has_worker || worker_->fetched) &&
(!params.valid_primary_icon || IsIconFetched(IconPurpose::ANY)) && (!params.valid_primary_icon || IsPrimaryIconFetched(params)) &&
(!params.valid_badge_icon || IsIconFetched(IconPurpose::BADGE)); (!params.valid_badge_icon || IsIconFetched(IconPurpose::BADGE));
} }
...@@ -347,6 +372,7 @@ void InstallableManager::SetManifestDependentTasksComplete() { ...@@ -347,6 +372,7 @@ void InstallableManager::SetManifestDependentTasksComplete() {
worker_->fetched = true; worker_->fetched = true;
SetIconFetched(IconPurpose::ANY); SetIconFetched(IconPurpose::ANY);
SetIconFetched(IconPurpose::BADGE); SetIconFetched(IconPurpose::BADGE);
SetIconFetched(IconPurpose::MASKABLE);
} }
void InstallableManager::RunCallback(const InstallableTask& task, void InstallableManager::RunCallback(const InstallableTask& task,
...@@ -354,11 +380,15 @@ void InstallableManager::RunCallback(const InstallableTask& task, ...@@ -354,11 +380,15 @@ void InstallableManager::RunCallback(const InstallableTask& task,
const InstallableParams& params = task.params; const InstallableParams& params = task.params;
IconProperty null_icon; IconProperty null_icon;
IconProperty* primary_icon = &null_icon; IconProperty* primary_icon = &null_icon;
bool has_maskable_primary_icon = false;
IconProperty* badge_icon = &null_icon; IconProperty* badge_icon = &null_icon;
if (params.valid_primary_icon && base::ContainsKey(icons_, IconPurpose::ANY)) IconPurpose purpose = GetPrimaryIconPurpose(params);
primary_icon = &icons_[IconPurpose::ANY]; if (params.valid_primary_icon && IsIconFetched(purpose)) {
if (params.valid_badge_icon && base::ContainsKey(icons_, IconPurpose::BADGE)) primary_icon = &icons_[purpose];
has_maskable_primary_icon = (purpose == IconPurpose::MASKABLE);
}
if (params.valid_badge_icon && IsIconFetched(IconPurpose::BADGE))
badge_icon = &icons_[IconPurpose::BADGE]; badge_icon = &icons_[IconPurpose::BADGE];
InstallableData data = { InstallableData data = {
...@@ -367,6 +397,7 @@ void InstallableManager::RunCallback(const InstallableTask& task, ...@@ -367,6 +397,7 @@ void InstallableManager::RunCallback(const InstallableTask& task,
&manifest(), &manifest(),
primary_icon->url, primary_icon->url,
primary_icon->icon.get(), primary_icon->icon.get(),
has_maskable_primary_icon,
badge_icon->url, badge_icon->url,
badge_icon->icon.get(), badge_icon->icon.get(),
valid_manifest_->is_valid, valid_manifest_->is_valid,
...@@ -404,6 +435,11 @@ void InstallableManager::WorkOnTask() { ...@@ -404,6 +435,11 @@ void InstallableManager::WorkOnTask() {
CheckEligiblity(); CheckEligiblity();
} else if (!manifest_->fetched) { } else if (!manifest_->fetched) {
FetchManifest(); FetchManifest();
} else if (params.valid_primary_icon && params.prefer_maskable_icon &&
!IsIconFetched(IconPurpose::MASKABLE)) {
CheckAndFetchBestIcon(GetIdealPrimaryIconSizeInPx(),
GetMinimumPrimaryIconSizeInPx(),
IconPurpose::MASKABLE);
} else if (params.valid_primary_icon && !IsIconFetched(IconPurpose::ANY)) { } else if (params.valid_primary_icon && !IsIconFetched(IconPurpose::ANY)) {
CheckAndFetchBestIcon(GetIdealPrimaryIconSizeInPx(), CheckAndFetchBestIcon(GetIdealPrimaryIconSizeInPx(),
GetMinimumPrimaryIconSizeInPx(), IconPurpose::ANY); GetMinimumPrimaryIconSizeInPx(), IconPurpose::ANY);
......
...@@ -133,10 +133,14 @@ class InstallableManager ...@@ -133,10 +133,14 @@ class InstallableManager
// Returns true if |purpose| matches any fetched icon, or false if no icon has // Returns true if |purpose| matches any fetched icon, or false if no icon has
// been requested yet or there is no match. // been requested yet or there is no match.
bool IsIconFetched(const IconPurpose purpose) const; bool IsIconFetched(const IconPurpose purpose) const;
bool IsPrimaryIconFetched(const InstallableParams& params) const;
// Sets the icon matching |purpose| as fetched. // Sets the icon matching |purpose| as fetched.
void SetIconFetched(const IconPurpose purpose); void SetIconFetched(const IconPurpose purpose);
// Gets the purpose of the icon to use as a primary icon.
IconPurpose GetPrimaryIconPurpose(const InstallableParams& params) const;
// Returns the error code associated with the resources requested in |params|, // Returns the error code associated with the resources requested in |params|,
// or NO_ERROR_DETECTED if there is no error. // or NO_ERROR_DETECTED if there is no error.
InstallableStatusCode GetErrorCode(const InstallableParams& params); InstallableStatusCode GetErrorCode(const InstallableParams& params);
......
...@@ -53,6 +53,14 @@ InstallableParams GetPrimaryIconAndBadgeIconParams() { ...@@ -53,6 +53,14 @@ InstallableParams GetPrimaryIconAndBadgeIconParams() {
return params; return params;
} }
InstallableParams GetPrimaryIconPreferMaskableParams() {
InstallableParams params = GetManifestParams();
params.valid_primary_icon = true;
params.prefer_maskable_icon = true;
params.wait_for_worker = true;
return params;
}
} // anonymous namespace } // anonymous namespace
// Used only for testing pages with no service workers. This class will dispatch // Used only for testing pages with no service workers. This class will dispatch
...@@ -106,6 +114,7 @@ class CallbackTester { ...@@ -106,6 +114,7 @@ class CallbackTester {
primary_icon_url_ = data.primary_icon_url; primary_icon_url_ = data.primary_icon_url;
if (data.primary_icon) if (data.primary_icon)
primary_icon_.reset(new SkBitmap(*data.primary_icon)); primary_icon_.reset(new SkBitmap(*data.primary_icon));
has_maskable_primary_icon_ = data.has_maskable_primary_icon;
badge_icon_url_ = data.badge_icon_url; badge_icon_url_ = data.badge_icon_url;
if (data.badge_icon) if (data.badge_icon)
badge_icon_.reset(new SkBitmap(*data.badge_icon)); badge_icon_.reset(new SkBitmap(*data.badge_icon));
...@@ -119,6 +128,7 @@ class CallbackTester { ...@@ -119,6 +128,7 @@ class CallbackTester {
const blink::Manifest& manifest() const { return manifest_; } const blink::Manifest& manifest() const { return manifest_; }
const GURL& primary_icon_url() const { return primary_icon_url_; } const GURL& primary_icon_url() const { return primary_icon_url_; }
const SkBitmap* primary_icon() const { return primary_icon_.get(); } const SkBitmap* primary_icon() const { return primary_icon_.get(); }
bool has_maskable_primary_icon() const { return has_maskable_primary_icon_; }
const GURL& badge_icon_url() const { return badge_icon_url_; } const GURL& badge_icon_url() const { return badge_icon_url_; }
const SkBitmap* badge_icon() const { return badge_icon_.get(); } const SkBitmap* badge_icon() const { return badge_icon_.get(); }
bool valid_manifest() const { return valid_manifest_; } bool valid_manifest() const { return valid_manifest_; }
...@@ -131,6 +141,7 @@ class CallbackTester { ...@@ -131,6 +141,7 @@ class CallbackTester {
blink::Manifest manifest_; blink::Manifest manifest_;
GURL primary_icon_url_; GURL primary_icon_url_;
std::unique_ptr<SkBitmap> primary_icon_; std::unique_ptr<SkBitmap> primary_icon_;
bool has_maskable_primary_icon_;
GURL badge_icon_url_; GURL badge_icon_url_;
std::unique_ptr<SkBitmap> badge_icon_; std::unique_ptr<SkBitmap> badge_icon_;
bool valid_manifest_; bool valid_manifest_;
...@@ -311,6 +322,7 @@ IN_PROC_BROWSER_TEST_F(InstallableManagerBrowserTest, CheckNoManifest) { ...@@ -311,6 +322,7 @@ IN_PROC_BROWSER_TEST_F(InstallableManagerBrowserTest, CheckNoManifest) {
EXPECT_TRUE(tester->manifest_url().is_empty()); EXPECT_TRUE(tester->manifest_url().is_empty());
EXPECT_TRUE(tester->primary_icon_url().is_empty()); EXPECT_TRUE(tester->primary_icon_url().is_empty());
EXPECT_EQ(nullptr, tester->primary_icon()); EXPECT_EQ(nullptr, tester->primary_icon());
EXPECT_FALSE(tester->has_maskable_primary_icon());
EXPECT_FALSE(tester->valid_manifest()); EXPECT_FALSE(tester->valid_manifest());
EXPECT_FALSE(tester->has_worker()); EXPECT_FALSE(tester->has_worker());
EXPECT_TRUE(tester->badge_icon_url().is_empty()); EXPECT_TRUE(tester->badge_icon_url().is_empty());
...@@ -353,6 +365,7 @@ IN_PROC_BROWSER_TEST_F(InstallableManagerBrowserTest, CheckManifest404) { ...@@ -353,6 +365,7 @@ IN_PROC_BROWSER_TEST_F(InstallableManagerBrowserTest, CheckManifest404) {
EXPECT_FALSE(tester->manifest_url().is_empty()); EXPECT_FALSE(tester->manifest_url().is_empty());
EXPECT_TRUE(tester->primary_icon_url().is_empty()); EXPECT_TRUE(tester->primary_icon_url().is_empty());
EXPECT_EQ(nullptr, tester->primary_icon()); EXPECT_EQ(nullptr, tester->primary_icon());
EXPECT_FALSE(tester->has_maskable_primary_icon());
EXPECT_FALSE(tester->valid_manifest()); EXPECT_FALSE(tester->valid_manifest());
EXPECT_FALSE(tester->has_worker()); EXPECT_FALSE(tester->has_worker());
EXPECT_TRUE(tester->badge_icon_url().is_empty()); EXPECT_TRUE(tester->badge_icon_url().is_empty());
...@@ -375,6 +388,7 @@ IN_PROC_BROWSER_TEST_F(InstallableManagerBrowserTest, CheckManifestOnly) { ...@@ -375,6 +388,7 @@ IN_PROC_BROWSER_TEST_F(InstallableManagerBrowserTest, CheckManifestOnly) {
EXPECT_TRUE(tester->primary_icon_url().is_empty()); EXPECT_TRUE(tester->primary_icon_url().is_empty());
EXPECT_EQ(nullptr, tester->primary_icon()); EXPECT_EQ(nullptr, tester->primary_icon());
EXPECT_FALSE(tester->has_maskable_primary_icon());
EXPECT_FALSE(tester->valid_manifest()); EXPECT_FALSE(tester->valid_manifest());
EXPECT_FALSE(tester->has_worker()); EXPECT_FALSE(tester->has_worker());
EXPECT_TRUE(tester->badge_icon_url().is_empty()); EXPECT_TRUE(tester->badge_icon_url().is_empty());
...@@ -400,6 +414,7 @@ IN_PROC_BROWSER_TEST_F(InstallableManagerBrowserTest, ...@@ -400,6 +414,7 @@ IN_PROC_BROWSER_TEST_F(InstallableManagerBrowserTest,
EXPECT_TRUE(tester->primary_icon_url().is_empty()); EXPECT_TRUE(tester->primary_icon_url().is_empty());
EXPECT_EQ(nullptr, tester->primary_icon()); EXPECT_EQ(nullptr, tester->primary_icon());
EXPECT_FALSE(tester->has_maskable_primary_icon());
EXPECT_FALSE(tester->valid_manifest()); EXPECT_FALSE(tester->valid_manifest());
EXPECT_FALSE(tester->has_worker()); EXPECT_FALSE(tester->has_worker());
EXPECT_TRUE(tester->badge_icon_url().is_empty()); EXPECT_TRUE(tester->badge_icon_url().is_empty());
...@@ -769,6 +784,92 @@ IN_PROC_BROWSER_TEST_F(InstallableManagerBrowserTest, CheckWebapp) { ...@@ -769,6 +784,92 @@ IN_PROC_BROWSER_TEST_F(InstallableManagerBrowserTest, CheckWebapp) {
} }
} }
IN_PROC_BROWSER_TEST_F(InstallableManagerBrowserTest, CheckMaskableIcon) {
// Checks that InstallableManager chooses the correct primary icon when the
// manifest contains maskable icons.
// Checks that if a MASKABLE icon is specified, it is used as primary icon.
{
base::RunLoop run_loop;
std::unique_ptr<CallbackTester> tester(
new CallbackTester(run_loop.QuitClosure()));
NavigateAndRunInstallableManager(browser(), tester.get(),
GetPrimaryIconPreferMaskableParams(),
GetURLOfPageWithServiceWorkerAndManifest(
"/banners/manifest_maskable.json"));
run_loop.Run();
EXPECT_FALSE(tester->manifest().IsEmpty());
EXPECT_FALSE(tester->manifest_url().is_empty());
EXPECT_FALSE(tester->primary_icon_url().is_empty());
EXPECT_NE(nullptr, tester->primary_icon());
EXPECT_TRUE(tester->has_maskable_primary_icon());
EXPECT_FALSE(tester->valid_manifest());
EXPECT_FALSE(tester->has_worker());
EXPECT_TRUE(tester->badge_icon_url().is_empty());
EXPECT_EQ(nullptr, tester->badge_icon());
EXPECT_EQ(NO_ERROR_DETECTED, tester->error_code());
}
// Checks that we don't pick a MASKABLE icon if it was not requested.
{
base::RunLoop run_loop;
std::unique_ptr<CallbackTester> tester(
new CallbackTester(run_loop.QuitClosure()));
NavigateAndRunInstallableManager(browser(), tester.get(),
GetPrimaryIconParams(),
GetURLOfPageWithServiceWorkerAndManifest(
"/banners/manifest_maskable.json"));
run_loop.Run();
EXPECT_FALSE(tester->manifest().IsEmpty());
EXPECT_FALSE(tester->manifest_url().is_empty());
EXPECT_FALSE(tester->primary_icon_url().is_empty());
EXPECT_NE(nullptr, tester->primary_icon());
EXPECT_FALSE(tester->has_maskable_primary_icon());
EXPECT_FALSE(tester->valid_manifest());
EXPECT_FALSE(tester->has_worker());
EXPECT_TRUE(tester->badge_icon_url().is_empty());
EXPECT_EQ(nullptr, tester->badge_icon());
EXPECT_EQ(NO_ERROR_DETECTED, tester->error_code());
}
// Checks that we fall back to using an ANY icon if a MASKABLE icon is
// requested but not in the manifest.
{
base::RunLoop run_loop;
std::unique_ptr<CallbackTester> tester(
new CallbackTester(run_loop.QuitClosure()));
NavigateAndRunInstallableManager(browser(), tester.get(),
GetPrimaryIconPreferMaskableParams(),
"/banners/manifest_test_page.html");
run_loop.Run();
EXPECT_FALSE(tester->manifest().IsEmpty());
EXPECT_FALSE(tester->manifest_url().is_empty());
EXPECT_FALSE(tester->primary_icon_url().is_empty());
EXPECT_NE(nullptr, tester->primary_icon());
EXPECT_FALSE(tester->has_maskable_primary_icon());
EXPECT_FALSE(tester->valid_manifest());
EXPECT_FALSE(tester->has_worker());
EXPECT_TRUE(tester->badge_icon_url().is_empty());
EXPECT_EQ(nullptr, tester->badge_icon());
EXPECT_EQ(NO_ERROR_DETECTED, tester->error_code());
}
}
IN_PROC_BROWSER_TEST_F(InstallableManagerBrowserTest, IN_PROC_BROWSER_TEST_F(InstallableManagerBrowserTest,
CheckNavigationWithoutRunning) { CheckNavigationWithoutRunning) {
// Verify that we record "not started" metrics if we don't run the installable // Verify that we record "not started" metrics if we don't run the installable
......
...@@ -20,6 +20,9 @@ struct InstallableParams { ...@@ -20,6 +20,9 @@ struct InstallableParams {
// conforming to the primary icon size parameters. // conforming to the primary icon size parameters.
bool valid_primary_icon = false; bool valid_primary_icon = false;
// Whether to prefer an icon with purpose 'maskable' for the primary icon.
bool prefer_maskable_icon = false;
// Check whether there is a fetchable, non-empty icon in the manifest // Check whether there is a fetchable, non-empty icon in the manifest
// conforming to the badge icon size parameters. // conforming to the badge icon size parameters.
bool valid_badge_icon = false; bool valid_badge_icon = false;
......
...@@ -67,8 +67,8 @@ class TestBookmarkAppHelper : public BookmarkAppHelper { ...@@ -67,8 +67,8 @@ class TestBookmarkAppHelper : public BookmarkAppHelper {
void CompleteInstallableCheck() { void CompleteInstallableCheck() {
blink::Manifest manifest; blink::Manifest manifest;
InstallableData data = { InstallableData data = {
NO_MANIFEST, GURL(), &manifest, GURL(), nullptr, NO_MANIFEST, GURL(), &manifest, GURL(), nullptr,
GURL(), nullptr, false, false, false, GURL(), nullptr, false, false,
}; };
BookmarkAppHelper::OnDidPerformInstallableCheck(data); BookmarkAppHelper::OnDidPerformInstallableCheck(data);
} }
......
{
"name": "Manifest test app",
"icons": [
{
"src": "launcher-icon-4x.png",
"sizes": "192x192",
"type": "image/png",
"purpose": "any"
},
{
"src": "launcher-icon-3x.png",
"sizes": "144x144",
"type": "image/png",
"purpose": "maskable"
}
],
"start_url": "manifest_test_page.html",
"display": "standalone",
"orientation": "landscape"
}
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