Home | History | Annotate | Download | only in pepper
      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