blob: 0dbe1b79b8425dbf48478db2702f724e47c2f3e7 [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;
Sailesh Nepal35faf8c2014-07-08 22:02:34 -070031import android.telecomm.StatusHints;
Sailesh Nepalc92c4362014-07-04 18:33:21 -070032import android.telephony.DisconnectCause;
33
34import com.android.internal.os.SomeArgs;
Santos Cordonf2f14ef2014-07-20 18:00:20 -070035import com.android.internal.telecomm.ICallVideoProvider;
Sailesh Nepalc92c4362014-07-04 18:33:21 -070036import com.android.internal.telecomm.IConnectionService;
37import com.android.internal.telecomm.IConnectionServiceAdapter;
Sailesh Nepalc92c4362014-07-04 18:33:21 -070038import com.android.internal.telecomm.RemoteServiceCallback;
Sailesh Nepalc92c4362014-07-04 18:33:21 -070039import com.google.common.base.Preconditions;
Sailesh Nepalc92c4362014-07-04 18:33:21 -070040
Sailesh Nepalc92c4362014-07-04 18:33:21 -070041import java.util.ArrayList;
42import java.util.Collection;
43import java.util.HashMap;
44import java.util.HashSet;
45import java.util.List;
46import java.util.Map;
47import java.util.Set;
48
49/**
50 * Wrapper for {@link IConnectionService}s, handles binding to {@link IConnectionService} and keeps
51 * track of when the object can safely be unbound. Other classes should not use
52 * {@link IConnectionService} directly and instead should use this class to invoke methods of
53 * {@link IConnectionService}.
54 */
55final class ConnectionServiceWrapper extends ServiceBinder<IConnectionService> {
Sailesh Nepal664837f2014-07-14 16:31:51 -070056 private static final int MSG_HANDLE_CREATE_CONNECTION_SUCCESSFUL = 1;
57 private static final int MSG_HANDLE_CREATE_CONNECTION_FAILED = 2;
58 private static final int MSG_HANDLE_CREATE_CONNECTION_CANCELLED = 3;
59 private static final int MSG_SET_ACTIVE = 4;
60 private static final int MSG_SET_RINGING = 5;
61 private static final int MSG_SET_DIALING = 6;
62 private static final int MSG_SET_DISCONNECTED = 7;
63 private static final int MSG_SET_ON_HOLD = 8;
64 private static final int MSG_SET_REQUESTING_RINGBACK = 9;
65 private static final int MSG_SET_CALL_CAPABILITIES = 10;
66 private static final int MSG_SET_IS_CONFERENCED = 11;
67 private static final int MSG_ADD_CONFERENCE_CALL = 12;
68 private static final int MSG_REMOVE_CALL = 13;
69 private static final int MSG_ON_POST_DIAL_WAIT = 14;
70 private static final int MSG_QUERY_REMOTE_CALL_SERVICES = 15;
71 private static final int MSG_SET_CALL_VIDEO_PROVIDER = 16;
72 private static final int MSG_SET_AUDIO_MODE_IS_VOIP = 17;
73 private static final int MSG_SET_STATUS_HINTS = 18;
74 private static final int MSG_SET_HANDLE = 19;
75 private static final int MSG_SET_CALLER_DISPLAY_NAME = 20;
Tyler Gunn0a388fc2014-07-17 12:21:17 -070076 private static final int MSG_SET_VIDEO_STATE = 21;
Sailesh Nepal9d58de52014-07-18 14:53:19 -070077 private static final int MSG_START_ACTIVITY_FROM_IN_CALL = 22;
Sailesh Nepalc92c4362014-07-04 18:33:21 -070078
79 private final Handler mHandler = new Handler() {
80 @Override
81 public void handleMessage(Message msg) {
82 Call call;
83 switch (msg.what) {
Sailesh Nepal664837f2014-07-14 16:31:51 -070084 case MSG_HANDLE_CREATE_CONNECTION_SUCCESSFUL: {
Sailesh Nepalc92c4362014-07-04 18:33:21 -070085 ConnectionRequest request = (ConnectionRequest) msg.obj;
Sailesh Nepal664837f2014-07-14 16:31:51 -070086 if (mPendingResponses.containsKey(request.getCallId())) {
87 mPendingResponses.remove(
88 request.getCallId()).handleCreateConnectionSuccessful(request);
Sailesh Nepalc92c4362014-07-04 18:33:21 -070089 } else {
Sailesh Nepal664837f2014-07-14 16:31:51 -070090 //Log.w(this, "handleCreateConnectionSuccessful, unknown call: %s", callId);
Sailesh Nepalc92c4362014-07-04 18:33:21 -070091 }
92 break;
93 }
Sailesh Nepal664837f2014-07-14 16:31:51 -070094 case MSG_HANDLE_CREATE_CONNECTION_FAILED: {
Sailesh Nepalc92c4362014-07-04 18:33:21 -070095 SomeArgs args = (SomeArgs) msg.obj;
96 try {
Sailesh Nepala49c6432014-07-07 22:47:11 -070097 ConnectionRequest request = (ConnectionRequest) args.arg1;
Sailesh Nepalc92c4362014-07-04 18:33:21 -070098 int statusCode = args.argi1;
99 String statusMsg = (String) args.arg2;
Sailesh Nepal664837f2014-07-14 16:31:51 -0700100 if (mPendingResponses.containsKey(request.getCallId())) {
101 mPendingResponses.remove(request.getCallId())
102 .handleCreateConnectionFailed(statusCode, statusMsg);
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700103 mCallIdMapper.removeCall(request.getCallId());
104 } else {
Sailesh Nepal664837f2014-07-14 16:31:51 -0700105 //Log.w(this, "handleCreateConnectionFailed, unknown call: %s", callId);
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700106 }
107 } finally {
108 args.recycle();
109 }
110 break;
111 }
Sailesh Nepal664837f2014-07-14 16:31:51 -0700112 case MSG_HANDLE_CREATE_CONNECTION_CANCELLED: {
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700113 ConnectionRequest request = (ConnectionRequest) msg.obj;
Sailesh Nepal664837f2014-07-14 16:31:51 -0700114 if (mPendingResponses.containsKey(request.getCallId())) {
115 mPendingResponses.remove(
116 request.getCallId()).handleCreateConnectionCancelled();
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700117 } else {
Sailesh Nepal664837f2014-07-14 16:31:51 -0700118 //Log.w(this, "handleCreateConnectionCancelled, unknown call: %s", callId);
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700119 }
120 break;
121 }
122 case MSG_SET_ACTIVE:
123 call = mCallIdMapper.getCall(msg.obj);
124 if (call != null) {
125 mCallsManager.markCallAsActive(call);
126 } else {
127 //Log.w(this, "setActive, unknown call id: %s", msg.obj);
128 }
129 break;
130 case MSG_SET_RINGING:
131 call = mCallIdMapper.getCall(msg.obj);
132 if (call != null) {
133 mCallsManager.markCallAsRinging(call);
134 } else {
135 //Log.w(this, "setRinging, unknown call id: %s", msg.obj);
136 }
137 break;
138 case MSG_SET_DIALING:
139 call = mCallIdMapper.getCall(msg.obj);
140 if (call != null) {
141 mCallsManager.markCallAsDialing(call);
142 } else {
143 //Log.w(this, "setDialing, unknown call id: %s", msg.obj);
144 }
145 break;
146 case MSG_SET_DISCONNECTED: {
147 SomeArgs args = (SomeArgs) msg.obj;
148 try {
149 call = mCallIdMapper.getCall(args.arg1);
150 String disconnectMessage = (String) args.arg2;
151 int disconnectCause = args.argi1;
152 if (call != null) {
153 mCallsManager.markCallAsDisconnected(call, disconnectCause,
154 disconnectMessage);
155 } else {
156 //Log.w(this, "setDisconnected, unknown call id: %s", args.arg1);
157 }
158 } finally {
159 args.recycle();
160 }
161 break;
162 }
163 case MSG_SET_ON_HOLD:
164 call = mCallIdMapper.getCall(msg.obj);
165 if (call != null) {
166 mCallsManager.markCallAsOnHold(call);
167 } else {
168 //Log.w(this, "setOnHold, unknown call id: %s", msg.obj);
169 }
170 break;
171 case MSG_SET_REQUESTING_RINGBACK: {
Sailesh Nepal9d58de52014-07-18 14:53:19 -0700172 call = mCallIdMapper.getCall(msg.obj);
173 if (call != null) {
174 call.setRequestingRingback(msg.arg1 == 1);
175 } else {
176 //Log.w(this, "setRingback, unknown call id: %s", args.arg1);
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700177 }
178 break;
179 }
Sailesh Nepale20bc972014-07-09 21:22:36 -0700180 case MSG_SET_CALL_CAPABILITIES: {
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700181 call = mCallIdMapper.getCall(msg.obj);
182 if (call != null) {
Sailesh Nepale20bc972014-07-09 21:22:36 -0700183 call.setCallCapabilities(msg.arg1);
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700184 } else {
185 //Log.w(ConnectionServiceWrapper.this,
Sailesh Nepale20bc972014-07-09 21:22:36 -0700186 // "setCallCapabilities, unknown call id: %s", msg.obj);
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700187 }
188 break;
189 }
190 case MSG_SET_IS_CONFERENCED: {
191 SomeArgs args = (SomeArgs) msg.obj;
192 try {
193 Call childCall = mCallIdMapper.getCall(args.arg1);
194 if (childCall != null) {
195 String conferenceCallId = (String) args.arg2;
196 if (conferenceCallId == null) {
197 childCall.setParentCall(null);
198 } else {
199 Call conferenceCall = mCallIdMapper.getCall(conferenceCallId);
200 if (conferenceCall != null &&
201 !mPendingConferenceCalls.contains(conferenceCall)) {
202 childCall.setParentCall(conferenceCall);
203 } else {
204 //Log.w(this, "setIsConferenced, unknown conference id %s",
205 // conferenceCallId);
206 }
207 }
208 } else {
209 //Log.w(this, "setIsConferenced, unknown call id: %s", args.arg1);
210 }
211 } finally {
212 args.recycle();
213 }
214 break;
215 }
216 case MSG_ADD_CONFERENCE_CALL: {
217 Call conferenceCall = mCallIdMapper.getCall(msg.obj);
218 if (mPendingConferenceCalls.remove(conferenceCall)) {
219 Log.v(this, "confirming conf call %s", conferenceCall);
220 conferenceCall.confirmConference();
221 } else {
222 //Log.w(this, "addConference, unknown call id: %s", callId);
223 }
224 break;
225 }
226 case MSG_REMOVE_CALL:
227 break;
228 case MSG_ON_POST_DIAL_WAIT: {
229 SomeArgs args = (SomeArgs) msg.obj;
230 try {
231 call = mCallIdMapper.getCall(args.arg1);
232 if (call != null) {
233 String remaining = (String) args.arg2;
234 call.onPostDialWait(remaining);
235 } else {
236 //Log.w(this, "onPostDialWait, unknown call id: %s", args.arg1);
237 }
238 } finally {
239 args.recycle();
240 }
241 break;
242 }
243 case MSG_QUERY_REMOTE_CALL_SERVICES: {
Sailesh Nepal664837f2014-07-14 16:31:51 -0700244 queryRemoteConnectionServices((RemoteServiceCallback) msg.obj);
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700245 break;
246 }
247 case MSG_SET_CALL_VIDEO_PROVIDER: {
248 SomeArgs args = (SomeArgs) msg.obj;
249 try {
250 call = mCallIdMapper.getCall(args.arg1);
251 ICallVideoProvider callVideoProvider = (ICallVideoProvider) args.arg2;
252 if (call != null) {
253 call.setCallVideoProvider(callVideoProvider);
254 }
255 } finally {
256 args.recycle();
257 }
258 break;
259 }
Sailesh Nepal7e669572014-07-08 21:29:12 -0700260 case MSG_SET_AUDIO_MODE_IS_VOIP: {
Sailesh Nepale20bc972014-07-09 21:22:36 -0700261 call = mCallIdMapper.getCall(msg.obj);
262 if (call != null) {
263 call.setAudioModeIsVoip(msg.arg1 == 1);
Sailesh Nepal7e669572014-07-08 21:29:12 -0700264 }
265 break;
266 }
Sailesh Nepal35faf8c2014-07-08 22:02:34 -0700267 case MSG_SET_STATUS_HINTS: {
268 SomeArgs args = (SomeArgs) msg.obj;
269 try {
270 call = mCallIdMapper.getCall(args.arg1);
271 StatusHints statusHints = (StatusHints) args.arg2;
272 if (call != null) {
273 call.setStatusHints(statusHints);
274 }
275 } finally {
276 args.recycle();
277 }
278 break;
279 }
Sailesh Nepale8ecb982014-07-11 17:19:42 -0700280 case MSG_SET_HANDLE: {
281 SomeArgs args = (SomeArgs) msg.obj;
282 try {
283 call = mCallIdMapper.getCall(args.arg1);
284 if (call != null) {
285 call.setHandle((Uri) args.arg2, args.argi1);
286 }
287 } finally {
288 args.recycle();
289 }
290 break;
291 }
292 case MSG_SET_CALLER_DISPLAY_NAME: {
293 SomeArgs args = (SomeArgs) msg.obj;
294 try {
295 call = mCallIdMapper.getCall(args.arg1);
296 if (call != null) {
297 call.setCallerDisplayName((String) args.arg2, args.argi1);
298 }
299 } finally {
300 args.recycle();
301 }
302 break;
303 }
Tyler Gunn0a388fc2014-07-17 12:21:17 -0700304 case MSG_SET_VIDEO_STATE: {
305 call = mCallIdMapper.getCall(msg.obj);
306 if (call != null) {
307 call.setVideoState(msg.arg1);
308 }
309 }
Sailesh Nepal9d58de52014-07-18 14:53:19 -0700310 case MSG_START_ACTIVITY_FROM_IN_CALL: {
311 SomeArgs args = (SomeArgs) msg.obj;
312 try {
313 call = mCallIdMapper.getCall(args.arg1);
314 if (call != null) {
315 call.startActivityFromInCall((PendingIntent) args.arg2);
316 }
317 } finally {
318 args.recycle();
319 }
320 break;
321 }
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700322 }
323 }
324 };
325
326 private final class Adapter extends IConnectionServiceAdapter.Stub {
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700327 @Override
Sailesh Nepal664837f2014-07-14 16:31:51 -0700328 public void handleCreateConnectionSuccessful(ConnectionRequest request) {
329 logIncoming("handleCreateConnectionSuccessful %s", request);
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700330 mCallIdMapper.checkValidCallId(request.getCallId());
Sailesh Nepal664837f2014-07-14 16:31:51 -0700331 mHandler.obtainMessage(MSG_HANDLE_CREATE_CONNECTION_SUCCESSFUL, request).sendToTarget();
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700332 }
333
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700334 @Override
Sailesh Nepal664837f2014-07-14 16:31:51 -0700335 public void handleCreateConnectionFailed(
336 ConnectionRequest request, int errorCode, String errorMsg) {
337 logIncoming("handleCreateConnectionFailed %s %d %s", request, errorCode, errorMsg);
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700338 mCallIdMapper.checkValidCallId(request.getCallId());
339 SomeArgs args = SomeArgs.obtain();
340 args.arg1 = request;
341 args.argi1 = errorCode;
342 args.arg2 = errorMsg;
Sailesh Nepal664837f2014-07-14 16:31:51 -0700343 mHandler.obtainMessage(MSG_HANDLE_CREATE_CONNECTION_FAILED, args).sendToTarget();
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700344 }
345
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700346 @Override
Sailesh Nepal664837f2014-07-14 16:31:51 -0700347 public void handleCreateConnectionCancelled(ConnectionRequest request) {
348 logIncoming("handleCreateConnectionCancelled %s", request);
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700349 mCallIdMapper.checkValidCallId(request.getCallId());
Sailesh Nepal664837f2014-07-14 16:31:51 -0700350 mHandler.obtainMessage(MSG_HANDLE_CREATE_CONNECTION_CANCELLED, request).sendToTarget();
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700351 }
352
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700353 @Override
354 public void setActive(String callId) {
355 logIncoming("setActive %s", callId);
356 mCallIdMapper.checkValidCallId(callId);
357 mHandler.obtainMessage(MSG_SET_ACTIVE, callId).sendToTarget();
358 }
359
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700360 @Override
361 public void setRinging(String callId) {
362 logIncoming("setRinging %s", callId);
363 mCallIdMapper.checkValidCallId(callId);
364 mHandler.obtainMessage(MSG_SET_RINGING, callId).sendToTarget();
365 }
366
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700367 @Override
368 public void setCallVideoProvider(String callId, ICallVideoProvider callVideoProvider) {
369 logIncoming("setCallVideoProvider %s", callId);
370 mCallIdMapper.checkValidCallId(callId);
371 SomeArgs args = SomeArgs.obtain();
372 args.arg1 = callId;
373 args.arg2 = callVideoProvider;
374 mHandler.obtainMessage(MSG_SET_CALL_VIDEO_PROVIDER, args).sendToTarget();
375 }
376
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700377 @Override
378 public void setDialing(String callId) {
379 logIncoming("setDialing %s", callId);
380 mCallIdMapper.checkValidCallId(callId);
381 mHandler.obtainMessage(MSG_SET_DIALING, callId).sendToTarget();
382 }
383
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700384 @Override
385 public void setDisconnected(
386 String callId, int disconnectCause, String disconnectMessage) {
387 logIncoming("setDisconnected %s %d %s", callId, disconnectCause, disconnectMessage);
388 mCallIdMapper.checkValidCallId(callId);
389 SomeArgs args = SomeArgs.obtain();
390 args.arg1 = callId;
391 args.arg2 = disconnectMessage;
392 args.argi1 = disconnectCause;
393 mHandler.obtainMessage(MSG_SET_DISCONNECTED, args).sendToTarget();
394 }
395
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700396 @Override
397 public void setOnHold(String callId) {
398 logIncoming("setOnHold %s", callId);
399 mCallIdMapper.checkValidCallId(callId);
400 mHandler.obtainMessage(MSG_SET_ON_HOLD, callId).sendToTarget();
401 }
402
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700403 @Override
404 public void setRequestingRingback(String callId, boolean ringback) {
405 logIncoming("setRequestingRingback %s %b", callId, ringback);
406 mCallIdMapper.checkValidCallId(callId);
Sailesh Nepal9d58de52014-07-18 14:53:19 -0700407 mHandler.obtainMessage(MSG_SET_REQUESTING_RINGBACK, ringback ? 1 : 0, 0, callId)
408 .sendToTarget();
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700409 }
410
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700411 @Override
412 public void removeCall(String callId) {
413 logIncoming("removeCall %s", callId);
414 }
415
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700416 @Override
Sailesh Nepale20bc972014-07-09 21:22:36 -0700417 public void setCallCapabilities(String callId, int callCapabilities) {
418 logIncoming("setCallCapabilities %s %d", callId, callCapabilities);
419 mHandler.obtainMessage(MSG_SET_CALL_CAPABILITIES, callCapabilities, 0, callId)
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700420 .sendToTarget();
421 }
422
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700423 @Override
424 public void setIsConferenced(String callId, String conferenceCallId) {
425 logIncoming("setIsConferenced %s %s", callId, conferenceCallId);
426 SomeArgs args = SomeArgs.obtain();
427 args.arg1 = callId;
428 args.arg2 = conferenceCallId;
429 mHandler.obtainMessage(MSG_SET_IS_CONFERENCED, args).sendToTarget();
430 }
431
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700432 @Override
433 public void addConferenceCall(String callId) {
434 logIncoming("addConferenceCall %s", callId);
435 mCallIdMapper.checkValidCallId(callId);
436 mHandler.obtainMessage(MSG_ADD_CONFERENCE_CALL, callId).sendToTarget();
437 }
438
439 @Override
440 public void onPostDialWait(String callId, String remaining) throws RemoteException {
441 logIncoming("onPostDialWait %s %s", callId, remaining);
442 mCallIdMapper.checkValidCallId(callId);
443 SomeArgs args = SomeArgs.obtain();
444 args.arg1 = callId;
445 args.arg2 = remaining;
446 mHandler.obtainMessage(MSG_ON_POST_DIAL_WAIT, args).sendToTarget();
447 }
448
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700449 @Override
450 public void queryRemoteConnectionServices(RemoteServiceCallback callback) {
451 logIncoming("queryRemoteCSs");
452 mHandler.obtainMessage(MSG_QUERY_REMOTE_CALL_SERVICES, callback).sendToTarget();
453 }
454
455 @Override
Tyler Gunn0a388fc2014-07-17 12:21:17 -0700456 public void setVideoState(String callId, int videoState) {
457 logIncoming("setVideoState %s %d", callId, videoState);
458 mCallIdMapper.checkValidCallId(callId);
459 mHandler.obtainMessage(MSG_SET_VIDEO_STATE, videoState, 0, callId).sendToTarget();
460 }
461
462 @Override
Sailesh Nepal7e669572014-07-08 21:29:12 -0700463 public void setAudioModeIsVoip(String callId, boolean isVoip) {
Sailesh Nepal7fa33ca2014-07-10 15:28:21 -0700464 logIncoming("setAudioModeIsVoip %s %b", callId, isVoip);
Sailesh Nepal7e669572014-07-08 21:29:12 -0700465 mCallIdMapper.checkValidCallId(callId);
Sailesh Nepale20bc972014-07-09 21:22:36 -0700466 mHandler.obtainMessage(MSG_SET_AUDIO_MODE_IS_VOIP, isVoip ? 1 : 0, 0,
467 callId).sendToTarget();
Sailesh Nepal7e669572014-07-08 21:29:12 -0700468 }
Sailesh Nepal35faf8c2014-07-08 22:02:34 -0700469
470 @Override
471 public void setStatusHints(String callId, StatusHints statusHints) {
472 logIncoming("setStatusHints %s %s", callId, statusHints);
473 mCallIdMapper.checkValidCallId(callId);
474 SomeArgs args = SomeArgs.obtain();
475 args.arg1 = callId;
476 args.arg2 = statusHints;
477 mHandler.obtainMessage(MSG_SET_STATUS_HINTS, args).sendToTarget();
478 }
Sailesh Nepale8ecb982014-07-11 17:19:42 -0700479
480 @Override
481 public void setHandle(String callId, Uri handle, int presentation) {
482 logIncoming("setHandle %s %s %d", callId, handle, presentation);
483 mCallIdMapper.checkValidCallId(callId);
484 SomeArgs args = SomeArgs.obtain();
485 args.arg1 = callId;
486 args.arg2 = handle;
487 args.argi1 = presentation;
488 mHandler.obtainMessage(MSG_SET_HANDLE, args).sendToTarget();
489 }
490
491 @Override
492 public void setCallerDisplayName(
493 String callId, String callerDisplayName, int presentation) {
494 logIncoming("setCallerDisplayName %s %s %d", callId, callerDisplayName, presentation);
495 mCallIdMapper.checkValidCallId(callId);
496 SomeArgs args = SomeArgs.obtain();
497 args.arg1 = callId;
498 args.arg2 = callerDisplayName;
499 args.argi1 = presentation;
500 mHandler.obtainMessage(MSG_SET_CALLER_DISPLAY_NAME, args).sendToTarget();
501 }
Sailesh Nepal9d58de52014-07-18 14:53:19 -0700502
503 @Override
504 public void startActivityFromInCall(String callId, PendingIntent intent) {
505 logIncoming("startActivityFromInCall %s %s", callId, intent);
506 mCallIdMapper.checkValidCallId(callId);
507 SomeArgs args = SomeArgs.obtain();
508 args.arg1 = callId;
509 args.arg2 = intent;
510 mHandler.obtainMessage(MSG_START_ACTIVITY_FROM_IN_CALL, args).sendToTarget();
511 }
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700512 }
513
514 private final Adapter mAdapter = new Adapter();
515 private final CallsManager mCallsManager = CallsManager.getInstance();
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700516 private final Set<Call> mPendingConferenceCalls = new HashSet<>();
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700517 private final CallIdMapper mCallIdMapper = new CallIdMapper("ConnectionService");
Sailesh Nepal664837f2014-07-14 16:31:51 -0700518 private final Map<String, CreateConnectionResponse> mPendingResponses = new HashMap<>();
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700519
520 private Binder mBinder = new Binder();
521 private IConnectionService mServiceInterface;
Sailesh Nepal905dfba2014-07-14 08:20:41 -0700522 private final ConnectionServiceRepository mConnectionServiceRepository;
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700523
524 /**
Sailesh Nepal905dfba2014-07-14 08:20:41 -0700525 * Creates a connection service.
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700526 *
Sailesh Nepal905dfba2014-07-14 08:20:41 -0700527 * @param componentName The component name of the service with which to bind.
Sailesh Nepal905dfba2014-07-14 08:20:41 -0700528 * @param connectionServiceRepository Connection service repository.
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700529 */
530 ConnectionServiceWrapper(
Sailesh Nepal664837f2014-07-14 16:31:51 -0700531 ComponentName componentName, ConnectionServiceRepository connectionServiceRepository) {
Santos Cordonf2f14ef2014-07-20 18:00:20 -0700532 super(ConnectionService.SERVICE_INTERFACE, componentName);
Sailesh Nepal905dfba2014-07-14 08:20:41 -0700533 mConnectionServiceRepository = connectionServiceRepository;
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700534 }
535
536 /** See {@link IConnectionService#addConnectionServiceAdapter}. */
537 private void addConnectionServiceAdapter(IConnectionServiceAdapter adapter) {
538 if (isServiceValid("addConnectionServiceAdapter")) {
539 try {
Sailesh Nepal3fe8b722014-07-08 10:07:26 -0700540 logOutgoing("addConnectionServiceAdapter %s", adapter);
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700541 mServiceInterface.addConnectionServiceAdapter(adapter);
542 } catch (RemoteException e) {
543 }
544 }
545 }
546
547 /**
Sailesh Nepal664837f2014-07-14 16:31:51 -0700548 * Creates a new connection for a new outgoing call or to attach to an existing incoming call.
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700549 */
Sailesh Nepal664837f2014-07-14 16:31:51 -0700550 void createConnection(final Call call, final CreateConnectionResponse response) {
551 Log.d(this, "createConnection(%s) via %s.", call, getComponentName());
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700552 BindCallback callback = new BindCallback() {
553 @Override
554 public void onSuccess() {
555 String callId = mCallIdMapper.getCallId(call);
Sailesh Nepal664837f2014-07-14 16:31:51 -0700556 mPendingResponses.put(callId, response);
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700557
558 GatewayInfo gatewayInfo = call.getGatewayInfo();
559 Bundle extras = call.getExtras();
560 if (gatewayInfo != null && gatewayInfo.getGatewayProviderPackageName() != null &&
561 gatewayInfo.getOriginalHandle() != null) {
562 extras = (Bundle) extras.clone();
563 extras.putString(
564 NewOutgoingCallIntentBroadcaster.EXTRA_GATEWAY_PROVIDER_PACKAGE,
565 gatewayInfo.getGatewayProviderPackageName());
566 extras.putParcelable(
567 NewOutgoingCallIntentBroadcaster.EXTRA_GATEWAY_ORIGINAL_URI,
568 gatewayInfo.getOriginalHandle());
569 }
Sailesh Nepale8ecb982014-07-11 17:19:42 -0700570 ConnectionRequest request = new ConnectionRequest(
571 call.getPhoneAccount(),
572 callId,
573 call.getHandle(),
574 call.getHandlePresentation(),
575 extras,
Tyler Gunnc4abd912014-07-08 14:22:10 -0700576 call.getVideoState());
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700577
578 try {
Sailesh Nepal664837f2014-07-14 16:31:51 -0700579 mServiceInterface.createConnection(request, call.isIncoming());
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700580 } catch (RemoteException e) {
Sailesh Nepal664837f2014-07-14 16:31:51 -0700581 Log.e(this, e, "Failure to createConnection -- %s", getComponentName());
582 mPendingResponses.remove(callId).handleCreateConnectionFailed(
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700583 DisconnectCause.ERROR_UNSPECIFIED, e.toString());
584 }
585 }
586
587 @Override
588 public void onFailure() {
Sailesh Nepal905dfba2014-07-14 08:20:41 -0700589 Log.e(this, new Exception(), "Failure to call %s", getComponentName());
Sailesh Nepal664837f2014-07-14 16:31:51 -0700590 response.handleCreateConnectionFailed(DisconnectCause.ERROR_UNSPECIFIED, null);
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700591 }
592 };
593
594 mBinder.bind(callback);
595 }
596
597 /** @see ConnectionService#abort(String) */
598 void abort(Call call) {
599 // Clear out any pending outgoing call data
600 String callId = mCallIdMapper.getCallId(call);
601
602 // If still bound, tell the connection service to abort.
603 if (isServiceValid("abort")) {
604 try {
605 logOutgoing("abort %s", callId);
606 mServiceInterface.abort(callId);
607 } catch (RemoteException e) {
608 }
609 }
610
611 removeCall(call);
612 }
613
614 /** @see ConnectionService#hold(String) */
615 void hold(Call call) {
616 if (isServiceValid("hold")) {
617 try {
618 logOutgoing("hold %s", mCallIdMapper.getCallId(call));
619 mServiceInterface.hold(mCallIdMapper.getCallId(call));
620 } catch (RemoteException e) {
621 }
622 }
623 }
624
625 /** @see ConnectionService#unhold(String) */
626 void unhold(Call call) {
627 if (isServiceValid("unhold")) {
628 try {
629 logOutgoing("unhold %s", mCallIdMapper.getCallId(call));
630 mServiceInterface.unhold(mCallIdMapper.getCallId(call));
631 } catch (RemoteException e) {
632 }
633 }
634 }
635
636 /** @see ConnectionService#onAudioStateChanged(String,CallAudioState) */
637 void onAudioStateChanged(Call activeCall, CallAudioState audioState) {
638 if (isServiceValid("onAudioStateChanged")) {
639 try {
640 logOutgoing("onAudioStateChanged %s %s",
641 mCallIdMapper.getCallId(activeCall), audioState);
642 mServiceInterface.onAudioStateChanged(mCallIdMapper.getCallId(activeCall),
643 audioState);
644 } catch (RemoteException e) {
645 }
646 }
647 }
648
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700649 /** @see ConnectionService#disconnect(String) */
650 void disconnect(Call call) {
651 if (isServiceValid("disconnect")) {
652 try {
653 logOutgoing("disconnect %s", mCallIdMapper.getCallId(call));
654 mServiceInterface.disconnect(mCallIdMapper.getCallId(call));
655 } catch (RemoteException e) {
656 }
657 }
658 }
659
660 /** @see ConnectionService#answer(String) */
Andrew Lee38931d02014-07-16 10:17:36 -0700661 void answer(Call call, int videoState) {
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700662 if (isServiceValid("answer")) {
663 try {
Andrew Lee38931d02014-07-16 10:17:36 -0700664 logOutgoing("answer %s %d", mCallIdMapper.getCallId(call), videoState);
665 mServiceInterface.answer(mCallIdMapper.getCallId(call), videoState);
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700666 } catch (RemoteException e) {
667 }
668 }
669 }
670
671 /** @see ConnectionService#reject(String) */
672 void reject(Call call) {
673 if (isServiceValid("reject")) {
674 try {
675 logOutgoing("reject %s", mCallIdMapper.getCallId(call));
676 mServiceInterface.reject(mCallIdMapper.getCallId(call));
677 } catch (RemoteException e) {
678 }
679 }
680 }
681
682 /** @see ConnectionService#playDtmfTone(String,char) */
683 void playDtmfTone(Call call, char digit) {
684 if (isServiceValid("playDtmfTone")) {
685 try {
686 logOutgoing("playDtmfTone %s %c", mCallIdMapper.getCallId(call), digit);
687 mServiceInterface.playDtmfTone(mCallIdMapper.getCallId(call), digit);
688 } catch (RemoteException e) {
689 }
690 }
691 }
692
693 /** @see ConnectionService#stopDtmfTone(String) */
694 void stopDtmfTone(Call call) {
695 if (isServiceValid("stopDtmfTone")) {
696 try {
697 logOutgoing("stopDtmfTone %s", mCallIdMapper.getCallId(call));
698 mServiceInterface.stopDtmfTone(mCallIdMapper.getCallId(call));
699 } catch (RemoteException e) {
700 }
701 }
702 }
703
704 void addCall(Call call) {
705 if (mCallIdMapper.getCallId(call) == null) {
706 mCallIdMapper.addCall(call);
707 }
708 }
709
710 /**
711 * Associates newCall with this connection service by replacing callToReplace.
712 */
713 void replaceCall(Call newCall, Call callToReplace) {
714 Preconditions.checkState(callToReplace.getConnectionService() == this);
715 mCallIdMapper.replaceCall(newCall, callToReplace);
716 }
717
718 void removeCall(Call call) {
Sailesh Nepal664837f2014-07-14 16:31:51 -0700719 CreateConnectionResponse response = mPendingResponses.remove(mCallIdMapper.getCallId(call));
720 if (response != null) {
721 response.handleCreateConnectionFailed(DisconnectCause.ERROR_UNSPECIFIED, null);
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700722 }
723
724 mCallIdMapper.removeCall(call);
725 }
726
727 void onPostDialContinue(Call call, boolean proceed) {
728 if (isServiceValid("onPostDialContinue")) {
729 try {
730 logOutgoing("onPostDialContinue %s %b", mCallIdMapper.getCallId(call), proceed);
731 mServiceInterface.onPostDialContinue(mCallIdMapper.getCallId(call), proceed);
732 } catch (RemoteException ignored) {
733 }
734 }
735 }
736
737 void onPhoneAccountClicked(Call call) {
738 if (isServiceValid("onPhoneAccountClicked")) {
739 try {
740 logOutgoing("onPhoneAccountClicked %s", mCallIdMapper.getCallId(call));
741 mServiceInterface.onPhoneAccountClicked(mCallIdMapper.getCallId(call));
742 } catch (RemoteException ignored) {
743 }
744 }
745 }
746
747 void conference(final Call conferenceCall, Call call) {
748 if (isServiceValid("conference")) {
749 try {
750 conferenceCall.setConnectionService(this);
751 mPendingConferenceCalls.add(conferenceCall);
752 mHandler.postDelayed(new Runnable() {
753 @Override public void run() {
754 if (mPendingConferenceCalls.remove(conferenceCall)) {
755 conferenceCall.expireConference();
756 Log.i(this, "Conference call expired: %s", conferenceCall);
757 }
758 }
759 }, Timeouts.getConferenceCallExpireMillis());
760
761 logOutgoing("conference %s %s",
762 mCallIdMapper.getCallId(conferenceCall),
763 mCallIdMapper.getCallId(call));
764 mServiceInterface.conference(
765 mCallIdMapper.getCallId(conferenceCall),
766 mCallIdMapper.getCallId(call));
767 } catch (RemoteException ignored) {
768 }
769 }
770 }
771
772 void splitFromConference(Call call) {
773 if (isServiceValid("splitFromConference")) {
774 try {
775 logOutgoing("splitFromConference %s", mCallIdMapper.getCallId(call));
776 mServiceInterface.splitFromConference(mCallIdMapper.getCallId(call));
777 } catch (RemoteException ignored) {
778 }
779 }
780 }
781
Sailesh Nepale8ecb982014-07-11 17:19:42 -0700782 void swapWithBackgroundCall(Call call) {
783 if (isServiceValid("swapWithBackgroundCall")) {
784 try {
785 logOutgoing("swapWithBackgroundCall %s", mCallIdMapper.getCallId(call));
786 mServiceInterface.swapWithBackgroundCall(mCallIdMapper.getCallId(call));
787 } catch (RemoteException ignored) {
788 }
789 }
790 }
791
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700792 /** {@inheritDoc} */
793 @Override
794 protected void setServiceInterface(IBinder binder) {
795 if (binder == null) {
796 // We have lost our service connection. Notify the world that this service is done.
797 // We must notify the adapter before CallsManager. The adapter will force any pending
798 // outgoing calls to try the next service. This needs to happen before CallsManager
799 // tries to clean up any calls still associated with this service.
800 handleConnectionServiceDeath();
801 CallsManager.getInstance().handleConnectionServiceDeath(this);
802 mServiceInterface = null;
803 } else {
804 mServiceInterface = IConnectionService.Stub.asInterface(binder);
805 addConnectionServiceAdapter(mAdapter);
806 }
807 }
808
809 /**
810 * Called when the associated connection service dies.
811 */
812 private void handleConnectionServiceDeath() {
Sailesh Nepal664837f2014-07-14 16:31:51 -0700813 if (!mPendingResponses.isEmpty()) {
814 CreateConnectionResponse[] responses = mPendingResponses.values().toArray(
815 new CreateConnectionResponse[mPendingResponses.values().size()]);
816 mPendingResponses.clear();
817 for (int i = 0; i < responses.length; i++) {
818 responses[i].handleCreateConnectionFailed(DisconnectCause.ERROR_UNSPECIFIED, null);
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700819 }
820 }
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700821 mCallIdMapper.clear();
822 }
823
824 private void logIncoming(String msg, Object... params) {
825 Log.d(this, "ConnectionService -> Telecomm: " + msg, params);
826 }
827
828 private void logOutgoing(String msg, Object... params) {
829 Log.d(this, "Telecomm -> ConnectionService: " + msg, params);
830 }
831
832 private void queryRemoteConnectionServices(final RemoteServiceCallback callback) {
833 final List<IBinder> connectionServices = new ArrayList<>();
834 final List<ComponentName> components = new ArrayList<>();
Sailesh Nepal664837f2014-07-14 16:31:51 -0700835 final List<ConnectionServiceWrapper> servciesAttempted = new ArrayList<>();
Sailesh Nepal905dfba2014-07-14 08:20:41 -0700836 final Collection<ConnectionServiceWrapper> services =
837 mConnectionServiceRepository.lookupServices();
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700838
Sailesh Nepal664837f2014-07-14 16:31:51 -0700839 Log.v(this, "queryRemoteConnectionServices, services: " + services.size());
840
Sailesh Nepal905dfba2014-07-14 08:20:41 -0700841 for (ConnectionServiceWrapper cs : services) {
842 if (cs != this) {
843 final ConnectionServiceWrapper currentConnectionService = cs;
844 cs.mBinder.bind(new BindCallback() {
Sailesh Nepal905dfba2014-07-14 08:20:41 -0700845 @Override
846 public void onSuccess() {
847 Log.d(this, "Adding ***** %s", currentConnectionService.getComponentName());
848 connectionServices.add(
849 currentConnectionService.mServiceInterface.asBinder());
850 components.add(currentConnectionService.getComponentName());
851 maybeComplete();
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700852 }
Sailesh Nepal905dfba2014-07-14 08:20:41 -0700853
854 @Override
855 public void onFailure() {
Sailesh Nepal905dfba2014-07-14 08:20:41 -0700856 maybeComplete();
857 }
858
859 private void maybeComplete() {
Sailesh Nepal664837f2014-07-14 16:31:51 -0700860 servciesAttempted.add(currentConnectionService);
861 if (servciesAttempted.size() == services.size() - 1) {
Sailesh Nepal905dfba2014-07-14 08:20:41 -0700862 try {
863 callback.onResult(components, connectionServices);
864 } catch (RemoteException ignored) {
865 }
866 }
867 }
868 });
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700869 }
Sailesh Nepal905dfba2014-07-14 08:20:41 -0700870 }
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700871 }
872}