dom/telephony/Telephony.cpp

changeset 0
6474c204b198
equal deleted inserted replaced
-1:000000000000 0:17b004455728
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 "Telephony.h"
8 #include "mozilla/dom/TelephonyBinding.h"
9 #include "mozilla/dom/Promise.h"
10
11 #include "nsIURI.h"
12 #include "nsPIDOMWindow.h"
13 #include "nsIPermissionManager.h"
14
15 #include "mozilla/dom/UnionTypes.h"
16 #include "mozilla/Preferences.h"
17 #include "nsCharSeparatedTokenizer.h"
18 #include "nsContentUtils.h"
19 #include "nsCxPusher.h"
20 #include "nsNetUtil.h"
21 #include "nsServiceManagerUtils.h"
22 #include "nsThreadUtils.h"
23
24 #include "CallEvent.h"
25 #include "CallsList.h"
26 #include "TelephonyCall.h"
27 #include "TelephonyCallGroup.h"
28
29 using namespace mozilla::dom;
30 using mozilla::ErrorResult;
31 using mozilla::dom::telephony::kOutgoingPlaceholderCallIndex;
32
33 class Telephony::Listener : public nsITelephonyListener
34 {
35 Telephony* mTelephony;
36
37 public:
38 NS_DECL_ISUPPORTS
39 NS_FORWARD_SAFE_NSITELEPHONYLISTENER(mTelephony)
40
41 Listener(Telephony* aTelephony)
42 : mTelephony(aTelephony)
43 {
44 MOZ_ASSERT(mTelephony);
45 }
46
47 virtual ~Listener() {}
48
49 void
50 Disconnect()
51 {
52 MOZ_ASSERT(mTelephony);
53 mTelephony = nullptr;
54 }
55 };
56
57 class Telephony::Callback : public nsITelephonyCallback
58 {
59 nsRefPtr<Telephony> mTelephony;
60 nsRefPtr<Promise> mPromise;
61 uint32_t mServiceId;
62 nsString mNumber;
63
64 public:
65 NS_DECL_ISUPPORTS
66
67 Callback(Telephony* aTelephony, Promise* aPromise, uint32_t aServiceId,
68 const nsAString& aNumber)
69 : mTelephony(aTelephony), mPromise(aPromise), mServiceId(aServiceId),
70 mNumber(aNumber)
71 {
72 MOZ_ASSERT(mTelephony);
73 }
74
75 virtual ~Callback() {}
76
77 NS_IMETHODIMP
78 NotifyDialError(const nsAString& aError)
79 {
80 mPromise->MaybeReject(aError);
81 return NS_OK;
82 }
83
84 NS_IMETHODIMP
85 NotifyDialSuccess()
86 {
87 nsRefPtr<TelephonyCall> call =
88 mTelephony->CreateNewDialingCall(mServiceId, mNumber);
89
90 mPromise->MaybeResolve(call);
91 return NS_OK;
92 }
93 };
94
95 class Telephony::EnumerationAck : public nsRunnable
96 {
97 nsRefPtr<Telephony> mTelephony;
98
99 public:
100 EnumerationAck(Telephony* aTelephony)
101 : mTelephony(aTelephony)
102 {
103 MOZ_ASSERT(mTelephony);
104 }
105
106 NS_IMETHOD Run()
107 {
108 mTelephony->NotifyCallsChanged(nullptr);
109 return NS_OK;
110 }
111 };
112
113 Telephony::Telephony(nsPIDOMWindow* aOwner)
114 : DOMEventTargetHelper(aOwner), mActiveCall(nullptr), mEnumerated(false)
115 {
116 }
117
118 Telephony::~Telephony()
119 {
120 Shutdown();
121 }
122
123 void
124 Telephony::Shutdown()
125 {
126 if (mListener) {
127 mListener->Disconnect();
128
129 if (mProvider) {
130 mProvider->UnregisterListener(mListener);
131 mProvider = nullptr;
132 }
133
134 mListener = nullptr;
135 }
136 }
137
138 JSObject*
139 Telephony::WrapObject(JSContext* aCx)
140 {
141 return TelephonyBinding::Wrap(aCx, this);
142 }
143
144 // static
145 already_AddRefed<Telephony>
146 Telephony::Create(nsPIDOMWindow* aOwner, ErrorResult& aRv)
147 {
148 NS_ASSERTION(aOwner, "Null owner!");
149
150 nsCOMPtr<nsITelephonyProvider> ril =
151 do_GetService(TELEPHONY_PROVIDER_CONTRACTID);
152 if (!ril) {
153 aRv.Throw(NS_ERROR_UNEXPECTED);
154 return nullptr;
155 }
156
157 nsCOMPtr<nsIScriptGlobalObject> sgo = do_QueryInterface(aOwner);
158 if (!sgo) {
159 aRv.Throw(NS_ERROR_UNEXPECTED);
160 return nullptr;
161 }
162
163 nsCOMPtr<nsIScriptContext> scriptContext = sgo->GetContext();
164 if (!scriptContext) {
165 aRv.Throw(NS_ERROR_UNEXPECTED);
166 return nullptr;
167 }
168
169 nsRefPtr<Telephony> telephony = new Telephony(aOwner);
170
171 telephony->mProvider = ril;
172 telephony->mListener = new Listener(telephony);
173 telephony->mCallsList = new CallsList(telephony);
174 telephony->mGroup = TelephonyCallGroup::Create(telephony);
175
176 nsresult rv = ril->EnumerateCalls(telephony->mListener);
177 if (NS_FAILED(rv)) {
178 aRv.Throw(rv);
179 return nullptr;
180 }
181
182 return telephony.forget();
183 }
184
185 // static
186 bool
187 Telephony::IsValidNumber(const nsAString& aNumber)
188 {
189 return !aNumber.IsEmpty();
190 }
191
192 // static
193 uint32_t
194 Telephony::GetNumServices() {
195 return mozilla::Preferences::GetInt("ril.numRadioInterfaces", 1);
196 }
197
198 // static
199 bool
200 Telephony::IsValidServiceId(uint32_t aServiceId)
201 {
202 return aServiceId < GetNumServices();
203 }
204
205 // static
206 bool
207 Telephony::IsActiveState(uint16_t aCallState) {
208 return aCallState == nsITelephonyProvider::CALL_STATE_DIALING ||
209 aCallState == nsITelephonyProvider::CALL_STATE_ALERTING ||
210 aCallState == nsITelephonyProvider::CALL_STATE_CONNECTED;
211 }
212
213 uint32_t
214 Telephony::ProvidedOrDefaultServiceId(const Optional<uint32_t>& aServiceId)
215 {
216 if (aServiceId.WasPassed()) {
217 return aServiceId.Value();
218 } else {
219 uint32_t serviceId = 0;
220 mProvider->GetDefaultServiceId(&serviceId);
221 return serviceId;
222 }
223 }
224
225 bool
226 Telephony::HasDialingCall()
227 {
228 for (uint32_t i = 0; i < mCalls.Length(); i++) {
229 const nsRefPtr<TelephonyCall>& call = mCalls[i];
230 if (call->CallState() > nsITelephonyProvider::CALL_STATE_UNKNOWN &&
231 call->CallState() < nsITelephonyProvider::CALL_STATE_CONNECTED) {
232 return true;
233 }
234 }
235
236 return false;
237 }
238
239 bool
240 Telephony::MatchActiveCall(TelephonyCall* aCall)
241 {
242 return (mActiveCall &&
243 mActiveCall->CallIndex() == aCall->CallIndex() &&
244 mActiveCall->ServiceId() == aCall->ServiceId());
245 }
246
247 already_AddRefed<Promise>
248 Telephony::DialInternal(uint32_t aServiceId, const nsAString& aNumber,
249 bool aIsEmergency)
250 {
251 nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(GetOwner());
252 if (!global) {
253 return nullptr;
254 }
255
256 nsRefPtr<Promise> promise = new Promise(global);
257
258 if (!IsValidNumber(aNumber) || !IsValidServiceId(aServiceId)) {
259 promise->MaybeReject(NS_LITERAL_STRING("InvalidAccessError"));
260 return promise.forget();
261 }
262
263 // We only support one outgoing call at a time.
264 if (HasDialingCall()) {
265 promise->MaybeReject(NS_LITERAL_STRING("InvalidStateError"));
266 return promise.forget();
267 }
268
269 nsCOMPtr<nsITelephonyCallback> callback =
270 new Callback(this, promise, aServiceId, aNumber);
271 nsresult rv = mProvider->Dial(aServiceId, aNumber, aIsEmergency, callback);
272 if (NS_FAILED(rv)) {
273 promise->MaybeReject(NS_LITERAL_STRING("InvalidStateError"));
274 return promise.forget();
275 }
276
277 return promise.forget();
278 }
279
280 already_AddRefed<TelephonyCall>
281 Telephony::CreateNewDialingCall(uint32_t aServiceId, const nsAString& aNumber)
282 {
283 nsRefPtr<TelephonyCall> call =
284 TelephonyCall::Create(this, aServiceId, aNumber,
285 nsITelephonyProvider::CALL_STATE_DIALING);
286 NS_ASSERTION(call, "This should never fail!");
287
288 NS_ASSERTION(mCalls.Contains(call), "Should have auto-added new call!");
289
290 return call.forget();
291 }
292
293 nsresult
294 Telephony::NotifyCallsChanged(TelephonyCall* aCall)
295 {
296 return DispatchCallEvent(NS_LITERAL_STRING("callschanged"), aCall);
297 }
298
299 void
300 Telephony::UpdateActiveCall(TelephonyCall* aCall, bool aIsActive)
301 {
302 if (aIsActive) {
303 mActiveCall = aCall;
304 } else if (MatchActiveCall(aCall)) {
305 mActiveCall = nullptr;
306 }
307 }
308
309 already_AddRefed<TelephonyCall>
310 Telephony::GetCall(uint32_t aServiceId, uint32_t aCallIndex)
311 {
312 nsRefPtr<TelephonyCall> call;
313
314 for (uint32_t i = 0; i < mCalls.Length(); i++) {
315 nsRefPtr<TelephonyCall>& tempCall = mCalls[i];
316 if (tempCall->ServiceId() == aServiceId &&
317 tempCall->CallIndex() == aCallIndex) {
318 call = tempCall;
319 break;
320 }
321 }
322
323 return call.forget();
324 }
325
326 already_AddRefed<TelephonyCall>
327 Telephony::GetOutgoingCall()
328 {
329 nsRefPtr<TelephonyCall> call;
330
331 for (uint32_t i = 0; i < mCalls.Length(); i++) {
332 nsRefPtr<TelephonyCall>& tempCall = mCalls[i];
333 if (tempCall->CallIndex() == kOutgoingPlaceholderCallIndex) {
334 NS_ASSERTION(!call, "More than one outgoing call not supported!");
335 NS_ASSERTION(tempCall->CallState() == nsITelephonyProvider::CALL_STATE_DIALING,
336 "Something really wrong here!");
337
338 call = tempCall;
339 // No break. We will search entire list to ensure only one outgoing call.
340 }
341 }
342
343 return call.forget();
344 }
345
346 already_AddRefed<TelephonyCall>
347 Telephony::GetCallFromEverywhere(uint32_t aServiceId, uint32_t aCallIndex)
348 {
349 nsRefPtr<TelephonyCall> call = GetCall(aServiceId, aCallIndex);
350
351 if (!call) {
352 call = mGroup->GetCall(aServiceId, aCallIndex);
353 }
354
355 return call.forget();
356 }
357
358 NS_IMPL_CYCLE_COLLECTION_CLASS(Telephony)
359
360 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(Telephony,
361 DOMEventTargetHelper)
362 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mCalls)
363 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mCallsList)
364 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mGroup)
365 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
366
367 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(Telephony,
368 DOMEventTargetHelper)
369 tmp->Shutdown();
370 tmp->mActiveCall = nullptr;
371 NS_IMPL_CYCLE_COLLECTION_UNLINK(mCalls)
372 NS_IMPL_CYCLE_COLLECTION_UNLINK(mCallsList)
373 NS_IMPL_CYCLE_COLLECTION_UNLINK(mGroup)
374 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
375
376 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(Telephony)
377 NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper)
378
379 NS_IMPL_ADDREF_INHERITED(Telephony, DOMEventTargetHelper)
380 NS_IMPL_RELEASE_INHERITED(Telephony, DOMEventTargetHelper)
381
382 NS_IMPL_ISUPPORTS(Telephony::Listener, nsITelephonyListener)
383 NS_IMPL_ISUPPORTS(Telephony::Callback, nsITelephonyCallback)
384
385 // Telephony WebIDL
386
387 already_AddRefed<Promise>
388 Telephony::Dial(const nsAString& aNumber, const Optional<uint32_t>& aServiceId)
389 {
390 uint32_t serviceId = ProvidedOrDefaultServiceId(aServiceId);
391 nsRefPtr<Promise> promise = DialInternal(serviceId, aNumber, false);
392 return promise.forget();
393 }
394
395 already_AddRefed<Promise>
396 Telephony::DialEmergency(const nsAString& aNumber,
397 const Optional<uint32_t>& aServiceId)
398 {
399 uint32_t serviceId = ProvidedOrDefaultServiceId(aServiceId);
400 nsRefPtr<Promise> promise = DialInternal(serviceId, aNumber, true);
401 return promise.forget();
402 }
403
404 void
405 Telephony::StartTone(const nsAString& aDTMFChar,
406 const Optional<uint32_t>& aServiceId,
407 ErrorResult& aRv)
408 {
409 uint32_t serviceId = ProvidedOrDefaultServiceId(aServiceId);
410
411 if (aDTMFChar.IsEmpty()) {
412 NS_WARNING("Empty tone string will be ignored");
413 return;
414 }
415
416 if (aDTMFChar.Length() > 1 || !IsValidServiceId(serviceId)) {
417 aRv.Throw(NS_ERROR_INVALID_ARG);
418 return;
419 }
420
421 aRv = mProvider->StartTone(serviceId, aDTMFChar);
422 }
423
424 void
425 Telephony::StopTone(const Optional<uint32_t>& aServiceId, ErrorResult& aRv)
426 {
427 uint32_t serviceId = ProvidedOrDefaultServiceId(aServiceId);
428
429 if (!IsValidServiceId(serviceId)) {
430 aRv.Throw(NS_ERROR_INVALID_ARG);
431 return;
432 }
433
434 aRv = mProvider->StopTone(serviceId);
435 }
436
437 bool
438 Telephony::GetMuted(ErrorResult& aRv) const
439 {
440 bool muted = false;
441 aRv = mProvider->GetMicrophoneMuted(&muted);
442
443 return muted;
444 }
445
446 void
447 Telephony::SetMuted(bool aMuted, ErrorResult& aRv)
448 {
449 aRv = mProvider->SetMicrophoneMuted(aMuted);
450 }
451
452 bool
453 Telephony::GetSpeakerEnabled(ErrorResult& aRv) const
454 {
455 bool enabled = false;
456 aRv = mProvider->GetSpeakerEnabled(&enabled);
457
458 return enabled;
459 }
460
461 void
462 Telephony::SetSpeakerEnabled(bool aEnabled, ErrorResult& aRv)
463 {
464 aRv = mProvider->SetSpeakerEnabled(aEnabled);
465 }
466
467 void
468 Telephony::GetActive(Nullable<OwningTelephonyCallOrTelephonyCallGroup>& aValue)
469 {
470 if (mActiveCall) {
471 aValue.SetValue().SetAsTelephonyCall() = mActiveCall;
472 } else if (mGroup->CallState() == nsITelephonyProvider::CALL_STATE_CONNECTED) {
473 aValue.SetValue().SetAsTelephonyCallGroup() = mGroup;
474 } else {
475 aValue.SetNull();
476 }
477 }
478
479 already_AddRefed<CallsList>
480 Telephony::Calls() const
481 {
482 nsRefPtr<CallsList> list = mCallsList;
483 return list.forget();
484 }
485
486 already_AddRefed<TelephonyCallGroup>
487 Telephony::ConferenceGroup() const
488 {
489 nsRefPtr<TelephonyCallGroup> group = mGroup;
490 return group.forget();
491 }
492
493 // EventTarget
494
495 void
496 Telephony::EventListenerAdded(nsIAtom* aType)
497 {
498 if (aType == nsGkAtoms::oncallschanged) {
499 // Fire oncallschanged on the next tick if the calls array is ready.
500 EnqueueEnumerationAck();
501 }
502 }
503
504 // nsITelephonyListener
505
506 NS_IMETHODIMP
507 Telephony::CallStateChanged(uint32_t aServiceId, uint32_t aCallIndex,
508 uint16_t aCallState, const nsAString& aNumber,
509 bool aIsActive, bool aIsOutgoing, bool aIsEmergency,
510 bool aIsConference, bool aIsSwitchable, bool aIsMergeable)
511 {
512 nsRefPtr<TelephonyCall> modifiedCall
513 = GetCallFromEverywhere(aServiceId, aCallIndex);
514
515 // Try to use the outgoing call if we don't find the modified call.
516 if (!modifiedCall) {
517 nsRefPtr<TelephonyCall> outgoingCall = GetOutgoingCall();
518
519 // If the call state isn't incoming but we do have an outgoing call then
520 // we must be seeing a status update for our outgoing call.
521 if (outgoingCall &&
522 aCallState != nsITelephonyProvider::CALL_STATE_INCOMING) {
523 outgoingCall->UpdateCallIndex(aCallIndex);
524 outgoingCall->UpdateEmergency(aIsEmergency);
525 modifiedCall.swap(outgoingCall);
526 }
527 }
528
529 if (modifiedCall) {
530 modifiedCall->UpdateSwitchable(aIsSwitchable);
531 modifiedCall->UpdateMergeable(aIsMergeable);
532
533 if (!aIsConference) {
534 UpdateActiveCall(modifiedCall, aIsActive);
535 }
536
537 if (modifiedCall->CallState() != aCallState) {
538 // We don't fire the statechange event on a call in conference here.
539 // Instead, the event will be fired later in
540 // TelephonyCallGroup::ChangeState(). Thus the sequence of firing the
541 // statechange events is guaranteed: first on TelephonyCallGroup then on
542 // individual TelephonyCall objects.
543 bool fireEvent = !aIsConference;
544 modifiedCall->ChangeStateInternal(aCallState, fireEvent);
545 }
546
547 nsRefPtr<TelephonyCallGroup> group = modifiedCall->GetGroup();
548
549 if (!group && aIsConference) {
550 // Add to conference.
551 NS_ASSERTION(mCalls.Contains(modifiedCall), "Should in mCalls");
552 mGroup->AddCall(modifiedCall);
553 RemoveCall(modifiedCall);
554 } else if (group && !aIsConference) {
555 // Remove from conference.
556 NS_ASSERTION(mGroup->CallsArray().Contains(modifiedCall), "Should in mGroup");
557 mGroup->RemoveCall(modifiedCall);
558 AddCall(modifiedCall);
559 }
560
561 return NS_OK;
562 }
563
564 // Do nothing since we didn't know anything about it before now and it's
565 // ended already.
566 if (aCallState == nsITelephonyProvider::CALL_STATE_DISCONNECTED) {
567 return NS_OK;
568 }
569
570 // Didn't find this call in mCalls or mGroup. Create a new call.
571 nsRefPtr<TelephonyCall> call =
572 TelephonyCall::Create(this, aServiceId, aNumber, aCallState, aCallIndex,
573 aIsEmergency, aIsConference, aIsSwitchable,
574 aIsMergeable);
575 NS_ASSERTION(call, "This should never fail!");
576
577 NS_ASSERTION(aIsConference ? mGroup->CallsArray().Contains(call) :
578 mCalls.Contains(call),
579 "Should have auto-added new call!");
580
581 if (aCallState == nsITelephonyProvider::CALL_STATE_INCOMING) {
582 nsresult rv = DispatchCallEvent(NS_LITERAL_STRING("incoming"), call);
583 NS_ENSURE_SUCCESS(rv, rv);
584 }
585
586 return NS_OK;
587 }
588
589 NS_IMETHODIMP
590 Telephony::ConferenceCallStateChanged(uint16_t aCallState)
591 {
592 mGroup->ChangeState(aCallState);
593 return NS_OK;
594 }
595
596 NS_IMETHODIMP
597 Telephony::EnumerateCallStateComplete()
598 {
599 MOZ_ASSERT(!mEnumerated);
600
601 mEnumerated = true;
602
603 if (NS_FAILED(NotifyCallsChanged(nullptr))) {
604 NS_WARNING("Failed to notify calls changed!");
605 }
606
607 if (NS_FAILED(mProvider->RegisterListener(mListener))) {
608 NS_WARNING("Failed to register listener!");
609 }
610 return NS_OK;
611 }
612
613 NS_IMETHODIMP
614 Telephony::EnumerateCallState(uint32_t aServiceId, uint32_t aCallIndex,
615 uint16_t aCallState, const nsAString& aNumber,
616 bool aIsActive, bool aIsOutgoing, bool aIsEmergency,
617 bool aIsConference, bool aIsSwitchable, bool aIsMergeable)
618 {
619 nsRefPtr<TelephonyCall> call;
620
621 // We request calls enumeration in constructor, and the asynchronous result
622 // will be sent back through the callback function EnumerateCallState().
623 // However, it is likely to have call state changes, i.e. CallStateChanged()
624 // being called, before the enumeration result comes back. We'd make sure
625 // we don't somehow add duplicates due to the race condition.
626 call = GetCallFromEverywhere(aServiceId, aCallIndex);
627 if (call) {
628 return NS_OK;
629 }
630
631 // Didn't know anything about this call before now.
632 call = TelephonyCall::Create(this, aServiceId, aNumber, aCallState,
633 aCallIndex, aIsEmergency, aIsConference,
634 aIsSwitchable, aIsMergeable);
635 NS_ASSERTION(call, "This should never fail!");
636
637 NS_ASSERTION(aIsConference ? mGroup->CallsArray().Contains(call) :
638 mCalls.Contains(call),
639 "Should have auto-added new call!");
640
641 return NS_OK;
642 }
643
644 NS_IMETHODIMP
645 Telephony::SupplementaryServiceNotification(uint32_t aServiceId,
646 int32_t aCallIndex,
647 uint16_t aNotification)
648 {
649 nsRefPtr<TelephonyCall> associatedCall;
650 if (!mCalls.IsEmpty()) {
651 associatedCall = GetCall(aServiceId, aCallIndex);
652 }
653
654 nsresult rv;
655 switch (aNotification) {
656 case nsITelephonyProvider::NOTIFICATION_REMOTE_HELD:
657 rv = DispatchCallEvent(NS_LITERAL_STRING("remoteheld"), associatedCall);
658 break;
659 case nsITelephonyProvider::NOTIFICATION_REMOTE_RESUMED:
660 rv = DispatchCallEvent(NS_LITERAL_STRING("remoteresumed"), associatedCall);
661 break;
662 default:
663 NS_ERROR("Got a bad notification!");
664 return NS_ERROR_UNEXPECTED;
665 }
666
667 NS_ENSURE_SUCCESS(rv, rv);
668 return NS_OK;
669 }
670
671 NS_IMETHODIMP
672 Telephony::NotifyError(uint32_t aServiceId,
673 int32_t aCallIndex,
674 const nsAString& aError)
675 {
676 if (mCalls.IsEmpty()) {
677 NS_ERROR("No existing call!");
678 return NS_ERROR_UNEXPECTED;
679 }
680
681 nsRefPtr<TelephonyCall> callToNotify = GetCall(aServiceId, aCallIndex);
682 if (!callToNotify) {
683 NS_ERROR("Don't call me with a bad call index!");
684 return NS_ERROR_UNEXPECTED;
685 }
686
687 UpdateActiveCall(callToNotify, false);
688
689 // Set the call state to 'disconnected' and remove it from the calls list.
690 callToNotify->NotifyError(aError);
691
692 return NS_OK;
693 }
694
695 NS_IMETHODIMP
696 Telephony::NotifyCdmaCallWaiting(uint32_t aServiceId, const nsAString& aNumber)
697 {
698 MOZ_ASSERT(mCalls.Length() == 1);
699
700 nsRefPtr<TelephonyCall> callToNotify = mCalls[0];
701 MOZ_ASSERT(callToNotify && callToNotify->ServiceId() == aServiceId);
702
703 callToNotify->UpdateSecondNumber(aNumber);
704 DispatchCallEvent(NS_LITERAL_STRING("callschanged"), callToNotify);
705 return NS_OK;
706 }
707
708 NS_IMETHODIMP
709 Telephony::NotifyConferenceError(const nsAString& aName,
710 const nsAString& aMessage)
711 {
712 mGroup->NotifyError(aName, aMessage);
713 return NS_OK;
714 }
715
716 nsresult
717 Telephony::DispatchCallEvent(const nsAString& aType,
718 TelephonyCall* aCall)
719 {
720 // The call may be null in following cases:
721 // 1. callschanged when notifying enumeration being completed
722 // 2. remoteheld/remoteresumed.
723 MOZ_ASSERT(aCall ||
724 aType.EqualsLiteral("callschanged") ||
725 aType.EqualsLiteral("remoteheld") ||
726 aType.EqualsLiteral("remtoeresumed"));
727
728 nsRefPtr<CallEvent> event = CallEvent::Create(this, aType, aCall, false, false);
729
730 return DispatchTrustedEvent(event);
731 }
732
733 void
734 Telephony::EnqueueEnumerationAck()
735 {
736 if (!mEnumerated) {
737 return;
738 }
739
740 nsCOMPtr<nsIRunnable> task = new EnumerationAck(this);
741 if (NS_FAILED(NS_DispatchToCurrentThread(task))) {
742 NS_WARNING("Failed to dispatch to current thread!");
743 }
744 }

mercurial