dom/telephony/TelephonyCall.cpp

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

michael@0 1 /* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
michael@0 2 /* vim: set ts=2 et sw=2 tw=40: */
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 "TelephonyCall.h"
michael@0 8 #include "mozilla/dom/TelephonyCallBinding.h"
michael@0 9
michael@0 10 #include "mozilla/dom/DOMError.h"
michael@0 11
michael@0 12 #include "CallEvent.h"
michael@0 13 #include "Telephony.h"
michael@0 14 #include "TelephonyCallGroup.h"
michael@0 15
michael@0 16 using namespace mozilla::dom;
michael@0 17 using mozilla::ErrorResult;
michael@0 18 using mozilla::dom::telephony::kOutgoingPlaceholderCallIndex;
michael@0 19
michael@0 20 // static
michael@0 21 already_AddRefed<TelephonyCall>
michael@0 22 TelephonyCall::Create(Telephony* aTelephony, uint32_t aServiceId,
michael@0 23 const nsAString& aNumber, uint16_t aCallState,
michael@0 24 uint32_t aCallIndex, bool aEmergency, bool aIsConference,
michael@0 25 bool aSwitchable, bool aMergeable)
michael@0 26 {
michael@0 27 NS_ASSERTION(aTelephony, "Null pointer!");
michael@0 28 NS_ASSERTION(!aNumber.IsEmpty(), "Empty number!");
michael@0 29 NS_ASSERTION(aCallIndex >= 1, "Invalid call index!");
michael@0 30
michael@0 31 nsRefPtr<TelephonyCall> call = new TelephonyCall(aTelephony->GetOwner());
michael@0 32
michael@0 33 call->mTelephony = aTelephony;
michael@0 34 call->mServiceId = aServiceId;
michael@0 35 call->mNumber = aNumber;
michael@0 36 call->mCallIndex = aCallIndex;
michael@0 37 call->mError = nullptr;
michael@0 38 call->mEmergency = aEmergency;
michael@0 39 call->mGroup = aIsConference ? aTelephony->ConferenceGroup() : nullptr;
michael@0 40 call->mSwitchable = aSwitchable;
michael@0 41 call->mMergeable = aMergeable;
michael@0 42
michael@0 43 call->ChangeStateInternal(aCallState, false);
michael@0 44
michael@0 45 return call.forget();
michael@0 46 }
michael@0 47
michael@0 48 TelephonyCall::TelephonyCall(nsPIDOMWindow* aOwner)
michael@0 49 : DOMEventTargetHelper(aOwner),
michael@0 50 mCallIndex(kOutgoingPlaceholderCallIndex),
michael@0 51 mCallState(nsITelephonyProvider::CALL_STATE_UNKNOWN),
michael@0 52 mLive(false)
michael@0 53 {
michael@0 54 }
michael@0 55
michael@0 56 TelephonyCall::~TelephonyCall()
michael@0 57 {
michael@0 58 }
michael@0 59
michael@0 60 JSObject*
michael@0 61 TelephonyCall::WrapObject(JSContext* aCx)
michael@0 62 {
michael@0 63 return TelephonyCallBinding::Wrap(aCx, this);
michael@0 64 }
michael@0 65
michael@0 66 void
michael@0 67 TelephonyCall::ChangeStateInternal(uint16_t aCallState, bool aFireEvents)
michael@0 68 {
michael@0 69 nsRefPtr<TelephonyCall> kungFuDeathGrip(this);
michael@0 70
michael@0 71 nsString stateString;
michael@0 72 switch (aCallState) {
michael@0 73 case nsITelephonyProvider::CALL_STATE_DIALING:
michael@0 74 stateString.AssignLiteral("dialing");
michael@0 75 break;
michael@0 76 case nsITelephonyProvider::CALL_STATE_ALERTING:
michael@0 77 stateString.AssignLiteral("alerting");
michael@0 78 break;
michael@0 79 case nsITelephonyProvider::CALL_STATE_CONNECTING:
michael@0 80 stateString.AssignLiteral("connecting");
michael@0 81 break;
michael@0 82 case nsITelephonyProvider::CALL_STATE_CONNECTED:
michael@0 83 stateString.AssignLiteral("connected");
michael@0 84 break;
michael@0 85 case nsITelephonyProvider::CALL_STATE_HOLDING:
michael@0 86 stateString.AssignLiteral("holding");
michael@0 87 break;
michael@0 88 case nsITelephonyProvider::CALL_STATE_HELD:
michael@0 89 stateString.AssignLiteral("held");
michael@0 90 break;
michael@0 91 case nsITelephonyProvider::CALL_STATE_RESUMING:
michael@0 92 stateString.AssignLiteral("resuming");
michael@0 93 break;
michael@0 94 case nsITelephonyProvider::CALL_STATE_DISCONNECTING:
michael@0 95 stateString.AssignLiteral("disconnecting");
michael@0 96 break;
michael@0 97 case nsITelephonyProvider::CALL_STATE_DISCONNECTED:
michael@0 98 stateString.AssignLiteral("disconnected");
michael@0 99 break;
michael@0 100 case nsITelephonyProvider::CALL_STATE_INCOMING:
michael@0 101 stateString.AssignLiteral("incoming");
michael@0 102 break;
michael@0 103 default:
michael@0 104 NS_NOTREACHED("Unknown state!");
michael@0 105 }
michael@0 106
michael@0 107 mState = stateString;
michael@0 108 mCallState = aCallState;
michael@0 109
michael@0 110 if (aCallState == nsITelephonyProvider::CALL_STATE_DISCONNECTED) {
michael@0 111 NS_ASSERTION(mLive, "Should be live!");
michael@0 112 mLive = false;
michael@0 113 if (mGroup) {
michael@0 114 mGroup->RemoveCall(this);
michael@0 115 } else {
michael@0 116 mTelephony->RemoveCall(this);
michael@0 117 }
michael@0 118 } else if (!mLive) {
michael@0 119 mLive = true;
michael@0 120 if (mGroup) {
michael@0 121 mGroup->AddCall(this);
michael@0 122 } else {
michael@0 123 mTelephony->AddCall(this);
michael@0 124 }
michael@0 125 }
michael@0 126
michael@0 127 if (aFireEvents) {
michael@0 128 nsresult rv = DispatchCallEvent(NS_LITERAL_STRING("statechange"), this);
michael@0 129 if (NS_FAILED(rv)) {
michael@0 130 NS_WARNING("Failed to dispatch specific event!");
michael@0 131 }
michael@0 132
michael@0 133 // This can change if the statechange handler called back here... Need to
michael@0 134 // figure out something smarter.
michael@0 135 if (mCallState == aCallState) {
michael@0 136 rv = DispatchCallEvent(stateString, this);
michael@0 137 if (NS_FAILED(rv)) {
michael@0 138 NS_WARNING("Failed to dispatch specific event!");
michael@0 139 }
michael@0 140 }
michael@0 141 }
michael@0 142 }
michael@0 143
michael@0 144 nsresult
michael@0 145 TelephonyCall::DispatchCallEvent(const nsAString& aType,
michael@0 146 TelephonyCall* aCall)
michael@0 147 {
michael@0 148 MOZ_ASSERT(aCall);
michael@0 149
michael@0 150 nsRefPtr<CallEvent> event = CallEvent::Create(this, aType, aCall, false, false);
michael@0 151
michael@0 152 return DispatchTrustedEvent(event);
michael@0 153 }
michael@0 154
michael@0 155 void
michael@0 156 TelephonyCall::NotifyError(const nsAString& aError)
michael@0 157 {
michael@0 158 // Set the error string
michael@0 159 NS_ASSERTION(!mError, "Already have an error?");
michael@0 160
michael@0 161 mError = new DOMError(GetOwner(), aError);
michael@0 162
michael@0 163 // Do the state transitions
michael@0 164 ChangeStateInternal(nsITelephonyProvider::CALL_STATE_DISCONNECTED, true);
michael@0 165
michael@0 166 nsresult rv = DispatchCallEvent(NS_LITERAL_STRING("error"), this);
michael@0 167 if (NS_FAILED(rv)) {
michael@0 168 NS_WARNING("Failed to dispatch error event!");
michael@0 169 }
michael@0 170 }
michael@0 171
michael@0 172 void
michael@0 173 TelephonyCall::ChangeGroup(TelephonyCallGroup* aGroup)
michael@0 174 {
michael@0 175 mGroup = aGroup;
michael@0 176
michael@0 177 nsresult rv = DispatchCallEvent(NS_LITERAL_STRING("groupchange"), this);
michael@0 178 if (NS_FAILED(rv)) {
michael@0 179 NS_WARNING("Failed to dispatch error event!");
michael@0 180 }
michael@0 181 }
michael@0 182
michael@0 183 NS_IMPL_CYCLE_COLLECTION_INHERITED(TelephonyCall,
michael@0 184 DOMEventTargetHelper,
michael@0 185 mTelephony,
michael@0 186 mError,
michael@0 187 mGroup);
michael@0 188
michael@0 189 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(TelephonyCall)
michael@0 190 NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper)
michael@0 191
michael@0 192 NS_IMPL_ADDREF_INHERITED(TelephonyCall, DOMEventTargetHelper)
michael@0 193 NS_IMPL_RELEASE_INHERITED(TelephonyCall, DOMEventTargetHelper)
michael@0 194
michael@0 195 // TelephonyCall WebIDL
michael@0 196
michael@0 197 already_AddRefed<DOMError>
michael@0 198 TelephonyCall::GetError() const
michael@0 199 {
michael@0 200 nsRefPtr<DOMError> error = mError;
michael@0 201 return error.forget();
michael@0 202 }
michael@0 203
michael@0 204 already_AddRefed<TelephonyCallGroup>
michael@0 205 TelephonyCall::GetGroup() const
michael@0 206 {
michael@0 207 nsRefPtr<TelephonyCallGroup> group = mGroup;
michael@0 208 return group.forget();
michael@0 209 }
michael@0 210
michael@0 211 void
michael@0 212 TelephonyCall::Answer(ErrorResult& aRv)
michael@0 213 {
michael@0 214 if (mCallState != nsITelephonyProvider::CALL_STATE_INCOMING) {
michael@0 215 NS_WARNING("Answer on non-incoming call ignored!");
michael@0 216 return;
michael@0 217 }
michael@0 218
michael@0 219 nsresult rv = mTelephony->Provider()->AnswerCall(mServiceId, mCallIndex);
michael@0 220 if (NS_FAILED(rv)) {
michael@0 221 aRv.Throw(rv);
michael@0 222 return;
michael@0 223 }
michael@0 224
michael@0 225 ChangeStateInternal(nsITelephonyProvider::CALL_STATE_CONNECTING, true);
michael@0 226 }
michael@0 227
michael@0 228 void
michael@0 229 TelephonyCall::HangUp(ErrorResult& aRv)
michael@0 230 {
michael@0 231 if (mCallState == nsITelephonyProvider::CALL_STATE_DISCONNECTING ||
michael@0 232 mCallState == nsITelephonyProvider::CALL_STATE_DISCONNECTED) {
michael@0 233 NS_WARNING("HangUp on previously disconnected call ignored!");
michael@0 234 return;
michael@0 235 }
michael@0 236
michael@0 237 nsresult rv = mCallState == nsITelephonyProvider::CALL_STATE_INCOMING ?
michael@0 238 mTelephony->Provider()->RejectCall(mServiceId, mCallIndex) :
michael@0 239 mTelephony->Provider()->HangUp(mServiceId, mCallIndex);
michael@0 240 if (NS_FAILED(rv)) {
michael@0 241 aRv.Throw(rv);
michael@0 242 return;
michael@0 243 }
michael@0 244
michael@0 245 ChangeStateInternal(nsITelephonyProvider::CALL_STATE_DISCONNECTING, true);
michael@0 246 }
michael@0 247
michael@0 248 void
michael@0 249 TelephonyCall::Hold(ErrorResult& aRv)
michael@0 250 {
michael@0 251 if (mCallState != nsITelephonyProvider::CALL_STATE_CONNECTED) {
michael@0 252 NS_WARNING("Hold non-connected call ignored!");
michael@0 253 return;
michael@0 254 }
michael@0 255
michael@0 256 if (mGroup) {
michael@0 257 NS_WARNING("Hold a call in conference ignored!");
michael@0 258 return;
michael@0 259 }
michael@0 260
michael@0 261 if (!mSwitchable) {
michael@0 262 NS_WARNING("Hold a non-switchable call ignored!");
michael@0 263 return;
michael@0 264 }
michael@0 265
michael@0 266 nsresult rv = mTelephony->Provider()->HoldCall(mServiceId, mCallIndex);
michael@0 267 if (NS_FAILED(rv)) {
michael@0 268 aRv.Throw(rv);
michael@0 269 return;
michael@0 270 }
michael@0 271
michael@0 272 if (!mSecondNumber.IsEmpty()) {
michael@0 273 // No state transition when we switch two numbers within one TelephonyCall
michael@0 274 // object. Otherwise, the state here will be inconsistent with the backend
michael@0 275 // RIL and will never be right.
michael@0 276 return;
michael@0 277 }
michael@0 278
michael@0 279 ChangeStateInternal(nsITelephonyProvider::CALL_STATE_HOLDING, true);
michael@0 280 }
michael@0 281
michael@0 282 void
michael@0 283 TelephonyCall::Resume(ErrorResult& aRv)
michael@0 284 {
michael@0 285 if (mCallState != nsITelephonyProvider::CALL_STATE_HELD) {
michael@0 286 NS_WARNING("Resume non-held call ignored!");
michael@0 287 return;
michael@0 288 }
michael@0 289
michael@0 290 if (mGroup) {
michael@0 291 NS_WARNING("Resume a call in conference ignored!");
michael@0 292 return;
michael@0 293 }
michael@0 294
michael@0 295 if (!mSwitchable) {
michael@0 296 NS_WARNING("Resume a non-switchable call ignored!");
michael@0 297 return;
michael@0 298 }
michael@0 299
michael@0 300 nsresult rv = mTelephony->Provider()->ResumeCall(mServiceId, mCallIndex);
michael@0 301 if (NS_FAILED(rv)) {
michael@0 302 aRv.Throw(rv);
michael@0 303 return;
michael@0 304 }
michael@0 305
michael@0 306 ChangeStateInternal(nsITelephonyProvider::CALL_STATE_RESUMING, true);
michael@0 307 }

mercurial