diff --git a/dom/bluetooth2/BluetoothGatt.cpp b/dom/bluetooth2/BluetoothGatt.cpp index 1580fa2c81e..d69f01bdc62 100644 --- a/dom/bluetooth2/BluetoothGatt.cpp +++ b/dom/bluetooth2/BluetoothGatt.cpp @@ -167,6 +167,55 @@ BluetoothGatt::Disconnect(ErrorResult& aRv) return promise.forget(); } +class ReadRemoteRssiTask MOZ_FINAL : public BluetoothReplyRunnable +{ +public: + ReadRemoteRssiTask(Promise* aPromise) + : BluetoothReplyRunnable(nullptr, aPromise, + NS_LITERAL_STRING("GattClientReadRemoteRssi")) + { + MOZ_ASSERT(aPromise); + } + + bool + ParseSuccessfulReply(JS::MutableHandle aValue) + { + aValue.setUndefined(); + + const BluetoothValue& v = mReply->get_BluetoothReplySuccess().value(); + NS_ENSURE_TRUE(v.type() == BluetoothValue::Tuint32_t, false); + + aValue.setInt32(static_cast(v.get_uint32_t())); + return true; + } +}; + +already_AddRefed +BluetoothGatt::ReadRemoteRssi(ErrorResult& aRv) +{ + nsCOMPtr global = do_QueryInterface(GetParentObject()); + if (!global) { + aRv.Throw(NS_ERROR_FAILURE); + return nullptr; + } + + nsRefPtr promise = Promise::Create(global, aRv); + NS_ENSURE_TRUE(!aRv.Failed(), nullptr); + + BT_ENSURE_TRUE_REJECT( + mConnectionState == BluetoothConnectionState::Connected, + NS_ERROR_DOM_INVALID_STATE_ERR); + + BluetoothService* bs = BluetoothService::Get(); + BT_ENSURE_TRUE_REJECT(bs, NS_ERROR_NOT_AVAILABLE); + + nsRefPtr result = + new ReadRemoteRssiTask(promise); + bs->GattClientReadRemoteRssiInternal(mClientIf, mDeviceAddr, result); + + return promise.forget(); +} + void BluetoothGatt::UpdateConnectionState(BluetoothConnectionState aState) { diff --git a/dom/bluetooth2/BluetoothGatt.h b/dom/bluetooth2/BluetoothGatt.h index 96ffb5afc59..41b0f028eb0 100644 --- a/dom/bluetooth2/BluetoothGatt.h +++ b/dom/bluetooth2/BluetoothGatt.h @@ -51,6 +51,7 @@ public: ***************************************************************************/ already_AddRefed Connect(ErrorResult& aRv); already_AddRefed Disconnect(ErrorResult& aRv); + already_AddRefed ReadRemoteRssi(ErrorResult& aRv); /**************************************************************************** * Others diff --git a/dom/bluetooth2/BluetoothService.h b/dom/bluetooth2/BluetoothService.h index 410330e8a34..d219a317c08 100644 --- a/dom/bluetooth2/BluetoothService.h +++ b/dom/bluetooth2/BluetoothService.h @@ -349,6 +349,13 @@ public: UnregisterGattClientInternal(int aClientIf, BluetoothReplyRunnable* aRunnable) = 0; + /** + * Request RSSI for a remote GATT server. (platform specific implementation) + */ + virtual void + GattClientReadRemoteRssiInternal(int aClientIf, + const nsAString& aDeviceAddress, + BluetoothReplyRunnable* aRunnable) = 0; bool IsEnabled() const diff --git a/dom/bluetooth2/bluedroid/BluetoothGattManager.cpp b/dom/bluetooth2/bluedroid/BluetoothGattManager.cpp index 510e62a9989..598d6f6ae58 100644 --- a/dom/bluetooth2/bluedroid/BluetoothGattManager.cpp +++ b/dom/bluetooth2/bluedroid/BluetoothGattManager.cpp @@ -57,6 +57,7 @@ public: mConnectRunnable = nullptr; mDisconnectRunnable = nullptr; mUnregisterClientRunnable = nullptr; + mReadRemoteRssiRunnable = nullptr; } nsString mAppUuid; @@ -66,6 +67,7 @@ public: nsRefPtr mConnectRunnable; nsRefPtr mDisconnectRunnable; nsRefPtr mUnregisterClientRunnable; + nsRefPtr mReadRemoteRssiRunnable; }; NS_IMPL_ISUPPORTS0(BluetoothGattClient) @@ -484,6 +486,63 @@ BluetoothGattManager::Disconnect(const nsAString& aAppUuid, new DisconnectResultHandler(client)); } +class BluetoothGattManager::ReadRemoteRssiResultHandler MOZ_FINAL + : public BluetoothGattClientResultHandler +{ +public: + ReadRemoteRssiResultHandler(BluetoothGattClient* aClient) + : mClient(aClient) + { + MOZ_ASSERT(mClient); + } + + void OnError(BluetoothStatus aStatus) MOZ_OVERRIDE + { + BT_WARNING("BluetoothGattClientInterface::ReadRemoteRssi failed: %d", + (int)aStatus); + MOZ_ASSERT(mClient->mReadRemoteRssiRunnable); + + BluetoothService* bs = BluetoothService::Get(); + NS_ENSURE_TRUE_VOID(bs); + + // Reject the read remote rssi request + DispatchReplyError(mClient->mReadRemoteRssiRunnable, + NS_LITERAL_STRING("ReadRemoteRssi failed")); + mClient->mReadRemoteRssiRunnable = nullptr; + } + +private: + nsRefPtr mClient; +}; + +void +BluetoothGattManager::ReadRemoteRssi(int aClientIf, + const nsAString& aDeviceAddr, + BluetoothReplyRunnable* aRunnable) +{ + MOZ_ASSERT(NS_IsMainThread()); + MOZ_ASSERT(aRunnable); + + ENSURE_GATT_CLIENT_INTF_IS_READY_VOID(aRunnable); + + size_t index = sClients->IndexOf(aClientIf, 0 /* Start */, + ClientIfComparator()); + + // Reject the read remote rssi request if the client is not found + if (index == sClients->NoIndex) { + DispatchReplyError(aRunnable, + NS_LITERAL_STRING("Read remote RSSI failed")); + return; + } + + nsRefPtr client = sClients->ElementAt(index); + client->mReadRemoteRssiRunnable = aRunnable; + + sBluetoothGattClientInterface->ReadRemoteRssi( + aClientIf, aDeviceAddr, + new ReadRemoteRssiResultHandler(client)); +} + // // Notification Handlers // @@ -728,7 +787,40 @@ BluetoothGattManager::ReadRemoteRssiNotification(int aClientIf, const nsAString& aBdAddr, int aRssi, BluetoothGattStatus aStatus) -{ } +{ + BT_API2_LOGR(); + MOZ_ASSERT(NS_IsMainThread()); + + BluetoothService* bs = BluetoothService::Get(); + NS_ENSURE_TRUE_VOID(bs); + + size_t index = sClients->IndexOf(aClientIf, 0 /* Start */, + ClientIfComparator()); + NS_ENSURE_TRUE_VOID(index != sClients->NoIndex); + nsRefPtr client = sClients->ElementAt(index); + + if (aStatus != GATT_STATUS_SUCCESS) { // operation failed + BT_API2_LOGR("ReadRemoteRssi failed, clientIf = %d, bdAddr = %s, " \ + "rssi = %d, status = %d", aClientIf, + NS_ConvertUTF16toUTF8(aBdAddr).get(), aRssi, (int)aStatus); + + // Reject the read remote rssi request + if (client->mReadRemoteRssiRunnable) { + DispatchReplyError(client->mReadRemoteRssiRunnable, + NS_LITERAL_STRING("ReadRemoteRssi failed")); + client->mReadRemoteRssiRunnable = nullptr; + } + + return; + } + + // Resolve the read remote rssi request + if (client->mReadRemoteRssiRunnable) { + DispatchReplySuccess(client->mReadRemoteRssiRunnable, + BluetoothValue(static_cast(aRssi))); + client->mReadRemoteRssiRunnable = nullptr; + } +} void BluetoothGattManager::ListenNotification(BluetoothGattStatus aStatus, diff --git a/dom/bluetooth2/bluedroid/BluetoothGattManager.h b/dom/bluetooth2/bluedroid/BluetoothGattManager.h index f5d7336c6cf..a09f4ad63aa 100644 --- a/dom/bluetooth2/bluedroid/BluetoothGattManager.h +++ b/dom/bluetooth2/bluedroid/BluetoothGattManager.h @@ -38,6 +38,10 @@ public: void UnregisterClient(int aClientIf, BluetoothReplyRunnable* aRunnable); + void ReadRemoteRssi(int aClientIf, + const nsAString& aDeviceAddr, + BluetoothReplyRunnable* aRunnable); + private: class CleanupResultHandler; class CleanupResultHandlerRunnable; @@ -46,6 +50,7 @@ private: class UnregisterClientResultHandler; class ConnectResultHandler; class DisconnectResultHandler; + class ReadRemoteRssiResultHandler; BluetoothGattManager(); diff --git a/dom/bluetooth2/bluedroid/BluetoothServiceBluedroid.cpp b/dom/bluetooth2/bluedroid/BluetoothServiceBluedroid.cpp index b536a77d280..df7f4057e87 100644 --- a/dom/bluetooth2/bluedroid/BluetoothServiceBluedroid.cpp +++ b/dom/bluetooth2/bluedroid/BluetoothServiceBluedroid.cpp @@ -1131,6 +1131,21 @@ BluetoothServiceBluedroid::UnregisterGattClientInternal( gatt->UnregisterClient(aClientIf, aRunnable); } +void +BluetoothServiceBluedroid::GattClientReadRemoteRssiInternal( + int aClientIf, const nsAString& aDeviceAddress, + BluetoothReplyRunnable* aRunnable) +{ + MOZ_ASSERT(NS_IsMainThread()); + + ENSURE_BLUETOOTH_IS_READY_VOID(aRunnable); + + BluetoothGattManager* gatt = BluetoothGattManager::Get(); + ENSURE_GATT_MGR_IS_READY_VOID(gatt, aRunnable); + + gatt->ReadRemoteRssi(aClientIf, aDeviceAddress, aRunnable); +} + // // Bluetooth notifications // diff --git a/dom/bluetooth2/bluedroid/BluetoothServiceBluedroid.h b/dom/bluetooth2/bluedroid/BluetoothServiceBluedroid.h index dd77a5a6c4e..bff28cb610c 100644 --- a/dom/bluetooth2/bluedroid/BluetoothServiceBluedroid.h +++ b/dom/bluetooth2/bluedroid/BluetoothServiceBluedroid.h @@ -188,6 +188,11 @@ public: UnregisterGattClientInternal(int aClientIf, BluetoothReplyRunnable* aRunnable) MOZ_OVERRIDE; + virtual void + GattClientReadRemoteRssiInternal( + int aClientIf, const nsAString& aDeviceAddress, + BluetoothReplyRunnable* aRunnable) MOZ_OVERRIDE; + // // Bluetooth notifications // diff --git a/dom/bluetooth2/bluez/BluetoothDBusService.cpp b/dom/bluetooth2/bluez/BluetoothDBusService.cpp index d483069e327..5e797ea3aa2 100644 --- a/dom/bluetooth2/bluez/BluetoothDBusService.cpp +++ b/dom/bluetooth2/bluez/BluetoothDBusService.cpp @@ -4296,3 +4296,10 @@ BluetoothDBusService::UnregisterGattClientInternal( int aClientIf, BluetoothReplyRunnable* aRunnable) { } + +void +BluetoothDBusService::GattClientReadRemoteRssiInternal( + int aClientIf, const nsAString& aDeviceAddress, + BluetoothReplyRunnable* aRunnable) +{ +} diff --git a/dom/bluetooth2/bluez/BluetoothDBusService.h b/dom/bluetooth2/bluez/BluetoothDBusService.h index f52ee6b94a0..bee49940ccc 100644 --- a/dom/bluetooth2/bluez/BluetoothDBusService.h +++ b/dom/bluetooth2/bluez/BluetoothDBusService.h @@ -198,6 +198,11 @@ public: UnregisterGattClientInternal(int aClientIf, BluetoothReplyRunnable* aRunnable) MOZ_OVERRIDE; + virtual void + GattClientReadRemoteRssiInternal( + int aClientIf, const nsAString& aDeviceAddress, + BluetoothReplyRunnable* aRunnable) MOZ_OVERRIDE; + private: nsresult SendGetPropertyMessage(const nsAString& aPath, const char* aInterface, diff --git a/dom/bluetooth2/ipc/BluetoothParent.cpp b/dom/bluetooth2/ipc/BluetoothParent.cpp index 7b63ee74ae8..bfee2825cb4 100644 --- a/dom/bluetooth2/ipc/BluetoothParent.cpp +++ b/dom/bluetooth2/ipc/BluetoothParent.cpp @@ -256,6 +256,8 @@ BluetoothParent::RecvPBluetoothRequestConstructor( return actor->DoRequest(aRequest.get_DisconnectGattClientRequest()); case Request::TUnregisterGattClientRequest: return actor->DoRequest(aRequest.get_UnregisterGattClientRequest()); + case Request::TGattClientReadRemoteRssiRequest: + return actor->DoRequest(aRequest.get_GattClientReadRemoteRssiRequest()); default: MOZ_CRASH("Unknown type!"); } @@ -728,3 +730,17 @@ BluetoothRequestParent::DoRequest(const UnregisterGattClientRequest& aRequest) return true; } + +bool +BluetoothRequestParent::DoRequest( + const GattClientReadRemoteRssiRequest& aRequest) +{ + MOZ_ASSERT(mService); + MOZ_ASSERT(mRequestType == Request::TGattClientReadRemoteRssiRequest); + + mService->GattClientReadRemoteRssiInternal(aRequest.clientIf(), + aRequest.deviceAddress(), + mReplyRunnable.get()); + + return true; +} diff --git a/dom/bluetooth2/ipc/BluetoothParent.h b/dom/bluetooth2/ipc/BluetoothParent.h index 8e45f880f09..e76b8c23efb 100644 --- a/dom/bluetooth2/ipc/BluetoothParent.h +++ b/dom/bluetooth2/ipc/BluetoothParent.h @@ -225,6 +225,9 @@ protected: bool DoRequest(const UnregisterGattClientRequest& aRequest); + + bool + DoRequest(const GattClientReadRemoteRssiRequest& aRequest); }; END_BLUETOOTH_NAMESPACE diff --git a/dom/bluetooth2/ipc/BluetoothServiceChildProcess.cpp b/dom/bluetooth2/ipc/BluetoothServiceChildProcess.cpp index 3822c7c775e..c7a1f924ec9 100644 --- a/dom/bluetooth2/ipc/BluetoothServiceChildProcess.cpp +++ b/dom/bluetooth2/ipc/BluetoothServiceChildProcess.cpp @@ -404,6 +404,16 @@ BluetoothServiceChildProcess::UnregisterGattClientInternal( SendRequest(aRunnable, UnregisterGattClientRequest(aClientIf)); } +void +BluetoothServiceChildProcess::GattClientReadRemoteRssiInternal( + int aClientIf, const nsAString& aDeviceAddress, + BluetoothReplyRunnable* aRunnable) +{ + SendRequest(aRunnable, + GattClientReadRemoteRssiRequest(aClientIf, + nsString(aDeviceAddress))); +} + nsresult BluetoothServiceChildProcess::HandleStartup() { diff --git a/dom/bluetooth2/ipc/BluetoothServiceChildProcess.h b/dom/bluetooth2/ipc/BluetoothServiceChildProcess.h index 4b0f2303f88..082dd3b0b8d 100644 --- a/dom/bluetooth2/ipc/BluetoothServiceChildProcess.h +++ b/dom/bluetooth2/ipc/BluetoothServiceChildProcess.h @@ -206,6 +206,11 @@ public: UnregisterGattClientInternal(int aClientIf, BluetoothReplyRunnable* aRunnable) MOZ_OVERRIDE; + virtual void + GattClientReadRemoteRssiInternal(int aClientIf, + const nsAString& aDeviceAddress, + BluetoothReplyRunnable* aRunnable) MOZ_OVERRIDE; + protected: BluetoothServiceChildProcess(); virtual ~BluetoothServiceChildProcess(); diff --git a/dom/bluetooth2/ipc/PBluetooth.ipdl b/dom/bluetooth2/ipc/PBluetooth.ipdl index 152d2095832..1d1edc64eb6 100644 --- a/dom/bluetooth2/ipc/PBluetooth.ipdl +++ b/dom/bluetooth2/ipc/PBluetooth.ipdl @@ -193,6 +193,12 @@ struct UnregisterGattClientRequest int clientIf; }; +struct GattClientReadRemoteRssiRequest +{ + int clientIf; + nsString deviceAddress; +}; + union Request { GetAdaptersRequest; @@ -228,6 +234,7 @@ union Request ConnectGattClientRequest; DisconnectGattClientRequest; UnregisterGattClientRequest; + GattClientReadRemoteRssiRequest; }; protocol PBluetooth diff --git a/dom/webidl/BluetoothGatt.webidl b/dom/webidl/BluetoothGatt.webidl index cd271c7ceea..2c58e2c15aa 100644 --- a/dom/webidl/BluetoothGatt.webidl +++ b/dom/webidl/BluetoothGatt.webidl @@ -27,6 +27,13 @@ interface BluetoothGatt : EventTarget Promise connect(); [NewObject] Promise disconnect(); + + /** + * Read RSSI for the remote BLE device if the connectState is connected. + * Otherwise, the Promise will be rejected directly. + */ + [NewObject] + Promise readRemoteRssi(); }; enum BluetoothConnectionState