bluetooth_chooser_controller.cc 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277
  1. // Copyright 2015 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. #include "components/permissions/bluetooth_chooser_controller.h"
  5. #include <algorithm>
  6. #include "base/check_op.h"
  7. #include "base/debug/dump_without_crashing.h"
  8. #include "base/metrics/histogram_macros.h"
  9. #include "base/notreached.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"
  13. namespace permissions {
  14. namespace {
  15. void RecordInteractionWithChooser(bool has_null_handler) {
  16. UMA_HISTOGRAM_BOOLEAN("Bluetooth.Web.ChooserInteraction", has_null_handler);
  17. }
  18. } // namespace
  19. BluetoothChooserController::BluetoothChooserController(
  20. content::RenderFrameHost* owner,
  21. const content::BluetoothChooser::EventHandler& event_handler,
  22. std::u16string title)
  23. : ChooserController(title), event_handler_(event_handler) {}
  24. BluetoothChooserController::~BluetoothChooserController() {
  25. if (event_handler_) {
  26. event_handler_.Run(content::BluetoothChooserEvent::CANCELLED,
  27. std::string());
  28. }
  29. }
  30. bool BluetoothChooserController::ShouldShowIconBeforeText() const {
  31. return true;
  32. }
  33. bool BluetoothChooserController::ShouldShowReScanButton() const {
  34. return true;
  35. }
  36. std::u16string BluetoothChooserController::GetNoOptionsText() const {
  37. return l10n_util::GetStringUTF16(
  38. IDS_BLUETOOTH_DEVICE_CHOOSER_NO_DEVICES_FOUND_PROMPT);
  39. }
  40. std::u16string BluetoothChooserController::GetOkButtonLabel() const {
  41. return l10n_util::GetStringUTF16(
  42. IDS_BLUETOOTH_DEVICE_CHOOSER_PAIR_BUTTON_TEXT);
  43. }
  44. std::pair<std::u16string, std::u16string>
  45. BluetoothChooserController::GetThrobberLabelAndTooltip() const {
  46. return {
  47. l10n_util::GetStringUTF16(IDS_BLUETOOTH_DEVICE_CHOOSER_SCANNING_LABEL),
  48. l10n_util::GetStringUTF16(
  49. IDS_BLUETOOTH_DEVICE_CHOOSER_SCANNING_LABEL_TOOLTIP)};
  50. }
  51. size_t BluetoothChooserController::NumOptions() const {
  52. return devices_.size();
  53. }
  54. int BluetoothChooserController::GetSignalStrengthLevel(size_t index) const {
  55. return devices_[index].signal_strength_level;
  56. }
  57. bool BluetoothChooserController::IsConnected(size_t index) const {
  58. return devices_[index].is_connected;
  59. }
  60. bool BluetoothChooserController::IsPaired(size_t index) const {
  61. return devices_[index].is_paired;
  62. }
  63. std::u16string BluetoothChooserController::GetOption(size_t index) const {
  64. // Change these back to DCHECKs once https://crbug.com/1292234 is resolved.
  65. if (index >= devices_.size())
  66. base::debug::DumpWithoutCrashing();
  67. const std::string& device_id = devices_[index].id;
  68. const auto& device_name_it = device_id_to_name_map_.find(device_id);
  69. if (device_name_it == device_id_to_name_map_.end())
  70. base::debug::DumpWithoutCrashing();
  71. const auto& it = device_name_counts_.find(device_name_it->second);
  72. if (it == device_name_counts_.end())
  73. base::debug::DumpWithoutCrashing();
  74. return it->second == 1
  75. ? device_name_it->second
  76. : l10n_util::GetStringFUTF16(
  77. IDS_DEVICE_CHOOSER_DEVICE_NAME_WITH_ID,
  78. device_name_it->second, base::UTF8ToUTF16(device_id));
  79. }
  80. void BluetoothChooserController::RefreshOptions() {
  81. RecordInteractionWithChooser(event_handler_.is_null());
  82. if (event_handler_.is_null())
  83. return;
  84. ClearAllDevices();
  85. event_handler_.Run(content::BluetoothChooserEvent::RESCAN, std::string());
  86. }
  87. void BluetoothChooserController::Select(const std::vector<size_t>& indices) {
  88. DCHECK_EQ(1u, indices.size());
  89. size_t index = indices[0];
  90. RecordInteractionWithChooser(event_handler_.is_null());
  91. if (event_handler_.is_null()) {
  92. return;
  93. }
  94. DCHECK_LT(index, devices_.size());
  95. event_handler_.Run(content::BluetoothChooserEvent::SELECTED,
  96. devices_[index].id);
  97. event_handler_.Reset();
  98. }
  99. void BluetoothChooserController::Cancel() {
  100. RecordInteractionWithChooser(event_handler_.is_null());
  101. if (event_handler_.is_null())
  102. return;
  103. event_handler_.Run(content::BluetoothChooserEvent::CANCELLED, std::string());
  104. event_handler_.Reset();
  105. }
  106. void BluetoothChooserController::Close() {
  107. RecordInteractionWithChooser(event_handler_.is_null());
  108. if (event_handler_.is_null())
  109. return;
  110. event_handler_.Run(content::BluetoothChooserEvent::CANCELLED, std::string());
  111. event_handler_.Reset();
  112. }
  113. void BluetoothChooserController::OnAdapterPresenceChanged(
  114. content::BluetoothChooser::AdapterPresence presence) {
  115. ClearAllDevices();
  116. switch (presence) {
  117. case content::BluetoothChooser::AdapterPresence::ABSENT:
  118. NOTREACHED();
  119. break;
  120. case content::BluetoothChooser::AdapterPresence::POWERED_OFF:
  121. if (view()) {
  122. view()->OnAdapterEnabledChanged(
  123. false /* Bluetooth adapter is turned off */);
  124. }
  125. break;
  126. case content::BluetoothChooser::AdapterPresence::POWERED_ON:
  127. if (view()) {
  128. view()->OnAdapterEnabledChanged(
  129. true /* Bluetooth adapter is turned on */);
  130. }
  131. break;
  132. case content::BluetoothChooser::AdapterPresence::UNAUTHORIZED:
  133. if (view()) {
  134. view()->OnAdapterAuthorizationChanged(/*authorized=*/false);
  135. }
  136. break;
  137. }
  138. }
  139. void BluetoothChooserController::OnDiscoveryStateChanged(
  140. content::BluetoothChooser::DiscoveryState state) {
  141. switch (state) {
  142. case content::BluetoothChooser::DiscoveryState::DISCOVERING:
  143. if (view()) {
  144. view()->OnRefreshStateChanged(
  145. true /* Refreshing options is in progress */);
  146. }
  147. break;
  148. case content::BluetoothChooser::DiscoveryState::IDLE:
  149. case content::BluetoothChooser::DiscoveryState::FAILED_TO_START:
  150. if (view()) {
  151. view()->OnRefreshStateChanged(
  152. false /* Refreshing options is complete */);
  153. }
  154. break;
  155. }
  156. }
  157. void BluetoothChooserController::AddOrUpdateDevice(
  158. const std::string& device_id,
  159. bool should_update_name,
  160. const std::u16string& device_name,
  161. bool is_gatt_connected,
  162. bool is_paired,
  163. int signal_strength_level) {
  164. auto name_it = device_id_to_name_map_.find(device_id);
  165. if (name_it != device_id_to_name_map_.end()) {
  166. if (should_update_name) {
  167. std::u16string previous_device_name = name_it->second;
  168. name_it->second = device_name;
  169. const auto& it = device_name_counts_.find(previous_device_name);
  170. DCHECK(it != device_name_counts_.end());
  171. DCHECK_GT(it->second, 0);
  172. if (--(it->second) == 0)
  173. device_name_counts_.erase(it);
  174. ++device_name_counts_[device_name];
  175. }
  176. auto device_it =
  177. std::find_if(devices_.begin(), devices_.end(),
  178. [&device_id](const BluetoothDeviceInfo& device) {
  179. return device.id == device_id;
  180. });
  181. DCHECK(device_it != devices_.end());
  182. // When Bluetooth device scanning stops, the |signal_strength_level|
  183. // is -1, and in this case, should still use the previously stored
  184. // signal strength level value.
  185. if (signal_strength_level != -1)
  186. device_it->signal_strength_level = signal_strength_level;
  187. device_it->is_connected = is_gatt_connected;
  188. device_it->is_paired = is_paired;
  189. if (view())
  190. view()->OnOptionUpdated(device_it - devices_.begin());
  191. return;
  192. }
  193. devices_.push_back(
  194. {device_id, signal_strength_level, is_gatt_connected, is_paired});
  195. device_id_to_name_map_.insert({device_id, device_name});
  196. ++device_name_counts_[device_name];
  197. if (view())
  198. view()->OnOptionAdded(devices_.size() - 1);
  199. }
  200. void BluetoothChooserController::RemoveDevice(const std::string& device_id) {
  201. const auto& name_it = device_id_to_name_map_.find(device_id);
  202. if (name_it == device_id_to_name_map_.end())
  203. return;
  204. auto device_it =
  205. std::find_if(devices_.begin(), devices_.end(),
  206. [&device_id](const BluetoothDeviceInfo& device) {
  207. return device.id == device_id;
  208. });
  209. if (device_it != devices_.end()) {
  210. size_t index = device_it - devices_.begin();
  211. devices_.erase(device_it);
  212. const auto& it = device_name_counts_.find(name_it->second);
  213. DCHECK(it != device_name_counts_.end());
  214. DCHECK_GT(it->second, 0);
  215. if (--(it->second) == 0)
  216. device_name_counts_.erase(it);
  217. device_id_to_name_map_.erase(name_it);
  218. if (view())
  219. view()->OnOptionRemoved(index);
  220. }
  221. }
  222. void BluetoothChooserController::ResetEventHandler() {
  223. event_handler_.Reset();
  224. }
  225. base::WeakPtr<BluetoothChooserController>
  226. BluetoothChooserController::GetWeakPtr() {
  227. return weak_factory_.GetWeakPtr();
  228. }
  229. void BluetoothChooserController::ClearAllDevices() {
  230. devices_.clear();
  231. device_id_to_name_map_.clear();
  232. device_name_counts_.clear();
  233. }
  234. } // namespace permissions