1 // Copyright 2014 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/apps/chrome_app_delegate.h" 6 7 #include "base/memory/scoped_ptr.h" 8 #include "base/strings/stringprintf.h" 9 #include "chrome/browser/app_mode/app_mode_utils.h" 10 #include "chrome/browser/apps/scoped_keep_alive.h" 11 #include "chrome/browser/chrome_notification_types.h" 12 #include "chrome/browser/extensions/chrome_extension_web_contents_observer.h" 13 #include "chrome/browser/favicon/favicon_tab_helper.h" 14 #include "chrome/browser/file_select_helper.h" 15 #include "chrome/browser/media/media_capture_devices_dispatcher.h" 16 #include "chrome/browser/platform_util.h" 17 #include "chrome/browser/profiles/profile.h" 18 #include "chrome/browser/shell_integration.h" 19 #include "chrome/browser/ui/browser.h" 20 #include "chrome/browser/ui/browser_dialogs.h" 21 #include "chrome/browser/ui/browser_tabstrip.h" 22 #include "chrome/browser/ui/browser_window.h" 23 #include "chrome/browser/ui/scoped_tabbed_browser_displayer.h" 24 #include "chrome/browser/ui/web_contents_sizer.h" 25 #include "chrome/browser/ui/zoom/zoom_controller.h" 26 #include "chrome/common/extensions/chrome_extension_messages.h" 27 #include "content/public/browser/browser_context.h" 28 #include "content/public/browser/notification_service.h" 29 #include "content/public/browser/render_view_host.h" 30 #include "content/public/browser/web_contents.h" 31 #include "content/public/browser/web_contents_delegate.h" 32 #include "extensions/common/constants.h" 33 34 #if defined(USE_ASH) 35 #include "ash/shelf/shelf_constants.h" 36 #endif 37 38 #if defined(ENABLE_PRINTING) 39 #if defined(ENABLE_FULL_PRINTING) 40 #include "chrome/browser/printing/print_preview_message_handler.h" 41 #include "chrome/browser/printing/print_view_manager.h" 42 #else 43 #include "chrome/browser/printing/print_view_manager_basic.h" 44 #endif // defined(ENABLE_FULL_PRINTING) 45 #endif // defined(ENABLE_PRINTING) 46 47 namespace { 48 49 bool disable_external_open_for_testing_ = false; 50 51 // Opens a URL with Chromium (not external browser) with the right profile. 52 content::WebContents* OpenURLFromTabInternal( 53 content::BrowserContext* context, 54 const content::OpenURLParams& params) { 55 // Force all links to open in a new tab, even if they were trying to open a 56 // window. 57 chrome::NavigateParams new_tab_params( 58 static_cast<Browser*>(NULL), params.url, params.transition); 59 if (params.disposition == NEW_BACKGROUND_TAB) { 60 new_tab_params.disposition = NEW_BACKGROUND_TAB; 61 } else { 62 new_tab_params.disposition = NEW_FOREGROUND_TAB; 63 new_tab_params.window_action = chrome::NavigateParams::SHOW_WINDOW; 64 } 65 66 new_tab_params.initiating_profile = Profile::FromBrowserContext(context); 67 chrome::Navigate(&new_tab_params); 68 69 return new_tab_params.target_contents; 70 } 71 72 // Helper class that opens a URL based on if this browser instance is the 73 // default system browser. If it is the default, open the URL directly instead 74 // of asking the system to open it. 75 class OpenURLFromTabBasedOnBrowserDefault 76 : public ShellIntegration::DefaultWebClientObserver { 77 public: 78 OpenURLFromTabBasedOnBrowserDefault(scoped_ptr<content::WebContents> source, 79 const content::OpenURLParams& params) 80 : source_(source.Pass()), params_(params) {} 81 82 // Opens a URL when called with the result of if this is the default system 83 // browser or not. 84 virtual void SetDefaultWebClientUIState( 85 ShellIntegration::DefaultWebClientUIState state) OVERRIDE { 86 Profile* profile = 87 Profile::FromBrowserContext(source_->GetBrowserContext()); 88 DCHECK(profile); 89 if (!profile) 90 return; 91 switch (state) { 92 case ShellIntegration::STATE_PROCESSING: 93 break; 94 case ShellIntegration::STATE_IS_DEFAULT: 95 OpenURLFromTabInternal(profile, params_); 96 break; 97 case ShellIntegration::STATE_NOT_DEFAULT: 98 case ShellIntegration::STATE_UNKNOWN: 99 platform_util::OpenExternal(profile, params_.url); 100 break; 101 } 102 } 103 104 virtual bool IsOwnedByWorker() OVERRIDE { return true; } 105 106 private: 107 scoped_ptr<content::WebContents> source_; 108 const content::OpenURLParams params_; 109 }; 110 111 } // namespace 112 113 class ChromeAppDelegate::NewWindowContentsDelegate 114 : public content::WebContentsDelegate { 115 public: 116 NewWindowContentsDelegate() {} 117 virtual ~NewWindowContentsDelegate() {} 118 119 virtual content::WebContents* OpenURLFromTab( 120 content::WebContents* source, 121 const content::OpenURLParams& params) OVERRIDE; 122 123 private: 124 DISALLOW_COPY_AND_ASSIGN(NewWindowContentsDelegate); 125 }; 126 127 content::WebContents* 128 ChromeAppDelegate::NewWindowContentsDelegate::OpenURLFromTab( 129 content::WebContents* source, 130 const content::OpenURLParams& params) { 131 if (source) { 132 // This NewWindowContentsDelegate was given ownership of the incoming 133 // WebContents by being assigned as its delegate within 134 // ChromeAppDelegate::AddNewContents, but this is the first time 135 // NewWindowContentsDelegate actually sees the WebContents. 136 // Here it is captured for deletion. 137 scoped_ptr<content::WebContents> owned_source(source); 138 scoped_refptr<ShellIntegration::DefaultWebClientWorker> 139 check_if_default_browser_worker = 140 new ShellIntegration::DefaultBrowserWorker( 141 new OpenURLFromTabBasedOnBrowserDefault(owned_source.Pass(), 142 params)); 143 // Object lifetime notes: The OpenURLFromTabBasedOnBrowserDefault is owned 144 // by check_if_default_browser_worker. StartCheckIsDefault() takes lifetime 145 // ownership of check_if_default_browser_worker and will clean up after 146 // the asynchronous tasks. 147 check_if_default_browser_worker->StartCheckIsDefault(); 148 } 149 return NULL; 150 } 151 152 ChromeAppDelegate::ChromeAppDelegate(scoped_ptr<ScopedKeepAlive> keep_alive) 153 : keep_alive_(keep_alive.Pass()), 154 new_window_contents_delegate_(new NewWindowContentsDelegate()) { 155 registrar_.Add(this, 156 chrome::NOTIFICATION_APP_TERMINATING, 157 content::NotificationService::AllSources()); 158 } 159 160 ChromeAppDelegate::~ChromeAppDelegate() { 161 // Unregister now to prevent getting notified if |keep_alive_| is the last. 162 terminating_callback_.Reset(); 163 } 164 165 void ChromeAppDelegate::DisableExternalOpenForTesting() { 166 disable_external_open_for_testing_ = true; 167 } 168 169 void ChromeAppDelegate::InitWebContents(content::WebContents* web_contents) { 170 FaviconTabHelper::CreateForWebContents(web_contents); 171 172 #if defined(ENABLE_PRINTING) 173 #if defined(ENABLE_FULL_PRINTING) 174 printing::PrintViewManager::CreateForWebContents(web_contents); 175 printing::PrintPreviewMessageHandler::CreateForWebContents(web_contents); 176 #else 177 printing::PrintViewManagerBasic::CreateForWebContents(web_contents); 178 #endif // defined(ENABLE_FULL_PRINTING) 179 #endif // defined(ENABLE_PRINTING) 180 extensions::ChromeExtensionWebContentsObserver::CreateForWebContents( 181 web_contents); 182 183 // Kiosk app supports zooming. 184 if (chrome::IsRunningInForcedAppMode()) 185 ZoomController::CreateForWebContents(web_contents); 186 } 187 188 void ChromeAppDelegate::ResizeWebContents(content::WebContents* web_contents, 189 const gfx::Size& size) { 190 ::ResizeWebContents(web_contents, size); 191 } 192 193 content::WebContents* ChromeAppDelegate::OpenURLFromTab( 194 content::BrowserContext* context, 195 content::WebContents* source, 196 const content::OpenURLParams& params) { 197 return OpenURLFromTabInternal(context, params); 198 } 199 200 void ChromeAppDelegate::AddNewContents(content::BrowserContext* context, 201 content::WebContents* new_contents, 202 WindowOpenDisposition disposition, 203 const gfx::Rect& initial_pos, 204 bool user_gesture, 205 bool* was_blocked) { 206 if (!disable_external_open_for_testing_) { 207 // We don't really want to open a window for |new_contents|, but we need to 208 // capture its intended navigation. Here we give ownership to the 209 // NewWindowContentsDelegate, which will dispose of the contents once 210 // a navigation is captured. 211 new_contents->SetDelegate(new_window_contents_delegate_.get()); 212 return; 213 } 214 chrome::ScopedTabbedBrowserDisplayer displayer( 215 Profile::FromBrowserContext(context), chrome::GetActiveDesktop()); 216 // Force all links to open in a new tab, even if they were trying to open a 217 // new window. 218 disposition = 219 disposition == NEW_BACKGROUND_TAB ? disposition : NEW_FOREGROUND_TAB; 220 chrome::AddWebContents(displayer.browser(), 221 NULL, 222 new_contents, 223 disposition, 224 initial_pos, 225 user_gesture, 226 was_blocked); 227 } 228 229 content::ColorChooser* ChromeAppDelegate::ShowColorChooser( 230 content::WebContents* web_contents, 231 SkColor initial_color) { 232 return chrome::ShowColorChooser(web_contents, initial_color); 233 } 234 235 void ChromeAppDelegate::RunFileChooser( 236 content::WebContents* tab, 237 const content::FileChooserParams& params) { 238 FileSelectHelper::RunFileChooser(tab, params); 239 } 240 241 void ChromeAppDelegate::RequestMediaAccessPermission( 242 content::WebContents* web_contents, 243 const content::MediaStreamRequest& request, 244 const content::MediaResponseCallback& callback, 245 const extensions::Extension* extension) { 246 MediaCaptureDevicesDispatcher::GetInstance()->ProcessMediaAccessRequest( 247 web_contents, request, callback, extension); 248 } 249 250 bool ChromeAppDelegate::CheckMediaAccessPermission( 251 content::WebContents* web_contents, 252 const GURL& security_origin, 253 content::MediaStreamType type, 254 const extensions::Extension* extension) { 255 return MediaCaptureDevicesDispatcher::GetInstance() 256 ->CheckMediaAccessPermission( 257 web_contents, security_origin, type, extension); 258 } 259 260 int ChromeAppDelegate::PreferredIconSize() { 261 #if defined(USE_ASH) 262 return ash::kShelfSize; 263 #else 264 return extension_misc::EXTENSION_ICON_SMALL; 265 #endif 266 } 267 268 void ChromeAppDelegate::SetWebContentsBlocked( 269 content::WebContents* web_contents, 270 bool blocked) { 271 // RenderViewHost may be NULL during shutdown. 272 content::RenderViewHost* host = web_contents->GetRenderViewHost(); 273 if (host) { 274 host->Send(new ChromeViewMsg_SetVisuallyDeemphasized(host->GetRoutingID(), 275 blocked)); 276 } 277 } 278 279 bool ChromeAppDelegate::IsWebContentsVisible( 280 content::WebContents* web_contents) { 281 return platform_util::IsVisible(web_contents->GetNativeView()); 282 } 283 284 void ChromeAppDelegate::SetTerminatingCallback(const base::Closure& callback) { 285 terminating_callback_ = callback; 286 } 287 288 void ChromeAppDelegate::Observe(int type, 289 const content::NotificationSource& source, 290 const content::NotificationDetails& details) { 291 switch (type) { 292 case chrome::NOTIFICATION_APP_TERMINATING: 293 if (!terminating_callback_.is_null()) 294 terminating_callback_.Run(); 295 break; 296 default: 297 NOTREACHED() << "Received unexpected notification"; 298 } 299 } 300