blob: 946ecb0f2087ae324ea1b6b74ed71945d19df01a [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;
Sailesh Nepal664837f2014-07-14 16:31:51 -0700105 if (mPendingResponses.containsKey(request.getCallId())) {
106 mPendingResponses.remove(request.getCallId())
107 .handleCreateConnectionFailed(statusCode, statusMsg);
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700108 mCallIdMapper.removeCall(request.getCallId());
109 } else {
Sailesh Nepal664837f2014-07-14 16:31:51 -0700110 //Log.w(this, "handleCreateConnectionFailed, unknown call: %s", callId);
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700111 }
112 } finally {
113 args.recycle();
114 }
115 break;
116 }
Sailesh Nepal664837f2014-07-14 16:31:51 -0700117 case MSG_HANDLE_CREATE_CONNECTION_CANCELLED: {
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700118 ConnectionRequest request = (ConnectionRequest) msg.obj;
Sailesh Nepal664837f2014-07-14 16:31:51 -0700119 if (mPendingResponses.containsKey(request.getCallId())) {
120 mPendingResponses.remove(
121 request.getCallId()).handleCreateConnectionCancelled();
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700122 } else {
Sailesh Nepal664837f2014-07-14 16:31:51 -0700123 //Log.w(this, "handleCreateConnectionCancelled, unknown call: %s", callId);
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700124 }
125 break;
126 }
127 case MSG_SET_ACTIVE:
128 call = mCallIdMapper.getCall(msg.obj);
129 if (call != null) {
130 mCallsManager.markCallAsActive(call);
131 } else {
132 //Log.w(this, "setActive, unknown call id: %s", msg.obj);
133 }
134 break;
135 case MSG_SET_RINGING:
136 call = mCallIdMapper.getCall(msg.obj);
137 if (call != null) {
138 mCallsManager.markCallAsRinging(call);
139 } else {
140 //Log.w(this, "setRinging, unknown call id: %s", msg.obj);
141 }
142 break;
143 case MSG_SET_DIALING:
144 call = mCallIdMapper.getCall(msg.obj);
145 if (call != null) {
146 mCallsManager.markCallAsDialing(call);
147 } else {
148 //Log.w(this, "setDialing, unknown call id: %s", msg.obj);
149 }
150 break;
151 case MSG_SET_DISCONNECTED: {
152 SomeArgs args = (SomeArgs) msg.obj;
153 try {
154 call = mCallIdMapper.getCall(args.arg1);
155 String disconnectMessage = (String) args.arg2;
156 int disconnectCause = args.argi1;
157 if (call != null) {
158 mCallsManager.markCallAsDisconnected(call, disconnectCause,
159 disconnectMessage);
160 } else {
161 //Log.w(this, "setDisconnected, unknown call id: %s", args.arg1);
162 }
163 } finally {
164 args.recycle();
165 }
166 break;
167 }
168 case MSG_SET_ON_HOLD:
169 call = mCallIdMapper.getCall(msg.obj);
170 if (call != null) {
171 mCallsManager.markCallAsOnHold(call);
172 } else {
173 //Log.w(this, "setOnHold, unknown call id: %s", msg.obj);
174 }
175 break;
176 case MSG_SET_REQUESTING_RINGBACK: {
Sailesh Nepal9d58de52014-07-18 14:53:19 -0700177 call = mCallIdMapper.getCall(msg.obj);
178 if (call != null) {
179 call.setRequestingRingback(msg.arg1 == 1);
180 } else {
181 //Log.w(this, "setRingback, unknown call id: %s", args.arg1);
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700182 }
183 break;
184 }
Sailesh Nepale20bc972014-07-09 21:22:36 -0700185 case MSG_SET_CALL_CAPABILITIES: {
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700186 call = mCallIdMapper.getCall(msg.obj);
187 if (call != null) {
Sailesh Nepale20bc972014-07-09 21:22:36 -0700188 call.setCallCapabilities(msg.arg1);
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700189 } else {
190 //Log.w(ConnectionServiceWrapper.this,
Sailesh Nepale20bc972014-07-09 21:22:36 -0700191 // "setCallCapabilities, unknown call id: %s", msg.obj);
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700192 }
193 break;
194 }
195 case MSG_SET_IS_CONFERENCED: {
196 SomeArgs args = (SomeArgs) msg.obj;
197 try {
198 Call childCall = mCallIdMapper.getCall(args.arg1);
199 if (childCall != null) {
200 String conferenceCallId = (String) args.arg2;
201 if (conferenceCallId == null) {
202 childCall.setParentCall(null);
203 } else {
204 Call conferenceCall = mCallIdMapper.getCall(conferenceCallId);
205 if (conferenceCall != null &&
206 !mPendingConferenceCalls.contains(conferenceCall)) {
207 childCall.setParentCall(conferenceCall);
208 } else {
209 //Log.w(this, "setIsConferenced, unknown conference id %s",
210 // conferenceCallId);
211 }
212 }
213 } else {
214 //Log.w(this, "setIsConferenced, unknown call id: %s", args.arg1);
215 }
216 } finally {
217 args.recycle();
218 }
219 break;
220 }
221 case MSG_ADD_CONFERENCE_CALL: {
222 Call conferenceCall = mCallIdMapper.getCall(msg.obj);
223 if (mPendingConferenceCalls.remove(conferenceCall)) {
224 Log.v(this, "confirming conf call %s", conferenceCall);
225 conferenceCall.confirmConference();
226 } else {
227 //Log.w(this, "addConference, unknown call id: %s", callId);
228 }
229 break;
230 }
231 case MSG_REMOVE_CALL:
232 break;
233 case MSG_ON_POST_DIAL_WAIT: {
234 SomeArgs args = (SomeArgs) msg.obj;
235 try {
236 call = mCallIdMapper.getCall(args.arg1);
237 if (call != null) {
238 String remaining = (String) args.arg2;
239 call.onPostDialWait(remaining);
240 } else {
241 //Log.w(this, "onPostDialWait, unknown call id: %s", args.arg1);
242 }
243 } finally {
244 args.recycle();
245 }
246 break;
247 }
248 case MSG_QUERY_REMOTE_CALL_SERVICES: {
Sailesh Nepal664837f2014-07-14 16:31:51 -0700249 queryRemoteConnectionServices((RemoteServiceCallback) msg.obj);
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700250 break;
251 }
252 case MSG_SET_CALL_VIDEO_PROVIDER: {
253 SomeArgs args = (SomeArgs) msg.obj;
254 try {
255 call = mCallIdMapper.getCall(args.arg1);
256 ICallVideoProvider callVideoProvider = (ICallVideoProvider) args.arg2;
257 if (call != null) {
258 call.setCallVideoProvider(callVideoProvider);
259 }
260 } finally {
261 args.recycle();
262 }
263 break;
264 }
Sailesh Nepal7e669572014-07-08 21:29:12 -0700265 case MSG_SET_AUDIO_MODE_IS_VOIP: {
Sailesh Nepale20bc972014-07-09 21:22:36 -0700266 call = mCallIdMapper.getCall(msg.obj);
267 if (call != null) {
268 call.setAudioModeIsVoip(msg.arg1 == 1);
Sailesh Nepal7e669572014-07-08 21:29:12 -0700269 }
270 break;
271 }
Sailesh Nepal35faf8c2014-07-08 22:02:34 -0700272 case MSG_SET_STATUS_HINTS: {
273 SomeArgs args = (SomeArgs) msg.obj;
274 try {
275 call = mCallIdMapper.getCall(args.arg1);
276 StatusHints statusHints = (StatusHints) args.arg2;
277 if (call != null) {
278 call.setStatusHints(statusHints);
279 }
280 } finally {
281 args.recycle();
282 }
283 break;
284 }
Sailesh Nepale8ecb982014-07-11 17:19:42 -0700285 case MSG_SET_HANDLE: {
286 SomeArgs args = (SomeArgs) msg.obj;
287 try {
288 call = mCallIdMapper.getCall(args.arg1);
289 if (call != null) {
290 call.setHandle((Uri) args.arg2, args.argi1);
291 }
292 } finally {
293 args.recycle();
294 }
295 break;
296 }
297 case MSG_SET_CALLER_DISPLAY_NAME: {
298 SomeArgs args = (SomeArgs) msg.obj;
299 try {
300 call = mCallIdMapper.getCall(args.arg1);
301 if (call != null) {
302 call.setCallerDisplayName((String) args.arg2, args.argi1);
303 }
304 } finally {
305 args.recycle();
306 }
307 break;
308 }
Tyler Gunn0a388fc2014-07-17 12:21:17 -0700309 case MSG_SET_VIDEO_STATE: {
310 call = mCallIdMapper.getCall(msg.obj);
311 if (call != null) {
312 call.setVideoState(msg.arg1);
313 }
Tyler Gunn7e0df312014-07-21 14:34:58 -0700314 break;
Tyler Gunn0a388fc2014-07-17 12:21:17 -0700315 }
Sailesh Nepal9d58de52014-07-18 14:53:19 -0700316 case MSG_START_ACTIVITY_FROM_IN_CALL: {
317 SomeArgs args = (SomeArgs) msg.obj;
318 try {
319 call = mCallIdMapper.getCall(args.arg1);
320 if (call != null) {
321 call.startActivityFromInCall((PendingIntent) args.arg2);
322 }
323 } finally {
324 args.recycle();
325 }
326 break;
327 }
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700328 }
329 }
330 };
331
332 private final class Adapter extends IConnectionServiceAdapter.Stub {
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700333 @Override
Santos Cordon72890ce2014-07-21 01:32:04 -0700334 public void handleCreateConnectionSuccessful(
335 ConnectionRequest request, ParcelableConnection connection) {
336
Sailesh Nepal664837f2014-07-14 16:31:51 -0700337 logIncoming("handleCreateConnectionSuccessful %s", request);
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700338 mCallIdMapper.checkValidCallId(request.getCallId());
Santos Cordon72890ce2014-07-21 01:32:04 -0700339 SomeArgs args = SomeArgs.obtain();
340 args.arg1 = request;
341 args.arg2 = connection;
342 mHandler.obtainMessage(MSG_HANDLE_CREATE_CONNECTION_SUCCESSFUL, args).sendToTarget();
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700343 }
344
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700345 @Override
Sailesh Nepal664837f2014-07-14 16:31:51 -0700346 public void handleCreateConnectionFailed(
347 ConnectionRequest request, int errorCode, String errorMsg) {
348 logIncoming("handleCreateConnectionFailed %s %d %s", request, errorCode, errorMsg);
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700349 mCallIdMapper.checkValidCallId(request.getCallId());
350 SomeArgs args = SomeArgs.obtain();
351 args.arg1 = request;
352 args.argi1 = errorCode;
353 args.arg2 = errorMsg;
Sailesh Nepal664837f2014-07-14 16:31:51 -0700354 mHandler.obtainMessage(MSG_HANDLE_CREATE_CONNECTION_FAILED, args).sendToTarget();
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700355 }
356
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700357 @Override
Sailesh Nepal664837f2014-07-14 16:31:51 -0700358 public void handleCreateConnectionCancelled(ConnectionRequest request) {
359 logIncoming("handleCreateConnectionCancelled %s", request);
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700360 mCallIdMapper.checkValidCallId(request.getCallId());
Sailesh Nepal664837f2014-07-14 16:31:51 -0700361 mHandler.obtainMessage(MSG_HANDLE_CREATE_CONNECTION_CANCELLED, request).sendToTarget();
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700362 }
363
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700364 @Override
365 public void setActive(String callId) {
366 logIncoming("setActive %s", callId);
367 mCallIdMapper.checkValidCallId(callId);
368 mHandler.obtainMessage(MSG_SET_ACTIVE, callId).sendToTarget();
369 }
370
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700371 @Override
372 public void setRinging(String callId) {
373 logIncoming("setRinging %s", callId);
374 mCallIdMapper.checkValidCallId(callId);
375 mHandler.obtainMessage(MSG_SET_RINGING, callId).sendToTarget();
376 }
377
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700378 @Override
379 public void setCallVideoProvider(String callId, ICallVideoProvider callVideoProvider) {
380 logIncoming("setCallVideoProvider %s", callId);
381 mCallIdMapper.checkValidCallId(callId);
382 SomeArgs args = SomeArgs.obtain();
383 args.arg1 = callId;
384 args.arg2 = callVideoProvider;
385 mHandler.obtainMessage(MSG_SET_CALL_VIDEO_PROVIDER, args).sendToTarget();
386 }
387
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700388 @Override
389 public void setDialing(String callId) {
390 logIncoming("setDialing %s", callId);
391 mCallIdMapper.checkValidCallId(callId);
392 mHandler.obtainMessage(MSG_SET_DIALING, callId).sendToTarget();
393 }
394
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700395 @Override
396 public void setDisconnected(
397 String callId, int disconnectCause, String disconnectMessage) {
398 logIncoming("setDisconnected %s %d %s", callId, disconnectCause, disconnectMessage);
399 mCallIdMapper.checkValidCallId(callId);
400 SomeArgs args = SomeArgs.obtain();
401 args.arg1 = callId;
402 args.arg2 = disconnectMessage;
403 args.argi1 = disconnectCause;
404 mHandler.obtainMessage(MSG_SET_DISCONNECTED, args).sendToTarget();
405 }
406
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700407 @Override
408 public void setOnHold(String callId) {
409 logIncoming("setOnHold %s", callId);
410 mCallIdMapper.checkValidCallId(callId);
411 mHandler.obtainMessage(MSG_SET_ON_HOLD, callId).sendToTarget();
412 }
413
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700414 @Override
415 public void setRequestingRingback(String callId, boolean ringback) {
416 logIncoming("setRequestingRingback %s %b", callId, ringback);
417 mCallIdMapper.checkValidCallId(callId);
Sailesh Nepal9d58de52014-07-18 14:53:19 -0700418 mHandler.obtainMessage(MSG_SET_REQUESTING_RINGBACK, ringback ? 1 : 0, 0, callId)
419 .sendToTarget();
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700420 }
421
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700422 @Override
423 public void removeCall(String callId) {
424 logIncoming("removeCall %s", callId);
425 }
426
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700427 @Override
Sailesh Nepale20bc972014-07-09 21:22:36 -0700428 public void setCallCapabilities(String callId, int callCapabilities) {
429 logIncoming("setCallCapabilities %s %d", callId, callCapabilities);
430 mHandler.obtainMessage(MSG_SET_CALL_CAPABILITIES, callCapabilities, 0, callId)
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700431 .sendToTarget();
432 }
433
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700434 @Override
435 public void setIsConferenced(String callId, String conferenceCallId) {
436 logIncoming("setIsConferenced %s %s", callId, conferenceCallId);
437 SomeArgs args = SomeArgs.obtain();
438 args.arg1 = callId;
439 args.arg2 = conferenceCallId;
440 mHandler.obtainMessage(MSG_SET_IS_CONFERENCED, args).sendToTarget();
441 }
442
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700443 @Override
444 public void addConferenceCall(String callId) {
445 logIncoming("addConferenceCall %s", callId);
446 mCallIdMapper.checkValidCallId(callId);
447 mHandler.obtainMessage(MSG_ADD_CONFERENCE_CALL, callId).sendToTarget();
448 }
449
450 @Override
451 public void onPostDialWait(String callId, String remaining) throws RemoteException {
452 logIncoming("onPostDialWait %s %s", callId, remaining);
453 mCallIdMapper.checkValidCallId(callId);
454 SomeArgs args = SomeArgs.obtain();
455 args.arg1 = callId;
456 args.arg2 = remaining;
457 mHandler.obtainMessage(MSG_ON_POST_DIAL_WAIT, args).sendToTarget();
458 }
459
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700460 @Override
461 public void queryRemoteConnectionServices(RemoteServiceCallback callback) {
462 logIncoming("queryRemoteCSs");
463 mHandler.obtainMessage(MSG_QUERY_REMOTE_CALL_SERVICES, callback).sendToTarget();
464 }
465
466 @Override
Tyler Gunn0a388fc2014-07-17 12:21:17 -0700467 public void setVideoState(String callId, int videoState) {
468 logIncoming("setVideoState %s %d", callId, videoState);
469 mCallIdMapper.checkValidCallId(callId);
470 mHandler.obtainMessage(MSG_SET_VIDEO_STATE, videoState, 0, callId).sendToTarget();
471 }
472
473 @Override
Sailesh Nepal7e669572014-07-08 21:29:12 -0700474 public void setAudioModeIsVoip(String callId, boolean isVoip) {
Sailesh Nepal7fa33ca2014-07-10 15:28:21 -0700475 logIncoming("setAudioModeIsVoip %s %b", callId, isVoip);
Sailesh Nepal7e669572014-07-08 21:29:12 -0700476 mCallIdMapper.checkValidCallId(callId);
Sailesh Nepale20bc972014-07-09 21:22:36 -0700477 mHandler.obtainMessage(MSG_SET_AUDIO_MODE_IS_VOIP, isVoip ? 1 : 0, 0,
478 callId).sendToTarget();
Sailesh Nepal7e669572014-07-08 21:29:12 -0700479 }
Sailesh Nepal35faf8c2014-07-08 22:02:34 -0700480
481 @Override
482 public void setStatusHints(String callId, StatusHints statusHints) {
483 logIncoming("setStatusHints %s %s", callId, statusHints);
484 mCallIdMapper.checkValidCallId(callId);
485 SomeArgs args = SomeArgs.obtain();
486 args.arg1 = callId;
487 args.arg2 = statusHints;
488 mHandler.obtainMessage(MSG_SET_STATUS_HINTS, args).sendToTarget();
489 }
Sailesh Nepale8ecb982014-07-11 17:19:42 -0700490
491 @Override
492 public void setHandle(String callId, Uri handle, int presentation) {
493 logIncoming("setHandle %s %s %d", callId, handle, presentation);
494 mCallIdMapper.checkValidCallId(callId);
495 SomeArgs args = SomeArgs.obtain();
496 args.arg1 = callId;
497 args.arg2 = handle;
498 args.argi1 = presentation;
499 mHandler.obtainMessage(MSG_SET_HANDLE, args).sendToTarget();
500 }
501
502 @Override
503 public void setCallerDisplayName(
504 String callId, String callerDisplayName, int presentation) {
505 logIncoming("setCallerDisplayName %s %s %d", callId, callerDisplayName, presentation);
506 mCallIdMapper.checkValidCallId(callId);
507 SomeArgs args = SomeArgs.obtain();
508 args.arg1 = callId;
509 args.arg2 = callerDisplayName;
510 args.argi1 = presentation;
511 mHandler.obtainMessage(MSG_SET_CALLER_DISPLAY_NAME, args).sendToTarget();
512 }
Sailesh Nepal9d58de52014-07-18 14:53:19 -0700513
514 @Override
515 public void startActivityFromInCall(String callId, PendingIntent intent) {
516 logIncoming("startActivityFromInCall %s %s", callId, intent);
517 mCallIdMapper.checkValidCallId(callId);
518 SomeArgs args = SomeArgs.obtain();
519 args.arg1 = callId;
520 args.arg2 = intent;
521 mHandler.obtainMessage(MSG_START_ACTIVITY_FROM_IN_CALL, args).sendToTarget();
522 }
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700523 }
524
525 private final Adapter mAdapter = new Adapter();
526 private final CallsManager mCallsManager = CallsManager.getInstance();
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700527 private final Set<Call> mPendingConferenceCalls = new HashSet<>();
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700528 private final CallIdMapper mCallIdMapper = new CallIdMapper("ConnectionService");
Sailesh Nepal664837f2014-07-14 16:31:51 -0700529 private final Map<String, CreateConnectionResponse> mPendingResponses = new HashMap<>();
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700530
531 private Binder mBinder = new Binder();
532 private IConnectionService mServiceInterface;
Sailesh Nepal905dfba2014-07-14 08:20:41 -0700533 private final ConnectionServiceRepository mConnectionServiceRepository;
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700534
535 /**
Sailesh Nepal905dfba2014-07-14 08:20:41 -0700536 * Creates a connection service.
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700537 *
Sailesh Nepal905dfba2014-07-14 08:20:41 -0700538 * @param componentName The component name of the service with which to bind.
Sailesh Nepal905dfba2014-07-14 08:20:41 -0700539 * @param connectionServiceRepository Connection service repository.
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700540 */
541 ConnectionServiceWrapper(
Sailesh Nepal664837f2014-07-14 16:31:51 -0700542 ComponentName componentName, ConnectionServiceRepository connectionServiceRepository) {
Santos Cordonf2f14ef2014-07-20 18:00:20 -0700543 super(ConnectionService.SERVICE_INTERFACE, componentName);
Sailesh Nepal905dfba2014-07-14 08:20:41 -0700544 mConnectionServiceRepository = connectionServiceRepository;
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700545 }
546
547 /** See {@link IConnectionService#addConnectionServiceAdapter}. */
548 private void addConnectionServiceAdapter(IConnectionServiceAdapter adapter) {
549 if (isServiceValid("addConnectionServiceAdapter")) {
550 try {
Sailesh Nepal3fe8b722014-07-08 10:07:26 -0700551 logOutgoing("addConnectionServiceAdapter %s", adapter);
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700552 mServiceInterface.addConnectionServiceAdapter(adapter);
553 } catch (RemoteException e) {
554 }
555 }
556 }
557
558 /**
Sailesh Nepal664837f2014-07-14 16:31:51 -0700559 * Creates a new connection for a new outgoing call or to attach to an existing incoming call.
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700560 */
Sailesh Nepal664837f2014-07-14 16:31:51 -0700561 void createConnection(final Call call, final CreateConnectionResponse response) {
562 Log.d(this, "createConnection(%s) via %s.", call, getComponentName());
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700563 BindCallback callback = new BindCallback() {
564 @Override
565 public void onSuccess() {
566 String callId = mCallIdMapper.getCallId(call);
Sailesh Nepal664837f2014-07-14 16:31:51 -0700567 mPendingResponses.put(callId, response);
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700568
569 GatewayInfo gatewayInfo = call.getGatewayInfo();
570 Bundle extras = call.getExtras();
571 if (gatewayInfo != null && gatewayInfo.getGatewayProviderPackageName() != null &&
572 gatewayInfo.getOriginalHandle() != null) {
573 extras = (Bundle) extras.clone();
574 extras.putString(
575 NewOutgoingCallIntentBroadcaster.EXTRA_GATEWAY_PROVIDER_PACKAGE,
576 gatewayInfo.getGatewayProviderPackageName());
577 extras.putParcelable(
578 NewOutgoingCallIntentBroadcaster.EXTRA_GATEWAY_ORIGINAL_URI,
579 gatewayInfo.getOriginalHandle());
580 }
Sailesh Nepale8ecb982014-07-11 17:19:42 -0700581 ConnectionRequest request = new ConnectionRequest(
582 call.getPhoneAccount(),
583 callId,
584 call.getHandle(),
585 call.getHandlePresentation(),
586 extras,
Tyler Gunnc4abd912014-07-08 14:22:10 -0700587 call.getVideoState());
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700588
589 try {
Sailesh Nepal664837f2014-07-14 16:31:51 -0700590 mServiceInterface.createConnection(request, call.isIncoming());
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700591 } catch (RemoteException e) {
Sailesh Nepal664837f2014-07-14 16:31:51 -0700592 Log.e(this, e, "Failure to createConnection -- %s", getComponentName());
593 mPendingResponses.remove(callId).handleCreateConnectionFailed(
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700594 DisconnectCause.ERROR_UNSPECIFIED, e.toString());
595 }
596 }
597
598 @Override
599 public void onFailure() {
Sailesh Nepal905dfba2014-07-14 08:20:41 -0700600 Log.e(this, new Exception(), "Failure to call %s", getComponentName());
Sailesh Nepal664837f2014-07-14 16:31:51 -0700601 response.handleCreateConnectionFailed(DisconnectCause.ERROR_UNSPECIFIED, null);
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700602 }
603 };
604
605 mBinder.bind(callback);
606 }
607
608 /** @see ConnectionService#abort(String) */
609 void abort(Call call) {
610 // Clear out any pending outgoing call data
611 String callId = mCallIdMapper.getCallId(call);
612
613 // If still bound, tell the connection service to abort.
614 if (isServiceValid("abort")) {
615 try {
616 logOutgoing("abort %s", callId);
617 mServiceInterface.abort(callId);
618 } catch (RemoteException e) {
619 }
620 }
621
622 removeCall(call);
623 }
624
625 /** @see ConnectionService#hold(String) */
626 void hold(Call call) {
627 if (isServiceValid("hold")) {
628 try {
629 logOutgoing("hold %s", mCallIdMapper.getCallId(call));
630 mServiceInterface.hold(mCallIdMapper.getCallId(call));
631 } catch (RemoteException e) {
632 }
633 }
634 }
635
636 /** @see ConnectionService#unhold(String) */
637 void unhold(Call call) {
638 if (isServiceValid("unhold")) {
639 try {
640 logOutgoing("unhold %s", mCallIdMapper.getCallId(call));
641 mServiceInterface.unhold(mCallIdMapper.getCallId(call));
642 } catch (RemoteException e) {
643 }
644 }
645 }
646
647 /** @see ConnectionService#onAudioStateChanged(String,CallAudioState) */
648 void onAudioStateChanged(Call activeCall, CallAudioState audioState) {
649 if (isServiceValid("onAudioStateChanged")) {
650 try {
651 logOutgoing("onAudioStateChanged %s %s",
652 mCallIdMapper.getCallId(activeCall), audioState);
653 mServiceInterface.onAudioStateChanged(mCallIdMapper.getCallId(activeCall),
654 audioState);
655 } catch (RemoteException e) {
656 }
657 }
658 }
659
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700660 /** @see ConnectionService#disconnect(String) */
661 void disconnect(Call call) {
662 if (isServiceValid("disconnect")) {
663 try {
664 logOutgoing("disconnect %s", mCallIdMapper.getCallId(call));
665 mServiceInterface.disconnect(mCallIdMapper.getCallId(call));
666 } catch (RemoteException e) {
667 }
668 }
669 }
670
671 /** @see ConnectionService#answer(String) */
Andrew Lee38931d02014-07-16 10:17:36 -0700672 void answer(Call call, int videoState) {
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700673 if (isServiceValid("answer")) {
674 try {
Andrew Lee38931d02014-07-16 10:17:36 -0700675 logOutgoing("answer %s %d", mCallIdMapper.getCallId(call), videoState);
676 mServiceInterface.answer(mCallIdMapper.getCallId(call), videoState);
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700677 } catch (RemoteException e) {
678 }
679 }
680 }
681
682 /** @see ConnectionService#reject(String) */
683 void reject(Call call) {
684 if (isServiceValid("reject")) {
685 try {
686 logOutgoing("reject %s", mCallIdMapper.getCallId(call));
687 mServiceInterface.reject(mCallIdMapper.getCallId(call));
688 } catch (RemoteException e) {
689 }
690 }
691 }
692
693 /** @see ConnectionService#playDtmfTone(String,char) */
694 void playDtmfTone(Call call, char digit) {
695 if (isServiceValid("playDtmfTone")) {
696 try {
697 logOutgoing("playDtmfTone %s %c", mCallIdMapper.getCallId(call), digit);
698 mServiceInterface.playDtmfTone(mCallIdMapper.getCallId(call), digit);
699 } catch (RemoteException e) {
700 }
701 }
702 }
703
704 /** @see ConnectionService#stopDtmfTone(String) */
705 void stopDtmfTone(Call call) {
706 if (isServiceValid("stopDtmfTone")) {
707 try {
708 logOutgoing("stopDtmfTone %s", mCallIdMapper.getCallId(call));
709 mServiceInterface.stopDtmfTone(mCallIdMapper.getCallId(call));
710 } catch (RemoteException e) {
711 }
712 }
713 }
714
715 void addCall(Call call) {
716 if (mCallIdMapper.getCallId(call) == null) {
717 mCallIdMapper.addCall(call);
718 }
719 }
720
721 /**
722 * Associates newCall with this connection service by replacing callToReplace.
723 */
724 void replaceCall(Call newCall, Call callToReplace) {
725 Preconditions.checkState(callToReplace.getConnectionService() == this);
726 mCallIdMapper.replaceCall(newCall, callToReplace);
727 }
728
729 void removeCall(Call call) {
Sailesh Nepal664837f2014-07-14 16:31:51 -0700730 CreateConnectionResponse response = mPendingResponses.remove(mCallIdMapper.getCallId(call));
731 if (response != null) {
732 response.handleCreateConnectionFailed(DisconnectCause.ERROR_UNSPECIFIED, null);
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700733 }
734
735 mCallIdMapper.removeCall(call);
736 }
737
738 void onPostDialContinue(Call call, boolean proceed) {
739 if (isServiceValid("onPostDialContinue")) {
740 try {
741 logOutgoing("onPostDialContinue %s %b", mCallIdMapper.getCallId(call), proceed);
742 mServiceInterface.onPostDialContinue(mCallIdMapper.getCallId(call), proceed);
743 } catch (RemoteException ignored) {
744 }
745 }
746 }
747
748 void onPhoneAccountClicked(Call call) {
749 if (isServiceValid("onPhoneAccountClicked")) {
750 try {
751 logOutgoing("onPhoneAccountClicked %s", mCallIdMapper.getCallId(call));
752 mServiceInterface.onPhoneAccountClicked(mCallIdMapper.getCallId(call));
753 } catch (RemoteException ignored) {
754 }
755 }
756 }
757
758 void conference(final Call conferenceCall, Call call) {
759 if (isServiceValid("conference")) {
760 try {
761 conferenceCall.setConnectionService(this);
762 mPendingConferenceCalls.add(conferenceCall);
763 mHandler.postDelayed(new Runnable() {
764 @Override public void run() {
765 if (mPendingConferenceCalls.remove(conferenceCall)) {
766 conferenceCall.expireConference();
767 Log.i(this, "Conference call expired: %s", conferenceCall);
768 }
769 }
770 }, Timeouts.getConferenceCallExpireMillis());
771
772 logOutgoing("conference %s %s",
773 mCallIdMapper.getCallId(conferenceCall),
774 mCallIdMapper.getCallId(call));
775 mServiceInterface.conference(
776 mCallIdMapper.getCallId(conferenceCall),
777 mCallIdMapper.getCallId(call));
778 } catch (RemoteException ignored) {
779 }
780 }
781 }
782
783 void splitFromConference(Call call) {
784 if (isServiceValid("splitFromConference")) {
785 try {
786 logOutgoing("splitFromConference %s", mCallIdMapper.getCallId(call));
787 mServiceInterface.splitFromConference(mCallIdMapper.getCallId(call));
788 } catch (RemoteException ignored) {
789 }
790 }
791 }
792
Sailesh Nepale8ecb982014-07-11 17:19:42 -0700793 void swapWithBackgroundCall(Call call) {
794 if (isServiceValid("swapWithBackgroundCall")) {
795 try {
796 logOutgoing("swapWithBackgroundCall %s", mCallIdMapper.getCallId(call));
797 mServiceInterface.swapWithBackgroundCall(mCallIdMapper.getCallId(call));
798 } catch (RemoteException ignored) {
799 }
800 }
801 }
802
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700803 /** {@inheritDoc} */
804 @Override
805 protected void setServiceInterface(IBinder binder) {
806 if (binder == null) {
807 // We have lost our service connection. Notify the world that this service is done.
808 // We must notify the adapter before CallsManager. The adapter will force any pending
809 // outgoing calls to try the next service. This needs to happen before CallsManager
810 // tries to clean up any calls still associated with this service.
811 handleConnectionServiceDeath();
812 CallsManager.getInstance().handleConnectionServiceDeath(this);
813 mServiceInterface = null;
814 } else {
815 mServiceInterface = IConnectionService.Stub.asInterface(binder);
816 addConnectionServiceAdapter(mAdapter);
817 }
818 }
819
820 /**
821 * Called when the associated connection service dies.
822 */
823 private void handleConnectionServiceDeath() {
Sailesh Nepal664837f2014-07-14 16:31:51 -0700824 if (!mPendingResponses.isEmpty()) {
825 CreateConnectionResponse[] responses = mPendingResponses.values().toArray(
826 new CreateConnectionResponse[mPendingResponses.values().size()]);
827 mPendingResponses.clear();
828 for (int i = 0; i < responses.length; i++) {
829 responses[i].handleCreateConnectionFailed(DisconnectCause.ERROR_UNSPECIFIED, null);
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700830 }
831 }
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700832 mCallIdMapper.clear();
833 }
834
835 private void logIncoming(String msg, Object... params) {
836 Log.d(this, "ConnectionService -> Telecomm: " + msg, params);
837 }
838
839 private void logOutgoing(String msg, Object... params) {
840 Log.d(this, "Telecomm -> ConnectionService: " + msg, params);
841 }
842
843 private void queryRemoteConnectionServices(final RemoteServiceCallback callback) {
844 final List<IBinder> connectionServices = new ArrayList<>();
845 final List<ComponentName> components = new ArrayList<>();
Sailesh Nepal664837f2014-07-14 16:31:51 -0700846 final List<ConnectionServiceWrapper> servciesAttempted = new ArrayList<>();
Sailesh Nepal905dfba2014-07-14 08:20:41 -0700847 final Collection<ConnectionServiceWrapper> services =
848 mConnectionServiceRepository.lookupServices();
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700849
Sailesh Nepal664837f2014-07-14 16:31:51 -0700850 Log.v(this, "queryRemoteConnectionServices, services: " + services.size());
851
Sailesh Nepal905dfba2014-07-14 08:20:41 -0700852 for (ConnectionServiceWrapper cs : services) {
853 if (cs != this) {
854 final ConnectionServiceWrapper currentConnectionService = cs;
855 cs.mBinder.bind(new BindCallback() {
Sailesh Nepal905dfba2014-07-14 08:20:41 -0700856 @Override
857 public void onSuccess() {
858 Log.d(this, "Adding ***** %s", currentConnectionService.getComponentName());
859 connectionServices.add(
860 currentConnectionService.mServiceInterface.asBinder());
861 components.add(currentConnectionService.getComponentName());
862 maybeComplete();
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700863 }
Sailesh Nepal905dfba2014-07-14 08:20:41 -0700864
865 @Override
866 public void onFailure() {
Sailesh Nepal905dfba2014-07-14 08:20:41 -0700867 maybeComplete();
868 }
869
870 private void maybeComplete() {
Sailesh Nepal664837f2014-07-14 16:31:51 -0700871 servciesAttempted.add(currentConnectionService);
872 if (servciesAttempted.size() == services.size() - 1) {
Sailesh Nepal905dfba2014-07-14 08:20:41 -0700873 try {
874 callback.onResult(components, connectionServices);
875 } catch (RemoteException ignored) {
876 }
877 }
878 }
879 });
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700880 }
Sailesh Nepal905dfba2014-07-14 08:20:41 -0700881 }
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700882 }
883}