blob: 09ddeb0b86477dd42842ec7ee9085fd5725f444b [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;
Evan Charltonb35fc312014-07-19 15:02:55 -070032import android.telecomm.TelecommManager;
Sailesh Nepalc92c4362014-07-04 18:33:21 -070033import 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;
Sailesh Nepalc92c4362014-07-04 18:33:21 -070041
42import org.apache.http.conn.ClientConnectionRequest;
43
44import java.util.ArrayList;
45import java.util.Collection;
46import java.util.HashMap;
47import java.util.HashSet;
48import java.util.List;
49import java.util.Map;
50import java.util.Set;
51
52/**
53 * Wrapper for {@link IConnectionService}s, handles binding to {@link IConnectionService} and keeps
54 * track of when the object can safely be unbound. Other classes should not use
55 * {@link IConnectionService} directly and instead should use this class to invoke methods of
56 * {@link IConnectionService}.
57 */
58final class ConnectionServiceWrapper extends ServiceBinder<IConnectionService> {
Sailesh Nepal664837f2014-07-14 16:31:51 -070059 private static final int MSG_HANDLE_CREATE_CONNECTION_SUCCESSFUL = 1;
60 private static final int MSG_HANDLE_CREATE_CONNECTION_FAILED = 2;
61 private static final int MSG_HANDLE_CREATE_CONNECTION_CANCELLED = 3;
62 private static final int MSG_SET_ACTIVE = 4;
63 private static final int MSG_SET_RINGING = 5;
64 private static final int MSG_SET_DIALING = 6;
65 private static final int MSG_SET_DISCONNECTED = 7;
66 private static final int MSG_SET_ON_HOLD = 8;
67 private static final int MSG_SET_REQUESTING_RINGBACK = 9;
68 private static final int MSG_SET_CALL_CAPABILITIES = 10;
69 private static final int MSG_SET_IS_CONFERENCED = 11;
70 private static final int MSG_ADD_CONFERENCE_CALL = 12;
71 private static final int MSG_REMOVE_CALL = 13;
72 private static final int MSG_ON_POST_DIAL_WAIT = 14;
73 private static final int MSG_QUERY_REMOTE_CALL_SERVICES = 15;
74 private static final int MSG_SET_CALL_VIDEO_PROVIDER = 16;
75 private static final int MSG_SET_AUDIO_MODE_IS_VOIP = 17;
76 private static final int MSG_SET_STATUS_HINTS = 18;
77 private static final int MSG_SET_HANDLE = 19;
78 private static final int MSG_SET_CALLER_DISPLAY_NAME = 20;
Tyler Gunn0a388fc2014-07-17 12:21:17 -070079 private static final int MSG_SET_VIDEO_STATE = 21;
Sailesh Nepal9d58de52014-07-18 14:53:19 -070080 private static final int MSG_START_ACTIVITY_FROM_IN_CALL = 22;
Sailesh Nepalc92c4362014-07-04 18:33:21 -070081
82 private final Handler mHandler = new Handler() {
83 @Override
84 public void handleMessage(Message msg) {
85 Call call;
86 switch (msg.what) {
Sailesh Nepal664837f2014-07-14 16:31:51 -070087 case MSG_HANDLE_CREATE_CONNECTION_SUCCESSFUL: {
Sailesh Nepalc92c4362014-07-04 18:33:21 -070088 ConnectionRequest request = (ConnectionRequest) msg.obj;
Sailesh Nepal664837f2014-07-14 16:31:51 -070089 if (mPendingResponses.containsKey(request.getCallId())) {
90 mPendingResponses.remove(
91 request.getCallId()).handleCreateConnectionSuccessful(request);
Sailesh Nepalc92c4362014-07-04 18:33:21 -070092 } else {
Sailesh Nepal664837f2014-07-14 16:31:51 -070093 //Log.w(this, "handleCreateConnectionSuccessful, unknown call: %s", callId);
Sailesh Nepalc92c4362014-07-04 18:33:21 -070094 }
95 break;
96 }
Sailesh Nepal664837f2014-07-14 16:31:51 -070097 case MSG_HANDLE_CREATE_CONNECTION_FAILED: {
Sailesh Nepalc92c4362014-07-04 18:33:21 -070098 SomeArgs args = (SomeArgs) msg.obj;
99 try {
Sailesh Nepala49c6432014-07-07 22:47:11 -0700100 ConnectionRequest request = (ConnectionRequest) args.arg1;
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700101 int statusCode = args.argi1;
102 String statusMsg = (String) args.arg2;
Sailesh Nepal664837f2014-07-14 16:31:51 -0700103 if (mPendingResponses.containsKey(request.getCallId())) {
104 mPendingResponses.remove(request.getCallId())
105 .handleCreateConnectionFailed(statusCode, statusMsg);
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700106 mCallIdMapper.removeCall(request.getCallId());
107 } else {
Sailesh Nepal664837f2014-07-14 16:31:51 -0700108 //Log.w(this, "handleCreateConnectionFailed, unknown call: %s", callId);
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700109 }
110 } finally {
111 args.recycle();
112 }
113 break;
114 }
Sailesh Nepal664837f2014-07-14 16:31:51 -0700115 case MSG_HANDLE_CREATE_CONNECTION_CANCELLED: {
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700116 ConnectionRequest request = (ConnectionRequest) msg.obj;
Sailesh Nepal664837f2014-07-14 16:31:51 -0700117 if (mPendingResponses.containsKey(request.getCallId())) {
118 mPendingResponses.remove(
119 request.getCallId()).handleCreateConnectionCancelled();
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700120 } else {
Sailesh Nepal664837f2014-07-14 16:31:51 -0700121 //Log.w(this, "handleCreateConnectionCancelled, unknown call: %s", callId);
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700122 }
123 break;
124 }
125 case MSG_SET_ACTIVE:
126 call = mCallIdMapper.getCall(msg.obj);
127 if (call != null) {
128 mCallsManager.markCallAsActive(call);
129 } else {
130 //Log.w(this, "setActive, unknown call id: %s", msg.obj);
131 }
132 break;
133 case MSG_SET_RINGING:
134 call = mCallIdMapper.getCall(msg.obj);
135 if (call != null) {
136 mCallsManager.markCallAsRinging(call);
137 } else {
138 //Log.w(this, "setRinging, unknown call id: %s", msg.obj);
139 }
140 break;
141 case MSG_SET_DIALING:
142 call = mCallIdMapper.getCall(msg.obj);
143 if (call != null) {
144 mCallsManager.markCallAsDialing(call);
145 } else {
146 //Log.w(this, "setDialing, unknown call id: %s", msg.obj);
147 }
148 break;
149 case MSG_SET_DISCONNECTED: {
150 SomeArgs args = (SomeArgs) msg.obj;
151 try {
152 call = mCallIdMapper.getCall(args.arg1);
153 String disconnectMessage = (String) args.arg2;
154 int disconnectCause = args.argi1;
155 if (call != null) {
156 mCallsManager.markCallAsDisconnected(call, disconnectCause,
157 disconnectMessage);
158 } else {
159 //Log.w(this, "setDisconnected, unknown call id: %s", args.arg1);
160 }
161 } finally {
162 args.recycle();
163 }
164 break;
165 }
166 case MSG_SET_ON_HOLD:
167 call = mCallIdMapper.getCall(msg.obj);
168 if (call != null) {
169 mCallsManager.markCallAsOnHold(call);
170 } else {
171 //Log.w(this, "setOnHold, unknown call id: %s", msg.obj);
172 }
173 break;
174 case MSG_SET_REQUESTING_RINGBACK: {
Sailesh Nepal9d58de52014-07-18 14:53:19 -0700175 call = mCallIdMapper.getCall(msg.obj);
176 if (call != null) {
177 call.setRequestingRingback(msg.arg1 == 1);
178 } else {
179 //Log.w(this, "setRingback, unknown call id: %s", args.arg1);
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700180 }
181 break;
182 }
Sailesh Nepale20bc972014-07-09 21:22:36 -0700183 case MSG_SET_CALL_CAPABILITIES: {
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700184 call = mCallIdMapper.getCall(msg.obj);
185 if (call != null) {
Sailesh Nepale20bc972014-07-09 21:22:36 -0700186 call.setCallCapabilities(msg.arg1);
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700187 } else {
188 //Log.w(ConnectionServiceWrapper.this,
Sailesh Nepale20bc972014-07-09 21:22:36 -0700189 // "setCallCapabilities, unknown call id: %s", msg.obj);
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700190 }
191 break;
192 }
193 case MSG_SET_IS_CONFERENCED: {
194 SomeArgs args = (SomeArgs) msg.obj;
195 try {
196 Call childCall = mCallIdMapper.getCall(args.arg1);
197 if (childCall != null) {
198 String conferenceCallId = (String) args.arg2;
199 if (conferenceCallId == null) {
200 childCall.setParentCall(null);
201 } else {
202 Call conferenceCall = mCallIdMapper.getCall(conferenceCallId);
203 if (conferenceCall != null &&
204 !mPendingConferenceCalls.contains(conferenceCall)) {
205 childCall.setParentCall(conferenceCall);
206 } else {
207 //Log.w(this, "setIsConferenced, unknown conference id %s",
208 // conferenceCallId);
209 }
210 }
211 } else {
212 //Log.w(this, "setIsConferenced, unknown call id: %s", args.arg1);
213 }
214 } finally {
215 args.recycle();
216 }
217 break;
218 }
219 case MSG_ADD_CONFERENCE_CALL: {
220 Call conferenceCall = mCallIdMapper.getCall(msg.obj);
221 if (mPendingConferenceCalls.remove(conferenceCall)) {
222 Log.v(this, "confirming conf call %s", conferenceCall);
223 conferenceCall.confirmConference();
224 } else {
225 //Log.w(this, "addConference, unknown call id: %s", callId);
226 }
227 break;
228 }
229 case MSG_REMOVE_CALL:
230 break;
231 case MSG_ON_POST_DIAL_WAIT: {
232 SomeArgs args = (SomeArgs) msg.obj;
233 try {
234 call = mCallIdMapper.getCall(args.arg1);
235 if (call != null) {
236 String remaining = (String) args.arg2;
237 call.onPostDialWait(remaining);
238 } else {
239 //Log.w(this, "onPostDialWait, unknown call id: %s", args.arg1);
240 }
241 } finally {
242 args.recycle();
243 }
244 break;
245 }
246 case MSG_QUERY_REMOTE_CALL_SERVICES: {
Sailesh Nepal664837f2014-07-14 16:31:51 -0700247 queryRemoteConnectionServices((RemoteServiceCallback) msg.obj);
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700248 break;
249 }
250 case MSG_SET_CALL_VIDEO_PROVIDER: {
251 SomeArgs args = (SomeArgs) msg.obj;
252 try {
253 call = mCallIdMapper.getCall(args.arg1);
254 ICallVideoProvider callVideoProvider = (ICallVideoProvider) args.arg2;
255 if (call != null) {
256 call.setCallVideoProvider(callVideoProvider);
257 }
258 } finally {
259 args.recycle();
260 }
261 break;
262 }
Sailesh Nepal7e669572014-07-08 21:29:12 -0700263 case MSG_SET_AUDIO_MODE_IS_VOIP: {
Sailesh Nepale20bc972014-07-09 21:22:36 -0700264 call = mCallIdMapper.getCall(msg.obj);
265 if (call != null) {
266 call.setAudioModeIsVoip(msg.arg1 == 1);
Sailesh Nepal7e669572014-07-08 21:29:12 -0700267 }
268 break;
269 }
Sailesh Nepal35faf8c2014-07-08 22:02:34 -0700270 case MSG_SET_STATUS_HINTS: {
271 SomeArgs args = (SomeArgs) msg.obj;
272 try {
273 call = mCallIdMapper.getCall(args.arg1);
274 StatusHints statusHints = (StatusHints) args.arg2;
275 if (call != null) {
276 call.setStatusHints(statusHints);
277 }
278 } finally {
279 args.recycle();
280 }
281 break;
282 }
Sailesh Nepale8ecb982014-07-11 17:19:42 -0700283 case MSG_SET_HANDLE: {
284 SomeArgs args = (SomeArgs) msg.obj;
285 try {
286 call = mCallIdMapper.getCall(args.arg1);
287 if (call != null) {
288 call.setHandle((Uri) args.arg2, args.argi1);
289 }
290 } finally {
291 args.recycle();
292 }
293 break;
294 }
295 case MSG_SET_CALLER_DISPLAY_NAME: {
296 SomeArgs args = (SomeArgs) msg.obj;
297 try {
298 call = mCallIdMapper.getCall(args.arg1);
299 if (call != null) {
300 call.setCallerDisplayName((String) args.arg2, args.argi1);
301 }
302 } finally {
303 args.recycle();
304 }
305 break;
306 }
Tyler Gunn0a388fc2014-07-17 12:21:17 -0700307 case MSG_SET_VIDEO_STATE: {
308 call = mCallIdMapper.getCall(msg.obj);
309 if (call != null) {
310 call.setVideoState(msg.arg1);
311 }
312 }
Sailesh Nepal9d58de52014-07-18 14:53:19 -0700313 case MSG_START_ACTIVITY_FROM_IN_CALL: {
314 SomeArgs args = (SomeArgs) msg.obj;
315 try {
316 call = mCallIdMapper.getCall(args.arg1);
317 if (call != null) {
318 call.startActivityFromInCall((PendingIntent) args.arg2);
319 }
320 } finally {
321 args.recycle();
322 }
323 break;
324 }
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700325 }
326 }
327 };
328
329 private final class Adapter extends IConnectionServiceAdapter.Stub {
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700330 @Override
Sailesh Nepal664837f2014-07-14 16:31:51 -0700331 public void handleCreateConnectionSuccessful(ConnectionRequest request) {
332 logIncoming("handleCreateConnectionSuccessful %s", request);
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700333 mCallIdMapper.checkValidCallId(request.getCallId());
Sailesh Nepal664837f2014-07-14 16:31:51 -0700334 mHandler.obtainMessage(MSG_HANDLE_CREATE_CONNECTION_SUCCESSFUL, request).sendToTarget();
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700335 }
336
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700337 @Override
Sailesh Nepal664837f2014-07-14 16:31:51 -0700338 public void handleCreateConnectionFailed(
339 ConnectionRequest request, int errorCode, String errorMsg) {
340 logIncoming("handleCreateConnectionFailed %s %d %s", request, errorCode, errorMsg);
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700341 mCallIdMapper.checkValidCallId(request.getCallId());
342 SomeArgs args = SomeArgs.obtain();
343 args.arg1 = request;
344 args.argi1 = errorCode;
345 args.arg2 = errorMsg;
Sailesh Nepal664837f2014-07-14 16:31:51 -0700346 mHandler.obtainMessage(MSG_HANDLE_CREATE_CONNECTION_FAILED, args).sendToTarget();
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700347 }
348
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700349 @Override
Sailesh Nepal664837f2014-07-14 16:31:51 -0700350 public void handleCreateConnectionCancelled(ConnectionRequest request) {
351 logIncoming("handleCreateConnectionCancelled %s", request);
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700352 mCallIdMapper.checkValidCallId(request.getCallId());
Sailesh Nepal664837f2014-07-14 16:31:51 -0700353 mHandler.obtainMessage(MSG_HANDLE_CREATE_CONNECTION_CANCELLED, request).sendToTarget();
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700354 }
355
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700356 @Override
357 public void setActive(String callId) {
358 logIncoming("setActive %s", callId);
359 mCallIdMapper.checkValidCallId(callId);
360 mHandler.obtainMessage(MSG_SET_ACTIVE, callId).sendToTarget();
361 }
362
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700363 @Override
364 public void setRinging(String callId) {
365 logIncoming("setRinging %s", callId);
366 mCallIdMapper.checkValidCallId(callId);
367 mHandler.obtainMessage(MSG_SET_RINGING, callId).sendToTarget();
368 }
369
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700370 @Override
371 public void setCallVideoProvider(String callId, ICallVideoProvider callVideoProvider) {
372 logIncoming("setCallVideoProvider %s", callId);
373 mCallIdMapper.checkValidCallId(callId);
374 SomeArgs args = SomeArgs.obtain();
375 args.arg1 = callId;
376 args.arg2 = callVideoProvider;
377 mHandler.obtainMessage(MSG_SET_CALL_VIDEO_PROVIDER, args).sendToTarget();
378 }
379
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700380 @Override
381 public void setDialing(String callId) {
382 logIncoming("setDialing %s", callId);
383 mCallIdMapper.checkValidCallId(callId);
384 mHandler.obtainMessage(MSG_SET_DIALING, callId).sendToTarget();
385 }
386
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700387 @Override
388 public void setDisconnected(
389 String callId, int disconnectCause, String disconnectMessage) {
390 logIncoming("setDisconnected %s %d %s", callId, disconnectCause, disconnectMessage);
391 mCallIdMapper.checkValidCallId(callId);
392 SomeArgs args = SomeArgs.obtain();
393 args.arg1 = callId;
394 args.arg2 = disconnectMessage;
395 args.argi1 = disconnectCause;
396 mHandler.obtainMessage(MSG_SET_DISCONNECTED, args).sendToTarget();
397 }
398
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700399 @Override
400 public void setOnHold(String callId) {
401 logIncoming("setOnHold %s", callId);
402 mCallIdMapper.checkValidCallId(callId);
403 mHandler.obtainMessage(MSG_SET_ON_HOLD, callId).sendToTarget();
404 }
405
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700406 @Override
407 public void setRequestingRingback(String callId, boolean ringback) {
408 logIncoming("setRequestingRingback %s %b", callId, ringback);
409 mCallIdMapper.checkValidCallId(callId);
Sailesh Nepal9d58de52014-07-18 14:53:19 -0700410 mHandler.obtainMessage(MSG_SET_REQUESTING_RINGBACK, ringback ? 1 : 0, 0, callId)
411 .sendToTarget();
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700412 }
413
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700414 @Override
415 public void removeCall(String callId) {
416 logIncoming("removeCall %s", callId);
417 }
418
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700419 @Override
Sailesh Nepale20bc972014-07-09 21:22:36 -0700420 public void setCallCapabilities(String callId, int callCapabilities) {
421 logIncoming("setCallCapabilities %s %d", callId, callCapabilities);
422 mHandler.obtainMessage(MSG_SET_CALL_CAPABILITIES, callCapabilities, 0, callId)
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700423 .sendToTarget();
424 }
425
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700426 @Override
427 public void setIsConferenced(String callId, String conferenceCallId) {
428 logIncoming("setIsConferenced %s %s", callId, conferenceCallId);
429 SomeArgs args = SomeArgs.obtain();
430 args.arg1 = callId;
431 args.arg2 = conferenceCallId;
432 mHandler.obtainMessage(MSG_SET_IS_CONFERENCED, args).sendToTarget();
433 }
434
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700435 @Override
436 public void addConferenceCall(String callId) {
437 logIncoming("addConferenceCall %s", callId);
438 mCallIdMapper.checkValidCallId(callId);
439 mHandler.obtainMessage(MSG_ADD_CONFERENCE_CALL, callId).sendToTarget();
440 }
441
442 @Override
443 public void onPostDialWait(String callId, String remaining) throws RemoteException {
444 logIncoming("onPostDialWait %s %s", callId, remaining);
445 mCallIdMapper.checkValidCallId(callId);
446 SomeArgs args = SomeArgs.obtain();
447 args.arg1 = callId;
448 args.arg2 = remaining;
449 mHandler.obtainMessage(MSG_ON_POST_DIAL_WAIT, args).sendToTarget();
450 }
451
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700452 @Override
453 public void queryRemoteConnectionServices(RemoteServiceCallback callback) {
454 logIncoming("queryRemoteCSs");
455 mHandler.obtainMessage(MSG_QUERY_REMOTE_CALL_SERVICES, callback).sendToTarget();
456 }
457
458 @Override
Tyler Gunn0a388fc2014-07-17 12:21:17 -0700459 public void setVideoState(String callId, int videoState) {
460 logIncoming("setVideoState %s %d", callId, videoState);
461 mCallIdMapper.checkValidCallId(callId);
462 mHandler.obtainMessage(MSG_SET_VIDEO_STATE, videoState, 0, callId).sendToTarget();
463 }
464
465 @Override
Sailesh Nepal7e669572014-07-08 21:29:12 -0700466 public void setAudioModeIsVoip(String callId, boolean isVoip) {
Sailesh Nepal7fa33ca2014-07-10 15:28:21 -0700467 logIncoming("setAudioModeIsVoip %s %b", callId, isVoip);
Sailesh Nepal7e669572014-07-08 21:29:12 -0700468 mCallIdMapper.checkValidCallId(callId);
Sailesh Nepale20bc972014-07-09 21:22:36 -0700469 mHandler.obtainMessage(MSG_SET_AUDIO_MODE_IS_VOIP, isVoip ? 1 : 0, 0,
470 callId).sendToTarget();
Sailesh Nepal7e669572014-07-08 21:29:12 -0700471 }
Sailesh Nepal35faf8c2014-07-08 22:02:34 -0700472
473 @Override
474 public void setStatusHints(String callId, StatusHints statusHints) {
475 logIncoming("setStatusHints %s %s", callId, statusHints);
476 mCallIdMapper.checkValidCallId(callId);
477 SomeArgs args = SomeArgs.obtain();
478 args.arg1 = callId;
479 args.arg2 = statusHints;
480 mHandler.obtainMessage(MSG_SET_STATUS_HINTS, args).sendToTarget();
481 }
Sailesh Nepale8ecb982014-07-11 17:19:42 -0700482
483 @Override
484 public void setHandle(String callId, Uri handle, int presentation) {
485 logIncoming("setHandle %s %s %d", callId, handle, presentation);
486 mCallIdMapper.checkValidCallId(callId);
487 SomeArgs args = SomeArgs.obtain();
488 args.arg1 = callId;
489 args.arg2 = handle;
490 args.argi1 = presentation;
491 mHandler.obtainMessage(MSG_SET_HANDLE, args).sendToTarget();
492 }
493
494 @Override
495 public void setCallerDisplayName(
496 String callId, String callerDisplayName, int presentation) {
497 logIncoming("setCallerDisplayName %s %s %d", callId, callerDisplayName, presentation);
498 mCallIdMapper.checkValidCallId(callId);
499 SomeArgs args = SomeArgs.obtain();
500 args.arg1 = callId;
501 args.arg2 = callerDisplayName;
502 args.argi1 = presentation;
503 mHandler.obtainMessage(MSG_SET_CALLER_DISPLAY_NAME, args).sendToTarget();
504 }
Sailesh Nepal9d58de52014-07-18 14:53:19 -0700505
506 @Override
507 public void startActivityFromInCall(String callId, PendingIntent intent) {
508 logIncoming("startActivityFromInCall %s %s", callId, intent);
509 mCallIdMapper.checkValidCallId(callId);
510 SomeArgs args = SomeArgs.obtain();
511 args.arg1 = callId;
512 args.arg2 = intent;
513 mHandler.obtainMessage(MSG_START_ACTIVITY_FROM_IN_CALL, args).sendToTarget();
514 }
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700515 }
516
517 private final Adapter mAdapter = new Adapter();
518 private final CallsManager mCallsManager = CallsManager.getInstance();
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700519 private final Set<Call> mPendingConferenceCalls = new HashSet<>();
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700520 private final CallIdMapper mCallIdMapper = new CallIdMapper("ConnectionService");
Sailesh Nepal664837f2014-07-14 16:31:51 -0700521 private final Map<String, CreateConnectionResponse> mPendingResponses = new HashMap<>();
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700522
523 private Binder mBinder = new Binder();
524 private IConnectionService mServiceInterface;
Sailesh Nepal905dfba2014-07-14 08:20:41 -0700525 private final ConnectionServiceRepository mConnectionServiceRepository;
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700526
527 /**
Sailesh Nepal905dfba2014-07-14 08:20:41 -0700528 * Creates a connection service.
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700529 *
Sailesh Nepal905dfba2014-07-14 08:20:41 -0700530 * @param componentName The component name of the service with which to bind.
Sailesh Nepal905dfba2014-07-14 08:20:41 -0700531 * @param connectionServiceRepository Connection service repository.
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700532 */
533 ConnectionServiceWrapper(
Sailesh Nepal664837f2014-07-14 16:31:51 -0700534 ComponentName componentName, ConnectionServiceRepository connectionServiceRepository) {
Evan Charltonb35fc312014-07-19 15:02:55 -0700535 super(TelecommManager.ACTION_CONNECTION_SERVICE, componentName);
Sailesh Nepal905dfba2014-07-14 08:20:41 -0700536 mConnectionServiceRepository = connectionServiceRepository;
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700537 }
538
539 /** See {@link IConnectionService#addConnectionServiceAdapter}. */
540 private void addConnectionServiceAdapter(IConnectionServiceAdapter adapter) {
541 if (isServiceValid("addConnectionServiceAdapter")) {
542 try {
Sailesh Nepal3fe8b722014-07-08 10:07:26 -0700543 logOutgoing("addConnectionServiceAdapter %s", adapter);
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700544 mServiceInterface.addConnectionServiceAdapter(adapter);
545 } catch (RemoteException e) {
546 }
547 }
548 }
549
550 /**
Sailesh Nepal664837f2014-07-14 16:31:51 -0700551 * Creates a new connection for a new outgoing call or to attach to an existing incoming call.
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700552 */
Sailesh Nepal664837f2014-07-14 16:31:51 -0700553 void createConnection(final Call call, final CreateConnectionResponse response) {
554 Log.d(this, "createConnection(%s) via %s.", call, getComponentName());
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700555 BindCallback callback = new BindCallback() {
556 @Override
557 public void onSuccess() {
558 String callId = mCallIdMapper.getCallId(call);
Sailesh Nepal664837f2014-07-14 16:31:51 -0700559 mPendingResponses.put(callId, response);
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700560
561 GatewayInfo gatewayInfo = call.getGatewayInfo();
562 Bundle extras = call.getExtras();
563 if (gatewayInfo != null && gatewayInfo.getGatewayProviderPackageName() != null &&
564 gatewayInfo.getOriginalHandle() != null) {
565 extras = (Bundle) extras.clone();
566 extras.putString(
567 NewOutgoingCallIntentBroadcaster.EXTRA_GATEWAY_PROVIDER_PACKAGE,
568 gatewayInfo.getGatewayProviderPackageName());
569 extras.putParcelable(
570 NewOutgoingCallIntentBroadcaster.EXTRA_GATEWAY_ORIGINAL_URI,
571 gatewayInfo.getOriginalHandle());
572 }
Sailesh Nepale8ecb982014-07-11 17:19:42 -0700573 ConnectionRequest request = new ConnectionRequest(
574 call.getPhoneAccount(),
575 callId,
576 call.getHandle(),
577 call.getHandlePresentation(),
578 extras,
Tyler Gunnc4abd912014-07-08 14:22:10 -0700579 call.getVideoState());
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700580
581 try {
Sailesh Nepal664837f2014-07-14 16:31:51 -0700582 mServiceInterface.createConnection(request, call.isIncoming());
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700583 } catch (RemoteException e) {
Sailesh Nepal664837f2014-07-14 16:31:51 -0700584 Log.e(this, e, "Failure to createConnection -- %s", getComponentName());
585 mPendingResponses.remove(callId).handleCreateConnectionFailed(
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700586 DisconnectCause.ERROR_UNSPECIFIED, e.toString());
587 }
588 }
589
590 @Override
591 public void onFailure() {
Sailesh Nepal905dfba2014-07-14 08:20:41 -0700592 Log.e(this, new Exception(), "Failure to call %s", getComponentName());
Sailesh Nepal664837f2014-07-14 16:31:51 -0700593 response.handleCreateConnectionFailed(DisconnectCause.ERROR_UNSPECIFIED, null);
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700594 }
595 };
596
597 mBinder.bind(callback);
598 }
599
600 /** @see ConnectionService#abort(String) */
601 void abort(Call call) {
602 // Clear out any pending outgoing call data
603 String callId = mCallIdMapper.getCallId(call);
604
605 // If still bound, tell the connection service to abort.
606 if (isServiceValid("abort")) {
607 try {
608 logOutgoing("abort %s", callId);
609 mServiceInterface.abort(callId);
610 } catch (RemoteException e) {
611 }
612 }
613
614 removeCall(call);
615 }
616
617 /** @see ConnectionService#hold(String) */
618 void hold(Call call) {
619 if (isServiceValid("hold")) {
620 try {
621 logOutgoing("hold %s", mCallIdMapper.getCallId(call));
622 mServiceInterface.hold(mCallIdMapper.getCallId(call));
623 } catch (RemoteException e) {
624 }
625 }
626 }
627
628 /** @see ConnectionService#unhold(String) */
629 void unhold(Call call) {
630 if (isServiceValid("unhold")) {
631 try {
632 logOutgoing("unhold %s", mCallIdMapper.getCallId(call));
633 mServiceInterface.unhold(mCallIdMapper.getCallId(call));
634 } catch (RemoteException e) {
635 }
636 }
637 }
638
639 /** @see ConnectionService#onAudioStateChanged(String,CallAudioState) */
640 void onAudioStateChanged(Call activeCall, CallAudioState audioState) {
641 if (isServiceValid("onAudioStateChanged")) {
642 try {
643 logOutgoing("onAudioStateChanged %s %s",
644 mCallIdMapper.getCallId(activeCall), audioState);
645 mServiceInterface.onAudioStateChanged(mCallIdMapper.getCallId(activeCall),
646 audioState);
647 } catch (RemoteException e) {
648 }
649 }
650 }
651
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700652 /** @see ConnectionService#disconnect(String) */
653 void disconnect(Call call) {
654 if (isServiceValid("disconnect")) {
655 try {
656 logOutgoing("disconnect %s", mCallIdMapper.getCallId(call));
657 mServiceInterface.disconnect(mCallIdMapper.getCallId(call));
658 } catch (RemoteException e) {
659 }
660 }
661 }
662
663 /** @see ConnectionService#answer(String) */
Andrew Lee38931d02014-07-16 10:17:36 -0700664 void answer(Call call, int videoState) {
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700665 if (isServiceValid("answer")) {
666 try {
Andrew Lee38931d02014-07-16 10:17:36 -0700667 logOutgoing("answer %s %d", mCallIdMapper.getCallId(call), videoState);
668 mServiceInterface.answer(mCallIdMapper.getCallId(call), videoState);
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700669 } catch (RemoteException e) {
670 }
671 }
672 }
673
674 /** @see ConnectionService#reject(String) */
675 void reject(Call call) {
676 if (isServiceValid("reject")) {
677 try {
678 logOutgoing("reject %s", mCallIdMapper.getCallId(call));
679 mServiceInterface.reject(mCallIdMapper.getCallId(call));
680 } catch (RemoteException e) {
681 }
682 }
683 }
684
685 /** @see ConnectionService#playDtmfTone(String,char) */
686 void playDtmfTone(Call call, char digit) {
687 if (isServiceValid("playDtmfTone")) {
688 try {
689 logOutgoing("playDtmfTone %s %c", mCallIdMapper.getCallId(call), digit);
690 mServiceInterface.playDtmfTone(mCallIdMapper.getCallId(call), digit);
691 } catch (RemoteException e) {
692 }
693 }
694 }
695
696 /** @see ConnectionService#stopDtmfTone(String) */
697 void stopDtmfTone(Call call) {
698 if (isServiceValid("stopDtmfTone")) {
699 try {
700 logOutgoing("stopDtmfTone %s", mCallIdMapper.getCallId(call));
701 mServiceInterface.stopDtmfTone(mCallIdMapper.getCallId(call));
702 } catch (RemoteException e) {
703 }
704 }
705 }
706
707 void addCall(Call call) {
708 if (mCallIdMapper.getCallId(call) == null) {
709 mCallIdMapper.addCall(call);
710 }
711 }
712
713 /**
714 * Associates newCall with this connection service by replacing callToReplace.
715 */
716 void replaceCall(Call newCall, Call callToReplace) {
717 Preconditions.checkState(callToReplace.getConnectionService() == this);
718 mCallIdMapper.replaceCall(newCall, callToReplace);
719 }
720
721 void removeCall(Call call) {
Sailesh Nepal664837f2014-07-14 16:31:51 -0700722 CreateConnectionResponse response = mPendingResponses.remove(mCallIdMapper.getCallId(call));
723 if (response != null) {
724 response.handleCreateConnectionFailed(DisconnectCause.ERROR_UNSPECIFIED, null);
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700725 }
726
727 mCallIdMapper.removeCall(call);
728 }
729
730 void onPostDialContinue(Call call, boolean proceed) {
731 if (isServiceValid("onPostDialContinue")) {
732 try {
733 logOutgoing("onPostDialContinue %s %b", mCallIdMapper.getCallId(call), proceed);
734 mServiceInterface.onPostDialContinue(mCallIdMapper.getCallId(call), proceed);
735 } catch (RemoteException ignored) {
736 }
737 }
738 }
739
740 void onPhoneAccountClicked(Call call) {
741 if (isServiceValid("onPhoneAccountClicked")) {
742 try {
743 logOutgoing("onPhoneAccountClicked %s", mCallIdMapper.getCallId(call));
744 mServiceInterface.onPhoneAccountClicked(mCallIdMapper.getCallId(call));
745 } catch (RemoteException ignored) {
746 }
747 }
748 }
749
750 void conference(final Call conferenceCall, Call call) {
751 if (isServiceValid("conference")) {
752 try {
753 conferenceCall.setConnectionService(this);
754 mPendingConferenceCalls.add(conferenceCall);
755 mHandler.postDelayed(new Runnable() {
756 @Override public void run() {
757 if (mPendingConferenceCalls.remove(conferenceCall)) {
758 conferenceCall.expireConference();
759 Log.i(this, "Conference call expired: %s", conferenceCall);
760 }
761 }
762 }, Timeouts.getConferenceCallExpireMillis());
763
764 logOutgoing("conference %s %s",
765 mCallIdMapper.getCallId(conferenceCall),
766 mCallIdMapper.getCallId(call));
767 mServiceInterface.conference(
768 mCallIdMapper.getCallId(conferenceCall),
769 mCallIdMapper.getCallId(call));
770 } catch (RemoteException ignored) {
771 }
772 }
773 }
774
775 void splitFromConference(Call call) {
776 if (isServiceValid("splitFromConference")) {
777 try {
778 logOutgoing("splitFromConference %s", mCallIdMapper.getCallId(call));
779 mServiceInterface.splitFromConference(mCallIdMapper.getCallId(call));
780 } catch (RemoteException ignored) {
781 }
782 }
783 }
784
Sailesh Nepale8ecb982014-07-11 17:19:42 -0700785 void swapWithBackgroundCall(Call call) {
786 if (isServiceValid("swapWithBackgroundCall")) {
787 try {
788 logOutgoing("swapWithBackgroundCall %s", mCallIdMapper.getCallId(call));
789 mServiceInterface.swapWithBackgroundCall(mCallIdMapper.getCallId(call));
790 } catch (RemoteException ignored) {
791 }
792 }
793 }
794
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700795 /** {@inheritDoc} */
796 @Override
797 protected void setServiceInterface(IBinder binder) {
798 if (binder == null) {
799 // We have lost our service connection. Notify the world that this service is done.
800 // We must notify the adapter before CallsManager. The adapter will force any pending
801 // outgoing calls to try the next service. This needs to happen before CallsManager
802 // tries to clean up any calls still associated with this service.
803 handleConnectionServiceDeath();
804 CallsManager.getInstance().handleConnectionServiceDeath(this);
805 mServiceInterface = null;
806 } else {
807 mServiceInterface = IConnectionService.Stub.asInterface(binder);
808 addConnectionServiceAdapter(mAdapter);
809 }
810 }
811
812 /**
813 * Called when the associated connection service dies.
814 */
815 private void handleConnectionServiceDeath() {
Sailesh Nepal664837f2014-07-14 16:31:51 -0700816 if (!mPendingResponses.isEmpty()) {
817 CreateConnectionResponse[] responses = mPendingResponses.values().toArray(
818 new CreateConnectionResponse[mPendingResponses.values().size()]);
819 mPendingResponses.clear();
820 for (int i = 0; i < responses.length; i++) {
821 responses[i].handleCreateConnectionFailed(DisconnectCause.ERROR_UNSPECIFIED, null);
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700822 }
823 }
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700824 mCallIdMapper.clear();
825 }
826
827 private void logIncoming(String msg, Object... params) {
828 Log.d(this, "ConnectionService -> Telecomm: " + msg, params);
829 }
830
831 private void logOutgoing(String msg, Object... params) {
832 Log.d(this, "Telecomm -> ConnectionService: " + msg, params);
833 }
834
835 private void queryRemoteConnectionServices(final RemoteServiceCallback callback) {
836 final List<IBinder> connectionServices = new ArrayList<>();
837 final List<ComponentName> components = new ArrayList<>();
Sailesh Nepal664837f2014-07-14 16:31:51 -0700838 final List<ConnectionServiceWrapper> servciesAttempted = new ArrayList<>();
Sailesh Nepal905dfba2014-07-14 08:20:41 -0700839 final Collection<ConnectionServiceWrapper> services =
840 mConnectionServiceRepository.lookupServices();
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700841
Sailesh Nepal664837f2014-07-14 16:31:51 -0700842 Log.v(this, "queryRemoteConnectionServices, services: " + services.size());
843
Sailesh Nepal905dfba2014-07-14 08:20:41 -0700844 for (ConnectionServiceWrapper cs : services) {
845 if (cs != this) {
846 final ConnectionServiceWrapper currentConnectionService = cs;
847 cs.mBinder.bind(new BindCallback() {
Sailesh Nepal905dfba2014-07-14 08:20:41 -0700848 @Override
849 public void onSuccess() {
850 Log.d(this, "Adding ***** %s", currentConnectionService.getComponentName());
851 connectionServices.add(
852 currentConnectionService.mServiceInterface.asBinder());
853 components.add(currentConnectionService.getComponentName());
854 maybeComplete();
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700855 }
Sailesh Nepal905dfba2014-07-14 08:20:41 -0700856
857 @Override
858 public void onFailure() {
Sailesh Nepal905dfba2014-07-14 08:20:41 -0700859 maybeComplete();
860 }
861
862 private void maybeComplete() {
Sailesh Nepal664837f2014-07-14 16:31:51 -0700863 servciesAttempted.add(currentConnectionService);
864 if (servciesAttempted.size() == services.size() - 1) {
Sailesh Nepal905dfba2014-07-14 08:20:41 -0700865 try {
866 callback.onResult(components, connectionServices);
867 } catch (RemoteException ignored) {
868 }
869 }
870 }
871 });
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700872 }
Sailesh Nepal905dfba2014-07-14 08:20:41 -0700873 }
Sailesh Nepalc92c4362014-07-04 18:33:21 -0700874 }
875}