/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */ /* vim: set ts=2 et sw=2 tw=80: */ /* ** Copyright 2006, The Android Open Source Project ** ** Licensed under the Apache License, Version 2.0 (the "License"); ** you may not use this file except in compliance with the License. ** You may obtain a copy of the License at ** ** http://www.apache.org/licenses/LICENSE-2.0 ** ** Unless required by applicable law or agreed to in writing, software ** distributed under the License is distributed on an "AS IS" BASIS, ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ** See the License for the specific language governing permissions and ** limitations under the License. */ #include "BluetoothServiceBluedroid.h" #include "BluetoothA2dpManager.h" #include "BluetoothHfpManager.h" #include "BluetoothOppManager.h" #include "BluetoothProfileController.h" #include "BluetoothReplyRunnable.h" #include "BluetoothUtils.h" #include "BluetoothUuid.h" #include "mozilla/dom/bluetooth/BluetoothTypes.h" #include "mozilla/ipc/UnixSocket.h" #include "mozilla/StaticMutex.h" #include "mozilla/StaticPtr.h" #include "mozilla/unused.h" #define ENSURE_BLUETOOTH_IS_READY(runnable, result) \ do { \ if (!sBtInterface || !IsEnabled()) { \ NS_NAMED_LITERAL_STRING(errorStr, "Bluetooth is not ready"); \ DispatchBluetoothReply(runnable, BluetoothValue(), errorStr); \ return result; \ } \ } while(0) // 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 static nsString sAdapterBdAddress; static nsString sAdapterBdName; static InfallibleTArray sAdapterBondedAddressArray; static BluetoothInterface* sBtInterface; static nsTArray > sControllerArray; static InfallibleTArray sRemoteDevicesPack; static nsTArray sRequestedDeviceCountArray; static nsTArray > sSetPropertyRunnableArray; static nsTArray > sGetDeviceRunnableArray; static nsTArray > sBondingRunnableArray; static nsTArray > sUnbondingRunnableArray; static bool sAdapterDiscoverable(false); static uint32_t sAdapterDiscoverableTimeout(0); /** * Static callback functions */ void BluetoothServiceBluedroid::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; } if (aRetIcon.IsEmpty()) { if (HAS_AUDIO(aClass)) { /** * Property 'Icon' may be missed due to CoD of major class is TOY(0x08). * But we need to assign Icon as audio-card if service class is 'Audio'. * This is for PTS test case TC_AG_COD_BV_02_I. As HFP specification * defines that service class is 'Audio' can be considered as HFP HF. */ aRetIcon.AssignLiteral("audio-card"); } else { BT_LOGR("No icon to match class: %x", aClass); } } } ControlPlayStatus BluetoothServiceBluedroid::PlayStatusStringToControlPlayStatus( const nsAString& aPlayStatus) { ControlPlayStatus playStatus = ControlPlayStatus::PLAYSTATUS_UNKNOWN; if (aPlayStatus.EqualsLiteral("STOPPED")) { playStatus = ControlPlayStatus::PLAYSTATUS_STOPPED; } else if (aPlayStatus.EqualsLiteral("PLAYING")) { playStatus = ControlPlayStatus::PLAYSTATUS_PLAYING; } else if (aPlayStatus.EqualsLiteral("PAUSED")) { playStatus = ControlPlayStatus::PLAYSTATUS_PAUSED; } else if (aPlayStatus.EqualsLiteral("FWD_SEEK")) { playStatus = ControlPlayStatus::PLAYSTATUS_FWD_SEEK; } else if (aPlayStatus.EqualsLiteral("REV_SEEK")) { playStatus = ControlPlayStatus::PLAYSTATUS_REV_SEEK; } else if (aPlayStatus.EqualsLiteral("ERROR")) { playStatus = ControlPlayStatus::PLAYSTATUS_ERROR; } return playStatus; } /** * Static functions */ bool BluetoothServiceBluedroid::EnsureBluetoothHalLoad() { sBtInterface = BluetoothInterface::GetInstance(); NS_ENSURE_TRUE(sBtInterface, false); return true; } class BluetoothServiceBluedroid::EnableResultHandler MOZ_FINAL : public BluetoothResultHandler { public: void OnError(BluetoothStatus aStatus) MOZ_OVERRIDE { MOZ_ASSERT(NS_IsMainThread()); BT_LOGR("BluetoothInterface::Enable failed: %d", aStatus); BluetoothService::AcknowledgeToggleBt(false); } }; /* |ProfileInitResultHandler| collect the results of all profile * result handlers and calls |Proceed| after all results handlers * have been run. */ class BluetoothServiceBluedroid::ProfileInitResultHandler MOZ_FINAL : public BluetoothProfileResultHandler { public: ProfileInitResultHandler(unsigned char aNumProfiles) : mNumProfiles(aNumProfiles) { MOZ_ASSERT(mNumProfiles); } void Init() MOZ_OVERRIDE { if (!(--mNumProfiles)) { Proceed(); } } void OnError(nsresult aResult) MOZ_OVERRIDE { if (!(--mNumProfiles)) { Proceed(); } } private: void Proceed() const { sBtInterface->Enable(new EnableResultHandler()); } unsigned char mNumProfiles; }; class BluetoothServiceBluedroid::InitResultHandler MOZ_FINAL : public BluetoothResultHandler { public: void Init() MOZ_OVERRIDE { static void (* const sInitManager[])(BluetoothProfileResultHandler*) = { BluetoothHfpManager::InitHfpInterface, BluetoothA2dpManager::InitA2dpInterface }; MOZ_ASSERT(NS_IsMainThread()); // Register all the bluedroid callbacks before enable() get called // It is required to register a2dp callbacks before a2dp media task starts up. // If any interface cannot be initialized, turn on bluetooth core anyway. nsRefPtr res = new ProfileInitResultHandler(MOZ_ARRAY_LENGTH(sInitManager)); for (size_t i = 0; i < MOZ_ARRAY_LENGTH(sInitManager); ++i) { sInitManager[i](res); } } void OnError(BluetoothStatus aStatus) MOZ_OVERRIDE { MOZ_ASSERT(NS_IsMainThread()); BT_LOGR("BluetoothInterface::Init failed: %d", aStatus); sBtInterface = nullptr; BluetoothService::AcknowledgeToggleBt(false); } }; nsresult BluetoothServiceBluedroid::StartGonkBluetooth() { MOZ_ASSERT(NS_IsMainThread()); NS_ENSURE_TRUE(sBtInterface, NS_ERROR_FAILURE); BluetoothService* bs = BluetoothService::Get(); NS_ENSURE_TRUE(bs, NS_ERROR_FAILURE); if (bs->IsEnabled()) { // Keep current enable status BluetoothService::AcknowledgeToggleBt(true); return NS_OK; } sBtInterface->Init(reinterpret_cast(bs), new InitResultHandler()); return NS_OK; } class BluetoothServiceBluedroid::DisableResultHandler MOZ_FINAL : public BluetoothResultHandler { public: void OnError(BluetoothStatus aStatus) MOZ_OVERRIDE { MOZ_ASSERT(NS_IsMainThread()); BT_LOGR("BluetoothInterface::Disable failed: %d", aStatus); BluetoothService::AcknowledgeToggleBt(true); } }; nsresult BluetoothServiceBluedroid::StopGonkBluetooth() { MOZ_ASSERT(NS_IsMainThread()); NS_ENSURE_TRUE(sBtInterface, NS_ERROR_FAILURE); BluetoothService* bs = BluetoothService::Get(); NS_ENSURE_TRUE(bs, NS_ERROR_FAILURE); if (!bs->IsEnabled()) { // Keep current enable status BluetoothService::AcknowledgeToggleBt(false); return NS_OK; } sBtInterface->Disable(new DisableResultHandler()); return NS_OK; } static void ReplyStatusError(BluetoothReplyRunnable* aBluetoothReplyRunnable, BluetoothStatus aStatusCode, const nsAString& aCustomMsg) { MOZ_ASSERT(aBluetoothReplyRunnable, "Reply runnable is nullptr"); BT_LOGR("error code(%d)", aStatusCode); nsAutoString replyError; replyError.Assign(aCustomMsg); if (aStatusCode == STATUS_BUSY) { replyError.AppendLiteral(":BT_STATUS_BUSY"); } else if (aStatusCode == STATUS_NOT_READY) { replyError.AppendLiteral(":BT_STATUS_NOT_READY"); } else if (aStatusCode == STATUS_DONE) { replyError.AppendLiteral(":BT_STATUS_DONE"); } else if (aStatusCode == STATUS_AUTH_FAILURE) { replyError.AppendLiteral(":BT_STATUS_AUTH_FAILURE"); } else if (aStatusCode == STATUS_RMT_DEV_DOWN) { replyError.AppendLiteral(":BT_STATUS_RMT_DEV_DOWN"); } else if (aStatusCode == STATUS_FAIL) { replyError.AppendLiteral(":BT_STATUS_FAIL"); } DispatchBluetoothReply(aBluetoothReplyRunnable, BluetoothValue(true), replyError); } /** * Member functions */ BluetoothServiceBluedroid::BluetoothServiceBluedroid() { if (!EnsureBluetoothHalLoad()) { BT_LOGR("Error! Failed to load bluedroid library."); return; } } BluetoothServiceBluedroid::~BluetoothServiceBluedroid() { } nsresult BluetoothServiceBluedroid::StartInternal() { MOZ_ASSERT(NS_IsMainThread()); nsresult ret = StartGonkBluetooth(); if (NS_FAILED(ret)) { BluetoothService::AcknowledgeToggleBt(false); BT_LOGR("Error"); } return ret; } nsresult BluetoothServiceBluedroid::StopInternal() { MOZ_ASSERT(NS_IsMainThread()); nsresult ret = StopGonkBluetooth(); if (NS_FAILED(ret)) { BluetoothService::AcknowledgeToggleBt(true); BT_LOGR("Error"); } return ret; } nsresult BluetoothServiceBluedroid::GetDefaultAdapterPathInternal( BluetoothReplyRunnable* aRunnable) { MOZ_ASSERT(NS_IsMainThread()); // Since Atomic<*> is not acceptable for BT_APPEND_NAMED_VALUE(), // create another variable to store data. bool discoverable = sAdapterDiscoverable; uint32_t discoverableTimeout = sAdapterDiscoverableTimeout; BluetoothValue v = InfallibleTArray(); BT_APPEND_NAMED_VALUE(v.get_ArrayOfBluetoothNamedValue(), "Address", sAdapterBdAddress); BT_APPEND_NAMED_VALUE(v.get_ArrayOfBluetoothNamedValue(), "Name", sAdapterBdName); BT_APPEND_NAMED_VALUE(v.get_ArrayOfBluetoothNamedValue(), "Discoverable", discoverable); BT_APPEND_NAMED_VALUE(v.get_ArrayOfBluetoothNamedValue(), "DiscoverableTimeout", discoverableTimeout); BT_APPEND_NAMED_VALUE(v.get_ArrayOfBluetoothNamedValue(), "Devices", sAdapterBondedAddressArray); DispatchBluetoothReply(aRunnable, v, EmptyString()); return NS_OK; } class BluetoothServiceBluedroid::GetRemoteDevicePropertiesResultHandler MOZ_FINAL : public BluetoothResultHandler { public: GetRemoteDevicePropertiesResultHandler(const nsAString& aDeviceAddress) : mDeviceAddress(aDeviceAddress) { } void OnError(BluetoothStatus aStatus) MOZ_OVERRIDE { MOZ_ASSERT(NS_IsMainThread()); BT_WARNING("GetRemoteDeviceProperties(%s) failed: %d", mDeviceAddress.get(), aStatus); /* dispatch result after final pending operation */ if (--sRequestedDeviceCountArray[0] == 0) { if (!sGetDeviceRunnableArray.IsEmpty()) { DispatchBluetoothReply(sGetDeviceRunnableArray[0], sRemoteDevicesPack, EmptyString()); sGetDeviceRunnableArray.RemoveElementAt(0); } sRequestedDeviceCountArray.RemoveElementAt(0); sRemoteDevicesPack.Clear(); } } private: nsString mDeviceAddress; }; nsresult BluetoothServiceBluedroid::GetConnectedDevicePropertiesInternal( uint16_t aServiceUuid, BluetoothReplyRunnable* aRunnable) { MOZ_ASSERT(NS_IsMainThread()); ENSURE_BLUETOOTH_IS_READY(aRunnable, NS_OK); BluetoothProfileManagerBase* profile = BluetoothUuidHelper::GetBluetoothProfileManager(aServiceUuid); if (!profile) { InfallibleTArray emptyArr; DispatchBluetoothReply(aRunnable, emptyArr, NS_LITERAL_STRING(ERR_UNKNOWN_PROFILE)); return NS_OK; } nsTArray deviceAddresses; if (profile->IsConnected()) { nsString address; profile->GetAddress(address); deviceAddresses.AppendElement(address); } int requestedDeviceCount = deviceAddresses.Length(); if (requestedDeviceCount == 0) { InfallibleTArray emptyArr; DispatchBluetoothReply(aRunnable, emptyArr, EmptyString()); return NS_OK; } sRequestedDeviceCountArray.AppendElement(requestedDeviceCount); sGetDeviceRunnableArray.AppendElement(aRunnable); for (int i = 0; i < requestedDeviceCount; i++) { // Retrieve all properties of devices sBtInterface->GetRemoteDeviceProperties(deviceAddresses[i], new GetRemoteDevicePropertiesResultHandler(deviceAddresses[i])); } return NS_OK; } nsresult BluetoothServiceBluedroid::GetPairedDevicePropertiesInternal( const nsTArray& aDeviceAddress, BluetoothReplyRunnable* aRunnable) { MOZ_ASSERT(NS_IsMainThread()); ENSURE_BLUETOOTH_IS_READY(aRunnable, NS_OK); int requestedDeviceCount = aDeviceAddress.Length(); if (requestedDeviceCount == 0) { InfallibleTArray emptyArr; DispatchBluetoothReply(aRunnable, BluetoothValue(emptyArr), EmptyString()); return NS_OK; } sRequestedDeviceCountArray.AppendElement(requestedDeviceCount); sGetDeviceRunnableArray.AppendElement(aRunnable); for (int i = 0; i < requestedDeviceCount; i++) { // Retrieve all properties of devices sBtInterface->GetRemoteDeviceProperties(aDeviceAddress[i], new GetRemoteDevicePropertiesResultHandler(aDeviceAddress[i])); } return NS_OK; } class BluetoothServiceBluedroid::StartDiscoveryResultHandler MOZ_FINAL : public BluetoothResultHandler { public: StartDiscoveryResultHandler(BluetoothReplyRunnable* aRunnable) : mRunnable(aRunnable) { } void StartDiscovery() MOZ_OVERRIDE { MOZ_ASSERT(NS_IsMainThread()); DispatchBluetoothReply(mRunnable, true, EmptyString()); } void OnError(BluetoothStatus aStatus) MOZ_OVERRIDE { MOZ_ASSERT(NS_IsMainThread()); ReplyStatusError(mRunnable, aStatus, NS_LITERAL_STRING("StartDiscovery")); } private: BluetoothReplyRunnable* mRunnable; }; nsresult BluetoothServiceBluedroid::StartDiscoveryInternal( BluetoothReplyRunnable* aRunnable) { MOZ_ASSERT(NS_IsMainThread()); ENSURE_BLUETOOTH_IS_READY(aRunnable, NS_OK); sBtInterface->StartDiscovery(new StartDiscoveryResultHandler(aRunnable)); return NS_OK; } class BluetoothServiceBluedroid::CancelDiscoveryResultHandler MOZ_FINAL : public BluetoothResultHandler { public: CancelDiscoveryResultHandler(BluetoothReplyRunnable* aRunnable) : mRunnable(aRunnable) { } void CancelDiscovery() MOZ_OVERRIDE { MOZ_ASSERT(NS_IsMainThread()); DispatchBluetoothReply(mRunnable, true, EmptyString()); } void OnError(BluetoothStatus aStatus) MOZ_OVERRIDE { MOZ_ASSERT(NS_IsMainThread()); ReplyStatusError(mRunnable, aStatus, NS_LITERAL_STRING("StopDiscovery")); } private: BluetoothReplyRunnable* mRunnable; }; nsresult BluetoothServiceBluedroid::StopDiscoveryInternal( BluetoothReplyRunnable* aRunnable) { MOZ_ASSERT(NS_IsMainThread()); ENSURE_BLUETOOTH_IS_READY(aRunnable, NS_OK); sBtInterface->CancelDiscovery(new CancelDiscoveryResultHandler(aRunnable)); return NS_OK; } class BluetoothServiceBluedroid::SetAdapterPropertyResultHandler MOZ_FINAL : public BluetoothResultHandler { public: SetAdapterPropertyResultHandler(BluetoothReplyRunnable* aRunnable) : mRunnable(aRunnable) { } void OnError(BluetoothStatus aStatus) MOZ_OVERRIDE { MOZ_ASSERT(NS_IsMainThread()); ReplyStatusError(mRunnable, aStatus, NS_LITERAL_STRING("SetProperty")); } private: BluetoothReplyRunnable* mRunnable; }; nsresult BluetoothServiceBluedroid::SetProperty(BluetoothObjectType aType, const BluetoothNamedValue& aValue, BluetoothReplyRunnable* aRunnable) { MOZ_ASSERT(NS_IsMainThread()); ENSURE_BLUETOOTH_IS_READY(aRunnable, NS_OK); sSetPropertyRunnableArray.AppendElement(aRunnable); sBtInterface->SetAdapterProperty(aValue, new SetAdapterPropertyResultHandler(aRunnable)); return NS_OK; } nsresult BluetoothServiceBluedroid::GetServiceChannel( const nsAString& aDeviceAddress, const nsAString& aServiceUuid, BluetoothProfileManagerBase* aManager) { return NS_OK; } bool BluetoothServiceBluedroid::UpdateSdpRecords( const nsAString& aDeviceAddress, BluetoothProfileManagerBase* aManager) { return true; } class BluetoothServiceBluedroid::CreateBondResultHandler MOZ_FINAL : public BluetoothResultHandler { public: CreateBondResultHandler(BluetoothReplyRunnable* aRunnable) : mRunnable(aRunnable) { } void OnError(BluetoothStatus aStatus) MOZ_OVERRIDE { sBondingRunnableArray.RemoveElement(mRunnable); ReplyStatusError(mRunnable, aStatus, NS_LITERAL_STRING("CreatedPairedDevice")); } private: nsRefPtr mRunnable; }; nsresult BluetoothServiceBluedroid::CreatePairedDeviceInternal( const nsAString& aDeviceAddress, int aTimeout, BluetoothReplyRunnable* aRunnable) { MOZ_ASSERT(NS_IsMainThread()); ENSURE_BLUETOOTH_IS_READY(aRunnable, NS_OK); sBondingRunnableArray.AppendElement(aRunnable); sBtInterface->CreateBond(aDeviceAddress, new CreateBondResultHandler(aRunnable)); return NS_OK; } class BluetoothServiceBluedroid::RemoveBondResultHandler MOZ_FINAL : public BluetoothResultHandler { public: RemoveBondResultHandler(BluetoothReplyRunnable* aRunnable) : mRunnable(aRunnable) { } void OnError(BluetoothStatus aStatus) MOZ_OVERRIDE { sUnbondingRunnableArray.RemoveElement(mRunnable); ReplyStatusError(mRunnable, aStatus, NS_LITERAL_STRING("RemoveDevice")); } private: nsRefPtr mRunnable; }; nsresult BluetoothServiceBluedroid::RemoveDeviceInternal( const nsAString& aDeviceAddress, BluetoothReplyRunnable* aRunnable) { MOZ_ASSERT(NS_IsMainThread()); ENSURE_BLUETOOTH_IS_READY(aRunnable, NS_OK); sUnbondingRunnableArray.AppendElement(aRunnable); sBtInterface->RemoveBond(aDeviceAddress, new RemoveBondResultHandler(aRunnable)); return NS_OK; } class BluetoothServiceBluedroid::PinReplyResultHandler MOZ_FINAL : public BluetoothResultHandler { public: PinReplyResultHandler(BluetoothReplyRunnable* aRunnable) : mRunnable(aRunnable) { } void PinReply() MOZ_OVERRIDE { DispatchBluetoothReply(mRunnable, BluetoothValue(true), EmptyString()); } void OnError(BluetoothStatus aStatus) MOZ_OVERRIDE { ReplyStatusError(mRunnable, aStatus, NS_LITERAL_STRING("SetPinCode")); } private: BluetoothReplyRunnable* mRunnable; }; bool BluetoothServiceBluedroid::SetPinCodeInternal( const nsAString& aDeviceAddress, const nsAString& aPinCode, BluetoothReplyRunnable* aRunnable) { MOZ_ASSERT(NS_IsMainThread()); ENSURE_BLUETOOTH_IS_READY(aRunnable, false); sBtInterface->PinReply(aDeviceAddress, true, aPinCode, new PinReplyResultHandler(aRunnable)); return true; } bool BluetoothServiceBluedroid::SetPasskeyInternal( const nsAString& aDeviceAddress, uint32_t aPasskey, BluetoothReplyRunnable* aRunnable) { return true; } class BluetoothServiceBluedroid::SspReplyResultHandler MOZ_FINAL : public BluetoothResultHandler { public: SspReplyResultHandler(BluetoothReplyRunnable* aRunnable) : mRunnable(aRunnable) { } void SspReply() MOZ_OVERRIDE { DispatchBluetoothReply(mRunnable, BluetoothValue(true), EmptyString()); } void OnError(BluetoothStatus aStatus) MOZ_OVERRIDE { ReplyStatusError(mRunnable, aStatus, NS_LITERAL_STRING("SetPairingConfirmation")); } private: BluetoothReplyRunnable* mRunnable; }; bool BluetoothServiceBluedroid::SetPairingConfirmationInternal( const nsAString& aDeviceAddress, bool aConfirm, BluetoothReplyRunnable* aRunnable) { MOZ_ASSERT(NS_IsMainThread()); ENSURE_BLUETOOTH_IS_READY(aRunnable, false); sBtInterface->SspReply(aDeviceAddress, NS_ConvertUTF8toUTF16("PasskeyConfirmation"), aConfirm, 0, new SspReplyResultHandler(aRunnable)); return true; } bool BluetoothServiceBluedroid::SetAuthorizationInternal( const nsAString& aDeviceAddress, bool aAllow, BluetoothReplyRunnable* aRunnable) { return true; } nsresult BluetoothServiceBluedroid::PrepareAdapterInternal() { return NS_OK; } static void NextBluetoothProfileController() { MOZ_ASSERT(NS_IsMainThread()); // First, remove the task at the front which has been already done. NS_ENSURE_FALSE_VOID(sControllerArray.IsEmpty()); sControllerArray.RemoveElementAt(0); // Re-check if the task array is empty, if it's not, the next task will begin. if (!sControllerArray.IsEmpty()) { sControllerArray[0]->StartSession(); } } static void ConnectDisconnect(bool aConnect, const nsAString& aDeviceAddress, BluetoothReplyRunnable* aRunnable, uint16_t aServiceUuid, uint32_t aCod = 0) { MOZ_ASSERT(NS_IsMainThread()); MOZ_ASSERT(aRunnable); BluetoothProfileController* controller = new BluetoothProfileController(aConnect, aDeviceAddress, aRunnable, NextBluetoothProfileController, aServiceUuid, aCod); sControllerArray.AppendElement(controller); /** * If the request is the first element of the quene, start from here. Note * that other request is pushed into the quene and is popped out after the * first one is completed. See NextBluetoothProfileController() for details. */ if (sControllerArray.Length() == 1) { sControllerArray[0]->StartSession(); } } void BluetoothServiceBluedroid::Connect(const nsAString& aDeviceAddress, uint32_t aCod, uint16_t aServiceUuid, BluetoothReplyRunnable* aRunnable) { ConnectDisconnect(true, aDeviceAddress, aRunnable, aServiceUuid, aCod); } void BluetoothServiceBluedroid::Disconnect( const nsAString& aDeviceAddress, uint16_t aServiceUuid, BluetoothReplyRunnable* aRunnable) { ConnectDisconnect(false, aDeviceAddress, aRunnable, aServiceUuid); } void BluetoothServiceBluedroid::IsConnected(const uint16_t aServiceUuid, BluetoothReplyRunnable* aRunnable) { MOZ_ASSERT(NS_IsMainThread()); MOZ_ASSERT(aRunnable); BluetoothProfileManagerBase* profile = BluetoothUuidHelper::GetBluetoothProfileManager(aServiceUuid); if (profile) { DispatchBluetoothReply(aRunnable, profile->IsConnected(), EmptyString()); } else { BT_WARNING("Can't find profile manager with uuid: %x", aServiceUuid); DispatchBluetoothReply(aRunnable, false, EmptyString()); } } void BluetoothServiceBluedroid::SendFile(const nsAString& aDeviceAddress, BlobParent* aBlobParent, BlobChild* aBlobChild, BluetoothReplyRunnable* aRunnable) { MOZ_ASSERT(NS_IsMainThread()); // Currently we only support one device sending one file at a time, // so we don't need aDeviceAddress here because the target device // has been determined when calling 'Connect()'. Nevertheless, keep // it for future use. BluetoothOppManager* opp = BluetoothOppManager::Get(); nsAutoString errorStr; if (!opp || !opp->SendFile(aDeviceAddress, aBlobParent)) { errorStr.AssignLiteral("Calling SendFile() failed"); } DispatchBluetoothReply(aRunnable, BluetoothValue(true), errorStr); } void BluetoothServiceBluedroid::SendFile(const nsAString& aDeviceAddress, nsIDOMBlob* aBlob, BluetoothReplyRunnable* aRunnable) { MOZ_ASSERT(NS_IsMainThread()); // Currently we only support one device sending one file at a time, // so we don't need aDeviceAddress here because the target device // has been determined when calling 'Connect()'. Nevertheless, keep // it for future use. BluetoothOppManager* opp = BluetoothOppManager::Get(); nsAutoString errorStr; if (!opp || !opp->SendFile(aDeviceAddress, aBlob)) { errorStr.AssignLiteral("Calling SendFile() failed"); } DispatchBluetoothReply(aRunnable, BluetoothValue(true), errorStr); } void BluetoothServiceBluedroid::StopSendingFile(const nsAString& aDeviceAddress, BluetoothReplyRunnable* aRunnable) { MOZ_ASSERT(NS_IsMainThread()); // Currently we only support one device sending one file at a time, // so we don't need aDeviceAddress here because the target device // has been determined when calling 'Connect()'. Nevertheless, keep // it for future use. BluetoothOppManager* opp = BluetoothOppManager::Get(); nsAutoString errorStr; if (!opp || !opp->StopSendingFile()) { errorStr.AssignLiteral("Calling StopSendingFile() failed"); } DispatchBluetoothReply(aRunnable, BluetoothValue(true), errorStr); } void BluetoothServiceBluedroid::ConfirmReceivingFile( const nsAString& aDeviceAddress, bool aConfirm, BluetoothReplyRunnable* aRunnable) { MOZ_ASSERT(NS_IsMainThread(), "Must be called from main thread!"); // Currently we only support one device sending one file at a time, // so we don't need aDeviceAddress here because the target device // has been determined when calling 'Connect()'. Nevertheless, keep // it for future use. BluetoothOppManager* opp = BluetoothOppManager::Get(); nsAutoString errorStr; if (!opp || !opp->ConfirmReceivingFile(aConfirm)) { errorStr.AssignLiteral("Calling ConfirmReceivingFile() failed"); } DispatchBluetoothReply(aRunnable, BluetoothValue(true), errorStr); } void BluetoothServiceBluedroid::ConnectSco(BluetoothReplyRunnable* aRunnable) { MOZ_ASSERT(NS_IsMainThread()); BluetoothHfpManager* hfp = BluetoothHfpManager::Get(); if (!hfp || !hfp->ConnectSco()) { NS_NAMED_LITERAL_STRING(replyError, "Calling ConnectSco() failed"); DispatchBluetoothReply(aRunnable, BluetoothValue(), replyError); return; } DispatchBluetoothReply(aRunnable, BluetoothValue(true), EmptyString()); } void BluetoothServiceBluedroid::DisconnectSco(BluetoothReplyRunnable* aRunnable) { MOZ_ASSERT(NS_IsMainThread()); BluetoothHfpManager* hfp = BluetoothHfpManager::Get(); if (!hfp || !hfp->DisconnectSco()) { NS_NAMED_LITERAL_STRING(replyError, "Calling DisconnectSco() failed"); DispatchBluetoothReply(aRunnable, BluetoothValue(), replyError); return; } DispatchBluetoothReply(aRunnable, BluetoothValue(true), EmptyString()); } void BluetoothServiceBluedroid::IsScoConnected(BluetoothReplyRunnable* aRunnable) { MOZ_ASSERT(NS_IsMainThread()); BluetoothHfpManager* hfp = BluetoothHfpManager::Get(); if (!hfp) { NS_NAMED_LITERAL_STRING(replyError, "Fail to get BluetoothHfpManager"); DispatchBluetoothReply(aRunnable, BluetoothValue(), replyError); return; } DispatchBluetoothReply(aRunnable, hfp->IsScoConnected(), EmptyString()); } void BluetoothServiceBluedroid::SendMetaData(const nsAString& aTitle, const nsAString& aArtist, const nsAString& aAlbum, int64_t aMediaNumber, int64_t aTotalMediaCount, int64_t aDuration, BluetoothReplyRunnable* aRunnable) { BluetoothA2dpManager* a2dp = BluetoothA2dpManager::Get(); if (a2dp) { a2dp->UpdateMetaData(aTitle, aArtist, aAlbum, aMediaNumber, aTotalMediaCount, aDuration); } DispatchBluetoothReply(aRunnable, BluetoothValue(true), EmptyString()); } void BluetoothServiceBluedroid::SendPlayStatus( int64_t aDuration, int64_t aPosition, const nsAString& aPlayStatus, BluetoothReplyRunnable* aRunnable) { BluetoothA2dpManager* a2dp = BluetoothA2dpManager::Get(); if (a2dp) { ControlPlayStatus playStatus = PlayStatusStringToControlPlayStatus(aPlayStatus); a2dp->UpdatePlayStatus(aDuration, aPosition, playStatus); } DispatchBluetoothReply(aRunnable, BluetoothValue(true), EmptyString()); } void BluetoothServiceBluedroid::UpdatePlayStatus( uint32_t aDuration, uint32_t aPosition, ControlPlayStatus aPlayStatus) { // We don't need this function for bluedroid. // In bluez, it only calls dbus api // But it does not update BluetoothA2dpManager member fields MOZ_ASSERT(false); } nsresult BluetoothServiceBluedroid::SendSinkMessage(const nsAString& aDeviceAddresses, const nsAString& aMessage) { return NS_OK; } nsresult BluetoothServiceBluedroid::SendInputMessage(const nsAString& aDeviceAddresses, const nsAString& aMessage) { return NS_OK; } void BluetoothServiceBluedroid::AnswerWaitingCall(BluetoothReplyRunnable* aRunnable) { } void BluetoothServiceBluedroid::IgnoreWaitingCall(BluetoothReplyRunnable* aRunnable) { } void BluetoothServiceBluedroid::ToggleCalls(BluetoothReplyRunnable* aRunnable) { } // // Bluetooth notifications // /* |ProfileDeinitResultHandler| collect the results of all profile * result handlers and calls |Proceed| after all results handlers * have been run. */ class BluetoothServiceBluedroid::ProfileDeinitResultHandler MOZ_FINAL : public BluetoothProfileResultHandler { public: ProfileDeinitResultHandler(unsigned char aNumProfiles) : mNumProfiles(aNumProfiles) { MOZ_ASSERT(mNumProfiles); } void Deinit() MOZ_OVERRIDE { if (!(--mNumProfiles)) { Proceed(); } } void OnError(nsresult aResult) MOZ_OVERRIDE { if (!(--mNumProfiles)) { Proceed(); } } private: void Proceed() const { sBtInterface->Cleanup(nullptr); } unsigned char mNumProfiles; }; class BluetoothServiceBluedroid::SetAdapterPropertyDiscoverableResultHandler MOZ_FINAL : public BluetoothResultHandler { public: void OnError(BluetoothStatus aStatus) MOZ_OVERRIDE { BT_LOGR("Fail to set: BT_SCAN_MODE_CONNECTABLE"); } }; void BluetoothServiceBluedroid::AdapterStateChangedNotification(bool aState) { MOZ_ASSERT(NS_IsMainThread()); BT_LOGR("BT_STATE: %d", aState); bool isBtEnabled = (aState == true); if (!isBtEnabled) { static void (* const sDeinitManager[])(BluetoothProfileResultHandler*) = { BluetoothHfpManager::DeinitHfpInterface, BluetoothA2dpManager::DeinitA2dpInterface }; // Cleanup bluetooth interfaces after BT state becomes BT_STATE_OFF. nsRefPtr res = new ProfileDeinitResultHandler(MOZ_ARRAY_LENGTH(sDeinitManager)); for (size_t i = 0; i < MOZ_ARRAY_LENGTH(sDeinitManager); ++i) { sDeinitManager[i](res); } } BluetoothService::AcknowledgeToggleBt(isBtEnabled); if (isBtEnabled) { // Bluetooth just enabled, clear profile controllers and runnable arrays. sControllerArray.Clear(); sBondingRunnableArray.Clear(); sGetDeviceRunnableArray.Clear(); sSetPropertyRunnableArray.Clear(); sUnbondingRunnableArray.Clear(); // Bluetooth scan mode is SCAN_MODE_CONNECTABLE by default, i.e., It should // be connectable and non-discoverable. NS_ENSURE_TRUE_VOID(sBtInterface); sBtInterface->SetAdapterProperty( BluetoothNamedValue(NS_ConvertUTF8toUTF16("Discoverable"), false), new SetAdapterPropertyDiscoverableResultHandler()); // Try to fire event 'AdapterAdded' to fit the original behaviour when // we used BlueZ as backend. BluetoothService* bs = BluetoothService::Get(); NS_ENSURE_TRUE_VOID(bs); bs->AdapterAddedReceived(); bs->TryFiringAdapterAdded(); // Trigger BluetoothOppManager to listen BluetoothOppManager* opp = BluetoothOppManager::Get(); if (!opp || !opp->Listen()) { BT_LOGR("Fail to start BluetoothOppManager listening"); } } } /** * AdapterPropertiesNotification will be called after enable() but * before AdapterStateChangeCallback is called. At that moment, both * BluetoothManager and BluetoothAdapter, do not register observer * yet. */ void BluetoothServiceBluedroid::AdapterPropertiesNotification( BluetoothStatus aStatus, int aNumProperties, const BluetoothProperty* aProperties) { MOZ_ASSERT(NS_IsMainThread()); BluetoothValue propertyValue; InfallibleTArray props; for (int i = 0; i < aNumProperties; i++) { const BluetoothProperty& p = aProperties[i]; if (p.mType == PROPERTY_BDADDR) { sAdapterBdAddress = p.mString; propertyValue = sAdapterBdAddress; BT_APPEND_NAMED_VALUE(props, "Address", propertyValue); } else if (p.mType == PROPERTY_BDNAME) { sAdapterBdName = p.mString; propertyValue = sAdapterBdName; BT_APPEND_NAMED_VALUE(props, "Name", propertyValue); } else if (p.mType == PROPERTY_ADAPTER_SCAN_MODE) { BluetoothScanMode newMode = p.mScanMode; if (newMode == SCAN_MODE_CONNECTABLE_DISCOVERABLE) { propertyValue = sAdapterDiscoverable = true; } else { propertyValue = sAdapterDiscoverable = false; } BT_APPEND_NAMED_VALUE(props, "Discoverable", propertyValue); } else if (p.mType == PROPERTY_ADAPTER_DISCOVERY_TIMEOUT) { propertyValue = sAdapterDiscoverableTimeout = p.mUint32; BT_APPEND_NAMED_VALUE(props, "DiscoverableTimeout", propertyValue); } else if (p.mType == PROPERTY_ADAPTER_BONDED_DEVICES) { // We have to cache addresses of bonded devices. Unlike BlueZ, // Bluedroid would not send another PROPERTY_ADAPTER_BONDED_DEVICES // event after bond completed. BT_LOGD("Adapter property: BONDED_DEVICES. Count: %d", p.mStringArray.Length()); // Whenever reloading paired devices, force refresh sAdapterBondedAddressArray.Clear(); for (size_t index = 0; index < p.mStringArray.Length(); index++) { sAdapterBondedAddressArray.AppendElement(p.mStringArray[index]); } propertyValue = sAdapterBondedAddressArray; BT_APPEND_NAMED_VALUE(props, "Devices", propertyValue); } else if (p.mType == PROPERTY_UUIDS) { //FIXME: This will be implemented in the later patchset continue; } else if (p.mType == PROPERTY_UNKNOWN) { /* Bug 1065999: working around unknown properties */ continue; } else { BT_LOGD("Unhandled adapter property type: %d", p.mType); continue; } } NS_ENSURE_TRUE_VOID(props.Length() > 0); DistributeSignal(BluetoothSignal(NS_LITERAL_STRING("PropertyChanged"), NS_LITERAL_STRING(KEY_ADAPTER), BluetoothValue(props))); // Send reply for SetProperty if (!sSetPropertyRunnableArray.IsEmpty()) { DispatchBluetoothReply(sSetPropertyRunnableArray[0], BluetoothValue(true), EmptyString()); sSetPropertyRunnableArray.RemoveElementAt(0); } } /** * RemoteDevicePropertiesNotification will be called * * (1) automatically by Bluedroid when BT is turning on, or * (2) as result of GetRemoteDeviceProperties. */ void BluetoothServiceBluedroid::RemoteDevicePropertiesNotification( BluetoothStatus aStatus, const nsAString& aBdAddr, int aNumProperties, const BluetoothProperty* aProperties) { MOZ_ASSERT(NS_IsMainThread()); InfallibleTArray props; BT_APPEND_NAMED_VALUE(props, "Address", BluetoothValue(nsString(aBdAddr))); bool isCodInvalid = false; for (int i = 0; i < aNumProperties; ++i) { const BluetoothProperty& p = aProperties[i]; if (p.mType == PROPERTY_BDNAME) { BT_APPEND_NAMED_VALUE(props, "Name", p.mString); } else if (p.mType == PROPERTY_CLASS_OF_DEVICE) { uint32_t cod = p.mUint32; nsString icon; ClassToIcon(cod, 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.mType == PROPERTY_UUIDS) { InfallibleTArray uuidsArray; uint32_t cod = 0; for (size_t i = 0; i < p.mUuidArray.Length(); i++) { uint16_t uuidServiceClass = UuidToServiceClassInt(p.mUuidArray[i]); 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 if (p.mType == PROPERTY_UNKNOWN) { /* Bug 1065999: working around unknown properties */ } else { BT_LOGD("Other non-handled device properties. Type: %d", p.mType); } } if (sRequestedDeviceCountArray.IsEmpty()) { // This is possible because the callback would be called after turning // Bluetooth on. return; } // Use address as the index sRemoteDevicesPack.AppendElement( BluetoothNamedValue(nsString(aBdAddr), props)); if (--sRequestedDeviceCountArray[0] == 0) { if (!sGetDeviceRunnableArray.IsEmpty()) { DispatchBluetoothReply(sGetDeviceRunnableArray[0], sRemoteDevicesPack, EmptyString()); sGetDeviceRunnableArray.RemoveElementAt(0); } sRequestedDeviceCountArray.RemoveElementAt(0); sRemoteDevicesPack.Clear(); } // Update to registered BluetoothDevice objects DistributeSignal(BluetoothSignal(NS_LITERAL_STRING("PropertyChanged"), nsString(aBdAddr), BluetoothValue(props))); } void BluetoothServiceBluedroid::DeviceFoundNotification( int aNumProperties, const BluetoothProperty* aProperties) { MOZ_ASSERT(NS_IsMainThread()); BluetoothValue propertyValue; InfallibleTArray propertiesArray; for (int i = 0; i < aNumProperties; i++) { const BluetoothProperty& p = aProperties[i]; if (p.mType == PROPERTY_BDADDR) { propertyValue = p.mString; BT_APPEND_NAMED_VALUE(propertiesArray, "Address", propertyValue); } else if (p.mType == PROPERTY_BDNAME) { BT_APPEND_NAMED_VALUE(propertiesArray, "Name", p.mString); } else if (p.mType == PROPERTY_CLASS_OF_DEVICE) { uint32_t cod = p.mUint32; propertyValue = cod; BT_APPEND_NAMED_VALUE(propertiesArray, "Class", propertyValue); nsString icon; ClassToIcon(cod, icon); propertyValue = icon; BT_APPEND_NAMED_VALUE(propertiesArray, "Icon", propertyValue); } else if (p.mType == PROPERTY_UNKNOWN) { /* Bug 1065999: working around unknown properties */ } else { BT_LOGD("Not handled remote device property: %d", p.mType); } } DistributeSignal(BluetoothSignal(NS_LITERAL_STRING("DeviceFound"), NS_LITERAL_STRING(KEY_ADAPTER), BluetoothValue(propertiesArray))); } void BluetoothServiceBluedroid::DiscoveryStateChangedNotification(bool aState) { MOZ_ASSERT(NS_IsMainThread()); bool isDiscovering = (aState == true); DistributeSignal( BluetoothSignal(NS_LITERAL_STRING(DISCOVERY_STATE_CHANGED_ID), NS_LITERAL_STRING(KEY_ADAPTER), isDiscovering)); // Distribute "PropertyChanged" signal to notice adapter this change since // Bluedroid don' treat "discovering" as a property of adapter. InfallibleTArray props; BT_APPEND_NAMED_VALUE(props, "Discovering", BluetoothValue(isDiscovering)); DistributeSignal(BluetoothSignal(NS_LITERAL_STRING("PropertyChanged"), NS_LITERAL_STRING(KEY_ADAPTER), BluetoothValue(props))); } void BluetoothServiceBluedroid::PinRequestNotification(const nsAString& aRemoteBdAddr, const nsAString& aBdName, uint32_t aCod) { MOZ_ASSERT(NS_IsMainThread()); InfallibleTArray propertiesArray; BT_APPEND_NAMED_VALUE(propertiesArray, "address", nsString(aRemoteBdAddr)); BT_APPEND_NAMED_VALUE(propertiesArray, "method", NS_LITERAL_STRING("pincode")); BT_APPEND_NAMED_VALUE(propertiesArray, "name", nsString(aBdName)); DistributeSignal(BluetoothSignal(NS_LITERAL_STRING("RequestPinCode"), NS_LITERAL_STRING(KEY_LOCAL_AGENT), BluetoothValue(propertiesArray))); } void BluetoothServiceBluedroid::SspRequestNotification( const nsAString& aRemoteBdAddr, const nsAString& aBdName, uint32_t aCod, const nsAString& aPairingaVariant, uint32_t aPassKey) { MOZ_ASSERT(NS_IsMainThread()); InfallibleTArray propertiesArray; BT_APPEND_NAMED_VALUE(propertiesArray, "address", nsString(aRemoteBdAddr)); BT_APPEND_NAMED_VALUE(propertiesArray, "method", NS_LITERAL_STRING("confirmation")); BT_APPEND_NAMED_VALUE(propertiesArray, "name", nsString(aBdName)); BT_APPEND_NAMED_VALUE(propertiesArray, "passkey", aPassKey); DistributeSignal(BluetoothSignal(NS_LITERAL_STRING("RequestConfirmation"), NS_LITERAL_STRING(KEY_LOCAL_AGENT), BluetoothValue(propertiesArray))); } void BluetoothServiceBluedroid::BondStateChangedNotification( BluetoothStatus aStatus, const nsAString& aRemoteBdAddr, BluetoothBondState aState) { MOZ_ASSERT(NS_IsMainThread()); if (aState == BOND_STATE_BONDING) { // No need to handle bonding state return; } if (aState == BOND_STATE_BONDED && sAdapterBondedAddressArray.Contains(aRemoteBdAddr)) { // See bug 940271 for more details about this case. return; } switch (aStatus) { case STATUS_SUCCESS: { bool bonded; if (aState == BOND_STATE_NONE) { bonded = false; sAdapterBondedAddressArray.RemoveElement(aRemoteBdAddr); } else if (aState == BOND_STATE_BONDED) { bonded = true; sAdapterBondedAddressArray.AppendElement(aRemoteBdAddr); } else { return; } // Update bonded address list to BluetoothAdapter InfallibleTArray propertiesChangeArray; BT_APPEND_NAMED_VALUE(propertiesChangeArray, "Devices", sAdapterBondedAddressArray); DistributeSignal(BluetoothSignal(NS_LITERAL_STRING("PropertyChanged"), NS_LITERAL_STRING(KEY_ADAPTER), BluetoothValue(propertiesChangeArray))); if (bonded && !sBondingRunnableArray.IsEmpty()) { DispatchBluetoothReply(sBondingRunnableArray[0], BluetoothValue(true), EmptyString()); sBondingRunnableArray.RemoveElementAt(0); } else if (!bonded && !sUnbondingRunnableArray.IsEmpty()) { DispatchBluetoothReply(sUnbondingRunnableArray[0], BluetoothValue(true), EmptyString()); sUnbondingRunnableArray.RemoveElementAt(0); } // Update bonding status to gaia InfallibleTArray propertiesArray; BT_APPEND_NAMED_VALUE(propertiesArray, "address", nsString(aRemoteBdAddr)); BT_APPEND_NAMED_VALUE(propertiesArray, "status", bonded); DistributeSignal( BluetoothSignal(NS_LITERAL_STRING(PAIRED_STATUS_CHANGED_ID), NS_LITERAL_STRING(KEY_ADAPTER), BluetoothValue(propertiesArray))); break; } case STATUS_BUSY: case STATUS_AUTH_FAILURE: case STATUS_RMT_DEV_DOWN: { InfallibleTArray propertiesArray; DistributeSignal(BluetoothSignal(NS_LITERAL_STRING("Cancel"), NS_LITERAL_STRING(KEY_LOCAL_AGENT), BluetoothValue(propertiesArray))); if (!sBondingRunnableArray.IsEmpty()) { DispatchBluetoothReply(sBondingRunnableArray[0], BluetoothValue(true), NS_LITERAL_STRING("Authentication failure")); sBondingRunnableArray.RemoveElementAt(0); } break; } default: BT_WARNING("Got an unhandled status of BondStateChangedCallback!"); break; } } void BluetoothServiceBluedroid::AclStateChangedNotification( BluetoothStatus aStatus, const nsAString& aRemoteBdAddr, bool aState) { MOZ_ASSERT(NS_IsMainThread()); // FIXME: This will be implemented in the later patchset } void BluetoothServiceBluedroid::DutModeRecvNotification(uint16_t aOpcode, const uint8_t* aBuf, uint8_t aLen) { MOZ_ASSERT(NS_IsMainThread()); // FIXME: This will be implemented in the later patchset } void BluetoothServiceBluedroid::LeTestModeNotification(BluetoothStatus aStatus, uint16_t aNumPackets) { MOZ_ASSERT(NS_IsMainThread()); // FIXME: This will be implemented in the later patchset }