pepper_talk_host.cc revision 03b57e008b61dfcb1fbad3aea950ae0e001748b0
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
27namespace chrome {
28
29namespace {
30
31ppapi::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)
84void 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
90ppapi::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
117void 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
128ppapi::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
137PepperTalkHost::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
145PepperTalkHost::~PepperTalkHost() {
146  if (remoting_started_) {
147    content::BrowserThread::PostTask(content::BrowserThread::UI,
148                                     FROM_HERE,
149                                     base::Bind(&StopRemotingOnUIThread));
150  }
151}
152
153int32_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
167int32_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
192int32_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
215int32_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
227void 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
234void PepperTalkHost::OnRequestPermissionCompleted(
235    ppapi::host::ReplyMessageContext reply) {
236  DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
237  host()->SendReply(reply, PpapiPluginMsg_Talk_RequestPermissionReply());
238}
239
240void 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
250void 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