blob: ce3144bbeacfc2964ddd83e7fd720344bec58ba3 [file] [log] [blame]
Ihab Awad542e0ea2014-05-16 10:22:16 -07001/*
2 * Copyright (C) 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
Tyler Gunnef9f6f92014-09-12 22:16:17 -070017package android.telecom;
Ihab Awad542e0ea2014-05-16 10:22:16 -070018
Santos Cordon5c6fa952014-07-20 17:47:12 -070019import android.annotation.SdkConstant;
Sailesh Nepal2a46b902014-07-04 17:21:07 -070020import android.app.Service;
Santos Cordon52d8a152014-06-17 19:08:45 -070021import android.content.ComponentName;
Santos Cordon5c6fa952014-07-20 17:47:12 -070022import android.content.Intent;
Ihab Awad542e0ea2014-05-16 10:22:16 -070023import android.net.Uri;
Santos Cordon6b7f9552015-05-27 17:21:45 -070024import android.os.Bundle;
Santos Cordon52d8a152014-06-17 19:08:45 -070025import android.os.Handler;
26import android.os.IBinder;
27import android.os.Looper;
Sailesh Nepal2a46b902014-07-04 17:21:07 -070028import android.os.Message;
Brad Ebingerb32d4f82016-10-24 16:40:49 -070029import android.telecom.Logging.Session;
Andrew Lee14185762014-07-25 09:41:56 -070030
Sailesh Nepal2a46b902014-07-04 17:21:07 -070031import com.android.internal.os.SomeArgs;
Tyler Gunnef9f6f92014-09-12 22:16:17 -070032import com.android.internal.telecom.IConnectionService;
33import com.android.internal.telecom.IConnectionServiceAdapter;
34import com.android.internal.telecom.RemoteServiceCallback;
Santos Cordon52d8a152014-06-17 19:08:45 -070035
Ihab Awad5d0410f2014-07-30 10:07:40 -070036import java.util.ArrayList;
Santos Cordonb6939982014-06-04 20:20:58 -070037import java.util.Collection;
Santos Cordon7c7bc7f2014-07-28 18:15:48 -070038import java.util.Collections;
Santos Cordon52d8a152014-06-17 19:08:45 -070039import java.util.List;
Ihab Awad542e0ea2014-05-16 10:22:16 -070040import java.util.Map;
Santos Cordon823fd3c2014-08-07 18:35:18 -070041import java.util.UUID;
mike dooley95e80702014-09-18 14:07:52 -070042import java.util.concurrent.ConcurrentHashMap;
Ihab Awad542e0ea2014-05-16 10:22:16 -070043
44/**
Tyler Gunnf5035432017-01-09 09:43:12 -080045 * An abstract service that should be implemented by any apps which either:
46 * <ol>
47 * <li>Can make phone calls (VoIP or otherwise) and want those calls to be integrated into the
48 * built-in phone app. Referred to as a <b>system managed</b> {@link ConnectionService}.</li>
49 * <li>Are a standalone calling app and don't want their calls to be integrated into the
50 * built-in phone app. Referred to as a <b>self managed</b> {@link ConnectionService}.</li>
51 * </ol>
52 * Once implemented, the {@link ConnectionService} needs to take the following steps so that Telecom
53 * will bind to it:
Santos Cordona663f862014-10-29 13:49:58 -070054 * <p>
55 * 1. <i>Registration in AndroidManifest.xml</i>
56 * <br/>
57 * <pre>
58 * &lt;service android:name="com.example.package.MyConnectionService"
59 * android:label="@string/some_label_for_my_connection_service"
Yorke Lee249c12e2015-05-13 15:59:29 -070060 * android:permission="android.permission.BIND_TELECOM_CONNECTION_SERVICE"&gt;
Santos Cordona663f862014-10-29 13:49:58 -070061 * &lt;intent-filter&gt;
62 * &lt;action android:name="android.telecom.ConnectionService" /&gt;
63 * &lt;/intent-filter&gt;
64 * &lt;/service&gt;
65 * </pre>
66 * <p>
67 * 2. <i> Registration of {@link PhoneAccount} with {@link TelecomManager}.</i>
68 * <br/>
69 * See {@link PhoneAccount} and {@link TelecomManager#registerPhoneAccount} for more information.
70 * <p>
Tyler Gunnf5035432017-01-09 09:43:12 -080071 * System managed {@link ConnectionService}s must be enabled by the user in the phone app settings
72 * before Telecom will bind to them. Self-manged {@link ConnectionService}s must be granted the
73 * appropriate permission before Telecom will bind to them.
74 * <p>
75 * Once registered and enabled by the user in the phone app settings or granted permission, telecom
76 * will bind to a {@link ConnectionService} implementation when it wants that
77 * {@link ConnectionService} to place a call or the service has indicated that is has an incoming
78 * call through {@link TelecomManager#addNewIncomingCall}. The {@link ConnectionService} can then
79 * expect a call to {@link #onCreateIncomingConnection} or {@link #onCreateOutgoingConnection}
80 * wherein it should provide a new instance of a {@link Connection} object. It is through this
81 * {@link Connection} object that telecom receives state updates and the {@link ConnectionService}
Santos Cordona663f862014-10-29 13:49:58 -070082 * receives call-commands such as answer, reject, hold and disconnect.
83 * <p>
Tyler Gunnf5035432017-01-09 09:43:12 -080084 * When there are no more live calls, telecom will unbind from the {@link ConnectionService}.
Ihab Awad542e0ea2014-05-16 10:22:16 -070085 */
Sailesh Nepal2a46b902014-07-04 17:21:07 -070086public abstract class ConnectionService extends Service {
Santos Cordon5c6fa952014-07-20 17:47:12 -070087 /**
88 * The {@link Intent} that must be declared as handled by the service.
89 */
Ihab Awadb19a0bc2014-08-07 19:46:01 -070090 @SdkConstant(SdkConstant.SdkConstantType.SERVICE_ACTION)
Tyler Gunnef9f6f92014-09-12 22:16:17 -070091 public static final String SERVICE_INTERFACE = "android.telecom.ConnectionService";
Santos Cordon5c6fa952014-07-20 17:47:12 -070092
Ihab Awad542e0ea2014-05-16 10:22:16 -070093 // Flag controlling whether PII is emitted into the logs
Ihab Awad60ac30b2014-05-20 22:32:12 -070094 private static final boolean PII_DEBUG = Log.isLoggable(android.util.Log.DEBUG);
Ihab Awad542e0ea2014-05-16 10:22:16 -070095
Brad Ebingerb32d4f82016-10-24 16:40:49 -070096 // Session Definitions
97 private static final String SESSION_HANDLER = "H.";
98 private static final String SESSION_ADD_CS_ADAPTER = "CS.aCSA";
99 private static final String SESSION_REMOVE_CS_ADAPTER = "CS.rCSA";
100 private static final String SESSION_CREATE_CONN = "CS.crCo";
101 private static final String SESSION_ABORT = "CS.ab";
102 private static final String SESSION_ANSWER = "CS.an";
103 private static final String SESSION_ANSWER_VIDEO = "CS.anV";
104 private static final String SESSION_REJECT = "CS.r";
105 private static final String SESSION_REJECT_MESSAGE = "CS.rWM";
106 private static final String SESSION_SILENCE = "CS.s";
107 private static final String SESSION_DISCONNECT = "CS.d";
108 private static final String SESSION_HOLD = "CS.h";
109 private static final String SESSION_UNHOLD = "CS.u";
110 private static final String SESSION_CALL_AUDIO_SC = "CS.cASC";
111 private static final String SESSION_PLAY_DTMF = "CS.pDT";
112 private static final String SESSION_STOP_DTMF = "CS.sDT";
113 private static final String SESSION_CONFERENCE = "CS.c";
114 private static final String SESSION_SPLIT_CONFERENCE = "CS.sFC";
115 private static final String SESSION_MERGE_CONFERENCE = "CS.mC";
116 private static final String SESSION_SWAP_CONFERENCE = "CS.sC";
117 private static final String SESSION_POST_DIAL_CONT = "CS.oPDC";
118 private static final String SESSION_PULL_EXTERNAL_CALL = "CS.pEC";
119 private static final String SESSION_SEND_CALL_EVENT = "CS.sCE";
120 private static final String SESSION_EXTRAS_CHANGED = "CS.oEC";
121
Ihab Awad8aecfed2014-08-08 17:06:11 -0700122 private static final int MSG_ADD_CONNECTION_SERVICE_ADAPTER = 1;
Sailesh Nepalc5b01572014-07-14 16:29:44 -0700123 private static final int MSG_CREATE_CONNECTION = 2;
Sailesh Nepal2a46b902014-07-04 17:21:07 -0700124 private static final int MSG_ABORT = 3;
Sailesh Nepalc5b01572014-07-14 16:29:44 -0700125 private static final int MSG_ANSWER = 4;
126 private static final int MSG_REJECT = 5;
127 private static final int MSG_DISCONNECT = 6;
128 private static final int MSG_HOLD = 7;
129 private static final int MSG_UNHOLD = 8;
Yorke Lee4af59352015-05-13 14:14:54 -0700130 private static final int MSG_ON_CALL_AUDIO_STATE_CHANGED = 9;
Sailesh Nepalc5b01572014-07-14 16:29:44 -0700131 private static final int MSG_PLAY_DTMF_TONE = 10;
132 private static final int MSG_STOP_DTMF_TONE = 11;
133 private static final int MSG_CONFERENCE = 12;
134 private static final int MSG_SPLIT_FROM_CONFERENCE = 13;
Ihab Awadb19a0bc2014-08-07 19:46:01 -0700135 private static final int MSG_ON_POST_DIAL_CONTINUE = 14;
Ihab Awadb19a0bc2014-08-07 19:46:01 -0700136 private static final int MSG_REMOVE_CONNECTION_SERVICE_ADAPTER = 16;
Tyler Gunnbe74de02014-08-29 14:51:48 -0700137 private static final int MSG_ANSWER_VIDEO = 17;
Santos Cordona4868042014-09-04 17:39:22 -0700138 private static final int MSG_MERGE_CONFERENCE = 18;
139 private static final int MSG_SWAP_CONFERENCE = 19;
Bryce Lee81901682015-08-28 16:38:02 -0700140 private static final int MSG_REJECT_WITH_MESSAGE = 20;
Bryce Leecac50772015-11-17 15:13:29 -0800141 private static final int MSG_SILENCE = 21;
Tyler Gunn876dbfb2016-03-14 15:18:07 -0700142 private static final int MSG_PULL_EXTERNAL_CALL = 22;
143 private static final int MSG_SEND_CALL_EVENT = 23;
Tyler Gunndee56a82016-03-23 16:06:34 -0700144 private static final int MSG_ON_EXTRAS_CHANGED = 24;
Santos Cordon7c7bc7f2014-07-28 18:15:48 -0700145
Sailesh Nepalcf7020b2014-08-20 10:07:19 -0700146 private static Connection sNullConnection;
147
mike dooley95e80702014-09-18 14:07:52 -0700148 private final Map<String, Connection> mConnectionById = new ConcurrentHashMap<>();
149 private final Map<Connection, String> mIdByConnection = new ConcurrentHashMap<>();
150 private final Map<String, Conference> mConferenceById = new ConcurrentHashMap<>();
151 private final Map<Conference, String> mIdByConference = new ConcurrentHashMap<>();
Ihab Awadb8e85c72014-08-23 20:34:57 -0700152 private final RemoteConnectionManager mRemoteConnectionManager =
153 new RemoteConnectionManager(this);
Ihab Awad5d0410f2014-07-30 10:07:40 -0700154 private final List<Runnable> mPreInitializationConnectionRequests = new ArrayList<>();
Sailesh Nepal2a46b902014-07-04 17:21:07 -0700155 private final ConnectionServiceAdapter mAdapter = new ConnectionServiceAdapter();
Ihab Awad542e0ea2014-05-16 10:22:16 -0700156
Santos Cordon823fd3c2014-08-07 18:35:18 -0700157 private boolean mAreAccountsInitialized = false;
Santos Cordon0159ac02014-08-21 14:28:11 -0700158 private Conference sNullConference;
Tyler Gunnf0500bd2015-09-01 10:59:48 -0700159 private Object mIdSyncRoot = new Object();
160 private int mId = 0;
Santos Cordon823fd3c2014-08-07 18:35:18 -0700161
Sailesh Nepal2a46b902014-07-04 17:21:07 -0700162 private final IBinder mBinder = new IConnectionService.Stub() {
163 @Override
Brad Ebingerb32d4f82016-10-24 16:40:49 -0700164 public void addConnectionServiceAdapter(IConnectionServiceAdapter adapter,
165 Session.Info sessionInfo) {
166 Log.startSession(sessionInfo, SESSION_ADD_CS_ADAPTER);
167 try {
168 SomeArgs args = SomeArgs.obtain();
169 args.arg1 = adapter;
170 args.arg2 = Log.createSubsession();
171 mHandler.obtainMessage(MSG_ADD_CONNECTION_SERVICE_ADAPTER, args).sendToTarget();
172 } finally {
173 Log.endSession();
174 }
Ihab Awad8aecfed2014-08-08 17:06:11 -0700175 }
176
Brad Ebingerb32d4f82016-10-24 16:40:49 -0700177 public void removeConnectionServiceAdapter(IConnectionServiceAdapter adapter,
178 Session.Info sessionInfo) {
179 Log.startSession(sessionInfo, SESSION_REMOVE_CS_ADAPTER);
180 try {
181 SomeArgs args = SomeArgs.obtain();
182 args.arg1 = adapter;
183 args.arg2 = Log.createSubsession();
184 mHandler.obtainMessage(MSG_REMOVE_CONNECTION_SERVICE_ADAPTER, args).sendToTarget();
185 } finally {
186 Log.endSession();
187 }
Sailesh Nepal2a46b902014-07-04 17:21:07 -0700188 }
189
190 @Override
Ihab Awadf8b69882014-07-25 15:14:01 -0700191 public void createConnection(
192 PhoneAccountHandle connectionManagerPhoneAccount,
Ihab Awadb19a0bc2014-08-07 19:46:01 -0700193 String id,
Ihab Awadf8b69882014-07-25 15:14:01 -0700194 ConnectionRequest request,
Yorke Leec3cf9822014-10-02 09:38:39 -0700195 boolean isIncoming,
Brad Ebingerb32d4f82016-10-24 16:40:49 -0700196 boolean isUnknown,
197 Session.Info sessionInfo) {
198 Log.startSession(sessionInfo, SESSION_CREATE_CONN);
199 try {
200 SomeArgs args = SomeArgs.obtain();
201 args.arg1 = connectionManagerPhoneAccount;
202 args.arg2 = id;
203 args.arg3 = request;
204 args.arg4 = Log.createSubsession();
205 args.argi1 = isIncoming ? 1 : 0;
206 args.argi2 = isUnknown ? 1 : 0;
207 mHandler.obtainMessage(MSG_CREATE_CONNECTION, args).sendToTarget();
208 } finally {
209 Log.endSession();
210 }
Sailesh Nepal2a46b902014-07-04 17:21:07 -0700211 }
212
213 @Override
Brad Ebingerb32d4f82016-10-24 16:40:49 -0700214 public void abort(String callId, Session.Info sessionInfo) {
215 Log.startSession(sessionInfo, SESSION_ABORT);
216 try {
217 SomeArgs args = SomeArgs.obtain();
218 args.arg1 = callId;
219 args.arg2 = Log.createSubsession();
220 mHandler.obtainMessage(MSG_ABORT, args).sendToTarget();
221 } finally {
222 Log.endSession();
223 }
Sailesh Nepal2a46b902014-07-04 17:21:07 -0700224 }
225
226 @Override
Brad Ebingerb32d4f82016-10-24 16:40:49 -0700227 public void answerVideo(String callId, int videoState, Session.Info sessionInfo) {
228 Log.startSession(sessionInfo, SESSION_ANSWER_VIDEO);
229 try {
230 SomeArgs args = SomeArgs.obtain();
231 args.arg1 = callId;
232 args.arg2 = Log.createSubsession();
233 args.argi1 = videoState;
234 mHandler.obtainMessage(MSG_ANSWER_VIDEO, args).sendToTarget();
235 } finally {
236 Log.endSession();
237 }
Tyler Gunnbe74de02014-08-29 14:51:48 -0700238 }
239
240 @Override
Brad Ebingerb32d4f82016-10-24 16:40:49 -0700241 public void answer(String callId, Session.Info sessionInfo) {
242 Log.startSession(sessionInfo, SESSION_ANSWER);
243 try {
244 SomeArgs args = SomeArgs.obtain();
245 args.arg1 = callId;
246 args.arg2 = Log.createSubsession();
247 mHandler.obtainMessage(MSG_ANSWER, args).sendToTarget();
248 } finally {
249 Log.endSession();
250 }
Sailesh Nepal2a46b902014-07-04 17:21:07 -0700251 }
252
253 @Override
Brad Ebingerb32d4f82016-10-24 16:40:49 -0700254 public void reject(String callId, Session.Info sessionInfo) {
255 Log.startSession(sessionInfo, SESSION_REJECT);
256 try {
257 SomeArgs args = SomeArgs.obtain();
258 args.arg1 = callId;
259 args.arg2 = Log.createSubsession();
260 mHandler.obtainMessage(MSG_REJECT, args).sendToTarget();
261 } finally {
262 Log.endSession();
263 }
Sailesh Nepal2a46b902014-07-04 17:21:07 -0700264 }
265
266 @Override
Brad Ebingerb32d4f82016-10-24 16:40:49 -0700267 public void rejectWithMessage(String callId, String message, Session.Info sessionInfo) {
268 Log.startSession(sessionInfo, SESSION_REJECT_MESSAGE);
269 try {
270 SomeArgs args = SomeArgs.obtain();
271 args.arg1 = callId;
272 args.arg2 = message;
273 args.arg3 = Log.createSubsession();
274 mHandler.obtainMessage(MSG_REJECT_WITH_MESSAGE, args).sendToTarget();
275 } finally {
276 Log.endSession();
277 }
Bryce Lee81901682015-08-28 16:38:02 -0700278 }
279
280 @Override
Brad Ebingerb32d4f82016-10-24 16:40:49 -0700281 public void silence(String callId, Session.Info sessionInfo) {
282 Log.startSession(sessionInfo, SESSION_SILENCE);
283 try {
284 SomeArgs args = SomeArgs.obtain();
285 args.arg1 = callId;
286 args.arg2 = Log.createSubsession();
287 mHandler.obtainMessage(MSG_SILENCE, args).sendToTarget();
288 } finally {
289 Log.endSession();
290 }
Bryce Leecac50772015-11-17 15:13:29 -0800291 }
292
293 @Override
Brad Ebingerb32d4f82016-10-24 16:40:49 -0700294 public void disconnect(String callId, Session.Info sessionInfo) {
295 Log.startSession(sessionInfo, SESSION_DISCONNECT);
296 try {
297 SomeArgs args = SomeArgs.obtain();
298 args.arg1 = callId;
299 args.arg2 = Log.createSubsession();
300 mHandler.obtainMessage(MSG_DISCONNECT, args).sendToTarget();
301 } finally {
302 Log.endSession();
303 }
Sailesh Nepal2a46b902014-07-04 17:21:07 -0700304 }
305
306 @Override
Brad Ebingerb32d4f82016-10-24 16:40:49 -0700307 public void hold(String callId, Session.Info sessionInfo) {
308 Log.startSession(sessionInfo, SESSION_HOLD);
309 try {
310 SomeArgs args = SomeArgs.obtain();
311 args.arg1 = callId;
312 args.arg2 = Log.createSubsession();
313 mHandler.obtainMessage(MSG_HOLD, args).sendToTarget();
314 } finally {
315 Log.endSession();
316 }
Sailesh Nepal2a46b902014-07-04 17:21:07 -0700317 }
318
319 @Override
Brad Ebingerb32d4f82016-10-24 16:40:49 -0700320 public void unhold(String callId, Session.Info sessionInfo) {
321 Log.startSession(sessionInfo, SESSION_UNHOLD);
322 try {
323 SomeArgs args = SomeArgs.obtain();
324 args.arg1 = callId;
325 args.arg2 = Log.createSubsession();
326 mHandler.obtainMessage(MSG_UNHOLD, args).sendToTarget();
327 } finally {
328 Log.endSession();
329 }
Sailesh Nepal2a46b902014-07-04 17:21:07 -0700330 }
331
332 @Override
Brad Ebingerb32d4f82016-10-24 16:40:49 -0700333 public void onCallAudioStateChanged(String callId, CallAudioState callAudioState,
334 Session.Info sessionInfo) {
335 Log.startSession(sessionInfo, SESSION_CALL_AUDIO_SC);
336 try {
337 SomeArgs args = SomeArgs.obtain();
338 args.arg1 = callId;
339 args.arg2 = callAudioState;
340 args.arg3 = Log.createSubsession();
341 mHandler.obtainMessage(MSG_ON_CALL_AUDIO_STATE_CHANGED, args).sendToTarget();
342 } finally {
343 Log.endSession();
344 }
Sailesh Nepal2a46b902014-07-04 17:21:07 -0700345 }
346
347 @Override
Brad Ebingerb32d4f82016-10-24 16:40:49 -0700348 public void playDtmfTone(String callId, char digit, Session.Info sessionInfo) {
349 Log.startSession(sessionInfo, SESSION_PLAY_DTMF);
350 try {
351 SomeArgs args = SomeArgs.obtain();
352 args.arg1 = digit;
353 args.arg2 = callId;
354 args.arg3 = Log.createSubsession();
355 mHandler.obtainMessage(MSG_PLAY_DTMF_TONE, args).sendToTarget();
356 } finally {
357 Log.endSession();
358 }
Sailesh Nepal2a46b902014-07-04 17:21:07 -0700359 }
360
361 @Override
Brad Ebingerb32d4f82016-10-24 16:40:49 -0700362 public void stopDtmfTone(String callId, Session.Info sessionInfo) {
363 Log.startSession(sessionInfo, SESSION_STOP_DTMF);
364 try {
365 SomeArgs args = SomeArgs.obtain();
366 args.arg1 = callId;
367 args.arg2 = Log.createSubsession();
368 mHandler.obtainMessage(MSG_STOP_DTMF_TONE, args).sendToTarget();
369 } finally {
370 Log.endSession();
371 }
Sailesh Nepal2a46b902014-07-04 17:21:07 -0700372 }
373
374 @Override
Brad Ebingerb32d4f82016-10-24 16:40:49 -0700375 public void conference(String callId1, String callId2, Session.Info sessionInfo) {
376 Log.startSession(sessionInfo, SESSION_CONFERENCE);
377 try {
378 SomeArgs args = SomeArgs.obtain();
379 args.arg1 = callId1;
380 args.arg2 = callId2;
381 args.arg3 = Log.createSubsession();
382 mHandler.obtainMessage(MSG_CONFERENCE, args).sendToTarget();
383 } finally {
384 Log.endSession();
385 }
Sailesh Nepal2a46b902014-07-04 17:21:07 -0700386 }
387
388 @Override
Brad Ebingerb32d4f82016-10-24 16:40:49 -0700389 public void splitFromConference(String callId, Session.Info sessionInfo) {
390 Log.startSession(sessionInfo, SESSION_SPLIT_CONFERENCE);
391 try {
392 SomeArgs args = SomeArgs.obtain();
393 args.arg1 = callId;
394 args.arg2 = Log.createSubsession();
395 mHandler.obtainMessage(MSG_SPLIT_FROM_CONFERENCE, args).sendToTarget();
396 } finally {
397 Log.endSession();
398 }
Sailesh Nepal2a46b902014-07-04 17:21:07 -0700399 }
400
401 @Override
Brad Ebingerb32d4f82016-10-24 16:40:49 -0700402 public void mergeConference(String callId, Session.Info sessionInfo) {
403 Log.startSession(sessionInfo, SESSION_MERGE_CONFERENCE);
404 try {
405 SomeArgs args = SomeArgs.obtain();
406 args.arg1 = callId;
407 args.arg2 = Log.createSubsession();
408 mHandler.obtainMessage(MSG_MERGE_CONFERENCE, args).sendToTarget();
409 } finally {
410 Log.endSession();
411 }
Santos Cordona4868042014-09-04 17:39:22 -0700412 }
413
414 @Override
Brad Ebingerb32d4f82016-10-24 16:40:49 -0700415 public void swapConference(String callId, Session.Info sessionInfo) {
416 Log.startSession(sessionInfo, SESSION_SWAP_CONFERENCE);
417 try {
418 SomeArgs args = SomeArgs.obtain();
419 args.arg1 = callId;
420 args.arg2 = Log.createSubsession();
421 mHandler.obtainMessage(MSG_SWAP_CONFERENCE, args).sendToTarget();
422 } finally {
423 Log.endSession();
424 }
Santos Cordona4868042014-09-04 17:39:22 -0700425 }
426
427 @Override
Brad Ebingerb32d4f82016-10-24 16:40:49 -0700428 public void onPostDialContinue(String callId, boolean proceed, Session.Info sessionInfo) {
429 Log.startSession(sessionInfo, SESSION_POST_DIAL_CONT);
430 try {
431 SomeArgs args = SomeArgs.obtain();
432 args.arg1 = callId;
433 args.arg2 = Log.createSubsession();
434 args.argi1 = proceed ? 1 : 0;
435 mHandler.obtainMessage(MSG_ON_POST_DIAL_CONTINUE, args).sendToTarget();
436 } finally {
437 Log.endSession();
438 }
Sailesh Nepal2a46b902014-07-04 17:21:07 -0700439 }
Tyler Gunn876dbfb2016-03-14 15:18:07 -0700440
441 @Override
Brad Ebingerb32d4f82016-10-24 16:40:49 -0700442 public void pullExternalCall(String callId, Session.Info sessionInfo) {
443 Log.startSession(sessionInfo, SESSION_PULL_EXTERNAL_CALL);
444 try {
445 SomeArgs args = SomeArgs.obtain();
446 args.arg1 = callId;
447 args.arg2 = Log.createSubsession();
448 mHandler.obtainMessage(MSG_PULL_EXTERNAL_CALL, args).sendToTarget();
449 } finally {
450 Log.endSession();
451 }
Tyler Gunn876dbfb2016-03-14 15:18:07 -0700452 }
453
454 @Override
Brad Ebingerb32d4f82016-10-24 16:40:49 -0700455 public void sendCallEvent(String callId, String event, Bundle extras,
456 Session.Info sessionInfo) {
457 Log.startSession(sessionInfo, SESSION_SEND_CALL_EVENT);
458 try {
459 SomeArgs args = SomeArgs.obtain();
460 args.arg1 = callId;
461 args.arg2 = event;
462 args.arg3 = extras;
463 args.arg4 = Log.createSubsession();
464 mHandler.obtainMessage(MSG_SEND_CALL_EVENT, args).sendToTarget();
465 } finally {
466 Log.endSession();
467 }
Tyler Gunn876dbfb2016-03-14 15:18:07 -0700468 }
Tyler Gunndee56a82016-03-23 16:06:34 -0700469
470 @Override
Brad Ebingerb32d4f82016-10-24 16:40:49 -0700471 public void onExtrasChanged(String callId, Bundle extras, Session.Info sessionInfo) {
472 Log.startSession(sessionInfo, SESSION_EXTRAS_CHANGED);
473 try {
474 SomeArgs args = SomeArgs.obtain();
475 args.arg1 = callId;
476 args.arg2 = extras;
477 args.arg3 = Log.createSubsession();
478 mHandler.obtainMessage(MSG_ON_EXTRAS_CHANGED, args).sendToTarget();
479 } finally {
480 Log.endSession();
481 }
Tyler Gunndee56a82016-03-23 16:06:34 -0700482 }
Sailesh Nepal2a46b902014-07-04 17:21:07 -0700483 };
484
485 private final Handler mHandler = new Handler(Looper.getMainLooper()) {
486 @Override
487 public void handleMessage(Message msg) {
488 switch (msg.what) {
Brad Ebingerb32d4f82016-10-24 16:40:49 -0700489 case MSG_ADD_CONNECTION_SERVICE_ADAPTER: {
490 SomeArgs args = (SomeArgs) msg.obj;
491 try {
492 IConnectionServiceAdapter adapter = (IConnectionServiceAdapter) args.arg1;
493 Log.continueSession((Session) args.arg2,
494 SESSION_HANDLER + SESSION_ADD_CS_ADAPTER);
495 mAdapter.addAdapter(adapter);
496 onAdapterAttached();
497 } finally {
498 args.recycle();
499 Log.endSession();
500 }
Sailesh Nepal2a46b902014-07-04 17:21:07 -0700501 break;
Brad Ebingerb32d4f82016-10-24 16:40:49 -0700502 }
503 case MSG_REMOVE_CONNECTION_SERVICE_ADAPTER: {
504 SomeArgs args = (SomeArgs) msg.obj;
505 try {
506 Log.continueSession((Session) args.arg2,
507 SESSION_HANDLER + SESSION_REMOVE_CS_ADAPTER);
508 mAdapter.removeAdapter((IConnectionServiceAdapter) args.arg1);
509 } finally {
510 args.recycle();
511 Log.endSession();
512 }
Ihab Awad8aecfed2014-08-08 17:06:11 -0700513 break;
Brad Ebingerb32d4f82016-10-24 16:40:49 -0700514 }
Ihab Awadf8b69882014-07-25 15:14:01 -0700515 case MSG_CREATE_CONNECTION: {
516 SomeArgs args = (SomeArgs) msg.obj;
Brad Ebingerb32d4f82016-10-24 16:40:49 -0700517 Log.continueSession((Session) args.arg4, SESSION_HANDLER + SESSION_CREATE_CONN);
Ihab Awadf8b69882014-07-25 15:14:01 -0700518 try {
Ihab Awad5d0410f2014-07-30 10:07:40 -0700519 final PhoneAccountHandle connectionManagerPhoneAccount =
Ihab Awadf8b69882014-07-25 15:14:01 -0700520 (PhoneAccountHandle) args.arg1;
Ihab Awadb19a0bc2014-08-07 19:46:01 -0700521 final String id = (String) args.arg2;
522 final ConnectionRequest request = (ConnectionRequest) args.arg3;
Ihab Awad5d0410f2014-07-30 10:07:40 -0700523 final boolean isIncoming = args.argi1 == 1;
Yorke Leec3cf9822014-10-02 09:38:39 -0700524 final boolean isUnknown = args.argi2 == 1;
Ihab Awad5d0410f2014-07-30 10:07:40 -0700525 if (!mAreAccountsInitialized) {
Ihab Awadb19a0bc2014-08-07 19:46:01 -0700526 Log.d(this, "Enqueueing pre-init request %s", id);
Brad Ebinger0c3541b2016-11-01 14:11:38 -0700527 mPreInitializationConnectionRequests.add(
528 new android.telecom.Logging.Runnable(
529 SESSION_HANDLER + SESSION_CREATE_CONN + ".pICR",
530 null /*lock*/) {
Ihab Awad5d0410f2014-07-30 10:07:40 -0700531 @Override
Brad Ebinger0c3541b2016-11-01 14:11:38 -0700532 public void loggedRun() {
Ihab Awad5d0410f2014-07-30 10:07:40 -0700533 createConnection(
534 connectionManagerPhoneAccount,
Ihab Awadb19a0bc2014-08-07 19:46:01 -0700535 id,
Ihab Awad5d0410f2014-07-30 10:07:40 -0700536 request,
Yorke Leec3cf9822014-10-02 09:38:39 -0700537 isIncoming,
538 isUnknown);
Ihab Awad5d0410f2014-07-30 10:07:40 -0700539 }
Brad Ebinger0c3541b2016-11-01 14:11:38 -0700540 }.prepare());
Ihab Awad5d0410f2014-07-30 10:07:40 -0700541 } else {
Ihab Awadb19a0bc2014-08-07 19:46:01 -0700542 createConnection(
543 connectionManagerPhoneAccount,
544 id,
545 request,
Yorke Leec3cf9822014-10-02 09:38:39 -0700546 isIncoming,
547 isUnknown);
Ihab Awad5d0410f2014-07-30 10:07:40 -0700548 }
Ihab Awadf8b69882014-07-25 15:14:01 -0700549 } finally {
550 args.recycle();
Brad Ebingerb32d4f82016-10-24 16:40:49 -0700551 Log.endSession();
Ihab Awadf8b69882014-07-25 15:14:01 -0700552 }
Sailesh Nepal2a46b902014-07-04 17:21:07 -0700553 break;
Ihab Awadf8b69882014-07-25 15:14:01 -0700554 }
Brad Ebingerb32d4f82016-10-24 16:40:49 -0700555 case MSG_ABORT: {
556 SomeArgs args = (SomeArgs) msg.obj;
557 Log.continueSession((Session) args.arg2, SESSION_HANDLER + SESSION_ABORT);
558 try {
559 abort((String) args.arg1);
560 } finally {
561 args.recycle();
562 Log.endSession();
563 }
Sailesh Nepal2a46b902014-07-04 17:21:07 -0700564 break;
Brad Ebingerb32d4f82016-10-24 16:40:49 -0700565 }
566 case MSG_ANSWER: {
567 SomeArgs args = (SomeArgs) msg.obj;
568 Log.continueSession((Session) args.arg2, SESSION_HANDLER + SESSION_ANSWER);
569 try {
570 answer((String) args.arg1);
571 } finally {
572 args.recycle();
573 Log.endSession();
574 }
Tyler Gunnbe74de02014-08-29 14:51:48 -0700575 break;
Brad Ebingerb32d4f82016-10-24 16:40:49 -0700576 }
Tyler Gunnbe74de02014-08-29 14:51:48 -0700577 case MSG_ANSWER_VIDEO: {
Andrew Lee8da4c3c2014-07-16 10:11:42 -0700578 SomeArgs args = (SomeArgs) msg.obj;
Brad Ebingerb32d4f82016-10-24 16:40:49 -0700579 Log.continueSession((Session) args.arg2,
580 SESSION_HANDLER + SESSION_ANSWER_VIDEO);
Andrew Lee8da4c3c2014-07-16 10:11:42 -0700581 try {
582 String callId = (String) args.arg1;
Evan Charltonbf11f982014-07-20 22:06:28 -0700583 int videoState = args.argi1;
Tyler Gunnbe74de02014-08-29 14:51:48 -0700584 answerVideo(callId, videoState);
Andrew Lee8da4c3c2014-07-16 10:11:42 -0700585 } finally {
586 args.recycle();
Brad Ebingerb32d4f82016-10-24 16:40:49 -0700587 Log.endSession();
Andrew Lee8da4c3c2014-07-16 10:11:42 -0700588 }
Sailesh Nepal2a46b902014-07-04 17:21:07 -0700589 break;
Andrew Lee8da4c3c2014-07-16 10:11:42 -0700590 }
Brad Ebingerb32d4f82016-10-24 16:40:49 -0700591 case MSG_REJECT: {
592 SomeArgs args = (SomeArgs) msg.obj;
593 Log.continueSession((Session) args.arg2, SESSION_HANDLER + SESSION_REJECT);
594 try {
595 reject((String) args.arg1);
596 } finally {
597 args.recycle();
598 Log.endSession();
599 }
Sailesh Nepal2a46b902014-07-04 17:21:07 -0700600 break;
Brad Ebingerb32d4f82016-10-24 16:40:49 -0700601 }
Bryce Lee81901682015-08-28 16:38:02 -0700602 case MSG_REJECT_WITH_MESSAGE: {
603 SomeArgs args = (SomeArgs) msg.obj;
Brad Ebingerb32d4f82016-10-24 16:40:49 -0700604 Log.continueSession((Session) args.arg3,
605 SESSION_HANDLER + SESSION_REJECT_MESSAGE);
Bryce Lee81901682015-08-28 16:38:02 -0700606 try {
607 reject((String) args.arg1, (String) args.arg2);
608 } finally {
609 args.recycle();
Brad Ebingerb32d4f82016-10-24 16:40:49 -0700610 Log.endSession();
Bryce Lee81901682015-08-28 16:38:02 -0700611 }
612 break;
613 }
Brad Ebingerb32d4f82016-10-24 16:40:49 -0700614 case MSG_DISCONNECT: {
615 SomeArgs args = (SomeArgs) msg.obj;
616 Log.continueSession((Session) args.arg2, SESSION_HANDLER + SESSION_DISCONNECT);
617 try {
618 disconnect((String) args.arg1);
619 } finally {
620 args.recycle();
621 Log.endSession();
622 }
Sailesh Nepal2a46b902014-07-04 17:21:07 -0700623 break;
Brad Ebingerb32d4f82016-10-24 16:40:49 -0700624 }
625 case MSG_SILENCE: {
626 SomeArgs args = (SomeArgs) msg.obj;
627 Log.continueSession((Session) args.arg2, SESSION_HANDLER + SESSION_SILENCE);
628 try {
629 silence((String) args.arg1);
630 } finally {
631 args.recycle();
632 Log.endSession();
633 }
Bryce Leecac50772015-11-17 15:13:29 -0800634 break;
Brad Ebingerb32d4f82016-10-24 16:40:49 -0700635 }
636 case MSG_HOLD: {
637 SomeArgs args = (SomeArgs) msg.obj;
638 Log.continueSession((Session) args.arg2, SESSION_HANDLER + SESSION_REJECT);
639 try {
640 hold((String) args.arg1);
641 } finally {
642 args.recycle();
643 Log.endSession();
644 }
Sailesh Nepal2a46b902014-07-04 17:21:07 -0700645 break;
Brad Ebingerb32d4f82016-10-24 16:40:49 -0700646 }
647 case MSG_UNHOLD: {
648 SomeArgs args = (SomeArgs) msg.obj;
649 Log.continueSession((Session) args.arg2, SESSION_HANDLER + SESSION_UNHOLD);
650 try {
651 unhold((String) args.arg1);
652 } finally {
653 args.recycle();
654 Log.endSession();
655 }
Sailesh Nepal2a46b902014-07-04 17:21:07 -0700656 break;
Brad Ebingerb32d4f82016-10-24 16:40:49 -0700657 }
Yorke Lee4af59352015-05-13 14:14:54 -0700658 case MSG_ON_CALL_AUDIO_STATE_CHANGED: {
Sailesh Nepal2a46b902014-07-04 17:21:07 -0700659 SomeArgs args = (SomeArgs) msg.obj;
Brad Ebingerb32d4f82016-10-24 16:40:49 -0700660 Log.continueSession((Session) args.arg3,
661 SESSION_HANDLER + SESSION_CALL_AUDIO_SC);
Sailesh Nepal2a46b902014-07-04 17:21:07 -0700662 try {
663 String callId = (String) args.arg1;
Yorke Lee4af59352015-05-13 14:14:54 -0700664 CallAudioState audioState = (CallAudioState) args.arg2;
665 onCallAudioStateChanged(callId, new CallAudioState(audioState));
Sailesh Nepal2a46b902014-07-04 17:21:07 -0700666 } finally {
667 args.recycle();
Brad Ebingerb32d4f82016-10-24 16:40:49 -0700668 Log.endSession();
Sailesh Nepal2a46b902014-07-04 17:21:07 -0700669 }
670 break;
671 }
Brad Ebingerb32d4f82016-10-24 16:40:49 -0700672 case MSG_PLAY_DTMF_TONE: {
673 SomeArgs args = (SomeArgs) msg.obj;
674 try {
675 Log.continueSession((Session) args.arg3,
676 SESSION_HANDLER + SESSION_PLAY_DTMF);
677 playDtmfTone((String) args.arg2, (char) args.arg1);
678 } finally {
679 args.recycle();
680 Log.endSession();
681 }
Sailesh Nepal2a46b902014-07-04 17:21:07 -0700682 break;
Brad Ebingerb32d4f82016-10-24 16:40:49 -0700683 }
684 case MSG_STOP_DTMF_TONE: {
685 SomeArgs args = (SomeArgs) msg.obj;
686 try {
687 Log.continueSession((Session) args.arg2,
688 SESSION_HANDLER + SESSION_STOP_DTMF);
689 stopDtmfTone((String) args.arg1);
690 } finally {
691 args.recycle();
692 Log.endSession();
693 }
Sailesh Nepal2a46b902014-07-04 17:21:07 -0700694 break;
Brad Ebingerb32d4f82016-10-24 16:40:49 -0700695 }
Sailesh Nepal2a46b902014-07-04 17:21:07 -0700696 case MSG_CONFERENCE: {
697 SomeArgs args = (SomeArgs) msg.obj;
698 try {
Brad Ebingerb32d4f82016-10-24 16:40:49 -0700699 Log.continueSession((Session) args.arg3,
700 SESSION_HANDLER + SESSION_CONFERENCE);
Santos Cordon823fd3c2014-08-07 18:35:18 -0700701 String callId1 = (String) args.arg1;
702 String callId2 = (String) args.arg2;
703 conference(callId1, callId2);
Sailesh Nepal2a46b902014-07-04 17:21:07 -0700704 } finally {
705 args.recycle();
Brad Ebingerb32d4f82016-10-24 16:40:49 -0700706 Log.endSession();
Sailesh Nepal2a46b902014-07-04 17:21:07 -0700707 }
708 break;
709 }
Brad Ebingerb32d4f82016-10-24 16:40:49 -0700710 case MSG_SPLIT_FROM_CONFERENCE: {
711 SomeArgs args = (SomeArgs) msg.obj;
712 try {
713 Log.continueSession((Session) args.arg2,
714 SESSION_HANDLER + SESSION_SPLIT_CONFERENCE);
715 splitFromConference((String) args.arg1);
716 } finally {
717 args.recycle();
718 Log.endSession();
719 }
Sailesh Nepal2a46b902014-07-04 17:21:07 -0700720 break;
Brad Ebingerb32d4f82016-10-24 16:40:49 -0700721 }
722 case MSG_MERGE_CONFERENCE: {
723 SomeArgs args = (SomeArgs) msg.obj;
724 try {
725 Log.continueSession((Session) args.arg2,
726 SESSION_HANDLER + SESSION_MERGE_CONFERENCE);
727 mergeConference((String) args.arg1);
728 } finally {
729 args.recycle();
730 Log.endSession();
731 }
Santos Cordona4868042014-09-04 17:39:22 -0700732 break;
Brad Ebingerb32d4f82016-10-24 16:40:49 -0700733 }
734 case MSG_SWAP_CONFERENCE: {
735 SomeArgs args = (SomeArgs) msg.obj;
736 try {
737 Log.continueSession((Session) args.arg2,
738 SESSION_HANDLER + SESSION_SWAP_CONFERENCE);
739 swapConference((String) args.arg1);
740 } finally {
741 args.recycle();
742 Log.endSession();
743 }
Santos Cordona4868042014-09-04 17:39:22 -0700744 break;
Brad Ebingerb32d4f82016-10-24 16:40:49 -0700745 }
Sailesh Nepal2a46b902014-07-04 17:21:07 -0700746 case MSG_ON_POST_DIAL_CONTINUE: {
747 SomeArgs args = (SomeArgs) msg.obj;
748 try {
Brad Ebingerb32d4f82016-10-24 16:40:49 -0700749 Log.continueSession((Session) args.arg2,
750 SESSION_HANDLER + SESSION_POST_DIAL_CONT);
Sailesh Nepal2a46b902014-07-04 17:21:07 -0700751 String callId = (String) args.arg1;
752 boolean proceed = (args.argi1 == 1);
753 onPostDialContinue(callId, proceed);
754 } finally {
755 args.recycle();
Brad Ebingerb32d4f82016-10-24 16:40:49 -0700756 Log.endSession();
Sailesh Nepal2a46b902014-07-04 17:21:07 -0700757 }
758 break;
759 }
Tyler Gunn876dbfb2016-03-14 15:18:07 -0700760 case MSG_PULL_EXTERNAL_CALL: {
Brad Ebingerb32d4f82016-10-24 16:40:49 -0700761 SomeArgs args = (SomeArgs) msg.obj;
762 try {
763 Log.continueSession((Session) args.arg2,
764 SESSION_HANDLER + SESSION_PULL_EXTERNAL_CALL);
765 pullExternalCall((String) args.arg1);
766 } finally {
767 args.recycle();
768 Log.endSession();
769 }
Tyler Gunn876dbfb2016-03-14 15:18:07 -0700770 break;
771 }
772 case MSG_SEND_CALL_EVENT: {
773 SomeArgs args = (SomeArgs) msg.obj;
774 try {
Brad Ebingerb32d4f82016-10-24 16:40:49 -0700775 Log.continueSession((Session) args.arg4,
776 SESSION_HANDLER + SESSION_SEND_CALL_EVENT);
Tyler Gunn876dbfb2016-03-14 15:18:07 -0700777 String callId = (String) args.arg1;
778 String event = (String) args.arg2;
779 Bundle extras = (Bundle) args.arg3;
780 sendCallEvent(callId, event, extras);
781 } finally {
782 args.recycle();
Brad Ebingerb32d4f82016-10-24 16:40:49 -0700783 Log.endSession();
Tyler Gunn876dbfb2016-03-14 15:18:07 -0700784 }
785 break;
786 }
Tyler Gunndee56a82016-03-23 16:06:34 -0700787 case MSG_ON_EXTRAS_CHANGED: {
788 SomeArgs args = (SomeArgs) msg.obj;
789 try {
Brad Ebingerb32d4f82016-10-24 16:40:49 -0700790 Log.continueSession((Session) args.arg3,
791 SESSION_HANDLER + SESSION_EXTRAS_CHANGED);
Tyler Gunndee56a82016-03-23 16:06:34 -0700792 String callId = (String) args.arg1;
793 Bundle extras = (Bundle) args.arg2;
794 handleExtrasChanged(callId, extras);
795 } finally {
796 args.recycle();
Brad Ebingerb32d4f82016-10-24 16:40:49 -0700797 Log.endSession();
Tyler Gunndee56a82016-03-23 16:06:34 -0700798 }
799 break;
800 }
Sailesh Nepal2a46b902014-07-04 17:21:07 -0700801 default:
802 break;
803 }
804 }
805 };
806
Santos Cordon823fd3c2014-08-07 18:35:18 -0700807 private final Conference.Listener mConferenceListener = new Conference.Listener() {
808 @Override
809 public void onStateChanged(Conference conference, int oldState, int newState) {
810 String id = mIdByConference.get(conference);
811 switch (newState) {
812 case Connection.STATE_ACTIVE:
813 mAdapter.setActive(id);
814 break;
815 case Connection.STATE_HOLDING:
816 mAdapter.setOnHold(id);
817 break;
818 case Connection.STATE_DISCONNECTED:
819 // handled by onDisconnected
820 break;
821 }
822 }
823
824 @Override
Andrew Lee7f3d41f2014-09-11 17:33:16 -0700825 public void onDisconnected(Conference conference, DisconnectCause disconnectCause) {
Santos Cordon823fd3c2014-08-07 18:35:18 -0700826 String id = mIdByConference.get(conference);
Andrew Lee7f3d41f2014-09-11 17:33:16 -0700827 mAdapter.setDisconnected(id, disconnectCause);
Santos Cordon823fd3c2014-08-07 18:35:18 -0700828 }
829
830 @Override
831 public void onConnectionAdded(Conference conference, Connection connection) {
832 }
833
834 @Override
835 public void onConnectionRemoved(Conference conference, Connection connection) {
836 }
837
838 @Override
Ihab Awad50e35062014-09-30 09:17:03 -0700839 public void onConferenceableConnectionsChanged(
840 Conference conference, List<Connection> conferenceableConnections) {
841 mAdapter.setConferenceableConnections(
842 mIdByConference.get(conference),
843 createConnectionIdList(conferenceableConnections));
844 }
845
846 @Override
Santos Cordon823fd3c2014-08-07 18:35:18 -0700847 public void onDestroyed(Conference conference) {
848 removeConference(conference);
849 }
850
851 @Override
Ihab Awad5c9c86e2014-11-12 13:41:16 -0800852 public void onConnectionCapabilitiesChanged(
853 Conference conference,
854 int connectionCapabilities) {
Santos Cordon823fd3c2014-08-07 18:35:18 -0700855 String id = mIdByConference.get(conference);
856 Log.d(this, "call capabilities: conference: %s",
Ihab Awad5c9c86e2014-11-12 13:41:16 -0800857 Connection.capabilitiesToString(connectionCapabilities));
858 mAdapter.setConnectionCapabilities(id, connectionCapabilities);
Santos Cordon823fd3c2014-08-07 18:35:18 -0700859 }
Rekha Kumar07366812015-03-24 16:42:31 -0700860
861 @Override
Tyler Gunn720c6642016-03-22 09:02:47 -0700862 public void onConnectionPropertiesChanged(
863 Conference conference,
864 int connectionProperties) {
865 String id = mIdByConference.get(conference);
866 Log.d(this, "call capabilities: conference: %s",
867 Connection.propertiesToString(connectionProperties));
868 mAdapter.setConnectionProperties(id, connectionProperties);
869 }
870
871 @Override
Rekha Kumar07366812015-03-24 16:42:31 -0700872 public void onVideoStateChanged(Conference c, int videoState) {
873 String id = mIdByConference.get(c);
874 Log.d(this, "onVideoStateChanged set video state %d", videoState);
875 mAdapter.setVideoState(id, videoState);
876 }
877
878 @Override
879 public void onVideoProviderChanged(Conference c, Connection.VideoProvider videoProvider) {
880 String id = mIdByConference.get(c);
881 Log.d(this, "onVideoProviderChanged: Connection: %s, VideoProvider: %s", c,
882 videoProvider);
883 mAdapter.setVideoProvider(id, videoProvider);
884 }
Andrew Lee0f51da32015-04-16 13:11:55 -0700885
886 @Override
Andrew Leeedc625f2015-04-14 13:38:12 -0700887 public void onStatusHintsChanged(Conference conference, StatusHints statusHints) {
888 String id = mIdByConference.get(conference);
Tyler Gunndee56a82016-03-23 16:06:34 -0700889 if (id != null) {
890 mAdapter.setStatusHints(id, statusHints);
891 }
Andrew Leeedc625f2015-04-14 13:38:12 -0700892 }
Santos Cordon6b7f9552015-05-27 17:21:45 -0700893
894 @Override
Tyler Gunndee56a82016-03-23 16:06:34 -0700895 public void onExtrasChanged(Conference c, Bundle extras) {
896 String id = mIdByConference.get(c);
897 if (id != null) {
898 mAdapter.putExtras(id, extras);
899 }
900 }
901
902 @Override
903 public void onExtrasRemoved(Conference c, List<String> keys) {
904 String id = mIdByConference.get(c);
905 if (id != null) {
906 mAdapter.removeExtras(id, keys);
907 }
Santos Cordon6b7f9552015-05-27 17:21:45 -0700908 }
Santos Cordon823fd3c2014-08-07 18:35:18 -0700909 };
910
Ihab Awad542e0ea2014-05-16 10:22:16 -0700911 private final Connection.Listener mConnectionListener = new Connection.Listener() {
912 @Override
913 public void onStateChanged(Connection c, int state) {
914 String id = mIdByConnection.get(c);
Ihab Awad42b30e12014-05-22 09:49:34 -0700915 Log.d(this, "Adapter set state %s %s", id, Connection.stateToString(state));
Ihab Awad542e0ea2014-05-16 10:22:16 -0700916 switch (state) {
Ihab Awadb19a0bc2014-08-07 19:46:01 -0700917 case Connection.STATE_ACTIVE:
Sailesh Nepal2a46b902014-07-04 17:21:07 -0700918 mAdapter.setActive(id);
Ihab Awad542e0ea2014-05-16 10:22:16 -0700919 break;
Ihab Awadb19a0bc2014-08-07 19:46:01 -0700920 case Connection.STATE_DIALING:
Sailesh Nepal2a46b902014-07-04 17:21:07 -0700921 mAdapter.setDialing(id);
Ihab Awad542e0ea2014-05-16 10:22:16 -0700922 break;
Tyler Gunnc96b5e02016-07-07 22:53:57 -0700923 case Connection.STATE_PULLING_CALL:
924 mAdapter.setPulling(id);
925 break;
Ihab Awadb19a0bc2014-08-07 19:46:01 -0700926 case Connection.STATE_DISCONNECTED:
Ihab Awad542e0ea2014-05-16 10:22:16 -0700927 // Handled in onDisconnected()
928 break;
Ihab Awadb19a0bc2014-08-07 19:46:01 -0700929 case Connection.STATE_HOLDING:
Sailesh Nepal2a46b902014-07-04 17:21:07 -0700930 mAdapter.setOnHold(id);
Ihab Awad542e0ea2014-05-16 10:22:16 -0700931 break;
Ihab Awadb19a0bc2014-08-07 19:46:01 -0700932 case Connection.STATE_NEW:
Tyler Gunnef9f6f92014-09-12 22:16:17 -0700933 // Nothing to tell Telecom
Ihab Awad542e0ea2014-05-16 10:22:16 -0700934 break;
Ihab Awadb19a0bc2014-08-07 19:46:01 -0700935 case Connection.STATE_RINGING:
Sailesh Nepal2a46b902014-07-04 17:21:07 -0700936 mAdapter.setRinging(id);
Ihab Awad542e0ea2014-05-16 10:22:16 -0700937 break;
938 }
939 }
940
941 @Override
Andrew Lee7f3d41f2014-09-11 17:33:16 -0700942 public void onDisconnected(Connection c, DisconnectCause disconnectCause) {
Ihab Awad542e0ea2014-05-16 10:22:16 -0700943 String id = mIdByConnection.get(c);
Andrew Lee26786392014-09-16 18:14:59 -0700944 Log.d(this, "Adapter set disconnected %s", disconnectCause);
Andrew Lee7f3d41f2014-09-11 17:33:16 -0700945 mAdapter.setDisconnected(id, disconnectCause);
Ihab Awad542e0ea2014-05-16 10:22:16 -0700946 }
947
948 @Override
Tyler Gunnaa07df82014-07-17 07:50:22 -0700949 public void onVideoStateChanged(Connection c, int videoState) {
950 String id = mIdByConnection.get(c);
951 Log.d(this, "Adapter set video state %d", videoState);
952 mAdapter.setVideoState(id, videoState);
953 }
954
955 @Override
Andrew Lee100e2932014-09-08 15:34:24 -0700956 public void onAddressChanged(Connection c, Uri address, int presentation) {
Sailesh Nepal61203862014-07-11 14:50:13 -0700957 String id = mIdByConnection.get(c);
Andrew Lee100e2932014-09-08 15:34:24 -0700958 mAdapter.setAddress(id, address, presentation);
Sailesh Nepal61203862014-07-11 14:50:13 -0700959 }
960
961 @Override
962 public void onCallerDisplayNameChanged(
963 Connection c, String callerDisplayName, int presentation) {
964 String id = mIdByConnection.get(c);
965 mAdapter.setCallerDisplayName(id, callerDisplayName, presentation);
Ihab Awad542e0ea2014-05-16 10:22:16 -0700966 }
967
968 @Override
Ihab Awad542e0ea2014-05-16 10:22:16 -0700969 public void onDestroyed(Connection c) {
970 removeConnection(c);
971 }
Ihab Awadf8358972014-05-28 16:46:42 -0700972
973 @Override
Sailesh Nepal2a46b902014-07-04 17:21:07 -0700974 public void onPostDialWait(Connection c, String remaining) {
Sailesh Nepal091768c2014-06-30 15:15:23 -0700975 String id = mIdByConnection.get(c);
976 Log.d(this, "Adapter onPostDialWait %s, %s", c, remaining);
Sailesh Nepal2a46b902014-07-04 17:21:07 -0700977 mAdapter.onPostDialWait(id, remaining);
Sailesh Nepal091768c2014-06-30 15:15:23 -0700978 }
979
980 @Override
Nancy Chen27d1c2d2014-12-15 16:12:50 -0800981 public void onPostDialChar(Connection c, char nextChar) {
982 String id = mIdByConnection.get(c);
983 Log.d(this, "Adapter onPostDialChar %s, %s", c, nextChar);
984 mAdapter.onPostDialChar(id, nextChar);
985 }
986
987 @Override
Andrew Lee100e2932014-09-08 15:34:24 -0700988 public void onRingbackRequested(Connection c, boolean ringback) {
Ihab Awadf8358972014-05-28 16:46:42 -0700989 String id = mIdByConnection.get(c);
990 Log.d(this, "Adapter onRingback %b", ringback);
Andrew Lee100e2932014-09-08 15:34:24 -0700991 mAdapter.setRingbackRequested(id, ringback);
Ihab Awadf8358972014-05-28 16:46:42 -0700992 }
Santos Cordonb6939982014-06-04 20:20:58 -0700993
994 @Override
Ihab Awad5c9c86e2014-11-12 13:41:16 -0800995 public void onConnectionCapabilitiesChanged(Connection c, int capabilities) {
Santos Cordonb6939982014-06-04 20:20:58 -0700996 String id = mIdByConnection.get(c);
Ihab Awadb19a0bc2014-08-07 19:46:01 -0700997 Log.d(this, "capabilities: parcelableconnection: %s",
Ihab Awad5c9c86e2014-11-12 13:41:16 -0800998 Connection.capabilitiesToString(capabilities));
999 mAdapter.setConnectionCapabilities(id, capabilities);
Santos Cordonb6939982014-06-04 20:20:58 -07001000 }
1001
Santos Cordonb6939982014-06-04 20:20:58 -07001002 @Override
Tyler Gunn720c6642016-03-22 09:02:47 -07001003 public void onConnectionPropertiesChanged(Connection c, int properties) {
1004 String id = mIdByConnection.get(c);
1005 Log.d(this, "properties: parcelableconnection: %s",
1006 Connection.propertiesToString(properties));
1007 mAdapter.setConnectionProperties(id, properties);
1008 }
1009
1010 @Override
Ihab Awadb19a0bc2014-08-07 19:46:01 -07001011 public void onVideoProviderChanged(Connection c, Connection.VideoProvider videoProvider) {
Andrew Lee5ffbe8b82014-06-20 16:29:33 -07001012 String id = mIdByConnection.get(c);
Rekha Kumar07366812015-03-24 16:42:31 -07001013 Log.d(this, "onVideoProviderChanged: Connection: %s, VideoProvider: %s", c,
1014 videoProvider);
Ihab Awadb19a0bc2014-08-07 19:46:01 -07001015 mAdapter.setVideoProvider(id, videoProvider);
Andrew Lee5ffbe8b82014-06-20 16:29:33 -07001016 }
Sailesh Nepal33aaae42014-07-07 22:49:44 -07001017
1018 @Override
Sailesh Nepal001bbbb2014-07-15 14:40:39 -07001019 public void onAudioModeIsVoipChanged(Connection c, boolean isVoip) {
Sailesh Nepal33aaae42014-07-07 22:49:44 -07001020 String id = mIdByConnection.get(c);
Andrew Lee100e2932014-09-08 15:34:24 -07001021 mAdapter.setIsVoipAudioMode(id, isVoip);
Sailesh Nepal33aaae42014-07-07 22:49:44 -07001022 }
Sailesh Nepale7ef59a2014-07-08 21:48:22 -07001023
1024 @Override
Sailesh Nepal001bbbb2014-07-15 14:40:39 -07001025 public void onStatusHintsChanged(Connection c, StatusHints statusHints) {
Sailesh Nepale7ef59a2014-07-08 21:48:22 -07001026 String id = mIdByConnection.get(c);
1027 mAdapter.setStatusHints(id, statusHints);
1028 }
Sailesh Nepal2ab88cc2014-07-18 14:49:18 -07001029
1030 @Override
Tyler Gunn6d76ca02014-11-17 15:49:51 -08001031 public void onConferenceablesChanged(
Tyler Gunndf2cbc82015-04-20 09:13:01 -07001032 Connection connection, List<Conferenceable> conferenceables) {
Ihab Awadb8e85c72014-08-23 20:34:57 -07001033 mAdapter.setConferenceableConnections(
1034 mIdByConnection.get(connection),
Tyler Gunn6d76ca02014-11-17 15:49:51 -08001035 createIdList(conferenceables));
Santos Cordon7c7bc7f2014-07-28 18:15:48 -07001036 }
Santos Cordon823fd3c2014-08-07 18:35:18 -07001037
1038 @Override
1039 public void onConferenceChanged(Connection connection, Conference conference) {
1040 String id = mIdByConnection.get(connection);
1041 if (id != null) {
1042 String conferenceId = null;
1043 if (conference != null) {
1044 conferenceId = mIdByConference.get(conference);
1045 }
1046 mAdapter.setIsConferenced(id, conferenceId);
1047 }
1048 }
Anthony Lee17455a32015-04-24 15:25:29 -07001049
1050 @Override
1051 public void onConferenceMergeFailed(Connection connection) {
1052 String id = mIdByConnection.get(connection);
1053 if (id != null) {
1054 mAdapter.onConferenceMergeFailed(id);
1055 }
1056 }
Santos Cordon6b7f9552015-05-27 17:21:45 -07001057
1058 @Override
Tyler Gunndee56a82016-03-23 16:06:34 -07001059 public void onExtrasChanged(Connection c, Bundle extras) {
1060 String id = mIdByConnection.get(c);
Santos Cordon6b7f9552015-05-27 17:21:45 -07001061 if (id != null) {
Tyler Gunndee56a82016-03-23 16:06:34 -07001062 mAdapter.putExtras(id, extras);
Santos Cordon6b7f9552015-05-27 17:21:45 -07001063 }
1064 }
Brad Ebingerb32d4f82016-10-24 16:40:49 -07001065
Tyler Gunnf5035432017-01-09 09:43:12 -08001066 @Override
Tyler Gunndee56a82016-03-23 16:06:34 -07001067 public void onExtrasRemoved(Connection c, List<String> keys) {
1068 String id = mIdByConnection.get(c);
1069 if (id != null) {
1070 mAdapter.removeExtras(id, keys);
1071 }
1072 }
1073
Tyler Gunnbd1eb1f2016-02-16 14:36:20 -08001074 @Override
Tyler Gunn876dbfb2016-03-14 15:18:07 -07001075 public void onConnectionEvent(Connection connection, String event, Bundle extras) {
Tyler Gunnbd1eb1f2016-02-16 14:36:20 -08001076 String id = mIdByConnection.get(connection);
1077 if (id != null) {
Tyler Gunn876dbfb2016-03-14 15:18:07 -07001078 mAdapter.onConnectionEvent(id, event, extras);
Tyler Gunnbd1eb1f2016-02-16 14:36:20 -08001079 }
1080 }
Tyler Gunnf5035432017-01-09 09:43:12 -08001081
1082 @Override
1083 public void onAudioRouteChanged(Connection c, int audioRoute) {
1084 String id = mIdByConnection.get(c);
1085 if (id != null) {
1086 mAdapter.setAudioRoute(id, audioRoute);
1087 }
1088 }
Ihab Awad542e0ea2014-05-16 10:22:16 -07001089 };
1090
Sailesh Nepal2a46b902014-07-04 17:21:07 -07001091 /** {@inheritDoc} */
Ihab Awad542e0ea2014-05-16 10:22:16 -07001092 @Override
Sailesh Nepal2a46b902014-07-04 17:21:07 -07001093 public final IBinder onBind(Intent intent) {
1094 return mBinder;
1095 }
1096
Santos Cordon29f2f2e2014-09-11 19:50:24 -07001097 /** {@inheritDoc} */
1098 @Override
1099 public boolean onUnbind(Intent intent) {
1100 endAllConnections();
1101 return super.onUnbind(intent);
1102 }
1103
Sailesh Nepalc5b01572014-07-14 16:29:44 -07001104 /**
Tyler Gunnef9f6f92014-09-12 22:16:17 -07001105 * This can be used by telecom to either create a new outgoing call or attach to an existing
1106 * incoming call. In either case, telecom will cycle through a set of services and call
Sailesh Nepalc5b01572014-07-14 16:29:44 -07001107 * createConnection util a connection service cancels the process or completes it successfully.
1108 */
Ihab Awadf8b69882014-07-25 15:14:01 -07001109 private void createConnection(
1110 final PhoneAccountHandle callManagerAccount,
Ihab Awadb19a0bc2014-08-07 19:46:01 -07001111 final String callId,
Ihab Awadf8b69882014-07-25 15:14:01 -07001112 final ConnectionRequest request,
Yorke Leec3cf9822014-10-02 09:38:39 -07001113 boolean isIncoming,
1114 boolean isUnknown) {
Sailesh Nepalcf7020b2014-08-20 10:07:19 -07001115 Log.d(this, "createConnection, callManagerAccount: %s, callId: %s, request: %s, " +
Tyler Gunnf0500bd2015-09-01 10:59:48 -07001116 "isIncoming: %b, isUnknown: %b", callManagerAccount, callId, request,
1117 isIncoming,
Yorke Leec3cf9822014-10-02 09:38:39 -07001118 isUnknown);
Ihab Awad542e0ea2014-05-16 10:22:16 -07001119
Yorke Leec3cf9822014-10-02 09:38:39 -07001120 Connection connection = isUnknown ? onCreateUnknownConnection(callManagerAccount, request)
1121 : isIncoming ? onCreateIncomingConnection(callManagerAccount, request)
Ihab Awad6107bab2014-08-18 09:23:25 -07001122 : onCreateOutgoingConnection(callManagerAccount, request);
Sailesh Nepalcf7020b2014-08-20 10:07:19 -07001123 Log.d(this, "createConnection, connection: %s", connection);
1124 if (connection == null) {
Andrew Lee7f3d41f2014-09-11 17:33:16 -07001125 connection = Connection.createFailedConnection(
1126 new DisconnectCause(DisconnectCause.ERROR));
Sailesh Nepalc5b01572014-07-14 16:29:44 -07001127 }
Ihab Awad542e0ea2014-05-16 10:22:16 -07001128
Tyler Gunnf0500bd2015-09-01 10:59:48 -07001129 connection.setTelecomCallId(callId);
Sailesh Nepalcf7020b2014-08-20 10:07:19 -07001130 if (connection.getState() != Connection.STATE_DISCONNECTED) {
Ihab Awad6107bab2014-08-18 09:23:25 -07001131 addConnection(callId, connection);
1132 }
1133
Andrew Lee100e2932014-09-08 15:34:24 -07001134 Uri address = connection.getAddress();
1135 String number = address == null ? "null" : address.getSchemeSpecificPart();
Tyler Gunn720c6642016-03-22 09:02:47 -07001136 Log.v(this, "createConnection, number: %s, state: %s, capabilities: %s, properties: %s",
Ihab Awadb19a0bc2014-08-07 19:46:01 -07001137 Connection.toLogSafePhoneNumber(number),
Sailesh Nepalcf7020b2014-08-20 10:07:19 -07001138 Connection.stateToString(connection.getState()),
Tyler Gunn720c6642016-03-22 09:02:47 -07001139 Connection.capabilitiesToString(connection.getConnectionCapabilities()),
1140 Connection.propertiesToString(connection.getConnectionProperties()));
Santos Cordon7c7bc7f2014-07-28 18:15:48 -07001141
Sailesh Nepalcf7020b2014-08-20 10:07:19 -07001142 Log.d(this, "createConnection, calling handleCreateConnectionSuccessful %s", callId);
Ihab Awad6107bab2014-08-18 09:23:25 -07001143 mAdapter.handleCreateConnectionComplete(
Ihab Awadb19a0bc2014-08-07 19:46:01 -07001144 callId,
Evan Charltonbf11f982014-07-20 22:06:28 -07001145 request,
1146 new ParcelableConnection(
1147 request.getAccountHandle(),
1148 connection.getState(),
Ihab Awad5c9c86e2014-11-12 13:41:16 -08001149 connection.getConnectionCapabilities(),
Tyler Gunn720c6642016-03-22 09:02:47 -07001150 connection.getConnectionProperties(),
Christine Hallstrom2830ce92016-11-30 16:06:42 -08001151 connection.getSupportedAudioRoutes(),
Andrew Lee100e2932014-09-08 15:34:24 -07001152 connection.getAddress(),
1153 connection.getAddressPresentation(),
Evan Charltonbf11f982014-07-20 22:06:28 -07001154 connection.getCallerDisplayName(),
1155 connection.getCallerDisplayNamePresentation(),
Ihab Awadb19a0bc2014-08-07 19:46:01 -07001156 connection.getVideoProvider() == null ?
1157 null : connection.getVideoProvider().getInterface(),
Sailesh Nepal8b9d3ca2014-08-14 17:39:34 -07001158 connection.getVideoState(),
Andrew Lee100e2932014-09-08 15:34:24 -07001159 connection.isRingbackRequested(),
Sailesh Nepal8b9d3ca2014-08-14 17:39:34 -07001160 connection.getAudioModeIsVoip(),
Roshan Piuse927ec02015-07-15 15:47:21 -07001161 connection.getConnectTimeMillis(),
Ihab Awad6107bab2014-08-18 09:23:25 -07001162 connection.getStatusHints(),
Sailesh Nepalcf7020b2014-08-20 10:07:19 -07001163 connection.getDisconnectCause(),
Santos Cordon6b7f9552015-05-27 17:21:45 -07001164 createIdList(connection.getConferenceables()),
1165 connection.getExtras()));
Tyler Gunnf5035432017-01-09 09:43:12 -08001166
1167 if (isIncoming && request.shouldShowIncomingCallUi() &&
1168 (connection.getConnectionProperties() & Connection.PROPERTY_SELF_MANAGED) ==
1169 Connection.PROPERTY_SELF_MANAGED) {
1170 // Tell ConnectionService to show its incoming call UX.
1171 connection.onShowIncomingCallUi();
1172 }
Shriram Ganesh6bf35ac2014-12-11 17:53:38 -08001173 if (isUnknown) {
1174 triggerConferenceRecalculate();
1175 }
Evan Charltonbf11f982014-07-20 22:06:28 -07001176 }
1177
Sailesh Nepal2a46b902014-07-04 17:21:07 -07001178 private void abort(String callId) {
Ihab Awad60ac30b2014-05-20 22:32:12 -07001179 Log.d(this, "abort %s", callId);
Sailesh Nepal2a46b902014-07-04 17:21:07 -07001180 findConnectionForAction(callId, "abort").onAbort();
Ihab Awad542e0ea2014-05-16 10:22:16 -07001181 }
1182
Tyler Gunnbe74de02014-08-29 14:51:48 -07001183 private void answerVideo(String callId, int videoState) {
1184 Log.d(this, "answerVideo %s", callId);
Andrew Lee8da4c3c2014-07-16 10:11:42 -07001185 findConnectionForAction(callId, "answer").onAnswer(videoState);
Ihab Awad542e0ea2014-05-16 10:22:16 -07001186 }
1187
Tyler Gunnbe74de02014-08-29 14:51:48 -07001188 private void answer(String callId) {
1189 Log.d(this, "answer %s", callId);
1190 findConnectionForAction(callId, "answer").onAnswer();
1191 }
1192
Sailesh Nepal2a46b902014-07-04 17:21:07 -07001193 private void reject(String callId) {
Ihab Awad60ac30b2014-05-20 22:32:12 -07001194 Log.d(this, "reject %s", callId);
Sailesh Nepal2a46b902014-07-04 17:21:07 -07001195 findConnectionForAction(callId, "reject").onReject();
Ihab Awad542e0ea2014-05-16 10:22:16 -07001196 }
1197
Bryce Lee81901682015-08-28 16:38:02 -07001198 private void reject(String callId, String rejectWithMessage) {
1199 Log.d(this, "reject %s with message", callId);
1200 findConnectionForAction(callId, "reject").onReject(rejectWithMessage);
1201 }
1202
Bryce Leecac50772015-11-17 15:13:29 -08001203 private void silence(String callId) {
1204 Log.d(this, "silence %s", callId);
1205 findConnectionForAction(callId, "silence").onSilence();
1206 }
1207
Sailesh Nepal2a46b902014-07-04 17:21:07 -07001208 private void disconnect(String callId) {
Ihab Awad60ac30b2014-05-20 22:32:12 -07001209 Log.d(this, "disconnect %s", callId);
Santos Cordon0159ac02014-08-21 14:28:11 -07001210 if (mConnectionById.containsKey(callId)) {
1211 findConnectionForAction(callId, "disconnect").onDisconnect();
1212 } else {
1213 findConferenceForAction(callId, "disconnect").onDisconnect();
1214 }
Ihab Awad542e0ea2014-05-16 10:22:16 -07001215 }
1216
Sailesh Nepal2a46b902014-07-04 17:21:07 -07001217 private void hold(String callId) {
Ihab Awad60ac30b2014-05-20 22:32:12 -07001218 Log.d(this, "hold %s", callId);
Santos Cordon0159ac02014-08-21 14:28:11 -07001219 if (mConnectionById.containsKey(callId)) {
1220 findConnectionForAction(callId, "hold").onHold();
1221 } else {
1222 findConferenceForAction(callId, "hold").onHold();
1223 }
Ihab Awad542e0ea2014-05-16 10:22:16 -07001224 }
1225
Sailesh Nepal2a46b902014-07-04 17:21:07 -07001226 private void unhold(String callId) {
Ihab Awad60ac30b2014-05-20 22:32:12 -07001227 Log.d(this, "unhold %s", callId);
Santos Cordon0159ac02014-08-21 14:28:11 -07001228 if (mConnectionById.containsKey(callId)) {
1229 findConnectionForAction(callId, "unhold").onUnhold();
1230 } else {
1231 findConferenceForAction(callId, "unhold").onUnhold();
1232 }
Ihab Awad542e0ea2014-05-16 10:22:16 -07001233 }
1234
Yorke Lee4af59352015-05-13 14:14:54 -07001235 private void onCallAudioStateChanged(String callId, CallAudioState callAudioState) {
1236 Log.d(this, "onAudioStateChanged %s %s", callId, callAudioState);
Yorke Leea0d3ca92014-09-15 19:18:13 -07001237 if (mConnectionById.containsKey(callId)) {
Yorke Lee4af59352015-05-13 14:14:54 -07001238 findConnectionForAction(callId, "onCallAudioStateChanged").setCallAudioState(
1239 callAudioState);
Yorke Leea0d3ca92014-09-15 19:18:13 -07001240 } else {
Yorke Lee4af59352015-05-13 14:14:54 -07001241 findConferenceForAction(callId, "onCallAudioStateChanged").setCallAudioState(
1242 callAudioState);
Yorke Leea0d3ca92014-09-15 19:18:13 -07001243 }
Ihab Awad542e0ea2014-05-16 10:22:16 -07001244 }
1245
Sailesh Nepal2a46b902014-07-04 17:21:07 -07001246 private void playDtmfTone(String callId, char digit) {
1247 Log.d(this, "playDtmfTone %s %c", callId, digit);
Yorke Leea0d3ca92014-09-15 19:18:13 -07001248 if (mConnectionById.containsKey(callId)) {
1249 findConnectionForAction(callId, "playDtmfTone").onPlayDtmfTone(digit);
1250 } else {
1251 findConferenceForAction(callId, "playDtmfTone").onPlayDtmfTone(digit);
1252 }
Sailesh Nepal2a46b902014-07-04 17:21:07 -07001253 }
1254
1255 private void stopDtmfTone(String callId) {
1256 Log.d(this, "stopDtmfTone %s", callId);
Yorke Leea0d3ca92014-09-15 19:18:13 -07001257 if (mConnectionById.containsKey(callId)) {
1258 findConnectionForAction(callId, "stopDtmfTone").onStopDtmfTone();
1259 } else {
1260 findConferenceForAction(callId, "stopDtmfTone").onStopDtmfTone();
1261 }
Sailesh Nepal2a46b902014-07-04 17:21:07 -07001262 }
1263
Santos Cordon823fd3c2014-08-07 18:35:18 -07001264 private void conference(String callId1, String callId2) {
1265 Log.d(this, "conference %s, %s", callId1, callId2);
Santos Cordon980acb92014-05-31 10:31:19 -07001266
Tyler Gunn6d76ca02014-11-17 15:49:51 -08001267 // Attempt to get second connection or conference.
Santos Cordon823fd3c2014-08-07 18:35:18 -07001268 Connection connection2 = findConnectionForAction(callId2, "conference");
Tyler Gunn6d76ca02014-11-17 15:49:51 -08001269 Conference conference2 = getNullConference();
Sailesh Nepalcf7020b2014-08-20 10:07:19 -07001270 if (connection2 == getNullConnection()) {
Tyler Gunn6d76ca02014-11-17 15:49:51 -08001271 conference2 = findConferenceForAction(callId2, "conference");
1272 if (conference2 == getNullConference()) {
1273 Log.w(this, "Connection2 or Conference2 missing in conference request %s.",
1274 callId2);
1275 return;
1276 }
Santos Cordon823fd3c2014-08-07 18:35:18 -07001277 }
Santos Cordonb6939982014-06-04 20:20:58 -07001278
Tyler Gunn6d76ca02014-11-17 15:49:51 -08001279 // Attempt to get first connection or conference and perform merge.
Ihab Awad50e35062014-09-30 09:17:03 -07001280 Connection connection1 = findConnectionForAction(callId1, "conference");
1281 if (connection1 == getNullConnection()) {
1282 Conference conference1 = findConferenceForAction(callId1, "addConnection");
1283 if (conference1 == getNullConference()) {
1284 Log.w(this,
1285 "Connection1 or Conference1 missing in conference request %s.",
1286 callId1);
1287 } else {
Tyler Gunn6d76ca02014-11-17 15:49:51 -08001288 // Call 1 is a conference.
1289 if (connection2 != getNullConnection()) {
1290 // Call 2 is a connection so merge via call 1 (conference).
1291 conference1.onMerge(connection2);
1292 } else {
1293 // Call 2 is ALSO a conference; this should never happen.
1294 Log.wtf(this, "There can only be one conference and an attempt was made to " +
1295 "merge two conferences.");
1296 return;
1297 }
Ihab Awad50e35062014-09-30 09:17:03 -07001298 }
1299 } else {
Tyler Gunn6d76ca02014-11-17 15:49:51 -08001300 // Call 1 is a connection.
1301 if (conference2 != getNullConference()) {
1302 // Call 2 is a conference, so merge via call 2.
1303 conference2.onMerge(connection1);
1304 } else {
1305 // Call 2 is a connection, so merge together.
1306 onConference(connection1, connection2);
1307 }
Ihab Awad50e35062014-09-30 09:17:03 -07001308 }
Santos Cordon980acb92014-05-31 10:31:19 -07001309 }
1310
Sailesh Nepal2a46b902014-07-04 17:21:07 -07001311 private void splitFromConference(String callId) {
Santos Cordonb6939982014-06-04 20:20:58 -07001312 Log.d(this, "splitFromConference(%s)", callId);
Santos Cordon980acb92014-05-31 10:31:19 -07001313
1314 Connection connection = findConnectionForAction(callId, "splitFromConference");
Sailesh Nepalcf7020b2014-08-20 10:07:19 -07001315 if (connection == getNullConnection()) {
Santos Cordon980acb92014-05-31 10:31:19 -07001316 Log.w(this, "Connection missing in conference request %s.", callId);
1317 return;
1318 }
1319
Santos Cordon0159ac02014-08-21 14:28:11 -07001320 Conference conference = connection.getConference();
1321 if (conference != null) {
1322 conference.onSeparate(connection);
1323 }
Santos Cordon980acb92014-05-31 10:31:19 -07001324 }
1325
Santos Cordona4868042014-09-04 17:39:22 -07001326 private void mergeConference(String callId) {
1327 Log.d(this, "mergeConference(%s)", callId);
1328 Conference conference = findConferenceForAction(callId, "mergeConference");
1329 if (conference != null) {
1330 conference.onMerge();
1331 }
1332 }
1333
1334 private void swapConference(String callId) {
1335 Log.d(this, "swapConference(%s)", callId);
1336 Conference conference = findConferenceForAction(callId, "swapConference");
1337 if (conference != null) {
1338 conference.onSwap();
1339 }
1340 }
1341
Tyler Gunn876dbfb2016-03-14 15:18:07 -07001342 /**
1343 * Notifies a {@link Connection} of a request to pull an external call.
1344 *
1345 * See {@link Call#pullExternalCall()}.
1346 *
1347 * @param callId The ID of the call to pull.
1348 */
1349 private void pullExternalCall(String callId) {
1350 Log.d(this, "pullExternalCall(%s)", callId);
1351 Connection connection = findConnectionForAction(callId, "pullExternalCall");
1352 if (connection != null) {
1353 connection.onPullExternalCall();
1354 }
1355 }
1356
1357 /**
1358 * Notifies a {@link Connection} of a call event.
1359 *
1360 * See {@link Call#sendCallEvent(String, Bundle)}.
1361 *
1362 * @param callId The ID of the call receiving the event.
1363 * @param event The event.
1364 * @param extras Extras associated with the event.
1365 */
1366 private void sendCallEvent(String callId, String event, Bundle extras) {
1367 Log.d(this, "sendCallEvent(%s, %s)", callId, event);
1368 Connection connection = findConnectionForAction(callId, "sendCallEvent");
1369 if (connection != null) {
1370 connection.onCallEvent(event, extras);
1371 }
1372
1373 }
1374
Tyler Gunndee56a82016-03-23 16:06:34 -07001375 /**
1376 * Notifies a {@link Connection} or {@link Conference} of a change to the extras from Telecom.
1377 * <p>
1378 * These extra changes can originate from Telecom itself, or from an {@link InCallService} via
1379 * the {@link android.telecom.Call#putExtra(String, boolean)},
1380 * {@link android.telecom.Call#putExtra(String, int)},
1381 * {@link android.telecom.Call#putExtra(String, String)},
1382 * {@link Call#removeExtras(List)}.
1383 *
1384 * @param callId The ID of the call receiving the event.
1385 * @param extras The new extras bundle.
1386 */
1387 private void handleExtrasChanged(String callId, Bundle extras) {
1388 Log.d(this, "handleExtrasChanged(%s, %s)", callId, extras);
1389 if (mConnectionById.containsKey(callId)) {
1390 findConnectionForAction(callId, "handleExtrasChanged").handleExtrasChanged(extras);
1391 } else if (mConferenceById.containsKey(callId)) {
1392 findConferenceForAction(callId, "handleExtrasChanged").handleExtrasChanged(extras);
1393 }
1394 }
1395
Sailesh Nepal2a46b902014-07-04 17:21:07 -07001396 private void onPostDialContinue(String callId, boolean proceed) {
Evan Charlton6dea4ac2014-06-03 14:07:13 -07001397 Log.d(this, "onPostDialContinue(%s)", callId);
Sailesh Nepal2a46b902014-07-04 17:21:07 -07001398 findConnectionForAction(callId, "stopDtmfTone").onPostDialContinue(proceed);
Evan Charlton6dea4ac2014-06-03 14:07:13 -07001399 }
1400
Sailesh Nepal2a46b902014-07-04 17:21:07 -07001401 private void onAdapterAttached() {
Ihab Awad9c3f1882014-06-30 21:17:13 -07001402 if (mAreAccountsInitialized) {
Santos Cordon52d8a152014-06-17 19:08:45 -07001403 // No need to query again if we already did it.
1404 return;
1405 }
1406
Sailesh Nepal2a46b902014-07-04 17:21:07 -07001407 mAdapter.queryRemoteConnectionServices(new RemoteServiceCallback.Stub() {
Santos Cordon52d8a152014-06-17 19:08:45 -07001408 @Override
1409 public void onResult(
1410 final List<ComponentName> componentNames,
Sailesh Nepal2a46b902014-07-04 17:21:07 -07001411 final List<IBinder> services) {
Brad Ebinger0c3541b2016-11-01 14:11:38 -07001412 mHandler.post(new android.telecom.Logging.Runnable("oAA.qRCS.oR", null /*lock*/) {
Ihab Awad6107bab2014-08-18 09:23:25 -07001413 @Override
Brad Ebinger0c3541b2016-11-01 14:11:38 -07001414 public void loggedRun() {
Sailesh Nepal2a46b902014-07-04 17:21:07 -07001415 for (int i = 0; i < componentNames.size() && i < services.size(); i++) {
Santos Cordon52d8a152014-06-17 19:08:45 -07001416 mRemoteConnectionManager.addConnectionService(
1417 componentNames.get(i),
Sailesh Nepal2a46b902014-07-04 17:21:07 -07001418 IConnectionService.Stub.asInterface(services.get(i)));
Santos Cordon52d8a152014-06-17 19:08:45 -07001419 }
Ihab Awad5d0410f2014-07-30 10:07:40 -07001420 onAccountsInitialized();
Sailesh Nepalc5b01572014-07-14 16:29:44 -07001421 Log.d(this, "remote connection services found: " + services);
Santos Cordon52d8a152014-06-17 19:08:45 -07001422 }
Brad Ebinger0c3541b2016-11-01 14:11:38 -07001423 }.prepare());
Santos Cordon52d8a152014-06-17 19:08:45 -07001424 }
1425
1426 @Override
1427 public void onError() {
Brad Ebinger0c3541b2016-11-01 14:11:38 -07001428 mHandler.post(new android.telecom.Logging.Runnable("oAA.qRCS.oE", null /*lock*/) {
Ihab Awad6107bab2014-08-18 09:23:25 -07001429 @Override
Brad Ebinger0c3541b2016-11-01 14:11:38 -07001430 public void loggedRun() {
Ihab Awad9c3f1882014-06-30 21:17:13 -07001431 mAreAccountsInitialized = true;
Santos Cordon52d8a152014-06-17 19:08:45 -07001432 }
Brad Ebinger0c3541b2016-11-01 14:11:38 -07001433 }.prepare());
Santos Cordon52d8a152014-06-17 19:08:45 -07001434 }
1435 });
1436 }
1437
Ihab Awadf8b69882014-07-25 15:14:01 -07001438 /**
1439 * Ask some other {@code ConnectionService} to create a {@code RemoteConnection} given an
Santos Cordona663f862014-10-29 13:49:58 -07001440 * incoming request. This is used by {@code ConnectionService}s that are registered with
1441 * {@link PhoneAccount#CAPABILITY_CONNECTION_MANAGER} and want to be able to manage
1442 * SIM-based incoming calls.
Ihab Awadf8b69882014-07-25 15:14:01 -07001443 *
1444 * @param connectionManagerPhoneAccount See description at
1445 * {@link #onCreateOutgoingConnection(PhoneAccountHandle, ConnectionRequest)}.
1446 * @param request Details about the incoming call.
1447 * @return The {@code Connection} object to satisfy this call, or {@code null} to
1448 * not handle the call.
1449 */
1450 public final RemoteConnection createRemoteIncomingConnection(
1451 PhoneAccountHandle connectionManagerPhoneAccount,
1452 ConnectionRequest request) {
1453 return mRemoteConnectionManager.createRemoteConnection(
1454 connectionManagerPhoneAccount, request, true);
Santos Cordon52d8a152014-06-17 19:08:45 -07001455 }
1456
1457 /**
Ihab Awadf8b69882014-07-25 15:14:01 -07001458 * Ask some other {@code ConnectionService} to create a {@code RemoteConnection} given an
Santos Cordona663f862014-10-29 13:49:58 -07001459 * outgoing request. This is used by {@code ConnectionService}s that are registered with
1460 * {@link PhoneAccount#CAPABILITY_CONNECTION_MANAGER} and want to be able to use the
1461 * SIM-based {@code ConnectionService} to place its outgoing calls.
Ihab Awadf8b69882014-07-25 15:14:01 -07001462 *
1463 * @param connectionManagerPhoneAccount See description at
1464 * {@link #onCreateOutgoingConnection(PhoneAccountHandle, ConnectionRequest)}.
Cuihtlauac ALVARADO0b3b2a52016-09-13 14:49:41 +02001465 * @param request Details about the outgoing call.
Ihab Awadf8b69882014-07-25 15:14:01 -07001466 * @return The {@code Connection} object to satisfy this call, or {@code null} to
1467 * not handle the call.
1468 */
1469 public final RemoteConnection createRemoteOutgoingConnection(
1470 PhoneAccountHandle connectionManagerPhoneAccount,
1471 ConnectionRequest request) {
1472 return mRemoteConnectionManager.createRemoteConnection(
1473 connectionManagerPhoneAccount, request, false);
1474 }
1475
1476 /**
Santos Cordona663f862014-10-29 13:49:58 -07001477 * Indicates to the relevant {@code RemoteConnectionService} that the specified
1478 * {@link RemoteConnection}s should be merged into a conference call.
1479 * <p>
1480 * If the conference request is successful, the method {@link #onRemoteConferenceAdded} will
1481 * be invoked.
1482 *
1483 * @param remoteConnection1 The first of the remote connections to conference.
1484 * @param remoteConnection2 The second of the remote connections to conference.
Ihab Awadb8e85c72014-08-23 20:34:57 -07001485 */
1486 public final void conferenceRemoteConnections(
Santos Cordona663f862014-10-29 13:49:58 -07001487 RemoteConnection remoteConnection1,
1488 RemoteConnection remoteConnection2) {
1489 mRemoteConnectionManager.conferenceRemoteConnections(remoteConnection1, remoteConnection2);
Ihab Awadb8e85c72014-08-23 20:34:57 -07001490 }
1491
1492 /**
Santos Cordon823fd3c2014-08-07 18:35:18 -07001493 * Adds a new conference call. When a conference call is created either as a result of an
1494 * explicit request via {@link #onConference} or otherwise, the connection service should supply
1495 * an instance of {@link Conference} by invoking this method. A conference call provided by this
1496 * method will persist until {@link Conference#destroy} is invoked on the conference instance.
1497 *
1498 * @param conference The new conference object.
1499 */
1500 public final void addConference(Conference conference) {
Rekha Kumar07366812015-03-24 16:42:31 -07001501 Log.d(this, "addConference: conference=%s", conference);
1502
Santos Cordon823fd3c2014-08-07 18:35:18 -07001503 String id = addConferenceInternal(conference);
1504 if (id != null) {
1505 List<String> connectionIds = new ArrayList<>(2);
1506 for (Connection connection : conference.getConnections()) {
1507 if (mIdByConnection.containsKey(connection)) {
1508 connectionIds.add(mIdByConnection.get(connection));
1509 }
1510 }
Tyler Gunnf0500bd2015-09-01 10:59:48 -07001511 conference.setTelecomCallId(id);
Santos Cordon823fd3c2014-08-07 18:35:18 -07001512 ParcelableConference parcelableConference = new ParcelableConference(
Nancy Chenea38cca2014-09-05 16:38:49 -07001513 conference.getPhoneAccountHandle(),
Santos Cordon823fd3c2014-08-07 18:35:18 -07001514 conference.getState(),
Ihab Awad5c9c86e2014-11-12 13:41:16 -08001515 conference.getConnectionCapabilities(),
Tyler Gunn720c6642016-03-22 09:02:47 -07001516 conference.getConnectionProperties(),
Tyler Gunncd5d33c2015-01-12 09:02:01 -08001517 connectionIds,
Rekha Kumar07366812015-03-24 16:42:31 -07001518 conference.getVideoProvider() == null ?
1519 null : conference.getVideoProvider().getInterface(),
1520 conference.getVideoState(),
Andrew Lee3e3e2f22015-04-16 13:48:43 -07001521 conference.getConnectTimeMillis(),
Santos Cordon6b7f9552015-05-27 17:21:45 -07001522 conference.getStatusHints(),
1523 conference.getExtras());
Andrew Lee0f51da32015-04-16 13:11:55 -07001524
Santos Cordon823fd3c2014-08-07 18:35:18 -07001525 mAdapter.addConferenceCall(id, parcelableConference);
Rekha Kumar07366812015-03-24 16:42:31 -07001526 mAdapter.setVideoProvider(id, conference.getVideoProvider());
1527 mAdapter.setVideoState(id, conference.getVideoState());
Santos Cordon823fd3c2014-08-07 18:35:18 -07001528
1529 // Go through any child calls and set the parent.
1530 for (Connection connection : conference.getConnections()) {
1531 String connectionId = mIdByConnection.get(connection);
1532 if (connectionId != null) {
1533 mAdapter.setIsConferenced(connectionId, id);
1534 }
1535 }
1536 }
1537 }
1538
1539 /**
Tyler Gunn4a57b9b2014-10-30 14:27:48 -07001540 * Adds a connection created by the {@link ConnectionService} and informs telecom of the new
1541 * connection.
1542 *
1543 * @param phoneAccountHandle The phone account handle for the connection.
1544 * @param connection The connection to add.
1545 */
1546 public final void addExistingConnection(PhoneAccountHandle phoneAccountHandle,
1547 Connection connection) {
1548
Tyler Gunnf0500bd2015-09-01 10:59:48 -07001549 String id = addExistingConnectionInternal(phoneAccountHandle, connection);
Tyler Gunn4a57b9b2014-10-30 14:27:48 -07001550 if (id != null) {
1551 List<String> emptyList = new ArrayList<>(0);
1552
1553 ParcelableConnection parcelableConnection = new ParcelableConnection(
1554 phoneAccountHandle,
1555 connection.getState(),
Ihab Awad5c9c86e2014-11-12 13:41:16 -08001556 connection.getConnectionCapabilities(),
Tyler Gunn720c6642016-03-22 09:02:47 -07001557 connection.getConnectionProperties(),
Christine Hallstrom2830ce92016-11-30 16:06:42 -08001558 connection.getSupportedAudioRoutes(),
Tyler Gunn4a57b9b2014-10-30 14:27:48 -07001559 connection.getAddress(),
1560 connection.getAddressPresentation(),
1561 connection.getCallerDisplayName(),
1562 connection.getCallerDisplayNamePresentation(),
1563 connection.getVideoProvider() == null ?
1564 null : connection.getVideoProvider().getInterface(),
1565 connection.getVideoState(),
1566 connection.isRingbackRequested(),
1567 connection.getAudioModeIsVoip(),
Roshan Piuse927ec02015-07-15 15:47:21 -07001568 connection.getConnectTimeMillis(),
Tyler Gunn4a57b9b2014-10-30 14:27:48 -07001569 connection.getStatusHints(),
1570 connection.getDisconnectCause(),
Santos Cordon6b7f9552015-05-27 17:21:45 -07001571 emptyList,
1572 connection.getExtras());
Tyler Gunn4a57b9b2014-10-30 14:27:48 -07001573 mAdapter.addExistingConnection(id, parcelableConnection);
1574 }
1575 }
1576
1577 /**
Ihab Awadf8b69882014-07-25 15:14:01 -07001578 * Returns all the active {@code Connection}s for which this {@code ConnectionService}
1579 * has taken responsibility.
1580 *
1581 * @return A collection of {@code Connection}s created by this {@code ConnectionService}.
Santos Cordonb6939982014-06-04 20:20:58 -07001582 */
Sailesh Nepal091768c2014-06-30 15:15:23 -07001583 public final Collection<Connection> getAllConnections() {
Santos Cordonb6939982014-06-04 20:20:58 -07001584 return mConnectionById.values();
1585 }
1586
1587 /**
Santos Cordona6018b92016-02-16 14:23:12 -08001588 * Returns all the active {@code Conference}s for which this {@code ConnectionService}
1589 * has taken responsibility.
1590 *
1591 * @return A collection of {@code Conference}s created by this {@code ConnectionService}.
1592 */
1593 public final Collection<Conference> getAllConferences() {
1594 return mConferenceById.values();
1595 }
1596
1597 /**
Ihab Awadf8b69882014-07-25 15:14:01 -07001598 * Create a {@code Connection} given an incoming request. This is used to attach to existing
1599 * incoming calls.
Evan Charltonbf11f982014-07-20 22:06:28 -07001600 *
Ihab Awadf8b69882014-07-25 15:14:01 -07001601 * @param connectionManagerPhoneAccount See description at
1602 * {@link #onCreateOutgoingConnection(PhoneAccountHandle, ConnectionRequest)}.
1603 * @param request Details about the incoming call.
1604 * @return The {@code Connection} object to satisfy this call, or {@code null} to
1605 * not handle the call.
Ihab Awad542e0ea2014-05-16 10:22:16 -07001606 */
Ihab Awadf8b69882014-07-25 15:14:01 -07001607 public Connection onCreateIncomingConnection(
1608 PhoneAccountHandle connectionManagerPhoneAccount,
1609 ConnectionRequest request) {
1610 return null;
1611 }
Sailesh Nepalc5b01572014-07-14 16:29:44 -07001612
1613 /**
Tyler Gunnf5035432017-01-09 09:43:12 -08001614 * Called by Telecom to inform the {@link ConnectionService} that its request to create a new
1615 * incoming {@link Connection} was denied.
1616 * <p>
1617 * Used when a self-managed {@link ConnectionService} attempts to create a new incoming
1618 * {@link Connection}, but Telecom has determined that the call cannot be allowed at this time.
1619 * The {@link ConnectionService} is responsible for silently rejecting the new incoming
1620 * {@link Connection}.
1621 * <p>
1622 * See {@link TelecomManager#isIncomingCallPermitted(PhoneAccountHandle)} for more information.
1623 *
1624 * @param request The incoming connection request.
1625 */
1626 public void onCreateIncomingConnectionFailed(ConnectionRequest request) {
1627 }
1628
1629 /**
1630 * Called by Telecom to inform the {@link ConnectionService} that its request to create a new
1631 * outgoing {@link Connection} was denied.
1632 * <p>
1633 * Used when a self-managed {@link ConnectionService} attempts to create a new outgoing
1634 * {@link Connection}, but Telecom has determined that the call cannot be placed at this time.
1635 * The {@link ConnectionService} is responisible for informing the user that the
1636 * {@link Connection} cannot be made at this time.
1637 * <p>
1638 * See {@link TelecomManager#isOutgoingCallPermitted(PhoneAccountHandle)} for more information.
1639 *
1640 * @param request The outgoing connection request.
1641 */
1642 public void onCreateOutgoingConnectionFailed(ConnectionRequest request) {
1643 }
1644
1645 /**
Shriram Ganesh6bf35ac2014-12-11 17:53:38 -08001646 * Trigger recalculate functinality for conference calls. This is used when a Telephony
1647 * Connection is part of a conference controller but is not yet added to Connection
1648 * Service and hence cannot be added to the conference call.
1649 *
1650 * @hide
1651 */
1652 public void triggerConferenceRecalculate() {
1653 }
1654
1655 /**
Ihab Awadf8b69882014-07-25 15:14:01 -07001656 * Create a {@code Connection} given an outgoing request. This is used to initiate new
1657 * outgoing calls.
Sailesh Nepalc5b01572014-07-14 16:29:44 -07001658 *
Ihab Awadf8b69882014-07-25 15:14:01 -07001659 * @param connectionManagerPhoneAccount The connection manager account to use for managing
1660 * this call.
1661 * <p>
1662 * If this parameter is not {@code null}, it means that this {@code ConnectionService}
1663 * has registered one or more {@code PhoneAccount}s having
1664 * {@link PhoneAccount#CAPABILITY_CONNECTION_MANAGER}. This parameter will contain
1665 * one of these {@code PhoneAccount}s, while the {@code request} will contain another
1666 * (usually but not always distinct) {@code PhoneAccount} to be used for actually
1667 * making the connection.
1668 * <p>
1669 * If this parameter is {@code null}, it means that this {@code ConnectionService} is
1670 * being asked to make a direct connection. The
1671 * {@link ConnectionRequest#getAccountHandle()} of parameter {@code request} will be
1672 * a {@code PhoneAccount} registered by this {@code ConnectionService} to use for
1673 * making the connection.
1674 * @param request Details about the outgoing call.
1675 * @return The {@code Connection} object to satisfy this call, or the result of an invocation
Andrew Lee7f3d41f2014-09-11 17:33:16 -07001676 * of {@link Connection#createFailedConnection(DisconnectCause)} to not handle the call.
Sailesh Nepalc5b01572014-07-14 16:29:44 -07001677 */
Ihab Awadf8b69882014-07-25 15:14:01 -07001678 public Connection onCreateOutgoingConnection(
1679 PhoneAccountHandle connectionManagerPhoneAccount,
1680 ConnectionRequest request) {
1681 return null;
1682 }
Ihab Awad542e0ea2014-05-16 10:22:16 -07001683
1684 /**
Yorke Leec3cf9822014-10-02 09:38:39 -07001685 * Create a {@code Connection} for a new unknown call. An unknown call is a call originating
1686 * from the ConnectionService that was neither a user-initiated outgoing call, nor an incoming
1687 * call created using
1688 * {@code TelecomManager#addNewIncomingCall(PhoneAccountHandle, android.os.Bundle)}.
1689 *
Yorke Lee770ed6e2014-10-06 18:58:52 -07001690 * @hide
Yorke Leec3cf9822014-10-02 09:38:39 -07001691 */
1692 public Connection onCreateUnknownConnection(PhoneAccountHandle connectionManagerPhoneAccount,
1693 ConnectionRequest request) {
Brad Ebingerb32d4f82016-10-24 16:40:49 -07001694 return null;
Yorke Leec3cf9822014-10-02 09:38:39 -07001695 }
1696
1697 /**
Santos Cordon823fd3c2014-08-07 18:35:18 -07001698 * Conference two specified connections. Invoked when the user has made a request to merge the
1699 * specified connections into a conference call. In response, the connection service should
1700 * create an instance of {@link Conference} and pass it into {@link #addConference}.
Santos Cordonb6939982014-06-04 20:20:58 -07001701 *
Santos Cordon823fd3c2014-08-07 18:35:18 -07001702 * @param connection1 A connection to merge into a conference call.
1703 * @param connection2 A connection to merge into a conference call.
Santos Cordonb6939982014-06-04 20:20:58 -07001704 */
Santos Cordon823fd3c2014-08-07 18:35:18 -07001705 public void onConference(Connection connection1, Connection connection2) {}
Santos Cordonb6939982014-06-04 20:20:58 -07001706
Santos Cordona663f862014-10-29 13:49:58 -07001707 /**
1708 * Indicates that a remote conference has been created for existing {@link RemoteConnection}s.
1709 * When this method is invoked, this {@link ConnectionService} should create its own
1710 * representation of the conference call and send it to telecom using {@link #addConference}.
1711 * <p>
1712 * This is only relevant to {@link ConnectionService}s which are registered with
1713 * {@link PhoneAccount#CAPABILITY_CONNECTION_MANAGER}.
1714 *
1715 * @param conference The remote conference call.
1716 */
Ihab Awadb8e85c72014-08-23 20:34:57 -07001717 public void onRemoteConferenceAdded(RemoteConference conference) {}
1718
Santos Cordon823fd3c2014-08-07 18:35:18 -07001719 /**
Tyler Gunn4a57b9b2014-10-30 14:27:48 -07001720 * Called when an existing connection is added remotely.
1721 * @param connection The existing connection which was added.
1722 */
1723 public void onRemoteExistingConnectionAdded(RemoteConnection connection) {}
1724
1725 /**
Santos Cordon823fd3c2014-08-07 18:35:18 -07001726 * @hide
1727 */
1728 public boolean containsConference(Conference conference) {
1729 return mIdByConference.containsKey(conference);
1730 }
1731
Ihab Awadb8e85c72014-08-23 20:34:57 -07001732 /** {@hide} */
1733 void addRemoteConference(RemoteConference remoteConference) {
1734 onRemoteConferenceAdded(remoteConference);
1735 }
1736
Tyler Gunn4a57b9b2014-10-30 14:27:48 -07001737 /** {@hide} */
1738 void addRemoteExistingConnection(RemoteConnection remoteConnection) {
1739 onRemoteExistingConnectionAdded(remoteConnection);
1740 }
1741
Ihab Awad5d0410f2014-07-30 10:07:40 -07001742 private void onAccountsInitialized() {
1743 mAreAccountsInitialized = true;
1744 for (Runnable r : mPreInitializationConnectionRequests) {
1745 r.run();
1746 }
1747 mPreInitializationConnectionRequests.clear();
1748 }
1749
Tyler Gunn4a57b9b2014-10-30 14:27:48 -07001750 /**
Tyler Gunnf0500bd2015-09-01 10:59:48 -07001751 * Adds an existing connection to the list of connections, identified by a new call ID unique
1752 * to this connection service.
Tyler Gunn4a57b9b2014-10-30 14:27:48 -07001753 *
1754 * @param connection The connection.
Tyler Gunnf0500bd2015-09-01 10:59:48 -07001755 * @return The ID of the connection (e.g. the call-id).
Tyler Gunn4a57b9b2014-10-30 14:27:48 -07001756 */
Tyler Gunnf0500bd2015-09-01 10:59:48 -07001757 private String addExistingConnectionInternal(PhoneAccountHandle handle, Connection connection) {
1758 String id;
1759 if (handle == null) {
1760 // If no phone account handle was provided, we cannot be sure the call ID is unique,
1761 // so just use a random UUID.
1762 id = UUID.randomUUID().toString();
1763 } else {
1764 // Phone account handle was provided, so use the ConnectionService class name as a
1765 // prefix for a unique incremental call ID.
1766 id = handle.getComponentName().getClassName() + "@" + getNextCallId();
1767 }
Tyler Gunn4a57b9b2014-10-30 14:27:48 -07001768 addConnection(id, connection);
1769 return id;
1770 }
1771
Ihab Awad542e0ea2014-05-16 10:22:16 -07001772 private void addConnection(String callId, Connection connection) {
Tyler Gunnf0500bd2015-09-01 10:59:48 -07001773 connection.setTelecomCallId(callId);
Ihab Awad542e0ea2014-05-16 10:22:16 -07001774 mConnectionById.put(callId, connection);
1775 mIdByConnection.put(connection, callId);
1776 connection.addConnectionListener(mConnectionListener);
Santos Cordon823fd3c2014-08-07 18:35:18 -07001777 connection.setConnectionService(this);
Ihab Awad542e0ea2014-05-16 10:22:16 -07001778 }
1779
Anthony Lee30e65842014-11-06 16:30:53 -08001780 /** {@hide} */
1781 protected void removeConnection(Connection connection) {
Santos Cordon823fd3c2014-08-07 18:35:18 -07001782 connection.unsetConnectionService(this);
Ihab Awad542e0ea2014-05-16 10:22:16 -07001783 connection.removeConnectionListener(mConnectionListener);
Chenjie Luoe370b532016-05-12 16:59:43 -07001784 String id = mIdByConnection.get(connection);
1785 if (id != null) {
1786 mConnectionById.remove(id);
1787 mIdByConnection.remove(connection);
1788 mAdapter.removeCall(id);
1789 }
Ihab Awad542e0ea2014-05-16 10:22:16 -07001790 }
1791
Santos Cordon823fd3c2014-08-07 18:35:18 -07001792 private String addConferenceInternal(Conference conference) {
1793 if (mIdByConference.containsKey(conference)) {
1794 Log.w(this, "Re-adding an existing conference: %s.", conference);
1795 } else if (conference != null) {
Tyler Gunnf0500bd2015-09-01 10:59:48 -07001796 // Conferences do not (yet) have a PhoneAccountHandle associated with them, so we
1797 // cannot determine a ConnectionService class name to associate with the ID, so use
1798 // a unique UUID (for now).
Santos Cordon823fd3c2014-08-07 18:35:18 -07001799 String id = UUID.randomUUID().toString();
1800 mConferenceById.put(id, conference);
1801 mIdByConference.put(conference, id);
1802 conference.addListener(mConferenceListener);
1803 return id;
1804 }
1805
1806 return null;
1807 }
1808
1809 private void removeConference(Conference conference) {
1810 if (mIdByConference.containsKey(conference)) {
1811 conference.removeListener(mConferenceListener);
1812
1813 String id = mIdByConference.get(conference);
1814 mConferenceById.remove(id);
1815 mIdByConference.remove(conference);
1816 mAdapter.removeCall(id);
1817 }
1818 }
1819
Ihab Awad542e0ea2014-05-16 10:22:16 -07001820 private Connection findConnectionForAction(String callId, String action) {
1821 if (mConnectionById.containsKey(callId)) {
1822 return mConnectionById.get(callId);
1823 }
Ihab Awad60ac30b2014-05-20 22:32:12 -07001824 Log.w(this, "%s - Cannot find Connection %s", action, callId);
Sailesh Nepalcf7020b2014-08-20 10:07:19 -07001825 return getNullConnection();
1826 }
1827
1828 static synchronized Connection getNullConnection() {
1829 if (sNullConnection == null) {
1830 sNullConnection = new Connection() {};
1831 }
1832 return sNullConnection;
Santos Cordon7c7bc7f2014-07-28 18:15:48 -07001833 }
Santos Cordon0159ac02014-08-21 14:28:11 -07001834
1835 private Conference findConferenceForAction(String conferenceId, String action) {
1836 if (mConferenceById.containsKey(conferenceId)) {
1837 return mConferenceById.get(conferenceId);
1838 }
1839 Log.w(this, "%s - Cannot find conference %s", action, conferenceId);
1840 return getNullConference();
1841 }
1842
Ihab Awadb8e85c72014-08-23 20:34:57 -07001843 private List<String> createConnectionIdList(List<Connection> connections) {
1844 List<String> ids = new ArrayList<>();
1845 for (Connection c : connections) {
1846 if (mIdByConnection.containsKey(c)) {
1847 ids.add(mIdByConnection.get(c));
1848 }
1849 }
1850 Collections.sort(ids);
1851 return ids;
1852 }
1853
Tyler Gunn6d76ca02014-11-17 15:49:51 -08001854 /**
1855 * Builds a list of {@link Connection} and {@link Conference} IDs based on the list of
Tyler Gunndf2cbc82015-04-20 09:13:01 -07001856 * {@link Conferenceable}s passed in.
Tyler Gunn6d76ca02014-11-17 15:49:51 -08001857 *
Tyler Gunndf2cbc82015-04-20 09:13:01 -07001858 * @param conferenceables The {@link Conferenceable} connections and conferences.
Tyler Gunn6d76ca02014-11-17 15:49:51 -08001859 * @return List of string conference and call Ids.
1860 */
Tyler Gunndf2cbc82015-04-20 09:13:01 -07001861 private List<String> createIdList(List<Conferenceable> conferenceables) {
Tyler Gunn6d76ca02014-11-17 15:49:51 -08001862 List<String> ids = new ArrayList<>();
Tyler Gunndf2cbc82015-04-20 09:13:01 -07001863 for (Conferenceable c : conferenceables) {
Tyler Gunn6d76ca02014-11-17 15:49:51 -08001864 // Only allow Connection and Conference conferenceables.
1865 if (c instanceof Connection) {
1866 Connection connection = (Connection) c;
1867 if (mIdByConnection.containsKey(connection)) {
1868 ids.add(mIdByConnection.get(connection));
1869 }
1870 } else if (c instanceof Conference) {
1871 Conference conference = (Conference) c;
1872 if (mIdByConference.containsKey(conference)) {
1873 ids.add(mIdByConference.get(conference));
1874 }
1875 }
1876 }
1877 Collections.sort(ids);
1878 return ids;
1879 }
1880
Santos Cordon0159ac02014-08-21 14:28:11 -07001881 private Conference getNullConference() {
1882 if (sNullConference == null) {
1883 sNullConference = new Conference(null) {};
1884 }
1885 return sNullConference;
1886 }
Santos Cordon29f2f2e2014-09-11 19:50:24 -07001887
1888 private void endAllConnections() {
1889 // Unbound from telecomm. We should end all connections and conferences.
1890 for (Connection connection : mIdByConnection.keySet()) {
1891 // only operate on top-level calls. Conference calls will be removed on their own.
1892 if (connection.getConference() == null) {
1893 connection.onDisconnect();
1894 }
1895 }
1896 for (Conference conference : mIdByConference.keySet()) {
1897 conference.onDisconnect();
1898 }
1899 }
Tyler Gunnf0500bd2015-09-01 10:59:48 -07001900
1901 /**
1902 * Retrieves the next call ID as maintainted by the connection service.
1903 *
1904 * @return The call ID.
1905 */
1906 private int getNextCallId() {
Brad Ebingerb32d4f82016-10-24 16:40:49 -07001907 synchronized (mIdSyncRoot) {
Tyler Gunnf0500bd2015-09-01 10:59:48 -07001908 return ++mId;
1909 }
1910 }
Santos Cordon980acb92014-05-31 10:31:19 -07001911}