dom/telephony/TelephonyCallGroup.cpp

branch
TOR_BUG_3246
changeset 7
129ffea94266
equal deleted inserted replaced
-1:000000000000 0:1822761b1bd8
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 "TelephonyCallGroup.h"
8 #include "mozilla/dom/TelephonyCallGroupBinding.h"
9
10 #include "CallEvent.h"
11 #include "CallsList.h"
12 #include "mozilla/dom/CallGroupErrorEvent.h"
13 #include "Telephony.h"
14
15 using namespace mozilla::dom;
16 using mozilla::ErrorResult;
17
18 TelephonyCallGroup::TelephonyCallGroup(nsPIDOMWindow* aOwner)
19 : DOMEventTargetHelper(aOwner)
20 , mCallState(nsITelephonyProvider::CALL_STATE_UNKNOWN)
21 {
22 }
23
24 TelephonyCallGroup::~TelephonyCallGroup()
25 {
26 }
27
28 // static
29 already_AddRefed<TelephonyCallGroup>
30 TelephonyCallGroup::Create(Telephony* aTelephony)
31 {
32 NS_ASSERTION(aTelephony, "Null telephony!");
33
34 nsRefPtr<TelephonyCallGroup> group =
35 new TelephonyCallGroup(aTelephony->GetOwner());
36
37 group->mTelephony = aTelephony;
38 group->mCallsList = new CallsList(aTelephony, group);
39
40 return group.forget();
41 }
42
43 JSObject*
44 TelephonyCallGroup::WrapObject(JSContext* aCx)
45 {
46 return TelephonyCallGroupBinding::Wrap(aCx, this);
47 }
48
49 void
50 TelephonyCallGroup::AddCall(TelephonyCall* aCall)
51 {
52 NS_ASSERTION(!mCalls.Contains(aCall), "Already know about this one!");
53 mCalls.AppendElement(aCall);
54 aCall->ChangeGroup(this);
55 NotifyCallsChanged(aCall);
56 }
57
58 void
59 TelephonyCallGroup::RemoveCall(TelephonyCall* aCall)
60 {
61 NS_ASSERTION(mCalls.Contains(aCall), "Didn't know about this one!");
62 mCalls.RemoveElement(aCall);
63 aCall->ChangeGroup(nullptr);
64 NotifyCallsChanged(aCall);
65 }
66
67 nsresult
68 TelephonyCallGroup::NotifyError(const nsAString& aName, const nsAString& aMessage)
69 {
70 CallGroupErrorEventInit init;
71 init.mBubbles = false;
72 init.mCancelable = false;
73 init.mName = aName;
74 init.mMessage = aMessage;
75
76 nsRefPtr<CallGroupErrorEvent> event =
77 CallGroupErrorEvent::Constructor(this, NS_LITERAL_STRING("error"), init);
78
79 return DispatchTrustedEvent(event);
80 }
81
82 void
83 TelephonyCallGroup::ChangeState(uint16_t aCallState)
84 {
85 if (mCallState == aCallState) {
86 return;
87 }
88
89 nsString stateString;
90 switch (aCallState) {
91 case nsITelephonyProvider::CALL_STATE_UNKNOWN:
92 break;
93 case nsITelephonyProvider::CALL_STATE_CONNECTED:
94 stateString.AssignLiteral("connected");
95 break;
96 case nsITelephonyProvider::CALL_STATE_HOLDING:
97 stateString.AssignLiteral("holding");
98 break;
99 case nsITelephonyProvider::CALL_STATE_HELD:
100 stateString.AssignLiteral("held");
101 break;
102 case nsITelephonyProvider::CALL_STATE_RESUMING:
103 stateString.AssignLiteral("resuming");
104 break;
105 default:
106 NS_NOTREACHED("Unknown state!");
107 }
108
109 mState = stateString;
110 mCallState = aCallState;
111
112 nsresult rv = DispatchCallEvent(NS_LITERAL_STRING("statechange"), nullptr);
113 if (NS_FAILED(rv)) {
114 NS_WARNING("Failed to dispatch specific event!");
115 }
116 if (!stateString.IsEmpty()) {
117 // This can change if the statechange handler called back here... Need to
118 // figure out something smarter.
119 if (mCallState == aCallState) {
120 rv = DispatchCallEvent(stateString, nullptr);
121 if (NS_FAILED(rv)) {
122 NS_WARNING("Failed to dispatch specific event!");
123 }
124 }
125 }
126
127 for (uint32_t index = 0; index < mCalls.Length(); index++) {
128 nsRefPtr<TelephonyCall> call = mCalls[index];
129 call->ChangeState(aCallState);
130
131 MOZ_ASSERT(call->CallState() == aCallState);
132 }
133 }
134
135 nsresult
136 TelephonyCallGroup::NotifyCallsChanged(TelephonyCall* aCall)
137 {
138 return DispatchCallEvent(NS_LITERAL_STRING("callschanged"), aCall);
139 }
140
141 nsresult
142 TelephonyCallGroup::DispatchCallEvent(const nsAString& aType,
143 TelephonyCall* aCall)
144 {
145 nsRefPtr<CallEvent> event = CallEvent::Create(this, aType, aCall, false, false);
146 return DispatchTrustedEvent(event);
147 }
148
149 bool
150 TelephonyCallGroup::CanConference(const TelephonyCall& aCall,
151 TelephonyCall* aSecondCall)
152 {
153 if (!aCall.Mergeable()) {
154 return false;
155 }
156
157 if (!aSecondCall) {
158 MOZ_ASSERT(!mCalls.IsEmpty());
159
160 return (mCallState == nsITelephonyProvider::CALL_STATE_CONNECTED &&
161 aCall.CallState() == nsITelephonyProvider::CALL_STATE_HELD) ||
162 (mCallState == nsITelephonyProvider::CALL_STATE_HELD &&
163 aCall.CallState() == nsITelephonyProvider::CALL_STATE_CONNECTED);
164 }
165
166 MOZ_ASSERT(mCallState == nsITelephonyProvider::CALL_STATE_UNKNOWN);
167
168 if (aCall.ServiceId() != aSecondCall->ServiceId()) {
169 return false;
170 }
171
172 if (!aSecondCall->Mergeable()) {
173 return false;
174 }
175
176 return (aCall.CallState() == nsITelephonyProvider::CALL_STATE_CONNECTED &&
177 aSecondCall->CallState() == nsITelephonyProvider::CALL_STATE_HELD) ||
178 (aCall.CallState() == nsITelephonyProvider::CALL_STATE_HELD &&
179 aSecondCall->CallState() == nsITelephonyProvider::CALL_STATE_CONNECTED);
180 }
181
182 already_AddRefed<TelephonyCall>
183 TelephonyCallGroup::GetCall(uint32_t aServiceId, uint32_t aCallIndex)
184 {
185 nsRefPtr<TelephonyCall> call;
186
187 for (uint32_t index = 0; index < mCalls.Length(); index++) {
188 nsRefPtr<TelephonyCall>& tempCall = mCalls[index];
189 if (tempCall->ServiceId() == aServiceId &&
190 tempCall->CallIndex() == aCallIndex) {
191 call = tempCall;
192 break;
193 }
194 }
195
196 return call.forget();
197 }
198
199 NS_IMPL_CYCLE_COLLECTION_CLASS(TelephonyCallGroup)
200
201 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(TelephonyCallGroup,
202 DOMEventTargetHelper)
203 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mCalls)
204 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mCallsList)
205 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mTelephony)
206 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
207
208 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(TelephonyCallGroup,
209 DOMEventTargetHelper)
210 NS_IMPL_CYCLE_COLLECTION_UNLINK(mCalls)
211 NS_IMPL_CYCLE_COLLECTION_UNLINK(mCallsList)
212 NS_IMPL_CYCLE_COLLECTION_UNLINK(mTelephony)
213 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
214
215 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(TelephonyCallGroup)
216 NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper)
217
218 NS_IMPL_ADDREF_INHERITED(TelephonyCallGroup, DOMEventTargetHelper)
219 NS_IMPL_RELEASE_INHERITED(TelephonyCallGroup, DOMEventTargetHelper)
220
221 // WebIDL
222 already_AddRefed<CallsList>
223 TelephonyCallGroup::Calls() const
224 {
225 nsRefPtr<CallsList> list = mCallsList;
226 return list.forget();
227 }
228
229 void
230 TelephonyCallGroup::Add(TelephonyCall& aCall,
231 ErrorResult& aRv)
232 {
233 if (!CanConference(aCall, nullptr)) {
234 aRv.Throw(NS_ERROR_NOT_AVAILABLE);
235 return;
236 }
237
238 aRv = mTelephony->Provider()->ConferenceCall(aCall.ServiceId());
239 }
240
241 void
242 TelephonyCallGroup::Add(TelephonyCall& aCall,
243 TelephonyCall& aSecondCall,
244 ErrorResult& aRv)
245 {
246 if (!CanConference(aCall, &aSecondCall)) {
247 aRv.Throw(NS_ERROR_NOT_AVAILABLE);
248 return;
249 }
250
251 aRv = mTelephony->Provider()->ConferenceCall(aCall.ServiceId());
252 }
253
254 void
255 TelephonyCallGroup::Remove(TelephonyCall& aCall, ErrorResult& aRv)
256 {
257 if (mCallState != nsITelephonyProvider::CALL_STATE_CONNECTED) {
258 NS_WARNING("Remove call from a non-connected call group. Ignore!");
259 return;
260 }
261
262 uint32_t serviceId = aCall.ServiceId();
263 uint32_t callIndex = aCall.CallIndex();
264
265 nsRefPtr<TelephonyCall> call;
266
267 call = GetCall(serviceId, callIndex);
268 if (call) {
269 aRv = mTelephony->Provider()->SeparateCall(serviceId, callIndex);
270 } else {
271 NS_WARNING("Didn't have this call. Ignore!");
272 }
273 }
274
275 void
276 TelephonyCallGroup::Hold(ErrorResult& aRv)
277 {
278 if (mCallState != nsITelephonyProvider::CALL_STATE_CONNECTED) {
279 NS_WARNING("Hold non-connected call ignored!");
280 return;
281 }
282
283 MOZ_ASSERT(!mCalls.IsEmpty());
284
285 nsresult rv = mTelephony->Provider()->HoldConference(mCalls[0]->ServiceId());
286 if (NS_FAILED(rv)) {
287 aRv.Throw(rv);
288 return;
289 }
290
291 ChangeState(nsITelephonyProvider::CALL_STATE_HOLDING);
292 }
293
294 void
295 TelephonyCallGroup::Resume(ErrorResult& aRv)
296 {
297 if (mCallState != nsITelephonyProvider::CALL_STATE_HELD) {
298 NS_WARNING("Resume non-held call ignored!");
299 return;
300 }
301
302 MOZ_ASSERT(!mCalls.IsEmpty());
303
304 nsresult rv = mTelephony->Provider()->ResumeConference(mCalls[0]->ServiceId());
305 if (NS_FAILED(rv)) {
306 aRv.Throw(rv);
307 return;
308 }
309
310 ChangeState(nsITelephonyProvider::CALL_STATE_RESUMING);
311 }

mercurial