blob: 4040e33884e8b1a8490be5e55a405551cfe26d07 [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
Santos Cordon682fe6b2014-05-20 08:56:39 -070039import java.util.HashMap;
40import java.util.Map;
Santos Cordon3d3b4052014-05-05 12:05:36 -070041import java.util.Set;
Santos Cordon63aeb162014-02-10 09:20:40 -080042
43/**
44 * Wrapper for {@link ICallService}s, handles binding to {@link ICallService} and keeps track of
45 * when the object can safely be unbound. Other classes should not use {@link ICallService} directly
46 * and instead should use this class to invoke methods of {@link ICallService}.
Santos Cordon63aeb162014-02-10 09:20:40 -080047 */
Ben Gilad61925612014-03-11 19:06:36 -070048final class CallServiceWrapper extends ServiceBinder<ICallService> {
Santos Cordon63aeb162014-02-10 09:20:40 -080049
Santos Cordon3d3b4052014-05-05 12:05:36 -070050 private final class Adapter extends ICallServiceAdapter.Stub {
Santos Cordon3d3b4052014-05-05 12:05:36 -070051 private static final int MSG_NOTIFY_INCOMING_CALL = 1;
52 private static final int MSG_HANDLE_SUCCESSFUL_OUTGOING_CALL = 2;
53 private static final int MSG_HANDLE_FAILED_OUTGOING_CALL = 3;
54 private static final int MSG_SET_ACTIVE = 4;
55 private static final int MSG_SET_RINGING = 5;
56 private static final int MSG_SET_DIALING = 6;
57 private static final int MSG_SET_DISCONNECTED = 7;
58 private static final int MSG_SET_ON_HOLD = 8;
59
60 private final Handler mHandler = new Handler() {
61 @Override
62 public void handleMessage(Message msg) {
63 Call call;
64 switch (msg.what) {
Santos Cordon3d3b4052014-05-05 12:05:36 -070065 case MSG_NOTIFY_INCOMING_CALL:
66 CallInfo clientCallInfo = (CallInfo) msg.obj;
67 call = mCallIdMapper.getCall(clientCallInfo.getId());
Santos Cordon682fe6b2014-05-20 08:56:39 -070068 if (call != null && mPendingIncomingCalls.remove(call) &&
69 call.isIncoming()) {
Santos Cordon3d3b4052014-05-05 12:05:36 -070070 CallInfo callInfo = new CallInfo(null, clientCallInfo.getState(),
71 clientCallInfo.getHandle());
72 mIncomingCallsManager.handleSuccessfulIncomingCall(call, callInfo);
73 } else {
74 Log.w(this, "notifyIncomingCall, unknown incoming call: %s, id: %s",
75 call,
76 clientCallInfo.getId());
77 }
78 break;
Santos Cordon682fe6b2014-05-20 08:56:39 -070079 case MSG_HANDLE_SUCCESSFUL_OUTGOING_CALL: {
80 String callId = (String) msg.obj;
81 if (mPendingOutgoingCalls.containsKey(callId)) {
82 mPendingOutgoingCalls.remove(callId).onResult(true);
Santos Cordon3d3b4052014-05-05 12:05:36 -070083 } else {
Santos Cordon682fe6b2014-05-20 08:56:39 -070084 Log.w(this, "handleSuccessfulOutgoingCall, unknown call: %s", callId);
Santos Cordon3d3b4052014-05-05 12:05:36 -070085 }
86 break;
Santos Cordon682fe6b2014-05-20 08:56:39 -070087 }
Santos Cordon3d3b4052014-05-05 12:05:36 -070088 case MSG_HANDLE_FAILED_OUTGOING_CALL: {
89 SomeArgs args = (SomeArgs) msg.obj;
90 try {
Santos Cordon682fe6b2014-05-20 08:56:39 -070091 String callId = (String) args.arg1;
Santos Cordon3d3b4052014-05-05 12:05:36 -070092 String reason = (String) args.arg2;
Santos Cordon682fe6b2014-05-20 08:56:39 -070093 // TODO(santoscordon): Do something with 'reason' or get rid of it.
94
95 if (mPendingOutgoingCalls.containsKey(callId)) {
96 mPendingOutgoingCalls.remove(callId).onResult(false);
97 mCallIdMapper.removeCall(callId);
Santos Cordon3d3b4052014-05-05 12:05:36 -070098 } else {
Santos Cordon682fe6b2014-05-20 08:56:39 -070099 Log.w(this, "handleFailedOutgoingCall, unknown call: %s", callId);
Santos Cordon3d3b4052014-05-05 12:05:36 -0700100 }
101 } finally {
102 args.recycle();
103 }
104 break;
105 }
106 case MSG_SET_ACTIVE:
107 call = mCallIdMapper.getCall(msg.obj);
108 if (call != null) {
109 mCallsManager.markCallAsActive(call);
110 } else {
111 Log.w(this, "setActive, unknown call id: %s", msg.obj);
112 }
113 break;
114 case MSG_SET_RINGING:
115 call = mCallIdMapper.getCall(msg.obj);
116 if (call != null) {
117 mCallsManager.markCallAsRinging(call);
118 } else {
119 Log.w(this, "setRinging, unknown call id: %s", msg.obj);
120 }
121 break;
122 case MSG_SET_DIALING:
123 call = mCallIdMapper.getCall(msg.obj);
124 if (call != null) {
125 mCallsManager.markCallAsDialing(call);
126 } else {
127 Log.w(this, "setDialing, unknown call id: %s", msg.obj);
128 }
129 break;
130 case MSG_SET_DISCONNECTED: {
131 SomeArgs args = (SomeArgs) msg.obj;
132 try {
133 call = mCallIdMapper.getCall(args.arg1);
134 String disconnectMessage = (String) args.arg2;
135 int disconnectCause = args.argi1;
136 if (call != null) {
137 mCallsManager.markCallAsDisconnected(call, disconnectCause,
138 disconnectMessage);
139 } else {
140 Log.w(this, "setDisconnected, unknown call id: %s", args.arg1);
141 }
142 } finally {
143 args.recycle();
144 }
145 break;
146 }
147 case MSG_SET_ON_HOLD:
148 call = mCallIdMapper.getCall(msg.obj);
149 if (call != null) {
150 mCallsManager.markCallAsOnHold(call);
151 } else {
152 Log.w(this, "setOnHold, unknown call id: %s", msg.obj);
153 }
154 break;
155 }
156 }
157 };
158
159 /** {@inheritDoc} */
160 @Override
161 public void setIsCompatibleWith(String callId, boolean isCompatible) {
Santos Cordon682fe6b2014-05-20 08:56:39 -0700162 Log.wtf(this, "Not expected.");
Santos Cordon3d3b4052014-05-05 12:05:36 -0700163 }
164
165 /** {@inheritDoc} */
166 @Override
167 public void notifyIncomingCall(CallInfo callInfo) {
168 mCallIdMapper.checkValidCallId(callInfo.getId());
169 mHandler.obtainMessage(MSG_NOTIFY_INCOMING_CALL, callInfo).sendToTarget();
170 }
171
172 /** {@inheritDoc} */
173 @Override
174 public void handleSuccessfulOutgoingCall(String callId) {
Santos Cordon682fe6b2014-05-20 08:56:39 -0700175 Log.d(this, "handleSuccessfulOutgoingCall %s", callId);
Santos Cordon3d3b4052014-05-05 12:05:36 -0700176 mCallIdMapper.checkValidCallId(callId);
177 mHandler.obtainMessage(MSG_HANDLE_SUCCESSFUL_OUTGOING_CALL, callId).sendToTarget();
178 }
179
180 /** {@inheritDoc} */
181 @Override
182 public void handleFailedOutgoingCall(String callId, String reason) {
183 mCallIdMapper.checkValidCallId(callId);
Santos Cordon682fe6b2014-05-20 08:56:39 -0700184 Log.d(this, "handleFailedOutgoingCall %d", callId);
Santos Cordon3d3b4052014-05-05 12:05:36 -0700185 SomeArgs args = SomeArgs.obtain();
186 args.arg1 = callId;
187 args.arg2 = reason;
188 mHandler.obtainMessage(MSG_HANDLE_FAILED_OUTGOING_CALL, args).sendToTarget();
189 }
190
191 /** {@inheritDoc} */
192 @Override
193 public void setActive(String callId) {
194 mCallIdMapper.checkValidCallId(callId);
195 mHandler.obtainMessage(MSG_SET_ACTIVE, callId).sendToTarget();
196 }
197
198 /** {@inheritDoc} */
199 @Override
200 public void setRinging(String callId) {
201 mCallIdMapper.checkValidCallId(callId);
202 mHandler.obtainMessage(MSG_SET_RINGING, callId).sendToTarget();
203 }
204
205 /** {@inheritDoc} */
206 @Override
207 public void setDialing(String callId) {
208 mCallIdMapper.checkValidCallId(callId);
209 mHandler.obtainMessage(MSG_SET_DIALING, callId).sendToTarget();
210 }
211
212 /** {@inheritDoc} */
213 @Override
214 public void setDisconnected(
215 String callId, int disconnectCause, String disconnectMessage) {
216 mCallIdMapper.checkValidCallId(callId);
217 SomeArgs args = SomeArgs.obtain();
218 args.arg1 = callId;
219 args.arg2 = disconnectMessage;
220 args.argi1 = disconnectCause;
221 mHandler.obtainMessage(MSG_SET_DISCONNECTED, args).sendToTarget();
222 }
223
224 /** {@inheritDoc} */
225 @Override
226 public void setOnHold(String callId) {
227 mCallIdMapper.checkValidCallId(callId);
228 mHandler.obtainMessage(MSG_SET_ON_HOLD, callId).sendToTarget();
229 }
230 }
231
232 private final Adapter mAdapter = new Adapter();
233 private final CallsManager mCallsManager = CallsManager.getInstance();
Santos Cordon682fe6b2014-05-20 08:56:39 -0700234 private final Set<Call> mPendingIncomingCalls = Sets.newHashSet();
Ben Giladc5b22692014-02-18 20:03:22 -0800235 private final CallServiceDescriptor mDescriptor;
Santos Cordon3d3b4052014-05-05 12:05:36 -0700236 private final CallIdMapper mCallIdMapper = new CallIdMapper("CallService");
Santos Cordon3d3b4052014-05-05 12:05:36 -0700237 private final IncomingCallsManager mIncomingCallsManager;
Santos Cordon682fe6b2014-05-20 08:56:39 -0700238 private final Map<String, AsyncResultCallback<Boolean>> mPendingOutgoingCalls = new HashMap<>();
Santos Cordonc195e362014-02-11 17:05:31 -0800239
Ben Gilad61925612014-03-11 19:06:36 -0700240 private Binder mBinder = new Binder();
Santos Cordon3d3b4052014-05-05 12:05:36 -0700241 private ICallService mServiceInterface;
Ben Gilad61925612014-03-11 19:06:36 -0700242
Santos Cordon63aeb162014-02-10 09:20:40 -0800243 /**
Sailesh Nepale59bb192014-04-01 18:33:59 -0700244 * Creates a call-service for the specified descriptor.
Santos Cordonc195e362014-02-11 17:05:31 -0800245 *
Santos Cordon61d0f702014-02-19 02:52:23 -0800246 * @param descriptor The call-service descriptor from
Santos Cordon3d3b4052014-05-05 12:05:36 -0700247 * {@link ICallServiceProvider#lookupCallServices}.
Sailesh Nepale59bb192014-04-01 18:33:59 -0700248 * @param incomingCallsManager Manages the incoming call initialization flow.
Santos Cordon63aeb162014-02-10 09:20:40 -0800249 */
Sailesh Nepale59bb192014-04-01 18:33:59 -0700250 CallServiceWrapper(
251 CallServiceDescriptor descriptor,
Sailesh Nepale59bb192014-04-01 18:33:59 -0700252 IncomingCallsManager incomingCallsManager) {
Sailesh Nepala439e1b2014-03-11 18:19:58 -0700253 super(TelecommConstants.ACTION_CALL_SERVICE, descriptor.getServiceComponent());
Ben Giladc5b22692014-02-18 20:03:22 -0800254 mDescriptor = descriptor;
Santos Cordon3d3b4052014-05-05 12:05:36 -0700255 mIncomingCallsManager = incomingCallsManager;
Santos Cordon63aeb162014-02-10 09:20:40 -0800256 }
257
Ben Gilad61925612014-03-11 19:06:36 -0700258 CallServiceDescriptor getDescriptor() {
Ben Giladc5b22692014-02-18 20:03:22 -0800259 return mDescriptor;
Santos Cordonc195e362014-02-11 17:05:31 -0800260 }
261
Santos Cordon63aeb162014-02-10 09:20:40 -0800262 /** See {@link ICallService#setCallServiceAdapter}. */
Sailesh Nepale59bb192014-04-01 18:33:59 -0700263 private void setCallServiceAdapter(ICallServiceAdapter callServiceAdapter) {
Santos Cordon61d0f702014-02-19 02:52:23 -0800264 if (isServiceValid("setCallServiceAdapter")) {
265 try {
Santos Cordon63aeb162014-02-10 09:20:40 -0800266 mServiceInterface.setCallServiceAdapter(callServiceAdapter);
Santos Cordon61d0f702014-02-19 02:52:23 -0800267 } catch (RemoteException e) {
Santos Cordon63aeb162014-02-10 09:20:40 -0800268 }
Santos Cordon63aeb162014-02-10 09:20:40 -0800269 }
270 }
271
Ben Gilad61925612014-03-11 19:06:36 -0700272 /**
Santos Cordon682fe6b2014-05-20 08:56:39 -0700273 * Attempts to place the specified call, see {@link ICallService#call}. Returns the result
274 * asynchronously through the specified callback.
Ben Gilad61925612014-03-11 19:06:36 -0700275 */
Santos Cordon682fe6b2014-05-20 08:56:39 -0700276 void call(final Call call, final AsyncResultCallback<Boolean> resultCallback) {
277 Log.d(this, "call(%s) via %s.", call, getComponentName());
Ben Gilad61925612014-03-11 19:06:36 -0700278 BindCallback callback = new BindCallback() {
Santos Cordon3d3b4052014-05-05 12:05:36 -0700279 @Override
280 public void onSuccess() {
Santos Cordon682fe6b2014-05-20 08:56:39 -0700281 String callId = mCallIdMapper.getCallId(call);
282 mPendingOutgoingCalls.put(callId, resultCallback);
283
284 try {
285 CallInfo callInfo = call.toCallInfo(callId);
286 mServiceInterface.call(callInfo);
287 } catch (RemoteException e) {
288 mPendingOutgoingCalls.remove(callId).onResult(false);
Ben Gilad61925612014-03-11 19:06:36 -0700289 }
Santos Cordon63aeb162014-02-10 09:20:40 -0800290 }
Santos Cordon3d3b4052014-05-05 12:05:36 -0700291
292 @Override
293 public void onFailure() {
Santos Cordon682fe6b2014-05-20 08:56:39 -0700294 resultCallback.onResult(false);
Ben Gilad61925612014-03-11 19:06:36 -0700295 }
296 };
297
298 mBinder.bind(callback);
Santos Cordon63aeb162014-02-10 09:20:40 -0800299 }
300
Ihab Awad74549ec2014-03-10 15:33:25 -0700301 /** @see CallService#abort(String) */
Sailesh Nepale59bb192014-04-01 18:33:59 -0700302 void abort(Call call) {
Santos Cordon682fe6b2014-05-20 08:56:39 -0700303 // Clear out any pending outgoing call data
304 String callId = mCallIdMapper.getCallId(call);
305
306 // If still bound, tell the call service to abort.
Ben Gilad28e8ad62014-03-06 17:01:54 -0800307 if (isServiceValid("abort")) {
308 try {
Santos Cordon682fe6b2014-05-20 08:56:39 -0700309 mServiceInterface.abort(callId);
Ben Gilad28e8ad62014-03-06 17:01:54 -0800310 } catch (RemoteException e) {
Santos Cordon63aeb162014-02-10 09:20:40 -0800311 }
Santos Cordon61d0f702014-02-19 02:52:23 -0800312 }
Santos Cordon682fe6b2014-05-20 08:56:39 -0700313
314 removeCall(call);
Santos Cordon61d0f702014-02-19 02:52:23 -0800315 }
316
Ihab Awad74549ec2014-03-10 15:33:25 -0700317 /** @see CallService#hold(String) */
Sailesh Nepale59bb192014-04-01 18:33:59 -0700318 void hold(Call call) {
Yorke Leecdf3ebd2014-03-12 18:31:41 -0700319 if (isServiceValid("hold")) {
320 try {
Sailesh Nepale59bb192014-04-01 18:33:59 -0700321 mServiceInterface.hold(mCallIdMapper.getCallId(call));
Yorke Leecdf3ebd2014-03-12 18:31:41 -0700322 } catch (RemoteException e) {
Yorke Leecdf3ebd2014-03-12 18:31:41 -0700323 }
324 }
325 }
326
Ihab Awad74549ec2014-03-10 15:33:25 -0700327 /** @see CallService#unhold(String) */
Sailesh Nepale59bb192014-04-01 18:33:59 -0700328 void unhold(Call call) {
Yorke Leecdf3ebd2014-03-12 18:31:41 -0700329 if (isServiceValid("unhold")) {
330 try {
Sailesh Nepale59bb192014-04-01 18:33:59 -0700331 mServiceInterface.unhold(mCallIdMapper.getCallId(call));
Yorke Leecdf3ebd2014-03-12 18:31:41 -0700332 } catch (RemoteException e) {
Yorke Leecdf3ebd2014-03-12 18:31:41 -0700333 }
334 }
335 }
336
Ihab Awad74549ec2014-03-10 15:33:25 -0700337 /** @see CallService#onAudioStateChanged(String,CallAudioState) */
Sailesh Nepale59bb192014-04-01 18:33:59 -0700338 void onAudioStateChanged(Call activeCall, CallAudioState audioState) {
Sailesh Nepal6aca10a2014-03-24 16:11:02 -0700339 if (isServiceValid("onAudioStateChanged")) {
340 try {
Sailesh Nepale59bb192014-04-01 18:33:59 -0700341 mServiceInterface.onAudioStateChanged(mCallIdMapper.getCallId(activeCall),
342 audioState);
Sailesh Nepal6aca10a2014-03-24 16:11:02 -0700343 } catch (RemoteException e) {
Sailesh Nepal6aca10a2014-03-24 16:11:02 -0700344 }
345 }
346 }
347
Ben Gilad61925612014-03-11 19:06:36 -0700348 /**
349 * Starts retrieval of details for an incoming call. Details are returned through the
350 * call-service adapter using the specified call ID. Upon failure, the specified error callback
Santos Cordon3d3b4052014-05-05 12:05:36 -0700351 * is invoked. Can be invoked even when the call service is unbound. See
352 * {@link ICallService#setIncomingCallId}.
Ben Gilad61925612014-03-11 19:06:36 -0700353 *
Sailesh Nepale59bb192014-04-01 18:33:59 -0700354 * @param call The call used for the incoming call.
Ben Gilad61925612014-03-11 19:06:36 -0700355 * @param extras The {@link CallService}-provided extras which need to be sent back.
356 * @param errorCallback The callback to invoke upon failure.
357 */
Sailesh Nepale59bb192014-04-01 18:33:59 -0700358 void setIncomingCallId(final Call call, final Bundle extras, final Runnable errorCallback) {
359 Log.d(this, "setIncomingCall(%s) via %s.", call, getComponentName());
Ben Gilad61925612014-03-11 19:06:36 -0700360 BindCallback callback = new BindCallback() {
Santos Cordon3d3b4052014-05-05 12:05:36 -0700361 @Override
362 public void onSuccess() {
Ben Gilad61925612014-03-11 19:06:36 -0700363 if (isServiceValid("setIncomingCallId")) {
Santos Cordon682fe6b2014-05-20 08:56:39 -0700364 mPendingIncomingCalls.add(call);
Ben Gilad61925612014-03-11 19:06:36 -0700365 try {
Sailesh Nepale59bb192014-04-01 18:33:59 -0700366 mServiceInterface.setIncomingCallId(mCallIdMapper.getCallId(call),
367 extras);
Ben Gilad61925612014-03-11 19:06:36 -0700368 } catch (RemoteException e) {
Ben Gilad61925612014-03-11 19:06:36 -0700369 }
370 }
Santos Cordon61d0f702014-02-19 02:52:23 -0800371 }
Santos Cordon3d3b4052014-05-05 12:05:36 -0700372
373 @Override
374 public void onFailure() {
Ben Gilad61925612014-03-11 19:06:36 -0700375 errorCallback.run();
376 }
377 };
378
379 mBinder.bind(callback);
Santos Cordon63aeb162014-02-10 09:20:40 -0800380 }
381
Ihab Awad74549ec2014-03-10 15:33:25 -0700382 /** @see CallService#disconnect(String) */
Sailesh Nepale59bb192014-04-01 18:33:59 -0700383 void disconnect(Call call) {
Santos Cordon61d0f702014-02-19 02:52:23 -0800384 if (isServiceValid("disconnect")) {
385 try {
Sailesh Nepale59bb192014-04-01 18:33:59 -0700386 mServiceInterface.disconnect(mCallIdMapper.getCallId(call));
Santos Cordon61d0f702014-02-19 02:52:23 -0800387 } catch (RemoteException e) {
Santos Cordon63aeb162014-02-10 09:20:40 -0800388 }
Santos Cordon63aeb162014-02-10 09:20:40 -0800389 }
390 }
Santos Cordon5c12c6e2014-02-13 14:35:31 -0800391
Ihab Awad74549ec2014-03-10 15:33:25 -0700392 /** @see CallService#answer(String) */
Sailesh Nepale59bb192014-04-01 18:33:59 -0700393 void answer(Call call) {
Santos Cordon61d0f702014-02-19 02:52:23 -0800394 if (isServiceValid("answer")) {
395 try {
Sailesh Nepale59bb192014-04-01 18:33:59 -0700396 mServiceInterface.answer(mCallIdMapper.getCallId(call));
Santos Cordon61d0f702014-02-19 02:52:23 -0800397 } catch (RemoteException e) {
Santos Cordon7917d382014-02-14 02:31:18 -0800398 }
Santos Cordon61d0f702014-02-19 02:52:23 -0800399 }
400 }
401
Ihab Awad74549ec2014-03-10 15:33:25 -0700402 /** @see CallService#reject(String) */
Sailesh Nepale59bb192014-04-01 18:33:59 -0700403 void reject(Call call) {
Santos Cordon61d0f702014-02-19 02:52:23 -0800404 if (isServiceValid("reject")) {
405 try {
Sailesh Nepale59bb192014-04-01 18:33:59 -0700406 mServiceInterface.reject(mCallIdMapper.getCallId(call));
Santos Cordon61d0f702014-02-19 02:52:23 -0800407 } catch (RemoteException e) {
Ihab Awad74549ec2014-03-10 15:33:25 -0700408 }
409 }
410 }
411
412 /** @see CallService#playDtmfTone(String,char) */
Sailesh Nepale59bb192014-04-01 18:33:59 -0700413 void playDtmfTone(Call call, char digit) {
Ihab Awad74549ec2014-03-10 15:33:25 -0700414 if (isServiceValid("playDtmfTone")) {
415 try {
Sailesh Nepale59bb192014-04-01 18:33:59 -0700416 mServiceInterface.playDtmfTone(mCallIdMapper.getCallId(call), digit);
Ihab Awad74549ec2014-03-10 15:33:25 -0700417 } catch (RemoteException e) {
Ihab Awad74549ec2014-03-10 15:33:25 -0700418 }
419 }
420 }
421
422 /** @see CallService#stopDtmfTone(String) */
Sailesh Nepale59bb192014-04-01 18:33:59 -0700423 void stopDtmfTone(Call call) {
Ihab Awad74549ec2014-03-10 15:33:25 -0700424 if (isServiceValid("stopDtmfTone")) {
425 try {
Sailesh Nepale59bb192014-04-01 18:33:59 -0700426 mServiceInterface.stopDtmfTone(mCallIdMapper.getCallId(call));
Ihab Awad74549ec2014-03-10 15:33:25 -0700427 } catch (RemoteException e) {
Santos Cordon61d0f702014-02-19 02:52:23 -0800428 }
Santos Cordon7917d382014-02-14 02:31:18 -0800429 }
430 }
431
Sailesh Nepale59bb192014-04-01 18:33:59 -0700432 void addCall(Call call) {
433 mCallIdMapper.addCall(call);
Santos Cordon7917d382014-02-14 02:31:18 -0800434 }
435
Sailesh Nepal0e5410a2014-04-04 01:20:58 -0700436 /**
437 * Associates newCall with this call service by replacing callToReplace.
438 */
439 void replaceCall(Call newCall, Call callToReplace) {
440 Preconditions.checkState(callToReplace.getCallService() == this);
441 mCallIdMapper.replaceCall(newCall, callToReplace);
442 }
443
Sailesh Nepale59bb192014-04-01 18:33:59 -0700444 void removeCall(Call call) {
Santos Cordon682fe6b2014-05-20 08:56:39 -0700445 mPendingIncomingCalls.remove(call);
446
447 AsyncResultCallback<Boolean> outgoingResultCallback =
448 mPendingOutgoingCalls.remove(mCallIdMapper.getCallId(call));
449 if (outgoingResultCallback != null) {
450 outgoingResultCallback.onResult(false);
451 }
452
Sailesh Nepale59bb192014-04-01 18:33:59 -0700453 mCallIdMapper.removeCall(call);
Yorke Leeadee12d2014-03-13 12:08:30 -0700454 }
455
Santos Cordon5c12c6e2014-02-13 14:35:31 -0800456 /** {@inheritDoc} */
Santos Cordon3d3b4052014-05-05 12:05:36 -0700457 @Override
458 protected void setServiceInterface(IBinder binder) {
Santos Cordon4b2c1192014-03-19 18:15:38 -0700459 if (binder == null) {
460 // We have lost our service connection. Notify the world that this call service is done.
461 // We must notify the adapter before CallsManager. The adapter will force any pending
462 // outgoing calls to try the next call service. This needs to happen before CallsManager
463 // tries to clean up any calls still associated with this call service.
Santos Cordon3d3b4052014-05-05 12:05:36 -0700464 handleCallServiceDeath();
Santos Cordon4b2c1192014-03-19 18:15:38 -0700465 CallsManager.getInstance().handleCallServiceDeath(this);
466 mServiceInterface = null;
467 } else {
468 mServiceInterface = ICallService.Stub.asInterface(binder);
469 setCallServiceAdapter(mAdapter);
470 }
Santos Cordon5c12c6e2014-02-13 14:35:31 -0800471 }
Santos Cordon3d3b4052014-05-05 12:05:36 -0700472
473 /**
474 * Called when the associated call service dies.
475 */
476 private void handleCallServiceDeath() {
Santos Cordon682fe6b2014-05-20 08:56:39 -0700477 if (!mPendingOutgoingCalls.isEmpty()) {
478 for (AsyncResultCallback<Boolean> callback : mPendingOutgoingCalls.values()) {
479 callback.onResult(false);
480 }
481 mPendingOutgoingCalls.clear();
482 }
483
484 if (!mPendingIncomingCalls.isEmpty()) {
Santos Cordon3d3b4052014-05-05 12:05:36 -0700485 // Iterate through a copy because the code inside the loop will modify the original
486 // list.
Santos Cordon682fe6b2014-05-20 08:56:39 -0700487 for (Call call : ImmutableList.copyOf(mPendingIncomingCalls)) {
488 Preconditions.checkState(call.isIncoming());
489 mIncomingCallsManager.handleFailedIncomingCall(call);
Santos Cordon3d3b4052014-05-05 12:05:36 -0700490 }
491
Santos Cordon682fe6b2014-05-20 08:56:39 -0700492 if (!mPendingIncomingCalls.isEmpty()) {
Santos Cordon3d3b4052014-05-05 12:05:36 -0700493 Log.wtf(this, "Pending calls did not get cleared.");
Santos Cordon682fe6b2014-05-20 08:56:39 -0700494 mPendingIncomingCalls.clear();
Santos Cordon3d3b4052014-05-05 12:05:36 -0700495 }
496 }
Santos Cordon682fe6b2014-05-20 08:56:39 -0700497
498 mCallIdMapper.clear();
Santos Cordon3d3b4052014-05-05 12:05:36 -0700499 }
Santos Cordon63aeb162014-02-10 09:20:40 -0800500}