Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / chrome / browser / extensions / api / webstore_private / webstore_private_api.cc
blob8f28c8cdbfc331a6a639c90ef71a5ec1cfd26fb8
1 // Copyright (c) 2012 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.
5 #include "chrome/browser/extensions/api/webstore_private/webstore_private_api.h"
7 #include "base/bind.h"
8 #include "base/lazy_instance.h"
9 #include "base/memory/scoped_vector.h"
10 #include "base/metrics/histogram.h"
11 #include "base/prefs/pref_service.h"
12 #include "base/strings/stringprintf.h"
13 #include "base/thread_task_runner_handle.h"
14 #include "base/values.h"
15 #include "base/version.h"
16 #include "chrome/browser/apps/ephemeral_app_launcher.h"
17 #include "chrome/browser/bitmap_fetcher/bitmap_fetcher.h"
18 #include "chrome/browser/extensions/crx_installer.h"
19 #include "chrome/browser/extensions/extension_install_ui_util.h"
20 #include "chrome/browser/extensions/extension_service.h"
21 #include "chrome/browser/extensions/install_tracker.h"
22 #include "chrome/browser/gpu/gpu_feature_checker.h"
23 #include "chrome/browser/profiles/profile.h"
24 #include "chrome/browser/signin/signin_manager_factory.h"
25 #include "chrome/browser/ui/app_list/app_list_service.h"
26 #include "chrome/browser/ui/app_list/app_list_util.h"
27 #include "chrome/common/extensions/extension_constants.h"
28 #include "chrome/common/pref_names.h"
29 #include "components/crx_file/id_util.h"
30 #include "components/signin/core/browser/signin_manager.h"
31 #include "content/public/browser/web_contents.h"
32 #include "extensions/browser/extension_registry.h"
33 #include "extensions/browser/extension_system.h"
34 #include "extensions/browser/extension_util.h"
35 #include "extensions/common/extension.h"
36 #include "net/base/load_flags.h"
37 #include "net/url_request/url_request.h"
38 #include "url/gurl.h"
40 namespace extensions {
42 namespace BeginInstallWithManifest3 =
43 api::webstore_private::BeginInstallWithManifest3;
44 namespace CompleteInstall = api::webstore_private::CompleteInstall;
45 namespace GetBrowserLogin = api::webstore_private::GetBrowserLogin;
46 namespace GetEphemeralAppsEnabled =
47 api::webstore_private::GetEphemeralAppsEnabled;
48 namespace GetIsLauncherEnabled = api::webstore_private::GetIsLauncherEnabled;
49 namespace GetStoreLogin = api::webstore_private::GetStoreLogin;
50 namespace GetWebGLStatus = api::webstore_private::GetWebGLStatus;
51 namespace InstallBundle = api::webstore_private::InstallBundle;
52 namespace IsInIncognitoMode = api::webstore_private::IsInIncognitoMode;
53 namespace LaunchEphemeralApp = api::webstore_private::LaunchEphemeralApp;
54 namespace SetStoreLogin = api::webstore_private::SetStoreLogin;
56 namespace {
58 // Holds the Approvals between the time we prompt and start the installs.
59 class PendingApprovals {
60 public:
61 PendingApprovals();
62 ~PendingApprovals();
64 void PushApproval(scoped_ptr<WebstoreInstaller::Approval> approval);
65 scoped_ptr<WebstoreInstaller::Approval> PopApproval(
66 Profile* profile, const std::string& id);
67 private:
68 typedef ScopedVector<WebstoreInstaller::Approval> ApprovalList;
70 ApprovalList approvals_;
72 DISALLOW_COPY_AND_ASSIGN(PendingApprovals);
75 PendingApprovals::PendingApprovals() {}
76 PendingApprovals::~PendingApprovals() {}
78 void PendingApprovals::PushApproval(
79 scoped_ptr<WebstoreInstaller::Approval> approval) {
80 approvals_.push_back(approval.release());
83 scoped_ptr<WebstoreInstaller::Approval> PendingApprovals::PopApproval(
84 Profile* profile, const std::string& id) {
85 for (size_t i = 0; i < approvals_.size(); ++i) {
86 WebstoreInstaller::Approval* approval = approvals_[i];
87 if (approval->extension_id == id &&
88 profile->IsSameProfile(approval->profile)) {
89 approvals_.weak_erase(approvals_.begin() + i);
90 return scoped_ptr<WebstoreInstaller::Approval>(approval);
93 return scoped_ptr<WebstoreInstaller::Approval>();
96 chrome::HostDesktopType GetHostDesktopTypeForWebContents(
97 content::WebContents* contents) {
98 return chrome::GetHostDesktopTypeForNativeWindow(
99 contents->GetTopLevelNativeWindow());
102 api::webstore_private::Result WebstoreInstallResultToApiResult(
103 webstore_install::Result result) {
104 switch (result) {
105 case webstore_install::SUCCESS:
106 return api::webstore_private::RESULT_SUCCESS;
107 case webstore_install::OTHER_ERROR:
108 return api::webstore_private::RESULT_UNKNOWN_ERROR;
109 case webstore_install::INVALID_ID:
110 return api::webstore_private::RESULT_INVALID_ID;
111 case webstore_install::NOT_PERMITTED:
112 case webstore_install::WEBSTORE_REQUEST_ERROR:
113 case webstore_install::INVALID_WEBSTORE_RESPONSE:
114 return api::webstore_private::RESULT_INSTALL_ERROR;
115 case webstore_install::INVALID_MANIFEST:
116 return api::webstore_private::RESULT_MANIFEST_ERROR;
117 case webstore_install::ICON_ERROR:
118 return api::webstore_private::RESULT_ICON_ERROR;
119 case webstore_install::ABORTED:
120 case webstore_install::USER_CANCELLED:
121 return api::webstore_private::RESULT_USER_CANCELLED;
122 case webstore_install::BLACKLISTED:
123 return api::webstore_private::RESULT_BLACKLISTED;
124 case webstore_install::MISSING_DEPENDENCIES:
125 case webstore_install::REQUIREMENT_VIOLATIONS:
126 return api::webstore_private::RESULT_MISSING_DEPENDENCIES;
127 case webstore_install::BLOCKED_BY_POLICY:
128 return api::webstore_private::RESULT_BLOCKED_BY_POLICY;
129 case webstore_install::LAUNCH_FEATURE_DISABLED:
130 return api::webstore_private::RESULT_FEATURE_DISABLED;
131 case webstore_install::LAUNCH_UNSUPPORTED_EXTENSION_TYPE:
132 return api::webstore_private::RESULT_UNSUPPORTED_EXTENSION_TYPE;
133 case webstore_install::INSTALL_IN_PROGRESS:
134 return api::webstore_private::RESULT_INSTALL_IN_PROGRESS;
135 case webstore_install::LAUNCH_IN_PROGRESS:
136 return api::webstore_private::RESULT_LAUNCH_IN_PROGRESS;
138 NOTREACHED();
139 return api::webstore_private::RESULT_NONE;
142 api::webstore_private::Result WebstoreInstallHelperResultToApiResult(
143 WebstoreInstallHelper::Delegate::InstallHelperResultCode result) {
144 switch (result) {
145 case WebstoreInstallHelper::Delegate::UNKNOWN_ERROR:
146 return api::webstore_private::RESULT_UNKNOWN_ERROR;
147 case WebstoreInstallHelper::Delegate::ICON_ERROR:
148 return api::webstore_private::RESULT_ICON_ERROR;
149 case WebstoreInstallHelper::Delegate::MANIFEST_ERROR:
150 return api::webstore_private::RESULT_MANIFEST_ERROR;
152 NOTREACHED();
153 return api::webstore_private::RESULT_NONE;
156 static base::LazyInstance<PendingApprovals> g_pending_approvals =
157 LAZY_INSTANCE_INITIALIZER;
159 // A preference set by the web store to indicate login information for
160 // purchased apps.
161 const char kWebstoreLogin[] = "extensions.webstore_login";
163 // Error messages that can be returned by the API.
164 const char kAlreadyInstalledError[] = "This item is already installed";
165 const char kCannotSpecifyIconDataAndUrlError[] =
166 "You cannot specify both icon data and an icon url";
167 const char kInvalidBundleError[] = "Invalid bundle";
168 const char kInvalidIconUrlError[] = "Invalid icon url";
169 const char kInvalidIdError[] = "Invalid id";
170 const char kInvalidManifestError[] = "Invalid manifest";
171 const char kNoPreviousBeginInstallWithManifestError[] =
172 "* does not match a previous call to beginInstallWithManifest3";
173 const char kBlockedByPolicyError[] = "Blocked by policy";
174 const char kUserCancelledError[] = "User cancelled install";
175 const char kIncognitoError[] =
176 "Apps cannot be installed in guest/incognito mode";
178 WebstoreInstaller::Delegate* test_webstore_installer_delegate = nullptr;
180 // We allow the web store to set a string containing login information when a
181 // purchase is made, so that when a user logs into sync with a different
182 // account we can recognize the situation. The Get function returns the login if
183 // there was previously stored data, or an empty string otherwise. The Set will
184 // overwrite any previous login.
185 std::string GetWebstoreLogin(Profile* profile) {
186 if (profile->GetPrefs()->HasPrefPath(kWebstoreLogin))
187 return profile->GetPrefs()->GetString(kWebstoreLogin);
188 return std::string();
191 void SetWebstoreLogin(Profile* profile, const std::string& login) {
192 profile->GetPrefs()->SetString(kWebstoreLogin, login);
195 void RecordWebstoreExtensionInstallResult(bool success) {
196 UMA_HISTOGRAM_BOOLEAN("Webstore.ExtensionInstallResult", success);
199 } // namespace
201 // static
202 void WebstorePrivateApi::SetWebstoreInstallerDelegateForTesting(
203 WebstoreInstaller::Delegate* delegate) {
204 test_webstore_installer_delegate = delegate;
207 // static
208 scoped_ptr<WebstoreInstaller::Approval>
209 WebstorePrivateApi::PopApprovalForTesting(
210 Profile* profile, const std::string& extension_id) {
211 return g_pending_approvals.Get().PopApproval(profile, extension_id);
214 WebstorePrivateBeginInstallWithManifest3Function::
215 WebstorePrivateBeginInstallWithManifest3Function() : chrome_details_(this) {
218 WebstorePrivateBeginInstallWithManifest3Function::
219 ~WebstorePrivateBeginInstallWithManifest3Function() {
222 ExtensionFunction::ResponseAction
223 WebstorePrivateBeginInstallWithManifest3Function::Run() {
224 params_ = Params::Create(*args_);
225 EXTENSION_FUNCTION_VALIDATE(params_);
227 if (!crx_file::id_util::IdIsValid(details().id)) {
228 return RespondNow(BuildResponse(api::webstore_private::RESULT_INVALID_ID,
229 kInvalidIdError));
232 if (details().icon_data && details().icon_url) {
233 return RespondNow(BuildResponse(api::webstore_private::RESULT_ICON_ERROR,
234 kCannotSpecifyIconDataAndUrlError));
237 GURL icon_url;
238 if (details().icon_url) {
239 icon_url = source_url().Resolve(*details().icon_url);
240 if (!icon_url.is_valid()) {
241 return RespondNow(BuildResponse(
242 api::webstore_private::RESULT_INVALID_ICON_URL,
243 kInvalidIconUrlError));
247 InstallTracker* tracker = InstallTracker::Get(browser_context());
248 DCHECK(tracker);
249 if (util::IsExtensionInstalledPermanently(details().id, browser_context()) ||
250 tracker->GetActiveInstall(details().id)) {
251 return RespondNow(BuildResponse(
252 api::webstore_private::RESULT_ALREADY_INSTALLED,
253 kAlreadyInstalledError));
255 ActiveInstallData install_data(details().id);
256 scoped_active_install_.reset(new ScopedActiveInstall(tracker, install_data));
258 net::URLRequestContextGetter* context_getter = nullptr;
259 if (!icon_url.is_empty())
260 context_getter = browser_context()->GetRequestContext();
262 scoped_refptr<WebstoreInstallHelper> helper = new WebstoreInstallHelper(
263 this, details().id, details().manifest, icon_url, context_getter);
265 // The helper will call us back via OnWebstoreParseSuccess or
266 // OnWebstoreParseFailure.
267 helper->Start();
269 // Matched with a Release in OnWebstoreParseSuccess/OnWebstoreParseFailure.
270 AddRef();
272 // The response is sent asynchronously in OnWebstoreParseSuccess/
273 // OnWebstoreParseFailure.
274 return RespondLater();
277 void WebstorePrivateBeginInstallWithManifest3Function::OnWebstoreParseSuccess(
278 const std::string& id,
279 const SkBitmap& icon,
280 base::DictionaryValue* parsed_manifest) {
281 CHECK_EQ(details().id, id);
282 CHECK(parsed_manifest);
283 parsed_manifest_.reset(parsed_manifest);
284 icon_ = icon;
286 std::string localized_name =
287 details().localized_name ? *details().localized_name : std::string();
289 std::string error;
290 dummy_extension_ = ExtensionInstallPrompt::GetLocalizedExtensionForDisplay(
291 parsed_manifest_.get(),
292 Extension::FROM_WEBSTORE,
294 localized_name,
295 std::string(),
296 &error);
298 if (!dummy_extension_.get()) {
299 OnWebstoreParseFailure(details().id,
300 WebstoreInstallHelper::Delegate::MANIFEST_ERROR,
301 kInvalidManifestError);
302 return;
305 // Check the management policy before the installation process begins
306 bool allow = ExtensionSystem::Get(chrome_details_.GetProfile())->
307 management_policy()->UserMayLoad(extension_.get(),
308 NULL);
309 if (!allow) {
310 Respond(BuildResponse(api::webstore_private::RESULT_BLOCKED_BY_POLICY,
311 kBlockedByPolicyError));
312 // Matches the AddRef in Run().
313 Release();
314 return;
317 content::WebContents* web_contents = GetAssociatedWebContents();
318 if (!web_contents) {
319 // The browser window has gone away.
320 Respond(BuildResponse(api::webstore_private::RESULT_USER_CANCELLED,
321 kUserCancelledError));
322 // Matches the AddRef in Run().
323 Release();
324 return;
326 install_prompt_.reset(new ExtensionInstallPrompt(web_contents));
327 install_prompt_->ConfirmWebstoreInstall(
328 this, dummy_extension_.get(), &icon_,
329 ExtensionInstallPrompt::GetDefaultShowDialogCallback());
330 // Control flow finishes up in InstallUIProceed or InstallUIAbort.
333 void WebstorePrivateBeginInstallWithManifest3Function::OnWebstoreParseFailure(
334 const std::string& id,
335 WebstoreInstallHelper::Delegate::InstallHelperResultCode result,
336 const std::string& error_message) {
337 CHECK_EQ(details().id, id);
339 Respond(BuildResponse(WebstoreInstallHelperResultToApiResult(result),
340 error_message));
342 // Matches the AddRef in Run().
343 Release();
346 void WebstorePrivateBeginInstallWithManifest3Function::InstallUIProceed() {
347 // This gets cleared in CrxInstaller::ConfirmInstall(). TODO(asargent) - in
348 // the future we may also want to add time-based expiration, where a whitelist
349 // entry is only valid for some number of minutes.
350 scoped_ptr<WebstoreInstaller::Approval> approval(
351 WebstoreInstaller::Approval::CreateWithNoInstallPrompt(
352 chrome_details_.GetProfile(),
353 details().id,
354 parsed_manifest_.Pass(),
355 false));
356 approval->use_app_installed_bubble = details().app_install_bubble;
357 approval->enable_launcher = details().enable_launcher;
358 // If we are enabling the launcher, we should not show the app list in order
359 // to train the user to open it themselves at least once.
360 approval->skip_post_install_ui = details().enable_launcher;
361 approval->dummy_extension = dummy_extension_.get();
362 approval->installing_icon = gfx::ImageSkia::CreateFrom1xBitmap(icon_);
363 if (details().authuser)
364 approval->authuser = *details().authuser;
365 g_pending_approvals.Get().PushApproval(approval.Pass());
367 DCHECK(scoped_active_install_.get());
368 scoped_active_install_->CancelDeregister();
370 // The Permissions_Install histogram is recorded from the ExtensionService
371 // for all extension installs, so we only need to record the web store
372 // specific histogram here.
373 ExtensionService::RecordPermissionMessagesHistogram(
374 dummy_extension_.get(), "WebStoreInstall");
376 Respond(BuildResponse(api::webstore_private::RESULT_SUCCESS, std::string()));
378 // Matches the AddRef in Run().
379 Release();
382 void WebstorePrivateBeginInstallWithManifest3Function::InstallUIAbort(
383 bool user_initiated) {
384 // The web store install histograms are a subset of the install histograms.
385 // We need to record both histograms here since CrxInstaller::InstallUIAbort
386 // is never called for web store install cancellations.
387 std::string histogram_name = user_initiated ? "WebStoreInstallCancel"
388 : "WebStoreInstallAbort";
389 ExtensionService::RecordPermissionMessagesHistogram(dummy_extension_.get(),
390 histogram_name.c_str());
392 histogram_name = user_initiated ? "InstallCancel" : "InstallAbort";
393 ExtensionService::RecordPermissionMessagesHistogram(dummy_extension_.get(),
394 histogram_name.c_str());
396 Respond(BuildResponse(api::webstore_private::RESULT_USER_CANCELLED,
397 kUserCancelledError));
399 // Matches the AddRef in Run().
400 Release();
403 ExtensionFunction::ResponseValue
404 WebstorePrivateBeginInstallWithManifest3Function::BuildResponse(
405 api::webstore_private::Result result, const std::string& error) {
406 if (result != api::webstore_private::RESULT_SUCCESS)
407 return ErrorWithArguments(CreateResults(result), error);
409 // The web store expects an empty string on success, so don't use
410 // RESULT_SUCCESS here.
411 return ArgumentList(
412 CreateResults(api::webstore_private::RESULT_EMPTY_STRING));
415 scoped_ptr<base::ListValue>
416 WebstorePrivateBeginInstallWithManifest3Function::CreateResults(
417 api::webstore_private::Result result) const {
418 return BeginInstallWithManifest3::Results::Create(result);
421 WebstorePrivateCompleteInstallFunction::
422 WebstorePrivateCompleteInstallFunction() : chrome_details_(this) {}
424 WebstorePrivateCompleteInstallFunction::
425 ~WebstorePrivateCompleteInstallFunction() {}
427 ExtensionFunction::ResponseAction
428 WebstorePrivateCompleteInstallFunction::Run() {
429 scoped_ptr<CompleteInstall::Params> params(
430 CompleteInstall::Params::Create(*args_));
431 EXTENSION_FUNCTION_VALIDATE(params);
432 if (chrome_details_.GetProfile()->IsGuestSession() ||
433 chrome_details_.GetProfile()->IsOffTheRecord()) {
434 return RespondNow(Error(kIncognitoError));
437 if (!crx_file::id_util::IdIsValid(params->expected_id))
438 return RespondNow(Error(kInvalidIdError));
440 approval_ =
441 g_pending_approvals.Get().PopApproval(chrome_details_.GetProfile(),
442 params->expected_id).Pass();
443 if (!approval_) {
444 return RespondNow(Error(kNoPreviousBeginInstallWithManifestError,
445 params->expected_id));
448 scoped_active_install_.reset(new ScopedActiveInstall(
449 InstallTracker::Get(browser_context()), params->expected_id));
451 AppListService* app_list_service = AppListService::Get(
452 GetHostDesktopTypeForWebContents(GetAssociatedWebContents()));
454 if (approval_->enable_launcher) {
455 app_list_service->EnableAppList(chrome_details_.GetProfile(),
456 AppListService::ENABLE_FOR_APP_INSTALL);
459 if (IsAppLauncherEnabled() && approval_->manifest->is_app()) {
460 // Show the app list to show download is progressing. Don't show the app
461 // list on first app install so users can be trained to open it themselves.
462 app_list_service->ShowForAppInstall(
463 chrome_details_.GetProfile(),
464 params->expected_id,
465 approval_->enable_launcher);
468 // If the target extension has already been installed ephemerally and is
469 // up to date, it can be promoted to a regular installed extension and
470 // downloading from the Web Store is not necessary.
471 const Extension* extension = ExtensionRegistry::Get(browser_context())->
472 GetExtensionById(params->expected_id, ExtensionRegistry::EVERYTHING);
473 if (extension && approval_->dummy_extension.get() &&
474 util::IsEphemeralApp(extension->id(), browser_context()) &&
475 extension->version()->CompareTo(*approval_->dummy_extension->version()) >=
476 0) {
477 install_ui::ShowPostInstallUIForApproval(
478 browser_context(), *approval_, extension);
480 ExtensionService* extension_service =
481 ExtensionSystem::Get(browser_context())->extension_service();
482 extension_service->PromoteEphemeralApp(extension, false);
483 OnInstallSuccess(extension->id());
484 VLOG(1) << "Install success, sending response";
485 return RespondNow(NoArguments());
488 // Balanced in OnExtensionInstallSuccess() or OnExtensionInstallFailure().
489 AddRef();
491 // The extension will install through the normal extension install flow, but
492 // the whitelist entry will bypass the normal permissions install dialog.
493 scoped_refptr<WebstoreInstaller> installer = new WebstoreInstaller(
494 chrome_details_.GetProfile(),
495 this,
496 chrome_details_.GetAssociatedWebContents(),
497 params->expected_id,
498 approval_.Pass(),
499 WebstoreInstaller::INSTALL_SOURCE_OTHER);
500 installer->Start();
502 return RespondLater();
505 void WebstorePrivateCompleteInstallFunction::OnExtensionInstallSuccess(
506 const std::string& id) {
507 OnInstallSuccess(id);
508 VLOG(1) << "Install success, sending response";
509 Respond(NoArguments());
511 RecordWebstoreExtensionInstallResult(true);
513 // Matches the AddRef in Run().
514 Release();
517 void WebstorePrivateCompleteInstallFunction::OnExtensionInstallFailure(
518 const std::string& id,
519 const std::string& error,
520 WebstoreInstaller::FailureReason reason) {
521 if (test_webstore_installer_delegate) {
522 test_webstore_installer_delegate->OnExtensionInstallFailure(
523 id, error, reason);
526 VLOG(1) << "Install failed, sending response";
527 Respond(Error(error));
529 RecordWebstoreExtensionInstallResult(false);
531 // Matches the AddRef in Run().
532 Release();
535 void WebstorePrivateCompleteInstallFunction::OnInstallSuccess(
536 const std::string& id) {
537 if (test_webstore_installer_delegate)
538 test_webstore_installer_delegate->OnExtensionInstallSuccess(id);
541 WebstorePrivateInstallBundleFunction::WebstorePrivateInstallBundleFunction()
542 : chrome_details_(this) {
545 WebstorePrivateInstallBundleFunction::~WebstorePrivateInstallBundleFunction() {
548 ExtensionFunction::ResponseAction WebstorePrivateInstallBundleFunction::Run() {
549 params_ = Params::Create(*args_);
550 EXTENSION_FUNCTION_VALIDATE(params_);
552 if (params_->contents.empty())
553 return RespondNow(Error(kInvalidBundleError));
555 if (details().icon_url) {
556 GURL icon_url = source_url().Resolve(*details().icon_url);
557 if (!icon_url.is_valid())
558 return RespondNow(Error(kInvalidIconUrlError));
560 // The bitmap fetcher will call us back via OnFetchComplete.
561 icon_fetcher_.reset(new chrome::BitmapFetcher(icon_url, this));
562 icon_fetcher_->Init(
563 browser_context()->GetRequestContext(), std::string(),
564 net::URLRequest::CLEAR_REFERRER_ON_TRANSITION_FROM_SECURE_TO_INSECURE,
565 net::LOAD_DO_NOT_SAVE_COOKIES | net::LOAD_DO_NOT_SEND_COOKIES);
566 icon_fetcher_->Start();
567 } else {
568 base::ThreadTaskRunnerHandle::Get()->PostTask(
569 FROM_HERE,
570 base::Bind(&WebstorePrivateInstallBundleFunction::OnFetchComplete,
571 this, GURL(), nullptr));
574 AddRef(); // Balanced in OnFetchComplete.
576 // The response is sent asynchronously in OnFetchComplete, OnInstallApproval,
577 // or OnInstallComplete.
578 return RespondLater();
581 void WebstorePrivateInstallBundleFunction::OnFetchComplete(
582 const GURL& url, const SkBitmap* bitmap) {
583 BundleInstaller::ItemList items;
584 for (const auto& entry : params_->contents) {
585 // Skip already-installed items.
586 if (util::IsExtensionInstalledPermanently(entry->id, browser_context()) ||
587 InstallTracker::Get(browser_context())->GetActiveInstall(entry->id)) {
588 continue;
590 BundleInstaller::Item item;
591 item.id = entry->id;
592 item.manifest = entry->manifest;
593 item.localized_name = entry->localized_name;
594 if (entry->icon_url)
595 item.icon_url = source_url().Resolve(*entry->icon_url);
596 items.push_back(item);
598 if (items.empty()) {
599 Respond(Error(kAlreadyInstalledError));
600 Release(); // Matches the AddRef in Run.
601 return;
604 std::string authuser =
605 details().authuser ? *details().authuser : std::string();
606 bundle_.reset(new BundleInstaller(chrome_details_.GetCurrentBrowser(),
607 details().localized_name,
608 bitmap ? *bitmap : SkBitmap(), authuser,
609 std::string(), items));
611 bundle_->PromptForApproval(base::Bind(
612 &WebstorePrivateInstallBundleFunction::OnInstallApproval, this));
614 Release(); // Matches the AddRef in Run.
617 void WebstorePrivateInstallBundleFunction::OnInstallApproval(
618 BundleInstaller::ApprovalState state) {
619 if (state != BundleInstaller::APPROVED) {
620 Respond(Error(state == BundleInstaller::USER_CANCELED
621 ? kUserCancelledError
622 : kInvalidBundleError));
623 return;
626 // The bundle installer will call us back via OnInstallComplete.
627 bundle_->CompleteInstall(
628 GetSenderWebContents(),
629 base::Bind(&WebstorePrivateInstallBundleFunction::OnInstallComplete,
630 this));
633 void WebstorePrivateInstallBundleFunction::OnInstallComplete() {
634 Respond(NoArguments());
637 WebstorePrivateEnableAppLauncherFunction::
638 WebstorePrivateEnableAppLauncherFunction() : chrome_details_(this) {}
640 WebstorePrivateEnableAppLauncherFunction::
641 ~WebstorePrivateEnableAppLauncherFunction() {}
643 ExtensionFunction::ResponseAction
644 WebstorePrivateEnableAppLauncherFunction::Run() {
645 AppListService* app_list_service = AppListService::Get(
646 GetHostDesktopTypeForWebContents(
647 chrome_details_.GetAssociatedWebContents()));
648 app_list_service->EnableAppList(chrome_details_.GetProfile(),
649 AppListService::ENABLE_VIA_WEBSTORE_LINK);
650 return RespondNow(NoArguments());
653 WebstorePrivateGetBrowserLoginFunction::
654 WebstorePrivateGetBrowserLoginFunction() : chrome_details_(this) {}
656 WebstorePrivateGetBrowserLoginFunction::
657 ~WebstorePrivateGetBrowserLoginFunction() {}
659 ExtensionFunction::ResponseAction
660 WebstorePrivateGetBrowserLoginFunction::Run() {
661 GetBrowserLogin::Results::Info info;
662 info.login = SigninManagerFactory::GetForProfile(
663 chrome_details_.GetProfile()->GetOriginalProfile())
664 ->GetAuthenticatedAccountInfo()
665 .email;
666 return RespondNow(ArgumentList(GetBrowserLogin::Results::Create(info)));
669 WebstorePrivateGetStoreLoginFunction::
670 WebstorePrivateGetStoreLoginFunction() : chrome_details_(this) {}
672 WebstorePrivateGetStoreLoginFunction::
673 ~WebstorePrivateGetStoreLoginFunction() {}
675 ExtensionFunction::ResponseAction WebstorePrivateGetStoreLoginFunction::Run() {
676 return RespondNow(ArgumentList(GetStoreLogin::Results::Create(
677 GetWebstoreLogin(chrome_details_.GetProfile()))));
680 WebstorePrivateSetStoreLoginFunction::
681 WebstorePrivateSetStoreLoginFunction() : chrome_details_(this) {}
683 WebstorePrivateSetStoreLoginFunction::
684 ~WebstorePrivateSetStoreLoginFunction() {}
686 ExtensionFunction::ResponseAction WebstorePrivateSetStoreLoginFunction::Run() {
687 scoped_ptr<SetStoreLogin::Params> params(
688 SetStoreLogin::Params::Create(*args_));
689 EXTENSION_FUNCTION_VALIDATE(params);
690 SetWebstoreLogin(chrome_details_.GetProfile(), params->login);
691 return RespondNow(NoArguments());
694 WebstorePrivateGetWebGLStatusFunction::WebstorePrivateGetWebGLStatusFunction()
695 : feature_checker_(new GPUFeatureChecker(
696 gpu::GPU_FEATURE_TYPE_WEBGL,
697 base::Bind(&WebstorePrivateGetWebGLStatusFunction::OnFeatureCheck,
698 base::Unretained(this)))) {
701 WebstorePrivateGetWebGLStatusFunction::
702 ~WebstorePrivateGetWebGLStatusFunction() {}
704 ExtensionFunction::ResponseAction WebstorePrivateGetWebGLStatusFunction::Run() {
705 feature_checker_->CheckGPUFeatureAvailability();
706 return RespondLater();
709 void WebstorePrivateGetWebGLStatusFunction::OnFeatureCheck(
710 bool feature_allowed) {
711 Respond(ArgumentList(
712 GetWebGLStatus::Results::Create(api::webstore_private::ParseWebGlStatus(
713 feature_allowed ? "webgl_allowed" : "webgl_blocked"))));
716 WebstorePrivateGetIsLauncherEnabledFunction::
717 WebstorePrivateGetIsLauncherEnabledFunction() {}
719 WebstorePrivateGetIsLauncherEnabledFunction::
720 ~WebstorePrivateGetIsLauncherEnabledFunction() {}
722 ExtensionFunction::ResponseAction
723 WebstorePrivateGetIsLauncherEnabledFunction::Run() {
724 return RespondNow(ArgumentList(
725 GetIsLauncherEnabled::Results::Create(IsAppLauncherEnabled())));
728 WebstorePrivateIsInIncognitoModeFunction::
729 WebstorePrivateIsInIncognitoModeFunction() : chrome_details_(this) {}
731 WebstorePrivateIsInIncognitoModeFunction::
732 ~WebstorePrivateIsInIncognitoModeFunction() {}
734 ExtensionFunction::ResponseAction
735 WebstorePrivateIsInIncognitoModeFunction::Run() {
736 Profile* profile = chrome_details_.GetProfile();
737 return RespondNow(ArgumentList(IsInIncognitoMode::Results::Create(
738 profile != profile->GetOriginalProfile())));
741 WebstorePrivateLaunchEphemeralAppFunction::
742 WebstorePrivateLaunchEphemeralAppFunction() : chrome_details_(this) {}
744 WebstorePrivateLaunchEphemeralAppFunction::
745 ~WebstorePrivateLaunchEphemeralAppFunction() {}
747 ExtensionFunction::ResponseAction
748 WebstorePrivateLaunchEphemeralAppFunction::Run() {
749 // Check whether the browser window still exists.
750 content::WebContents* web_contents =
751 chrome_details_.GetAssociatedWebContents();
752 if (!web_contents)
753 return RespondNow(Error("aborted"));
755 if (!user_gesture()) {
756 return RespondNow(BuildResponse(
757 api::webstore_private::RESULT_USER_GESTURE_REQUIRED,
758 "User gesture is required"));
761 scoped_ptr<LaunchEphemeralApp::Params> params(
762 LaunchEphemeralApp::Params::Create(*args_));
763 EXTENSION_FUNCTION_VALIDATE(params);
765 AddRef(); // Balanced in OnLaunchComplete()
767 scoped_refptr<EphemeralAppLauncher> launcher =
768 EphemeralAppLauncher::CreateForWebContents(
769 params->id,
770 web_contents,
771 base::Bind(
772 &WebstorePrivateLaunchEphemeralAppFunction::OnLaunchComplete,
773 base::Unretained(this)));
774 launcher->Start();
776 return RespondLater();
779 void WebstorePrivateLaunchEphemeralAppFunction::OnLaunchComplete(
780 webstore_install::Result result, const std::string& error) {
781 Respond(BuildResponse(WebstoreInstallResultToApiResult(result), error));
782 Release(); // Matches AddRef() in Run()
785 ExtensionFunction::ResponseValue
786 WebstorePrivateLaunchEphemeralAppFunction::BuildResponse(
787 api::webstore_private::Result result, const std::string& error) {
788 if (result != api::webstore_private::RESULT_SUCCESS) {
789 std::string error_message;
790 if (error.empty()) {
791 error_message = base::StringPrintf(
792 "[%s]", api::webstore_private::ToString(result).c_str());
793 } else {
794 error_message = base::StringPrintf(
795 "[%s]: %s",
796 api::webstore_private::ToString(result).c_str(),
797 error.c_str());
799 return ErrorWithArguments(LaunchEphemeralApp::Results::Create(result),
800 error_message);
802 return ArgumentList(LaunchEphemeralApp::Results::Create(result));
805 WebstorePrivateGetEphemeralAppsEnabledFunction::
806 WebstorePrivateGetEphemeralAppsEnabledFunction() {}
808 WebstorePrivateGetEphemeralAppsEnabledFunction::
809 ~WebstorePrivateGetEphemeralAppsEnabledFunction() {}
811 ExtensionFunction::ResponseAction
812 WebstorePrivateGetEphemeralAppsEnabledFunction::Run() {
813 return RespondNow(ArgumentList(GetEphemeralAppsEnabled::Results::Create(
814 EphemeralAppLauncher::IsFeatureEnabled())));
817 } // namespace extensions