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"
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"
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
;
58 // Holds the Approvals between the time we prompt and start the installs.
59 class PendingApprovals
{
64 void PushApproval(scoped_ptr
<WebstoreInstaller::Approval
> approval
);
65 scoped_ptr
<WebstoreInstaller::Approval
> PopApproval(
66 Profile
* profile
, const std::string
& id
);
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
) {
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
;
139 return api::webstore_private::RESULT_NONE
;
142 api::webstore_private::Result
WebstoreInstallHelperResultToApiResult(
143 WebstoreInstallHelper::Delegate::InstallHelperResultCode 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
;
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
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 kUserCancelledError
[] = "User cancelled install";
174 const char kIncognitoError
[] =
175 "Apps cannot be installed in guest/incognito mode";
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 WebstorePrivateBeginInstallWithManifest3Function::
214 WebstorePrivateBeginInstallWithManifest3Function() : chrome_details_(this) {
217 WebstorePrivateBeginInstallWithManifest3Function::
218 ~WebstorePrivateBeginInstallWithManifest3Function() {
221 ExtensionFunction::ResponseAction
222 WebstorePrivateBeginInstallWithManifest3Function::Run() {
223 params_
= Params::Create(*args_
);
224 EXTENSION_FUNCTION_VALIDATE(params_
);
226 if (!crx_file::id_util::IdIsValid(details().id
)) {
227 return RespondNow(BuildResponse(api::webstore_private::RESULT_INVALID_ID
,
231 if (details().icon_data
&& details().icon_url
) {
232 return RespondNow(BuildResponse(api::webstore_private::RESULT_ICON_ERROR
,
233 kCannotSpecifyIconDataAndUrlError
));
237 if (details().icon_url
) {
238 icon_url
= source_url().Resolve(*details().icon_url
);
239 if (!icon_url
.is_valid()) {
240 return RespondNow(BuildResponse(
241 api::webstore_private::RESULT_INVALID_ICON_URL
,
242 kInvalidIconUrlError
));
246 InstallTracker
* tracker
= InstallTracker::Get(browser_context());
248 if (util::IsExtensionInstalledPermanently(details().id
, browser_context()) ||
249 tracker
->GetActiveInstall(details().id
)) {
250 return RespondNow(BuildResponse(
251 api::webstore_private::RESULT_ALREADY_INSTALLED
,
252 kAlreadyInstalledError
));
254 ActiveInstallData
install_data(details().id
);
255 scoped_active_install_
.reset(new ScopedActiveInstall(tracker
, install_data
));
257 net::URLRequestContextGetter
* context_getter
= nullptr;
258 if (!icon_url
.is_empty())
259 context_getter
= browser_context()->GetRequestContext();
261 scoped_refptr
<WebstoreInstallHelper
> helper
= new WebstoreInstallHelper(
262 this, details().id
, details().manifest
, icon_url
, context_getter
);
264 // The helper will call us back via OnWebstoreParseSuccess or
265 // OnWebstoreParseFailure.
268 // Matched with a Release in OnWebstoreParseSuccess/OnWebstoreParseFailure.
271 // The response is sent asynchronously in OnWebstoreParseSuccess/
272 // OnWebstoreParseFailure.
273 return RespondLater();
276 void WebstorePrivateBeginInstallWithManifest3Function::OnWebstoreParseSuccess(
277 const std::string
& id
,
278 const SkBitmap
& icon
,
279 base::DictionaryValue
* parsed_manifest
) {
280 CHECK_EQ(details().id
, id
);
281 CHECK(parsed_manifest
);
282 parsed_manifest_
.reset(parsed_manifest
);
285 std::string localized_name
=
286 details().localized_name
? *details().localized_name
: std::string();
289 dummy_extension_
= ExtensionInstallPrompt::GetLocalizedExtensionForDisplay(
290 parsed_manifest_
.get(),
291 Extension::FROM_WEBSTORE
,
297 if (!dummy_extension_
.get()) {
298 OnWebstoreParseFailure(details().id
,
299 WebstoreInstallHelper::Delegate::MANIFEST_ERROR
,
300 kInvalidManifestError
);
304 content::WebContents
* web_contents
= GetAssociatedWebContents();
306 // The browser window has gone away.
307 Respond(BuildResponse(api::webstore_private::RESULT_USER_CANCELLED
,
308 kUserCancelledError
));
309 // Matches the AddRef in Run().
313 install_prompt_
.reset(new ExtensionInstallPrompt(web_contents
));
314 install_prompt_
->ConfirmWebstoreInstall(
315 this, dummy_extension_
.get(), &icon_
,
316 ExtensionInstallPrompt::GetDefaultShowDialogCallback());
317 // Control flow finishes up in InstallUIProceed or InstallUIAbort.
320 void WebstorePrivateBeginInstallWithManifest3Function::OnWebstoreParseFailure(
321 const std::string
& id
,
322 WebstoreInstallHelper::Delegate::InstallHelperResultCode result
,
323 const std::string
& error_message
) {
324 CHECK_EQ(details().id
, id
);
326 Respond(BuildResponse(WebstoreInstallHelperResultToApiResult(result
),
329 // Matches the AddRef in Run().
333 void WebstorePrivateBeginInstallWithManifest3Function::InstallUIProceed() {
334 // This gets cleared in CrxInstaller::ConfirmInstall(). TODO(asargent) - in
335 // the future we may also want to add time-based expiration, where a whitelist
336 // entry is only valid for some number of minutes.
337 scoped_ptr
<WebstoreInstaller::Approval
> approval(
338 WebstoreInstaller::Approval::CreateWithNoInstallPrompt(
339 chrome_details_
.GetProfile(),
341 parsed_manifest_
.Pass(),
343 approval
->use_app_installed_bubble
= details().app_install_bubble
;
344 approval
->enable_launcher
= details().enable_launcher
;
345 // If we are enabling the launcher, we should not show the app list in order
346 // to train the user to open it themselves at least once.
347 approval
->skip_post_install_ui
= details().enable_launcher
;
348 approval
->dummy_extension
= dummy_extension_
.get();
349 approval
->installing_icon
= gfx::ImageSkia::CreateFrom1xBitmap(icon_
);
350 if (details().authuser
)
351 approval
->authuser
= *details().authuser
;
352 g_pending_approvals
.Get().PushApproval(approval
.Pass());
354 DCHECK(scoped_active_install_
.get());
355 scoped_active_install_
->CancelDeregister();
357 // The Permissions_Install histogram is recorded from the ExtensionService
358 // for all extension installs, so we only need to record the web store
359 // specific histogram here.
360 ExtensionService::RecordPermissionMessagesHistogram(
361 dummy_extension_
.get(), "WebStoreInstall");
363 Respond(BuildResponse(api::webstore_private::RESULT_SUCCESS
, std::string()));
365 // Matches the AddRef in Run().
369 void WebstorePrivateBeginInstallWithManifest3Function::InstallUIAbort(
370 bool user_initiated
) {
371 // The web store install histograms are a subset of the install histograms.
372 // We need to record both histograms here since CrxInstaller::InstallUIAbort
373 // is never called for web store install cancellations.
374 std::string histogram_name
= user_initiated
? "WebStoreInstallCancel"
375 : "WebStoreInstallAbort";
376 ExtensionService::RecordPermissionMessagesHistogram(dummy_extension_
.get(),
377 histogram_name
.c_str());
379 histogram_name
= user_initiated
? "InstallCancel" : "InstallAbort";
380 ExtensionService::RecordPermissionMessagesHistogram(dummy_extension_
.get(),
381 histogram_name
.c_str());
383 Respond(BuildResponse(api::webstore_private::RESULT_USER_CANCELLED
,
384 kUserCancelledError
));
386 // Matches the AddRef in Run().
390 ExtensionFunction::ResponseValue
391 WebstorePrivateBeginInstallWithManifest3Function::BuildResponse(
392 api::webstore_private::Result result
, const std::string
& error
) {
393 if (result
!= api::webstore_private::RESULT_SUCCESS
)
394 return ErrorWithArguments(CreateResults(result
), error
);
396 // The web store expects an empty string on success, so don't use
397 // RESULT_SUCCESS here.
399 CreateResults(api::webstore_private::RESULT_EMPTY_STRING
));
402 scoped_ptr
<base::ListValue
>
403 WebstorePrivateBeginInstallWithManifest3Function::CreateResults(
404 api::webstore_private::Result result
) const {
405 return BeginInstallWithManifest3::Results::Create(result
);
408 WebstorePrivateCompleteInstallFunction::
409 WebstorePrivateCompleteInstallFunction() : chrome_details_(this) {}
411 WebstorePrivateCompleteInstallFunction::
412 ~WebstorePrivateCompleteInstallFunction() {}
414 ExtensionFunction::ResponseAction
415 WebstorePrivateCompleteInstallFunction::Run() {
416 scoped_ptr
<CompleteInstall::Params
> params(
417 CompleteInstall::Params::Create(*args_
));
418 EXTENSION_FUNCTION_VALIDATE(params
);
419 if (chrome_details_
.GetProfile()->IsGuestSession() ||
420 chrome_details_
.GetProfile()->IsOffTheRecord()) {
421 return RespondNow(Error(kIncognitoError
));
424 if (!crx_file::id_util::IdIsValid(params
->expected_id
))
425 return RespondNow(Error(kInvalidIdError
));
428 g_pending_approvals
.Get().PopApproval(chrome_details_
.GetProfile(),
429 params
->expected_id
).Pass();
431 return RespondNow(Error(kNoPreviousBeginInstallWithManifestError
,
432 params
->expected_id
));
435 scoped_active_install_
.reset(new ScopedActiveInstall(
436 InstallTracker::Get(browser_context()), params
->expected_id
));
438 AppListService
* app_list_service
= AppListService::Get(
439 GetHostDesktopTypeForWebContents(GetAssociatedWebContents()));
441 if (approval_
->enable_launcher
) {
442 app_list_service
->EnableAppList(chrome_details_
.GetProfile(),
443 AppListService::ENABLE_FOR_APP_INSTALL
);
446 if (IsAppLauncherEnabled() && approval_
->manifest
->is_app()) {
447 // Show the app list to show download is progressing. Don't show the app
448 // list on first app install so users can be trained to open it themselves.
449 app_list_service
->ShowForAppInstall(
450 chrome_details_
.GetProfile(),
452 approval_
->enable_launcher
);
455 // If the target extension has already been installed ephemerally and is
456 // up to date, it can be promoted to a regular installed extension and
457 // downloading from the Web Store is not necessary.
458 const Extension
* extension
= ExtensionRegistry::Get(browser_context())->
459 GetExtensionById(params
->expected_id
, ExtensionRegistry::EVERYTHING
);
460 if (extension
&& approval_
->dummy_extension
.get() &&
461 util::IsEphemeralApp(extension
->id(), browser_context()) &&
462 extension
->version()->CompareTo(*approval_
->dummy_extension
->version()) >=
464 install_ui::ShowPostInstallUIForApproval(
465 browser_context(), *approval_
, extension
);
467 ExtensionService
* extension_service
=
468 ExtensionSystem::Get(browser_context())->extension_service();
469 extension_service
->PromoteEphemeralApp(extension
, false);
470 OnInstallSuccess(extension
->id());
471 VLOG(1) << "Install success, sending response";
472 return RespondNow(NoArguments());
475 // Balanced in OnExtensionInstallSuccess() or OnExtensionInstallFailure().
478 // The extension will install through the normal extension install flow, but
479 // the whitelist entry will bypass the normal permissions install dialog.
480 scoped_refptr
<WebstoreInstaller
> installer
= new WebstoreInstaller(
481 chrome_details_
.GetProfile(),
483 chrome_details_
.GetAssociatedWebContents(),
486 WebstoreInstaller::INSTALL_SOURCE_OTHER
);
489 return RespondLater();
492 void WebstorePrivateCompleteInstallFunction::OnExtensionInstallSuccess(
493 const std::string
& id
) {
494 OnInstallSuccess(id
);
495 VLOG(1) << "Install success, sending response";
496 Respond(NoArguments());
498 RecordWebstoreExtensionInstallResult(true);
500 // Matches the AddRef in Run().
504 void WebstorePrivateCompleteInstallFunction::OnExtensionInstallFailure(
505 const std::string
& id
,
506 const std::string
& error
,
507 WebstoreInstaller::FailureReason reason
) {
508 if (test_webstore_installer_delegate
) {
509 test_webstore_installer_delegate
->OnExtensionInstallFailure(
513 VLOG(1) << "Install failed, sending response";
514 Respond(Error(error
));
516 RecordWebstoreExtensionInstallResult(false);
518 // Matches the AddRef in Run().
522 void WebstorePrivateCompleteInstallFunction::OnInstallSuccess(
523 const std::string
& id
) {
524 if (test_webstore_installer_delegate
)
525 test_webstore_installer_delegate
->OnExtensionInstallSuccess(id
);
528 WebstorePrivateInstallBundleFunction::WebstorePrivateInstallBundleFunction()
529 : chrome_details_(this) {
532 WebstorePrivateInstallBundleFunction::~WebstorePrivateInstallBundleFunction() {
535 ExtensionFunction::ResponseAction
WebstorePrivateInstallBundleFunction::Run() {
536 params_
= Params::Create(*args_
);
537 EXTENSION_FUNCTION_VALIDATE(params_
);
539 if (params_
->contents
.empty())
540 return RespondNow(Error(kInvalidBundleError
));
542 if (details().icon_url
) {
543 GURL icon_url
= source_url().Resolve(*details().icon_url
);
544 if (!icon_url
.is_valid())
545 return RespondNow(Error(kInvalidIconUrlError
));
547 // The bitmap fetcher will call us back via OnFetchComplete.
548 icon_fetcher_
.reset(new chrome::BitmapFetcher(icon_url
, this));
550 browser_context()->GetRequestContext(), std::string(),
551 net::URLRequest::CLEAR_REFERRER_ON_TRANSITION_FROM_SECURE_TO_INSECURE
,
552 net::LOAD_DO_NOT_SAVE_COOKIES
| net::LOAD_DO_NOT_SEND_COOKIES
);
553 icon_fetcher_
->Start();
555 base::ThreadTaskRunnerHandle::Get()->PostTask(
557 base::Bind(&WebstorePrivateInstallBundleFunction::OnFetchComplete
,
558 this, GURL(), nullptr));
561 AddRef(); // Balanced in OnFetchComplete.
563 // The response is sent asynchronously in OnFetchComplete, OnInstallApproval,
564 // or OnInstallComplete.
565 return RespondLater();
568 void WebstorePrivateInstallBundleFunction::OnFetchComplete(
569 const GURL
& url
, const SkBitmap
* bitmap
) {
570 BundleInstaller::ItemList items
;
571 for (const auto& entry
: params_
->contents
) {
572 // Skip already-installed items.
573 if (util::IsExtensionInstalledPermanently(entry
->id
, browser_context()) ||
574 InstallTracker::Get(browser_context())->GetActiveInstall(entry
->id
)) {
577 BundleInstaller::Item item
;
579 item
.manifest
= entry
->manifest
;
580 item
.localized_name
= entry
->localized_name
;
582 item
.icon_url
= source_url().Resolve(*entry
->icon_url
);
583 items
.push_back(item
);
586 Respond(Error(kAlreadyInstalledError
));
587 Release(); // Matches the AddRef in Run.
591 std::string authuser
=
592 details().authuser
? *details().authuser
: std::string();
593 bundle_
.reset(new BundleInstaller(chrome_details_
.GetCurrentBrowser(),
594 details().localized_name
,
595 bitmap
? *bitmap
: SkBitmap(), authuser
,
596 std::string(), items
));
598 bundle_
->PromptForApproval(base::Bind(
599 &WebstorePrivateInstallBundleFunction::OnInstallApproval
, this));
601 Release(); // Matches the AddRef in Run.
604 void WebstorePrivateInstallBundleFunction::OnInstallApproval(
605 BundleInstaller::ApprovalState state
) {
606 if (state
!= BundleInstaller::APPROVED
) {
607 Respond(Error(state
== BundleInstaller::USER_CANCELED
608 ? kUserCancelledError
609 : kInvalidBundleError
));
613 // The bundle installer will call us back via OnInstallComplete.
614 bundle_
->CompleteInstall(
615 GetSenderWebContents(),
616 base::Bind(&WebstorePrivateInstallBundleFunction::OnInstallComplete
,
620 void WebstorePrivateInstallBundleFunction::OnInstallComplete() {
621 Respond(NoArguments());
624 WebstorePrivateEnableAppLauncherFunction::
625 WebstorePrivateEnableAppLauncherFunction() : chrome_details_(this) {}
627 WebstorePrivateEnableAppLauncherFunction::
628 ~WebstorePrivateEnableAppLauncherFunction() {}
630 ExtensionFunction::ResponseAction
631 WebstorePrivateEnableAppLauncherFunction::Run() {
632 AppListService
* app_list_service
= AppListService::Get(
633 GetHostDesktopTypeForWebContents(
634 chrome_details_
.GetAssociatedWebContents()));
635 app_list_service
->EnableAppList(chrome_details_
.GetProfile(),
636 AppListService::ENABLE_VIA_WEBSTORE_LINK
);
637 return RespondNow(NoArguments());
640 WebstorePrivateGetBrowserLoginFunction::
641 WebstorePrivateGetBrowserLoginFunction() : chrome_details_(this) {}
643 WebstorePrivateGetBrowserLoginFunction::
644 ~WebstorePrivateGetBrowserLoginFunction() {}
646 ExtensionFunction::ResponseAction
647 WebstorePrivateGetBrowserLoginFunction::Run() {
648 GetBrowserLogin::Results::Info info
;
649 info
.login
= SigninManagerFactory::GetForProfile(
650 chrome_details_
.GetProfile()->GetOriginalProfile())
651 ->GetAuthenticatedAccountInfo()
653 return RespondNow(ArgumentList(GetBrowserLogin::Results::Create(info
)));
656 WebstorePrivateGetStoreLoginFunction::
657 WebstorePrivateGetStoreLoginFunction() : chrome_details_(this) {}
659 WebstorePrivateGetStoreLoginFunction::
660 ~WebstorePrivateGetStoreLoginFunction() {}
662 ExtensionFunction::ResponseAction
WebstorePrivateGetStoreLoginFunction::Run() {
663 return RespondNow(ArgumentList(GetStoreLogin::Results::Create(
664 GetWebstoreLogin(chrome_details_
.GetProfile()))));
667 WebstorePrivateSetStoreLoginFunction::
668 WebstorePrivateSetStoreLoginFunction() : chrome_details_(this) {}
670 WebstorePrivateSetStoreLoginFunction::
671 ~WebstorePrivateSetStoreLoginFunction() {}
673 ExtensionFunction::ResponseAction
WebstorePrivateSetStoreLoginFunction::Run() {
674 scoped_ptr
<SetStoreLogin::Params
> params(
675 SetStoreLogin::Params::Create(*args_
));
676 EXTENSION_FUNCTION_VALIDATE(params
);
677 SetWebstoreLogin(chrome_details_
.GetProfile(), params
->login
);
678 return RespondNow(NoArguments());
681 WebstorePrivateGetWebGLStatusFunction::WebstorePrivateGetWebGLStatusFunction()
682 : feature_checker_(new GPUFeatureChecker(
683 gpu::GPU_FEATURE_TYPE_WEBGL
,
684 base::Bind(&WebstorePrivateGetWebGLStatusFunction::OnFeatureCheck
,
685 base::Unretained(this)))) {
688 WebstorePrivateGetWebGLStatusFunction::
689 ~WebstorePrivateGetWebGLStatusFunction() {}
691 ExtensionFunction::ResponseAction
WebstorePrivateGetWebGLStatusFunction::Run() {
692 feature_checker_
->CheckGPUFeatureAvailability();
693 return RespondLater();
696 void WebstorePrivateGetWebGLStatusFunction::OnFeatureCheck(
697 bool feature_allowed
) {
698 Respond(ArgumentList(
699 GetWebGLStatus::Results::Create(api::webstore_private::ParseWebGlStatus(
700 feature_allowed
? "webgl_allowed" : "webgl_blocked"))));
703 WebstorePrivateGetIsLauncherEnabledFunction::
704 WebstorePrivateGetIsLauncherEnabledFunction() {}
706 WebstorePrivateGetIsLauncherEnabledFunction::
707 ~WebstorePrivateGetIsLauncherEnabledFunction() {}
709 ExtensionFunction::ResponseAction
710 WebstorePrivateGetIsLauncherEnabledFunction::Run() {
711 return RespondNow(ArgumentList(
712 GetIsLauncherEnabled::Results::Create(IsAppLauncherEnabled())));
715 WebstorePrivateIsInIncognitoModeFunction::
716 WebstorePrivateIsInIncognitoModeFunction() : chrome_details_(this) {}
718 WebstorePrivateIsInIncognitoModeFunction::
719 ~WebstorePrivateIsInIncognitoModeFunction() {}
721 ExtensionFunction::ResponseAction
722 WebstorePrivateIsInIncognitoModeFunction::Run() {
723 Profile
* profile
= chrome_details_
.GetProfile();
724 return RespondNow(ArgumentList(IsInIncognitoMode::Results::Create(
725 profile
!= profile
->GetOriginalProfile())));
728 WebstorePrivateLaunchEphemeralAppFunction::
729 WebstorePrivateLaunchEphemeralAppFunction() : chrome_details_(this) {}
731 WebstorePrivateLaunchEphemeralAppFunction::
732 ~WebstorePrivateLaunchEphemeralAppFunction() {}
734 ExtensionFunction::ResponseAction
735 WebstorePrivateLaunchEphemeralAppFunction::Run() {
736 // Check whether the browser window still exists.
737 content::WebContents
* web_contents
=
738 chrome_details_
.GetAssociatedWebContents();
740 return RespondNow(Error("aborted"));
742 if (!user_gesture()) {
743 return RespondNow(BuildResponse(
744 api::webstore_private::RESULT_USER_GESTURE_REQUIRED
,
745 "User gesture is required"));
748 scoped_ptr
<LaunchEphemeralApp::Params
> params(
749 LaunchEphemeralApp::Params::Create(*args_
));
750 EXTENSION_FUNCTION_VALIDATE(params
);
752 AddRef(); // Balanced in OnLaunchComplete()
754 scoped_refptr
<EphemeralAppLauncher
> launcher
=
755 EphemeralAppLauncher::CreateForWebContents(
759 &WebstorePrivateLaunchEphemeralAppFunction::OnLaunchComplete
,
760 base::Unretained(this)));
763 return RespondLater();
766 void WebstorePrivateLaunchEphemeralAppFunction::OnLaunchComplete(
767 webstore_install::Result result
, const std::string
& error
) {
768 Respond(BuildResponse(WebstoreInstallResultToApiResult(result
), error
));
769 Release(); // Matches AddRef() in Run()
772 ExtensionFunction::ResponseValue
773 WebstorePrivateLaunchEphemeralAppFunction::BuildResponse(
774 api::webstore_private::Result result
, const std::string
& error
) {
775 if (result
!= api::webstore_private::RESULT_SUCCESS
) {
776 std::string error_message
;
778 error_message
= base::StringPrintf(
779 "[%s]", api::webstore_private::ToString(result
).c_str());
781 error_message
= base::StringPrintf(
783 api::webstore_private::ToString(result
).c_str(),
786 return ErrorWithArguments(LaunchEphemeralApp::Results::Create(result
),
789 return ArgumentList(LaunchEphemeralApp::Results::Create(result
));
792 WebstorePrivateGetEphemeralAppsEnabledFunction::
793 WebstorePrivateGetEphemeralAppsEnabledFunction() {}
795 WebstorePrivateGetEphemeralAppsEnabledFunction::
796 ~WebstorePrivateGetEphemeralAppsEnabledFunction() {}
798 ExtensionFunction::ResponseAction
799 WebstorePrivateGetEphemeralAppsEnabledFunction::Run() {
800 return RespondNow(ArgumentList(GetEphemeralAppsEnabled::Results::Create(
801 EphemeralAppLauncher::IsFeatureEnabled())));
804 } // namespace extensions