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.

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

mercurial