blob: 1414e0a5e000bf8218d2dab41c29a0395ded8cce [file] [log] [blame]
Santos Cordon63aeb162014-02-10 09:20:40 -08001/*
2 * Copyright 2014, The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.telecomm;
18
Santos Cordon5924bea2014-06-18 06:39:51 -070019import android.content.ComponentName;
Evan Charltona05805b2014-03-05 08:21:46 -080020import android.os.Bundle;
Santos Cordon3d3b4052014-05-05 12:05:36 -070021import android.os.Handler;
Santos Cordon63aeb162014-02-10 09:20:40 -080022import android.os.IBinder;
Santos Cordon3d3b4052014-05-05 12:05:36 -070023import android.os.Message;
Santos Cordon63aeb162014-02-10 09:20:40 -080024import android.os.RemoteException;
Sailesh Nepal6aca10a2014-03-24 16:11:02 -070025import android.telecomm.CallAudioState;
Santos Cordon63aeb162014-02-10 09:20:40 -080026import android.telecomm.CallInfo;
Evan Charltona05805b2014-03-05 08:21:46 -080027import android.telecomm.CallService;
Ben Giladc5b22692014-02-18 20:03:22 -080028import android.telecomm.CallServiceDescriptor;
Ihab Awada3cb9e32014-06-03 18:45:05 -070029import android.telecomm.ConnectionRequest;
Sailesh Nepal83cfe7c2014-03-11 19:54:22 -070030import android.telecomm.TelecommConstants;
Ihab Awada3cb9e32014-06-03 18:45:05 -070031import android.telephony.DisconnectCause;
Sailesh Nepala439e1b2014-03-11 18:19:58 -070032
Santos Cordon3d3b4052014-05-05 12:05:36 -070033import com.android.internal.os.SomeArgs;
Andrew Leee9a77652014-06-26 13:07:57 -070034
Sailesh Nepala439e1b2014-03-11 18:19:58 -070035import com.android.internal.telecomm.ICallService;
36import com.android.internal.telecomm.ICallServiceAdapter;
37import com.android.internal.telecomm.ICallServiceProvider;
Andrew Leee9a77652014-06-26 13:07:57 -070038import com.android.internal.telecomm.ICallVideoProvider;
Santos Cordon5924bea2014-06-18 06:39:51 -070039import com.android.internal.telecomm.RemoteServiceCallback;
40import com.android.telecomm.BaseRepository.LookupCallback;
Sailesh Nepal0e5410a2014-04-04 01:20:58 -070041import com.google.common.base.Preconditions;
Santos Cordon3d3b4052014-05-05 12:05:36 -070042import com.google.common.collect.ImmutableList;
Santos Cordon3d3b4052014-05-05 12:05:36 -070043
Ihab Awada3cb9e32014-06-03 18:45:05 -070044import org.apache.http.conn.ClientConnectionRequest;
45
Santos Cordon5924bea2014-06-18 06:39:51 -070046import java.util.ArrayList;
47import java.util.Collection;
Santos Cordon682fe6b2014-05-20 08:56:39 -070048import java.util.HashMap;
Santos Cordona1610702014-06-04 20:22:56 -070049import java.util.HashSet;
Santos Cordon8f3282c2014-06-01 13:56:02 -070050import java.util.List;
Santos Cordon682fe6b2014-05-20 08:56:39 -070051import java.util.Map;
Santos Cordon3d3b4052014-05-05 12:05:36 -070052import java.util.Set;
Santos Cordon63aeb162014-02-10 09:20:40 -080053
54/**
55 * Wrapper for {@link ICallService}s, handles binding to {@link ICallService} and keeps track of
56 * when the object can safely be unbound. Other classes should not use {@link ICallService} directly
57 * and instead should use this class to invoke methods of {@link ICallService}.
Santos Cordon63aeb162014-02-10 09:20:40 -080058 */
Ben Gilad61925612014-03-11 19:06:36 -070059final class CallServiceWrapper extends ServiceBinder<ICallService> {
Santos Cordona1610702014-06-04 20:22:56 -070060 private static final String TAG = CallServiceWrapper.class.getSimpleName();
Santos Cordon63aeb162014-02-10 09:20:40 -080061
Santos Cordon3d3b4052014-05-05 12:05:36 -070062 private final class Adapter extends ICallServiceAdapter.Stub {
Santos Cordon3d3b4052014-05-05 12:05:36 -070063 private static final int MSG_NOTIFY_INCOMING_CALL = 1;
64 private static final int MSG_HANDLE_SUCCESSFUL_OUTGOING_CALL = 2;
65 private static final int MSG_HANDLE_FAILED_OUTGOING_CALL = 3;
Sailesh Nepal5a73b032014-06-25 15:53:21 -070066 private static final int MSG_CANCEL_OUTGOING_CALL = 4;
67 private static final int MSG_SET_ACTIVE = 5;
68 private static final int MSG_SET_RINGING = 6;
69 private static final int MSG_SET_DIALING = 7;
70 private static final int MSG_SET_DISCONNECTED = 8;
71 private static final int MSG_SET_ON_HOLD = 9;
72 private static final int MSG_SET_REQUESTING_RINGBACK = 10;
73 private static final int MSG_ON_POST_DIAL_WAIT = 11;
74 private static final int MSG_CAN_CONFERENCE = 12;
75 private static final int MSG_SET_IS_CONFERENCED = 13;
76 private static final int MSG_ADD_CONFERENCE_CALL = 14;
Sailesh Nepal77da19e2014-07-02 21:31:16 -070077 private static final int MSG_QUERY_REMOTE_CALL_SERVICES = 15;
78 private static final int MSG_SET_CALL_VIDEO_PROVIDER = 16;
79 private static final int MSG_SET_FEATURES = 17;
Santos Cordon3d3b4052014-05-05 12:05:36 -070080
81 private final Handler mHandler = new Handler() {
82 @Override
83 public void handleMessage(Message msg) {
84 Call call;
85 switch (msg.what) {
Santos Cordon3d3b4052014-05-05 12:05:36 -070086 case MSG_NOTIFY_INCOMING_CALL:
87 CallInfo clientCallInfo = (CallInfo) msg.obj;
88 call = mCallIdMapper.getCall(clientCallInfo.getId());
Santos Cordon682fe6b2014-05-20 08:56:39 -070089 if (call != null && mPendingIncomingCalls.remove(call) &&
90 call.isIncoming()) {
Santos Cordon3d3b4052014-05-05 12:05:36 -070091 CallInfo callInfo = new CallInfo(null, clientCallInfo.getState(),
92 clientCallInfo.getHandle());
93 mIncomingCallsManager.handleSuccessfulIncomingCall(call, callInfo);
94 } else {
Santos Cordon5924bea2014-06-18 06:39:51 -070095 // TODO(santoscordon): For this an the other commented logging, we need
96 // to reenable it. At the moment all CallServiceAdapters receive
97 // notification of changes to all calls, even calls which it may not own
98 // (ala remote connections). We need to fix that and then uncomment the
99 // logging calls here.
100 //Log.w(this, "notifyIncomingCall, unknown incoming call: %s, id: %s",
101 // call, clientCallInfo.getId());
Santos Cordon3d3b4052014-05-05 12:05:36 -0700102 }
103 break;
Santos Cordon682fe6b2014-05-20 08:56:39 -0700104 case MSG_HANDLE_SUCCESSFUL_OUTGOING_CALL: {
105 String callId = (String) msg.obj;
106 if (mPendingOutgoingCalls.containsKey(callId)) {
Sailesh Nepal5a73b032014-06-25 15:53:21 -0700107 mPendingOutgoingCalls.remove(callId).onOutgoingCallSuccess();
Santos Cordon3d3b4052014-05-05 12:05:36 -0700108 } else {
Santos Cordon5924bea2014-06-18 06:39:51 -0700109 //Log.w(this, "handleSuccessfulOutgoingCall, unknown call: %s", callId);
Santos Cordon3d3b4052014-05-05 12:05:36 -0700110 }
111 break;
Santos Cordon682fe6b2014-05-20 08:56:39 -0700112 }
Santos Cordon3d3b4052014-05-05 12:05:36 -0700113 case MSG_HANDLE_FAILED_OUTGOING_CALL: {
114 SomeArgs args = (SomeArgs) msg.obj;
115 try {
Santos Cordon682fe6b2014-05-20 08:56:39 -0700116 String callId = (String) args.arg1;
Ihab Awada3cb9e32014-06-03 18:45:05 -0700117 int statusCode = args.argi1;
118 String statusMsg = (String) args.arg2;
Santos Cordon682fe6b2014-05-20 08:56:39 -0700119 // TODO(santoscordon): Do something with 'reason' or get rid of it.
120
121 if (mPendingOutgoingCalls.containsKey(callId)) {
Sailesh Nepal5a73b032014-06-25 15:53:21 -0700122 mPendingOutgoingCalls.remove(callId).onOutgoingCallFailure(
123 statusCode, statusMsg);
Santos Cordon682fe6b2014-05-20 08:56:39 -0700124 mCallIdMapper.removeCall(callId);
Santos Cordon3d3b4052014-05-05 12:05:36 -0700125 } else {
Santos Cordon5924bea2014-06-18 06:39:51 -0700126 //Log.w(this, "handleFailedOutgoingCall, unknown call: %s", callId);
Santos Cordon3d3b4052014-05-05 12:05:36 -0700127 }
128 } finally {
129 args.recycle();
130 }
131 break;
132 }
Sailesh Nepal5a73b032014-06-25 15:53:21 -0700133 case MSG_CANCEL_OUTGOING_CALL: {
134 String callId = (String) msg.obj;
135 if (mPendingOutgoingCalls.containsKey(callId)) {
136 mPendingOutgoingCalls.remove(callId).onOutgoingCallCancel();
137 } else {
138 //Log.w(this, "cancelOutgoingCall, unknown call: %s", callId);
139 }
140 break;
141 }
Santos Cordon3d3b4052014-05-05 12:05:36 -0700142 case MSG_SET_ACTIVE:
143 call = mCallIdMapper.getCall(msg.obj);
144 if (call != null) {
145 mCallsManager.markCallAsActive(call);
146 } else {
Santos Cordon5924bea2014-06-18 06:39:51 -0700147 //Log.w(this, "setActive, unknown call id: %s", msg.obj);
Santos Cordon3d3b4052014-05-05 12:05:36 -0700148 }
149 break;
150 case MSG_SET_RINGING:
151 call = mCallIdMapper.getCall(msg.obj);
152 if (call != null) {
153 mCallsManager.markCallAsRinging(call);
154 } else {
Santos Cordon5924bea2014-06-18 06:39:51 -0700155 //Log.w(this, "setRinging, unknown call id: %s", msg.obj);
Santos Cordon3d3b4052014-05-05 12:05:36 -0700156 }
157 break;
158 case MSG_SET_DIALING:
159 call = mCallIdMapper.getCall(msg.obj);
160 if (call != null) {
161 mCallsManager.markCallAsDialing(call);
162 } else {
Santos Cordon5924bea2014-06-18 06:39:51 -0700163 //Log.w(this, "setDialing, unknown call id: %s", msg.obj);
Santos Cordon3d3b4052014-05-05 12:05:36 -0700164 }
165 break;
166 case MSG_SET_DISCONNECTED: {
167 SomeArgs args = (SomeArgs) msg.obj;
168 try {
169 call = mCallIdMapper.getCall(args.arg1);
170 String disconnectMessage = (String) args.arg2;
171 int disconnectCause = args.argi1;
172 if (call != null) {
173 mCallsManager.markCallAsDisconnected(call, disconnectCause,
174 disconnectMessage);
175 } else {
Santos Cordon5924bea2014-06-18 06:39:51 -0700176 //Log.w(this, "setDisconnected, unknown call id: %s", args.arg1);
Santos Cordon3d3b4052014-05-05 12:05:36 -0700177 }
178 } finally {
179 args.recycle();
180 }
181 break;
182 }
183 case MSG_SET_ON_HOLD:
184 call = mCallIdMapper.getCall(msg.obj);
185 if (call != null) {
186 mCallsManager.markCallAsOnHold(call);
187 } else {
Santos Cordon5924bea2014-06-18 06:39:51 -0700188 //Log.w(this, "setOnHold, unknown call id: %s", msg.obj);
Santos Cordon3d3b4052014-05-05 12:05:36 -0700189 }
190 break;
Evan Charlton352105c2014-06-03 14:10:54 -0700191 case MSG_SET_REQUESTING_RINGBACK: {
Ihab Awad50a57132014-05-28 16:49:38 -0700192 SomeArgs args = (SomeArgs) msg.obj;
193 try {
194 call = mCallIdMapper.getCall(args.arg1);
195 boolean ringback = (boolean) args.arg2;
196 if (call != null) {
197 call.setRequestingRingback(ringback);
198 } else {
Santos Cordon5924bea2014-06-18 06:39:51 -0700199 //Log.w(this, "setRingback, unknown call id: %s", args.arg1);
Ihab Awad50a57132014-05-28 16:49:38 -0700200 }
201 } finally {
202 args.recycle();
203 }
204 break;
Evan Charlton352105c2014-06-03 14:10:54 -0700205 }
Santos Cordona1610702014-06-04 20:22:56 -0700206 case MSG_ON_POST_DIAL_WAIT: {
Evan Charlton352105c2014-06-03 14:10:54 -0700207 SomeArgs args = (SomeArgs) msg.obj;
208 try {
209 call = mCallIdMapper.getCall(args.arg1);
210 if (call != null) {
211 String remaining = (String) args.arg2;
212 call.onPostDialWait(remaining);
213 } else {
Santos Cordon5924bea2014-06-18 06:39:51 -0700214 //Log.w(this, "onPostDialWait, unknown call id: %s", args.arg1);
Evan Charlton352105c2014-06-03 14:10:54 -0700215 }
216 } finally {
217 args.recycle();
218 }
Santos Cordona1610702014-06-04 20:22:56 -0700219 break;
220 }
Santos Cordona1610702014-06-04 20:22:56 -0700221 case MSG_CAN_CONFERENCE: {
222 call = mCallIdMapper.getCall(msg.obj);
223 if (call != null) {
224 call.setIsConferenceCapable(msg.arg1 == 1);
225 } else {
Santos Cordon5924bea2014-06-18 06:39:51 -0700226 //Log.w(CallServiceWrapper.this, "canConference, unknown call id: %s",
227 // msg.obj);
Santos Cordona1610702014-06-04 20:22:56 -0700228 }
229 break;
230 }
231 case MSG_SET_IS_CONFERENCED: {
232 SomeArgs args = (SomeArgs) msg.obj;
233 try {
234 Call childCall = mCallIdMapper.getCall(args.arg1);
235 if (childCall != null) {
236 String conferenceCallId = (String) args.arg2;
Santos Cordona1610702014-06-04 20:22:56 -0700237 if (conferenceCallId == null) {
238 childCall.setParentCall(null);
239 } else {
240 Call conferenceCall = mCallIdMapper.getCall(conferenceCallId);
241 if (conferenceCall != null &&
242 !mPendingConferenceCalls.contains(conferenceCall)) {
243 childCall.setParentCall(conferenceCall);
244 } else {
Santos Cordon5924bea2014-06-18 06:39:51 -0700245 //Log.w(this, "setIsConferenced, unknown conference id %s",
246 // conferenceCallId);
Santos Cordona1610702014-06-04 20:22:56 -0700247 }
248 }
249 } else {
Santos Cordon5924bea2014-06-18 06:39:51 -0700250 //Log.w(this, "setIsConferenced, unknown call id: %s", args.arg1);
Santos Cordona1610702014-06-04 20:22:56 -0700251 }
252 } finally {
253 args.recycle();
254 }
255 break;
256 }
257 case MSG_ADD_CONFERENCE_CALL: {
258 SomeArgs args = (SomeArgs) msg.obj;
259 try {
260 String callId = (String) args.arg1;
Santos Cordona1610702014-06-04 20:22:56 -0700261 Call conferenceCall = mCallIdMapper.getCall(callId);
262 if (mPendingConferenceCalls.remove(conferenceCall)) {
263 Log.v(this, "confirming conf call %s", conferenceCall);
264 conferenceCall.confirmConference();
265 } else {
Santos Cordon5924bea2014-06-18 06:39:51 -0700266 //Log.w(this, "addConference, unknown call id: %s", callId);
Santos Cordona1610702014-06-04 20:22:56 -0700267 }
268 } finally {
269 args.recycle();
270 }
271 break;
272 }
Santos Cordon5924bea2014-06-18 06:39:51 -0700273 case MSG_QUERY_REMOTE_CALL_SERVICES: {
274 CallServiceWrapper.this.queryRemoteConnectionServices(
275 (RemoteServiceCallback) msg.obj);
Andrew Leee9a77652014-06-26 13:07:57 -0700276 break;
277 }
278 case MSG_SET_CALL_VIDEO_PROVIDER: {
279 SomeArgs args = (SomeArgs) msg.obj;
280 try {
281 call = mCallIdMapper.getCall(args.arg1);
Nancy Chena65d41f2014-06-24 12:06:03 -0700282 ICallVideoProvider callVideoProvider = (ICallVideoProvider) args.arg2;
Andrew Leee9a77652014-06-26 13:07:57 -0700283 if (call != null) {
Nancy Chena65d41f2014-06-24 12:06:03 -0700284 call.setCallVideoProvider(callVideoProvider);
Andrew Leee9a77652014-06-26 13:07:57 -0700285 }
286 } finally {
287 args.recycle();
288 }
289 break;
Santos Cordon5924bea2014-06-18 06:39:51 -0700290 }
Tyler Gunne19cc002014-07-01 11:32:53 -0700291 case MSG_SET_FEATURES: {
292 SomeArgs args = (SomeArgs) msg.obj;
293 try {
294 call = mCallIdMapper.getCall(args.arg1);
295 int features = (int) args.arg2;
296 if (call != null) {
297 call.setFeatures(features);
298 }
299 } finally {
300 args.recycle();
301 }
302 break;
303 }
Santos Cordon3d3b4052014-05-05 12:05:36 -0700304 }
305 }
306 };
307
308 /** {@inheritDoc} */
309 @Override
Santos Cordon3d3b4052014-05-05 12:05:36 -0700310 public void notifyIncomingCall(CallInfo callInfo) {
Ihab Awad55a34282014-06-18 10:31:09 -0700311 logIncoming("notifyIncomingCall %s", callInfo);
Santos Cordon3d3b4052014-05-05 12:05:36 -0700312 mCallIdMapper.checkValidCallId(callInfo.getId());
313 mHandler.obtainMessage(MSG_NOTIFY_INCOMING_CALL, callInfo).sendToTarget();
314 }
315
316 /** {@inheritDoc} */
317 @Override
318 public void handleSuccessfulOutgoingCall(String callId) {
Ihab Awad55a34282014-06-18 10:31:09 -0700319 logIncoming("handleSuccessfulOutgoingCall %s", callId);
Santos Cordon3d3b4052014-05-05 12:05:36 -0700320 mCallIdMapper.checkValidCallId(callId);
321 mHandler.obtainMessage(MSG_HANDLE_SUCCESSFUL_OUTGOING_CALL, callId).sendToTarget();
322 }
323
324 /** {@inheritDoc} */
325 @Override
Ihab Awada3cb9e32014-06-03 18:45:05 -0700326 public void handleFailedOutgoingCall(
327 ConnectionRequest request,
328 int errorCode,
329 String errorMsg) {
Ihab Awad55a34282014-06-18 10:31:09 -0700330 logIncoming("handleFailedOutgoingCall %s %d %s", request, errorCode, errorMsg);
Ihab Awada3cb9e32014-06-03 18:45:05 -0700331 mCallIdMapper.checkValidCallId(request.getCallId());
Santos Cordon3d3b4052014-05-05 12:05:36 -0700332 SomeArgs args = SomeArgs.obtain();
Ihab Awada3cb9e32014-06-03 18:45:05 -0700333 args.arg1 = request.getCallId();
334 args.argi1 = errorCode;
335 args.arg2 = errorMsg;
Santos Cordon3d3b4052014-05-05 12:05:36 -0700336 mHandler.obtainMessage(MSG_HANDLE_FAILED_OUTGOING_CALL, args).sendToTarget();
337 }
338
339 /** {@inheritDoc} */
340 @Override
Sailesh Nepal5a73b032014-06-25 15:53:21 -0700341 public void cancelOutgoingCall(String callId) {
342 logIncoming("cancelOutgoingCall %s", callId);
343 mCallIdMapper.checkValidCallId(callId);
344 mHandler.obtainMessage(MSG_CANCEL_OUTGOING_CALL, callId).sendToTarget();
345 }
346
347 /** {@inheritDoc} */
348 @Override
Santos Cordon3d3b4052014-05-05 12:05:36 -0700349 public void setActive(String callId) {
Ihab Awad55a34282014-06-18 10:31:09 -0700350 logIncoming("setActive %s", callId);
Santos Cordon3d3b4052014-05-05 12:05:36 -0700351 mCallIdMapper.checkValidCallId(callId);
352 mHandler.obtainMessage(MSG_SET_ACTIVE, callId).sendToTarget();
353 }
354
355 /** {@inheritDoc} */
356 @Override
357 public void setRinging(String callId) {
Ihab Awad55a34282014-06-18 10:31:09 -0700358 logIncoming("setRinging %s", callId);
Santos Cordon3d3b4052014-05-05 12:05:36 -0700359 mCallIdMapper.checkValidCallId(callId);
360 mHandler.obtainMessage(MSG_SET_RINGING, callId).sendToTarget();
361 }
362
363 /** {@inheritDoc} */
364 @Override
Andrew Leee9a77652014-06-26 13:07:57 -0700365 public void setCallVideoProvider(String callId, ICallVideoProvider callVideoProvider) {
366 logIncoming("setCallVideoProvider %s", callId);
367 mCallIdMapper.checkValidCallId(callId);
368 SomeArgs args = SomeArgs.obtain();
369 args.arg1 = callId;
370 args.arg2 = callVideoProvider;
371 mHandler.obtainMessage(MSG_SET_CALL_VIDEO_PROVIDER, args).sendToTarget();
372 }
373
374 /** {@inheritDoc} */
375 @Override
Santos Cordon3d3b4052014-05-05 12:05:36 -0700376 public void setDialing(String callId) {
Ihab Awad55a34282014-06-18 10:31:09 -0700377 logIncoming("setDialing %s", callId);
Santos Cordon3d3b4052014-05-05 12:05:36 -0700378 mCallIdMapper.checkValidCallId(callId);
379 mHandler.obtainMessage(MSG_SET_DIALING, callId).sendToTarget();
380 }
381
382 /** {@inheritDoc} */
383 @Override
384 public void setDisconnected(
385 String callId, int disconnectCause, String disconnectMessage) {
Ihab Awad55a34282014-06-18 10:31:09 -0700386 logIncoming("setDisconnected %s %d %s", callId, disconnectCause, disconnectMessage);
Santos Cordon3d3b4052014-05-05 12:05:36 -0700387 mCallIdMapper.checkValidCallId(callId);
388 SomeArgs args = SomeArgs.obtain();
389 args.arg1 = callId;
390 args.arg2 = disconnectMessage;
391 args.argi1 = disconnectCause;
392 mHandler.obtainMessage(MSG_SET_DISCONNECTED, args).sendToTarget();
393 }
394
395 /** {@inheritDoc} */
396 @Override
397 public void setOnHold(String callId) {
Ihab Awad55a34282014-06-18 10:31:09 -0700398 logIncoming("setOnHold %s", callId);
Santos Cordon3d3b4052014-05-05 12:05:36 -0700399 mCallIdMapper.checkValidCallId(callId);
400 mHandler.obtainMessage(MSG_SET_ON_HOLD, callId).sendToTarget();
401 }
Ihab Awad50a57132014-05-28 16:49:38 -0700402
403 /** {@inheritDoc} */
404 @Override
405 public void setRequestingRingback(String callId, boolean ringback) {
Ihab Awad55a34282014-06-18 10:31:09 -0700406 logIncoming("setRequestingRingback %s %b", callId, ringback);
Ihab Awad50a57132014-05-28 16:49:38 -0700407 mCallIdMapper.checkValidCallId(callId);
408 SomeArgs args = SomeArgs.obtain();
409 args.arg1 = callId;
410 args.arg2 = ringback;
411 mHandler.obtainMessage(MSG_SET_REQUESTING_RINGBACK, args).sendToTarget();
412 }
Santos Cordon8f3282c2014-06-01 13:56:02 -0700413
414 /** ${inheritDoc} */
415 @Override
416 public void removeCall(String callId) {
Ihab Awad55a34282014-06-18 10:31:09 -0700417 logIncoming("removeCall %s", callId);
Santos Cordon8f3282c2014-06-01 13:56:02 -0700418 }
419
420 /** ${inheritDoc} */
421 @Override
Santos Cordona1610702014-06-04 20:22:56 -0700422 public void setCanConference(String callId, boolean canConference) {
Ihab Awad55a34282014-06-18 10:31:09 -0700423 logIncoming("setCanConference %s %b", callId, canConference);
Santos Cordona1610702014-06-04 20:22:56 -0700424 mHandler.obtainMessage(MSG_CAN_CONFERENCE, canConference ? 1 : 0, 0, callId)
425 .sendToTarget();
Santos Cordon8f3282c2014-06-01 13:56:02 -0700426 }
427
428 /** ${inheritDoc} */
429 @Override
Santos Cordona1610702014-06-04 20:22:56 -0700430 public void setIsConferenced(String callId, String conferenceCallId) {
Ihab Awad55a34282014-06-18 10:31:09 -0700431 logIncoming("setIsConferenced %s %s", callId, conferenceCallId);
Santos Cordona1610702014-06-04 20:22:56 -0700432 SomeArgs args = SomeArgs.obtain();
433 args.arg1 = callId;
434 args.arg2 = conferenceCallId;
435 mHandler.obtainMessage(MSG_SET_IS_CONFERENCED, args).sendToTarget();
436 }
437
438 /** ${InheritDoc} */
439 @Override
440 public void addConferenceCall(String callId, CallInfo callInfo) {
Ihab Awad55a34282014-06-18 10:31:09 -0700441 logIncoming("addConferenceCall %s %s", callId, callInfo);
Santos Cordona1610702014-06-04 20:22:56 -0700442 mCallIdMapper.checkValidCallId(callId);
443 SomeArgs args = SomeArgs.obtain();
444 args.arg1 = callId;
445 args.arg2 = callInfo;
446 mHandler.obtainMessage(MSG_ADD_CONFERENCE_CALL, args).sendToTarget();
Santos Cordon8f3282c2014-06-01 13:56:02 -0700447 }
Evan Charlton352105c2014-06-03 14:10:54 -0700448
449 @Override
450 public void onPostDialWait(String callId, String remaining) throws RemoteException {
Ihab Awad55a34282014-06-18 10:31:09 -0700451 logIncoming("onPostDialWait %s %s", callId, remaining);
Evan Charlton352105c2014-06-03 14:10:54 -0700452 mCallIdMapper.checkValidCallId(callId);
453 SomeArgs args = SomeArgs.obtain();
454 args.arg1 = callId;
455 args.arg2 = remaining;
456 mHandler.obtainMessage(MSG_ON_POST_DIAL_WAIT, args).sendToTarget();
457 }
Sailesh Nepal6098d2c2014-06-06 10:56:53 -0700458
Santos Cordon5924bea2014-06-18 06:39:51 -0700459 /** ${inheritDoc} */
460 @Override
461 public void queryRemoteConnectionServices(RemoteServiceCallback callback) {
462 logIncoming("queryRemoteCSs");
463 mHandler.obtainMessage(MSG_QUERY_REMOTE_CALL_SERVICES, callback).sendToTarget();
464 }
Tyler Gunne19cc002014-07-01 11:32:53 -0700465
466 @Override
467 public void setFeatures(String callId, int features) {
468 logIncoming("setFeatures %s %d", callId, features);
469 mCallIdMapper.checkValidCallId(callId);
470 SomeArgs args = SomeArgs.obtain();
471 args.arg1 = callId;
472 args.arg2 = features;
473 mHandler.obtainMessage(MSG_SET_FEATURES, args).sendToTarget();
474 }
Santos Cordon3d3b4052014-05-05 12:05:36 -0700475 }
476
477 private final Adapter mAdapter = new Adapter();
478 private final CallsManager mCallsManager = CallsManager.getInstance();
Santos Cordona1610702014-06-04 20:22:56 -0700479 private final Set<Call> mPendingIncomingCalls = new HashSet<>();
480 private final Set<Call> mPendingConferenceCalls = new HashSet<>();
Ben Giladc5b22692014-02-18 20:03:22 -0800481 private final CallServiceDescriptor mDescriptor;
Santos Cordon3d3b4052014-05-05 12:05:36 -0700482 private final CallIdMapper mCallIdMapper = new CallIdMapper("CallService");
Santos Cordon3d3b4052014-05-05 12:05:36 -0700483 private final IncomingCallsManager mIncomingCallsManager;
Sailesh Nepal5a73b032014-06-25 15:53:21 -0700484 private final Map<String, OutgoingCallResponse> mPendingOutgoingCalls = new HashMap<>();
Santos Cordona1610702014-06-04 20:22:56 -0700485 private final Handler mHandler = new Handler();
Santos Cordonc195e362014-02-11 17:05:31 -0800486
Ben Gilad61925612014-03-11 19:06:36 -0700487 private Binder mBinder = new Binder();
Santos Cordon3d3b4052014-05-05 12:05:36 -0700488 private ICallService mServiceInterface;
Santos Cordon5924bea2014-06-18 06:39:51 -0700489 private final CallServiceRepository mCallServiceRepository;
Ben Gilad61925612014-03-11 19:06:36 -0700490
Santos Cordon63aeb162014-02-10 09:20:40 -0800491 /**
Sailesh Nepale59bb192014-04-01 18:33:59 -0700492 * Creates a call-service for the specified descriptor.
Santos Cordonc195e362014-02-11 17:05:31 -0800493 *
Santos Cordon61d0f702014-02-19 02:52:23 -0800494 * @param descriptor The call-service descriptor from
Santos Cordon3d3b4052014-05-05 12:05:36 -0700495 * {@link ICallServiceProvider#lookupCallServices}.
Sailesh Nepale59bb192014-04-01 18:33:59 -0700496 * @param incomingCallsManager Manages the incoming call initialization flow.
Santos Cordon5924bea2014-06-18 06:39:51 -0700497 * @param callServiceRepository Call service repository.
Santos Cordon63aeb162014-02-10 09:20:40 -0800498 */
Sailesh Nepale59bb192014-04-01 18:33:59 -0700499 CallServiceWrapper(
500 CallServiceDescriptor descriptor,
Santos Cordon5924bea2014-06-18 06:39:51 -0700501 IncomingCallsManager incomingCallsManager,
502 CallServiceRepository callServiceRepository) {
Sailesh Nepala439e1b2014-03-11 18:19:58 -0700503 super(TelecommConstants.ACTION_CALL_SERVICE, descriptor.getServiceComponent());
Ben Giladc5b22692014-02-18 20:03:22 -0800504 mDescriptor = descriptor;
Santos Cordon3d3b4052014-05-05 12:05:36 -0700505 mIncomingCallsManager = incomingCallsManager;
Santos Cordon5924bea2014-06-18 06:39:51 -0700506 mCallServiceRepository = callServiceRepository;
Santos Cordon63aeb162014-02-10 09:20:40 -0800507 }
508
Ben Gilad61925612014-03-11 19:06:36 -0700509 CallServiceDescriptor getDescriptor() {
Ben Giladc5b22692014-02-18 20:03:22 -0800510 return mDescriptor;
Santos Cordonc195e362014-02-11 17:05:31 -0800511 }
512
Santos Cordon63aeb162014-02-10 09:20:40 -0800513 /** See {@link ICallService#setCallServiceAdapter}. */
Sailesh Nepale59bb192014-04-01 18:33:59 -0700514 private void setCallServiceAdapter(ICallServiceAdapter callServiceAdapter) {
Santos Cordon61d0f702014-02-19 02:52:23 -0800515 if (isServiceValid("setCallServiceAdapter")) {
516 try {
Ihab Awad55a34282014-06-18 10:31:09 -0700517 logOutgoing("setCallServiceAdapter %s", callServiceAdapter);
Santos Cordon63aeb162014-02-10 09:20:40 -0800518 mServiceInterface.setCallServiceAdapter(callServiceAdapter);
Santos Cordon61d0f702014-02-19 02:52:23 -0800519 } catch (RemoteException e) {
Santos Cordon63aeb162014-02-10 09:20:40 -0800520 }
Santos Cordon63aeb162014-02-10 09:20:40 -0800521 }
522 }
523
Ben Gilad61925612014-03-11 19:06:36 -0700524 /**
Santos Cordon682fe6b2014-05-20 08:56:39 -0700525 * Attempts to place the specified call, see {@link ICallService#call}. Returns the result
526 * asynchronously through the specified callback.
Ben Gilad61925612014-03-11 19:06:36 -0700527 */
Sailesh Nepal5a73b032014-06-25 15:53:21 -0700528 void call(final Call call, final OutgoingCallResponse callResponse) {
Santos Cordon682fe6b2014-05-20 08:56:39 -0700529 Log.d(this, "call(%s) via %s.", call, getComponentName());
Ben Gilad61925612014-03-11 19:06:36 -0700530 BindCallback callback = new BindCallback() {
Santos Cordon3d3b4052014-05-05 12:05:36 -0700531 @Override
532 public void onSuccess() {
Santos Cordon682fe6b2014-05-20 08:56:39 -0700533 String callId = mCallIdMapper.getCallId(call);
Sailesh Nepal5a73b032014-06-25 15:53:21 -0700534 mPendingOutgoingCalls.put(callId, callResponse);
Santos Cordon682fe6b2014-05-20 08:56:39 -0700535
536 try {
537 CallInfo callInfo = call.toCallInfo(callId);
Ihab Awad55a34282014-06-18 10:31:09 -0700538 logOutgoing("call %s", callInfo);
Santos Cordon682fe6b2014-05-20 08:56:39 -0700539 mServiceInterface.call(callInfo);
540 } catch (RemoteException e) {
Santos Cordon5924bea2014-06-18 06:39:51 -0700541 Log.e(this, e, "Failure to call -- %s", getDescriptor());
Sailesh Nepal5a73b032014-06-25 15:53:21 -0700542 mPendingOutgoingCalls.remove(callId).onOutgoingCallFailure(
543 DisconnectCause.ERROR_UNSPECIFIED, e.toString());
Ben Gilad61925612014-03-11 19:06:36 -0700544 }
Santos Cordon63aeb162014-02-10 09:20:40 -0800545 }
Santos Cordon3d3b4052014-05-05 12:05:36 -0700546
547 @Override
548 public void onFailure() {
Santos Cordon5924bea2014-06-18 06:39:51 -0700549 Log.e(this, new Exception(), "Failure to call %s", getDescriptor());
Sailesh Nepal5a73b032014-06-25 15:53:21 -0700550 callResponse.onOutgoingCallFailure(DisconnectCause.ERROR_UNSPECIFIED, null);
Ben Gilad61925612014-03-11 19:06:36 -0700551 }
552 };
553
554 mBinder.bind(callback);
Santos Cordon63aeb162014-02-10 09:20:40 -0800555 }
556
Ihab Awad74549ec2014-03-10 15:33:25 -0700557 /** @see CallService#abort(String) */
Sailesh Nepale59bb192014-04-01 18:33:59 -0700558 void abort(Call call) {
Santos Cordon682fe6b2014-05-20 08:56:39 -0700559 // Clear out any pending outgoing call data
560 String callId = mCallIdMapper.getCallId(call);
561
562 // If still bound, tell the call service to abort.
Ben Gilad28e8ad62014-03-06 17:01:54 -0800563 if (isServiceValid("abort")) {
564 try {
Ihab Awad55a34282014-06-18 10:31:09 -0700565 logOutgoing("abort %s", callId);
Santos Cordon682fe6b2014-05-20 08:56:39 -0700566 mServiceInterface.abort(callId);
Ben Gilad28e8ad62014-03-06 17:01:54 -0800567 } catch (RemoteException e) {
Santos Cordon63aeb162014-02-10 09:20:40 -0800568 }
Santos Cordon61d0f702014-02-19 02:52:23 -0800569 }
Santos Cordon682fe6b2014-05-20 08:56:39 -0700570
571 removeCall(call);
Santos Cordon61d0f702014-02-19 02:52:23 -0800572 }
573
Ihab Awad74549ec2014-03-10 15:33:25 -0700574 /** @see CallService#hold(String) */
Sailesh Nepale59bb192014-04-01 18:33:59 -0700575 void hold(Call call) {
Yorke Leecdf3ebd2014-03-12 18:31:41 -0700576 if (isServiceValid("hold")) {
577 try {
Ihab Awad55a34282014-06-18 10:31:09 -0700578 logOutgoing("hold %s", mCallIdMapper.getCallId(call));
Sailesh Nepale59bb192014-04-01 18:33:59 -0700579 mServiceInterface.hold(mCallIdMapper.getCallId(call));
Yorke Leecdf3ebd2014-03-12 18:31:41 -0700580 } catch (RemoteException e) {
Yorke Leecdf3ebd2014-03-12 18:31:41 -0700581 }
582 }
583 }
584
Ihab Awad74549ec2014-03-10 15:33:25 -0700585 /** @see CallService#unhold(String) */
Sailesh Nepale59bb192014-04-01 18:33:59 -0700586 void unhold(Call call) {
Yorke Leecdf3ebd2014-03-12 18:31:41 -0700587 if (isServiceValid("unhold")) {
588 try {
Ihab Awad55a34282014-06-18 10:31:09 -0700589 logOutgoing("unhold %s", mCallIdMapper.getCallId(call));
Sailesh Nepale59bb192014-04-01 18:33:59 -0700590 mServiceInterface.unhold(mCallIdMapper.getCallId(call));
Yorke Leecdf3ebd2014-03-12 18:31:41 -0700591 } catch (RemoteException e) {
Yorke Leecdf3ebd2014-03-12 18:31:41 -0700592 }
593 }
594 }
595
Ihab Awad74549ec2014-03-10 15:33:25 -0700596 /** @see CallService#onAudioStateChanged(String,CallAudioState) */
Sailesh Nepale59bb192014-04-01 18:33:59 -0700597 void onAudioStateChanged(Call activeCall, CallAudioState audioState) {
Sailesh Nepal6aca10a2014-03-24 16:11:02 -0700598 if (isServiceValid("onAudioStateChanged")) {
599 try {
Ihab Awad55a34282014-06-18 10:31:09 -0700600 logOutgoing("onAudioStateChanged %s %s",
601 mCallIdMapper.getCallId(activeCall), audioState);
Sailesh Nepale59bb192014-04-01 18:33:59 -0700602 mServiceInterface.onAudioStateChanged(mCallIdMapper.getCallId(activeCall),
603 audioState);
Sailesh Nepal6aca10a2014-03-24 16:11:02 -0700604 } catch (RemoteException e) {
Sailesh Nepal6aca10a2014-03-24 16:11:02 -0700605 }
606 }
607 }
608
Ben Gilad61925612014-03-11 19:06:36 -0700609 /**
610 * Starts retrieval of details for an incoming call. Details are returned through the
611 * call-service adapter using the specified call ID. Upon failure, the specified error callback
Santos Cordon3d3b4052014-05-05 12:05:36 -0700612 * is invoked. Can be invoked even when the call service is unbound. See
613 * {@link ICallService#setIncomingCallId}.
Ben Gilad61925612014-03-11 19:06:36 -0700614 *
Sailesh Nepale59bb192014-04-01 18:33:59 -0700615 * @param call The call used for the incoming call.
Ben Gilad61925612014-03-11 19:06:36 -0700616 * @param extras The {@link CallService}-provided extras which need to be sent back.
617 * @param errorCallback The callback to invoke upon failure.
618 */
Sailesh Nepale59bb192014-04-01 18:33:59 -0700619 void setIncomingCallId(final Call call, final Bundle extras, final Runnable errorCallback) {
620 Log.d(this, "setIncomingCall(%s) via %s.", call, getComponentName());
Ben Gilad61925612014-03-11 19:06:36 -0700621 BindCallback callback = new BindCallback() {
Santos Cordon3d3b4052014-05-05 12:05:36 -0700622 @Override
623 public void onSuccess() {
Ben Gilad61925612014-03-11 19:06:36 -0700624 if (isServiceValid("setIncomingCallId")) {
Santos Cordon682fe6b2014-05-20 08:56:39 -0700625 mPendingIncomingCalls.add(call);
Ben Gilad61925612014-03-11 19:06:36 -0700626 try {
Ihab Awad55a34282014-06-18 10:31:09 -0700627 logOutgoing("setIncomingCallId %s %s",
628 mCallIdMapper.getCallId(call), extras);
Sailesh Nepale59bb192014-04-01 18:33:59 -0700629 mServiceInterface.setIncomingCallId(mCallIdMapper.getCallId(call),
630 extras);
Ben Gilad61925612014-03-11 19:06:36 -0700631 } catch (RemoteException e) {
Ben Gilad61925612014-03-11 19:06:36 -0700632 }
633 }
Santos Cordon61d0f702014-02-19 02:52:23 -0800634 }
Santos Cordon3d3b4052014-05-05 12:05:36 -0700635
636 @Override
637 public void onFailure() {
Ben Gilad61925612014-03-11 19:06:36 -0700638 errorCallback.run();
639 }
640 };
641
642 mBinder.bind(callback);
Santos Cordon63aeb162014-02-10 09:20:40 -0800643 }
644
Ihab Awad74549ec2014-03-10 15:33:25 -0700645 /** @see CallService#disconnect(String) */
Sailesh Nepale59bb192014-04-01 18:33:59 -0700646 void disconnect(Call call) {
Santos Cordon61d0f702014-02-19 02:52:23 -0800647 if (isServiceValid("disconnect")) {
648 try {
Ihab Awad55a34282014-06-18 10:31:09 -0700649 logOutgoing("disconnect %s", mCallIdMapper.getCallId(call));
Sailesh Nepale59bb192014-04-01 18:33:59 -0700650 mServiceInterface.disconnect(mCallIdMapper.getCallId(call));
Santos Cordon61d0f702014-02-19 02:52:23 -0800651 } catch (RemoteException e) {
Santos Cordon63aeb162014-02-10 09:20:40 -0800652 }
Santos Cordon63aeb162014-02-10 09:20:40 -0800653 }
654 }
Santos Cordon5c12c6e2014-02-13 14:35:31 -0800655
Ihab Awad74549ec2014-03-10 15:33:25 -0700656 /** @see CallService#answer(String) */
Sailesh Nepale59bb192014-04-01 18:33:59 -0700657 void answer(Call call) {
Santos Cordon61d0f702014-02-19 02:52:23 -0800658 if (isServiceValid("answer")) {
659 try {
Ihab Awad55a34282014-06-18 10:31:09 -0700660 logOutgoing("answer %s", mCallIdMapper.getCallId(call));
Sailesh Nepale59bb192014-04-01 18:33:59 -0700661 mServiceInterface.answer(mCallIdMapper.getCallId(call));
Santos Cordon61d0f702014-02-19 02:52:23 -0800662 } catch (RemoteException e) {
Santos Cordon7917d382014-02-14 02:31:18 -0800663 }
Santos Cordon61d0f702014-02-19 02:52:23 -0800664 }
665 }
666
Ihab Awad74549ec2014-03-10 15:33:25 -0700667 /** @see CallService#reject(String) */
Sailesh Nepale59bb192014-04-01 18:33:59 -0700668 void reject(Call call) {
Santos Cordon61d0f702014-02-19 02:52:23 -0800669 if (isServiceValid("reject")) {
670 try {
Ihab Awad55a34282014-06-18 10:31:09 -0700671 logOutgoing("reject %s", mCallIdMapper.getCallId(call));
Sailesh Nepale59bb192014-04-01 18:33:59 -0700672 mServiceInterface.reject(mCallIdMapper.getCallId(call));
Santos Cordon61d0f702014-02-19 02:52:23 -0800673 } catch (RemoteException e) {
Ihab Awad74549ec2014-03-10 15:33:25 -0700674 }
675 }
676 }
677
678 /** @see CallService#playDtmfTone(String,char) */
Sailesh Nepale59bb192014-04-01 18:33:59 -0700679 void playDtmfTone(Call call, char digit) {
Ihab Awad74549ec2014-03-10 15:33:25 -0700680 if (isServiceValid("playDtmfTone")) {
681 try {
Ihab Awad55a34282014-06-18 10:31:09 -0700682 logOutgoing("playDtmfTone %s %c", mCallIdMapper.getCallId(call), digit);
Sailesh Nepale59bb192014-04-01 18:33:59 -0700683 mServiceInterface.playDtmfTone(mCallIdMapper.getCallId(call), digit);
Ihab Awad74549ec2014-03-10 15:33:25 -0700684 } catch (RemoteException e) {
Ihab Awad74549ec2014-03-10 15:33:25 -0700685 }
686 }
687 }
688
689 /** @see CallService#stopDtmfTone(String) */
Sailesh Nepale59bb192014-04-01 18:33:59 -0700690 void stopDtmfTone(Call call) {
Ihab Awad74549ec2014-03-10 15:33:25 -0700691 if (isServiceValid("stopDtmfTone")) {
692 try {
Ihab Awad55a34282014-06-18 10:31:09 -0700693 logOutgoing("stopDtmfTone %s", mCallIdMapper.getCallId(call));
Sailesh Nepale59bb192014-04-01 18:33:59 -0700694 mServiceInterface.stopDtmfTone(mCallIdMapper.getCallId(call));
Ihab Awad74549ec2014-03-10 15:33:25 -0700695 } catch (RemoteException e) {
Santos Cordon61d0f702014-02-19 02:52:23 -0800696 }
Santos Cordon7917d382014-02-14 02:31:18 -0800697 }
698 }
699
Sailesh Nepale59bb192014-04-01 18:33:59 -0700700 void addCall(Call call) {
Santos Cordona1610702014-06-04 20:22:56 -0700701 if (mCallIdMapper.getCallId(call) == null) {
702 mCallIdMapper.addCall(call);
703 }
Santos Cordon7917d382014-02-14 02:31:18 -0800704 }
705
Sailesh Nepal0e5410a2014-04-04 01:20:58 -0700706 /**
707 * Associates newCall with this call service by replacing callToReplace.
708 */
709 void replaceCall(Call newCall, Call callToReplace) {
710 Preconditions.checkState(callToReplace.getCallService() == this);
711 mCallIdMapper.replaceCall(newCall, callToReplace);
712 }
713
Sailesh Nepale59bb192014-04-01 18:33:59 -0700714 void removeCall(Call call) {
Santos Cordon682fe6b2014-05-20 08:56:39 -0700715 mPendingIncomingCalls.remove(call);
716
Sailesh Nepal5a73b032014-06-25 15:53:21 -0700717 OutgoingCallResponse outgoingResultCallback =
718 mPendingOutgoingCalls.remove(mCallIdMapper.getCallId(call));
Santos Cordon682fe6b2014-05-20 08:56:39 -0700719 if (outgoingResultCallback != null) {
Sailesh Nepal5a73b032014-06-25 15:53:21 -0700720 outgoingResultCallback.onOutgoingCallFailure(DisconnectCause.ERROR_UNSPECIFIED, null);
Santos Cordon682fe6b2014-05-20 08:56:39 -0700721 }
722
Sailesh Nepale59bb192014-04-01 18:33:59 -0700723 mCallIdMapper.removeCall(call);
Yorke Leeadee12d2014-03-13 12:08:30 -0700724 }
725
Evan Charlton352105c2014-06-03 14:10:54 -0700726 void onPostDialContinue(Call call, boolean proceed) {
727 if (isServiceValid("onPostDialContinue")) {
728 try {
Ihab Awad55a34282014-06-18 10:31:09 -0700729 logOutgoing("onPostDialContinue %s %b", mCallIdMapper.getCallId(call), proceed);
Evan Charlton352105c2014-06-03 14:10:54 -0700730 mServiceInterface.onPostDialContinue(mCallIdMapper.getCallId(call), proceed);
731 } catch (RemoteException ignored) {
732 }
733 }
734 }
735
Sailesh Nepal77da19e2014-07-02 21:31:16 -0700736 void onPhoneAccountClicked(Call call) {
737 if (isServiceValid("onPhoneAccountClicked")) {
738 try {
739 logOutgoing("onPhoneAccountClicked %s", mCallIdMapper.getCallId(call));
740 mServiceInterface.onPhoneAccountClicked(mCallIdMapper.getCallId(call));
741 } catch (RemoteException ignored) {
742 }
743 }
744 }
745
Santos Cordona1610702014-06-04 20:22:56 -0700746 void conference(final Call conferenceCall, Call call) {
747 if (isServiceValid("conference")) {
748 try {
749 conferenceCall.setCallService(this);
750 mPendingConferenceCalls.add(conferenceCall);
751 mHandler.postDelayed(new Runnable() {
752 @Override public void run() {
753 if (mPendingConferenceCalls.remove(conferenceCall)) {
754 conferenceCall.expireConference();
755 Log.i(this, "Conference call expired: %s", conferenceCall);
756 }
757 }
758 }, Timeouts.getConferenceCallExpireMillis());
759
Ihab Awad55a34282014-06-18 10:31:09 -0700760 logOutgoing("conference %s %s",
761 mCallIdMapper.getCallId(conferenceCall),
762 mCallIdMapper.getCallId(call));
Santos Cordona1610702014-06-04 20:22:56 -0700763 mServiceInterface.conference(
764 mCallIdMapper.getCallId(conferenceCall),
765 mCallIdMapper.getCallId(call));
766 } catch (RemoteException ignored) {
767 }
768 }
769 }
770
771 void splitFromConference(Call call) {
772 if (isServiceValid("splitFromConference")) {
773 try {
Ihab Awad55a34282014-06-18 10:31:09 -0700774 logOutgoing("splitFromConference %s", mCallIdMapper.getCallId(call));
Santos Cordona1610702014-06-04 20:22:56 -0700775 mServiceInterface.splitFromConference(mCallIdMapper.getCallId(call));
776 } catch (RemoteException ignored) {
777 }
778 }
779 }
780
Santos Cordon5c12c6e2014-02-13 14:35:31 -0800781 /** {@inheritDoc} */
Santos Cordon3d3b4052014-05-05 12:05:36 -0700782 @Override
783 protected void setServiceInterface(IBinder binder) {
Santos Cordon4b2c1192014-03-19 18:15:38 -0700784 if (binder == null) {
785 // We have lost our service connection. Notify the world that this call service is done.
786 // We must notify the adapter before CallsManager. The adapter will force any pending
787 // outgoing calls to try the next call service. This needs to happen before CallsManager
788 // tries to clean up any calls still associated with this call service.
Santos Cordon3d3b4052014-05-05 12:05:36 -0700789 handleCallServiceDeath();
Santos Cordon4b2c1192014-03-19 18:15:38 -0700790 CallsManager.getInstance().handleCallServiceDeath(this);
791 mServiceInterface = null;
792 } else {
793 mServiceInterface = ICallService.Stub.asInterface(binder);
794 setCallServiceAdapter(mAdapter);
795 }
Santos Cordon5c12c6e2014-02-13 14:35:31 -0800796 }
Santos Cordon3d3b4052014-05-05 12:05:36 -0700797
798 /**
799 * Called when the associated call service dies.
800 */
801 private void handleCallServiceDeath() {
Santos Cordon682fe6b2014-05-20 08:56:39 -0700802 if (!mPendingOutgoingCalls.isEmpty()) {
Sailesh Nepal5a73b032014-06-25 15:53:21 -0700803 for (OutgoingCallResponse callback : mPendingOutgoingCalls.values()) {
804 callback.onOutgoingCallFailure(DisconnectCause.ERROR_UNSPECIFIED, null);
Santos Cordon682fe6b2014-05-20 08:56:39 -0700805 }
806 mPendingOutgoingCalls.clear();
807 }
808
809 if (!mPendingIncomingCalls.isEmpty()) {
Santos Cordon3d3b4052014-05-05 12:05:36 -0700810 // Iterate through a copy because the code inside the loop will modify the original
811 // list.
Santos Cordon682fe6b2014-05-20 08:56:39 -0700812 for (Call call : ImmutableList.copyOf(mPendingIncomingCalls)) {
813 Preconditions.checkState(call.isIncoming());
814 mIncomingCallsManager.handleFailedIncomingCall(call);
Santos Cordon3d3b4052014-05-05 12:05:36 -0700815 }
816
Santos Cordona1610702014-06-04 20:22:56 -0700817 if (!mPendingIncomingCalls.isEmpty()) {
818 Log.wtf(this, "Pending calls did not get cleared.");
819 mPendingIncomingCalls.clear();
820 }
821 }
Santos Cordon8f3282c2014-06-01 13:56:02 -0700822
Santos Cordona1610702014-06-04 20:22:56 -0700823 mCallIdMapper.clear();
824 }
Ihab Awad55a34282014-06-18 10:31:09 -0700825
826 private void logIncoming(String msg, Object... params) {
827 Log.d(this, "CallService -> Telecomm: " + msg, params);
828 }
829
830 private void logOutgoing(String msg, Object... params) {
831 Log.d(this, "Telecomm -> CallService: " + msg, params);
832 }
Santos Cordon5924bea2014-06-18 06:39:51 -0700833
834 private void queryRemoteConnectionServices(final RemoteServiceCallback callback) {
835 final List<IBinder> callServices = new ArrayList<>();
836 final List<ComponentName> components = new ArrayList<>();
837
838 mCallServiceRepository.lookupServices(new LookupCallback<CallServiceWrapper>() {
839 private int mRemainingResponses;
840
841 /** ${inheritDoc} */
842 @Override
843 public void onComplete(Collection<CallServiceWrapper> services) {
844 mRemainingResponses = services.size() - 1;
845 for (CallServiceWrapper cs : services) {
846 if (cs != CallServiceWrapper.this) {
847 final CallServiceWrapper currentCallService = cs;
848 cs.mBinder.bind(new BindCallback() {
849 @Override
850 public void onSuccess() {
851 Log.d(this, "Adding ***** %s", currentCallService.getDescriptor());
852 callServices.add(currentCallService.mServiceInterface.asBinder());
853 components.add(currentCallService.getComponentName());
854 maybeComplete();
855 }
856
857 @Override
858 public void onFailure() {
859 // add null so that we always add up to totalExpected even if
860 // some of the call services fail to bind.
861 maybeComplete();
862 }
863
864 private void maybeComplete() {
865 if (--mRemainingResponses == 0) {
866 try {
867 callback.onResult(components, callServices);
868 } catch (RemoteException ignored) {
869 }
870 }
871 }
872 });
873 }
874 }
875 }
876 });
877 }
Santos Cordon63aeb162014-02-10 09:20:40 -0800878}