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/renderer_host/pepper/pepper_talk_host.h" 6 7 #include "base/bind.h" 8 #include "chrome/grit/generated_resources.h" 9 #include "content/public/browser/browser_ppapi_host.h" 10 #include "content/public/browser/browser_thread.h" 11 #include "content/public/browser/render_frame_host.h" 12 #include "ppapi/c/pp_errors.h" 13 #include "ppapi/host/dispatch_host_message.h" 14 #include "ppapi/host/host_message_context.h" 15 #include "ppapi/host/ppapi_host.h" 16 #include "ppapi/proxy/ppapi_messages.h" 17 #include "ui/base/l10n/l10n_util.h" 18 19 #if defined(USE_ASH) 20 #include "ash/shell.h" 21 #include "ash/shell_window_ids.h" 22 #include "ash/system/tray/system_tray_notifier.h" 23 #include "chrome/browser/ui/simple_message_box.h" 24 #include "ui/aura/window.h" 25 #endif 26 27 namespace chrome { 28 29 namespace { 30 31 ppapi::host::ReplyMessageContext GetPermissionOnUIThread( 32 PP_TalkPermission permission, 33 int render_process_id, 34 int render_frame_id, 35 ppapi::host::ReplyMessageContext reply) { 36 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); 37 reply.params.set_result(0); 38 39 content::RenderFrameHost* render_frame_host = 40 content::RenderFrameHost::FromID(render_process_id, render_frame_id); 41 if (!render_frame_host) 42 return reply; // RFH destroyed while task was pending. 43 44 // crbug.com/381398, crbug.com/413906 for !USE_ATHENA 45 #if defined(USE_ASH) && !defined(USE_ATHENA) 46 base::string16 title; 47 base::string16 message; 48 49 switch (permission) { 50 case PP_TALKPERMISSION_SCREENCAST: 51 title = l10n_util::GetStringUTF16(IDS_GTALK_SCREEN_SHARE_DIALOG_TITLE); 52 message = 53 l10n_util::GetStringUTF16(IDS_GTALK_SCREEN_SHARE_DIALOG_MESSAGE); 54 break; 55 case PP_TALKPERMISSION_REMOTING: 56 title = l10n_util::GetStringUTF16(IDS_GTALK_REMOTING_DIALOG_TITLE); 57 message = l10n_util::GetStringUTF16(IDS_GTALK_REMOTING_DIALOG_MESSAGE); 58 break; 59 case PP_TALKPERMISSION_REMOTING_CONTINUE: 60 title = l10n_util::GetStringUTF16(IDS_GTALK_REMOTING_DIALOG_TITLE); 61 message = 62 l10n_util::GetStringUTF16(IDS_GTALK_REMOTING_CONTINUE_DIALOG_MESSAGE); 63 break; 64 default: 65 NOTREACHED(); 66 return reply; 67 } 68 69 // TODO(brettw). We should not be grabbing the active toplevel window, we 70 // should use the toplevel window associated with the render view. 71 aura::Window* parent = 72 ash::Shell::GetContainer(ash::Shell::GetTargetRootWindow(), 73 ash::kShellWindowId_SystemModalContainer); 74 reply.params.set_result(static_cast<int32_t>( 75 chrome::ShowMessageBox( 76 parent, title, message, chrome::MESSAGE_BOX_TYPE_QUESTION) == 77 chrome::MESSAGE_BOX_RESULT_YES)); 78 #else 79 NOTIMPLEMENTED(); 80 #endif 81 return reply; 82 } 83 84 #if defined(USE_ASH) && defined(OS_CHROMEOS) && !defined(USE_ATHENA) 85 void OnTerminateRemotingEventOnUIThread(const base::Closure& stop_callback) { 86 content::BrowserThread::PostTask( 87 content::BrowserThread::IO, FROM_HERE, stop_callback); 88 } 89 #endif // defined(USE_ASH) && defined(OS_CHROMEOS) 90 91 ppapi::host::ReplyMessageContext StartRemotingOnUIThread( 92 const base::Closure& stop_callback, 93 int render_process_id, 94 int render_frame_id, 95 ppapi::host::ReplyMessageContext reply) { 96 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); 97 content::RenderFrameHost* render_frame_host = 98 content::RenderFrameHost::FromID(render_process_id, render_frame_id); 99 if (!render_frame_host) { 100 reply.params.set_result(PP_ERROR_FAILED); 101 return reply; // RFH destroyed while task was pending. 102 } 103 104 #if defined(USE_ASH) && defined(OS_CHROMEOS) && !defined(USE_ATHENA) 105 base::Closure stop_callback_ui_thread = 106 base::Bind(&OnTerminateRemotingEventOnUIThread, stop_callback); 107 108 ash::Shell::GetInstance()->system_tray_notifier()->NotifyScreenShareStart( 109 stop_callback_ui_thread, base::string16()); 110 reply.params.set_result(PP_OK); 111 #else 112 NOTIMPLEMENTED(); 113 reply.params.set_result(PP_ERROR_NOTSUPPORTED); 114 #endif 115 return reply; 116 } 117 118 void StopRemotingOnUIThread() { 119 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); 120 #if defined(USE_ASH) && defined(OS_CHROMEOS) && !defined(USE_ATHENA) 121 if (ash::Shell::GetInstance()) { 122 ash::Shell::GetInstance()->system_tray_notifier()->NotifyScreenShareStop(); 123 } 124 #else 125 NOTIMPLEMENTED(); 126 #endif 127 } 128 129 ppapi::host::ReplyMessageContext StopRemotingOnUIThreadWithResult( 130 ppapi::host::ReplyMessageContext reply) { 131 reply.params.set_result(PP_OK); 132 StopRemotingOnUIThread(); 133 return reply; 134 } 135 136 } // namespace 137 138 PepperTalkHost::PepperTalkHost(content::BrowserPpapiHost* host, 139 PP_Instance instance, 140 PP_Resource resource) 141 : ppapi::host::ResourceHost(host->GetPpapiHost(), instance, resource), 142 browser_ppapi_host_(host), 143 remoting_started_(false), 144 weak_factory_(this) {} 145 146 PepperTalkHost::~PepperTalkHost() { 147 if (remoting_started_) { 148 content::BrowserThread::PostTask(content::BrowserThread::UI, 149 FROM_HERE, 150 base::Bind(&StopRemotingOnUIThread)); 151 } 152 } 153 154 int32_t PepperTalkHost::OnResourceMessageReceived( 155 const IPC::Message& msg, 156 ppapi::host::HostMessageContext* context) { 157 PPAPI_BEGIN_MESSAGE_MAP(PepperTalkHost, msg) 158 PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_Talk_RequestPermission, 159 OnRequestPermission) 160 PPAPI_DISPATCH_HOST_RESOURCE_CALL_0(PpapiHostMsg_Talk_StartRemoting, 161 OnStartRemoting) 162 PPAPI_DISPATCH_HOST_RESOURCE_CALL_0(PpapiHostMsg_Talk_StopRemoting, 163 OnStopRemoting) 164 PPAPI_END_MESSAGE_MAP() 165 return PP_ERROR_FAILED; 166 } 167 168 int32_t PepperTalkHost::OnRequestPermission( 169 ppapi::host::HostMessageContext* context, 170 PP_TalkPermission permission) { 171 if (permission < PP_TALKPERMISSION_SCREENCAST || 172 permission >= PP_TALKPERMISSION_NUM_PERMISSIONS) 173 return PP_ERROR_BADARGUMENT; 174 175 int render_process_id = 0; 176 int render_frame_id = 0; 177 browser_ppapi_host_->GetRenderFrameIDsForInstance( 178 pp_instance(), &render_process_id, &render_frame_id); 179 180 content::BrowserThread::PostTaskAndReplyWithResult( 181 content::BrowserThread::UI, 182 FROM_HERE, 183 base::Bind(&GetPermissionOnUIThread, 184 permission, 185 render_process_id, 186 render_frame_id, 187 context->MakeReplyMessageContext()), 188 base::Bind(&PepperTalkHost::OnRequestPermissionCompleted, 189 weak_factory_.GetWeakPtr())); 190 return PP_OK_COMPLETIONPENDING; 191 } 192 193 int32_t PepperTalkHost::OnStartRemoting( 194 ppapi::host::HostMessageContext* context) { 195 int render_process_id = 0; 196 int render_frame_id = 0; 197 browser_ppapi_host_->GetRenderFrameIDsForInstance( 198 pp_instance(), &render_process_id, &render_frame_id); 199 200 base::Closure remoting_stop_callback = base::Bind( 201 &PepperTalkHost::OnRemotingStopEvent, weak_factory_.GetWeakPtr()); 202 203 content::BrowserThread::PostTaskAndReplyWithResult( 204 content::BrowserThread::UI, 205 FROM_HERE, 206 base::Bind(&StartRemotingOnUIThread, 207 remoting_stop_callback, 208 render_process_id, 209 render_frame_id, 210 context->MakeReplyMessageContext()), 211 base::Bind(&PepperTalkHost::OnStartRemotingCompleted, 212 weak_factory_.GetWeakPtr())); 213 return PP_OK_COMPLETIONPENDING; 214 } 215 216 int32_t PepperTalkHost::OnStopRemoting( 217 ppapi::host::HostMessageContext* context) { 218 content::BrowserThread::PostTaskAndReplyWithResult( 219 content::BrowserThread::UI, 220 FROM_HERE, 221 base::Bind(&StopRemotingOnUIThreadWithResult, 222 context->MakeReplyMessageContext()), 223 base::Bind(&PepperTalkHost::OnStopRemotingCompleted, 224 weak_factory_.GetWeakPtr())); 225 return PP_OK_COMPLETIONPENDING; 226 } 227 228 void PepperTalkHost::OnRemotingStopEvent() { 229 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO)); 230 remoting_started_ = false; 231 host()->SendUnsolicitedReply( 232 pp_resource(), PpapiPluginMsg_Talk_NotifyEvent(PP_TALKEVENT_TERMINATE)); 233 } 234 235 void PepperTalkHost::OnRequestPermissionCompleted( 236 ppapi::host::ReplyMessageContext reply) { 237 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO)); 238 host()->SendReply(reply, PpapiPluginMsg_Talk_RequestPermissionReply()); 239 } 240 241 void PepperTalkHost::OnStartRemotingCompleted( 242 ppapi::host::ReplyMessageContext reply) { 243 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO)); 244 // Remember to hide remoting UI when resource is deleted. 245 if (reply.params.result() == PP_OK) 246 remoting_started_ = true; 247 248 host()->SendReply(reply, PpapiPluginMsg_Talk_StartRemotingReply()); 249 } 250 251 void PepperTalkHost::OnStopRemotingCompleted( 252 ppapi::host::ReplyMessageContext reply) { 253 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO)); 254 remoting_started_ = false; 255 host()->SendReply(reply, PpapiPluginMsg_Talk_StopRemotingReply()); 256 } 257 258 } // namespace chrome 259