144 lines
		
	
	
	
		
			4.6 KiB
			
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			144 lines
		
	
	
	
		
			4.6 KiB
			
		
	
	
	
		
			C++
		
	
	
	
	
	
| // Copyright (c) 2016 GitHub, Inc.
 | |
| // Use of this source code is governed by the MIT license that can be
 | |
| // found in the LICENSE file.
 | |
| 
 | |
| #include "shell/browser/lib/bluetooth_chooser.h"
 | |
| 
 | |
| #include "shell/common/gin_converters/callback_converter.h"
 | |
| #include "shell/common/gin_helper/dictionary.h"
 | |
| 
 | |
| namespace gin {
 | |
| 
 | |
| template <>
 | |
| struct Converter<electron::BluetoothChooser::DeviceInfo> {
 | |
|   static v8::Local<v8::Value> ToV8(
 | |
|       v8::Isolate* isolate,
 | |
|       const electron::BluetoothChooser::DeviceInfo& val) {
 | |
|     gin_helper::Dictionary dict = gin::Dictionary::CreateEmpty(isolate);
 | |
|     dict.Set("deviceName", val.device_name);
 | |
|     dict.Set("deviceId", val.device_id);
 | |
|     return gin::ConvertToV8(isolate, dict);
 | |
|   }
 | |
| };
 | |
| 
 | |
| }  // namespace gin
 | |
| 
 | |
| namespace electron {
 | |
| 
 | |
| namespace {
 | |
| 
 | |
| void OnDeviceChosen(const content::BluetoothChooser::EventHandler& handler,
 | |
|                     const std::string& device_id) {
 | |
|   if (device_id.empty()) {
 | |
|     handler.Run(content::BluetoothChooserEvent::CANCELLED, device_id);
 | |
|   } else {
 | |
|     handler.Run(content::BluetoothChooserEvent::SELECTED, device_id);
 | |
|   }
 | |
| }
 | |
| 
 | |
| }  // namespace
 | |
| 
 | |
| BluetoothChooser::BluetoothChooser(api::WebContents* contents,
 | |
|                                    const EventHandler& event_handler)
 | |
|     : api_web_contents_(contents), event_handler_(event_handler) {}
 | |
| 
 | |
| BluetoothChooser::~BluetoothChooser() {
 | |
|   event_handler_.Reset();
 | |
| }
 | |
| 
 | |
| void BluetoothChooser::SetAdapterPresence(AdapterPresence presence) {
 | |
|   switch (presence) {
 | |
|     case AdapterPresence::ABSENT:
 | |
|     case AdapterPresence::POWERED_OFF:
 | |
|     // Chrome currently directs the user to system preferences
 | |
|     // to grant bluetooth permission for this case, should we
 | |
|     // do something similar ?
 | |
|     // https://chromium-review.googlesource.com/c/chromium/src/+/2617129
 | |
|     case AdapterPresence::UNAUTHORIZED:
 | |
|       event_handler_.Run(content::BluetoothChooserEvent::CANCELLED, "");
 | |
|       break;
 | |
|     case AdapterPresence::POWERED_ON:
 | |
|       rescan_ = true;
 | |
|       break;
 | |
|   }
 | |
| }
 | |
| 
 | |
| void BluetoothChooser::ShowDiscoveryState(DiscoveryState state) {
 | |
|   bool idle_state = false;
 | |
|   switch (state) {
 | |
|     case DiscoveryState::FAILED_TO_START:
 | |
|       refreshing_ = false;
 | |
|       event_handler_.Run(content::BluetoothChooserEvent::CANCELLED, "");
 | |
|       return;
 | |
|     case DiscoveryState::IDLE:
 | |
|       refreshing_ = false;
 | |
|       idle_state = true;
 | |
|       break;
 | |
|     case DiscoveryState::DISCOVERING:
 | |
|       // The first time this state fires is due to a rescan triggering so set a
 | |
|       // flag to ignore devices
 | |
|       if (rescan_ && !refreshing_) {
 | |
|         refreshing_ = true;
 | |
|       } else {
 | |
|         // The second time this state fires we are now safe to pick a device
 | |
|         refreshing_ = false;
 | |
|       }
 | |
|       break;
 | |
|   }
 | |
|   bool prevent_default =
 | |
|       api_web_contents_->Emit("select-bluetooth-device", GetDeviceList(),
 | |
|                               base::BindOnce(&OnDeviceChosen, event_handler_));
 | |
|   if (!prevent_default && idle_state) {
 | |
|     if (device_map_.empty()) {
 | |
|       event_handler_.Run(content::BluetoothChooserEvent::CANCELLED, "");
 | |
|     } else {
 | |
|       auto it = device_map_.begin();
 | |
|       auto device_id = it->first;
 | |
|       event_handler_.Run(content::BluetoothChooserEvent::SELECTED, device_id);
 | |
|     }
 | |
|   }
 | |
| }
 | |
| 
 | |
| void BluetoothChooser::AddOrUpdateDevice(const std::string& device_id,
 | |
|                                          bool should_update_name,
 | |
|                                          const std::u16string& device_name,
 | |
|                                          bool is_gatt_connected,
 | |
|                                          bool is_paired,
 | |
|                                          int signal_strength_level) {
 | |
|   if (refreshing_) {
 | |
|     // If the list of bluetooth devices is currently being generated don't fire
 | |
|     // an event
 | |
|     return;
 | |
|   }
 | |
| 
 | |
|   auto [iter, changed] = device_map_.try_emplace(device_id, device_name);
 | |
|   if (!changed && should_update_name) {
 | |
|     iter->second = device_name;
 | |
|     changed = true;
 | |
|   }
 | |
| 
 | |
|   if (changed) {
 | |
|     // Emit a select-bluetooth-device handler to allow for user to listen for
 | |
|     // bluetooth device found.
 | |
|     bool prevent_default = api_web_contents_->Emit(
 | |
|         "select-bluetooth-device", GetDeviceList(),
 | |
|         base::BindOnce(&OnDeviceChosen, event_handler_));
 | |
| 
 | |
|     // If emit not implemented select first device that matches the filters
 | |
|     //  provided.
 | |
|     if (!prevent_default) {
 | |
|       event_handler_.Run(content::BluetoothChooserEvent::SELECTED, device_id);
 | |
|     }
 | |
|   }
 | |
| }
 | |
| 
 | |
| std::vector<electron::BluetoothChooser::DeviceInfo>
 | |
| BluetoothChooser::GetDeviceList() {
 | |
|   std::vector<electron::BluetoothChooser::DeviceInfo> vec;
 | |
|   vec.reserve(device_map_.size());
 | |
|   for (const auto& [device_id, device_name] : device_map_)
 | |
|     vec.emplace_back(device_id, device_name);
 | |
|   return vec;
 | |
| }
 | |
| 
 | |
| }  // namespace electron
 | 
