1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/dom/bluetooth/bluedroid/BluetoothServiceBluedroid.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,1409 @@ 1.4 +/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */ 1.5 +/* vim: set ts=2 et sw=2 tw=80: */ 1.6 +/* 1.7 +** Copyright 2006, The Android Open Source Project 1.8 +** 1.9 +** Licensed under the Apache License, Version 2.0 (the "License"); 1.10 +** you may not use this file except in compliance with the License. 1.11 +** You may obtain a copy of the License at 1.12 +** 1.13 +** http://www.apache.org/licenses/LICENSE-2.0 1.14 +** 1.15 +** Unless required by applicable law or agreed to in writing, software 1.16 +** distributed under the License is distributed on an "AS IS" BASIS, 1.17 +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1.18 +** See the License for the specific language governing permissions and 1.19 +** limitations under the License. 1.20 +*/ 1.21 + 1.22 +#include "BluetoothServiceBluedroid.h" 1.23 + 1.24 +#include <hardware/hardware.h> 1.25 + 1.26 +#include "BluetoothA2dpManager.h" 1.27 +#include "BluetoothHfpManager.h" 1.28 +#include "BluetoothOppManager.h" 1.29 +#include "BluetoothProfileController.h" 1.30 +#include "BluetoothReplyRunnable.h" 1.31 +#include "BluetoothUtils.h" 1.32 +#include "BluetoothUuid.h" 1.33 +#include "mozilla/dom/bluetooth/BluetoothTypes.h" 1.34 +#include "mozilla/ipc/UnixSocket.h" 1.35 +#include "mozilla/StaticMutex.h" 1.36 +#include "mozilla/StaticPtr.h" 1.37 +#include "mozilla/unused.h" 1.38 + 1.39 +using namespace mozilla; 1.40 +using namespace mozilla::ipc; 1.41 +USING_BLUETOOTH_NAMESPACE 1.42 + 1.43 +/** 1.44 + * Static variables 1.45 + */ 1.46 +static bluetooth_device_t* sBtDevice; 1.47 +static const bt_interface_t* sBtInterface; 1.48 +static bool sAdapterDiscoverable = false; 1.49 +static bool sIsBtEnabled = false; 1.50 +static nsString sAdapterBdAddress; 1.51 +static nsString sAdapterBdName; 1.52 +static uint32_t sAdapterDiscoverableTimeout; 1.53 +static InfallibleTArray<nsString> sAdapterBondedAddressArray; 1.54 +static InfallibleTArray<BluetoothNamedValue> sRemoteDevicesPack; 1.55 +static nsTArray<nsRefPtr<BluetoothProfileController> > sControllerArray; 1.56 +static nsTArray<nsRefPtr<BluetoothReplyRunnable> > sBondingRunnableArray; 1.57 +static nsTArray<nsRefPtr<BluetoothReplyRunnable> > sChangeDiscoveryRunnableArray; 1.58 +static nsTArray<nsRefPtr<BluetoothReplyRunnable> > sGetDeviceRunnableArray; 1.59 +static nsTArray<nsRefPtr<BluetoothReplyRunnable> > sSetPropertyRunnableArray; 1.60 +static nsTArray<nsRefPtr<BluetoothReplyRunnable> > sUnbondingRunnableArray; 1.61 +static nsTArray<int> sRequestedDeviceCountArray; 1.62 + 1.63 +/** 1.64 + * Classes only used in this file 1.65 + */ 1.66 +class DistributeBluetoothSignalTask : public nsRunnable { 1.67 +public: 1.68 + DistributeBluetoothSignalTask(const BluetoothSignal& aSignal) : 1.69 + mSignal(aSignal) 1.70 + { 1.71 + } 1.72 + 1.73 + NS_IMETHOD 1.74 + Run() 1.75 + { 1.76 + MOZ_ASSERT(NS_IsMainThread()); 1.77 + 1.78 + BluetoothService* bs = BluetoothService::Get(); 1.79 + NS_ENSURE_TRUE(bs, NS_ERROR_FAILURE); 1.80 + 1.81 + bs->DistributeSignal(mSignal); 1.82 + 1.83 + return NS_OK; 1.84 + } 1.85 + 1.86 +private: 1.87 + BluetoothSignal mSignal; 1.88 +}; 1.89 + 1.90 +class SetupAfterEnabledTask : public nsRunnable 1.91 +{ 1.92 +public: 1.93 + SetupAfterEnabledTask() 1.94 + { } 1.95 + 1.96 + NS_IMETHOD 1.97 + Run() 1.98 + { 1.99 + MOZ_ASSERT(NS_IsMainThread()); 1.100 + 1.101 + // Bluetooth scan mode is NONE by default 1.102 + bt_scan_mode_t mode = BT_SCAN_MODE_CONNECTABLE; 1.103 + bt_property_t prop; 1.104 + prop.type = BT_PROPERTY_ADAPTER_SCAN_MODE; 1.105 + prop.val = (void*)&mode; 1.106 + prop.len = sizeof(mode); 1.107 + 1.108 + NS_ENSURE_TRUE(sBtInterface, NS_ERROR_FAILURE); 1.109 + 1.110 + int ret = sBtInterface->set_adapter_property(&prop); 1.111 + if (ret != BT_STATUS_SUCCESS) { 1.112 + BT_LOGR("Fail to set: BT_SCAN_MODE_CONNECTABLE"); 1.113 + } 1.114 + 1.115 + // Try to fire event 'AdapterAdded' to fit the original behaviour when 1.116 + // we used BlueZ as backend. 1.117 + BluetoothService* bs = BluetoothService::Get(); 1.118 + NS_ENSURE_TRUE(bs, NS_ERROR_FAILURE); 1.119 + 1.120 + bs->AdapterAddedReceived(); 1.121 + bs->TryFiringAdapterAdded(); 1.122 + 1.123 + // Trigger BluetoothOppManager to listen 1.124 + BluetoothOppManager* opp = BluetoothOppManager::Get(); 1.125 + if (!opp || !opp->Listen()) { 1.126 + BT_LOGR("Fail to start BluetoothOppManager listening"); 1.127 + } 1.128 + 1.129 + return NS_OK; 1.130 + } 1.131 +}; 1.132 + 1.133 +/** 1.134 + * Static callback functions 1.135 + */ 1.136 +static void 1.137 +ClassToIcon(uint32_t aClass, nsAString& aRetIcon) 1.138 +{ 1.139 + switch ((aClass & 0x1f00) >> 8) { 1.140 + case 0x01: 1.141 + aRetIcon.AssignLiteral("computer"); 1.142 + break; 1.143 + case 0x02: 1.144 + switch ((aClass & 0xfc) >> 2) { 1.145 + case 0x01: 1.146 + case 0x02: 1.147 + case 0x03: 1.148 + case 0x05: 1.149 + aRetIcon.AssignLiteral("phone"); 1.150 + break; 1.151 + case 0x04: 1.152 + aRetIcon.AssignLiteral("modem"); 1.153 + break; 1.154 + } 1.155 + break; 1.156 + case 0x03: 1.157 + aRetIcon.AssignLiteral("network-wireless"); 1.158 + break; 1.159 + case 0x04: 1.160 + switch ((aClass & 0xfc) >> 2) { 1.161 + case 0x01: 1.162 + case 0x02: 1.163 + case 0x06: 1.164 + aRetIcon.AssignLiteral("audio-card"); 1.165 + break; 1.166 + case 0x0b: 1.167 + case 0x0c: 1.168 + case 0x0d: 1.169 + aRetIcon.AssignLiteral("camera-video"); 1.170 + break; 1.171 + default: 1.172 + aRetIcon.AssignLiteral("audio-card"); 1.173 + break; 1.174 + } 1.175 + break; 1.176 + case 0x05: 1.177 + switch ((aClass & 0xc0) >> 6) { 1.178 + case 0x00: 1.179 + switch ((aClass && 0x1e) >> 2) { 1.180 + case 0x01: 1.181 + case 0x02: 1.182 + aRetIcon.AssignLiteral("input-gaming"); 1.183 + break; 1.184 + } 1.185 + break; 1.186 + case 0x01: 1.187 + aRetIcon.AssignLiteral("input-keyboard"); 1.188 + break; 1.189 + case 0x02: 1.190 + switch ((aClass && 0x1e) >> 2) { 1.191 + case 0x05: 1.192 + aRetIcon.AssignLiteral("input-tablet"); 1.193 + break; 1.194 + default: 1.195 + aRetIcon.AssignLiteral("input-mouse"); 1.196 + break; 1.197 + } 1.198 + } 1.199 + break; 1.200 + case 0x06: 1.201 + if (aClass & 0x80) { 1.202 + aRetIcon.AssignLiteral("printer"); 1.203 + break; 1.204 + } 1.205 + if (aClass & 0x20) { 1.206 + aRetIcon.AssignLiteral("camera-photo"); 1.207 + break; 1.208 + } 1.209 + break; 1.210 + } 1.211 + 1.212 + if (aRetIcon.IsEmpty()) { 1.213 + if (HAS_AUDIO(aClass)) { 1.214 + /** 1.215 + * Property 'Icon' may be missed due to CoD of major class is TOY(0x08). 1.216 + * But we need to assign Icon as audio-card if service class is 'Audio'. 1.217 + * This is for PTS test case TC_AG_COD_BV_02_I. As HFP specification 1.218 + * defines that service class is 'Audio' can be considered as HFP HF. 1.219 + */ 1.220 + aRetIcon.AssignLiteral("audio-card"); 1.221 + } else { 1.222 + BT_LOGR("No icon to match class: %x", aClass); 1.223 + } 1.224 + } 1.225 +} 1.226 + 1.227 +static ControlPlayStatus 1.228 +PlayStatusStringToControlPlayStatus(const nsAString& aPlayStatus) 1.229 +{ 1.230 + ControlPlayStatus playStatus = ControlPlayStatus::PLAYSTATUS_UNKNOWN; 1.231 + if (aPlayStatus.EqualsLiteral("STOPPED")) { 1.232 + playStatus = ControlPlayStatus::PLAYSTATUS_STOPPED; 1.233 + } else if (aPlayStatus.EqualsLiteral("PLAYING")) { 1.234 + playStatus = ControlPlayStatus::PLAYSTATUS_PLAYING; 1.235 + } else if (aPlayStatus.EqualsLiteral("PAUSED")) { 1.236 + playStatus = ControlPlayStatus::PLAYSTATUS_PAUSED; 1.237 + } else if (aPlayStatus.EqualsLiteral("FWD_SEEK")) { 1.238 + playStatus = ControlPlayStatus::PLAYSTATUS_FWD_SEEK; 1.239 + } else if (aPlayStatus.EqualsLiteral("REV_SEEK")) { 1.240 + playStatus = ControlPlayStatus::PLAYSTATUS_REV_SEEK; 1.241 + } else if (aPlayStatus.EqualsLiteral("ERROR")) { 1.242 + playStatus = ControlPlayStatus::PLAYSTATUS_ERROR; 1.243 + } 1.244 + 1.245 + return playStatus; 1.246 +} 1.247 + 1.248 +static bool 1.249 +IsReady() 1.250 +{ 1.251 + if (!sBtInterface || !sIsBtEnabled) { 1.252 + BT_LOGR("Warning! Bluetooth Service is not ready"); 1.253 + return false; 1.254 + } 1.255 + return true; 1.256 +} 1.257 + 1.258 +static void 1.259 +AdapterStateChangeCallback(bt_state_t aStatus) 1.260 +{ 1.261 + MOZ_ASSERT(!NS_IsMainThread()); 1.262 + 1.263 + BT_LOGR("BT_STATE %d", aStatus); 1.264 + 1.265 + sIsBtEnabled = (aStatus == BT_STATE_ON); 1.266 + 1.267 + nsRefPtr<nsRunnable> runnable = 1.268 + new BluetoothService::ToggleBtAck(sIsBtEnabled); 1.269 + if (NS_FAILED(NS_DispatchToMainThread(runnable))) { 1.270 + BT_WARNING("Failed to dispatch to main thread!"); 1.271 + return; 1.272 + } 1.273 + 1.274 + if (sIsBtEnabled && 1.275 + NS_FAILED(NS_DispatchToMainThread(new SetupAfterEnabledTask()))) { 1.276 + BT_WARNING("Failed to dispatch to main thread!"); 1.277 + } 1.278 +} 1.279 + 1.280 +/** 1.281 + * AdapterPropertiesCallback will be called after enable() but before 1.282 + * AdapterStateChangeCallback sIsBtEnabled get updated. At that moment, both 1.283 + * BluetoothManager/BluetoothAdapter does not register observer yet. 1.284 + */ 1.285 +static void 1.286 +AdapterPropertiesCallback(bt_status_t aStatus, int aNumProperties, 1.287 + bt_property_t *aProperties) 1.288 +{ 1.289 + MOZ_ASSERT(!NS_IsMainThread()); 1.290 + 1.291 + BluetoothValue propertyValue; 1.292 + InfallibleTArray<BluetoothNamedValue> props; 1.293 + 1.294 + for (int i = 0; i < aNumProperties; i++) { 1.295 + bt_property_t p = aProperties[i]; 1.296 + 1.297 + if (p.type == BT_PROPERTY_BDADDR) { 1.298 + BdAddressTypeToString((bt_bdaddr_t*)p.val, sAdapterBdAddress); 1.299 + propertyValue = sAdapterBdAddress; 1.300 + BT_APPEND_NAMED_VALUE(props, "Address", propertyValue); 1.301 + } else if (p.type == BT_PROPERTY_BDNAME) { 1.302 + // Construct nsCString here because Bd name returned from bluedroid 1.303 + // is missing a null terminated character after SetProperty. 1.304 + propertyValue = sAdapterBdName = NS_ConvertUTF8toUTF16( 1.305 + nsCString((char*)p.val, p.len)); 1.306 + BT_APPEND_NAMED_VALUE(props, "Name", propertyValue); 1.307 + } else if (p.type == BT_PROPERTY_ADAPTER_SCAN_MODE) { 1.308 + bt_scan_mode_t newMode = *(bt_scan_mode_t*)p.val; 1.309 + 1.310 + if (newMode == BT_SCAN_MODE_CONNECTABLE_DISCOVERABLE) { 1.311 + propertyValue = sAdapterDiscoverable = true; 1.312 + } else { 1.313 + propertyValue = sAdapterDiscoverable = false; 1.314 + } 1.315 + 1.316 + BT_APPEND_NAMED_VALUE(props, "Discoverable", propertyValue); 1.317 + } else if (p.type == BT_PROPERTY_ADAPTER_DISCOVERY_TIMEOUT) { 1.318 + propertyValue = sAdapterDiscoverableTimeout = *(uint32_t*)p.val; 1.319 + BT_APPEND_NAMED_VALUE(props, "DiscoverableTimeout", propertyValue); 1.320 + } else if (p.type == BT_PROPERTY_ADAPTER_BONDED_DEVICES) { 1.321 + // We have to cache addresses of bonded devices. Unlike BlueZ, 1.322 + // bluedroid would not send an another BT_PROPERTY_ADAPTER_BONDED_DEVICES 1.323 + // event after bond completed 1.324 + bt_bdaddr_t* deviceBdAddressTypes = (bt_bdaddr_t*)p.val; 1.325 + int numOfAddresses = p.len / BLUETOOTH_ADDRESS_BYTES; 1.326 + BT_LOGD("Adapter property: BONDED_DEVICES. Count: %d", numOfAddresses); 1.327 + 1.328 + // Whenever reloading paired devices, force refresh 1.329 + sAdapterBondedAddressArray.Clear(); 1.330 + 1.331 + for (int index = 0; index < numOfAddresses; index++) { 1.332 + nsAutoString deviceBdAddress; 1.333 + BdAddressTypeToString(deviceBdAddressTypes + index, deviceBdAddress); 1.334 + sAdapterBondedAddressArray.AppendElement(deviceBdAddress); 1.335 + } 1.336 + 1.337 + propertyValue = sAdapterBondedAddressArray; 1.338 + BT_APPEND_NAMED_VALUE(props, "Devices", propertyValue); 1.339 + } else if (p.type == BT_PROPERTY_UUIDS) { 1.340 + //FIXME: This will be implemented in the later patchset 1.341 + continue; 1.342 + } else { 1.343 + BT_LOGD("Unhandled adapter property type: %d", p.type); 1.344 + continue; 1.345 + } 1.346 + } 1.347 + 1.348 + NS_ENSURE_TRUE_VOID(props.Length() > 0); 1.349 + 1.350 + BluetoothValue value(props); 1.351 + BluetoothSignal signal(NS_LITERAL_STRING("PropertyChanged"), 1.352 + NS_LITERAL_STRING(KEY_ADAPTER), value); 1.353 + nsRefPtr<DistributeBluetoothSignalTask> 1.354 + t = new DistributeBluetoothSignalTask(signal); 1.355 + if (NS_FAILED(NS_DispatchToMainThread(t))) { 1.356 + BT_WARNING("Failed to dispatch to main thread!"); 1.357 + } 1.358 + 1.359 + // bluedroid BTU task was stored in the task queue, see GKI_send_msg 1.360 + if (!sSetPropertyRunnableArray.IsEmpty()) { 1.361 + DispatchBluetoothReply(sSetPropertyRunnableArray[0], BluetoothValue(true), 1.362 + EmptyString()); 1.363 + sSetPropertyRunnableArray.RemoveElementAt(0); 1.364 + } 1.365 +} 1.366 + 1.367 +/** 1.368 + * RemoteDevicePropertiesCallback will be called, as the following conditions: 1.369 + * 1. When BT is turning on, bluedroid automatically execute this callback 1.370 + * 2. When get_remote_device_properties() 1.371 + */ 1.372 +static void 1.373 +RemoteDevicePropertiesCallback(bt_status_t aStatus, bt_bdaddr_t *aBdAddress, 1.374 + int aNumProperties, bt_property_t *aProperties) 1.375 +{ 1.376 + MOZ_ASSERT(!NS_IsMainThread()); 1.377 + 1.378 + if (sRequestedDeviceCountArray.IsEmpty()) { 1.379 + MOZ_ASSERT(sGetDeviceRunnableArray.IsEmpty()); 1.380 + return; 1.381 + } 1.382 + 1.383 + sRequestedDeviceCountArray[0]--; 1.384 + 1.385 + InfallibleTArray<BluetoothNamedValue> props; 1.386 + 1.387 + nsString remoteDeviceBdAddress; 1.388 + BdAddressTypeToString(aBdAddress, remoteDeviceBdAddress); 1.389 + BT_APPEND_NAMED_VALUE(props, "Address", remoteDeviceBdAddress); 1.390 + 1.391 + for (int i = 0; i < aNumProperties; ++i) { 1.392 + bt_property_t p = aProperties[i]; 1.393 + 1.394 + if (p.type == BT_PROPERTY_BDNAME) { 1.395 + BluetoothValue propertyValue = NS_ConvertUTF8toUTF16((char*)p.val); 1.396 + BT_APPEND_NAMED_VALUE(props, "Name", propertyValue); 1.397 + } else if (p.type == BT_PROPERTY_CLASS_OF_DEVICE) { 1.398 + uint32_t cod = *(uint32_t*)p.val; 1.399 + BT_APPEND_NAMED_VALUE(props, "Class", cod); 1.400 + 1.401 + nsString icon; 1.402 + ClassToIcon(cod, icon); 1.403 + BT_APPEND_NAMED_VALUE(props, "Icon", icon); 1.404 + } else { 1.405 + BT_LOGD("Other non-handled device properties. Type: %d", p.type); 1.406 + } 1.407 + } 1.408 + 1.409 + // Update to registered BluetoothDevice objects 1.410 + BluetoothSignal signal(NS_LITERAL_STRING("PropertyChanged"), 1.411 + remoteDeviceBdAddress, props); 1.412 + nsRefPtr<DistributeBluetoothSignalTask> 1.413 + t = new DistributeBluetoothSignalTask(signal); 1.414 + if (NS_FAILED(NS_DispatchToMainThread(t))) { 1.415 + BT_WARNING("Failed to dispatch to main thread!"); 1.416 + } 1.417 + 1.418 + // Use address as the index 1.419 + sRemoteDevicesPack.AppendElement( 1.420 + BluetoothNamedValue(remoteDeviceBdAddress, props)); 1.421 + 1.422 + if (sRequestedDeviceCountArray[0] == 0) { 1.423 + MOZ_ASSERT(!sGetDeviceRunnableArray.IsEmpty()); 1.424 + 1.425 + if (sGetDeviceRunnableArray.IsEmpty()) { 1.426 + BT_LOGR("No runnable to return"); 1.427 + return; 1.428 + } 1.429 + 1.430 + DispatchBluetoothReply(sGetDeviceRunnableArray[0], 1.431 + sRemoteDevicesPack, EmptyString()); 1.432 + 1.433 + // After firing it, clean up cache 1.434 + sRemoteDevicesPack.Clear(); 1.435 + 1.436 + sRequestedDeviceCountArray.RemoveElementAt(0); 1.437 + sGetDeviceRunnableArray.RemoveElementAt(0); 1.438 + } 1.439 +} 1.440 + 1.441 +static void 1.442 +DeviceFoundCallback(int aNumProperties, bt_property_t *aProperties) 1.443 +{ 1.444 + MOZ_ASSERT(!NS_IsMainThread()); 1.445 + 1.446 + BluetoothValue propertyValue; 1.447 + InfallibleTArray<BluetoothNamedValue> propertiesArray; 1.448 + 1.449 + for (int i = 0; i < aNumProperties; i++) { 1.450 + bt_property_t p = aProperties[i]; 1.451 + 1.452 + if (p.type == BT_PROPERTY_BDADDR) { 1.453 + nsString remoteDeviceBdAddress; 1.454 + BdAddressTypeToString((bt_bdaddr_t*)p.val, remoteDeviceBdAddress); 1.455 + propertyValue = remoteDeviceBdAddress; 1.456 + 1.457 + BT_APPEND_NAMED_VALUE(propertiesArray, "Address", propertyValue); 1.458 + } else if (p.type == BT_PROPERTY_BDNAME) { 1.459 + propertyValue = NS_ConvertUTF8toUTF16((char*)p.val); 1.460 + BT_APPEND_NAMED_VALUE(propertiesArray, "Name", propertyValue); 1.461 + } else if (p.type == BT_PROPERTY_CLASS_OF_DEVICE) { 1.462 + uint32_t cod = *(uint32_t*)p.val; 1.463 + propertyValue = cod; 1.464 + BT_APPEND_NAMED_VALUE(propertiesArray, "Class", propertyValue); 1.465 + 1.466 + nsString icon; 1.467 + ClassToIcon(cod, icon); 1.468 + propertyValue = icon; 1.469 + BT_APPEND_NAMED_VALUE(propertiesArray, "Icon", propertyValue); 1.470 + } else { 1.471 + BT_LOGD("Not handled remote device property: %d", p.type); 1.472 + } 1.473 + } 1.474 + 1.475 + BluetoothValue value = propertiesArray; 1.476 + BluetoothSignal signal(NS_LITERAL_STRING("DeviceFound"), 1.477 + NS_LITERAL_STRING(KEY_ADAPTER), value); 1.478 + nsRefPtr<DistributeBluetoothSignalTask> 1.479 + t = new DistributeBluetoothSignalTask(signal); 1.480 + if (NS_FAILED(NS_DispatchToMainThread(t))) { 1.481 + BT_WARNING("Failed to dispatch to main thread!"); 1.482 + } 1.483 +} 1.484 + 1.485 +static void 1.486 +DiscoveryStateChangedCallback(bt_discovery_state_t aState) 1.487 +{ 1.488 + MOZ_ASSERT(!NS_IsMainThread()); 1.489 + 1.490 + if (!sChangeDiscoveryRunnableArray.IsEmpty()) { 1.491 + BluetoothValue values(true); 1.492 + DispatchBluetoothReply(sChangeDiscoveryRunnableArray[0], 1.493 + values, EmptyString()); 1.494 + 1.495 + sChangeDiscoveryRunnableArray.RemoveElementAt(0); 1.496 + } 1.497 +} 1.498 + 1.499 +static void 1.500 +PinRequestCallback(bt_bdaddr_t* aRemoteBdAddress, 1.501 + bt_bdname_t* aRemoteBdName, uint32_t aRemoteClass) 1.502 +{ 1.503 + MOZ_ASSERT(!NS_IsMainThread()); 1.504 + 1.505 + InfallibleTArray<BluetoothNamedValue> propertiesArray; 1.506 + nsAutoString remoteAddress; 1.507 + BdAddressTypeToString(aRemoteBdAddress, remoteAddress); 1.508 + 1.509 + BT_APPEND_NAMED_VALUE(propertiesArray, "address", remoteAddress); 1.510 + BT_APPEND_NAMED_VALUE(propertiesArray, "method", 1.511 + NS_LITERAL_STRING("pincode")); 1.512 + BT_APPEND_NAMED_VALUE(propertiesArray, "name", 1.513 + NS_ConvertUTF8toUTF16( 1.514 + (const char*)aRemoteBdName->name)); 1.515 + 1.516 + BluetoothValue value = propertiesArray; 1.517 + BluetoothSignal signal(NS_LITERAL_STRING("RequestPinCode"), 1.518 + NS_LITERAL_STRING(KEY_LOCAL_AGENT), value); 1.519 + nsRefPtr<DistributeBluetoothSignalTask> 1.520 + t = new DistributeBluetoothSignalTask(signal); 1.521 + if (NS_FAILED(NS_DispatchToMainThread(t))) { 1.522 + BT_WARNING("Failed to dispatch to main thread!"); 1.523 + } 1.524 +} 1.525 + 1.526 +static void 1.527 +SspRequestCallback(bt_bdaddr_t* aRemoteBdAddress, bt_bdname_t* aRemoteBdName, 1.528 + uint32_t aRemoteClass, bt_ssp_variant_t aPairingVariant, 1.529 + uint32_t aPasskey) 1.530 +{ 1.531 + MOZ_ASSERT(!NS_IsMainThread()); 1.532 + 1.533 + InfallibleTArray<BluetoothNamedValue> propertiesArray; 1.534 + nsAutoString remoteAddress; 1.535 + BdAddressTypeToString(aRemoteBdAddress, remoteAddress); 1.536 + 1.537 + BT_APPEND_NAMED_VALUE(propertiesArray, "address", remoteAddress); 1.538 + BT_APPEND_NAMED_VALUE(propertiesArray, "method", 1.539 + NS_LITERAL_STRING("confirmation")); 1.540 + BT_APPEND_NAMED_VALUE(propertiesArray, "name", 1.541 + NS_ConvertUTF8toUTF16( 1.542 + (const char*)aRemoteBdName->name)); 1.543 + BT_APPEND_NAMED_VALUE(propertiesArray, "passkey", aPasskey); 1.544 + 1.545 + BluetoothValue value = propertiesArray; 1.546 + BluetoothSignal signal(NS_LITERAL_STRING("RequestConfirmation"), 1.547 + NS_LITERAL_STRING(KEY_LOCAL_AGENT), value); 1.548 + nsRefPtr<DistributeBluetoothSignalTask> 1.549 + t = new DistributeBluetoothSignalTask(signal); 1.550 + if (NS_FAILED(NS_DispatchToMainThread(t))) { 1.551 + BT_WARNING("Failed to dispatch to main thread!"); 1.552 + } 1.553 +} 1.554 + 1.555 +static void 1.556 +BondStateChangedCallback(bt_status_t aStatus, bt_bdaddr_t* aRemoteBdAddress, 1.557 + bt_bond_state_t aState) 1.558 +{ 1.559 + MOZ_ASSERT(!NS_IsMainThread()); 1.560 + 1.561 + nsAutoString remoteAddress; 1.562 + BdAddressTypeToString(aRemoteBdAddress, remoteAddress); 1.563 + 1.564 + // We don't need to handle bonding state 1.565 + NS_ENSURE_TRUE_VOID(aState != BT_BOND_STATE_BONDING); 1.566 + NS_ENSURE_FALSE_VOID(aState == BT_BOND_STATE_BONDED && 1.567 + sAdapterBondedAddressArray.Contains(remoteAddress)); 1.568 + bool bonded; 1.569 + if (aState == BT_BOND_STATE_NONE) { 1.570 + bonded = false; 1.571 + sAdapterBondedAddressArray.RemoveElement(remoteAddress); 1.572 + } else if (aState == BT_BOND_STATE_BONDED) { 1.573 + bonded = true; 1.574 + sAdapterBondedAddressArray.AppendElement(remoteAddress); 1.575 + } 1.576 + 1.577 + // Update bonded address list to BluetoothAdapter 1.578 + InfallibleTArray<BluetoothNamedValue> propertiesChangeArray; 1.579 + BT_APPEND_NAMED_VALUE(propertiesChangeArray, "Devices", 1.580 + sAdapterBondedAddressArray); 1.581 + 1.582 + BluetoothValue value(propertiesChangeArray); 1.583 + BluetoothSignal signal(NS_LITERAL_STRING("PropertyChanged"), 1.584 + NS_LITERAL_STRING(KEY_ADAPTER), 1.585 + BluetoothValue(propertiesChangeArray)); 1.586 + NS_DispatchToMainThread(new DistributeBluetoothSignalTask(signal)); 1.587 + 1.588 + // Update bonding status to gaia 1.589 + InfallibleTArray<BluetoothNamedValue> propertiesArray; 1.590 + BT_APPEND_NAMED_VALUE(propertiesArray, "address", remoteAddress); 1.591 + BT_APPEND_NAMED_VALUE(propertiesArray, "status", bonded); 1.592 + 1.593 + BluetoothSignal newSignal(NS_LITERAL_STRING(PAIRED_STATUS_CHANGED_ID), 1.594 + NS_LITERAL_STRING(KEY_ADAPTER), 1.595 + BluetoothValue(propertiesArray)); 1.596 + NS_DispatchToMainThread(new DistributeBluetoothSignalTask(newSignal)); 1.597 + 1.598 + if (bonded && !sBondingRunnableArray.IsEmpty()) { 1.599 + DispatchBluetoothReply(sBondingRunnableArray[0], 1.600 + BluetoothValue(true), EmptyString()); 1.601 + 1.602 + sBondingRunnableArray.RemoveElementAt(0); 1.603 + } else if (!bonded && !sUnbondingRunnableArray.IsEmpty()) { 1.604 + DispatchBluetoothReply(sUnbondingRunnableArray[0], 1.605 + BluetoothValue(true), EmptyString()); 1.606 + 1.607 + sUnbondingRunnableArray.RemoveElementAt(0); 1.608 + } 1.609 +} 1.610 + 1.611 +static void 1.612 +AclStateChangedCallback(bt_status_t aStatus, bt_bdaddr_t* aRemoteBdAddress, 1.613 + bt_acl_state_t aState) 1.614 +{ 1.615 + //FIXME: This will be implemented in the later patchset 1.616 +} 1.617 + 1.618 +static void 1.619 +CallbackThreadEvent(bt_cb_thread_evt evt) 1.620 +{ 1.621 + //FIXME: This will be implemented in the later patchset 1.622 +} 1.623 + 1.624 +bt_callbacks_t sBluetoothCallbacks = 1.625 +{ 1.626 + sizeof(sBluetoothCallbacks), 1.627 + AdapterStateChangeCallback, 1.628 + AdapterPropertiesCallback, 1.629 + RemoteDevicePropertiesCallback, 1.630 + DeviceFoundCallback, 1.631 + DiscoveryStateChangedCallback, 1.632 + PinRequestCallback, 1.633 + SspRequestCallback, 1.634 + BondStateChangedCallback, 1.635 + AclStateChangedCallback, 1.636 + CallbackThreadEvent 1.637 +}; 1.638 + 1.639 +/** 1.640 + * Static functions 1.641 + */ 1.642 +static bool 1.643 +EnsureBluetoothHalLoad() 1.644 +{ 1.645 + hw_module_t* module; 1.646 + hw_device_t* device; 1.647 + int err = hw_get_module(BT_HARDWARE_MODULE_ID, (hw_module_t const**)&module); 1.648 + if (err != 0) { 1.649 + BT_LOGR("Error: %s", strerror(err)); 1.650 + return false; 1.651 + } 1.652 + module->methods->open(module, BT_HARDWARE_MODULE_ID, &device); 1.653 + sBtDevice = (bluetooth_device_t *)device; 1.654 + sBtInterface = sBtDevice->get_bluetooth_interface(); 1.655 + 1.656 + int ret = sBtInterface->init(&sBluetoothCallbacks); 1.657 + if (ret != BT_STATUS_SUCCESS) { 1.658 + BT_LOGR("Error while setting the callbacks"); 1.659 + sBtInterface = nullptr; 1.660 + } 1.661 + 1.662 + return true; 1.663 +} 1.664 + 1.665 +static nsresult 1.666 +StartStopGonkBluetooth(bool aShouldEnable) 1.667 +{ 1.668 + MOZ_ASSERT(NS_IsMainThread()); 1.669 + NS_ENSURE_TRUE(sBtInterface, NS_ERROR_FAILURE); 1.670 + 1.671 + if (sIsBtEnabled == aShouldEnable) { 1.672 + // Keep current enable status 1.673 + nsRefPtr<nsRunnable> runnable = 1.674 + new BluetoothService::ToggleBtAck(sIsBtEnabled); 1.675 + if (NS_FAILED(NS_DispatchToMainThread(runnable))) { 1.676 + BT_WARNING("Failed to dispatch to main thread!"); 1.677 + } 1.678 + return NS_OK; 1.679 + } 1.680 + 1.681 + int ret = aShouldEnable ? sBtInterface->enable() : sBtInterface->disable(); 1.682 + NS_ENSURE_TRUE(ret == BT_STATUS_SUCCESS, NS_ERROR_FAILURE); 1.683 + 1.684 + return NS_OK; 1.685 +} 1.686 + 1.687 +static void 1.688 +ReplyStatusError(BluetoothReplyRunnable* aBluetoothReplyRunnable, 1.689 + int aStatusCode, const nsAString& aCustomMsg) 1.690 +{ 1.691 + MOZ_ASSERT(aBluetoothReplyRunnable, "Reply runnable is nullptr"); 1.692 + 1.693 + BT_LOGR("error code(%d)", aStatusCode); 1.694 + 1.695 + nsAutoString replyError; 1.696 + replyError.Assign(aCustomMsg); 1.697 + 1.698 + if (aStatusCode == BT_STATUS_BUSY) { 1.699 + replyError.AppendLiteral(":BT_STATUS_BUSY"); 1.700 + } else if (aStatusCode == BT_STATUS_NOT_READY) { 1.701 + replyError.AppendLiteral(":BT_STATUS_NOT_READY"); 1.702 + } else if (aStatusCode == BT_STATUS_DONE) { 1.703 + replyError.AppendLiteral(":BT_STATUS_DONE"); 1.704 + } else if (aStatusCode == BT_STATUS_AUTH_FAILURE) { 1.705 + replyError.AppendLiteral(":BT_STATUS_AUTH_FAILURE"); 1.706 + } else if (aStatusCode == BT_STATUS_RMT_DEV_DOWN) { 1.707 + replyError.AppendLiteral(":BT_STATUS_RMT_DEV_DOWN"); 1.708 + } else if (aStatusCode == BT_STATUS_FAIL) { 1.709 + replyError.AppendLiteral(":BT_STATUS_FAIL"); 1.710 + } 1.711 + 1.712 + DispatchBluetoothReply(aBluetoothReplyRunnable, BluetoothValue(true), 1.713 + replyError); 1.714 +} 1.715 + 1.716 +/** 1.717 + * Member functions 1.718 + */ 1.719 +BluetoothServiceBluedroid::BluetoothServiceBluedroid() 1.720 +{ 1.721 + if (!EnsureBluetoothHalLoad()) { 1.722 + BT_LOGR("Error! Failed to load bluedroid library."); 1.723 + return; 1.724 + } 1.725 + 1.726 + // Register all the bluedroid callbacks before enable() get called 1.727 + // It is required to register a2dp callbacks before a2dp media task starts up. 1.728 + BluetoothHfpManager::Get(); 1.729 + BluetoothA2dpManager::Get(); 1.730 +} 1.731 + 1.732 +BluetoothServiceBluedroid::~BluetoothServiceBluedroid() 1.733 +{ 1.734 +} 1.735 + 1.736 +nsresult 1.737 +BluetoothServiceBluedroid::StartInternal() 1.738 +{ 1.739 + MOZ_ASSERT(NS_IsMainThread()); 1.740 + 1.741 + nsresult ret = StartStopGonkBluetooth(true); 1.742 + if (NS_FAILED(ret)) { 1.743 + nsRefPtr<nsRunnable> runnable = 1.744 + new BluetoothService::ToggleBtAck(false); 1.745 + if (NS_FAILED(NS_DispatchToMainThread(runnable))) { 1.746 + BT_WARNING("Failed to dispatch to main thread!"); 1.747 + } 1.748 + BT_LOGR("Error"); 1.749 + } 1.750 + 1.751 + return ret; 1.752 +} 1.753 + 1.754 +nsresult 1.755 +BluetoothServiceBluedroid::StopInternal() 1.756 +{ 1.757 + MOZ_ASSERT(NS_IsMainThread()); 1.758 + 1.759 + nsresult ret = StartStopGonkBluetooth(false); 1.760 + if (NS_FAILED(ret)) { 1.761 + nsRefPtr<nsRunnable> runnable = 1.762 + new BluetoothService::ToggleBtAck(true); 1.763 + if (NS_FAILED(NS_DispatchToMainThread(runnable))) { 1.764 + BT_WARNING("Failed to dispatch to main thread!"); 1.765 + } 1.766 + BT_LOGR("Error"); 1.767 + } 1.768 + 1.769 + return ret; 1.770 +} 1.771 + 1.772 +nsresult 1.773 +BluetoothServiceBluedroid::GetDefaultAdapterPathInternal( 1.774 + BluetoothReplyRunnable* aRunnable) 1.775 +{ 1.776 + MOZ_ASSERT(NS_IsMainThread()); 1.777 + 1.778 + nsRefPtr<BluetoothReplyRunnable> runnable(aRunnable); 1.779 + 1.780 + BluetoothValue v = InfallibleTArray<BluetoothNamedValue>(); 1.781 + 1.782 + BT_APPEND_NAMED_VALUE(v.get_ArrayOfBluetoothNamedValue(), 1.783 + "Address", sAdapterBdAddress); 1.784 + 1.785 + BT_APPEND_NAMED_VALUE(v.get_ArrayOfBluetoothNamedValue(), 1.786 + "Name", sAdapterBdName); 1.787 + 1.788 + BT_APPEND_NAMED_VALUE(v.get_ArrayOfBluetoothNamedValue(), 1.789 + "Discoverable", sAdapterDiscoverable); 1.790 + 1.791 + BT_APPEND_NAMED_VALUE(v.get_ArrayOfBluetoothNamedValue(), 1.792 + "DiscoverableTimeout", sAdapterDiscoverableTimeout); 1.793 + 1.794 + BT_APPEND_NAMED_VALUE(v.get_ArrayOfBluetoothNamedValue(), 1.795 + "Devices", sAdapterBondedAddressArray); 1.796 + 1.797 + nsAutoString replyError; 1.798 + DispatchBluetoothReply(runnable.get(), v, replyError); 1.799 + 1.800 + unused << runnable.forget(); // picked up in DispatchBluetoothReply 1.801 + 1.802 + return NS_OK; 1.803 +} 1.804 + 1.805 +nsresult 1.806 +BluetoothServiceBluedroid::GetConnectedDevicePropertiesInternal( 1.807 + uint16_t aServiceUuid, BluetoothReplyRunnable* aRunnable) 1.808 +{ 1.809 + MOZ_ASSERT(NS_IsMainThread()); 1.810 + 1.811 + if (!IsReady()) { 1.812 + NS_NAMED_LITERAL_STRING(errorStr, "Bluetooth service is not ready yet!"); 1.813 + DispatchBluetoothReply(aRunnable, BluetoothValue(), errorStr); 1.814 + return NS_OK; 1.815 + } 1.816 + 1.817 + BluetoothProfileManagerBase* profile = 1.818 + BluetoothUuidHelper::GetBluetoothProfileManager(aServiceUuid); 1.819 + if (!profile) { 1.820 + InfallibleTArray<BluetoothNamedValue> emptyArr; 1.821 + DispatchBluetoothReply(aRunnable, emptyArr, 1.822 + NS_LITERAL_STRING(ERR_UNKNOWN_PROFILE)); 1.823 + return NS_OK; 1.824 + } 1.825 + 1.826 + nsTArray<nsString> deviceAddresses; 1.827 + if (profile->IsConnected()) { 1.828 + nsString address; 1.829 + profile->GetAddress(address); 1.830 + deviceAddresses.AppendElement(address); 1.831 + } 1.832 + 1.833 + int requestedDeviceCount = deviceAddresses.Length(); 1.834 + if (requestedDeviceCount == 0) { 1.835 + InfallibleTArray<BluetoothNamedValue> emptyArr; 1.836 + DispatchBluetoothReply(aRunnable, emptyArr, EmptyString()); 1.837 + return NS_OK; 1.838 + } 1.839 + 1.840 + for (int i = 0; i < requestedDeviceCount; i++) { 1.841 + // Retrieve all properties of devices 1.842 + bt_bdaddr_t addressType; 1.843 + StringToBdAddressType(deviceAddresses[i], &addressType); 1.844 + 1.845 + int ret = sBtInterface->get_remote_device_properties(&addressType); 1.846 + if (ret != BT_STATUS_SUCCESS) { 1.847 + DispatchBluetoothReply(aRunnable, BluetoothValue(true), 1.848 + NS_LITERAL_STRING("GetConnectedDeviceFailed")); 1.849 + return NS_OK; 1.850 + } 1.851 + } 1.852 + 1.853 + sRequestedDeviceCountArray.AppendElement(requestedDeviceCount); 1.854 + sGetDeviceRunnableArray.AppendElement(aRunnable); 1.855 + 1.856 + return NS_OK; 1.857 +} 1.858 + 1.859 +nsresult 1.860 +BluetoothServiceBluedroid::GetPairedDevicePropertiesInternal( 1.861 + const nsTArray<nsString>& aDeviceAddress, BluetoothReplyRunnable* aRunnable) 1.862 +{ 1.863 + MOZ_ASSERT(NS_IsMainThread()); 1.864 + 1.865 + if (!IsReady()) { 1.866 + NS_NAMED_LITERAL_STRING(errorStr, "Bluetooth service is not ready yet!"); 1.867 + DispatchBluetoothReply(aRunnable, BluetoothValue(), errorStr); 1.868 + return NS_OK; 1.869 + } 1.870 + 1.871 + int requestedDeviceCount = aDeviceAddress.Length(); 1.872 + if (requestedDeviceCount == 0) { 1.873 + InfallibleTArray<BluetoothNamedValue> emptyArr; 1.874 + DispatchBluetoothReply(aRunnable, BluetoothValue(emptyArr), EmptyString()); 1.875 + return NS_OK; 1.876 + } 1.877 + 1.878 + for (int i = 0; i < requestedDeviceCount; i++) { 1.879 + // Retrieve all properties of devices 1.880 + bt_bdaddr_t addressType; 1.881 + StringToBdAddressType(aDeviceAddress[i], &addressType); 1.882 + int ret = sBtInterface->get_remote_device_properties(&addressType); 1.883 + if (ret != BT_STATUS_SUCCESS) { 1.884 + DispatchBluetoothReply(aRunnable, BluetoothValue(true), 1.885 + NS_LITERAL_STRING("GetPairedDeviceFailed")); 1.886 + return NS_OK; 1.887 + } 1.888 + } 1.889 + 1.890 + sRequestedDeviceCountArray.AppendElement(requestedDeviceCount); 1.891 + sGetDeviceRunnableArray.AppendElement(aRunnable); 1.892 + 1.893 + return NS_OK; 1.894 +} 1.895 + 1.896 +nsresult 1.897 +BluetoothServiceBluedroid::StartDiscoveryInternal( 1.898 + BluetoothReplyRunnable* aRunnable) 1.899 +{ 1.900 + MOZ_ASSERT(NS_IsMainThread()); 1.901 + 1.902 + if (!IsReady()) { 1.903 + NS_NAMED_LITERAL_STRING(errorStr, "Bluetooth service is not ready yet!"); 1.904 + DispatchBluetoothReply(aRunnable, BluetoothValue(), errorStr); 1.905 + 1.906 + return NS_OK; 1.907 + } 1.908 + int ret = sBtInterface->start_discovery(); 1.909 + if (ret != BT_STATUS_SUCCESS) { 1.910 + ReplyStatusError(aRunnable, ret, NS_LITERAL_STRING("StartDiscovery")); 1.911 + 1.912 + return NS_OK; 1.913 + } 1.914 + 1.915 + sChangeDiscoveryRunnableArray.AppendElement(aRunnable); 1.916 + return NS_OK; 1.917 +} 1.918 + 1.919 +nsresult 1.920 +BluetoothServiceBluedroid::StopDiscoveryInternal( 1.921 + BluetoothReplyRunnable* aRunnable) 1.922 +{ 1.923 + MOZ_ASSERT(NS_IsMainThread()); 1.924 + 1.925 + if (!IsReady()) { 1.926 + NS_NAMED_LITERAL_STRING(errorStr, "Bluetooth service is not ready yet!"); 1.927 + DispatchBluetoothReply(aRunnable, BluetoothValue(), errorStr); 1.928 + return NS_OK; 1.929 + } 1.930 + 1.931 + int ret = sBtInterface->cancel_discovery(); 1.932 + if (ret != BT_STATUS_SUCCESS) { 1.933 + ReplyStatusError(aRunnable, ret, NS_LITERAL_STRING("StopDiscovery")); 1.934 + return NS_OK; 1.935 + } 1.936 + 1.937 + sChangeDiscoveryRunnableArray.AppendElement(aRunnable); 1.938 + 1.939 + return NS_OK; 1.940 +} 1.941 + 1.942 +nsresult 1.943 +BluetoothServiceBluedroid::SetProperty(BluetoothObjectType aType, 1.944 + const BluetoothNamedValue& aValue, 1.945 + BluetoothReplyRunnable* aRunnable) 1.946 +{ 1.947 + MOZ_ASSERT(NS_IsMainThread()); 1.948 + 1.949 + if (!IsReady()) { 1.950 + NS_NAMED_LITERAL_STRING(errorStr, "Bluetooth service is not ready yet!"); 1.951 + DispatchBluetoothReply(aRunnable, BluetoothValue(), errorStr); 1.952 + 1.953 + return NS_OK; 1.954 + } 1.955 + 1.956 + const nsString propName = aValue.name(); 1.957 + bt_property_t prop; 1.958 + bt_scan_mode_t scanMode; 1.959 + nsCString str; 1.960 + 1.961 + // For Bluedroid, it's necessary to check property name for SetProperty 1.962 + if (propName.EqualsLiteral("Name")) { 1.963 + prop.type = BT_PROPERTY_BDNAME; 1.964 + } else if (propName.EqualsLiteral("Discoverable")) { 1.965 + prop.type = BT_PROPERTY_ADAPTER_SCAN_MODE; 1.966 + } else if (propName.EqualsLiteral("DiscoverableTimeout")) { 1.967 + prop.type = BT_PROPERTY_ADAPTER_DISCOVERY_TIMEOUT; 1.968 + } else { 1.969 + BT_LOGR("Warning: Property type is not supported yet, type: %d", prop.type); 1.970 + } 1.971 + 1.972 + if (aValue.value().type() == BluetoothValue::Tuint32_t) { 1.973 + // Set discoverable timeout 1.974 + prop.val = (void*)aValue.value().get_uint32_t(); 1.975 + } else if (aValue.value().type() == BluetoothValue::TnsString) { 1.976 + // Set name 1.977 + str = NS_ConvertUTF16toUTF8(aValue.value().get_nsString()); 1.978 + const char* name = str.get(); 1.979 + prop.val = (void*)name; 1.980 + prop.len = strlen(name); 1.981 + } else if (aValue.value().type() == BluetoothValue::Tbool) { 1.982 + scanMode = aValue.value().get_bool() ? 1.983 + BT_SCAN_MODE_CONNECTABLE_DISCOVERABLE : 1.984 + BT_SCAN_MODE_CONNECTABLE; 1.985 + 1.986 + prop.val = (void*)&scanMode; 1.987 + prop.len = sizeof(scanMode); 1.988 + } else { 1.989 + BT_LOGR("SetProperty but the property cannot be recognized correctly."); 1.990 + return NS_OK; 1.991 + } 1.992 + 1.993 + sSetPropertyRunnableArray.AppendElement(aRunnable); 1.994 + 1.995 + int ret = sBtInterface->set_adapter_property(&prop); 1.996 + if (ret != BT_STATUS_SUCCESS) { 1.997 + ReplyStatusError(aRunnable, ret, NS_LITERAL_STRING("SetProperty")); 1.998 + } 1.999 + 1.1000 + return NS_OK; 1.1001 +} 1.1002 + 1.1003 +nsresult 1.1004 +BluetoothServiceBluedroid::GetServiceChannel( 1.1005 + const nsAString& aDeviceAddress, 1.1006 + const nsAString& aServiceUuid, 1.1007 + BluetoothProfileManagerBase* aManager) 1.1008 +{ 1.1009 + return NS_OK; 1.1010 +} 1.1011 + 1.1012 +bool 1.1013 +BluetoothServiceBluedroid::UpdateSdpRecords( 1.1014 + const nsAString& aDeviceAddress, 1.1015 + BluetoothProfileManagerBase* aManager) 1.1016 +{ 1.1017 + return true; 1.1018 +} 1.1019 + 1.1020 +nsresult 1.1021 +BluetoothServiceBluedroid::CreatePairedDeviceInternal( 1.1022 + const nsAString& aDeviceAddress, int aTimeout, 1.1023 + BluetoothReplyRunnable* aRunnable) 1.1024 +{ 1.1025 + MOZ_ASSERT(NS_IsMainThread()); 1.1026 + 1.1027 + if (!IsReady()) { 1.1028 + NS_NAMED_LITERAL_STRING(errorStr, "Bluetooth service is not ready yet!"); 1.1029 + DispatchBluetoothReply(aRunnable, BluetoothValue(), errorStr); 1.1030 + return NS_OK; 1.1031 + } 1.1032 + 1.1033 + bt_bdaddr_t remoteAddress; 1.1034 + StringToBdAddressType(aDeviceAddress, &remoteAddress); 1.1035 + 1.1036 + int ret = sBtInterface->create_bond(&remoteAddress); 1.1037 + if (ret != BT_STATUS_SUCCESS) { 1.1038 + ReplyStatusError(aRunnable, ret, NS_LITERAL_STRING("CreatedPairedDevice")); 1.1039 + } else { 1.1040 + sBondingRunnableArray.AppendElement(aRunnable); 1.1041 + } 1.1042 + 1.1043 + return NS_OK; 1.1044 +} 1.1045 + 1.1046 +nsresult 1.1047 +BluetoothServiceBluedroid::RemoveDeviceInternal( 1.1048 + const nsAString& aDeviceAddress, BluetoothReplyRunnable* aRunnable) 1.1049 +{ 1.1050 + MOZ_ASSERT(NS_IsMainThread()); 1.1051 + 1.1052 + if (!IsReady()) { 1.1053 + NS_NAMED_LITERAL_STRING(errorStr, "Bluetooth service is not ready yet!"); 1.1054 + DispatchBluetoothReply(aRunnable, BluetoothValue(), errorStr); 1.1055 + return NS_OK; 1.1056 + } 1.1057 + 1.1058 + bt_bdaddr_t remoteAddress; 1.1059 + StringToBdAddressType(aDeviceAddress, &remoteAddress); 1.1060 + 1.1061 + int ret = sBtInterface->remove_bond(&remoteAddress); 1.1062 + if (ret != BT_STATUS_SUCCESS) { 1.1063 + ReplyStatusError(aRunnable, ret, 1.1064 + NS_LITERAL_STRING("RemoveDevice")); 1.1065 + } else { 1.1066 + sUnbondingRunnableArray.AppendElement(aRunnable); 1.1067 + } 1.1068 + 1.1069 + return NS_OK; 1.1070 +} 1.1071 + 1.1072 +bool 1.1073 +BluetoothServiceBluedroid::SetPinCodeInternal( 1.1074 + const nsAString& aDeviceAddress, const nsAString& aPinCode, 1.1075 + BluetoothReplyRunnable* aRunnable) 1.1076 +{ 1.1077 + MOZ_ASSERT(NS_IsMainThread()); 1.1078 + 1.1079 + if (!IsReady()) { 1.1080 + NS_NAMED_LITERAL_STRING(errorStr, "Bluetooth service is not ready yet!"); 1.1081 + DispatchBluetoothReply(aRunnable, BluetoothValue(), errorStr); 1.1082 + return false; 1.1083 + } 1.1084 + 1.1085 + bt_bdaddr_t remoteAddress; 1.1086 + StringToBdAddressType(aDeviceAddress, &remoteAddress); 1.1087 + 1.1088 + int ret = sBtInterface->pin_reply( 1.1089 + &remoteAddress, true, aPinCode.Length(), 1.1090 + (bt_pin_code_t*)NS_ConvertUTF16toUTF8(aPinCode).get()); 1.1091 + 1.1092 + if (ret != BT_STATUS_SUCCESS) { 1.1093 + ReplyStatusError(aRunnable, ret, NS_LITERAL_STRING("SetPinCode")); 1.1094 + } else { 1.1095 + DispatchBluetoothReply(aRunnable, BluetoothValue(true), EmptyString()); 1.1096 + } 1.1097 + 1.1098 + return true; 1.1099 +} 1.1100 + 1.1101 +bool 1.1102 +BluetoothServiceBluedroid::SetPasskeyInternal( 1.1103 + const nsAString& aDeviceAddress, uint32_t aPasskey, 1.1104 + BluetoothReplyRunnable* aRunnable) 1.1105 +{ 1.1106 + return true; 1.1107 +} 1.1108 + 1.1109 +bool 1.1110 +BluetoothServiceBluedroid::SetPairingConfirmationInternal( 1.1111 + const nsAString& aDeviceAddress, bool aConfirm, 1.1112 + BluetoothReplyRunnable* aRunnable) 1.1113 +{ 1.1114 + MOZ_ASSERT(NS_IsMainThread()); 1.1115 + 1.1116 + if (!IsReady()) { 1.1117 + NS_NAMED_LITERAL_STRING(errorStr, "Bluetooth service is not ready yet!"); 1.1118 + DispatchBluetoothReply(aRunnable, BluetoothValue(), errorStr); 1.1119 + return false; 1.1120 + } 1.1121 + 1.1122 + bt_bdaddr_t remoteAddress; 1.1123 + StringToBdAddressType(aDeviceAddress, &remoteAddress); 1.1124 + 1.1125 + int ret = sBtInterface->ssp_reply(&remoteAddress, (bt_ssp_variant_t)0, 1.1126 + aConfirm, 0); 1.1127 + if (ret != BT_STATUS_SUCCESS) { 1.1128 + ReplyStatusError(aRunnable, ret, 1.1129 + NS_LITERAL_STRING("SetPairingConfirmation")); 1.1130 + } else { 1.1131 + DispatchBluetoothReply(aRunnable, BluetoothValue(true), EmptyString()); 1.1132 + } 1.1133 + 1.1134 + return true; 1.1135 +} 1.1136 + 1.1137 +bool 1.1138 +BluetoothServiceBluedroid::SetAuthorizationInternal( 1.1139 + const nsAString& aDeviceAddress, bool aAllow, 1.1140 + BluetoothReplyRunnable* aRunnable) 1.1141 +{ 1.1142 + return true; 1.1143 +} 1.1144 + 1.1145 +nsresult 1.1146 +BluetoothServiceBluedroid::PrepareAdapterInternal() 1.1147 +{ 1.1148 + return NS_OK; 1.1149 +} 1.1150 + 1.1151 +static void 1.1152 +NextBluetoothProfileController() 1.1153 +{ 1.1154 + MOZ_ASSERT(NS_IsMainThread()); 1.1155 + 1.1156 + // First, remove the task at the front which has been already done. 1.1157 + NS_ENSURE_FALSE_VOID(sControllerArray.IsEmpty()); 1.1158 + sControllerArray.RemoveElementAt(0); 1.1159 + // Re-check if the task array is empty, if it's not, the next task will begin. 1.1160 + NS_ENSURE_FALSE_VOID(sControllerArray.IsEmpty()); 1.1161 + sControllerArray[0]->StartSession(); 1.1162 +} 1.1163 + 1.1164 +static void 1.1165 +ConnectDisconnect(bool aConnect, const nsAString& aDeviceAddress, 1.1166 + BluetoothReplyRunnable* aRunnable, 1.1167 + uint16_t aServiceUuid, uint32_t aCod = 0) 1.1168 +{ 1.1169 + MOZ_ASSERT(NS_IsMainThread()); 1.1170 + MOZ_ASSERT(aRunnable); 1.1171 + 1.1172 + BluetoothProfileController* controller = 1.1173 + new BluetoothProfileController(aConnect, aDeviceAddress, aRunnable, 1.1174 + NextBluetoothProfileController, 1.1175 + aServiceUuid, aCod); 1.1176 + sControllerArray.AppendElement(controller); 1.1177 + 1.1178 + /** 1.1179 + * If the request is the first element of the quene, start from here. Note 1.1180 + * that other request is pushed into the quene and is popped out after the 1.1181 + * first one is completed. See NextBluetoothProfileController() for details. 1.1182 + */ 1.1183 + if (sControllerArray.Length() == 1) { 1.1184 + sControllerArray[0]->StartSession(); 1.1185 + } 1.1186 +} 1.1187 + 1.1188 +const bt_interface_t* 1.1189 +BluetoothServiceBluedroid::GetBluetoothInterface() 1.1190 +{ 1.1191 + return sBtInterface; 1.1192 +} 1.1193 + 1.1194 +void 1.1195 +BluetoothServiceBluedroid::Connect(const nsAString& aDeviceAddress, 1.1196 + uint32_t aCod, 1.1197 + uint16_t aServiceUuid, 1.1198 + BluetoothReplyRunnable* aRunnable) 1.1199 +{ 1.1200 + ConnectDisconnect(true, aDeviceAddress, aRunnable, aServiceUuid, aCod); 1.1201 +} 1.1202 + 1.1203 +bool 1.1204 +BluetoothServiceBluedroid::IsConnected(uint16_t aProfileId) 1.1205 +{ 1.1206 + return true; 1.1207 +} 1.1208 + 1.1209 +void 1.1210 +BluetoothServiceBluedroid::Disconnect( 1.1211 + const nsAString& aDeviceAddress, uint16_t aServiceUuid, 1.1212 + BluetoothReplyRunnable* aRunnable) 1.1213 +{ 1.1214 + ConnectDisconnect(false, aDeviceAddress, aRunnable, aServiceUuid); 1.1215 +} 1.1216 + 1.1217 +void 1.1218 +BluetoothServiceBluedroid::SendFile(const nsAString& aDeviceAddress, 1.1219 + BlobParent* aBlobParent, 1.1220 + BlobChild* aBlobChild, 1.1221 + BluetoothReplyRunnable* aRunnable) 1.1222 +{ 1.1223 + MOZ_ASSERT(NS_IsMainThread()); 1.1224 + 1.1225 + // Currently we only support one device sending one file at a time, 1.1226 + // so we don't need aDeviceAddress here because the target device 1.1227 + // has been determined when calling 'Connect()'. Nevertheless, keep 1.1228 + // it for future use. 1.1229 + BluetoothOppManager* opp = BluetoothOppManager::Get(); 1.1230 + nsAutoString errorStr; 1.1231 + if (!opp || !opp->SendFile(aDeviceAddress, aBlobParent)) { 1.1232 + errorStr.AssignLiteral("Calling SendFile() failed"); 1.1233 + } 1.1234 + 1.1235 + DispatchBluetoothReply(aRunnable, BluetoothValue(true), errorStr); 1.1236 +} 1.1237 + 1.1238 +void 1.1239 +BluetoothServiceBluedroid::SendFile(const nsAString& aDeviceAddress, 1.1240 + nsIDOMBlob* aBlob, 1.1241 + BluetoothReplyRunnable* aRunnable) 1.1242 +{ 1.1243 + MOZ_ASSERT(NS_IsMainThread()); 1.1244 + 1.1245 + // Currently we only support one device sending one file at a time, 1.1246 + // so we don't need aDeviceAddress here because the target device 1.1247 + // has been determined when calling 'Connect()'. Nevertheless, keep 1.1248 + // it for future use. 1.1249 + BluetoothOppManager* opp = BluetoothOppManager::Get(); 1.1250 + nsAutoString errorStr; 1.1251 + if (!opp || !opp->SendFile(aDeviceAddress, aBlob)) { 1.1252 + errorStr.AssignLiteral("Calling SendFile() failed"); 1.1253 + } 1.1254 + 1.1255 + DispatchBluetoothReply(aRunnable, BluetoothValue(true), errorStr); 1.1256 +} 1.1257 + 1.1258 +void 1.1259 +BluetoothServiceBluedroid::StopSendingFile(const nsAString& aDeviceAddress, 1.1260 + BluetoothReplyRunnable* aRunnable) 1.1261 +{ 1.1262 + MOZ_ASSERT(NS_IsMainThread()); 1.1263 + 1.1264 + // Currently we only support one device sending one file at a time, 1.1265 + // so we don't need aDeviceAddress here because the target device 1.1266 + // has been determined when calling 'Connect()'. Nevertheless, keep 1.1267 + // it for future use. 1.1268 + BluetoothOppManager* opp = BluetoothOppManager::Get(); 1.1269 + nsAutoString errorStr; 1.1270 + if (!opp || !opp->StopSendingFile()) { 1.1271 + errorStr.AssignLiteral("Calling StopSendingFile() failed"); 1.1272 + } 1.1273 + 1.1274 + DispatchBluetoothReply(aRunnable, BluetoothValue(true), errorStr); 1.1275 +} 1.1276 + 1.1277 +void 1.1278 +BluetoothServiceBluedroid::ConfirmReceivingFile( 1.1279 + const nsAString& aDeviceAddress, bool aConfirm, 1.1280 + BluetoothReplyRunnable* aRunnable) 1.1281 +{ 1.1282 + MOZ_ASSERT(NS_IsMainThread(), "Must be called from main thread!"); 1.1283 + 1.1284 + // Currently we only support one device sending one file at a time, 1.1285 + // so we don't need aDeviceAddress here because the target device 1.1286 + // has been determined when calling 'Connect()'. Nevertheless, keep 1.1287 + // it for future use. 1.1288 + BluetoothOppManager* opp = BluetoothOppManager::Get(); 1.1289 + nsAutoString errorStr; 1.1290 + if (!opp || !opp->ConfirmReceivingFile(aConfirm)) { 1.1291 + errorStr.AssignLiteral("Calling ConfirmReceivingFile() failed"); 1.1292 + } 1.1293 + 1.1294 + DispatchBluetoothReply(aRunnable, BluetoothValue(true), errorStr); 1.1295 +} 1.1296 + 1.1297 +void 1.1298 +BluetoothServiceBluedroid::ConnectSco(BluetoothReplyRunnable* aRunnable) 1.1299 +{ 1.1300 + MOZ_ASSERT(NS_IsMainThread()); 1.1301 + 1.1302 + BluetoothHfpManager* hfp = BluetoothHfpManager::Get(); 1.1303 + if (!hfp || !hfp->ConnectSco()) { 1.1304 + NS_NAMED_LITERAL_STRING(replyError, "Calling ConnectSco() failed"); 1.1305 + DispatchBluetoothReply(aRunnable, BluetoothValue(), replyError); 1.1306 + return; 1.1307 + } 1.1308 + 1.1309 + DispatchBluetoothReply(aRunnable, BluetoothValue(true), EmptyString()); 1.1310 +} 1.1311 + 1.1312 +void 1.1313 +BluetoothServiceBluedroid::DisconnectSco(BluetoothReplyRunnable* aRunnable) 1.1314 +{ 1.1315 + MOZ_ASSERT(NS_IsMainThread()); 1.1316 + 1.1317 + BluetoothHfpManager* hfp = BluetoothHfpManager::Get(); 1.1318 + if (!hfp || !hfp->DisconnectSco()) { 1.1319 + NS_NAMED_LITERAL_STRING(replyError, "Calling DisconnectSco() failed"); 1.1320 + DispatchBluetoothReply(aRunnable, BluetoothValue(), replyError); 1.1321 + return; 1.1322 + } 1.1323 + 1.1324 + DispatchBluetoothReply(aRunnable, BluetoothValue(true), EmptyString()); 1.1325 +} 1.1326 + 1.1327 +void 1.1328 +BluetoothServiceBluedroid::IsScoConnected(BluetoothReplyRunnable* aRunnable) 1.1329 +{ 1.1330 + MOZ_ASSERT(NS_IsMainThread()); 1.1331 + 1.1332 + BluetoothHfpManager* hfp = BluetoothHfpManager::Get(); 1.1333 + if (!hfp) { 1.1334 + NS_NAMED_LITERAL_STRING(replyError, "Fail to get BluetoothHfpManager"); 1.1335 + DispatchBluetoothReply(aRunnable, BluetoothValue(), replyError); 1.1336 + return; 1.1337 + } 1.1338 + 1.1339 + DispatchBluetoothReply(aRunnable, hfp->IsScoConnected(), EmptyString()); 1.1340 +} 1.1341 + 1.1342 +void 1.1343 +BluetoothServiceBluedroid::SendMetaData(const nsAString& aTitle, 1.1344 + const nsAString& aArtist, 1.1345 + const nsAString& aAlbum, 1.1346 + int64_t aMediaNumber, 1.1347 + int64_t aTotalMediaCount, 1.1348 + int64_t aDuration, 1.1349 + BluetoothReplyRunnable* aRunnable) 1.1350 +{ 1.1351 + BluetoothA2dpManager* a2dp = BluetoothA2dpManager::Get(); 1.1352 + if (a2dp) { 1.1353 + a2dp->UpdateMetaData(aTitle, aArtist, aAlbum, aMediaNumber, 1.1354 + aTotalMediaCount, aDuration); 1.1355 + } 1.1356 + DispatchBluetoothReply(aRunnable, BluetoothValue(true), EmptyString()); 1.1357 +} 1.1358 + 1.1359 +void 1.1360 +BluetoothServiceBluedroid::SendPlayStatus( 1.1361 + int64_t aDuration, int64_t aPosition, 1.1362 + const nsAString& aPlayStatus, 1.1363 + BluetoothReplyRunnable* aRunnable) 1.1364 +{ 1.1365 + BluetoothA2dpManager* a2dp = BluetoothA2dpManager::Get(); 1.1366 + if (a2dp) { 1.1367 + ControlPlayStatus playStatus = 1.1368 + PlayStatusStringToControlPlayStatus(aPlayStatus); 1.1369 + a2dp->UpdatePlayStatus(aDuration, aPosition, playStatus); 1.1370 + } 1.1371 + DispatchBluetoothReply(aRunnable, BluetoothValue(true), EmptyString()); 1.1372 +} 1.1373 + 1.1374 +void 1.1375 +BluetoothServiceBluedroid::UpdatePlayStatus( 1.1376 + uint32_t aDuration, uint32_t aPosition, ControlPlayStatus aPlayStatus) 1.1377 +{ 1.1378 + // We don't need this function for bluedroid. 1.1379 + // In bluez, it only calls dbus api 1.1380 + // But it does not update BluetoothA2dpManager member fields 1.1381 + MOZ_ASSERT(false); 1.1382 +} 1.1383 + 1.1384 +nsresult 1.1385 +BluetoothServiceBluedroid::SendSinkMessage(const nsAString& aDeviceAddresses, 1.1386 + const nsAString& aMessage) 1.1387 +{ 1.1388 + return NS_OK; 1.1389 +} 1.1390 + 1.1391 +nsresult 1.1392 +BluetoothServiceBluedroid::SendInputMessage(const nsAString& aDeviceAddresses, 1.1393 + const nsAString& aMessage) 1.1394 +{ 1.1395 + return NS_OK; 1.1396 +} 1.1397 + 1.1398 +void 1.1399 +BluetoothServiceBluedroid::AnswerWaitingCall(BluetoothReplyRunnable* aRunnable) 1.1400 +{ 1.1401 +} 1.1402 + 1.1403 +void 1.1404 +BluetoothServiceBluedroid::IgnoreWaitingCall(BluetoothReplyRunnable* aRunnable) 1.1405 +{ 1.1406 +} 1.1407 + 1.1408 +void 1.1409 +BluetoothServiceBluedroid::ToggleCalls(BluetoothReplyRunnable* aRunnable) 1.1410 +{ 1.1411 +} 1.1412 +