blob: eca7e097f184debe55bbcc2542e824cd5cd2d833 [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 }
314 }
Sailesh Nepal9d58de52014-07-18 14:53:19 -0700315 case MSG_START_ACTIVITY_FROM_IN_CALL: {
316 SomeArgs args = (SomeArgs) msg.obj;
317 try {
318 call = mCallIdMapper.getCall(args.arg1);
319 if (call != null) {
320 call.startActivityFromInCall((PendingIntent) args.arg2);
321 }
322 } finally {
323 args.recycle();
324 }
325 break;
326 }
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700327 }
328 }
329 };
330
331 private final class Adapter extends IConnectionServiceAdapter.Stub {
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700332 @Override
Santos Cordon72890ce2014-07-21 01:32:04 -0700333 public void handleCreateConnectionSuccessful(
334 ConnectionRequest request, ParcelableConnection connection) {
335
Sailesh Nepal664837f2014-07-14 16:31:51 -0700336 logIncoming("handleCreateConnectionSuccessful %s", request);
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700337 mCallIdMapper.checkValidCallId(request.getCallId());
Santos Cordon72890ce2014-07-21 01:32:04 -0700338 SomeArgs args = SomeArgs.obtain();
339 args.arg1 = request;
340 args.arg2 = connection;
341 mHandler.obtainMessage(MSG_HANDLE_CREATE_CONNECTION_SUCCESSFUL, args).sendToTarget();
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700342 }
343
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700344 @Override
Sailesh Nepal664837f2014-07-14 16:31:51 -0700345 public void handleCreateConnectionFailed(
346 ConnectionRequest request, int errorCode, String errorMsg) {
347 logIncoming("handleCreateConnectionFailed %s %d %s", request, errorCode, errorMsg);
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700348 mCallIdMapper.checkValidCallId(request.getCallId());
349 SomeArgs args = SomeArgs.obtain();
350 args.arg1 = request;
351 args.argi1 = errorCode;
352 args.arg2 = errorMsg;
Sailesh Nepal664837f2014-07-14 16:31:51 -0700353 mHandler.obtainMessage(MSG_HANDLE_CREATE_CONNECTION_FAILED, args).sendToTarget();
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700354 }
355
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700356 @Override
Sailesh Nepal664837f2014-07-14 16:31:51 -0700357 public void handleCreateConnectionCancelled(ConnectionRequest request) {
358 logIncoming("handleCreateConnectionCancelled %s", request);
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700359 mCallIdMapper.checkValidCallId(request.getCallId());
Sailesh Nepal664837f2014-07-14 16:31:51 -0700360 mHandler.obtainMessage(MSG_HANDLE_CREATE_CONNECTION_CANCELLED, request).sendToTarget();
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700361 }
362
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700363 @Override
364 public void setActive(String callId) {
365 logIncoming("setActive %s", callId);
366 mCallIdMapper.checkValidCallId(callId);
367 mHandler.obtainMessage(MSG_SET_ACTIVE, callId).sendToTarget();
368 }
369
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700370 @Override
371 public void setRinging(String callId) {
372 logIncoming("setRinging %s", callId);
373 mCallIdMapper.checkValidCallId(callId);
374 mHandler.obtainMessage(MSG_SET_RINGING, callId).sendToTarget();
375 }
376
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700377 @Override
378 public void setCallVideoProvider(String callId, ICallVideoProvider callVideoProvider) {
379 logIncoming("setCallVideoProvider %s", callId);
380 mCallIdMapper.checkValidCallId(callId);
381 SomeArgs args = SomeArgs.obtain();
382 args.arg1 = callId;
383 args.arg2 = callVideoProvider;
384 mHandler.obtainMessage(MSG_SET_CALL_VIDEO_PROVIDER, args).sendToTarget();
385 }
386
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700387 @Override
388 public void setDialing(String callId) {
389 logIncoming("setDialing %s", callId);
390 mCallIdMapper.checkValidCallId(callId);
391 mHandler.obtainMessage(MSG_SET_DIALING, callId).sendToTarget();
392 }
393
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700394 @Override
395 public void setDisconnected(
396 String callId, int disconnectCause, String disconnectMessage) {
397 logIncoming("setDisconnected %s %d %s", callId, disconnectCause, disconnectMessage);
398 mCallIdMapper.checkValidCallId(callId);
399 SomeArgs args = SomeArgs.obtain();
400 args.arg1 = callId;
401 args.arg2 = disconnectMessage;
402 args.argi1 = disconnectCause;
403 mHandler.obtainMessage(MSG_SET_DISCONNECTED, args).sendToTarget();
404 }
405
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700406 @Override
407 public void setOnHold(String callId) {
408 logIncoming("setOnHold %s", callId);
409 mCallIdMapper.checkValidCallId(callId);
410 mHandler.obtainMessage(MSG_SET_ON_HOLD, callId).sendToTarget();
411 }
412
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700413 @Override
414 public void setRequestingRingback(String callId, boolean ringback) {
415 logIncoming("setRequestingRingback %s %b", callId, ringback);
416 mCallIdMapper.checkValidCallId(callId);
Sailesh Nepal9d58de52014-07-18 14:53:19 -0700417 mHandler.obtainMessage(MSG_SET_REQUESTING_RINGBACK, ringback ? 1 : 0, 0, callId)
418 .sendToTarget();
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700419 }
420
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700421 @Override
422 public void removeCall(String callId) {
423 logIncoming("removeCall %s", callId);
424 }
425
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700426 @Override
Sailesh Nepale20bc972014-07-09 21:22:36 -0700427 public void setCallCapabilities(String callId, int callCapabilities) {
428 logIncoming("setCallCapabilities %s %d", callId, callCapabilities);
429 mHandler.obtainMessage(MSG_SET_CALL_CAPABILITIES, callCapabilities, 0, callId)
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700430 .sendToTarget();
431 }
432
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700433 @Override
434 public void setIsConferenced(String callId, String conferenceCallId) {
435 logIncoming("setIsConferenced %s %s", callId, conferenceCallId);
436 SomeArgs args = SomeArgs.obtain();
437 args.arg1 = callId;
438 args.arg2 = conferenceCallId;
439 mHandler.obtainMessage(MSG_SET_IS_CONFERENCED, args).sendToTarget();
440 }
441
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700442 @Override
443 public void addConferenceCall(String callId) {
444 logIncoming("addConferenceCall %s", callId);
445 mCallIdMapper.checkValidCallId(callId);
446 mHandler.obtainMessage(MSG_ADD_CONFERENCE_CALL, callId).sendToTarget();
447 }
448
449 @Override
450 public void onPostDialWait(String callId, String remaining) throws RemoteException {
451 logIncoming("onPostDialWait %s %s", callId, remaining);
452 mCallIdMapper.checkValidCallId(callId);
453 SomeArgs args = SomeArgs.obtain();
454 args.arg1 = callId;
455 args.arg2 = remaining;
456 mHandler.obtainMessage(MSG_ON_POST_DIAL_WAIT, args).sendToTarget();
457 }
458
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700459 @Override
460 public void queryRemoteConnectionServices(RemoteServiceCallback callback) {
461 logIncoming("queryRemoteCSs");
462 mHandler.obtainMessage(MSG_QUERY_REMOTE_CALL_SERVICES, callback).sendToTarget();
463 }
464
465 @Override
Tyler Gunn0a388fc2014-07-17 12:21:17 -0700466 public void setVideoState(String callId, int videoState) {
467 logIncoming("setVideoState %s %d", callId, videoState);
468 mCallIdMapper.checkValidCallId(callId);
469 mHandler.obtainMessage(MSG_SET_VIDEO_STATE, videoState, 0, callId).sendToTarget();
470 }
471
472 @Override
Sailesh Nepal7e669572014-07-08 21:29:12 -0700473 public void setAudioModeIsVoip(String callId, boolean isVoip) {
Sailesh Nepal7fa33ca2014-07-10 15:28:21 -0700474 logIncoming("setAudioModeIsVoip %s %b", callId, isVoip);
Sailesh Nepal7e669572014-07-08 21:29:12 -0700475 mCallIdMapper.checkValidCallId(callId);
Sailesh Nepale20bc972014-07-09 21:22:36 -0700476 mHandler.obtainMessage(MSG_SET_AUDIO_MODE_IS_VOIP, isVoip ? 1 : 0, 0,
477 callId).sendToTarget();
Sailesh Nepal7e669572014-07-08 21:29:12 -0700478 }
Sailesh Nepal35faf8c2014-07-08 22:02:34 -0700479
480 @Override
481 public void setStatusHints(String callId, StatusHints statusHints) {
482 logIncoming("setStatusHints %s %s", callId, statusHints);
483 mCallIdMapper.checkValidCallId(callId);
484 SomeArgs args = SomeArgs.obtain();
485 args.arg1 = callId;
486 args.arg2 = statusHints;
487 mHandler.obtainMessage(MSG_SET_STATUS_HINTS, args).sendToTarget();
488 }
Sailesh Nepale8ecb982014-07-11 17:19:42 -0700489
490 @Override
491 public void setHandle(String callId, Uri handle, int presentation) {
492 logIncoming("setHandle %s %s %d", callId, handle, presentation);
493 mCallIdMapper.checkValidCallId(callId);
494 SomeArgs args = SomeArgs.obtain();
495 args.arg1 = callId;
496 args.arg2 = handle;
497 args.argi1 = presentation;
498 mHandler.obtainMessage(MSG_SET_HANDLE, args).sendToTarget();
499 }
500
501 @Override
502 public void setCallerDisplayName(
503 String callId, String callerDisplayName, int presentation) {
504 logIncoming("setCallerDisplayName %s %s %d", callId, callerDisplayName, presentation);
505 mCallIdMapper.checkValidCallId(callId);
506 SomeArgs args = SomeArgs.obtain();
507 args.arg1 = callId;
508 args.arg2 = callerDisplayName;
509 args.argi1 = presentation;
510 mHandler.obtainMessage(MSG_SET_CALLER_DISPLAY_NAME, args).sendToTarget();
511 }
Sailesh Nepal9d58de52014-07-18 14:53:19 -0700512
513 @Override
514 public void startActivityFromInCall(String callId, PendingIntent intent) {
515 logIncoming("startActivityFromInCall %s %s", callId, intent);
516 mCallIdMapper.checkValidCallId(callId);
517 SomeArgs args = SomeArgs.obtain();
518 args.arg1 = callId;
519 args.arg2 = intent;
520 mHandler.obtainMessage(MSG_START_ACTIVITY_FROM_IN_CALL, args).sendToTarget();
521 }
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700522 }
523
524 private final Adapter mAdapter = new Adapter();
525 private final CallsManager mCallsManager = CallsManager.getInstance();
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700526 private final Set<Call> mPendingConferenceCalls = new HashSet<>();
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700527 private final CallIdMapper mCallIdMapper = new CallIdMapper("ConnectionService");
Sailesh Nepal664837f2014-07-14 16:31:51 -0700528 private final Map<String, CreateConnectionResponse> mPendingResponses = new HashMap<>();
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700529
530 private Binder mBinder = new Binder();
531 private IConnectionService mServiceInterface;
Sailesh Nepal905dfba2014-07-14 08:20:41 -0700532 private final ConnectionServiceRepository mConnectionServiceRepository;
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700533
534 /**
Sailesh Nepal905dfba2014-07-14 08:20:41 -0700535 * Creates a connection service.
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700536 *
Sailesh Nepal905dfba2014-07-14 08:20:41 -0700537 * @param componentName The component name of the service with which to bind.
Sailesh Nepal905dfba2014-07-14 08:20:41 -0700538 * @param connectionServiceRepository Connection service repository.
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700539 */
540 ConnectionServiceWrapper(
Sailesh Nepal664837f2014-07-14 16:31:51 -0700541 ComponentName componentName, ConnectionServiceRepository connectionServiceRepository) {
Santos Cordonf2f14ef2014-07-20 18:00:20 -0700542 super(ConnectionService.SERVICE_INTERFACE, componentName);
Sailesh Nepal905dfba2014-07-14 08:20:41 -0700543 mConnectionServiceRepository = connectionServiceRepository;
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700544 }
545
546 /** See {@link IConnectionService#addConnectionServiceAdapter}. */
547 private void addConnectionServiceAdapter(IConnectionServiceAdapter adapter) {
548 if (isServiceValid("addConnectionServiceAdapter")) {
549 try {
Sailesh Nepal3fe8b722014-07-08 10:07:26 -0700550 logOutgoing("addConnectionServiceAdapter %s", adapter);
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700551 mServiceInterface.addConnectionServiceAdapter(adapter);
552 } catch (RemoteException e) {
553 }
554 }
555 }
556
557 /**
Sailesh Nepal664837f2014-07-14 16:31:51 -0700558 * Creates a new connection for a new outgoing call or to attach to an existing incoming call.
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700559 */
Sailesh Nepal664837f2014-07-14 16:31:51 -0700560 void createConnection(final Call call, final CreateConnectionResponse response) {
561 Log.d(this, "createConnection(%s) via %s.", call, getComponentName());
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700562 BindCallback callback = new BindCallback() {
563 @Override
564 public void onSuccess() {
565 String callId = mCallIdMapper.getCallId(call);
Sailesh Nepal664837f2014-07-14 16:31:51 -0700566 mPendingResponses.put(callId, response);
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700567
568 GatewayInfo gatewayInfo = call.getGatewayInfo();
569 Bundle extras = call.getExtras();
570 if (gatewayInfo != null && gatewayInfo.getGatewayProviderPackageName() != null &&
571 gatewayInfo.getOriginalHandle() != null) {
572 extras = (Bundle) extras.clone();
573 extras.putString(
574 NewOutgoingCallIntentBroadcaster.EXTRA_GATEWAY_PROVIDER_PACKAGE,
575 gatewayInfo.getGatewayProviderPackageName());
576 extras.putParcelable(
577 NewOutgoingCallIntentBroadcaster.EXTRA_GATEWAY_ORIGINAL_URI,
578 gatewayInfo.getOriginalHandle());
579 }
Sailesh Nepale8ecb982014-07-11 17:19:42 -0700580 ConnectionRequest request = new ConnectionRequest(
581 call.getPhoneAccount(),
582 callId,
583 call.getHandle(),
584 call.getHandlePresentation(),
585 extras,
Tyler Gunnc4abd912014-07-08 14:22:10 -0700586 call.getVideoState());
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700587
588 try {
Sailesh Nepal664837f2014-07-14 16:31:51 -0700589 mServiceInterface.createConnection(request, call.isIncoming());
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700590 } catch (RemoteException e) {
Sailesh Nepal664837f2014-07-14 16:31:51 -0700591 Log.e(this, e, "Failure to createConnection -- %s", getComponentName());
592 mPendingResponses.remove(callId).handleCreateConnectionFailed(
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700593 DisconnectCause.ERROR_UNSPECIFIED, e.toString());
594 }
595 }
596
597 @Override
598 public void onFailure() {
Sailesh Nepal905dfba2014-07-14 08:20:41 -0700599 Log.e(this, new Exception(), "Failure to call %s", getComponentName());
Sailesh Nepal664837f2014-07-14 16:31:51 -0700600 response.handleCreateConnectionFailed(DisconnectCause.ERROR_UNSPECIFIED, null);
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700601 }
602 };
603
604 mBinder.bind(callback);
605 }
606
607 /** @see ConnectionService#abort(String) */
608 void abort(Call call) {
609 // Clear out any pending outgoing call data
610 String callId = mCallIdMapper.getCallId(call);
611
612 // If still bound, tell the connection service to abort.
613 if (isServiceValid("abort")) {
614 try {
615 logOutgoing("abort %s", callId);
616 mServiceInterface.abort(callId);
617 } catch (RemoteException e) {
618 }
619 }
620
621 removeCall(call);
622 }
623
624 /** @see ConnectionService#hold(String) */
625 void hold(Call call) {
626 if (isServiceValid("hold")) {
627 try {
628 logOutgoing("hold %s", mCallIdMapper.getCallId(call));
629 mServiceInterface.hold(mCallIdMapper.getCallId(call));
630 } catch (RemoteException e) {
631 }
632 }
633 }
634
635 /** @see ConnectionService#unhold(String) */
636 void unhold(Call call) {
637 if (isServiceValid("unhold")) {
638 try {
639 logOutgoing("unhold %s", mCallIdMapper.getCallId(call));
640 mServiceInterface.unhold(mCallIdMapper.getCallId(call));
641 } catch (RemoteException e) {
642 }
643 }
644 }
645
646 /** @see ConnectionService#onAudioStateChanged(String,CallAudioState) */
647 void onAudioStateChanged(Call activeCall, CallAudioState audioState) {
648 if (isServiceValid("onAudioStateChanged")) {
649 try {
650 logOutgoing("onAudioStateChanged %s %s",
651 mCallIdMapper.getCallId(activeCall), audioState);
652 mServiceInterface.onAudioStateChanged(mCallIdMapper.getCallId(activeCall),
653 audioState);
654 } catch (RemoteException e) {
655 }
656 }
657 }
658
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700659 /** @see ConnectionService#disconnect(String) */
660 void disconnect(Call call) {
661 if (isServiceValid("disconnect")) {
662 try {
663 logOutgoing("disconnect %s", mCallIdMapper.getCallId(call));
664 mServiceInterface.disconnect(mCallIdMapper.getCallId(call));
665 } catch (RemoteException e) {
666 }
667 }
668 }
669
670 /** @see ConnectionService#answer(String) */
Andrew Lee38931d02014-07-16 10:17:36 -0700671 void answer(Call call, int videoState) {
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700672 if (isServiceValid("answer")) {
673 try {
Andrew Lee38931d02014-07-16 10:17:36 -0700674 logOutgoing("answer %s %d", mCallIdMapper.getCallId(call), videoState);
675 mServiceInterface.answer(mCallIdMapper.getCallId(call), videoState);
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700676 } catch (RemoteException e) {
677 }
678 }
679 }
680
681 /** @see ConnectionService#reject(String) */
682 void reject(Call call) {
683 if (isServiceValid("reject")) {
684 try {
685 logOutgoing("reject %s", mCallIdMapper.getCallId(call));
686 mServiceInterface.reject(mCallIdMapper.getCallId(call));
687 } catch (RemoteException e) {
688 }
689 }
690 }
691
692 /** @see ConnectionService#playDtmfTone(String,char) */
693 void playDtmfTone(Call call, char digit) {
694 if (isServiceValid("playDtmfTone")) {
695 try {
696 logOutgoing("playDtmfTone %s %c", mCallIdMapper.getCallId(call), digit);
697 mServiceInterface.playDtmfTone(mCallIdMapper.getCallId(call), digit);
698 } catch (RemoteException e) {
699 }
700 }
701 }
702
703 /** @see ConnectionService#stopDtmfTone(String) */
704 void stopDtmfTone(Call call) {
705 if (isServiceValid("stopDtmfTone")) {
706 try {
707 logOutgoing("stopDtmfTone %s", mCallIdMapper.getCallId(call));
708 mServiceInterface.stopDtmfTone(mCallIdMapper.getCallId(call));
709 } catch (RemoteException e) {
710 }
711 }
712 }
713
714 void addCall(Call call) {
715 if (mCallIdMapper.getCallId(call) == null) {
716 mCallIdMapper.addCall(call);
717 }
718 }
719
720 /**
721 * Associates newCall with this connection service by replacing callToReplace.
722 */
723 void replaceCall(Call newCall, Call callToReplace) {
724 Preconditions.checkState(callToReplace.getConnectionService() == this);
725 mCallIdMapper.replaceCall(newCall, callToReplace);
726 }
727
728 void removeCall(Call call) {
Sailesh Nepal664837f2014-07-14 16:31:51 -0700729 CreateConnectionResponse response = mPendingResponses.remove(mCallIdMapper.getCallId(call));
730 if (response != null) {
731 response.handleCreateConnectionFailed(DisconnectCause.ERROR_UNSPECIFIED, null);
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700732 }
733
734 mCallIdMapper.removeCall(call);
735 }
736
737 void onPostDialContinue(Call call, boolean proceed) {
738 if (isServiceValid("onPostDialContinue")) {
739 try {
740 logOutgoing("onPostDialContinue %s %b", mCallIdMapper.getCallId(call), proceed);
741 mServiceInterface.onPostDialContinue(mCallIdMapper.getCallId(call), proceed);
742 } catch (RemoteException ignored) {
743 }
744 }
745 }
746
747 void onPhoneAccountClicked(Call call) {
748 if (isServiceValid("onPhoneAccountClicked")) {
749 try {
750 logOutgoing("onPhoneAccountClicked %s", mCallIdMapper.getCallId(call));
751 mServiceInterface.onPhoneAccountClicked(mCallIdMapper.getCallId(call));
752 } catch (RemoteException ignored) {
753 }
754 }
755 }
756
757 void conference(final Call conferenceCall, Call call) {
758 if (isServiceValid("conference")) {
759 try {
760 conferenceCall.setConnectionService(this);
761 mPendingConferenceCalls.add(conferenceCall);
762 mHandler.postDelayed(new Runnable() {
763 @Override public void run() {
764 if (mPendingConferenceCalls.remove(conferenceCall)) {
765 conferenceCall.expireConference();
766 Log.i(this, "Conference call expired: %s", conferenceCall);
767 }
768 }
769 }, Timeouts.getConferenceCallExpireMillis());
770
771 logOutgoing("conference %s %s",
772 mCallIdMapper.getCallId(conferenceCall),
773 mCallIdMapper.getCallId(call));
774 mServiceInterface.conference(
775 mCallIdMapper.getCallId(conferenceCall),
776 mCallIdMapper.getCallId(call));
777 } catch (RemoteException ignored) {
778 }
779 }
780 }
781
782 void splitFromConference(Call call) {
783 if (isServiceValid("splitFromConference")) {
784 try {
785 logOutgoing("splitFromConference %s", mCallIdMapper.getCallId(call));
786 mServiceInterface.splitFromConference(mCallIdMapper.getCallId(call));
787 } catch (RemoteException ignored) {
788 }
789 }
790 }
791
Sailesh Nepale8ecb982014-07-11 17:19:42 -0700792 void swapWithBackgroundCall(Call call) {
793 if (isServiceValid("swapWithBackgroundCall")) {
794 try {
795 logOutgoing("swapWithBackgroundCall %s", mCallIdMapper.getCallId(call));
796 mServiceInterface.swapWithBackgroundCall(mCallIdMapper.getCallId(call));
797 } catch (RemoteException ignored) {
798 }
799 }
800 }
801
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700802 /** {@inheritDoc} */
803 @Override
804 protected void setServiceInterface(IBinder binder) {
805 if (binder == null) {
806 // We have lost our service connection. Notify the world that this service is done.
807 // We must notify the adapter before CallsManager. The adapter will force any pending
808 // outgoing calls to try the next service. This needs to happen before CallsManager
809 // tries to clean up any calls still associated with this service.
810 handleConnectionServiceDeath();
811 CallsManager.getInstance().handleConnectionServiceDeath(this);
812 mServiceInterface = null;
813 } else {
814 mServiceInterface = IConnectionService.Stub.asInterface(binder);
815 addConnectionServiceAdapter(mAdapter);
816 }
817 }
818
819 /**
820 * Called when the associated connection service dies.
821 */
822 private void handleConnectionServiceDeath() {
Sailesh Nepal664837f2014-07-14 16:31:51 -0700823 if (!mPendingResponses.isEmpty()) {
824 CreateConnectionResponse[] responses = mPendingResponses.values().toArray(
825 new CreateConnectionResponse[mPendingResponses.values().size()]);
826 mPendingResponses.clear();
827 for (int i = 0; i < responses.length; i++) {
828 responses[i].handleCreateConnectionFailed(DisconnectCause.ERROR_UNSPECIFIED, null);
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700829 }
830 }
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700831 mCallIdMapper.clear();
832 }
833
834 private void logIncoming(String msg, Object... params) {
835 Log.d(this, "ConnectionService -> Telecomm: " + msg, params);
836 }
837
838 private void logOutgoing(String msg, Object... params) {
839 Log.d(this, "Telecomm -> ConnectionService: " + msg, params);
840 }
841
842 private void queryRemoteConnectionServices(final RemoteServiceCallback callback) {
843 final List<IBinder> connectionServices = new ArrayList<>();
844 final List<ComponentName> components = new ArrayList<>();
Sailesh Nepal664837f2014-07-14 16:31:51 -0700845 final List<ConnectionServiceWrapper> servciesAttempted = new ArrayList<>();
Sailesh Nepal905dfba2014-07-14 08:20:41 -0700846 final Collection<ConnectionServiceWrapper> services =
847 mConnectionServiceRepository.lookupServices();
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700848
Sailesh Nepal664837f2014-07-14 16:31:51 -0700849 Log.v(this, "queryRemoteConnectionServices, services: " + services.size());
850
Sailesh Nepal905dfba2014-07-14 08:20:41 -0700851 for (ConnectionServiceWrapper cs : services) {
852 if (cs != this) {
853 final ConnectionServiceWrapper currentConnectionService = cs;
854 cs.mBinder.bind(new BindCallback() {
Sailesh Nepal905dfba2014-07-14 08:20:41 -0700855 @Override
856 public void onSuccess() {
857 Log.d(this, "Adding ***** %s", currentConnectionService.getComponentName());
858 connectionServices.add(
859 currentConnectionService.mServiceInterface.asBinder());
860 components.add(currentConnectionService.getComponentName());
861 maybeComplete();
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700862 }
Sailesh Nepal905dfba2014-07-14 08:20:41 -0700863
864 @Override
865 public void onFailure() {
Sailesh Nepal905dfba2014-07-14 08:20:41 -0700866 maybeComplete();
867 }
868
869 private void maybeComplete() {
Sailesh Nepal664837f2014-07-14 16:31:51 -0700870 servciesAttempted.add(currentConnectionService);
871 if (servciesAttempted.size() == services.size() - 1) {
Sailesh Nepal905dfba2014-07-14 08:20:41 -0700872 try {
873 callback.onResult(components, connectionServices);
874 } catch (RemoteException ignored) {
875 }
876 }
877 }
878 });
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700879 }
Sailesh Nepal905dfba2014-07-14 08:20:41 -0700880 }
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700881 }
882}