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