pepper_talk_host.cc revision d0247b1b59f9c528cb6df88b4f2b9afaf80d181e
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_view_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
27namespace chrome {
28
29namespace {
30
31ppapi::host::ReplyMessageContext GetPermissionOnUIThread(
32    PP_TalkPermission permission,
33    int render_process_id,
34    int render_view_id,
35    ppapi::host::ReplyMessageContext reply) {
36  DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
37  reply.params.set_result(0);
38
39  content::RenderViewHost* render_view_host =
40      content::RenderViewHost::FromID(render_process_id, render_view_id);
41  if (!render_view_host)
42    return reply;  // RVH destroyed while task was pending.
43
44#if defined(USE_ASH)
45  string16 title;
46  string16 message;
47
48  switch (permission) {
49    case PP_TALKPERMISSION_SCREENCAST:
50      title = l10n_util::GetStringUTF16(IDS_GTALK_SCREEN_SHARE_DIALOG_TITLE);
51      message = l10n_util::GetStringUTF16(
52          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(
57          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 = l10n_util::GetStringUTF16(
62          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 = ash::Shell::GetContainer(
72      ash::Shell::GetTargetRootWindow(),
73      ash::internal::kShellWindowId_SystemModalContainer);
74  reply.params.set_result(static_cast<int32_t>(
75      chrome::ShowMessageBox(parent, title, message,
76                             chrome::MESSAGE_BOX_TYPE_QUESTION) ==
77      chrome::MESSAGE_BOX_RESULT_YES));
78#else
79  NOTIMPLEMENTED();
80#endif
81  return reply;
82}
83
84void OnTerminateRemotingEventOnUIThread(const base::Closure& stop_callback) {
85  content::BrowserThread::PostTask(content::BrowserThread::IO, FROM_HERE,
86                                   stop_callback);
87}
88
89ppapi::host::ReplyMessageContext StartRemotingOnUIThread(
90    const base::Closure& stop_callback,
91    int render_process_id,
92    int render_view_id,
93    ppapi::host::ReplyMessageContext reply) {
94  DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
95  content::RenderViewHost* render_view_host =
96      content::RenderViewHost::FromID(render_process_id, render_view_id);
97  if (!render_view_host) {
98    reply.params.set_result(PP_ERROR_FAILED);
99    return reply;  // RVH destroyed while task was pending.
100  }
101
102#if defined(USE_ASH) && defined(OS_CHROMEOS)
103  base::Closure stop_callback_ui_thread = base::Bind(
104      &OnTerminateRemotingEventOnUIThread,
105      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      weak_factory_(this),
142      browser_ppapi_host_(host),
143      remoting_started_(false) {
144}
145
146PepperTalkHost::~PepperTalkHost() {
147  if (remoting_started_) {
148    content::BrowserThread::PostTask(
149        content::BrowserThread::UI, FROM_HERE,
150        base::Bind(&StopRemotingOnUIThread));
151  }
152}
153
154int32_t PepperTalkHost::OnResourceMessageReceived(
155    const IPC::Message& msg,
156    ppapi::host::HostMessageContext* context) {
157  IPC_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  IPC_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_view_id = 0;
177  browser_ppapi_host_->GetRenderViewIDsForInstance(
178      pp_instance(), &render_process_id, &render_view_id);
179
180  content::BrowserThread::PostTaskAndReplyWithResult(
181      content::BrowserThread::UI, FROM_HERE,
182      base::Bind(&GetPermissionOnUIThread, permission, render_process_id,
183                 render_view_id, context->MakeReplyMessageContext()),
184      base::Bind(&PepperTalkHost::OnRequestPermissionCompleted,
185                 weak_factory_.GetWeakPtr()));
186  return PP_OK_COMPLETIONPENDING;
187}
188
189int32_t PepperTalkHost::OnStartRemoting(
190    ppapi::host::HostMessageContext* context) {
191  int render_process_id = 0;
192  int render_view_id = 0;
193  browser_ppapi_host_->GetRenderViewIDsForInstance(
194      pp_instance(), &render_process_id, &render_view_id);
195
196  base::Closure remoting_stop_callback = base::Bind(
197      &PepperTalkHost::OnRemotingStopEvent,
198      weak_factory_.GetWeakPtr());
199
200  content::BrowserThread::PostTaskAndReplyWithResult(
201      content::BrowserThread::UI, FROM_HERE,
202      base::Bind(&StartRemotingOnUIThread, remoting_stop_callback,
203                 render_process_id, render_view_id,
204                 context->MakeReplyMessageContext()),
205      base::Bind(&PepperTalkHost::OnStartRemotingCompleted,
206                 weak_factory_.GetWeakPtr()));
207  return PP_OK_COMPLETIONPENDING;
208}
209
210int32_t PepperTalkHost::OnStopRemoting(
211    ppapi::host::HostMessageContext* context) {
212  content::BrowserThread::PostTaskAndReplyWithResult(
213      content::BrowserThread::UI, FROM_HERE,
214      base::Bind(&StopRemotingOnUIThreadWithResult,
215                 context->MakeReplyMessageContext()),
216      base::Bind(&PepperTalkHost::OnStopRemotingCompleted,
217                 weak_factory_.GetWeakPtr()));
218  return PP_OK_COMPLETIONPENDING;
219}
220
221void PepperTalkHost::OnRemotingStopEvent() {
222  DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
223  remoting_started_ = false;
224  host()->SendUnsolicitedReply(
225      pp_resource(), PpapiPluginMsg_Talk_NotifyEvent(PP_TALKEVENT_TERMINATE));
226}
227
228void PepperTalkHost::OnRequestPermissionCompleted(
229    ppapi::host::ReplyMessageContext reply) {
230  DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
231  host()->SendReply(reply, PpapiPluginMsg_Talk_RequestPermissionReply());
232}
233
234void PepperTalkHost::OnStartRemotingCompleted(
235    ppapi::host::ReplyMessageContext reply) {
236  DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
237  // Remember to hide remoting UI when resource is deleted.
238  if (reply.params.result() == PP_OK)
239    remoting_started_ = true;
240
241  host()->SendReply(reply, PpapiPluginMsg_Talk_StartRemotingReply());
242}
243
244void PepperTalkHost::OnStopRemotingCompleted(
245    ppapi::host::ReplyMessageContext reply) {
246  DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
247  remoting_started_ = false;
248  host()->SendReply(reply, PpapiPluginMsg_Talk_StopRemotingReply());
249}
250
251}  // namespace chrome
252