Coverage Report

Created: 2018-09-25 14:53

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