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/notifications/balloon_host.h" 6 7 #include "chrome/browser/chrome_notification_types.h" 8 #include "chrome/browser/extensions/extension_web_contents_observer.h" 9 #include "chrome/browser/notifications/balloon.h" 10 #include "chrome/browser/notifications/balloon_collection_impl.h" 11 #include "chrome/browser/notifications/notification.h" 12 #include "chrome/browser/profiles/profile.h" 13 #include "chrome/browser/renderer_preferences_util.h" 14 #include "chrome/browser/ui/browser.h" 15 #include "chrome/browser/ui/browser_finder.h" 16 #include "chrome/browser/ui/browser_tabstrip.h" 17 #include "chrome/browser/ui/host_desktop.h" 18 #include "chrome/browser/ui/webui/chrome_web_ui_controller_factory.h" 19 #include "chrome/common/extensions/extension_messages.h" 20 #include "chrome/common/render_messages.h" 21 #include "chrome/common/url_constants.h" 22 #include "content/public/browser/navigation_controller.h" 23 #include "content/public/browser/notification_service.h" 24 #include "content/public/browser/notification_source.h" 25 #include "content/public/browser/render_process_host.h" 26 #include "content/public/browser/render_view_host.h" 27 #include "content/public/browser/site_instance.h" 28 #include "content/public/browser/web_contents.h" 29 #include "content/public/common/bindings_policy.h" 30 #include "content/public/common/renderer_preferences.h" 31 #include "extensions/browser/view_type_utils.h" 32 #include "ipc/ipc_message.h" 33 34 using content::SiteInstance; 35 using content::WebContents; 36 37 BalloonHost::BalloonHost(Balloon* balloon) 38 : balloon_(balloon), 39 initialized_(false), 40 should_notify_on_disconnect_(false), 41 enable_web_ui_(false), 42 extension_function_dispatcher_(balloon_->profile(), this) { 43 site_instance_ = SiteInstance::CreateForURL( 44 balloon_->profile(), balloon_->notification().content_url()); 45 } 46 47 void BalloonHost::Shutdown() { 48 NotifyDisconnect(); 49 web_contents_.reset(); 50 site_instance_ = NULL; 51 balloon_ = NULL; // No longer safe to access |balloon_| 52 } 53 54 extensions::WindowController* 55 BalloonHost::GetExtensionWindowController() const { 56 // Notifications don't have a window controller. 57 return NULL; 58 } 59 60 content::WebContents* BalloonHost::GetAssociatedWebContents() const { 61 return NULL; 62 } 63 64 const base::string16& BalloonHost::GetSource() const { 65 return balloon_->notification().display_source(); 66 } 67 68 void BalloonHost::CloseContents(WebContents* source) { 69 if (!balloon_) 70 return; 71 balloon_->CloseByScript(); 72 NotifyDisconnect(); 73 } 74 75 void BalloonHost::HandleMouseDown() { 76 if (balloon_) 77 balloon_->OnClick(); 78 } 79 80 void BalloonHost::ResizeDueToAutoResize(WebContents* source, 81 const gfx::Size& pref_size) { 82 if (balloon_) 83 balloon_->ResizeDueToAutoResize(pref_size); 84 } 85 86 void BalloonHost::AddNewContents(WebContents* source, 87 WebContents* new_contents, 88 WindowOpenDisposition disposition, 89 const gfx::Rect& initial_pos, 90 bool user_gesture, 91 bool* was_blocked) { 92 Browser* browser = chrome::FindLastActiveWithProfile( 93 Profile::FromBrowserContext(new_contents->GetBrowserContext()), 94 chrome::GetActiveDesktop()); 95 if (browser) { 96 chrome::AddWebContents(browser, NULL, new_contents, disposition, 97 initial_pos, user_gesture, was_blocked); 98 } 99 } 100 101 void BalloonHost::RenderViewCreated(content::RenderViewHost* render_view_host) { 102 gfx::Size min_size(BalloonCollectionImpl::min_balloon_width(), 103 BalloonCollectionImpl::min_balloon_height()); 104 gfx::Size max_size(BalloonCollectionImpl::max_balloon_width(), 105 BalloonCollectionImpl::max_balloon_height()); 106 render_view_host->EnableAutoResize(min_size, max_size); 107 108 if (enable_web_ui_) 109 render_view_host->AllowBindings(content::BINDINGS_POLICY_WEB_UI); 110 } 111 112 void BalloonHost::RenderViewReady() { 113 should_notify_on_disconnect_ = true; 114 content::NotificationService::current()->Notify( 115 chrome::NOTIFICATION_NOTIFY_BALLOON_CONNECTED, 116 content::Source<BalloonHost>(this), 117 content::NotificationService::NoDetails()); 118 } 119 120 void BalloonHost::RenderProcessGone(base::TerminationStatus status) { 121 CloseContents(web_contents_.get()); 122 } 123 124 bool BalloonHost::OnMessageReceived(const IPC::Message& message) { 125 bool handled = true; 126 IPC_BEGIN_MESSAGE_MAP(BalloonHost, message) 127 IPC_MESSAGE_HANDLER(ExtensionHostMsg_Request, OnRequest) 128 IPC_MESSAGE_UNHANDLED(handled = false) 129 IPC_END_MESSAGE_MAP() 130 return handled; 131 } 132 133 void BalloonHost::OnRequest(const ExtensionHostMsg_Request_Params& params) { 134 extension_function_dispatcher_.Dispatch(params, 135 web_contents_->GetRenderViewHost()); 136 } 137 138 void BalloonHost::Init() { 139 DCHECK(!web_contents_.get()) << "BalloonViewHost already initialized."; 140 web_contents_.reset(WebContents::Create( 141 WebContents::CreateParams(balloon_->profile(), site_instance_.get()))); 142 extensions::SetViewType( 143 web_contents_.get(), extensions::VIEW_TYPE_NOTIFICATION); 144 web_contents_->SetDelegate(this); 145 extensions::ExtensionWebContentsObserver::CreateForWebContents( 146 web_contents_.get()); 147 Observe(web_contents_.get()); 148 renderer_preferences_util::UpdateFromSystemSettings( 149 web_contents_->GetMutableRendererPrefs(), balloon_->profile()); 150 web_contents_->GetRenderViewHost()->SyncRendererPrefs(); 151 152 web_contents_->GetController().LoadURL( 153 balloon_->notification().content_url(), content::Referrer(), 154 content::PAGE_TRANSITION_LINK, std::string()); 155 156 initialized_ = true; 157 } 158 159 void BalloonHost::EnableWebUI() { 160 DCHECK(!web_contents_.get()) << 161 "EnableWebUI has to be called before a renderer is created."; 162 enable_web_ui_ = true; 163 } 164 165 BalloonHost::~BalloonHost() { 166 } 167 168 void BalloonHost::NotifyDisconnect() { 169 if (!should_notify_on_disconnect_) 170 return; 171 172 should_notify_on_disconnect_ = false; 173 content::NotificationService::current()->Notify( 174 chrome::NOTIFICATION_NOTIFY_BALLOON_DISCONNECTED, 175 content::Source<BalloonHost>(this), 176 content::NotificationService::NoDetails()); 177 } 178 179 bool BalloonHost::IsRenderViewReady() const { 180 return should_notify_on_disconnect_; 181 } 182 183 bool BalloonHost::CanLoadDataURLsInWebUI() const { 184 #if defined(OS_CHROMEOS) 185 // Chrome OS uses data URLs in WebUI BalloonHosts. We normally do not allow 186 // data URLs in WebUI renderers, but normal pages cannot target BalloonHosts, 187 // so this should be safe. 188 return true; 189 #else 190 return false; 191 #endif 192 } 193