Commit ed75d1b5 authored by benwells's avatar benwells Committed by Commit bot

Sync bookmark app icon urls and sizes, and download icons for new apps.

This means bookmark apps can use proper icons from the web page or the
pages manifest, and have these reflectd on all devices the bookmark
app is synced to.

BUG=480049

Review URL: https://codereview.chromium.org/1066623008

Cr-Commit-Position: refs/heads/master@{#327424}
parent 35d9c460
......@@ -6,6 +6,7 @@
#include "chrome/common/extensions/manifest_handlers/app_icon_color_info.h"
#include "chrome/common/extensions/manifest_handlers/app_launch_info.h"
#include "chrome/common/extensions/manifest_handlers/linked_app_icons.h"
#include "extensions/common/extension.h"
#include "sync/api/sync_data.h"
#include "sync/protocol/app_specifics.pb.h"
......@@ -13,6 +14,12 @@
namespace extensions {
AppSyncData::LinkedAppIconInfo::LinkedAppIconInfo() {
}
AppSyncData::LinkedAppIconInfo::~LinkedAppIconInfo() {
}
AppSyncData::AppSyncData() {}
AppSyncData::AppSyncData(const Extension& extension,
......@@ -35,6 +42,14 @@ AppSyncData::AppSyncData(const Extension& extension,
bookmark_app_description_ = extension.description();
bookmark_app_url_ = AppLaunchInfo::GetLaunchWebURL(&extension).spec();
bookmark_app_icon_color_ = AppIconColorInfo::GetIconColorString(&extension);
extensions::LinkedAppIcons icons =
LinkedAppIcons::GetLinkedAppIcons(&extension);
for (const auto& icon : icons.icons) {
LinkedAppIconInfo linked_icon;
linked_icon.url = icon.url;
linked_icon.size = icon.size;
linked_icons_.push_back(linked_icon);
}
}
}
......@@ -102,6 +117,13 @@ void AppSyncData::PopulateAppSpecifics(sync_pb::AppSpecifics* specifics) const {
if (!bookmark_app_icon_color_.empty())
specifics->set_bookmark_app_icon_color(bookmark_app_icon_color_);
for (const auto& linked_icon : linked_icons_) {
sync_pb::LinkedAppIconInfo* linked_app_icon_info =
specifics->add_linked_app_icons();
linked_app_icon_info->set_url(linked_icon.url.spec());
linked_app_icon_info->set_size(linked_icon.size);
}
extension_sync_data_.PopulateExtensionSpecifics(
specifics->mutable_extension());
}
......@@ -122,6 +144,18 @@ bool AppSyncData::PopulateFromAppSpecifics(
bookmark_app_url_ = specifics.bookmark_app_url();
bookmark_app_description_ = specifics.bookmark_app_description();
bookmark_app_icon_color_ = specifics.bookmark_app_icon_color();
for (int i = 0; i < specifics.linked_app_icons_size(); ++i) {
const sync_pb::LinkedAppIconInfo& linked_app_icon_info =
specifics.linked_app_icons(i);
if (linked_app_icon_info.has_url() && linked_app_icon_info.has_size()) {
LinkedAppIconInfo linked_icon;
linked_icon.url = GURL(linked_app_icon_info.url());
linked_icon.size = linked_app_icon_info.size();
linked_icons_.push_back(linked_icon);
}
}
return true;
}
......
......@@ -28,6 +28,14 @@ class ExtensionSyncData;
// A class that encapsulates the synced properties of an Application.
class AppSyncData {
public:
struct LinkedAppIconInfo {
LinkedAppIconInfo();
~LinkedAppIconInfo();
GURL url;
int size;
};
AppSyncData();
AppSyncData(const Extension& extension,
bool enabled,
......@@ -82,6 +90,10 @@ class AppSyncData {
return bookmark_app_icon_color_;
}
const std::vector<LinkedAppIconInfo>& linked_icons() const {
return linked_icons_;
}
private:
// Convert an AppSyncData back out to a sync structure.
void PopulateAppSpecifics(sync_pb::AppSpecifics* specifics) const;
......@@ -98,6 +110,7 @@ class AppSyncData {
std::string bookmark_app_url_;
std::string bookmark_app_description_;
std::string bookmark_app_icon_color_;
std::vector<LinkedAppIconInfo> linked_icons_;
};
} // namespace extensions
......
......@@ -34,6 +34,15 @@ class Extension;
// A helper class for creating bookmark apps from a WebContents.
class BookmarkAppHelper : public content::NotificationObserver {
public:
struct BitmapAndSource {
BitmapAndSource();
BitmapAndSource(const GURL& source_url_p, const SkBitmap& bitmap_p);
~BitmapAndSource();
GURL source_url;
SkBitmap bitmap;
};
typedef base::Callback<void(const Extension*, const WebApplicationInfo&)>
CreateBookmarkAppCallback;
......@@ -56,18 +65,35 @@ class BookmarkAppHelper : public content::NotificationObserver {
// |sizes| and resizes it to that size. This returns a map of sizes to bitmaps
// which contains only bitmaps of a size in |sizes| and at most one bitmap of
// each size.
static std::map<int, SkBitmap> ConstrainBitmapsToSizes(
const std::vector<SkBitmap>& bitmaps,
static std::map<int, BitmapAndSource> ConstrainBitmapsToSizes(
const std::vector<BitmapAndSource>& bitmaps,
const std::set<int>& sizes);
// Adds a square container icon of |output_size| pixels to |bitmaps| by
// drawing the given |letter| into a rounded background of |color|.
// Does nothing if an icon of |output_size| already exists in |bitmaps|.
static void GenerateIcon(std::map<int, SkBitmap>* bitmaps,
static void GenerateIcon(std::map<int, BitmapAndSource>* bitmaps,
int output_size,
SkColor color,
char letter);
// Resize icons to the accepted sizes, and generate any that are missing. Does
// not update |web_app_info| except to update |generated_icon_color|.
static std::map<int, BitmapAndSource> ResizeIconsAndGenerateMissing(
std::vector<BitmapAndSource> icons,
WebApplicationInfo* web_app_info);
// It is important that the linked app information in any extension that
// gets created from sync matches the linked app information that came from
// sync. If there are any changes, they will be synced back to other devices
// and could potentially create a never ending sync cycle.
// This function updates |web_app_info| with the image data of any icon from
// |bitmap_map| that has a URL and size matching that in |web_app_info|, as
// well as adding any new images from |bitmap_map| that have no URL.
static void UpdateWebAppIconsWithoutChangingLinks(
std::map<int, BookmarkAppHelper::BitmapAndSource> bitmap_map,
WebApplicationInfo* web_app_info);
// Begins the asynchronous bookmark app creation.
void Create(const CreateBookmarkAppCallback& callback);
......
......@@ -20,6 +20,8 @@
#include "third_party/skia/include/core/SkBitmap.h"
#include "ui/gfx/skia_util.h"
namespace extensions {
namespace {
const char kAppUrl[] = "http://www.chromium.org";
......@@ -31,11 +33,16 @@ const char kAppDescription[] = "Test description";
const char kAppIcon1[] = "fav1.png";
const char kAppIcon2[] = "fav2.png";
const char kAppIcon3[] = "fav3.png";
const char kAppIconURL1[] = "http://foo.com/1.png";
const char kAppIconURL2[] = "http://foo.com/2.png";
const char kAppIconURL3[] = "http://foo.com/3.png";
const char kAppIconURL4[] = "http://foo.com/4.png";
const int kIconSizeTiny = extension_misc::EXTENSION_ICON_BITTY;
const int kIconSizeSmall = extension_misc::EXTENSION_ICON_SMALL;
const int kIconSizeMedium = extension_misc::EXTENSION_ICON_MEDIUM;
const int kIconSizeLarge = extension_misc::EXTENSION_ICON_LARGE;
const int kIconSizeUnsupported = 123;
class BookmarkAppHelperTest : public testing::Test {
public:
......@@ -83,6 +90,21 @@ SkBitmap CreateSquareBitmapWithColor(int size, SkColor color) {
return bitmap;
}
BookmarkAppHelper::BitmapAndSource CreateSquareBitmapAndSourceWithColor(
int size,
SkColor color) {
return BookmarkAppHelper::BitmapAndSource(
GURL(), CreateSquareBitmapWithColor(size, color));
}
void ValidateBitmapSizeAndColor(SkBitmap bitmap, int size, SkColor color) {
// Obtain pixel lock to access pixels.
SkAutoLockPixels lock(bitmap);
EXPECT_EQ(color, bitmap.getColor(0, 0));
EXPECT_EQ(size, bitmap.width());
EXPECT_EQ(size, bitmap.height());
}
WebApplicationInfo::IconInfo CreateIconInfoWithBitmap(int size, SkColor color) {
WebApplicationInfo::IconInfo icon_info;
icon_info.width = size;
......@@ -91,27 +113,36 @@ WebApplicationInfo::IconInfo CreateIconInfoWithBitmap(int size, SkColor color) {
return icon_info;
}
void ValidateWebApplicationInfo(base::Closure callback,
const WebApplicationInfo& expected,
const WebApplicationInfo& actual) {
EXPECT_EQ(expected.title, actual.title);
EXPECT_EQ(expected.description, actual.description);
EXPECT_EQ(expected.app_url, actual.app_url);
EXPECT_EQ(expected.icons.size(), actual.icons.size());
for (size_t i = 0; i < expected.icons.size(); ++i) {
EXPECT_EQ(expected.icons[i].width, actual.icons[i].width);
EXPECT_EQ(expected.icons[i].height, actual.icons[i].height);
EXPECT_EQ(expected.icons[i].url, actual.icons[i].url);
EXPECT_TRUE(
gfx::BitmapsAreEqual(expected.icons[i].data, actual.icons[i].data));
void ValidateAllIconsWithURLsArePresent(const WebApplicationInfo& info_to_check,
const WebApplicationInfo& other_info) {
for (const auto& icon : info_to_check.icons) {
if (!icon.url.is_empty()) {
bool found = false;
for (const auto& other_icon : info_to_check.icons) {
if (other_icon.url == icon.url && other_icon.width == icon.width) {
found = true;
break;
}
}
EXPECT_TRUE(found);
}
}
}
void ValidateWebApplicationInfo(base::Closure callback,
const WebApplicationInfo& original,
const WebApplicationInfo& newly_made) {
EXPECT_EQ(original.title, newly_made.title);
EXPECT_EQ(original.description, newly_made.description);
EXPECT_EQ(original.app_url, newly_made.app_url);
// There should be 6 icons, as there are three sizes which need to be
// generated, and each will generate a 1x and 2x icon.
EXPECT_EQ(6u, newly_made.icons.size());
callback.Run();
}
} // namespace
namespace extensions {
class TestBookmarkAppHelper : public BookmarkAppHelper {
public:
TestBookmarkAppHelper(ExtensionService* service,
......@@ -226,8 +257,7 @@ TEST_F(BookmarkAppHelperExtensionServiceTest, CreateBookmarkAppNoContents) {
EXPECT_EQ(kAppTitle, extension->name());
EXPECT_EQ(kAppDescription, extension->description());
EXPECT_EQ(GURL(kAppUrl), AppLaunchInfo::GetLaunchWebURL(extension));
// The tiny icon should have been removed and only the generated ones used.
EXPECT_TRUE(
EXPECT_FALSE(
IconsInfo::GetIconResource(extension, kIconSizeTiny,
ExtensionIconSet::MATCH_EXACTLY).empty());
EXPECT_FALSE(
......@@ -285,9 +315,9 @@ TEST_F(BookmarkAppHelperExtensionServiceTest, CreateAndUpdateBookmarkApp) {
EXPECT_EQ(kAlternativeAppTitle, extension->name());
EXPECT_EQ(kAppDescription, extension->description());
EXPECT_EQ(GURL(kAppUrl), AppLaunchInfo::GetLaunchWebURL(extension));
EXPECT_TRUE(extensions::IconsInfo::GetIconResource(
extension, kIconSizeSmall, ExtensionIconSet::MATCH_EXACTLY)
.empty());
EXPECT_FALSE(extensions::IconsInfo::GetIconResource(
extension, kIconSizeSmall, ExtensionIconSet::MATCH_EXACTLY)
.empty());
EXPECT_FALSE(extensions::IconsInfo::GetIconResource(
extension, kIconSizeLarge, ExtensionIconSet::MATCH_EXACTLY)
.empty());
......@@ -300,11 +330,6 @@ TEST_F(BookmarkAppHelperExtensionServiceTest, GetWebApplicationInfo) {
web_app_info.title = base::UTF8ToUTF16(kAppTitle);
web_app_info.description = base::UTF8ToUTF16(kAppDescription);
web_app_info.icons.push_back(
CreateIconInfoWithBitmap(kIconSizeSmall, SK_ColorRED));
web_app_info.icons.push_back(
CreateIconInfoWithBitmap(kIconSizeLarge, SK_ColorRED));
extensions::CreateOrUpdateBookmarkApp(service_, &web_app_info);
base::RunLoop().RunUntilIdle();
......@@ -317,6 +342,53 @@ TEST_F(BookmarkAppHelperExtensionServiceTest, GetWebApplicationInfo) {
run_loop.Run();
}
TEST_F(BookmarkAppHelperExtensionServiceTest, LinkedAppIconsAreNotChanged) {
WebApplicationInfo web_app_info;
// Add two icons with a URL and bitmap, two icons with just a bitmap, an
// icon with just URL and an icon in an unsupported size with just a URL.
WebApplicationInfo::IconInfo icon_info =
CreateIconInfoWithBitmap(kIconSizeSmall, SK_ColorRED);
icon_info.url = GURL(kAppIconURL1);
web_app_info.icons.push_back(icon_info);
icon_info = CreateIconInfoWithBitmap(kIconSizeMedium, SK_ColorRED);
icon_info.url = GURL(kAppIconURL2);
web_app_info.icons.push_back(icon_info);
icon_info.data = SkBitmap();
icon_info.url = GURL(kAppIconURL3);
icon_info.width = 0;
icon_info.height = 0;
web_app_info.icons.push_back(icon_info);
icon_info.url = GURL(kAppIconURL4);
web_app_info.icons.push_back(icon_info);
icon_info = CreateIconInfoWithBitmap(kIconSizeLarge, SK_ColorRED);
web_app_info.icons.push_back(icon_info);
icon_info = CreateIconInfoWithBitmap(kIconSizeUnsupported, SK_ColorRED);
web_app_info.icons.push_back(icon_info);
// 'Download' one of the icons without a size or bitmap.
std::vector<BookmarkAppHelper::BitmapAndSource> downloaded;
downloaded.push_back(BookmarkAppHelper::BitmapAndSource(
GURL(kAppIconURL3),
CreateSquareBitmapWithColor(kIconSizeLarge, SK_ColorBLACK)));
// Now run the resizing and generation into a new web app info.
WebApplicationInfo new_web_app_info;
std::map<int, BookmarkAppHelper::BitmapAndSource> size_map =
BookmarkAppHelper::ResizeIconsAndGenerateMissing(downloaded,
&new_web_app_info);
// Now check that the linked app icons (i.e. those with URLs) are matching in
// both lists.
ValidateAllIconsWithURLsArePresent(web_app_info, new_web_app_info);
ValidateAllIconsWithURLsArePresent(new_web_app_info, web_app_info);
}
TEST_F(BookmarkAppHelperTest, UpdateWebAppInfoFromManifest) {
WebApplicationInfo web_app_info;
web_app_info.title = base::UTF8ToUTF16(kAlternativeAppTitle);
......@@ -357,6 +429,46 @@ TEST_F(BookmarkAppHelperTest, UpdateWebAppInfoFromManifest) {
EXPECT_EQ(GURL(kAppIcon3), web_app_info.icons[1].url);
}
TEST_F(BookmarkAppHelperTest, ConstrainBitmapsToSizes) {
std::set<int> desired_sizes;
desired_sizes.insert(16);
desired_sizes.insert(32);
desired_sizes.insert(128);
desired_sizes.insert(256);
{
std::vector<BookmarkAppHelper::BitmapAndSource> bitmaps;
bitmaps.push_back(CreateSquareBitmapAndSourceWithColor(16, SK_ColorRED));
bitmaps.push_back(CreateSquareBitmapAndSourceWithColor(32, SK_ColorGREEN));
bitmaps.push_back(CreateSquareBitmapAndSourceWithColor(48, SK_ColorBLUE));
bitmaps.push_back(
CreateSquareBitmapAndSourceWithColor(144, SK_ColorYELLOW));
std::map<int, BookmarkAppHelper::BitmapAndSource> results(
BookmarkAppHelper::ConstrainBitmapsToSizes(bitmaps, desired_sizes));
EXPECT_EQ(3u, results.size());
ValidateBitmapSizeAndColor(results[16].bitmap, 16, SK_ColorRED);
ValidateBitmapSizeAndColor(results[32].bitmap, 32, SK_ColorGREEN);
ValidateBitmapSizeAndColor(results[128].bitmap, 128, SK_ColorYELLOW);
}
{
std::vector<BookmarkAppHelper::BitmapAndSource> bitmaps;
bitmaps.push_back(CreateSquareBitmapAndSourceWithColor(512, SK_ColorRED));
bitmaps.push_back(CreateSquareBitmapAndSourceWithColor(18, SK_ColorGREEN));
bitmaps.push_back(CreateSquareBitmapAndSourceWithColor(33, SK_ColorBLUE));
bitmaps.push_back(CreateSquareBitmapAndSourceWithColor(17, SK_ColorYELLOW));
std::map<int, BookmarkAppHelper::BitmapAndSource> results(
BookmarkAppHelper::ConstrainBitmapsToSizes(bitmaps, desired_sizes));
EXPECT_EQ(3u, results.size());
ValidateBitmapSizeAndColor(results[16].bitmap, 16, SK_ColorYELLOW);
ValidateBitmapSizeAndColor(results[32].bitmap, 32, SK_ColorBLUE);
ValidateBitmapSizeAndColor(results[256].bitmap, 256, SK_ColorRED);
}
}
TEST_F(BookmarkAppHelperTest, IsValidBookmarkAppUrl) {
EXPECT_TRUE(IsValidBookmarkAppUrl(GURL("https://www.chromium.org")));
EXPECT_TRUE(IsValidBookmarkAppUrl(GURL("http://www.chromium.org/path")));
......
......@@ -112,14 +112,23 @@ scoped_refptr<Extension> ConvertWebAppToExtension(
web_app.generated_icon_color));
}
// Add the icons.
// Add the icons and linked icon information.
base::DictionaryValue* icons = new base::DictionaryValue();
root->Set(keys::kIcons, icons);
for (size_t i = 0; i < web_app.icons.size(); ++i) {
std::string size = base::StringPrintf("%i", web_app.icons[i].width);
base::ListValue* linked_icons = new base::ListValue();
root->Set(keys::kLinkedAppIcons, linked_icons);
for (const auto& icon : web_app.icons) {
std::string size = base::StringPrintf("%i", icon.width);
std::string icon_path = base::StringPrintf("%s/%s.png", kIconsDirName,
size.c_str());
icons->SetString(size, icon_path);
if (icon.url.is_valid()) {
base::DictionaryValue* linked_icon = new base::DictionaryValue();
linked_icon->SetString(keys::kLinkedAppIconURL, icon.url.spec());
linked_icon->SetInteger(keys::kLinkedAppIconSize, icon.width);
linked_icons->Append(linked_icon);
}
}
// Write the manifest.
......
......@@ -418,6 +418,13 @@ void ExtensionSyncService::ProcessBookmarkAppSyncData(
app_sync_data.bookmark_app_icon_color(),
&web_app_info.generated_icon_color);
}
for (const auto& icon : app_sync_data.linked_icons()) {
WebApplicationInfo::IconInfo icon_info;
icon_info.url = icon.url;
icon_info.width = icon.size;
icon_info.height = icon.size;
web_app_info.icons.push_back(icon_info);
}
// If the bookmark app already exists, keep the old icons.
if (!extension) {
......
......@@ -187,6 +187,8 @@
'common/extensions/manifest_handlers/copresence_manifest.h',
'common/extensions/manifest_handlers/extension_action_handler.cc',
'common/extensions/manifest_handlers/extension_action_handler.h',
'common/extensions/manifest_handlers/linked_app_icons.cc',
'common/extensions/manifest_handlers/linked_app_icons.h',
'common/extensions/manifest_handlers/minimum_chrome_version_checker.cc',
'common/extensions/manifest_handlers/minimum_chrome_version_checker.h',
'common/extensions/manifest_handlers/settings_overrides_handler.cc',
......
......@@ -24,6 +24,10 @@
"channel": "stable",
"extension_types": ["hosted_app"]
},
"app.linked_icons": {
"channel": "dev",
"extension_types": ["hosted_app"]
},
"app.isolation": {
"channel": "stable",
// Platform apps always have isolated storage, thus they cannot specify it
......
......@@ -24,6 +24,7 @@
#include "chrome/common/extensions/manifest_handlers/content_scripts_handler.h"
#include "chrome/common/extensions/manifest_handlers/copresence_manifest.h"
#include "chrome/common/extensions/manifest_handlers/extension_action_handler.h"
#include "chrome/common/extensions/manifest_handlers/linked_app_icons.h"
#include "chrome/common/extensions/manifest_handlers/minimum_chrome_version_checker.h"
#include "chrome/common/extensions/manifest_handlers/settings_overrides_handler.h"
#include "chrome/common/extensions/manifest_handlers/theme_handler.h"
......@@ -51,6 +52,7 @@ void RegisterChromeManifestHandlers() {
#if defined(OS_CHROMEOS)
(new InputComponentsHandler)->Register();
#endif
(new LinkedAppIconsHandler)->Register();
(new MinimumChromeVersionChecker)->Register();
(new OmniboxHandler)->Register();
(new OptionsPageManifestHandler)->Register();
......
// Copyright 2015 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.
#include "chrome/common/extensions/manifest_handlers/linked_app_icons.h"
#include "base/lazy_instance.h"
#include "base/strings/utf_string_conversions.h"
#include "base/values.h"
#include "extensions/common/manifest.h"
#include "extensions/common/manifest_constants.h"
namespace extensions {
namespace keys = manifest_keys;
namespace errors = manifest_errors;
namespace {
static base::LazyInstance<LinkedAppIcons> g_empty_linked_app_icons =
LAZY_INSTANCE_INITIALIZER;
const LinkedAppIcons& GetInfo(const Extension* extension) {
LinkedAppIcons* info = static_cast<LinkedAppIcons*>(
extension->GetManifestData(keys::kLinkedAppIcons));
return info ? *info : g_empty_linked_app_icons.Get();
}
} // namespace
LinkedAppIcons::IconInfo::IconInfo() {
}
LinkedAppIcons::IconInfo::~IconInfo() {
}
LinkedAppIcons::LinkedAppIcons() {
}
LinkedAppIcons::~LinkedAppIcons() {
}
// static
const LinkedAppIcons& LinkedAppIcons::GetLinkedAppIcons(
const Extension* extension) {
return GetInfo(extension);
}
LinkedAppIconsHandler::LinkedAppIconsHandler() {
}
LinkedAppIconsHandler::~LinkedAppIconsHandler() {
}
bool LinkedAppIconsHandler::Parse(Extension* extension, base::string16* error) {
scoped_ptr<LinkedAppIcons> linked_app_icons(new LinkedAppIcons);
const base::Value* icons_value = nullptr;
const base::ListValue* icons_list = nullptr;
if (extension->manifest()->Get(keys::kLinkedAppIcons, &icons_value)) {
if (!icons_value->GetAsList(&icons_list)) {
*error = base::UTF8ToUTF16(
extensions::manifest_errors::kInvalidLinkedAppIcons);
return false;
}
for (const base::Value* icon_value : *icons_list) {
const base::DictionaryValue* icon_dict = nullptr;
if (!icon_value->GetAsDictionary(&icon_dict)) {
*error = base::UTF8ToUTF16(
extensions::manifest_errors::kInvalidLinkedAppIcon);
return false;
}
std::string url_string;
if (!icon_dict->GetString(keys::kLinkedAppIconURL, &url_string)) {
*error = base::UTF8ToUTF16(
extensions::manifest_errors::kInvalidLinkedAppIconURL);
return false;
}
LinkedAppIcons::IconInfo info;
info.url = GURL(url_string);
if (!info.url.is_valid()) {
*error = base::UTF8ToUTF16(
extensions::manifest_errors::kInvalidLinkedAppIconURL);
return false;
}
if (!icon_dict->GetInteger(keys::kLinkedAppIconSize, &info.size)) {
*error = base::UTF8ToUTF16(
extensions::manifest_errors::kInvalidLinkedAppIconSize);
return false;
}
linked_app_icons->icons.push_back(info);
}
}
extension->SetManifestData(keys::kLinkedAppIcons, linked_app_icons.release());
return true;
}
const std::vector<std::string> LinkedAppIconsHandler::Keys() const {
return SingleKey(keys::kLinkedAppIcons);
}
} // namespace extensions
// Copyright 2015 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.
#ifndef CHROME_COMMON_EXTENSIONS_MANIFEST_HANDLERS_LINKED_APP_ICONS_H_
#define CHROME_COMMON_EXTENSIONS_MANIFEST_HANDLERS_LINKED_APP_ICONS_H_
#include <vector>
#include "extensions/common/extension.h"
#include "extensions/common/manifest_handler.h"
namespace base {
class DictionaryValue;
}
namespace extensions {
// A structure to hold the parsed linked app icon data.
struct LinkedAppIcons : public Extension::ManifestData {
struct IconInfo {
IconInfo();
~IconInfo();
GURL url;
int size;
};
LinkedAppIcons();
~LinkedAppIcons() override;
static const LinkedAppIcons& GetLinkedAppIcons(const Extension* extension);
std::vector<IconInfo> icons;
};
// Parses the "app.linked_icons" manifest key.
class LinkedAppIconsHandler : public ManifestHandler {
public:
LinkedAppIconsHandler();
~LinkedAppIconsHandler() override;
bool Parse(Extension* extension, base::string16* error) override;
private:
const std::vector<std::string> Keys() const override;
DISALLOW_COPY_AND_ASSIGN(LinkedAppIconsHandler);
};
} // namespace extensions
#endif // CHROME_COMMON_EXTENSIONS_MANIFEST_HANDLERS_LINKED_APP_ICONS_H_
......@@ -79,6 +79,9 @@ const char kLaunchLocalPath[] = "app.launch.local_path";
const char kLaunchWebURL[] = "app.launch.web_url";
const char kLaunchWidth[] = "app.launch.width";
const char kLayouts[] = "layouts";
const char kLinkedAppIcons[] = "app.linked_icons";
const char kLinkedAppIconURL[] = "url";
const char kLinkedAppIconSize[] = "size";
const char kManifestVersion[] = "manifest_version";
const char kMatchAboutBlank[] = "match_about_blank";
const char kMatches[] = "matches";
......@@ -464,6 +467,14 @@ const char kInvalidLaunchValue[] =
"Invalid value for '*'.";
const char kInvalidLaunchValueContainer[] =
"Invalid container type for '*'.";
const char kInvalidLinkedAppIcon[] =
"Invalid linked app icon. Must be a dictionary";
const char kInvalidLinkedAppIconSize[] =
"Invalid 'size' for linked app icon. Must be an integer";
const char kInvalidLinkedAppIconURL[] =
"Invalid 'url' for linked app icon. Must be a string that is a valid URL";
const char kInvalidLinkedAppIcons[] =
"Invalid 'app.linked_icons'. Must be an array";
const char kInvalidManifest[] =
"Manifest file is invalid.";
const char kInvalidManifestVersion[] =
......
......@@ -82,6 +82,9 @@ extern const char kLaunchLocalPath[];
extern const char kLaunchWebURL[];
extern const char kLaunchWidth[];
extern const char kLayouts[];
extern const char kLinkedAppIcons[];
extern const char kLinkedAppIconURL[];
extern const char kLinkedAppIconSize[];
extern const char kManifestVersion[];
extern const char kMatchAboutBlank[];
extern const char kMatches[];
......@@ -352,6 +355,10 @@ extern const char kInvalidLauncherPagePage[];
extern const char kInvalidLaunchContainer[];
extern const char kInvalidLaunchValue[];
extern const char kInvalidLaunchValueContainer[];
extern const char kInvalidLinkedAppIcon[];
extern const char kInvalidLinkedAppIconSize[];
extern const char kInvalidLinkedAppIconURL[];
extern const char kInvalidLinkedAppIcons[];
extern const char kInvalidManifest[];
extern const char kInvalidManifestVersion[];
extern const char kInvalidManifestVersionOld[];
......
......@@ -38,6 +38,15 @@ message AppNotificationSettings {
optional string oauth_client_id = 3;
}
// Information about a linked app icon.
message LinkedAppIconInfo {
// The URL of the app icon.
optional string url = 1;
// The size of the app icon in DIPs.
optional uint32 size = 2;
}
// Properties of app sync objects.
//
// For now, an app is just an extension. We keep the two data types
......@@ -79,4 +88,8 @@ message AppSpecifics {
// This is the color to use when generating bookmark app icons. The string is
// in #rrggbb or #rgb syntax, e.g. #d8d8d8.
optional string bookmark_app_icon_color = 8;
// This is information about linked icons (that is, icons that are downloaded
// from outside the app's bundle of files.
repeated LinkedAppIconInfo linked_app_icons = 9;
}
......@@ -298,6 +298,14 @@ base::DictionaryValue* AppSettingSpecificsToValue(
return value;
}
base::DictionaryValue* LinkedAppIconInfoToValue(
const sync_pb::LinkedAppIconInfo& proto) {
base::DictionaryValue* value = new base::DictionaryValue();
SET_STR(url);
SET_INT32(size);
return value;
}
base::DictionaryValue* AppSpecificsToValue(
const sync_pb::AppSpecifics& proto) {
base::DictionaryValue* value = new base::DictionaryValue();
......@@ -308,6 +316,8 @@ base::DictionaryValue* AppSpecificsToValue(
SET_ENUM(launch_type, GetLaunchTypeString);
SET_STR(bookmark_app_url);
SET_STR(bookmark_app_description);
SET_STR(bookmark_app_icon_color);
SET_REP(linked_app_icons, LinkedAppIconInfoToValue);
return value;
}
......
......@@ -46,6 +46,7 @@ class FaviconTrackingSpecifics;
class GlobalIdDirective;
class HistoryDeleteDirectiveSpecifics;
class KeystoreEncryptionFlagsSpecifics;
class LinkedAppIconInfo;
class Media;
class ManagedUserSettingSpecifics;
class ManagedUserSharedSettingSpecifics;
......@@ -99,10 +100,13 @@ SYNC_EXPORT_PRIVATE base::DictionaryValue* EncryptedDataToValue(
SYNC_EXPORT_PRIVATE base::DictionaryValue* AppListSpecificsToValue(
const sync_pb::AppListSpecifics& proto);
// Sub-protocol of AppSpecifics.
// Sub-protocols of AppSpecifics.
SYNC_EXPORT_PRIVATE base::DictionaryValue* AppSettingsToValue(
const sync_pb::AppNotificationSettings& app_notification_settings);
SYNC_EXPORT_PRIVATE base::DictionaryValue* LinkedAppIconInfoToValue(
const sync_pb::LinkedAppIconInfo& linked_app_icon_info);
// Sub-protocols of SessionSpecifics.
SYNC_EXPORT_PRIVATE base::DictionaryValue* SessionHeaderToValue(
......
......@@ -182,6 +182,10 @@ TEST_F(ProtoValueConversionsTest, BookmarkSpecificsData) {
EXPECT_EQ("value2", meta_value);
}
TEST_F(ProtoValueConversionsTest, LinkedAppIconInfoToValue) {
TestSpecificsToValue(LinkedAppIconInfoToValue);
}
TEST_F(ProtoValueConversionsTest, PriorityPreferenceSpecificsToValue) {
TestSpecificsToValue(PriorityPreferenceSpecificsToValue);
}
......
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