1 // Copyright 2015 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "components/permissions/bluetooth_chooser_controller.h"
7 #include "base/check_op.h"
8 #include "base/notreached.h"
9 #include "base/ranges/algorithm.h"
10 #include "base/strings/utf_string_conversions.h"
11 #include "components/strings/grit/components_strings.h"
12 #include "ui/base/l10n/l10n_util.h"
14 namespace permissions {
16 BluetoothChooserController::BluetoothChooserController(
17 content::RenderFrameHost* owner,
18 const content::BluetoothChooser::EventHandler& event_handler,
20 : ChooserController(title), event_handler_(event_handler) {}
22 BluetoothChooserController::~BluetoothChooserController() {
24 event_handler_.Run(content::BluetoothChooserEvent::CANCELLED,
29 bool BluetoothChooserController::ShouldShowIconBeforeText() const {
33 bool BluetoothChooserController::ShouldShowReScanButton() const {
37 std::u16string BluetoothChooserController::GetNoOptionsText() const {
38 return l10n_util::GetStringUTF16(
39 IDS_BLUETOOTH_DEVICE_CHOOSER_NO_DEVICES_FOUND_PROMPT);
42 std::u16string BluetoothChooserController::GetOkButtonLabel() const {
43 return l10n_util::GetStringUTF16(
44 IDS_BLUETOOTH_DEVICE_CHOOSER_PAIR_BUTTON_TEXT);
47 std::pair<std::u16string, std::u16string>
48 BluetoothChooserController::GetThrobberLabelAndTooltip() const {
50 l10n_util::GetStringUTF16(IDS_BLUETOOTH_DEVICE_CHOOSER_SCANNING_LABEL),
51 l10n_util::GetStringUTF16(
52 IDS_BLUETOOTH_DEVICE_CHOOSER_SCANNING_LABEL_TOOLTIP)};
55 size_t BluetoothChooserController::NumOptions() const {
56 return devices_.size();
59 int BluetoothChooserController::GetSignalStrengthLevel(size_t index) const {
60 return devices_[index].signal_strength_level;
63 bool BluetoothChooserController::IsConnected(size_t index) const {
64 return devices_[index].is_connected;
67 bool BluetoothChooserController::IsPaired(size_t index) const {
68 return devices_[index].is_paired;
71 std::u16string BluetoothChooserController::GetOption(size_t index) const {
72 DCHECK_LT(index, devices_.size());
73 const std::string& device_id = devices_[index].id;
74 const auto& device_name_it = device_id_to_name_map_.find(device_id);
75 DCHECK(device_name_it != device_id_to_name_map_.end());
76 const auto& it = device_name_counts_.find(device_name_it->second);
77 DCHECK(it != device_name_counts_.end());
78 return it->second == 1
79 ? device_name_it->second
80 : l10n_util::GetStringFUTF16(
81 IDS_DEVICE_CHOOSER_DEVICE_NAME_WITH_ID,
82 device_name_it->second, base::UTF8ToUTF16(device_id));
85 void BluetoothChooserController::RefreshOptions() {
86 if (event_handler_.is_null())
89 event_handler_.Run(content::BluetoothChooserEvent::RESCAN, std::string());
92 void BluetoothChooserController::Select(const std::vector<size_t>& indices) {
93 DCHECK_EQ(1u, indices.size());
94 size_t index = indices[0];
95 if (event_handler_.is_null()) {
98 DCHECK_LT(index, devices_.size());
99 event_handler_.Run(content::BluetoothChooserEvent::SELECTED,
101 event_handler_.Reset();
104 void BluetoothChooserController::Cancel() {
105 if (event_handler_.is_null())
107 event_handler_.Run(content::BluetoothChooserEvent::CANCELLED, std::string());
108 event_handler_.Reset();
111 void BluetoothChooserController::Close() {
112 if (event_handler_.is_null())
114 event_handler_.Run(content::BluetoothChooserEvent::CANCELLED, std::string());
115 event_handler_.Reset();
118 void BluetoothChooserController::OnAdapterPresenceChanged(
119 content::BluetoothChooser::AdapterPresence presence) {
122 case content::BluetoothChooser::AdapterPresence::ABSENT:
125 case content::BluetoothChooser::AdapterPresence::POWERED_OFF:
127 view()->OnAdapterEnabledChanged(
128 false /* Bluetooth adapter is turned off */);
131 case content::BluetoothChooser::AdapterPresence::POWERED_ON:
133 view()->OnAdapterEnabledChanged(
134 true /* Bluetooth adapter is turned on */);
137 case content::BluetoothChooser::AdapterPresence::UNAUTHORIZED:
139 view()->OnAdapterAuthorizationChanged(/*authorized=*/false);
145 void BluetoothChooserController::OnDiscoveryStateChanged(
146 content::BluetoothChooser::DiscoveryState state) {
148 case content::BluetoothChooser::DiscoveryState::DISCOVERING:
150 view()->OnRefreshStateChanged(
151 true /* Refreshing options is in progress */);
154 case content::BluetoothChooser::DiscoveryState::IDLE:
155 case content::BluetoothChooser::DiscoveryState::FAILED_TO_START:
157 view()->OnRefreshStateChanged(
158 false /* Refreshing options is complete */);
164 void BluetoothChooserController::AddOrUpdateDevice(
165 const std::string& device_id,
166 bool should_update_name,
167 const std::u16string& device_name,
168 bool is_gatt_connected,
170 int signal_strength_level) {
171 auto name_it = device_id_to_name_map_.find(device_id);
172 if (name_it != device_id_to_name_map_.end()) {
173 if (should_update_name) {
174 std::u16string previous_device_name = name_it->second;
175 name_it->second = device_name;
177 const auto& it = device_name_counts_.find(previous_device_name);
178 DCHECK(it != device_name_counts_.end());
179 DCHECK_GT(it->second, 0);
181 if (--(it->second) == 0)
182 device_name_counts_.erase(it);
184 ++device_name_counts_[device_name];
188 base::ranges::find(devices_, device_id, &BluetoothDeviceInfo::id);
190 DCHECK(device_it != devices_.end());
191 // When Bluetooth device scanning stops, the |signal_strength_level|
192 // is -1, and in this case, should still use the previously stored
193 // signal strength level value.
194 if (signal_strength_level != -1)
195 device_it->signal_strength_level = signal_strength_level;
196 device_it->is_connected = is_gatt_connected;
197 device_it->is_paired = is_paired;
199 view()->OnOptionUpdated(device_it - devices_.begin());
204 {device_id, signal_strength_level, is_gatt_connected, is_paired});
205 device_id_to_name_map_.insert({device_id, device_name});
206 ++device_name_counts_[device_name];
208 view()->OnOptionAdded(devices_.size() - 1);
211 void BluetoothChooserController::RemoveDevice(const std::string& device_id) {
212 const auto& name_it = device_id_to_name_map_.find(device_id);
213 if (name_it == device_id_to_name_map_.end())
217 base::ranges::find(devices_, device_id, &BluetoothDeviceInfo::id);
219 if (device_it != devices_.end()) {
220 size_t index = device_it - devices_.begin();
221 devices_.erase(device_it);
223 const auto& it = device_name_counts_.find(name_it->second);
224 DCHECK(it != device_name_counts_.end());
225 DCHECK_GT(it->second, 0);
227 if (--(it->second) == 0)
228 device_name_counts_.erase(it);
230 device_id_to_name_map_.erase(name_it);
233 view()->OnOptionRemoved(index);
237 void BluetoothChooserController::ResetEventHandler() {
238 event_handler_.Reset();
241 base::WeakPtr<BluetoothChooserController>
242 BluetoothChooserController::GetWeakPtr() {
243 return weak_factory_.GetWeakPtr();
246 void BluetoothChooserController::ClearAllDevices() {
248 device_id_to_name_map_.clear();
249 device_name_counts_.clear();
252 } // namespace permissions