blob: a78f92833a08e3037b6cc6c9c19bcc0e70a2c7ef [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
Sailesh Nepal9d58de52014-07-18 14:53:19 -070019import android.app.PendingIntent;
Sailesh Nepalc92c4362014-07-04 18:33:21 -070020import android.content.ComponentName;
Sailesh Nepale8ecb982014-07-11 17:19:42 -070021import android.net.Uri;
Sailesh Nepalc92c4362014-07-04 18:33:21 -070022import android.os.Bundle;
23import android.os.Handler;
24import android.os.IBinder;
25import android.os.Message;
26import android.os.RemoteException;
27import android.telecomm.CallAudioState;
Sailesh Nepalc92c4362014-07-04 18:33:21 -070028import android.telecomm.ConnectionRequest;
Santos Cordonf2f14ef2014-07-20 18:00:20 -070029import android.telecomm.ConnectionService;
Sailesh Nepalc92c4362014-07-04 18:33:21 -070030import android.telecomm.GatewayInfo;
Santos Cordon72890ce2014-07-21 01:32:04 -070031import android.telecomm.ParcelableConnection;
Sailesh Nepal35faf8c2014-07-08 22:02:34 -070032import android.telecomm.StatusHints;
Sailesh Nepalc92c4362014-07-04 18:33:21 -070033import android.telephony.DisconnectCause;
34
35import com.android.internal.os.SomeArgs;
Santos Cordonf2f14ef2014-07-20 18:00:20 -070036import com.android.internal.telecomm.ICallVideoProvider;
Sailesh Nepalc92c4362014-07-04 18:33:21 -070037import com.android.internal.telecomm.IConnectionService;
38import com.android.internal.telecomm.IConnectionServiceAdapter;
Sailesh Nepalc92c4362014-07-04 18:33:21 -070039import com.android.internal.telecomm.RemoteServiceCallback;
Sailesh Nepalc92c4362014-07-04 18:33:21 -070040import com.google.common.base.Preconditions;
Sailesh Nepalc92c4362014-07-04 18:33:21 -070041
Sailesh Nepalc92c4362014-07-04 18:33:21 -070042import java.util.ArrayList;
43import java.util.Collection;
44import java.util.HashMap;
45import java.util.HashSet;
46import java.util.List;
47import java.util.Map;
48import java.util.Set;
49
50/**
51 * Wrapper for {@link IConnectionService}s, handles binding to {@link IConnectionService} and keeps
52 * track of when the object can safely be unbound. Other classes should not use
53 * {@link IConnectionService} directly and instead should use this class to invoke methods of
54 * {@link IConnectionService}.
55 */
56final class ConnectionServiceWrapper extends ServiceBinder<IConnectionService> {
Sailesh Nepal664837f2014-07-14 16:31:51 -070057 private static final int MSG_HANDLE_CREATE_CONNECTION_SUCCESSFUL = 1;
58 private static final int MSG_HANDLE_CREATE_CONNECTION_FAILED = 2;
59 private static final int MSG_HANDLE_CREATE_CONNECTION_CANCELLED = 3;
60 private static final int MSG_SET_ACTIVE = 4;
61 private static final int MSG_SET_RINGING = 5;
62 private static final int MSG_SET_DIALING = 6;
63 private static final int MSG_SET_DISCONNECTED = 7;
64 private static final int MSG_SET_ON_HOLD = 8;
65 private static final int MSG_SET_REQUESTING_RINGBACK = 9;
66 private static final int MSG_SET_CALL_CAPABILITIES = 10;
67 private static final int MSG_SET_IS_CONFERENCED = 11;
68 private static final int MSG_ADD_CONFERENCE_CALL = 12;
69 private static final int MSG_REMOVE_CALL = 13;
70 private static final int MSG_ON_POST_DIAL_WAIT = 14;
71 private static final int MSG_QUERY_REMOTE_CALL_SERVICES = 15;
72 private static final int MSG_SET_CALL_VIDEO_PROVIDER = 16;
73 private static final int MSG_SET_AUDIO_MODE_IS_VOIP = 17;
74 private static final int MSG_SET_STATUS_HINTS = 18;
75 private static final int MSG_SET_HANDLE = 19;
76 private static final int MSG_SET_CALLER_DISPLAY_NAME = 20;
Tyler Gunn0a388fc2014-07-17 12:21:17 -070077 private static final int MSG_SET_VIDEO_STATE = 21;
Sailesh Nepal9d58de52014-07-18 14:53:19 -070078 private static final int MSG_START_ACTIVITY_FROM_IN_CALL = 22;
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: {
Santos Cordon72890ce2014-07-21 01:32:04 -070086 SomeArgs args = (SomeArgs) msg.obj;
87 try {
88 ConnectionRequest request = (ConnectionRequest) args.arg1;
89 if (mPendingResponses.containsKey(request.getCallId())) {
90 ParcelableConnection connection = (ParcelableConnection) args.arg2;
91 mPendingResponses.remove(request.getCallId()).
92 handleCreateConnectionSuccessful(request, connection);
93 }
94 } finally {
95 args.recycle();
Sailesh Nepalc92c4362014-07-04 18:33:21 -070096 }
97 break;
98 }
Sailesh Nepal664837f2014-07-14 16:31:51 -070099 case MSG_HANDLE_CREATE_CONNECTION_FAILED: {
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700100 SomeArgs args = (SomeArgs) msg.obj;
101 try {
Sailesh Nepala49c6432014-07-07 22:47:11 -0700102 ConnectionRequest request = (ConnectionRequest) args.arg1;
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700103 int statusCode = args.argi1;
104 String statusMsg = (String) args.arg2;
Santos Cordonfd6ca442014-07-24 15:34:01 -0700105 removeCall(
106 mCallIdMapper.getCall(request.getCallId()),
107 statusCode,
108 statusMsg);
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700109 } 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: {
Sailesh Nepal9d58de52014-07-18 14:53:19 -0700174 call = mCallIdMapper.getCall(msg.obj);
175 if (call != null) {
176 call.setRequestingRingback(msg.arg1 == 1);
177 } else {
178 //Log.w(this, "setRingback, unknown call id: %s", args.arg1);
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700179 }
180 break;
181 }
Sailesh Nepale20bc972014-07-09 21:22:36 -0700182 case MSG_SET_CALL_CAPABILITIES: {
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700183 call = mCallIdMapper.getCall(msg.obj);
184 if (call != null) {
Sailesh Nepale20bc972014-07-09 21:22:36 -0700185 call.setCallCapabilities(msg.arg1);
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700186 } else {
187 //Log.w(ConnectionServiceWrapper.this,
Sailesh Nepale20bc972014-07-09 21:22:36 -0700188 // "setCallCapabilities, unknown call id: %s", msg.obj);
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700189 }
190 break;
191 }
192 case MSG_SET_IS_CONFERENCED: {
193 SomeArgs args = (SomeArgs) msg.obj;
194 try {
195 Call childCall = mCallIdMapper.getCall(args.arg1);
196 if (childCall != null) {
197 String conferenceCallId = (String) args.arg2;
198 if (conferenceCallId == null) {
199 childCall.setParentCall(null);
200 } else {
201 Call conferenceCall = mCallIdMapper.getCall(conferenceCallId);
202 if (conferenceCall != null &&
203 !mPendingConferenceCalls.contains(conferenceCall)) {
204 childCall.setParentCall(conferenceCall);
205 } else {
206 //Log.w(this, "setIsConferenced, unknown conference id %s",
207 // conferenceCallId);
208 }
209 }
210 } else {
211 //Log.w(this, "setIsConferenced, unknown call id: %s", args.arg1);
212 }
213 } finally {
214 args.recycle();
215 }
216 break;
217 }
218 case MSG_ADD_CONFERENCE_CALL: {
219 Call conferenceCall = mCallIdMapper.getCall(msg.obj);
220 if (mPendingConferenceCalls.remove(conferenceCall)) {
221 Log.v(this, "confirming conf call %s", conferenceCall);
222 conferenceCall.confirmConference();
223 } else {
224 //Log.w(this, "addConference, unknown call id: %s", callId);
225 }
226 break;
227 }
228 case MSG_REMOVE_CALL:
229 break;
230 case MSG_ON_POST_DIAL_WAIT: {
231 SomeArgs args = (SomeArgs) msg.obj;
232 try {
233 call = mCallIdMapper.getCall(args.arg1);
234 if (call != null) {
235 String remaining = (String) args.arg2;
236 call.onPostDialWait(remaining);
237 } else {
238 //Log.w(this, "onPostDialWait, unknown call id: %s", args.arg1);
239 }
240 } finally {
241 args.recycle();
242 }
243 break;
244 }
245 case MSG_QUERY_REMOTE_CALL_SERVICES: {
Sailesh Nepal664837f2014-07-14 16:31:51 -0700246 queryRemoteConnectionServices((RemoteServiceCallback) msg.obj);
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700247 break;
248 }
249 case MSG_SET_CALL_VIDEO_PROVIDER: {
250 SomeArgs args = (SomeArgs) msg.obj;
251 try {
252 call = mCallIdMapper.getCall(args.arg1);
253 ICallVideoProvider callVideoProvider = (ICallVideoProvider) args.arg2;
254 if (call != null) {
255 call.setCallVideoProvider(callVideoProvider);
256 }
257 } finally {
258 args.recycle();
259 }
260 break;
261 }
Sailesh Nepal7e669572014-07-08 21:29:12 -0700262 case MSG_SET_AUDIO_MODE_IS_VOIP: {
Sailesh Nepale20bc972014-07-09 21:22:36 -0700263 call = mCallIdMapper.getCall(msg.obj);
264 if (call != null) {
265 call.setAudioModeIsVoip(msg.arg1 == 1);
Sailesh Nepal7e669572014-07-08 21:29:12 -0700266 }
267 break;
268 }
Sailesh Nepal35faf8c2014-07-08 22:02:34 -0700269 case MSG_SET_STATUS_HINTS: {
270 SomeArgs args = (SomeArgs) msg.obj;
271 try {
272 call = mCallIdMapper.getCall(args.arg1);
273 StatusHints statusHints = (StatusHints) args.arg2;
274 if (call != null) {
275 call.setStatusHints(statusHints);
276 }
277 } finally {
278 args.recycle();
279 }
280 break;
281 }
Sailesh Nepale8ecb982014-07-11 17:19:42 -0700282 case MSG_SET_HANDLE: {
283 SomeArgs args = (SomeArgs) msg.obj;
284 try {
285 call = mCallIdMapper.getCall(args.arg1);
286 if (call != null) {
287 call.setHandle((Uri) args.arg2, args.argi1);
288 }
289 } finally {
290 args.recycle();
291 }
292 break;
293 }
294 case MSG_SET_CALLER_DISPLAY_NAME: {
295 SomeArgs args = (SomeArgs) msg.obj;
296 try {
297 call = mCallIdMapper.getCall(args.arg1);
298 if (call != null) {
299 call.setCallerDisplayName((String) args.arg2, args.argi1);
300 }
301 } finally {
302 args.recycle();
303 }
304 break;
305 }
Tyler Gunn0a388fc2014-07-17 12:21:17 -0700306 case MSG_SET_VIDEO_STATE: {
307 call = mCallIdMapper.getCall(msg.obj);
308 if (call != null) {
309 call.setVideoState(msg.arg1);
310 }
Tyler Gunn7e0df312014-07-21 14:34:58 -0700311 break;
Tyler Gunn0a388fc2014-07-17 12:21:17 -0700312 }
Sailesh Nepal9d58de52014-07-18 14:53:19 -0700313 case MSG_START_ACTIVITY_FROM_IN_CALL: {
314 SomeArgs args = (SomeArgs) msg.obj;
315 try {
316 call = mCallIdMapper.getCall(args.arg1);
317 if (call != null) {
318 call.startActivityFromInCall((PendingIntent) args.arg2);
319 }
320 } finally {
321 args.recycle();
322 }
323 break;
324 }
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700325 }
326 }
327 };
328
329 private final class Adapter extends IConnectionServiceAdapter.Stub {
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700330 @Override
Santos Cordon72890ce2014-07-21 01:32:04 -0700331 public void handleCreateConnectionSuccessful(
332 ConnectionRequest request, ParcelableConnection connection) {
333
Sailesh Nepal664837f2014-07-14 16:31:51 -0700334 logIncoming("handleCreateConnectionSuccessful %s", request);
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700335 mCallIdMapper.checkValidCallId(request.getCallId());
Santos Cordon72890ce2014-07-21 01:32:04 -0700336 SomeArgs args = SomeArgs.obtain();
337 args.arg1 = request;
338 args.arg2 = connection;
339 mHandler.obtainMessage(MSG_HANDLE_CREATE_CONNECTION_SUCCESSFUL, 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 handleCreateConnectionFailed(
344 ConnectionRequest request, int errorCode, String errorMsg) {
345 logIncoming("handleCreateConnectionFailed %s %d %s", request, errorCode, errorMsg);
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700346 mCallIdMapper.checkValidCallId(request.getCallId());
347 SomeArgs args = SomeArgs.obtain();
348 args.arg1 = request;
349 args.argi1 = errorCode;
350 args.arg2 = errorMsg;
Sailesh Nepal664837f2014-07-14 16:31:51 -0700351 mHandler.obtainMessage(MSG_HANDLE_CREATE_CONNECTION_FAILED, args).sendToTarget();
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700352 }
353
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700354 @Override
Sailesh Nepal664837f2014-07-14 16:31:51 -0700355 public void handleCreateConnectionCancelled(ConnectionRequest request) {
356 logIncoming("handleCreateConnectionCancelled %s", request);
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700357 mCallIdMapper.checkValidCallId(request.getCallId());
Sailesh Nepal664837f2014-07-14 16:31:51 -0700358 mHandler.obtainMessage(MSG_HANDLE_CREATE_CONNECTION_CANCELLED, request).sendToTarget();
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700359 }
360
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700361 @Override
362 public void setActive(String callId) {
363 logIncoming("setActive %s", callId);
364 mCallIdMapper.checkValidCallId(callId);
365 mHandler.obtainMessage(MSG_SET_ACTIVE, callId).sendToTarget();
366 }
367
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700368 @Override
369 public void setRinging(String callId) {
370 logIncoming("setRinging %s", callId);
371 mCallIdMapper.checkValidCallId(callId);
372 mHandler.obtainMessage(MSG_SET_RINGING, callId).sendToTarget();
373 }
374
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700375 @Override
376 public void setCallVideoProvider(String callId, ICallVideoProvider callVideoProvider) {
377 logIncoming("setCallVideoProvider %s", callId);
378 mCallIdMapper.checkValidCallId(callId);
379 SomeArgs args = SomeArgs.obtain();
380 args.arg1 = callId;
381 args.arg2 = callVideoProvider;
382 mHandler.obtainMessage(MSG_SET_CALL_VIDEO_PROVIDER, args).sendToTarget();
383 }
384
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700385 @Override
386 public void setDialing(String callId) {
387 logIncoming("setDialing %s", callId);
388 mCallIdMapper.checkValidCallId(callId);
389 mHandler.obtainMessage(MSG_SET_DIALING, callId).sendToTarget();
390 }
391
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700392 @Override
393 public void setDisconnected(
394 String callId, int disconnectCause, String disconnectMessage) {
395 logIncoming("setDisconnected %s %d %s", callId, disconnectCause, disconnectMessage);
396 mCallIdMapper.checkValidCallId(callId);
397 SomeArgs args = SomeArgs.obtain();
398 args.arg1 = callId;
399 args.arg2 = disconnectMessage;
400 args.argi1 = disconnectCause;
401 mHandler.obtainMessage(MSG_SET_DISCONNECTED, args).sendToTarget();
402 }
403
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700404 @Override
405 public void setOnHold(String callId) {
406 logIncoming("setOnHold %s", callId);
407 mCallIdMapper.checkValidCallId(callId);
408 mHandler.obtainMessage(MSG_SET_ON_HOLD, callId).sendToTarget();
409 }
410
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700411 @Override
412 public void setRequestingRingback(String callId, boolean ringback) {
413 logIncoming("setRequestingRingback %s %b", callId, ringback);
414 mCallIdMapper.checkValidCallId(callId);
Sailesh Nepal9d58de52014-07-18 14:53:19 -0700415 mHandler.obtainMessage(MSG_SET_REQUESTING_RINGBACK, ringback ? 1 : 0, 0, callId)
416 .sendToTarget();
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700417 }
418
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700419 @Override
420 public void removeCall(String callId) {
421 logIncoming("removeCall %s", callId);
422 }
423
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700424 @Override
Sailesh Nepale20bc972014-07-09 21:22:36 -0700425 public void setCallCapabilities(String callId, int callCapabilities) {
426 logIncoming("setCallCapabilities %s %d", callId, callCapabilities);
427 mHandler.obtainMessage(MSG_SET_CALL_CAPABILITIES, callCapabilities, 0, callId)
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700428 .sendToTarget();
429 }
430
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700431 @Override
432 public void setIsConferenced(String callId, String conferenceCallId) {
433 logIncoming("setIsConferenced %s %s", callId, conferenceCallId);
434 SomeArgs args = SomeArgs.obtain();
435 args.arg1 = callId;
436 args.arg2 = conferenceCallId;
437 mHandler.obtainMessage(MSG_SET_IS_CONFERENCED, args).sendToTarget();
438 }
439
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700440 @Override
441 public void addConferenceCall(String callId) {
442 logIncoming("addConferenceCall %s", callId);
443 mCallIdMapper.checkValidCallId(callId);
444 mHandler.obtainMessage(MSG_ADD_CONFERENCE_CALL, callId).sendToTarget();
445 }
446
447 @Override
448 public void onPostDialWait(String callId, String remaining) throws RemoteException {
449 logIncoming("onPostDialWait %s %s", callId, remaining);
450 mCallIdMapper.checkValidCallId(callId);
451 SomeArgs args = SomeArgs.obtain();
452 args.arg1 = callId;
453 args.arg2 = remaining;
454 mHandler.obtainMessage(MSG_ON_POST_DIAL_WAIT, args).sendToTarget();
455 }
456
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700457 @Override
458 public void queryRemoteConnectionServices(RemoteServiceCallback callback) {
459 logIncoming("queryRemoteCSs");
460 mHandler.obtainMessage(MSG_QUERY_REMOTE_CALL_SERVICES, callback).sendToTarget();
461 }
462
463 @Override
Tyler Gunn0a388fc2014-07-17 12:21:17 -0700464 public void setVideoState(String callId, int videoState) {
465 logIncoming("setVideoState %s %d", callId, videoState);
466 mCallIdMapper.checkValidCallId(callId);
467 mHandler.obtainMessage(MSG_SET_VIDEO_STATE, videoState, 0, callId).sendToTarget();
468 }
469
470 @Override
Sailesh Nepal7e669572014-07-08 21:29:12 -0700471 public void setAudioModeIsVoip(String callId, boolean isVoip) {
Sailesh Nepal7fa33ca2014-07-10 15:28:21 -0700472 logIncoming("setAudioModeIsVoip %s %b", callId, isVoip);
Sailesh Nepal7e669572014-07-08 21:29:12 -0700473 mCallIdMapper.checkValidCallId(callId);
Sailesh Nepale20bc972014-07-09 21:22:36 -0700474 mHandler.obtainMessage(MSG_SET_AUDIO_MODE_IS_VOIP, isVoip ? 1 : 0, 0,
475 callId).sendToTarget();
Sailesh Nepal7e669572014-07-08 21:29:12 -0700476 }
Sailesh Nepal35faf8c2014-07-08 22:02:34 -0700477
478 @Override
479 public void setStatusHints(String callId, StatusHints statusHints) {
480 logIncoming("setStatusHints %s %s", callId, statusHints);
481 mCallIdMapper.checkValidCallId(callId);
482 SomeArgs args = SomeArgs.obtain();
483 args.arg1 = callId;
484 args.arg2 = statusHints;
485 mHandler.obtainMessage(MSG_SET_STATUS_HINTS, args).sendToTarget();
486 }
Sailesh Nepale8ecb982014-07-11 17:19:42 -0700487
488 @Override
489 public void setHandle(String callId, Uri handle, int presentation) {
490 logIncoming("setHandle %s %s %d", callId, handle, presentation);
491 mCallIdMapper.checkValidCallId(callId);
492 SomeArgs args = SomeArgs.obtain();
493 args.arg1 = callId;
494 args.arg2 = handle;
495 args.argi1 = presentation;
496 mHandler.obtainMessage(MSG_SET_HANDLE, args).sendToTarget();
497 }
498
499 @Override
500 public void setCallerDisplayName(
501 String callId, String callerDisplayName, int presentation) {
502 logIncoming("setCallerDisplayName %s %s %d", callId, callerDisplayName, presentation);
503 mCallIdMapper.checkValidCallId(callId);
504 SomeArgs args = SomeArgs.obtain();
505 args.arg1 = callId;
506 args.arg2 = callerDisplayName;
507 args.argi1 = presentation;
508 mHandler.obtainMessage(MSG_SET_CALLER_DISPLAY_NAME, args).sendToTarget();
509 }
Sailesh Nepal9d58de52014-07-18 14:53:19 -0700510
511 @Override
512 public void startActivityFromInCall(String callId, PendingIntent intent) {
513 logIncoming("startActivityFromInCall %s %s", callId, intent);
514 mCallIdMapper.checkValidCallId(callId);
515 SomeArgs args = SomeArgs.obtain();
516 args.arg1 = callId;
517 args.arg2 = intent;
518 mHandler.obtainMessage(MSG_START_ACTIVITY_FROM_IN_CALL, args).sendToTarget();
519 }
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700520 }
521
522 private final Adapter mAdapter = new Adapter();
523 private final CallsManager mCallsManager = CallsManager.getInstance();
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700524 private final Set<Call> mPendingConferenceCalls = new HashSet<>();
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700525 private final CallIdMapper mCallIdMapper = new CallIdMapper("ConnectionService");
Sailesh Nepal664837f2014-07-14 16:31:51 -0700526 private final Map<String, CreateConnectionResponse> mPendingResponses = new HashMap<>();
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700527
528 private Binder mBinder = new Binder();
529 private IConnectionService mServiceInterface;
Sailesh Nepal905dfba2014-07-14 08:20:41 -0700530 private final ConnectionServiceRepository mConnectionServiceRepository;
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700531
532 /**
Sailesh Nepal905dfba2014-07-14 08:20:41 -0700533 * Creates a connection service.
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700534 *
Sailesh Nepal905dfba2014-07-14 08:20:41 -0700535 * @param componentName The component name of the service with which to bind.
Sailesh Nepal905dfba2014-07-14 08:20:41 -0700536 * @param connectionServiceRepository Connection service repository.
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700537 */
538 ConnectionServiceWrapper(
Sailesh Nepal664837f2014-07-14 16:31:51 -0700539 ComponentName componentName, ConnectionServiceRepository connectionServiceRepository) {
Santos Cordonf2f14ef2014-07-20 18:00:20 -0700540 super(ConnectionService.SERVICE_INTERFACE, componentName);
Sailesh Nepal905dfba2014-07-14 08:20:41 -0700541 mConnectionServiceRepository = connectionServiceRepository;
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700542 }
543
544 /** See {@link IConnectionService#addConnectionServiceAdapter}. */
545 private void addConnectionServiceAdapter(IConnectionServiceAdapter adapter) {
546 if (isServiceValid("addConnectionServiceAdapter")) {
547 try {
Sailesh Nepal3fe8b722014-07-08 10:07:26 -0700548 logOutgoing("addConnectionServiceAdapter %s", adapter);
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700549 mServiceInterface.addConnectionServiceAdapter(adapter);
550 } catch (RemoteException e) {
551 }
552 }
553 }
554
555 /**
Sailesh Nepal664837f2014-07-14 16:31:51 -0700556 * Creates a new connection for a new outgoing call or to attach to an existing incoming call.
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700557 */
Sailesh Nepal664837f2014-07-14 16:31:51 -0700558 void createConnection(final Call call, final CreateConnectionResponse response) {
559 Log.d(this, "createConnection(%s) via %s.", call, getComponentName());
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700560 BindCallback callback = new BindCallback() {
561 @Override
562 public void onSuccess() {
563 String callId = mCallIdMapper.getCallId(call);
Sailesh Nepal664837f2014-07-14 16:31:51 -0700564 mPendingResponses.put(callId, response);
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700565
566 GatewayInfo gatewayInfo = call.getGatewayInfo();
567 Bundle extras = call.getExtras();
568 if (gatewayInfo != null && gatewayInfo.getGatewayProviderPackageName() != null &&
569 gatewayInfo.getOriginalHandle() != null) {
570 extras = (Bundle) extras.clone();
571 extras.putString(
572 NewOutgoingCallIntentBroadcaster.EXTRA_GATEWAY_PROVIDER_PACKAGE,
573 gatewayInfo.getGatewayProviderPackageName());
574 extras.putParcelable(
575 NewOutgoingCallIntentBroadcaster.EXTRA_GATEWAY_ORIGINAL_URI,
576 gatewayInfo.getOriginalHandle());
577 }
Sailesh Nepale8ecb982014-07-11 17:19:42 -0700578 ConnectionRequest request = new ConnectionRequest(
579 call.getPhoneAccount(),
580 callId,
581 call.getHandle(),
582 call.getHandlePresentation(),
583 extras,
Tyler Gunnc4abd912014-07-08 14:22:10 -0700584 call.getVideoState());
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700585
586 try {
Sailesh Nepal664837f2014-07-14 16:31:51 -0700587 mServiceInterface.createConnection(request, call.isIncoming());
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700588 } catch (RemoteException e) {
Sailesh Nepal664837f2014-07-14 16:31:51 -0700589 Log.e(this, e, "Failure to createConnection -- %s", getComponentName());
590 mPendingResponses.remove(callId).handleCreateConnectionFailed(
Santos Cordonfd6ca442014-07-24 15:34:01 -0700591 DisconnectCause.OUTGOING_FAILURE, e.toString());
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700592 }
593 }
594
595 @Override
596 public void onFailure() {
Sailesh Nepal905dfba2014-07-14 08:20:41 -0700597 Log.e(this, new Exception(), "Failure to call %s", getComponentName());
Santos Cordonfd6ca442014-07-24 15:34:01 -0700598 response.handleCreateConnectionFailed(DisconnectCause.OUTGOING_FAILURE, null);
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700599 }
600 };
601
602 mBinder.bind(callback);
603 }
604
605 /** @see ConnectionService#abort(String) */
606 void abort(Call call) {
607 // Clear out any pending outgoing call data
608 String callId = mCallIdMapper.getCallId(call);
609
610 // If still bound, tell the connection service to abort.
611 if (isServiceValid("abort")) {
612 try {
613 logOutgoing("abort %s", callId);
614 mServiceInterface.abort(callId);
615 } catch (RemoteException e) {
616 }
617 }
618
Santos Cordonfd6ca442014-07-24 15:34:01 -0700619 removeCall(call, DisconnectCause.LOCAL, null);
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700620 }
621
622 /** @see ConnectionService#hold(String) */
623 void hold(Call call) {
624 if (isServiceValid("hold")) {
625 try {
626 logOutgoing("hold %s", mCallIdMapper.getCallId(call));
627 mServiceInterface.hold(mCallIdMapper.getCallId(call));
628 } catch (RemoteException e) {
629 }
630 }
631 }
632
633 /** @see ConnectionService#unhold(String) */
634 void unhold(Call call) {
635 if (isServiceValid("unhold")) {
636 try {
637 logOutgoing("unhold %s", mCallIdMapper.getCallId(call));
638 mServiceInterface.unhold(mCallIdMapper.getCallId(call));
639 } catch (RemoteException e) {
640 }
641 }
642 }
643
644 /** @see ConnectionService#onAudioStateChanged(String,CallAudioState) */
645 void onAudioStateChanged(Call activeCall, CallAudioState audioState) {
646 if (isServiceValid("onAudioStateChanged")) {
647 try {
648 logOutgoing("onAudioStateChanged %s %s",
649 mCallIdMapper.getCallId(activeCall), audioState);
650 mServiceInterface.onAudioStateChanged(mCallIdMapper.getCallId(activeCall),
651 audioState);
652 } catch (RemoteException e) {
653 }
654 }
655 }
656
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700657 /** @see ConnectionService#disconnect(String) */
658 void disconnect(Call call) {
659 if (isServiceValid("disconnect")) {
660 try {
661 logOutgoing("disconnect %s", mCallIdMapper.getCallId(call));
662 mServiceInterface.disconnect(mCallIdMapper.getCallId(call));
663 } catch (RemoteException e) {
664 }
665 }
666 }
667
668 /** @see ConnectionService#answer(String) */
Andrew Lee38931d02014-07-16 10:17:36 -0700669 void answer(Call call, int videoState) {
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700670 if (isServiceValid("answer")) {
671 try {
Andrew Lee38931d02014-07-16 10:17:36 -0700672 logOutgoing("answer %s %d", mCallIdMapper.getCallId(call), videoState);
673 mServiceInterface.answer(mCallIdMapper.getCallId(call), videoState);
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700674 } catch (RemoteException e) {
675 }
676 }
677 }
678
679 /** @see ConnectionService#reject(String) */
680 void reject(Call call) {
681 if (isServiceValid("reject")) {
682 try {
683 logOutgoing("reject %s", mCallIdMapper.getCallId(call));
684 mServiceInterface.reject(mCallIdMapper.getCallId(call));
685 } catch (RemoteException e) {
686 }
687 }
688 }
689
690 /** @see ConnectionService#playDtmfTone(String,char) */
691 void playDtmfTone(Call call, char digit) {
692 if (isServiceValid("playDtmfTone")) {
693 try {
694 logOutgoing("playDtmfTone %s %c", mCallIdMapper.getCallId(call), digit);
695 mServiceInterface.playDtmfTone(mCallIdMapper.getCallId(call), digit);
696 } catch (RemoteException e) {
697 }
698 }
699 }
700
701 /** @see ConnectionService#stopDtmfTone(String) */
702 void stopDtmfTone(Call call) {
703 if (isServiceValid("stopDtmfTone")) {
704 try {
705 logOutgoing("stopDtmfTone %s", mCallIdMapper.getCallId(call));
706 mServiceInterface.stopDtmfTone(mCallIdMapper.getCallId(call));
707 } catch (RemoteException e) {
708 }
709 }
710 }
711
712 void addCall(Call call) {
713 if (mCallIdMapper.getCallId(call) == null) {
714 mCallIdMapper.addCall(call);
715 }
716 }
717
718 /**
719 * Associates newCall with this connection service by replacing callToReplace.
720 */
721 void replaceCall(Call newCall, Call callToReplace) {
722 Preconditions.checkState(callToReplace.getConnectionService() == this);
723 mCallIdMapper.replaceCall(newCall, callToReplace);
724 }
725
726 void removeCall(Call call) {
Santos Cordonfd6ca442014-07-24 15:34:01 -0700727 removeCall(call, DisconnectCause.ERROR_UNSPECIFIED, null);
728 }
729
730 void removeCall(Call call, int disconnectCause, String disconnectMessage) {
Sailesh Nepal664837f2014-07-14 16:31:51 -0700731 CreateConnectionResponse response = mPendingResponses.remove(mCallIdMapper.getCallId(call));
732 if (response != null) {
Santos Cordonfd6ca442014-07-24 15:34:01 -0700733 response.handleCreateConnectionFailed(disconnectCause, disconnectMessage);
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700734 }
735
736 mCallIdMapper.removeCall(call);
737 }
738
739 void onPostDialContinue(Call call, boolean proceed) {
740 if (isServiceValid("onPostDialContinue")) {
741 try {
742 logOutgoing("onPostDialContinue %s %b", mCallIdMapper.getCallId(call), proceed);
743 mServiceInterface.onPostDialContinue(mCallIdMapper.getCallId(call), proceed);
744 } catch (RemoteException ignored) {
745 }
746 }
747 }
748
749 void onPhoneAccountClicked(Call call) {
750 if (isServiceValid("onPhoneAccountClicked")) {
751 try {
752 logOutgoing("onPhoneAccountClicked %s", mCallIdMapper.getCallId(call));
753 mServiceInterface.onPhoneAccountClicked(mCallIdMapper.getCallId(call));
754 } catch (RemoteException ignored) {
755 }
756 }
757 }
758
759 void conference(final Call conferenceCall, Call call) {
760 if (isServiceValid("conference")) {
761 try {
762 conferenceCall.setConnectionService(this);
763 mPendingConferenceCalls.add(conferenceCall);
764 mHandler.postDelayed(new Runnable() {
765 @Override public void run() {
766 if (mPendingConferenceCalls.remove(conferenceCall)) {
767 conferenceCall.expireConference();
768 Log.i(this, "Conference call expired: %s", conferenceCall);
769 }
770 }
771 }, Timeouts.getConferenceCallExpireMillis());
772
773 logOutgoing("conference %s %s",
774 mCallIdMapper.getCallId(conferenceCall),
775 mCallIdMapper.getCallId(call));
776 mServiceInterface.conference(
777 mCallIdMapper.getCallId(conferenceCall),
778 mCallIdMapper.getCallId(call));
779 } catch (RemoteException ignored) {
780 }
781 }
782 }
783
784 void splitFromConference(Call call) {
785 if (isServiceValid("splitFromConference")) {
786 try {
787 logOutgoing("splitFromConference %s", mCallIdMapper.getCallId(call));
788 mServiceInterface.splitFromConference(mCallIdMapper.getCallId(call));
789 } catch (RemoteException ignored) {
790 }
791 }
792 }
793
Sailesh Nepale8ecb982014-07-11 17:19:42 -0700794 void swapWithBackgroundCall(Call call) {
795 if (isServiceValid("swapWithBackgroundCall")) {
796 try {
797 logOutgoing("swapWithBackgroundCall %s", mCallIdMapper.getCallId(call));
798 mServiceInterface.swapWithBackgroundCall(mCallIdMapper.getCallId(call));
799 } catch (RemoteException ignored) {
800 }
801 }
802 }
803
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700804 /** {@inheritDoc} */
805 @Override
806 protected void setServiceInterface(IBinder binder) {
807 if (binder == null) {
808 // We have lost our service connection. Notify the world that this service is done.
809 // We must notify the adapter before CallsManager. The adapter will force any pending
810 // outgoing calls to try the next service. This needs to happen before CallsManager
811 // tries to clean up any calls still associated with this service.
812 handleConnectionServiceDeath();
813 CallsManager.getInstance().handleConnectionServiceDeath(this);
814 mServiceInterface = null;
815 } else {
816 mServiceInterface = IConnectionService.Stub.asInterface(binder);
817 addConnectionServiceAdapter(mAdapter);
818 }
819 }
820
821 /**
822 * Called when the associated connection service dies.
823 */
824 private void handleConnectionServiceDeath() {
Sailesh Nepal664837f2014-07-14 16:31:51 -0700825 if (!mPendingResponses.isEmpty()) {
826 CreateConnectionResponse[] responses = mPendingResponses.values().toArray(
827 new CreateConnectionResponse[mPendingResponses.values().size()]);
828 mPendingResponses.clear();
829 for (int i = 0; i < responses.length; i++) {
830 responses[i].handleCreateConnectionFailed(DisconnectCause.ERROR_UNSPECIFIED, null);
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700831 }
832 }
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700833 mCallIdMapper.clear();
834 }
835
836 private void logIncoming(String msg, Object... params) {
837 Log.d(this, "ConnectionService -> Telecomm: " + msg, params);
838 }
839
840 private void logOutgoing(String msg, Object... params) {
841 Log.d(this, "Telecomm -> ConnectionService: " + msg, params);
842 }
843
844 private void queryRemoteConnectionServices(final RemoteServiceCallback callback) {
845 final List<IBinder> connectionServices = new ArrayList<>();
846 final List<ComponentName> components = new ArrayList<>();
Sailesh Nepal664837f2014-07-14 16:31:51 -0700847 final List<ConnectionServiceWrapper> servciesAttempted = new ArrayList<>();
Sailesh Nepal905dfba2014-07-14 08:20:41 -0700848 final Collection<ConnectionServiceWrapper> services =
849 mConnectionServiceRepository.lookupServices();
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700850
Sailesh Nepal664837f2014-07-14 16:31:51 -0700851 Log.v(this, "queryRemoteConnectionServices, services: " + services.size());
852
Sailesh Nepal905dfba2014-07-14 08:20:41 -0700853 for (ConnectionServiceWrapper cs : services) {
854 if (cs != this) {
855 final ConnectionServiceWrapper currentConnectionService = cs;
856 cs.mBinder.bind(new BindCallback() {
Sailesh Nepal905dfba2014-07-14 08:20:41 -0700857 @Override
858 public void onSuccess() {
859 Log.d(this, "Adding ***** %s", currentConnectionService.getComponentName());
860 connectionServices.add(
861 currentConnectionService.mServiceInterface.asBinder());
862 components.add(currentConnectionService.getComponentName());
863 maybeComplete();
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700864 }
Sailesh Nepal905dfba2014-07-14 08:20:41 -0700865
866 @Override
867 public void onFailure() {
Sailesh Nepal905dfba2014-07-14 08:20:41 -0700868 maybeComplete();
869 }
870
871 private void maybeComplete() {
Sailesh Nepal664837f2014-07-14 16:31:51 -0700872 servciesAttempted.add(currentConnectionService);
873 if (servciesAttempted.size() == services.size() - 1) {
Sailesh Nepal905dfba2014-07-14 08:20:41 -0700874 try {
875 callback.onResult(components, connectionServices);
876 } catch (RemoteException ignored) {
877 }
878 }
879 }
880 });
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700881 }
Sailesh Nepal905dfba2014-07-14 08:20:41 -0700882 }
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700883 }
884}