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. 4 5 #include "chrome/browser/ui/extensions/extension_enable_flow.h" 6 7 #include "chrome/browser/chrome_notification_types.h" 8 #include "chrome/browser/extensions/extension_service.h" 9 #include "chrome/browser/extensions/extension_system.h" 10 #include "chrome/browser/ui/browser_finder.h" 11 #include "chrome/browser/ui/extensions/extension_enable_flow_delegate.h" 12 #include "content/public/browser/notification_details.h" 13 #include "content/public/browser/notification_source.h" 14 15 using extensions::Extension; 16 17 ExtensionEnableFlow::ExtensionEnableFlow(Profile* profile, 18 const std::string& extension_id, 19 ExtensionEnableFlowDelegate* delegate) 20 : profile_(profile), 21 extension_id_(extension_id), 22 delegate_(delegate), 23 parent_contents_(NULL), 24 parent_window_(NULL) { 25 } 26 27 ExtensionEnableFlow::~ExtensionEnableFlow() { 28 } 29 30 void ExtensionEnableFlow::StartForWebContents( 31 content::WebContents* parent_contents) { 32 parent_contents_ = parent_contents; 33 parent_window_ = NULL; 34 Run(); 35 } 36 37 void ExtensionEnableFlow::StartForNativeWindow( 38 gfx::NativeWindow parent_window) { 39 parent_contents_ = NULL; 40 parent_window_ = parent_window; 41 Run(); 42 } 43 44 void ExtensionEnableFlow::Run() { 45 ExtensionService* service = 46 extensions::ExtensionSystem::Get(profile_)->extension_service(); 47 const Extension* extension = service->GetExtensionById(extension_id_, true); 48 if (!extension) { 49 extension = service->GetTerminatedExtension(extension_id_); 50 // It's possible (though unlikely) the app could have been uninstalled since 51 // the user clicked on it. 52 if (!extension) 53 return; 54 // If the app was terminated, reload it first. 55 service->ReloadExtension(extension_id_); 56 57 // ReloadExtension reallocates the Extension object. 58 extension = service->GetExtensionById(extension_id_, true); 59 60 // |extension| could be NULL for asynchronous load, such as the case of 61 // an unpacked extension. Wait for the load to continue the flow. 62 if (!extension) { 63 StartObserving(); 64 return; 65 } 66 } 67 68 CheckPermissionAndMaybePromptUser(); 69 } 70 71 void ExtensionEnableFlow::CheckPermissionAndMaybePromptUser() { 72 ExtensionService* service = 73 extensions::ExtensionSystem::Get(profile_)->extension_service(); 74 const Extension* extension = service->GetExtensionById(extension_id_, true); 75 if (!extension) { 76 delegate_->ExtensionEnableFlowAborted(false); // |delegate_| may delete us. 77 return; 78 } 79 80 extensions::ExtensionPrefs* extension_prefs = service->extension_prefs(); 81 if (!extension_prefs->DidExtensionEscalatePermissions(extension_id_)) { 82 // Enable the extension immediately if its privileges weren't escalated. 83 // This is a no-op if the extension was previously terminated. 84 service->EnableExtension(extension_id_); 85 86 delegate_->ExtensionEnableFlowFinished(); // |delegate_| may delete us. 87 return; 88 } 89 90 CreatePrompt(); 91 prompt_->ConfirmReEnable(this, extension); 92 } 93 94 void ExtensionEnableFlow::CreatePrompt() { 95 prompt_.reset(parent_contents_ ? 96 new ExtensionInstallPrompt(parent_contents_) : 97 new ExtensionInstallPrompt(profile_, parent_window_, this)); 98 } 99 100 void ExtensionEnableFlow::StartObserving() { 101 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_LOADED, 102 content::Source<Profile>(profile_)); 103 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_LOAD_ERROR, 104 content::Source<Profile>(profile_)); 105 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_UNINSTALLED, 106 content::Source<Profile>(profile_)); 107 } 108 109 void ExtensionEnableFlow::StopObserving() { 110 registrar_.RemoveAll(); 111 } 112 113 void ExtensionEnableFlow::Observe(int type, 114 const content::NotificationSource& source, 115 const content::NotificationDetails& details) { 116 switch (type) { 117 case chrome::NOTIFICATION_EXTENSION_LOADED: { 118 const Extension* extension = 119 content::Details<const Extension>(details).ptr(); 120 if (extension->id() == extension_id_) { 121 StopObserving(); 122 CheckPermissionAndMaybePromptUser(); 123 } 124 125 break; 126 } 127 case chrome::NOTIFICATION_EXTENSION_LOAD_ERROR: { 128 StopObserving(); 129 delegate_->ExtensionEnableFlowAborted(false); 130 break; 131 } 132 case chrome::NOTIFICATION_EXTENSION_UNINSTALLED: { 133 const Extension* extension = 134 content::Details<const Extension>(details).ptr(); 135 if (extension->id() == extension_id_) { 136 StopObserving(); 137 delegate_->ExtensionEnableFlowAborted(false); 138 } 139 140 break; 141 } 142 default: 143 NOTREACHED(); 144 } 145 } 146 147 void ExtensionEnableFlow::InstallUIProceed() { 148 ExtensionService* service = 149 extensions::ExtensionSystem::Get(profile_)->extension_service(); 150 151 // The extension can be uninstalled in another window while the UI was 152 // showing. Treat it as a cancellation and notify |delegate_|. 153 const Extension* extension = service->GetExtensionById(extension_id_, true); 154 if (!extension) { 155 delegate_->ExtensionEnableFlowAborted(true); 156 return; 157 } 158 159 service->GrantPermissionsAndEnableExtension(extension); 160 delegate_->ExtensionEnableFlowFinished(); // |delegate_| may delete us. 161 } 162 163 void ExtensionEnableFlow::InstallUIAbort(bool user_initiated) { 164 delegate_->ExtensionEnableFlowAborted(user_initiated); 165 // |delegate_| may delete us. 166 } 167 168 content::WebContents* ExtensionEnableFlow::OpenURL( 169 const content::OpenURLParams& params) { 170 Browser* browser = chrome::FindOrCreateTabbedBrowser( 171 profile_, chrome::GetActiveDesktop()); 172 return browser->OpenURL(params); 173 } 174