Bug 1015819 - Part 1: [bluedroid] Restore CoD value based on SDP records. r=echou, f=btian, a=2.0+
authorShawn Huang <shuang@mozilla.com>
Fri, 20 Jun 2014 00:48:00 -0400
changeset 207339 444dc23190f4d0bfdcdf69378531dcb1abb22569
parent 207338 de320a360e704d991d8194bdc04a365ad455644a
child 207340 cf58e8801181f2907ce7e45c74356bab0d245432
push id3741
push userasasaki@mozilla.com
push dateMon, 21 Jul 2014 20:25:18 +0000
treeherdermozilla-beta@4d6f46f5af68 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersechou, 2
bugs1015819
milestone32.0a2
Bug 1015819 - Part 1: [bluedroid] Restore CoD value based on SDP records. r=echou, f=btian, a=2.0+
dom/bluetooth/BluetoothUuid.cpp
dom/bluetooth/BluetoothUuid.h
dom/bluetooth/bluedroid/BluetoothServiceBluedroid.cpp
dom/bluetooth/bluedroid/BluetoothUtils.cpp
dom/bluetooth/bluedroid/BluetoothUtils.h
--- a/dom/bluetooth/BluetoothUuid.cpp
+++ b/dom/bluetooth/BluetoothUuid.cpp
@@ -46,16 +46,17 @@ BluetoothUuidHelper::GetBluetoothService
 }
 
 BluetoothServiceClass
 BluetoothUuidHelper::GetBluetoothServiceClass(uint16_t aServiceUuid)
 {
   BluetoothServiceClass retValue = BluetoothServiceClass::UNKNOWN;
   switch (aServiceUuid) {
     case BluetoothServiceClass::A2DP:
+    case BluetoothServiceClass::A2DP_SINK:
     case BluetoothServiceClass::HANDSFREE:
     case BluetoothServiceClass::HANDSFREE_AG:
     case BluetoothServiceClass::HEADSET:
     case BluetoothServiceClass::HEADSET_AG:
     case BluetoothServiceClass::HID:
     case BluetoothServiceClass::OBJECT_PUSH:
       retValue = (BluetoothServiceClass)aServiceUuid;
   }
--- a/dom/bluetooth/BluetoothUuid.h
+++ b/dom/bluetooth/BluetoothUuid.h
@@ -20,16 +20,17 @@ class BluetoothProfileManagerBase;
  *
  * The value of each service class is defined in "AssignedNumbers/Service
  * Discovery Protocol (SDP)/Service classes and Profile Identifiers" in the
  * Bluetooth Core Specification.
  */
 enum BluetoothServiceClass
 {
   A2DP          = 0x110D,
+  A2DP_SINK     = 0x110B,
   HANDSFREE     = 0x111E,
   HANDSFREE_AG  = 0x111F,
   HEADSET       = 0x1108,
   HEADSET_AG    = 0x1112,
   HID           = 0x1124,
   OBJECT_PUSH   = 0x1105,
   UNKNOWN       = 0x0000
 };
--- a/dom/bluetooth/bluedroid/BluetoothServiceBluedroid.cpp
+++ b/dom/bluetooth/bluedroid/BluetoothServiceBluedroid.cpp
@@ -37,16 +37,22 @@
   do {                                                                 \
     if (!sBtInterface || !IsEnabled()) {                               \
       NS_NAMED_LITERAL_STRING(errorStr, "Bluetooth is not ready");     \
       DispatchBluetoothReply(runnable, BluetoothValue(), errorStr);    \
       return result;                                                   \
     }                                                                  \
   } while(0)
 
+#define MAX_UUID_SIZE 16
+// Audio: Major service class = 0x100 (Bit 21 is set)
+#define SET_AUDIO_BIT(cod)               (cod |= 0x200000)
+// Rendering: Major service class = 0x20 (Bit 18 is set)
+#define SET_RENDERING_BIT(cod)           (cod |= 0x40000)
+
 using namespace mozilla;
 using namespace mozilla::ipc;
 USING_BLUETOOTH_NAMESPACE
 
 // TODO: Non thread-safe static variables
 static nsString sAdapterBdAddress;
 static nsString sAdapterBdName;
 static InfallibleTArray<nsString> sAdapterBondedAddressArray;
@@ -475,29 +481,72 @@ RemoteDevicePropertiesCallback(bt_status
   MOZ_ASSERT(!NS_IsMainThread());
 
   InfallibleTArray<BluetoothNamedValue> props;
 
   nsString remoteDeviceBdAddress;
   BdAddressTypeToString(aBdAddress, remoteDeviceBdAddress);
   BT_APPEND_NAMED_VALUE(props, "Address", remoteDeviceBdAddress);
 
+  bool isCodInvalid = false;
   for (int i = 0; i < aNumProperties; ++i) {
     bt_property_t p = aProperties[i];
 
     if (p.type == BT_PROPERTY_BDNAME) {
       BluetoothValue propertyValue = NS_ConvertUTF8toUTF16((char*)p.val);
       BT_APPEND_NAMED_VALUE(props, "Name", propertyValue);
     } else if (p.type == BT_PROPERTY_CLASS_OF_DEVICE) {
       uint32_t cod = *(uint32_t*)p.val;
-      BT_APPEND_NAMED_VALUE(props, "Class", cod);
-
       nsString icon;
       ClassToIcon(cod, icon);
-      BT_APPEND_NAMED_VALUE(props, "Icon", icon);
+      if (!icon.IsEmpty()) {
+        // Valid CoD
+        BT_APPEND_NAMED_VALUE(props, "Class", cod);
+        BT_APPEND_NAMED_VALUE(props, "Icon", icon);
+      } else {
+        // If Cod is invalid, fallback to check UUIDs. It usually happens due to
+        // NFC directly trigger pairing. bluedroid sends wrong CoD due to missing
+        // EIR query records.
+        isCodInvalid = true;
+      }
+    } else if (p.type == BT_PROPERTY_UUIDS) {
+      InfallibleTArray<nsString> uuidsArray;
+      int uuidListLength = p.len / MAX_UUID_SIZE;
+      uint32_t cod = 0;
+
+      for (int i = 0; i < uuidListLength; i++) {
+        uint16_t uuidServiceClass = UuidToServiceClassInt((bt_uuid_t*)(p.val +
+          (i * MAX_UUID_SIZE)));
+        BluetoothServiceClass serviceClass = BluetoothUuidHelper::
+          GetBluetoothServiceClass(uuidServiceClass);
+
+        // Get Uuid string from BluetoothServiceClass
+        nsString uuid;
+        BluetoothUuidHelper::GetString(serviceClass, uuid);
+        uuidsArray.AppendElement(uuid);
+
+        // Restore CoD value
+        if (isCodInvalid) {
+          if (serviceClass == BluetoothServiceClass::HANDSFREE ||
+              serviceClass == BluetoothServiceClass::HEADSET) {
+            BT_LOGD("Restore Class Of Device to Audio bit");
+            SET_AUDIO_BIT(cod);
+          } else if (serviceClass == BluetoothServiceClass::A2DP_SINK) {
+            BT_LOGD("Restore Class of Device to Rendering bit");
+            SET_RENDERING_BIT(cod);
+          }
+        }
+      }
+
+      if (isCodInvalid) {
+        BT_APPEND_NAMED_VALUE(props, "Class", cod);
+        // 'audio-card' refers to 'Audio' device
+        BT_APPEND_NAMED_VALUE(props, "Icon", NS_LITERAL_STRING("audio-card"));
+      }
+      BT_APPEND_NAMED_VALUE(props, "UUIDS", uuidsArray);
     } else {
       BT_LOGD("Other non-handled device properties. Type: %d", p.type);
     }
   }
 
   // Redirect to main thread to avoid racing problem
   NS_DispatchToMainThread(
     new RemoteDevicePropertiesCallbackTask(props, remoteDeviceBdAddress));
--- a/dom/bluetooth/bluedroid/BluetoothUtils.cpp
+++ b/dom/bluetooth/bluedroid/BluetoothUtils.cpp
@@ -50,16 +50,25 @@ BdAddressTypeToString(bt_bdaddr_t* aBdAd
 
   sprintf(bdstr, "%02x:%02x:%02x:%02x:%02x:%02x",
           (int)addr[0],(int)addr[1],(int)addr[2],
           (int)addr[3],(int)addr[4],(int)addr[5]);
 
   aRetBdAddress = NS_ConvertUTF8toUTF16(bdstr);
 }
 
+uint16_t
+UuidToServiceClassInt(bt_uuid_t* p_uuid)
+{
+  // extract short UUID 0000xxxx-0000-1000-8000-00805f9b34fb
+  uint16_t shortUuid;
+  memcpy(&shortUuid, &(p_uuid->uu[2]), sizeof(uint16_t));
+  return ntohs(shortUuid);
+}
+
 bool
 SetJsObject(JSContext* aContext,
             const BluetoothValue& aValue,
             JS::Handle<JSObject*> aObj)
 {
   MOZ_ASSERT(aContext && aObj);
 
   if (aValue.type() != BluetoothValue::TArrayOfBluetoothNamedValue) {
--- a/dom/bluetooth/bluedroid/BluetoothUtils.h
+++ b/dom/bluetooth/bluedroid/BluetoothUtils.h
@@ -24,16 +24,19 @@ GetBluetoothInterface();
 void
 StringToBdAddressType(const nsAString& aBdAddress,
                       bt_bdaddr_t *aRetBdAddressType);
 
 void
 BdAddressTypeToString(bt_bdaddr_t* aBdAddressType,
                       nsAString& aRetBdAddress);
 
+uint16_t
+UuidToServiceClassInt(bt_uuid_t* p_uuid);
+
 bool
 SetJsObject(JSContext* aContext,
             const BluetoothValue& aValue,
             JS::Handle<JSObject*> aObj);
 
 bool
 BroadcastSystemMessage(const nsAString& aType,
                        const BluetoothValue& aData);