Bug 1006314 - Patch 3/3: Revise BluetoothAdapter, r=bz, r=echou

This commit is contained in:
Ben Tian 2014-07-02 16:25:50 +08:00
parent 431e479c90
commit 4b2882a458
4 changed files with 150 additions and 109 deletions

View File

@ -21,6 +21,7 @@
#include "BluetoothAdapter.h"
#include "BluetoothDevice.h"
#include "BluetoothDiscoveryHandle.h"
#include "BluetoothReplyRunnable.h"
#include "BluetoothService.h"
#include "BluetoothUtils.h"
@ -55,6 +56,49 @@ NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper)
NS_IMPL_ADDREF_INHERITED(BluetoothAdapter, DOMEventTargetHelper)
NS_IMPL_RELEASE_INHERITED(BluetoothAdapter, DOMEventTargetHelper)
class StartDiscoveryTask : public BluetoothReplyRunnable
{
public:
StartDiscoveryTask(BluetoothAdapter* aAdapter, Promise* aPromise)
: BluetoothReplyRunnable(nullptr, aPromise,
NS_LITERAL_STRING("StartDiscovery"))
, mAdapter(aAdapter)
{
MOZ_ASSERT(aPromise && aAdapter);
}
bool
ParseSuccessfulReply(JS::MutableHandle<JS::Value> aValue)
{
BT_API2_LOGR();
aValue.setUndefined();
AutoJSAPI jsapi;
NS_ENSURE_TRUE(jsapi.Init(mAdapter->GetParentObject()), false);
// Wrap BluetoothDiscoveryHandle to return
JSContext* cx = jsapi.cx();
nsRefPtr<BluetoothDiscoveryHandle> discoveryHandle =
BluetoothDiscoveryHandle::Create(mAdapter->GetParentObject());
if (!ToJSValue(cx, discoveryHandle, aValue)) {
JS_ClearPendingException(cx);
return false;
}
return true;
}
virtual void
ReleaseMembers() MOZ_OVERRIDE
{
BluetoothReplyRunnable::ReleaseMembers();
mAdapter = nullptr;
}
private:
nsRefPtr<BluetoothAdapter> mAdapter;
};
class GetDevicesTask : public BluetoothReplyRunnable
{
public:
@ -304,24 +348,10 @@ BluetoothAdapter::Notify(const BluetoothSignal& aData)
{
InfallibleTArray<BluetoothNamedValue> arr;
BT_LOGD("[A] %s: %s", __FUNCTION__,
NS_ConvertUTF16toUTF8(aData.name()).get());
BT_LOGD("[A] %s", NS_ConvertUTF16toUTF8(aData.name()).get());
BluetoothValue v = aData.value();
if (aData.name().EqualsLiteral("DeviceFound")) {
nsRefPtr<BluetoothDevice> device =
BluetoothDevice::Create(GetOwner(), aData.value());
BluetoothDeviceEventInit init;
init.mBubbles = false;
init.mCancelable = false;
init.mDevice = device;
nsRefPtr<BluetoothDeviceEvent> event =
BluetoothDeviceEvent::Constructor(this,
NS_LITERAL_STRING("devicefound"),
init);
DispatchTrustedEvent(event);
} else if (aData.name().EqualsLiteral("PropertyChanged")) {
if (aData.name().EqualsLiteral("PropertyChanged")) {
HandlePropertyChanged(v);
} else if (aData.name().EqualsLiteral(PAIRED_STATUS_CHANGED_ID) ||
aData.name().EqualsLiteral(HFP_STATUS_CHANGED_ID) ||
@ -360,49 +390,55 @@ BluetoothAdapter::Notify(const BluetoothSignal& aData)
}
}
already_AddRefed<DOMRequest>
already_AddRefed<Promise>
BluetoothAdapter::StartStopDiscovery(bool aStart, ErrorResult& aRv)
{
nsCOMPtr<nsPIDOMWindow> win = GetOwner();
if (!win) {
nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(GetOwner());
if (!global) {
aRv.Throw(NS_ERROR_FAILURE);
return nullptr;
}
nsRefPtr<Promise> promise = new Promise(global);
nsRefPtr<DOMRequest> request = new DOMRequest(win);
nsRefPtr<BluetoothVoidReplyRunnable> results =
new BluetoothVoidReplyRunnable(request);
/**
* Ensure
* - adapter does not already start/stop discovering,
* - adapter is already enabled, and
* - BluetoothService is available
*/
BT_ENSURE_TRUE_RESOLVE(mDiscovering != aStart, JS::UndefinedHandleValue);
BT_ENSURE_TRUE_REJECT(mState == BluetoothAdapterState::Enabled,
NS_ERROR_DOM_INVALID_STATE_ERR);
BluetoothService* bs = BluetoothService::Get();
if (!bs) {
aRv.Throw(NS_ERROR_FAILURE);
return nullptr;
}
BT_ENSURE_TRUE_REJECT(bs, NS_ERROR_NOT_AVAILABLE);
BT_API2_LOGR("aStart %d", aStart);
nsresult rv;
if (aStart) {
rv = bs->StartDiscoveryInternal(results);
// Start discovery: return BluetoothDiscoveryHandle in StartDiscoveryTask
nsRefPtr<BluetoothReplyRunnable> result =
new StartDiscoveryTask(this, promise);
rv = bs->StartDiscoveryInternal(result);
} else {
rv = bs->StopDiscoveryInternal(results);
}
if (NS_FAILED(rv)) {
BT_WARNING("Start/Stop Discovery failed!");
aRv.Throw(rv);
return nullptr;
// Stop discovery: void return
nsRefPtr<BluetoothReplyRunnable> result =
new BluetoothVoidReplyRunnable(nullptr /* DOMRequest */,
promise,
NS_LITERAL_STRING("StopDiscovery"));
rv = bs->StopDiscoveryInternal(result);
}
BT_ENSURE_TRUE_REJECT(NS_SUCCEEDED(rv), NS_ERROR_DOM_OPERATION_ERR);
// mDiscovering is not set here, we'll get a Property update from our external
// protocol to tell us that it's been set.
return request.forget();
return promise.forget();
}
already_AddRefed<DOMRequest>
already_AddRefed<Promise>
BluetoothAdapter::StartDiscovery(ErrorResult& aRv)
{
return StartStopDiscovery(true, aRv);
}
already_AddRefed<DOMRequest>
already_AddRefed<Promise>
BluetoothAdapter::StopDiscovery(ErrorResult& aRv)
{
return StartStopDiscovery(false, aRv);
@ -446,38 +482,32 @@ BluetoothAdapter::SetName(const nsAString& aName, ErrorResult& aRv)
aRv.Throw(NS_ERROR_FAILURE);
return nullptr;
}
nsRefPtr<Promise> promise = new Promise(global);
if (mState != BluetoothAdapterState::Enabled) {
promise->MaybeReject(NS_ERROR_DOM_INVALID_STATE_ERR);
return promise.forget();
}
if (mName.Equals(aName)) {
// Need to resolved with "undefined" since this method is Promise<void>
promise->MaybeResolve(JS::UndefinedHandleValue);
return promise.forget();
}
nsString name(aName);
BluetoothValue value(name);
BluetoothNamedValue property(NS_LITERAL_STRING("Name"), value);
/**
* Ensure
* - adapter's name does not equal to aName,
* - adapter is already enabled, and
* - BluetoothService is available
*/
BT_ENSURE_TRUE_RESOLVE(!mName.Equals(aName), JS::UndefinedHandleValue);
BT_ENSURE_TRUE_REJECT(mState == BluetoothAdapterState::Enabled,
NS_ERROR_DOM_INVALID_STATE_ERR);
BluetoothService* bs = BluetoothService::Get();
if (!bs) {
promise->MaybeReject(NS_ERROR_NOT_AVAILABLE);
return promise.forget();
}
BT_ENSURE_TRUE_REJECT(bs, NS_ERROR_NOT_AVAILABLE);
// Wrap property to set and runnable to handle result
nsString name(aName);
BluetoothNamedValue property(NS_LITERAL_STRING("Name"),
BluetoothValue(name));
nsRefPtr<BluetoothReplyRunnable> result =
new BluetoothVoidReplyRunnable(nullptr /* DOMRequest */,
promise,
NS_LITERAL_STRING("SetName"));
if (NS_FAILED(bs->SetProperty(BluetoothObjectType::TYPE_ADAPTER,
property, result))) {
promise->MaybeReject(NS_ERROR_DOM_OPERATION_ERR);
}
BT_ENSURE_TRUE_REJECT(
NS_SUCCEEDED(bs->SetProperty(BluetoothObjectType::TYPE_ADAPTER,
property, result)),
NS_ERROR_DOM_OPERATION_ERR);
return promise.forget();
}
@ -490,37 +520,32 @@ BluetoothAdapter::SetDiscoverable(bool aDiscoverable, ErrorResult& aRv)
aRv.Throw(NS_ERROR_FAILURE);
return nullptr;
}
nsRefPtr<Promise> promise = new Promise(global);
if (mState != BluetoothAdapterState::Enabled) {
promise->MaybeReject(NS_ERROR_DOM_INVALID_STATE_ERR);
return promise.forget();
}
if (aDiscoverable == mDiscoverable) {
// Need to resolved with "undefined" since this method is Promise<void>
promise->MaybeResolve(JS::UndefinedHandleValue);
return promise.forget();
}
BluetoothValue value(aDiscoverable);
BluetoothNamedValue property(NS_LITERAL_STRING("Discoverable"), value);
/**
* Ensure
* - mDiscoverable does not equal to aDiscoverable,
* - adapter is already enabled, and
* - BluetoothService is available
*/
BT_ENSURE_TRUE_RESOLVE(mDiscoverable != aDiscoverable,
JS::UndefinedHandleValue);
BT_ENSURE_TRUE_REJECT(mState == BluetoothAdapterState::Enabled,
NS_ERROR_DOM_INVALID_STATE_ERR);
BluetoothService* bs = BluetoothService::Get();
if (!bs) {
promise->MaybeReject(NS_ERROR_NOT_AVAILABLE);
return promise.forget();
}
BT_ENSURE_TRUE_REJECT(bs, NS_ERROR_NOT_AVAILABLE);
// Wrap property to set and runnable to handle result
BluetoothNamedValue property(NS_LITERAL_STRING("Discoverable"),
BluetoothValue(aDiscoverable));
nsRefPtr<BluetoothReplyRunnable> result =
new BluetoothVoidReplyRunnable(nullptr /* DOMRequest */,
promise,
NS_LITERAL_STRING("SetDiscoverable"));
if (NS_FAILED(bs->SetProperty(BluetoothObjectType::TYPE_ADAPTER,
property, result))) {
promise->MaybeReject(NS_ERROR_DOM_OPERATION_ERR);
}
BT_ENSURE_TRUE_REJECT(
NS_SUCCEEDED(bs->SetProperty(BluetoothObjectType::TYPE_ADAPTER,
property, result)),
NS_ERROR_DOM_OPERATION_ERR);
return promise.forget();
}
@ -723,42 +748,36 @@ BluetoothAdapter::EnableDisable(bool aEnable, ErrorResult& aRv)
aRv.Throw(NS_ERROR_FAILURE);
return nullptr;
}
nsRefPtr<Promise> promise = new Promise(global);
// Ensure BluetoothService is available before modifying adapter state
BluetoothService* bs = BluetoothService::Get();
if (!bs) {
promise->MaybeReject(NS_ERROR_NOT_AVAILABLE);
return promise.forget();
}
BT_ENSURE_TRUE_REJECT(bs, NS_ERROR_NOT_AVAILABLE);
nsString methodName;
// Modify adapter state to Enabling/Disabling if adapter is in a valid state
nsAutoString methodName;
if (aEnable) {
// Enable local adapter
if (mState != BluetoothAdapterState::Disabled) {
promise->MaybeReject(NS_ERROR_DOM_INVALID_STATE_ERR);
return promise.forget();
}
BT_ENSURE_TRUE_REJECT(mState == BluetoothAdapterState::Disabled,
NS_ERROR_DOM_INVALID_STATE_ERR);
methodName.AssignLiteral("Enable");
mState = BluetoothAdapterState::Enabling;
} else {
// Disable local adapter
if (mState != BluetoothAdapterState::Enabled) {
promise->MaybeReject(NS_ERROR_DOM_INVALID_STATE_ERR);
return promise.forget();
}
BT_ENSURE_TRUE_REJECT(mState == BluetoothAdapterState::Enabled,
NS_ERROR_DOM_INVALID_STATE_ERR);
methodName.AssignLiteral("Disable");
mState = BluetoothAdapterState::Disabling;
}
// Notify applications of adapter state change to Enabling/Disabling
nsTArray<nsString> types;
BT_APPEND_ENUM_STRING(types,
BluetoothAdapterAttribute,
BluetoothAdapterAttribute::State);
DispatchAttributeEvent(types);
// Wrap runnable to handle result
nsRefPtr<BluetoothReplyRunnable> result =
new BluetoothVoidReplyRunnable(nullptr, /* DOMRequest */
promise,

View File

@ -96,8 +96,8 @@ public:
already_AddRefed<Promise> SetName(const nsAString& aName, ErrorResult& aRv);
already_AddRefed<Promise>
SetDiscoverable(bool aDiscoverable, ErrorResult& aRv);
already_AddRefed<DOMRequest> StartDiscovery(ErrorResult& aRv);
already_AddRefed<DOMRequest> StopDiscovery(ErrorResult& aRv);
already_AddRefed<Promise> StartDiscovery(ErrorResult& aRv);
already_AddRefed<Promise> StopDiscovery(ErrorResult& aRv);
already_AddRefed<DOMRequest>
Pair(const nsAString& aDeviceAddress, ErrorResult& aRv);
@ -176,8 +176,7 @@ private:
void Root();
already_AddRefed<mozilla::dom::DOMRequest>
StartStopDiscovery(bool aStart, ErrorResult& aRv);
already_AddRefed<Promise> StartStopDiscovery(bool aStart, ErrorResult& aRv);
already_AddRefed<mozilla::dom::DOMRequest>
PairUnpair(bool aPair, const nsAString& aDeviceAddress, ErrorResult& aRv);

View File

@ -95,6 +95,30 @@ extern bool gBluetoothDebugFlag;
array.AppendElement(name); \
} while(0) \
/**
* Resolve promise with |ret| if |x| is false.
*/
#define BT_ENSURE_TRUE_RESOLVE(x, ret) \
do { \
if (MOZ_UNLIKELY(!(x))) { \
BT_API2_LOGR("BT_ENSURE_TRUE_RESOLVE(" #x ") failed"); \
promise->MaybeResolve(ret); \
return promise.forget(); \
} \
} while(0)
/**
* Reject promise with |ret| if |x| is false.
*/
#define BT_ENSURE_TRUE_REJECT(x, ret) \
do { \
if (MOZ_UNLIKELY(!(x))) { \
BT_API2_LOGR("BT_ENSURE_TRUE_REJECT(" #x ") failed"); \
promise->MaybeReject(ret); \
return promise.forget(); \
} \
} while(0)
#define BEGIN_BLUETOOTH_NAMESPACE \
namespace mozilla { namespace dom { namespace bluetooth {
#define END_BLUETOOTH_NAMESPACE \

View File

@ -6,7 +6,6 @@
#include "base/basictypes.h"
#include "BluetoothManager.h"
#include "BluetoothCommon.h"
#include "BluetoothAdapter.h"
#include "BluetoothService.h"
#include "BluetoothReplyRunnable.h"
@ -76,8 +75,8 @@ class GetAdaptersTask : public BluetoothReplyRunnable
return true;
}
void
ReleaseMembers()
virtual void
ReleaseMembers() MOZ_OVERRIDE
{
BluetoothReplyRunnable::ReleaseMembers();
mManager = nullptr;