dom/bluetooth/bluedroid/BluetoothServiceBluedroid.cpp

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

michael@0 1 /* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
michael@0 2 /* vim: set ts=2 et sw=2 tw=80: */
michael@0 3 /*
michael@0 4 ** Copyright 2006, The Android Open Source Project
michael@0 5 **
michael@0 6 ** Licensed under the Apache License, Version 2.0 (the "License");
michael@0 7 ** you may not use this file except in compliance with the License.
michael@0 8 ** You may obtain a copy of the License at
michael@0 9 **
michael@0 10 ** http://www.apache.org/licenses/LICENSE-2.0
michael@0 11 **
michael@0 12 ** Unless required by applicable law or agreed to in writing, software
michael@0 13 ** distributed under the License is distributed on an "AS IS" BASIS,
michael@0 14 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
michael@0 15 ** See the License for the specific language governing permissions and
michael@0 16 ** limitations under the License.
michael@0 17 */
michael@0 18
michael@0 19 #include "BluetoothServiceBluedroid.h"
michael@0 20
michael@0 21 #include <hardware/hardware.h>
michael@0 22
michael@0 23 #include "BluetoothA2dpManager.h"
michael@0 24 #include "BluetoothHfpManager.h"
michael@0 25 #include "BluetoothOppManager.h"
michael@0 26 #include "BluetoothProfileController.h"
michael@0 27 #include "BluetoothReplyRunnable.h"
michael@0 28 #include "BluetoothUtils.h"
michael@0 29 #include "BluetoothUuid.h"
michael@0 30 #include "mozilla/dom/bluetooth/BluetoothTypes.h"
michael@0 31 #include "mozilla/ipc/UnixSocket.h"
michael@0 32 #include "mozilla/StaticMutex.h"
michael@0 33 #include "mozilla/StaticPtr.h"
michael@0 34 #include "mozilla/unused.h"
michael@0 35
michael@0 36 using namespace mozilla;
michael@0 37 using namespace mozilla::ipc;
michael@0 38 USING_BLUETOOTH_NAMESPACE
michael@0 39
michael@0 40 /**
michael@0 41 * Static variables
michael@0 42 */
michael@0 43 static bluetooth_device_t* sBtDevice;
michael@0 44 static const bt_interface_t* sBtInterface;
michael@0 45 static bool sAdapterDiscoverable = false;
michael@0 46 static bool sIsBtEnabled = false;
michael@0 47 static nsString sAdapterBdAddress;
michael@0 48 static nsString sAdapterBdName;
michael@0 49 static uint32_t sAdapterDiscoverableTimeout;
michael@0 50 static InfallibleTArray<nsString> sAdapterBondedAddressArray;
michael@0 51 static InfallibleTArray<BluetoothNamedValue> sRemoteDevicesPack;
michael@0 52 static nsTArray<nsRefPtr<BluetoothProfileController> > sControllerArray;
michael@0 53 static nsTArray<nsRefPtr<BluetoothReplyRunnable> > sBondingRunnableArray;
michael@0 54 static nsTArray<nsRefPtr<BluetoothReplyRunnable> > sChangeDiscoveryRunnableArray;
michael@0 55 static nsTArray<nsRefPtr<BluetoothReplyRunnable> > sGetDeviceRunnableArray;
michael@0 56 static nsTArray<nsRefPtr<BluetoothReplyRunnable> > sSetPropertyRunnableArray;
michael@0 57 static nsTArray<nsRefPtr<BluetoothReplyRunnable> > sUnbondingRunnableArray;
michael@0 58 static nsTArray<int> sRequestedDeviceCountArray;
michael@0 59
michael@0 60 /**
michael@0 61 * Classes only used in this file
michael@0 62 */
michael@0 63 class DistributeBluetoothSignalTask : public nsRunnable {
michael@0 64 public:
michael@0 65 DistributeBluetoothSignalTask(const BluetoothSignal& aSignal) :
michael@0 66 mSignal(aSignal)
michael@0 67 {
michael@0 68 }
michael@0 69
michael@0 70 NS_IMETHOD
michael@0 71 Run()
michael@0 72 {
michael@0 73 MOZ_ASSERT(NS_IsMainThread());
michael@0 74
michael@0 75 BluetoothService* bs = BluetoothService::Get();
michael@0 76 NS_ENSURE_TRUE(bs, NS_ERROR_FAILURE);
michael@0 77
michael@0 78 bs->DistributeSignal(mSignal);
michael@0 79
michael@0 80 return NS_OK;
michael@0 81 }
michael@0 82
michael@0 83 private:
michael@0 84 BluetoothSignal mSignal;
michael@0 85 };
michael@0 86
michael@0 87 class SetupAfterEnabledTask : public nsRunnable
michael@0 88 {
michael@0 89 public:
michael@0 90 SetupAfterEnabledTask()
michael@0 91 { }
michael@0 92
michael@0 93 NS_IMETHOD
michael@0 94 Run()
michael@0 95 {
michael@0 96 MOZ_ASSERT(NS_IsMainThread());
michael@0 97
michael@0 98 // Bluetooth scan mode is NONE by default
michael@0 99 bt_scan_mode_t mode = BT_SCAN_MODE_CONNECTABLE;
michael@0 100 bt_property_t prop;
michael@0 101 prop.type = BT_PROPERTY_ADAPTER_SCAN_MODE;
michael@0 102 prop.val = (void*)&mode;
michael@0 103 prop.len = sizeof(mode);
michael@0 104
michael@0 105 NS_ENSURE_TRUE(sBtInterface, NS_ERROR_FAILURE);
michael@0 106
michael@0 107 int ret = sBtInterface->set_adapter_property(&prop);
michael@0 108 if (ret != BT_STATUS_SUCCESS) {
michael@0 109 BT_LOGR("Fail to set: BT_SCAN_MODE_CONNECTABLE");
michael@0 110 }
michael@0 111
michael@0 112 // Try to fire event 'AdapterAdded' to fit the original behaviour when
michael@0 113 // we used BlueZ as backend.
michael@0 114 BluetoothService* bs = BluetoothService::Get();
michael@0 115 NS_ENSURE_TRUE(bs, NS_ERROR_FAILURE);
michael@0 116
michael@0 117 bs->AdapterAddedReceived();
michael@0 118 bs->TryFiringAdapterAdded();
michael@0 119
michael@0 120 // Trigger BluetoothOppManager to listen
michael@0 121 BluetoothOppManager* opp = BluetoothOppManager::Get();
michael@0 122 if (!opp || !opp->Listen()) {
michael@0 123 BT_LOGR("Fail to start BluetoothOppManager listening");
michael@0 124 }
michael@0 125
michael@0 126 return NS_OK;
michael@0 127 }
michael@0 128 };
michael@0 129
michael@0 130 /**
michael@0 131 * Static callback functions
michael@0 132 */
michael@0 133 static void
michael@0 134 ClassToIcon(uint32_t aClass, nsAString& aRetIcon)
michael@0 135 {
michael@0 136 switch ((aClass & 0x1f00) >> 8) {
michael@0 137 case 0x01:
michael@0 138 aRetIcon.AssignLiteral("computer");
michael@0 139 break;
michael@0 140 case 0x02:
michael@0 141 switch ((aClass & 0xfc) >> 2) {
michael@0 142 case 0x01:
michael@0 143 case 0x02:
michael@0 144 case 0x03:
michael@0 145 case 0x05:
michael@0 146 aRetIcon.AssignLiteral("phone");
michael@0 147 break;
michael@0 148 case 0x04:
michael@0 149 aRetIcon.AssignLiteral("modem");
michael@0 150 break;
michael@0 151 }
michael@0 152 break;
michael@0 153 case 0x03:
michael@0 154 aRetIcon.AssignLiteral("network-wireless");
michael@0 155 break;
michael@0 156 case 0x04:
michael@0 157 switch ((aClass & 0xfc) >> 2) {
michael@0 158 case 0x01:
michael@0 159 case 0x02:
michael@0 160 case 0x06:
michael@0 161 aRetIcon.AssignLiteral("audio-card");
michael@0 162 break;
michael@0 163 case 0x0b:
michael@0 164 case 0x0c:
michael@0 165 case 0x0d:
michael@0 166 aRetIcon.AssignLiteral("camera-video");
michael@0 167 break;
michael@0 168 default:
michael@0 169 aRetIcon.AssignLiteral("audio-card");
michael@0 170 break;
michael@0 171 }
michael@0 172 break;
michael@0 173 case 0x05:
michael@0 174 switch ((aClass & 0xc0) >> 6) {
michael@0 175 case 0x00:
michael@0 176 switch ((aClass && 0x1e) >> 2) {
michael@0 177 case 0x01:
michael@0 178 case 0x02:
michael@0 179 aRetIcon.AssignLiteral("input-gaming");
michael@0 180 break;
michael@0 181 }
michael@0 182 break;
michael@0 183 case 0x01:
michael@0 184 aRetIcon.AssignLiteral("input-keyboard");
michael@0 185 break;
michael@0 186 case 0x02:
michael@0 187 switch ((aClass && 0x1e) >> 2) {
michael@0 188 case 0x05:
michael@0 189 aRetIcon.AssignLiteral("input-tablet");
michael@0 190 break;
michael@0 191 default:
michael@0 192 aRetIcon.AssignLiteral("input-mouse");
michael@0 193 break;
michael@0 194 }
michael@0 195 }
michael@0 196 break;
michael@0 197 case 0x06:
michael@0 198 if (aClass & 0x80) {
michael@0 199 aRetIcon.AssignLiteral("printer");
michael@0 200 break;
michael@0 201 }
michael@0 202 if (aClass & 0x20) {
michael@0 203 aRetIcon.AssignLiteral("camera-photo");
michael@0 204 break;
michael@0 205 }
michael@0 206 break;
michael@0 207 }
michael@0 208
michael@0 209 if (aRetIcon.IsEmpty()) {
michael@0 210 if (HAS_AUDIO(aClass)) {
michael@0 211 /**
michael@0 212 * Property 'Icon' may be missed due to CoD of major class is TOY(0x08).
michael@0 213 * But we need to assign Icon as audio-card if service class is 'Audio'.
michael@0 214 * This is for PTS test case TC_AG_COD_BV_02_I. As HFP specification
michael@0 215 * defines that service class is 'Audio' can be considered as HFP HF.
michael@0 216 */
michael@0 217 aRetIcon.AssignLiteral("audio-card");
michael@0 218 } else {
michael@0 219 BT_LOGR("No icon to match class: %x", aClass);
michael@0 220 }
michael@0 221 }
michael@0 222 }
michael@0 223
michael@0 224 static ControlPlayStatus
michael@0 225 PlayStatusStringToControlPlayStatus(const nsAString& aPlayStatus)
michael@0 226 {
michael@0 227 ControlPlayStatus playStatus = ControlPlayStatus::PLAYSTATUS_UNKNOWN;
michael@0 228 if (aPlayStatus.EqualsLiteral("STOPPED")) {
michael@0 229 playStatus = ControlPlayStatus::PLAYSTATUS_STOPPED;
michael@0 230 } else if (aPlayStatus.EqualsLiteral("PLAYING")) {
michael@0 231 playStatus = ControlPlayStatus::PLAYSTATUS_PLAYING;
michael@0 232 } else if (aPlayStatus.EqualsLiteral("PAUSED")) {
michael@0 233 playStatus = ControlPlayStatus::PLAYSTATUS_PAUSED;
michael@0 234 } else if (aPlayStatus.EqualsLiteral("FWD_SEEK")) {
michael@0 235 playStatus = ControlPlayStatus::PLAYSTATUS_FWD_SEEK;
michael@0 236 } else if (aPlayStatus.EqualsLiteral("REV_SEEK")) {
michael@0 237 playStatus = ControlPlayStatus::PLAYSTATUS_REV_SEEK;
michael@0 238 } else if (aPlayStatus.EqualsLiteral("ERROR")) {
michael@0 239 playStatus = ControlPlayStatus::PLAYSTATUS_ERROR;
michael@0 240 }
michael@0 241
michael@0 242 return playStatus;
michael@0 243 }
michael@0 244
michael@0 245 static bool
michael@0 246 IsReady()
michael@0 247 {
michael@0 248 if (!sBtInterface || !sIsBtEnabled) {
michael@0 249 BT_LOGR("Warning! Bluetooth Service is not ready");
michael@0 250 return false;
michael@0 251 }
michael@0 252 return true;
michael@0 253 }
michael@0 254
michael@0 255 static void
michael@0 256 AdapterStateChangeCallback(bt_state_t aStatus)
michael@0 257 {
michael@0 258 MOZ_ASSERT(!NS_IsMainThread());
michael@0 259
michael@0 260 BT_LOGR("BT_STATE %d", aStatus);
michael@0 261
michael@0 262 sIsBtEnabled = (aStatus == BT_STATE_ON);
michael@0 263
michael@0 264 nsRefPtr<nsRunnable> runnable =
michael@0 265 new BluetoothService::ToggleBtAck(sIsBtEnabled);
michael@0 266 if (NS_FAILED(NS_DispatchToMainThread(runnable))) {
michael@0 267 BT_WARNING("Failed to dispatch to main thread!");
michael@0 268 return;
michael@0 269 }
michael@0 270
michael@0 271 if (sIsBtEnabled &&
michael@0 272 NS_FAILED(NS_DispatchToMainThread(new SetupAfterEnabledTask()))) {
michael@0 273 BT_WARNING("Failed to dispatch to main thread!");
michael@0 274 }
michael@0 275 }
michael@0 276
michael@0 277 /**
michael@0 278 * AdapterPropertiesCallback will be called after enable() but before
michael@0 279 * AdapterStateChangeCallback sIsBtEnabled get updated. At that moment, both
michael@0 280 * BluetoothManager/BluetoothAdapter does not register observer yet.
michael@0 281 */
michael@0 282 static void
michael@0 283 AdapterPropertiesCallback(bt_status_t aStatus, int aNumProperties,
michael@0 284 bt_property_t *aProperties)
michael@0 285 {
michael@0 286 MOZ_ASSERT(!NS_IsMainThread());
michael@0 287
michael@0 288 BluetoothValue propertyValue;
michael@0 289 InfallibleTArray<BluetoothNamedValue> props;
michael@0 290
michael@0 291 for (int i = 0; i < aNumProperties; i++) {
michael@0 292 bt_property_t p = aProperties[i];
michael@0 293
michael@0 294 if (p.type == BT_PROPERTY_BDADDR) {
michael@0 295 BdAddressTypeToString((bt_bdaddr_t*)p.val, sAdapterBdAddress);
michael@0 296 propertyValue = sAdapterBdAddress;
michael@0 297 BT_APPEND_NAMED_VALUE(props, "Address", propertyValue);
michael@0 298 } else if (p.type == BT_PROPERTY_BDNAME) {
michael@0 299 // Construct nsCString here because Bd name returned from bluedroid
michael@0 300 // is missing a null terminated character after SetProperty.
michael@0 301 propertyValue = sAdapterBdName = NS_ConvertUTF8toUTF16(
michael@0 302 nsCString((char*)p.val, p.len));
michael@0 303 BT_APPEND_NAMED_VALUE(props, "Name", propertyValue);
michael@0 304 } else if (p.type == BT_PROPERTY_ADAPTER_SCAN_MODE) {
michael@0 305 bt_scan_mode_t newMode = *(bt_scan_mode_t*)p.val;
michael@0 306
michael@0 307 if (newMode == BT_SCAN_MODE_CONNECTABLE_DISCOVERABLE) {
michael@0 308 propertyValue = sAdapterDiscoverable = true;
michael@0 309 } else {
michael@0 310 propertyValue = sAdapterDiscoverable = false;
michael@0 311 }
michael@0 312
michael@0 313 BT_APPEND_NAMED_VALUE(props, "Discoverable", propertyValue);
michael@0 314 } else if (p.type == BT_PROPERTY_ADAPTER_DISCOVERY_TIMEOUT) {
michael@0 315 propertyValue = sAdapterDiscoverableTimeout = *(uint32_t*)p.val;
michael@0 316 BT_APPEND_NAMED_VALUE(props, "DiscoverableTimeout", propertyValue);
michael@0 317 } else if (p.type == BT_PROPERTY_ADAPTER_BONDED_DEVICES) {
michael@0 318 // We have to cache addresses of bonded devices. Unlike BlueZ,
michael@0 319 // bluedroid would not send an another BT_PROPERTY_ADAPTER_BONDED_DEVICES
michael@0 320 // event after bond completed
michael@0 321 bt_bdaddr_t* deviceBdAddressTypes = (bt_bdaddr_t*)p.val;
michael@0 322 int numOfAddresses = p.len / BLUETOOTH_ADDRESS_BYTES;
michael@0 323 BT_LOGD("Adapter property: BONDED_DEVICES. Count: %d", numOfAddresses);
michael@0 324
michael@0 325 // Whenever reloading paired devices, force refresh
michael@0 326 sAdapterBondedAddressArray.Clear();
michael@0 327
michael@0 328 for (int index = 0; index < numOfAddresses; index++) {
michael@0 329 nsAutoString deviceBdAddress;
michael@0 330 BdAddressTypeToString(deviceBdAddressTypes + index, deviceBdAddress);
michael@0 331 sAdapterBondedAddressArray.AppendElement(deviceBdAddress);
michael@0 332 }
michael@0 333
michael@0 334 propertyValue = sAdapterBondedAddressArray;
michael@0 335 BT_APPEND_NAMED_VALUE(props, "Devices", propertyValue);
michael@0 336 } else if (p.type == BT_PROPERTY_UUIDS) {
michael@0 337 //FIXME: This will be implemented in the later patchset
michael@0 338 continue;
michael@0 339 } else {
michael@0 340 BT_LOGD("Unhandled adapter property type: %d", p.type);
michael@0 341 continue;
michael@0 342 }
michael@0 343 }
michael@0 344
michael@0 345 NS_ENSURE_TRUE_VOID(props.Length() > 0);
michael@0 346
michael@0 347 BluetoothValue value(props);
michael@0 348 BluetoothSignal signal(NS_LITERAL_STRING("PropertyChanged"),
michael@0 349 NS_LITERAL_STRING(KEY_ADAPTER), value);
michael@0 350 nsRefPtr<DistributeBluetoothSignalTask>
michael@0 351 t = new DistributeBluetoothSignalTask(signal);
michael@0 352 if (NS_FAILED(NS_DispatchToMainThread(t))) {
michael@0 353 BT_WARNING("Failed to dispatch to main thread!");
michael@0 354 }
michael@0 355
michael@0 356 // bluedroid BTU task was stored in the task queue, see GKI_send_msg
michael@0 357 if (!sSetPropertyRunnableArray.IsEmpty()) {
michael@0 358 DispatchBluetoothReply(sSetPropertyRunnableArray[0], BluetoothValue(true),
michael@0 359 EmptyString());
michael@0 360 sSetPropertyRunnableArray.RemoveElementAt(0);
michael@0 361 }
michael@0 362 }
michael@0 363
michael@0 364 /**
michael@0 365 * RemoteDevicePropertiesCallback will be called, as the following conditions:
michael@0 366 * 1. When BT is turning on, bluedroid automatically execute this callback
michael@0 367 * 2. When get_remote_device_properties()
michael@0 368 */
michael@0 369 static void
michael@0 370 RemoteDevicePropertiesCallback(bt_status_t aStatus, bt_bdaddr_t *aBdAddress,
michael@0 371 int aNumProperties, bt_property_t *aProperties)
michael@0 372 {
michael@0 373 MOZ_ASSERT(!NS_IsMainThread());
michael@0 374
michael@0 375 if (sRequestedDeviceCountArray.IsEmpty()) {
michael@0 376 MOZ_ASSERT(sGetDeviceRunnableArray.IsEmpty());
michael@0 377 return;
michael@0 378 }
michael@0 379
michael@0 380 sRequestedDeviceCountArray[0]--;
michael@0 381
michael@0 382 InfallibleTArray<BluetoothNamedValue> props;
michael@0 383
michael@0 384 nsString remoteDeviceBdAddress;
michael@0 385 BdAddressTypeToString(aBdAddress, remoteDeviceBdAddress);
michael@0 386 BT_APPEND_NAMED_VALUE(props, "Address", remoteDeviceBdAddress);
michael@0 387
michael@0 388 for (int i = 0; i < aNumProperties; ++i) {
michael@0 389 bt_property_t p = aProperties[i];
michael@0 390
michael@0 391 if (p.type == BT_PROPERTY_BDNAME) {
michael@0 392 BluetoothValue propertyValue = NS_ConvertUTF8toUTF16((char*)p.val);
michael@0 393 BT_APPEND_NAMED_VALUE(props, "Name", propertyValue);
michael@0 394 } else if (p.type == BT_PROPERTY_CLASS_OF_DEVICE) {
michael@0 395 uint32_t cod = *(uint32_t*)p.val;
michael@0 396 BT_APPEND_NAMED_VALUE(props, "Class", cod);
michael@0 397
michael@0 398 nsString icon;
michael@0 399 ClassToIcon(cod, icon);
michael@0 400 BT_APPEND_NAMED_VALUE(props, "Icon", icon);
michael@0 401 } else {
michael@0 402 BT_LOGD("Other non-handled device properties. Type: %d", p.type);
michael@0 403 }
michael@0 404 }
michael@0 405
michael@0 406 // Update to registered BluetoothDevice objects
michael@0 407 BluetoothSignal signal(NS_LITERAL_STRING("PropertyChanged"),
michael@0 408 remoteDeviceBdAddress, props);
michael@0 409 nsRefPtr<DistributeBluetoothSignalTask>
michael@0 410 t = new DistributeBluetoothSignalTask(signal);
michael@0 411 if (NS_FAILED(NS_DispatchToMainThread(t))) {
michael@0 412 BT_WARNING("Failed to dispatch to main thread!");
michael@0 413 }
michael@0 414
michael@0 415 // Use address as the index
michael@0 416 sRemoteDevicesPack.AppendElement(
michael@0 417 BluetoothNamedValue(remoteDeviceBdAddress, props));
michael@0 418
michael@0 419 if (sRequestedDeviceCountArray[0] == 0) {
michael@0 420 MOZ_ASSERT(!sGetDeviceRunnableArray.IsEmpty());
michael@0 421
michael@0 422 if (sGetDeviceRunnableArray.IsEmpty()) {
michael@0 423 BT_LOGR("No runnable to return");
michael@0 424 return;
michael@0 425 }
michael@0 426
michael@0 427 DispatchBluetoothReply(sGetDeviceRunnableArray[0],
michael@0 428 sRemoteDevicesPack, EmptyString());
michael@0 429
michael@0 430 // After firing it, clean up cache
michael@0 431 sRemoteDevicesPack.Clear();
michael@0 432
michael@0 433 sRequestedDeviceCountArray.RemoveElementAt(0);
michael@0 434 sGetDeviceRunnableArray.RemoveElementAt(0);
michael@0 435 }
michael@0 436 }
michael@0 437
michael@0 438 static void
michael@0 439 DeviceFoundCallback(int aNumProperties, bt_property_t *aProperties)
michael@0 440 {
michael@0 441 MOZ_ASSERT(!NS_IsMainThread());
michael@0 442
michael@0 443 BluetoothValue propertyValue;
michael@0 444 InfallibleTArray<BluetoothNamedValue> propertiesArray;
michael@0 445
michael@0 446 for (int i = 0; i < aNumProperties; i++) {
michael@0 447 bt_property_t p = aProperties[i];
michael@0 448
michael@0 449 if (p.type == BT_PROPERTY_BDADDR) {
michael@0 450 nsString remoteDeviceBdAddress;
michael@0 451 BdAddressTypeToString((bt_bdaddr_t*)p.val, remoteDeviceBdAddress);
michael@0 452 propertyValue = remoteDeviceBdAddress;
michael@0 453
michael@0 454 BT_APPEND_NAMED_VALUE(propertiesArray, "Address", propertyValue);
michael@0 455 } else if (p.type == BT_PROPERTY_BDNAME) {
michael@0 456 propertyValue = NS_ConvertUTF8toUTF16((char*)p.val);
michael@0 457 BT_APPEND_NAMED_VALUE(propertiesArray, "Name", propertyValue);
michael@0 458 } else if (p.type == BT_PROPERTY_CLASS_OF_DEVICE) {
michael@0 459 uint32_t cod = *(uint32_t*)p.val;
michael@0 460 propertyValue = cod;
michael@0 461 BT_APPEND_NAMED_VALUE(propertiesArray, "Class", propertyValue);
michael@0 462
michael@0 463 nsString icon;
michael@0 464 ClassToIcon(cod, icon);
michael@0 465 propertyValue = icon;
michael@0 466 BT_APPEND_NAMED_VALUE(propertiesArray, "Icon", propertyValue);
michael@0 467 } else {
michael@0 468 BT_LOGD("Not handled remote device property: %d", p.type);
michael@0 469 }
michael@0 470 }
michael@0 471
michael@0 472 BluetoothValue value = propertiesArray;
michael@0 473 BluetoothSignal signal(NS_LITERAL_STRING("DeviceFound"),
michael@0 474 NS_LITERAL_STRING(KEY_ADAPTER), value);
michael@0 475 nsRefPtr<DistributeBluetoothSignalTask>
michael@0 476 t = new DistributeBluetoothSignalTask(signal);
michael@0 477 if (NS_FAILED(NS_DispatchToMainThread(t))) {
michael@0 478 BT_WARNING("Failed to dispatch to main thread!");
michael@0 479 }
michael@0 480 }
michael@0 481
michael@0 482 static void
michael@0 483 DiscoveryStateChangedCallback(bt_discovery_state_t aState)
michael@0 484 {
michael@0 485 MOZ_ASSERT(!NS_IsMainThread());
michael@0 486
michael@0 487 if (!sChangeDiscoveryRunnableArray.IsEmpty()) {
michael@0 488 BluetoothValue values(true);
michael@0 489 DispatchBluetoothReply(sChangeDiscoveryRunnableArray[0],
michael@0 490 values, EmptyString());
michael@0 491
michael@0 492 sChangeDiscoveryRunnableArray.RemoveElementAt(0);
michael@0 493 }
michael@0 494 }
michael@0 495
michael@0 496 static void
michael@0 497 PinRequestCallback(bt_bdaddr_t* aRemoteBdAddress,
michael@0 498 bt_bdname_t* aRemoteBdName, uint32_t aRemoteClass)
michael@0 499 {
michael@0 500 MOZ_ASSERT(!NS_IsMainThread());
michael@0 501
michael@0 502 InfallibleTArray<BluetoothNamedValue> propertiesArray;
michael@0 503 nsAutoString remoteAddress;
michael@0 504 BdAddressTypeToString(aRemoteBdAddress, remoteAddress);
michael@0 505
michael@0 506 BT_APPEND_NAMED_VALUE(propertiesArray, "address", remoteAddress);
michael@0 507 BT_APPEND_NAMED_VALUE(propertiesArray, "method",
michael@0 508 NS_LITERAL_STRING("pincode"));
michael@0 509 BT_APPEND_NAMED_VALUE(propertiesArray, "name",
michael@0 510 NS_ConvertUTF8toUTF16(
michael@0 511 (const char*)aRemoteBdName->name));
michael@0 512
michael@0 513 BluetoothValue value = propertiesArray;
michael@0 514 BluetoothSignal signal(NS_LITERAL_STRING("RequestPinCode"),
michael@0 515 NS_LITERAL_STRING(KEY_LOCAL_AGENT), value);
michael@0 516 nsRefPtr<DistributeBluetoothSignalTask>
michael@0 517 t = new DistributeBluetoothSignalTask(signal);
michael@0 518 if (NS_FAILED(NS_DispatchToMainThread(t))) {
michael@0 519 BT_WARNING("Failed to dispatch to main thread!");
michael@0 520 }
michael@0 521 }
michael@0 522
michael@0 523 static void
michael@0 524 SspRequestCallback(bt_bdaddr_t* aRemoteBdAddress, bt_bdname_t* aRemoteBdName,
michael@0 525 uint32_t aRemoteClass, bt_ssp_variant_t aPairingVariant,
michael@0 526 uint32_t aPasskey)
michael@0 527 {
michael@0 528 MOZ_ASSERT(!NS_IsMainThread());
michael@0 529
michael@0 530 InfallibleTArray<BluetoothNamedValue> propertiesArray;
michael@0 531 nsAutoString remoteAddress;
michael@0 532 BdAddressTypeToString(aRemoteBdAddress, remoteAddress);
michael@0 533
michael@0 534 BT_APPEND_NAMED_VALUE(propertiesArray, "address", remoteAddress);
michael@0 535 BT_APPEND_NAMED_VALUE(propertiesArray, "method",
michael@0 536 NS_LITERAL_STRING("confirmation"));
michael@0 537 BT_APPEND_NAMED_VALUE(propertiesArray, "name",
michael@0 538 NS_ConvertUTF8toUTF16(
michael@0 539 (const char*)aRemoteBdName->name));
michael@0 540 BT_APPEND_NAMED_VALUE(propertiesArray, "passkey", aPasskey);
michael@0 541
michael@0 542 BluetoothValue value = propertiesArray;
michael@0 543 BluetoothSignal signal(NS_LITERAL_STRING("RequestConfirmation"),
michael@0 544 NS_LITERAL_STRING(KEY_LOCAL_AGENT), value);
michael@0 545 nsRefPtr<DistributeBluetoothSignalTask>
michael@0 546 t = new DistributeBluetoothSignalTask(signal);
michael@0 547 if (NS_FAILED(NS_DispatchToMainThread(t))) {
michael@0 548 BT_WARNING("Failed to dispatch to main thread!");
michael@0 549 }
michael@0 550 }
michael@0 551
michael@0 552 static void
michael@0 553 BondStateChangedCallback(bt_status_t aStatus, bt_bdaddr_t* aRemoteBdAddress,
michael@0 554 bt_bond_state_t aState)
michael@0 555 {
michael@0 556 MOZ_ASSERT(!NS_IsMainThread());
michael@0 557
michael@0 558 nsAutoString remoteAddress;
michael@0 559 BdAddressTypeToString(aRemoteBdAddress, remoteAddress);
michael@0 560
michael@0 561 // We don't need to handle bonding state
michael@0 562 NS_ENSURE_TRUE_VOID(aState != BT_BOND_STATE_BONDING);
michael@0 563 NS_ENSURE_FALSE_VOID(aState == BT_BOND_STATE_BONDED &&
michael@0 564 sAdapterBondedAddressArray.Contains(remoteAddress));
michael@0 565 bool bonded;
michael@0 566 if (aState == BT_BOND_STATE_NONE) {
michael@0 567 bonded = false;
michael@0 568 sAdapterBondedAddressArray.RemoveElement(remoteAddress);
michael@0 569 } else if (aState == BT_BOND_STATE_BONDED) {
michael@0 570 bonded = true;
michael@0 571 sAdapterBondedAddressArray.AppendElement(remoteAddress);
michael@0 572 }
michael@0 573
michael@0 574 // Update bonded address list to BluetoothAdapter
michael@0 575 InfallibleTArray<BluetoothNamedValue> propertiesChangeArray;
michael@0 576 BT_APPEND_NAMED_VALUE(propertiesChangeArray, "Devices",
michael@0 577 sAdapterBondedAddressArray);
michael@0 578
michael@0 579 BluetoothValue value(propertiesChangeArray);
michael@0 580 BluetoothSignal signal(NS_LITERAL_STRING("PropertyChanged"),
michael@0 581 NS_LITERAL_STRING(KEY_ADAPTER),
michael@0 582 BluetoothValue(propertiesChangeArray));
michael@0 583 NS_DispatchToMainThread(new DistributeBluetoothSignalTask(signal));
michael@0 584
michael@0 585 // Update bonding status to gaia
michael@0 586 InfallibleTArray<BluetoothNamedValue> propertiesArray;
michael@0 587 BT_APPEND_NAMED_VALUE(propertiesArray, "address", remoteAddress);
michael@0 588 BT_APPEND_NAMED_VALUE(propertiesArray, "status", bonded);
michael@0 589
michael@0 590 BluetoothSignal newSignal(NS_LITERAL_STRING(PAIRED_STATUS_CHANGED_ID),
michael@0 591 NS_LITERAL_STRING(KEY_ADAPTER),
michael@0 592 BluetoothValue(propertiesArray));
michael@0 593 NS_DispatchToMainThread(new DistributeBluetoothSignalTask(newSignal));
michael@0 594
michael@0 595 if (bonded && !sBondingRunnableArray.IsEmpty()) {
michael@0 596 DispatchBluetoothReply(sBondingRunnableArray[0],
michael@0 597 BluetoothValue(true), EmptyString());
michael@0 598
michael@0 599 sBondingRunnableArray.RemoveElementAt(0);
michael@0 600 } else if (!bonded && !sUnbondingRunnableArray.IsEmpty()) {
michael@0 601 DispatchBluetoothReply(sUnbondingRunnableArray[0],
michael@0 602 BluetoothValue(true), EmptyString());
michael@0 603
michael@0 604 sUnbondingRunnableArray.RemoveElementAt(0);
michael@0 605 }
michael@0 606 }
michael@0 607
michael@0 608 static void
michael@0 609 AclStateChangedCallback(bt_status_t aStatus, bt_bdaddr_t* aRemoteBdAddress,
michael@0 610 bt_acl_state_t aState)
michael@0 611 {
michael@0 612 //FIXME: This will be implemented in the later patchset
michael@0 613 }
michael@0 614
michael@0 615 static void
michael@0 616 CallbackThreadEvent(bt_cb_thread_evt evt)
michael@0 617 {
michael@0 618 //FIXME: This will be implemented in the later patchset
michael@0 619 }
michael@0 620
michael@0 621 bt_callbacks_t sBluetoothCallbacks =
michael@0 622 {
michael@0 623 sizeof(sBluetoothCallbacks),
michael@0 624 AdapterStateChangeCallback,
michael@0 625 AdapterPropertiesCallback,
michael@0 626 RemoteDevicePropertiesCallback,
michael@0 627 DeviceFoundCallback,
michael@0 628 DiscoveryStateChangedCallback,
michael@0 629 PinRequestCallback,
michael@0 630 SspRequestCallback,
michael@0 631 BondStateChangedCallback,
michael@0 632 AclStateChangedCallback,
michael@0 633 CallbackThreadEvent
michael@0 634 };
michael@0 635
michael@0 636 /**
michael@0 637 * Static functions
michael@0 638 */
michael@0 639 static bool
michael@0 640 EnsureBluetoothHalLoad()
michael@0 641 {
michael@0 642 hw_module_t* module;
michael@0 643 hw_device_t* device;
michael@0 644 int err = hw_get_module(BT_HARDWARE_MODULE_ID, (hw_module_t const**)&module);
michael@0 645 if (err != 0) {
michael@0 646 BT_LOGR("Error: %s", strerror(err));
michael@0 647 return false;
michael@0 648 }
michael@0 649 module->methods->open(module, BT_HARDWARE_MODULE_ID, &device);
michael@0 650 sBtDevice = (bluetooth_device_t *)device;
michael@0 651 sBtInterface = sBtDevice->get_bluetooth_interface();
michael@0 652
michael@0 653 int ret = sBtInterface->init(&sBluetoothCallbacks);
michael@0 654 if (ret != BT_STATUS_SUCCESS) {
michael@0 655 BT_LOGR("Error while setting the callbacks");
michael@0 656 sBtInterface = nullptr;
michael@0 657 }
michael@0 658
michael@0 659 return true;
michael@0 660 }
michael@0 661
michael@0 662 static nsresult
michael@0 663 StartStopGonkBluetooth(bool aShouldEnable)
michael@0 664 {
michael@0 665 MOZ_ASSERT(NS_IsMainThread());
michael@0 666 NS_ENSURE_TRUE(sBtInterface, NS_ERROR_FAILURE);
michael@0 667
michael@0 668 if (sIsBtEnabled == aShouldEnable) {
michael@0 669 // Keep current enable status
michael@0 670 nsRefPtr<nsRunnable> runnable =
michael@0 671 new BluetoothService::ToggleBtAck(sIsBtEnabled);
michael@0 672 if (NS_FAILED(NS_DispatchToMainThread(runnable))) {
michael@0 673 BT_WARNING("Failed to dispatch to main thread!");
michael@0 674 }
michael@0 675 return NS_OK;
michael@0 676 }
michael@0 677
michael@0 678 int ret = aShouldEnable ? sBtInterface->enable() : sBtInterface->disable();
michael@0 679 NS_ENSURE_TRUE(ret == BT_STATUS_SUCCESS, NS_ERROR_FAILURE);
michael@0 680
michael@0 681 return NS_OK;
michael@0 682 }
michael@0 683
michael@0 684 static void
michael@0 685 ReplyStatusError(BluetoothReplyRunnable* aBluetoothReplyRunnable,
michael@0 686 int aStatusCode, const nsAString& aCustomMsg)
michael@0 687 {
michael@0 688 MOZ_ASSERT(aBluetoothReplyRunnable, "Reply runnable is nullptr");
michael@0 689
michael@0 690 BT_LOGR("error code(%d)", aStatusCode);
michael@0 691
michael@0 692 nsAutoString replyError;
michael@0 693 replyError.Assign(aCustomMsg);
michael@0 694
michael@0 695 if (aStatusCode == BT_STATUS_BUSY) {
michael@0 696 replyError.AppendLiteral(":BT_STATUS_BUSY");
michael@0 697 } else if (aStatusCode == BT_STATUS_NOT_READY) {
michael@0 698 replyError.AppendLiteral(":BT_STATUS_NOT_READY");
michael@0 699 } else if (aStatusCode == BT_STATUS_DONE) {
michael@0 700 replyError.AppendLiteral(":BT_STATUS_DONE");
michael@0 701 } else if (aStatusCode == BT_STATUS_AUTH_FAILURE) {
michael@0 702 replyError.AppendLiteral(":BT_STATUS_AUTH_FAILURE");
michael@0 703 } else if (aStatusCode == BT_STATUS_RMT_DEV_DOWN) {
michael@0 704 replyError.AppendLiteral(":BT_STATUS_RMT_DEV_DOWN");
michael@0 705 } else if (aStatusCode == BT_STATUS_FAIL) {
michael@0 706 replyError.AppendLiteral(":BT_STATUS_FAIL");
michael@0 707 }
michael@0 708
michael@0 709 DispatchBluetoothReply(aBluetoothReplyRunnable, BluetoothValue(true),
michael@0 710 replyError);
michael@0 711 }
michael@0 712
michael@0 713 /**
michael@0 714 * Member functions
michael@0 715 */
michael@0 716 BluetoothServiceBluedroid::BluetoothServiceBluedroid()
michael@0 717 {
michael@0 718 if (!EnsureBluetoothHalLoad()) {
michael@0 719 BT_LOGR("Error! Failed to load bluedroid library.");
michael@0 720 return;
michael@0 721 }
michael@0 722
michael@0 723 // Register all the bluedroid callbacks before enable() get called
michael@0 724 // It is required to register a2dp callbacks before a2dp media task starts up.
michael@0 725 BluetoothHfpManager::Get();
michael@0 726 BluetoothA2dpManager::Get();
michael@0 727 }
michael@0 728
michael@0 729 BluetoothServiceBluedroid::~BluetoothServiceBluedroid()
michael@0 730 {
michael@0 731 }
michael@0 732
michael@0 733 nsresult
michael@0 734 BluetoothServiceBluedroid::StartInternal()
michael@0 735 {
michael@0 736 MOZ_ASSERT(NS_IsMainThread());
michael@0 737
michael@0 738 nsresult ret = StartStopGonkBluetooth(true);
michael@0 739 if (NS_FAILED(ret)) {
michael@0 740 nsRefPtr<nsRunnable> runnable =
michael@0 741 new BluetoothService::ToggleBtAck(false);
michael@0 742 if (NS_FAILED(NS_DispatchToMainThread(runnable))) {
michael@0 743 BT_WARNING("Failed to dispatch to main thread!");
michael@0 744 }
michael@0 745 BT_LOGR("Error");
michael@0 746 }
michael@0 747
michael@0 748 return ret;
michael@0 749 }
michael@0 750
michael@0 751 nsresult
michael@0 752 BluetoothServiceBluedroid::StopInternal()
michael@0 753 {
michael@0 754 MOZ_ASSERT(NS_IsMainThread());
michael@0 755
michael@0 756 nsresult ret = StartStopGonkBluetooth(false);
michael@0 757 if (NS_FAILED(ret)) {
michael@0 758 nsRefPtr<nsRunnable> runnable =
michael@0 759 new BluetoothService::ToggleBtAck(true);
michael@0 760 if (NS_FAILED(NS_DispatchToMainThread(runnable))) {
michael@0 761 BT_WARNING("Failed to dispatch to main thread!");
michael@0 762 }
michael@0 763 BT_LOGR("Error");
michael@0 764 }
michael@0 765
michael@0 766 return ret;
michael@0 767 }
michael@0 768
michael@0 769 nsresult
michael@0 770 BluetoothServiceBluedroid::GetDefaultAdapterPathInternal(
michael@0 771 BluetoothReplyRunnable* aRunnable)
michael@0 772 {
michael@0 773 MOZ_ASSERT(NS_IsMainThread());
michael@0 774
michael@0 775 nsRefPtr<BluetoothReplyRunnable> runnable(aRunnable);
michael@0 776
michael@0 777 BluetoothValue v = InfallibleTArray<BluetoothNamedValue>();
michael@0 778
michael@0 779 BT_APPEND_NAMED_VALUE(v.get_ArrayOfBluetoothNamedValue(),
michael@0 780 "Address", sAdapterBdAddress);
michael@0 781
michael@0 782 BT_APPEND_NAMED_VALUE(v.get_ArrayOfBluetoothNamedValue(),
michael@0 783 "Name", sAdapterBdName);
michael@0 784
michael@0 785 BT_APPEND_NAMED_VALUE(v.get_ArrayOfBluetoothNamedValue(),
michael@0 786 "Discoverable", sAdapterDiscoverable);
michael@0 787
michael@0 788 BT_APPEND_NAMED_VALUE(v.get_ArrayOfBluetoothNamedValue(),
michael@0 789 "DiscoverableTimeout", sAdapterDiscoverableTimeout);
michael@0 790
michael@0 791 BT_APPEND_NAMED_VALUE(v.get_ArrayOfBluetoothNamedValue(),
michael@0 792 "Devices", sAdapterBondedAddressArray);
michael@0 793
michael@0 794 nsAutoString replyError;
michael@0 795 DispatchBluetoothReply(runnable.get(), v, replyError);
michael@0 796
michael@0 797 unused << runnable.forget(); // picked up in DispatchBluetoothReply
michael@0 798
michael@0 799 return NS_OK;
michael@0 800 }
michael@0 801
michael@0 802 nsresult
michael@0 803 BluetoothServiceBluedroid::GetConnectedDevicePropertiesInternal(
michael@0 804 uint16_t aServiceUuid, BluetoothReplyRunnable* aRunnable)
michael@0 805 {
michael@0 806 MOZ_ASSERT(NS_IsMainThread());
michael@0 807
michael@0 808 if (!IsReady()) {
michael@0 809 NS_NAMED_LITERAL_STRING(errorStr, "Bluetooth service is not ready yet!");
michael@0 810 DispatchBluetoothReply(aRunnable, BluetoothValue(), errorStr);
michael@0 811 return NS_OK;
michael@0 812 }
michael@0 813
michael@0 814 BluetoothProfileManagerBase* profile =
michael@0 815 BluetoothUuidHelper::GetBluetoothProfileManager(aServiceUuid);
michael@0 816 if (!profile) {
michael@0 817 InfallibleTArray<BluetoothNamedValue> emptyArr;
michael@0 818 DispatchBluetoothReply(aRunnable, emptyArr,
michael@0 819 NS_LITERAL_STRING(ERR_UNKNOWN_PROFILE));
michael@0 820 return NS_OK;
michael@0 821 }
michael@0 822
michael@0 823 nsTArray<nsString> deviceAddresses;
michael@0 824 if (profile->IsConnected()) {
michael@0 825 nsString address;
michael@0 826 profile->GetAddress(address);
michael@0 827 deviceAddresses.AppendElement(address);
michael@0 828 }
michael@0 829
michael@0 830 int requestedDeviceCount = deviceAddresses.Length();
michael@0 831 if (requestedDeviceCount == 0) {
michael@0 832 InfallibleTArray<BluetoothNamedValue> emptyArr;
michael@0 833 DispatchBluetoothReply(aRunnable, emptyArr, EmptyString());
michael@0 834 return NS_OK;
michael@0 835 }
michael@0 836
michael@0 837 for (int i = 0; i < requestedDeviceCount; i++) {
michael@0 838 // Retrieve all properties of devices
michael@0 839 bt_bdaddr_t addressType;
michael@0 840 StringToBdAddressType(deviceAddresses[i], &addressType);
michael@0 841
michael@0 842 int ret = sBtInterface->get_remote_device_properties(&addressType);
michael@0 843 if (ret != BT_STATUS_SUCCESS) {
michael@0 844 DispatchBluetoothReply(aRunnable, BluetoothValue(true),
michael@0 845 NS_LITERAL_STRING("GetConnectedDeviceFailed"));
michael@0 846 return NS_OK;
michael@0 847 }
michael@0 848 }
michael@0 849
michael@0 850 sRequestedDeviceCountArray.AppendElement(requestedDeviceCount);
michael@0 851 sGetDeviceRunnableArray.AppendElement(aRunnable);
michael@0 852
michael@0 853 return NS_OK;
michael@0 854 }
michael@0 855
michael@0 856 nsresult
michael@0 857 BluetoothServiceBluedroid::GetPairedDevicePropertiesInternal(
michael@0 858 const nsTArray<nsString>& aDeviceAddress, BluetoothReplyRunnable* aRunnable)
michael@0 859 {
michael@0 860 MOZ_ASSERT(NS_IsMainThread());
michael@0 861
michael@0 862 if (!IsReady()) {
michael@0 863 NS_NAMED_LITERAL_STRING(errorStr, "Bluetooth service is not ready yet!");
michael@0 864 DispatchBluetoothReply(aRunnable, BluetoothValue(), errorStr);
michael@0 865 return NS_OK;
michael@0 866 }
michael@0 867
michael@0 868 int requestedDeviceCount = aDeviceAddress.Length();
michael@0 869 if (requestedDeviceCount == 0) {
michael@0 870 InfallibleTArray<BluetoothNamedValue> emptyArr;
michael@0 871 DispatchBluetoothReply(aRunnable, BluetoothValue(emptyArr), EmptyString());
michael@0 872 return NS_OK;
michael@0 873 }
michael@0 874
michael@0 875 for (int i = 0; i < requestedDeviceCount; i++) {
michael@0 876 // Retrieve all properties of devices
michael@0 877 bt_bdaddr_t addressType;
michael@0 878 StringToBdAddressType(aDeviceAddress[i], &addressType);
michael@0 879 int ret = sBtInterface->get_remote_device_properties(&addressType);
michael@0 880 if (ret != BT_STATUS_SUCCESS) {
michael@0 881 DispatchBluetoothReply(aRunnable, BluetoothValue(true),
michael@0 882 NS_LITERAL_STRING("GetPairedDeviceFailed"));
michael@0 883 return NS_OK;
michael@0 884 }
michael@0 885 }
michael@0 886
michael@0 887 sRequestedDeviceCountArray.AppendElement(requestedDeviceCount);
michael@0 888 sGetDeviceRunnableArray.AppendElement(aRunnable);
michael@0 889
michael@0 890 return NS_OK;
michael@0 891 }
michael@0 892
michael@0 893 nsresult
michael@0 894 BluetoothServiceBluedroid::StartDiscoveryInternal(
michael@0 895 BluetoothReplyRunnable* aRunnable)
michael@0 896 {
michael@0 897 MOZ_ASSERT(NS_IsMainThread());
michael@0 898
michael@0 899 if (!IsReady()) {
michael@0 900 NS_NAMED_LITERAL_STRING(errorStr, "Bluetooth service is not ready yet!");
michael@0 901 DispatchBluetoothReply(aRunnable, BluetoothValue(), errorStr);
michael@0 902
michael@0 903 return NS_OK;
michael@0 904 }
michael@0 905 int ret = sBtInterface->start_discovery();
michael@0 906 if (ret != BT_STATUS_SUCCESS) {
michael@0 907 ReplyStatusError(aRunnable, ret, NS_LITERAL_STRING("StartDiscovery"));
michael@0 908
michael@0 909 return NS_OK;
michael@0 910 }
michael@0 911
michael@0 912 sChangeDiscoveryRunnableArray.AppendElement(aRunnable);
michael@0 913 return NS_OK;
michael@0 914 }
michael@0 915
michael@0 916 nsresult
michael@0 917 BluetoothServiceBluedroid::StopDiscoveryInternal(
michael@0 918 BluetoothReplyRunnable* aRunnable)
michael@0 919 {
michael@0 920 MOZ_ASSERT(NS_IsMainThread());
michael@0 921
michael@0 922 if (!IsReady()) {
michael@0 923 NS_NAMED_LITERAL_STRING(errorStr, "Bluetooth service is not ready yet!");
michael@0 924 DispatchBluetoothReply(aRunnable, BluetoothValue(), errorStr);
michael@0 925 return NS_OK;
michael@0 926 }
michael@0 927
michael@0 928 int ret = sBtInterface->cancel_discovery();
michael@0 929 if (ret != BT_STATUS_SUCCESS) {
michael@0 930 ReplyStatusError(aRunnable, ret, NS_LITERAL_STRING("StopDiscovery"));
michael@0 931 return NS_OK;
michael@0 932 }
michael@0 933
michael@0 934 sChangeDiscoveryRunnableArray.AppendElement(aRunnable);
michael@0 935
michael@0 936 return NS_OK;
michael@0 937 }
michael@0 938
michael@0 939 nsresult
michael@0 940 BluetoothServiceBluedroid::SetProperty(BluetoothObjectType aType,
michael@0 941 const BluetoothNamedValue& aValue,
michael@0 942 BluetoothReplyRunnable* aRunnable)
michael@0 943 {
michael@0 944 MOZ_ASSERT(NS_IsMainThread());
michael@0 945
michael@0 946 if (!IsReady()) {
michael@0 947 NS_NAMED_LITERAL_STRING(errorStr, "Bluetooth service is not ready yet!");
michael@0 948 DispatchBluetoothReply(aRunnable, BluetoothValue(), errorStr);
michael@0 949
michael@0 950 return NS_OK;
michael@0 951 }
michael@0 952
michael@0 953 const nsString propName = aValue.name();
michael@0 954 bt_property_t prop;
michael@0 955 bt_scan_mode_t scanMode;
michael@0 956 nsCString str;
michael@0 957
michael@0 958 // For Bluedroid, it's necessary to check property name for SetProperty
michael@0 959 if (propName.EqualsLiteral("Name")) {
michael@0 960 prop.type = BT_PROPERTY_BDNAME;
michael@0 961 } else if (propName.EqualsLiteral("Discoverable")) {
michael@0 962 prop.type = BT_PROPERTY_ADAPTER_SCAN_MODE;
michael@0 963 } else if (propName.EqualsLiteral("DiscoverableTimeout")) {
michael@0 964 prop.type = BT_PROPERTY_ADAPTER_DISCOVERY_TIMEOUT;
michael@0 965 } else {
michael@0 966 BT_LOGR("Warning: Property type is not supported yet, type: %d", prop.type);
michael@0 967 }
michael@0 968
michael@0 969 if (aValue.value().type() == BluetoothValue::Tuint32_t) {
michael@0 970 // Set discoverable timeout
michael@0 971 prop.val = (void*)aValue.value().get_uint32_t();
michael@0 972 } else if (aValue.value().type() == BluetoothValue::TnsString) {
michael@0 973 // Set name
michael@0 974 str = NS_ConvertUTF16toUTF8(aValue.value().get_nsString());
michael@0 975 const char* name = str.get();
michael@0 976 prop.val = (void*)name;
michael@0 977 prop.len = strlen(name);
michael@0 978 } else if (aValue.value().type() == BluetoothValue::Tbool) {
michael@0 979 scanMode = aValue.value().get_bool() ?
michael@0 980 BT_SCAN_MODE_CONNECTABLE_DISCOVERABLE :
michael@0 981 BT_SCAN_MODE_CONNECTABLE;
michael@0 982
michael@0 983 prop.val = (void*)&scanMode;
michael@0 984 prop.len = sizeof(scanMode);
michael@0 985 } else {
michael@0 986 BT_LOGR("SetProperty but the property cannot be recognized correctly.");
michael@0 987 return NS_OK;
michael@0 988 }
michael@0 989
michael@0 990 sSetPropertyRunnableArray.AppendElement(aRunnable);
michael@0 991
michael@0 992 int ret = sBtInterface->set_adapter_property(&prop);
michael@0 993 if (ret != BT_STATUS_SUCCESS) {
michael@0 994 ReplyStatusError(aRunnable, ret, NS_LITERAL_STRING("SetProperty"));
michael@0 995 }
michael@0 996
michael@0 997 return NS_OK;
michael@0 998 }
michael@0 999
michael@0 1000 nsresult
michael@0 1001 BluetoothServiceBluedroid::GetServiceChannel(
michael@0 1002 const nsAString& aDeviceAddress,
michael@0 1003 const nsAString& aServiceUuid,
michael@0 1004 BluetoothProfileManagerBase* aManager)
michael@0 1005 {
michael@0 1006 return NS_OK;
michael@0 1007 }
michael@0 1008
michael@0 1009 bool
michael@0 1010 BluetoothServiceBluedroid::UpdateSdpRecords(
michael@0 1011 const nsAString& aDeviceAddress,
michael@0 1012 BluetoothProfileManagerBase* aManager)
michael@0 1013 {
michael@0 1014 return true;
michael@0 1015 }
michael@0 1016
michael@0 1017 nsresult
michael@0 1018 BluetoothServiceBluedroid::CreatePairedDeviceInternal(
michael@0 1019 const nsAString& aDeviceAddress, int aTimeout,
michael@0 1020 BluetoothReplyRunnable* aRunnable)
michael@0 1021 {
michael@0 1022 MOZ_ASSERT(NS_IsMainThread());
michael@0 1023
michael@0 1024 if (!IsReady()) {
michael@0 1025 NS_NAMED_LITERAL_STRING(errorStr, "Bluetooth service is not ready yet!");
michael@0 1026 DispatchBluetoothReply(aRunnable, BluetoothValue(), errorStr);
michael@0 1027 return NS_OK;
michael@0 1028 }
michael@0 1029
michael@0 1030 bt_bdaddr_t remoteAddress;
michael@0 1031 StringToBdAddressType(aDeviceAddress, &remoteAddress);
michael@0 1032
michael@0 1033 int ret = sBtInterface->create_bond(&remoteAddress);
michael@0 1034 if (ret != BT_STATUS_SUCCESS) {
michael@0 1035 ReplyStatusError(aRunnable, ret, NS_LITERAL_STRING("CreatedPairedDevice"));
michael@0 1036 } else {
michael@0 1037 sBondingRunnableArray.AppendElement(aRunnable);
michael@0 1038 }
michael@0 1039
michael@0 1040 return NS_OK;
michael@0 1041 }
michael@0 1042
michael@0 1043 nsresult
michael@0 1044 BluetoothServiceBluedroid::RemoveDeviceInternal(
michael@0 1045 const nsAString& aDeviceAddress, BluetoothReplyRunnable* aRunnable)
michael@0 1046 {
michael@0 1047 MOZ_ASSERT(NS_IsMainThread());
michael@0 1048
michael@0 1049 if (!IsReady()) {
michael@0 1050 NS_NAMED_LITERAL_STRING(errorStr, "Bluetooth service is not ready yet!");
michael@0 1051 DispatchBluetoothReply(aRunnable, BluetoothValue(), errorStr);
michael@0 1052 return NS_OK;
michael@0 1053 }
michael@0 1054
michael@0 1055 bt_bdaddr_t remoteAddress;
michael@0 1056 StringToBdAddressType(aDeviceAddress, &remoteAddress);
michael@0 1057
michael@0 1058 int ret = sBtInterface->remove_bond(&remoteAddress);
michael@0 1059 if (ret != BT_STATUS_SUCCESS) {
michael@0 1060 ReplyStatusError(aRunnable, ret,
michael@0 1061 NS_LITERAL_STRING("RemoveDevice"));
michael@0 1062 } else {
michael@0 1063 sUnbondingRunnableArray.AppendElement(aRunnable);
michael@0 1064 }
michael@0 1065
michael@0 1066 return NS_OK;
michael@0 1067 }
michael@0 1068
michael@0 1069 bool
michael@0 1070 BluetoothServiceBluedroid::SetPinCodeInternal(
michael@0 1071 const nsAString& aDeviceAddress, const nsAString& aPinCode,
michael@0 1072 BluetoothReplyRunnable* aRunnable)
michael@0 1073 {
michael@0 1074 MOZ_ASSERT(NS_IsMainThread());
michael@0 1075
michael@0 1076 if (!IsReady()) {
michael@0 1077 NS_NAMED_LITERAL_STRING(errorStr, "Bluetooth service is not ready yet!");
michael@0 1078 DispatchBluetoothReply(aRunnable, BluetoothValue(), errorStr);
michael@0 1079 return false;
michael@0 1080 }
michael@0 1081
michael@0 1082 bt_bdaddr_t remoteAddress;
michael@0 1083 StringToBdAddressType(aDeviceAddress, &remoteAddress);
michael@0 1084
michael@0 1085 int ret = sBtInterface->pin_reply(
michael@0 1086 &remoteAddress, true, aPinCode.Length(),
michael@0 1087 (bt_pin_code_t*)NS_ConvertUTF16toUTF8(aPinCode).get());
michael@0 1088
michael@0 1089 if (ret != BT_STATUS_SUCCESS) {
michael@0 1090 ReplyStatusError(aRunnable, ret, NS_LITERAL_STRING("SetPinCode"));
michael@0 1091 } else {
michael@0 1092 DispatchBluetoothReply(aRunnable, BluetoothValue(true), EmptyString());
michael@0 1093 }
michael@0 1094
michael@0 1095 return true;
michael@0 1096 }
michael@0 1097
michael@0 1098 bool
michael@0 1099 BluetoothServiceBluedroid::SetPasskeyInternal(
michael@0 1100 const nsAString& aDeviceAddress, uint32_t aPasskey,
michael@0 1101 BluetoothReplyRunnable* aRunnable)
michael@0 1102 {
michael@0 1103 return true;
michael@0 1104 }
michael@0 1105
michael@0 1106 bool
michael@0 1107 BluetoothServiceBluedroid::SetPairingConfirmationInternal(
michael@0 1108 const nsAString& aDeviceAddress, bool aConfirm,
michael@0 1109 BluetoothReplyRunnable* aRunnable)
michael@0 1110 {
michael@0 1111 MOZ_ASSERT(NS_IsMainThread());
michael@0 1112
michael@0 1113 if (!IsReady()) {
michael@0 1114 NS_NAMED_LITERAL_STRING(errorStr, "Bluetooth service is not ready yet!");
michael@0 1115 DispatchBluetoothReply(aRunnable, BluetoothValue(), errorStr);
michael@0 1116 return false;
michael@0 1117 }
michael@0 1118
michael@0 1119 bt_bdaddr_t remoteAddress;
michael@0 1120 StringToBdAddressType(aDeviceAddress, &remoteAddress);
michael@0 1121
michael@0 1122 int ret = sBtInterface->ssp_reply(&remoteAddress, (bt_ssp_variant_t)0,
michael@0 1123 aConfirm, 0);
michael@0 1124 if (ret != BT_STATUS_SUCCESS) {
michael@0 1125 ReplyStatusError(aRunnable, ret,
michael@0 1126 NS_LITERAL_STRING("SetPairingConfirmation"));
michael@0 1127 } else {
michael@0 1128 DispatchBluetoothReply(aRunnable, BluetoothValue(true), EmptyString());
michael@0 1129 }
michael@0 1130
michael@0 1131 return true;
michael@0 1132 }
michael@0 1133
michael@0 1134 bool
michael@0 1135 BluetoothServiceBluedroid::SetAuthorizationInternal(
michael@0 1136 const nsAString& aDeviceAddress, bool aAllow,
michael@0 1137 BluetoothReplyRunnable* aRunnable)
michael@0 1138 {
michael@0 1139 return true;
michael@0 1140 }
michael@0 1141
michael@0 1142 nsresult
michael@0 1143 BluetoothServiceBluedroid::PrepareAdapterInternal()
michael@0 1144 {
michael@0 1145 return NS_OK;
michael@0 1146 }
michael@0 1147
michael@0 1148 static void
michael@0 1149 NextBluetoothProfileController()
michael@0 1150 {
michael@0 1151 MOZ_ASSERT(NS_IsMainThread());
michael@0 1152
michael@0 1153 // First, remove the task at the front which has been already done.
michael@0 1154 NS_ENSURE_FALSE_VOID(sControllerArray.IsEmpty());
michael@0 1155 sControllerArray.RemoveElementAt(0);
michael@0 1156 // Re-check if the task array is empty, if it's not, the next task will begin.
michael@0 1157 NS_ENSURE_FALSE_VOID(sControllerArray.IsEmpty());
michael@0 1158 sControllerArray[0]->StartSession();
michael@0 1159 }
michael@0 1160
michael@0 1161 static void
michael@0 1162 ConnectDisconnect(bool aConnect, const nsAString& aDeviceAddress,
michael@0 1163 BluetoothReplyRunnable* aRunnable,
michael@0 1164 uint16_t aServiceUuid, uint32_t aCod = 0)
michael@0 1165 {
michael@0 1166 MOZ_ASSERT(NS_IsMainThread());
michael@0 1167 MOZ_ASSERT(aRunnable);
michael@0 1168
michael@0 1169 BluetoothProfileController* controller =
michael@0 1170 new BluetoothProfileController(aConnect, aDeviceAddress, aRunnable,
michael@0 1171 NextBluetoothProfileController,
michael@0 1172 aServiceUuid, aCod);
michael@0 1173 sControllerArray.AppendElement(controller);
michael@0 1174
michael@0 1175 /**
michael@0 1176 * If the request is the first element of the quene, start from here. Note
michael@0 1177 * that other request is pushed into the quene and is popped out after the
michael@0 1178 * first one is completed. See NextBluetoothProfileController() for details.
michael@0 1179 */
michael@0 1180 if (sControllerArray.Length() == 1) {
michael@0 1181 sControllerArray[0]->StartSession();
michael@0 1182 }
michael@0 1183 }
michael@0 1184
michael@0 1185 const bt_interface_t*
michael@0 1186 BluetoothServiceBluedroid::GetBluetoothInterface()
michael@0 1187 {
michael@0 1188 return sBtInterface;
michael@0 1189 }
michael@0 1190
michael@0 1191 void
michael@0 1192 BluetoothServiceBluedroid::Connect(const nsAString& aDeviceAddress,
michael@0 1193 uint32_t aCod,
michael@0 1194 uint16_t aServiceUuid,
michael@0 1195 BluetoothReplyRunnable* aRunnable)
michael@0 1196 {
michael@0 1197 ConnectDisconnect(true, aDeviceAddress, aRunnable, aServiceUuid, aCod);
michael@0 1198 }
michael@0 1199
michael@0 1200 bool
michael@0 1201 BluetoothServiceBluedroid::IsConnected(uint16_t aProfileId)
michael@0 1202 {
michael@0 1203 return true;
michael@0 1204 }
michael@0 1205
michael@0 1206 void
michael@0 1207 BluetoothServiceBluedroid::Disconnect(
michael@0 1208 const nsAString& aDeviceAddress, uint16_t aServiceUuid,
michael@0 1209 BluetoothReplyRunnable* aRunnable)
michael@0 1210 {
michael@0 1211 ConnectDisconnect(false, aDeviceAddress, aRunnable, aServiceUuid);
michael@0 1212 }
michael@0 1213
michael@0 1214 void
michael@0 1215 BluetoothServiceBluedroid::SendFile(const nsAString& aDeviceAddress,
michael@0 1216 BlobParent* aBlobParent,
michael@0 1217 BlobChild* aBlobChild,
michael@0 1218 BluetoothReplyRunnable* aRunnable)
michael@0 1219 {
michael@0 1220 MOZ_ASSERT(NS_IsMainThread());
michael@0 1221
michael@0 1222 // Currently we only support one device sending one file at a time,
michael@0 1223 // so we don't need aDeviceAddress here because the target device
michael@0 1224 // has been determined when calling 'Connect()'. Nevertheless, keep
michael@0 1225 // it for future use.
michael@0 1226 BluetoothOppManager* opp = BluetoothOppManager::Get();
michael@0 1227 nsAutoString errorStr;
michael@0 1228 if (!opp || !opp->SendFile(aDeviceAddress, aBlobParent)) {
michael@0 1229 errorStr.AssignLiteral("Calling SendFile() failed");
michael@0 1230 }
michael@0 1231
michael@0 1232 DispatchBluetoothReply(aRunnable, BluetoothValue(true), errorStr);
michael@0 1233 }
michael@0 1234
michael@0 1235 void
michael@0 1236 BluetoothServiceBluedroid::SendFile(const nsAString& aDeviceAddress,
michael@0 1237 nsIDOMBlob* aBlob,
michael@0 1238 BluetoothReplyRunnable* aRunnable)
michael@0 1239 {
michael@0 1240 MOZ_ASSERT(NS_IsMainThread());
michael@0 1241
michael@0 1242 // Currently we only support one device sending one file at a time,
michael@0 1243 // so we don't need aDeviceAddress here because the target device
michael@0 1244 // has been determined when calling 'Connect()'. Nevertheless, keep
michael@0 1245 // it for future use.
michael@0 1246 BluetoothOppManager* opp = BluetoothOppManager::Get();
michael@0 1247 nsAutoString errorStr;
michael@0 1248 if (!opp || !opp->SendFile(aDeviceAddress, aBlob)) {
michael@0 1249 errorStr.AssignLiteral("Calling SendFile() failed");
michael@0 1250 }
michael@0 1251
michael@0 1252 DispatchBluetoothReply(aRunnable, BluetoothValue(true), errorStr);
michael@0 1253 }
michael@0 1254
michael@0 1255 void
michael@0 1256 BluetoothServiceBluedroid::StopSendingFile(const nsAString& aDeviceAddress,
michael@0 1257 BluetoothReplyRunnable* aRunnable)
michael@0 1258 {
michael@0 1259 MOZ_ASSERT(NS_IsMainThread());
michael@0 1260
michael@0 1261 // Currently we only support one device sending one file at a time,
michael@0 1262 // so we don't need aDeviceAddress here because the target device
michael@0 1263 // has been determined when calling 'Connect()'. Nevertheless, keep
michael@0 1264 // it for future use.
michael@0 1265 BluetoothOppManager* opp = BluetoothOppManager::Get();
michael@0 1266 nsAutoString errorStr;
michael@0 1267 if (!opp || !opp->StopSendingFile()) {
michael@0 1268 errorStr.AssignLiteral("Calling StopSendingFile() failed");
michael@0 1269 }
michael@0 1270
michael@0 1271 DispatchBluetoothReply(aRunnable, BluetoothValue(true), errorStr);
michael@0 1272 }
michael@0 1273
michael@0 1274 void
michael@0 1275 BluetoothServiceBluedroid::ConfirmReceivingFile(
michael@0 1276 const nsAString& aDeviceAddress, bool aConfirm,
michael@0 1277 BluetoothReplyRunnable* aRunnable)
michael@0 1278 {
michael@0 1279 MOZ_ASSERT(NS_IsMainThread(), "Must be called from main thread!");
michael@0 1280
michael@0 1281 // Currently we only support one device sending one file at a time,
michael@0 1282 // so we don't need aDeviceAddress here because the target device
michael@0 1283 // has been determined when calling 'Connect()'. Nevertheless, keep
michael@0 1284 // it for future use.
michael@0 1285 BluetoothOppManager* opp = BluetoothOppManager::Get();
michael@0 1286 nsAutoString errorStr;
michael@0 1287 if (!opp || !opp->ConfirmReceivingFile(aConfirm)) {
michael@0 1288 errorStr.AssignLiteral("Calling ConfirmReceivingFile() failed");
michael@0 1289 }
michael@0 1290
michael@0 1291 DispatchBluetoothReply(aRunnable, BluetoothValue(true), errorStr);
michael@0 1292 }
michael@0 1293
michael@0 1294 void
michael@0 1295 BluetoothServiceBluedroid::ConnectSco(BluetoothReplyRunnable* aRunnable)
michael@0 1296 {
michael@0 1297 MOZ_ASSERT(NS_IsMainThread());
michael@0 1298
michael@0 1299 BluetoothHfpManager* hfp = BluetoothHfpManager::Get();
michael@0 1300 if (!hfp || !hfp->ConnectSco()) {
michael@0 1301 NS_NAMED_LITERAL_STRING(replyError, "Calling ConnectSco() failed");
michael@0 1302 DispatchBluetoothReply(aRunnable, BluetoothValue(), replyError);
michael@0 1303 return;
michael@0 1304 }
michael@0 1305
michael@0 1306 DispatchBluetoothReply(aRunnable, BluetoothValue(true), EmptyString());
michael@0 1307 }
michael@0 1308
michael@0 1309 void
michael@0 1310 BluetoothServiceBluedroid::DisconnectSco(BluetoothReplyRunnable* aRunnable)
michael@0 1311 {
michael@0 1312 MOZ_ASSERT(NS_IsMainThread());
michael@0 1313
michael@0 1314 BluetoothHfpManager* hfp = BluetoothHfpManager::Get();
michael@0 1315 if (!hfp || !hfp->DisconnectSco()) {
michael@0 1316 NS_NAMED_LITERAL_STRING(replyError, "Calling DisconnectSco() failed");
michael@0 1317 DispatchBluetoothReply(aRunnable, BluetoothValue(), replyError);
michael@0 1318 return;
michael@0 1319 }
michael@0 1320
michael@0 1321 DispatchBluetoothReply(aRunnable, BluetoothValue(true), EmptyString());
michael@0 1322 }
michael@0 1323
michael@0 1324 void
michael@0 1325 BluetoothServiceBluedroid::IsScoConnected(BluetoothReplyRunnable* aRunnable)
michael@0 1326 {
michael@0 1327 MOZ_ASSERT(NS_IsMainThread());
michael@0 1328
michael@0 1329 BluetoothHfpManager* hfp = BluetoothHfpManager::Get();
michael@0 1330 if (!hfp) {
michael@0 1331 NS_NAMED_LITERAL_STRING(replyError, "Fail to get BluetoothHfpManager");
michael@0 1332 DispatchBluetoothReply(aRunnable, BluetoothValue(), replyError);
michael@0 1333 return;
michael@0 1334 }
michael@0 1335
michael@0 1336 DispatchBluetoothReply(aRunnable, hfp->IsScoConnected(), EmptyString());
michael@0 1337 }
michael@0 1338
michael@0 1339 void
michael@0 1340 BluetoothServiceBluedroid::SendMetaData(const nsAString& aTitle,
michael@0 1341 const nsAString& aArtist,
michael@0 1342 const nsAString& aAlbum,
michael@0 1343 int64_t aMediaNumber,
michael@0 1344 int64_t aTotalMediaCount,
michael@0 1345 int64_t aDuration,
michael@0 1346 BluetoothReplyRunnable* aRunnable)
michael@0 1347 {
michael@0 1348 BluetoothA2dpManager* a2dp = BluetoothA2dpManager::Get();
michael@0 1349 if (a2dp) {
michael@0 1350 a2dp->UpdateMetaData(aTitle, aArtist, aAlbum, aMediaNumber,
michael@0 1351 aTotalMediaCount, aDuration);
michael@0 1352 }
michael@0 1353 DispatchBluetoothReply(aRunnable, BluetoothValue(true), EmptyString());
michael@0 1354 }
michael@0 1355
michael@0 1356 void
michael@0 1357 BluetoothServiceBluedroid::SendPlayStatus(
michael@0 1358 int64_t aDuration, int64_t aPosition,
michael@0 1359 const nsAString& aPlayStatus,
michael@0 1360 BluetoothReplyRunnable* aRunnable)
michael@0 1361 {
michael@0 1362 BluetoothA2dpManager* a2dp = BluetoothA2dpManager::Get();
michael@0 1363 if (a2dp) {
michael@0 1364 ControlPlayStatus playStatus =
michael@0 1365 PlayStatusStringToControlPlayStatus(aPlayStatus);
michael@0 1366 a2dp->UpdatePlayStatus(aDuration, aPosition, playStatus);
michael@0 1367 }
michael@0 1368 DispatchBluetoothReply(aRunnable, BluetoothValue(true), EmptyString());
michael@0 1369 }
michael@0 1370
michael@0 1371 void
michael@0 1372 BluetoothServiceBluedroid::UpdatePlayStatus(
michael@0 1373 uint32_t aDuration, uint32_t aPosition, ControlPlayStatus aPlayStatus)
michael@0 1374 {
michael@0 1375 // We don't need this function for bluedroid.
michael@0 1376 // In bluez, it only calls dbus api
michael@0 1377 // But it does not update BluetoothA2dpManager member fields
michael@0 1378 MOZ_ASSERT(false);
michael@0 1379 }
michael@0 1380
michael@0 1381 nsresult
michael@0 1382 BluetoothServiceBluedroid::SendSinkMessage(const nsAString& aDeviceAddresses,
michael@0 1383 const nsAString& aMessage)
michael@0 1384 {
michael@0 1385 return NS_OK;
michael@0 1386 }
michael@0 1387
michael@0 1388 nsresult
michael@0 1389 BluetoothServiceBluedroid::SendInputMessage(const nsAString& aDeviceAddresses,
michael@0 1390 const nsAString& aMessage)
michael@0 1391 {
michael@0 1392 return NS_OK;
michael@0 1393 }
michael@0 1394
michael@0 1395 void
michael@0 1396 BluetoothServiceBluedroid::AnswerWaitingCall(BluetoothReplyRunnable* aRunnable)
michael@0 1397 {
michael@0 1398 }
michael@0 1399
michael@0 1400 void
michael@0 1401 BluetoothServiceBluedroid::IgnoreWaitingCall(BluetoothReplyRunnable* aRunnable)
michael@0 1402 {
michael@0 1403 }
michael@0 1404
michael@0 1405 void
michael@0 1406 BluetoothServiceBluedroid::ToggleCalls(BluetoothReplyRunnable* aRunnable)
michael@0 1407 {
michael@0 1408 }
michael@0 1409

mercurial