blob: 5e0d9a8d283696699eb64e2a5b37cf0dca056469 [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;
77 private static final int MSG_HANDOFF_CALL = 15;
78 private static final int MSG_QUERY_REMOTE_CALL_SERVICES = 16;
Andrew Leee9a77652014-06-26 13:07:57 -070079 private static final int MSG_SET_CALL_VIDEO_PROVIDER = 17;
Tyler Gunne19cc002014-07-01 11:32:53 -070080 private static final int MSG_SET_FEATURES = 18;
Santos Cordon3d3b4052014-05-05 12:05:36 -070081
82 private final Handler mHandler = new Handler() {
83 @Override
84 public void handleMessage(Message msg) {
85 Call call;
86 switch (msg.what) {
Santos Cordon3d3b4052014-05-05 12:05:36 -070087 case MSG_NOTIFY_INCOMING_CALL:
88 CallInfo clientCallInfo = (CallInfo) msg.obj;
89 call = mCallIdMapper.getCall(clientCallInfo.getId());
Santos Cordon682fe6b2014-05-20 08:56:39 -070090 if (call != null && mPendingIncomingCalls.remove(call) &&
91 call.isIncoming()) {
Santos Cordon3d3b4052014-05-05 12:05:36 -070092 CallInfo callInfo = new CallInfo(null, clientCallInfo.getState(),
93 clientCallInfo.getHandle());
94 mIncomingCallsManager.handleSuccessfulIncomingCall(call, callInfo);
95 } else {
Santos Cordon5924bea2014-06-18 06:39:51 -070096 // TODO(santoscordon): For this an the other commented logging, we need
97 // to reenable it. At the moment all CallServiceAdapters receive
98 // notification of changes to all calls, even calls which it may not own
99 // (ala remote connections). We need to fix that and then uncomment the
100 // logging calls here.
101 //Log.w(this, "notifyIncomingCall, unknown incoming call: %s, id: %s",
102 // call, clientCallInfo.getId());
Santos Cordon3d3b4052014-05-05 12:05:36 -0700103 }
104 break;
Santos Cordon682fe6b2014-05-20 08:56:39 -0700105 case MSG_HANDLE_SUCCESSFUL_OUTGOING_CALL: {
106 String callId = (String) msg.obj;
107 if (mPendingOutgoingCalls.containsKey(callId)) {
Sailesh Nepal5a73b032014-06-25 15:53:21 -0700108 mPendingOutgoingCalls.remove(callId).onOutgoingCallSuccess();
Santos Cordon3d3b4052014-05-05 12:05:36 -0700109 } else {
Santos Cordon5924bea2014-06-18 06:39:51 -0700110 //Log.w(this, "handleSuccessfulOutgoingCall, unknown call: %s", callId);
Santos Cordon3d3b4052014-05-05 12:05:36 -0700111 }
112 break;
Santos Cordon682fe6b2014-05-20 08:56:39 -0700113 }
Santos Cordon3d3b4052014-05-05 12:05:36 -0700114 case MSG_HANDLE_FAILED_OUTGOING_CALL: {
115 SomeArgs args = (SomeArgs) msg.obj;
116 try {
Santos Cordon682fe6b2014-05-20 08:56:39 -0700117 String callId = (String) args.arg1;
Ihab Awada3cb9e32014-06-03 18:45:05 -0700118 int statusCode = args.argi1;
119 String statusMsg = (String) args.arg2;
Santos Cordon682fe6b2014-05-20 08:56:39 -0700120 // TODO(santoscordon): Do something with 'reason' or get rid of it.
121
122 if (mPendingOutgoingCalls.containsKey(callId)) {
Sailesh Nepal5a73b032014-06-25 15:53:21 -0700123 mPendingOutgoingCalls.remove(callId).onOutgoingCallFailure(
124 statusCode, statusMsg);
Santos Cordon682fe6b2014-05-20 08:56:39 -0700125 mCallIdMapper.removeCall(callId);
Santos Cordon3d3b4052014-05-05 12:05:36 -0700126 } else {
Santos Cordon5924bea2014-06-18 06:39:51 -0700127 //Log.w(this, "handleFailedOutgoingCall, unknown call: %s", callId);
Santos Cordon3d3b4052014-05-05 12:05:36 -0700128 }
129 } finally {
130 args.recycle();
131 }
132 break;
133 }
Sailesh Nepal5a73b032014-06-25 15:53:21 -0700134 case MSG_CANCEL_OUTGOING_CALL: {
135 String callId = (String) msg.obj;
136 if (mPendingOutgoingCalls.containsKey(callId)) {
137 mPendingOutgoingCalls.remove(callId).onOutgoingCallCancel();
138 } else {
139 //Log.w(this, "cancelOutgoingCall, unknown call: %s", callId);
140 }
141 break;
142 }
Santos Cordon3d3b4052014-05-05 12:05:36 -0700143 case MSG_SET_ACTIVE:
144 call = mCallIdMapper.getCall(msg.obj);
145 if (call != null) {
146 mCallsManager.markCallAsActive(call);
147 } else {
Santos Cordon5924bea2014-06-18 06:39:51 -0700148 //Log.w(this, "setActive, unknown call id: %s", msg.obj);
Santos Cordon3d3b4052014-05-05 12:05:36 -0700149 }
150 break;
151 case MSG_SET_RINGING:
152 call = mCallIdMapper.getCall(msg.obj);
153 if (call != null) {
154 mCallsManager.markCallAsRinging(call);
155 } else {
Santos Cordon5924bea2014-06-18 06:39:51 -0700156 //Log.w(this, "setRinging, unknown call id: %s", msg.obj);
Santos Cordon3d3b4052014-05-05 12:05:36 -0700157 }
158 break;
159 case MSG_SET_DIALING:
160 call = mCallIdMapper.getCall(msg.obj);
161 if (call != null) {
162 mCallsManager.markCallAsDialing(call);
163 } else {
Santos Cordon5924bea2014-06-18 06:39:51 -0700164 //Log.w(this, "setDialing, unknown call id: %s", msg.obj);
Santos Cordon3d3b4052014-05-05 12:05:36 -0700165 }
166 break;
167 case MSG_SET_DISCONNECTED: {
168 SomeArgs args = (SomeArgs) msg.obj;
169 try {
170 call = mCallIdMapper.getCall(args.arg1);
171 String disconnectMessage = (String) args.arg2;
172 int disconnectCause = args.argi1;
173 if (call != null) {
174 mCallsManager.markCallAsDisconnected(call, disconnectCause,
175 disconnectMessage);
176 } else {
Santos Cordon5924bea2014-06-18 06:39:51 -0700177 //Log.w(this, "setDisconnected, unknown call id: %s", args.arg1);
Santos Cordon3d3b4052014-05-05 12:05:36 -0700178 }
179 } finally {
180 args.recycle();
181 }
182 break;
183 }
184 case MSG_SET_ON_HOLD:
185 call = mCallIdMapper.getCall(msg.obj);
186 if (call != null) {
187 mCallsManager.markCallAsOnHold(call);
188 } else {
Santos Cordon5924bea2014-06-18 06:39:51 -0700189 //Log.w(this, "setOnHold, unknown call id: %s", msg.obj);
Santos Cordon3d3b4052014-05-05 12:05:36 -0700190 }
191 break;
Evan Charlton352105c2014-06-03 14:10:54 -0700192 case MSG_SET_REQUESTING_RINGBACK: {
Ihab Awad50a57132014-05-28 16:49:38 -0700193 SomeArgs args = (SomeArgs) msg.obj;
194 try {
195 call = mCallIdMapper.getCall(args.arg1);
196 boolean ringback = (boolean) args.arg2;
197 if (call != null) {
198 call.setRequestingRingback(ringback);
199 } else {
Santos Cordon5924bea2014-06-18 06:39:51 -0700200 //Log.w(this, "setRingback, unknown call id: %s", args.arg1);
Ihab Awad50a57132014-05-28 16:49:38 -0700201 }
202 } finally {
203 args.recycle();
204 }
205 break;
Evan Charlton352105c2014-06-03 14:10:54 -0700206 }
Santos Cordona1610702014-06-04 20:22:56 -0700207 case MSG_ON_POST_DIAL_WAIT: {
Evan Charlton352105c2014-06-03 14:10:54 -0700208 SomeArgs args = (SomeArgs) msg.obj;
209 try {
210 call = mCallIdMapper.getCall(args.arg1);
211 if (call != null) {
212 String remaining = (String) args.arg2;
213 call.onPostDialWait(remaining);
214 } else {
Santos Cordon5924bea2014-06-18 06:39:51 -0700215 //Log.w(this, "onPostDialWait, unknown call id: %s", args.arg1);
Evan Charlton352105c2014-06-03 14:10:54 -0700216 }
217 } finally {
218 args.recycle();
219 }
Santos Cordona1610702014-06-04 20:22:56 -0700220 break;
221 }
Sailesh Nepal6098d2c2014-06-06 10:56:53 -0700222 case MSG_HANDOFF_CALL:
223 call = mCallIdMapper.getCall(msg.obj);
224 if (call != null) {
225 mCallsManager.startHandoffForCall(call);
226 } else {
Santos Cordon5924bea2014-06-18 06:39:51 -0700227 //Log.w(this, "handoffCall, unknown call id: %s", msg.obj);
Sailesh Nepal6098d2c2014-06-06 10:56:53 -0700228 }
229 break;
Santos Cordona1610702014-06-04 20:22:56 -0700230 case MSG_CAN_CONFERENCE: {
231 call = mCallIdMapper.getCall(msg.obj);
232 if (call != null) {
233 call.setIsConferenceCapable(msg.arg1 == 1);
234 } else {
Santos Cordon5924bea2014-06-18 06:39:51 -0700235 //Log.w(CallServiceWrapper.this, "canConference, unknown call id: %s",
236 // msg.obj);
Santos Cordona1610702014-06-04 20:22:56 -0700237 }
238 break;
239 }
240 case MSG_SET_IS_CONFERENCED: {
241 SomeArgs args = (SomeArgs) msg.obj;
242 try {
243 Call childCall = mCallIdMapper.getCall(args.arg1);
244 if (childCall != null) {
245 String conferenceCallId = (String) args.arg2;
Santos Cordona1610702014-06-04 20:22:56 -0700246 if (conferenceCallId == null) {
247 childCall.setParentCall(null);
248 } else {
249 Call conferenceCall = mCallIdMapper.getCall(conferenceCallId);
250 if (conferenceCall != null &&
251 !mPendingConferenceCalls.contains(conferenceCall)) {
252 childCall.setParentCall(conferenceCall);
253 } else {
Santos Cordon5924bea2014-06-18 06:39:51 -0700254 //Log.w(this, "setIsConferenced, unknown conference id %s",
255 // conferenceCallId);
Santos Cordona1610702014-06-04 20:22:56 -0700256 }
257 }
258 } else {
Santos Cordon5924bea2014-06-18 06:39:51 -0700259 //Log.w(this, "setIsConferenced, unknown call id: %s", args.arg1);
Santos Cordona1610702014-06-04 20:22:56 -0700260 }
261 } finally {
262 args.recycle();
263 }
264 break;
265 }
266 case MSG_ADD_CONFERENCE_CALL: {
267 SomeArgs args = (SomeArgs) msg.obj;
268 try {
269 String callId = (String) args.arg1;
Santos Cordona1610702014-06-04 20:22:56 -0700270 Call conferenceCall = mCallIdMapper.getCall(callId);
271 if (mPendingConferenceCalls.remove(conferenceCall)) {
272 Log.v(this, "confirming conf call %s", conferenceCall);
273 conferenceCall.confirmConference();
274 } else {
Santos Cordon5924bea2014-06-18 06:39:51 -0700275 //Log.w(this, "addConference, unknown call id: %s", callId);
Santos Cordona1610702014-06-04 20:22:56 -0700276 }
277 } finally {
278 args.recycle();
279 }
280 break;
281 }
Santos Cordon5924bea2014-06-18 06:39:51 -0700282 case MSG_QUERY_REMOTE_CALL_SERVICES: {
283 CallServiceWrapper.this.queryRemoteConnectionServices(
284 (RemoteServiceCallback) msg.obj);
Andrew Leee9a77652014-06-26 13:07:57 -0700285 break;
286 }
287 case MSG_SET_CALL_VIDEO_PROVIDER: {
288 SomeArgs args = (SomeArgs) msg.obj;
289 try {
290 call = mCallIdMapper.getCall(args.arg1);
Nancy Chena65d41f2014-06-24 12:06:03 -0700291 ICallVideoProvider callVideoProvider = (ICallVideoProvider) args.arg2;
Andrew Leee9a77652014-06-26 13:07:57 -0700292 if (call != null) {
Nancy Chena65d41f2014-06-24 12:06:03 -0700293 call.setCallVideoProvider(callVideoProvider);
Andrew Leee9a77652014-06-26 13:07:57 -0700294 }
295 } finally {
296 args.recycle();
297 }
298 break;
Santos Cordon5924bea2014-06-18 06:39:51 -0700299 }
Tyler Gunne19cc002014-07-01 11:32:53 -0700300 case MSG_SET_FEATURES: {
301 SomeArgs args = (SomeArgs) msg.obj;
302 try {
303 call = mCallIdMapper.getCall(args.arg1);
304 int features = (int) args.arg2;
305 if (call != null) {
306 call.setFeatures(features);
307 }
308 } finally {
309 args.recycle();
310 }
311 break;
312 }
Santos Cordon3d3b4052014-05-05 12:05:36 -0700313 }
314 }
315 };
316
317 /** {@inheritDoc} */
318 @Override
Santos Cordon3d3b4052014-05-05 12:05:36 -0700319 public void notifyIncomingCall(CallInfo callInfo) {
Ihab Awad55a34282014-06-18 10:31:09 -0700320 logIncoming("notifyIncomingCall %s", callInfo);
Santos Cordon3d3b4052014-05-05 12:05:36 -0700321 mCallIdMapper.checkValidCallId(callInfo.getId());
322 mHandler.obtainMessage(MSG_NOTIFY_INCOMING_CALL, callInfo).sendToTarget();
323 }
324
325 /** {@inheritDoc} */
326 @Override
327 public void handleSuccessfulOutgoingCall(String callId) {
Ihab Awad55a34282014-06-18 10:31:09 -0700328 logIncoming("handleSuccessfulOutgoingCall %s", callId);
Santos Cordon3d3b4052014-05-05 12:05:36 -0700329 mCallIdMapper.checkValidCallId(callId);
330 mHandler.obtainMessage(MSG_HANDLE_SUCCESSFUL_OUTGOING_CALL, callId).sendToTarget();
331 }
332
333 /** {@inheritDoc} */
334 @Override
Ihab Awada3cb9e32014-06-03 18:45:05 -0700335 public void handleFailedOutgoingCall(
336 ConnectionRequest request,
337 int errorCode,
338 String errorMsg) {
Ihab Awad55a34282014-06-18 10:31:09 -0700339 logIncoming("handleFailedOutgoingCall %s %d %s", request, errorCode, errorMsg);
Ihab Awada3cb9e32014-06-03 18:45:05 -0700340 mCallIdMapper.checkValidCallId(request.getCallId());
Santos Cordon3d3b4052014-05-05 12:05:36 -0700341 SomeArgs args = SomeArgs.obtain();
Ihab Awada3cb9e32014-06-03 18:45:05 -0700342 args.arg1 = request.getCallId();
343 args.argi1 = errorCode;
344 args.arg2 = errorMsg;
Santos Cordon3d3b4052014-05-05 12:05:36 -0700345 mHandler.obtainMessage(MSG_HANDLE_FAILED_OUTGOING_CALL, args).sendToTarget();
346 }
347
348 /** {@inheritDoc} */
349 @Override
Sailesh Nepal5a73b032014-06-25 15:53:21 -0700350 public void cancelOutgoingCall(String callId) {
351 logIncoming("cancelOutgoingCall %s", callId);
352 mCallIdMapper.checkValidCallId(callId);
353 mHandler.obtainMessage(MSG_CANCEL_OUTGOING_CALL, callId).sendToTarget();
354 }
355
356 /** {@inheritDoc} */
357 @Override
Santos Cordon3d3b4052014-05-05 12:05:36 -0700358 public void setActive(String callId) {
Ihab Awad55a34282014-06-18 10:31:09 -0700359 logIncoming("setActive %s", callId);
Santos Cordon3d3b4052014-05-05 12:05:36 -0700360 mCallIdMapper.checkValidCallId(callId);
361 mHandler.obtainMessage(MSG_SET_ACTIVE, callId).sendToTarget();
362 }
363
364 /** {@inheritDoc} */
365 @Override
366 public void setRinging(String callId) {
Ihab Awad55a34282014-06-18 10:31:09 -0700367 logIncoming("setRinging %s", callId);
Santos Cordon3d3b4052014-05-05 12:05:36 -0700368 mCallIdMapper.checkValidCallId(callId);
369 mHandler.obtainMessage(MSG_SET_RINGING, callId).sendToTarget();
370 }
371
372 /** {@inheritDoc} */
373 @Override
Andrew Leee9a77652014-06-26 13:07:57 -0700374 public void setCallVideoProvider(String callId, ICallVideoProvider callVideoProvider) {
375 logIncoming("setCallVideoProvider %s", callId);
376 mCallIdMapper.checkValidCallId(callId);
377 SomeArgs args = SomeArgs.obtain();
378 args.arg1 = callId;
379 args.arg2 = callVideoProvider;
380 mHandler.obtainMessage(MSG_SET_CALL_VIDEO_PROVIDER, args).sendToTarget();
381 }
382
383 /** {@inheritDoc} */
384 @Override
Santos Cordon3d3b4052014-05-05 12:05:36 -0700385 public void setDialing(String callId) {
Ihab Awad55a34282014-06-18 10:31:09 -0700386 logIncoming("setDialing %s", callId);
Santos Cordon3d3b4052014-05-05 12:05:36 -0700387 mCallIdMapper.checkValidCallId(callId);
388 mHandler.obtainMessage(MSG_SET_DIALING, callId).sendToTarget();
389 }
390
391 /** {@inheritDoc} */
392 @Override
393 public void setDisconnected(
394 String callId, int disconnectCause, String disconnectMessage) {
Ihab Awad55a34282014-06-18 10:31:09 -0700395 logIncoming("setDisconnected %s %d %s", callId, disconnectCause, disconnectMessage);
Santos Cordon3d3b4052014-05-05 12:05:36 -0700396 mCallIdMapper.checkValidCallId(callId);
397 SomeArgs args = SomeArgs.obtain();
398 args.arg1 = callId;
399 args.arg2 = disconnectMessage;
400 args.argi1 = disconnectCause;
401 mHandler.obtainMessage(MSG_SET_DISCONNECTED, args).sendToTarget();
402 }
403
404 /** {@inheritDoc} */
405 @Override
406 public void setOnHold(String callId) {
Ihab Awad55a34282014-06-18 10:31:09 -0700407 logIncoming("setOnHold %s", callId);
Santos Cordon3d3b4052014-05-05 12:05:36 -0700408 mCallIdMapper.checkValidCallId(callId);
409 mHandler.obtainMessage(MSG_SET_ON_HOLD, callId).sendToTarget();
410 }
Ihab Awad50a57132014-05-28 16:49:38 -0700411
412 /** {@inheritDoc} */
413 @Override
414 public void setRequestingRingback(String callId, boolean ringback) {
Ihab Awad55a34282014-06-18 10:31:09 -0700415 logIncoming("setRequestingRingback %s %b", callId, ringback);
Ihab Awad50a57132014-05-28 16:49:38 -0700416 mCallIdMapper.checkValidCallId(callId);
417 SomeArgs args = SomeArgs.obtain();
418 args.arg1 = callId;
419 args.arg2 = ringback;
420 mHandler.obtainMessage(MSG_SET_REQUESTING_RINGBACK, args).sendToTarget();
421 }
Santos Cordon8f3282c2014-06-01 13:56:02 -0700422
423 /** ${inheritDoc} */
424 @Override
425 public void removeCall(String callId) {
Ihab Awad55a34282014-06-18 10:31:09 -0700426 logIncoming("removeCall %s", callId);
Santos Cordon8f3282c2014-06-01 13:56:02 -0700427 }
428
429 /** ${inheritDoc} */
430 @Override
Santos Cordona1610702014-06-04 20:22:56 -0700431 public void setCanConference(String callId, boolean canConference) {
Ihab Awad55a34282014-06-18 10:31:09 -0700432 logIncoming("setCanConference %s %b", callId, canConference);
Santos Cordona1610702014-06-04 20:22:56 -0700433 mHandler.obtainMessage(MSG_CAN_CONFERENCE, canConference ? 1 : 0, 0, callId)
434 .sendToTarget();
Santos Cordon8f3282c2014-06-01 13:56:02 -0700435 }
436
437 /** ${inheritDoc} */
438 @Override
Santos Cordona1610702014-06-04 20:22:56 -0700439 public void setIsConferenced(String callId, String conferenceCallId) {
Ihab Awad55a34282014-06-18 10:31:09 -0700440 logIncoming("setIsConferenced %s %s", callId, conferenceCallId);
Santos Cordona1610702014-06-04 20:22:56 -0700441 SomeArgs args = SomeArgs.obtain();
442 args.arg1 = callId;
443 args.arg2 = conferenceCallId;
444 mHandler.obtainMessage(MSG_SET_IS_CONFERENCED, args).sendToTarget();
445 }
446
447 /** ${InheritDoc} */
448 @Override
449 public void addConferenceCall(String callId, CallInfo callInfo) {
Ihab Awad55a34282014-06-18 10:31:09 -0700450 logIncoming("addConferenceCall %s %s", callId, callInfo);
Santos Cordona1610702014-06-04 20:22:56 -0700451 mCallIdMapper.checkValidCallId(callId);
452 SomeArgs args = SomeArgs.obtain();
453 args.arg1 = callId;
454 args.arg2 = callInfo;
455 mHandler.obtainMessage(MSG_ADD_CONFERENCE_CALL, args).sendToTarget();
Santos Cordon8f3282c2014-06-01 13:56:02 -0700456 }
Evan Charlton352105c2014-06-03 14:10:54 -0700457
458 @Override
459 public void onPostDialWait(String callId, String remaining) throws RemoteException {
Ihab Awad55a34282014-06-18 10:31:09 -0700460 logIncoming("onPostDialWait %s %s", callId, remaining);
Evan Charlton352105c2014-06-03 14:10:54 -0700461 mCallIdMapper.checkValidCallId(callId);
462 SomeArgs args = SomeArgs.obtain();
463 args.arg1 = callId;
464 args.arg2 = remaining;
465 mHandler.obtainMessage(MSG_ON_POST_DIAL_WAIT, args).sendToTarget();
466 }
Sailesh Nepal6098d2c2014-06-06 10:56:53 -0700467
468 /** {@inheritDoc} */
469 @Override
470 public void handoffCall(String callId) {
Ihab Awad55a34282014-06-18 10:31:09 -0700471 logIncoming("handoffCall %s", callId);
Sailesh Nepal6098d2c2014-06-06 10:56:53 -0700472 mCallIdMapper.checkValidCallId(callId);
473 mHandler.obtainMessage(MSG_HANDOFF_CALL, callId).sendToTarget();
474 }
Santos Cordon5924bea2014-06-18 06:39:51 -0700475
476 /** ${inheritDoc} */
477 @Override
478 public void queryRemoteConnectionServices(RemoteServiceCallback callback) {
479 logIncoming("queryRemoteCSs");
480 mHandler.obtainMessage(MSG_QUERY_REMOTE_CALL_SERVICES, callback).sendToTarget();
481 }
Tyler Gunne19cc002014-07-01 11:32:53 -0700482
483 @Override
484 public void setFeatures(String callId, int features) {
485 logIncoming("setFeatures %s %d", callId, features);
486 mCallIdMapper.checkValidCallId(callId);
487 SomeArgs args = SomeArgs.obtain();
488 args.arg1 = callId;
489 args.arg2 = features;
490 mHandler.obtainMessage(MSG_SET_FEATURES, args).sendToTarget();
491 }
Santos Cordon3d3b4052014-05-05 12:05:36 -0700492 }
493
494 private final Adapter mAdapter = new Adapter();
495 private final CallsManager mCallsManager = CallsManager.getInstance();
Santos Cordona1610702014-06-04 20:22:56 -0700496 private final Set<Call> mPendingIncomingCalls = new HashSet<>();
497 private final Set<Call> mPendingConferenceCalls = new HashSet<>();
Ben Giladc5b22692014-02-18 20:03:22 -0800498 private final CallServiceDescriptor mDescriptor;
Santos Cordon3d3b4052014-05-05 12:05:36 -0700499 private final CallIdMapper mCallIdMapper = new CallIdMapper("CallService");
Santos Cordon3d3b4052014-05-05 12:05:36 -0700500 private final IncomingCallsManager mIncomingCallsManager;
Sailesh Nepal5a73b032014-06-25 15:53:21 -0700501 private final Map<String, OutgoingCallResponse> mPendingOutgoingCalls = new HashMap<>();
Santos Cordona1610702014-06-04 20:22:56 -0700502 private final Handler mHandler = new Handler();
Santos Cordonc195e362014-02-11 17:05:31 -0800503
Ben Gilad61925612014-03-11 19:06:36 -0700504 private Binder mBinder = new Binder();
Santos Cordon3d3b4052014-05-05 12:05:36 -0700505 private ICallService mServiceInterface;
Santos Cordon5924bea2014-06-18 06:39:51 -0700506 private final CallServiceRepository mCallServiceRepository;
Ben Gilad61925612014-03-11 19:06:36 -0700507
Santos Cordon63aeb162014-02-10 09:20:40 -0800508 /**
Sailesh Nepale59bb192014-04-01 18:33:59 -0700509 * Creates a call-service for the specified descriptor.
Santos Cordonc195e362014-02-11 17:05:31 -0800510 *
Santos Cordon61d0f702014-02-19 02:52:23 -0800511 * @param descriptor The call-service descriptor from
Santos Cordon3d3b4052014-05-05 12:05:36 -0700512 * {@link ICallServiceProvider#lookupCallServices}.
Sailesh Nepale59bb192014-04-01 18:33:59 -0700513 * @param incomingCallsManager Manages the incoming call initialization flow.
Santos Cordon5924bea2014-06-18 06:39:51 -0700514 * @param callServiceRepository Call service repository.
Santos Cordon63aeb162014-02-10 09:20:40 -0800515 */
Sailesh Nepale59bb192014-04-01 18:33:59 -0700516 CallServiceWrapper(
517 CallServiceDescriptor descriptor,
Santos Cordon5924bea2014-06-18 06:39:51 -0700518 IncomingCallsManager incomingCallsManager,
519 CallServiceRepository callServiceRepository) {
Sailesh Nepala439e1b2014-03-11 18:19:58 -0700520 super(TelecommConstants.ACTION_CALL_SERVICE, descriptor.getServiceComponent());
Ben Giladc5b22692014-02-18 20:03:22 -0800521 mDescriptor = descriptor;
Santos Cordon3d3b4052014-05-05 12:05:36 -0700522 mIncomingCallsManager = incomingCallsManager;
Santos Cordon5924bea2014-06-18 06:39:51 -0700523 mCallServiceRepository = callServiceRepository;
Santos Cordon63aeb162014-02-10 09:20:40 -0800524 }
525
Ben Gilad61925612014-03-11 19:06:36 -0700526 CallServiceDescriptor getDescriptor() {
Ben Giladc5b22692014-02-18 20:03:22 -0800527 return mDescriptor;
Santos Cordonc195e362014-02-11 17:05:31 -0800528 }
529
Santos Cordon63aeb162014-02-10 09:20:40 -0800530 /** See {@link ICallService#setCallServiceAdapter}. */
Sailesh Nepale59bb192014-04-01 18:33:59 -0700531 private void setCallServiceAdapter(ICallServiceAdapter callServiceAdapter) {
Santos Cordon61d0f702014-02-19 02:52:23 -0800532 if (isServiceValid("setCallServiceAdapter")) {
533 try {
Ihab Awad55a34282014-06-18 10:31:09 -0700534 logOutgoing("setCallServiceAdapter %s", callServiceAdapter);
Santos Cordon63aeb162014-02-10 09:20:40 -0800535 mServiceInterface.setCallServiceAdapter(callServiceAdapter);
Santos Cordon61d0f702014-02-19 02:52:23 -0800536 } catch (RemoteException e) {
Santos Cordon63aeb162014-02-10 09:20:40 -0800537 }
Santos Cordon63aeb162014-02-10 09:20:40 -0800538 }
539 }
540
Ben Gilad61925612014-03-11 19:06:36 -0700541 /**
Santos Cordon682fe6b2014-05-20 08:56:39 -0700542 * Attempts to place the specified call, see {@link ICallService#call}. Returns the result
543 * asynchronously through the specified callback.
Ben Gilad61925612014-03-11 19:06:36 -0700544 */
Sailesh Nepal5a73b032014-06-25 15:53:21 -0700545 void call(final Call call, final OutgoingCallResponse callResponse) {
Santos Cordon682fe6b2014-05-20 08:56:39 -0700546 Log.d(this, "call(%s) via %s.", call, getComponentName());
Ben Gilad61925612014-03-11 19:06:36 -0700547 BindCallback callback = new BindCallback() {
Santos Cordon3d3b4052014-05-05 12:05:36 -0700548 @Override
549 public void onSuccess() {
Santos Cordon682fe6b2014-05-20 08:56:39 -0700550 String callId = mCallIdMapper.getCallId(call);
Sailesh Nepal5a73b032014-06-25 15:53:21 -0700551 mPendingOutgoingCalls.put(callId, callResponse);
Santos Cordon682fe6b2014-05-20 08:56:39 -0700552
553 try {
554 CallInfo callInfo = call.toCallInfo(callId);
Ihab Awad55a34282014-06-18 10:31:09 -0700555 logOutgoing("call %s", callInfo);
Santos Cordon682fe6b2014-05-20 08:56:39 -0700556 mServiceInterface.call(callInfo);
557 } catch (RemoteException e) {
Santos Cordon5924bea2014-06-18 06:39:51 -0700558 Log.e(this, e, "Failure to call -- %s", getDescriptor());
Sailesh Nepal5a73b032014-06-25 15:53:21 -0700559 mPendingOutgoingCalls.remove(callId).onOutgoingCallFailure(
560 DisconnectCause.ERROR_UNSPECIFIED, e.toString());
Ben Gilad61925612014-03-11 19:06:36 -0700561 }
Santos Cordon63aeb162014-02-10 09:20:40 -0800562 }
Santos Cordon3d3b4052014-05-05 12:05:36 -0700563
564 @Override
565 public void onFailure() {
Santos Cordon5924bea2014-06-18 06:39:51 -0700566 Log.e(this, new Exception(), "Failure to call %s", getDescriptor());
Sailesh Nepal5a73b032014-06-25 15:53:21 -0700567 callResponse.onOutgoingCallFailure(DisconnectCause.ERROR_UNSPECIFIED, null);
Ben Gilad61925612014-03-11 19:06:36 -0700568 }
569 };
570
571 mBinder.bind(callback);
Santos Cordon63aeb162014-02-10 09:20:40 -0800572 }
573
Ihab Awad74549ec2014-03-10 15:33:25 -0700574 /** @see CallService#abort(String) */
Sailesh Nepale59bb192014-04-01 18:33:59 -0700575 void abort(Call call) {
Santos Cordon682fe6b2014-05-20 08:56:39 -0700576 // Clear out any pending outgoing call data
577 String callId = mCallIdMapper.getCallId(call);
578
579 // If still bound, tell the call service to abort.
Ben Gilad28e8ad62014-03-06 17:01:54 -0800580 if (isServiceValid("abort")) {
581 try {
Ihab Awad55a34282014-06-18 10:31:09 -0700582 logOutgoing("abort %s", callId);
Santos Cordon682fe6b2014-05-20 08:56:39 -0700583 mServiceInterface.abort(callId);
Ben Gilad28e8ad62014-03-06 17:01:54 -0800584 } catch (RemoteException e) {
Santos Cordon63aeb162014-02-10 09:20:40 -0800585 }
Santos Cordon61d0f702014-02-19 02:52:23 -0800586 }
Santos Cordon682fe6b2014-05-20 08:56:39 -0700587
588 removeCall(call);
Santos Cordon61d0f702014-02-19 02:52:23 -0800589 }
590
Ihab Awad74549ec2014-03-10 15:33:25 -0700591 /** @see CallService#hold(String) */
Sailesh Nepale59bb192014-04-01 18:33:59 -0700592 void hold(Call call) {
Yorke Leecdf3ebd2014-03-12 18:31:41 -0700593 if (isServiceValid("hold")) {
594 try {
Ihab Awad55a34282014-06-18 10:31:09 -0700595 logOutgoing("hold %s", mCallIdMapper.getCallId(call));
Sailesh Nepale59bb192014-04-01 18:33:59 -0700596 mServiceInterface.hold(mCallIdMapper.getCallId(call));
Yorke Leecdf3ebd2014-03-12 18:31:41 -0700597 } catch (RemoteException e) {
Yorke Leecdf3ebd2014-03-12 18:31:41 -0700598 }
599 }
600 }
601
Ihab Awad74549ec2014-03-10 15:33:25 -0700602 /** @see CallService#unhold(String) */
Sailesh Nepale59bb192014-04-01 18:33:59 -0700603 void unhold(Call call) {
Yorke Leecdf3ebd2014-03-12 18:31:41 -0700604 if (isServiceValid("unhold")) {
605 try {
Ihab Awad55a34282014-06-18 10:31:09 -0700606 logOutgoing("unhold %s", mCallIdMapper.getCallId(call));
Sailesh Nepale59bb192014-04-01 18:33:59 -0700607 mServiceInterface.unhold(mCallIdMapper.getCallId(call));
Yorke Leecdf3ebd2014-03-12 18:31:41 -0700608 } catch (RemoteException e) {
Yorke Leecdf3ebd2014-03-12 18:31:41 -0700609 }
610 }
611 }
612
Ihab Awad74549ec2014-03-10 15:33:25 -0700613 /** @see CallService#onAudioStateChanged(String,CallAudioState) */
Sailesh Nepale59bb192014-04-01 18:33:59 -0700614 void onAudioStateChanged(Call activeCall, CallAudioState audioState) {
Sailesh Nepal6aca10a2014-03-24 16:11:02 -0700615 if (isServiceValid("onAudioStateChanged")) {
616 try {
Ihab Awad55a34282014-06-18 10:31:09 -0700617 logOutgoing("onAudioStateChanged %s %s",
618 mCallIdMapper.getCallId(activeCall), audioState);
Sailesh Nepale59bb192014-04-01 18:33:59 -0700619 mServiceInterface.onAudioStateChanged(mCallIdMapper.getCallId(activeCall),
620 audioState);
Sailesh Nepal6aca10a2014-03-24 16:11:02 -0700621 } catch (RemoteException e) {
Sailesh Nepal6aca10a2014-03-24 16:11:02 -0700622 }
623 }
624 }
625
Ben Gilad61925612014-03-11 19:06:36 -0700626 /**
627 * Starts retrieval of details for an incoming call. Details are returned through the
628 * call-service adapter using the specified call ID. Upon failure, the specified error callback
Santos Cordon3d3b4052014-05-05 12:05:36 -0700629 * is invoked. Can be invoked even when the call service is unbound. See
630 * {@link ICallService#setIncomingCallId}.
Ben Gilad61925612014-03-11 19:06:36 -0700631 *
Sailesh Nepale59bb192014-04-01 18:33:59 -0700632 * @param call The call used for the incoming call.
Ben Gilad61925612014-03-11 19:06:36 -0700633 * @param extras The {@link CallService}-provided extras which need to be sent back.
634 * @param errorCallback The callback to invoke upon failure.
635 */
Sailesh Nepale59bb192014-04-01 18:33:59 -0700636 void setIncomingCallId(final Call call, final Bundle extras, final Runnable errorCallback) {
637 Log.d(this, "setIncomingCall(%s) via %s.", call, getComponentName());
Ben Gilad61925612014-03-11 19:06:36 -0700638 BindCallback callback = new BindCallback() {
Santos Cordon3d3b4052014-05-05 12:05:36 -0700639 @Override
640 public void onSuccess() {
Ben Gilad61925612014-03-11 19:06:36 -0700641 if (isServiceValid("setIncomingCallId")) {
Santos Cordon682fe6b2014-05-20 08:56:39 -0700642 mPendingIncomingCalls.add(call);
Ben Gilad61925612014-03-11 19:06:36 -0700643 try {
Ihab Awad55a34282014-06-18 10:31:09 -0700644 logOutgoing("setIncomingCallId %s %s",
645 mCallIdMapper.getCallId(call), extras);
Sailesh Nepale59bb192014-04-01 18:33:59 -0700646 mServiceInterface.setIncomingCallId(mCallIdMapper.getCallId(call),
647 extras);
Ben Gilad61925612014-03-11 19:06:36 -0700648 } catch (RemoteException e) {
Ben Gilad61925612014-03-11 19:06:36 -0700649 }
650 }
Santos Cordon61d0f702014-02-19 02:52:23 -0800651 }
Santos Cordon3d3b4052014-05-05 12:05:36 -0700652
653 @Override
654 public void onFailure() {
Ben Gilad61925612014-03-11 19:06:36 -0700655 errorCallback.run();
656 }
657 };
658
659 mBinder.bind(callback);
Santos Cordon63aeb162014-02-10 09:20:40 -0800660 }
661
Ihab Awad74549ec2014-03-10 15:33:25 -0700662 /** @see CallService#disconnect(String) */
Sailesh Nepale59bb192014-04-01 18:33:59 -0700663 void disconnect(Call call) {
Santos Cordon61d0f702014-02-19 02:52:23 -0800664 if (isServiceValid("disconnect")) {
665 try {
Ihab Awad55a34282014-06-18 10:31:09 -0700666 logOutgoing("disconnect %s", mCallIdMapper.getCallId(call));
Sailesh Nepale59bb192014-04-01 18:33:59 -0700667 mServiceInterface.disconnect(mCallIdMapper.getCallId(call));
Santos Cordon61d0f702014-02-19 02:52:23 -0800668 } catch (RemoteException e) {
Santos Cordon63aeb162014-02-10 09:20:40 -0800669 }
Santos Cordon63aeb162014-02-10 09:20:40 -0800670 }
671 }
Santos Cordon5c12c6e2014-02-13 14:35:31 -0800672
Ihab Awad74549ec2014-03-10 15:33:25 -0700673 /** @see CallService#answer(String) */
Sailesh Nepale59bb192014-04-01 18:33:59 -0700674 void answer(Call call) {
Santos Cordon61d0f702014-02-19 02:52:23 -0800675 if (isServiceValid("answer")) {
676 try {
Ihab Awad55a34282014-06-18 10:31:09 -0700677 logOutgoing("answer %s", mCallIdMapper.getCallId(call));
Sailesh Nepale59bb192014-04-01 18:33:59 -0700678 mServiceInterface.answer(mCallIdMapper.getCallId(call));
Santos Cordon61d0f702014-02-19 02:52:23 -0800679 } catch (RemoteException e) {
Santos Cordon7917d382014-02-14 02:31:18 -0800680 }
Santos Cordon61d0f702014-02-19 02:52:23 -0800681 }
682 }
683
Ihab Awad74549ec2014-03-10 15:33:25 -0700684 /** @see CallService#reject(String) */
Sailesh Nepale59bb192014-04-01 18:33:59 -0700685 void reject(Call call) {
Santos Cordon61d0f702014-02-19 02:52:23 -0800686 if (isServiceValid("reject")) {
687 try {
Ihab Awad55a34282014-06-18 10:31:09 -0700688 logOutgoing("reject %s", mCallIdMapper.getCallId(call));
Sailesh Nepale59bb192014-04-01 18:33:59 -0700689 mServiceInterface.reject(mCallIdMapper.getCallId(call));
Santos Cordon61d0f702014-02-19 02:52:23 -0800690 } catch (RemoteException e) {
Ihab Awad74549ec2014-03-10 15:33:25 -0700691 }
692 }
693 }
694
695 /** @see CallService#playDtmfTone(String,char) */
Sailesh Nepale59bb192014-04-01 18:33:59 -0700696 void playDtmfTone(Call call, char digit) {
Ihab Awad74549ec2014-03-10 15:33:25 -0700697 if (isServiceValid("playDtmfTone")) {
698 try {
Ihab Awad55a34282014-06-18 10:31:09 -0700699 logOutgoing("playDtmfTone %s %c", mCallIdMapper.getCallId(call), digit);
Sailesh Nepale59bb192014-04-01 18:33:59 -0700700 mServiceInterface.playDtmfTone(mCallIdMapper.getCallId(call), digit);
Ihab Awad74549ec2014-03-10 15:33:25 -0700701 } catch (RemoteException e) {
Ihab Awad74549ec2014-03-10 15:33:25 -0700702 }
703 }
704 }
705
706 /** @see CallService#stopDtmfTone(String) */
Sailesh Nepale59bb192014-04-01 18:33:59 -0700707 void stopDtmfTone(Call call) {
Ihab Awad74549ec2014-03-10 15:33:25 -0700708 if (isServiceValid("stopDtmfTone")) {
709 try {
Ihab Awad55a34282014-06-18 10:31:09 -0700710 logOutgoing("stopDtmfTone %s", mCallIdMapper.getCallId(call));
Sailesh Nepale59bb192014-04-01 18:33:59 -0700711 mServiceInterface.stopDtmfTone(mCallIdMapper.getCallId(call));
Ihab Awad74549ec2014-03-10 15:33:25 -0700712 } catch (RemoteException e) {
Santos Cordon61d0f702014-02-19 02:52:23 -0800713 }
Santos Cordon7917d382014-02-14 02:31:18 -0800714 }
715 }
716
Sailesh Nepale59bb192014-04-01 18:33:59 -0700717 void addCall(Call call) {
Santos Cordona1610702014-06-04 20:22:56 -0700718 if (mCallIdMapper.getCallId(call) == null) {
719 mCallIdMapper.addCall(call);
720 }
Santos Cordon7917d382014-02-14 02:31:18 -0800721 }
722
Sailesh Nepal0e5410a2014-04-04 01:20:58 -0700723 /**
724 * Associates newCall with this call service by replacing callToReplace.
725 */
726 void replaceCall(Call newCall, Call callToReplace) {
727 Preconditions.checkState(callToReplace.getCallService() == this);
728 mCallIdMapper.replaceCall(newCall, callToReplace);
729 }
730
Sailesh Nepale59bb192014-04-01 18:33:59 -0700731 void removeCall(Call call) {
Santos Cordon682fe6b2014-05-20 08:56:39 -0700732 mPendingIncomingCalls.remove(call);
733
Sailesh Nepal5a73b032014-06-25 15:53:21 -0700734 OutgoingCallResponse outgoingResultCallback =
735 mPendingOutgoingCalls.remove(mCallIdMapper.getCallId(call));
Santos Cordon682fe6b2014-05-20 08:56:39 -0700736 if (outgoingResultCallback != null) {
Sailesh Nepal5a73b032014-06-25 15:53:21 -0700737 outgoingResultCallback.onOutgoingCallFailure(DisconnectCause.ERROR_UNSPECIFIED, null);
Santos Cordon682fe6b2014-05-20 08:56:39 -0700738 }
739
Sailesh Nepale59bb192014-04-01 18:33:59 -0700740 mCallIdMapper.removeCall(call);
Yorke Leeadee12d2014-03-13 12:08:30 -0700741 }
742
Evan Charlton352105c2014-06-03 14:10:54 -0700743 void onPostDialContinue(Call call, boolean proceed) {
744 if (isServiceValid("onPostDialContinue")) {
745 try {
Ihab Awad55a34282014-06-18 10:31:09 -0700746 logOutgoing("onPostDialContinue %s %b", mCallIdMapper.getCallId(call), proceed);
Evan Charlton352105c2014-06-03 14:10:54 -0700747 mServiceInterface.onPostDialContinue(mCallIdMapper.getCallId(call), proceed);
748 } catch (RemoteException ignored) {
749 }
750 }
751 }
752
Santos Cordona1610702014-06-04 20:22:56 -0700753 void conference(final Call conferenceCall, Call call) {
754 if (isServiceValid("conference")) {
755 try {
756 conferenceCall.setCallService(this);
757 mPendingConferenceCalls.add(conferenceCall);
758 mHandler.postDelayed(new Runnable() {
759 @Override public void run() {
760 if (mPendingConferenceCalls.remove(conferenceCall)) {
761 conferenceCall.expireConference();
762 Log.i(this, "Conference call expired: %s", conferenceCall);
763 }
764 }
765 }, Timeouts.getConferenceCallExpireMillis());
766
Ihab Awad55a34282014-06-18 10:31:09 -0700767 logOutgoing("conference %s %s",
768 mCallIdMapper.getCallId(conferenceCall),
769 mCallIdMapper.getCallId(call));
Santos Cordona1610702014-06-04 20:22:56 -0700770 mServiceInterface.conference(
771 mCallIdMapper.getCallId(conferenceCall),
772 mCallIdMapper.getCallId(call));
773 } catch (RemoteException ignored) {
774 }
775 }
776 }
777
778 void splitFromConference(Call call) {
779 if (isServiceValid("splitFromConference")) {
780 try {
Ihab Awad55a34282014-06-18 10:31:09 -0700781 logOutgoing("splitFromConference %s", mCallIdMapper.getCallId(call));
Santos Cordona1610702014-06-04 20:22:56 -0700782 mServiceInterface.splitFromConference(mCallIdMapper.getCallId(call));
783 } catch (RemoteException ignored) {
784 }
785 }
786 }
787
Santos Cordon5c12c6e2014-02-13 14:35:31 -0800788 /** {@inheritDoc} */
Santos Cordon3d3b4052014-05-05 12:05:36 -0700789 @Override
790 protected void setServiceInterface(IBinder binder) {
Santos Cordon4b2c1192014-03-19 18:15:38 -0700791 if (binder == null) {
792 // We have lost our service connection. Notify the world that this call service is done.
793 // We must notify the adapter before CallsManager. The adapter will force any pending
794 // outgoing calls to try the next call service. This needs to happen before CallsManager
795 // tries to clean up any calls still associated with this call service.
Santos Cordon3d3b4052014-05-05 12:05:36 -0700796 handleCallServiceDeath();
Santos Cordon4b2c1192014-03-19 18:15:38 -0700797 CallsManager.getInstance().handleCallServiceDeath(this);
798 mServiceInterface = null;
799 } else {
800 mServiceInterface = ICallService.Stub.asInterface(binder);
801 setCallServiceAdapter(mAdapter);
802 }
Santos Cordon5c12c6e2014-02-13 14:35:31 -0800803 }
Santos Cordon3d3b4052014-05-05 12:05:36 -0700804
805 /**
806 * Called when the associated call service dies.
807 */
808 private void handleCallServiceDeath() {
Santos Cordon682fe6b2014-05-20 08:56:39 -0700809 if (!mPendingOutgoingCalls.isEmpty()) {
Sailesh Nepal5a73b032014-06-25 15:53:21 -0700810 for (OutgoingCallResponse callback : mPendingOutgoingCalls.values()) {
811 callback.onOutgoingCallFailure(DisconnectCause.ERROR_UNSPECIFIED, null);
Santos Cordon682fe6b2014-05-20 08:56:39 -0700812 }
813 mPendingOutgoingCalls.clear();
814 }
815
816 if (!mPendingIncomingCalls.isEmpty()) {
Santos Cordon3d3b4052014-05-05 12:05:36 -0700817 // Iterate through a copy because the code inside the loop will modify the original
818 // list.
Santos Cordon682fe6b2014-05-20 08:56:39 -0700819 for (Call call : ImmutableList.copyOf(mPendingIncomingCalls)) {
820 Preconditions.checkState(call.isIncoming());
821 mIncomingCallsManager.handleFailedIncomingCall(call);
Santos Cordon3d3b4052014-05-05 12:05:36 -0700822 }
823
Santos Cordona1610702014-06-04 20:22:56 -0700824 if (!mPendingIncomingCalls.isEmpty()) {
825 Log.wtf(this, "Pending calls did not get cleared.");
826 mPendingIncomingCalls.clear();
827 }
828 }
Santos Cordon8f3282c2014-06-01 13:56:02 -0700829
Santos Cordona1610702014-06-04 20:22:56 -0700830 mCallIdMapper.clear();
831 }
Ihab Awad55a34282014-06-18 10:31:09 -0700832
833 private void logIncoming(String msg, Object... params) {
834 Log.d(this, "CallService -> Telecomm: " + msg, params);
835 }
836
837 private void logOutgoing(String msg, Object... params) {
838 Log.d(this, "Telecomm -> CallService: " + msg, params);
839 }
Santos Cordon5924bea2014-06-18 06:39:51 -0700840
841 private void queryRemoteConnectionServices(final RemoteServiceCallback callback) {
842 final List<IBinder> callServices = new ArrayList<>();
843 final List<ComponentName> components = new ArrayList<>();
844
845 mCallServiceRepository.lookupServices(new LookupCallback<CallServiceWrapper>() {
846 private int mRemainingResponses;
847
848 /** ${inheritDoc} */
849 @Override
850 public void onComplete(Collection<CallServiceWrapper> services) {
851 mRemainingResponses = services.size() - 1;
852 for (CallServiceWrapper cs : services) {
853 if (cs != CallServiceWrapper.this) {
854 final CallServiceWrapper currentCallService = cs;
855 cs.mBinder.bind(new BindCallback() {
856 @Override
857 public void onSuccess() {
858 Log.d(this, "Adding ***** %s", currentCallService.getDescriptor());
859 callServices.add(currentCallService.mServiceInterface.asBinder());
860 components.add(currentCallService.getComponentName());
861 maybeComplete();
862 }
863
864 @Override
865 public void onFailure() {
866 // add null so that we always add up to totalExpected even if
867 // some of the call services fail to bind.
868 maybeComplete();
869 }
870
871 private void maybeComplete() {
872 if (--mRemainingResponses == 0) {
873 try {
874 callback.onResult(components, callServices);
875 } catch (RemoteException ignored) {
876 }
877 }
878 }
879 });
880 }
881 }
882 }
883 });
884 }
Santos Cordon63aeb162014-02-10 09:20:40 -0800885}