dom/telephony/Telephony.cpp

Sat, 03 Jan 2015 20:18:00 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Sat, 03 Jan 2015 20:18:00 +0100
branch
TOR_BUG_3246
changeset 7
129ffea94266
permissions
-rw-r--r--

Conditionally enable double key logic according to:
private browsing mode or privacy.thirdparty.isolate preference and
implement in GetCookieStringCommon and FindCookie where it counts...
With some reservations of how to convince FindCookie users to test
condition and pass a nullptr when disabling double key logic.

     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/. */
     7 #include "Telephony.h"
     8 #include "mozilla/dom/TelephonyBinding.h"
     9 #include "mozilla/dom/Promise.h"
    11 #include "nsIURI.h"
    12 #include "nsPIDOMWindow.h"
    13 #include "nsIPermissionManager.h"
    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"
    24 #include "CallEvent.h"
    25 #include "CallsList.h"
    26 #include "TelephonyCall.h"
    27 #include "TelephonyCallGroup.h"
    29 using namespace mozilla::dom;
    30 using mozilla::ErrorResult;
    31 using mozilla::dom::telephony::kOutgoingPlaceholderCallIndex;
    33 class Telephony::Listener : public nsITelephonyListener
    34 {
    35   Telephony* mTelephony;
    37 public:
    38   NS_DECL_ISUPPORTS
    39   NS_FORWARD_SAFE_NSITELEPHONYLISTENER(mTelephony)
    41   Listener(Telephony* aTelephony)
    42     : mTelephony(aTelephony)
    43   {
    44     MOZ_ASSERT(mTelephony);
    45   }
    47   virtual ~Listener() {}
    49   void
    50   Disconnect()
    51   {
    52     MOZ_ASSERT(mTelephony);
    53     mTelephony = nullptr;
    54   }
    55 };
    57 class Telephony::Callback : public nsITelephonyCallback
    58 {
    59   nsRefPtr<Telephony> mTelephony;
    60   nsRefPtr<Promise> mPromise;
    61   uint32_t mServiceId;
    62   nsString mNumber;
    64 public:
    65   NS_DECL_ISUPPORTS
    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   }
    75   virtual ~Callback() {}
    77   NS_IMETHODIMP
    78   NotifyDialError(const nsAString& aError)
    79   {
    80     mPromise->MaybeReject(aError);
    81     return NS_OK;
    82   }
    84   NS_IMETHODIMP
    85   NotifyDialSuccess()
    86   {
    87     nsRefPtr<TelephonyCall> call =
    88       mTelephony->CreateNewDialingCall(mServiceId, mNumber);
    90     mPromise->MaybeResolve(call);
    91     return NS_OK;
    92   }
    93 };
    95 class Telephony::EnumerationAck : public nsRunnable
    96 {
    97   nsRefPtr<Telephony> mTelephony;
    99 public:
   100   EnumerationAck(Telephony* aTelephony)
   101   : mTelephony(aTelephony)
   102   {
   103     MOZ_ASSERT(mTelephony);
   104   }
   106   NS_IMETHOD Run()
   107   {
   108     mTelephony->NotifyCallsChanged(nullptr);
   109     return NS_OK;
   110   }
   111 };
   113 Telephony::Telephony(nsPIDOMWindow* aOwner)
   114   : DOMEventTargetHelper(aOwner), mActiveCall(nullptr), mEnumerated(false)
   115 {
   116 }
   118 Telephony::~Telephony()
   119 {
   120   Shutdown();
   121 }
   123 void
   124 Telephony::Shutdown()
   125 {
   126   if (mListener) {
   127     mListener->Disconnect();
   129     if (mProvider) {
   130       mProvider->UnregisterListener(mListener);
   131       mProvider = nullptr;
   132     }
   134     mListener = nullptr;
   135   }
   136 }
   138 JSObject*
   139 Telephony::WrapObject(JSContext* aCx)
   140 {
   141   return TelephonyBinding::Wrap(aCx, this);
   142 }
   144 // static
   145 already_AddRefed<Telephony>
   146 Telephony::Create(nsPIDOMWindow* aOwner, ErrorResult& aRv)
   147 {
   148   NS_ASSERTION(aOwner, "Null owner!");
   150   nsCOMPtr<nsITelephonyProvider> ril =
   151     do_GetService(TELEPHONY_PROVIDER_CONTRACTID);
   152   if (!ril) {
   153     aRv.Throw(NS_ERROR_UNEXPECTED);
   154     return nullptr;
   155   }
   157   nsCOMPtr<nsIScriptGlobalObject> sgo = do_QueryInterface(aOwner);
   158   if (!sgo) {
   159     aRv.Throw(NS_ERROR_UNEXPECTED);
   160     return nullptr;
   161   }
   163   nsCOMPtr<nsIScriptContext> scriptContext = sgo->GetContext();
   164   if (!scriptContext) {
   165     aRv.Throw(NS_ERROR_UNEXPECTED);
   166     return nullptr;
   167   }
   169   nsRefPtr<Telephony> telephony = new Telephony(aOwner);
   171   telephony->mProvider = ril;
   172   telephony->mListener = new Listener(telephony);
   173   telephony->mCallsList = new CallsList(telephony);
   174   telephony->mGroup = TelephonyCallGroup::Create(telephony);
   176   nsresult rv = ril->EnumerateCalls(telephony->mListener);
   177   if (NS_FAILED(rv)) {
   178     aRv.Throw(rv);
   179     return nullptr;
   180   }
   182   return telephony.forget();
   183 }
   185 // static
   186 bool
   187 Telephony::IsValidNumber(const nsAString& aNumber)
   188 {
   189   return !aNumber.IsEmpty();
   190 }
   192 // static
   193 uint32_t
   194 Telephony::GetNumServices() {
   195   return mozilla::Preferences::GetInt("ril.numRadioInterfaces", 1);
   196 }
   198 // static
   199 bool
   200 Telephony::IsValidServiceId(uint32_t aServiceId)
   201 {
   202   return aServiceId < GetNumServices();
   203 }
   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 }
   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 }
   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   }
   236   return false;
   237 }
   239 bool
   240 Telephony::MatchActiveCall(TelephonyCall* aCall)
   241 {
   242   return (mActiveCall &&
   243           mActiveCall->CallIndex() == aCall->CallIndex() &&
   244           mActiveCall->ServiceId() == aCall->ServiceId());
   245 }
   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   }
   256   nsRefPtr<Promise> promise = new Promise(global);
   258   if (!IsValidNumber(aNumber) || !IsValidServiceId(aServiceId)) {
   259     promise->MaybeReject(NS_LITERAL_STRING("InvalidAccessError"));
   260     return promise.forget();
   261   }
   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   }
   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   }
   277   return promise.forget();
   278 }
   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!");
   288   NS_ASSERTION(mCalls.Contains(call), "Should have auto-added new call!");
   290   return call.forget();
   291 }
   293 nsresult
   294 Telephony::NotifyCallsChanged(TelephonyCall* aCall)
   295 {
   296   return DispatchCallEvent(NS_LITERAL_STRING("callschanged"), aCall);
   297 }
   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 }
   309 already_AddRefed<TelephonyCall>
   310 Telephony::GetCall(uint32_t aServiceId, uint32_t aCallIndex)
   311 {
   312   nsRefPtr<TelephonyCall> call;
   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   }
   323   return call.forget();
   324 }
   326 already_AddRefed<TelephonyCall>
   327 Telephony::GetOutgoingCall()
   328 {
   329   nsRefPtr<TelephonyCall> call;
   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!");
   338       call = tempCall;
   339       // No break. We will search entire list to ensure only one outgoing call.
   340     }
   341   }
   343   return call.forget();
   344 }
   346 already_AddRefed<TelephonyCall>
   347 Telephony::GetCallFromEverywhere(uint32_t aServiceId, uint32_t aCallIndex)
   348 {
   349   nsRefPtr<TelephonyCall> call = GetCall(aServiceId, aCallIndex);
   351   if (!call) {
   352     call = mGroup->GetCall(aServiceId, aCallIndex);
   353   }
   355   return call.forget();
   356 }
   358 NS_IMPL_CYCLE_COLLECTION_CLASS(Telephony)
   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
   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
   376 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(Telephony)
   377 NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper)
   379 NS_IMPL_ADDREF_INHERITED(Telephony, DOMEventTargetHelper)
   380 NS_IMPL_RELEASE_INHERITED(Telephony, DOMEventTargetHelper)
   382 NS_IMPL_ISUPPORTS(Telephony::Listener, nsITelephonyListener)
   383 NS_IMPL_ISUPPORTS(Telephony::Callback, nsITelephonyCallback)
   385 // Telephony WebIDL
   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 }
   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 }
   404 void
   405 Telephony::StartTone(const nsAString& aDTMFChar,
   406                      const Optional<uint32_t>& aServiceId,
   407                      ErrorResult& aRv)
   408 {
   409   uint32_t serviceId = ProvidedOrDefaultServiceId(aServiceId);
   411   if (aDTMFChar.IsEmpty()) {
   412     NS_WARNING("Empty tone string will be ignored");
   413     return;
   414   }
   416   if (aDTMFChar.Length() > 1 || !IsValidServiceId(serviceId)) {
   417     aRv.Throw(NS_ERROR_INVALID_ARG);
   418     return;
   419   }
   421   aRv = mProvider->StartTone(serviceId, aDTMFChar);
   422 }
   424 void
   425 Telephony::StopTone(const Optional<uint32_t>& aServiceId, ErrorResult& aRv)
   426 {
   427   uint32_t serviceId = ProvidedOrDefaultServiceId(aServiceId);
   429   if (!IsValidServiceId(serviceId)) {
   430     aRv.Throw(NS_ERROR_INVALID_ARG);
   431     return;
   432   }
   434   aRv = mProvider->StopTone(serviceId);
   435 }
   437 bool
   438 Telephony::GetMuted(ErrorResult& aRv) const
   439 {
   440   bool muted = false;
   441   aRv = mProvider->GetMicrophoneMuted(&muted);
   443   return muted;
   444 }
   446 void
   447 Telephony::SetMuted(bool aMuted, ErrorResult& aRv)
   448 {
   449   aRv = mProvider->SetMicrophoneMuted(aMuted);
   450 }
   452 bool
   453 Telephony::GetSpeakerEnabled(ErrorResult& aRv) const
   454 {
   455   bool enabled = false;
   456   aRv = mProvider->GetSpeakerEnabled(&enabled);
   458   return enabled;
   459 }
   461 void
   462 Telephony::SetSpeakerEnabled(bool aEnabled, ErrorResult& aRv)
   463 {
   464   aRv = mProvider->SetSpeakerEnabled(aEnabled);
   465 }
   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 }
   479 already_AddRefed<CallsList>
   480 Telephony::Calls() const
   481 {
   482   nsRefPtr<CallsList> list = mCallsList;
   483   return list.forget();
   484 }
   486 already_AddRefed<TelephonyCallGroup>
   487 Telephony::ConferenceGroup() const
   488 {
   489   nsRefPtr<TelephonyCallGroup> group = mGroup;
   490   return group.forget();
   491 }
   493 // EventTarget
   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 }
   504 // nsITelephonyListener
   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);
   515   // Try to use the outgoing call if we don't find the modified call.
   516   if (!modifiedCall) {
   517     nsRefPtr<TelephonyCall> outgoingCall = GetOutgoingCall();
   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   }
   529   if (modifiedCall) {
   530     modifiedCall->UpdateSwitchable(aIsSwitchable);
   531     modifiedCall->UpdateMergeable(aIsMergeable);
   533     if (!aIsConference) {
   534       UpdateActiveCall(modifiedCall, aIsActive);
   535     }
   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     }
   547     nsRefPtr<TelephonyCallGroup> group = modifiedCall->GetGroup();
   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     }
   561     return NS_OK;
   562   }
   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   }
   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!");
   577   NS_ASSERTION(aIsConference ? mGroup->CallsArray().Contains(call) :
   578                                mCalls.Contains(call),
   579                "Should have auto-added new call!");
   581   if (aCallState == nsITelephonyProvider::CALL_STATE_INCOMING) {
   582     nsresult rv = DispatchCallEvent(NS_LITERAL_STRING("incoming"), call);
   583     NS_ENSURE_SUCCESS(rv, rv);
   584   }
   586   return NS_OK;
   587 }
   589 NS_IMETHODIMP
   590 Telephony::ConferenceCallStateChanged(uint16_t aCallState)
   591 {
   592   mGroup->ChangeState(aCallState);
   593   return NS_OK;
   594 }
   596 NS_IMETHODIMP
   597 Telephony::EnumerateCallStateComplete()
   598 {
   599   MOZ_ASSERT(!mEnumerated);
   601   mEnumerated = true;
   603   if (NS_FAILED(NotifyCallsChanged(nullptr))) {
   604     NS_WARNING("Failed to notify calls changed!");
   605   }
   607   if (NS_FAILED(mProvider->RegisterListener(mListener))) {
   608     NS_WARNING("Failed to register listener!");
   609   }
   610   return NS_OK;
   611 }
   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;
   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   }
   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!");
   637   NS_ASSERTION(aIsConference ? mGroup->CallsArray().Contains(call) :
   638                                mCalls.Contains(call),
   639                "Should have auto-added new call!");
   641   return NS_OK;
   642 }
   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   }
   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   }
   667   NS_ENSURE_SUCCESS(rv, rv);
   668   return NS_OK;
   669 }
   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   }
   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   }
   687   UpdateActiveCall(callToNotify, false);
   689   // Set the call state to 'disconnected' and remove it from the calls list.
   690   callToNotify->NotifyError(aError);
   692   return NS_OK;
   693 }
   695 NS_IMETHODIMP
   696 Telephony::NotifyCdmaCallWaiting(uint32_t aServiceId, const nsAString& aNumber)
   697 {
   698   MOZ_ASSERT(mCalls.Length() == 1);
   700   nsRefPtr<TelephonyCall> callToNotify = mCalls[0];
   701   MOZ_ASSERT(callToNotify && callToNotify->ServiceId() == aServiceId);
   703   callToNotify->UpdateSecondNumber(aNumber);
   704   DispatchCallEvent(NS_LITERAL_STRING("callschanged"), callToNotify);
   705   return NS_OK;
   706 }
   708 NS_IMETHODIMP
   709 Telephony::NotifyConferenceError(const nsAString& aName,
   710                                  const nsAString& aMessage)
   711 {
   712   mGroup->NotifyError(aName, aMessage);
   713   return NS_OK;
   714 }
   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"));
   728   nsRefPtr<CallEvent> event = CallEvent::Create(this, aType, aCall, false, false);
   730   return DispatchTrustedEvent(event);
   731 }
   733 void
   734 Telephony::EnqueueEnumerationAck()
   735 {
   736   if (!mEnumerated) {
   737     return;
   738   }
   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