1// Copyright 2014 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "chrome/browser/apps/install_chrome_app.h"
6
7#include "base/basictypes.h"
8#include "base/command_line.h"
9#include "base/strings/stringprintf.h"
10#include "chrome/browser/browser_process.h"
11#include "chrome/browser/extensions/webstore_install_with_prompt.h"
12#include "chrome/browser/extensions/webstore_standalone_installer.h"
13#include "chrome/browser/profiles/profile.h"
14#include "chrome/browser/ui/browser.h"
15#include "chrome/browser/ui/browser_list.h"
16#include "chrome/browser/ui/browser_window.h"
17#include "chrome/common/extensions/webstore_install_result.h"
18#include "components/crx_file/id_util.h"
19#include "extensions/browser/extension_registry.h"
20#include "extensions/common/manifest_constants.h"
21
22using extensions::ExtensionRegistry;
23
24namespace {
25
26// The URL to the webstore page for a specific app.
27const char kWebstoreUrlFormat[] =
28    "https://chrome.google.com/webstore/detail/%s";
29
30// Error given when the extension is not an app.
31const char kInstallChromeAppErrorNotAnApp[] =
32    "--install-chrome-app can only be used to install apps.";
33
34// Returns the webstore URL for an app.
35GURL GetAppInstallUrl(const std::string& app_id) {
36  return GURL(base::StringPrintf(kWebstoreUrlFormat, app_id.c_str()));
37}
38
39// Checks the manifest and completes the installation with NOT_PERMITTED if the
40// extension is not an app.
41class WebstoreInstallWithPromptAppsOnly
42    : public extensions::WebstoreInstallWithPrompt {
43 public:
44  WebstoreInstallWithPromptAppsOnly(const std::string& app_id,
45                                    Profile* profile,
46                                    gfx::NativeWindow parent_window)
47      : WebstoreInstallWithPrompt(
48            app_id,
49            profile,
50            parent_window,
51            extensions::WebstoreStandaloneInstaller::Callback()) {}
52
53 private:
54  virtual ~WebstoreInstallWithPromptAppsOnly() {}
55
56  // extensions::WebstoreStandaloneInstaller overrides:
57  virtual void OnManifestParsed() OVERRIDE;
58
59  DISALLOW_COPY_AND_ASSIGN(WebstoreInstallWithPromptAppsOnly);
60};
61
62void WebstoreInstallWithPromptAppsOnly::OnManifestParsed() {
63  if (!manifest()->HasKey(extensions::manifest_keys::kApp)) {
64    CompleteInstall(extensions::webstore_install::NOT_PERMITTED,
65                    kInstallChromeAppErrorNotAnApp);
66    return;
67  }
68
69  ProceedWithInstallPrompt();
70}
71
72}  // namespace
73
74namespace install_chrome_app {
75
76void InstallChromeApp(const std::string& app_id) {
77  if (!crx_file::id_util::IdIsValid(app_id))
78    return;
79
80  // At the moment InstallChromeApp() is called immediately after handling
81  // startup URLs, so a browser is guaranteed to be created. If that changes we
82  // may need to start a browser or browser session here.
83  Browser* browser =
84      BrowserList::GetInstance(chrome::HOST_DESKTOP_TYPE_NATIVE)->get(0);
85  DCHECK(browser);
86
87  content::OpenURLParams params(GetAppInstallUrl(app_id),
88                                content::Referrer(),
89                                NEW_FOREGROUND_TAB,
90                                ui::PAGE_TRANSITION_AUTO_TOPLEVEL,
91                                false);
92  browser->OpenURL(params);
93
94  ExtensionRegistry* registry = ExtensionRegistry::Get(browser->profile());
95  // Skip if this app is already installed or blacklisted. For disabled or
96  // or terminated apps, going through the installation flow should re-enable
97  // them.
98  const extensions::Extension* installed_extension = registry->GetExtensionById(
99      app_id, ExtensionRegistry::ENABLED | ExtensionRegistry::BLACKLISTED);
100  // TODO(jackhou): For installed apps, maybe we should do something better,
101  // e.g. show the app list (and re-add it to the taskbar).
102  if (installed_extension)
103    return;
104
105  WebstoreInstallWithPromptAppsOnly* installer =
106      new WebstoreInstallWithPromptAppsOnly(
107          app_id, browser->profile(), browser->window()->GetNativeWindow());
108  installer->BeginInstall();
109}
110
111}  // namespace install_chrome_app
112