blob: fb9d34cd379d3ada04e5581439fffb6e9e86f50d [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;
Tyler Gunn0a388fc2014-07-17 12:21:17 -070079 private static final int MSG_SET_VIDEO_STATE = 21;
Sailesh Nepalc92c4362014-07-04 18:33:21 -070080
81 private final Handler mHandler = new Handler() {
82 @Override
83 public void handleMessage(Message msg) {
84 Call call;
85 switch (msg.what) {
Sailesh Nepal664837f2014-07-14 16:31:51 -070086 case MSG_HANDLE_CREATE_CONNECTION_SUCCESSFUL: {
Sailesh Nepalc92c4362014-07-04 18:33:21 -070087 ConnectionRequest request = (ConnectionRequest) msg.obj;
Sailesh Nepal664837f2014-07-14 16:31:51 -070088 if (mPendingResponses.containsKey(request.getCallId())) {
89 mPendingResponses.remove(
90 request.getCallId()).handleCreateConnectionSuccessful(request);
Sailesh Nepalc92c4362014-07-04 18:33:21 -070091 } else {
Sailesh Nepal664837f2014-07-14 16:31:51 -070092 //Log.w(this, "handleCreateConnectionSuccessful, unknown call: %s", callId);
Sailesh Nepalc92c4362014-07-04 18:33:21 -070093 }
94 break;
95 }
Sailesh Nepal664837f2014-07-14 16:31:51 -070096 case MSG_HANDLE_CREATE_CONNECTION_FAILED: {
Sailesh Nepalc92c4362014-07-04 18:33:21 -070097 SomeArgs args = (SomeArgs) msg.obj;
98 try {
Sailesh Nepala49c6432014-07-07 22:47:11 -070099 ConnectionRequest request = (ConnectionRequest) args.arg1;
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700100 int statusCode = args.argi1;
101 String statusMsg = (String) args.arg2;
Sailesh Nepal664837f2014-07-14 16:31:51 -0700102 if (mPendingResponses.containsKey(request.getCallId())) {
103 mPendingResponses.remove(request.getCallId())
104 .handleCreateConnectionFailed(statusCode, statusMsg);
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700105 mCallIdMapper.removeCall(request.getCallId());
106 } else {
Sailesh Nepal664837f2014-07-14 16:31:51 -0700107 //Log.w(this, "handleCreateConnectionFailed, unknown call: %s", callId);
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700108 }
109 } finally {
110 args.recycle();
111 }
112 break;
113 }
Sailesh Nepal664837f2014-07-14 16:31:51 -0700114 case MSG_HANDLE_CREATE_CONNECTION_CANCELLED: {
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700115 ConnectionRequest request = (ConnectionRequest) msg.obj;
Sailesh Nepal664837f2014-07-14 16:31:51 -0700116 if (mPendingResponses.containsKey(request.getCallId())) {
117 mPendingResponses.remove(
118 request.getCallId()).handleCreateConnectionCancelled();
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700119 } else {
Sailesh Nepal664837f2014-07-14 16:31:51 -0700120 //Log.w(this, "handleCreateConnectionCancelled, unknown call: %s", callId);
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700121 }
122 break;
123 }
124 case MSG_SET_ACTIVE:
125 call = mCallIdMapper.getCall(msg.obj);
126 if (call != null) {
127 mCallsManager.markCallAsActive(call);
128 } else {
129 //Log.w(this, "setActive, unknown call id: %s", msg.obj);
130 }
131 break;
132 case MSG_SET_RINGING:
133 call = mCallIdMapper.getCall(msg.obj);
134 if (call != null) {
135 mCallsManager.markCallAsRinging(call);
136 } else {
137 //Log.w(this, "setRinging, unknown call id: %s", msg.obj);
138 }
139 break;
140 case MSG_SET_DIALING:
141 call = mCallIdMapper.getCall(msg.obj);
142 if (call != null) {
143 mCallsManager.markCallAsDialing(call);
144 } else {
145 //Log.w(this, "setDialing, unknown call id: %s", msg.obj);
146 }
147 break;
148 case MSG_SET_DISCONNECTED: {
149 SomeArgs args = (SomeArgs) msg.obj;
150 try {
151 call = mCallIdMapper.getCall(args.arg1);
152 String disconnectMessage = (String) args.arg2;
153 int disconnectCause = args.argi1;
154 if (call != null) {
155 mCallsManager.markCallAsDisconnected(call, disconnectCause,
156 disconnectMessage);
157 } else {
158 //Log.w(this, "setDisconnected, unknown call id: %s", args.arg1);
159 }
160 } finally {
161 args.recycle();
162 }
163 break;
164 }
165 case MSG_SET_ON_HOLD:
166 call = mCallIdMapper.getCall(msg.obj);
167 if (call != null) {
168 mCallsManager.markCallAsOnHold(call);
169 } else {
170 //Log.w(this, "setOnHold, unknown call id: %s", msg.obj);
171 }
172 break;
173 case MSG_SET_REQUESTING_RINGBACK: {
174 SomeArgs args = (SomeArgs) msg.obj;
175 try {
176 call = mCallIdMapper.getCall(args.arg1);
177 boolean ringback = (boolean) args.arg2;
178 if (call != null) {
179 call.setRequestingRingback(ringback);
180 } else {
181 //Log.w(this, "setRingback, unknown call id: %s", args.arg1);
182 }
183 } finally {
184 args.recycle();
185 }
186 break;
187 }
Sailesh Nepale20bc972014-07-09 21:22:36 -0700188 case MSG_SET_CALL_CAPABILITIES: {
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700189 call = mCallIdMapper.getCall(msg.obj);
190 if (call != null) {
Sailesh Nepale20bc972014-07-09 21:22:36 -0700191 call.setCallCapabilities(msg.arg1);
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700192 } else {
193 //Log.w(ConnectionServiceWrapper.this,
Sailesh Nepale20bc972014-07-09 21:22:36 -0700194 // "setCallCapabilities, unknown call id: %s", msg.obj);
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700195 }
196 break;
197 }
198 case MSG_SET_IS_CONFERENCED: {
199 SomeArgs args = (SomeArgs) msg.obj;
200 try {
201 Call childCall = mCallIdMapper.getCall(args.arg1);
202 if (childCall != null) {
203 String conferenceCallId = (String) args.arg2;
204 if (conferenceCallId == null) {
205 childCall.setParentCall(null);
206 } else {
207 Call conferenceCall = mCallIdMapper.getCall(conferenceCallId);
208 if (conferenceCall != null &&
209 !mPendingConferenceCalls.contains(conferenceCall)) {
210 childCall.setParentCall(conferenceCall);
211 } else {
212 //Log.w(this, "setIsConferenced, unknown conference id %s",
213 // conferenceCallId);
214 }
215 }
216 } else {
217 //Log.w(this, "setIsConferenced, unknown call id: %s", args.arg1);
218 }
219 } finally {
220 args.recycle();
221 }
222 break;
223 }
224 case MSG_ADD_CONFERENCE_CALL: {
225 Call conferenceCall = mCallIdMapper.getCall(msg.obj);
226 if (mPendingConferenceCalls.remove(conferenceCall)) {
227 Log.v(this, "confirming conf call %s", conferenceCall);
228 conferenceCall.confirmConference();
229 } else {
230 //Log.w(this, "addConference, unknown call id: %s", callId);
231 }
232 break;
233 }
234 case MSG_REMOVE_CALL:
235 break;
236 case MSG_ON_POST_DIAL_WAIT: {
237 SomeArgs args = (SomeArgs) msg.obj;
238 try {
239 call = mCallIdMapper.getCall(args.arg1);
240 if (call != null) {
241 String remaining = (String) args.arg2;
242 call.onPostDialWait(remaining);
243 } else {
244 //Log.w(this, "onPostDialWait, unknown call id: %s", args.arg1);
245 }
246 } finally {
247 args.recycle();
248 }
249 break;
250 }
251 case MSG_QUERY_REMOTE_CALL_SERVICES: {
Sailesh Nepal664837f2014-07-14 16:31:51 -0700252 queryRemoteConnectionServices((RemoteServiceCallback) msg.obj);
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700253 break;
254 }
255 case MSG_SET_CALL_VIDEO_PROVIDER: {
256 SomeArgs args = (SomeArgs) msg.obj;
257 try {
258 call = mCallIdMapper.getCall(args.arg1);
259 ICallVideoProvider callVideoProvider = (ICallVideoProvider) args.arg2;
260 if (call != null) {
261 call.setCallVideoProvider(callVideoProvider);
262 }
263 } finally {
264 args.recycle();
265 }
266 break;
267 }
Sailesh Nepal7e669572014-07-08 21:29:12 -0700268 case MSG_SET_AUDIO_MODE_IS_VOIP: {
Sailesh Nepale20bc972014-07-09 21:22:36 -0700269 call = mCallIdMapper.getCall(msg.obj);
270 if (call != null) {
271 call.setAudioModeIsVoip(msg.arg1 == 1);
Sailesh Nepal7e669572014-07-08 21:29:12 -0700272 }
273 break;
274 }
Sailesh Nepal35faf8c2014-07-08 22:02:34 -0700275 case MSG_SET_STATUS_HINTS: {
276 SomeArgs args = (SomeArgs) msg.obj;
277 try {
278 call = mCallIdMapper.getCall(args.arg1);
279 StatusHints statusHints = (StatusHints) args.arg2;
280 if (call != null) {
281 call.setStatusHints(statusHints);
282 }
283 } finally {
284 args.recycle();
285 }
286 break;
287 }
Sailesh Nepale8ecb982014-07-11 17:19:42 -0700288 case MSG_SET_HANDLE: {
289 SomeArgs args = (SomeArgs) msg.obj;
290 try {
291 call = mCallIdMapper.getCall(args.arg1);
292 if (call != null) {
293 call.setHandle((Uri) args.arg2, args.argi1);
294 }
295 } finally {
296 args.recycle();
297 }
298 break;
299 }
300 case MSG_SET_CALLER_DISPLAY_NAME: {
301 SomeArgs args = (SomeArgs) msg.obj;
302 try {
303 call = mCallIdMapper.getCall(args.arg1);
304 if (call != null) {
305 call.setCallerDisplayName((String) args.arg2, args.argi1);
306 }
307 } finally {
308 args.recycle();
309 }
310 break;
311 }
Tyler Gunn0a388fc2014-07-17 12:21:17 -0700312 case MSG_SET_VIDEO_STATE: {
313 call = mCallIdMapper.getCall(msg.obj);
314 if (call != null) {
315 call.setVideoState(msg.arg1);
316 }
317 }
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700318 }
319 }
320 };
321
322 private final class Adapter extends IConnectionServiceAdapter.Stub {
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700323 @Override
Sailesh Nepal664837f2014-07-14 16:31:51 -0700324 public void handleCreateConnectionSuccessful(ConnectionRequest request) {
325 logIncoming("handleCreateConnectionSuccessful %s", request);
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700326 mCallIdMapper.checkValidCallId(request.getCallId());
Sailesh Nepal664837f2014-07-14 16:31:51 -0700327 mHandler.obtainMessage(MSG_HANDLE_CREATE_CONNECTION_SUCCESSFUL, request).sendToTarget();
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700328 }
329
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700330 @Override
Sailesh Nepal664837f2014-07-14 16:31:51 -0700331 public void handleCreateConnectionFailed(
332 ConnectionRequest request, int errorCode, String errorMsg) {
333 logIncoming("handleCreateConnectionFailed %s %d %s", request, errorCode, errorMsg);
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700334 mCallIdMapper.checkValidCallId(request.getCallId());
335 SomeArgs args = SomeArgs.obtain();
336 args.arg1 = request;
337 args.argi1 = errorCode;
338 args.arg2 = errorMsg;
Sailesh Nepal664837f2014-07-14 16:31:51 -0700339 mHandler.obtainMessage(MSG_HANDLE_CREATE_CONNECTION_FAILED, args).sendToTarget();
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700340 }
341
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700342 @Override
Sailesh Nepal664837f2014-07-14 16:31:51 -0700343 public void handleCreateConnectionCancelled(ConnectionRequest request) {
344 logIncoming("handleCreateConnectionCancelled %s", request);
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700345 mCallIdMapper.checkValidCallId(request.getCallId());
Sailesh Nepal664837f2014-07-14 16:31:51 -0700346 mHandler.obtainMessage(MSG_HANDLE_CREATE_CONNECTION_CANCELLED, request).sendToTarget();
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700347 }
348
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700349 @Override
350 public void setActive(String callId) {
351 logIncoming("setActive %s", callId);
352 mCallIdMapper.checkValidCallId(callId);
353 mHandler.obtainMessage(MSG_SET_ACTIVE, callId).sendToTarget();
354 }
355
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700356 @Override
357 public void setRinging(String callId) {
358 logIncoming("setRinging %s", callId);
359 mCallIdMapper.checkValidCallId(callId);
360 mHandler.obtainMessage(MSG_SET_RINGING, callId).sendToTarget();
361 }
362
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700363 @Override
364 public void setCallVideoProvider(String callId, ICallVideoProvider callVideoProvider) {
365 logIncoming("setCallVideoProvider %s", callId);
366 mCallIdMapper.checkValidCallId(callId);
367 SomeArgs args = SomeArgs.obtain();
368 args.arg1 = callId;
369 args.arg2 = callVideoProvider;
370 mHandler.obtainMessage(MSG_SET_CALL_VIDEO_PROVIDER, args).sendToTarget();
371 }
372
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700373 @Override
374 public void setDialing(String callId) {
375 logIncoming("setDialing %s", callId);
376 mCallIdMapper.checkValidCallId(callId);
377 mHandler.obtainMessage(MSG_SET_DIALING, callId).sendToTarget();
378 }
379
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700380 @Override
381 public void setDisconnected(
382 String callId, int disconnectCause, String disconnectMessage) {
383 logIncoming("setDisconnected %s %d %s", callId, disconnectCause, disconnectMessage);
384 mCallIdMapper.checkValidCallId(callId);
385 SomeArgs args = SomeArgs.obtain();
386 args.arg1 = callId;
387 args.arg2 = disconnectMessage;
388 args.argi1 = disconnectCause;
389 mHandler.obtainMessage(MSG_SET_DISCONNECTED, args).sendToTarget();
390 }
391
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700392 @Override
393 public void setOnHold(String callId) {
394 logIncoming("setOnHold %s", callId);
395 mCallIdMapper.checkValidCallId(callId);
396 mHandler.obtainMessage(MSG_SET_ON_HOLD, callId).sendToTarget();
397 }
398
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700399 @Override
400 public void setRequestingRingback(String callId, boolean ringback) {
401 logIncoming("setRequestingRingback %s %b", callId, ringback);
402 mCallIdMapper.checkValidCallId(callId);
403 SomeArgs args = SomeArgs.obtain();
404 args.arg1 = callId;
405 args.arg2 = ringback;
406 mHandler.obtainMessage(MSG_SET_REQUESTING_RINGBACK, args).sendToTarget();
407 }
408
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700409 @Override
410 public void removeCall(String callId) {
411 logIncoming("removeCall %s", callId);
412 }
413
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700414 @Override
Sailesh Nepale20bc972014-07-09 21:22:36 -0700415 public void setCallCapabilities(String callId, int callCapabilities) {
416 logIncoming("setCallCapabilities %s %d", callId, callCapabilities);
417 mHandler.obtainMessage(MSG_SET_CALL_CAPABILITIES, callCapabilities, 0, callId)
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700418 .sendToTarget();
419 }
420
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700421 @Override
422 public void setIsConferenced(String callId, String conferenceCallId) {
423 logIncoming("setIsConferenced %s %s", callId, conferenceCallId);
424 SomeArgs args = SomeArgs.obtain();
425 args.arg1 = callId;
426 args.arg2 = conferenceCallId;
427 mHandler.obtainMessage(MSG_SET_IS_CONFERENCED, args).sendToTarget();
428 }
429
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700430 @Override
431 public void addConferenceCall(String callId) {
432 logIncoming("addConferenceCall %s", callId);
433 mCallIdMapper.checkValidCallId(callId);
434 mHandler.obtainMessage(MSG_ADD_CONFERENCE_CALL, callId).sendToTarget();
435 }
436
437 @Override
438 public void onPostDialWait(String callId, String remaining) throws RemoteException {
439 logIncoming("onPostDialWait %s %s", callId, remaining);
440 mCallIdMapper.checkValidCallId(callId);
441 SomeArgs args = SomeArgs.obtain();
442 args.arg1 = callId;
443 args.arg2 = remaining;
444 mHandler.obtainMessage(MSG_ON_POST_DIAL_WAIT, args).sendToTarget();
445 }
446
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700447 @Override
448 public void queryRemoteConnectionServices(RemoteServiceCallback callback) {
449 logIncoming("queryRemoteCSs");
450 mHandler.obtainMessage(MSG_QUERY_REMOTE_CALL_SERVICES, callback).sendToTarget();
451 }
452
453 @Override
Tyler Gunn0a388fc2014-07-17 12:21:17 -0700454 public void setVideoState(String callId, int videoState) {
455 logIncoming("setVideoState %s %d", callId, videoState);
456 mCallIdMapper.checkValidCallId(callId);
457 mHandler.obtainMessage(MSG_SET_VIDEO_STATE, videoState, 0, callId).sendToTarget();
458 }
459
460 @Override
Sailesh Nepal7e669572014-07-08 21:29:12 -0700461 public void setAudioModeIsVoip(String callId, boolean isVoip) {
Sailesh Nepal7fa33ca2014-07-10 15:28:21 -0700462 logIncoming("setAudioModeIsVoip %s %b", callId, isVoip);
Sailesh Nepal7e669572014-07-08 21:29:12 -0700463 mCallIdMapper.checkValidCallId(callId);
Sailesh Nepale20bc972014-07-09 21:22:36 -0700464 mHandler.obtainMessage(MSG_SET_AUDIO_MODE_IS_VOIP, isVoip ? 1 : 0, 0,
465 callId).sendToTarget();
Sailesh Nepal7e669572014-07-08 21:29:12 -0700466 }
Sailesh Nepal35faf8c2014-07-08 22:02:34 -0700467
468 @Override
469 public void setStatusHints(String callId, StatusHints statusHints) {
470 logIncoming("setStatusHints %s %s", callId, statusHints);
471 mCallIdMapper.checkValidCallId(callId);
472 SomeArgs args = SomeArgs.obtain();
473 args.arg1 = callId;
474 args.arg2 = statusHints;
475 mHandler.obtainMessage(MSG_SET_STATUS_HINTS, args).sendToTarget();
476 }
Sailesh Nepale8ecb982014-07-11 17:19:42 -0700477
478 @Override
479 public void setHandle(String callId, Uri handle, int presentation) {
480 logIncoming("setHandle %s %s %d", callId, handle, presentation);
481 mCallIdMapper.checkValidCallId(callId);
482 SomeArgs args = SomeArgs.obtain();
483 args.arg1 = callId;
484 args.arg2 = handle;
485 args.argi1 = presentation;
486 mHandler.obtainMessage(MSG_SET_HANDLE, args).sendToTarget();
487 }
488
489 @Override
490 public void setCallerDisplayName(
491 String callId, String callerDisplayName, int presentation) {
492 logIncoming("setCallerDisplayName %s %s %d", callId, callerDisplayName, presentation);
493 mCallIdMapper.checkValidCallId(callId);
494 SomeArgs args = SomeArgs.obtain();
495 args.arg1 = callId;
496 args.arg2 = callerDisplayName;
497 args.argi1 = presentation;
498 mHandler.obtainMessage(MSG_SET_CALLER_DISPLAY_NAME, args).sendToTarget();
499 }
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700500 }
501
502 private final Adapter mAdapter = new Adapter();
503 private final CallsManager mCallsManager = CallsManager.getInstance();
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700504 private final Set<Call> mPendingConferenceCalls = new HashSet<>();
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700505 private final CallIdMapper mCallIdMapper = new CallIdMapper("ConnectionService");
Sailesh Nepal664837f2014-07-14 16:31:51 -0700506 private final Map<String, CreateConnectionResponse> mPendingResponses = new HashMap<>();
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700507
508 private Binder mBinder = new Binder();
509 private IConnectionService mServiceInterface;
Sailesh Nepal905dfba2014-07-14 08:20:41 -0700510 private final ConnectionServiceRepository mConnectionServiceRepository;
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700511
512 /**
Sailesh Nepal905dfba2014-07-14 08:20:41 -0700513 * Creates a connection service.
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700514 *
Sailesh Nepal905dfba2014-07-14 08:20:41 -0700515 * @param componentName The component name of the service with which to bind.
Sailesh Nepal905dfba2014-07-14 08:20:41 -0700516 * @param connectionServiceRepository Connection service repository.
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700517 */
518 ConnectionServiceWrapper(
Sailesh Nepal664837f2014-07-14 16:31:51 -0700519 ComponentName componentName, ConnectionServiceRepository connectionServiceRepository) {
Sailesh Nepal905dfba2014-07-14 08:20:41 -0700520 super(TelecommConstants.ACTION_CONNECTION_SERVICE, componentName);
Sailesh Nepal905dfba2014-07-14 08:20:41 -0700521 mConnectionServiceRepository = connectionServiceRepository;
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700522 }
523
524 /** See {@link IConnectionService#addConnectionServiceAdapter}. */
525 private void addConnectionServiceAdapter(IConnectionServiceAdapter adapter) {
526 if (isServiceValid("addConnectionServiceAdapter")) {
527 try {
Sailesh Nepal3fe8b722014-07-08 10:07:26 -0700528 logOutgoing("addConnectionServiceAdapter %s", adapter);
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700529 mServiceInterface.addConnectionServiceAdapter(adapter);
530 } catch (RemoteException e) {
531 }
532 }
533 }
534
535 /**
Sailesh Nepal664837f2014-07-14 16:31:51 -0700536 * Creates a new connection for a new outgoing call or to attach to an existing incoming call.
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700537 */
Sailesh Nepal664837f2014-07-14 16:31:51 -0700538 void createConnection(final Call call, final CreateConnectionResponse response) {
539 Log.d(this, "createConnection(%s) via %s.", call, getComponentName());
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700540 BindCallback callback = new BindCallback() {
541 @Override
542 public void onSuccess() {
543 String callId = mCallIdMapper.getCallId(call);
Sailesh Nepal664837f2014-07-14 16:31:51 -0700544 mPendingResponses.put(callId, response);
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700545
546 GatewayInfo gatewayInfo = call.getGatewayInfo();
547 Bundle extras = call.getExtras();
548 if (gatewayInfo != null && gatewayInfo.getGatewayProviderPackageName() != null &&
549 gatewayInfo.getOriginalHandle() != null) {
550 extras = (Bundle) extras.clone();
551 extras.putString(
552 NewOutgoingCallIntentBroadcaster.EXTRA_GATEWAY_PROVIDER_PACKAGE,
553 gatewayInfo.getGatewayProviderPackageName());
554 extras.putParcelable(
555 NewOutgoingCallIntentBroadcaster.EXTRA_GATEWAY_ORIGINAL_URI,
556 gatewayInfo.getOriginalHandle());
557 }
Sailesh Nepale8ecb982014-07-11 17:19:42 -0700558 ConnectionRequest request = new ConnectionRequest(
559 call.getPhoneAccount(),
560 callId,
561 call.getHandle(),
562 call.getHandlePresentation(),
563 extras,
Tyler Gunnc4abd912014-07-08 14:22:10 -0700564 call.getVideoState());
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700565
566 try {
Sailesh Nepal664837f2014-07-14 16:31:51 -0700567 mServiceInterface.createConnection(request, call.isIncoming());
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700568 } catch (RemoteException e) {
Sailesh Nepal664837f2014-07-14 16:31:51 -0700569 Log.e(this, e, "Failure to createConnection -- %s", getComponentName());
570 mPendingResponses.remove(callId).handleCreateConnectionFailed(
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700571 DisconnectCause.ERROR_UNSPECIFIED, e.toString());
572 }
573 }
574
575 @Override
576 public void onFailure() {
Sailesh Nepal905dfba2014-07-14 08:20:41 -0700577 Log.e(this, new Exception(), "Failure to call %s", getComponentName());
Sailesh Nepal664837f2014-07-14 16:31:51 -0700578 response.handleCreateConnectionFailed(DisconnectCause.ERROR_UNSPECIFIED, null);
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700579 }
580 };
581
582 mBinder.bind(callback);
583 }
584
585 /** @see ConnectionService#abort(String) */
586 void abort(Call call) {
587 // Clear out any pending outgoing call data
588 String callId = mCallIdMapper.getCallId(call);
589
590 // If still bound, tell the connection service to abort.
591 if (isServiceValid("abort")) {
592 try {
593 logOutgoing("abort %s", callId);
594 mServiceInterface.abort(callId);
595 } catch (RemoteException e) {
596 }
597 }
598
599 removeCall(call);
600 }
601
602 /** @see ConnectionService#hold(String) */
603 void hold(Call call) {
604 if (isServiceValid("hold")) {
605 try {
606 logOutgoing("hold %s", mCallIdMapper.getCallId(call));
607 mServiceInterface.hold(mCallIdMapper.getCallId(call));
608 } catch (RemoteException e) {
609 }
610 }
611 }
612
613 /** @see ConnectionService#unhold(String) */
614 void unhold(Call call) {
615 if (isServiceValid("unhold")) {
616 try {
617 logOutgoing("unhold %s", mCallIdMapper.getCallId(call));
618 mServiceInterface.unhold(mCallIdMapper.getCallId(call));
619 } catch (RemoteException e) {
620 }
621 }
622 }
623
624 /** @see ConnectionService#onAudioStateChanged(String,CallAudioState) */
625 void onAudioStateChanged(Call activeCall, CallAudioState audioState) {
626 if (isServiceValid("onAudioStateChanged")) {
627 try {
628 logOutgoing("onAudioStateChanged %s %s",
629 mCallIdMapper.getCallId(activeCall), audioState);
630 mServiceInterface.onAudioStateChanged(mCallIdMapper.getCallId(activeCall),
631 audioState);
632 } catch (RemoteException e) {
633 }
634 }
635 }
636
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700637 /** @see ConnectionService#disconnect(String) */
638 void disconnect(Call call) {
639 if (isServiceValid("disconnect")) {
640 try {
641 logOutgoing("disconnect %s", mCallIdMapper.getCallId(call));
642 mServiceInterface.disconnect(mCallIdMapper.getCallId(call));
643 } catch (RemoteException e) {
644 }
645 }
646 }
647
648 /** @see ConnectionService#answer(String) */
Andrew Lee38931d02014-07-16 10:17:36 -0700649 void answer(Call call, int videoState) {
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700650 if (isServiceValid("answer")) {
651 try {
Andrew Lee38931d02014-07-16 10:17:36 -0700652 logOutgoing("answer %s %d", mCallIdMapper.getCallId(call), videoState);
653 mServiceInterface.answer(mCallIdMapper.getCallId(call), videoState);
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700654 } catch (RemoteException e) {
655 }
656 }
657 }
658
659 /** @see ConnectionService#reject(String) */
660 void reject(Call call) {
661 if (isServiceValid("reject")) {
662 try {
663 logOutgoing("reject %s", mCallIdMapper.getCallId(call));
664 mServiceInterface.reject(mCallIdMapper.getCallId(call));
665 } catch (RemoteException e) {
666 }
667 }
668 }
669
670 /** @see ConnectionService#playDtmfTone(String,char) */
671 void playDtmfTone(Call call, char digit) {
672 if (isServiceValid("playDtmfTone")) {
673 try {
674 logOutgoing("playDtmfTone %s %c", mCallIdMapper.getCallId(call), digit);
675 mServiceInterface.playDtmfTone(mCallIdMapper.getCallId(call), digit);
676 } catch (RemoteException e) {
677 }
678 }
679 }
680
681 /** @see ConnectionService#stopDtmfTone(String) */
682 void stopDtmfTone(Call call) {
683 if (isServiceValid("stopDtmfTone")) {
684 try {
685 logOutgoing("stopDtmfTone %s", mCallIdMapper.getCallId(call));
686 mServiceInterface.stopDtmfTone(mCallIdMapper.getCallId(call));
687 } catch (RemoteException e) {
688 }
689 }
690 }
691
692 void addCall(Call call) {
693 if (mCallIdMapper.getCallId(call) == null) {
694 mCallIdMapper.addCall(call);
695 }
696 }
697
698 /**
699 * Associates newCall with this connection service by replacing callToReplace.
700 */
701 void replaceCall(Call newCall, Call callToReplace) {
702 Preconditions.checkState(callToReplace.getConnectionService() == this);
703 mCallIdMapper.replaceCall(newCall, callToReplace);
704 }
705
706 void removeCall(Call call) {
Sailesh Nepal664837f2014-07-14 16:31:51 -0700707 CreateConnectionResponse response = mPendingResponses.remove(mCallIdMapper.getCallId(call));
708 if (response != null) {
709 response.handleCreateConnectionFailed(DisconnectCause.ERROR_UNSPECIFIED, null);
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700710 }
711
712 mCallIdMapper.removeCall(call);
713 }
714
715 void onPostDialContinue(Call call, boolean proceed) {
716 if (isServiceValid("onPostDialContinue")) {
717 try {
718 logOutgoing("onPostDialContinue %s %b", mCallIdMapper.getCallId(call), proceed);
719 mServiceInterface.onPostDialContinue(mCallIdMapper.getCallId(call), proceed);
720 } catch (RemoteException ignored) {
721 }
722 }
723 }
724
725 void onPhoneAccountClicked(Call call) {
726 if (isServiceValid("onPhoneAccountClicked")) {
727 try {
728 logOutgoing("onPhoneAccountClicked %s", mCallIdMapper.getCallId(call));
729 mServiceInterface.onPhoneAccountClicked(mCallIdMapper.getCallId(call));
730 } catch (RemoteException ignored) {
731 }
732 }
733 }
734
735 void conference(final Call conferenceCall, Call call) {
736 if (isServiceValid("conference")) {
737 try {
738 conferenceCall.setConnectionService(this);
739 mPendingConferenceCalls.add(conferenceCall);
740 mHandler.postDelayed(new Runnable() {
741 @Override public void run() {
742 if (mPendingConferenceCalls.remove(conferenceCall)) {
743 conferenceCall.expireConference();
744 Log.i(this, "Conference call expired: %s", conferenceCall);
745 }
746 }
747 }, Timeouts.getConferenceCallExpireMillis());
748
749 logOutgoing("conference %s %s",
750 mCallIdMapper.getCallId(conferenceCall),
751 mCallIdMapper.getCallId(call));
752 mServiceInterface.conference(
753 mCallIdMapper.getCallId(conferenceCall),
754 mCallIdMapper.getCallId(call));
755 } catch (RemoteException ignored) {
756 }
757 }
758 }
759
760 void splitFromConference(Call call) {
761 if (isServiceValid("splitFromConference")) {
762 try {
763 logOutgoing("splitFromConference %s", mCallIdMapper.getCallId(call));
764 mServiceInterface.splitFromConference(mCallIdMapper.getCallId(call));
765 } catch (RemoteException ignored) {
766 }
767 }
768 }
769
Sailesh Nepale8ecb982014-07-11 17:19:42 -0700770 void swapWithBackgroundCall(Call call) {
771 if (isServiceValid("swapWithBackgroundCall")) {
772 try {
773 logOutgoing("swapWithBackgroundCall %s", mCallIdMapper.getCallId(call));
774 mServiceInterface.swapWithBackgroundCall(mCallIdMapper.getCallId(call));
775 } catch (RemoteException ignored) {
776 }
777 }
778 }
779
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700780 /** {@inheritDoc} */
781 @Override
782 protected void setServiceInterface(IBinder binder) {
783 if (binder == null) {
784 // We have lost our service connection. Notify the world that this service is done.
785 // We must notify the adapter before CallsManager. The adapter will force any pending
786 // outgoing calls to try the next service. This needs to happen before CallsManager
787 // tries to clean up any calls still associated with this service.
788 handleConnectionServiceDeath();
789 CallsManager.getInstance().handleConnectionServiceDeath(this);
790 mServiceInterface = null;
791 } else {
792 mServiceInterface = IConnectionService.Stub.asInterface(binder);
793 addConnectionServiceAdapter(mAdapter);
794 }
795 }
796
797 /**
798 * Called when the associated connection service dies.
799 */
800 private void handleConnectionServiceDeath() {
Sailesh Nepal664837f2014-07-14 16:31:51 -0700801 if (!mPendingResponses.isEmpty()) {
802 CreateConnectionResponse[] responses = mPendingResponses.values().toArray(
803 new CreateConnectionResponse[mPendingResponses.values().size()]);
804 mPendingResponses.clear();
805 for (int i = 0; i < responses.length; i++) {
806 responses[i].handleCreateConnectionFailed(DisconnectCause.ERROR_UNSPECIFIED, null);
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700807 }
808 }
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700809 mCallIdMapper.clear();
810 }
811
812 private void logIncoming(String msg, Object... params) {
813 Log.d(this, "ConnectionService -> Telecomm: " + msg, params);
814 }
815
816 private void logOutgoing(String msg, Object... params) {
817 Log.d(this, "Telecomm -> ConnectionService: " + msg, params);
818 }
819
820 private void queryRemoteConnectionServices(final RemoteServiceCallback callback) {
821 final List<IBinder> connectionServices = new ArrayList<>();
822 final List<ComponentName> components = new ArrayList<>();
Sailesh Nepal664837f2014-07-14 16:31:51 -0700823 final List<ConnectionServiceWrapper> servciesAttempted = new ArrayList<>();
Sailesh Nepal905dfba2014-07-14 08:20:41 -0700824 final Collection<ConnectionServiceWrapper> services =
825 mConnectionServiceRepository.lookupServices();
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700826
Sailesh Nepal664837f2014-07-14 16:31:51 -0700827 Log.v(this, "queryRemoteConnectionServices, services: " + services.size());
828
Sailesh Nepal905dfba2014-07-14 08:20:41 -0700829 for (ConnectionServiceWrapper cs : services) {
830 if (cs != this) {
831 final ConnectionServiceWrapper currentConnectionService = cs;
832 cs.mBinder.bind(new BindCallback() {
Sailesh Nepal905dfba2014-07-14 08:20:41 -0700833 @Override
834 public void onSuccess() {
835 Log.d(this, "Adding ***** %s", currentConnectionService.getComponentName());
836 connectionServices.add(
837 currentConnectionService.mServiceInterface.asBinder());
838 components.add(currentConnectionService.getComponentName());
839 maybeComplete();
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700840 }
Sailesh Nepal905dfba2014-07-14 08:20:41 -0700841
842 @Override
843 public void onFailure() {
Sailesh Nepal905dfba2014-07-14 08:20:41 -0700844 maybeComplete();
845 }
846
847 private void maybeComplete() {
Sailesh Nepal664837f2014-07-14 16:31:51 -0700848 servciesAttempted.add(currentConnectionService);
849 if (servciesAttempted.size() == services.size() - 1) {
Sailesh Nepal905dfba2014-07-14 08:20:41 -0700850 try {
851 callback.onResult(components, connectionServices);
852 } catch (RemoteException ignored) {
853 }
854 }
855 }
856 });
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700857 }
Sailesh Nepal905dfba2014-07-14 08:20:41 -0700858 }
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700859 }
860}