|
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/. */ |
|
6 |
|
7 #include "base/basictypes.h" |
|
8 |
|
9 #include "BluetoothHidManager.h" |
|
10 |
|
11 #include "BluetoothCommon.h" |
|
12 #include "BluetoothService.h" |
|
13 #include "BluetoothUtils.h" |
|
14 |
|
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" |
|
20 |
|
21 using namespace mozilla; |
|
22 USING_BLUETOOTH_NAMESPACE |
|
23 |
|
24 namespace { |
|
25 StaticRefPtr<BluetoothHidManager> sBluetoothHidManager; |
|
26 bool sInShutdown = false; |
|
27 } // anonymous namespace |
|
28 |
|
29 NS_IMETHODIMP |
|
30 BluetoothHidManager::Observe(nsISupports* aSubject, |
|
31 const char* aTopic, |
|
32 const char16_t* aData) |
|
33 { |
|
34 MOZ_ASSERT(sBluetoothHidManager); |
|
35 |
|
36 if (!strcmp(aTopic, NS_XPCOM_SHUTDOWN_OBSERVER_ID)) { |
|
37 HandleShutdown(); |
|
38 return NS_OK; |
|
39 } |
|
40 |
|
41 MOZ_ASSERT(false, "BluetoothHidManager got unexpected topic!"); |
|
42 return NS_ERROR_UNEXPECTED; |
|
43 } |
|
44 |
|
45 BluetoothHidManager::BluetoothHidManager() |
|
46 { |
|
47 Reset(); |
|
48 } |
|
49 |
|
50 void |
|
51 BluetoothHidManager::Reset() |
|
52 { |
|
53 mConnected = false; |
|
54 mController = nullptr; |
|
55 } |
|
56 |
|
57 bool |
|
58 BluetoothHidManager::Init() |
|
59 { |
|
60 MOZ_ASSERT(NS_IsMainThread()); |
|
61 |
|
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 } |
|
68 |
|
69 return true; |
|
70 } |
|
71 |
|
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 } |
|
80 |
|
81 //static |
|
82 BluetoothHidManager* |
|
83 BluetoothHidManager::Get() |
|
84 { |
|
85 MOZ_ASSERT(NS_IsMainThread()); |
|
86 |
|
87 // If we already exist, exit early |
|
88 if (sBluetoothHidManager) { |
|
89 return sBluetoothHidManager; |
|
90 } |
|
91 |
|
92 // If we're in shutdown, don't create a new instance |
|
93 NS_ENSURE_FALSE(sInShutdown, nullptr); |
|
94 |
|
95 // Create a new instance, register, and return |
|
96 BluetoothHidManager* manager = new BluetoothHidManager(); |
|
97 NS_ENSURE_TRUE(manager->Init(), nullptr); |
|
98 |
|
99 sBluetoothHidManager = manager; |
|
100 return sBluetoothHidManager; |
|
101 } |
|
102 |
|
103 void |
|
104 BluetoothHidManager::HandleShutdown() |
|
105 { |
|
106 MOZ_ASSERT(NS_IsMainThread()); |
|
107 sInShutdown = true; |
|
108 Disconnect(nullptr); |
|
109 sBluetoothHidManager = nullptr; |
|
110 } |
|
111 |
|
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); |
|
119 |
|
120 BluetoothService* bs = BluetoothService::Get(); |
|
121 if (!bs || sInShutdown) { |
|
122 aController->NotifyCompletion(NS_LITERAL_STRING(ERR_NO_AVAILABLE_RESOURCE)); |
|
123 return; |
|
124 } |
|
125 |
|
126 if (mConnected) { |
|
127 aController->NotifyCompletion(NS_LITERAL_STRING(ERR_ALREADY_CONNECTED)); |
|
128 return; |
|
129 } |
|
130 |
|
131 mDeviceAddress = aDeviceAddress; |
|
132 mController = aController; |
|
133 |
|
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 } |
|
140 |
|
141 void |
|
142 BluetoothHidManager::Disconnect(BluetoothProfileController* aController) |
|
143 { |
|
144 MOZ_ASSERT(NS_IsMainThread()); |
|
145 |
|
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 } |
|
153 |
|
154 if (!mConnected) { |
|
155 if (aController) { |
|
156 aController->NotifyCompletion(NS_LITERAL_STRING(ERR_ALREADY_DISCONNECTED)); |
|
157 } |
|
158 return; |
|
159 } |
|
160 |
|
161 MOZ_ASSERT(!mDeviceAddress.IsEmpty()); |
|
162 MOZ_ASSERT(!mController); |
|
163 |
|
164 mController = aController; |
|
165 |
|
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 } |
|
172 |
|
173 void |
|
174 BluetoothHidManager::OnConnect(const nsAString& aErrorStr) |
|
175 { |
|
176 MOZ_ASSERT(NS_IsMainThread()); |
|
177 |
|
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); |
|
183 |
|
184 nsRefPtr<BluetoothProfileController> controller = mController.forget(); |
|
185 controller->NotifyCompletion(aErrorStr); |
|
186 } |
|
187 |
|
188 void |
|
189 BluetoothHidManager::OnDisconnect(const nsAString& aErrorStr) |
|
190 { |
|
191 MOZ_ASSERT(NS_IsMainThread()); |
|
192 |
|
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); |
|
198 |
|
199 nsRefPtr<BluetoothProfileController> controller = mController.forget(); |
|
200 controller->NotifyCompletion(aErrorStr); |
|
201 } |
|
202 |
|
203 bool |
|
204 BluetoothHidManager::IsConnected() |
|
205 { |
|
206 return mConnected; |
|
207 } |
|
208 |
|
209 void |
|
210 BluetoothHidManager::HandleInputPropertyChanged(const BluetoothSignal& aSignal) |
|
211 { |
|
212 MOZ_ASSERT(NS_IsMainThread()); |
|
213 MOZ_ASSERT(aSignal.value().type() == BluetoothValue::TArrayOfBluetoothNamedValue); |
|
214 |
|
215 const InfallibleTArray<BluetoothNamedValue>& arr = |
|
216 aSignal.value().get_ArrayOfBluetoothNamedValue(); |
|
217 MOZ_ASSERT(arr.Length() == 1); |
|
218 |
|
219 const nsString& name = arr[0].name(); |
|
220 const BluetoothValue& value = arr[0].value(); |
|
221 |
|
222 if (name.EqualsLiteral("Connected")) { |
|
223 MOZ_ASSERT(value.type() == BluetoothValue::Tbool); |
|
224 MOZ_ASSERT(mConnected != value.get_bool()); |
|
225 |
|
226 mConnected = value.get_bool(); |
|
227 NotifyStatusChanged(); |
|
228 if (mConnected) { |
|
229 OnConnect(EmptyString()); |
|
230 } else { |
|
231 OnDisconnect(EmptyString()); |
|
232 } |
|
233 } |
|
234 } |
|
235 |
|
236 void |
|
237 BluetoothHidManager::NotifyStatusChanged() |
|
238 { |
|
239 MOZ_ASSERT(NS_IsMainThread()); |
|
240 |
|
241 NS_NAMED_LITERAL_STRING(type, BLUETOOTH_HID_STATUS_CHANGED_ID); |
|
242 InfallibleTArray<BluetoothNamedValue> parameters; |
|
243 |
|
244 BT_APPEND_NAMED_VALUE(parameters, "connected", mConnected); |
|
245 BT_APPEND_NAMED_VALUE(parameters, "address", mDeviceAddress); |
|
246 |
|
247 BT_ENSURE_TRUE_VOID_BROADCAST_SYSMSG(type, parameters); |
|
248 } |
|
249 |
|
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 } |
|
257 |
|
258 void |
|
259 BluetoothHidManager::OnUpdateSdpRecords(const nsAString& aDeviceAddress) |
|
260 { |
|
261 // Do nothing here as bluez acquires service channel and connects for us |
|
262 } |
|
263 |
|
264 void |
|
265 BluetoothHidManager::GetAddress(nsAString& aDeviceAddress) |
|
266 { |
|
267 aDeviceAddress = mDeviceAddress; |
|
268 } |
|
269 |
|
270 NS_IMPL_ISUPPORTS(BluetoothHidManager, nsIObserver) |