1 // Copyright 2019 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/sharing/click_to_call/click_to_call_context_menu_observer.h"
6
7 #include "base/bind.h"
8 #include "base/strings/utf_string_conversions.h"
9 #include "build/build_config.h"
10 #include "chrome/app/chrome_command_ids.h"
11 #include "chrome/browser/renderer_context_menu/render_view_context_menu.h"
12 #include "chrome/browser/sharing/click_to_call/click_to_call_metrics.h"
13 #include "chrome/browser/sharing/click_to_call/click_to_call_ui_controller.h"
14 #include "chrome/browser/sharing/click_to_call/feature.h"
15 #include "chrome/browser/sharing/sharing_constants.h"
16 #include "chrome/grit/generated_resources.h"
17 #include "components/sync_device_info/device_info.h"
18 #include "ui/base/l10n/l10n_util.h"
19 #include "ui/base/models/image_model.h"
20 #include "ui/gfx/color_palette.h"
21 #include "ui/gfx/paint_vector_icon.h"
22
SubMenuDelegate(ClickToCallContextMenuObserver * parent)23 ClickToCallContextMenuObserver::SubMenuDelegate::SubMenuDelegate(
24 ClickToCallContextMenuObserver* parent)
25 : parent_(parent) {}
26
27 ClickToCallContextMenuObserver::SubMenuDelegate::~SubMenuDelegate() = default;
28
IsCommandIdEnabled(int command_id) const29 bool ClickToCallContextMenuObserver::SubMenuDelegate::IsCommandIdEnabled(
30 int command_id) const {
31 // All supported commands are enabled in sub menu.
32 return true;
33 }
34
ExecuteCommand(int command_id,int event_flags)35 void ClickToCallContextMenuObserver::SubMenuDelegate::ExecuteCommand(
36 int command_id,
37 int event_flags) {
38 if (command_id < kSubMenuFirstDeviceCommandId ||
39 command_id > kSubMenuLastDeviceCommandId)
40 return;
41 int device_index = command_id - kSubMenuFirstDeviceCommandId;
42 parent_->SendClickToCallMessage(device_index);
43 }
44
ClickToCallContextMenuObserver(RenderViewContextMenuProxy * proxy)45 ClickToCallContextMenuObserver::ClickToCallContextMenuObserver(
46 RenderViewContextMenuProxy* proxy)
47 : proxy_(proxy),
48 controller_(ClickToCallUiController::GetOrCreateFromWebContents(
49 proxy_->GetWebContents())) {}
50
51 ClickToCallContextMenuObserver::~ClickToCallContextMenuObserver() = default;
52
BuildMenu(const std::string & phone_number,const std::string & selection_text,SharingClickToCallEntryPoint entry_point)53 void ClickToCallContextMenuObserver::BuildMenu(
54 const std::string& phone_number,
55 const std::string& selection_text,
56 SharingClickToCallEntryPoint entry_point) {
57 DCHECK(!phone_number.empty());
58
59 phone_number_ = phone_number;
60 selection_text_ = selection_text;
61 entry_point_ = entry_point;
62 devices_ = controller_->GetDevices();
63 LogSharingDevicesToShow(controller_->GetFeatureMetricsPrefix(),
64 kSharingUiContextMenu, devices_.size());
65 if (devices_.empty())
66 return;
67
68 if (devices_.size() == 1) {
69 #if defined(OS_MAC)
70 proxy_->AddMenuItem(
71 IDC_CONTENT_CONTEXT_SHARING_CLICK_TO_CALL_SINGLE_DEVICE,
72 l10n_util::GetStringFUTF16(
73 IDS_CONTENT_CONTEXT_SHARING_CLICK_TO_CALL_SINGLE_DEVICE,
74 base::UTF8ToUTF16(devices_[0]->client_name())));
75 #else
76 proxy_->AddMenuItemWithIcon(
77 IDC_CONTENT_CONTEXT_SHARING_CLICK_TO_CALL_SINGLE_DEVICE,
78 l10n_util::GetStringFUTF16(
79 IDS_CONTENT_CONTEXT_SHARING_CLICK_TO_CALL_SINGLE_DEVICE,
80 base::UTF8ToUTF16(devices_[0]->client_name())),
81 ui::ImageModel::FromVectorIcon(controller_->GetVectorIcon(),
82 /*color_id=*/-1,
83 ui::SimpleMenuModel::kDefaultIconSize));
84 #endif
85 } else {
86 BuildSubMenu();
87 #if defined(OS_MAC)
88 proxy_->AddSubMenu(
89 IDC_CONTENT_CONTEXT_SHARING_CLICK_TO_CALL_MULTIPLE_DEVICES,
90 l10n_util::GetStringUTF16(
91 IDS_CONTENT_CONTEXT_SHARING_CLICK_TO_CALL_MULTIPLE_DEVICES),
92 sub_menu_model_.get());
93 #else
94 proxy_->AddSubMenuWithStringIdAndIcon(
95 IDC_CONTENT_CONTEXT_SHARING_CLICK_TO_CALL_MULTIPLE_DEVICES,
96 IDS_CONTENT_CONTEXT_SHARING_CLICK_TO_CALL_MULTIPLE_DEVICES,
97 sub_menu_model_.get(),
98 ui::ImageModel::FromVectorIcon(controller_->GetVectorIcon(),
99 /*color_id=*/-1,
100 ui::SimpleMenuModel::kDefaultIconSize));
101 #endif
102 }
103 }
104
BuildSubMenu()105 void ClickToCallContextMenuObserver::BuildSubMenu() {
106 sub_menu_model_ = std::make_unique<ui::SimpleMenuModel>(&sub_menu_delegate_);
107
108 int command_id = kSubMenuFirstDeviceCommandId;
109 for (const auto& device : devices_) {
110 if (command_id > kSubMenuLastDeviceCommandId)
111 break;
112 sub_menu_model_->AddItem(command_id++,
113 base::UTF8ToUTF16(device->client_name()));
114 }
115 }
116
IsCommandIdSupported(int command_id)117 bool ClickToCallContextMenuObserver::IsCommandIdSupported(int command_id) {
118 size_t device_count = devices_.size();
119 if (device_count == 0)
120 return false;
121
122 if (device_count == 1) {
123 return command_id ==
124 IDC_CONTENT_CONTEXT_SHARING_CLICK_TO_CALL_SINGLE_DEVICE;
125 } else {
126 return command_id ==
127 IDC_CONTENT_CONTEXT_SHARING_CLICK_TO_CALL_MULTIPLE_DEVICES;
128 }
129 }
130
IsCommandIdEnabled(int command_id)131 bool ClickToCallContextMenuObserver::IsCommandIdEnabled(int command_id) {
132 // All supported commands are enabled.
133 return true;
134 }
135
ExecuteCommand(int command_id)136 void ClickToCallContextMenuObserver::ExecuteCommand(int command_id) {
137 if (command_id == IDC_CONTENT_CONTEXT_SHARING_CLICK_TO_CALL_SINGLE_DEVICE) {
138 DCHECK_EQ(1u, devices_.size());
139 SendClickToCallMessage(0);
140 }
141 }
142
SendClickToCallMessage(int chosen_device_index)143 void ClickToCallContextMenuObserver::SendClickToCallMessage(
144 int chosen_device_index) {
145 DCHECK(entry_point_);
146 if (size_t{chosen_device_index} >= devices_.size())
147 return;
148
149 LogSharingSelectedIndex(controller_->GetFeatureMetricsPrefix(),
150 kSharingUiContextMenu, chosen_device_index);
151
152 controller_->OnDeviceSelected(phone_number_, *devices_[chosen_device_index],
153 *entry_point_);
154 }
155