michael@0: /* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */ michael@0: /* vim: set ts=2 et sw=2 tw=80: */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this file, michael@0: * You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #include "base/basictypes.h" michael@0: #include "BluetoothManager.h" michael@0: #include "BluetoothCommon.h" michael@0: #include "BluetoothAdapter.h" michael@0: #include "BluetoothService.h" michael@0: #include "BluetoothReplyRunnable.h" michael@0: michael@0: #include "DOMRequest.h" michael@0: #include "nsContentUtils.h" michael@0: #include "nsDOMClassInfo.h" michael@0: #include "nsIPermissionManager.h" michael@0: #include "nsThreadUtils.h" michael@0: #include "mozilla/dom/bluetooth/BluetoothTypes.h" michael@0: #include "mozilla/dom/BluetoothManagerBinding.h" michael@0: michael@0: using namespace mozilla; michael@0: michael@0: USING_BLUETOOTH_NAMESPACE michael@0: michael@0: // QueryInterface implementation for BluetoothManager michael@0: NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(BluetoothManager) michael@0: NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper) michael@0: michael@0: NS_IMPL_ADDREF_INHERITED(BluetoothManager, DOMEventTargetHelper) michael@0: NS_IMPL_RELEASE_INHERITED(BluetoothManager, DOMEventTargetHelper) michael@0: michael@0: class GetAdapterTask : public BluetoothReplyRunnable michael@0: { michael@0: public: michael@0: GetAdapterTask(BluetoothManager* aManager, michael@0: nsIDOMDOMRequest* aReq) : michael@0: BluetoothReplyRunnable(aReq), michael@0: mManagerPtr(aManager) michael@0: { michael@0: } michael@0: michael@0: bool michael@0: ParseSuccessfulReply(JS::MutableHandle aValue) michael@0: { michael@0: aValue.setUndefined(); michael@0: michael@0: const BluetoothValue& v = mReply->get_BluetoothReplySuccess().value(); michael@0: if (v.type() != BluetoothValue::TArrayOfBluetoothNamedValue) { michael@0: BT_WARNING("Not a BluetoothNamedValue array!"); michael@0: SetError(NS_LITERAL_STRING("BluetoothReplyTypeError")); michael@0: return false; michael@0: } michael@0: michael@0: if (!mManagerPtr->GetOwner()) { michael@0: BT_WARNING("Bluetooth manager was disconnected from owner window."); michael@0: michael@0: // Stop to create adapter since owner window of Bluetooth manager was michael@0: // gone. These is no need to create a DOMEvent target which has no owner michael@0: // to reply to. michael@0: return false; michael@0: } michael@0: michael@0: const InfallibleTArray& values = michael@0: v.get_ArrayOfBluetoothNamedValue(); michael@0: nsRefPtr adapter = michael@0: BluetoothAdapter::Create(mManagerPtr->GetOwner(), values); michael@0: michael@0: nsresult rv; michael@0: nsIScriptContext* sc = mManagerPtr->GetContextForEventHandlers(&rv); michael@0: if (!sc) { michael@0: BT_WARNING("Cannot create script context!"); michael@0: SetError(NS_LITERAL_STRING("BluetoothScriptContextError")); michael@0: return false; michael@0: } michael@0: michael@0: AutoPushJSContext cx(sc->GetNativeContext()); michael@0: michael@0: JS::Rooted scope(cx, sc->GetWindowProxy()); michael@0: JSAutoCompartment ac(cx, scope); michael@0: rv = nsContentUtils::WrapNative(cx, adapter, aValue); michael@0: if (NS_FAILED(rv)) { michael@0: BT_WARNING("Cannot create native object!"); michael@0: SetError(NS_LITERAL_STRING("BluetoothNativeObjectError")); michael@0: return false; michael@0: } michael@0: michael@0: return true; michael@0: } michael@0: michael@0: void michael@0: ReleaseMembers() michael@0: { michael@0: BluetoothReplyRunnable::ReleaseMembers(); michael@0: mManagerPtr = nullptr; michael@0: } michael@0: michael@0: private: michael@0: nsRefPtr mManagerPtr; michael@0: }; michael@0: michael@0: BluetoothManager::BluetoothManager(nsPIDOMWindow *aWindow) michael@0: : DOMEventTargetHelper(aWindow) michael@0: , BluetoothPropertyContainer(BluetoothObjectType::TYPE_MANAGER) michael@0: { michael@0: MOZ_ASSERT(aWindow); michael@0: MOZ_ASSERT(IsDOMBinding()); michael@0: michael@0: mPath.AssignLiteral("/"); michael@0: michael@0: BluetoothService* bs = BluetoothService::Get(); michael@0: NS_ENSURE_TRUE_VOID(bs); michael@0: bs->RegisterBluetoothSignalHandler(NS_LITERAL_STRING(KEY_MANAGER), this); michael@0: } michael@0: michael@0: BluetoothManager::~BluetoothManager() michael@0: { michael@0: BluetoothService* bs = BluetoothService::Get(); michael@0: NS_ENSURE_TRUE_VOID(bs); michael@0: bs->UnregisterBluetoothSignalHandler(NS_LITERAL_STRING(KEY_MANAGER), this); michael@0: } michael@0: michael@0: void michael@0: BluetoothManager::DisconnectFromOwner() michael@0: { michael@0: DOMEventTargetHelper::DisconnectFromOwner(); michael@0: michael@0: BluetoothService* bs = BluetoothService::Get(); michael@0: NS_ENSURE_TRUE_VOID(bs); michael@0: bs->UnregisterBluetoothSignalHandler(NS_LITERAL_STRING(KEY_MANAGER), this); michael@0: } michael@0: michael@0: void michael@0: BluetoothManager::SetPropertyByValue(const BluetoothNamedValue& aValue) michael@0: { michael@0: #ifdef DEBUG michael@0: const nsString& name = aValue.name(); michael@0: nsCString warningMsg; michael@0: warningMsg.AssignLiteral("Not handling manager property: "); michael@0: warningMsg.Append(NS_ConvertUTF16toUTF8(name)); michael@0: BT_WARNING(warningMsg.get()); michael@0: #endif michael@0: } michael@0: michael@0: bool michael@0: BluetoothManager::GetEnabled(ErrorResult& aRv) michael@0: { michael@0: BluetoothService* bs = BluetoothService::Get(); michael@0: if (!bs) { michael@0: aRv.Throw(NS_ERROR_FAILURE); michael@0: return false; michael@0: } michael@0: michael@0: return bs->IsEnabled(); michael@0: } michael@0: michael@0: already_AddRefed michael@0: BluetoothManager::GetDefaultAdapter(ErrorResult& aRv) michael@0: { michael@0: nsCOMPtr win = GetOwner(); michael@0: if (!win) { michael@0: aRv.Throw(NS_ERROR_FAILURE); michael@0: return nullptr; michael@0: } michael@0: michael@0: nsRefPtr request = new DOMRequest(win); michael@0: nsRefPtr results = michael@0: new GetAdapterTask(this, request); michael@0: michael@0: BluetoothService* bs = BluetoothService::Get(); michael@0: if (!bs) { michael@0: aRv.Throw(NS_ERROR_FAILURE); michael@0: return nullptr; michael@0: } michael@0: michael@0: nsresult rv = bs->GetDefaultAdapterPathInternal(results); michael@0: if (NS_FAILED(rv)) { michael@0: aRv.Throw(rv); michael@0: return nullptr; michael@0: } michael@0: michael@0: return request.forget(); michael@0: } michael@0: michael@0: // static michael@0: already_AddRefed michael@0: BluetoothManager::Create(nsPIDOMWindow* aWindow) michael@0: { michael@0: MOZ_ASSERT(NS_IsMainThread()); michael@0: MOZ_ASSERT(aWindow); michael@0: michael@0: nsRefPtr manager = new BluetoothManager(aWindow); michael@0: return manager.forget(); michael@0: } michael@0: michael@0: // static michael@0: bool michael@0: BluetoothManager::CheckPermission(nsPIDOMWindow* aWindow) michael@0: { michael@0: NS_ASSERTION(aWindow, "Null pointer!"); michael@0: michael@0: nsCOMPtr permMgr = michael@0: do_GetService(NS_PERMISSIONMANAGER_CONTRACTID); michael@0: NS_ENSURE_TRUE(permMgr, false); michael@0: michael@0: uint32_t permission; michael@0: nsresult rv = michael@0: permMgr->TestPermissionFromWindow(aWindow, "bluetooth", michael@0: &permission); michael@0: NS_ENSURE_SUCCESS(rv, false); michael@0: michael@0: return permission == nsIPermissionManager::ALLOW_ACTION; michael@0: } michael@0: michael@0: void michael@0: BluetoothManager::Notify(const BluetoothSignal& aData) michael@0: { michael@0: BT_LOGD("[M] %s: %s", __FUNCTION__, NS_ConvertUTF16toUTF8(aData.name()).get()); michael@0: michael@0: if (aData.name().EqualsLiteral("AdapterAdded")) { michael@0: DispatchTrustedEvent(NS_LITERAL_STRING("adapteradded")); michael@0: } else if (aData.name().EqualsLiteral("Enabled")) { michael@0: DispatchTrustedEvent(NS_LITERAL_STRING("enabled")); michael@0: } else if (aData.name().EqualsLiteral("Disabled")) { michael@0: DispatchTrustedEvent(NS_LITERAL_STRING("disabled")); michael@0: } else { michael@0: #ifdef DEBUG michael@0: nsCString warningMsg; michael@0: warningMsg.AssignLiteral("Not handling manager signal: "); michael@0: warningMsg.Append(NS_ConvertUTF16toUTF8(aData.name())); michael@0: BT_WARNING(warningMsg.get()); michael@0: #endif michael@0: } michael@0: } michael@0: michael@0: bool michael@0: BluetoothManager::IsConnected(uint16_t aProfileId, ErrorResult& aRv) michael@0: { michael@0: BluetoothService* bs = BluetoothService::Get(); michael@0: if (!bs) { michael@0: aRv.Throw(NS_ERROR_FAILURE); michael@0: return false; michael@0: } michael@0: michael@0: return bs->IsConnected(aProfileId); michael@0: } michael@0: michael@0: JSObject* michael@0: BluetoothManager::WrapObject(JSContext* aCx) michael@0: { michael@0: return BluetoothManagerBinding::Wrap(aCx, this); michael@0: }