123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177 |
- // Copyright 2018 The Chromium Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style license that can be
- // found in the LICENSE file.
- #include "device/bluetooth/bluetooth_low_energy_advertisement_manager_mac.h"
- #include "base/bind.h"
- #include "base/logging.h"
- #include "base/mac/scoped_nsobject.h"
- #include "base/strings/sys_string_conversions.h"
- #include "device/bluetooth/bluetooth_advertisement.h"
- #include "third_party/abseil-cpp/absl/types/optional.h"
- namespace device {
- BluetoothLowEnergyAdvertisementManagerMac::
- BluetoothLowEnergyAdvertisementManagerMac() {}
- BluetoothLowEnergyAdvertisementManagerMac::
- ~BluetoothLowEnergyAdvertisementManagerMac() {}
- void BluetoothLowEnergyAdvertisementManagerMac::Init(
- scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner,
- CBPeripheralManager* peripheral_manager) {
- ui_task_runner_ = ui_task_runner;
- peripheral_manager_ = peripheral_manager;
- }
- void BluetoothLowEnergyAdvertisementManagerMac::
- OnPeripheralManagerStateChanged() {
- // This function handles several cases:
- // 1. Error out when registering an advertisement, but the adapter is not
- // powered on.
- // 2. Start advertising a registered advertisement if the adapter is powered
- // on.
- // 3. Stop the advertisement when the adapter is powered off.
- // Note that if the adapter is powered off while advertising, macOS will
- // automatically restart advertising when the adapter is powered back on,
- // so we need to explicitly stop advertising in this case.
- if (!active_advertisement_) {
- return;
- }
- CBManagerState adapter_state = [peripheral_manager_ state];
- if (adapter_state == CBManagerStateUnknown) {
- // Wait for the adapter to initialize.
- return;
- }
- if (active_advertisement_->is_waiting_for_adapter() &&
- adapter_state < CBManagerStatePoweredOn) {
- DVLOG(1)
- << "Registration failed. Adapter changed to invalid adapter_state.";
- BluetoothAdvertisement::ErrorCode error_code =
- adapter_state == CBManagerStatePoweredOff
- ? BluetoothAdvertisement::ERROR_ADAPTER_POWERED_OFF
- : BluetoothAdvertisement::ERROR_UNSUPPORTED_PLATFORM;
- active_advertisement_->OnAdvertisementError(ui_task_runner_.get(),
- error_code);
- active_advertisement_ = nullptr;
- return;
- }
- if (active_advertisement_->is_advertising() &&
- adapter_state == CBManagerStateResetting) {
- DVLOG(1) << "Adapter resetting. Invalidating advertisement.";
- active_advertisement_->OnAdapterReset();
- active_advertisement_ = nullptr;
- return;
- }
- if (active_advertisement_->is_advertising() &&
- adapter_state == CBManagerStatePoweredOff) {
- DVLOG(1) << "Adapter powered off. Stopping advertisement.";
- // Note: we purposefully don't unregister the active advertisement for
- // consistency with ChromeOS. The caller must manually unregister
- // the advertisement themselves.
- [peripheral_manager_ stopAdvertising];
- return;
- }
- if (active_advertisement_->is_waiting_for_adapter()) {
- StartAdvertising();
- }
- }
- void BluetoothLowEnergyAdvertisementManagerMac::StartAdvertising() {
- base::scoped_nsobject<NSMutableArray> service_uuid_array(
- [[NSMutableArray alloc]
- initWithCapacity:active_advertisement_->service_uuids().size()]);
- for (const std::string& service_uuid :
- active_advertisement_->service_uuids()) {
- NSString* uuid_string = base::SysUTF8ToNSString(service_uuid);
- [service_uuid_array addObject:[CBUUID UUIDWithString:uuid_string]];
- }
- active_advertisement_->OnAdvertisementPending();
- [peripheral_manager_ startAdvertising:@{
- CBAdvertisementDataServiceUUIDsKey : service_uuid_array
- }];
- }
- void BluetoothLowEnergyAdvertisementManagerMac::RegisterAdvertisement(
- std::unique_ptr<BluetoothAdvertisement::Data> advertisement_data,
- BluetoothAdapter::CreateAdvertisementCallback callback,
- BluetoothAdapter::AdvertisementErrorCallback error_callback) {
- absl::optional<BluetoothAdvertisement::ErrorCode> error_code;
- std::unique_ptr<BluetoothAdvertisement::UUIDList> service_uuids =
- advertisement_data->service_uuids();
- if (!service_uuids || advertisement_data->manufacturer_data() ||
- advertisement_data->solicit_uuids() ||
- advertisement_data->service_data()) {
- DVLOG(1) << "macOS only supports advertising service UUIDs.";
- error_code = BluetoothAdvertisement::ERROR_UNSUPPORTED_PLATFORM;
- }
- if (active_advertisement_ && active_advertisement_->status() !=
- BluetoothAdvertisementMac::UNREGISTERED) {
- DVLOG(1) << "Only one active BLE advertisement is currently supported.";
- error_code = BluetoothAdvertisement::ERROR_ADVERTISEMENT_ALREADY_EXISTS;
- }
- if (error_code) {
- ui_task_runner_->PostTask(
- FROM_HERE, base::BindOnce(std::move(error_callback), *error_code));
- return;
- }
- active_advertisement_ = base::MakeRefCounted<BluetoothAdvertisementMac>(
- std::move(service_uuids), std::move(callback), std::move(error_callback),
- this);
- OnPeripheralManagerStateChanged();
- }
- void BluetoothLowEnergyAdvertisementManagerMac::UnregisterAdvertisement(
- BluetoothAdvertisementMac* advertisement,
- BluetoothAdvertisement::SuccessCallback success_callback,
- BluetoothAdvertisement::ErrorCallback error_callback) {
- if (advertisement != active_advertisement_.get()) {
- DVLOG(1) << "Cannot unregister none-active advertisement.";
- ui_task_runner_->PostTask(
- FROM_HERE,
- base::BindOnce(std::move(error_callback),
- BluetoothAdvertisement::ERROR_RESET_ADVERTISING));
- return;
- }
- active_advertisement_ = nullptr;
- [peripheral_manager_ stopAdvertising];
- ui_task_runner_->PostTask(FROM_HERE, std::move(success_callback));
- }
- void BluetoothLowEnergyAdvertisementManagerMac::DidStartAdvertising(
- NSError* error) {
- DCHECK(active_advertisement_ &&
- active_advertisement_->is_advertisement_pending());
- if (!active_advertisement_ ||
- !active_advertisement_->is_advertisement_pending()) {
- return;
- }
- if (error != nil) {
- DVLOG(1) << "Error advertising: "
- << base::SysNSStringToUTF8(error.localizedDescription);
- active_advertisement_->OnAdvertisementError(
- ui_task_runner_.get(),
- BluetoothAdvertisement::ERROR_STARTING_ADVERTISEMENT);
- active_advertisement_ = nullptr;
- return;
- }
- active_advertisement_->OnAdvertisementSuccess(ui_task_runner_.get());
- }
- } // device
|