Line data Source code
1 : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : /* vim: set ts=8 sts=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
5 : * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 :
7 : #include "PresentationDeviceManager.h"
8 :
9 : #include "mozilla/Services.h"
10 : #include "MainThreadUtils.h"
11 : #include "nsArrayUtils.h"
12 : #include "nsCategoryCache.h"
13 : #include "nsCOMPtr.h"
14 : #include "nsIMutableArray.h"
15 : #include "nsIObserverService.h"
16 : #include "nsXULAppAPI.h"
17 : #include "PresentationSessionRequest.h"
18 : #include "PresentationTerminateRequest.h"
19 :
20 : namespace mozilla {
21 : namespace dom {
22 :
23 16 : NS_IMPL_ISUPPORTS(PresentationDeviceManager,
24 : nsIPresentationDeviceManager,
25 : nsIPresentationDeviceListener,
26 : nsIObserver,
27 : nsISupportsWeakReference)
28 :
29 1 : PresentationDeviceManager::PresentationDeviceManager()
30 : {
31 1 : }
32 :
33 0 : PresentationDeviceManager::~PresentationDeviceManager()
34 : {
35 0 : UnloadDeviceProviders();
36 0 : mDevices.Clear();
37 0 : }
38 :
39 : void
40 1 : PresentationDeviceManager::Init()
41 : {
42 2 : nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
43 1 : if (obs) {
44 1 : obs->AddObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, false);
45 : }
46 :
47 1 : LoadDeviceProviders();
48 1 : }
49 :
50 : void
51 0 : PresentationDeviceManager::Shutdown()
52 : {
53 0 : nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
54 0 : if (obs) {
55 0 : obs->RemoveObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID);
56 : }
57 :
58 0 : UnloadDeviceProviders();
59 0 : }
60 :
61 : void
62 1 : PresentationDeviceManager::LoadDeviceProviders()
63 : {
64 1 : MOZ_ASSERT(mProviders.IsEmpty());
65 :
66 2 : nsCategoryCache<nsIPresentationDeviceProvider> providerCache(PRESENTATION_DEVICE_PROVIDER_CATEGORY);
67 1 : providerCache.GetEntries(mProviders);
68 :
69 1 : for (uint32_t i = 0; i < mProviders.Length(); ++i) {
70 0 : mProviders[i]->SetListener(this);
71 : }
72 1 : }
73 :
74 : void
75 0 : PresentationDeviceManager::UnloadDeviceProviders()
76 : {
77 0 : for (uint32_t i = 0; i < mProviders.Length(); ++i) {
78 0 : mProviders[i]->SetListener(nullptr);
79 : }
80 :
81 0 : mProviders.Clear();
82 0 : }
83 :
84 : void
85 0 : PresentationDeviceManager::NotifyDeviceChange(nsIPresentationDevice* aDevice,
86 : const char16_t* aType)
87 : {
88 0 : nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
89 0 : if (obs) {
90 0 : obs->NotifyObservers(aDevice,
91 : PRESENTATION_DEVICE_CHANGE_TOPIC,
92 0 : aType);
93 : }
94 0 : }
95 :
96 : // nsIPresentationDeviceManager
97 : NS_IMETHODIMP
98 0 : PresentationDeviceManager::ForceDiscovery()
99 : {
100 0 : MOZ_ASSERT(NS_IsMainThread());
101 :
102 0 : for (uint32_t i = 0; i < mProviders.Length(); ++i) {
103 0 : mProviders[i]->ForceDiscovery();
104 : }
105 :
106 0 : return NS_OK;
107 : }
108 :
109 : NS_IMETHODIMP
110 0 : PresentationDeviceManager::AddDeviceProvider(nsIPresentationDeviceProvider* aProvider)
111 : {
112 0 : NS_ENSURE_ARG(aProvider);
113 0 : MOZ_ASSERT(NS_IsMainThread());
114 :
115 0 : if (NS_WARN_IF(mProviders.Contains(aProvider))) {
116 0 : return NS_OK;
117 : }
118 :
119 0 : mProviders.AppendElement(aProvider);
120 0 : aProvider->SetListener(this);
121 :
122 0 : return NS_OK;
123 : }
124 :
125 : NS_IMETHODIMP
126 0 : PresentationDeviceManager::RemoveDeviceProvider(nsIPresentationDeviceProvider* aProvider)
127 : {
128 0 : NS_ENSURE_ARG(aProvider);
129 0 : MOZ_ASSERT(NS_IsMainThread());
130 :
131 0 : if (NS_WARN_IF(!mProviders.RemoveElement(aProvider))) {
132 0 : return NS_ERROR_FAILURE;
133 : }
134 :
135 0 : aProvider->SetListener(nullptr);
136 :
137 0 : return NS_OK;
138 : }
139 :
140 : NS_IMETHODIMP
141 0 : PresentationDeviceManager::GetDeviceAvailable(bool* aRetVal)
142 : {
143 0 : NS_ENSURE_ARG_POINTER(aRetVal);
144 0 : MOZ_ASSERT(NS_IsMainThread());
145 :
146 0 : *aRetVal = !mDevices.IsEmpty();
147 :
148 0 : return NS_OK;
149 : }
150 :
151 : NS_IMETHODIMP
152 0 : PresentationDeviceManager::GetAvailableDevices(nsIArray* aPresentationUrls, nsIArray** aRetVal)
153 : {
154 0 : NS_ENSURE_ARG_POINTER(aRetVal);
155 0 : MOZ_ASSERT(NS_IsMainThread());
156 :
157 : // Bug 1194049: some providers may discontinue discovery after timeout.
158 : // Call |ForceDiscovery()| here to make sure device lists are updated.
159 0 : NS_DispatchToMainThread(
160 0 : NewRunnableMethod("dom::PresentationDeviceManager::ForceDiscovery",
161 : this,
162 0 : &PresentationDeviceManager::ForceDiscovery));
163 :
164 0 : nsTArray<nsString> presentationUrls;
165 0 : if (aPresentationUrls) {
166 : uint32_t length;
167 0 : nsresult rv = aPresentationUrls->GetLength(&length);
168 0 : if (NS_SUCCEEDED(rv)) {
169 0 : for (uint32_t i = 0; i < length; ++i) {
170 : nsCOMPtr<nsISupportsString> isupportStr =
171 0 : do_QueryElementAt(aPresentationUrls, i);
172 :
173 0 : nsAutoString presentationUrl;
174 0 : rv = isupportStr->GetData(presentationUrl);
175 0 : if (NS_WARN_IF(NS_FAILED(rv))) {
176 0 : continue;
177 : }
178 :
179 0 : presentationUrls.AppendElement(presentationUrl);
180 : }
181 : }
182 : }
183 :
184 0 : nsCOMPtr<nsIMutableArray> devices = do_CreateInstance(NS_ARRAY_CONTRACTID);
185 0 : for (uint32_t i = 0; i < mDevices.Length(); ++i) {
186 0 : if (presentationUrls.IsEmpty()) {
187 0 : devices->AppendElement(mDevices[i], false);
188 0 : continue;
189 : }
190 :
191 0 : for (uint32_t j = 0; j < presentationUrls.Length(); ++j) {
192 : bool isSupported;
193 0 : if (NS_SUCCEEDED(mDevices[i]->IsRequestedUrlSupported(presentationUrls[j],
194 0 : &isSupported)) &&
195 : isSupported) {
196 0 : devices->AppendElement(mDevices[i], false);
197 0 : break;
198 : }
199 : }
200 : }
201 :
202 0 : devices.forget(aRetVal);
203 :
204 0 : return NS_OK;
205 : }
206 :
207 : // nsIPresentationDeviceListener
208 : NS_IMETHODIMP
209 0 : PresentationDeviceManager::AddDevice(nsIPresentationDevice* aDevice)
210 : {
211 0 : NS_ENSURE_ARG(aDevice);
212 0 : MOZ_ASSERT(NS_IsMainThread());
213 :
214 0 : if (NS_WARN_IF(mDevices.Contains(aDevice))) {
215 0 : return NS_ERROR_FAILURE;
216 : }
217 :
218 0 : mDevices.AppendElement(aDevice);
219 :
220 0 : NotifyDeviceChange(aDevice, u"add");
221 :
222 0 : return NS_OK;
223 : }
224 :
225 : NS_IMETHODIMP
226 0 : PresentationDeviceManager::RemoveDevice(nsIPresentationDevice* aDevice)
227 : {
228 0 : NS_ENSURE_ARG(aDevice);
229 0 : MOZ_ASSERT(NS_IsMainThread());
230 :
231 0 : int32_t index = mDevices.IndexOf(aDevice);
232 0 : if (NS_WARN_IF(index < 0)) {
233 0 : return NS_ERROR_FAILURE;
234 : }
235 :
236 0 : mDevices.RemoveElementAt(index);
237 :
238 0 : NotifyDeviceChange(aDevice, u"remove");
239 :
240 0 : return NS_OK;
241 : }
242 :
243 : NS_IMETHODIMP
244 0 : PresentationDeviceManager::UpdateDevice(nsIPresentationDevice* aDevice)
245 : {
246 0 : NS_ENSURE_ARG(aDevice);
247 0 : MOZ_ASSERT(NS_IsMainThread());
248 :
249 0 : if (NS_WARN_IF(!mDevices.Contains(aDevice))) {
250 0 : return NS_ERROR_FAILURE;
251 : }
252 :
253 0 : NotifyDeviceChange(aDevice, u"update");
254 :
255 0 : return NS_OK;
256 : }
257 :
258 : NS_IMETHODIMP
259 0 : PresentationDeviceManager::OnSessionRequest(nsIPresentationDevice* aDevice,
260 : const nsAString& aUrl,
261 : const nsAString& aPresentationId,
262 : nsIPresentationControlChannel* aControlChannel)
263 : {
264 0 : NS_ENSURE_ARG(aDevice);
265 0 : NS_ENSURE_ARG(aControlChannel);
266 :
267 0 : nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
268 0 : NS_ENSURE_TRUE(obs, NS_ERROR_FAILURE);
269 :
270 : RefPtr<PresentationSessionRequest> request =
271 0 : new PresentationSessionRequest(aDevice, aUrl, aPresentationId, aControlChannel);
272 0 : obs->NotifyObservers(request,
273 : PRESENTATION_SESSION_REQUEST_TOPIC,
274 0 : nullptr);
275 :
276 0 : return NS_OK;
277 : }
278 :
279 : NS_IMETHODIMP
280 0 : PresentationDeviceManager::OnTerminateRequest(nsIPresentationDevice* aDevice,
281 : const nsAString& aPresentationId,
282 : nsIPresentationControlChannel* aControlChannel,
283 : bool aIsFromReceiver)
284 : {
285 0 : NS_ENSURE_ARG(aDevice);
286 0 : NS_ENSURE_ARG(aControlChannel);
287 :
288 0 : nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
289 0 : NS_ENSURE_TRUE(obs, NS_ERROR_FAILURE);
290 :
291 : RefPtr<PresentationTerminateRequest> request =
292 : new PresentationTerminateRequest(aDevice, aPresentationId,
293 0 : aControlChannel, aIsFromReceiver);
294 0 : obs->NotifyObservers(request,
295 : PRESENTATION_TERMINATE_REQUEST_TOPIC,
296 0 : nullptr);
297 :
298 0 : return NS_OK;
299 : }
300 :
301 : NS_IMETHODIMP
302 0 : PresentationDeviceManager::OnReconnectRequest(nsIPresentationDevice* aDevice,
303 : const nsAString& aUrl,
304 : const nsAString& aPresentationId,
305 : nsIPresentationControlChannel* aControlChannel)
306 : {
307 0 : NS_ENSURE_ARG(aDevice);
308 0 : NS_ENSURE_ARG(aControlChannel);
309 :
310 0 : nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
311 0 : NS_ENSURE_TRUE(obs, NS_ERROR_FAILURE);
312 :
313 : RefPtr<PresentationSessionRequest> request =
314 0 : new PresentationSessionRequest(aDevice, aUrl, aPresentationId, aControlChannel);
315 0 : obs->NotifyObservers(request,
316 : PRESENTATION_RECONNECT_REQUEST_TOPIC,
317 0 : nullptr);
318 :
319 0 : return NS_OK;
320 : }
321 :
322 : // nsIObserver
323 : NS_IMETHODIMP
324 1 : PresentationDeviceManager::Observe(nsISupports *aSubject,
325 : const char *aTopic,
326 : const char16_t *aData)
327 : {
328 1 : if (!strcmp(aTopic, "profile-after-change")) {
329 1 : Init();
330 0 : } else if (!strcmp(aTopic, NS_XPCOM_SHUTDOWN_OBSERVER_ID)) {
331 0 : Shutdown();
332 : }
333 :
334 1 : return NS_OK;
335 : }
336 :
337 : } // namespace dom
338 : } // namespace mozilla
|