michael@0: /* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */ michael@0: /* vim: set ts=2 et sw=2 tw=80: */ michael@0: /* michael@0: ** Copyright 2006, The Android Open Source Project michael@0: ** michael@0: ** Licensed under the Apache License, Version 2.0 (the "License"); michael@0: ** you may not use this file except in compliance with the License. michael@0: ** You may obtain a copy of the License at michael@0: ** michael@0: ** http://www.apache.org/licenses/LICENSE-2.0 michael@0: ** michael@0: ** Unless required by applicable law or agreed to in writing, software michael@0: ** distributed under the License is distributed on an "AS IS" BASIS, michael@0: ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. michael@0: ** See the License for the specific language governing permissions and michael@0: ** limitations under the License. michael@0: */ michael@0: michael@0: #include "BluetoothServiceBluedroid.h" michael@0: michael@0: #include michael@0: michael@0: #include "BluetoothA2dpManager.h" michael@0: #include "BluetoothHfpManager.h" michael@0: #include "BluetoothOppManager.h" michael@0: #include "BluetoothProfileController.h" michael@0: #include "BluetoothReplyRunnable.h" michael@0: #include "BluetoothUtils.h" michael@0: #include "BluetoothUuid.h" michael@0: #include "mozilla/dom/bluetooth/BluetoothTypes.h" michael@0: #include "mozilla/ipc/UnixSocket.h" michael@0: #include "mozilla/StaticMutex.h" michael@0: #include "mozilla/StaticPtr.h" michael@0: #include "mozilla/unused.h" michael@0: michael@0: using namespace mozilla; michael@0: using namespace mozilla::ipc; michael@0: USING_BLUETOOTH_NAMESPACE michael@0: michael@0: /** michael@0: * Static variables michael@0: */ michael@0: static bluetooth_device_t* sBtDevice; michael@0: static const bt_interface_t* sBtInterface; michael@0: static bool sAdapterDiscoverable = false; michael@0: static bool sIsBtEnabled = false; michael@0: static nsString sAdapterBdAddress; michael@0: static nsString sAdapterBdName; michael@0: static uint32_t sAdapterDiscoverableTimeout; michael@0: static InfallibleTArray sAdapterBondedAddressArray; michael@0: static InfallibleTArray sRemoteDevicesPack; michael@0: static nsTArray > sControllerArray; michael@0: static nsTArray > sBondingRunnableArray; michael@0: static nsTArray > sChangeDiscoveryRunnableArray; michael@0: static nsTArray > sGetDeviceRunnableArray; michael@0: static nsTArray > sSetPropertyRunnableArray; michael@0: static nsTArray > sUnbondingRunnableArray; michael@0: static nsTArray sRequestedDeviceCountArray; michael@0: michael@0: /** michael@0: * Classes only used in this file michael@0: */ michael@0: class DistributeBluetoothSignalTask : public nsRunnable { michael@0: public: michael@0: DistributeBluetoothSignalTask(const BluetoothSignal& aSignal) : michael@0: mSignal(aSignal) michael@0: { michael@0: } michael@0: michael@0: NS_IMETHOD michael@0: Run() michael@0: { michael@0: MOZ_ASSERT(NS_IsMainThread()); michael@0: michael@0: BluetoothService* bs = BluetoothService::Get(); michael@0: NS_ENSURE_TRUE(bs, NS_ERROR_FAILURE); michael@0: michael@0: bs->DistributeSignal(mSignal); michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: private: michael@0: BluetoothSignal mSignal; michael@0: }; michael@0: michael@0: class SetupAfterEnabledTask : public nsRunnable michael@0: { michael@0: public: michael@0: SetupAfterEnabledTask() michael@0: { } michael@0: michael@0: NS_IMETHOD michael@0: Run() michael@0: { michael@0: MOZ_ASSERT(NS_IsMainThread()); michael@0: michael@0: // Bluetooth scan mode is NONE by default michael@0: bt_scan_mode_t mode = BT_SCAN_MODE_CONNECTABLE; michael@0: bt_property_t prop; michael@0: prop.type = BT_PROPERTY_ADAPTER_SCAN_MODE; michael@0: prop.val = (void*)&mode; michael@0: prop.len = sizeof(mode); michael@0: michael@0: NS_ENSURE_TRUE(sBtInterface, NS_ERROR_FAILURE); michael@0: michael@0: int ret = sBtInterface->set_adapter_property(&prop); michael@0: if (ret != BT_STATUS_SUCCESS) { michael@0: BT_LOGR("Fail to set: BT_SCAN_MODE_CONNECTABLE"); michael@0: } michael@0: michael@0: // Try to fire event 'AdapterAdded' to fit the original behaviour when michael@0: // we used BlueZ as backend. michael@0: BluetoothService* bs = BluetoothService::Get(); michael@0: NS_ENSURE_TRUE(bs, NS_ERROR_FAILURE); michael@0: michael@0: bs->AdapterAddedReceived(); michael@0: bs->TryFiringAdapterAdded(); michael@0: michael@0: // Trigger BluetoothOppManager to listen michael@0: BluetoothOppManager* opp = BluetoothOppManager::Get(); michael@0: if (!opp || !opp->Listen()) { michael@0: BT_LOGR("Fail to start BluetoothOppManager listening"); michael@0: } michael@0: michael@0: return NS_OK; michael@0: } michael@0: }; michael@0: michael@0: /** michael@0: * Static callback functions michael@0: */ michael@0: static void michael@0: ClassToIcon(uint32_t aClass, nsAString& aRetIcon) michael@0: { michael@0: switch ((aClass & 0x1f00) >> 8) { michael@0: case 0x01: michael@0: aRetIcon.AssignLiteral("computer"); michael@0: break; michael@0: case 0x02: michael@0: switch ((aClass & 0xfc) >> 2) { michael@0: case 0x01: michael@0: case 0x02: michael@0: case 0x03: michael@0: case 0x05: michael@0: aRetIcon.AssignLiteral("phone"); michael@0: break; michael@0: case 0x04: michael@0: aRetIcon.AssignLiteral("modem"); michael@0: break; michael@0: } michael@0: break; michael@0: case 0x03: michael@0: aRetIcon.AssignLiteral("network-wireless"); michael@0: break; michael@0: case 0x04: michael@0: switch ((aClass & 0xfc) >> 2) { michael@0: case 0x01: michael@0: case 0x02: michael@0: case 0x06: michael@0: aRetIcon.AssignLiteral("audio-card"); michael@0: break; michael@0: case 0x0b: michael@0: case 0x0c: michael@0: case 0x0d: michael@0: aRetIcon.AssignLiteral("camera-video"); michael@0: break; michael@0: default: michael@0: aRetIcon.AssignLiteral("audio-card"); michael@0: break; michael@0: } michael@0: break; michael@0: case 0x05: michael@0: switch ((aClass & 0xc0) >> 6) { michael@0: case 0x00: michael@0: switch ((aClass && 0x1e) >> 2) { michael@0: case 0x01: michael@0: case 0x02: michael@0: aRetIcon.AssignLiteral("input-gaming"); michael@0: break; michael@0: } michael@0: break; michael@0: case 0x01: michael@0: aRetIcon.AssignLiteral("input-keyboard"); michael@0: break; michael@0: case 0x02: michael@0: switch ((aClass && 0x1e) >> 2) { michael@0: case 0x05: michael@0: aRetIcon.AssignLiteral("input-tablet"); michael@0: break; michael@0: default: michael@0: aRetIcon.AssignLiteral("input-mouse"); michael@0: break; michael@0: } michael@0: } michael@0: break; michael@0: case 0x06: michael@0: if (aClass & 0x80) { michael@0: aRetIcon.AssignLiteral("printer"); michael@0: break; michael@0: } michael@0: if (aClass & 0x20) { michael@0: aRetIcon.AssignLiteral("camera-photo"); michael@0: break; michael@0: } michael@0: break; michael@0: } michael@0: michael@0: if (aRetIcon.IsEmpty()) { michael@0: if (HAS_AUDIO(aClass)) { michael@0: /** michael@0: * Property 'Icon' may be missed due to CoD of major class is TOY(0x08). michael@0: * But we need to assign Icon as audio-card if service class is 'Audio'. michael@0: * This is for PTS test case TC_AG_COD_BV_02_I. As HFP specification michael@0: * defines that service class is 'Audio' can be considered as HFP HF. michael@0: */ michael@0: aRetIcon.AssignLiteral("audio-card"); michael@0: } else { michael@0: BT_LOGR("No icon to match class: %x", aClass); michael@0: } michael@0: } michael@0: } michael@0: michael@0: static ControlPlayStatus michael@0: PlayStatusStringToControlPlayStatus(const nsAString& aPlayStatus) michael@0: { michael@0: ControlPlayStatus playStatus = ControlPlayStatus::PLAYSTATUS_UNKNOWN; michael@0: if (aPlayStatus.EqualsLiteral("STOPPED")) { michael@0: playStatus = ControlPlayStatus::PLAYSTATUS_STOPPED; michael@0: } else if (aPlayStatus.EqualsLiteral("PLAYING")) { michael@0: playStatus = ControlPlayStatus::PLAYSTATUS_PLAYING; michael@0: } else if (aPlayStatus.EqualsLiteral("PAUSED")) { michael@0: playStatus = ControlPlayStatus::PLAYSTATUS_PAUSED; michael@0: } else if (aPlayStatus.EqualsLiteral("FWD_SEEK")) { michael@0: playStatus = ControlPlayStatus::PLAYSTATUS_FWD_SEEK; michael@0: } else if (aPlayStatus.EqualsLiteral("REV_SEEK")) { michael@0: playStatus = ControlPlayStatus::PLAYSTATUS_REV_SEEK; michael@0: } else if (aPlayStatus.EqualsLiteral("ERROR")) { michael@0: playStatus = ControlPlayStatus::PLAYSTATUS_ERROR; michael@0: } michael@0: michael@0: return playStatus; michael@0: } michael@0: michael@0: static bool michael@0: IsReady() michael@0: { michael@0: if (!sBtInterface || !sIsBtEnabled) { michael@0: BT_LOGR("Warning! Bluetooth Service is not ready"); michael@0: return false; michael@0: } michael@0: return true; michael@0: } michael@0: michael@0: static void michael@0: AdapterStateChangeCallback(bt_state_t aStatus) michael@0: { michael@0: MOZ_ASSERT(!NS_IsMainThread()); michael@0: michael@0: BT_LOGR("BT_STATE %d", aStatus); michael@0: michael@0: sIsBtEnabled = (aStatus == BT_STATE_ON); michael@0: michael@0: nsRefPtr runnable = michael@0: new BluetoothService::ToggleBtAck(sIsBtEnabled); michael@0: if (NS_FAILED(NS_DispatchToMainThread(runnable))) { michael@0: BT_WARNING("Failed to dispatch to main thread!"); michael@0: return; michael@0: } michael@0: michael@0: if (sIsBtEnabled && michael@0: NS_FAILED(NS_DispatchToMainThread(new SetupAfterEnabledTask()))) { michael@0: BT_WARNING("Failed to dispatch to main thread!"); michael@0: } michael@0: } michael@0: michael@0: /** michael@0: * AdapterPropertiesCallback will be called after enable() but before michael@0: * AdapterStateChangeCallback sIsBtEnabled get updated. At that moment, both michael@0: * BluetoothManager/BluetoothAdapter does not register observer yet. michael@0: */ michael@0: static void michael@0: AdapterPropertiesCallback(bt_status_t aStatus, int aNumProperties, michael@0: bt_property_t *aProperties) michael@0: { michael@0: MOZ_ASSERT(!NS_IsMainThread()); michael@0: michael@0: BluetoothValue propertyValue; michael@0: InfallibleTArray props; michael@0: michael@0: for (int i = 0; i < aNumProperties; i++) { michael@0: bt_property_t p = aProperties[i]; michael@0: michael@0: if (p.type == BT_PROPERTY_BDADDR) { michael@0: BdAddressTypeToString((bt_bdaddr_t*)p.val, sAdapterBdAddress); michael@0: propertyValue = sAdapterBdAddress; michael@0: BT_APPEND_NAMED_VALUE(props, "Address", propertyValue); michael@0: } else if (p.type == BT_PROPERTY_BDNAME) { michael@0: // Construct nsCString here because Bd name returned from bluedroid michael@0: // is missing a null terminated character after SetProperty. michael@0: propertyValue = sAdapterBdName = NS_ConvertUTF8toUTF16( michael@0: nsCString((char*)p.val, p.len)); michael@0: BT_APPEND_NAMED_VALUE(props, "Name", propertyValue); michael@0: } else if (p.type == BT_PROPERTY_ADAPTER_SCAN_MODE) { michael@0: bt_scan_mode_t newMode = *(bt_scan_mode_t*)p.val; michael@0: michael@0: if (newMode == BT_SCAN_MODE_CONNECTABLE_DISCOVERABLE) { michael@0: propertyValue = sAdapterDiscoverable = true; michael@0: } else { michael@0: propertyValue = sAdapterDiscoverable = false; michael@0: } michael@0: michael@0: BT_APPEND_NAMED_VALUE(props, "Discoverable", propertyValue); michael@0: } else if (p.type == BT_PROPERTY_ADAPTER_DISCOVERY_TIMEOUT) { michael@0: propertyValue = sAdapterDiscoverableTimeout = *(uint32_t*)p.val; michael@0: BT_APPEND_NAMED_VALUE(props, "DiscoverableTimeout", propertyValue); michael@0: } else if (p.type == BT_PROPERTY_ADAPTER_BONDED_DEVICES) { michael@0: // We have to cache addresses of bonded devices. Unlike BlueZ, michael@0: // bluedroid would not send an another BT_PROPERTY_ADAPTER_BONDED_DEVICES michael@0: // event after bond completed michael@0: bt_bdaddr_t* deviceBdAddressTypes = (bt_bdaddr_t*)p.val; michael@0: int numOfAddresses = p.len / BLUETOOTH_ADDRESS_BYTES; michael@0: BT_LOGD("Adapter property: BONDED_DEVICES. Count: %d", numOfAddresses); michael@0: michael@0: // Whenever reloading paired devices, force refresh michael@0: sAdapterBondedAddressArray.Clear(); michael@0: michael@0: for (int index = 0; index < numOfAddresses; index++) { michael@0: nsAutoString deviceBdAddress; michael@0: BdAddressTypeToString(deviceBdAddressTypes + index, deviceBdAddress); michael@0: sAdapterBondedAddressArray.AppendElement(deviceBdAddress); michael@0: } michael@0: michael@0: propertyValue = sAdapterBondedAddressArray; michael@0: BT_APPEND_NAMED_VALUE(props, "Devices", propertyValue); michael@0: } else if (p.type == BT_PROPERTY_UUIDS) { michael@0: //FIXME: This will be implemented in the later patchset michael@0: continue; michael@0: } else { michael@0: BT_LOGD("Unhandled adapter property type: %d", p.type); michael@0: continue; michael@0: } michael@0: } michael@0: michael@0: NS_ENSURE_TRUE_VOID(props.Length() > 0); michael@0: michael@0: BluetoothValue value(props); michael@0: BluetoothSignal signal(NS_LITERAL_STRING("PropertyChanged"), michael@0: NS_LITERAL_STRING(KEY_ADAPTER), value); michael@0: nsRefPtr michael@0: t = new DistributeBluetoothSignalTask(signal); michael@0: if (NS_FAILED(NS_DispatchToMainThread(t))) { michael@0: BT_WARNING("Failed to dispatch to main thread!"); michael@0: } michael@0: michael@0: // bluedroid BTU task was stored in the task queue, see GKI_send_msg michael@0: if (!sSetPropertyRunnableArray.IsEmpty()) { michael@0: DispatchBluetoothReply(sSetPropertyRunnableArray[0], BluetoothValue(true), michael@0: EmptyString()); michael@0: sSetPropertyRunnableArray.RemoveElementAt(0); michael@0: } michael@0: } michael@0: michael@0: /** michael@0: * RemoteDevicePropertiesCallback will be called, as the following conditions: michael@0: * 1. When BT is turning on, bluedroid automatically execute this callback michael@0: * 2. When get_remote_device_properties() michael@0: */ michael@0: static void michael@0: RemoteDevicePropertiesCallback(bt_status_t aStatus, bt_bdaddr_t *aBdAddress, michael@0: int aNumProperties, bt_property_t *aProperties) michael@0: { michael@0: MOZ_ASSERT(!NS_IsMainThread()); michael@0: michael@0: if (sRequestedDeviceCountArray.IsEmpty()) { michael@0: MOZ_ASSERT(sGetDeviceRunnableArray.IsEmpty()); michael@0: return; michael@0: } michael@0: michael@0: sRequestedDeviceCountArray[0]--; michael@0: michael@0: InfallibleTArray props; michael@0: michael@0: nsString remoteDeviceBdAddress; michael@0: BdAddressTypeToString(aBdAddress, remoteDeviceBdAddress); michael@0: BT_APPEND_NAMED_VALUE(props, "Address", remoteDeviceBdAddress); michael@0: michael@0: for (int i = 0; i < aNumProperties; ++i) { michael@0: bt_property_t p = aProperties[i]; michael@0: michael@0: if (p.type == BT_PROPERTY_BDNAME) { michael@0: BluetoothValue propertyValue = NS_ConvertUTF8toUTF16((char*)p.val); michael@0: BT_APPEND_NAMED_VALUE(props, "Name", propertyValue); michael@0: } else if (p.type == BT_PROPERTY_CLASS_OF_DEVICE) { michael@0: uint32_t cod = *(uint32_t*)p.val; michael@0: BT_APPEND_NAMED_VALUE(props, "Class", cod); michael@0: michael@0: nsString icon; michael@0: ClassToIcon(cod, icon); michael@0: BT_APPEND_NAMED_VALUE(props, "Icon", icon); michael@0: } else { michael@0: BT_LOGD("Other non-handled device properties. Type: %d", p.type); michael@0: } michael@0: } michael@0: michael@0: // Update to registered BluetoothDevice objects michael@0: BluetoothSignal signal(NS_LITERAL_STRING("PropertyChanged"), michael@0: remoteDeviceBdAddress, props); michael@0: nsRefPtr michael@0: t = new DistributeBluetoothSignalTask(signal); michael@0: if (NS_FAILED(NS_DispatchToMainThread(t))) { michael@0: BT_WARNING("Failed to dispatch to main thread!"); michael@0: } michael@0: michael@0: // Use address as the index michael@0: sRemoteDevicesPack.AppendElement( michael@0: BluetoothNamedValue(remoteDeviceBdAddress, props)); michael@0: michael@0: if (sRequestedDeviceCountArray[0] == 0) { michael@0: MOZ_ASSERT(!sGetDeviceRunnableArray.IsEmpty()); michael@0: michael@0: if (sGetDeviceRunnableArray.IsEmpty()) { michael@0: BT_LOGR("No runnable to return"); michael@0: return; michael@0: } michael@0: michael@0: DispatchBluetoothReply(sGetDeviceRunnableArray[0], michael@0: sRemoteDevicesPack, EmptyString()); michael@0: michael@0: // After firing it, clean up cache michael@0: sRemoteDevicesPack.Clear(); michael@0: michael@0: sRequestedDeviceCountArray.RemoveElementAt(0); michael@0: sGetDeviceRunnableArray.RemoveElementAt(0); michael@0: } michael@0: } michael@0: michael@0: static void michael@0: DeviceFoundCallback(int aNumProperties, bt_property_t *aProperties) michael@0: { michael@0: MOZ_ASSERT(!NS_IsMainThread()); michael@0: michael@0: BluetoothValue propertyValue; michael@0: InfallibleTArray propertiesArray; michael@0: michael@0: for (int i = 0; i < aNumProperties; i++) { michael@0: bt_property_t p = aProperties[i]; michael@0: michael@0: if (p.type == BT_PROPERTY_BDADDR) { michael@0: nsString remoteDeviceBdAddress; michael@0: BdAddressTypeToString((bt_bdaddr_t*)p.val, remoteDeviceBdAddress); michael@0: propertyValue = remoteDeviceBdAddress; michael@0: michael@0: BT_APPEND_NAMED_VALUE(propertiesArray, "Address", propertyValue); michael@0: } else if (p.type == BT_PROPERTY_BDNAME) { michael@0: propertyValue = NS_ConvertUTF8toUTF16((char*)p.val); michael@0: BT_APPEND_NAMED_VALUE(propertiesArray, "Name", propertyValue); michael@0: } else if (p.type == BT_PROPERTY_CLASS_OF_DEVICE) { michael@0: uint32_t cod = *(uint32_t*)p.val; michael@0: propertyValue = cod; michael@0: BT_APPEND_NAMED_VALUE(propertiesArray, "Class", propertyValue); michael@0: michael@0: nsString icon; michael@0: ClassToIcon(cod, icon); michael@0: propertyValue = icon; michael@0: BT_APPEND_NAMED_VALUE(propertiesArray, "Icon", propertyValue); michael@0: } else { michael@0: BT_LOGD("Not handled remote device property: %d", p.type); michael@0: } michael@0: } michael@0: michael@0: BluetoothValue value = propertiesArray; michael@0: BluetoothSignal signal(NS_LITERAL_STRING("DeviceFound"), michael@0: NS_LITERAL_STRING(KEY_ADAPTER), value); michael@0: nsRefPtr michael@0: t = new DistributeBluetoothSignalTask(signal); michael@0: if (NS_FAILED(NS_DispatchToMainThread(t))) { michael@0: BT_WARNING("Failed to dispatch to main thread!"); michael@0: } michael@0: } michael@0: michael@0: static void michael@0: DiscoveryStateChangedCallback(bt_discovery_state_t aState) michael@0: { michael@0: MOZ_ASSERT(!NS_IsMainThread()); michael@0: michael@0: if (!sChangeDiscoveryRunnableArray.IsEmpty()) { michael@0: BluetoothValue values(true); michael@0: DispatchBluetoothReply(sChangeDiscoveryRunnableArray[0], michael@0: values, EmptyString()); michael@0: michael@0: sChangeDiscoveryRunnableArray.RemoveElementAt(0); michael@0: } michael@0: } michael@0: michael@0: static void michael@0: PinRequestCallback(bt_bdaddr_t* aRemoteBdAddress, michael@0: bt_bdname_t* aRemoteBdName, uint32_t aRemoteClass) michael@0: { michael@0: MOZ_ASSERT(!NS_IsMainThread()); michael@0: michael@0: InfallibleTArray propertiesArray; michael@0: nsAutoString remoteAddress; michael@0: BdAddressTypeToString(aRemoteBdAddress, remoteAddress); michael@0: michael@0: BT_APPEND_NAMED_VALUE(propertiesArray, "address", remoteAddress); michael@0: BT_APPEND_NAMED_VALUE(propertiesArray, "method", michael@0: NS_LITERAL_STRING("pincode")); michael@0: BT_APPEND_NAMED_VALUE(propertiesArray, "name", michael@0: NS_ConvertUTF8toUTF16( michael@0: (const char*)aRemoteBdName->name)); michael@0: michael@0: BluetoothValue value = propertiesArray; michael@0: BluetoothSignal signal(NS_LITERAL_STRING("RequestPinCode"), michael@0: NS_LITERAL_STRING(KEY_LOCAL_AGENT), value); michael@0: nsRefPtr michael@0: t = new DistributeBluetoothSignalTask(signal); michael@0: if (NS_FAILED(NS_DispatchToMainThread(t))) { michael@0: BT_WARNING("Failed to dispatch to main thread!"); michael@0: } michael@0: } michael@0: michael@0: static void michael@0: SspRequestCallback(bt_bdaddr_t* aRemoteBdAddress, bt_bdname_t* aRemoteBdName, michael@0: uint32_t aRemoteClass, bt_ssp_variant_t aPairingVariant, michael@0: uint32_t aPasskey) michael@0: { michael@0: MOZ_ASSERT(!NS_IsMainThread()); michael@0: michael@0: InfallibleTArray propertiesArray; michael@0: nsAutoString remoteAddress; michael@0: BdAddressTypeToString(aRemoteBdAddress, remoteAddress); michael@0: michael@0: BT_APPEND_NAMED_VALUE(propertiesArray, "address", remoteAddress); michael@0: BT_APPEND_NAMED_VALUE(propertiesArray, "method", michael@0: NS_LITERAL_STRING("confirmation")); michael@0: BT_APPEND_NAMED_VALUE(propertiesArray, "name", michael@0: NS_ConvertUTF8toUTF16( michael@0: (const char*)aRemoteBdName->name)); michael@0: BT_APPEND_NAMED_VALUE(propertiesArray, "passkey", aPasskey); michael@0: michael@0: BluetoothValue value = propertiesArray; michael@0: BluetoothSignal signal(NS_LITERAL_STRING("RequestConfirmation"), michael@0: NS_LITERAL_STRING(KEY_LOCAL_AGENT), value); michael@0: nsRefPtr michael@0: t = new DistributeBluetoothSignalTask(signal); michael@0: if (NS_FAILED(NS_DispatchToMainThread(t))) { michael@0: BT_WARNING("Failed to dispatch to main thread!"); michael@0: } michael@0: } michael@0: michael@0: static void michael@0: BondStateChangedCallback(bt_status_t aStatus, bt_bdaddr_t* aRemoteBdAddress, michael@0: bt_bond_state_t aState) michael@0: { michael@0: MOZ_ASSERT(!NS_IsMainThread()); michael@0: michael@0: nsAutoString remoteAddress; michael@0: BdAddressTypeToString(aRemoteBdAddress, remoteAddress); michael@0: michael@0: // We don't need to handle bonding state michael@0: NS_ENSURE_TRUE_VOID(aState != BT_BOND_STATE_BONDING); michael@0: NS_ENSURE_FALSE_VOID(aState == BT_BOND_STATE_BONDED && michael@0: sAdapterBondedAddressArray.Contains(remoteAddress)); michael@0: bool bonded; michael@0: if (aState == BT_BOND_STATE_NONE) { michael@0: bonded = false; michael@0: sAdapterBondedAddressArray.RemoveElement(remoteAddress); michael@0: } else if (aState == BT_BOND_STATE_BONDED) { michael@0: bonded = true; michael@0: sAdapterBondedAddressArray.AppendElement(remoteAddress); michael@0: } michael@0: michael@0: // Update bonded address list to BluetoothAdapter michael@0: InfallibleTArray propertiesChangeArray; michael@0: BT_APPEND_NAMED_VALUE(propertiesChangeArray, "Devices", michael@0: sAdapterBondedAddressArray); michael@0: michael@0: BluetoothValue value(propertiesChangeArray); michael@0: BluetoothSignal signal(NS_LITERAL_STRING("PropertyChanged"), michael@0: NS_LITERAL_STRING(KEY_ADAPTER), michael@0: BluetoothValue(propertiesChangeArray)); michael@0: NS_DispatchToMainThread(new DistributeBluetoothSignalTask(signal)); michael@0: michael@0: // Update bonding status to gaia michael@0: InfallibleTArray propertiesArray; michael@0: BT_APPEND_NAMED_VALUE(propertiesArray, "address", remoteAddress); michael@0: BT_APPEND_NAMED_VALUE(propertiesArray, "status", bonded); michael@0: michael@0: BluetoothSignal newSignal(NS_LITERAL_STRING(PAIRED_STATUS_CHANGED_ID), michael@0: NS_LITERAL_STRING(KEY_ADAPTER), michael@0: BluetoothValue(propertiesArray)); michael@0: NS_DispatchToMainThread(new DistributeBluetoothSignalTask(newSignal)); michael@0: michael@0: if (bonded && !sBondingRunnableArray.IsEmpty()) { michael@0: DispatchBluetoothReply(sBondingRunnableArray[0], michael@0: BluetoothValue(true), EmptyString()); michael@0: michael@0: sBondingRunnableArray.RemoveElementAt(0); michael@0: } else if (!bonded && !sUnbondingRunnableArray.IsEmpty()) { michael@0: DispatchBluetoothReply(sUnbondingRunnableArray[0], michael@0: BluetoothValue(true), EmptyString()); michael@0: michael@0: sUnbondingRunnableArray.RemoveElementAt(0); michael@0: } michael@0: } michael@0: michael@0: static void michael@0: AclStateChangedCallback(bt_status_t aStatus, bt_bdaddr_t* aRemoteBdAddress, michael@0: bt_acl_state_t aState) michael@0: { michael@0: //FIXME: This will be implemented in the later patchset michael@0: } michael@0: michael@0: static void michael@0: CallbackThreadEvent(bt_cb_thread_evt evt) michael@0: { michael@0: //FIXME: This will be implemented in the later patchset michael@0: } michael@0: michael@0: bt_callbacks_t sBluetoothCallbacks = michael@0: { michael@0: sizeof(sBluetoothCallbacks), michael@0: AdapterStateChangeCallback, michael@0: AdapterPropertiesCallback, michael@0: RemoteDevicePropertiesCallback, michael@0: DeviceFoundCallback, michael@0: DiscoveryStateChangedCallback, michael@0: PinRequestCallback, michael@0: SspRequestCallback, michael@0: BondStateChangedCallback, michael@0: AclStateChangedCallback, michael@0: CallbackThreadEvent michael@0: }; michael@0: michael@0: /** michael@0: * Static functions michael@0: */ michael@0: static bool michael@0: EnsureBluetoothHalLoad() michael@0: { michael@0: hw_module_t* module; michael@0: hw_device_t* device; michael@0: int err = hw_get_module(BT_HARDWARE_MODULE_ID, (hw_module_t const**)&module); michael@0: if (err != 0) { michael@0: BT_LOGR("Error: %s", strerror(err)); michael@0: return false; michael@0: } michael@0: module->methods->open(module, BT_HARDWARE_MODULE_ID, &device); michael@0: sBtDevice = (bluetooth_device_t *)device; michael@0: sBtInterface = sBtDevice->get_bluetooth_interface(); michael@0: michael@0: int ret = sBtInterface->init(&sBluetoothCallbacks); michael@0: if (ret != BT_STATUS_SUCCESS) { michael@0: BT_LOGR("Error while setting the callbacks"); michael@0: sBtInterface = nullptr; michael@0: } michael@0: michael@0: return true; michael@0: } michael@0: michael@0: static nsresult michael@0: StartStopGonkBluetooth(bool aShouldEnable) michael@0: { michael@0: MOZ_ASSERT(NS_IsMainThread()); michael@0: NS_ENSURE_TRUE(sBtInterface, NS_ERROR_FAILURE); michael@0: michael@0: if (sIsBtEnabled == aShouldEnable) { michael@0: // Keep current enable status michael@0: nsRefPtr runnable = michael@0: new BluetoothService::ToggleBtAck(sIsBtEnabled); michael@0: if (NS_FAILED(NS_DispatchToMainThread(runnable))) { michael@0: BT_WARNING("Failed to dispatch to main thread!"); michael@0: } michael@0: return NS_OK; michael@0: } michael@0: michael@0: int ret = aShouldEnable ? sBtInterface->enable() : sBtInterface->disable(); michael@0: NS_ENSURE_TRUE(ret == BT_STATUS_SUCCESS, NS_ERROR_FAILURE); michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: static void michael@0: ReplyStatusError(BluetoothReplyRunnable* aBluetoothReplyRunnable, michael@0: int aStatusCode, const nsAString& aCustomMsg) michael@0: { michael@0: MOZ_ASSERT(aBluetoothReplyRunnable, "Reply runnable is nullptr"); michael@0: michael@0: BT_LOGR("error code(%d)", aStatusCode); michael@0: michael@0: nsAutoString replyError; michael@0: replyError.Assign(aCustomMsg); michael@0: michael@0: if (aStatusCode == BT_STATUS_BUSY) { michael@0: replyError.AppendLiteral(":BT_STATUS_BUSY"); michael@0: } else if (aStatusCode == BT_STATUS_NOT_READY) { michael@0: replyError.AppendLiteral(":BT_STATUS_NOT_READY"); michael@0: } else if (aStatusCode == BT_STATUS_DONE) { michael@0: replyError.AppendLiteral(":BT_STATUS_DONE"); michael@0: } else if (aStatusCode == BT_STATUS_AUTH_FAILURE) { michael@0: replyError.AppendLiteral(":BT_STATUS_AUTH_FAILURE"); michael@0: } else if (aStatusCode == BT_STATUS_RMT_DEV_DOWN) { michael@0: replyError.AppendLiteral(":BT_STATUS_RMT_DEV_DOWN"); michael@0: } else if (aStatusCode == BT_STATUS_FAIL) { michael@0: replyError.AppendLiteral(":BT_STATUS_FAIL"); michael@0: } michael@0: michael@0: DispatchBluetoothReply(aBluetoothReplyRunnable, BluetoothValue(true), michael@0: replyError); michael@0: } michael@0: michael@0: /** michael@0: * Member functions michael@0: */ michael@0: BluetoothServiceBluedroid::BluetoothServiceBluedroid() michael@0: { michael@0: if (!EnsureBluetoothHalLoad()) { michael@0: BT_LOGR("Error! Failed to load bluedroid library."); michael@0: return; michael@0: } michael@0: michael@0: // Register all the bluedroid callbacks before enable() get called michael@0: // It is required to register a2dp callbacks before a2dp media task starts up. michael@0: BluetoothHfpManager::Get(); michael@0: BluetoothA2dpManager::Get(); michael@0: } michael@0: michael@0: BluetoothServiceBluedroid::~BluetoothServiceBluedroid() michael@0: { michael@0: } michael@0: michael@0: nsresult michael@0: BluetoothServiceBluedroid::StartInternal() michael@0: { michael@0: MOZ_ASSERT(NS_IsMainThread()); michael@0: michael@0: nsresult ret = StartStopGonkBluetooth(true); michael@0: if (NS_FAILED(ret)) { michael@0: nsRefPtr runnable = michael@0: new BluetoothService::ToggleBtAck(false); michael@0: if (NS_FAILED(NS_DispatchToMainThread(runnable))) { michael@0: BT_WARNING("Failed to dispatch to main thread!"); michael@0: } michael@0: BT_LOGR("Error"); michael@0: } michael@0: michael@0: return ret; michael@0: } michael@0: michael@0: nsresult michael@0: BluetoothServiceBluedroid::StopInternal() michael@0: { michael@0: MOZ_ASSERT(NS_IsMainThread()); michael@0: michael@0: nsresult ret = StartStopGonkBluetooth(false); michael@0: if (NS_FAILED(ret)) { michael@0: nsRefPtr runnable = michael@0: new BluetoothService::ToggleBtAck(true); michael@0: if (NS_FAILED(NS_DispatchToMainThread(runnable))) { michael@0: BT_WARNING("Failed to dispatch to main thread!"); michael@0: } michael@0: BT_LOGR("Error"); michael@0: } michael@0: michael@0: return ret; michael@0: } michael@0: michael@0: nsresult michael@0: BluetoothServiceBluedroid::GetDefaultAdapterPathInternal( michael@0: BluetoothReplyRunnable* aRunnable) michael@0: { michael@0: MOZ_ASSERT(NS_IsMainThread()); michael@0: michael@0: nsRefPtr runnable(aRunnable); michael@0: michael@0: BluetoothValue v = InfallibleTArray(); michael@0: michael@0: BT_APPEND_NAMED_VALUE(v.get_ArrayOfBluetoothNamedValue(), michael@0: "Address", sAdapterBdAddress); michael@0: michael@0: BT_APPEND_NAMED_VALUE(v.get_ArrayOfBluetoothNamedValue(), michael@0: "Name", sAdapterBdName); michael@0: michael@0: BT_APPEND_NAMED_VALUE(v.get_ArrayOfBluetoothNamedValue(), michael@0: "Discoverable", sAdapterDiscoverable); michael@0: michael@0: BT_APPEND_NAMED_VALUE(v.get_ArrayOfBluetoothNamedValue(), michael@0: "DiscoverableTimeout", sAdapterDiscoverableTimeout); michael@0: michael@0: BT_APPEND_NAMED_VALUE(v.get_ArrayOfBluetoothNamedValue(), michael@0: "Devices", sAdapterBondedAddressArray); michael@0: michael@0: nsAutoString replyError; michael@0: DispatchBluetoothReply(runnable.get(), v, replyError); michael@0: michael@0: unused << runnable.forget(); // picked up in DispatchBluetoothReply michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: nsresult michael@0: BluetoothServiceBluedroid::GetConnectedDevicePropertiesInternal( michael@0: uint16_t aServiceUuid, BluetoothReplyRunnable* aRunnable) michael@0: { michael@0: MOZ_ASSERT(NS_IsMainThread()); michael@0: michael@0: if (!IsReady()) { michael@0: NS_NAMED_LITERAL_STRING(errorStr, "Bluetooth service is not ready yet!"); michael@0: DispatchBluetoothReply(aRunnable, BluetoothValue(), errorStr); michael@0: return NS_OK; michael@0: } michael@0: michael@0: BluetoothProfileManagerBase* profile = michael@0: BluetoothUuidHelper::GetBluetoothProfileManager(aServiceUuid); michael@0: if (!profile) { michael@0: InfallibleTArray emptyArr; michael@0: DispatchBluetoothReply(aRunnable, emptyArr, michael@0: NS_LITERAL_STRING(ERR_UNKNOWN_PROFILE)); michael@0: return NS_OK; michael@0: } michael@0: michael@0: nsTArray deviceAddresses; michael@0: if (profile->IsConnected()) { michael@0: nsString address; michael@0: profile->GetAddress(address); michael@0: deviceAddresses.AppendElement(address); michael@0: } michael@0: michael@0: int requestedDeviceCount = deviceAddresses.Length(); michael@0: if (requestedDeviceCount == 0) { michael@0: InfallibleTArray emptyArr; michael@0: DispatchBluetoothReply(aRunnable, emptyArr, EmptyString()); michael@0: return NS_OK; michael@0: } michael@0: michael@0: for (int i = 0; i < requestedDeviceCount; i++) { michael@0: // Retrieve all properties of devices michael@0: bt_bdaddr_t addressType; michael@0: StringToBdAddressType(deviceAddresses[i], &addressType); michael@0: michael@0: int ret = sBtInterface->get_remote_device_properties(&addressType); michael@0: if (ret != BT_STATUS_SUCCESS) { michael@0: DispatchBluetoothReply(aRunnable, BluetoothValue(true), michael@0: NS_LITERAL_STRING("GetConnectedDeviceFailed")); michael@0: return NS_OK; michael@0: } michael@0: } michael@0: michael@0: sRequestedDeviceCountArray.AppendElement(requestedDeviceCount); michael@0: sGetDeviceRunnableArray.AppendElement(aRunnable); michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: nsresult michael@0: BluetoothServiceBluedroid::GetPairedDevicePropertiesInternal( michael@0: const nsTArray& aDeviceAddress, BluetoothReplyRunnable* aRunnable) michael@0: { michael@0: MOZ_ASSERT(NS_IsMainThread()); michael@0: michael@0: if (!IsReady()) { michael@0: NS_NAMED_LITERAL_STRING(errorStr, "Bluetooth service is not ready yet!"); michael@0: DispatchBluetoothReply(aRunnable, BluetoothValue(), errorStr); michael@0: return NS_OK; michael@0: } michael@0: michael@0: int requestedDeviceCount = aDeviceAddress.Length(); michael@0: if (requestedDeviceCount == 0) { michael@0: InfallibleTArray emptyArr; michael@0: DispatchBluetoothReply(aRunnable, BluetoothValue(emptyArr), EmptyString()); michael@0: return NS_OK; michael@0: } michael@0: michael@0: for (int i = 0; i < requestedDeviceCount; i++) { michael@0: // Retrieve all properties of devices michael@0: bt_bdaddr_t addressType; michael@0: StringToBdAddressType(aDeviceAddress[i], &addressType); michael@0: int ret = sBtInterface->get_remote_device_properties(&addressType); michael@0: if (ret != BT_STATUS_SUCCESS) { michael@0: DispatchBluetoothReply(aRunnable, BluetoothValue(true), michael@0: NS_LITERAL_STRING("GetPairedDeviceFailed")); michael@0: return NS_OK; michael@0: } michael@0: } michael@0: michael@0: sRequestedDeviceCountArray.AppendElement(requestedDeviceCount); michael@0: sGetDeviceRunnableArray.AppendElement(aRunnable); michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: nsresult michael@0: BluetoothServiceBluedroid::StartDiscoveryInternal( michael@0: BluetoothReplyRunnable* aRunnable) michael@0: { michael@0: MOZ_ASSERT(NS_IsMainThread()); michael@0: michael@0: if (!IsReady()) { michael@0: NS_NAMED_LITERAL_STRING(errorStr, "Bluetooth service is not ready yet!"); michael@0: DispatchBluetoothReply(aRunnable, BluetoothValue(), errorStr); michael@0: michael@0: return NS_OK; michael@0: } michael@0: int ret = sBtInterface->start_discovery(); michael@0: if (ret != BT_STATUS_SUCCESS) { michael@0: ReplyStatusError(aRunnable, ret, NS_LITERAL_STRING("StartDiscovery")); michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: sChangeDiscoveryRunnableArray.AppendElement(aRunnable); michael@0: return NS_OK; michael@0: } michael@0: michael@0: nsresult michael@0: BluetoothServiceBluedroid::StopDiscoveryInternal( michael@0: BluetoothReplyRunnable* aRunnable) michael@0: { michael@0: MOZ_ASSERT(NS_IsMainThread()); michael@0: michael@0: if (!IsReady()) { michael@0: NS_NAMED_LITERAL_STRING(errorStr, "Bluetooth service is not ready yet!"); michael@0: DispatchBluetoothReply(aRunnable, BluetoothValue(), errorStr); michael@0: return NS_OK; michael@0: } michael@0: michael@0: int ret = sBtInterface->cancel_discovery(); michael@0: if (ret != BT_STATUS_SUCCESS) { michael@0: ReplyStatusError(aRunnable, ret, NS_LITERAL_STRING("StopDiscovery")); michael@0: return NS_OK; michael@0: } michael@0: michael@0: sChangeDiscoveryRunnableArray.AppendElement(aRunnable); michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: nsresult michael@0: BluetoothServiceBluedroid::SetProperty(BluetoothObjectType aType, michael@0: const BluetoothNamedValue& aValue, michael@0: BluetoothReplyRunnable* aRunnable) michael@0: { michael@0: MOZ_ASSERT(NS_IsMainThread()); michael@0: michael@0: if (!IsReady()) { michael@0: NS_NAMED_LITERAL_STRING(errorStr, "Bluetooth service is not ready yet!"); michael@0: DispatchBluetoothReply(aRunnable, BluetoothValue(), errorStr); michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: const nsString propName = aValue.name(); michael@0: bt_property_t prop; michael@0: bt_scan_mode_t scanMode; michael@0: nsCString str; michael@0: michael@0: // For Bluedroid, it's necessary to check property name for SetProperty michael@0: if (propName.EqualsLiteral("Name")) { michael@0: prop.type = BT_PROPERTY_BDNAME; michael@0: } else if (propName.EqualsLiteral("Discoverable")) { michael@0: prop.type = BT_PROPERTY_ADAPTER_SCAN_MODE; michael@0: } else if (propName.EqualsLiteral("DiscoverableTimeout")) { michael@0: prop.type = BT_PROPERTY_ADAPTER_DISCOVERY_TIMEOUT; michael@0: } else { michael@0: BT_LOGR("Warning: Property type is not supported yet, type: %d", prop.type); michael@0: } michael@0: michael@0: if (aValue.value().type() == BluetoothValue::Tuint32_t) { michael@0: // Set discoverable timeout michael@0: prop.val = (void*)aValue.value().get_uint32_t(); michael@0: } else if (aValue.value().type() == BluetoothValue::TnsString) { michael@0: // Set name michael@0: str = NS_ConvertUTF16toUTF8(aValue.value().get_nsString()); michael@0: const char* name = str.get(); michael@0: prop.val = (void*)name; michael@0: prop.len = strlen(name); michael@0: } else if (aValue.value().type() == BluetoothValue::Tbool) { michael@0: scanMode = aValue.value().get_bool() ? michael@0: BT_SCAN_MODE_CONNECTABLE_DISCOVERABLE : michael@0: BT_SCAN_MODE_CONNECTABLE; michael@0: michael@0: prop.val = (void*)&scanMode; michael@0: prop.len = sizeof(scanMode); michael@0: } else { michael@0: BT_LOGR("SetProperty but the property cannot be recognized correctly."); michael@0: return NS_OK; michael@0: } michael@0: michael@0: sSetPropertyRunnableArray.AppendElement(aRunnable); michael@0: michael@0: int ret = sBtInterface->set_adapter_property(&prop); michael@0: if (ret != BT_STATUS_SUCCESS) { michael@0: ReplyStatusError(aRunnable, ret, NS_LITERAL_STRING("SetProperty")); michael@0: } michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: nsresult michael@0: BluetoothServiceBluedroid::GetServiceChannel( michael@0: const nsAString& aDeviceAddress, michael@0: const nsAString& aServiceUuid, michael@0: BluetoothProfileManagerBase* aManager) michael@0: { michael@0: return NS_OK; michael@0: } michael@0: michael@0: bool michael@0: BluetoothServiceBluedroid::UpdateSdpRecords( michael@0: const nsAString& aDeviceAddress, michael@0: BluetoothProfileManagerBase* aManager) michael@0: { michael@0: return true; michael@0: } michael@0: michael@0: nsresult michael@0: BluetoothServiceBluedroid::CreatePairedDeviceInternal( michael@0: const nsAString& aDeviceAddress, int aTimeout, michael@0: BluetoothReplyRunnable* aRunnable) michael@0: { michael@0: MOZ_ASSERT(NS_IsMainThread()); michael@0: michael@0: if (!IsReady()) { michael@0: NS_NAMED_LITERAL_STRING(errorStr, "Bluetooth service is not ready yet!"); michael@0: DispatchBluetoothReply(aRunnable, BluetoothValue(), errorStr); michael@0: return NS_OK; michael@0: } michael@0: michael@0: bt_bdaddr_t remoteAddress; michael@0: StringToBdAddressType(aDeviceAddress, &remoteAddress); michael@0: michael@0: int ret = sBtInterface->create_bond(&remoteAddress); michael@0: if (ret != BT_STATUS_SUCCESS) { michael@0: ReplyStatusError(aRunnable, ret, NS_LITERAL_STRING("CreatedPairedDevice")); michael@0: } else { michael@0: sBondingRunnableArray.AppendElement(aRunnable); michael@0: } michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: nsresult michael@0: BluetoothServiceBluedroid::RemoveDeviceInternal( michael@0: const nsAString& aDeviceAddress, BluetoothReplyRunnable* aRunnable) michael@0: { michael@0: MOZ_ASSERT(NS_IsMainThread()); michael@0: michael@0: if (!IsReady()) { michael@0: NS_NAMED_LITERAL_STRING(errorStr, "Bluetooth service is not ready yet!"); michael@0: DispatchBluetoothReply(aRunnable, BluetoothValue(), errorStr); michael@0: return NS_OK; michael@0: } michael@0: michael@0: bt_bdaddr_t remoteAddress; michael@0: StringToBdAddressType(aDeviceAddress, &remoteAddress); michael@0: michael@0: int ret = sBtInterface->remove_bond(&remoteAddress); michael@0: if (ret != BT_STATUS_SUCCESS) { michael@0: ReplyStatusError(aRunnable, ret, michael@0: NS_LITERAL_STRING("RemoveDevice")); michael@0: } else { michael@0: sUnbondingRunnableArray.AppendElement(aRunnable); michael@0: } michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: bool michael@0: BluetoothServiceBluedroid::SetPinCodeInternal( michael@0: const nsAString& aDeviceAddress, const nsAString& aPinCode, michael@0: BluetoothReplyRunnable* aRunnable) michael@0: { michael@0: MOZ_ASSERT(NS_IsMainThread()); michael@0: michael@0: if (!IsReady()) { michael@0: NS_NAMED_LITERAL_STRING(errorStr, "Bluetooth service is not ready yet!"); michael@0: DispatchBluetoothReply(aRunnable, BluetoothValue(), errorStr); michael@0: return false; michael@0: } michael@0: michael@0: bt_bdaddr_t remoteAddress; michael@0: StringToBdAddressType(aDeviceAddress, &remoteAddress); michael@0: michael@0: int ret = sBtInterface->pin_reply( michael@0: &remoteAddress, true, aPinCode.Length(), michael@0: (bt_pin_code_t*)NS_ConvertUTF16toUTF8(aPinCode).get()); michael@0: michael@0: if (ret != BT_STATUS_SUCCESS) { michael@0: ReplyStatusError(aRunnable, ret, NS_LITERAL_STRING("SetPinCode")); michael@0: } else { michael@0: DispatchBluetoothReply(aRunnable, BluetoothValue(true), EmptyString()); michael@0: } michael@0: michael@0: return true; michael@0: } michael@0: michael@0: bool michael@0: BluetoothServiceBluedroid::SetPasskeyInternal( michael@0: const nsAString& aDeviceAddress, uint32_t aPasskey, michael@0: BluetoothReplyRunnable* aRunnable) michael@0: { michael@0: return true; michael@0: } michael@0: michael@0: bool michael@0: BluetoothServiceBluedroid::SetPairingConfirmationInternal( michael@0: const nsAString& aDeviceAddress, bool aConfirm, michael@0: BluetoothReplyRunnable* aRunnable) michael@0: { michael@0: MOZ_ASSERT(NS_IsMainThread()); michael@0: michael@0: if (!IsReady()) { michael@0: NS_NAMED_LITERAL_STRING(errorStr, "Bluetooth service is not ready yet!"); michael@0: DispatchBluetoothReply(aRunnable, BluetoothValue(), errorStr); michael@0: return false; michael@0: } michael@0: michael@0: bt_bdaddr_t remoteAddress; michael@0: StringToBdAddressType(aDeviceAddress, &remoteAddress); michael@0: michael@0: int ret = sBtInterface->ssp_reply(&remoteAddress, (bt_ssp_variant_t)0, michael@0: aConfirm, 0); michael@0: if (ret != BT_STATUS_SUCCESS) { michael@0: ReplyStatusError(aRunnable, ret, michael@0: NS_LITERAL_STRING("SetPairingConfirmation")); michael@0: } else { michael@0: DispatchBluetoothReply(aRunnable, BluetoothValue(true), EmptyString()); michael@0: } michael@0: michael@0: return true; michael@0: } michael@0: michael@0: bool michael@0: BluetoothServiceBluedroid::SetAuthorizationInternal( michael@0: const nsAString& aDeviceAddress, bool aAllow, michael@0: BluetoothReplyRunnable* aRunnable) michael@0: { michael@0: return true; michael@0: } michael@0: michael@0: nsresult michael@0: BluetoothServiceBluedroid::PrepareAdapterInternal() michael@0: { michael@0: return NS_OK; michael@0: } michael@0: michael@0: static void michael@0: NextBluetoothProfileController() michael@0: { michael@0: MOZ_ASSERT(NS_IsMainThread()); michael@0: michael@0: // First, remove the task at the front which has been already done. michael@0: NS_ENSURE_FALSE_VOID(sControllerArray.IsEmpty()); michael@0: sControllerArray.RemoveElementAt(0); michael@0: // Re-check if the task array is empty, if it's not, the next task will begin. michael@0: NS_ENSURE_FALSE_VOID(sControllerArray.IsEmpty()); michael@0: sControllerArray[0]->StartSession(); michael@0: } michael@0: michael@0: static void michael@0: ConnectDisconnect(bool aConnect, const nsAString& aDeviceAddress, michael@0: BluetoothReplyRunnable* aRunnable, michael@0: uint16_t aServiceUuid, uint32_t aCod = 0) michael@0: { michael@0: MOZ_ASSERT(NS_IsMainThread()); michael@0: MOZ_ASSERT(aRunnable); michael@0: michael@0: BluetoothProfileController* controller = michael@0: new BluetoothProfileController(aConnect, aDeviceAddress, aRunnable, michael@0: NextBluetoothProfileController, michael@0: aServiceUuid, aCod); michael@0: sControllerArray.AppendElement(controller); michael@0: michael@0: /** michael@0: * If the request is the first element of the quene, start from here. Note michael@0: * that other request is pushed into the quene and is popped out after the michael@0: * first one is completed. See NextBluetoothProfileController() for details. michael@0: */ michael@0: if (sControllerArray.Length() == 1) { michael@0: sControllerArray[0]->StartSession(); michael@0: } michael@0: } michael@0: michael@0: const bt_interface_t* michael@0: BluetoothServiceBluedroid::GetBluetoothInterface() michael@0: { michael@0: return sBtInterface; michael@0: } michael@0: michael@0: void michael@0: BluetoothServiceBluedroid::Connect(const nsAString& aDeviceAddress, michael@0: uint32_t aCod, michael@0: uint16_t aServiceUuid, michael@0: BluetoothReplyRunnable* aRunnable) michael@0: { michael@0: ConnectDisconnect(true, aDeviceAddress, aRunnable, aServiceUuid, aCod); michael@0: } michael@0: michael@0: bool michael@0: BluetoothServiceBluedroid::IsConnected(uint16_t aProfileId) michael@0: { michael@0: return true; michael@0: } michael@0: michael@0: void michael@0: BluetoothServiceBluedroid::Disconnect( michael@0: const nsAString& aDeviceAddress, uint16_t aServiceUuid, michael@0: BluetoothReplyRunnable* aRunnable) michael@0: { michael@0: ConnectDisconnect(false, aDeviceAddress, aRunnable, aServiceUuid); michael@0: } michael@0: michael@0: void michael@0: BluetoothServiceBluedroid::SendFile(const nsAString& aDeviceAddress, michael@0: BlobParent* aBlobParent, michael@0: BlobChild* aBlobChild, michael@0: BluetoothReplyRunnable* aRunnable) michael@0: { michael@0: MOZ_ASSERT(NS_IsMainThread()); michael@0: michael@0: // Currently we only support one device sending one file at a time, michael@0: // so we don't need aDeviceAddress here because the target device michael@0: // has been determined when calling 'Connect()'. Nevertheless, keep michael@0: // it for future use. michael@0: BluetoothOppManager* opp = BluetoothOppManager::Get(); michael@0: nsAutoString errorStr; michael@0: if (!opp || !opp->SendFile(aDeviceAddress, aBlobParent)) { michael@0: errorStr.AssignLiteral("Calling SendFile() failed"); michael@0: } michael@0: michael@0: DispatchBluetoothReply(aRunnable, BluetoothValue(true), errorStr); michael@0: } michael@0: michael@0: void michael@0: BluetoothServiceBluedroid::SendFile(const nsAString& aDeviceAddress, michael@0: nsIDOMBlob* aBlob, michael@0: BluetoothReplyRunnable* aRunnable) michael@0: { michael@0: MOZ_ASSERT(NS_IsMainThread()); michael@0: michael@0: // Currently we only support one device sending one file at a time, michael@0: // so we don't need aDeviceAddress here because the target device michael@0: // has been determined when calling 'Connect()'. Nevertheless, keep michael@0: // it for future use. michael@0: BluetoothOppManager* opp = BluetoothOppManager::Get(); michael@0: nsAutoString errorStr; michael@0: if (!opp || !opp->SendFile(aDeviceAddress, aBlob)) { michael@0: errorStr.AssignLiteral("Calling SendFile() failed"); michael@0: } michael@0: michael@0: DispatchBluetoothReply(aRunnable, BluetoothValue(true), errorStr); michael@0: } michael@0: michael@0: void michael@0: BluetoothServiceBluedroid::StopSendingFile(const nsAString& aDeviceAddress, michael@0: BluetoothReplyRunnable* aRunnable) michael@0: { michael@0: MOZ_ASSERT(NS_IsMainThread()); michael@0: michael@0: // Currently we only support one device sending one file at a time, michael@0: // so we don't need aDeviceAddress here because the target device michael@0: // has been determined when calling 'Connect()'. Nevertheless, keep michael@0: // it for future use. michael@0: BluetoothOppManager* opp = BluetoothOppManager::Get(); michael@0: nsAutoString errorStr; michael@0: if (!opp || !opp->StopSendingFile()) { michael@0: errorStr.AssignLiteral("Calling StopSendingFile() failed"); michael@0: } michael@0: michael@0: DispatchBluetoothReply(aRunnable, BluetoothValue(true), errorStr); michael@0: } michael@0: michael@0: void michael@0: BluetoothServiceBluedroid::ConfirmReceivingFile( michael@0: const nsAString& aDeviceAddress, bool aConfirm, michael@0: BluetoothReplyRunnable* aRunnable) michael@0: { michael@0: MOZ_ASSERT(NS_IsMainThread(), "Must be called from main thread!"); michael@0: michael@0: // Currently we only support one device sending one file at a time, michael@0: // so we don't need aDeviceAddress here because the target device michael@0: // has been determined when calling 'Connect()'. Nevertheless, keep michael@0: // it for future use. michael@0: BluetoothOppManager* opp = BluetoothOppManager::Get(); michael@0: nsAutoString errorStr; michael@0: if (!opp || !opp->ConfirmReceivingFile(aConfirm)) { michael@0: errorStr.AssignLiteral("Calling ConfirmReceivingFile() failed"); michael@0: } michael@0: michael@0: DispatchBluetoothReply(aRunnable, BluetoothValue(true), errorStr); michael@0: } michael@0: michael@0: void michael@0: BluetoothServiceBluedroid::ConnectSco(BluetoothReplyRunnable* aRunnable) michael@0: { michael@0: MOZ_ASSERT(NS_IsMainThread()); michael@0: michael@0: BluetoothHfpManager* hfp = BluetoothHfpManager::Get(); michael@0: if (!hfp || !hfp->ConnectSco()) { michael@0: NS_NAMED_LITERAL_STRING(replyError, "Calling ConnectSco() failed"); michael@0: DispatchBluetoothReply(aRunnable, BluetoothValue(), replyError); michael@0: return; michael@0: } michael@0: michael@0: DispatchBluetoothReply(aRunnable, BluetoothValue(true), EmptyString()); michael@0: } michael@0: michael@0: void michael@0: BluetoothServiceBluedroid::DisconnectSco(BluetoothReplyRunnable* aRunnable) michael@0: { michael@0: MOZ_ASSERT(NS_IsMainThread()); michael@0: michael@0: BluetoothHfpManager* hfp = BluetoothHfpManager::Get(); michael@0: if (!hfp || !hfp->DisconnectSco()) { michael@0: NS_NAMED_LITERAL_STRING(replyError, "Calling DisconnectSco() failed"); michael@0: DispatchBluetoothReply(aRunnable, BluetoothValue(), replyError); michael@0: return; michael@0: } michael@0: michael@0: DispatchBluetoothReply(aRunnable, BluetoothValue(true), EmptyString()); michael@0: } michael@0: michael@0: void michael@0: BluetoothServiceBluedroid::IsScoConnected(BluetoothReplyRunnable* aRunnable) michael@0: { michael@0: MOZ_ASSERT(NS_IsMainThread()); michael@0: michael@0: BluetoothHfpManager* hfp = BluetoothHfpManager::Get(); michael@0: if (!hfp) { michael@0: NS_NAMED_LITERAL_STRING(replyError, "Fail to get BluetoothHfpManager"); michael@0: DispatchBluetoothReply(aRunnable, BluetoothValue(), replyError); michael@0: return; michael@0: } michael@0: michael@0: DispatchBluetoothReply(aRunnable, hfp->IsScoConnected(), EmptyString()); michael@0: } michael@0: michael@0: void michael@0: BluetoothServiceBluedroid::SendMetaData(const nsAString& aTitle, michael@0: const nsAString& aArtist, michael@0: const nsAString& aAlbum, michael@0: int64_t aMediaNumber, michael@0: int64_t aTotalMediaCount, michael@0: int64_t aDuration, michael@0: BluetoothReplyRunnable* aRunnable) michael@0: { michael@0: BluetoothA2dpManager* a2dp = BluetoothA2dpManager::Get(); michael@0: if (a2dp) { michael@0: a2dp->UpdateMetaData(aTitle, aArtist, aAlbum, aMediaNumber, michael@0: aTotalMediaCount, aDuration); michael@0: } michael@0: DispatchBluetoothReply(aRunnable, BluetoothValue(true), EmptyString()); michael@0: } michael@0: michael@0: void michael@0: BluetoothServiceBluedroid::SendPlayStatus( michael@0: int64_t aDuration, int64_t aPosition, michael@0: const nsAString& aPlayStatus, michael@0: BluetoothReplyRunnable* aRunnable) michael@0: { michael@0: BluetoothA2dpManager* a2dp = BluetoothA2dpManager::Get(); michael@0: if (a2dp) { michael@0: ControlPlayStatus playStatus = michael@0: PlayStatusStringToControlPlayStatus(aPlayStatus); michael@0: a2dp->UpdatePlayStatus(aDuration, aPosition, playStatus); michael@0: } michael@0: DispatchBluetoothReply(aRunnable, BluetoothValue(true), EmptyString()); michael@0: } michael@0: michael@0: void michael@0: BluetoothServiceBluedroid::UpdatePlayStatus( michael@0: uint32_t aDuration, uint32_t aPosition, ControlPlayStatus aPlayStatus) michael@0: { michael@0: // We don't need this function for bluedroid. michael@0: // In bluez, it only calls dbus api michael@0: // But it does not update BluetoothA2dpManager member fields michael@0: MOZ_ASSERT(false); michael@0: } michael@0: michael@0: nsresult michael@0: BluetoothServiceBluedroid::SendSinkMessage(const nsAString& aDeviceAddresses, michael@0: const nsAString& aMessage) michael@0: { michael@0: return NS_OK; michael@0: } michael@0: michael@0: nsresult michael@0: BluetoothServiceBluedroid::SendInputMessage(const nsAString& aDeviceAddresses, michael@0: const nsAString& aMessage) michael@0: { michael@0: return NS_OK; michael@0: } michael@0: michael@0: void michael@0: BluetoothServiceBluedroid::AnswerWaitingCall(BluetoothReplyRunnable* aRunnable) michael@0: { michael@0: } michael@0: michael@0: void michael@0: BluetoothServiceBluedroid::IgnoreWaitingCall(BluetoothReplyRunnable* aRunnable) michael@0: { michael@0: } michael@0: michael@0: void michael@0: BluetoothServiceBluedroid::ToggleCalls(BluetoothReplyRunnable* aRunnable) michael@0: { michael@0: } michael@0: