blob: a4e3d24c13717e56b21b45911fcb96bd27bdd0bc [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 -070020
21import 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;
Sailesh Nepal83cfe7c2014-03-11 19:54:22 -070029import android.telecomm.TelecommConstants;
Sailesh Nepala439e1b2014-03-11 18:19:58 -070030
Santos Cordon3d3b4052014-05-05 12:05:36 -070031import com.android.internal.os.SomeArgs;
Sailesh Nepala439e1b2014-03-11 18:19:58 -070032import com.android.internal.telecomm.ICallService;
33import com.android.internal.telecomm.ICallServiceAdapter;
34import com.android.internal.telecomm.ICallServiceProvider;
Sailesh Nepal0e5410a2014-04-04 01:20:58 -070035import com.google.common.base.Preconditions;
Santos Cordon3d3b4052014-05-05 12:05:36 -070036import com.google.common.collect.ImmutableList;
37import com.google.common.collect.Sets;
38
39import java.util.Set;
Santos Cordon63aeb162014-02-10 09:20:40 -080040
41/**
42 * Wrapper for {@link ICallService}s, handles binding to {@link ICallService} and keeps track of
43 * when the object can safely be unbound. Other classes should not use {@link ICallService} directly
44 * and instead should use this class to invoke methods of {@link ICallService}.
Santos Cordon63aeb162014-02-10 09:20:40 -080045 */
Ben Gilad61925612014-03-11 19:06:36 -070046final class CallServiceWrapper extends ServiceBinder<ICallService> {
Santos Cordon63aeb162014-02-10 09:20:40 -080047
Santos Cordon3d3b4052014-05-05 12:05:36 -070048 private final class Adapter extends ICallServiceAdapter.Stub {
49 private static final int MSG_SET_IS_COMPATIBLE_WITH = 0;
50 private static final int MSG_NOTIFY_INCOMING_CALL = 1;
51 private static final int MSG_HANDLE_SUCCESSFUL_OUTGOING_CALL = 2;
52 private static final int MSG_HANDLE_FAILED_OUTGOING_CALL = 3;
53 private static final int MSG_SET_ACTIVE = 4;
54 private static final int MSG_SET_RINGING = 5;
55 private static final int MSG_SET_DIALING = 6;
56 private static final int MSG_SET_DISCONNECTED = 7;
57 private static final int MSG_SET_ON_HOLD = 8;
58
59 private final Handler mHandler = new Handler() {
60 @Override
61 public void handleMessage(Message msg) {
62 Call call;
63 switch (msg.what) {
64 case MSG_SET_IS_COMPATIBLE_WITH:
65 call = mCallIdMapper.getCall(msg.obj);
66 if (call != null && !call.isIncoming()) {
67 mOutgoingCallsManager.setIsCompatibleWith(call,
68 msg.arg1 == 1 ? true : false);
69 } else {
70 Log.w(this, "setIsCompatibleWith, unknown call: %s, id: %s", call,
71 msg.obj);
72 }
73 break;
74 case MSG_NOTIFY_INCOMING_CALL:
75 CallInfo clientCallInfo = (CallInfo) msg.obj;
76 call = mCallIdMapper.getCall(clientCallInfo.getId());
77 if (call != null && mPendingCalls.remove(call) && call.isIncoming()) {
78 CallInfo callInfo = new CallInfo(null, clientCallInfo.getState(),
79 clientCallInfo.getHandle());
80 mIncomingCallsManager.handleSuccessfulIncomingCall(call, callInfo);
81 } else {
82 Log.w(this, "notifyIncomingCall, unknown incoming call: %s, id: %s",
83 call,
84 clientCallInfo.getId());
85 }
86 break;
87 case MSG_HANDLE_SUCCESSFUL_OUTGOING_CALL:
88 call = mCallIdMapper.getCall(msg.obj);
89 if (call != null && mPendingCalls.remove(call) && !call.isIncoming()) {
90 mOutgoingCallsManager.handleSuccessfulCallAttempt(call);
91 } else {
92 // TODO(gilad): Figure out how to wire up the callService.abort() call.
93 Log.w(this,
94 "handleSuccessfulOutgoingCall, unknown call: %s, id: %s",
95 call, msg.obj);
96 }
97 break;
98 case MSG_HANDLE_FAILED_OUTGOING_CALL: {
99 SomeArgs args = (SomeArgs) msg.obj;
100 try {
101 call = mCallIdMapper.getCall(args.arg1);
102 String reason = (String) args.arg2;
103 if (call != null && mPendingCalls.remove(call) && !call.isIncoming()) {
104 mOutgoingCallsManager.handleFailedCallAttempt(call, reason);
105 } else {
106 Log.w(this,
107 "handleFailedOutgoingCall, unknown call: %s, id: %s",
108 call, args.arg1);
109 }
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;
164 }
165 }
166 };
167
168 /** {@inheritDoc} */
169 @Override
170 public void setIsCompatibleWith(String callId, boolean isCompatible) {
171 Log.v(this, "setIsCompatibleWith id: %s, isCompatible: %b", callId, isCompatible);
172 mCallIdMapper.checkValidCallId(callId);
173 mHandler.obtainMessage(MSG_SET_IS_COMPATIBLE_WITH, isCompatible ? 1 : 0, 0, callId).
174 sendToTarget();
175 }
176
177 /** {@inheritDoc} */
178 @Override
179 public void notifyIncomingCall(CallInfo callInfo) {
180 mCallIdMapper.checkValidCallId(callInfo.getId());
181 mHandler.obtainMessage(MSG_NOTIFY_INCOMING_CALL, callInfo).sendToTarget();
182 }
183
184 /** {@inheritDoc} */
185 @Override
186 public void handleSuccessfulOutgoingCall(String callId) {
187 mCallIdMapper.checkValidCallId(callId);
188 mHandler.obtainMessage(MSG_HANDLE_SUCCESSFUL_OUTGOING_CALL, callId).sendToTarget();
189 }
190
191 /** {@inheritDoc} */
192 @Override
193 public void handleFailedOutgoingCall(String callId, String reason) {
194 mCallIdMapper.checkValidCallId(callId);
195 SomeArgs args = SomeArgs.obtain();
196 args.arg1 = callId;
197 args.arg2 = reason;
198 mHandler.obtainMessage(MSG_HANDLE_FAILED_OUTGOING_CALL, args).sendToTarget();
199 }
200
201 /** {@inheritDoc} */
202 @Override
203 public void setActive(String callId) {
204 mCallIdMapper.checkValidCallId(callId);
205 mHandler.obtainMessage(MSG_SET_ACTIVE, callId).sendToTarget();
206 }
207
208 /** {@inheritDoc} */
209 @Override
210 public void setRinging(String callId) {
211 mCallIdMapper.checkValidCallId(callId);
212 mHandler.obtainMessage(MSG_SET_RINGING, callId).sendToTarget();
213 }
214
215 /** {@inheritDoc} */
216 @Override
217 public void setDialing(String callId) {
218 mCallIdMapper.checkValidCallId(callId);
219 mHandler.obtainMessage(MSG_SET_DIALING, callId).sendToTarget();
220 }
221
222 /** {@inheritDoc} */
223 @Override
224 public void setDisconnected(
225 String callId, int disconnectCause, String disconnectMessage) {
226 mCallIdMapper.checkValidCallId(callId);
227 SomeArgs args = SomeArgs.obtain();
228 args.arg1 = callId;
229 args.arg2 = disconnectMessage;
230 args.argi1 = disconnectCause;
231 mHandler.obtainMessage(MSG_SET_DISCONNECTED, args).sendToTarget();
232 }
233
234 /** {@inheritDoc} */
235 @Override
236 public void setOnHold(String callId) {
237 mCallIdMapper.checkValidCallId(callId);
238 mHandler.obtainMessage(MSG_SET_ON_HOLD, callId).sendToTarget();
239 }
240 }
241
242 private final Adapter mAdapter = new Adapter();
243 private final CallsManager mCallsManager = CallsManager.getInstance();
244 private final Set<Call> mPendingCalls = Sets.newHashSet();
Ben Giladc5b22692014-02-18 20:03:22 -0800245 private final CallServiceDescriptor mDescriptor;
Santos Cordon3d3b4052014-05-05 12:05:36 -0700246 private final CallIdMapper mCallIdMapper = new CallIdMapper("CallService");
247 private final OutgoingCallsManager mOutgoingCallsManager;
248 private final IncomingCallsManager mIncomingCallsManager;
Santos Cordonc195e362014-02-11 17:05:31 -0800249
Ben Gilad61925612014-03-11 19:06:36 -0700250 private Binder mBinder = new Binder();
Santos Cordon3d3b4052014-05-05 12:05:36 -0700251 private ICallService mServiceInterface;
Ben Gilad61925612014-03-11 19:06:36 -0700252
Santos Cordon63aeb162014-02-10 09:20:40 -0800253 /**
Sailesh Nepale59bb192014-04-01 18:33:59 -0700254 * Creates a call-service for the specified descriptor.
Santos Cordonc195e362014-02-11 17:05:31 -0800255 *
Santos Cordon61d0f702014-02-19 02:52:23 -0800256 * @param descriptor The call-service descriptor from
Santos Cordon3d3b4052014-05-05 12:05:36 -0700257 * {@link ICallServiceProvider#lookupCallServices}.
Sailesh Nepale59bb192014-04-01 18:33:59 -0700258 * @param outgoingCallsManager Manages the placing of outgoing calls.
259 * @param incomingCallsManager Manages the incoming call initialization flow.
Santos Cordon63aeb162014-02-10 09:20:40 -0800260 */
Sailesh Nepale59bb192014-04-01 18:33:59 -0700261 CallServiceWrapper(
262 CallServiceDescriptor descriptor,
263 OutgoingCallsManager outgoingCallsManager,
264 IncomingCallsManager incomingCallsManager) {
Sailesh Nepala439e1b2014-03-11 18:19:58 -0700265 super(TelecommConstants.ACTION_CALL_SERVICE, descriptor.getServiceComponent());
Ben Giladc5b22692014-02-18 20:03:22 -0800266 mDescriptor = descriptor;
Santos Cordon3d3b4052014-05-05 12:05:36 -0700267 mIncomingCallsManager = incomingCallsManager;
268 mOutgoingCallsManager = outgoingCallsManager;
Santos Cordon63aeb162014-02-10 09:20:40 -0800269 }
270
Ben Gilad61925612014-03-11 19:06:36 -0700271 CallServiceDescriptor getDescriptor() {
Ben Giladc5b22692014-02-18 20:03:22 -0800272 return mDescriptor;
Santos Cordonc195e362014-02-11 17:05:31 -0800273 }
274
Santos Cordon63aeb162014-02-10 09:20:40 -0800275 /** See {@link ICallService#setCallServiceAdapter}. */
Sailesh Nepale59bb192014-04-01 18:33:59 -0700276 private void setCallServiceAdapter(ICallServiceAdapter callServiceAdapter) {
Santos Cordon61d0f702014-02-19 02:52:23 -0800277 if (isServiceValid("setCallServiceAdapter")) {
278 try {
Santos Cordon63aeb162014-02-10 09:20:40 -0800279 mServiceInterface.setCallServiceAdapter(callServiceAdapter);
Santos Cordon61d0f702014-02-19 02:52:23 -0800280 } catch (RemoteException e) {
Santos Cordon63aeb162014-02-10 09:20:40 -0800281 }
Santos Cordon63aeb162014-02-10 09:20:40 -0800282 }
283 }
284
Ben Gilad61925612014-03-11 19:06:36 -0700285 /**
286 * Checks whether or not the specified call is compatible with this call-service implementation,
Santos Cordon3d3b4052014-05-05 12:05:36 -0700287 * see {@link ICallService#isCompatibleWith}. Upon failure, the specified error callback is
Ben Gilad61925612014-03-11 19:06:36 -0700288 * invoked. Can be invoked even when the call service is unbound.
289 *
Ben Gilad61925612014-03-11 19:06:36 -0700290 * @param errorCallback The callback to invoke upon failure.
291 */
Sailesh Nepale59bb192014-04-01 18:33:59 -0700292 void isCompatibleWith(final Call call, final Runnable errorCallback) {
293 Log.d(this, "isCompatibleWith(%s) via %s.", call, getComponentName());
Ben Gilad61925612014-03-11 19:06:36 -0700294 BindCallback callback = new BindCallback() {
Santos Cordon3d3b4052014-05-05 12:05:36 -0700295 @Override
296 public void onSuccess() {
Ben Gilad61925612014-03-11 19:06:36 -0700297 if (isServiceValid("isCompatibleWith")) {
298 try {
Santos Cordon3d3b4052014-05-05 12:05:36 -0700299 mPendingCalls.add(call);
Sailesh Nepale59bb192014-04-01 18:33:59 -0700300 CallInfo callInfo = call.toCallInfo(mCallIdMapper.getCallId(call));
Ben Gilad61925612014-03-11 19:06:36 -0700301 mServiceInterface.isCompatibleWith(callInfo);
302 } catch (RemoteException e) {
Ben Gilad61925612014-03-11 19:06:36 -0700303 }
304 }
Santos Cordon63aeb162014-02-10 09:20:40 -0800305 }
Santos Cordon3d3b4052014-05-05 12:05:36 -0700306
307 @Override
308 public void onFailure() {
Ben Gilad61925612014-03-11 19:06:36 -0700309 errorCallback.run();
310 }
311 };
312
313 mBinder.bind(callback);
Santos Cordon63aeb162014-02-10 09:20:40 -0800314 }
315
Ben Gilad61925612014-03-11 19:06:36 -0700316 /**
Santos Cordon3d3b4052014-05-05 12:05:36 -0700317 * Attempts to place the specified call, see {@link ICallService#call}. Upon failure, the
Ben Gilad61925612014-03-11 19:06:36 -0700318 * specified error callback is invoked. Can be invoked even when the call service is unbound.
Ben Gilad61925612014-03-11 19:06:36 -0700319 */
Sailesh Nepale59bb192014-04-01 18:33:59 -0700320 void call(Call call) {
321 Log.d(this, "call(%s) via %s.", call, getComponentName());
322 if (isServiceValid("call")) {
323 try {
324 CallInfo callInfo = call.toCallInfo(mCallIdMapper.getCallId(call));
325 mServiceInterface.call(callInfo);
326 } catch (RemoteException e) {
Ben Gilad28e8ad62014-03-06 17:01:54 -0800327 }
Sailesh Nepale59bb192014-04-01 18:33:59 -0700328 }
Ben Gilad28e8ad62014-03-06 17:01:54 -0800329 }
330
Ihab Awad74549ec2014-03-10 15:33:25 -0700331 /** @see CallService#abort(String) */
Sailesh Nepale59bb192014-04-01 18:33:59 -0700332 void abort(Call call) {
Santos Cordon3d3b4052014-05-05 12:05:36 -0700333 mPendingCalls.remove(call);
Ben Gilad28e8ad62014-03-06 17:01:54 -0800334 if (isServiceValid("abort")) {
335 try {
Sailesh Nepale59bb192014-04-01 18:33:59 -0700336 mServiceInterface.abort(mCallIdMapper.getCallId(call));
Ben Gilad28e8ad62014-03-06 17:01:54 -0800337 } catch (RemoteException e) {
Santos Cordon63aeb162014-02-10 09:20:40 -0800338 }
Santos Cordon61d0f702014-02-19 02:52:23 -0800339 }
340 }
341
Ihab Awad74549ec2014-03-10 15:33:25 -0700342 /** @see CallService#hold(String) */
Sailesh Nepale59bb192014-04-01 18:33:59 -0700343 void hold(Call call) {
Yorke Leecdf3ebd2014-03-12 18:31:41 -0700344 if (isServiceValid("hold")) {
345 try {
Sailesh Nepale59bb192014-04-01 18:33:59 -0700346 mServiceInterface.hold(mCallIdMapper.getCallId(call));
Yorke Leecdf3ebd2014-03-12 18:31:41 -0700347 } catch (RemoteException e) {
Yorke Leecdf3ebd2014-03-12 18:31:41 -0700348 }
349 }
350 }
351
Ihab Awad74549ec2014-03-10 15:33:25 -0700352 /** @see CallService#unhold(String) */
Sailesh Nepale59bb192014-04-01 18:33:59 -0700353 void unhold(Call call) {
Yorke Leecdf3ebd2014-03-12 18:31:41 -0700354 if (isServiceValid("unhold")) {
355 try {
Sailesh Nepale59bb192014-04-01 18:33:59 -0700356 mServiceInterface.unhold(mCallIdMapper.getCallId(call));
Yorke Leecdf3ebd2014-03-12 18:31:41 -0700357 } catch (RemoteException e) {
Yorke Leecdf3ebd2014-03-12 18:31:41 -0700358 }
359 }
360 }
361
Ihab Awad74549ec2014-03-10 15:33:25 -0700362 /** @see CallService#onAudioStateChanged(String,CallAudioState) */
Sailesh Nepale59bb192014-04-01 18:33:59 -0700363 void onAudioStateChanged(Call activeCall, CallAudioState audioState) {
Sailesh Nepal6aca10a2014-03-24 16:11:02 -0700364 if (isServiceValid("onAudioStateChanged")) {
365 try {
Sailesh Nepale59bb192014-04-01 18:33:59 -0700366 mServiceInterface.onAudioStateChanged(mCallIdMapper.getCallId(activeCall),
367 audioState);
Sailesh Nepal6aca10a2014-03-24 16:11:02 -0700368 } catch (RemoteException e) {
Sailesh Nepal6aca10a2014-03-24 16:11:02 -0700369 }
370 }
371 }
372
Ben Gilad61925612014-03-11 19:06:36 -0700373 /**
374 * Starts retrieval of details for an incoming call. Details are returned through the
375 * call-service adapter using the specified call ID. Upon failure, the specified error callback
Santos Cordon3d3b4052014-05-05 12:05:36 -0700376 * is invoked. Can be invoked even when the call service is unbound. See
377 * {@link ICallService#setIncomingCallId}.
Ben Gilad61925612014-03-11 19:06:36 -0700378 *
Sailesh Nepale59bb192014-04-01 18:33:59 -0700379 * @param call The call used for the incoming call.
Ben Gilad61925612014-03-11 19:06:36 -0700380 * @param extras The {@link CallService}-provided extras which need to be sent back.
381 * @param errorCallback The callback to invoke upon failure.
382 */
Sailesh Nepale59bb192014-04-01 18:33:59 -0700383 void setIncomingCallId(final Call call, final Bundle extras, final Runnable errorCallback) {
384 Log.d(this, "setIncomingCall(%s) via %s.", call, getComponentName());
Ben Gilad61925612014-03-11 19:06:36 -0700385 BindCallback callback = new BindCallback() {
Santos Cordon3d3b4052014-05-05 12:05:36 -0700386 @Override
387 public void onSuccess() {
Ben Gilad61925612014-03-11 19:06:36 -0700388 if (isServiceValid("setIncomingCallId")) {
Santos Cordon3d3b4052014-05-05 12:05:36 -0700389 mPendingCalls.add(call);
Ben Gilad61925612014-03-11 19:06:36 -0700390 try {
Sailesh Nepale59bb192014-04-01 18:33:59 -0700391 mServiceInterface.setIncomingCallId(mCallIdMapper.getCallId(call),
392 extras);
Ben Gilad61925612014-03-11 19:06:36 -0700393 } catch (RemoteException e) {
Ben Gilad61925612014-03-11 19:06:36 -0700394 }
395 }
Santos Cordon61d0f702014-02-19 02:52:23 -0800396 }
Santos Cordon3d3b4052014-05-05 12:05:36 -0700397
398 @Override
399 public void onFailure() {
Ben Gilad61925612014-03-11 19:06:36 -0700400 errorCallback.run();
401 }
402 };
403
404 mBinder.bind(callback);
Santos Cordon63aeb162014-02-10 09:20:40 -0800405 }
406
Ihab Awad74549ec2014-03-10 15:33:25 -0700407 /** @see CallService#disconnect(String) */
Sailesh Nepale59bb192014-04-01 18:33:59 -0700408 void disconnect(Call call) {
Santos Cordon61d0f702014-02-19 02:52:23 -0800409 if (isServiceValid("disconnect")) {
410 try {
Sailesh Nepale59bb192014-04-01 18:33:59 -0700411 mServiceInterface.disconnect(mCallIdMapper.getCallId(call));
Santos Cordon61d0f702014-02-19 02:52:23 -0800412 } catch (RemoteException e) {
Santos Cordon63aeb162014-02-10 09:20:40 -0800413 }
Santos Cordon63aeb162014-02-10 09:20:40 -0800414 }
415 }
Santos Cordon5c12c6e2014-02-13 14:35:31 -0800416
Ihab Awad74549ec2014-03-10 15:33:25 -0700417 /** @see CallService#answer(String) */
Sailesh Nepale59bb192014-04-01 18:33:59 -0700418 void answer(Call call) {
Santos Cordon61d0f702014-02-19 02:52:23 -0800419 if (isServiceValid("answer")) {
420 try {
Sailesh Nepale59bb192014-04-01 18:33:59 -0700421 mServiceInterface.answer(mCallIdMapper.getCallId(call));
Santos Cordon61d0f702014-02-19 02:52:23 -0800422 } catch (RemoteException e) {
Santos Cordon7917d382014-02-14 02:31:18 -0800423 }
Santos Cordon61d0f702014-02-19 02:52:23 -0800424 }
425 }
426
Ihab Awad74549ec2014-03-10 15:33:25 -0700427 /** @see CallService#reject(String) */
Sailesh Nepale59bb192014-04-01 18:33:59 -0700428 void reject(Call call) {
Santos Cordon61d0f702014-02-19 02:52:23 -0800429 if (isServiceValid("reject")) {
430 try {
Sailesh Nepale59bb192014-04-01 18:33:59 -0700431 mServiceInterface.reject(mCallIdMapper.getCallId(call));
Santos Cordon61d0f702014-02-19 02:52:23 -0800432 } catch (RemoteException e) {
Ihab Awad74549ec2014-03-10 15:33:25 -0700433 }
434 }
435 }
436
437 /** @see CallService#playDtmfTone(String,char) */
Sailesh Nepale59bb192014-04-01 18:33:59 -0700438 void playDtmfTone(Call call, char digit) {
Ihab Awad74549ec2014-03-10 15:33:25 -0700439 if (isServiceValid("playDtmfTone")) {
440 try {
Sailesh Nepale59bb192014-04-01 18:33:59 -0700441 mServiceInterface.playDtmfTone(mCallIdMapper.getCallId(call), digit);
Ihab Awad74549ec2014-03-10 15:33:25 -0700442 } catch (RemoteException e) {
Ihab Awad74549ec2014-03-10 15:33:25 -0700443 }
444 }
445 }
446
447 /** @see CallService#stopDtmfTone(String) */
Sailesh Nepale59bb192014-04-01 18:33:59 -0700448 void stopDtmfTone(Call call) {
Ihab Awad74549ec2014-03-10 15:33:25 -0700449 if (isServiceValid("stopDtmfTone")) {
450 try {
Sailesh Nepale59bb192014-04-01 18:33:59 -0700451 mServiceInterface.stopDtmfTone(mCallIdMapper.getCallId(call));
Ihab Awad74549ec2014-03-10 15:33:25 -0700452 } catch (RemoteException e) {
Santos Cordon61d0f702014-02-19 02:52:23 -0800453 }
Santos Cordon7917d382014-02-14 02:31:18 -0800454 }
455 }
456
Sailesh Nepale59bb192014-04-01 18:33:59 -0700457 void addCall(Call call) {
458 mCallIdMapper.addCall(call);
Santos Cordon7917d382014-02-14 02:31:18 -0800459 }
460
Sailesh Nepal0e5410a2014-04-04 01:20:58 -0700461 /**
462 * Associates newCall with this call service by replacing callToReplace.
463 */
464 void replaceCall(Call newCall, Call callToReplace) {
465 Preconditions.checkState(callToReplace.getCallService() == this);
466 mCallIdMapper.replaceCall(newCall, callToReplace);
467 }
468
Sailesh Nepale59bb192014-04-01 18:33:59 -0700469 void removeCall(Call call) {
Santos Cordon3d3b4052014-05-05 12:05:36 -0700470 mPendingCalls.remove(call);
Sailesh Nepale59bb192014-04-01 18:33:59 -0700471 mCallIdMapper.removeCall(call);
Yorke Leeadee12d2014-03-13 12:08:30 -0700472 }
473
Santos Cordon5c12c6e2014-02-13 14:35:31 -0800474 /** {@inheritDoc} */
Santos Cordon3d3b4052014-05-05 12:05:36 -0700475 @Override
476 protected void setServiceInterface(IBinder binder) {
Santos Cordon4b2c1192014-03-19 18:15:38 -0700477 if (binder == null) {
478 // We have lost our service connection. Notify the world that this call service is done.
479 // We must notify the adapter before CallsManager. The adapter will force any pending
480 // outgoing calls to try the next call service. This needs to happen before CallsManager
481 // tries to clean up any calls still associated with this call service.
Santos Cordon3d3b4052014-05-05 12:05:36 -0700482 handleCallServiceDeath();
Santos Cordon4b2c1192014-03-19 18:15:38 -0700483 CallsManager.getInstance().handleCallServiceDeath(this);
484 mServiceInterface = null;
485 } else {
486 mServiceInterface = ICallService.Stub.asInterface(binder);
487 setCallServiceAdapter(mAdapter);
488 }
Santos Cordon5c12c6e2014-02-13 14:35:31 -0800489 }
Santos Cordon3d3b4052014-05-05 12:05:36 -0700490
491 /**
492 * Called when the associated call service dies.
493 */
494 private void handleCallServiceDeath() {
495 if (!mPendingCalls.isEmpty()) {
496 // Iterate through a copy because the code inside the loop will modify the original
497 // list.
498 for (Call call : ImmutableList.copyOf(mPendingCalls)) {
499 if (call.isIncoming()) {
500 mIncomingCallsManager.handleFailedIncomingCall(call);
501 } else {
502 mOutgoingCallsManager.handleFailedCallAttempt(call,
503 "Call service disconnected.");
504 }
505 }
506
507 if (!mPendingCalls.isEmpty()) {
508 Log.wtf(this, "Pending calls did not get cleared.");
509 mPendingCalls.clear();
510 }
511 }
512 }
Santos Cordon63aeb162014-02-10 09:20:40 -0800513}