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