• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2013 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/ephemeral_app_launcher.h"
6 
7 #include "chrome/browser/chrome_notification_types.h"
8 #include "chrome/browser/extensions/extension_install_prompt.h"
9 #include "chrome/browser/extensions/extension_service.h"
10 #include "chrome/browser/extensions/extension_system.h"
11 #include "chrome/browser/profiles/profile.h"
12 #include "chrome/browser/ui/extensions/application_launch.h"
13 #include "content/public/browser/notification_details.h"
14 #include "content/public/browser/notification_source.h"
15 #include "content/public/browser/web_contents.h"
16 #include "content/public/browser/web_contents_view.h"
17 
18 using content::WebContents;
19 using extensions::Extension;
20 using extensions::ExtensionSystem;
21 using extensions::WebstoreInstaller;
22 
23 namespace {
24 
25 const char kExtensionTypeError[] = "Ephemeral extensions are not permitted";
26 
ProfileForWebContents(content::WebContents * contents)27 Profile* ProfileForWebContents(content::WebContents* contents) {
28   if (!contents)
29     return NULL;
30 
31   return Profile::FromBrowserContext(contents->GetBrowserContext());
32 }
33 
NativeWindowForWebContents(content::WebContents * contents)34 gfx::NativeWindow NativeWindowForWebContents(content::WebContents* contents) {
35   if (!contents)
36     return NULL;
37 
38   return contents->GetView()->GetTopLevelNativeWindow();
39 }
40 
41 }  // namespace
42 
43 // static
44 scoped_refptr<EphemeralAppLauncher>
CreateForLauncher(const std::string & webstore_item_id,Profile * profile,gfx::NativeWindow parent_window,const Callback & callback)45 EphemeralAppLauncher::CreateForLauncher(
46     const std::string& webstore_item_id,
47     Profile* profile,
48     gfx::NativeWindow parent_window,
49     const Callback& callback) {
50   scoped_refptr<EphemeralAppLauncher> installer =
51       new EphemeralAppLauncher(webstore_item_id,
52                                profile,
53                                parent_window,
54                                callback);
55   installer->set_install_source(WebstoreInstaller::INSTALL_SOURCE_APP_LAUNCHER);
56   return installer;
57 }
58 
59 // static
60 scoped_refptr<EphemeralAppLauncher>
CreateForLink(const std::string & webstore_item_id,content::WebContents * web_contents)61 EphemeralAppLauncher::CreateForLink(
62     const std::string& webstore_item_id,
63     content::WebContents* web_contents) {
64   scoped_refptr<EphemeralAppLauncher> installer =
65       new EphemeralAppLauncher(webstore_item_id,
66                                web_contents,
67                                Callback());
68   installer->set_install_source(WebstoreInstaller::INSTALL_SOURCE_OTHER);
69   return installer;
70 }
71 
Start()72 void EphemeralAppLauncher::Start() {
73   ExtensionService* extension_service =
74       extensions::ExtensionSystem::Get(profile())->extension_service();
75   DCHECK(extension_service);
76 
77   const Extension* extension = extension_service->GetInstalledExtension(id());
78   if (extension) {
79     LaunchApp(extension);
80     return;
81   }
82 
83   BeginInstall();
84 }
85 
EphemeralAppLauncher(const std::string & webstore_item_id,Profile * profile,gfx::NativeWindow parent_window,const Callback & callback)86 EphemeralAppLauncher::EphemeralAppLauncher(
87     const std::string& webstore_item_id,
88     Profile* profile,
89     gfx::NativeWindow parent_window,
90     const Callback& callback)
91         : WebstoreStandaloneInstaller(
92               webstore_item_id,
93               profile,
94               callback),
95           parent_window_(parent_window),
96           dummy_web_contents_(
97               WebContents::Create(WebContents::CreateParams(profile))) {
98   Init();
99 }
100 
EphemeralAppLauncher(const std::string & webstore_item_id,content::WebContents * web_contents,const Callback & callback)101 EphemeralAppLauncher::EphemeralAppLauncher(
102     const std::string& webstore_item_id,
103     content::WebContents* web_contents,
104     const Callback& callback)
105         : WebstoreStandaloneInstaller(
106               webstore_item_id,
107               ProfileForWebContents(web_contents),
108               callback),
109           content::WebContentsObserver(web_contents),
110           parent_window_(NativeWindowForWebContents(web_contents)) {
111   Init();
112 }
113 
~EphemeralAppLauncher()114 EphemeralAppLauncher::~EphemeralAppLauncher() {}
115 
Init()116 void EphemeralAppLauncher::Init() {
117   registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_LOADED,
118                  content::Source<Profile>(profile()->GetOriginalProfile()));
119 }
120 
LaunchApp(const Extension * extension) const121 void EphemeralAppLauncher::LaunchApp(const Extension* extension) const {
122   DCHECK(extension);
123   if (!extension->is_app()) {
124     LOG(ERROR) << "Unable to launch extension " << extension->id()
125                << ". It is not an app.";
126     return;
127   }
128 
129   AppLaunchParams params(profile(), extension, NEW_FOREGROUND_TAB);
130   params.desktop_type =
131       chrome::GetHostDesktopTypeForNativeWindow(parent_window_);
132   OpenApplication(params);
133 }
134 
CheckRequestorAlive() const135 bool EphemeralAppLauncher::CheckRequestorAlive() const {
136   return dummy_web_contents_.get() != NULL || web_contents() != NULL;
137 }
138 
GetRequestorURL() const139 const GURL& EphemeralAppLauncher::GetRequestorURL() const {
140   return GURL::EmptyGURL();
141 }
142 
ShouldShowPostInstallUI() const143 bool EphemeralAppLauncher::ShouldShowPostInstallUI() const {
144   return false;
145 }
146 
ShouldShowAppInstalledBubble() const147 bool EphemeralAppLauncher::ShouldShowAppInstalledBubble() const {
148   return false;
149 }
150 
GetWebContents() const151 WebContents* EphemeralAppLauncher::GetWebContents() const {
152   return web_contents() ? web_contents() : dummy_web_contents_.get();
153 }
154 
155 scoped_ptr<ExtensionInstallPrompt::Prompt>
CreateInstallPrompt() const156 EphemeralAppLauncher::CreateInstallPrompt() const {
157   return make_scoped_ptr(new ExtensionInstallPrompt::Prompt(
158       ExtensionInstallPrompt::LAUNCH_PROMPT));
159 }
160 
CheckInlineInstallPermitted(const base::DictionaryValue & webstore_data,std::string * error) const161 bool EphemeralAppLauncher::CheckInlineInstallPermitted(
162     const base::DictionaryValue& webstore_data,
163     std::string* error) const {
164   *error = "";
165   return true;
166 }
167 
CheckRequestorPermitted(const base::DictionaryValue & webstore_data,std::string * error) const168 bool EphemeralAppLauncher::CheckRequestorPermitted(
169     const base::DictionaryValue& webstore_data,
170     std::string* error) const {
171   *error = "";
172   return true;
173 }
174 
CheckInstallValid(const base::DictionaryValue & manifest,std::string * error)175 bool EphemeralAppLauncher::CheckInstallValid(
176     const base::DictionaryValue& manifest,
177     std::string* error) {
178   extensions::Manifest extension_manifest(
179       extensions::Manifest::INTERNAL,
180       scoped_ptr<DictionaryValue>(manifest.DeepCopy()));
181   if (!extension_manifest.is_app()) {
182     *error = kExtensionTypeError;
183     return false;
184   }
185 
186   return true;
187 }
188 
189 scoped_ptr<ExtensionInstallPrompt>
CreateInstallUI()190 EphemeralAppLauncher::CreateInstallUI() {
191   if (web_contents())
192     return make_scoped_ptr(new ExtensionInstallPrompt(web_contents()));
193 
194   return make_scoped_ptr(
195       new ExtensionInstallPrompt(profile(), parent_window_, NULL));
196 }
197 
198 scoped_ptr<WebstoreInstaller::Approval>
CreateApproval() const199 EphemeralAppLauncher::CreateApproval() const {
200   scoped_ptr<WebstoreInstaller::Approval> approval =
201       WebstoreStandaloneInstaller::CreateApproval();
202   approval->is_ephemeral = true;
203   return approval.Pass();
204 }
205 
CompleteInstall(const std::string & error)206 void EphemeralAppLauncher::CompleteInstall(const std::string& error) {
207   if (!error.empty())
208     WebstoreStandaloneInstaller::CompleteInstall(error);
209 
210   // If the installation succeeds, we reach this point as a result of
211   // chrome::NOTIFICATION_EXTENSION_INSTALLED, but this is broadcasted before
212   // ExtensionService has added the extension to its list of installed
213   // extensions and is too early to launch the app. Instead, we will launch at
214   // chrome::NOTIFICATION_EXTENSION_LOADED.
215   // TODO(tmdiep): Refactor extensions/WebstoreInstaller or
216   // WebstoreStandaloneInstaller to support this cleanly.
217 }
218 
WebContentsDestroyed(content::WebContents * web_contents)219 void EphemeralAppLauncher::WebContentsDestroyed(
220     content::WebContents* web_contents) {
221   AbortInstall();
222 }
223 
Observe(int type,const content::NotificationSource & source,const content::NotificationDetails & details)224 void EphemeralAppLauncher::Observe(
225     int type,
226     const content::NotificationSource& source,
227     const content::NotificationDetails& details) {
228   switch (type) {
229     case chrome::NOTIFICATION_EXTENSION_LOADED: {
230       const extensions::Extension* extension =
231           content::Details<const extensions::Extension>(details).ptr();
232       DCHECK(extension);
233       if (extension->id() == id()) {
234         LaunchApp(extension);
235         WebstoreStandaloneInstaller::CompleteInstall(std::string());
236       }
237       break;
238     }
239 
240     default:
241       NOTREACHED();
242   }
243 }
244