blob: 870d61c461d35a847278d4786ce0421400803f1c [file] [log] [blame]
Sailesh Nepalc92c4362014-07-04 18:33:21 -07001/*
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
19import android.content.ComponentName;
Sailesh Nepale8ecb982014-07-11 17:19:42 -070020import android.net.Uri;
Sailesh Nepalc92c4362014-07-04 18:33:21 -070021import android.os.Bundle;
22import android.os.Handler;
23import android.os.IBinder;
24import android.os.Message;
25import android.os.RemoteException;
26import android.telecomm.CallAudioState;
27import android.telecomm.ConnectionService;
Sailesh Nepalc92c4362014-07-04 18:33:21 -070028import android.telecomm.ConnectionRequest;
29import android.telecomm.GatewayInfo;
Sailesh Nepal35faf8c2014-07-08 22:02:34 -070030import android.telecomm.StatusHints;
Sailesh Nepalc92c4362014-07-04 18:33:21 -070031import android.telecomm.TelecommConstants;
32import android.telephony.DisconnectCause;
33
34import com.android.internal.os.SomeArgs;
Sailesh Nepalc92c4362014-07-04 18:33:21 -070035import com.android.internal.telecomm.IConnectionService;
36import com.android.internal.telecomm.IConnectionServiceAdapter;
Sailesh Nepalc92c4362014-07-04 18:33:21 -070037import com.android.internal.telecomm.ICallVideoProvider;
38import com.android.internal.telecomm.RemoteServiceCallback;
Sailesh Nepalc92c4362014-07-04 18:33:21 -070039import com.google.common.base.Preconditions;
40import com.google.common.collect.ImmutableList;
41
42import org.apache.http.conn.ClientConnectionRequest;
43
44import java.util.ArrayList;
45import java.util.Collection;
46import java.util.HashMap;
47import java.util.HashSet;
48import java.util.List;
49import java.util.Map;
50import java.util.Set;
51
52/**
53 * Wrapper for {@link IConnectionService}s, handles binding to {@link IConnectionService} and keeps
54 * track of when the object can safely be unbound. Other classes should not use
55 * {@link IConnectionService} directly and instead should use this class to invoke methods of
56 * {@link IConnectionService}.
57 */
58final class ConnectionServiceWrapper extends ServiceBinder<IConnectionService> {
Sailesh Nepal664837f2014-07-14 16:31:51 -070059 private static final int MSG_HANDLE_CREATE_CONNECTION_SUCCESSFUL = 1;
60 private static final int MSG_HANDLE_CREATE_CONNECTION_FAILED = 2;
61 private static final int MSG_HANDLE_CREATE_CONNECTION_CANCELLED = 3;
62 private static final int MSG_SET_ACTIVE = 4;
63 private static final int MSG_SET_RINGING = 5;
64 private static final int MSG_SET_DIALING = 6;
65 private static final int MSG_SET_DISCONNECTED = 7;
66 private static final int MSG_SET_ON_HOLD = 8;
67 private static final int MSG_SET_REQUESTING_RINGBACK = 9;
68 private static final int MSG_SET_CALL_CAPABILITIES = 10;
69 private static final int MSG_SET_IS_CONFERENCED = 11;
70 private static final int MSG_ADD_CONFERENCE_CALL = 12;
71 private static final int MSG_REMOVE_CALL = 13;
72 private static final int MSG_ON_POST_DIAL_WAIT = 14;
73 private static final int MSG_QUERY_REMOTE_CALL_SERVICES = 15;
74 private static final int MSG_SET_CALL_VIDEO_PROVIDER = 16;
75 private static final int MSG_SET_AUDIO_MODE_IS_VOIP = 17;
76 private static final int MSG_SET_STATUS_HINTS = 18;
77 private static final int MSG_SET_HANDLE = 19;
78 private static final int MSG_SET_CALLER_DISPLAY_NAME = 20;
Sailesh Nepalc92c4362014-07-04 18:33:21 -070079
80 private final Handler mHandler = new Handler() {
81 @Override
82 public void handleMessage(Message msg) {
83 Call call;
84 switch (msg.what) {
Sailesh Nepal664837f2014-07-14 16:31:51 -070085 case MSG_HANDLE_CREATE_CONNECTION_SUCCESSFUL: {
Sailesh Nepalc92c4362014-07-04 18:33:21 -070086 ConnectionRequest request = (ConnectionRequest) msg.obj;
Sailesh Nepal664837f2014-07-14 16:31:51 -070087 if (mPendingResponses.containsKey(request.getCallId())) {
88 mPendingResponses.remove(
89 request.getCallId()).handleCreateConnectionSuccessful(request);
Sailesh Nepalc92c4362014-07-04 18:33:21 -070090 } else {
Sailesh Nepal664837f2014-07-14 16:31:51 -070091 //Log.w(this, "handleCreateConnectionSuccessful, unknown call: %s", callId);
Sailesh Nepalc92c4362014-07-04 18:33:21 -070092 }
93 break;
94 }
Sailesh Nepal664837f2014-07-14 16:31:51 -070095 case MSG_HANDLE_CREATE_CONNECTION_FAILED: {
Sailesh Nepalc92c4362014-07-04 18:33:21 -070096 SomeArgs args = (SomeArgs) msg.obj;
97 try {
Sailesh Nepala49c6432014-07-07 22:47:11 -070098 ConnectionRequest request = (ConnectionRequest) args.arg1;
Sailesh Nepalc92c4362014-07-04 18:33:21 -070099 int statusCode = args.argi1;
100 String statusMsg = (String) args.arg2;
Sailesh Nepal664837f2014-07-14 16:31:51 -0700101 if (mPendingResponses.containsKey(request.getCallId())) {
102 mPendingResponses.remove(request.getCallId())
103 .handleCreateConnectionFailed(statusCode, statusMsg);
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700104 mCallIdMapper.removeCall(request.getCallId());
105 } else {
Sailesh Nepal664837f2014-07-14 16:31:51 -0700106 //Log.w(this, "handleCreateConnectionFailed, unknown call: %s", callId);
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700107 }
108 } finally {
109 args.recycle();
110 }
111 break;
112 }
Sailesh Nepal664837f2014-07-14 16:31:51 -0700113 case MSG_HANDLE_CREATE_CONNECTION_CANCELLED: {
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700114 ConnectionRequest request = (ConnectionRequest) msg.obj;
Sailesh Nepal664837f2014-07-14 16:31:51 -0700115 if (mPendingResponses.containsKey(request.getCallId())) {
116 mPendingResponses.remove(
117 request.getCallId()).handleCreateConnectionCancelled();
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700118 } else {
Sailesh Nepal664837f2014-07-14 16:31:51 -0700119 //Log.w(this, "handleCreateConnectionCancelled, unknown call: %s", callId);
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700120 }
121 break;
122 }
123 case MSG_SET_ACTIVE:
124 call = mCallIdMapper.getCall(msg.obj);
125 if (call != null) {
126 mCallsManager.markCallAsActive(call);
127 } else {
128 //Log.w(this, "setActive, unknown call id: %s", msg.obj);
129 }
130 break;
131 case MSG_SET_RINGING:
132 call = mCallIdMapper.getCall(msg.obj);
133 if (call != null) {
134 mCallsManager.markCallAsRinging(call);
135 } else {
136 //Log.w(this, "setRinging, unknown call id: %s", msg.obj);
137 }
138 break;
139 case MSG_SET_DIALING:
140 call = mCallIdMapper.getCall(msg.obj);
141 if (call != null) {
142 mCallsManager.markCallAsDialing(call);
143 } else {
144 //Log.w(this, "setDialing, unknown call id: %s", msg.obj);
145 }
146 break;
147 case MSG_SET_DISCONNECTED: {
148 SomeArgs args = (SomeArgs) msg.obj;
149 try {
150 call = mCallIdMapper.getCall(args.arg1);
151 String disconnectMessage = (String) args.arg2;
152 int disconnectCause = args.argi1;
153 if (call != null) {
154 mCallsManager.markCallAsDisconnected(call, disconnectCause,
155 disconnectMessage);
156 } else {
157 //Log.w(this, "setDisconnected, unknown call id: %s", args.arg1);
158 }
159 } finally {
160 args.recycle();
161 }
162 break;
163 }
164 case MSG_SET_ON_HOLD:
165 call = mCallIdMapper.getCall(msg.obj);
166 if (call != null) {
167 mCallsManager.markCallAsOnHold(call);
168 } else {
169 //Log.w(this, "setOnHold, unknown call id: %s", msg.obj);
170 }
171 break;
172 case MSG_SET_REQUESTING_RINGBACK: {
173 SomeArgs args = (SomeArgs) msg.obj;
174 try {
175 call = mCallIdMapper.getCall(args.arg1);
176 boolean ringback = (boolean) args.arg2;
177 if (call != null) {
178 call.setRequestingRingback(ringback);
179 } else {
180 //Log.w(this, "setRingback, unknown call id: %s", args.arg1);
181 }
182 } finally {
183 args.recycle();
184 }
185 break;
186 }
Sailesh Nepale20bc972014-07-09 21:22:36 -0700187 case MSG_SET_CALL_CAPABILITIES: {
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700188 call = mCallIdMapper.getCall(msg.obj);
189 if (call != null) {
Sailesh Nepale20bc972014-07-09 21:22:36 -0700190 call.setCallCapabilities(msg.arg1);
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700191 } else {
192 //Log.w(ConnectionServiceWrapper.this,
Sailesh Nepale20bc972014-07-09 21:22:36 -0700193 // "setCallCapabilities, unknown call id: %s", msg.obj);
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700194 }
195 break;
196 }
197 case MSG_SET_IS_CONFERENCED: {
198 SomeArgs args = (SomeArgs) msg.obj;
199 try {
200 Call childCall = mCallIdMapper.getCall(args.arg1);
201 if (childCall != null) {
202 String conferenceCallId = (String) args.arg2;
203 if (conferenceCallId == null) {
204 childCall.setParentCall(null);
205 } else {
206 Call conferenceCall = mCallIdMapper.getCall(conferenceCallId);
207 if (conferenceCall != null &&
208 !mPendingConferenceCalls.contains(conferenceCall)) {
209 childCall.setParentCall(conferenceCall);
210 } else {
211 //Log.w(this, "setIsConferenced, unknown conference id %s",
212 // conferenceCallId);
213 }
214 }
215 } else {
216 //Log.w(this, "setIsConferenced, unknown call id: %s", args.arg1);
217 }
218 } finally {
219 args.recycle();
220 }
221 break;
222 }
223 case MSG_ADD_CONFERENCE_CALL: {
224 Call conferenceCall = mCallIdMapper.getCall(msg.obj);
225 if (mPendingConferenceCalls.remove(conferenceCall)) {
226 Log.v(this, "confirming conf call %s", conferenceCall);
227 conferenceCall.confirmConference();
228 } else {
229 //Log.w(this, "addConference, unknown call id: %s", callId);
230 }
231 break;
232 }
233 case MSG_REMOVE_CALL:
234 break;
235 case MSG_ON_POST_DIAL_WAIT: {
236 SomeArgs args = (SomeArgs) msg.obj;
237 try {
238 call = mCallIdMapper.getCall(args.arg1);
239 if (call != null) {
240 String remaining = (String) args.arg2;
241 call.onPostDialWait(remaining);
242 } else {
243 //Log.w(this, "onPostDialWait, unknown call id: %s", args.arg1);
244 }
245 } finally {
246 args.recycle();
247 }
248 break;
249 }
250 case MSG_QUERY_REMOTE_CALL_SERVICES: {
Sailesh Nepal664837f2014-07-14 16:31:51 -0700251 queryRemoteConnectionServices((RemoteServiceCallback) msg.obj);
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700252 break;
253 }
254 case MSG_SET_CALL_VIDEO_PROVIDER: {
255 SomeArgs args = (SomeArgs) msg.obj;
256 try {
257 call = mCallIdMapper.getCall(args.arg1);
258 ICallVideoProvider callVideoProvider = (ICallVideoProvider) args.arg2;
259 if (call != null) {
260 call.setCallVideoProvider(callVideoProvider);
261 }
262 } finally {
263 args.recycle();
264 }
265 break;
266 }
Sailesh Nepal7e669572014-07-08 21:29:12 -0700267 case MSG_SET_AUDIO_MODE_IS_VOIP: {
Sailesh Nepale20bc972014-07-09 21:22:36 -0700268 call = mCallIdMapper.getCall(msg.obj);
269 if (call != null) {
270 call.setAudioModeIsVoip(msg.arg1 == 1);
Sailesh Nepal7e669572014-07-08 21:29:12 -0700271 }
272 break;
273 }
Sailesh Nepal35faf8c2014-07-08 22:02:34 -0700274 case MSG_SET_STATUS_HINTS: {
275 SomeArgs args = (SomeArgs) msg.obj;
276 try {
277 call = mCallIdMapper.getCall(args.arg1);
278 StatusHints statusHints = (StatusHints) args.arg2;
279 if (call != null) {
280 call.setStatusHints(statusHints);
281 }
282 } finally {
283 args.recycle();
284 }
285 break;
286 }
Sailesh Nepale8ecb982014-07-11 17:19:42 -0700287 case MSG_SET_HANDLE: {
288 SomeArgs args = (SomeArgs) msg.obj;
289 try {
290 call = mCallIdMapper.getCall(args.arg1);
291 if (call != null) {
292 call.setHandle((Uri) args.arg2, args.argi1);
293 }
294 } finally {
295 args.recycle();
296 }
297 break;
298 }
299 case MSG_SET_CALLER_DISPLAY_NAME: {
300 SomeArgs args = (SomeArgs) msg.obj;
301 try {
302 call = mCallIdMapper.getCall(args.arg1);
303 if (call != null) {
304 call.setCallerDisplayName((String) args.arg2, args.argi1);
305 }
306 } finally {
307 args.recycle();
308 }
309 break;
310 }
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700311 }
312 }
313 };
314
315 private final class Adapter extends IConnectionServiceAdapter.Stub {
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700316 @Override
Sailesh Nepal664837f2014-07-14 16:31:51 -0700317 public void handleCreateConnectionSuccessful(ConnectionRequest request) {
318 logIncoming("handleCreateConnectionSuccessful %s", request);
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700319 mCallIdMapper.checkValidCallId(request.getCallId());
Sailesh Nepal664837f2014-07-14 16:31:51 -0700320 mHandler.obtainMessage(MSG_HANDLE_CREATE_CONNECTION_SUCCESSFUL, request).sendToTarget();
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700321 }
322
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700323 @Override
Sailesh Nepal664837f2014-07-14 16:31:51 -0700324 public void handleCreateConnectionFailed(
325 ConnectionRequest request, int errorCode, String errorMsg) {
326 logIncoming("handleCreateConnectionFailed %s %d %s", request, errorCode, errorMsg);
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700327 mCallIdMapper.checkValidCallId(request.getCallId());
328 SomeArgs args = SomeArgs.obtain();
329 args.arg1 = request;
330 args.argi1 = errorCode;
331 args.arg2 = errorMsg;
Sailesh Nepal664837f2014-07-14 16:31:51 -0700332 mHandler.obtainMessage(MSG_HANDLE_CREATE_CONNECTION_FAILED, args).sendToTarget();
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700333 }
334
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700335 @Override
Sailesh Nepal664837f2014-07-14 16:31:51 -0700336 public void handleCreateConnectionCancelled(ConnectionRequest request) {
337 logIncoming("handleCreateConnectionCancelled %s", request);
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700338 mCallIdMapper.checkValidCallId(request.getCallId());
Sailesh Nepal664837f2014-07-14 16:31:51 -0700339 mHandler.obtainMessage(MSG_HANDLE_CREATE_CONNECTION_CANCELLED, request).sendToTarget();
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700340 }
341
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700342 @Override
343 public void setActive(String callId) {
344 logIncoming("setActive %s", callId);
345 mCallIdMapper.checkValidCallId(callId);
346 mHandler.obtainMessage(MSG_SET_ACTIVE, callId).sendToTarget();
347 }
348
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700349 @Override
350 public void setRinging(String callId) {
351 logIncoming("setRinging %s", callId);
352 mCallIdMapper.checkValidCallId(callId);
353 mHandler.obtainMessage(MSG_SET_RINGING, callId).sendToTarget();
354 }
355
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700356 @Override
357 public void setCallVideoProvider(String callId, ICallVideoProvider callVideoProvider) {
358 logIncoming("setCallVideoProvider %s", callId);
359 mCallIdMapper.checkValidCallId(callId);
360 SomeArgs args = SomeArgs.obtain();
361 args.arg1 = callId;
362 args.arg2 = callVideoProvider;
363 mHandler.obtainMessage(MSG_SET_CALL_VIDEO_PROVIDER, args).sendToTarget();
364 }
365
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700366 @Override
367 public void setDialing(String callId) {
368 logIncoming("setDialing %s", callId);
369 mCallIdMapper.checkValidCallId(callId);
370 mHandler.obtainMessage(MSG_SET_DIALING, callId).sendToTarget();
371 }
372
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700373 @Override
374 public void setDisconnected(
375 String callId, int disconnectCause, String disconnectMessage) {
376 logIncoming("setDisconnected %s %d %s", callId, disconnectCause, disconnectMessage);
377 mCallIdMapper.checkValidCallId(callId);
378 SomeArgs args = SomeArgs.obtain();
379 args.arg1 = callId;
380 args.arg2 = disconnectMessage;
381 args.argi1 = disconnectCause;
382 mHandler.obtainMessage(MSG_SET_DISCONNECTED, args).sendToTarget();
383 }
384
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700385 @Override
386 public void setOnHold(String callId) {
387 logIncoming("setOnHold %s", callId);
388 mCallIdMapper.checkValidCallId(callId);
389 mHandler.obtainMessage(MSG_SET_ON_HOLD, callId).sendToTarget();
390 }
391
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700392 @Override
393 public void setRequestingRingback(String callId, boolean ringback) {
394 logIncoming("setRequestingRingback %s %b", callId, ringback);
395 mCallIdMapper.checkValidCallId(callId);
396 SomeArgs args = SomeArgs.obtain();
397 args.arg1 = callId;
398 args.arg2 = ringback;
399 mHandler.obtainMessage(MSG_SET_REQUESTING_RINGBACK, args).sendToTarget();
400 }
401
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700402 @Override
403 public void removeCall(String callId) {
404 logIncoming("removeCall %s", callId);
405 }
406
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700407 @Override
Sailesh Nepale20bc972014-07-09 21:22:36 -0700408 public void setCallCapabilities(String callId, int callCapabilities) {
409 logIncoming("setCallCapabilities %s %d", callId, callCapabilities);
410 mHandler.obtainMessage(MSG_SET_CALL_CAPABILITIES, callCapabilities, 0, callId)
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700411 .sendToTarget();
412 }
413
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700414 @Override
415 public void setIsConferenced(String callId, String conferenceCallId) {
416 logIncoming("setIsConferenced %s %s", callId, conferenceCallId);
417 SomeArgs args = SomeArgs.obtain();
418 args.arg1 = callId;
419 args.arg2 = conferenceCallId;
420 mHandler.obtainMessage(MSG_SET_IS_CONFERENCED, args).sendToTarget();
421 }
422
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700423 @Override
424 public void addConferenceCall(String callId) {
425 logIncoming("addConferenceCall %s", callId);
426 mCallIdMapper.checkValidCallId(callId);
427 mHandler.obtainMessage(MSG_ADD_CONFERENCE_CALL, callId).sendToTarget();
428 }
429
430 @Override
431 public void onPostDialWait(String callId, String remaining) throws RemoteException {
432 logIncoming("onPostDialWait %s %s", callId, remaining);
433 mCallIdMapper.checkValidCallId(callId);
434 SomeArgs args = SomeArgs.obtain();
435 args.arg1 = callId;
436 args.arg2 = remaining;
437 mHandler.obtainMessage(MSG_ON_POST_DIAL_WAIT, args).sendToTarget();
438 }
439
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700440 @Override
441 public void queryRemoteConnectionServices(RemoteServiceCallback callback) {
442 logIncoming("queryRemoteCSs");
443 mHandler.obtainMessage(MSG_QUERY_REMOTE_CALL_SERVICES, callback).sendToTarget();
444 }
445
446 @Override
Sailesh Nepal7e669572014-07-08 21:29:12 -0700447 public void setAudioModeIsVoip(String callId, boolean isVoip) {
Sailesh Nepal7fa33ca2014-07-10 15:28:21 -0700448 logIncoming("setAudioModeIsVoip %s %b", callId, isVoip);
Sailesh Nepal7e669572014-07-08 21:29:12 -0700449 mCallIdMapper.checkValidCallId(callId);
Sailesh Nepale20bc972014-07-09 21:22:36 -0700450 mHandler.obtainMessage(MSG_SET_AUDIO_MODE_IS_VOIP, isVoip ? 1 : 0, 0,
451 callId).sendToTarget();
Sailesh Nepal7e669572014-07-08 21:29:12 -0700452 }
Sailesh Nepal35faf8c2014-07-08 22:02:34 -0700453
454 @Override
455 public void setStatusHints(String callId, StatusHints statusHints) {
456 logIncoming("setStatusHints %s %s", callId, statusHints);
457 mCallIdMapper.checkValidCallId(callId);
458 SomeArgs args = SomeArgs.obtain();
459 args.arg1 = callId;
460 args.arg2 = statusHints;
461 mHandler.obtainMessage(MSG_SET_STATUS_HINTS, args).sendToTarget();
462 }
Sailesh Nepale8ecb982014-07-11 17:19:42 -0700463
464 @Override
465 public void setHandle(String callId, Uri handle, int presentation) {
466 logIncoming("setHandle %s %s %d", callId, handle, presentation);
467 mCallIdMapper.checkValidCallId(callId);
468 SomeArgs args = SomeArgs.obtain();
469 args.arg1 = callId;
470 args.arg2 = handle;
471 args.argi1 = presentation;
472 mHandler.obtainMessage(MSG_SET_HANDLE, args).sendToTarget();
473 }
474
475 @Override
476 public void setCallerDisplayName(
477 String callId, String callerDisplayName, int presentation) {
478 logIncoming("setCallerDisplayName %s %s %d", callId, callerDisplayName, presentation);
479 mCallIdMapper.checkValidCallId(callId);
480 SomeArgs args = SomeArgs.obtain();
481 args.arg1 = callId;
482 args.arg2 = callerDisplayName;
483 args.argi1 = presentation;
484 mHandler.obtainMessage(MSG_SET_CALLER_DISPLAY_NAME, args).sendToTarget();
485 }
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700486 }
487
488 private final Adapter mAdapter = new Adapter();
489 private final CallsManager mCallsManager = CallsManager.getInstance();
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700490 private final Set<Call> mPendingConferenceCalls = new HashSet<>();
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700491 private final CallIdMapper mCallIdMapper = new CallIdMapper("ConnectionService");
Sailesh Nepal664837f2014-07-14 16:31:51 -0700492 private final Map<String, CreateConnectionResponse> mPendingResponses = new HashMap<>();
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700493
494 private Binder mBinder = new Binder();
495 private IConnectionService mServiceInterface;
Sailesh Nepal905dfba2014-07-14 08:20:41 -0700496 private final ConnectionServiceRepository mConnectionServiceRepository;
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700497
498 /**
Sailesh Nepal905dfba2014-07-14 08:20:41 -0700499 * Creates a connection service.
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700500 *
Sailesh Nepal905dfba2014-07-14 08:20:41 -0700501 * @param componentName The component name of the service with which to bind.
Sailesh Nepal905dfba2014-07-14 08:20:41 -0700502 * @param connectionServiceRepository Connection service repository.
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700503 */
504 ConnectionServiceWrapper(
Sailesh Nepal664837f2014-07-14 16:31:51 -0700505 ComponentName componentName, ConnectionServiceRepository connectionServiceRepository) {
Sailesh Nepal905dfba2014-07-14 08:20:41 -0700506 super(TelecommConstants.ACTION_CONNECTION_SERVICE, componentName);
Sailesh Nepal905dfba2014-07-14 08:20:41 -0700507 mConnectionServiceRepository = connectionServiceRepository;
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700508 }
509
510 /** See {@link IConnectionService#addConnectionServiceAdapter}. */
511 private void addConnectionServiceAdapter(IConnectionServiceAdapter adapter) {
512 if (isServiceValid("addConnectionServiceAdapter")) {
513 try {
Sailesh Nepal3fe8b722014-07-08 10:07:26 -0700514 logOutgoing("addConnectionServiceAdapter %s", adapter);
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700515 mServiceInterface.addConnectionServiceAdapter(adapter);
516 } catch (RemoteException e) {
517 }
518 }
519 }
520
521 /**
Sailesh Nepal664837f2014-07-14 16:31:51 -0700522 * Creates a new connection for a new outgoing call or to attach to an existing incoming call.
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700523 */
Sailesh Nepal664837f2014-07-14 16:31:51 -0700524 void createConnection(final Call call, final CreateConnectionResponse response) {
525 Log.d(this, "createConnection(%s) via %s.", call, getComponentName());
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700526 BindCallback callback = new BindCallback() {
527 @Override
528 public void onSuccess() {
529 String callId = mCallIdMapper.getCallId(call);
Sailesh Nepal664837f2014-07-14 16:31:51 -0700530 mPendingResponses.put(callId, response);
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700531
532 GatewayInfo gatewayInfo = call.getGatewayInfo();
533 Bundle extras = call.getExtras();
534 if (gatewayInfo != null && gatewayInfo.getGatewayProviderPackageName() != null &&
535 gatewayInfo.getOriginalHandle() != null) {
536 extras = (Bundle) extras.clone();
537 extras.putString(
538 NewOutgoingCallIntentBroadcaster.EXTRA_GATEWAY_PROVIDER_PACKAGE,
539 gatewayInfo.getGatewayProviderPackageName());
540 extras.putParcelable(
541 NewOutgoingCallIntentBroadcaster.EXTRA_GATEWAY_ORIGINAL_URI,
542 gatewayInfo.getOriginalHandle());
543 }
Sailesh Nepale8ecb982014-07-11 17:19:42 -0700544 ConnectionRequest request = new ConnectionRequest(
545 call.getPhoneAccount(),
546 callId,
547 call.getHandle(),
548 call.getHandlePresentation(),
549 extras,
Tyler Gunnc4abd912014-07-08 14:22:10 -0700550 call.getVideoState());
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700551
552 try {
Sailesh Nepal664837f2014-07-14 16:31:51 -0700553 mServiceInterface.createConnection(request, call.isIncoming());
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700554 } catch (RemoteException e) {
Sailesh Nepal664837f2014-07-14 16:31:51 -0700555 Log.e(this, e, "Failure to createConnection -- %s", getComponentName());
556 mPendingResponses.remove(callId).handleCreateConnectionFailed(
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700557 DisconnectCause.ERROR_UNSPECIFIED, e.toString());
558 }
559 }
560
561 @Override
562 public void onFailure() {
Sailesh Nepal905dfba2014-07-14 08:20:41 -0700563 Log.e(this, new Exception(), "Failure to call %s", getComponentName());
Sailesh Nepal664837f2014-07-14 16:31:51 -0700564 response.handleCreateConnectionFailed(DisconnectCause.ERROR_UNSPECIFIED, null);
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700565 }
566 };
567
568 mBinder.bind(callback);
569 }
570
571 /** @see ConnectionService#abort(String) */
572 void abort(Call call) {
573 // Clear out any pending outgoing call data
574 String callId = mCallIdMapper.getCallId(call);
575
576 // If still bound, tell the connection service to abort.
577 if (isServiceValid("abort")) {
578 try {
579 logOutgoing("abort %s", callId);
580 mServiceInterface.abort(callId);
581 } catch (RemoteException e) {
582 }
583 }
584
585 removeCall(call);
586 }
587
588 /** @see ConnectionService#hold(String) */
589 void hold(Call call) {
590 if (isServiceValid("hold")) {
591 try {
592 logOutgoing("hold %s", mCallIdMapper.getCallId(call));
593 mServiceInterface.hold(mCallIdMapper.getCallId(call));
594 } catch (RemoteException e) {
595 }
596 }
597 }
598
599 /** @see ConnectionService#unhold(String) */
600 void unhold(Call call) {
601 if (isServiceValid("unhold")) {
602 try {
603 logOutgoing("unhold %s", mCallIdMapper.getCallId(call));
604 mServiceInterface.unhold(mCallIdMapper.getCallId(call));
605 } catch (RemoteException e) {
606 }
607 }
608 }
609
610 /** @see ConnectionService#onAudioStateChanged(String,CallAudioState) */
611 void onAudioStateChanged(Call activeCall, CallAudioState audioState) {
612 if (isServiceValid("onAudioStateChanged")) {
613 try {
614 logOutgoing("onAudioStateChanged %s %s",
615 mCallIdMapper.getCallId(activeCall), audioState);
616 mServiceInterface.onAudioStateChanged(mCallIdMapper.getCallId(activeCall),
617 audioState);
618 } catch (RemoteException e) {
619 }
620 }
621 }
622
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700623 /** @see ConnectionService#disconnect(String) */
624 void disconnect(Call call) {
625 if (isServiceValid("disconnect")) {
626 try {
627 logOutgoing("disconnect %s", mCallIdMapper.getCallId(call));
628 mServiceInterface.disconnect(mCallIdMapper.getCallId(call));
629 } catch (RemoteException e) {
630 }
631 }
632 }
633
634 /** @see ConnectionService#answer(String) */
635 void answer(Call call) {
636 if (isServiceValid("answer")) {
637 try {
638 logOutgoing("answer %s", mCallIdMapper.getCallId(call));
639 mServiceInterface.answer(mCallIdMapper.getCallId(call));
640 } catch (RemoteException e) {
641 }
642 }
643 }
644
645 /** @see ConnectionService#reject(String) */
646 void reject(Call call) {
647 if (isServiceValid("reject")) {
648 try {
649 logOutgoing("reject %s", mCallIdMapper.getCallId(call));
650 mServiceInterface.reject(mCallIdMapper.getCallId(call));
651 } catch (RemoteException e) {
652 }
653 }
654 }
655
656 /** @see ConnectionService#playDtmfTone(String,char) */
657 void playDtmfTone(Call call, char digit) {
658 if (isServiceValid("playDtmfTone")) {
659 try {
660 logOutgoing("playDtmfTone %s %c", mCallIdMapper.getCallId(call), digit);
661 mServiceInterface.playDtmfTone(mCallIdMapper.getCallId(call), digit);
662 } catch (RemoteException e) {
663 }
664 }
665 }
666
667 /** @see ConnectionService#stopDtmfTone(String) */
668 void stopDtmfTone(Call call) {
669 if (isServiceValid("stopDtmfTone")) {
670 try {
671 logOutgoing("stopDtmfTone %s", mCallIdMapper.getCallId(call));
672 mServiceInterface.stopDtmfTone(mCallIdMapper.getCallId(call));
673 } catch (RemoteException e) {
674 }
675 }
676 }
677
678 void addCall(Call call) {
679 if (mCallIdMapper.getCallId(call) == null) {
680 mCallIdMapper.addCall(call);
681 }
682 }
683
684 /**
685 * Associates newCall with this connection service by replacing callToReplace.
686 */
687 void replaceCall(Call newCall, Call callToReplace) {
688 Preconditions.checkState(callToReplace.getConnectionService() == this);
689 mCallIdMapper.replaceCall(newCall, callToReplace);
690 }
691
692 void removeCall(Call call) {
Sailesh Nepal664837f2014-07-14 16:31:51 -0700693 CreateConnectionResponse response = mPendingResponses.remove(mCallIdMapper.getCallId(call));
694 if (response != null) {
695 response.handleCreateConnectionFailed(DisconnectCause.ERROR_UNSPECIFIED, null);
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700696 }
697
698 mCallIdMapper.removeCall(call);
699 }
700
701 void onPostDialContinue(Call call, boolean proceed) {
702 if (isServiceValid("onPostDialContinue")) {
703 try {
704 logOutgoing("onPostDialContinue %s %b", mCallIdMapper.getCallId(call), proceed);
705 mServiceInterface.onPostDialContinue(mCallIdMapper.getCallId(call), proceed);
706 } catch (RemoteException ignored) {
707 }
708 }
709 }
710
711 void onPhoneAccountClicked(Call call) {
712 if (isServiceValid("onPhoneAccountClicked")) {
713 try {
714 logOutgoing("onPhoneAccountClicked %s", mCallIdMapper.getCallId(call));
715 mServiceInterface.onPhoneAccountClicked(mCallIdMapper.getCallId(call));
716 } catch (RemoteException ignored) {
717 }
718 }
719 }
720
721 void conference(final Call conferenceCall, Call call) {
722 if (isServiceValid("conference")) {
723 try {
724 conferenceCall.setConnectionService(this);
725 mPendingConferenceCalls.add(conferenceCall);
726 mHandler.postDelayed(new Runnable() {
727 @Override public void run() {
728 if (mPendingConferenceCalls.remove(conferenceCall)) {
729 conferenceCall.expireConference();
730 Log.i(this, "Conference call expired: %s", conferenceCall);
731 }
732 }
733 }, Timeouts.getConferenceCallExpireMillis());
734
735 logOutgoing("conference %s %s",
736 mCallIdMapper.getCallId(conferenceCall),
737 mCallIdMapper.getCallId(call));
738 mServiceInterface.conference(
739 mCallIdMapper.getCallId(conferenceCall),
740 mCallIdMapper.getCallId(call));
741 } catch (RemoteException ignored) {
742 }
743 }
744 }
745
746 void splitFromConference(Call call) {
747 if (isServiceValid("splitFromConference")) {
748 try {
749 logOutgoing("splitFromConference %s", mCallIdMapper.getCallId(call));
750 mServiceInterface.splitFromConference(mCallIdMapper.getCallId(call));
751 } catch (RemoteException ignored) {
752 }
753 }
754 }
755
Sailesh Nepale8ecb982014-07-11 17:19:42 -0700756 void swapWithBackgroundCall(Call call) {
757 if (isServiceValid("swapWithBackgroundCall")) {
758 try {
759 logOutgoing("swapWithBackgroundCall %s", mCallIdMapper.getCallId(call));
760 mServiceInterface.swapWithBackgroundCall(mCallIdMapper.getCallId(call));
761 } catch (RemoteException ignored) {
762 }
763 }
764 }
765
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700766 /** {@inheritDoc} */
767 @Override
768 protected void setServiceInterface(IBinder binder) {
769 if (binder == null) {
770 // We have lost our service connection. Notify the world that this service is done.
771 // We must notify the adapter before CallsManager. The adapter will force any pending
772 // outgoing calls to try the next service. This needs to happen before CallsManager
773 // tries to clean up any calls still associated with this service.
774 handleConnectionServiceDeath();
775 CallsManager.getInstance().handleConnectionServiceDeath(this);
776 mServiceInterface = null;
777 } else {
778 mServiceInterface = IConnectionService.Stub.asInterface(binder);
779 addConnectionServiceAdapter(mAdapter);
780 }
781 }
782
783 /**
784 * Called when the associated connection service dies.
785 */
786 private void handleConnectionServiceDeath() {
Sailesh Nepal664837f2014-07-14 16:31:51 -0700787 if (!mPendingResponses.isEmpty()) {
788 CreateConnectionResponse[] responses = mPendingResponses.values().toArray(
789 new CreateConnectionResponse[mPendingResponses.values().size()]);
790 mPendingResponses.clear();
791 for (int i = 0; i < responses.length; i++) {
792 responses[i].handleCreateConnectionFailed(DisconnectCause.ERROR_UNSPECIFIED, null);
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700793 }
794 }
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700795 mCallIdMapper.clear();
796 }
797
798 private void logIncoming(String msg, Object... params) {
799 Log.d(this, "ConnectionService -> Telecomm: " + msg, params);
800 }
801
802 private void logOutgoing(String msg, Object... params) {
803 Log.d(this, "Telecomm -> ConnectionService: " + msg, params);
804 }
805
806 private void queryRemoteConnectionServices(final RemoteServiceCallback callback) {
807 final List<IBinder> connectionServices = new ArrayList<>();
808 final List<ComponentName> components = new ArrayList<>();
Sailesh Nepal664837f2014-07-14 16:31:51 -0700809 final List<ConnectionServiceWrapper> servciesAttempted = new ArrayList<>();
Sailesh Nepal905dfba2014-07-14 08:20:41 -0700810 final Collection<ConnectionServiceWrapper> services =
811 mConnectionServiceRepository.lookupServices();
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700812
Sailesh Nepal664837f2014-07-14 16:31:51 -0700813 Log.v(this, "queryRemoteConnectionServices, services: " + services.size());
814
Sailesh Nepal905dfba2014-07-14 08:20:41 -0700815 for (ConnectionServiceWrapper cs : services) {
816 if (cs != this) {
817 final ConnectionServiceWrapper currentConnectionService = cs;
818 cs.mBinder.bind(new BindCallback() {
Sailesh Nepal905dfba2014-07-14 08:20:41 -0700819 @Override
820 public void onSuccess() {
821 Log.d(this, "Adding ***** %s", currentConnectionService.getComponentName());
822 connectionServices.add(
823 currentConnectionService.mServiceInterface.asBinder());
824 components.add(currentConnectionService.getComponentName());
825 maybeComplete();
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700826 }
Sailesh Nepal905dfba2014-07-14 08:20:41 -0700827
828 @Override
829 public void onFailure() {
Sailesh Nepal905dfba2014-07-14 08:20:41 -0700830 maybeComplete();
831 }
832
833 private void maybeComplete() {
Sailesh Nepal664837f2014-07-14 16:31:51 -0700834 servciesAttempted.add(currentConnectionService);
835 if (servciesAttempted.size() == services.size() - 1) {
Sailesh Nepal905dfba2014-07-14 08:20:41 -0700836 try {
837 callback.onResult(components, connectionServices);
838 } catch (RemoteException ignored) {
839 }
840 }
841 }
842 });
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700843 }
Sailesh Nepal905dfba2014-07-14 08:20:41 -0700844 }
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700845 }
846}