summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--chrome/browser/chrome_browser_main.cc8
-rw-r--r--chrome/browser/extensions/crx_installer.cc14
-rw-r--r--chrome/browser/extensions/extension_install_dialog.cc4
-rw-r--r--chrome/browser/extensions/startup_helper.cc75
-rw-r--r--chrome/browser/extensions/startup_helper.h5
-rw-r--r--chrome/browser/extensions/tab_helper.cc29
-rw-r--r--chrome/browser/extensions/tab_helper.h12
-rw-r--r--chrome/browser/extensions/webstore_inline_install_browsertest.cc60
-rw-r--r--chrome/browser/extensions/webstore_inline_installer.cc51
-rw-r--r--chrome/browser/extensions/webstore_inline_installer.h33
-rw-r--r--chrome/common/chrome_result_codes.h4
-rw-r--r--chrome/common/chrome_switches.cc7
-rw-r--r--chrome/common/chrome_switches.h1
13 files changed, 232 insertions, 71 deletions
diff --git a/chrome/browser/chrome_browser_main.cc b/chrome/browser/chrome_browser_main.cc
index f619d2a0..a5ab527 100644
--- a/chrome/browser/chrome_browser_main.cc
+++ b/chrome/browser/chrome_browser_main.cc
@@ -1292,6 +1292,14 @@ int ChromeBrowserMainParts::PreMainMessageLoopRunImpl() {
return chrome::RESULT_CODE_UNINSTALL_EXTENSION_ERROR;
}
+ if (parsed_command_line().HasSwitch(switches::kInstallFromWebstore)) {
+ extensions::StartupHelper helper;
+ if (helper.InstallFromWebstore(parsed_command_line(), profile_))
+ return content::RESULT_CODE_NORMAL_EXIT;
+ return chrome::RESULT_CODE_INSTALL_FROM_WEBSTORE_ERROR;
+ }
+
+
// Start watching for hangs during startup. We disarm this hang detector when
// ThreadWatcher takes over or when browser is shutdown or when
// startup_watcher_ is deleted.
diff --git a/chrome/browser/extensions/crx_installer.cc b/chrome/browser/extensions/crx_installer.cc
index 3886528..d1f2a77 100644
--- a/chrome/browser/extensions/crx_installer.cc
+++ b/chrome/browser/extensions/crx_installer.cc
@@ -110,9 +110,11 @@ CrxInstaller::CrxInstaller(
return;
CHECK(profile_->IsSameProfile(approval->profile));
- client_->install_ui()->SetUseAppInstalledBubble(
- approval->use_app_installed_bubble);
- client_->install_ui()->SetSkipPostInstallUI(approval->skip_post_install_ui);
+ if (client_) {
+ client_->install_ui()->SetUseAppInstalledBubble(
+ approval->use_app_installed_bubble);
+ client_->install_ui()->SetSkipPostInstallUI(approval->skip_post_install_ui);
+ }
if (approval->skip_install_dialog) {
// Mark the extension as approved, but save the expected manifest and ID
@@ -139,8 +141,10 @@ CrxInstaller::~CrxInstaller() {
base::Bind(&extension_file_util::DeleteFile, source_file_, false));
}
// Make sure the UI is deleted on the ui thread.
- BrowserThread::DeleteSoon(BrowserThread::UI, FROM_HERE, client_);
- client_ = NULL;
+ if (client_) {
+ BrowserThread::DeleteSoon(BrowserThread::UI, FROM_HERE, client_);
+ client_ = NULL;
+ }
}
void CrxInstaller::InstallCrx(const FilePath& source_file) {
diff --git a/chrome/browser/extensions/extension_install_dialog.cc b/chrome/browser/extensions/extension_install_dialog.cc
index 71fa908bd..a3cd87b 100644
--- a/chrome/browser/extensions/extension_install_dialog.cc
+++ b/chrome/browser/extensions/extension_install_dialog.cc
@@ -68,9 +68,5 @@ void ShowExtensionInstallDialog(gfx::NativeWindow parent,
DoAutoConfirm(auto_confirm, delegate);
return;
}
- if (!parent) {
- delegate->InstallUIAbort(false);
- return;
- }
ShowExtensionInstallDialogImpl(parent, navigator, delegate, prompt);
}
diff --git a/chrome/browser/extensions/startup_helper.cc b/chrome/browser/extensions/startup_helper.cc
index b0c90bc..aabbf71 100644
--- a/chrome/browser/extensions/startup_helper.cc
+++ b/chrome/browser/extensions/startup_helper.cc
@@ -4,13 +4,19 @@
#include "chrome/browser/extensions/startup_helper.h"
+#include "base/bind.h"
#include "base/command_line.h"
+#include "base/message_loop.h"
#include "base/string_util.h"
#include "base/stringprintf.h"
#include "base/utf_string_conversions.h"
#include "chrome/browser/extensions/extension_service.h"
+#include "chrome/browser/extensions/webstore_inline_installer.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/common/chrome_switches.h"
+#include "chrome/common/extensions/extension.h"
+#include "content/public/browser/web_contents.h"
+#include "ipc/ipc_message.h"
namespace {
@@ -76,6 +82,75 @@ bool StartupHelper::UninstallExtension(const CommandLine& cmd_line,
extension_id);
}
+namespace {
+
+class AppInstallHelper {
+ public:
+ AppInstallHelper();
+ virtual ~AppInstallHelper();
+ bool success() { return success_; }
+ const std::string& error() { return error_; }
+
+ WebstoreInlineInstaller::Callback Callback();
+ void OnAppInstallComplete(bool success, const std::string& error);
+
+ private:
+ // These hold on to the result of the app install when it is complete.
+ bool success_;
+ std::string error_;
+};
+
+AppInstallHelper::AppInstallHelper() : success_(false) {}
+
+AppInstallHelper::~AppInstallHelper() {}
+
+WebstoreInlineInstaller::Callback AppInstallHelper::Callback() {
+ return base::Bind(&AppInstallHelper::OnAppInstallComplete,
+ base::Unretained(this));
+}
+void AppInstallHelper::OnAppInstallComplete(bool success,
+ const std::string& error) {
+ success_ = success;
+ error_= error;
+ MessageLoop::current()->Quit();
+}
+
+} // namespace
+
+bool StartupHelper::InstallFromWebstore(const CommandLine& cmd_line,
+ Profile* profile) {
+ std::string id = cmd_line.GetSwitchValueASCII(switches::kInstallFromWebstore);
+ if (!Extension::IdIsValid(id)) {
+ LOG(ERROR) << "Invalid id for " << switches::kInstallFromWebstore
+ << " : '" << id << "'";
+ return false;
+ }
+
+ // TODO(asargent) - it would be nice not to need a WebContents just to
+ // use the inline installer. (crbug.com/149039)
+ scoped_ptr<content::WebContents> web_contents(
+ content::WebContents::Create(profile, NULL, MSG_ROUTING_NONE, NULL));
+
+ AppInstallHelper helper;
+ WebstoreInlineInstaller::Callback callback =
+ base::Bind(&AppInstallHelper::OnAppInstallComplete,
+ base::Unretained(&helper));
+ scoped_refptr<WebstoreInlineInstaller> installer(
+ new WebstoreInlineInstaller(
+ web_contents.get(),
+ id,
+ WebstoreInlineInstaller::DO_NOT_REQUIRE_VERIFIED_SITE,
+ GURL(),
+ callback));
+ installer->set_skip_post_install_ui(true);
+ installer->BeginInstall();
+
+ MessageLoop::current()->Run();
+ if (!helper.success())
+ LOG(ERROR) << "InstallFromWebstore failed with error: " << helper.error();
+ return helper.success();
+}
+
StartupHelper::~StartupHelper() {
if (pack_job_.get())
pack_job_->ClearClient();
diff --git a/chrome/browser/extensions/startup_helper.h b/chrome/browser/extensions/startup_helper.h
index f4aedc4..1f88d99 100644
--- a/chrome/browser/extensions/startup_helper.h
+++ b/chrome/browser/extensions/startup_helper.h
@@ -33,6 +33,11 @@ class StartupHelper : public PackExtensionJob::Client {
// could not be started.
bool UninstallExtension(const CommandLine& cmd_line, Profile* profile);
+ // Handle --install-from-webstore flag from |cmd_line| by downloading
+ // metadata from the webstore for the given id, prompting the user to
+ // confirm, and then downloading the crx and installing it.
+ bool InstallFromWebstore(const CommandLine& cmd_line, Profile* profile);
+
private:
scoped_refptr<PackExtensionJob> pack_job_;
bool pack_job_succeeded_;
diff --git a/chrome/browser/extensions/tab_helper.cc b/chrome/browser/extensions/tab_helper.cc
index 0f5c91f..0d3c477 100644
--- a/chrome/browser/extensions/tab_helper.cc
+++ b/chrome/browser/extensions/tab_helper.cc
@@ -259,13 +259,15 @@ void TabHelper::OnInlineWebstoreInstall(
int return_route_id,
const std::string& webstore_item_id,
const GURL& requestor_url) {
+ WebstoreInlineInstaller::Callback callback =
+ base::Bind(&TabHelper::OnInlineInstallComplete, base::Unretained(this),
+ install_id, return_route_id);
scoped_refptr<WebstoreInlineInstaller> installer(new WebstoreInlineInstaller(
web_contents(),
- install_id,
- return_route_id,
webstore_item_id,
+ WebstoreInlineInstaller::REQUIRE_VERIFIED_SITE,
requestor_url,
- this));
+ callback));
installer->BeginInstall();
}
@@ -415,16 +417,17 @@ WindowController* TabHelper::GetExtensionWindowController() const {
return ExtensionTabUtil::GetWindowControllerOfTab(web_contents());
}
-void TabHelper::OnInlineInstallSuccess(int install_id, int return_route_id) {
- Send(new ExtensionMsg_InlineWebstoreInstallResponse(
- return_route_id, install_id, true, ""));
-}
-
-void TabHelper::OnInlineInstallFailure(int install_id,
- int return_route_id,
- const std::string& error) {
- Send(new ExtensionMsg_InlineWebstoreInstallResponse(
- return_route_id, install_id, false, error));
+void TabHelper::OnInlineInstallComplete(int install_id,
+ int return_route_id,
+ bool success,
+ const std::string& error) {
+ if (success) {
+ Send(new ExtensionMsg_InlineWebstoreInstallResponse(
+ return_route_id, install_id, true, ""));
+ } else {
+ Send(new ExtensionMsg_InlineWebstoreInstallResponse(
+ return_route_id, install_id, false, error));
+ }
}
WebContents* TabHelper::GetAssociatedWebContents() const {
diff --git a/chrome/browser/extensions/tab_helper.h b/chrome/browser/extensions/tab_helper.h
index 05a2665..f9fac32 100644
--- a/chrome/browser/extensions/tab_helper.h
+++ b/chrome/browser/extensions/tab_helper.h
@@ -37,7 +37,6 @@ class ScriptExecutor;
class TabHelper : public content::WebContentsObserver,
public ExtensionFunctionDispatcher::Delegate,
public ImageLoadingTracker::Observer,
- public WebstoreInlineInstaller::Delegate,
public AppNotifyChannelSetup::Delegate,
public base::SupportsWeakPtr<TabHelper>,
public content::NotificationObserver,
@@ -163,12 +162,11 @@ class TabHelper : public content::WebContentsObserver,
const std::string& extension_id,
int index) OVERRIDE;
- // WebstoreInlineInstaller::Delegate.
- virtual void OnInlineInstallSuccess(int install_id,
- int return_route_id) OVERRIDE;
- virtual void OnInlineInstallFailure(int install_id,
- int return_route_id,
- const std::string& error) OVERRIDE;
+ // WebstoreInlineInstaller::Callback.
+ virtual void OnInlineInstallComplete(int install_id,
+ int return_route_id,
+ bool success,
+ const std::string& error);
// AppNotifyChannelSetup::Delegate.
virtual void AppNotifyChannelSetupComplete(
diff --git a/chrome/browser/extensions/webstore_inline_install_browsertest.cc b/chrome/browser/extensions/webstore_inline_install_browsertest.cc
index becb99d..737ce5b 100644
--- a/chrome/browser/extensions/webstore_inline_install_browsertest.cc
+++ b/chrome/browser/extensions/webstore_inline_install_browsertest.cc
@@ -9,6 +9,7 @@
#include "chrome/browser/extensions/extension_install_dialog.h"
#include "chrome/browser/extensions/extension_install_ui.h"
#include "chrome/browser/extensions/extension_service.h"
+#include "chrome/browser/extensions/startup_helper.h"
#include "chrome/browser/extensions/webstore_inline_installer.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_tabstrip.h"
@@ -17,6 +18,8 @@
#include "chrome/common/chrome_switches.h"
#include "chrome/test/base/in_process_browser_test.h"
#include "chrome/test/base/ui_test_utils.h"
+#include "content/public/browser/notification_registrar.h"
+#include "content/public/browser/notification_service.h"
#include "content/public/browser/notification_types.h"
#include "content/public/browser/web_contents.h"
#include "content/public/test/browser_test_utils.h"
@@ -25,10 +28,12 @@
#include "net/base/mock_host_resolver.h"
using content::WebContents;
+using extensions::Extension;
const char kWebstoreDomain[] = "cws.com";
const char kAppDomain[] = "app.com";
const char kNonAppDomain[] = "nonapp.com";
+const char kTestExtensionId[] = "ecglahbcnmdpdciemllbhojghbkagdje";
class WebstoreInlineInstallTest : public InProcessBrowserTest {
public:
@@ -93,8 +98,7 @@ IN_PROC_BROWSER_TEST_F(WebstoreInlineInstallTest, Install) {
RunInlineInstallTest("runTest");
const extensions::Extension* extension = browser()->profile()->
- GetExtensionService()->GetExtensionById(
- "ecglahbcnmdpdciemllbhojghbkagdje", false);
+ GetExtensionService()->GetExtensionById(kTestExtensionId, false);
EXPECT_TRUE(extension);
}
@@ -174,3 +178,55 @@ IN_PROC_BROWSER_TEST_F(WebstoreInlineInstallUnpackFailureTest,
RunInlineInstallTest("runTest");
}
+
+class CommandLineWebstoreInstall : public WebstoreInlineInstallTest,
+ public content::NotificationObserver {
+ public:
+ CommandLineWebstoreInstall() : saw_install_(false) {}
+ virtual ~CommandLineWebstoreInstall() {}
+
+ virtual void SetUpOnMainThread() OVERRIDE {
+ WebstoreInlineInstallTest::SetUpOnMainThread();
+ registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_INSTALLED,
+ content::NotificationService::AllSources());
+ CommandLine::ForCurrentProcess()->AppendSwitchASCII(
+ switches::kInstallFromWebstore, kTestExtensionId);
+ }
+
+ bool saw_install() { return saw_install_; }
+
+ protected:
+ // NotificationObserver interface.
+ virtual void Observe(int type,
+ const content::NotificationSource& source,
+ const content::NotificationDetails& details) OVERRIDE {
+ ASSERT_EQ(chrome::NOTIFICATION_EXTENSION_INSTALLED, type);
+ const Extension* extension = content::Details<Extension>(details).ptr();
+ ASSERT_TRUE(extension != NULL);
+ EXPECT_EQ(extension->id(), kTestExtensionId);
+ saw_install_ = true;
+ }
+
+ content::NotificationRegistrar registrar_;
+
+ // Have we seen an installation notification for kTestExtensionId ?
+ bool saw_install_;
+};
+
+IN_PROC_BROWSER_TEST_F(CommandLineWebstoreInstall, Accept) {
+ CommandLine* command_line = CommandLine::ForCurrentProcess();
+ command_line->AppendSwitchASCII(
+ switches::kAppsGalleryInstallAutoConfirmForTests, "accept");
+ extensions::StartupHelper helper;
+ EXPECT_TRUE(helper.InstallFromWebstore(*command_line, browser()->profile()));
+ EXPECT_TRUE(saw_install());
+}
+
+IN_PROC_BROWSER_TEST_F(CommandLineWebstoreInstall, Cancel) {
+ CommandLine* command_line = CommandLine::ForCurrentProcess();
+ command_line->AppendSwitchASCII(
+ switches::kAppsGalleryInstallAutoConfirmForTests, "cancel");
+ extensions::StartupHelper helper;
+ EXPECT_FALSE(helper.InstallFromWebstore(*command_line, browser()->profile()));
+ EXPECT_FALSE(saw_install());
+}
diff --git a/chrome/browser/extensions/webstore_inline_installer.cc b/chrome/browser/extensions/webstore_inline_installer.cc
index c833c7a..6fe8c37 100644
--- a/chrome/browser/extensions/webstore_inline_installer.cc
+++ b/chrome/browser/extensions/webstore_inline_installer.cc
@@ -147,20 +147,21 @@ class SafeWebstoreResponseParser : public UtilityProcessHostClient {
scoped_ptr<DictionaryValue> parsed_webstore_data_;
};
-WebstoreInlineInstaller::WebstoreInlineInstaller(WebContents* web_contents,
- int install_id,
- int return_route_id,
- std::string webstore_item_id,
- GURL requestor_url,
- Delegate* delegate)
+WebstoreInlineInstaller::WebstoreInlineInstaller(
+ WebContents* web_contents,
+ std::string webstore_item_id,
+ VerifiedSiteRequired require_verified_site,
+ GURL requestor_url,
+ Callback callback)
: content::WebContentsObserver(web_contents),
- install_id_(install_id),
- return_route_id_(return_route_id),
id_(webstore_item_id),
+ require_verified_site_(require_verified_site == REQUIRE_VERIFIED_SITE),
requestor_url_(requestor_url),
- delegate_(delegate),
+ callback_(callback),
+ skip_post_install_ui_(false),
average_rating_(0.0),
rating_count_(0) {
+ CHECK(!callback.is_null());
}
void WebstoreInlineInstaller::BeginInstall() {
@@ -294,21 +295,21 @@ void WebstoreInlineInstaller::OnWebstoreResponseParseSuccess(
}
}
- // Verified site is required
- if (webstore_data->HasKey(kVerifiedSiteKey)) {
+ // Check for a verified site if required.
+ if (require_verified_site_) {
+ if (!webstore_data->HasKey(kVerifiedSiteKey)) {
+ CompleteInstall(kNoVerifiedSiteError);
+ return;
+ }
std::string verified_site;
if (!webstore_data->GetString(kVerifiedSiteKey, &verified_site)) {
CompleteInstall(kInvalidWebstoreResponseError);
return;
}
-
if (!IsRequestorURLInVerifiedSite(requestor_url_, verified_site)) {
CompleteInstall(kNotFromVerifiedSiteError);
return;
}
- } else {
- CompleteInstall(kNoVerifiedSiteError);
- return;
}
scoped_refptr<WebstoreInstallHelper> helper = new WebstoreInstallHelper(
@@ -365,8 +366,7 @@ void WebstoreInlineInstaller::OnWebstoreParseSuccess(
return;
}
- install_ui_.reset(
- ExtensionInstallUI::CreateInstallPromptWithWebContents(web_contents()));
+ install_ui_.reset(new ExtensionInstallPrompt(NULL, web_contents(), profile));
install_ui_->ConfirmInlineInstall(this, dummy_extension_, &icon_, prompt);
// Control flow finishes up in InstallUIProceed or InstallUIAbort.
}
@@ -393,7 +393,10 @@ void WebstoreInlineInstaller::InstallUIProceed() {
profile,
id_,
scoped_ptr<base::DictionaryValue>(manifest_.get()->DeepCopy())));
- approval->use_app_installed_bubble = true;
+ if (skip_post_install_ui_)
+ approval->skip_post_install_ui = true;
+ else
+ approval->use_app_installed_bubble = true;
scoped_refptr<WebstoreInstaller> installer = new WebstoreInstaller(
profile, this, &(web_contents()->GetController()), id_, approval.Pass(),
@@ -406,6 +409,7 @@ void WebstoreInlineInstaller::InstallUIAbort(bool user_initiated) {
}
void WebstoreInlineInstaller::WebContentsDestroyed(WebContents* web_contents) {
+ callback_.Reset();
// Abort any in-progress fetches.
if (webstore_data_url_fetcher_.get()) {
webstore_data_url_fetcher_.reset();
@@ -425,15 +429,8 @@ void WebstoreInlineInstaller::OnExtensionInstallFailure(
}
void WebstoreInlineInstaller::CompleteInstall(const std::string& error) {
- // Only bother responding if there's still a tab contents to send back the
- // response to.
- if (web_contents()) {
- if (error.empty()) {
- delegate_->OnInlineInstallSuccess(install_id_, return_route_id_);
- } else {
- delegate_->OnInlineInstallFailure(install_id_, return_route_id_, error);
- }
- }
+ if (!callback_.is_null())
+ callback_.Run(error.empty(), error);
Release(); // Matches the AddRef in BeginInstall.
}
diff --git a/chrome/browser/extensions/webstore_inline_installer.h b/chrome/browser/extensions/webstore_inline_installer.h
index c01b481..5525b69 100644
--- a/chrome/browser/extensions/webstore_inline_installer.h
+++ b/chrome/browser/extensions/webstore_inline_installer.h
@@ -7,6 +7,7 @@
#include <string>
+#include "base/callback.h"
#include "base/memory/ref_counted.h"
#include "base/memory/scoped_ptr.h"
#include "base/values.h"
@@ -27,6 +28,9 @@ namespace extensions {
class Extension;
class SafeWebstoreResponseParser;
+// TODO(asargent) - rename this class to something like
+// WebstoreStandaloneInstaller.
+//
// Manages inline installs requested by a page (downloads and parses metadata
// from the webstore, shows the install UI, starts the download once the user
// confirms). Clients must implement the WebstoreInlineInstaller::Delegate
@@ -41,21 +45,24 @@ class WebstoreInlineInstaller
public WebstoreInstaller::Delegate,
public WebstoreInstallHelper::Delegate {
public:
- class Delegate {
- public:
- virtual void OnInlineInstallSuccess(int install_id,
- int return_route_id) = 0;
- virtual void OnInlineInstallFailure(int install_id,
- int return_route_id,
- const std::string& error) = 0;
+ enum VerifiedSiteRequired {
+ REQUIRE_VERIFIED_SITE,
+ DO_NOT_REQUIRE_VERIFIED_SITE
};
+ // A callback for when the install process completes successfully or not. If
+ // there was a failure, |success| will be false and |error| may contain a
+ // developer-readable error message about why it failed.
+ typedef base::Callback<void(bool success, const std::string& error)> Callback;
+
WebstoreInlineInstaller(content::WebContents* web_contents,
- int install_id,
- int return_route_id,
std::string webstore_item_id,
+ VerifiedSiteRequired require_verified_site,
GURL requestor_url,
- Delegate* d);
+ Callback callback);
+
+ void set_skip_post_install_ui(bool skip) { skip_post_install_ui_ = skip; }
+
void BeginInstall();
private:
@@ -115,12 +122,12 @@ class WebstoreInlineInstaller
static bool IsRequestorURLInVerifiedSite(const GURL& requestor_url,
const std::string& verified_site);
- int install_id_;
- int return_route_id_;
std::string id_;
+ bool require_verified_site_;
GURL requestor_url_;
- Delegate* delegate_;
+ Callback callback_;
scoped_ptr<ExtensionInstallPrompt> install_ui_;
+ bool skip_post_install_ui_;
// For fetching webstore JSON data.
scoped_ptr<net::URLFetcher> webstore_data_url_fetcher_;
diff --git a/chrome/common/chrome_result_codes.h b/chrome/common/chrome_result_codes.h
index 8d9077a..045edd9 100644
--- a/chrome/common/chrome_result_codes.h
+++ b/chrome/common/chrome_result_codes.h
@@ -72,6 +72,10 @@ enum ResultCode {
// running browser.
RESULT_CODE_NORMAL_EXIT_PROCESS_NOTIFIED,
+ // Failed to install an item from the webstore when the kInstallFromWebstore
+ // command line flag was present.
+ RESULT_CODE_INSTALL_FROM_WEBSTORE_ERROR,
+
// Last return code (keep this last).
RESULT_CODE_CHROME_LAST_CODE,
};
diff --git a/chrome/common/chrome_switches.cc b/chrome/common/chrome_switches.cc
index b638862..9962f3d 100644
--- a/chrome/common/chrome_switches.cc
+++ b/chrome/common/chrome_switches.cc
@@ -91,6 +91,9 @@ const char kAppsGalleryURL[] = "apps-gallery-url";
// The update url used by gallery/webstore extensions.
const char kAppsGalleryUpdateURL[] = "apps-gallery-update-url";
+// TODO(asargent) - remove this flag and change uses of it to instead use
+// kInstallFromWebstore.
+//
// Specifies the URL of an application manifest to retrieve. The user will be
// prompted for consent and the application retrieved/installed if consented.
const char kAppsInstallFromManifestURL[] = "apps-install-from-manifest-url";
@@ -793,6 +796,10 @@ const char kImportFromFile[] = "import-from-file";
// Causes the browser to launch directly in incognito mode.
const char kIncognito[] = "incognito";
+// Causes Chrome to attempt to get metadata from the webstore for the
+// app/extension ID given, and then prompt the user to download and install it.
+const char kInstallFromWebstore[] = "install-from-webstore";
+
// URL to use for instant. If specified this overrides the url from the
// TemplateURL.
const char kInstantURL[] = "instant-url";
diff --git a/chrome/common/chrome_switches.h b/chrome/common/chrome_switches.h
index a126885..67dc75b 100644
--- a/chrome/common/chrome_switches.h
+++ b/chrome/common/chrome_switches.h
@@ -214,6 +214,7 @@ extern const char kIgnoreGpuBlacklist[];
extern const char kImport[];
extern const char kImportFromFile[];
extern const char kIncognito[];
+extern const char kInstallFromWebstore[];
extern const char kInstantURL[];
extern const char kKeepAliveForTest[];
extern const char kKioskMode[];