1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/dom/bluetooth/BluetoothDevice.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,243 @@ 1.4 +/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */ 1.5 +/* vim: set ts=2 et sw=2 tw=80: */ 1.6 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this file, 1.8 + * You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.9 + 1.10 +#include "base/basictypes.h" 1.11 +#include "BluetoothDevice.h" 1.12 +#include "BluetoothReplyRunnable.h" 1.13 +#include "BluetoothService.h" 1.14 +#include "BluetoothUtils.h" 1.15 + 1.16 +#include "nsDOMClassInfo.h" 1.17 +#include "nsTArrayHelpers.h" 1.18 + 1.19 +#include "mozilla/dom/bluetooth/BluetoothTypes.h" 1.20 +#include "mozilla/dom/BluetoothDeviceBinding.h" 1.21 + 1.22 +USING_BLUETOOTH_NAMESPACE 1.23 + 1.24 +DOMCI_DATA(BluetoothDevice, BluetoothDevice) 1.25 + 1.26 +NS_IMPL_CYCLE_COLLECTION_CLASS(BluetoothDevice) 1.27 + 1.28 +NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(BluetoothDevice, 1.29 + DOMEventTargetHelper) 1.30 + NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mJsUuids) 1.31 + NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mJsServices) 1.32 +NS_IMPL_CYCLE_COLLECTION_TRACE_END 1.33 + 1.34 +NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(BluetoothDevice, 1.35 + DOMEventTargetHelper) 1.36 + NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS 1.37 +NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END 1.38 + 1.39 +NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(BluetoothDevice, 1.40 + DOMEventTargetHelper) 1.41 + tmp->Unroot(); 1.42 +NS_IMPL_CYCLE_COLLECTION_UNLINK_END 1.43 + 1.44 +NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(BluetoothDevice) 1.45 +NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper) 1.46 + 1.47 +NS_IMPL_ADDREF_INHERITED(BluetoothDevice, DOMEventTargetHelper) 1.48 +NS_IMPL_RELEASE_INHERITED(BluetoothDevice, DOMEventTargetHelper) 1.49 + 1.50 +BluetoothDevice::BluetoothDevice(nsPIDOMWindow* aWindow, 1.51 + const nsAString& aAdapterPath, 1.52 + const BluetoothValue& aValue) 1.53 + : DOMEventTargetHelper(aWindow) 1.54 + , BluetoothPropertyContainer(BluetoothObjectType::TYPE_DEVICE) 1.55 + , mJsUuids(nullptr) 1.56 + , mJsServices(nullptr) 1.57 + , mAdapterPath(aAdapterPath) 1.58 + , mIsRooted(false) 1.59 +{ 1.60 + MOZ_ASSERT(aWindow); 1.61 + MOZ_ASSERT(IsDOMBinding()); 1.62 + 1.63 + const InfallibleTArray<BluetoothNamedValue>& values = 1.64 + aValue.get_ArrayOfBluetoothNamedValue(); 1.65 + for (uint32_t i = 0; i < values.Length(); ++i) { 1.66 + SetPropertyByValue(values[i]); 1.67 + } 1.68 + 1.69 + BluetoothService* bs = BluetoothService::Get(); 1.70 + NS_ENSURE_TRUE_VOID(bs); 1.71 + bs->RegisterBluetoothSignalHandler(mAddress, this); 1.72 +} 1.73 + 1.74 +BluetoothDevice::~BluetoothDevice() 1.75 +{ 1.76 + BluetoothService* bs = BluetoothService::Get(); 1.77 + // bs can be null on shutdown, where destruction might happen. 1.78 + NS_ENSURE_TRUE_VOID(bs); 1.79 + bs->UnregisterBluetoothSignalHandler(mAddress, this); 1.80 + Unroot(); 1.81 +} 1.82 + 1.83 +void 1.84 +BluetoothDevice::DisconnectFromOwner() 1.85 +{ 1.86 + DOMEventTargetHelper::DisconnectFromOwner(); 1.87 + 1.88 + BluetoothService* bs = BluetoothService::Get(); 1.89 + NS_ENSURE_TRUE_VOID(bs); 1.90 + bs->UnregisterBluetoothSignalHandler(mAddress, this); 1.91 +} 1.92 + 1.93 +void 1.94 +BluetoothDevice::Root() 1.95 +{ 1.96 + if (!mIsRooted) { 1.97 + mozilla::HoldJSObjects(this); 1.98 + mIsRooted = true; 1.99 + } 1.100 +} 1.101 + 1.102 +void 1.103 +BluetoothDevice::Unroot() 1.104 +{ 1.105 + if (mIsRooted) { 1.106 + mJsUuids = nullptr; 1.107 + mJsServices = nullptr; 1.108 + mozilla::DropJSObjects(this); 1.109 + mIsRooted = false; 1.110 + } 1.111 +} 1.112 + 1.113 +void 1.114 +BluetoothDevice::SetPropertyByValue(const BluetoothNamedValue& aValue) 1.115 +{ 1.116 + const nsString& name = aValue.name(); 1.117 + const BluetoothValue& value = aValue.value(); 1.118 + if (name.EqualsLiteral("Name")) { 1.119 + mName = value.get_nsString(); 1.120 + } else if (name.EqualsLiteral("Path")) { 1.121 + MOZ_ASSERT(value.get_nsString().Length() > 0); 1.122 + mPath = value.get_nsString(); 1.123 + } else if (name.EqualsLiteral("Address")) { 1.124 + mAddress = value.get_nsString(); 1.125 + } else if (name.EqualsLiteral("Class")) { 1.126 + mClass = value.get_uint32_t(); 1.127 + } else if (name.EqualsLiteral("Icon")) { 1.128 + mIcon = value.get_nsString(); 1.129 + } else if (name.EqualsLiteral("Connected")) { 1.130 + mConnected = value.get_bool(); 1.131 + } else if (name.EqualsLiteral("Paired")) { 1.132 + mPaired = value.get_bool(); 1.133 + } else if (name.EqualsLiteral("UUIDs")) { 1.134 + mUuids = value.get_ArrayOfnsString(); 1.135 + nsresult rv; 1.136 + nsIScriptContext* sc = GetContextForEventHandlers(&rv); 1.137 + NS_ENSURE_SUCCESS_VOID(rv); 1.138 + NS_ENSURE_TRUE_VOID(sc); 1.139 + 1.140 + AutoPushJSContext cx(sc->GetNativeContext()); 1.141 + 1.142 + JS::Rooted<JSObject*> uuids(cx); 1.143 + if (NS_FAILED(nsTArrayToJSArray(cx, mUuids, uuids.address()))) { 1.144 + BT_WARNING("Cannot set JS UUIDs object!"); 1.145 + return; 1.146 + } 1.147 + mJsUuids = uuids; 1.148 + Root(); 1.149 + } else if (name.EqualsLiteral("Services")) { 1.150 + mServices = value.get_ArrayOfnsString(); 1.151 + nsresult rv; 1.152 + nsIScriptContext* sc = GetContextForEventHandlers(&rv); 1.153 + NS_ENSURE_SUCCESS_VOID(rv); 1.154 + NS_ENSURE_TRUE_VOID(sc); 1.155 + 1.156 + AutoPushJSContext cx(sc->GetNativeContext()); 1.157 + 1.158 + JS::Rooted<JSObject*> services(cx); 1.159 + if (NS_FAILED(nsTArrayToJSArray(cx, mServices, services.address()))) { 1.160 + BT_WARNING("Cannot set JS Services object!"); 1.161 + return; 1.162 + } 1.163 + mJsServices = services; 1.164 + Root(); 1.165 + } else { 1.166 + nsCString warningMsg; 1.167 + warningMsg.AssignLiteral("Not handling device property: "); 1.168 + warningMsg.Append(NS_ConvertUTF16toUTF8(name)); 1.169 + BT_WARNING(warningMsg.get()); 1.170 + } 1.171 +} 1.172 + 1.173 +// static 1.174 +already_AddRefed<BluetoothDevice> 1.175 +BluetoothDevice::Create(nsPIDOMWindow* aWindow, 1.176 + const nsAString& aAdapterPath, 1.177 + const BluetoothValue& aValue) 1.178 +{ 1.179 + MOZ_ASSERT(NS_IsMainThread()); 1.180 + MOZ_ASSERT(aWindow); 1.181 + 1.182 + nsRefPtr<BluetoothDevice> device = 1.183 + new BluetoothDevice(aWindow, aAdapterPath, aValue); 1.184 + return device.forget(); 1.185 +} 1.186 + 1.187 +void 1.188 +BluetoothDevice::Notify(const BluetoothSignal& aData) 1.189 +{ 1.190 + BT_LOGD("[D] %s: %s", __FUNCTION__, NS_ConvertUTF16toUTF8(aData.name()).get()); 1.191 + 1.192 + BluetoothValue v = aData.value(); 1.193 + if (aData.name().EqualsLiteral("PropertyChanged")) { 1.194 + MOZ_ASSERT(v.type() == BluetoothValue::TArrayOfBluetoothNamedValue); 1.195 + 1.196 + const InfallibleTArray<BluetoothNamedValue>& arr = 1.197 + v.get_ArrayOfBluetoothNamedValue(); 1.198 + 1.199 + for (uint32_t i = 0, propCount = arr.Length(); i < propCount; ++i) { 1.200 + SetPropertyByValue(arr[i]); 1.201 + } 1.202 + } else { 1.203 +#ifdef DEBUG 1.204 + nsCString warningMsg; 1.205 + warningMsg.AssignLiteral("Not handling device signal: "); 1.206 + warningMsg.Append(NS_ConvertUTF16toUTF8(aData.name())); 1.207 + BT_WARNING(warningMsg.get()); 1.208 +#endif 1.209 + } 1.210 +} 1.211 + 1.212 +void 1.213 +BluetoothDevice::GetUuids(JSContext* aContext, 1.214 + JS::MutableHandle<JS::Value> aUuids, 1.215 + ErrorResult& aRv) 1.216 +{ 1.217 + if (!mJsUuids) { 1.218 + BT_WARNING("UUIDs not yet set!"); 1.219 + aRv.Throw(NS_ERROR_FAILURE); 1.220 + return; 1.221 + } 1.222 + 1.223 + JS::ExposeObjectToActiveJS(mJsUuids); 1.224 + aUuids.setObject(*mJsUuids); 1.225 +} 1.226 + 1.227 +void 1.228 +BluetoothDevice::GetServices(JSContext* aCx, 1.229 + JS::MutableHandle<JS::Value> aServices, 1.230 + ErrorResult& aRv) 1.231 +{ 1.232 + if (!mJsServices) { 1.233 + BT_WARNING("Services not yet set!"); 1.234 + aRv.Throw(NS_ERROR_FAILURE); 1.235 + return; 1.236 + } 1.237 + 1.238 + JS::ExposeObjectToActiveJS(mJsServices); 1.239 + aServices.setObject(*mJsServices); 1.240 +} 1.241 + 1.242 +JSObject* 1.243 +BluetoothDevice::WrapObject(JSContext* aContext) 1.244 +{ 1.245 + return BluetoothDeviceBinding::Wrap(aContext, this); 1.246 +}