pepper_talk_host.cc revision 1320f92c476a1ad9d19dba2a48c72b75566198e9
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  // 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)
85void 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
91ppapi::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
118void 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
129ppapi::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
138PepperTalkHost::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
146PepperTalkHost::~PepperTalkHost() {
147  if (remoting_started_) {
148    content::BrowserThread::PostTask(content::BrowserThread::UI,
149                                     FROM_HERE,
150                                     base::Bind(&StopRemotingOnUIThread));
151  }
152}
153
154int32_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
168int32_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
193int32_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
216int32_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
228void 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
235void PepperTalkHost::OnRequestPermissionCompleted(
236    ppapi::host::ReplyMessageContext reply) {
237  DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
238  host()->SendReply(reply, PpapiPluginMsg_Talk_RequestPermissionReply());
239}
240
241void 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
251void 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