Thu, 22 Jan 2015 13:21:57 +0100
Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6
1 /* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
2 /* vim: set ts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
5 * You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "base/basictypes.h"
9 #include "BluetoothHidManager.h"
11 #include "BluetoothCommon.h"
12 #include "BluetoothService.h"
13 #include "BluetoothUtils.h"
15 #include "mozilla/dom/bluetooth/BluetoothTypes.h"
16 #include "mozilla/Services.h"
17 #include "mozilla/StaticPtr.h"
18 #include "nsIObserverService.h"
19 #include "MainThreadUtils.h"
21 using namespace mozilla;
22 USING_BLUETOOTH_NAMESPACE
24 namespace {
25 StaticRefPtr<BluetoothHidManager> sBluetoothHidManager;
26 bool sInShutdown = false;
27 } // anonymous namespace
29 NS_IMETHODIMP
30 BluetoothHidManager::Observe(nsISupports* aSubject,
31 const char* aTopic,
32 const char16_t* aData)
33 {
34 MOZ_ASSERT(sBluetoothHidManager);
36 if (!strcmp(aTopic, NS_XPCOM_SHUTDOWN_OBSERVER_ID)) {
37 HandleShutdown();
38 return NS_OK;
39 }
41 MOZ_ASSERT(false, "BluetoothHidManager got unexpected topic!");
42 return NS_ERROR_UNEXPECTED;
43 }
45 BluetoothHidManager::BluetoothHidManager()
46 {
47 Reset();
48 }
50 void
51 BluetoothHidManager::Reset()
52 {
53 mConnected = false;
54 mController = nullptr;
55 }
57 bool
58 BluetoothHidManager::Init()
59 {
60 MOZ_ASSERT(NS_IsMainThread());
62 nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
63 NS_ENSURE_TRUE(obs, false);
64 if (NS_FAILED(obs->AddObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, false))) {
65 BT_WARNING("Failed to add shutdown observer!");
66 return false;
67 }
69 return true;
70 }
72 BluetoothHidManager::~BluetoothHidManager()
73 {
74 nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
75 NS_ENSURE_TRUE_VOID(obs);
76 if (NS_FAILED(obs->RemoveObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID))) {
77 BT_WARNING("Failed to remove shutdown observer!");
78 }
79 }
81 //static
82 BluetoothHidManager*
83 BluetoothHidManager::Get()
84 {
85 MOZ_ASSERT(NS_IsMainThread());
87 // If we already exist, exit early
88 if (sBluetoothHidManager) {
89 return sBluetoothHidManager;
90 }
92 // If we're in shutdown, don't create a new instance
93 NS_ENSURE_FALSE(sInShutdown, nullptr);
95 // Create a new instance, register, and return
96 BluetoothHidManager* manager = new BluetoothHidManager();
97 NS_ENSURE_TRUE(manager->Init(), nullptr);
99 sBluetoothHidManager = manager;
100 return sBluetoothHidManager;
101 }
103 void
104 BluetoothHidManager::HandleShutdown()
105 {
106 MOZ_ASSERT(NS_IsMainThread());
107 sInShutdown = true;
108 Disconnect(nullptr);
109 sBluetoothHidManager = nullptr;
110 }
112 void
113 BluetoothHidManager::Connect(const nsAString& aDeviceAddress,
114 BluetoothProfileController* aController)
115 {
116 MOZ_ASSERT(NS_IsMainThread());
117 MOZ_ASSERT(!aDeviceAddress.IsEmpty());
118 MOZ_ASSERT(aController && !mController);
120 BluetoothService* bs = BluetoothService::Get();
121 if (!bs || sInShutdown) {
122 aController->NotifyCompletion(NS_LITERAL_STRING(ERR_NO_AVAILABLE_RESOURCE));
123 return;
124 }
126 if (mConnected) {
127 aController->NotifyCompletion(NS_LITERAL_STRING(ERR_ALREADY_CONNECTED));
128 return;
129 }
131 mDeviceAddress = aDeviceAddress;
132 mController = aController;
134 if (NS_FAILED(bs->SendInputMessage(aDeviceAddress,
135 NS_LITERAL_STRING("Connect")))) {
136 aController->NotifyCompletion(NS_LITERAL_STRING(ERR_NO_AVAILABLE_RESOURCE));
137 return;
138 }
139 }
141 void
142 BluetoothHidManager::Disconnect(BluetoothProfileController* aController)
143 {
144 MOZ_ASSERT(NS_IsMainThread());
146 BluetoothService* bs = BluetoothService::Get();
147 if (!bs) {
148 if (aController) {
149 aController->NotifyCompletion(NS_LITERAL_STRING(ERR_NO_AVAILABLE_RESOURCE));
150 }
151 return;
152 }
154 if (!mConnected) {
155 if (aController) {
156 aController->NotifyCompletion(NS_LITERAL_STRING(ERR_ALREADY_DISCONNECTED));
157 }
158 return;
159 }
161 MOZ_ASSERT(!mDeviceAddress.IsEmpty());
162 MOZ_ASSERT(!mController);
164 mController = aController;
166 if (NS_FAILED(bs->SendInputMessage(mDeviceAddress,
167 NS_LITERAL_STRING("Disconnect")))) {
168 aController->NotifyCompletion(NS_LITERAL_STRING(ERR_NO_AVAILABLE_RESOURCE));
169 return;
170 }
171 }
173 void
174 BluetoothHidManager::OnConnect(const nsAString& aErrorStr)
175 {
176 MOZ_ASSERT(NS_IsMainThread());
178 /**
179 * On the one hand, notify the controller that we've done for outbound
180 * connections. On the other hand, we do nothing for inbound connections.
181 */
182 NS_ENSURE_TRUE_VOID(mController);
184 nsRefPtr<BluetoothProfileController> controller = mController.forget();
185 controller->NotifyCompletion(aErrorStr);
186 }
188 void
189 BluetoothHidManager::OnDisconnect(const nsAString& aErrorStr)
190 {
191 MOZ_ASSERT(NS_IsMainThread());
193 /**
194 * On the one hand, notify the controller that we've done for outbound
195 * connections. On the other hand, we do nothing for inbound connections.
196 */
197 NS_ENSURE_TRUE_VOID(mController);
199 nsRefPtr<BluetoothProfileController> controller = mController.forget();
200 controller->NotifyCompletion(aErrorStr);
201 }
203 bool
204 BluetoothHidManager::IsConnected()
205 {
206 return mConnected;
207 }
209 void
210 BluetoothHidManager::HandleInputPropertyChanged(const BluetoothSignal& aSignal)
211 {
212 MOZ_ASSERT(NS_IsMainThread());
213 MOZ_ASSERT(aSignal.value().type() == BluetoothValue::TArrayOfBluetoothNamedValue);
215 const InfallibleTArray<BluetoothNamedValue>& arr =
216 aSignal.value().get_ArrayOfBluetoothNamedValue();
217 MOZ_ASSERT(arr.Length() == 1);
219 const nsString& name = arr[0].name();
220 const BluetoothValue& value = arr[0].value();
222 if (name.EqualsLiteral("Connected")) {
223 MOZ_ASSERT(value.type() == BluetoothValue::Tbool);
224 MOZ_ASSERT(mConnected != value.get_bool());
226 mConnected = value.get_bool();
227 NotifyStatusChanged();
228 if (mConnected) {
229 OnConnect(EmptyString());
230 } else {
231 OnDisconnect(EmptyString());
232 }
233 }
234 }
236 void
237 BluetoothHidManager::NotifyStatusChanged()
238 {
239 MOZ_ASSERT(NS_IsMainThread());
241 NS_NAMED_LITERAL_STRING(type, BLUETOOTH_HID_STATUS_CHANGED_ID);
242 InfallibleTArray<BluetoothNamedValue> parameters;
244 BT_APPEND_NAMED_VALUE(parameters, "connected", mConnected);
245 BT_APPEND_NAMED_VALUE(parameters, "address", mDeviceAddress);
247 BT_ENSURE_TRUE_VOID_BROADCAST_SYSMSG(type, parameters);
248 }
250 void
251 BluetoothHidManager::OnGetServiceChannel(const nsAString& aDeviceAddress,
252 const nsAString& aServiceUuid,
253 int aChannel)
254 {
255 // Do nothing here as bluez acquires service channel and connects for us
256 }
258 void
259 BluetoothHidManager::OnUpdateSdpRecords(const nsAString& aDeviceAddress)
260 {
261 // Do nothing here as bluez acquires service channel and connects for us
262 }
264 void
265 BluetoothHidManager::GetAddress(nsAString& aDeviceAddress)
266 {
267 aDeviceAddress = mDeviceAddress;
268 }
270 NS_IMPL_ISUPPORTS(BluetoothHidManager, nsIObserver)