// Copyright 2020 Google LLC // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // https://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #include "core/internal/medium_manager.h" #include "platform/synchronized.h" namespace location { namespace nearby { namespace connections { template MediumManager::MediumManager() : mediums_(new Mediums()), bluetooth_classic_lock_(Platform::createLock()), ble_lock_(Platform::createLock()) {} template MediumManager::~MediumManager() { // TODO(reznor): log.atDebug().log("Initiating shutdown of MediumManager."); Synchronized s1(bluetooth_classic_lock_.get()); Synchronized s2(ble_lock_.get()); mediums_.destroy(); // TODO(reznor): log.atDebug().log("MediumManager has shut down."); } // ~~~~~~~~~~~~~~~~~~~~~~~~ BLUETOOTH ~~~~~~~~~~~~~~~~~~~~~~~~ template bool MediumManager::isBluetoothAvailable() { Synchronized s(bluetooth_classic_lock_.get()); return mediums_->bluetoothClassic()->isAvailable(); } template bool MediumManager::turnOnBluetoothDiscoverability( const string& device_name) { Synchronized s(bluetooth_classic_lock_.get()); return mediums_->bluetoothRadio()->enable() && mediums_->bluetoothClassic()->turnOnDiscoverability(device_name); } template void MediumManager::turnOffBluetoothDiscoverability() { Synchronized s(bluetooth_classic_lock_.get()); mediums_->bluetoothClassic()->turnOffDiscoverability(); } template class DiscoveredDeviceCallback : public BluetoothClassic::DiscoveredDeviceCallback { public: typedef typename MediumManager::FoundBluetoothDeviceProcessor FoundBluetoothDeviceProcessor; explicit DiscoveredDeviceCallback( Ptr found_bluetooth_device_processor) : found_bluetooth_device_processor_(found_bluetooth_device_processor) {} void onDeviceDiscovered(Ptr device) override { found_bluetooth_device_processor_->onFoundBluetoothDevice(device); } void onDeviceNameChanged(Ptr device) override { found_bluetooth_device_processor_->onFoundBluetoothDevice(device); } void onDeviceLost(Ptr device) override { found_bluetooth_device_processor_->onLostBluetoothDevice(device); } private: ScopedPtr > found_bluetooth_device_processor_; }; template bool MediumManager::startScanningForBluetoothDevices( Ptr found_bluetooth_device_processor) { Synchronized s(bluetooth_classic_lock_.get()); return mediums_->bluetoothRadio()->enable() && mediums_->bluetoothClassic()->startDiscovery( MakePtr(new DiscoveredDeviceCallback( found_bluetooth_device_processor))); } template void MediumManager::stopScanningForBluetoothDevices() { Synchronized s(bluetooth_classic_lock_.get()); mediums_->bluetoothClassic()->stopDiscovery(); } template bool MediumManager::isListeningForIncomingBluetoothConnections( const string& service_name) { Synchronized s(bluetooth_classic_lock_.get()); return mediums_->bluetoothClassic()->isAcceptingConnections(service_name); } template class BluetoothAcceptedConnectionCallback : public BluetoothClassic::AcceptedConnectionCallback { public: typedef typename MediumManager::IncomingBluetoothConnectionProcessor IncomingBluetoothConnectionProcessor; explicit BluetoothAcceptedConnectionCallback( Ptr incoming_bluetooth_connection_processor) : incoming_bluetooth_connection_processor_( incoming_bluetooth_connection_processor) {} void onConnectionAccepted(Ptr socket) override { incoming_bluetooth_connection_processor_->onIncomingBluetoothConnection( socket); } private: ScopedPtr > incoming_bluetooth_connection_processor_; }; template bool MediumManager::startListeningForIncomingBluetoothConnections( const string& service_name, Ptr incoming_bluetooth_connection_processor) { Synchronized s(bluetooth_classic_lock_.get()); return mediums_->bluetoothRadio()->enable() && mediums_->bluetoothClassic()->startAcceptingConnections( service_name, MakePtr(new BluetoothAcceptedConnectionCallback( incoming_bluetooth_connection_processor))); } template void MediumManager::stopListeningForIncomingBluetoothConnections( const string& service_name) { Synchronized s(bluetooth_classic_lock_.get()); mediums_->bluetoothClassic()->stopAcceptingConnections(service_name); } template Ptr MediumManager::connectToBluetoothDevice( Ptr bluetooth_device, const string& service_name) { Synchronized s(bluetooth_classic_lock_.get()); if (!mediums_->bluetoothRadio()->enable()) { return Ptr(); } return mediums_->bluetoothClassic()->connect(bluetooth_device, service_name); } // ~~~~~~~~~~~~~~~~~~~~~~~~ BLE ~~~~~~~~~~~~~~~~~~~~~~~~ template bool MediumManager::isBleAvailable() { Synchronized s(ble_lock_.get()); #if BLE_V2_IMPLEMENTED return mediums_->bleV2()->isAvailable(); #else return mediums_->ble()->isAvailable(); #endif } // TODO(ahlee): Add nearbyNotificationsBeaconData for phase 2 of implementation. // TODO(ahlee): Add fast_advertisement_service_uuid and power_level to // AdvertisingOptions and pass it through. template bool MediumManager::startBleAdvertising( const string& service_id, ConstPtr advertisement_data) { Synchronized s(ble_lock_.get()); return mediums_->bluetoothRadio()->enable() && #if BLE_V2_IMPLEMENTED mediums_->bleV2()->startAdvertising( service_id, advertisement_data, BLEMediumV2::PowerMode::HIGH, /* fast_advertisement_service_uuid= */ ""); #else mediums_->ble()->startAdvertising(service_id, advertisement_data); #endif } template void MediumManager::stopBleAdvertising(const string& service_id) { Synchronized s(ble_lock_.get()); #if BLE_V2_IMPLEMENTED mediums_->bleV2()->stopAdvertising(); #else mediums_->ble()->stopAdvertising(); #endif } #if BLE_V2_IMPLEMENTED template class BLEAcceptedConnectionCallback : public mediums::BLEV2::AcceptedConnectionCallback { public: BLEAcceptedConnectionCallback() {} }; #else template class BLEAcceptedConnectionCallback : public BLE::AcceptedConnectionCallback { public: typedef typename MediumManager::IncomingBleConnectionProcessor IncomingBleConnectionProcessor; explicit BLEAcceptedConnectionCallback( Ptr incoming_ble_connection_processor) : incoming_ble_connection_processor_(incoming_ble_connection_processor) {} void onConnectionAccepted(Ptr socket, const string& service_id) override { incoming_ble_connection_processor_->onIncomingBleConnection(socket, service_id); } private: ScopedPtr > incoming_ble_connection_processor_; }; #endif template bool MediumManager::isListeningForIncomingBleConnections( const string& service_id) { Synchronized s(ble_lock_.get()); #if BLE_V2_IMPLEMENTED return mediums_->bleV2()->isAcceptingConnections(); #else return mediums_->ble()->isAcceptingConnections(); #endif } template bool MediumManager::startListeningForIncomingBleConnections( const string& service_id, Ptr incoming_ble_connection_processor) { Synchronized s(ble_lock_.get()); return mediums_->bluetoothRadio()->enable() && #if BLE_V2_IMPLEMENTED mediums_->bleV2()->startAcceptingConnections( service_id, MakePtr(new BLEAcceptedConnectionCallback())); #else mediums_->ble()->startAcceptingConnections( service_id, MakePtr(new BLEAcceptedConnectionCallback( incoming_ble_connection_processor))); #endif } template void MediumManager::stopListeningForIncomingBleConnections( const string& service_id) { Synchronized s(ble_lock_.get()); #if BLE_V2_IMPLEMENTED mediums_->bleV2()->stopAcceptingConnections(); #else mediums_->ble()->stopAcceptingConnections(); #endif } template class DiscoveredPeripheralCallback : public DISCOVERED_PERIPHERAL_CALLBACK { public: typedef typename MediumManager::FoundBlePeripheralProcessor FoundBlePeripheralProcessor; explicit DiscoveredPeripheralCallback( Ptr found_ble_peripheral_processor) : found_ble_peripheral_processor_(found_ble_peripheral_processor) {} void onPeripheralDiscovered(Ptr ble_peripheral, const string& service_id, #if BLE_V2_IMPLEMENTED ConstPtr advertisement_data, // TODO(ahlee): Add is_fast_advertisement to // FoundBlePeripheralProcessor. bool is_fast_advertisement) override { #else ConstPtr advertisement_data) { #endif found_ble_peripheral_processor_->onFoundBlePeripheral( ble_peripheral, service_id, advertisement_data); } void onPeripheralLost(Ptr ble_peripheral, const string& service_id) override { found_ble_peripheral_processor_->onLostBlePeripheral(ble_peripheral, service_id); } private: ScopedPtr > found_ble_peripheral_processor_; }; // TODO(ahlee): Add fast_advertisement_service_uuid and power_level to // DiscoveryOptions and pass it through. template bool MediumManager::startBleScanning( const string& service_id, Ptr found_ble_peripheral_processor) { Synchronized s(ble_lock_.get()); return mediums_->bluetoothRadio()->enable() && #if BLE_V2_IMPLEMENTED mediums_->bleV2()->startScanning( service_id, MakePtr(new DiscoveredPeripheralCallback( found_ble_peripheral_processor)), BLEMediumV2::PowerMode::HIGH, /* fast_advertisement_service_uuid= */ ""); #else mediums_->ble()->startScanning( service_id, MakePtr(new DiscoveredPeripheralCallback( found_ble_peripheral_processor))); #endif } template void MediumManager::stopBleScanning(const string& service_id) { Synchronized s(ble_lock_.get()); #if BLE_V2_IMPLEMENTED mediums_->bleV2()->stopScanning(); #else mediums_->ble()->stopScanning(); #endif } template Ptr MediumManager::connectToBlePeripheral( Ptr ble_peripheral, const string& service_id) { Synchronized s(ble_lock_.get()); if (!mediums_->bluetoothRadio()->enable()) { return Ptr(); } #if BLE_V2_IMPLEMENTED // TODO(ahlee): Replace when connecting logic is implemented. return Ptr(); #else return mediums_->ble()->connect(ble_peripheral, service_id); #endif } } // namespace connections } // namespace nearby } // namespace location