blob: 6165804b4be7bf300af308e49329c3662e59fb1d [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
Evan Charltona05805b2014-03-05 08:21:46 -080019import android.os.Bundle;
Santos Cordon3d3b4052014-05-05 12:05:36 -070020import android.os.Handler;
Santos Cordon63aeb162014-02-10 09:20:40 -080021import android.os.IBinder;
Santos Cordon3d3b4052014-05-05 12:05:36 -070022import android.os.Message;
Santos Cordon63aeb162014-02-10 09:20:40 -080023import android.os.RemoteException;
Sailesh Nepal6aca10a2014-03-24 16:11:02 -070024import android.telecomm.CallAudioState;
Santos Cordon63aeb162014-02-10 09:20:40 -080025import android.telecomm.CallInfo;
Evan Charltona05805b2014-03-05 08:21:46 -080026import android.telecomm.CallService;
Ben Giladc5b22692014-02-18 20:03:22 -080027import android.telecomm.CallServiceDescriptor;
Ihab Awada3cb9e32014-06-03 18:45:05 -070028import android.telecomm.ConnectionRequest;
Sailesh Nepal83cfe7c2014-03-11 19:54:22 -070029import android.telecomm.TelecommConstants;
Ihab Awada3cb9e32014-06-03 18:45:05 -070030import android.telephony.DisconnectCause;
Sailesh Nepala439e1b2014-03-11 18:19:58 -070031
Santos Cordon3d3b4052014-05-05 12:05:36 -070032import com.android.internal.os.SomeArgs;
Sailesh Nepala439e1b2014-03-11 18:19:58 -070033import com.android.internal.telecomm.ICallService;
34import com.android.internal.telecomm.ICallServiceAdapter;
35import com.android.internal.telecomm.ICallServiceProvider;
Sailesh Nepal0e5410a2014-04-04 01:20:58 -070036import com.google.common.base.Preconditions;
Santos Cordon3d3b4052014-05-05 12:05:36 -070037import com.google.common.collect.ImmutableList;
38import com.google.common.collect.Sets;
39
Ihab Awada3cb9e32014-06-03 18:45:05 -070040import org.apache.http.conn.ClientConnectionRequest;
41
Santos Cordon682fe6b2014-05-20 08:56:39 -070042import java.util.HashMap;
Santos Cordon8f3282c2014-06-01 13:56:02 -070043import java.util.List;
Santos Cordon682fe6b2014-05-20 08:56:39 -070044import java.util.Map;
Santos Cordon3d3b4052014-05-05 12:05:36 -070045import java.util.Set;
Santos Cordon63aeb162014-02-10 09:20:40 -080046
47/**
48 * Wrapper for {@link ICallService}s, handles binding to {@link ICallService} and keeps track of
49 * when the object can safely be unbound. Other classes should not use {@link ICallService} directly
50 * and instead should use this class to invoke methods of {@link ICallService}.
Santos Cordon63aeb162014-02-10 09:20:40 -080051 */
Ben Gilad61925612014-03-11 19:06:36 -070052final class CallServiceWrapper extends ServiceBinder<ICallService> {
Santos Cordon63aeb162014-02-10 09:20:40 -080053
Santos Cordon3d3b4052014-05-05 12:05:36 -070054 private final class Adapter extends ICallServiceAdapter.Stub {
Santos Cordon3d3b4052014-05-05 12:05:36 -070055 private static final int MSG_NOTIFY_INCOMING_CALL = 1;
56 private static final int MSG_HANDLE_SUCCESSFUL_OUTGOING_CALL = 2;
57 private static final int MSG_HANDLE_FAILED_OUTGOING_CALL = 3;
58 private static final int MSG_SET_ACTIVE = 4;
59 private static final int MSG_SET_RINGING = 5;
60 private static final int MSG_SET_DIALING = 6;
61 private static final int MSG_SET_DISCONNECTED = 7;
62 private static final int MSG_SET_ON_HOLD = 8;
Ihab Awad50a57132014-05-28 16:49:38 -070063 private static final int MSG_SET_REQUESTING_RINGBACK = 9;
Evan Charlton352105c2014-06-03 14:10:54 -070064 private static final int MSG_ON_POST_DIAL_WAIT = 10;
Sailesh Nepal6098d2c2014-06-06 10:56:53 -070065 private static final int MSG_HANDOFF_CALL = 11;
Santos Cordon3d3b4052014-05-05 12:05:36 -070066
67 private final Handler mHandler = new Handler() {
68 @Override
69 public void handleMessage(Message msg) {
70 Call call;
71 switch (msg.what) {
Santos Cordon3d3b4052014-05-05 12:05:36 -070072 case MSG_NOTIFY_INCOMING_CALL:
73 CallInfo clientCallInfo = (CallInfo) msg.obj;
74 call = mCallIdMapper.getCall(clientCallInfo.getId());
Santos Cordon682fe6b2014-05-20 08:56:39 -070075 if (call != null && mPendingIncomingCalls.remove(call) &&
76 call.isIncoming()) {
Santos Cordon3d3b4052014-05-05 12:05:36 -070077 CallInfo callInfo = new CallInfo(null, clientCallInfo.getState(),
78 clientCallInfo.getHandle());
79 mIncomingCallsManager.handleSuccessfulIncomingCall(call, callInfo);
80 } else {
81 Log.w(this, "notifyIncomingCall, unknown incoming call: %s, id: %s",
82 call,
83 clientCallInfo.getId());
84 }
85 break;
Santos Cordon682fe6b2014-05-20 08:56:39 -070086 case MSG_HANDLE_SUCCESSFUL_OUTGOING_CALL: {
87 String callId = (String) msg.obj;
88 if (mPendingOutgoingCalls.containsKey(callId)) {
Ihab Awada3cb9e32014-06-03 18:45:05 -070089 mPendingOutgoingCalls.remove(callId).onResult(true, 0, null);
Santos Cordon3d3b4052014-05-05 12:05:36 -070090 } else {
Santos Cordon682fe6b2014-05-20 08:56:39 -070091 Log.w(this, "handleSuccessfulOutgoingCall, unknown call: %s", callId);
Santos Cordon3d3b4052014-05-05 12:05:36 -070092 }
93 break;
Santos Cordon682fe6b2014-05-20 08:56:39 -070094 }
Santos Cordon3d3b4052014-05-05 12:05:36 -070095 case MSG_HANDLE_FAILED_OUTGOING_CALL: {
96 SomeArgs args = (SomeArgs) msg.obj;
97 try {
Santos Cordon682fe6b2014-05-20 08:56:39 -070098 String callId = (String) args.arg1;
Ihab Awada3cb9e32014-06-03 18:45:05 -070099 int statusCode = args.argi1;
100 String statusMsg = (String) args.arg2;
Santos Cordon682fe6b2014-05-20 08:56:39 -0700101 // TODO(santoscordon): Do something with 'reason' or get rid of it.
102
103 if (mPendingOutgoingCalls.containsKey(callId)) {
Ihab Awada3cb9e32014-06-03 18:45:05 -0700104 mPendingOutgoingCalls.remove(callId).onResult(
105 false, statusCode, statusMsg);
Santos Cordon682fe6b2014-05-20 08:56:39 -0700106 mCallIdMapper.removeCall(callId);
Santos Cordon3d3b4052014-05-05 12:05:36 -0700107 } else {
Santos Cordon682fe6b2014-05-20 08:56:39 -0700108 Log.w(this, "handleFailedOutgoingCall, unknown call: %s", callId);
Santos Cordon3d3b4052014-05-05 12:05:36 -0700109 }
110 } finally {
111 args.recycle();
112 }
113 break;
114 }
115 case MSG_SET_ACTIVE:
116 call = mCallIdMapper.getCall(msg.obj);
117 if (call != null) {
118 mCallsManager.markCallAsActive(call);
119 } else {
120 Log.w(this, "setActive, unknown call id: %s", msg.obj);
121 }
122 break;
123 case MSG_SET_RINGING:
124 call = mCallIdMapper.getCall(msg.obj);
125 if (call != null) {
126 mCallsManager.markCallAsRinging(call);
127 } else {
128 Log.w(this, "setRinging, unknown call id: %s", msg.obj);
129 }
130 break;
131 case MSG_SET_DIALING:
132 call = mCallIdMapper.getCall(msg.obj);
133 if (call != null) {
134 mCallsManager.markCallAsDialing(call);
135 } else {
136 Log.w(this, "setDialing, unknown call id: %s", msg.obj);
137 }
138 break;
139 case MSG_SET_DISCONNECTED: {
140 SomeArgs args = (SomeArgs) msg.obj;
141 try {
142 call = mCallIdMapper.getCall(args.arg1);
143 String disconnectMessage = (String) args.arg2;
144 int disconnectCause = args.argi1;
145 if (call != null) {
146 mCallsManager.markCallAsDisconnected(call, disconnectCause,
147 disconnectMessage);
148 } else {
149 Log.w(this, "setDisconnected, unknown call id: %s", args.arg1);
150 }
151 } finally {
152 args.recycle();
153 }
154 break;
155 }
156 case MSG_SET_ON_HOLD:
157 call = mCallIdMapper.getCall(msg.obj);
158 if (call != null) {
159 mCallsManager.markCallAsOnHold(call);
160 } else {
161 Log.w(this, "setOnHold, unknown call id: %s", msg.obj);
162 }
163 break;
Evan Charlton352105c2014-06-03 14:10:54 -0700164 case MSG_SET_REQUESTING_RINGBACK: {
Ihab Awad50a57132014-05-28 16:49:38 -0700165 SomeArgs args = (SomeArgs) msg.obj;
166 try {
167 call = mCallIdMapper.getCall(args.arg1);
168 boolean ringback = (boolean) args.arg2;
169 if (call != null) {
170 call.setRequestingRingback(ringback);
171 } else {
172 Log.w(this, "setRingback, unknown call id: %s", args.arg1);
173 }
174 } finally {
175 args.recycle();
176 }
177 break;
Evan Charlton352105c2014-06-03 14:10:54 -0700178 }
179 case MSG_ON_POST_DIAL_WAIT:
180 SomeArgs args = (SomeArgs) msg.obj;
181 try {
182 call = mCallIdMapper.getCall(args.arg1);
183 if (call != null) {
184 String remaining = (String) args.arg2;
185 call.onPostDialWait(remaining);
186 } else {
187 Log.w(this, "onPostDialWait, unknown call id: %s", args.arg1);
188 }
189 } finally {
190 args.recycle();
191 }
Sailesh Nepal6098d2c2014-06-06 10:56:53 -0700192 case MSG_HANDOFF_CALL:
193 call = mCallIdMapper.getCall(msg.obj);
194 if (call != null) {
195 mCallsManager.startHandoffForCall(call);
196 } else {
197 Log.w(this, "handoffCall, unknown call id: %s", msg.obj);
198 }
199 break;
Santos Cordon3d3b4052014-05-05 12:05:36 -0700200 }
201 }
202 };
203
204 /** {@inheritDoc} */
205 @Override
206 public void setIsCompatibleWith(String callId, boolean isCompatible) {
Santos Cordon682fe6b2014-05-20 08:56:39 -0700207 Log.wtf(this, "Not expected.");
Santos Cordon3d3b4052014-05-05 12:05:36 -0700208 }
209
210 /** {@inheritDoc} */
211 @Override
212 public void notifyIncomingCall(CallInfo callInfo) {
213 mCallIdMapper.checkValidCallId(callInfo.getId());
214 mHandler.obtainMessage(MSG_NOTIFY_INCOMING_CALL, callInfo).sendToTarget();
215 }
216
217 /** {@inheritDoc} */
218 @Override
219 public void handleSuccessfulOutgoingCall(String callId) {
Santos Cordon682fe6b2014-05-20 08:56:39 -0700220 Log.d(this, "handleSuccessfulOutgoingCall %s", callId);
Santos Cordon3d3b4052014-05-05 12:05:36 -0700221 mCallIdMapper.checkValidCallId(callId);
222 mHandler.obtainMessage(MSG_HANDLE_SUCCESSFUL_OUTGOING_CALL, callId).sendToTarget();
223 }
224
225 /** {@inheritDoc} */
226 @Override
Ihab Awada3cb9e32014-06-03 18:45:05 -0700227 public void handleFailedOutgoingCall(
228 ConnectionRequest request,
229 int errorCode,
230 String errorMsg) {
231 mCallIdMapper.checkValidCallId(request.getCallId());
232 Log.d(this, "handleFailedOutgoingCall %s", request.getCallId());
Santos Cordon3d3b4052014-05-05 12:05:36 -0700233 SomeArgs args = SomeArgs.obtain();
Ihab Awada3cb9e32014-06-03 18:45:05 -0700234 args.arg1 = request.getCallId();
235 args.argi1 = errorCode;
236 args.arg2 = errorMsg;
Santos Cordon3d3b4052014-05-05 12:05:36 -0700237 mHandler.obtainMessage(MSG_HANDLE_FAILED_OUTGOING_CALL, args).sendToTarget();
238 }
239
240 /** {@inheritDoc} */
241 @Override
242 public void setActive(String callId) {
243 mCallIdMapper.checkValidCallId(callId);
244 mHandler.obtainMessage(MSG_SET_ACTIVE, callId).sendToTarget();
245 }
246
247 /** {@inheritDoc} */
248 @Override
249 public void setRinging(String callId) {
250 mCallIdMapper.checkValidCallId(callId);
251 mHandler.obtainMessage(MSG_SET_RINGING, callId).sendToTarget();
252 }
253
254 /** {@inheritDoc} */
255 @Override
256 public void setDialing(String callId) {
257 mCallIdMapper.checkValidCallId(callId);
258 mHandler.obtainMessage(MSG_SET_DIALING, callId).sendToTarget();
259 }
260
261 /** {@inheritDoc} */
262 @Override
263 public void setDisconnected(
264 String callId, int disconnectCause, String disconnectMessage) {
265 mCallIdMapper.checkValidCallId(callId);
266 SomeArgs args = SomeArgs.obtain();
267 args.arg1 = callId;
268 args.arg2 = disconnectMessage;
269 args.argi1 = disconnectCause;
270 mHandler.obtainMessage(MSG_SET_DISCONNECTED, args).sendToTarget();
271 }
272
273 /** {@inheritDoc} */
274 @Override
275 public void setOnHold(String callId) {
276 mCallIdMapper.checkValidCallId(callId);
277 mHandler.obtainMessage(MSG_SET_ON_HOLD, callId).sendToTarget();
278 }
Ihab Awad50a57132014-05-28 16:49:38 -0700279
280 /** {@inheritDoc} */
281 @Override
282 public void setRequestingRingback(String callId, boolean ringback) {
283 mCallIdMapper.checkValidCallId(callId);
284 SomeArgs args = SomeArgs.obtain();
285 args.arg1 = callId;
286 args.arg2 = ringback;
287 mHandler.obtainMessage(MSG_SET_REQUESTING_RINGBACK, args).sendToTarget();
288 }
Santos Cordon8f3282c2014-06-01 13:56:02 -0700289
290 /** ${inheritDoc} */
291 @Override
292 public void removeCall(String callId) {
293 }
294
295 /** ${inheritDoc} */
296 @Override
297 public void setCanConferenceWith(String callId, List<String> conferenceCapableCallIds) {
298 }
299
300 /** ${inheritDoc} */
301 @Override
302 public void setIsConferenced(String conferenceCallId, String callId, boolean isConferenced) {
303 }
Evan Charlton352105c2014-06-03 14:10:54 -0700304
305 @Override
306 public void onPostDialWait(String callId, String remaining) throws RemoteException {
307 mCallIdMapper.checkValidCallId(callId);
308 SomeArgs args = SomeArgs.obtain();
309 args.arg1 = callId;
310 args.arg2 = remaining;
311 mHandler.obtainMessage(MSG_ON_POST_DIAL_WAIT, args).sendToTarget();
312 }
Sailesh Nepal6098d2c2014-06-06 10:56:53 -0700313
314 /** {@inheritDoc} */
315 @Override
316 public void handoffCall(String callId) {
317 mCallIdMapper.checkValidCallId(callId);
318 mHandler.obtainMessage(MSG_HANDOFF_CALL, callId).sendToTarget();
319 }
Santos Cordon3d3b4052014-05-05 12:05:36 -0700320 }
321
322 private final Adapter mAdapter = new Adapter();
323 private final CallsManager mCallsManager = CallsManager.getInstance();
Santos Cordon682fe6b2014-05-20 08:56:39 -0700324 private final Set<Call> mPendingIncomingCalls = Sets.newHashSet();
Ben Giladc5b22692014-02-18 20:03:22 -0800325 private final CallServiceDescriptor mDescriptor;
Santos Cordon3d3b4052014-05-05 12:05:36 -0700326 private final CallIdMapper mCallIdMapper = new CallIdMapper("CallService");
Santos Cordon3d3b4052014-05-05 12:05:36 -0700327 private final IncomingCallsManager mIncomingCallsManager;
Santos Cordon682fe6b2014-05-20 08:56:39 -0700328 private final Map<String, AsyncResultCallback<Boolean>> mPendingOutgoingCalls = new HashMap<>();
Santos Cordonc195e362014-02-11 17:05:31 -0800329
Ben Gilad61925612014-03-11 19:06:36 -0700330 private Binder mBinder = new Binder();
Santos Cordon3d3b4052014-05-05 12:05:36 -0700331 private ICallService mServiceInterface;
Ben Gilad61925612014-03-11 19:06:36 -0700332
Santos Cordon63aeb162014-02-10 09:20:40 -0800333 /**
Sailesh Nepale59bb192014-04-01 18:33:59 -0700334 * Creates a call-service for the specified descriptor.
Santos Cordonc195e362014-02-11 17:05:31 -0800335 *
Santos Cordon61d0f702014-02-19 02:52:23 -0800336 * @param descriptor The call-service descriptor from
Santos Cordon3d3b4052014-05-05 12:05:36 -0700337 * {@link ICallServiceProvider#lookupCallServices}.
Sailesh Nepale59bb192014-04-01 18:33:59 -0700338 * @param incomingCallsManager Manages the incoming call initialization flow.
Santos Cordon63aeb162014-02-10 09:20:40 -0800339 */
Sailesh Nepale59bb192014-04-01 18:33:59 -0700340 CallServiceWrapper(
341 CallServiceDescriptor descriptor,
Sailesh Nepale59bb192014-04-01 18:33:59 -0700342 IncomingCallsManager incomingCallsManager) {
Sailesh Nepala439e1b2014-03-11 18:19:58 -0700343 super(TelecommConstants.ACTION_CALL_SERVICE, descriptor.getServiceComponent());
Ben Giladc5b22692014-02-18 20:03:22 -0800344 mDescriptor = descriptor;
Santos Cordon3d3b4052014-05-05 12:05:36 -0700345 mIncomingCallsManager = incomingCallsManager;
Santos Cordon63aeb162014-02-10 09:20:40 -0800346 }
347
Ben Gilad61925612014-03-11 19:06:36 -0700348 CallServiceDescriptor getDescriptor() {
Ben Giladc5b22692014-02-18 20:03:22 -0800349 return mDescriptor;
Santos Cordonc195e362014-02-11 17:05:31 -0800350 }
351
Santos Cordon63aeb162014-02-10 09:20:40 -0800352 /** See {@link ICallService#setCallServiceAdapter}. */
Sailesh Nepale59bb192014-04-01 18:33:59 -0700353 private void setCallServiceAdapter(ICallServiceAdapter callServiceAdapter) {
Santos Cordon61d0f702014-02-19 02:52:23 -0800354 if (isServiceValid("setCallServiceAdapter")) {
355 try {
Santos Cordon63aeb162014-02-10 09:20:40 -0800356 mServiceInterface.setCallServiceAdapter(callServiceAdapter);
Santos Cordon61d0f702014-02-19 02:52:23 -0800357 } catch (RemoteException e) {
Santos Cordon63aeb162014-02-10 09:20:40 -0800358 }
Santos Cordon63aeb162014-02-10 09:20:40 -0800359 }
360 }
361
Ben Gilad61925612014-03-11 19:06:36 -0700362 /**
Santos Cordon682fe6b2014-05-20 08:56:39 -0700363 * Attempts to place the specified call, see {@link ICallService#call}. Returns the result
364 * asynchronously through the specified callback.
Ben Gilad61925612014-03-11 19:06:36 -0700365 */
Santos Cordon682fe6b2014-05-20 08:56:39 -0700366 void call(final Call call, final AsyncResultCallback<Boolean> resultCallback) {
367 Log.d(this, "call(%s) via %s.", call, getComponentName());
Ben Gilad61925612014-03-11 19:06:36 -0700368 BindCallback callback = new BindCallback() {
Santos Cordon3d3b4052014-05-05 12:05:36 -0700369 @Override
370 public void onSuccess() {
Santos Cordon682fe6b2014-05-20 08:56:39 -0700371 String callId = mCallIdMapper.getCallId(call);
372 mPendingOutgoingCalls.put(callId, resultCallback);
373
374 try {
375 CallInfo callInfo = call.toCallInfo(callId);
376 mServiceInterface.call(callInfo);
377 } catch (RemoteException e) {
Ihab Awada3cb9e32014-06-03 18:45:05 -0700378 mPendingOutgoingCalls.remove(callId).onResult(
379 false, DisconnectCause.ERROR_UNSPECIFIED, e.toString());
Ben Gilad61925612014-03-11 19:06:36 -0700380 }
Santos Cordon63aeb162014-02-10 09:20:40 -0800381 }
Santos Cordon3d3b4052014-05-05 12:05:36 -0700382
383 @Override
384 public void onFailure() {
Ihab Awada3cb9e32014-06-03 18:45:05 -0700385 resultCallback.onResult(false, DisconnectCause.ERROR_UNSPECIFIED, null);
Ben Gilad61925612014-03-11 19:06:36 -0700386 }
387 };
388
389 mBinder.bind(callback);
Santos Cordon63aeb162014-02-10 09:20:40 -0800390 }
391
Ihab Awad74549ec2014-03-10 15:33:25 -0700392 /** @see CallService#abort(String) */
Sailesh Nepale59bb192014-04-01 18:33:59 -0700393 void abort(Call call) {
Santos Cordon682fe6b2014-05-20 08:56:39 -0700394 // Clear out any pending outgoing call data
395 String callId = mCallIdMapper.getCallId(call);
396
397 // If still bound, tell the call service to abort.
Ben Gilad28e8ad62014-03-06 17:01:54 -0800398 if (isServiceValid("abort")) {
399 try {
Santos Cordon682fe6b2014-05-20 08:56:39 -0700400 mServiceInterface.abort(callId);
Ben Gilad28e8ad62014-03-06 17:01:54 -0800401 } catch (RemoteException e) {
Santos Cordon63aeb162014-02-10 09:20:40 -0800402 }
Santos Cordon61d0f702014-02-19 02:52:23 -0800403 }
Santos Cordon682fe6b2014-05-20 08:56:39 -0700404
405 removeCall(call);
Santos Cordon61d0f702014-02-19 02:52:23 -0800406 }
407
Ihab Awad74549ec2014-03-10 15:33:25 -0700408 /** @see CallService#hold(String) */
Sailesh Nepale59bb192014-04-01 18:33:59 -0700409 void hold(Call call) {
Yorke Leecdf3ebd2014-03-12 18:31:41 -0700410 if (isServiceValid("hold")) {
411 try {
Sailesh Nepale59bb192014-04-01 18:33:59 -0700412 mServiceInterface.hold(mCallIdMapper.getCallId(call));
Yorke Leecdf3ebd2014-03-12 18:31:41 -0700413 } catch (RemoteException e) {
Yorke Leecdf3ebd2014-03-12 18:31:41 -0700414 }
415 }
416 }
417
Ihab Awad74549ec2014-03-10 15:33:25 -0700418 /** @see CallService#unhold(String) */
Sailesh Nepale59bb192014-04-01 18:33:59 -0700419 void unhold(Call call) {
Yorke Leecdf3ebd2014-03-12 18:31:41 -0700420 if (isServiceValid("unhold")) {
421 try {
Sailesh Nepale59bb192014-04-01 18:33:59 -0700422 mServiceInterface.unhold(mCallIdMapper.getCallId(call));
Yorke Leecdf3ebd2014-03-12 18:31:41 -0700423 } catch (RemoteException e) {
Yorke Leecdf3ebd2014-03-12 18:31:41 -0700424 }
425 }
426 }
427
Ihab Awad74549ec2014-03-10 15:33:25 -0700428 /** @see CallService#onAudioStateChanged(String,CallAudioState) */
Sailesh Nepale59bb192014-04-01 18:33:59 -0700429 void onAudioStateChanged(Call activeCall, CallAudioState audioState) {
Sailesh Nepal6aca10a2014-03-24 16:11:02 -0700430 if (isServiceValid("onAudioStateChanged")) {
431 try {
Sailesh Nepale59bb192014-04-01 18:33:59 -0700432 mServiceInterface.onAudioStateChanged(mCallIdMapper.getCallId(activeCall),
433 audioState);
Sailesh Nepal6aca10a2014-03-24 16:11:02 -0700434 } catch (RemoteException e) {
Sailesh Nepal6aca10a2014-03-24 16:11:02 -0700435 }
436 }
437 }
438
Ben Gilad61925612014-03-11 19:06:36 -0700439 /**
440 * Starts retrieval of details for an incoming call. Details are returned through the
441 * call-service adapter using the specified call ID. Upon failure, the specified error callback
Santos Cordon3d3b4052014-05-05 12:05:36 -0700442 * is invoked. Can be invoked even when the call service is unbound. See
443 * {@link ICallService#setIncomingCallId}.
Ben Gilad61925612014-03-11 19:06:36 -0700444 *
Sailesh Nepale59bb192014-04-01 18:33:59 -0700445 * @param call The call used for the incoming call.
Ben Gilad61925612014-03-11 19:06:36 -0700446 * @param extras The {@link CallService}-provided extras which need to be sent back.
447 * @param errorCallback The callback to invoke upon failure.
448 */
Sailesh Nepale59bb192014-04-01 18:33:59 -0700449 void setIncomingCallId(final Call call, final Bundle extras, final Runnable errorCallback) {
450 Log.d(this, "setIncomingCall(%s) via %s.", call, getComponentName());
Ben Gilad61925612014-03-11 19:06:36 -0700451 BindCallback callback = new BindCallback() {
Santos Cordon3d3b4052014-05-05 12:05:36 -0700452 @Override
453 public void onSuccess() {
Ben Gilad61925612014-03-11 19:06:36 -0700454 if (isServiceValid("setIncomingCallId")) {
Santos Cordon682fe6b2014-05-20 08:56:39 -0700455 mPendingIncomingCalls.add(call);
Ben Gilad61925612014-03-11 19:06:36 -0700456 try {
Sailesh Nepale59bb192014-04-01 18:33:59 -0700457 mServiceInterface.setIncomingCallId(mCallIdMapper.getCallId(call),
458 extras);
Ben Gilad61925612014-03-11 19:06:36 -0700459 } catch (RemoteException e) {
Ben Gilad61925612014-03-11 19:06:36 -0700460 }
461 }
Santos Cordon61d0f702014-02-19 02:52:23 -0800462 }
Santos Cordon3d3b4052014-05-05 12:05:36 -0700463
464 @Override
465 public void onFailure() {
Ben Gilad61925612014-03-11 19:06:36 -0700466 errorCallback.run();
467 }
468 };
469
470 mBinder.bind(callback);
Santos Cordon63aeb162014-02-10 09:20:40 -0800471 }
472
Ihab Awad74549ec2014-03-10 15:33:25 -0700473 /** @see CallService#disconnect(String) */
Sailesh Nepale59bb192014-04-01 18:33:59 -0700474 void disconnect(Call call) {
Santos Cordon61d0f702014-02-19 02:52:23 -0800475 if (isServiceValid("disconnect")) {
476 try {
Sailesh Nepale59bb192014-04-01 18:33:59 -0700477 mServiceInterface.disconnect(mCallIdMapper.getCallId(call));
Santos Cordon61d0f702014-02-19 02:52:23 -0800478 } catch (RemoteException e) {
Santos Cordon63aeb162014-02-10 09:20:40 -0800479 }
Santos Cordon63aeb162014-02-10 09:20:40 -0800480 }
481 }
Santos Cordon5c12c6e2014-02-13 14:35:31 -0800482
Ihab Awad74549ec2014-03-10 15:33:25 -0700483 /** @see CallService#answer(String) */
Sailesh Nepale59bb192014-04-01 18:33:59 -0700484 void answer(Call call) {
Santos Cordon61d0f702014-02-19 02:52:23 -0800485 if (isServiceValid("answer")) {
486 try {
Sailesh Nepale59bb192014-04-01 18:33:59 -0700487 mServiceInterface.answer(mCallIdMapper.getCallId(call));
Santos Cordon61d0f702014-02-19 02:52:23 -0800488 } catch (RemoteException e) {
Santos Cordon7917d382014-02-14 02:31:18 -0800489 }
Santos Cordon61d0f702014-02-19 02:52:23 -0800490 }
491 }
492
Ihab Awad74549ec2014-03-10 15:33:25 -0700493 /** @see CallService#reject(String) */
Sailesh Nepale59bb192014-04-01 18:33:59 -0700494 void reject(Call call) {
Santos Cordon61d0f702014-02-19 02:52:23 -0800495 if (isServiceValid("reject")) {
496 try {
Sailesh Nepale59bb192014-04-01 18:33:59 -0700497 mServiceInterface.reject(mCallIdMapper.getCallId(call));
Santos Cordon61d0f702014-02-19 02:52:23 -0800498 } catch (RemoteException e) {
Ihab Awad74549ec2014-03-10 15:33:25 -0700499 }
500 }
501 }
502
503 /** @see CallService#playDtmfTone(String,char) */
Sailesh Nepale59bb192014-04-01 18:33:59 -0700504 void playDtmfTone(Call call, char digit) {
Ihab Awad74549ec2014-03-10 15:33:25 -0700505 if (isServiceValid("playDtmfTone")) {
506 try {
Sailesh Nepale59bb192014-04-01 18:33:59 -0700507 mServiceInterface.playDtmfTone(mCallIdMapper.getCallId(call), digit);
Ihab Awad74549ec2014-03-10 15:33:25 -0700508 } catch (RemoteException e) {
Ihab Awad74549ec2014-03-10 15:33:25 -0700509 }
510 }
511 }
512
513 /** @see CallService#stopDtmfTone(String) */
Sailesh Nepale59bb192014-04-01 18:33:59 -0700514 void stopDtmfTone(Call call) {
Ihab Awad74549ec2014-03-10 15:33:25 -0700515 if (isServiceValid("stopDtmfTone")) {
516 try {
Sailesh Nepale59bb192014-04-01 18:33:59 -0700517 mServiceInterface.stopDtmfTone(mCallIdMapper.getCallId(call));
Ihab Awad74549ec2014-03-10 15:33:25 -0700518 } catch (RemoteException e) {
Santos Cordon61d0f702014-02-19 02:52:23 -0800519 }
Santos Cordon7917d382014-02-14 02:31:18 -0800520 }
521 }
522
Sailesh Nepale59bb192014-04-01 18:33:59 -0700523 void addCall(Call call) {
524 mCallIdMapper.addCall(call);
Santos Cordon7917d382014-02-14 02:31:18 -0800525 }
526
Sailesh Nepal0e5410a2014-04-04 01:20:58 -0700527 /**
528 * Associates newCall with this call service by replacing callToReplace.
529 */
530 void replaceCall(Call newCall, Call callToReplace) {
531 Preconditions.checkState(callToReplace.getCallService() == this);
532 mCallIdMapper.replaceCall(newCall, callToReplace);
533 }
534
Sailesh Nepale59bb192014-04-01 18:33:59 -0700535 void removeCall(Call call) {
Santos Cordon682fe6b2014-05-20 08:56:39 -0700536 mPendingIncomingCalls.remove(call);
537
538 AsyncResultCallback<Boolean> outgoingResultCallback =
539 mPendingOutgoingCalls.remove(mCallIdMapper.getCallId(call));
540 if (outgoingResultCallback != null) {
Ihab Awada3cb9e32014-06-03 18:45:05 -0700541 outgoingResultCallback.onResult(false, DisconnectCause.ERROR_UNSPECIFIED, null);
Santos Cordon682fe6b2014-05-20 08:56:39 -0700542 }
543
Sailesh Nepale59bb192014-04-01 18:33:59 -0700544 mCallIdMapper.removeCall(call);
Yorke Leeadee12d2014-03-13 12:08:30 -0700545 }
546
Evan Charlton352105c2014-06-03 14:10:54 -0700547 void onPostDialContinue(Call call, boolean proceed) {
548 if (isServiceValid("onPostDialContinue")) {
549 try {
550 mServiceInterface.onPostDialContinue(mCallIdMapper.getCallId(call), proceed);
551 } catch (RemoteException ignored) {
552 }
553 }
554 }
555
Santos Cordon5c12c6e2014-02-13 14:35:31 -0800556 /** {@inheritDoc} */
Santos Cordon3d3b4052014-05-05 12:05:36 -0700557 @Override
558 protected void setServiceInterface(IBinder binder) {
Santos Cordon4b2c1192014-03-19 18:15:38 -0700559 if (binder == null) {
560 // We have lost our service connection. Notify the world that this call service is done.
561 // We must notify the adapter before CallsManager. The adapter will force any pending
562 // outgoing calls to try the next call service. This needs to happen before CallsManager
563 // tries to clean up any calls still associated with this call service.
Santos Cordon3d3b4052014-05-05 12:05:36 -0700564 handleCallServiceDeath();
Santos Cordon4b2c1192014-03-19 18:15:38 -0700565 CallsManager.getInstance().handleCallServiceDeath(this);
566 mServiceInterface = null;
567 } else {
568 mServiceInterface = ICallService.Stub.asInterface(binder);
569 setCallServiceAdapter(mAdapter);
570 }
Santos Cordon5c12c6e2014-02-13 14:35:31 -0800571 }
Santos Cordon3d3b4052014-05-05 12:05:36 -0700572
573 /**
574 * Called when the associated call service dies.
575 */
576 private void handleCallServiceDeath() {
Santos Cordon682fe6b2014-05-20 08:56:39 -0700577 if (!mPendingOutgoingCalls.isEmpty()) {
578 for (AsyncResultCallback<Boolean> callback : mPendingOutgoingCalls.values()) {
Ihab Awada3cb9e32014-06-03 18:45:05 -0700579 callback.onResult(false, DisconnectCause.ERROR_UNSPECIFIED, null);
Santos Cordon682fe6b2014-05-20 08:56:39 -0700580 }
581 mPendingOutgoingCalls.clear();
582 }
583
584 if (!mPendingIncomingCalls.isEmpty()) {
Santos Cordon3d3b4052014-05-05 12:05:36 -0700585 // Iterate through a copy because the code inside the loop will modify the original
586 // list.
Santos Cordon682fe6b2014-05-20 08:56:39 -0700587 for (Call call : ImmutableList.copyOf(mPendingIncomingCalls)) {
588 Preconditions.checkState(call.isIncoming());
589 mIncomingCallsManager.handleFailedIncomingCall(call);
Santos Cordon3d3b4052014-05-05 12:05:36 -0700590 }
591
Santos Cordon8f3282c2014-06-01 13:56:02 -0700592 if (!mPendingIncomingCalls.isEmpty()) {
593 Log.wtf(this, "Pending calls did not get cleared.");
594 mPendingIncomingCalls.clear();
595 }
Santos Cordon3d3b4052014-05-05 12:05:36 -0700596 }
Santos Cordon8f3282c2014-06-01 13:56:02 -0700597
598 mCallIdMapper.clear();
599 }
Santos Cordon63aeb162014-02-10 09:20:40 -0800600}