blob: eb2e0ac9a8181fd38a650d882140ddd7374d5512 [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;
28import android.telecomm.ConnectionService;
Sailesh Nepalc92c4362014-07-04 18:33:21 -070029import android.telecomm.ConnectionRequest;
30import android.telecomm.GatewayInfo;
Sailesh Nepal35faf8c2014-07-08 22:02:34 -070031import android.telecomm.StatusHints;
Sailesh Nepalc92c4362014-07-04 18:33:21 -070032import android.telecomm.TelecommConstants;
33import android.telephony.DisconnectCause;
34
35import com.android.internal.os.SomeArgs;
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.ICallVideoProvider;
39import com.android.internal.telecomm.RemoteServiceCallback;
Sailesh Nepalc92c4362014-07-04 18:33:21 -070040import com.google.common.base.Preconditions;
41import com.google.common.collect.ImmutableList;
42
43import org.apache.http.conn.ClientConnectionRequest;
44
45import java.util.ArrayList;
46import java.util.Collection;
47import java.util.HashMap;
48import java.util.HashSet;
49import java.util.List;
50import java.util.Map;
51import java.util.Set;
52
53/**
54 * Wrapper for {@link IConnectionService}s, handles binding to {@link IConnectionService} and keeps
55 * track of when the object can safely be unbound. Other classes should not use
56 * {@link IConnectionService} directly and instead should use this class to invoke methods of
57 * {@link IConnectionService}.
58 */
59final class ConnectionServiceWrapper extends ServiceBinder<IConnectionService> {
Sailesh Nepal664837f2014-07-14 16:31:51 -070060 private static final int MSG_HANDLE_CREATE_CONNECTION_SUCCESSFUL = 1;
61 private static final int MSG_HANDLE_CREATE_CONNECTION_FAILED = 2;
62 private static final int MSG_HANDLE_CREATE_CONNECTION_CANCELLED = 3;
63 private static final int MSG_SET_ACTIVE = 4;
64 private static final int MSG_SET_RINGING = 5;
65 private static final int MSG_SET_DIALING = 6;
66 private static final int MSG_SET_DISCONNECTED = 7;
67 private static final int MSG_SET_ON_HOLD = 8;
68 private static final int MSG_SET_REQUESTING_RINGBACK = 9;
69 private static final int MSG_SET_CALL_CAPABILITIES = 10;
70 private static final int MSG_SET_IS_CONFERENCED = 11;
71 private static final int MSG_ADD_CONFERENCE_CALL = 12;
72 private static final int MSG_REMOVE_CALL = 13;
73 private static final int MSG_ON_POST_DIAL_WAIT = 14;
74 private static final int MSG_QUERY_REMOTE_CALL_SERVICES = 15;
75 private static final int MSG_SET_CALL_VIDEO_PROVIDER = 16;
76 private static final int MSG_SET_AUDIO_MODE_IS_VOIP = 17;
77 private static final int MSG_SET_STATUS_HINTS = 18;
78 private static final int MSG_SET_HANDLE = 19;
79 private static final int MSG_SET_CALLER_DISPLAY_NAME = 20;
Tyler Gunn0a388fc2014-07-17 12:21:17 -070080 private static final int MSG_SET_VIDEO_STATE = 21;
Sailesh Nepal9d58de52014-07-18 14:53:19 -070081 private static final int MSG_START_ACTIVITY_FROM_IN_CALL = 22;
Sailesh Nepalc92c4362014-07-04 18:33:21 -070082
83 private final Handler mHandler = new Handler() {
84 @Override
85 public void handleMessage(Message msg) {
86 Call call;
87 switch (msg.what) {
Sailesh Nepal664837f2014-07-14 16:31:51 -070088 case MSG_HANDLE_CREATE_CONNECTION_SUCCESSFUL: {
Sailesh Nepalc92c4362014-07-04 18:33:21 -070089 ConnectionRequest request = (ConnectionRequest) msg.obj;
Sailesh Nepal664837f2014-07-14 16:31:51 -070090 if (mPendingResponses.containsKey(request.getCallId())) {
91 mPendingResponses.remove(
92 request.getCallId()).handleCreateConnectionSuccessful(request);
Sailesh Nepalc92c4362014-07-04 18:33:21 -070093 } else {
Sailesh Nepal664837f2014-07-14 16:31:51 -070094 //Log.w(this, "handleCreateConnectionSuccessful, unknown call: %s", callId);
Sailesh Nepalc92c4362014-07-04 18:33:21 -070095 }
96 break;
97 }
Sailesh Nepal664837f2014-07-14 16:31:51 -070098 case MSG_HANDLE_CREATE_CONNECTION_FAILED: {
Sailesh Nepalc92c4362014-07-04 18:33:21 -070099 SomeArgs args = (SomeArgs) msg.obj;
100 try {
Sailesh Nepala49c6432014-07-07 22:47:11 -0700101 ConnectionRequest request = (ConnectionRequest) args.arg1;
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700102 int statusCode = args.argi1;
103 String statusMsg = (String) args.arg2;
Sailesh Nepal664837f2014-07-14 16:31:51 -0700104 if (mPendingResponses.containsKey(request.getCallId())) {
105 mPendingResponses.remove(request.getCallId())
106 .handleCreateConnectionFailed(statusCode, statusMsg);
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700107 mCallIdMapper.removeCall(request.getCallId());
108 } else {
Sailesh Nepal664837f2014-07-14 16:31:51 -0700109 //Log.w(this, "handleCreateConnectionFailed, unknown call: %s", callId);
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700110 }
111 } finally {
112 args.recycle();
113 }
114 break;
115 }
Sailesh Nepal664837f2014-07-14 16:31:51 -0700116 case MSG_HANDLE_CREATE_CONNECTION_CANCELLED: {
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700117 ConnectionRequest request = (ConnectionRequest) msg.obj;
Sailesh Nepal664837f2014-07-14 16:31:51 -0700118 if (mPendingResponses.containsKey(request.getCallId())) {
119 mPendingResponses.remove(
120 request.getCallId()).handleCreateConnectionCancelled();
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700121 } else {
Sailesh Nepal664837f2014-07-14 16:31:51 -0700122 //Log.w(this, "handleCreateConnectionCancelled, unknown call: %s", callId);
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700123 }
124 break;
125 }
126 case MSG_SET_ACTIVE:
127 call = mCallIdMapper.getCall(msg.obj);
128 if (call != null) {
129 mCallsManager.markCallAsActive(call);
130 } else {
131 //Log.w(this, "setActive, unknown call id: %s", msg.obj);
132 }
133 break;
134 case MSG_SET_RINGING:
135 call = mCallIdMapper.getCall(msg.obj);
136 if (call != null) {
137 mCallsManager.markCallAsRinging(call);
138 } else {
139 //Log.w(this, "setRinging, unknown call id: %s", msg.obj);
140 }
141 break;
142 case MSG_SET_DIALING:
143 call = mCallIdMapper.getCall(msg.obj);
144 if (call != null) {
145 mCallsManager.markCallAsDialing(call);
146 } else {
147 //Log.w(this, "setDialing, unknown call id: %s", msg.obj);
148 }
149 break;
150 case MSG_SET_DISCONNECTED: {
151 SomeArgs args = (SomeArgs) msg.obj;
152 try {
153 call = mCallIdMapper.getCall(args.arg1);
154 String disconnectMessage = (String) args.arg2;
155 int disconnectCause = args.argi1;
156 if (call != null) {
157 mCallsManager.markCallAsDisconnected(call, disconnectCause,
158 disconnectMessage);
159 } else {
160 //Log.w(this, "setDisconnected, unknown call id: %s", args.arg1);
161 }
162 } finally {
163 args.recycle();
164 }
165 break;
166 }
167 case MSG_SET_ON_HOLD:
168 call = mCallIdMapper.getCall(msg.obj);
169 if (call != null) {
170 mCallsManager.markCallAsOnHold(call);
171 } else {
172 //Log.w(this, "setOnHold, unknown call id: %s", msg.obj);
173 }
174 break;
175 case MSG_SET_REQUESTING_RINGBACK: {
Sailesh Nepal9d58de52014-07-18 14:53:19 -0700176 call = mCallIdMapper.getCall(msg.obj);
177 if (call != null) {
178 call.setRequestingRingback(msg.arg1 == 1);
179 } else {
180 //Log.w(this, "setRingback, unknown call id: %s", args.arg1);
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700181 }
182 break;
183 }
Sailesh Nepale20bc972014-07-09 21:22:36 -0700184 case MSG_SET_CALL_CAPABILITIES: {
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700185 call = mCallIdMapper.getCall(msg.obj);
186 if (call != null) {
Sailesh Nepale20bc972014-07-09 21:22:36 -0700187 call.setCallCapabilities(msg.arg1);
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700188 } else {
189 //Log.w(ConnectionServiceWrapper.this,
Sailesh Nepale20bc972014-07-09 21:22:36 -0700190 // "setCallCapabilities, unknown call id: %s", msg.obj);
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700191 }
192 break;
193 }
194 case MSG_SET_IS_CONFERENCED: {
195 SomeArgs args = (SomeArgs) msg.obj;
196 try {
197 Call childCall = mCallIdMapper.getCall(args.arg1);
198 if (childCall != null) {
199 String conferenceCallId = (String) args.arg2;
200 if (conferenceCallId == null) {
201 childCall.setParentCall(null);
202 } else {
203 Call conferenceCall = mCallIdMapper.getCall(conferenceCallId);
204 if (conferenceCall != null &&
205 !mPendingConferenceCalls.contains(conferenceCall)) {
206 childCall.setParentCall(conferenceCall);
207 } else {
208 //Log.w(this, "setIsConferenced, unknown conference id %s",
209 // conferenceCallId);
210 }
211 }
212 } else {
213 //Log.w(this, "setIsConferenced, unknown call id: %s", args.arg1);
214 }
215 } finally {
216 args.recycle();
217 }
218 break;
219 }
220 case MSG_ADD_CONFERENCE_CALL: {
221 Call conferenceCall = mCallIdMapper.getCall(msg.obj);
222 if (mPendingConferenceCalls.remove(conferenceCall)) {
223 Log.v(this, "confirming conf call %s", conferenceCall);
224 conferenceCall.confirmConference();
225 } else {
226 //Log.w(this, "addConference, unknown call id: %s", callId);
227 }
228 break;
229 }
230 case MSG_REMOVE_CALL:
231 break;
232 case MSG_ON_POST_DIAL_WAIT: {
233 SomeArgs args = (SomeArgs) msg.obj;
234 try {
235 call = mCallIdMapper.getCall(args.arg1);
236 if (call != null) {
237 String remaining = (String) args.arg2;
238 call.onPostDialWait(remaining);
239 } else {
240 //Log.w(this, "onPostDialWait, unknown call id: %s", args.arg1);
241 }
242 } finally {
243 args.recycle();
244 }
245 break;
246 }
247 case MSG_QUERY_REMOTE_CALL_SERVICES: {
Sailesh Nepal664837f2014-07-14 16:31:51 -0700248 queryRemoteConnectionServices((RemoteServiceCallback) msg.obj);
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700249 break;
250 }
251 case MSG_SET_CALL_VIDEO_PROVIDER: {
252 SomeArgs args = (SomeArgs) msg.obj;
253 try {
254 call = mCallIdMapper.getCall(args.arg1);
255 ICallVideoProvider callVideoProvider = (ICallVideoProvider) args.arg2;
256 if (call != null) {
257 call.setCallVideoProvider(callVideoProvider);
258 }
259 } finally {
260 args.recycle();
261 }
262 break;
263 }
Sailesh Nepal7e669572014-07-08 21:29:12 -0700264 case MSG_SET_AUDIO_MODE_IS_VOIP: {
Sailesh Nepale20bc972014-07-09 21:22:36 -0700265 call = mCallIdMapper.getCall(msg.obj);
266 if (call != null) {
267 call.setAudioModeIsVoip(msg.arg1 == 1);
Sailesh Nepal7e669572014-07-08 21:29:12 -0700268 }
269 break;
270 }
Sailesh Nepal35faf8c2014-07-08 22:02:34 -0700271 case MSG_SET_STATUS_HINTS: {
272 SomeArgs args = (SomeArgs) msg.obj;
273 try {
274 call = mCallIdMapper.getCall(args.arg1);
275 StatusHints statusHints = (StatusHints) args.arg2;
276 if (call != null) {
277 call.setStatusHints(statusHints);
278 }
279 } finally {
280 args.recycle();
281 }
282 break;
283 }
Sailesh Nepale8ecb982014-07-11 17:19:42 -0700284 case MSG_SET_HANDLE: {
285 SomeArgs args = (SomeArgs) msg.obj;
286 try {
287 call = mCallIdMapper.getCall(args.arg1);
288 if (call != null) {
289 call.setHandle((Uri) args.arg2, args.argi1);
290 }
291 } finally {
292 args.recycle();
293 }
294 break;
295 }
296 case MSG_SET_CALLER_DISPLAY_NAME: {
297 SomeArgs args = (SomeArgs) msg.obj;
298 try {
299 call = mCallIdMapper.getCall(args.arg1);
300 if (call != null) {
301 call.setCallerDisplayName((String) args.arg2, args.argi1);
302 }
303 } finally {
304 args.recycle();
305 }
306 break;
307 }
Tyler Gunn0a388fc2014-07-17 12:21:17 -0700308 case MSG_SET_VIDEO_STATE: {
309 call = mCallIdMapper.getCall(msg.obj);
310 if (call != null) {
311 call.setVideoState(msg.arg1);
312 }
313 }
Sailesh Nepal9d58de52014-07-18 14:53:19 -0700314 case MSG_START_ACTIVITY_FROM_IN_CALL: {
315 SomeArgs args = (SomeArgs) msg.obj;
316 try {
317 call = mCallIdMapper.getCall(args.arg1);
318 if (call != null) {
319 call.startActivityFromInCall((PendingIntent) args.arg2);
320 }
321 } finally {
322 args.recycle();
323 }
324 break;
325 }
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700326 }
327 }
328 };
329
330 private final class Adapter extends IConnectionServiceAdapter.Stub {
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700331 @Override
Sailesh Nepal664837f2014-07-14 16:31:51 -0700332 public void handleCreateConnectionSuccessful(ConnectionRequest request) {
333 logIncoming("handleCreateConnectionSuccessful %s", request);
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700334 mCallIdMapper.checkValidCallId(request.getCallId());
Sailesh Nepal664837f2014-07-14 16:31:51 -0700335 mHandler.obtainMessage(MSG_HANDLE_CREATE_CONNECTION_SUCCESSFUL, request).sendToTarget();
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700336 }
337
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700338 @Override
Sailesh Nepal664837f2014-07-14 16:31:51 -0700339 public void handleCreateConnectionFailed(
340 ConnectionRequest request, int errorCode, String errorMsg) {
341 logIncoming("handleCreateConnectionFailed %s %d %s", request, errorCode, errorMsg);
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700342 mCallIdMapper.checkValidCallId(request.getCallId());
343 SomeArgs args = SomeArgs.obtain();
344 args.arg1 = request;
345 args.argi1 = errorCode;
346 args.arg2 = errorMsg;
Sailesh Nepal664837f2014-07-14 16:31:51 -0700347 mHandler.obtainMessage(MSG_HANDLE_CREATE_CONNECTION_FAILED, args).sendToTarget();
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700348 }
349
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700350 @Override
Sailesh Nepal664837f2014-07-14 16:31:51 -0700351 public void handleCreateConnectionCancelled(ConnectionRequest request) {
352 logIncoming("handleCreateConnectionCancelled %s", request);
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700353 mCallIdMapper.checkValidCallId(request.getCallId());
Sailesh Nepal664837f2014-07-14 16:31:51 -0700354 mHandler.obtainMessage(MSG_HANDLE_CREATE_CONNECTION_CANCELLED, request).sendToTarget();
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700355 }
356
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700357 @Override
358 public void setActive(String callId) {
359 logIncoming("setActive %s", callId);
360 mCallIdMapper.checkValidCallId(callId);
361 mHandler.obtainMessage(MSG_SET_ACTIVE, callId).sendToTarget();
362 }
363
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700364 @Override
365 public void setRinging(String callId) {
366 logIncoming("setRinging %s", callId);
367 mCallIdMapper.checkValidCallId(callId);
368 mHandler.obtainMessage(MSG_SET_RINGING, callId).sendToTarget();
369 }
370
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700371 @Override
372 public void setCallVideoProvider(String callId, ICallVideoProvider callVideoProvider) {
373 logIncoming("setCallVideoProvider %s", callId);
374 mCallIdMapper.checkValidCallId(callId);
375 SomeArgs args = SomeArgs.obtain();
376 args.arg1 = callId;
377 args.arg2 = callVideoProvider;
378 mHandler.obtainMessage(MSG_SET_CALL_VIDEO_PROVIDER, args).sendToTarget();
379 }
380
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700381 @Override
382 public void setDialing(String callId) {
383 logIncoming("setDialing %s", callId);
384 mCallIdMapper.checkValidCallId(callId);
385 mHandler.obtainMessage(MSG_SET_DIALING, callId).sendToTarget();
386 }
387
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700388 @Override
389 public void setDisconnected(
390 String callId, int disconnectCause, String disconnectMessage) {
391 logIncoming("setDisconnected %s %d %s", callId, disconnectCause, disconnectMessage);
392 mCallIdMapper.checkValidCallId(callId);
393 SomeArgs args = SomeArgs.obtain();
394 args.arg1 = callId;
395 args.arg2 = disconnectMessage;
396 args.argi1 = disconnectCause;
397 mHandler.obtainMessage(MSG_SET_DISCONNECTED, args).sendToTarget();
398 }
399
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700400 @Override
401 public void setOnHold(String callId) {
402 logIncoming("setOnHold %s", callId);
403 mCallIdMapper.checkValidCallId(callId);
404 mHandler.obtainMessage(MSG_SET_ON_HOLD, callId).sendToTarget();
405 }
406
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700407 @Override
408 public void setRequestingRingback(String callId, boolean ringback) {
409 logIncoming("setRequestingRingback %s %b", callId, ringback);
410 mCallIdMapper.checkValidCallId(callId);
Sailesh Nepal9d58de52014-07-18 14:53:19 -0700411 mHandler.obtainMessage(MSG_SET_REQUESTING_RINGBACK, ringback ? 1 : 0, 0, callId)
412 .sendToTarget();
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700413 }
414
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700415 @Override
416 public void removeCall(String callId) {
417 logIncoming("removeCall %s", callId);
418 }
419
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700420 @Override
Sailesh Nepale20bc972014-07-09 21:22:36 -0700421 public void setCallCapabilities(String callId, int callCapabilities) {
422 logIncoming("setCallCapabilities %s %d", callId, callCapabilities);
423 mHandler.obtainMessage(MSG_SET_CALL_CAPABILITIES, callCapabilities, 0, callId)
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700424 .sendToTarget();
425 }
426
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700427 @Override
428 public void setIsConferenced(String callId, String conferenceCallId) {
429 logIncoming("setIsConferenced %s %s", callId, conferenceCallId);
430 SomeArgs args = SomeArgs.obtain();
431 args.arg1 = callId;
432 args.arg2 = conferenceCallId;
433 mHandler.obtainMessage(MSG_SET_IS_CONFERENCED, args).sendToTarget();
434 }
435
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700436 @Override
437 public void addConferenceCall(String callId) {
438 logIncoming("addConferenceCall %s", callId);
439 mCallIdMapper.checkValidCallId(callId);
440 mHandler.obtainMessage(MSG_ADD_CONFERENCE_CALL, callId).sendToTarget();
441 }
442
443 @Override
444 public void onPostDialWait(String callId, String remaining) throws RemoteException {
445 logIncoming("onPostDialWait %s %s", callId, remaining);
446 mCallIdMapper.checkValidCallId(callId);
447 SomeArgs args = SomeArgs.obtain();
448 args.arg1 = callId;
449 args.arg2 = remaining;
450 mHandler.obtainMessage(MSG_ON_POST_DIAL_WAIT, args).sendToTarget();
451 }
452
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700453 @Override
454 public void queryRemoteConnectionServices(RemoteServiceCallback callback) {
455 logIncoming("queryRemoteCSs");
456 mHandler.obtainMessage(MSG_QUERY_REMOTE_CALL_SERVICES, callback).sendToTarget();
457 }
458
459 @Override
Tyler Gunn0a388fc2014-07-17 12:21:17 -0700460 public void setVideoState(String callId, int videoState) {
461 logIncoming("setVideoState %s %d", callId, videoState);
462 mCallIdMapper.checkValidCallId(callId);
463 mHandler.obtainMessage(MSG_SET_VIDEO_STATE, videoState, 0, callId).sendToTarget();
464 }
465
466 @Override
Sailesh Nepal7e669572014-07-08 21:29:12 -0700467 public void setAudioModeIsVoip(String callId, boolean isVoip) {
Sailesh Nepal7fa33ca2014-07-10 15:28:21 -0700468 logIncoming("setAudioModeIsVoip %s %b", callId, isVoip);
Sailesh Nepal7e669572014-07-08 21:29:12 -0700469 mCallIdMapper.checkValidCallId(callId);
Sailesh Nepale20bc972014-07-09 21:22:36 -0700470 mHandler.obtainMessage(MSG_SET_AUDIO_MODE_IS_VOIP, isVoip ? 1 : 0, 0,
471 callId).sendToTarget();
Sailesh Nepal7e669572014-07-08 21:29:12 -0700472 }
Sailesh Nepal35faf8c2014-07-08 22:02:34 -0700473
474 @Override
475 public void setStatusHints(String callId, StatusHints statusHints) {
476 logIncoming("setStatusHints %s %s", callId, statusHints);
477 mCallIdMapper.checkValidCallId(callId);
478 SomeArgs args = SomeArgs.obtain();
479 args.arg1 = callId;
480 args.arg2 = statusHints;
481 mHandler.obtainMessage(MSG_SET_STATUS_HINTS, args).sendToTarget();
482 }
Sailesh Nepale8ecb982014-07-11 17:19:42 -0700483
484 @Override
485 public void setHandle(String callId, Uri handle, int presentation) {
486 logIncoming("setHandle %s %s %d", callId, handle, presentation);
487 mCallIdMapper.checkValidCallId(callId);
488 SomeArgs args = SomeArgs.obtain();
489 args.arg1 = callId;
490 args.arg2 = handle;
491 args.argi1 = presentation;
492 mHandler.obtainMessage(MSG_SET_HANDLE, args).sendToTarget();
493 }
494
495 @Override
496 public void setCallerDisplayName(
497 String callId, String callerDisplayName, int presentation) {
498 logIncoming("setCallerDisplayName %s %s %d", callId, callerDisplayName, presentation);
499 mCallIdMapper.checkValidCallId(callId);
500 SomeArgs args = SomeArgs.obtain();
501 args.arg1 = callId;
502 args.arg2 = callerDisplayName;
503 args.argi1 = presentation;
504 mHandler.obtainMessage(MSG_SET_CALLER_DISPLAY_NAME, args).sendToTarget();
505 }
Sailesh Nepal9d58de52014-07-18 14:53:19 -0700506
507 @Override
508 public void startActivityFromInCall(String callId, PendingIntent intent) {
509 logIncoming("startActivityFromInCall %s %s", callId, intent);
510 mCallIdMapper.checkValidCallId(callId);
511 SomeArgs args = SomeArgs.obtain();
512 args.arg1 = callId;
513 args.arg2 = intent;
514 mHandler.obtainMessage(MSG_START_ACTIVITY_FROM_IN_CALL, args).sendToTarget();
515 }
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700516 }
517
518 private final Adapter mAdapter = new Adapter();
519 private final CallsManager mCallsManager = CallsManager.getInstance();
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700520 private final Set<Call> mPendingConferenceCalls = new HashSet<>();
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700521 private final CallIdMapper mCallIdMapper = new CallIdMapper("ConnectionService");
Sailesh Nepal664837f2014-07-14 16:31:51 -0700522 private final Map<String, CreateConnectionResponse> mPendingResponses = new HashMap<>();
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700523
524 private Binder mBinder = new Binder();
525 private IConnectionService mServiceInterface;
Sailesh Nepal905dfba2014-07-14 08:20:41 -0700526 private final ConnectionServiceRepository mConnectionServiceRepository;
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700527
528 /**
Sailesh Nepal905dfba2014-07-14 08:20:41 -0700529 * Creates a connection service.
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700530 *
Sailesh Nepal905dfba2014-07-14 08:20:41 -0700531 * @param componentName The component name of the service with which to bind.
Sailesh Nepal905dfba2014-07-14 08:20:41 -0700532 * @param connectionServiceRepository Connection service repository.
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700533 */
534 ConnectionServiceWrapper(
Sailesh Nepal664837f2014-07-14 16:31:51 -0700535 ComponentName componentName, ConnectionServiceRepository connectionServiceRepository) {
Sailesh Nepal905dfba2014-07-14 08:20:41 -0700536 super(TelecommConstants.ACTION_CONNECTION_SERVICE, componentName);
Sailesh Nepal905dfba2014-07-14 08:20:41 -0700537 mConnectionServiceRepository = connectionServiceRepository;
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700538 }
539
540 /** See {@link IConnectionService#addConnectionServiceAdapter}. */
541 private void addConnectionServiceAdapter(IConnectionServiceAdapter adapter) {
542 if (isServiceValid("addConnectionServiceAdapter")) {
543 try {
Sailesh Nepal3fe8b722014-07-08 10:07:26 -0700544 logOutgoing("addConnectionServiceAdapter %s", adapter);
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700545 mServiceInterface.addConnectionServiceAdapter(adapter);
546 } catch (RemoteException e) {
547 }
548 }
549 }
550
551 /**
Sailesh Nepal664837f2014-07-14 16:31:51 -0700552 * Creates a new connection for a new outgoing call or to attach to an existing incoming call.
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700553 */
Sailesh Nepal664837f2014-07-14 16:31:51 -0700554 void createConnection(final Call call, final CreateConnectionResponse response) {
555 Log.d(this, "createConnection(%s) via %s.", call, getComponentName());
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700556 BindCallback callback = new BindCallback() {
557 @Override
558 public void onSuccess() {
559 String callId = mCallIdMapper.getCallId(call);
Sailesh Nepal664837f2014-07-14 16:31:51 -0700560 mPendingResponses.put(callId, response);
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700561
562 GatewayInfo gatewayInfo = call.getGatewayInfo();
563 Bundle extras = call.getExtras();
564 if (gatewayInfo != null && gatewayInfo.getGatewayProviderPackageName() != null &&
565 gatewayInfo.getOriginalHandle() != null) {
566 extras = (Bundle) extras.clone();
567 extras.putString(
568 NewOutgoingCallIntentBroadcaster.EXTRA_GATEWAY_PROVIDER_PACKAGE,
569 gatewayInfo.getGatewayProviderPackageName());
570 extras.putParcelable(
571 NewOutgoingCallIntentBroadcaster.EXTRA_GATEWAY_ORIGINAL_URI,
572 gatewayInfo.getOriginalHandle());
573 }
Sailesh Nepale8ecb982014-07-11 17:19:42 -0700574 ConnectionRequest request = new ConnectionRequest(
575 call.getPhoneAccount(),
576 callId,
577 call.getHandle(),
578 call.getHandlePresentation(),
579 extras,
Tyler Gunnc4abd912014-07-08 14:22:10 -0700580 call.getVideoState());
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700581
582 try {
Sailesh Nepal664837f2014-07-14 16:31:51 -0700583 mServiceInterface.createConnection(request, call.isIncoming());
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700584 } catch (RemoteException e) {
Sailesh Nepal664837f2014-07-14 16:31:51 -0700585 Log.e(this, e, "Failure to createConnection -- %s", getComponentName());
586 mPendingResponses.remove(callId).handleCreateConnectionFailed(
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700587 DisconnectCause.ERROR_UNSPECIFIED, e.toString());
588 }
589 }
590
591 @Override
592 public void onFailure() {
Sailesh Nepal905dfba2014-07-14 08:20:41 -0700593 Log.e(this, new Exception(), "Failure to call %s", getComponentName());
Sailesh Nepal664837f2014-07-14 16:31:51 -0700594 response.handleCreateConnectionFailed(DisconnectCause.ERROR_UNSPECIFIED, null);
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700595 }
596 };
597
598 mBinder.bind(callback);
599 }
600
601 /** @see ConnectionService#abort(String) */
602 void abort(Call call) {
603 // Clear out any pending outgoing call data
604 String callId = mCallIdMapper.getCallId(call);
605
606 // If still bound, tell the connection service to abort.
607 if (isServiceValid("abort")) {
608 try {
609 logOutgoing("abort %s", callId);
610 mServiceInterface.abort(callId);
611 } catch (RemoteException e) {
612 }
613 }
614
615 removeCall(call);
616 }
617
618 /** @see ConnectionService#hold(String) */
619 void hold(Call call) {
620 if (isServiceValid("hold")) {
621 try {
622 logOutgoing("hold %s", mCallIdMapper.getCallId(call));
623 mServiceInterface.hold(mCallIdMapper.getCallId(call));
624 } catch (RemoteException e) {
625 }
626 }
627 }
628
629 /** @see ConnectionService#unhold(String) */
630 void unhold(Call call) {
631 if (isServiceValid("unhold")) {
632 try {
633 logOutgoing("unhold %s", mCallIdMapper.getCallId(call));
634 mServiceInterface.unhold(mCallIdMapper.getCallId(call));
635 } catch (RemoteException e) {
636 }
637 }
638 }
639
640 /** @see ConnectionService#onAudioStateChanged(String,CallAudioState) */
641 void onAudioStateChanged(Call activeCall, CallAudioState audioState) {
642 if (isServiceValid("onAudioStateChanged")) {
643 try {
644 logOutgoing("onAudioStateChanged %s %s",
645 mCallIdMapper.getCallId(activeCall), audioState);
646 mServiceInterface.onAudioStateChanged(mCallIdMapper.getCallId(activeCall),
647 audioState);
648 } catch (RemoteException e) {
649 }
650 }
651 }
652
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700653 /** @see ConnectionService#disconnect(String) */
654 void disconnect(Call call) {
655 if (isServiceValid("disconnect")) {
656 try {
657 logOutgoing("disconnect %s", mCallIdMapper.getCallId(call));
658 mServiceInterface.disconnect(mCallIdMapper.getCallId(call));
659 } catch (RemoteException e) {
660 }
661 }
662 }
663
664 /** @see ConnectionService#answer(String) */
Andrew Lee38931d02014-07-16 10:17:36 -0700665 void answer(Call call, int videoState) {
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700666 if (isServiceValid("answer")) {
667 try {
Andrew Lee38931d02014-07-16 10:17:36 -0700668 logOutgoing("answer %s %d", mCallIdMapper.getCallId(call), videoState);
669 mServiceInterface.answer(mCallIdMapper.getCallId(call), videoState);
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700670 } catch (RemoteException e) {
671 }
672 }
673 }
674
675 /** @see ConnectionService#reject(String) */
676 void reject(Call call) {
677 if (isServiceValid("reject")) {
678 try {
679 logOutgoing("reject %s", mCallIdMapper.getCallId(call));
680 mServiceInterface.reject(mCallIdMapper.getCallId(call));
681 } catch (RemoteException e) {
682 }
683 }
684 }
685
686 /** @see ConnectionService#playDtmfTone(String,char) */
687 void playDtmfTone(Call call, char digit) {
688 if (isServiceValid("playDtmfTone")) {
689 try {
690 logOutgoing("playDtmfTone %s %c", mCallIdMapper.getCallId(call), digit);
691 mServiceInterface.playDtmfTone(mCallIdMapper.getCallId(call), digit);
692 } catch (RemoteException e) {
693 }
694 }
695 }
696
697 /** @see ConnectionService#stopDtmfTone(String) */
698 void stopDtmfTone(Call call) {
699 if (isServiceValid("stopDtmfTone")) {
700 try {
701 logOutgoing("stopDtmfTone %s", mCallIdMapper.getCallId(call));
702 mServiceInterface.stopDtmfTone(mCallIdMapper.getCallId(call));
703 } catch (RemoteException e) {
704 }
705 }
706 }
707
708 void addCall(Call call) {
709 if (mCallIdMapper.getCallId(call) == null) {
710 mCallIdMapper.addCall(call);
711 }
712 }
713
714 /**
715 * Associates newCall with this connection service by replacing callToReplace.
716 */
717 void replaceCall(Call newCall, Call callToReplace) {
718 Preconditions.checkState(callToReplace.getConnectionService() == this);
719 mCallIdMapper.replaceCall(newCall, callToReplace);
720 }
721
722 void removeCall(Call call) {
Sailesh Nepal664837f2014-07-14 16:31:51 -0700723 CreateConnectionResponse response = mPendingResponses.remove(mCallIdMapper.getCallId(call));
724 if (response != null) {
725 response.handleCreateConnectionFailed(DisconnectCause.ERROR_UNSPECIFIED, null);
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700726 }
727
728 mCallIdMapper.removeCall(call);
729 }
730
731 void onPostDialContinue(Call call, boolean proceed) {
732 if (isServiceValid("onPostDialContinue")) {
733 try {
734 logOutgoing("onPostDialContinue %s %b", mCallIdMapper.getCallId(call), proceed);
735 mServiceInterface.onPostDialContinue(mCallIdMapper.getCallId(call), proceed);
736 } catch (RemoteException ignored) {
737 }
738 }
739 }
740
741 void onPhoneAccountClicked(Call call) {
742 if (isServiceValid("onPhoneAccountClicked")) {
743 try {
744 logOutgoing("onPhoneAccountClicked %s", mCallIdMapper.getCallId(call));
745 mServiceInterface.onPhoneAccountClicked(mCallIdMapper.getCallId(call));
746 } catch (RemoteException ignored) {
747 }
748 }
749 }
750
751 void conference(final Call conferenceCall, Call call) {
752 if (isServiceValid("conference")) {
753 try {
754 conferenceCall.setConnectionService(this);
755 mPendingConferenceCalls.add(conferenceCall);
756 mHandler.postDelayed(new Runnable() {
757 @Override public void run() {
758 if (mPendingConferenceCalls.remove(conferenceCall)) {
759 conferenceCall.expireConference();
760 Log.i(this, "Conference call expired: %s", conferenceCall);
761 }
762 }
763 }, Timeouts.getConferenceCallExpireMillis());
764
765 logOutgoing("conference %s %s",
766 mCallIdMapper.getCallId(conferenceCall),
767 mCallIdMapper.getCallId(call));
768 mServiceInterface.conference(
769 mCallIdMapper.getCallId(conferenceCall),
770 mCallIdMapper.getCallId(call));
771 } catch (RemoteException ignored) {
772 }
773 }
774 }
775
776 void splitFromConference(Call call) {
777 if (isServiceValid("splitFromConference")) {
778 try {
779 logOutgoing("splitFromConference %s", mCallIdMapper.getCallId(call));
780 mServiceInterface.splitFromConference(mCallIdMapper.getCallId(call));
781 } catch (RemoteException ignored) {
782 }
783 }
784 }
785
Sailesh Nepale8ecb982014-07-11 17:19:42 -0700786 void swapWithBackgroundCall(Call call) {
787 if (isServiceValid("swapWithBackgroundCall")) {
788 try {
789 logOutgoing("swapWithBackgroundCall %s", mCallIdMapper.getCallId(call));
790 mServiceInterface.swapWithBackgroundCall(mCallIdMapper.getCallId(call));
791 } catch (RemoteException ignored) {
792 }
793 }
794 }
795
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700796 /** {@inheritDoc} */
797 @Override
798 protected void setServiceInterface(IBinder binder) {
799 if (binder == null) {
800 // We have lost our service connection. Notify the world that this service is done.
801 // We must notify the adapter before CallsManager. The adapter will force any pending
802 // outgoing calls to try the next service. This needs to happen before CallsManager
803 // tries to clean up any calls still associated with this service.
804 handleConnectionServiceDeath();
805 CallsManager.getInstance().handleConnectionServiceDeath(this);
806 mServiceInterface = null;
807 } else {
808 mServiceInterface = IConnectionService.Stub.asInterface(binder);
809 addConnectionServiceAdapter(mAdapter);
810 }
811 }
812
813 /**
814 * Called when the associated connection service dies.
815 */
816 private void handleConnectionServiceDeath() {
Sailesh Nepal664837f2014-07-14 16:31:51 -0700817 if (!mPendingResponses.isEmpty()) {
818 CreateConnectionResponse[] responses = mPendingResponses.values().toArray(
819 new CreateConnectionResponse[mPendingResponses.values().size()]);
820 mPendingResponses.clear();
821 for (int i = 0; i < responses.length; i++) {
822 responses[i].handleCreateConnectionFailed(DisconnectCause.ERROR_UNSPECIFIED, null);
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700823 }
824 }
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700825 mCallIdMapper.clear();
826 }
827
828 private void logIncoming(String msg, Object... params) {
829 Log.d(this, "ConnectionService -> Telecomm: " + msg, params);
830 }
831
832 private void logOutgoing(String msg, Object... params) {
833 Log.d(this, "Telecomm -> ConnectionService: " + msg, params);
834 }
835
836 private void queryRemoteConnectionServices(final RemoteServiceCallback callback) {
837 final List<IBinder> connectionServices = new ArrayList<>();
838 final List<ComponentName> components = new ArrayList<>();
Sailesh Nepal664837f2014-07-14 16:31:51 -0700839 final List<ConnectionServiceWrapper> servciesAttempted = new ArrayList<>();
Sailesh Nepal905dfba2014-07-14 08:20:41 -0700840 final Collection<ConnectionServiceWrapper> services =
841 mConnectionServiceRepository.lookupServices();
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700842
Sailesh Nepal664837f2014-07-14 16:31:51 -0700843 Log.v(this, "queryRemoteConnectionServices, services: " + services.size());
844
Sailesh Nepal905dfba2014-07-14 08:20:41 -0700845 for (ConnectionServiceWrapper cs : services) {
846 if (cs != this) {
847 final ConnectionServiceWrapper currentConnectionService = cs;
848 cs.mBinder.bind(new BindCallback() {
Sailesh Nepal905dfba2014-07-14 08:20:41 -0700849 @Override
850 public void onSuccess() {
851 Log.d(this, "Adding ***** %s", currentConnectionService.getComponentName());
852 connectionServices.add(
853 currentConnectionService.mServiceInterface.asBinder());
854 components.add(currentConnectionService.getComponentName());
855 maybeComplete();
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700856 }
Sailesh Nepal905dfba2014-07-14 08:20:41 -0700857
858 @Override
859 public void onFailure() {
Sailesh Nepal905dfba2014-07-14 08:20:41 -0700860 maybeComplete();
861 }
862
863 private void maybeComplete() {
Sailesh Nepal664837f2014-07-14 16:31:51 -0700864 servciesAttempted.add(currentConnectionService);
865 if (servciesAttempted.size() == services.size() - 1) {
Sailesh Nepal905dfba2014-07-14 08:20:41 -0700866 try {
867 callback.onResult(components, connectionServices);
868 } catch (RemoteException ignored) {
869 }
870 }
871 }
872 });
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700873 }
Sailesh Nepal905dfba2014-07-14 08:20:41 -0700874 }
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700875 }
876}