/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */ /* vim: set ts=2 et sw=2 tw=40: */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this file, * You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "base/basictypes.h" #include "BluetoothAdapter.h" #include "BluetoothDevice.h" #include "BluetoothDeviceEvent.h" #include "BluetoothService.h" #include "BluetoothTypes.h" #include "BluetoothReplyRunnable.h" #include "nsDOMClassInfo.h" #include "nsDOMEvent.h" #include "nsThreadUtils.h" #include "nsXPCOMCIDInternal.h" #include "nsIDOMDOMRequest.h" #include "mozilla/LazyIdleThread.h" #include "mozilla/Util.h" using namespace mozilla; USING_BLUETOOTH_NAMESPACE DOMCI_DATA(BluetoothAdapter, BluetoothAdapter) NS_IMPL_CYCLE_COLLECTION_CLASS(BluetoothAdapter) NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(BluetoothAdapter, nsDOMEventTargetHelper) NS_CYCLE_COLLECTION_TRAVERSE_EVENT_HANDLER(devicefound) NS_CYCLE_COLLECTION_TRAVERSE_EVENT_HANDLER(devicedisappeared) NS_CYCLE_COLLECTION_TRAVERSE_EVENT_HANDLER(propertychanged) NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(BluetoothAdapter, nsDOMEventTargetHelper) NS_CYCLE_COLLECTION_UNLINK_EVENT_HANDLER(devicefound) NS_CYCLE_COLLECTION_UNLINK_EVENT_HANDLER(devicedisappeared) NS_CYCLE_COLLECTION_UNLINK_EVENT_HANDLER(propertychanged) NS_IMPL_CYCLE_COLLECTION_UNLINK_END NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(BluetoothAdapter) NS_INTERFACE_MAP_ENTRY(nsIDOMBluetoothAdapter) NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(BluetoothAdapter) NS_INTERFACE_MAP_END_INHERITING(nsDOMEventTargetHelper) NS_IMPL_ADDREF_INHERITED(BluetoothAdapter, nsDOMEventTargetHelper) NS_IMPL_RELEASE_INHERITED(BluetoothAdapter, nsDOMEventTargetHelper) class GetPropertiesTask : public BluetoothReplyRunnable { public: GetPropertiesTask(BluetoothAdapter* aAdapter, nsIDOMDOMRequest* aReq) : BluetoothReplyRunnable(aReq), mAdapterPtr(aAdapter) { } bool ParseSuccessfulReply(jsval* aValue) { const InfallibleTArray& values = mReply->get_BluetoothReplySuccess().value().get_ArrayOfBluetoothNamedValue(); for (uint32_t i = 0; i < values.Length(); ++i) { mAdapterPtr->SetPropertyByValue(values[i]); } *aValue = JSVAL_VOID; return true; } void ReleaseMembers() { BluetoothReplyRunnable::ReleaseMembers(); mAdapterPtr = nsnull; } private: nsRefPtr mAdapterPtr; }; BluetoothAdapter::~BluetoothAdapter() { BluetoothService* bs = BluetoothService::Get(); // We can be null on shutdown, where this might happen if (bs) { if (NS_FAILED(bs->UnregisterBluetoothSignalHandler(mPath, this))) { NS_WARNING("Failed to unregister object with observer!"); } } } void BluetoothAdapter::SetPropertyByValue(const BluetoothNamedValue& aValue) { const nsString& name = aValue.name(); const BluetoothValue& value = aValue.value(); if (name.EqualsLiteral("Name")) { mName = value.get_nsString(); } else if (name.EqualsLiteral("Address")) { mAddress = value.get_nsString(); } else if (name.EqualsLiteral("Enabled")) { mEnabled = value.get_bool(); } else if (name.EqualsLiteral("Discoverable")) { mDiscoverable = value.get_bool(); } else if (name.EqualsLiteral("Pairable")) { mPairable = value.get_bool(); } else if (name.EqualsLiteral("Powered")) { mPowered = value.get_bool(); } else if (name.EqualsLiteral("PairableTimeout")) { mPairableTimeout = value.get_uint32_t(); } else if (name.EqualsLiteral("DiscoverableTimeout")) { mDiscoverableTimeout = value.get_uint32_t(); } else if (name.EqualsLiteral("Class")) { mClass = value.get_uint32_t(); } else if (name.EqualsLiteral("UUIDs")) { mUuids = value.get_ArrayOfnsString(); } else { #ifdef DEBUG nsCString warningMsg; warningMsg.AssignLiteral("Not handling adapter property: "); warningMsg.Append(NS_ConvertUTF16toUTF8(name)); NS_WARNING(warningMsg.get()); #endif } } // static already_AddRefed BluetoothAdapter::Create(nsPIDOMWindow* aOwner, const nsAString& aPath) { // Make sure we at least have a path NS_ASSERTION(!aPath.IsEmpty(), "Adapter created with empty path!"); BluetoothService* bs = BluetoothService::Get(); MOZ_ASSERT(bs); nsRefPtr adapter = new BluetoothAdapter(aPath); adapter->BindToOwner(aOwner); if (NS_FAILED(bs->RegisterBluetoothSignalHandler(aPath, adapter))) { NS_WARNING("Failed to register object with observer!"); return nsnull; } return adapter.forget(); } void BluetoothAdapter::Notify(const BluetoothSignal& aData) { if (aData.name().EqualsLiteral("DeviceFound")) { nsRefPtr d = BluetoothDevice::Create(GetOwner(), aData); nsRefPtr e = BluetoothDeviceEvent::Create(d); e->Dispatch(ToIDOMEventTarget(), NS_LITERAL_STRING("devicefound")); } else { #ifdef DEBUG nsCString warningMsg; warningMsg.AssignLiteral("Not handling manager signal: "); warningMsg.Append(NS_ConvertUTF16toUTF8(aData.name())); NS_WARNING(warningMsg.get()); #endif } } nsresult BluetoothAdapter::StartStopDiscovery(bool aStart, nsIDOMDOMRequest** aRequest) { BluetoothService* bs = BluetoothService::Get(); MOZ_ASSERT(bs); nsCOMPtr rs = do_GetService("@mozilla.org/dom/dom-request-service;1"); if (!rs) { NS_WARNING("No DOMRequest Service!"); return NS_ERROR_FAILURE; } nsCOMPtr req; nsresult rv = rs->CreateRequest(GetOwner(), getter_AddRefs(req)); if (NS_FAILED(rv)) { NS_WARNING("Can't create DOMRequest!"); return NS_ERROR_FAILURE; } nsRefPtr results = new BluetoothVoidReplyRunnable(req); if (aStart) { rv = bs->StartDiscoveryInternal(mPath, results); } else { rv = bs->StopDiscoveryInternal(mPath, results); } if (NS_FAILED(rv)) { NS_WARNING("Starting discovery failed!"); return NS_ERROR_FAILURE; } req.forget(aRequest); // mDiscovering is not set here, we'll get a Property update from our external // protocol to tell us that it's been set. return NS_OK; } NS_IMETHODIMP BluetoothAdapter::StartDiscovery(nsIDOMDOMRequest** aRequest) { return StartStopDiscovery(true, aRequest); } NS_IMETHODIMP BluetoothAdapter::StopDiscovery(nsIDOMDOMRequest** aRequest) { return StartStopDiscovery(false, aRequest); } NS_IMETHODIMP BluetoothAdapter::GetEnabled(bool* aEnabled) { *aEnabled = mEnabled; return NS_OK; } NS_IMETHODIMP BluetoothAdapter::GetAddress(nsAString& aAddress) { aAddress = mAddress; return NS_OK; } NS_IMETHODIMP BluetoothAdapter::GetAdapterClass(PRUint32* aClass) { *aClass = mClass; return NS_OK; } NS_IMETHODIMP BluetoothAdapter::GetDiscovering(bool* aDiscovering) { *aDiscovering = mDiscovering; return NS_OK; } NS_IMETHODIMP BluetoothAdapter::GetName(nsAString& aName) { aName = mName; return NS_OK; } NS_IMETHODIMP BluetoothAdapter::GetDiscoverable(bool* aDiscoverable) { *aDiscoverable = mDiscoverable; return NS_OK; } NS_IMETHODIMP BluetoothAdapter::GetDiscoverableTimeout(PRUint32* aDiscoverableTimeout) { *aDiscoverableTimeout = mDiscoverableTimeout; return NS_OK; } NS_IMETHODIMP BluetoothAdapter::GetDevices(JSContext* aCx, jsval* aDevices) { NS_WARNING("GetDevices not yet implemented."); return NS_OK; } NS_IMPL_EVENT_HANDLER(BluetoothAdapter, propertychanged) NS_IMPL_EVENT_HANDLER(BluetoothAdapter, devicefound) NS_IMPL_EVENT_HANDLER(BluetoothAdapter, devicedisappeared)