Bug 777665 - patch 1: Hook up settings to Bluetooth. r=qdot, sr=mrbkap

This commit is contained in:
Eric Chou 2012-08-30 14:08:50 +08:00
parent 097a4578df
commit ffd0038d61
5 changed files with 171 additions and 87 deletions

View File

@ -13,13 +13,17 @@
#include "BluetoothReplyRunnable.h"
#include "nsContentUtils.h"
#include "nsIDOMDOMRequest.h"
#include "nsIPermissionManager.h"
#include "nsDOMClassInfo.h"
#include "nsDOMEvent.h"
#include "nsDOMEventTargetHelper.h"
#include "nsIDOMDOMRequest.h"
#include "nsIJSContextStack.h"
#include "nsIObserverService.h"
#include "nsIPermissionManager.h"
#include "nsThreadUtils.h"
#include "nsXPCOMCIDInternal.h"
#include "mozilla/LazyIdleThread.h"
#include "mozilla/Services.h"
#include "mozilla/Util.h"
#include "nsIDOMDOMRequest.h"
@ -34,11 +38,13 @@ NS_IMPL_CYCLE_COLLECTION_CLASS(BluetoothManager)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(BluetoothManager,
nsDOMEventTargetHelper)
NS_CYCLE_COLLECTION_TRAVERSE_EVENT_HANDLER(enabled)
NS_CYCLE_COLLECTION_TRAVERSE_EVENT_HANDLER(disabled)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(BluetoothManager,
nsDOMEventTargetHelper)
NS_CYCLE_COLLECTION_UNLINK_EVENT_HANDLER(enabled)
NS_CYCLE_COLLECTION_UNLINK_EVENT_HANDLER(disabled)
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(BluetoothManager)
@ -101,51 +107,68 @@ private:
nsRefPtr<BluetoothManager> mManagerPtr;
};
class ToggleBtResultTask : public BluetoothReplyRunnable
class ToggleBtResultTask : public nsRunnable
{
public:
ToggleBtResultTask(BluetoothManager* aManager,
nsIDOMDOMRequest* aReq,
bool aEnabled)
: BluetoothReplyRunnable(aReq),
mManagerPtr(aManager),
ToggleBtResultTask(BluetoothManager* aManager, bool aEnabled)
: mManagerPtr(aManager),
mEnabled(aEnabled)
{
}
~ToggleBtResultTask()
{
}
bool
ParseSuccessfulReply(jsval* aValue)
NS_IMETHOD Run()
{
MOZ_ASSERT(NS_IsMainThread());
*aValue = JSVAL_VOID;
mManagerPtr->SetEnabledInternal(mEnabled);
return true;
}
void
ReleaseMembers()
{
BluetoothReplyRunnable::ReleaseMembers();
mManagerPtr->SetEnabledInternal(mEnabled);
mManagerPtr->FireEnabledDisabledEvent();
// mManagerPtr must be null before returning to prevent the background
// thread from racing to release it during the destruction of this runnable.
mManagerPtr = nullptr;
return NS_OK;
}
private:
nsRefPtr<BluetoothManager> mManagerPtr;
bool mEnabled;
};
nsresult
BluetoothManager::FireEnabledDisabledEvent()
{
nsString eventName;
if (mEnabled) {
eventName.AssignLiteral("enabled");
} else {
eventName.AssignLiteral("disabled");
}
nsRefPtr<nsDOMEvent> event = new nsDOMEvent(nullptr, nullptr);
nsresult rv = event->InitEvent(eventName, false, false);
NS_ENSURE_SUCCESS(rv, rv);
rv = event->SetTrusted(true);
NS_ENSURE_SUCCESS(rv, rv);
bool dummy;
rv = DispatchEvent(event, &dummy);
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
}
BluetoothManager::BluetoothManager(nsPIDOMWindow *aWindow) :
BluetoothPropertyContainer(BluetoothObjectType::TYPE_MANAGER),
mEnabled(false)
{
BindToOwner(aWindow);
mPath.AssignLiteral("/");
nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
obs->AddObserver(this, "mozsettings-changed", false);
}
BluetoothManager::~BluetoothManager()
@ -157,6 +180,104 @@ BluetoothManager::~BluetoothManager()
NS_WARNING("Failed to unregister object with observer!");
}
}
nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
obs->RemoveObserver(this, "mozsettings-changed");
}
nsresult
BluetoothManager::HandleMozsettingChanged(const PRUnichar* aData)
{
// The string that we're interested in will be a JSON string that looks like:
// {"key":"bluetooth.enabled","value":true}
nsresult rv;
nsIScriptContext* sc = GetContextForEventHandlers(&rv);
if (NS_FAILED(rv)) {
return NS_ERROR_UNEXPECTED;
}
JSContext *cx = sc->GetNativeContext();
if (!cx) {
return NS_OK;
}
// In the following [if] blocks, NS_OK will be returned even if JS_* functions
// return false. That's because this function gets called whenever mozSettings
// changes, so that we'll receive signals we're not interested in and it would
// be one of the reasons for making JS_* functions return false.
nsDependentString dataStr(aData);
JS::Value val;
if (!JS_ParseJSON(cx, dataStr.get(), dataStr.Length(), &val)) {
return NS_OK;
}
if (!val.isObject()) {
return NS_OK;
}
JSObject &obj(val.toObject());
JS::Value key;
if (!JS_GetProperty(cx, &obj, "key", &key)) {
return NS_OK;
}
if (!key.isString()) {
return NS_OK;
}
JSBool match;
if (!JS_StringEqualsAscii(cx, key.toString(), "bluetooth.enabled", &match)) {
return NS_OK;
}
if (!match) {
return NS_OK;
}
JS::Value value;
if (!JS_GetProperty(cx, &obj, "value", &value)) {
return NS_OK;
}
if (!value.isBoolean()) {
return NS_OK;
}
BluetoothService* bs = BluetoothService::Get();
if (!bs) {
NS_WARNING("BluetoothService not available!");
return NS_ERROR_FAILURE;
}
bool enabled = value.toBoolean();
nsCOMPtr<nsIRunnable> resultTask = new ToggleBtResultTask(this, enabled);
if (enabled) {
if (NS_FAILED(bs->Start(resultTask))) {
return NS_ERROR_FAILURE;
}
} else {
if (NS_FAILED(bs->Stop(resultTask))) {
return NS_ERROR_FAILURE;
}
}
return NS_OK;
}
NS_IMETHODIMP
BluetoothManager::Observe(nsISupports* aSubject,
const char* aTopic,
const PRUnichar* aData)
{
nsresult rv = NS_OK;
if (!strcmp("mozsettings-changed", aTopic)) {
rv = HandleMozsettingChanged(aData);
}
return rv;
}
void
@ -171,44 +292,6 @@ BluetoothManager::SetPropertyByValue(const BluetoothNamedValue& aValue)
#endif
}
NS_IMETHODIMP
BluetoothManager::SetEnabled(bool aEnabled, nsIDOMDOMRequest** aDomRequest)
{
BluetoothService* bs = BluetoothService::Get();
if (!bs) {
NS_WARNING("BluetoothService not available!");
return NS_ERROR_FAILURE;
}
nsCOMPtr<nsIDOMRequestService> rs = do_GetService("@mozilla.org/dom/dom-request-service;1");
if (!rs) {
NS_WARNING("No DOMRequest Service!");
return NS_ERROR_FAILURE;
}
nsCOMPtr<nsIDOMDOMRequest> request;
nsresult rv = rs->CreateRequest(GetOwner(), getter_AddRefs(request));
if (NS_FAILED(rv)) {
NS_WARNING("Can't create DOM request!");
return NS_ERROR_FAILURE;
}
nsRefPtr<BluetoothReplyRunnable> results = new ToggleBtResultTask(this, request, aEnabled);
if (aEnabled) {
if (NS_FAILED(bs->Start(results))) {
return NS_ERROR_FAILURE;
}
}
else {
if (NS_FAILED(bs->Stop(results))) {
return NS_ERROR_FAILURE;
}
}
request.forget(aDomRequest);
return NS_OK;
}
NS_IMETHODIMP
BluetoothManager::GetEnabled(bool* aEnabled)
{
@ -318,3 +401,6 @@ BluetoothManager::Notify(const BluetoothSignal& aData)
NS_WARNING(warningMsg.get());
#endif
}
NS_IMPL_EVENT_HANDLER(BluetoothManager, enabled)
NS_IMPL_EVENT_HANDLER(BluetoothManager, disabled)

View File

@ -11,8 +11,9 @@
#include "BluetoothPropertyContainer.h"
#include "nsDOMEventTargetHelper.h"
#include "nsIDOMBluetoothManager.h"
#include "mozilla/Observer.h"
#include "nsIEventTarget.h"
#include "nsIObserver.h"
#include "mozilla/Observer.h"
BEGIN_BLUETOOTH_NAMESPACE
@ -22,10 +23,12 @@ class BluetoothManager : public nsDOMEventTargetHelper
, public nsIDOMBluetoothManager
, public BluetoothSignalObserver
, public BluetoothPropertyContainer
, public nsIObserver
{
public:
NS_DECL_ISUPPORTS_INHERITED
NS_DECL_NSIDOMBLUETOOTHMANAGER
NS_DECL_NSIOBSERVER
NS_FORWARD_NSIDOMEVENTTARGET(nsDOMEventTargetHelper::)
@ -39,12 +42,17 @@ public:
Create(nsPIDOMWindow* aWindow);
void Notify(const BluetoothSignal& aData);
virtual void SetPropertyByValue(const BluetoothNamedValue& aValue);
nsresult FireEnabledDisabledEvent();
private:
BluetoothManager(nsPIDOMWindow* aWindow);
~BluetoothManager();
nsresult HandleMozsettingChanged(const PRUnichar* aData);
bool mEnabled;
NS_DECL_EVENT_HANDLER(enabled)
NS_DECL_EVENT_HANDLER(disabled)
};
END_BLUETOOTH_NAMESPACE

View File

@ -30,8 +30,7 @@ NS_IMPL_ISUPPORTS1(BluetoothService, nsIObserver)
class ToggleBtAck : public nsRunnable
{
public:
ToggleBtAck(bool aEnabled) :
mEnabled(aEnabled)
ToggleBtAck(bool aEnabled) : mEnabled(aEnabled)
{
}
@ -61,7 +60,7 @@ class ToggleBtTask : public nsRunnable
{
public:
ToggleBtTask(bool aEnabled,
BluetoothReplyRunnable* aRunnable)
nsIRunnable* aRunnable)
: mEnabled(aEnabled),
mRunnable(aRunnable)
{
@ -95,17 +94,7 @@ public:
if (!mRunnable) {
return NS_OK;
}
// Reply will be deleted by the runnable after running on main thread
BluetoothReply* reply;
if (!replyError.IsEmpty()) {
reply = new BluetoothReply(BluetoothReplyError(replyError));
}
else {
reply = new BluetoothReply(BluetoothReplySuccess());
}
mRunnable->SetReply(reply);
if (NS_FAILED(NS_DispatchToMainThread(mRunnable))) {
NS_WARNING("Failed to dispatch to main thread!");
}
@ -115,7 +104,7 @@ public:
private:
bool mEnabled;
nsRefPtr<BluetoothReplyRunnable> mRunnable;
nsCOMPtr<nsIRunnable> mRunnable;
};
nsresult
@ -163,8 +152,7 @@ BluetoothService::DistributeSignal(const BluetoothSignal& signal)
}
nsresult
BluetoothService::StartStopBluetooth(BluetoothReplyRunnable* aResultRunnable,
bool aStart)
BluetoothService::StartStopBluetooth(nsIRunnable* aResultRunnable, bool aStart)
{
MOZ_ASSERT(NS_IsMainThread());
@ -187,13 +175,13 @@ BluetoothService::StartStopBluetooth(BluetoothReplyRunnable* aResultRunnable,
}
nsresult
BluetoothService::Start(BluetoothReplyRunnable* aResultRunnable)
BluetoothService::Start(nsIRunnable* aResultRunnable)
{
return StartStopBluetooth(aResultRunnable, true);
}
nsresult
BluetoothService::Stop(BluetoothReplyRunnable* aResultRunnable)
BluetoothService::Stop(nsIRunnable* aResultRunnable)
{
return StartStopBluetooth(aResultRunnable, false);
}

View File

@ -10,6 +10,7 @@
#include "nsThreadUtils.h"
#include "nsClassHashtable.h"
#include "nsIObserver.h"
#include "nsIRunnable.h"
#include "BluetoothCommon.h"
BEGIN_BLUETOOTH_NAMESPACE
@ -72,7 +73,7 @@ public:
* @return NS_OK on initialization starting correctly, NS_ERROR_FAILURE
* otherwise
*/
nsresult Start(BluetoothReplyRunnable* aResultRunnable);
nsresult Start(nsIRunnable* aResultRunnable);
/**
* Stop bluetooth services. Starts up any threads and connections that
@ -87,7 +88,7 @@ public:
* @return NS_OK on initialization starting correctly, NS_ERROR_FAILURE
* otherwise
*/
nsresult Stop(BluetoothReplyRunnable* aResultRunnable);
nsresult Stop(nsIRunnable* aResultRunnable);
/**
* Returns the BluetoothService singleton. Only to be called from main thread.
@ -249,8 +250,7 @@ protected:
{
}
nsresult StartStopBluetooth(BluetoothReplyRunnable* aResultRunnable,
bool aStart);
nsresult StartStopBluetooth(nsIRunnable* aResultRunnable, bool aStart);
// This function is implemented in platform-specific BluetoothServiceFactory
// files
static BluetoothService* Create();

View File

@ -9,11 +9,13 @@
interface nsIDOMDOMRequest;
interface nsIDOMBluetoothAdapter;
[scriptable, builtinclass, uuid(1442c310-8233-4670-8aa9-752ad673bae0)]
[scriptable, builtinclass, uuid(033d9774-f983-422f-ab6b-06a0b540d6f2)]
interface nsIDOMBluetoothManager : nsIDOMEventTarget
{
readonly attribute bool enabled;
nsIDOMDOMRequest getDefaultAdapter();
nsIDOMDOMRequest setEnabled(in boolean enabled);
attribute nsIDOMEventListener onenabled;
attribute nsIDOMEventListener ondisabled;
};