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/ui/extensions/extension_enable_flow.h"
7 #include "chrome/browser/chrome_notification_types.h"
8 #include "chrome/browser/extensions/extension_service.h"
9 #include "chrome/browser/extensions/extension_util.h"
10 #include "chrome/browser/profiles/profile.h"
11 #include "chrome/browser/profiles/profiles_state.h"
12 #include "chrome/browser/ui/extensions/extension_enable_flow_delegate.h"
13 #include "chrome/browser/ui/user_manager.h"
14 #include "content/public/browser/notification_details.h"
15 #include "content/public/browser/notification_source.h"
16 #include "extensions/browser/extension_prefs.h"
17 #include "extensions/browser/extension_registry.h"
18 #include "extensions/browser/extension_system.h"
20 using extensions::Extension
;
22 ExtensionEnableFlow::ExtensionEnableFlow(Profile
* profile
,
23 const std::string
& extension_id
,
24 ExtensionEnableFlowDelegate
* delegate
)
26 extension_id_(extension_id
),
28 parent_contents_(NULL
),
30 extension_registry_observer_(this) {
33 ExtensionEnableFlow::~ExtensionEnableFlow() {
36 void ExtensionEnableFlow::StartForWebContents(
37 content::WebContents
* parent_contents
) {
38 parent_contents_
= parent_contents
;
39 parent_window_
= NULL
;
43 void ExtensionEnableFlow::StartForNativeWindow(
44 gfx::NativeWindow parent_window
) {
45 parent_contents_
= NULL
;
46 parent_window_
= parent_window
;
50 void ExtensionEnableFlow::StartForCurrentlyNonexistentWindow(
51 base::Callback
<gfx::NativeWindow(void)> window_getter
) {
52 window_getter_
= window_getter
;
56 void ExtensionEnableFlow::Run() {
57 ExtensionService
* service
=
58 extensions::ExtensionSystem::Get(profile_
)->extension_service();
59 const Extension
* extension
= service
->GetExtensionById(extension_id_
, true);
61 extension
= extensions::ExtensionRegistry::Get(profile_
)->GetExtensionById(
62 extension_id_
, extensions::ExtensionRegistry::TERMINATED
);
63 // It's possible (though unlikely) the app could have been uninstalled since
64 // the user clicked on it.
67 // If the app was terminated, reload it first.
68 service
->ReloadExtension(extension_id_
);
70 // ReloadExtension reallocates the Extension object.
71 extension
= service
->GetExtensionById(extension_id_
, true);
73 // |extension| could be NULL for asynchronous load, such as the case of
74 // an unpacked extension. Wait for the load to continue the flow.
81 CheckPermissionAndMaybePromptUser();
84 void ExtensionEnableFlow::CheckPermissionAndMaybePromptUser() {
85 ExtensionService
* service
=
86 extensions::ExtensionSystem::Get(profile_
)->extension_service();
87 const Extension
* extension
= service
->GetExtensionById(extension_id_
, true);
89 delegate_
->ExtensionEnableFlowAborted(false); // |delegate_| may delete us.
93 // Supervised users can't re-enable custodian-installed extensions.
94 if (extensions::util::IsExtensionSupervised(extension
, profile_
)) {
95 delegate_
->ExtensionEnableFlowAborted(false); // |delegate_| may delete us.
99 if (profiles::IsProfileLocked(profile_
->GetPath())) {
100 UserManager::Show(base::FilePath(),
101 profiles::USER_MANAGER_NO_TUTORIAL
,
102 profiles::USER_MANAGER_SELECT_PROFILE_APP_LAUNCHER
);
106 extensions::ExtensionPrefs
* prefs
= extensions::ExtensionPrefs::Get(profile_
);
107 if (!prefs
->DidExtensionEscalatePermissions(extension_id_
)) {
108 // Enable the extension immediately if its privileges weren't escalated.
109 // This is a no-op if the extension was previously terminated.
110 service
->EnableExtension(extension_id_
);
112 delegate_
->ExtensionEnableFlowFinished(); // |delegate_| may delete us.
117 prompt_
->ConfirmReEnable(this, extension
);
120 void ExtensionEnableFlow::CreatePrompt() {
121 if (!window_getter_
.is_null())
122 parent_window_
= window_getter_
.Run();
123 prompt_
.reset(parent_contents_
?
124 new ExtensionInstallPrompt(parent_contents_
) :
125 new ExtensionInstallPrompt(profile_
, parent_window_
));
128 void ExtensionEnableFlow::StartObserving() {
129 extension_registry_observer_
.Add(
130 extensions::ExtensionRegistry::Get(profile_
));
132 extensions::NOTIFICATION_EXTENSION_LOAD_ERROR
,
133 content::Source
<Profile
>(profile_
));
136 void ExtensionEnableFlow::StopObserving() {
137 registrar_
.RemoveAll();
138 extension_registry_observer_
.RemoveAll();
141 void ExtensionEnableFlow::Observe(int type
,
142 const content::NotificationSource
& source
,
143 const content::NotificationDetails
& details
) {
144 DCHECK_EQ(extensions::NOTIFICATION_EXTENSION_LOAD_ERROR
, type
);
146 delegate_
->ExtensionEnableFlowAborted(false);
149 void ExtensionEnableFlow::OnExtensionLoaded(
150 content::BrowserContext
* browser_context
,
151 const Extension
* extension
) {
152 if (extension
->id() == extension_id_
) {
154 CheckPermissionAndMaybePromptUser();
158 void ExtensionEnableFlow::OnExtensionUninstalled(
159 content::BrowserContext
* browser_context
,
160 const Extension
* extension
,
161 extensions::UninstallReason reason
) {
162 if (extension
->id() == extension_id_
) {
164 delegate_
->ExtensionEnableFlowAborted(false);
168 void ExtensionEnableFlow::InstallUIProceed() {
169 ExtensionService
* service
=
170 extensions::ExtensionSystem::Get(profile_
)->extension_service();
172 // The extension can be uninstalled in another window while the UI was
173 // showing. Treat it as a cancellation and notify |delegate_|.
174 const Extension
* extension
= service
->GetExtensionById(extension_id_
, true);
176 delegate_
->ExtensionEnableFlowAborted(true);
180 service
->GrantPermissionsAndEnableExtension(extension
);
181 delegate_
->ExtensionEnableFlowFinished(); // |delegate_| may delete us.
184 void ExtensionEnableFlow::InstallUIAbort(bool user_initiated
) {
185 delegate_
->ExtensionEnableFlowAborted(user_initiated
);
186 // |delegate_| may delete us.