summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorwjywbs@gmail.com <wjywbs@gmail.com@0039d316-1c4b-4281-b951-d872f2087c98>2014-06-04 08:57:41 +0000
committerwjywbs@gmail.com <wjywbs@gmail.com@0039d316-1c4b-4281-b951-d872f2087c98>2014-06-04 08:57:41 +0000
commit7584de288d217916961f4109b1a10f922754ae70 (patch)
tree34b70ff0344998ad6a3f7f9302bac43b090316e7
parentca11059ee2dd9abe0c64b47cda1f58d6c662e855 (diff)
downloadchromium_src-7584de288d217916961f4109b1a10f922754ae70.zip
chromium_src-7584de288d217916961f4109b1a10f922754ae70.tar.gz
chromium_src-7584de288d217916961f4109b1a10f922754ae70.tar.bz2
Reland: Add generateAppForLink function in chrome.management
This function takes a url and a title as input, generates and returns a bookmark app. R=benwells@chromium.org,kalman@chromium.org,calamity@chromium.org BUG=370350 Review URL: https://codereview.chromium.org/266353006 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@274732 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--chrome/browser/extensions/api/management/management_api.cc87
-rw-r--r--chrome/browser/extensions/api/management/management_api.h30
-rw-r--r--chrome/browser/extensions/api/management/management_api_constants.cc6
-rw-r--r--chrome/browser/extensions/api/management/management_api_constants.h4
-rw-r--r--chrome/browser/extensions/api/management/management_apitest.cc14
-rw-r--r--chrome/browser/extensions/bookmark_app_helper.cc21
-rw-r--r--chrome/browser/extensions/bookmark_app_helper.h3
-rw-r--r--chrome/browser/extensions/bookmark_app_helper_unittest.cc63
-rw-r--r--chrome/common/extensions/api/_api_features.json5
-rw-r--r--chrome/common/extensions/api/management.json27
-rw-r--r--chrome/test/data/extensions/api_test/management/test/generateAppForLink.html7
-rw-r--r--chrome/test/data/extensions/api_test/management/test/generateAppForLink.js78
-rw-r--r--chrome/test/data/extensions/api_test/management/test/generateAppForLinkNotInStable.html7
-rw-r--r--chrome/test/data/extensions/api_test/management/test/generateAppForLinkNotInStable.js12
-rw-r--r--extensions/browser/extension_function_histogram_value.h1
-rw-r--r--tools/metrics/histograms/histograms.xml1
16 files changed, 363 insertions, 3 deletions
diff --git a/chrome/browser/extensions/api/management/management_api.cc b/chrome/browser/extensions/api/management/management_api.cc
index 189692a..3160c87 100644
--- a/chrome/browser/extensions/api/management/management_api.cc
+++ b/chrome/browser/extensions/api/management/management_api.cc
@@ -25,6 +25,7 @@
#include "chrome/browser/extensions/extension_ui_util.h"
#include "chrome/browser/extensions/extension_uninstall_dialog.h"
#include "chrome/browser/extensions/launch_util.h"
+#include "chrome/browser/favicon/favicon_service_factory.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/browser_dialogs.h"
#include "chrome/browser/ui/browser_finder.h"
@@ -56,6 +57,7 @@
#include "extensions/common/permissions/permission_set.h"
#include "extensions/common/permissions/permissions_data.h"
#include "extensions/common/url_pattern.h"
+#include "ui/gfx/favicon_size.h"
#if !defined(OS_ANDROID)
#include "chrome/browser/ui/webui/ntp/core_app_launcher_handler.h"
@@ -852,6 +854,91 @@ bool ManagementSetLaunchTypeFunction::RunSync() {
return true;
}
+ManagementGenerateAppForLinkFunction::ManagementGenerateAppForLinkFunction() {
+}
+
+ManagementGenerateAppForLinkFunction::~ManagementGenerateAppForLinkFunction() {
+}
+
+void ManagementGenerateAppForLinkFunction::FinishCreateBookmarkApp(
+ const extensions::Extension* extension,
+ const WebApplicationInfo& web_app_info) {
+ if (extension) {
+ scoped_ptr<management::ExtensionInfo> info =
+ CreateExtensionInfo(*extension, ExtensionSystem::Get(GetProfile()));
+ results_ = management::GenerateAppForLink::Results::Create(*info);
+
+ SendResponse(true);
+ Release();
+ } else {
+ error_ = keys::kGenerateAppForLinkInstallError;
+ SendResponse(false);
+ Release();
+ }
+}
+
+void ManagementGenerateAppForLinkFunction::OnFaviconForApp(
+ const favicon_base::FaviconImageResult& image_result) {
+ WebApplicationInfo web_app;
+ web_app.title = base::UTF8ToUTF16(title_);
+ web_app.app_url = launch_url_;
+
+ if (!image_result.image.IsEmpty()) {
+ WebApplicationInfo::IconInfo icon;
+ icon.data = image_result.image.AsBitmap();
+ icon.width = icon.data.width();
+ icon.height = icon.data.height();
+ web_app.icons.push_back(icon);
+ }
+
+ bookmark_app_helper_.reset(new BookmarkAppHelper(service(), web_app, NULL));
+ bookmark_app_helper_->Create(base::Bind(
+ &ManagementGenerateAppForLinkFunction::FinishCreateBookmarkApp, this));
+}
+
+bool ManagementGenerateAppForLinkFunction::RunAsync() {
+ if (!user_gesture()) {
+ error_ = keys::kGestureNeededForGenerateAppForLinkError;
+ return false;
+ }
+
+ scoped_ptr<management::GenerateAppForLink::Params> params(
+ management::GenerateAppForLink::Params::Create(*args_));
+ EXTENSION_FUNCTION_VALIDATE(params.get());
+
+ GURL launch_url(params->url);
+ if (!launch_url.is_valid() || !launch_url.SchemeIsHTTPOrHTTPS()) {
+ error_ = ErrorUtils::FormatErrorMessage(keys::kInvalidURLError,
+ params->url);
+ return false;
+ }
+
+ if (params->title.empty()) {
+ error_ = keys::kEmptyTitleError;
+ return false;
+ }
+
+ FaviconService* favicon_service =
+ FaviconServiceFactory::GetForProfile(GetProfile(),
+ Profile::EXPLICIT_ACCESS);
+ DCHECK(favicon_service);
+
+ title_ = params->title;
+ launch_url_ = launch_url;
+
+ favicon_service->GetFaviconImageForURL(
+ FaviconService::FaviconForURLParams(
+ launch_url, favicon_base::FAVICON, gfx::kFaviconSize),
+ base::Bind(&ManagementGenerateAppForLinkFunction::OnFaviconForApp, this),
+ &cancelable_task_tracker_);
+
+ // Matched with a Release() in OnExtensionLoaded().
+ AddRef();
+
+ // Response is sent async in OnExtensionLoaded().
+ return true;
+}
+
ManagementEventRouter::ManagementEventRouter(Profile* profile)
: profile_(profile) {
int types[] = {chrome::NOTIFICATION_EXTENSION_INSTALLED_DEPRECATED,
diff --git a/chrome/browser/extensions/api/management/management_api.h b/chrome/browser/extensions/api/management/management_api.h
index 6c98306..264a08f 100644
--- a/chrome/browser/extensions/api/management/management_api.h
+++ b/chrome/browser/extensions/api/management/management_api.h
@@ -6,9 +6,13 @@
#define CHROME_BROWSER_EXTENSIONS_API_MANAGEMENT_MANAGEMENT_API_H_
#include "base/compiler_specific.h"
+#include "base/task/cancelable_task_tracker.h"
+#include "chrome/browser/extensions/bookmark_app_helper.h"
#include "chrome/browser/extensions/chrome_extension_function.h"
#include "chrome/browser/extensions/extension_install_prompt.h"
#include "chrome/browser/extensions/extension_uninstall_dialog.h"
+#include "chrome/common/web_application_info.h"
+#include "components/favicon_base/favicon_types.h"
#include "components/keyed_service/core/keyed_service.h"
#include "content/public/browser/notification_observer.h"
#include "content/public/browser/notification_registrar.h"
@@ -200,6 +204,32 @@ class ManagementSetLaunchTypeFunction : public ManagementFunction {
virtual bool RunSync() OVERRIDE;
};
+class ManagementGenerateAppForLinkFunction : public AsyncManagementFunction {
+ public:
+ DECLARE_EXTENSION_FUNCTION("management.generateAppForLink",
+ MANAGEMENT_GENERATEAPPFORLINK);
+
+ ManagementGenerateAppForLinkFunction();
+
+ protected:
+ virtual ~ManagementGenerateAppForLinkFunction();
+
+ virtual bool RunAsync() OVERRIDE;
+
+ private:
+ void OnFaviconForApp(const favicon_base::FaviconImageResult& image_result);
+ void FinishCreateBookmarkApp(const extensions::Extension* extension,
+ const WebApplicationInfo& web_app_info);
+
+ std::string title_;
+ GURL launch_url_;
+
+ scoped_ptr<BookmarkAppHelper> bookmark_app_helper_;
+
+ // Used for favicon loading tasks.
+ base::CancelableTaskTracker cancelable_task_tracker_;
+};
+
class ManagementEventRouter : public content::NotificationObserver {
public:
explicit ManagementEventRouter(Profile* profile);
diff --git a/chrome/browser/extensions/api/management/management_api_constants.cc b/chrome/browser/extensions/api/management/management_api_constants.cc
index 3251084..bb2e0cb 100644
--- a/chrome/browser/extensions/api/management/management_api_constants.cc
+++ b/chrome/browser/extensions/api/management/management_api_constants.cc
@@ -37,5 +37,11 @@ const char kGestureNeededForSetLaunchTypeError[] =
"chrome.management.setLaunchType requires a user gesture.";
const char kLaunchTypeNotAvailableError[] =
"The launch type is not available for this app.";
+const char kGestureNeededForGenerateAppForLinkError[] =
+ "chrome.management.generateAppForLink requires a user gesture.";
+const char kInvalidURLError[] = "The URL \"*\" is invalid.";
+const char kEmptyTitleError[] = "The title can not be empty.";
+const char kGenerateAppForLinkInstallError[] =
+ "Failed to install the generated app.";
} // namespace extension_management_api_constants
diff --git a/chrome/browser/extensions/api/management/management_api_constants.h b/chrome/browser/extensions/api/management/management_api_constants.h
index 2c96554..4592231 100644
--- a/chrome/browser/extensions/api/management/management_api_constants.h
+++ b/chrome/browser/extensions/api/management/management_api_constants.h
@@ -29,6 +29,10 @@ extern const char kCreateOnlyPackagedAppShortcutMac[];
extern const char kCreateShortcutCanceledError[];
extern const char kGestureNeededForSetLaunchTypeError[];
extern const char kLaunchTypeNotAvailableError[];
+extern const char kGestureNeededForGenerateAppForLinkError[];
+extern const char kInvalidURLError[];
+extern const char kEmptyTitleError[];
+extern const char kGenerateAppForLinkInstallError[];
} // namespace extension_management_api_constants
diff --git a/chrome/browser/extensions/api/management/management_apitest.cc b/chrome/browser/extensions/api/management/management_apitest.cc
index a275eaf0..ee0b508 100644
--- a/chrome/browser/extensions/api/management/management_apitest.cc
+++ b/chrome/browser/extensions/api/management/management_apitest.cc
@@ -149,6 +149,20 @@ IN_PROC_BROWSER_TEST_F(ExtensionManagementApiTest,
"createAppShortcutNotInStable.html"));
}
+IN_PROC_BROWSER_TEST_F(ExtensionManagementApiTest, GenerateAppForLink) {
+ LoadExtensions();
+ ASSERT_TRUE(RunExtensionSubtest("management/test",
+ "generateAppForLink.html"));
+}
+
+IN_PROC_BROWSER_TEST_F(ExtensionManagementApiTest,
+ GenerateAppForLinkNotInStable) {
+ extensions::ScopedCurrentChannel channel(
+ chrome::VersionInfo::CHANNEL_STABLE);
+ ASSERT_TRUE(RunExtensionSubtest("management/test",
+ "generateAppForLinkNotInStable.html"));
+}
+
// Fails often on Windows dbg bots. http://crbug.com/177163
#if defined(OS_WIN)
#define MAYBE_ManagementPolicyAllowed DISABLED_ManagementPolicyAllowed
diff --git a/chrome/browser/extensions/bookmark_app_helper.cc b/chrome/browser/extensions/bookmark_app_helper.cc
index 4ef223f..bd5e2df 100644
--- a/chrome/browser/extensions/bookmark_app_helper.cc
+++ b/chrome/browser/extensions/bookmark_app_helper.cc
@@ -183,6 +183,9 @@ BookmarkAppHelper::BookmarkAppHelper(ExtensionService* service,
crx_installer_->set_error_on_unsupported_requirements(true);
+ if (!contents)
+ return;
+
// Add urls from the WebApplicationInfo.
std::vector<GURL> web_app_info_icon_urls;
for (std::vector<WebApplicationInfo::IconInfo>::const_iterator it =
@@ -204,7 +207,11 @@ BookmarkAppHelper::~BookmarkAppHelper() {}
void BookmarkAppHelper::Create(const CreateBookmarkAppCallback& callback) {
callback_ = callback;
- favicon_downloader_->Start();
+
+ if (favicon_downloader_.get())
+ favicon_downloader_->Start();
+ else
+ OnIconsDownloaded(true, std::map<GURL, std::vector<SkBitmap> >());
}
void BookmarkAppHelper::OnIconsDownloaded(
@@ -239,6 +246,18 @@ void BookmarkAppHelper::OnIconsDownloaded(
}
}
+ // Add all existing icons from WebApplicationInfo.
+ for (std::vector<WebApplicationInfo::IconInfo>::const_iterator it =
+ web_app_info_.icons.begin();
+ it != web_app_info_.icons.end();
+ ++it) {
+ const SkBitmap& icon = it->data;
+ if (!icon.drawsNothing() && icon.width() == icon.height())
+ downloaded_icons.push_back(icon);
+ }
+
+ web_app_info_.icons.clear();
+
// If there are icons that don't match the accepted icon sizes, find the
// closest bigger icon to the accepted sizes and resize the icon to it. An
// icon will be resized and used for at most one size.
diff --git a/chrome/browser/extensions/bookmark_app_helper.h b/chrome/browser/extensions/bookmark_app_helper.h
index b0cb661..c9bd9e9 100644
--- a/chrome/browser/extensions/bookmark_app_helper.h
+++ b/chrome/browser/extensions/bookmark_app_helper.h
@@ -37,7 +37,8 @@ class BookmarkAppHelper : public content::NotificationObserver {
// This helper class will create a bookmark app out of |web_app_info| and
// install it to |service|. Icons will be downloaded from the URLs in
- // |web_app_info.icons| using |contents|.
+ // |web_app_info.icons| using |contents| if |contents| is not NULL.
+ // All existing icons from WebApplicationInfo will also be used.
BookmarkAppHelper(ExtensionService* service,
WebApplicationInfo web_app_info,
content::WebContents* contents);
diff --git a/chrome/browser/extensions/bookmark_app_helper_unittest.cc b/chrome/browser/extensions/bookmark_app_helper_unittest.cc
index dccc06f..b3941fa 100644
--- a/chrome/browser/extensions/bookmark_app_helper_unittest.cc
+++ b/chrome/browser/extensions/bookmark_app_helper_unittest.cc
@@ -8,6 +8,9 @@
#include "chrome/browser/extensions/extension_service_unittest.h"
#include "chrome/common/extensions/manifest_handlers/app_launch_info.h"
#include "chrome/test/base/testing_profile.h"
+#include "content/public/browser/render_process_host.h"
+#include "content/public/browser/web_contents.h"
+#include "content/public/test/web_contents_tester.h"
#include "extensions/browser/extension_registry.h"
#include "extensions/common/constants.h"
#include "extensions/common/extension_icon_set.h"
@@ -24,7 +27,9 @@ const char kAppTitle[] = "Test title";
const char kAlternativeAppTitle[] = "Different test title";
const char kAppDescription[] = "Test description";
+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;
#endif
@@ -49,6 +54,19 @@ class BookmarkAppHelperExtensionServiceTest : public ExtensionServiceTestBase {
EXPECT_EQ(0u, service_->extensions()->size());
}
+ virtual void TearDown() OVERRIDE {
+ ExtensionServiceTestBase::TearDown();
+ for (content::RenderProcessHost::iterator i(
+ content::RenderProcessHost::AllHostsIterator());
+ !i.IsAtEnd();
+ i.Advance()) {
+ content::RenderProcessHost* host = i.GetCurrentValue();
+ if (Profile::FromBrowserContext(host->GetBrowserContext()) ==
+ profile_.get())
+ host->Cleanup();
+ }
+ }
+
private:
DISALLOW_COPY_AND_ASSIGN(BookmarkAppHelperExtensionServiceTest);
};
@@ -136,7 +154,9 @@ TEST_F(BookmarkAppHelperExtensionServiceTest, CreateBookmarkApp) {
web_app_info.title = base::UTF8ToUTF16(kAppTitle);
web_app_info.description = base::UTF8ToUTF16(kAppDescription);
- TestBookmarkAppHelper helper(service_, web_app_info, NULL);
+ scoped_ptr<content::WebContents> contents(
+ content::WebContentsTester::CreateTestWebContents(profile_.get(), NULL));
+ TestBookmarkAppHelper helper(service_, web_app_info, contents.get());
helper.Create(base::Bind(&TestBookmarkAppHelper::CreationComplete,
base::Unretained(&helper)));
@@ -160,6 +180,47 @@ TEST_F(BookmarkAppHelperExtensionServiceTest, CreateBookmarkApp) {
extension, kIconSizeSmall, ExtensionIconSet::MATCH_EXACTLY).empty());
}
+TEST_F(BookmarkAppHelperExtensionServiceTest, CreateBookmarkAppNoContents) {
+ WebApplicationInfo web_app_info;
+ web_app_info.app_url = GURL(kAppUrl);
+ web_app_info.title = base::UTF8ToUTF16(kAppTitle);
+ web_app_info.description = base::UTF8ToUTF16(kAppDescription);
+ web_app_info.icons.push_back(
+ CreateIconInfoWithBitmap(kIconSizeTiny, SK_ColorRED));
+
+ TestBookmarkAppHelper helper(service_, web_app_info, NULL);
+ helper.Create(base::Bind(&TestBookmarkAppHelper::CreationComplete,
+ base::Unretained(&helper)));
+
+ base::RunLoop().RunUntilIdle();
+ EXPECT_TRUE(helper.extension());
+ const Extension* extension =
+ service_->GetInstalledExtension(helper.extension()->id());
+ EXPECT_TRUE(extension);
+ EXPECT_EQ(1u, service_->extensions()->size());
+ EXPECT_TRUE(extension->from_bookmark());
+ EXPECT_EQ(kAppTitle, extension->name());
+ EXPECT_EQ(kAppDescription, extension->description());
+ EXPECT_EQ(GURL(kAppUrl), AppLaunchInfo::GetLaunchWebURL(extension));
+ EXPECT_FALSE(
+ IconsInfo::GetIconResource(
+ extension, kIconSizeTiny, ExtensionIconSet::MATCH_EXACTLY).empty());
+ EXPECT_FALSE(
+ IconsInfo::GetIconResource(
+ extension, kIconSizeSmall, ExtensionIconSet::MATCH_EXACTLY).empty());
+ EXPECT_FALSE(
+ IconsInfo::GetIconResource(extension,
+ kIconSizeSmall * 2,
+ ExtensionIconSet::MATCH_EXACTLY).empty());
+ EXPECT_FALSE(
+ IconsInfo::GetIconResource(
+ extension, kIconSizeMedium, ExtensionIconSet::MATCH_EXACTLY).empty());
+ EXPECT_FALSE(
+ IconsInfo::GetIconResource(extension,
+ kIconSizeMedium * 2,
+ ExtensionIconSet::MATCH_EXACTLY).empty());
+}
+
TEST_F(BookmarkAppHelperExtensionServiceTest, CreateAndUpdateBookmarkApp) {
EXPECT_EQ(0u, registry_->enabled_extensions().size());
WebApplicationInfo web_app_info;
diff --git a/chrome/common/extensions/api/_api_features.json b/chrome/common/extensions/api/_api_features.json
index 6dc9dc9..186226c 100644
--- a/chrome/common/extensions/api/_api_features.json
+++ b/chrome/common/extensions/api/_api_features.json
@@ -542,6 +542,11 @@
"channel": "dev",
"contexts": ["blessed_extension"]
},
+ "management.generateAppForLink": {
+ "dependencies": ["permission:management"],
+ "channel": "dev",
+ "contexts": ["blessed_extension"]
+ },
// This is not a real API, only here for documentation purposes.
// See http://crbug.com/275944 for background.
"manifestTypes": {
diff --git a/chrome/common/extensions/api/management.json b/chrome/common/extensions/api/management.json
index fb0868e..eac94c8 100644
--- a/chrome/common/extensions/api/management.json
+++ b/chrome/common/extensions/api/management.json
@@ -355,6 +355,33 @@
"parameters": []
}
]
+ },
+ {
+ "name": "generateAppForLink",
+ "description": "Generate an app for a URL. Returns the generated bookmark app. Note: This function is only available to Chrome users on the dev channel.",
+ "parameters": [
+ {
+ "name": "url",
+ "type": "string",
+ "description": "The URL of a web page. The scheme of the URL can only be \"http\" or \"https\"."
+ },
+ {
+ "name": "title",
+ "type": "string",
+ "description": "The title of the generated app."
+ },
+ {
+ "name": "callback",
+ "type": "function",
+ "optional": true,
+ "parameters": [
+ {
+ "name": "result",
+ "$ref": "ExtensionInfo"
+ }
+ ]
+ }
+ ]
}
],
"events": [
diff --git a/chrome/test/data/extensions/api_test/management/test/generateAppForLink.html b/chrome/test/data/extensions/api_test/management/test/generateAppForLink.html
new file mode 100644
index 0000000..c44fa6f
--- /dev/null
+++ b/chrome/test/data/extensions/api_test/management/test/generateAppForLink.html
@@ -0,0 +1,7 @@
+<!--
+ * Copyright 2014 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.
+-->
+<script src="common.js"></script>
+<script src="generateAppForLink.js"></script>
diff --git a/chrome/test/data/extensions/api_test/management/test/generateAppForLink.js b/chrome/test/data/extensions/api_test/management/test/generateAppForLink.js
new file mode 100644
index 0000000..c7eba3b
--- /dev/null
+++ b/chrome/test/data/extensions/api_test/management/test/generateAppForLink.js
@@ -0,0 +1,78 @@
+// Copyright 2014 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.
+
+function testGenerateAppForLink(url, title, error, func) {
+ chrome.test.runWithUserGesture(function() {
+ if (error)
+ chrome.management.generateAppForLink(
+ url, title, callback(function(data) {}, error));
+ else
+ chrome.management.generateAppForLink(url, title, callback(func));
+ });
+}
+
+var tests = [
+ function generateAppForLinkWithoutUserGesture() {
+ chrome.management.generateAppForLink(
+ "http://google.com", "test", callback(function() {},
+ "chrome.management.generateAppForLink requires a user gesture."));
+ },
+
+ function generateAppForInvalidLink() {
+ testGenerateAppForLink("", "test", "The URL \"\" is invalid.");
+ testGenerateAppForLink("aaaa", "test", "The URL \"aaaa\" is invalid.");
+ testGenerateAppForLink("http1://google.com", "test",
+ "The URL \"http1://google.com\" is invalid.");
+ testGenerateAppForLink("chrome://about", "test",
+ "The URL \"chrome://about\" is invalid.");
+ testGenerateAppForLink("chrome-extension://test/test", "test",
+ "The URL \"chrome-extension://test/test\" is invalid.");
+ },
+
+ function generateAppWithEmptyTitle() {
+ testGenerateAppForLink("http://google.com", "",
+ "The title can not be empty.");
+ },
+
+ function generateAppForLinkWithShortURL() {
+ var url = "http://google.com", title = "testApp";
+ testGenerateAppForLink(
+ url, title, null, function(data) {
+ assertEq("http://google.com/", data.appLaunchUrl);
+ assertEq(title, data.name);
+ // There is no favicon in the test browser, so only 4 icons will
+ // be created.
+ assertEq(4, data.icons.length);
+ assertEq(32, data.icons[0].size);
+ assertEq(48, data.icons[1].size);
+ assertEq(64, data.icons[2].size);
+ assertEq(96, data.icons[3].size);
+
+ chrome.management.getAll(callback(function(items) {
+ assertTrue(getItemNamed(items, title) != null);
+ }));
+ });
+ },
+
+ function generateAppForLinkWithLongURL() {
+ var url = "http://google.com/page/page?aa=bb&cc=dd", title = "test App 2";
+ testGenerateAppForLink(
+ url, title, null, function(data) {
+ assertEq(url, data.appLaunchUrl);
+ assertEq(title, data.name);
+ assertEq(4, data.icons.length);
+ assertEq(32, data.icons[0].size);
+ assertEq(48, data.icons[1].size);
+ assertEq(64, data.icons[2].size);
+ assertEq(96, data.icons[3].size);
+
+ chrome.management.getAll(callback(function(items) {
+ assertTrue(getItemNamed(items, title) != null);
+ }));
+ });
+ }
+];
+
+chrome.test.runTests(tests);
+
diff --git a/chrome/test/data/extensions/api_test/management/test/generateAppForLinkNotInStable.html b/chrome/test/data/extensions/api_test/management/test/generateAppForLinkNotInStable.html
new file mode 100644
index 0000000..7edf7b6
--- /dev/null
+++ b/chrome/test/data/extensions/api_test/management/test/generateAppForLinkNotInStable.html
@@ -0,0 +1,7 @@
+<!--
+ * Copyright 2014 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.
+-->
+<script src="common.js"></script>
+<script src="generateAppForLinkNotInStable.js"></script>
diff --git a/chrome/test/data/extensions/api_test/management/test/generateAppForLinkNotInStable.js b/chrome/test/data/extensions/api_test/management/test/generateAppForLinkNotInStable.js
new file mode 100644
index 0000000..3d5eadc
--- /dev/null
+++ b/chrome/test/data/extensions/api_test/management/test/generateAppForLinkNotInStable.js
@@ -0,0 +1,12 @@
+// Copyright 2014 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.
+
+var tests = [
+ function generateAppForLinkNotInStable() {
+ assertEq(chrome.management.generateAppForLink, undefined);
+ succeed();
+ }
+];
+
+chrome.test.runTests(tests);
diff --git a/extensions/browser/extension_function_histogram_value.h b/extensions/browser/extension_function_histogram_value.h
index dbe0581..f0cfd15 100644
--- a/extensions/browser/extension_function_histogram_value.h
+++ b/extensions/browser/extension_function_histogram_value.h
@@ -843,6 +843,7 @@ enum HistogramValue {
FILEBROWSERPRIVATE_OPENINSPECTOR,
STREAMSPRIVATE_ABORT,
MANAGEMENT_SETLAUNCHTYPE,
+ MANAGEMENT_GENERATEAPPFORLINK,
// Last entry: Add new entries above and ensure to update
// tools/metrics/histograms/histograms/histograms.xml.
ENUM_BOUNDARY
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml
index 4828deb..c2fd7d3 100644
--- a/tools/metrics/histograms/histograms.xml
+++ b/tools/metrics/histograms/histograms.xml
@@ -35779,6 +35779,7 @@ Therefore, the affected-histogram name has to have at least one dot in it.
<int value="782" label="FILEBROWSERPRIVATE_OPENINSPECTOR"/>
<int value="783" label="STREAMSPRIVATE_ABORT"/>
<int value="784" label="MANAGEMENT_SETLAUNCHTYPE"/>
+ <int value="785" label="MANAGEMENT_GENERATEAPPFORLINK"/>
</enum>
<enum name="ExtensionInstallCause" type="int">