1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/dom/telephony/TelephonyCallGroup.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,311 @@ 1.4 +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ 1.6 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.9 + 1.10 +#include "TelephonyCallGroup.h" 1.11 +#include "mozilla/dom/TelephonyCallGroupBinding.h" 1.12 + 1.13 +#include "CallEvent.h" 1.14 +#include "CallsList.h" 1.15 +#include "mozilla/dom/CallGroupErrorEvent.h" 1.16 +#include "Telephony.h" 1.17 + 1.18 +using namespace mozilla::dom; 1.19 +using mozilla::ErrorResult; 1.20 + 1.21 +TelephonyCallGroup::TelephonyCallGroup(nsPIDOMWindow* aOwner) 1.22 + : DOMEventTargetHelper(aOwner) 1.23 + , mCallState(nsITelephonyProvider::CALL_STATE_UNKNOWN) 1.24 +{ 1.25 +} 1.26 + 1.27 +TelephonyCallGroup::~TelephonyCallGroup() 1.28 +{ 1.29 +} 1.30 + 1.31 +// static 1.32 +already_AddRefed<TelephonyCallGroup> 1.33 +TelephonyCallGroup::Create(Telephony* aTelephony) 1.34 +{ 1.35 + NS_ASSERTION(aTelephony, "Null telephony!"); 1.36 + 1.37 + nsRefPtr<TelephonyCallGroup> group = 1.38 + new TelephonyCallGroup(aTelephony->GetOwner()); 1.39 + 1.40 + group->mTelephony = aTelephony; 1.41 + group->mCallsList = new CallsList(aTelephony, group); 1.42 + 1.43 + return group.forget(); 1.44 +} 1.45 + 1.46 +JSObject* 1.47 +TelephonyCallGroup::WrapObject(JSContext* aCx) 1.48 +{ 1.49 + return TelephonyCallGroupBinding::Wrap(aCx, this); 1.50 +} 1.51 + 1.52 +void 1.53 +TelephonyCallGroup::AddCall(TelephonyCall* aCall) 1.54 +{ 1.55 + NS_ASSERTION(!mCalls.Contains(aCall), "Already know about this one!"); 1.56 + mCalls.AppendElement(aCall); 1.57 + aCall->ChangeGroup(this); 1.58 + NotifyCallsChanged(aCall); 1.59 +} 1.60 + 1.61 +void 1.62 +TelephonyCallGroup::RemoveCall(TelephonyCall* aCall) 1.63 +{ 1.64 + NS_ASSERTION(mCalls.Contains(aCall), "Didn't know about this one!"); 1.65 + mCalls.RemoveElement(aCall); 1.66 + aCall->ChangeGroup(nullptr); 1.67 + NotifyCallsChanged(aCall); 1.68 +} 1.69 + 1.70 +nsresult 1.71 +TelephonyCallGroup::NotifyError(const nsAString& aName, const nsAString& aMessage) 1.72 +{ 1.73 + CallGroupErrorEventInit init; 1.74 + init.mBubbles = false; 1.75 + init.mCancelable = false; 1.76 + init.mName = aName; 1.77 + init.mMessage = aMessage; 1.78 + 1.79 + nsRefPtr<CallGroupErrorEvent> event = 1.80 + CallGroupErrorEvent::Constructor(this, NS_LITERAL_STRING("error"), init); 1.81 + 1.82 + return DispatchTrustedEvent(event); 1.83 +} 1.84 + 1.85 +void 1.86 +TelephonyCallGroup::ChangeState(uint16_t aCallState) 1.87 +{ 1.88 + if (mCallState == aCallState) { 1.89 + return; 1.90 + } 1.91 + 1.92 + nsString stateString; 1.93 + switch (aCallState) { 1.94 + case nsITelephonyProvider::CALL_STATE_UNKNOWN: 1.95 + break; 1.96 + case nsITelephonyProvider::CALL_STATE_CONNECTED: 1.97 + stateString.AssignLiteral("connected"); 1.98 + break; 1.99 + case nsITelephonyProvider::CALL_STATE_HOLDING: 1.100 + stateString.AssignLiteral("holding"); 1.101 + break; 1.102 + case nsITelephonyProvider::CALL_STATE_HELD: 1.103 + stateString.AssignLiteral("held"); 1.104 + break; 1.105 + case nsITelephonyProvider::CALL_STATE_RESUMING: 1.106 + stateString.AssignLiteral("resuming"); 1.107 + break; 1.108 + default: 1.109 + NS_NOTREACHED("Unknown state!"); 1.110 + } 1.111 + 1.112 + mState = stateString; 1.113 + mCallState = aCallState; 1.114 + 1.115 + nsresult rv = DispatchCallEvent(NS_LITERAL_STRING("statechange"), nullptr); 1.116 + if (NS_FAILED(rv)) { 1.117 + NS_WARNING("Failed to dispatch specific event!"); 1.118 + } 1.119 + if (!stateString.IsEmpty()) { 1.120 + // This can change if the statechange handler called back here... Need to 1.121 + // figure out something smarter. 1.122 + if (mCallState == aCallState) { 1.123 + rv = DispatchCallEvent(stateString, nullptr); 1.124 + if (NS_FAILED(rv)) { 1.125 + NS_WARNING("Failed to dispatch specific event!"); 1.126 + } 1.127 + } 1.128 + } 1.129 + 1.130 + for (uint32_t index = 0; index < mCalls.Length(); index++) { 1.131 + nsRefPtr<TelephonyCall> call = mCalls[index]; 1.132 + call->ChangeState(aCallState); 1.133 + 1.134 + MOZ_ASSERT(call->CallState() == aCallState); 1.135 + } 1.136 +} 1.137 + 1.138 +nsresult 1.139 +TelephonyCallGroup::NotifyCallsChanged(TelephonyCall* aCall) 1.140 +{ 1.141 + return DispatchCallEvent(NS_LITERAL_STRING("callschanged"), aCall); 1.142 +} 1.143 + 1.144 +nsresult 1.145 +TelephonyCallGroup::DispatchCallEvent(const nsAString& aType, 1.146 + TelephonyCall* aCall) 1.147 +{ 1.148 + nsRefPtr<CallEvent> event = CallEvent::Create(this, aType, aCall, false, false); 1.149 + return DispatchTrustedEvent(event); 1.150 +} 1.151 + 1.152 +bool 1.153 +TelephonyCallGroup::CanConference(const TelephonyCall& aCall, 1.154 + TelephonyCall* aSecondCall) 1.155 +{ 1.156 + if (!aCall.Mergeable()) { 1.157 + return false; 1.158 + } 1.159 + 1.160 + if (!aSecondCall) { 1.161 + MOZ_ASSERT(!mCalls.IsEmpty()); 1.162 + 1.163 + return (mCallState == nsITelephonyProvider::CALL_STATE_CONNECTED && 1.164 + aCall.CallState() == nsITelephonyProvider::CALL_STATE_HELD) || 1.165 + (mCallState == nsITelephonyProvider::CALL_STATE_HELD && 1.166 + aCall.CallState() == nsITelephonyProvider::CALL_STATE_CONNECTED); 1.167 + } 1.168 + 1.169 + MOZ_ASSERT(mCallState == nsITelephonyProvider::CALL_STATE_UNKNOWN); 1.170 + 1.171 + if (aCall.ServiceId() != aSecondCall->ServiceId()) { 1.172 + return false; 1.173 + } 1.174 + 1.175 + if (!aSecondCall->Mergeable()) { 1.176 + return false; 1.177 + } 1.178 + 1.179 + return (aCall.CallState() == nsITelephonyProvider::CALL_STATE_CONNECTED && 1.180 + aSecondCall->CallState() == nsITelephonyProvider::CALL_STATE_HELD) || 1.181 + (aCall.CallState() == nsITelephonyProvider::CALL_STATE_HELD && 1.182 + aSecondCall->CallState() == nsITelephonyProvider::CALL_STATE_CONNECTED); 1.183 +} 1.184 + 1.185 +already_AddRefed<TelephonyCall> 1.186 +TelephonyCallGroup::GetCall(uint32_t aServiceId, uint32_t aCallIndex) 1.187 +{ 1.188 + nsRefPtr<TelephonyCall> call; 1.189 + 1.190 + for (uint32_t index = 0; index < mCalls.Length(); index++) { 1.191 + nsRefPtr<TelephonyCall>& tempCall = mCalls[index]; 1.192 + if (tempCall->ServiceId() == aServiceId && 1.193 + tempCall->CallIndex() == aCallIndex) { 1.194 + call = tempCall; 1.195 + break; 1.196 + } 1.197 + } 1.198 + 1.199 + return call.forget(); 1.200 +} 1.201 + 1.202 +NS_IMPL_CYCLE_COLLECTION_CLASS(TelephonyCallGroup) 1.203 + 1.204 +NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(TelephonyCallGroup, 1.205 + DOMEventTargetHelper) 1.206 + NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mCalls) 1.207 + NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mCallsList) 1.208 + NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mTelephony) 1.209 +NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END 1.210 + 1.211 +NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(TelephonyCallGroup, 1.212 + DOMEventTargetHelper) 1.213 + NS_IMPL_CYCLE_COLLECTION_UNLINK(mCalls) 1.214 + NS_IMPL_CYCLE_COLLECTION_UNLINK(mCallsList) 1.215 + NS_IMPL_CYCLE_COLLECTION_UNLINK(mTelephony) 1.216 +NS_IMPL_CYCLE_COLLECTION_UNLINK_END 1.217 + 1.218 +NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(TelephonyCallGroup) 1.219 +NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper) 1.220 + 1.221 +NS_IMPL_ADDREF_INHERITED(TelephonyCallGroup, DOMEventTargetHelper) 1.222 +NS_IMPL_RELEASE_INHERITED(TelephonyCallGroup, DOMEventTargetHelper) 1.223 + 1.224 +// WebIDL 1.225 +already_AddRefed<CallsList> 1.226 +TelephonyCallGroup::Calls() const 1.227 +{ 1.228 + nsRefPtr<CallsList> list = mCallsList; 1.229 + return list.forget(); 1.230 +} 1.231 + 1.232 +void 1.233 +TelephonyCallGroup::Add(TelephonyCall& aCall, 1.234 + ErrorResult& aRv) 1.235 +{ 1.236 + if (!CanConference(aCall, nullptr)) { 1.237 + aRv.Throw(NS_ERROR_NOT_AVAILABLE); 1.238 + return; 1.239 + } 1.240 + 1.241 + aRv = mTelephony->Provider()->ConferenceCall(aCall.ServiceId()); 1.242 +} 1.243 + 1.244 +void 1.245 +TelephonyCallGroup::Add(TelephonyCall& aCall, 1.246 + TelephonyCall& aSecondCall, 1.247 + ErrorResult& aRv) 1.248 +{ 1.249 + if (!CanConference(aCall, &aSecondCall)) { 1.250 + aRv.Throw(NS_ERROR_NOT_AVAILABLE); 1.251 + return; 1.252 + } 1.253 + 1.254 + aRv = mTelephony->Provider()->ConferenceCall(aCall.ServiceId()); 1.255 +} 1.256 + 1.257 +void 1.258 +TelephonyCallGroup::Remove(TelephonyCall& aCall, ErrorResult& aRv) 1.259 +{ 1.260 + if (mCallState != nsITelephonyProvider::CALL_STATE_CONNECTED) { 1.261 + NS_WARNING("Remove call from a non-connected call group. Ignore!"); 1.262 + return; 1.263 + } 1.264 + 1.265 + uint32_t serviceId = aCall.ServiceId(); 1.266 + uint32_t callIndex = aCall.CallIndex(); 1.267 + 1.268 + nsRefPtr<TelephonyCall> call; 1.269 + 1.270 + call = GetCall(serviceId, callIndex); 1.271 + if (call) { 1.272 + aRv = mTelephony->Provider()->SeparateCall(serviceId, callIndex); 1.273 + } else { 1.274 + NS_WARNING("Didn't have this call. Ignore!"); 1.275 + } 1.276 +} 1.277 + 1.278 +void 1.279 +TelephonyCallGroup::Hold(ErrorResult& aRv) 1.280 +{ 1.281 + if (mCallState != nsITelephonyProvider::CALL_STATE_CONNECTED) { 1.282 + NS_WARNING("Hold non-connected call ignored!"); 1.283 + return; 1.284 + } 1.285 + 1.286 + MOZ_ASSERT(!mCalls.IsEmpty()); 1.287 + 1.288 + nsresult rv = mTelephony->Provider()->HoldConference(mCalls[0]->ServiceId()); 1.289 + if (NS_FAILED(rv)) { 1.290 + aRv.Throw(rv); 1.291 + return; 1.292 + } 1.293 + 1.294 + ChangeState(nsITelephonyProvider::CALL_STATE_HOLDING); 1.295 +} 1.296 + 1.297 +void 1.298 +TelephonyCallGroup::Resume(ErrorResult& aRv) 1.299 +{ 1.300 + if (mCallState != nsITelephonyProvider::CALL_STATE_HELD) { 1.301 + NS_WARNING("Resume non-held call ignored!"); 1.302 + return; 1.303 + } 1.304 + 1.305 + MOZ_ASSERT(!mCalls.IsEmpty()); 1.306 + 1.307 + nsresult rv = mTelephony->Provider()->ResumeConference(mCalls[0]->ServiceId()); 1.308 + if (NS_FAILED(rv)) { 1.309 + aRv.Throw(rv); 1.310 + return; 1.311 + } 1.312 + 1.313 + ChangeState(nsITelephonyProvider::CALL_STATE_RESUMING); 1.314 +}