1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/dom/bluetooth/BluetoothHidManager.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,270 @@ 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 + 1.12 +#include "BluetoothHidManager.h" 1.13 + 1.14 +#include "BluetoothCommon.h" 1.15 +#include "BluetoothService.h" 1.16 +#include "BluetoothUtils.h" 1.17 + 1.18 +#include "mozilla/dom/bluetooth/BluetoothTypes.h" 1.19 +#include "mozilla/Services.h" 1.20 +#include "mozilla/StaticPtr.h" 1.21 +#include "nsIObserverService.h" 1.22 +#include "MainThreadUtils.h" 1.23 + 1.24 +using namespace mozilla; 1.25 +USING_BLUETOOTH_NAMESPACE 1.26 + 1.27 +namespace { 1.28 + StaticRefPtr<BluetoothHidManager> sBluetoothHidManager; 1.29 + bool sInShutdown = false; 1.30 +} // anonymous namespace 1.31 + 1.32 +NS_IMETHODIMP 1.33 +BluetoothHidManager::Observe(nsISupports* aSubject, 1.34 + const char* aTopic, 1.35 + const char16_t* aData) 1.36 +{ 1.37 + MOZ_ASSERT(sBluetoothHidManager); 1.38 + 1.39 + if (!strcmp(aTopic, NS_XPCOM_SHUTDOWN_OBSERVER_ID)) { 1.40 + HandleShutdown(); 1.41 + return NS_OK; 1.42 + } 1.43 + 1.44 + MOZ_ASSERT(false, "BluetoothHidManager got unexpected topic!"); 1.45 + return NS_ERROR_UNEXPECTED; 1.46 +} 1.47 + 1.48 +BluetoothHidManager::BluetoothHidManager() 1.49 +{ 1.50 + Reset(); 1.51 +} 1.52 + 1.53 +void 1.54 +BluetoothHidManager::Reset() 1.55 +{ 1.56 + mConnected = false; 1.57 + mController = nullptr; 1.58 +} 1.59 + 1.60 +bool 1.61 +BluetoothHidManager::Init() 1.62 +{ 1.63 + MOZ_ASSERT(NS_IsMainThread()); 1.64 + 1.65 + nsCOMPtr<nsIObserverService> obs = services::GetObserverService(); 1.66 + NS_ENSURE_TRUE(obs, false); 1.67 + if (NS_FAILED(obs->AddObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, false))) { 1.68 + BT_WARNING("Failed to add shutdown observer!"); 1.69 + return false; 1.70 + } 1.71 + 1.72 + return true; 1.73 +} 1.74 + 1.75 +BluetoothHidManager::~BluetoothHidManager() 1.76 +{ 1.77 + nsCOMPtr<nsIObserverService> obs = services::GetObserverService(); 1.78 + NS_ENSURE_TRUE_VOID(obs); 1.79 + if (NS_FAILED(obs->RemoveObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID))) { 1.80 + BT_WARNING("Failed to remove shutdown observer!"); 1.81 + } 1.82 +} 1.83 + 1.84 +//static 1.85 +BluetoothHidManager* 1.86 +BluetoothHidManager::Get() 1.87 +{ 1.88 + MOZ_ASSERT(NS_IsMainThread()); 1.89 + 1.90 + // If we already exist, exit early 1.91 + if (sBluetoothHidManager) { 1.92 + return sBluetoothHidManager; 1.93 + } 1.94 + 1.95 + // If we're in shutdown, don't create a new instance 1.96 + NS_ENSURE_FALSE(sInShutdown, nullptr); 1.97 + 1.98 + // Create a new instance, register, and return 1.99 + BluetoothHidManager* manager = new BluetoothHidManager(); 1.100 + NS_ENSURE_TRUE(manager->Init(), nullptr); 1.101 + 1.102 + sBluetoothHidManager = manager; 1.103 + return sBluetoothHidManager; 1.104 +} 1.105 + 1.106 +void 1.107 +BluetoothHidManager::HandleShutdown() 1.108 +{ 1.109 + MOZ_ASSERT(NS_IsMainThread()); 1.110 + sInShutdown = true; 1.111 + Disconnect(nullptr); 1.112 + sBluetoothHidManager = nullptr; 1.113 +} 1.114 + 1.115 +void 1.116 +BluetoothHidManager::Connect(const nsAString& aDeviceAddress, 1.117 + BluetoothProfileController* aController) 1.118 +{ 1.119 + MOZ_ASSERT(NS_IsMainThread()); 1.120 + MOZ_ASSERT(!aDeviceAddress.IsEmpty()); 1.121 + MOZ_ASSERT(aController && !mController); 1.122 + 1.123 + BluetoothService* bs = BluetoothService::Get(); 1.124 + if (!bs || sInShutdown) { 1.125 + aController->NotifyCompletion(NS_LITERAL_STRING(ERR_NO_AVAILABLE_RESOURCE)); 1.126 + return; 1.127 + } 1.128 + 1.129 + if (mConnected) { 1.130 + aController->NotifyCompletion(NS_LITERAL_STRING(ERR_ALREADY_CONNECTED)); 1.131 + return; 1.132 + } 1.133 + 1.134 + mDeviceAddress = aDeviceAddress; 1.135 + mController = aController; 1.136 + 1.137 + if (NS_FAILED(bs->SendInputMessage(aDeviceAddress, 1.138 + NS_LITERAL_STRING("Connect")))) { 1.139 + aController->NotifyCompletion(NS_LITERAL_STRING(ERR_NO_AVAILABLE_RESOURCE)); 1.140 + return; 1.141 + } 1.142 +} 1.143 + 1.144 +void 1.145 +BluetoothHidManager::Disconnect(BluetoothProfileController* aController) 1.146 +{ 1.147 + MOZ_ASSERT(NS_IsMainThread()); 1.148 + 1.149 + BluetoothService* bs = BluetoothService::Get(); 1.150 + if (!bs) { 1.151 + if (aController) { 1.152 + aController->NotifyCompletion(NS_LITERAL_STRING(ERR_NO_AVAILABLE_RESOURCE)); 1.153 + } 1.154 + return; 1.155 + } 1.156 + 1.157 + if (!mConnected) { 1.158 + if (aController) { 1.159 + aController->NotifyCompletion(NS_LITERAL_STRING(ERR_ALREADY_DISCONNECTED)); 1.160 + } 1.161 + return; 1.162 + } 1.163 + 1.164 + MOZ_ASSERT(!mDeviceAddress.IsEmpty()); 1.165 + MOZ_ASSERT(!mController); 1.166 + 1.167 + mController = aController; 1.168 + 1.169 + if (NS_FAILED(bs->SendInputMessage(mDeviceAddress, 1.170 + NS_LITERAL_STRING("Disconnect")))) { 1.171 + aController->NotifyCompletion(NS_LITERAL_STRING(ERR_NO_AVAILABLE_RESOURCE)); 1.172 + return; 1.173 + } 1.174 +} 1.175 + 1.176 +void 1.177 +BluetoothHidManager::OnConnect(const nsAString& aErrorStr) 1.178 +{ 1.179 + MOZ_ASSERT(NS_IsMainThread()); 1.180 + 1.181 + /** 1.182 + * On the one hand, notify the controller that we've done for outbound 1.183 + * connections. On the other hand, we do nothing for inbound connections. 1.184 + */ 1.185 + NS_ENSURE_TRUE_VOID(mController); 1.186 + 1.187 + nsRefPtr<BluetoothProfileController> controller = mController.forget(); 1.188 + controller->NotifyCompletion(aErrorStr); 1.189 +} 1.190 + 1.191 +void 1.192 +BluetoothHidManager::OnDisconnect(const nsAString& aErrorStr) 1.193 +{ 1.194 + MOZ_ASSERT(NS_IsMainThread()); 1.195 + 1.196 + /** 1.197 + * On the one hand, notify the controller that we've done for outbound 1.198 + * connections. On the other hand, we do nothing for inbound connections. 1.199 + */ 1.200 + NS_ENSURE_TRUE_VOID(mController); 1.201 + 1.202 + nsRefPtr<BluetoothProfileController> controller = mController.forget(); 1.203 + controller->NotifyCompletion(aErrorStr); 1.204 +} 1.205 + 1.206 +bool 1.207 +BluetoothHidManager::IsConnected() 1.208 +{ 1.209 + return mConnected; 1.210 +} 1.211 + 1.212 +void 1.213 +BluetoothHidManager::HandleInputPropertyChanged(const BluetoothSignal& aSignal) 1.214 +{ 1.215 + MOZ_ASSERT(NS_IsMainThread()); 1.216 + MOZ_ASSERT(aSignal.value().type() == BluetoothValue::TArrayOfBluetoothNamedValue); 1.217 + 1.218 + const InfallibleTArray<BluetoothNamedValue>& arr = 1.219 + aSignal.value().get_ArrayOfBluetoothNamedValue(); 1.220 + MOZ_ASSERT(arr.Length() == 1); 1.221 + 1.222 + const nsString& name = arr[0].name(); 1.223 + const BluetoothValue& value = arr[0].value(); 1.224 + 1.225 + if (name.EqualsLiteral("Connected")) { 1.226 + MOZ_ASSERT(value.type() == BluetoothValue::Tbool); 1.227 + MOZ_ASSERT(mConnected != value.get_bool()); 1.228 + 1.229 + mConnected = value.get_bool(); 1.230 + NotifyStatusChanged(); 1.231 + if (mConnected) { 1.232 + OnConnect(EmptyString()); 1.233 + } else { 1.234 + OnDisconnect(EmptyString()); 1.235 + } 1.236 + } 1.237 +} 1.238 + 1.239 +void 1.240 +BluetoothHidManager::NotifyStatusChanged() 1.241 +{ 1.242 + MOZ_ASSERT(NS_IsMainThread()); 1.243 + 1.244 + NS_NAMED_LITERAL_STRING(type, BLUETOOTH_HID_STATUS_CHANGED_ID); 1.245 + InfallibleTArray<BluetoothNamedValue> parameters; 1.246 + 1.247 + BT_APPEND_NAMED_VALUE(parameters, "connected", mConnected); 1.248 + BT_APPEND_NAMED_VALUE(parameters, "address", mDeviceAddress); 1.249 + 1.250 + BT_ENSURE_TRUE_VOID_BROADCAST_SYSMSG(type, parameters); 1.251 +} 1.252 + 1.253 +void 1.254 +BluetoothHidManager::OnGetServiceChannel(const nsAString& aDeviceAddress, 1.255 + const nsAString& aServiceUuid, 1.256 + int aChannel) 1.257 +{ 1.258 + // Do nothing here as bluez acquires service channel and connects for us 1.259 +} 1.260 + 1.261 +void 1.262 +BluetoothHidManager::OnUpdateSdpRecords(const nsAString& aDeviceAddress) 1.263 +{ 1.264 + // Do nothing here as bluez acquires service channel and connects for us 1.265 +} 1.266 + 1.267 +void 1.268 +BluetoothHidManager::GetAddress(nsAString& aDeviceAddress) 1.269 +{ 1.270 + aDeviceAddress = mDeviceAddress; 1.271 +} 1.272 + 1.273 +NS_IMPL_ISUPPORTS(BluetoothHidManager, nsIObserver)