Bug 1100818 - Launch bluetooth certified app by sending system message if it's not ready for receiving BluetoothPairingEvent. r=btian

This commit is contained in:
Jamin Liu 2014-12-19 11:12:33 +08:00
parent 397c80fd42
commit 4dfa0f58f1
8 changed files with 137 additions and 51 deletions

View File

@ -6,8 +6,9 @@
#include "BluetoothReplyRunnable.h"
#include "BluetoothService.h"
#include "BluetoothUtils.h"
#include "DOMRequest.h"
#include "nsIDocument.h"
#include "nsIPrincipal.h"
#include "nsTArrayHelpers.h"
#include "mozilla/dom/BluetoothAdapter2Binding.h"
@ -193,11 +194,15 @@ BluetoothAdapter::BluetoothAdapter(nsPIDOMWindow* aWindow,
, mState(BluetoothAdapterState::Disabled)
, mDiscoverable(false)
, mDiscovering(false)
, mPairingReqs(nullptr)
, mDiscoveryHandleInUse(nullptr)
{
MOZ_ASSERT(aWindow);
// Only allow certified bluetooth application to receive pairing requests
if (IsBluetoothCertifiedApp()) {
mPairingReqs = BluetoothPairingListener::Create(aWindow);
}
const InfallibleTArray<BluetoothNamedValue>& values =
aValue.get_ArrayOfBluetoothNamedValue();
@ -329,8 +334,6 @@ BluetoothAdapter::Notify(const BluetoothSignal& aData)
if (mDiscoveryHandleInUse) {
HandleDeviceFound(v);
}
} else if (aData.name().EqualsLiteral("PairingRequest")) {
HandlePairingRequest(v);
} else if (aData.name().EqualsLiteral(DEVICE_PAIRED_ID)) {
HandleDevicePaired(aData.value());
} else if (aData.name().EqualsLiteral(DEVICE_UNPAIRED_ID)) {
@ -762,6 +765,23 @@ BluetoothAdapter::IsAdapterAttributeChanged(BluetoothAdapterAttribute aType,
}
}
bool
BluetoothAdapter::IsBluetoothCertifiedApp()
{
// Retrieve the app status and origin for permission checking
nsCOMPtr<nsIDocument> doc = GetOwner()->GetExtantDoc();
NS_ENSURE_TRUE(doc, false);
uint16_t appStatus = nsIPrincipal::APP_STATUS_NOT_INSTALLED;
nsAutoCString appOrigin;
doc->NodePrincipal()->GetAppStatus(&appStatus);
doc->NodePrincipal()->GetOrigin(getter_Copies(appOrigin));
return appStatus == nsIPrincipal::APP_STATUS_CERTIFIED &&
appOrigin.EqualsLiteral(BLUETOOTH_APP_ORIGIN);
}
void
BluetoothAdapter::SetAdapterState(BluetoothAdapterState aState)
{
@ -831,42 +851,6 @@ BluetoothAdapter::HandleDeviceFound(const BluetoothValue& aValue)
mDiscoveryHandleInUse->DispatchDeviceEvent(discoveredDevice);
}
void
BluetoothAdapter::HandlePairingRequest(const BluetoothValue& aValue)
{
MOZ_ASSERT(mPairingReqs);
MOZ_ASSERT(aValue.type() == BluetoothValue::TArrayOfBluetoothNamedValue);
const InfallibleTArray<BluetoothNamedValue>& arr =
aValue.get_ArrayOfBluetoothNamedValue();
MOZ_ASSERT(arr.Length() == 3 &&
arr[0].value().type() == BluetoothValue::TnsString && // address
arr[1].value().type() == BluetoothValue::TnsString && // passkey
arr[2].value().type() == BluetoothValue::TnsString); // type
nsString deviceAddress = arr[0].value().get_nsString();
nsString passkey = arr[1].value().get_nsString();
nsString type = arr[2].value().get_nsString();
// Create a temporary device with deviceAddress for searching
InfallibleTArray<BluetoothNamedValue> props;
BT_APPEND_NAMED_VALUE(props, "Address", deviceAddress);
nsRefPtr<BluetoothDevice> device =
BluetoothDevice::Create(GetOwner(), props);
// Find the remote device by address
size_t index = mDevices.IndexOf(device);
if (index == mDevices.NoIndex) {
BT_WARNING("Cannot find the remote device with address %s",
NS_ConvertUTF16toUTF8(deviceAddress).get());
return;
}
// Notify application of pairing requests
mPairingReqs->DispatchPairingEvent(mDevices[index], passkey, type);
}
void
BluetoothAdapter::DispatchAttributeEvent(const nsTArray<nsString>& aTypes)
{

View File

@ -248,13 +248,6 @@ private:
*/
void HandleDeviceFound(const BluetoothValue& aValue);
/**
* Handle "PairingRequest" bluetooth signal.
*
* @param aValue [in] Array of information about the pairing request.
*/
void HandlePairingRequest(const BluetoothValue& aValue);
/**
* Fire BluetoothAttributeEvent to trigger onattributechanged event handler.
*/
@ -287,6 +280,13 @@ private:
bool IsAdapterAttributeChanged(BluetoothAdapterAttribute aType,
const BluetoothValue& aValue);
/**
* Check whether this adapter is owned by Bluetooth certified app.
*
* @return a boolean value to indicate whether it's owned by Bluetooth app.
*/
bool IsBluetoothCertifiedApp();
/****************************************************************************
* Variables
***************************************************************************/

View File

@ -143,6 +143,7 @@ extern bool gBluetoothDebugFlag;
#define KEY_REMOTE_AGENT "/B2G/bluetooth/remote_device_agent"
#define KEY_MANAGER "/B2G/bluetooth/manager"
#define KEY_ADAPTER "/B2G/bluetooth/adapter"
#define KEY_PAIRING_LISTENER "/B2G/bluetooth/pairing_listener"
/**
* When the connection status of a Bluetooth profile is changed, we'll notify
@ -170,6 +171,18 @@ extern bool gBluetoothDebugFlag;
#define PAIRING_REQ_TYPE_CONFIRMATION "pairingconfirmationreq"
#define PAIRING_REQ_TYPE_CONSENT "pairingconsentreq"
/**
* System message to launch bluetooth app if no pairing listener is ready to
* receive pairing requests.
*/
#define SYS_MSG_BT_PAIRING_REQ "bluetooth-pairing-request"
/**
* The app origin of bluetooth app, which is responsible for listening pairing
* requests.
*/
#define BLUETOOTH_APP_ORIGIN "app://bluetooth.gaiamobile.org"
/**
* When a remote device gets paired / unpaired with local bluetooth adapter,
* we'll dispatch an event.

View File

@ -6,8 +6,10 @@
#include "mozilla/dom/bluetooth/BluetoothPairingListener.h"
#include "mozilla/dom/bluetooth/BluetoothPairingHandle.h"
#include "mozilla/dom/bluetooth/BluetoothTypes.h"
#include "mozilla/dom/BluetoothPairingEvent.h"
#include "mozilla/dom/BluetoothPairingListenerBinding.h"
#include "BluetoothService.h"
USING_BLUETOOTH_NAMESPACE
@ -21,6 +23,11 @@ BluetoothPairingListener::BluetoothPairingListener(nsPIDOMWindow* aWindow)
: DOMEventTargetHelper(aWindow)
{
MOZ_ASSERT(aWindow);
BluetoothService* bs = BluetoothService::Get();
NS_ENSURE_TRUE_VOID(bs);
bs->RegisterBluetoothSignalHandler(NS_LITERAL_STRING(KEY_PAIRING_LISTENER),
this);
}
already_AddRefed<BluetoothPairingListener>
@ -37,6 +44,11 @@ BluetoothPairingListener::Create(nsPIDOMWindow* aWindow)
BluetoothPairingListener::~BluetoothPairingListener()
{
BluetoothService* bs = BluetoothService::Get();
// It can be nullptr on shutdown.
NS_ENSURE_TRUE_VOID(bs);
bs->UnregisterBluetoothSignalHandler(NS_LITERAL_STRING(KEY_PAIRING_LISTENER),
this);
}
void
@ -67,8 +79,55 @@ BluetoothPairingListener::DispatchPairingEvent(BluetoothDevice* aDevice,
DispatchTrustedEvent(event);
}
void
BluetoothPairingListener::Notify(const BluetoothSignal& aData)
{
InfallibleTArray<BluetoothNamedValue> arr;
BluetoothValue value = aData.value();
if (aData.name().EqualsLiteral("PairingRequest")) {
MOZ_ASSERT(value.type() == BluetoothValue::TArrayOfBluetoothNamedValue);
const InfallibleTArray<BluetoothNamedValue>& arr =
value.get_ArrayOfBluetoothNamedValue();
MOZ_ASSERT(arr.Length() == 3 &&
arr[0].value().type() == BluetoothValue::TnsString && // address
arr[1].value().type() == BluetoothValue::TnsString && // passkey
arr[2].value().type() == BluetoothValue::TnsString); // type
nsString deviceAddress = arr[0].value().get_nsString();
nsString passkey = arr[1].value().get_nsString();
nsString type = arr[2].value().get_nsString();
// Create a temporary device with deviceAddress for searching
InfallibleTArray<BluetoothNamedValue> props;
BT_APPEND_NAMED_VALUE(props, "Address", deviceAddress);
nsRefPtr<BluetoothDevice> device =
BluetoothDevice::Create(GetOwner(), props);
// Notify pairing listener of pairing requests
DispatchPairingEvent(device, passkey, type);
} else {
BT_WARNING("Not handling pairing listener signal: %s",
NS_ConvertUTF16toUTF8(aData.name()).get());
}
}
JSObject*
BluetoothPairingListener::WrapObject(JSContext* aCx)
{
return BluetoothPairingListenerBinding::Wrap(aCx, this);
}
void
BluetoothPairingListener::DisconnectFromOwner()
{
DOMEventTargetHelper::DisconnectFromOwner();
BluetoothService* bs = BluetoothService::Get();
NS_ENSURE_TRUE_VOID(bs);
bs->UnregisterBluetoothSignalHandler(NS_LITERAL_STRING(KEY_PAIRING_LISTENER),
this);
}

View File

@ -14,8 +14,10 @@
BEGIN_BLUETOOTH_NAMESPACE
class BluetoothDevice;
class BluetoothSignal;
class BluetoothPairingListener MOZ_FINAL : public DOMEventTargetHelper
, public BluetoothSignalObserver
{
public:
NS_DECL_ISUPPORTS_INHERITED
@ -27,12 +29,15 @@ public:
const nsAString& aPasskey,
const nsAString& aType);
void Notify(const BluetoothSignal& aParam); // BluetoothSignalObserver
nsPIDOMWindow* GetParentObject() const
{
return GetOwner();
}
virtual JSObject* WrapObject(JSContext* aCx) MOZ_OVERRIDE;
virtual void DisconnectFromOwner() MOZ_OVERRIDE;
IMPL_EVENT_HANDLER(displaypasskeyreq);
IMPL_EVENT_HANDLER(enterpincodereq);

View File

@ -273,6 +273,17 @@ BluetoothService::RegisterBluetoothSignalHandler(
}
ol->AddObserver(aHandler);
// Distribute pending pairing requests when pairing listener has been added
// to signal observer table.
if (IsMainProcess() &&
!mPendingPairReqSignals.IsEmpty() &&
aNodeName.EqualsLiteral(KEY_PAIRING_LISTENER)) {
for (uint32_t i = 0; i < mPendingPairReqSignals.Length(); ++i) {
DistributeSignal(mPendingPairReqSignals[i]);
}
mPendingPairReqSignals.Clear();
}
}
void
@ -331,8 +342,19 @@ BluetoothService::DistributeSignal(const BluetoothSignal& aSignal)
BluetoothSignalObserverList* ol;
if (!mBluetoothSignalObserverTable.Get(aSignal.path(), &ol)) {
// If there is no BluetoohPairingListener in observer table, put the signal
// into a pending queue of pairing requests and send a system message to
// launch bluetooth certified app.
if (aSignal.path().EqualsLiteral(KEY_PAIRING_LISTENER)) {
mPendingPairReqSignals.AppendElement(aSignal);
BT_ENSURE_TRUE_VOID_BROADCAST_SYSMSG(
NS_LITERAL_STRING(SYS_MSG_BT_PAIRING_REQ),
BluetoothValue(EmptyString()));
} else {
BT_WARNING("No observer registered for path %s",
NS_ConvertUTF16toUTF8(aSignal.path()).get());
}
return;
}

View File

@ -8,6 +8,7 @@
#define mozilla_dom_bluetooth_bluetootheventservice_h__
#include "BluetoothCommon.h"
#include "BluetoothInterface.h"
#include "BluetoothProfileManagerBase.h"
#include "nsAutoPtr.h"
#include "nsClassHashtable.h"
@ -401,6 +402,8 @@ protected:
BluetoothSignalObserverTable mBluetoothSignalObserverTable;
nsTArray<BluetoothSignal> mPendingPairReqSignals;
bool mEnabled;
};

View File

@ -1473,7 +1473,7 @@ BluetoothServiceBluedroid::PinRequestNotification(const nsAString& aRemoteBdAddr
NS_LITERAL_STRING(PAIRING_REQ_TYPE_ENTERPINCODE));
DistributeSignal(BluetoothSignal(NS_LITERAL_STRING("PairingRequest"),
NS_LITERAL_STRING(KEY_ADAPTER),
NS_LITERAL_STRING(KEY_PAIRING_LISTENER),
BluetoothValue(propertiesArray)));
}
@ -1518,7 +1518,7 @@ BluetoothServiceBluedroid::SspRequestNotification(
BT_APPEND_NAMED_VALUE(propertiesArray, "type", pairingType);
DistributeSignal(BluetoothSignal(NS_LITERAL_STRING("PairingRequest"),
NS_LITERAL_STRING(KEY_ADAPTER),
NS_LITERAL_STRING(KEY_PAIRING_LISTENER),
BluetoothValue(propertiesArray)));
}