From a70749e80ae8fbc17f96c6007f3d440af5e38610 Mon Sep 17 00:00:00 2001 From: deepak1556 Date: Mon, 30 May 2016 18:08:09 +0530 Subject: [PATCH 1/5] browser: implement bluetooth chooser interface --- atom/browser/api/atom_api_web_contents.cc | 9 ++ atom/browser/api/atom_api_web_contents.h | 3 + atom/browser/bluetooth_chooser.cc | 107 ++++++++++++++++++++++ atom/browser/bluetooth_chooser.h | 45 +++++++++ filenames.gypi | 2 + 5 files changed, 166 insertions(+) create mode 100644 atom/browser/bluetooth_chooser.cc create mode 100644 atom/browser/bluetooth_chooser.h diff --git a/atom/browser/api/atom_api_web_contents.cc b/atom/browser/api/atom_api_web_contents.cc index 736fb7ca0fb..ab68fafe716 100644 --- a/atom/browser/api/atom_api_web_contents.cc +++ b/atom/browser/api/atom_api_web_contents.cc @@ -14,6 +14,7 @@ #include "atom/browser/atom_browser_context.h" #include "atom/browser/atom_browser_main_parts.h" #include "atom/browser/atom_security_state_model_client.h" +#include "atom/browser/bluetooth_chooser.h" #include "atom/browser/native_window.h" #include "atom/browser/net/atom_network_delegate.h" #include "atom/browser/web_contents_permission_helper.h" @@ -504,6 +505,14 @@ void WebContents::RequestToLockMouse( permission_helper->RequestPointerLockPermission(user_gesture); } +std::unique_ptr WebContents::RunBluetoothChooser( + content::RenderFrameHost* frame, + const content::BluetoothChooser::EventHandler& event_handler) { + std::unique_ptr bluetooth_chooser( + new BluetoothChooser(this, event_handler)); + return std::move(bluetooth_chooser); +} + void WebContents::BeforeUnloadFired(const base::TimeTicks& proceed_time) { // Do nothing, we override this method just to avoid compilation error since // there are two virtual functions named BeforeUnloadFired. diff --git a/atom/browser/api/atom_api_web_contents.h b/atom/browser/api/atom_api_web_contents.h index e03ab653a8c..85c43f1486a 100644 --- a/atom/browser/api/atom_api_web_contents.h +++ b/atom/browser/api/atom_api_web_contents.h @@ -211,6 +211,9 @@ class WebContents : public mate::TrackableObject, content::WebContents* web_contents, bool user_gesture, bool last_unlocked_by_target) override; + std::unique_ptr RunBluetoothChooser( + content::RenderFrameHost* frame, + const content::BluetoothChooser::EventHandler& handler) override; // content::WebContentsObserver: void BeforeUnloadFired(const base::TimeTicks& proceed_time) override; diff --git a/atom/browser/bluetooth_chooser.cc b/atom/browser/bluetooth_chooser.cc new file mode 100644 index 00000000000..37c30a36081 --- /dev/null +++ b/atom/browser/bluetooth_chooser.cc @@ -0,0 +1,107 @@ +// 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 "atom/browser/bluetooth_chooser.h" +#include "atom/common/native_mate_converters/callback.h" +#include "atom/common/native_mate_converters/string16_converter.h" +#include "native_mate/dictionary.h" + +namespace mate { + +template<> +struct Converter { + static v8::Local ToV8( + v8::Isolate* isolate, const atom::BluetoothChooser::DeviceInfo& val) { + mate::Dictionary dict = mate::Dictionary::CreateEmpty(isolate); + dict.Set("deviceName", val.device_name); + dict.Set("deviceId", val.device_id); + return mate::ConvertToV8(isolate, dict); + } +}; + +} // namespace mate + +namespace atom { + +namespace { + +const int kMaxScanRetries = 5; + +void OnDeviceChosen( + const content::BluetoothChooser::EventHandler& handler, + const std::string& device_id) { + if (device_id.empty()) { + handler.Run(content::BluetoothChooser::Event::CANCELLED, device_id); + } else { + handler.Run(content::BluetoothChooser::Event::SELECTED, device_id); + } +} + +} // namespace + +BluetoothChooser::BluetoothChooser( + api::WebContents* contents, + const EventHandler& event_handler) + : api_web_contents_(contents), + event_handler_(event_handler), + num_retries_(0) { +} + +BluetoothChooser::~BluetoothChooser() { +} + +void BluetoothChooser::SetAdapterPresence(AdapterPresence presence) { + switch (presence) { + case AdapterPresence::ABSENT: + case AdapterPresence::POWERED_OFF: + event_handler_.Run(Event::CANCELLED, ""); + break; + case AdapterPresence::POWERED_ON: + break; + } +} + +void BluetoothChooser::ShowDiscoveryState(DiscoveryState state) { + switch (state) { + case DiscoveryState::FAILED_TO_START: + event_handler_.Run(Event::CANCELLED, ""); + break; + case DiscoveryState::IDLE: + if (device_list_.empty()) { + auto event = ++num_retries_ > kMaxScanRetries ? Event::CANCELLED + : Event::RESCAN; + event_handler_.Run(event, ""); + } else { + bool prevent_default = + api_web_contents_->Emit("select-bluetooth-device", + device_list_, + base::Bind(&OnDeviceChosen, + event_handler_)); + if (!prevent_default) { + auto device_id = device_list_[0].device_id; + event_handler_.Run(Event::SELECTED, device_id); + } + } + break; + case DiscoveryState::DISCOVERING: + break; + } +} + +void BluetoothChooser::AddDevice(const std::string& device_id, + const base::string16& device_name) { + DeviceInfo info = {device_id, device_name}; + device_list_.push_back(info); +} + +void BluetoothChooser::RemoveDevice(const std::string& device_id) { + for (auto it = device_list_.begin(); it != device_list_.end(); ++it) { + if (it->device_id == device_id) { + device_list_.erase(it); + return; + } + } +} + +} // namespace atom diff --git a/atom/browser/bluetooth_chooser.h b/atom/browser/bluetooth_chooser.h new file mode 100644 index 00000000000..69617191ba4 --- /dev/null +++ b/atom/browser/bluetooth_chooser.h @@ -0,0 +1,45 @@ +// Copyright (c) 2016 GitHub, Inc. +// Use of this source code is governed by the MIT license that can be +// found in the LICENSE file. + +#ifndef ATOM_BROWSER_BLUETOOTH_CHOOSER_H_ +#define ATOM_BROWSER_BLUETOOTH_CHOOSER_H_ + +#include +#include + +#include "atom/browser/api/atom_api_web_contents.h" +#include "content/public/browser/bluetooth_chooser.h" + +namespace atom { + +class BluetoothChooser : public content::BluetoothChooser { + public: + struct DeviceInfo { + std::string device_id; + base::string16 device_name; + }; + + explicit BluetoothChooser(api::WebContents* contents, + const EventHandler& handler); + ~BluetoothChooser() override; + + // content::BluetoothChooser: + void SetAdapterPresence(AdapterPresence presence) override; + void ShowDiscoveryState(DiscoveryState state) override; + void AddDevice(const std::string& device_id, + const base::string16& device_name) override; + void RemoveDevice(const std::string& device_id) override; + + private: + std::vector device_list_; + api::WebContents* api_web_contents_; + EventHandler event_handler_; + int num_retries_; + + DISALLOW_COPY_AND_ASSIGN(BluetoothChooser); +}; + +} // namespace atom + +#endif // ATOM_BROWSER_BLUETOOTH_CHOOSER_H_ diff --git a/filenames.gypi b/filenames.gypi index ae71164a8ab..66874efc07d 100644 --- a/filenames.gypi +++ b/filenames.gypi @@ -167,6 +167,8 @@ 'atom/browser/atom_security_state_model_client.h', 'atom/browser/atom_speech_recognition_manager_delegate.cc', 'atom/browser/atom_speech_recognition_manager_delegate.h', + 'atom/browser/bluetooth_chooser.cc', + 'atom/browser/bluetooth_chooser.h', 'atom/browser/bridge_task_runner.cc', 'atom/browser/bridge_task_runner.h', 'atom/browser/browser.cc', From 51daf8e194d6d5660c29736f6dd1dc07d2ad24ee Mon Sep 17 00:00:00 2001 From: deepak1556 Date: Tue, 31 May 2016 13:37:45 +0530 Subject: [PATCH 2/5] add docs --- docs/api/web-contents.md | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/docs/api/web-contents.md b/docs/api/web-contents.md index 89d7e1245d7..941879b7f74 100644 --- a/docs/api/web-contents.md +++ b/docs/api/web-contents.md @@ -373,6 +373,22 @@ The `editFlags` is an object with the following properties: Emitted when there is a new context menu that needs to be handled. +### Event: 'select-bluetooth-device' + +Returns: + +* `event` Event +* `devices` [Objects] + * `deviceName` String + * `deviceId` String +* `callback` Function + * `deviceId` String + +Emitted when bluetooth device needs to be selected on call to +`navigator.bluetooth.requestDevice`. If `event.preventDefault` is not called, +first available device will be selected. `callback` should be called with `deviceId` +to be selected. + ## Instance Methods The `webContents` object has the following instance methods: From db4dc4757aa85da8c6b46b6c4ea81eff8f9ee895 Mon Sep 17 00:00:00 2001 From: deepak1556 Date: Wed, 1 Jun 2016 11:17:21 +0530 Subject: [PATCH 3/5] move bluetooth_chooser to atom/browser/lib --- atom/browser/{ => lib}/bluetooth_chooser.cc | 0 atom/browser/{ => lib}/bluetooth_chooser.h | 0 filenames.gypi | 4 ++-- 3 files changed, 2 insertions(+), 2 deletions(-) rename atom/browser/{ => lib}/bluetooth_chooser.cc (100%) rename atom/browser/{ => lib}/bluetooth_chooser.h (100%) diff --git a/atom/browser/bluetooth_chooser.cc b/atom/browser/lib/bluetooth_chooser.cc similarity index 100% rename from atom/browser/bluetooth_chooser.cc rename to atom/browser/lib/bluetooth_chooser.cc diff --git a/atom/browser/bluetooth_chooser.h b/atom/browser/lib/bluetooth_chooser.h similarity index 100% rename from atom/browser/bluetooth_chooser.h rename to atom/browser/lib/bluetooth_chooser.h diff --git a/filenames.gypi b/filenames.gypi index 66874efc07d..f66b98134c6 100644 --- a/filenames.gypi +++ b/filenames.gypi @@ -167,8 +167,6 @@ 'atom/browser/atom_security_state_model_client.h', 'atom/browser/atom_speech_recognition_manager_delegate.cc', 'atom/browser/atom_speech_recognition_manager_delegate.h', - 'atom/browser/bluetooth_chooser.cc', - 'atom/browser/bluetooth_chooser.h', 'atom/browser/bridge_task_runner.cc', 'atom/browser/bridge_task_runner.h', 'atom/browser/browser.cc', @@ -183,6 +181,8 @@ 'atom/browser/common_web_contents_delegate.h', 'atom/browser/javascript_environment.cc', 'atom/browser/javascript_environment.h', + 'atom/browser/lib/bluetooth_chooser.cc', + 'atom/browser/lib/bluetooth_chooser.h', 'atom/browser/login_handler.cc', 'atom/browser/login_handler.h', 'atom/browser/mac/atom_application.h', From de4bff003f82344efa83f0c183c62e09b824c766 Mon Sep 17 00:00:00 2001 From: deepak1556 Date: Wed, 1 Jun 2016 11:24:41 +0530 Subject: [PATCH 4/5] fix header paths and comments --- atom/browser/api/atom_api_web_contents.cc | 2 +- atom/browser/lib/bluetooth_chooser.cc | 2 +- atom/browser/lib/bluetooth_chooser.h | 6 +++--- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/atom/browser/api/atom_api_web_contents.cc b/atom/browser/api/atom_api_web_contents.cc index ab68fafe716..9d93d980be4 100644 --- a/atom/browser/api/atom_api_web_contents.cc +++ b/atom/browser/api/atom_api_web_contents.cc @@ -14,7 +14,7 @@ #include "atom/browser/atom_browser_context.h" #include "atom/browser/atom_browser_main_parts.h" #include "atom/browser/atom_security_state_model_client.h" -#include "atom/browser/bluetooth_chooser.h" +#include "atom/browser/lib/bluetooth_chooser.h" #include "atom/browser/native_window.h" #include "atom/browser/net/atom_network_delegate.h" #include "atom/browser/web_contents_permission_helper.h" diff --git a/atom/browser/lib/bluetooth_chooser.cc b/atom/browser/lib/bluetooth_chooser.cc index 37c30a36081..2ed21bd333f 100644 --- a/atom/browser/lib/bluetooth_chooser.cc +++ b/atom/browser/lib/bluetooth_chooser.cc @@ -2,7 +2,7 @@ // Use of this source code is governed by the MIT license that can be // found in the LICENSE file. -#include "atom/browser/bluetooth_chooser.h" +#include "atom/browser/lib/bluetooth_chooser.h" #include "atom/common/native_mate_converters/callback.h" #include "atom/common/native_mate_converters/string16_converter.h" #include "native_mate/dictionary.h" diff --git a/atom/browser/lib/bluetooth_chooser.h b/atom/browser/lib/bluetooth_chooser.h index 69617191ba4..615dfcb8c66 100644 --- a/atom/browser/lib/bluetooth_chooser.h +++ b/atom/browser/lib/bluetooth_chooser.h @@ -2,8 +2,8 @@ // Use of this source code is governed by the MIT license that can be // found in the LICENSE file. -#ifndef ATOM_BROWSER_BLUETOOTH_CHOOSER_H_ -#define ATOM_BROWSER_BLUETOOTH_CHOOSER_H_ +#ifndef ATOM_BROWSER_LIB_BLUETOOTH_CHOOSER_H_ +#define ATOM_BROWSER_LIB_BLUETOOTH_CHOOSER_H_ #include #include @@ -42,4 +42,4 @@ class BluetoothChooser : public content::BluetoothChooser { } // namespace atom -#endif // ATOM_BROWSER_BLUETOOTH_CHOOSER_H_ +#endif // ATOM_BROWSER_LIB_BLUETOOTH_CHOOSER_H_ From 743483846344515aa971be3d786d14e3ba125c82 Mon Sep 17 00:00:00 2001 From: deepak1556 Date: Wed, 1 Jun 2016 11:39:14 +0530 Subject: [PATCH 5/5] fix docs --- docs/api/web-contents.md | 26 +++++++++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-) diff --git a/docs/api/web-contents.md b/docs/api/web-contents.md index 941879b7f74..2d489c6726a 100644 --- a/docs/api/web-contents.md +++ b/docs/api/web-contents.md @@ -385,9 +385,29 @@ Returns: * `deviceId` String Emitted when bluetooth device needs to be selected on call to -`navigator.bluetooth.requestDevice`. If `event.preventDefault` is not called, -first available device will be selected. `callback` should be called with `deviceId` -to be selected. +`navigator.bluetooth.requestDevice`. To use `navigator.bluetooth` api +`webBluetooth` should be enabled. If `event.preventDefault` is not called, +first available device will be selected. `callback` should be called with +`deviceId` to be selected, passing empty string to `callback` will +cancel the request. + +```javacript +app.commandLine.appendSwitch('enable-web-bluetooth') + +app.on('ready', () => { + webContents.on('select-bluetooth-device', (event, deviceList, callback) => { + event.preventDefault() + let result = deviceList.find((device) => { + return device.deviceName === 'test' + }) + if (!result) { + callback('') + } else { + callback(result.deviceId) + } + }) +}) +``` ## Instance Methods