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_helpers.h"
8 #include "base/lazy_instance.h"
9 #include "base/memory/scoped_vector.h"
10 #include "base/message_loop/message_loop_proxy.h"
11 #include "base/metrics/histogram.h"
12 #include "base/prefs/pref_service.h"
13 #include "base/strings/stringprintf.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"
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
;
55 namespace ShowPermissionPromptForDelegatedInstall
=
56 api::webstore_private::ShowPermissionPromptForDelegatedInstall
;
60 // Holds the Approvals between the time we prompt and start the installs.
61 class PendingApprovals
{
66 void PushApproval(scoped_ptr
<WebstoreInstaller::Approval
> approval
);
67 scoped_ptr
<WebstoreInstaller::Approval
> PopApproval(
68 Profile
* profile
, const std::string
& id
);
70 typedef ScopedVector
<WebstoreInstaller::Approval
> ApprovalList
;
72 ApprovalList approvals_
;
74 DISALLOW_COPY_AND_ASSIGN(PendingApprovals
);
77 PendingApprovals::PendingApprovals() {}
78 PendingApprovals::~PendingApprovals() {}
80 void PendingApprovals::PushApproval(
81 scoped_ptr
<WebstoreInstaller::Approval
> approval
) {
82 approvals_
.push_back(approval
.release());
85 scoped_ptr
<WebstoreInstaller::Approval
> PendingApprovals::PopApproval(
86 Profile
* profile
, const std::string
& id
) {
87 for (size_t i
= 0; i
< approvals_
.size(); ++i
) {
88 WebstoreInstaller::Approval
* approval
= approvals_
[i
];
89 if (approval
->extension_id
== id
&&
90 profile
->IsSameProfile(approval
->profile
)) {
91 approvals_
.weak_erase(approvals_
.begin() + i
);
92 return scoped_ptr
<WebstoreInstaller::Approval
>(approval
);
95 return scoped_ptr
<WebstoreInstaller::Approval
>();
98 chrome::HostDesktopType
GetHostDesktopTypeForWebContents(
99 content::WebContents
* contents
) {
100 return chrome::GetHostDesktopTypeForNativeWindow(
101 contents
->GetTopLevelNativeWindow());
104 api::webstore_private::Result
WebstoreInstallResultToApiResult(
105 webstore_install::Result result
) {
107 case webstore_install::SUCCESS
:
108 return api::webstore_private::RESULT_SUCCESS
;
109 case webstore_install::OTHER_ERROR
:
110 return api::webstore_private::RESULT_UNKNOWN_ERROR
;
111 case webstore_install::INVALID_ID
:
112 return api::webstore_private::RESULT_INVALID_ID
;
113 case webstore_install::NOT_PERMITTED
:
114 case webstore_install::WEBSTORE_REQUEST_ERROR
:
115 case webstore_install::INVALID_WEBSTORE_RESPONSE
:
116 return api::webstore_private::RESULT_INSTALL_ERROR
;
117 case webstore_install::INVALID_MANIFEST
:
118 return api::webstore_private::RESULT_MANIFEST_ERROR
;
119 case webstore_install::ICON_ERROR
:
120 return api::webstore_private::RESULT_ICON_ERROR
;
121 case webstore_install::ABORTED
:
122 case webstore_install::USER_CANCELLED
:
123 return api::webstore_private::RESULT_USER_CANCELLED
;
124 case webstore_install::BLACKLISTED
:
125 return api::webstore_private::RESULT_BLACKLISTED
;
126 case webstore_install::MISSING_DEPENDENCIES
:
127 case webstore_install::REQUIREMENT_VIOLATIONS
:
128 return api::webstore_private::RESULT_MISSING_DEPENDENCIES
;
129 case webstore_install::BLOCKED_BY_POLICY
:
130 return api::webstore_private::RESULT_BLOCKED_BY_POLICY
;
131 case webstore_install::LAUNCH_FEATURE_DISABLED
:
132 return api::webstore_private::RESULT_FEATURE_DISABLED
;
133 case webstore_install::LAUNCH_UNSUPPORTED_EXTENSION_TYPE
:
134 return api::webstore_private::RESULT_UNSUPPORTED_EXTENSION_TYPE
;
135 case webstore_install::INSTALL_IN_PROGRESS
:
136 return api::webstore_private::RESULT_INSTALL_IN_PROGRESS
;
137 case webstore_install::LAUNCH_IN_PROGRESS
:
138 return api::webstore_private::RESULT_LAUNCH_IN_PROGRESS
;
141 return api::webstore_private::RESULT_NONE
;
144 api::webstore_private::Result
WebstoreInstallHelperResultToApiResult(
145 WebstoreInstallHelper::Delegate::InstallHelperResultCode result
) {
147 case WebstoreInstallHelper::Delegate::UNKNOWN_ERROR
:
148 return api::webstore_private::RESULT_UNKNOWN_ERROR
;
149 case WebstoreInstallHelper::Delegate::ICON_ERROR
:
150 return api::webstore_private::RESULT_ICON_ERROR
;
151 case WebstoreInstallHelper::Delegate::MANIFEST_ERROR
:
152 return api::webstore_private::RESULT_MANIFEST_ERROR
;
155 return api::webstore_private::RESULT_NONE
;
158 static base::LazyInstance
<PendingApprovals
> g_pending_approvals
=
159 LAZY_INSTANCE_INITIALIZER
;
161 // A preference set by the web store to indicate login information for
163 const char kWebstoreLogin
[] = "extensions.webstore_login";
165 // Error messages that can be returned by the API.
166 const char kAlreadyInstalledError
[] = "This item is already installed";
167 const char kCannotSpecifyIconDataAndUrlError
[] =
168 "You cannot specify both icon data and an icon url";
169 const char kInvalidBundleError
[] = "Invalid bundle";
170 const char kInvalidIconUrlError
[] = "Invalid icon url";
171 const char kInvalidIdError
[] = "Invalid id";
172 const char kInvalidManifestError
[] = "Invalid manifest";
173 const char kNoPreviousBeginInstallWithManifestError
[] =
174 "* does not match a previous call to beginInstallWithManifest3";
175 const char kUserCancelledError
[] = "User cancelled install";
177 WebstoreInstaller::Delegate
* test_webstore_installer_delegate
= nullptr;
179 // We allow the web store to set a string containing login information when a
180 // purchase is made, so that when a user logs into sync with a different
181 // account we can recognize the situation. The Get function returns the login if
182 // there was previously stored data, or an empty string otherwise. The Set will
183 // overwrite any previous login.
184 std::string
GetWebstoreLogin(Profile
* profile
) {
185 if (profile
->GetPrefs()->HasPrefPath(kWebstoreLogin
))
186 return profile
->GetPrefs()->GetString(kWebstoreLogin
);
187 return std::string();
190 void SetWebstoreLogin(Profile
* profile
, const std::string
& login
) {
191 profile
->GetPrefs()->SetString(kWebstoreLogin
, login
);
194 void RecordWebstoreExtensionInstallResult(bool success
) {
195 UMA_HISTOGRAM_BOOLEAN("Webstore.ExtensionInstallResult", success
);
201 void WebstorePrivateApi::SetWebstoreInstallerDelegateForTesting(
202 WebstoreInstaller::Delegate
* delegate
) {
203 test_webstore_installer_delegate
= delegate
;
207 scoped_ptr
<WebstoreInstaller::Approval
>
208 WebstorePrivateApi::PopApprovalForTesting(
209 Profile
* profile
, const std::string
& extension_id
) {
210 return g_pending_approvals
.Get().PopApproval(profile
, extension_id
);
213 template<typename Params
>
214 WebstorePrivateFunctionWithPermissionPrompt
<Params
>::
215 WebstorePrivateFunctionWithPermissionPrompt() {
218 template<typename Params
>
219 WebstorePrivateFunctionWithPermissionPrompt
<Params
>::
220 ~WebstorePrivateFunctionWithPermissionPrompt() {
223 template<typename Params
>
224 ExtensionFunction::ResponseValue
225 WebstorePrivateFunctionWithPermissionPrompt
<Params
>::RunExtraForResponse() {
226 return ExtensionFunction::ResponseValue();
229 template<typename Params
>
230 ExtensionFunction::ResponseValue
231 WebstorePrivateFunctionWithPermissionPrompt
<Params
>::BuildResponse(
232 api::webstore_private::Result result
, const std::string
& error
) {
233 if (result
!= api::webstore_private::RESULT_SUCCESS
)
234 return ErrorWithArguments(CreateResults(result
), error
);
236 // The web store expects an empty string on success, so don't use
237 // RESULT_SUCCESS here.
239 CreateResults(api::webstore_private::RESULT_EMPTY_STRING
));
242 template<typename Params
>
243 scoped_ptr
<base::DictionaryValue
>
244 WebstorePrivateFunctionWithPermissionPrompt
<Params
>::PassParsedManifest() {
245 return parsed_manifest_
.Pass();
248 template<typename Params
>
249 ExtensionFunction::ResponseAction
250 WebstorePrivateFunctionWithPermissionPrompt
<Params
>::Run() {
251 params_
= Params::Create(*args_
);
252 EXTENSION_FUNCTION_VALIDATE(params_
);
254 if (!crx_file::id_util::IdIsValid(params_
->details
.id
)) {
255 return RespondNow(BuildResponse(api::webstore_private::RESULT_INVALID_ID
,
259 if (params_
->details
.icon_data
&& params_
->details
.icon_url
) {
260 return RespondNow(BuildResponse(api::webstore_private::RESULT_ICON_ERROR
,
261 kCannotSpecifyIconDataAndUrlError
));
265 if (params_
->details
.icon_url
) {
266 icon_url
= source_url().Resolve(*params_
->details
.icon_url
);
267 if (!icon_url
.is_valid()) {
268 return RespondNow(BuildResponse(
269 api::webstore_private::RESULT_INVALID_ICON_URL
,
270 kInvalidIconUrlError
));
274 ExtensionFunction::ResponseValue response
= RunExtraForResponse();
276 return RespondNow(response
.Pass());
278 net::URLRequestContextGetter
* context_getter
= nullptr;
279 if (!icon_url
.is_empty())
280 context_getter
= browser_context()->GetRequestContext();
282 scoped_refptr
<WebstoreInstallHelper
> helper
= new WebstoreInstallHelper(
283 this, params_
->details
.id
, params_
->details
.manifest
, icon_url
,
286 // The helper will call us back via OnWebstoreParseSuccess or
287 // OnWebstoreParseFailure.
290 // Matched with a Release in OnWebstoreParseSuccess/OnWebstoreParseFailure.
293 // The response is sent asynchronously in OnWebstoreParseSuccess/
294 // OnWebstoreParseFailure.
295 return RespondLater();
298 template<typename Params
>
300 WebstorePrivateFunctionWithPermissionPrompt
<Params
>::OnWebstoreParseSuccess(
301 const std::string
& id
,
302 const SkBitmap
& icon
,
303 base::DictionaryValue
* parsed_manifest
) {
304 CHECK_EQ(params_
->details
.id
, id
);
305 CHECK(parsed_manifest
);
307 parsed_manifest_
.reset(parsed_manifest
);
309 std::string localized_name
= params_
->details
.localized_name
?
310 *params_
->details
.localized_name
: std::string();
313 dummy_extension_
= ExtensionInstallPrompt::GetLocalizedExtensionForDisplay(
314 parsed_manifest_
.get(),
315 Extension::FROM_WEBSTORE
,
321 if (!dummy_extension_
.get()) {
322 OnWebstoreParseFailure(params_
->details
.id
,
323 WebstoreInstallHelper::Delegate::MANIFEST_ERROR
,
324 kInvalidManifestError
);
328 content::WebContents
* web_contents
= GetAssociatedWebContents();
330 // The browser window has gone away.
331 Respond(BuildResponse(api::webstore_private::RESULT_USER_CANCELLED
,
332 kUserCancelledError
));
333 // Matches the AddRef in Run().
337 install_prompt_
.reset(new ExtensionInstallPrompt(web_contents
));
338 ShowPrompt(install_prompt_
.get());
339 // Control flow finishes up in InstallUIProceed or InstallUIAbort.
342 template<typename Params
>
344 WebstorePrivateFunctionWithPermissionPrompt
<Params
>::OnWebstoreParseFailure(
345 const std::string
& id
,
346 WebstoreInstallHelper::Delegate::InstallHelperResultCode result
,
347 const std::string
& error_message
) {
348 CHECK_EQ(params_
->details
.id
, id
);
350 Respond(BuildResponse(WebstoreInstallHelperResultToApiResult(result
),
353 // Matches the AddRef in Run().
357 template<typename Params
>
358 void WebstorePrivateFunctionWithPermissionPrompt
<Params
>::InstallUIProceed() {
359 InstallUIProceedHook();
361 Respond(BuildResponse(api::webstore_private::RESULT_SUCCESS
, std::string()));
363 // Matches the AddRef in Run().
367 template<typename Params
>
368 void WebstorePrivateFunctionWithPermissionPrompt
<Params
>::InstallUIAbort(
369 bool user_initiated
) {
370 InstallUIAbortHook(user_initiated
);
372 Respond(BuildResponse(api::webstore_private::RESULT_USER_CANCELLED
,
373 kUserCancelledError
));
375 // Matches the AddRef in Run().
379 WebstorePrivateBeginInstallWithManifest3Function::
380 WebstorePrivateBeginInstallWithManifest3Function() : chrome_details_(this) {
383 WebstorePrivateBeginInstallWithManifest3Function::
384 ~WebstorePrivateBeginInstallWithManifest3Function() {
387 ExtensionFunction::ResponseValue
388 WebstorePrivateBeginInstallWithManifest3Function::RunExtraForResponse() {
389 InstallTracker
* tracker
= InstallTracker::Get(browser_context());
391 if (util::IsExtensionInstalledPermanently(params().details
.id
,
392 browser_context()) ||
393 tracker
->GetActiveInstall(params().details
.id
)) {
394 return BuildResponse(api::webstore_private::RESULT_ALREADY_INSTALLED
,
395 kAlreadyInstalledError
);
397 ActiveInstallData
install_data(params().details
.id
);
398 scoped_active_install_
.reset(new ScopedActiveInstall(tracker
, install_data
));
399 return ExtensionFunction::ResponseValue();
402 void WebstorePrivateBeginInstallWithManifest3Function::InstallUIProceedHook() {
403 // This gets cleared in CrxInstaller::ConfirmInstall(). TODO(asargent) - in
404 // the future we may also want to add time-based expiration, where a whitelist
405 // entry is only valid for some number of minutes.
406 scoped_ptr
<WebstoreInstaller::Approval
> approval(
407 WebstoreInstaller::Approval::CreateWithNoInstallPrompt(
408 chrome_details_
.GetProfile(),
410 PassParsedManifest(),
412 approval
->use_app_installed_bubble
= params().details
.app_install_bubble
;
413 approval
->enable_launcher
= params().details
.enable_launcher
;
414 // If we are enabling the launcher, we should not show the app list in order
415 // to train the user to open it themselves at least once.
416 approval
->skip_post_install_ui
= params().details
.enable_launcher
;
417 approval
->dummy_extension
= dummy_extension();
418 approval
->installing_icon
= gfx::ImageSkia::CreateFrom1xBitmap(icon());
419 if (params().details
.authuser
)
420 approval
->authuser
= *params().details
.authuser
;
421 g_pending_approvals
.Get().PushApproval(approval
.Pass());
423 DCHECK(scoped_active_install_
.get());
424 scoped_active_install_
->CancelDeregister();
426 // The Permissions_Install histogram is recorded from the ExtensionService
427 // for all extension installs, so we only need to record the web store
428 // specific histogram here.
429 ExtensionService::RecordPermissionMessagesHistogram(
430 dummy_extension().get(), "Extensions.Permissions_WebStoreInstall2");
433 void WebstorePrivateBeginInstallWithManifest3Function::InstallUIAbortHook(
434 bool user_initiated
) {
435 // The web store install histograms are a subset of the install histograms.
436 // We need to record both histograms here since CrxInstaller::InstallUIAbort
437 // is never called for web store install cancellations.
438 std::string histogram_name
=
439 user_initiated
? "Extensions.Permissions_WebStoreInstallCancel2"
440 : "Extensions.Permissions_WebStoreInstallAbort2";
441 ExtensionService::RecordPermissionMessagesHistogram(dummy_extension().get(),
442 histogram_name
.c_str());
444 histogram_name
= user_initiated
? "Extensions.Permissions_InstallCancel2"
445 : "Extensions.Permissions_InstallAbort2";
446 ExtensionService::RecordPermissionMessagesHistogram(dummy_extension().get(),
447 histogram_name
.c_str());
450 void WebstorePrivateBeginInstallWithManifest3Function::ShowPrompt(
451 ExtensionInstallPrompt
* install_prompt
) {
452 install_prompt
->ConfirmWebstoreInstall(
453 this, dummy_extension().get(), &icon(),
454 ExtensionInstallPrompt::GetDefaultShowDialogCallback());
457 scoped_ptr
<base::ListValue
>
458 WebstorePrivateBeginInstallWithManifest3Function::CreateResults(
459 api::webstore_private::Result result
) const {
460 return BeginInstallWithManifest3::Results::Create(result
);
463 WebstorePrivateCompleteInstallFunction::
464 WebstorePrivateCompleteInstallFunction() : chrome_details_(this) {}
466 WebstorePrivateCompleteInstallFunction::
467 ~WebstorePrivateCompleteInstallFunction() {}
469 ExtensionFunction::ResponseAction
470 WebstorePrivateCompleteInstallFunction::Run() {
471 scoped_ptr
<CompleteInstall::Params
> params(
472 CompleteInstall::Params::Create(*args_
));
473 EXTENSION_FUNCTION_VALIDATE(params
);
474 if (!crx_file::id_util::IdIsValid(params
->expected_id
))
475 return RespondNow(Error(kInvalidIdError
));
478 g_pending_approvals
.Get().PopApproval(chrome_details_
.GetProfile(),
479 params
->expected_id
).Pass();
481 return RespondNow(Error(kNoPreviousBeginInstallWithManifestError
,
482 params
->expected_id
));
485 scoped_active_install_
.reset(new ScopedActiveInstall(
486 InstallTracker::Get(browser_context()), params
->expected_id
));
488 AppListService
* app_list_service
= AppListService::Get(
489 GetHostDesktopTypeForWebContents(GetAssociatedWebContents()));
491 if (approval_
->enable_launcher
) {
492 app_list_service
->EnableAppList(chrome_details_
.GetProfile(),
493 AppListService::ENABLE_FOR_APP_INSTALL
);
496 if (IsAppLauncherEnabled() && approval_
->manifest
->is_app()) {
497 // Show the app list to show download is progressing. Don't show the app
498 // list on first app install so users can be trained to open it themselves.
499 app_list_service
->ShowForAppInstall(
500 chrome_details_
.GetProfile(),
502 approval_
->enable_launcher
);
505 // If the target extension has already been installed ephemerally and is
506 // up to date, it can be promoted to a regular installed extension and
507 // downloading from the Web Store is not necessary.
508 const Extension
* extension
= ExtensionRegistry::Get(browser_context())->
509 GetExtensionById(params
->expected_id
, ExtensionRegistry::EVERYTHING
);
510 if (extension
&& approval_
->dummy_extension
.get() &&
511 util::IsEphemeralApp(extension
->id(), browser_context()) &&
512 extension
->version()->CompareTo(*approval_
->dummy_extension
->version()) >=
514 install_ui::ShowPostInstallUIForApproval(
515 browser_context(), *approval_
, extension
);
517 ExtensionService
* extension_service
=
518 ExtensionSystem::Get(browser_context())->extension_service();
519 extension_service
->PromoteEphemeralApp(extension
, false);
520 OnInstallSuccess(extension
->id());
521 VLOG(1) << "Install success, sending response";
522 return RespondNow(NoArguments());
525 // Balanced in OnExtensionInstallSuccess() or OnExtensionInstallFailure().
528 // The extension will install through the normal extension install flow, but
529 // the whitelist entry will bypass the normal permissions install dialog.
530 scoped_refptr
<WebstoreInstaller
> installer
= new WebstoreInstaller(
531 chrome_details_
.GetProfile(),
533 chrome_details_
.GetAssociatedWebContents(),
536 WebstoreInstaller::INSTALL_SOURCE_OTHER
);
539 return RespondLater();
542 void WebstorePrivateCompleteInstallFunction::OnExtensionInstallSuccess(
543 const std::string
& id
) {
544 OnInstallSuccess(id
);
545 VLOG(1) << "Install success, sending response";
546 Respond(NoArguments());
548 RecordWebstoreExtensionInstallResult(true);
550 // Matches the AddRef in Run().
554 void WebstorePrivateCompleteInstallFunction::OnExtensionInstallFailure(
555 const std::string
& id
,
556 const std::string
& error
,
557 WebstoreInstaller::FailureReason reason
) {
558 if (test_webstore_installer_delegate
) {
559 test_webstore_installer_delegate
->OnExtensionInstallFailure(
563 VLOG(1) << "Install failed, sending response";
564 Respond(Error(error
));
566 RecordWebstoreExtensionInstallResult(false);
568 // Matches the AddRef in Run().
572 void WebstorePrivateCompleteInstallFunction::OnInstallSuccess(
573 const std::string
& id
) {
574 if (test_webstore_installer_delegate
)
575 test_webstore_installer_delegate
->OnExtensionInstallSuccess(id
);
578 WebstorePrivateShowPermissionPromptForDelegatedInstallFunction::
579 WebstorePrivateShowPermissionPromptForDelegatedInstallFunction() {
582 WebstorePrivateShowPermissionPromptForDelegatedInstallFunction::
583 ~WebstorePrivateShowPermissionPromptForDelegatedInstallFunction() {
586 void WebstorePrivateShowPermissionPromptForDelegatedInstallFunction::ShowPrompt(
587 ExtensionInstallPrompt
* install_prompt
) {
588 install_prompt
->ConfirmPermissionsForDelegatedInstall(
589 this, dummy_extension().get(), params().details
.delegated_user
, &icon());
592 scoped_ptr
<base::ListValue
>
593 WebstorePrivateShowPermissionPromptForDelegatedInstallFunction::CreateResults(
594 api::webstore_private::Result result
) const {
595 return ShowPermissionPromptForDelegatedInstall::Results::Create(result
);
598 WebstorePrivateInstallBundleFunction::WebstorePrivateInstallBundleFunction()
599 : chrome_details_(this) {
602 WebstorePrivateInstallBundleFunction::~WebstorePrivateInstallBundleFunction() {
605 ExtensionFunction::ResponseAction
WebstorePrivateInstallBundleFunction::Run() {
606 params_
= InstallBundle::Params::Create(*args_
);
607 EXTENSION_FUNCTION_VALIDATE(params_
);
609 if (params_
->contents
.empty())
610 return RespondNow(Error(kInvalidBundleError
));
612 if (params_
->details
.icon_url
) {
613 GURL icon_url
= source_url().Resolve(*params_
->details
.icon_url
);
614 if (!icon_url
.is_valid())
615 return RespondNow(Error(kInvalidIconUrlError
));
617 // The bitmap fetcher will call us back via OnFetchComplete.
618 icon_fetcher_
.reset(new chrome::BitmapFetcher(icon_url
, this));
619 icon_fetcher_
->Start(
620 browser_context()->GetRequestContext(), std::string(),
621 net::URLRequest::CLEAR_REFERRER_ON_TRANSITION_FROM_SECURE_TO_INSECURE
,
622 net::LOAD_DO_NOT_SAVE_COOKIES
| net::LOAD_DO_NOT_SEND_COOKIES
);
624 base::MessageLoopProxy::current()->PostTask(
626 base::Bind(&WebstorePrivateInstallBundleFunction::OnFetchComplete
,
627 this, GURL(), nullptr));
630 AddRef(); // Balanced in OnFetchComplete.
632 // The response is sent asynchronously in OnFetchComplete, OnInstallApproval,
633 // or OnInstallComplete.
634 return RespondLater();
637 void WebstorePrivateInstallBundleFunction::OnFetchComplete(
638 const GURL
& url
, const SkBitmap
* bitmap
) {
639 InstallTracker
* tracker
= InstallTracker::Get(browser_context());
642 std::string authuser
;
643 if (params_
->details
.authuser
)
644 authuser
= *params_
->details
.authuser
;
646 BundleInstaller::ItemList items
;
647 for (const auto& entry
: params_
->contents
) {
648 // Skip already-installed items.
649 if (util::IsExtensionInstalledPermanently(entry
->id
, browser_context()) ||
650 tracker
->GetActiveInstall(entry
->id
)) {
653 BundleInstaller::Item item
;
655 item
.manifest
= entry
->manifest
;
656 item
.localized_name
= entry
->localized_name
;
658 item
.icon_url
= source_url().Resolve(*entry
->icon_url
);
659 items
.push_back(item
);
662 Respond(Error(kAlreadyInstalledError
));
663 Release(); // Matches the AddRef in Run.
666 bundle_
.reset(new BundleInstaller(chrome_details_
.GetCurrentBrowser(),
667 params_
->details
.localized_name
,
668 bitmap
? *bitmap
: SkBitmap(), authuser
,
671 // The bundle installer will call us back via OnInstallApproval.
672 bundle_
->PromptForApproval(
673 base::Bind(&WebstorePrivateInstallBundleFunction::OnInstallApproval
,
676 Release(); // Matches the AddRef in Run.
679 void WebstorePrivateInstallBundleFunction::OnInstallApproval(
680 BundleInstaller::ApprovalState state
) {
681 if (state
!= BundleInstaller::APPROVED
) {
682 Respond(Error(state
== BundleInstaller::USER_CANCELED
683 ? kUserCancelledError
684 : kInvalidBundleError
));
688 // The bundle installer will call us back via OnInstallComplete.
689 bundle_
->CompleteInstall(
690 chrome_details_
.GetAssociatedWebContents(),
691 base::Bind(&WebstorePrivateInstallBundleFunction::OnInstallComplete
,
695 void WebstorePrivateInstallBundleFunction::OnInstallComplete() {
696 Respond(NoArguments());
699 WebstorePrivateEnableAppLauncherFunction::
700 WebstorePrivateEnableAppLauncherFunction() : chrome_details_(this) {}
702 WebstorePrivateEnableAppLauncherFunction::
703 ~WebstorePrivateEnableAppLauncherFunction() {}
705 ExtensionFunction::ResponseAction
706 WebstorePrivateEnableAppLauncherFunction::Run() {
707 AppListService
* app_list_service
= AppListService::Get(
708 GetHostDesktopTypeForWebContents(
709 chrome_details_
.GetAssociatedWebContents()));
710 app_list_service
->EnableAppList(chrome_details_
.GetProfile(),
711 AppListService::ENABLE_VIA_WEBSTORE_LINK
);
712 return RespondNow(NoArguments());
715 WebstorePrivateGetBrowserLoginFunction::
716 WebstorePrivateGetBrowserLoginFunction() : chrome_details_(this) {}
718 WebstorePrivateGetBrowserLoginFunction::
719 ~WebstorePrivateGetBrowserLoginFunction() {}
721 ExtensionFunction::ResponseAction
722 WebstorePrivateGetBrowserLoginFunction::Run() {
723 GetBrowserLogin::Results::Info info
;
724 info
.login
= SigninManagerFactory::GetForProfile(
725 chrome_details_
.GetProfile()->GetOriginalProfile())
726 ->GetAuthenticatedUsername();
727 return RespondNow(ArgumentList(GetBrowserLogin::Results::Create(info
)));
730 WebstorePrivateGetStoreLoginFunction::
731 WebstorePrivateGetStoreLoginFunction() : chrome_details_(this) {}
733 WebstorePrivateGetStoreLoginFunction::
734 ~WebstorePrivateGetStoreLoginFunction() {}
736 ExtensionFunction::ResponseAction
WebstorePrivateGetStoreLoginFunction::Run() {
737 return RespondNow(ArgumentList(GetStoreLogin::Results::Create(
738 GetWebstoreLogin(chrome_details_
.GetProfile()))));
741 WebstorePrivateSetStoreLoginFunction::
742 WebstorePrivateSetStoreLoginFunction() : chrome_details_(this) {}
744 WebstorePrivateSetStoreLoginFunction::
745 ~WebstorePrivateSetStoreLoginFunction() {}
747 ExtensionFunction::ResponseAction
WebstorePrivateSetStoreLoginFunction::Run() {
748 scoped_ptr
<SetStoreLogin::Params
> params(
749 SetStoreLogin::Params::Create(*args_
));
750 EXTENSION_FUNCTION_VALIDATE(params
);
751 SetWebstoreLogin(chrome_details_
.GetProfile(), params
->login
);
752 return RespondNow(NoArguments());
755 WebstorePrivateGetWebGLStatusFunction::WebstorePrivateGetWebGLStatusFunction()
756 : feature_checker_(new GPUFeatureChecker(
757 gpu::GPU_FEATURE_TYPE_WEBGL
,
758 base::Bind(&WebstorePrivateGetWebGLStatusFunction::OnFeatureCheck
,
759 base::Unretained(this)))) {
762 WebstorePrivateGetWebGLStatusFunction::
763 ~WebstorePrivateGetWebGLStatusFunction() {}
765 ExtensionFunction::ResponseAction
WebstorePrivateGetWebGLStatusFunction::Run() {
766 feature_checker_
->CheckGPUFeatureAvailability();
767 return RespondLater();
770 void WebstorePrivateGetWebGLStatusFunction::OnFeatureCheck(
771 bool feature_allowed
) {
772 Respond(ArgumentList(GetWebGLStatus::Results::Create(
773 GetWebGLStatus::Results::ParseWebgl_status(
774 feature_allowed
? "webgl_allowed" : "webgl_blocked"))));
777 WebstorePrivateGetIsLauncherEnabledFunction::
778 WebstorePrivateGetIsLauncherEnabledFunction() {}
780 WebstorePrivateGetIsLauncherEnabledFunction::
781 ~WebstorePrivateGetIsLauncherEnabledFunction() {}
783 ExtensionFunction::ResponseAction
784 WebstorePrivateGetIsLauncherEnabledFunction::Run() {
785 return RespondNow(ArgumentList(
786 GetIsLauncherEnabled::Results::Create(IsAppLauncherEnabled())));
789 WebstorePrivateIsInIncognitoModeFunction::
790 WebstorePrivateIsInIncognitoModeFunction() : chrome_details_(this) {}
792 WebstorePrivateIsInIncognitoModeFunction::
793 ~WebstorePrivateIsInIncognitoModeFunction() {}
795 ExtensionFunction::ResponseAction
796 WebstorePrivateIsInIncognitoModeFunction::Run() {
797 Profile
* profile
= chrome_details_
.GetProfile();
798 return RespondNow(ArgumentList(IsInIncognitoMode::Results::Create(
799 profile
!= profile
->GetOriginalProfile())));
802 WebstorePrivateLaunchEphemeralAppFunction::
803 WebstorePrivateLaunchEphemeralAppFunction() : chrome_details_(this) {}
805 WebstorePrivateLaunchEphemeralAppFunction::
806 ~WebstorePrivateLaunchEphemeralAppFunction() {}
808 ExtensionFunction::ResponseAction
809 WebstorePrivateLaunchEphemeralAppFunction::Run() {
810 // Check whether the browser window still exists.
811 content::WebContents
* web_contents
=
812 chrome_details_
.GetAssociatedWebContents();
814 return RespondNow(Error("aborted"));
816 if (!user_gesture()) {
817 return RespondNow(BuildResponse(
818 api::webstore_private::RESULT_USER_GESTURE_REQUIRED
,
819 "User gesture is required"));
822 scoped_ptr
<LaunchEphemeralApp::Params
> params(
823 LaunchEphemeralApp::Params::Create(*args_
));
824 EXTENSION_FUNCTION_VALIDATE(params
);
826 AddRef(); // Balanced in OnLaunchComplete()
828 scoped_refptr
<EphemeralAppLauncher
> launcher
=
829 EphemeralAppLauncher::CreateForWebContents(
833 &WebstorePrivateLaunchEphemeralAppFunction::OnLaunchComplete
,
834 base::Unretained(this)));
837 return RespondLater();
840 void WebstorePrivateLaunchEphemeralAppFunction::OnLaunchComplete(
841 webstore_install::Result result
, const std::string
& error
) {
842 Respond(BuildResponse(WebstoreInstallResultToApiResult(result
), error
));
843 Release(); // Matches AddRef() in Run()
846 ExtensionFunction::ResponseValue
847 WebstorePrivateLaunchEphemeralAppFunction::BuildResponse(
848 api::webstore_private::Result result
, const std::string
& error
) {
849 if (result
!= api::webstore_private::RESULT_SUCCESS
) {
850 std::string error_message
;
852 error_message
= base::StringPrintf(
853 "[%s]", api::webstore_private::ToString(result
).c_str());
855 error_message
= base::StringPrintf(
857 api::webstore_private::ToString(result
).c_str(),
860 return ErrorWithArguments(LaunchEphemeralApp::Results::Create(result
),
863 return ArgumentList(LaunchEphemeralApp::Results::Create(result
));
866 WebstorePrivateGetEphemeralAppsEnabledFunction::
867 WebstorePrivateGetEphemeralAppsEnabledFunction() {}
869 WebstorePrivateGetEphemeralAppsEnabledFunction::
870 ~WebstorePrivateGetEphemeralAppsEnabledFunction() {}
872 ExtensionFunction::ResponseAction
873 WebstorePrivateGetEphemeralAppsEnabledFunction::Run() {
874 return RespondNow(ArgumentList(GetEphemeralAppsEnabled::Results::Create(
875 EphemeralAppLauncher::IsFeatureEnabled())));
878 } // namespace extensions