diff --git a/dom/bluetooth/BluetoothServiceBluedroid.cpp b/dom/bluetooth/BluetoothServiceBluedroid.cpp index 28035d922068..ad1e3dd11364 100644 --- a/dom/bluetooth/BluetoothServiceBluedroid.cpp +++ b/dom/bluetooth/BluetoothServiceBluedroid.cpp @@ -61,7 +61,6 @@ private: /** * Static variables */ - static bluetooth_device_t* sBtDevice; static const bt_interface_t* sBtInterface; static bool sIsBtEnabled = false; @@ -69,11 +68,89 @@ static bool sAdapterDiscoverable = false; static nsString sAdapterBdAddress; static nsString sAdapterBdName; static uint32_t sAdapterDiscoverableTimeout; +static nsTArray > sChangeDiscoveryRunnableArray; static nsTArray > sSetPropertyRunnableArray; /** * Static callback functions */ +static void +ClassToIcon(uint32_t aClass, nsAString& aRetIcon) +{ + switch ((aClass & 0x1f00) >> 8) { + case 0x01: + aRetIcon.AssignLiteral("computer"); + break; + case 0x02: + switch ((aClass & 0xfc) >> 2) { + case 0x01: + case 0x02: + case 0x03: + case 0x05: + aRetIcon.AssignLiteral("phone"); + break; + case 0x04: + aRetIcon.AssignLiteral("modem"); + break; + } + break; + case 0x03: + aRetIcon.AssignLiteral("network-wireless"); + break; + case 0x04: + switch ((aClass & 0xfc) >> 2) { + case 0x01: + case 0x02: + case 0x06: + aRetIcon.AssignLiteral("audio-card"); + break; + case 0x0b: + case 0x0c: + case 0x0d: + aRetIcon.AssignLiteral("camera-video"); + break; + default: + aRetIcon.AssignLiteral("audio-card"); + break; + } + break; + case 0x05: + switch ((aClass & 0xc0) >> 6) { + case 0x00: + switch ((aClass && 0x1e) >> 2) { + case 0x01: + case 0x02: + aRetIcon.AssignLiteral("input-gaming"); + break; + } + break; + case 0x01: + aRetIcon.AssignLiteral("input-keyboard"); + break; + case 0x02: + switch ((aClass && 0x1e) >> 2) { + case 0x05: + aRetIcon.AssignLiteral("input-tablet"); + break; + default: + aRetIcon.AssignLiteral("input-mouse"); + break; + } + } + break; + case 0x06: + if (aClass & 0x80) { + aRetIcon.AssignLiteral("printer"); + break; + } + if (aClass & 0x20) { + aRetIcon.AssignLiteral("camera-photo"); + break; + } + break; + } +} + static void AdapterStateChangeCallback(bt_state_t aStatus) { @@ -110,6 +187,16 @@ BdAddressTypeToString(bt_bdaddr_t* aBdAddressType, nsAString& aRetBdAddress) aRetBdAddress = NS_ConvertUTF8toUTF16((char*)bdstr); } +static bool +IsReady() +{ + if (!sBtInterface || !sIsBtEnabled) { + BT_LOGR("Warning! Bluetooth Service is not ready"); + return false; + } + return true; +} + static void AdapterPropertiesChangeCallback(bt_status_t aStatus, int aNumProperties, bt_property_t *aProperties) @@ -172,10 +259,110 @@ AdapterPropertiesChangeCallback(bt_status_t aStatus, int aNumProperties, } } -bt_callbacks_t sBluetoothCallbacks = { +static void +RemoteDevicePropertiesChangeCallback(bt_status_t aStatus, + bt_bdaddr_t *aBdAddress, + int aNumProperties, + bt_property_t *aProperties) +{ + MOZ_ASSERT(!NS_IsMainThread()); + + // First, get remote device bd_address since it will be the key of + // return name value pair. + nsString remoteDeviceBdAddress; + BdAddressTypeToString(aBdAddress, remoteDeviceBdAddress); + + InfallibleTArray deviceProperties; + + 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); + deviceProperties.AppendElement( + BluetoothNamedValue(NS_LITERAL_STRING("Name"), propertyValue)); + } else if (p.type == BT_PROPERTY_CLASS_OF_DEVICE) { + uint32_t cod = *(uint32_t*)p.val; + deviceProperties.AppendElement( + BluetoothNamedValue(NS_LITERAL_STRING("Class"), BluetoothValue(cod))); + nsString icon; + ClassToIcon(cod, icon); + deviceProperties.AppendElement( + BluetoothNamedValue(NS_LITERAL_STRING("Icon"), BluetoothValue(icon))); + } else { + BT_LOGR("Other non-handled device properties. Type: %d", p.type); + } + } +} + +static void +DeviceFoundCallback(int aNumProperties, bt_property_t *aProperties) +{ + MOZ_ASSERT(!NS_IsMainThread()); + + BluetoothValue propertyValue; + InfallibleTArray propertiesArray; + + for (int i = 0; i < aNumProperties; i++) { + bt_property_t p = aProperties[i]; + + if (p.type == BT_PROPERTY_BDADDR) { + nsString remoteDeviceBdAddress; + BdAddressTypeToString((bt_bdaddr_t*)p.val, remoteDeviceBdAddress); + propertyValue = remoteDeviceBdAddress; + propertiesArray.AppendElement( + BluetoothNamedValue(NS_LITERAL_STRING("Address"), propertyValue)); + } else if (p.type == BT_PROPERTY_BDNAME) { + propertyValue = NS_ConvertUTF8toUTF16((char*)p.val); + propertiesArray.AppendElement( + BluetoothNamedValue(NS_LITERAL_STRING("Name"), propertyValue)); + } else if (p.type == BT_PROPERTY_CLASS_OF_DEVICE) { + uint32_t cod = *(uint32_t*)p.val; + propertyValue = cod; + propertiesArray.AppendElement( + BluetoothNamedValue(NS_LITERAL_STRING("Class"), propertyValue)); + nsString icon; + ClassToIcon(cod, icon); + propertyValue = icon; + propertiesArray.AppendElement( + BluetoothNamedValue(NS_LITERAL_STRING("Icon"), propertyValue)); + } else { + BT_LOGD("Not handled remote device property: %d", p.type); + } + } + + BluetoothValue value = propertiesArray; + BluetoothSignal signal(NS_LITERAL_STRING("DeviceFound"), + NS_LITERAL_STRING(KEY_ADAPTER), value); + nsRefPtr + t = new DistributeBluetoothSignalTask(signal); + if (NS_FAILED(NS_DispatchToMainThread(t))) { + NS_WARNING("Failed to dispatch to main thread!"); + } +} + +static void +DiscoveryStateChangedCallback(bt_discovery_state_t aState) +{ + MOZ_ASSERT(!NS_IsMainThread()); + + if (!sChangeDiscoveryRunnableArray.IsEmpty()) { + BluetoothValue values(true); + DispatchBluetoothReply(sChangeDiscoveryRunnableArray[0], + values, EmptyString()); + + sChangeDiscoveryRunnableArray.RemoveElementAt(0); + } +} + +bt_callbacks_t sBluetoothCallbacks = +{ sizeof(sBluetoothCallbacks), AdapterStateChangeCallback, - AdapterPropertiesChangeCallback + AdapterPropertiesChangeCallback, + RemoteDevicePropertiesChangeCallback, + DeviceFoundCallback, + DiscoveryStateChangedCallback }; /** @@ -335,6 +522,22 @@ nsresult BluetoothServiceBluedroid::StartDiscoveryInternal( BluetoothReplyRunnable* aRunnable) { + MOZ_ASSERT(NS_IsMainThread()); + + if (!IsReady()) { + NS_NAMED_LITERAL_STRING(errorStr, "Bluetooth service is not ready yet!"); + DispatchBluetoothReply(aRunnable, BluetoothValue(), errorStr); + + return NS_OK; + } + int ret = sBtInterface->start_discovery(); + if (ret != BT_STATUS_SUCCESS) { + ReplyStatusError(aRunnable, ret, NS_LITERAL_STRING("StartDiscovery")); + + return NS_OK; + } + + sChangeDiscoveryRunnableArray.AppendElement(aRunnable); return NS_OK; } @@ -342,6 +545,20 @@ nsresult BluetoothServiceBluedroid::StopDiscoveryInternal( BluetoothReplyRunnable* aRunnable) { + MOZ_ASSERT(NS_IsMainThread()); + + if (!IsReady()) { + NS_NAMED_LITERAL_STRING(errorStr, "Bluetooth service is not ready yet!"); + DispatchBluetoothReply(aRunnable, BluetoothValue(), errorStr); + return NS_OK; + } + int ret = sBtInterface->cancel_discovery(); + if (ret != BT_STATUS_SUCCESS) { + ReplyStatusError(aRunnable, ret, NS_LITERAL_STRING("StopDiscovery")); + return NS_OK; + } + + sChangeDiscoveryRunnableArray.AppendElement(aRunnable); return NS_OK; } @@ -359,6 +576,13 @@ BluetoothServiceBluedroid::SetProperty(BluetoothObjectType aType, { MOZ_ASSERT(NS_IsMainThread()); + if (!IsReady()) { + NS_NAMED_LITERAL_STRING(errorStr, "Bluetooth service is not ready yet!"); + DispatchBluetoothReply(aRunnable, BluetoothValue(), errorStr); + + return NS_OK; + } + const nsString propName = aValue.name(); bt_property_t prop; nsString str;