blob: 9e4e5fa34b9970091c2523c9a6bcc60c892f3288 [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
Tyler Gunn5567d742019-10-31 13:04:37 -070019import android.annotation.NonNull;
20import android.annotation.Nullable;
Roopa Sattiraju45de470c2022-01-27 21:31:35 -080021import android.annotation.RequiresPermission;
Santos Cordon5c6fa952014-07-20 17:47:12 -070022import android.annotation.SdkConstant;
Tyler Gunn5567d742019-10-31 13:04:37 -070023import android.annotation.SystemApi;
Hall Liueb7c9ea2021-03-09 20:24:50 -080024import android.annotation.TestApi;
Sailesh Nepal2a46b902014-07-04 17:21:07 -070025import android.app.Service;
Santos Cordon52d8a152014-06-17 19:08:45 -070026import android.content.ComponentName;
Santos Cordon5c6fa952014-07-20 17:47:12 -070027import android.content.Intent;
Ihab Awad542e0ea2014-05-16 10:22:16 -070028import android.net.Uri;
Santos Cordon6b7f9552015-05-27 17:21:45 -070029import android.os.Bundle;
Santos Cordon52d8a152014-06-17 19:08:45 -070030import android.os.Handler;
31import android.os.IBinder;
32import android.os.Looper;
Sailesh Nepal2a46b902014-07-04 17:21:07 -070033import android.os.Message;
Junhoedf3d822022-11-24 09:26:37 +000034import android.os.OutcomeReceiver;
Hall Liub64ac4c2017-02-06 10:49:48 -080035import android.os.ParcelFileDescriptor;
36import android.os.RemoteException;
Brad Ebingerb32d4f82016-10-24 16:40:49 -070037import android.telecom.Logging.Session;
Andrew Lee14185762014-07-25 09:41:56 -070038
Brad Ebinger99f17ce2019-09-11 18:06:51 -070039import com.android.internal.annotations.VisibleForTesting;
Sailesh Nepal2a46b902014-07-04 17:21:07 -070040import com.android.internal.os.SomeArgs;
Tyler Gunnef9f6f92014-09-12 22:16:17 -070041import com.android.internal.telecom.IConnectionService;
42import com.android.internal.telecom.IConnectionServiceAdapter;
43import com.android.internal.telecom.RemoteServiceCallback;
Santos Cordon52d8a152014-06-17 19:08:45 -070044
Ihab Awad5d0410f2014-07-30 10:07:40 -070045import java.util.ArrayList;
Santos Cordonb6939982014-06-04 20:20:58 -070046import java.util.Collection;
Santos Cordon7c7bc7f2014-07-28 18:15:48 -070047import java.util.Collections;
Santos Cordon52d8a152014-06-17 19:08:45 -070048import java.util.List;
Ihab Awad542e0ea2014-05-16 10:22:16 -070049import java.util.Map;
Santos Cordon823fd3c2014-08-07 18:35:18 -070050import java.util.UUID;
mike dooley95e80702014-09-18 14:07:52 -070051import java.util.concurrent.ConcurrentHashMap;
Junhoedf3d822022-11-24 09:26:37 +000052import java.util.concurrent.Executor;
Ihab Awad542e0ea2014-05-16 10:22:16 -070053
54/**
Tyler Gunnf5035432017-01-09 09:43:12 -080055 * An abstract service that should be implemented by any apps which either:
56 * <ol>
57 * <li>Can make phone calls (VoIP or otherwise) and want those calls to be integrated into the
58 * built-in phone app. Referred to as a <b>system managed</b> {@link ConnectionService}.</li>
59 * <li>Are a standalone calling app and don't want their calls to be integrated into the
60 * built-in phone app. Referred to as a <b>self managed</b> {@link ConnectionService}.</li>
61 * </ol>
62 * Once implemented, the {@link ConnectionService} needs to take the following steps so that Telecom
63 * will bind to it:
Santos Cordona663f862014-10-29 13:49:58 -070064 * <p>
65 * 1. <i>Registration in AndroidManifest.xml</i>
66 * <br/>
67 * <pre>
68 * &lt;service android:name="com.example.package.MyConnectionService"
69 * android:label="@string/some_label_for_my_connection_service"
Yorke Lee249c12e2015-05-13 15:59:29 -070070 * android:permission="android.permission.BIND_TELECOM_CONNECTION_SERVICE"&gt;
Santos Cordona663f862014-10-29 13:49:58 -070071 * &lt;intent-filter&gt;
72 * &lt;action android:name="android.telecom.ConnectionService" /&gt;
73 * &lt;/intent-filter&gt;
74 * &lt;/service&gt;
75 * </pre>
76 * <p>
77 * 2. <i> Registration of {@link PhoneAccount} with {@link TelecomManager}.</i>
78 * <br/>
79 * See {@link PhoneAccount} and {@link TelecomManager#registerPhoneAccount} for more information.
80 * <p>
Tyler Gunnf5035432017-01-09 09:43:12 -080081 * System managed {@link ConnectionService}s must be enabled by the user in the phone app settings
Tyler Gunn8eeb94f2023-01-20 22:46:19 +000082 * before Telecom will bind to them. Self-managed {@link ConnectionService}s must declare the
83 * {@link android.Manifest.permission#MANAGE_OWN_CALLS} permission in their manifest before Telecom
84 * will bind to them.
Tyler Gunnf5035432017-01-09 09:43:12 -080085 * <p>
86 * Once registered and enabled by the user in the phone app settings or granted permission, telecom
87 * will bind to a {@link ConnectionService} implementation when it wants that
88 * {@link ConnectionService} to place a call or the service has indicated that is has an incoming
Tyler Gunn8eeb94f2023-01-20 22:46:19 +000089 * call through {@link TelecomManager#addNewIncomingCall(PhoneAccountHandle, Bundle)}. The
90 * {@link ConnectionService} can then expect a call to
91 * {@link #onCreateIncomingConnection(PhoneAccountHandle, ConnectionRequest)} or
92 * {@link #onCreateOutgoingConnection(PhoneAccountHandle, ConnectionRequest)}
Tyler Gunnf5035432017-01-09 09:43:12 -080093 * wherein it should provide a new instance of a {@link Connection} object. It is through this
94 * {@link Connection} object that telecom receives state updates and the {@link ConnectionService}
Santos Cordona663f862014-10-29 13:49:58 -070095 * receives call-commands such as answer, reject, hold and disconnect.
96 * <p>
Tyler Gunnf5035432017-01-09 09:43:12 -080097 * When there are no more live calls, telecom will unbind from the {@link ConnectionService}.
Tyler Gunn8eeb94f2023-01-20 22:46:19 +000098 * <p>
99 * <h1>Self-Managed Connection Services</h1>
100 * A VoIP app can implement a {@link ConnectionService} to ensure that its calls are integrated
101 * into the Android platform. There are numerous benefits to using the Telecom APIs for a VoIP app:
102 * <ul>
103 * <li>Call concurrency is handled - the user is able to swap between calls in different
104 * apps and on the mobile network.</li>
105 * <li>Simplified audio routing - the platform provides your app with a unified list of the
106 * audio routes which are available
107 * (e.g. {@link android.telecom.Connection#onAvailableCallEndpointsChanged(List)}) and a
108 * standardized way to switch audio routes
109 * (e.g. {@link android.telecom.Connection#requestCallEndpointChange(CallEndpoint, Executor,
110 * OutcomeReceiver)} ).</li>
111 * <li>Bluetooth integration - your calls will be visible on and controllable via
112 * bluetooth devices (e.g. car head units and headsets).</li>
113 * <li>Companion device integration - wearable devices such as watches which implement an
114 * {@link InCallService} can optionally subscribe to see self-managed calls. Similar to a
115 * bluetooth headunit, wearables will typically render your call using a generic call UX and
116 * provide the user with basic call controls such as hangup, answer, reject.</li>
117 * <li>Automotive calling experiences - Android supports automotive optimized experiences which
118 * provides a means for calls to be controlled and viewed in an automobile; these experiences
119 * are capable of leveraging call metadata provided by your app.</li>
120 * </ul>
121 * <h2>Registering a Phone Account</h2>
122 * Before your app can handle incoming or outgoing calls through Telecom it needs to register a
123 * {@link PhoneAccount} with Telecom indicating to the platform that your app is capable of calling.
124 * <p>
125 * Your app should create a new instance of {@link PhoneAccount} which meets the following
126 * requirements:
127 * <ul>
128 * <li>Has {@link PhoneAccount#CAPABILITY_SELF_MANAGED} (set using
129 * {@link PhoneAccount.Builder#setCapabilities(int)}). This indicates to Telecom that your
130 * app will report calls but that it provides a primary UI for the calls by itself.</li>
131 * <li>Provide a unique identifier for the {@link PhoneAccount} via the
132 * {@link PhoneAccountHandle#getId()} attribute. As per the {@link PhoneAccountHandle}
133 * documentation, you should NOT use an identifier which contains PII or other sensitive
134 * information. A typical choice is a UUID.</li>
135 * </ul>
136 * Your app should register the new {@link PhoneAccount} with Telecom using
137 * {@link TelecomManager#registerPhoneAccount(PhoneAccount)}. {@link PhoneAccount}s persist across
138 * reboot. You can use {@link TelecomManager#getOwnSelfManagedPhoneAccounts()} to confirm the
139 * {@link PhoneAccount} you registered. Your app should generally only register a single
140 * {@link PhoneAccount}.
141 *
142 * <h2>Implementing ConnectionService</h2>
143 * Your app uses {@link TelecomManager#placeCall(Uri, Bundle)} to start new outgoing calls and
144 * {@link TelecomManager#addNewIncomingCall(PhoneAccountHandle, Bundle)} to report new incoming
145 * calls. Calling these APIs causes the Telecom stack to bind to your app's
146 * {@link ConnectionService} implementation. Telecom will either inform your app that it cannot
147 * handle a call request at the current time (i.e. there could be an ongoing emergency call, which
148 * means your app is not allowed to handle calls at the current time), or it will ask your app to
149 * create a new instance of {@link Connection} to represent a call in your app.
150 *
151 * Your app should implement the following {@link ConnectionService} methods:
152 * <ul>
153 * <li>{@link ConnectionService#onCreateOutgoingConnection(PhoneAccountHandle,
154 * ConnectionRequest)} - called by Telecom to ask your app to make a new {@link Connection}
155 * to represent an outgoing call your app requested via
156 * {@link TelecomManager#placeCall(Uri, Bundle)}.</li>
157 * <li><{@link ConnectionService#onCreateOutgoingConnectionFailed(PhoneAccountHandle,
158 * ConnectionRequest)} - called by Telecom to inform your app that a call it reported via
159 * {@link TelecomManager#placeCall(Uri, Bundle)} cannot be handled at this time. Your app
160 * should NOT place a call at the current time.</li>
161 * <li>{@link ConnectionService#onCreateIncomingConnection(PhoneAccountHandle,
162 * ConnectionRequest)} - called by Telecom to ask your app to make a new {@link Connection}
163 * to represent an incoming call your app reported via
164 * {@link TelecomManager#addNewIncomingCall(PhoneAccountHandle, Bundle)}.</li>
165 * <li>{@link ConnectionService#onCreateIncomingConnectionFailed(PhoneAccountHandle,
166 * ConnectionRequest)} - called by Telecom to inform your app that an incoming call it reported
167 * via {@link TelecomManager#addNewIncomingCall(PhoneAccountHandle, Bundle)} cannot be handled
168 * at this time. Your app should NOT post a new incoming call notification and should silently
169 * reject the call.</li>
170 * </ul>
171 *
172 * <h2>Implementing a Connection</h2>
173 * Your app should extend the {@link Connection} class to represent calls in your app. When you
174 * create new instances of your {@link Connection}, you should ensure the following properties are
175 * set on the new {@link Connection} instance returned by your {@link ConnectionService}:
176 * <ul>
177 * <li>{@link Connection#setAddress(Uri, int)} - the identifier for the other party. For
178 * apps that user phone numbers the {@link Uri} can be a {@link PhoneAccount#SCHEME_TEL} URI
179 * representing the phone number.</li>
180 * <li>{@link Connection#setCallerDisplayName(String, int)} - the display name of the other
181 * party. This is what will be shown on Bluetooth devices and other calling surfaces such
182 * as wearable devices. This is particularly important for calls that do not use a phone
183 * number to identify the caller or called party.</li>
184 * <li>{@link Connection#setConnectionProperties(int)} - ensure you set
185 * {@link Connection#PROPERTY_SELF_MANAGED} to identify to the platform that the call is
186 * handled by your app.</li>
187 * <li>{@link Connection#setConnectionCapabilities(int)} - if your app supports making calls
188 * inactive (i.e. holding calls) you should get {@link Connection#CAPABILITY_SUPPORT_HOLD} and
189 * {@link Connection#CAPABILITY_HOLD} to indicate to the platform that you calls can potentially
190 * be held for concurrent calling scenarios.</li>
191 * <li>{@link Connection#setAudioModeIsVoip(boolean)} - set to {@code true} to ensure that the
192 * platform knows your call is a VoIP call.</li>
193 * <li>For newly created {@link Connection} instances, do NOT change the state of your call
194 * using {@link Connection#setActive()}, {@link Connection#setOnHold()} until the call is added
195 * to Telecom (ie you have returned it via
196 * {@link ConnectionService#onCreateOutgoingConnection(PhoneAccountHandle, ConnectionRequest)}
197 * or
198 * {@link ConnectionService#onCreateIncomingConnection(PhoneAccountHandle, ConnectionRequest)}).
199 * </li>
200 * </ul>
201 *
202 * <h2>How to Place Outgoing Calls</h2>
203 * When your app wants to place an outgoing call it calls
204 * {@link TelecomManager#placeCall(Uri, Bundle)}. You should specify a {@link Uri} to identify
205 * who the call is being placed to, and specify the {@link PhoneAccountHandle} associated with the
206 * {@link PhoneAccount} you registered for your app using
207 * {@link TelecomManager#EXTRA_PHONE_ACCOUNT_HANDLE} in the {@link Bundle} parameter.
208 * <p>
209 * Telecom will bind to your app's {@link ConnectionService} implementation and call either:
210 * <ul>
211 * <li>{@link ConnectionService#onCreateOutgoingConnection(PhoneAccountHandle,
212 * ConnectionRequest)} - the {@link ConnectionRequest#getAddress()} will match the address
213 * you specified when placing the call. You should return a new instance of your app's
214 * {@link Connection} class to represent the outgoing call.</li>
215 * <li>{@link ConnectionService#onCreateOutgoingConnectionFailed(PhoneAccountHandle,
216 * ConnectionRequest)} - your app should not place the call at this time; the call should be
217 * cancelled and the user informed that the call cannot be placed.</li>
218 * </ul>
219 * <p>
220 * New outgoing calls will start in a {@link Connection#STATE_DIALING} state. This state indicates
221 * that your app is in the process of connecting the call to the other party.
222 * <p>
223 * Once the other party answers the call (or it is set up successfully), your app should call
224 * {@link Connection#setActive()} to inform Telecom that the call is now active.
225 *
226 * <h2>How to Add Incoming Calls</h2>
227 * When your app receives an incoming call, it should call
228 * {@link TelecomManager#addNewIncomingCall(PhoneAccountHandle, Bundle)}. Set the
229 * {@link PhoneAccountHandle} parameter to the {@link PhoneAccountHandle} associated with your
230 * app's {@link PhoneAccount}.
231 * <p>
232 * Telecom will bind to your app's {@link ConnectionService} implementation and call either:
233 * <ul>
234 * <li>{@link ConnectionService#onCreateIncomingConnection(PhoneAccountHandle,
235 * ConnectionRequest)} - You should return a new instance of your app's
236 * {@link Connection} class to represent the incoming call.</li>
237 * <li>{@link ConnectionService#onCreateIncomingConnectionFailed(PhoneAccountHandle,
238 * ConnectionRequest)} - your app should not receive the call at this time; the call should be
239 * rejected silently; the user may be informed of a missed call.</li>
240 * </ul>
241 * <p>
242 * New incoming calls will start with a {@link Connection#STATE_RINGING} state. This state
243 * indicates that your app has a new incoming call pending. Telecom will NOT play a ringtone or
244 * post a notification for your app. It is up to your app to post an incoming call notification
245 * with an associated ringtone. Telecom will call {@link Connection#onShowIncomingCallUi()} on the
246 * {@link Connection} when your app can post its incoming call notification. See
247 * {@link Connection#onShowIncomingCallUi() the docs} for more information on how to post the
248 * notification.
249 * <p>
250 * Your incoming call notification (or full screen UI) will typically have an "answer" and "decline"
251 * action which the user chooses. When your app receives the "answer" or "decline"
252 * {@link android.app.PendingIntent}, you should must call either {@link Connection#setActive()} to
253 * inform Telecom that the call was answered, or
254 * {@link Connection#setDisconnected(DisconnectCause)} to inform Telecom that the call was rejected.
255 * If the call was rejected, supply an instance of {@link DisconnectCause} with
256 * {@link DisconnectCause#REJECTED}, and then call {@link Connection#destroy()}.
257 * <p>
258 * In addition to handling requests to answer or decline the call via notification actions, your
259 * app should also be implement the {@link Connection#onAnswer(int)} and
260 * {@link Connection#onAnswer()} methods on the {@link Connection}. These will be raised if the
261 * user answers your call via a Bluetooth device or another device like a wearable or automotive
262 * calling UX. In response, your app should call {@link Connection#setActive()} to inform Telecom
263 * that the call was answered.
264 * <p>
265 * Additionally, your app should implement {@link Connection#onReject()} to handle requests to
266 * reject the call which are raised via Bluetooth or other calling surfaces. Your app should call
267 * {@link Connection#setDisconnected(DisconnectCause)} and supply an instance of
268 * {@link DisconnectCause} with {@link DisconnectCause#REJECTED} in this case.
269 *
270 * <h2>Ending Calls</h2>
271 * When an ongoing active call (incoming or outgoing) has ended, your app is responsible for
272 * informing Telecom that the call ended.
273 * <p>
274 * Your app calls:
275 * <ul>
276 * <li>{@link Connection#setDisconnected(DisconnectCause)} - this informs Telecom that the
277 * call has terminated. You should provide a new instance of {@link DisconnectCause} with
278 * either {@link DisconnectCause#LOCAL} or {@link DisconnectCause#REMOTE} to indicate where the
279 * call disconnection took place. {@link DisconnectCause#LOCAL} indicates that the call
280 * terminated in your app on the current device (i.e. via user action), where
281 * {@link DisconnectCause#REMOTE} indicates that the call terminates on the remote device.</li>
282 * <li>{@link Connection#destroy()} - this informs Telecom that your call instance can be
283 * cleaned up. You should always call this when you are finished with a call.</li>
284 * </ul>
285 * <p>
286 * Similar to answering incoming calls, requests to disconnect your call may originate from outside
287 * your app. You can handle these by implementing {@link Connection#onDisconnect()}. Your app
288 * should call {@link Connection#setDisconnected(DisconnectCause)} with an instance of
289 * {@link DisconnectCause} and reason {@link DisconnectCause#LOCAL} to indicate to Telecom that your
290 * app has disconnected the call as requested based on the user's request.
291 *
292 * <h2>Holding and Unholding Calls</h2>
293 * When your app specifies {@link Connection#CAPABILITY_SUPPORT_HOLD} and
294 * {@link Connection#CAPABILITY_HOLD} on your {@link Connection} instance, it is telling Telecom
295 * that your calls can be placed into a suspended, or "held" state if required. If your app
296 * supports holding its calls, it will be possible for the user to switch between calls in your app
297 * and holdable calls in another app or on the mobile network. If your app does not support
298 * holding its calls, you may receive a request to disconnect the call from Telecom if the user
299 * opts to answer an incoming call in another app or on the mobile network; this ensures that the
300 * user can only be in one call at a time.
301 * <p>
302 * Your app is free to change a call between the held and active state using
303 * {@link Connection#setOnHold()} and {@link Connection#setActive()}.
304 * <p>
305 * Your app may receive a request from Telecom to hold or unhold a call via
306 * {@link Connection#onHold()} and {@link Connection#onUnhold()}. Telecom can ask your app to
307 * hold or unhold its {@link Connection} either if the user requests this action through another
308 * calling surface such as Bluetooth, or if the user answers or switches to a call in a different
309 * app or on the mobile network.
310 * <p>
311 * When your app receives an {@link Connection#onHold()} it must call {@link Connection#setOnHold()}
312 * to inform Telecom that the call has been held successfully.
313 * <p>
314 * When your app receives an {@link Connection#onUnhold()} it must call
315 * {@link Connection#setActive()} to inform Telecom that the call has been resumed successfully.
Ihab Awad542e0ea2014-05-16 10:22:16 -0700316 */
Sailesh Nepal2a46b902014-07-04 17:21:07 -0700317public abstract class ConnectionService extends Service {
Santos Cordon5c6fa952014-07-20 17:47:12 -0700318 /**
319 * The {@link Intent} that must be declared as handled by the service.
320 */
Ihab Awadb19a0bc2014-08-07 19:46:01 -0700321 @SdkConstant(SdkConstant.SdkConstantType.SERVICE_ACTION)
Tyler Gunnef9f6f92014-09-12 22:16:17 -0700322 public static final String SERVICE_INTERFACE = "android.telecom.ConnectionService";
Santos Cordon5c6fa952014-07-20 17:47:12 -0700323
Tyler Gunn8bf76572017-04-06 15:30:08 -0700324 /**
325 * Boolean extra used by Telecom to inform a {@link ConnectionService} that the purpose of it
326 * being asked to create a new outgoing {@link Connection} is to perform a handover of an
327 * ongoing call on the device from another {@link PhoneAccount}/{@link ConnectionService}. Will
328 * be specified in the {@link ConnectionRequest#getExtras()} passed by Telecom when
329 * {@link #onCreateOutgoingConnection(PhoneAccountHandle, ConnectionRequest)} is called.
330 * <p>
Tyler Gunn727c6bd2017-04-11 09:51:40 -0700331 * When your {@link ConnectionService} receives this extra, it should communicate the fact that
332 * this is a handover to the other device's matching {@link ConnectionService}. That
Tyler Gunn8bf76572017-04-06 15:30:08 -0700333 * {@link ConnectionService} will continue the handover using
334 * {@link TelecomManager#addNewIncomingCall(PhoneAccountHandle, Bundle)}, specifying
Tyler Gunn727c6bd2017-04-11 09:51:40 -0700335 * {@link TelecomManager#EXTRA_IS_HANDOVER}. Telecom will match the phone numbers of the
336 * handover call on the other device with ongoing calls for {@link ConnectionService}s which
337 * support {@link PhoneAccount#EXTRA_SUPPORTS_HANDOVER_FROM}.
Tyler Gunn8bf76572017-04-06 15:30:08 -0700338 * @hide
339 */
340 public static final String EXTRA_IS_HANDOVER = TelecomManager.EXTRA_IS_HANDOVER;
341
Ihab Awad542e0ea2014-05-16 10:22:16 -0700342 // Flag controlling whether PII is emitted into the logs
Ihab Awad60ac30b2014-05-20 22:32:12 -0700343 private static final boolean PII_DEBUG = Log.isLoggable(android.util.Log.DEBUG);
Ihab Awad542e0ea2014-05-16 10:22:16 -0700344
Brad Ebingerb32d4f82016-10-24 16:40:49 -0700345 // Session Definitions
346 private static final String SESSION_HANDLER = "H.";
347 private static final String SESSION_ADD_CS_ADAPTER = "CS.aCSA";
348 private static final String SESSION_REMOVE_CS_ADAPTER = "CS.rCSA";
349 private static final String SESSION_CREATE_CONN = "CS.crCo";
Tyler Gunn041a1fe2017-05-12 10:04:49 -0700350 private static final String SESSION_CREATE_CONN_COMPLETE = "CS.crCoC";
Tyler Gunn44e01912017-01-31 10:49:05 -0800351 private static final String SESSION_CREATE_CONN_FAILED = "CS.crCoF";
Brad Ebingerb32d4f82016-10-24 16:40:49 -0700352 private static final String SESSION_ABORT = "CS.ab";
353 private static final String SESSION_ANSWER = "CS.an";
354 private static final String SESSION_ANSWER_VIDEO = "CS.anV";
Pooja Jaind34698d2017-12-28 14:15:31 +0530355 private static final String SESSION_DEFLECT = "CS.def";
Ravi Palurif4b38e72020-02-05 12:35:41 +0530356 private static final String SESSION_TRANSFER = "CS.trans";
357 private static final String SESSION_CONSULTATIVE_TRANSFER = "CS.cTrans";
Brad Ebingerb32d4f82016-10-24 16:40:49 -0700358 private static final String SESSION_REJECT = "CS.r";
359 private static final String SESSION_REJECT_MESSAGE = "CS.rWM";
360 private static final String SESSION_SILENCE = "CS.s";
361 private static final String SESSION_DISCONNECT = "CS.d";
362 private static final String SESSION_HOLD = "CS.h";
363 private static final String SESSION_UNHOLD = "CS.u";
364 private static final String SESSION_CALL_AUDIO_SC = "CS.cASC";
Grace Jiae99fde92021-01-19 14:58:01 -0800365 private static final String SESSION_USING_ALTERNATIVE_UI = "CS.uAU";
366 private static final String SESSION_TRACKED_BY_NON_UI_SERVICE = "CS.tBNUS";
Brad Ebingerb32d4f82016-10-24 16:40:49 -0700367 private static final String SESSION_PLAY_DTMF = "CS.pDT";
368 private static final String SESSION_STOP_DTMF = "CS.sDT";
369 private static final String SESSION_CONFERENCE = "CS.c";
370 private static final String SESSION_SPLIT_CONFERENCE = "CS.sFC";
371 private static final String SESSION_MERGE_CONFERENCE = "CS.mC";
372 private static final String SESSION_SWAP_CONFERENCE = "CS.sC";
Ravi Paluri404babb2020-01-23 19:02:44 +0530373 private static final String SESSION_ADD_PARTICIPANT = "CS.aP";
Brad Ebingerb32d4f82016-10-24 16:40:49 -0700374 private static final String SESSION_POST_DIAL_CONT = "CS.oPDC";
375 private static final String SESSION_PULL_EXTERNAL_CALL = "CS.pEC";
376 private static final String SESSION_SEND_CALL_EVENT = "CS.sCE";
Hall Liu49cabcc2021-01-15 11:41:48 -0800377 private static final String SESSION_CALL_FILTERING_COMPLETED = "CS.oCFC";
Tyler Gunn79bc1ec2018-01-22 15:17:54 -0800378 private static final String SESSION_HANDOVER_COMPLETE = "CS.hC";
Brad Ebingerb32d4f82016-10-24 16:40:49 -0700379 private static final String SESSION_EXTRAS_CHANGED = "CS.oEC";
Hall Liub64ac4c2017-02-06 10:49:48 -0800380 private static final String SESSION_START_RTT = "CS.+RTT";
Hall Liua549fed2018-02-09 16:40:03 -0800381 private static final String SESSION_UPDATE_RTT_PIPES = "CS.uRTT";
Hall Liub64ac4c2017-02-06 10:49:48 -0800382 private static final String SESSION_STOP_RTT = "CS.-RTT";
383 private static final String SESSION_RTT_UPGRADE_RESPONSE = "CS.rTRUR";
Pengquan Meng731c1a32017-11-21 18:01:13 -0800384 private static final String SESSION_CONNECTION_SERVICE_FOCUS_LOST = "CS.cSFL";
385 private static final String SESSION_CONNECTION_SERVICE_FOCUS_GAINED = "CS.cSFG";
Sanket Padawe4cc8ed52017-12-04 16:22:20 -0800386 private static final String SESSION_HANDOVER_FAILED = "CS.haF";
Ravi Paluri80aa2142019-12-02 11:57:37 +0530387 private static final String SESSION_CREATE_CONF = "CS.crConf";
388 private static final String SESSION_CREATE_CONF_COMPLETE = "CS.crConfC";
389 private static final String SESSION_CREATE_CONF_FAILED = "CS.crConfF";
Junhoedf3d822022-11-24 09:26:37 +0000390 private static final String SESSION_CALL_ENDPOINT_CHANGED = "CS.oCEC";
391 private static final String SESSION_AVAILABLE_CALL_ENDPOINTS_CHANGED = "CS.oACEC";
392 private static final String SESSION_MUTE_STATE_CHANGED = "CS.oMSC";
Brad Ebingerb32d4f82016-10-24 16:40:49 -0700393
Ihab Awad8aecfed2014-08-08 17:06:11 -0700394 private static final int MSG_ADD_CONNECTION_SERVICE_ADAPTER = 1;
Sailesh Nepalc5b01572014-07-14 16:29:44 -0700395 private static final int MSG_CREATE_CONNECTION = 2;
Sailesh Nepal2a46b902014-07-04 17:21:07 -0700396 private static final int MSG_ABORT = 3;
Sailesh Nepalc5b01572014-07-14 16:29:44 -0700397 private static final int MSG_ANSWER = 4;
398 private static final int MSG_REJECT = 5;
399 private static final int MSG_DISCONNECT = 6;
400 private static final int MSG_HOLD = 7;
401 private static final int MSG_UNHOLD = 8;
Yorke Lee4af59352015-05-13 14:14:54 -0700402 private static final int MSG_ON_CALL_AUDIO_STATE_CHANGED = 9;
Sailesh Nepalc5b01572014-07-14 16:29:44 -0700403 private static final int MSG_PLAY_DTMF_TONE = 10;
404 private static final int MSG_STOP_DTMF_TONE = 11;
405 private static final int MSG_CONFERENCE = 12;
406 private static final int MSG_SPLIT_FROM_CONFERENCE = 13;
Ihab Awadb19a0bc2014-08-07 19:46:01 -0700407 private static final int MSG_ON_POST_DIAL_CONTINUE = 14;
Ihab Awadb19a0bc2014-08-07 19:46:01 -0700408 private static final int MSG_REMOVE_CONNECTION_SERVICE_ADAPTER = 16;
Tyler Gunnbe74de02014-08-29 14:51:48 -0700409 private static final int MSG_ANSWER_VIDEO = 17;
Santos Cordona4868042014-09-04 17:39:22 -0700410 private static final int MSG_MERGE_CONFERENCE = 18;
411 private static final int MSG_SWAP_CONFERENCE = 19;
Bryce Lee81901682015-08-28 16:38:02 -0700412 private static final int MSG_REJECT_WITH_MESSAGE = 20;
Bryce Leecac50772015-11-17 15:13:29 -0800413 private static final int MSG_SILENCE = 21;
Tyler Gunn876dbfb2016-03-14 15:18:07 -0700414 private static final int MSG_PULL_EXTERNAL_CALL = 22;
415 private static final int MSG_SEND_CALL_EVENT = 23;
Tyler Gunndee56a82016-03-23 16:06:34 -0700416 private static final int MSG_ON_EXTRAS_CHANGED = 24;
Tyler Gunn44e01912017-01-31 10:49:05 -0800417 private static final int MSG_CREATE_CONNECTION_FAILED = 25;
Hall Liub64ac4c2017-02-06 10:49:48 -0800418 private static final int MSG_ON_START_RTT = 26;
419 private static final int MSG_ON_STOP_RTT = 27;
420 private static final int MSG_RTT_UPGRADE_RESPONSE = 28;
Tyler Gunn041a1fe2017-05-12 10:04:49 -0700421 private static final int MSG_CREATE_CONNECTION_COMPLETE = 29;
Pengquan Meng731c1a32017-11-21 18:01:13 -0800422 private static final int MSG_CONNECTION_SERVICE_FOCUS_LOST = 30;
423 private static final int MSG_CONNECTION_SERVICE_FOCUS_GAINED = 31;
Sanket Padawe4cc8ed52017-12-04 16:22:20 -0800424 private static final int MSG_HANDOVER_FAILED = 32;
Tyler Gunn79bc1ec2018-01-22 15:17:54 -0800425 private static final int MSG_HANDOVER_COMPLETE = 33;
Pooja Jaind34698d2017-12-28 14:15:31 +0530426 private static final int MSG_DEFLECT = 34;
Ravi Paluri80aa2142019-12-02 11:57:37 +0530427 private static final int MSG_CREATE_CONFERENCE = 35;
428 private static final int MSG_CREATE_CONFERENCE_COMPLETE = 36;
429 private static final int MSG_CREATE_CONFERENCE_FAILED = 37;
Tyler Gunnfacfdee2020-01-23 13:10:37 -0800430 private static final int MSG_REJECT_WITH_REASON = 38;
Ravi Paluri404babb2020-01-23 19:02:44 +0530431 private static final int MSG_ADD_PARTICIPANT = 39;
Ravi Palurif4b38e72020-02-05 12:35:41 +0530432 private static final int MSG_EXPLICIT_CALL_TRANSFER = 40;
433 private static final int MSG_EXPLICIT_CALL_TRANSFER_CONSULTATIVE = 41;
Hall Liu49cabcc2021-01-15 11:41:48 -0800434 private static final int MSG_ON_CALL_FILTERING_COMPLETED = 42;
Grace Jiae99fde92021-01-19 14:58:01 -0800435 private static final int MSG_ON_USING_ALTERNATIVE_UI = 43;
436 private static final int MSG_ON_TRACKED_BY_NON_UI_SERVICE = 44;
Junhoedf3d822022-11-24 09:26:37 +0000437 private static final int MSG_ON_CALL_ENDPOINT_CHANGED = 45;
438 private static final int MSG_ON_AVAILABLE_CALL_ENDPOINTS_CHANGED = 46;
439 private static final int MSG_ON_MUTE_STATE_CHANGED = 47;
Santos Cordon7c7bc7f2014-07-28 18:15:48 -0700440
Sailesh Nepalcf7020b2014-08-20 10:07:19 -0700441 private static Connection sNullConnection;
442
mike dooley95e80702014-09-18 14:07:52 -0700443 private final Map<String, Connection> mConnectionById = new ConcurrentHashMap<>();
444 private final Map<Connection, String> mIdByConnection = new ConcurrentHashMap<>();
445 private final Map<String, Conference> mConferenceById = new ConcurrentHashMap<>();
446 private final Map<Conference, String> mIdByConference = new ConcurrentHashMap<>();
Ihab Awadb8e85c72014-08-23 20:34:57 -0700447 private final RemoteConnectionManager mRemoteConnectionManager =
448 new RemoteConnectionManager(this);
Ihab Awad5d0410f2014-07-30 10:07:40 -0700449 private final List<Runnable> mPreInitializationConnectionRequests = new ArrayList<>();
Sailesh Nepal2a46b902014-07-04 17:21:07 -0700450 private final ConnectionServiceAdapter mAdapter = new ConnectionServiceAdapter();
Ihab Awad542e0ea2014-05-16 10:22:16 -0700451
Santos Cordon823fd3c2014-08-07 18:35:18 -0700452 private boolean mAreAccountsInitialized = false;
Santos Cordon0159ac02014-08-21 14:28:11 -0700453 private Conference sNullConference;
Tyler Gunnf0500bd2015-09-01 10:59:48 -0700454 private Object mIdSyncRoot = new Object();
455 private int mId = 0;
Santos Cordon823fd3c2014-08-07 18:35:18 -0700456
Sailesh Nepal2a46b902014-07-04 17:21:07 -0700457 private final IBinder mBinder = new IConnectionService.Stub() {
458 @Override
Brad Ebingerb32d4f82016-10-24 16:40:49 -0700459 public void addConnectionServiceAdapter(IConnectionServiceAdapter adapter,
460 Session.Info sessionInfo) {
461 Log.startSession(sessionInfo, SESSION_ADD_CS_ADAPTER);
462 try {
463 SomeArgs args = SomeArgs.obtain();
464 args.arg1 = adapter;
465 args.arg2 = Log.createSubsession();
466 mHandler.obtainMessage(MSG_ADD_CONNECTION_SERVICE_ADAPTER, args).sendToTarget();
467 } finally {
468 Log.endSession();
469 }
Ihab Awad8aecfed2014-08-08 17:06:11 -0700470 }
471
Brad Ebingerb32d4f82016-10-24 16:40:49 -0700472 public void removeConnectionServiceAdapter(IConnectionServiceAdapter adapter,
473 Session.Info sessionInfo) {
474 Log.startSession(sessionInfo, SESSION_REMOVE_CS_ADAPTER);
475 try {
476 SomeArgs args = SomeArgs.obtain();
477 args.arg1 = adapter;
478 args.arg2 = Log.createSubsession();
479 mHandler.obtainMessage(MSG_REMOVE_CONNECTION_SERVICE_ADAPTER, args).sendToTarget();
480 } finally {
481 Log.endSession();
482 }
Sailesh Nepal2a46b902014-07-04 17:21:07 -0700483 }
484
485 @Override
Ihab Awadf8b69882014-07-25 15:14:01 -0700486 public void createConnection(
487 PhoneAccountHandle connectionManagerPhoneAccount,
Ihab Awadb19a0bc2014-08-07 19:46:01 -0700488 String id,
Ihab Awadf8b69882014-07-25 15:14:01 -0700489 ConnectionRequest request,
Yorke Leec3cf9822014-10-02 09:38:39 -0700490 boolean isIncoming,
Brad Ebingerb32d4f82016-10-24 16:40:49 -0700491 boolean isUnknown,
492 Session.Info sessionInfo) {
493 Log.startSession(sessionInfo, SESSION_CREATE_CONN);
494 try {
495 SomeArgs args = SomeArgs.obtain();
496 args.arg1 = connectionManagerPhoneAccount;
497 args.arg2 = id;
498 args.arg3 = request;
499 args.arg4 = Log.createSubsession();
500 args.argi1 = isIncoming ? 1 : 0;
501 args.argi2 = isUnknown ? 1 : 0;
502 mHandler.obtainMessage(MSG_CREATE_CONNECTION, args).sendToTarget();
503 } finally {
504 Log.endSession();
505 }
Sailesh Nepal2a46b902014-07-04 17:21:07 -0700506 }
507
508 @Override
Tyler Gunn041a1fe2017-05-12 10:04:49 -0700509 public void createConnectionComplete(String id, Session.Info sessionInfo) {
510 Log.startSession(sessionInfo, SESSION_CREATE_CONN_COMPLETE);
511 try {
512 SomeArgs args = SomeArgs.obtain();
513 args.arg1 = id;
514 args.arg2 = Log.createSubsession();
515 mHandler.obtainMessage(MSG_CREATE_CONNECTION_COMPLETE, args).sendToTarget();
516 } finally {
517 Log.endSession();
518 }
519 }
520
521 @Override
Tyler Gunn44e01912017-01-31 10:49:05 -0800522 public void createConnectionFailed(
Tyler Gunn159f35c2017-03-02 09:28:37 -0800523 PhoneAccountHandle connectionManagerPhoneAccount,
Tyler Gunn44e01912017-01-31 10:49:05 -0800524 String callId,
525 ConnectionRequest request,
526 boolean isIncoming,
527 Session.Info sessionInfo) {
528 Log.startSession(sessionInfo, SESSION_CREATE_CONN_FAILED);
529 try {
530 SomeArgs args = SomeArgs.obtain();
531 args.arg1 = callId;
532 args.arg2 = request;
533 args.arg3 = Log.createSubsession();
Tyler Gunn159f35c2017-03-02 09:28:37 -0800534 args.arg4 = connectionManagerPhoneAccount;
Tyler Gunn44e01912017-01-31 10:49:05 -0800535 args.argi1 = isIncoming ? 1 : 0;
536 mHandler.obtainMessage(MSG_CREATE_CONNECTION_FAILED, args).sendToTarget();
537 } finally {
538 Log.endSession();
539 }
540 }
541
542 @Override
Ravi Paluri80aa2142019-12-02 11:57:37 +0530543 public void createConference(
544 PhoneAccountHandle connectionManagerPhoneAccount,
545 String id,
546 ConnectionRequest request,
547 boolean isIncoming,
548 boolean isUnknown,
549 Session.Info sessionInfo) {
550 Log.startSession(sessionInfo, SESSION_CREATE_CONF);
551 try {
552 SomeArgs args = SomeArgs.obtain();
553 args.arg1 = connectionManagerPhoneAccount;
554 args.arg2 = id;
555 args.arg3 = request;
556 args.arg4 = Log.createSubsession();
557 args.argi1 = isIncoming ? 1 : 0;
558 args.argi2 = isUnknown ? 1 : 0;
559 mHandler.obtainMessage(MSG_CREATE_CONFERENCE, args).sendToTarget();
560 } finally {
561 Log.endSession();
562 }
563 }
564
565 @Override
566 public void createConferenceComplete(String id, Session.Info sessionInfo) {
567 Log.startSession(sessionInfo, SESSION_CREATE_CONF_COMPLETE);
568 try {
569 SomeArgs args = SomeArgs.obtain();
570 args.arg1 = id;
571 args.arg2 = Log.createSubsession();
572 mHandler.obtainMessage(MSG_CREATE_CONFERENCE_COMPLETE, args).sendToTarget();
573 } finally {
574 Log.endSession();
575 }
576 }
577
578 @Override
579 public void createConferenceFailed(
580 PhoneAccountHandle connectionManagerPhoneAccount,
581 String callId,
582 ConnectionRequest request,
583 boolean isIncoming,
584 Session.Info sessionInfo) {
585 Log.startSession(sessionInfo, SESSION_CREATE_CONF_FAILED);
586 try {
587 SomeArgs args = SomeArgs.obtain();
588 args.arg1 = callId;
589 args.arg2 = request;
590 args.arg3 = Log.createSubsession();
591 args.arg4 = connectionManagerPhoneAccount;
592 args.argi1 = isIncoming ? 1 : 0;
593 mHandler.obtainMessage(MSG_CREATE_CONFERENCE_FAILED, args).sendToTarget();
594 } finally {
595 Log.endSession();
596 }
597 }
598
599 @Override
Sanket Padawe4cc8ed52017-12-04 16:22:20 -0800600 public void handoverFailed(String callId, ConnectionRequest request, int reason,
601 Session.Info sessionInfo) {
602 Log.startSession(sessionInfo, SESSION_HANDOVER_FAILED);
603 try {
604 SomeArgs args = SomeArgs.obtain();
605 args.arg1 = callId;
606 args.arg2 = request;
607 args.arg3 = Log.createSubsession();
608 args.arg4 = reason;
609 mHandler.obtainMessage(MSG_HANDOVER_FAILED, args).sendToTarget();
610 } finally {
611 Log.endSession();
612 }
613 }
614
615 @Override
Tyler Gunn79bc1ec2018-01-22 15:17:54 -0800616 public void handoverComplete(String callId, Session.Info sessionInfo) {
617 Log.startSession(sessionInfo, SESSION_HANDOVER_COMPLETE);
618 try {
619 SomeArgs args = SomeArgs.obtain();
620 args.arg1 = callId;
621 args.arg2 = Log.createSubsession();
622 mHandler.obtainMessage(MSG_HANDOVER_COMPLETE, args).sendToTarget();
623 } finally {
624 Log.endSession();
625 }
626 }
627
628 @Override
Brad Ebingerb32d4f82016-10-24 16:40:49 -0700629 public void abort(String callId, Session.Info sessionInfo) {
630 Log.startSession(sessionInfo, SESSION_ABORT);
631 try {
632 SomeArgs args = SomeArgs.obtain();
633 args.arg1 = callId;
634 args.arg2 = Log.createSubsession();
635 mHandler.obtainMessage(MSG_ABORT, args).sendToTarget();
636 } finally {
637 Log.endSession();
638 }
Sailesh Nepal2a46b902014-07-04 17:21:07 -0700639 }
640
641 @Override
Brad Ebingerb32d4f82016-10-24 16:40:49 -0700642 public void answerVideo(String callId, int videoState, Session.Info sessionInfo) {
643 Log.startSession(sessionInfo, SESSION_ANSWER_VIDEO);
644 try {
645 SomeArgs args = SomeArgs.obtain();
646 args.arg1 = callId;
647 args.arg2 = Log.createSubsession();
648 args.argi1 = videoState;
649 mHandler.obtainMessage(MSG_ANSWER_VIDEO, args).sendToTarget();
650 } finally {
651 Log.endSession();
652 }
Tyler Gunnbe74de02014-08-29 14:51:48 -0700653 }
654
655 @Override
Brad Ebingerb32d4f82016-10-24 16:40:49 -0700656 public void answer(String callId, Session.Info sessionInfo) {
657 Log.startSession(sessionInfo, SESSION_ANSWER);
658 try {
659 SomeArgs args = SomeArgs.obtain();
660 args.arg1 = callId;
661 args.arg2 = Log.createSubsession();
662 mHandler.obtainMessage(MSG_ANSWER, args).sendToTarget();
663 } finally {
664 Log.endSession();
665 }
Sailesh Nepal2a46b902014-07-04 17:21:07 -0700666 }
667
668 @Override
Pooja Jaind34698d2017-12-28 14:15:31 +0530669 public void deflect(String callId, Uri address, Session.Info sessionInfo) {
670 Log.startSession(sessionInfo, SESSION_DEFLECT);
671 try {
672 SomeArgs args = SomeArgs.obtain();
673 args.arg1 = callId;
674 args.arg2 = address;
675 args.arg3 = Log.createSubsession();
676 mHandler.obtainMessage(MSG_DEFLECT, args).sendToTarget();
677 } finally {
678 Log.endSession();
679 }
680 }
681
682 @Override
Brad Ebingerb32d4f82016-10-24 16:40:49 -0700683 public void reject(String callId, Session.Info sessionInfo) {
684 Log.startSession(sessionInfo, SESSION_REJECT);
685 try {
686 SomeArgs args = SomeArgs.obtain();
687 args.arg1 = callId;
688 args.arg2 = Log.createSubsession();
689 mHandler.obtainMessage(MSG_REJECT, args).sendToTarget();
690 } finally {
691 Log.endSession();
692 }
Sailesh Nepal2a46b902014-07-04 17:21:07 -0700693 }
694
695 @Override
Tyler Gunnfacfdee2020-01-23 13:10:37 -0800696 public void rejectWithReason(String callId,
697 @android.telecom.Call.RejectReason int rejectReason, Session.Info sessionInfo) {
698 Log.startSession(sessionInfo, SESSION_REJECT);
699 try {
700 SomeArgs args = SomeArgs.obtain();
701 args.arg1 = callId;
702 args.argi1 = rejectReason;
703 args.arg2 = Log.createSubsession();
704 mHandler.obtainMessage(MSG_REJECT_WITH_REASON, args).sendToTarget();
705 } finally {
706 Log.endSession();
707 }
708 }
709
710 @Override
Brad Ebingerb32d4f82016-10-24 16:40:49 -0700711 public void rejectWithMessage(String callId, String message, Session.Info sessionInfo) {
712 Log.startSession(sessionInfo, SESSION_REJECT_MESSAGE);
713 try {
714 SomeArgs args = SomeArgs.obtain();
715 args.arg1 = callId;
716 args.arg2 = message;
717 args.arg3 = Log.createSubsession();
718 mHandler.obtainMessage(MSG_REJECT_WITH_MESSAGE, args).sendToTarget();
719 } finally {
720 Log.endSession();
721 }
Bryce Lee81901682015-08-28 16:38:02 -0700722 }
723
724 @Override
Ravi Palurif4b38e72020-02-05 12:35:41 +0530725 public void transfer(@NonNull String callId, @NonNull Uri number,
726 boolean isConfirmationRequired, Session.Info sessionInfo) {
727 Log.startSession(sessionInfo, SESSION_TRANSFER);
728 try {
729 SomeArgs args = SomeArgs.obtain();
730 args.arg1 = callId;
731 args.arg2 = number;
732 args.argi1 = isConfirmationRequired ? 1 : 0;
733 args.arg3 = Log.createSubsession();
734 mHandler.obtainMessage(MSG_EXPLICIT_CALL_TRANSFER, args).sendToTarget();
735 } finally {
736 Log.endSession();
737 }
738 }
739
740 @Override
741 public void consultativeTransfer(@NonNull String callId, @NonNull String otherCallId,
742 Session.Info sessionInfo) {
743 Log.startSession(sessionInfo, SESSION_CONSULTATIVE_TRANSFER);
744 try {
745 SomeArgs args = SomeArgs.obtain();
746 args.arg1 = callId;
747 args.arg2 = otherCallId;
748 args.arg3 = Log.createSubsession();
749 mHandler.obtainMessage(
750 MSG_EXPLICIT_CALL_TRANSFER_CONSULTATIVE, args).sendToTarget();
751 } finally {
752 Log.endSession();
753 }
754 }
755
756 @Override
Brad Ebingerb32d4f82016-10-24 16:40:49 -0700757 public void silence(String callId, Session.Info sessionInfo) {
758 Log.startSession(sessionInfo, SESSION_SILENCE);
759 try {
760 SomeArgs args = SomeArgs.obtain();
761 args.arg1 = callId;
762 args.arg2 = Log.createSubsession();
763 mHandler.obtainMessage(MSG_SILENCE, args).sendToTarget();
764 } finally {
765 Log.endSession();
766 }
Bryce Leecac50772015-11-17 15:13:29 -0800767 }
768
769 @Override
Brad Ebingerb32d4f82016-10-24 16:40:49 -0700770 public void disconnect(String callId, Session.Info sessionInfo) {
771 Log.startSession(sessionInfo, SESSION_DISCONNECT);
772 try {
773 SomeArgs args = SomeArgs.obtain();
774 args.arg1 = callId;
775 args.arg2 = Log.createSubsession();
776 mHandler.obtainMessage(MSG_DISCONNECT, args).sendToTarget();
777 } finally {
778 Log.endSession();
779 }
Sailesh Nepal2a46b902014-07-04 17:21:07 -0700780 }
781
782 @Override
Brad Ebingerb32d4f82016-10-24 16:40:49 -0700783 public void hold(String callId, Session.Info sessionInfo) {
784 Log.startSession(sessionInfo, SESSION_HOLD);
785 try {
786 SomeArgs args = SomeArgs.obtain();
787 args.arg1 = callId;
788 args.arg2 = Log.createSubsession();
789 mHandler.obtainMessage(MSG_HOLD, args).sendToTarget();
790 } finally {
791 Log.endSession();
792 }
Sailesh Nepal2a46b902014-07-04 17:21:07 -0700793 }
794
795 @Override
Brad Ebingerb32d4f82016-10-24 16:40:49 -0700796 public void unhold(String callId, Session.Info sessionInfo) {
797 Log.startSession(sessionInfo, SESSION_UNHOLD);
798 try {
799 SomeArgs args = SomeArgs.obtain();
800 args.arg1 = callId;
801 args.arg2 = Log.createSubsession();
802 mHandler.obtainMessage(MSG_UNHOLD, args).sendToTarget();
803 } finally {
804 Log.endSession();
805 }
Sailesh Nepal2a46b902014-07-04 17:21:07 -0700806 }
807
808 @Override
Brad Ebingerb32d4f82016-10-24 16:40:49 -0700809 public void onCallAudioStateChanged(String callId, CallAudioState callAudioState,
810 Session.Info sessionInfo) {
811 Log.startSession(sessionInfo, SESSION_CALL_AUDIO_SC);
812 try {
813 SomeArgs args = SomeArgs.obtain();
814 args.arg1 = callId;
815 args.arg2 = callAudioState;
816 args.arg3 = Log.createSubsession();
817 mHandler.obtainMessage(MSG_ON_CALL_AUDIO_STATE_CHANGED, args).sendToTarget();
818 } finally {
819 Log.endSession();
820 }
Sailesh Nepal2a46b902014-07-04 17:21:07 -0700821 }
822
823 @Override
Junhoedf3d822022-11-24 09:26:37 +0000824 public void onCallEndpointChanged(String callId, CallEndpoint callEndpoint,
825 Session.Info sessionInfo) {
826 Log.startSession(sessionInfo, SESSION_CALL_ENDPOINT_CHANGED);
827 try {
828 SomeArgs args = SomeArgs.obtain();
829 args.arg1 = callId;
830 args.arg2 = callEndpoint;
831 args.arg3 = Log.createSubsession();
832 mHandler.obtainMessage(MSG_ON_CALL_ENDPOINT_CHANGED, args).sendToTarget();
833 } finally {
834 Log.endSession();
835 }
836 }
837
838 @Override
839 public void onAvailableCallEndpointsChanged(String callId,
840 List<CallEndpoint> availableCallEndpoints, Session.Info sessionInfo) {
841 Log.startSession(sessionInfo, SESSION_AVAILABLE_CALL_ENDPOINTS_CHANGED);
842 try {
843 SomeArgs args = SomeArgs.obtain();
844 args.arg1 = callId;
845 args.arg2 = availableCallEndpoints;
846 args.arg3 = Log.createSubsession();
847 mHandler.obtainMessage(MSG_ON_AVAILABLE_CALL_ENDPOINTS_CHANGED, args)
848 .sendToTarget();
849 } finally {
850 Log.endSession();
851 }
852 }
853
854 @Override
855 public void onMuteStateChanged(String callId, boolean isMuted, Session.Info sessionInfo) {
856 Log.startSession(sessionInfo, SESSION_MUTE_STATE_CHANGED);
857 try {
858 SomeArgs args = SomeArgs.obtain();
859 args.arg1 = callId;
860 args.arg2 = isMuted;
861 args.arg3 = Log.createSubsession();
862 mHandler.obtainMessage(MSG_ON_MUTE_STATE_CHANGED, args).sendToTarget();
863 } finally {
864 Log.endSession();
865 }
866 }
867
868 @Override
Grace Jiae99fde92021-01-19 14:58:01 -0800869 public void onUsingAlternativeUi(String callId, boolean usingAlternativeUiShowing,
870 Session.Info sessionInfo) {
871 Log.startSession(sessionInfo, SESSION_USING_ALTERNATIVE_UI);
872 try {
873 SomeArgs args = SomeArgs.obtain();
874 args.arg1 = callId;
875 args.arg2 = usingAlternativeUiShowing;
876 args.arg3 = Log.createSubsession();
877 mHandler.obtainMessage(MSG_ON_USING_ALTERNATIVE_UI, args).sendToTarget();
878 } finally {
879 Log.endSession();
880 }
881 }
882
883 @Override
884 public void onTrackedByNonUiService(String callId, boolean isTracked,
885 Session.Info sessionInfo) {
886 Log.startSession(sessionInfo, SESSION_TRACKED_BY_NON_UI_SERVICE);
887 try {
888 SomeArgs args = SomeArgs.obtain();
889 args.arg1 = callId;
890 args.arg2 = isTracked;
891 args.arg3 = Log.createSubsession();
892 mHandler.obtainMessage(MSG_ON_TRACKED_BY_NON_UI_SERVICE, args).sendToTarget();
893 } finally {
894 Log.endSession();
895 }
896 }
897
898 @Override
Brad Ebingerb32d4f82016-10-24 16:40:49 -0700899 public void playDtmfTone(String callId, char digit, Session.Info sessionInfo) {
900 Log.startSession(sessionInfo, SESSION_PLAY_DTMF);
901 try {
902 SomeArgs args = SomeArgs.obtain();
903 args.arg1 = digit;
904 args.arg2 = callId;
905 args.arg3 = Log.createSubsession();
906 mHandler.obtainMessage(MSG_PLAY_DTMF_TONE, args).sendToTarget();
907 } finally {
908 Log.endSession();
909 }
Sailesh Nepal2a46b902014-07-04 17:21:07 -0700910 }
911
912 @Override
Brad Ebingerb32d4f82016-10-24 16:40:49 -0700913 public void stopDtmfTone(String callId, Session.Info sessionInfo) {
914 Log.startSession(sessionInfo, SESSION_STOP_DTMF);
915 try {
916 SomeArgs args = SomeArgs.obtain();
917 args.arg1 = callId;
918 args.arg2 = Log.createSubsession();
919 mHandler.obtainMessage(MSG_STOP_DTMF_TONE, args).sendToTarget();
920 } finally {
921 Log.endSession();
922 }
Sailesh Nepal2a46b902014-07-04 17:21:07 -0700923 }
924
925 @Override
Brad Ebingerb32d4f82016-10-24 16:40:49 -0700926 public void conference(String callId1, String callId2, Session.Info sessionInfo) {
927 Log.startSession(sessionInfo, SESSION_CONFERENCE);
928 try {
929 SomeArgs args = SomeArgs.obtain();
930 args.arg1 = callId1;
931 args.arg2 = callId2;
932 args.arg3 = Log.createSubsession();
933 mHandler.obtainMessage(MSG_CONFERENCE, args).sendToTarget();
934 } finally {
935 Log.endSession();
936 }
Sailesh Nepal2a46b902014-07-04 17:21:07 -0700937 }
938
939 @Override
Brad Ebingerb32d4f82016-10-24 16:40:49 -0700940 public void splitFromConference(String callId, Session.Info sessionInfo) {
941 Log.startSession(sessionInfo, SESSION_SPLIT_CONFERENCE);
942 try {
943 SomeArgs args = SomeArgs.obtain();
944 args.arg1 = callId;
945 args.arg2 = Log.createSubsession();
946 mHandler.obtainMessage(MSG_SPLIT_FROM_CONFERENCE, args).sendToTarget();
947 } finally {
948 Log.endSession();
949 }
Sailesh Nepal2a46b902014-07-04 17:21:07 -0700950 }
951
952 @Override
Brad Ebingerb32d4f82016-10-24 16:40:49 -0700953 public void mergeConference(String callId, Session.Info sessionInfo) {
954 Log.startSession(sessionInfo, SESSION_MERGE_CONFERENCE);
955 try {
956 SomeArgs args = SomeArgs.obtain();
957 args.arg1 = callId;
958 args.arg2 = Log.createSubsession();
959 mHandler.obtainMessage(MSG_MERGE_CONFERENCE, args).sendToTarget();
960 } finally {
961 Log.endSession();
962 }
Santos Cordona4868042014-09-04 17:39:22 -0700963 }
964
965 @Override
Brad Ebingerb32d4f82016-10-24 16:40:49 -0700966 public void swapConference(String callId, Session.Info sessionInfo) {
967 Log.startSession(sessionInfo, SESSION_SWAP_CONFERENCE);
968 try {
969 SomeArgs args = SomeArgs.obtain();
970 args.arg1 = callId;
971 args.arg2 = Log.createSubsession();
972 mHandler.obtainMessage(MSG_SWAP_CONFERENCE, args).sendToTarget();
973 } finally {
974 Log.endSession();
975 }
Santos Cordona4868042014-09-04 17:39:22 -0700976 }
977
978 @Override
Ravi Paluri404babb2020-01-23 19:02:44 +0530979 public void addConferenceParticipants(String callId, List<Uri> participants,
980 Session.Info sessionInfo) {
981 Log.startSession(sessionInfo, SESSION_ADD_PARTICIPANT);
982 try {
983 SomeArgs args = SomeArgs.obtain();
984 args.arg1 = callId;
985 args.arg2 = participants;
986 args.arg3 = Log.createSubsession();
987 mHandler.obtainMessage(MSG_ADD_PARTICIPANT, args).sendToTarget();
988 } finally {
989 Log.endSession();
990 }
991 }
992
993 @Override
Brad Ebingerb32d4f82016-10-24 16:40:49 -0700994 public void onPostDialContinue(String callId, boolean proceed, Session.Info sessionInfo) {
995 Log.startSession(sessionInfo, SESSION_POST_DIAL_CONT);
996 try {
997 SomeArgs args = SomeArgs.obtain();
998 args.arg1 = callId;
999 args.arg2 = Log.createSubsession();
1000 args.argi1 = proceed ? 1 : 0;
1001 mHandler.obtainMessage(MSG_ON_POST_DIAL_CONTINUE, args).sendToTarget();
1002 } finally {
1003 Log.endSession();
1004 }
Sailesh Nepal2a46b902014-07-04 17:21:07 -07001005 }
Tyler Gunn876dbfb2016-03-14 15:18:07 -07001006
1007 @Override
Brad Ebingerb32d4f82016-10-24 16:40:49 -07001008 public void pullExternalCall(String callId, Session.Info sessionInfo) {
1009 Log.startSession(sessionInfo, SESSION_PULL_EXTERNAL_CALL);
1010 try {
1011 SomeArgs args = SomeArgs.obtain();
1012 args.arg1 = callId;
1013 args.arg2 = Log.createSubsession();
1014 mHandler.obtainMessage(MSG_PULL_EXTERNAL_CALL, args).sendToTarget();
1015 } finally {
1016 Log.endSession();
1017 }
Tyler Gunn876dbfb2016-03-14 15:18:07 -07001018 }
1019
1020 @Override
Brad Ebingerb32d4f82016-10-24 16:40:49 -07001021 public void sendCallEvent(String callId, String event, Bundle extras,
1022 Session.Info sessionInfo) {
1023 Log.startSession(sessionInfo, SESSION_SEND_CALL_EVENT);
1024 try {
1025 SomeArgs args = SomeArgs.obtain();
1026 args.arg1 = callId;
1027 args.arg2 = event;
1028 args.arg3 = extras;
1029 args.arg4 = Log.createSubsession();
1030 mHandler.obtainMessage(MSG_SEND_CALL_EVENT, args).sendToTarget();
1031 } finally {
1032 Log.endSession();
1033 }
Tyler Gunn876dbfb2016-03-14 15:18:07 -07001034 }
Tyler Gunndee56a82016-03-23 16:06:34 -07001035
1036 @Override
Hall Liu73903142021-02-18 18:41:41 -08001037 public void onCallFilteringCompleted(String callId,
1038 Connection.CallFilteringCompletionInfo completionInfo,
Hall Liu49cabcc2021-01-15 11:41:48 -08001039 Session.Info sessionInfo) {
1040 Log.startSession(sessionInfo, SESSION_CALL_FILTERING_COMPLETED);
1041 try {
1042 SomeArgs args = SomeArgs.obtain();
1043 args.arg1 = callId;
Hall Liu73903142021-02-18 18:41:41 -08001044 args.arg2 = completionInfo;
1045 args.arg3 = Log.createSubsession();
Hall Liu49cabcc2021-01-15 11:41:48 -08001046 mHandler.obtainMessage(MSG_ON_CALL_FILTERING_COMPLETED, args).sendToTarget();
1047 } finally {
1048 Log.endSession();
1049 }
1050 }
1051
1052 @Override
Brad Ebingerb32d4f82016-10-24 16:40:49 -07001053 public void onExtrasChanged(String callId, Bundle extras, Session.Info sessionInfo) {
1054 Log.startSession(sessionInfo, SESSION_EXTRAS_CHANGED);
1055 try {
1056 SomeArgs args = SomeArgs.obtain();
1057 args.arg1 = callId;
1058 args.arg2 = extras;
1059 args.arg3 = Log.createSubsession();
1060 mHandler.obtainMessage(MSG_ON_EXTRAS_CHANGED, args).sendToTarget();
1061 } finally {
1062 Log.endSession();
1063 }
Tyler Gunndee56a82016-03-23 16:06:34 -07001064 }
Hall Liub64ac4c2017-02-06 10:49:48 -08001065
1066 @Override
1067 public void startRtt(String callId, ParcelFileDescriptor fromInCall,
1068 ParcelFileDescriptor toInCall, Session.Info sessionInfo) throws RemoteException {
1069 Log.startSession(sessionInfo, SESSION_START_RTT);
1070 try {
1071 SomeArgs args = SomeArgs.obtain();
1072 args.arg1 = callId;
1073 args.arg2 = new Connection.RttTextStream(toInCall, fromInCall);
1074 args.arg3 = Log.createSubsession();
1075 mHandler.obtainMessage(MSG_ON_START_RTT, args).sendToTarget();
1076 } finally {
1077 Log.endSession();
1078 }
1079 }
1080
1081 @Override
1082 public void stopRtt(String callId, Session.Info sessionInfo) throws RemoteException {
1083 Log.startSession(sessionInfo, SESSION_STOP_RTT);
1084 try {
1085 SomeArgs args = SomeArgs.obtain();
1086 args.arg1 = callId;
1087 args.arg2 = Log.createSubsession();
1088 mHandler.obtainMessage(MSG_ON_STOP_RTT, args).sendToTarget();
1089 } finally {
1090 Log.endSession();
1091 }
1092 }
1093
1094 @Override
1095 public void respondToRttUpgradeRequest(String callId, ParcelFileDescriptor fromInCall,
1096 ParcelFileDescriptor toInCall, Session.Info sessionInfo) throws RemoteException {
1097 Log.startSession(sessionInfo, SESSION_RTT_UPGRADE_RESPONSE);
1098 try {
1099 SomeArgs args = SomeArgs.obtain();
1100 args.arg1 = callId;
1101 if (toInCall == null || fromInCall == null) {
1102 args.arg2 = null;
1103 } else {
1104 args.arg2 = new Connection.RttTextStream(toInCall, fromInCall);
1105 }
1106 args.arg3 = Log.createSubsession();
1107 mHandler.obtainMessage(MSG_RTT_UPGRADE_RESPONSE, args).sendToTarget();
1108 } finally {
1109 Log.endSession();
1110 }
1111 }
Pengquan Meng731c1a32017-11-21 18:01:13 -08001112
1113 @Override
1114 public void connectionServiceFocusLost(Session.Info sessionInfo) throws RemoteException {
1115 Log.startSession(sessionInfo, SESSION_CONNECTION_SERVICE_FOCUS_LOST);
1116 try {
1117 mHandler.obtainMessage(MSG_CONNECTION_SERVICE_FOCUS_LOST).sendToTarget();
1118 } finally {
1119 Log.endSession();
1120 }
1121 }
1122
1123 @Override
1124 public void connectionServiceFocusGained(Session.Info sessionInfo) throws RemoteException {
1125 Log.startSession(sessionInfo, SESSION_CONNECTION_SERVICE_FOCUS_GAINED);
1126 try {
1127 mHandler.obtainMessage(MSG_CONNECTION_SERVICE_FOCUS_GAINED).sendToTarget();
1128 } finally {
1129 Log.endSession();
1130 }
1131 }
Sailesh Nepal2a46b902014-07-04 17:21:07 -07001132 };
1133
1134 private final Handler mHandler = new Handler(Looper.getMainLooper()) {
1135 @Override
1136 public void handleMessage(Message msg) {
1137 switch (msg.what) {
Brad Ebingerb32d4f82016-10-24 16:40:49 -07001138 case MSG_ADD_CONNECTION_SERVICE_ADAPTER: {
1139 SomeArgs args = (SomeArgs) msg.obj;
1140 try {
1141 IConnectionServiceAdapter adapter = (IConnectionServiceAdapter) args.arg1;
1142 Log.continueSession((Session) args.arg2,
1143 SESSION_HANDLER + SESSION_ADD_CS_ADAPTER);
1144 mAdapter.addAdapter(adapter);
1145 onAdapterAttached();
1146 } finally {
1147 args.recycle();
1148 Log.endSession();
1149 }
Sailesh Nepal2a46b902014-07-04 17:21:07 -07001150 break;
Brad Ebingerb32d4f82016-10-24 16:40:49 -07001151 }
1152 case MSG_REMOVE_CONNECTION_SERVICE_ADAPTER: {
1153 SomeArgs args = (SomeArgs) msg.obj;
1154 try {
1155 Log.continueSession((Session) args.arg2,
1156 SESSION_HANDLER + SESSION_REMOVE_CS_ADAPTER);
1157 mAdapter.removeAdapter((IConnectionServiceAdapter) args.arg1);
1158 } finally {
1159 args.recycle();
1160 Log.endSession();
1161 }
Ihab Awad8aecfed2014-08-08 17:06:11 -07001162 break;
Brad Ebingerb32d4f82016-10-24 16:40:49 -07001163 }
Ihab Awadf8b69882014-07-25 15:14:01 -07001164 case MSG_CREATE_CONNECTION: {
1165 SomeArgs args = (SomeArgs) msg.obj;
Brad Ebingerb32d4f82016-10-24 16:40:49 -07001166 Log.continueSession((Session) args.arg4, SESSION_HANDLER + SESSION_CREATE_CONN);
Ihab Awadf8b69882014-07-25 15:14:01 -07001167 try {
Ihab Awad5d0410f2014-07-30 10:07:40 -07001168 final PhoneAccountHandle connectionManagerPhoneAccount =
Ihab Awadf8b69882014-07-25 15:14:01 -07001169 (PhoneAccountHandle) args.arg1;
Ihab Awadb19a0bc2014-08-07 19:46:01 -07001170 final String id = (String) args.arg2;
1171 final ConnectionRequest request = (ConnectionRequest) args.arg3;
Ihab Awad5d0410f2014-07-30 10:07:40 -07001172 final boolean isIncoming = args.argi1 == 1;
Yorke Leec3cf9822014-10-02 09:38:39 -07001173 final boolean isUnknown = args.argi2 == 1;
Ihab Awad5d0410f2014-07-30 10:07:40 -07001174 if (!mAreAccountsInitialized) {
Ihab Awadb19a0bc2014-08-07 19:46:01 -07001175 Log.d(this, "Enqueueing pre-init request %s", id);
Brad Ebinger0c3541b2016-11-01 14:11:38 -07001176 mPreInitializationConnectionRequests.add(
1177 new android.telecom.Logging.Runnable(
1178 SESSION_HANDLER + SESSION_CREATE_CONN + ".pICR",
1179 null /*lock*/) {
Ihab Awad5d0410f2014-07-30 10:07:40 -07001180 @Override
Brad Ebinger0c3541b2016-11-01 14:11:38 -07001181 public void loggedRun() {
Ihab Awad5d0410f2014-07-30 10:07:40 -07001182 createConnection(
1183 connectionManagerPhoneAccount,
Ihab Awadb19a0bc2014-08-07 19:46:01 -07001184 id,
Ihab Awad5d0410f2014-07-30 10:07:40 -07001185 request,
Yorke Leec3cf9822014-10-02 09:38:39 -07001186 isIncoming,
1187 isUnknown);
Ihab Awad5d0410f2014-07-30 10:07:40 -07001188 }
Brad Ebinger0c3541b2016-11-01 14:11:38 -07001189 }.prepare());
Ihab Awad5d0410f2014-07-30 10:07:40 -07001190 } else {
Ihab Awadb19a0bc2014-08-07 19:46:01 -07001191 createConnection(
1192 connectionManagerPhoneAccount,
1193 id,
1194 request,
Yorke Leec3cf9822014-10-02 09:38:39 -07001195 isIncoming,
1196 isUnknown);
Ihab Awad5d0410f2014-07-30 10:07:40 -07001197 }
Ihab Awadf8b69882014-07-25 15:14:01 -07001198 } finally {
1199 args.recycle();
Brad Ebingerb32d4f82016-10-24 16:40:49 -07001200 Log.endSession();
Ihab Awadf8b69882014-07-25 15:14:01 -07001201 }
Sailesh Nepal2a46b902014-07-04 17:21:07 -07001202 break;
Ihab Awadf8b69882014-07-25 15:14:01 -07001203 }
Tyler Gunn041a1fe2017-05-12 10:04:49 -07001204 case MSG_CREATE_CONNECTION_COMPLETE: {
1205 SomeArgs args = (SomeArgs) msg.obj;
1206 Log.continueSession((Session) args.arg2,
1207 SESSION_HANDLER + SESSION_CREATE_CONN_COMPLETE);
1208 try {
1209 final String id = (String) args.arg1;
1210 if (!mAreAccountsInitialized) {
1211 Log.d(this, "Enqueueing pre-init request %s", id);
1212 mPreInitializationConnectionRequests.add(
1213 new android.telecom.Logging.Runnable(
1214 SESSION_HANDLER + SESSION_CREATE_CONN_COMPLETE
1215 + ".pICR",
1216 null /*lock*/) {
1217 @Override
1218 public void loggedRun() {
1219 notifyCreateConnectionComplete(id);
1220 }
1221 }.prepare());
1222 } else {
1223 notifyCreateConnectionComplete(id);
1224 }
1225 } finally {
1226 args.recycle();
1227 Log.endSession();
1228 }
1229 break;
1230 }
Tyler Gunn44e01912017-01-31 10:49:05 -08001231 case MSG_CREATE_CONNECTION_FAILED: {
1232 SomeArgs args = (SomeArgs) msg.obj;
1233 Log.continueSession((Session) args.arg3, SESSION_HANDLER +
1234 SESSION_CREATE_CONN_FAILED);
1235 try {
1236 final String id = (String) args.arg1;
1237 final ConnectionRequest request = (ConnectionRequest) args.arg2;
1238 final boolean isIncoming = args.argi1 == 1;
Tyler Gunn159f35c2017-03-02 09:28:37 -08001239 final PhoneAccountHandle connectionMgrPhoneAccount =
1240 (PhoneAccountHandle) args.arg4;
Tyler Gunn44e01912017-01-31 10:49:05 -08001241 if (!mAreAccountsInitialized) {
1242 Log.d(this, "Enqueueing pre-init request %s", id);
1243 mPreInitializationConnectionRequests.add(
1244 new android.telecom.Logging.Runnable(
1245 SESSION_HANDLER + SESSION_CREATE_CONN_FAILED + ".pICR",
1246 null /*lock*/) {
1247 @Override
1248 public void loggedRun() {
Tyler Gunn159f35c2017-03-02 09:28:37 -08001249 createConnectionFailed(connectionMgrPhoneAccount, id,
1250 request, isIncoming);
Tyler Gunn44e01912017-01-31 10:49:05 -08001251 }
1252 }.prepare());
1253 } else {
1254 Log.i(this, "createConnectionFailed %s", id);
Tyler Gunn159f35c2017-03-02 09:28:37 -08001255 createConnectionFailed(connectionMgrPhoneAccount, id, request,
1256 isIncoming);
Tyler Gunn44e01912017-01-31 10:49:05 -08001257 }
1258 } finally {
1259 args.recycle();
1260 Log.endSession();
1261 }
1262 break;
1263 }
Ravi Paluri80aa2142019-12-02 11:57:37 +05301264 case MSG_CREATE_CONFERENCE: {
1265 SomeArgs args = (SomeArgs) msg.obj;
1266 Log.continueSession((Session) args.arg4, SESSION_HANDLER + SESSION_CREATE_CONN);
1267 try {
1268 final PhoneAccountHandle connectionManagerPhoneAccount =
1269 (PhoneAccountHandle) args.arg1;
1270 final String id = (String) args.arg2;
1271 final ConnectionRequest request = (ConnectionRequest) args.arg3;
1272 final boolean isIncoming = args.argi1 == 1;
1273 final boolean isUnknown = args.argi2 == 1;
1274 if (!mAreAccountsInitialized) {
1275 Log.d(this, "Enqueueing pre-initconference request %s", id);
1276 mPreInitializationConnectionRequests.add(
1277 new android.telecom.Logging.Runnable(
1278 SESSION_HANDLER + SESSION_CREATE_CONF + ".pIConfR",
1279 null /*lock*/) {
1280 @Override
1281 public void loggedRun() {
1282 createConference(connectionManagerPhoneAccount,
1283 id,
1284 request,
1285 isIncoming,
1286 isUnknown);
1287 }
1288 }.prepare());
1289 } else {
1290 createConference(connectionManagerPhoneAccount,
1291 id,
1292 request,
1293 isIncoming,
1294 isUnknown);
1295 }
1296 } finally {
1297 args.recycle();
1298 Log.endSession();
1299 }
1300 break;
1301 }
1302 case MSG_CREATE_CONFERENCE_COMPLETE: {
1303 SomeArgs args = (SomeArgs) msg.obj;
1304 Log.continueSession((Session) args.arg2,
1305 SESSION_HANDLER + SESSION_CREATE_CONN_COMPLETE);
1306 try {
1307 final String id = (String) args.arg1;
1308 if (!mAreAccountsInitialized) {
1309 Log.d(this, "Enqueueing pre-init conference request %s", id);
1310 mPreInitializationConnectionRequests.add(
1311 new android.telecom.Logging.Runnable(
1312 SESSION_HANDLER + SESSION_CREATE_CONF_COMPLETE
1313 + ".pIConfR",
1314 null /*lock*/) {
1315 @Override
1316 public void loggedRun() {
1317 notifyCreateConferenceComplete(id);
1318 }
1319 }.prepare());
1320 } else {
1321 notifyCreateConferenceComplete(id);
1322 }
1323 } finally {
1324 args.recycle();
1325 Log.endSession();
1326 }
1327 break;
1328 }
1329 case MSG_CREATE_CONFERENCE_FAILED: {
1330 SomeArgs args = (SomeArgs) msg.obj;
1331 Log.continueSession((Session) args.arg3, SESSION_HANDLER +
1332 SESSION_CREATE_CONN_FAILED);
1333 try {
1334 final String id = (String) args.arg1;
1335 final ConnectionRequest request = (ConnectionRequest) args.arg2;
1336 final boolean isIncoming = args.argi1 == 1;
1337 final PhoneAccountHandle connectionMgrPhoneAccount =
1338 (PhoneAccountHandle) args.arg4;
1339 if (!mAreAccountsInitialized) {
1340 Log.d(this, "Enqueueing pre-init conference request %s", id);
1341 mPreInitializationConnectionRequests.add(
1342 new android.telecom.Logging.Runnable(
1343 SESSION_HANDLER + SESSION_CREATE_CONF_FAILED
1344 + ".pIConfR",
1345 null /*lock*/) {
1346 @Override
1347 public void loggedRun() {
1348 createConferenceFailed(connectionMgrPhoneAccount, id,
1349 request, isIncoming);
1350 }
1351 }.prepare());
1352 } else {
1353 Log.i(this, "createConferenceFailed %s", id);
1354 createConferenceFailed(connectionMgrPhoneAccount, id, request,
1355 isIncoming);
1356 }
1357 } finally {
1358 args.recycle();
1359 Log.endSession();
1360 }
1361 break;
1362 }
1363
Sanket Padawe4cc8ed52017-12-04 16:22:20 -08001364 case MSG_HANDOVER_FAILED: {
1365 SomeArgs args = (SomeArgs) msg.obj;
1366 Log.continueSession((Session) args.arg3, SESSION_HANDLER +
1367 SESSION_HANDOVER_FAILED);
1368 try {
1369 final String id = (String) args.arg1;
1370 final ConnectionRequest request = (ConnectionRequest) args.arg2;
1371 final int reason = (int) args.arg4;
1372 if (!mAreAccountsInitialized) {
1373 Log.d(this, "Enqueueing pre-init request %s", id);
1374 mPreInitializationConnectionRequests.add(
1375 new android.telecom.Logging.Runnable(
1376 SESSION_HANDLER
1377 + SESSION_HANDOVER_FAILED + ".pICR",
1378 null /*lock*/) {
1379 @Override
1380 public void loggedRun() {
1381 handoverFailed(id, request, reason);
1382 }
1383 }.prepare());
1384 } else {
1385 Log.i(this, "createConnectionFailed %s", id);
1386 handoverFailed(id, request, reason);
1387 }
1388 } finally {
1389 args.recycle();
1390 Log.endSession();
1391 }
1392 break;
1393 }
Brad Ebingerb32d4f82016-10-24 16:40:49 -07001394 case MSG_ABORT: {
1395 SomeArgs args = (SomeArgs) msg.obj;
1396 Log.continueSession((Session) args.arg2, SESSION_HANDLER + SESSION_ABORT);
1397 try {
1398 abort((String) args.arg1);
1399 } finally {
1400 args.recycle();
1401 Log.endSession();
1402 }
Sailesh Nepal2a46b902014-07-04 17:21:07 -07001403 break;
Brad Ebingerb32d4f82016-10-24 16:40:49 -07001404 }
1405 case MSG_ANSWER: {
1406 SomeArgs args = (SomeArgs) msg.obj;
1407 Log.continueSession((Session) args.arg2, SESSION_HANDLER + SESSION_ANSWER);
1408 try {
1409 answer((String) args.arg1);
1410 } finally {
1411 args.recycle();
1412 Log.endSession();
1413 }
Tyler Gunnbe74de02014-08-29 14:51:48 -07001414 break;
Brad Ebingerb32d4f82016-10-24 16:40:49 -07001415 }
Tyler Gunnbe74de02014-08-29 14:51:48 -07001416 case MSG_ANSWER_VIDEO: {
Andrew Lee8da4c3c2014-07-16 10:11:42 -07001417 SomeArgs args = (SomeArgs) msg.obj;
Brad Ebingerb32d4f82016-10-24 16:40:49 -07001418 Log.continueSession((Session) args.arg2,
1419 SESSION_HANDLER + SESSION_ANSWER_VIDEO);
Andrew Lee8da4c3c2014-07-16 10:11:42 -07001420 try {
1421 String callId = (String) args.arg1;
Evan Charltonbf11f982014-07-20 22:06:28 -07001422 int videoState = args.argi1;
Tyler Gunnbe74de02014-08-29 14:51:48 -07001423 answerVideo(callId, videoState);
Andrew Lee8da4c3c2014-07-16 10:11:42 -07001424 } finally {
1425 args.recycle();
Brad Ebingerb32d4f82016-10-24 16:40:49 -07001426 Log.endSession();
Andrew Lee8da4c3c2014-07-16 10:11:42 -07001427 }
Sailesh Nepal2a46b902014-07-04 17:21:07 -07001428 break;
Andrew Lee8da4c3c2014-07-16 10:11:42 -07001429 }
Pooja Jaind34698d2017-12-28 14:15:31 +05301430 case MSG_DEFLECT: {
1431 SomeArgs args = (SomeArgs) msg.obj;
1432 Log.continueSession((Session) args.arg3, SESSION_HANDLER + SESSION_DEFLECT);
1433 try {
1434 deflect((String) args.arg1, (Uri) args.arg2);
1435 } finally {
1436 args.recycle();
1437 Log.endSession();
1438 }
1439 break;
1440 }
Brad Ebingerb32d4f82016-10-24 16:40:49 -07001441 case MSG_REJECT: {
1442 SomeArgs args = (SomeArgs) msg.obj;
1443 Log.continueSession((Session) args.arg2, SESSION_HANDLER + SESSION_REJECT);
1444 try {
1445 reject((String) args.arg1);
1446 } finally {
1447 args.recycle();
1448 Log.endSession();
1449 }
Sailesh Nepal2a46b902014-07-04 17:21:07 -07001450 break;
Brad Ebingerb32d4f82016-10-24 16:40:49 -07001451 }
Tyler Gunnfacfdee2020-01-23 13:10:37 -08001452 case MSG_REJECT_WITH_REASON: {
1453 SomeArgs args = (SomeArgs) msg.obj;
1454 Log.continueSession((Session) args.arg2, SESSION_HANDLER + SESSION_REJECT);
1455 try {
1456 reject((String) args.arg1, args.argi1);
1457 } finally {
1458 args.recycle();
1459 Log.endSession();
1460 }
1461 break;
1462 }
Bryce Lee81901682015-08-28 16:38:02 -07001463 case MSG_REJECT_WITH_MESSAGE: {
1464 SomeArgs args = (SomeArgs) msg.obj;
Brad Ebingerb32d4f82016-10-24 16:40:49 -07001465 Log.continueSession((Session) args.arg3,
1466 SESSION_HANDLER + SESSION_REJECT_MESSAGE);
Bryce Lee81901682015-08-28 16:38:02 -07001467 try {
1468 reject((String) args.arg1, (String) args.arg2);
1469 } finally {
1470 args.recycle();
Brad Ebingerb32d4f82016-10-24 16:40:49 -07001471 Log.endSession();
Bryce Lee81901682015-08-28 16:38:02 -07001472 }
1473 break;
1474 }
Ravi Palurif4b38e72020-02-05 12:35:41 +05301475 case MSG_EXPLICIT_CALL_TRANSFER: {
1476 SomeArgs args = (SomeArgs) msg.obj;
1477 Log.continueSession((Session) args.arg3, SESSION_HANDLER + SESSION_TRANSFER);
1478 try {
1479 final boolean isConfirmationRequired = args.argi1 == 1;
1480 transfer((String) args.arg1, (Uri) args.arg2, isConfirmationRequired);
1481 } finally {
1482 args.recycle();
1483 Log.endSession();
1484 }
1485 break;
1486 }
1487 case MSG_EXPLICIT_CALL_TRANSFER_CONSULTATIVE: {
1488 SomeArgs args = (SomeArgs) msg.obj;
1489 Log.continueSession(
1490 (Session) args.arg3, SESSION_HANDLER + SESSION_CONSULTATIVE_TRANSFER);
1491 try {
1492 consultativeTransfer((String) args.arg1, (String) args.arg2);
1493 } finally {
1494 args.recycle();
1495 Log.endSession();
1496 }
1497 break;
1498 }
Brad Ebingerb32d4f82016-10-24 16:40:49 -07001499 case MSG_DISCONNECT: {
1500 SomeArgs args = (SomeArgs) msg.obj;
1501 Log.continueSession((Session) args.arg2, SESSION_HANDLER + SESSION_DISCONNECT);
1502 try {
1503 disconnect((String) args.arg1);
1504 } finally {
1505 args.recycle();
1506 Log.endSession();
1507 }
Sailesh Nepal2a46b902014-07-04 17:21:07 -07001508 break;
Brad Ebingerb32d4f82016-10-24 16:40:49 -07001509 }
1510 case MSG_SILENCE: {
1511 SomeArgs args = (SomeArgs) msg.obj;
1512 Log.continueSession((Session) args.arg2, SESSION_HANDLER + SESSION_SILENCE);
1513 try {
1514 silence((String) args.arg1);
1515 } finally {
1516 args.recycle();
1517 Log.endSession();
1518 }
Bryce Leecac50772015-11-17 15:13:29 -08001519 break;
Brad Ebingerb32d4f82016-10-24 16:40:49 -07001520 }
1521 case MSG_HOLD: {
1522 SomeArgs args = (SomeArgs) msg.obj;
1523 Log.continueSession((Session) args.arg2, SESSION_HANDLER + SESSION_REJECT);
1524 try {
1525 hold((String) args.arg1);
1526 } finally {
1527 args.recycle();
1528 Log.endSession();
1529 }
Sailesh Nepal2a46b902014-07-04 17:21:07 -07001530 break;
Brad Ebingerb32d4f82016-10-24 16:40:49 -07001531 }
1532 case MSG_UNHOLD: {
1533 SomeArgs args = (SomeArgs) msg.obj;
1534 Log.continueSession((Session) args.arg2, SESSION_HANDLER + SESSION_UNHOLD);
1535 try {
1536 unhold((String) args.arg1);
1537 } finally {
1538 args.recycle();
1539 Log.endSession();
1540 }
Sailesh Nepal2a46b902014-07-04 17:21:07 -07001541 break;
Brad Ebingerb32d4f82016-10-24 16:40:49 -07001542 }
Yorke Lee4af59352015-05-13 14:14:54 -07001543 case MSG_ON_CALL_AUDIO_STATE_CHANGED: {
Sailesh Nepal2a46b902014-07-04 17:21:07 -07001544 SomeArgs args = (SomeArgs) msg.obj;
Brad Ebingerb32d4f82016-10-24 16:40:49 -07001545 Log.continueSession((Session) args.arg3,
1546 SESSION_HANDLER + SESSION_CALL_AUDIO_SC);
Sailesh Nepal2a46b902014-07-04 17:21:07 -07001547 try {
1548 String callId = (String) args.arg1;
Yorke Lee4af59352015-05-13 14:14:54 -07001549 CallAudioState audioState = (CallAudioState) args.arg2;
1550 onCallAudioStateChanged(callId, new CallAudioState(audioState));
Sailesh Nepal2a46b902014-07-04 17:21:07 -07001551 } finally {
1552 args.recycle();
Brad Ebingerb32d4f82016-10-24 16:40:49 -07001553 Log.endSession();
Sailesh Nepal2a46b902014-07-04 17:21:07 -07001554 }
1555 break;
1556 }
Grace Jiae99fde92021-01-19 14:58:01 -08001557 case MSG_ON_USING_ALTERNATIVE_UI: {
1558 SomeArgs args = (SomeArgs) msg.obj;
1559 Log.continueSession((Session) args.arg3,
1560 SESSION_HANDLER + SESSION_USING_ALTERNATIVE_UI);
1561 try {
1562 String callId = (String) args.arg1;
1563 boolean isUsingAlternativeUi = (boolean) args.arg2;
1564 onUsingAlternativeUi(callId, isUsingAlternativeUi);
1565 } finally {
1566 args.recycle();
1567 Log.endSession();
1568 }
1569 break;
1570 }
1571 case MSG_ON_TRACKED_BY_NON_UI_SERVICE: {
1572 SomeArgs args = (SomeArgs) msg.obj;
1573 Log.continueSession((Session) args.arg3,
1574 SESSION_HANDLER + SESSION_TRACKED_BY_NON_UI_SERVICE);
1575 try {
1576 String callId = (String) args.arg1;
1577 boolean isTracked = (boolean) args.arg2;
1578 onTrackedByNonUiService(callId, isTracked);
1579 } finally {
1580 args.recycle();
1581 Log.endSession();
1582 }
1583 break;
1584 }
Brad Ebingerb32d4f82016-10-24 16:40:49 -07001585 case MSG_PLAY_DTMF_TONE: {
1586 SomeArgs args = (SomeArgs) msg.obj;
1587 try {
1588 Log.continueSession((Session) args.arg3,
1589 SESSION_HANDLER + SESSION_PLAY_DTMF);
1590 playDtmfTone((String) args.arg2, (char) args.arg1);
1591 } finally {
1592 args.recycle();
1593 Log.endSession();
1594 }
Sailesh Nepal2a46b902014-07-04 17:21:07 -07001595 break;
Brad Ebingerb32d4f82016-10-24 16:40:49 -07001596 }
1597 case MSG_STOP_DTMF_TONE: {
1598 SomeArgs args = (SomeArgs) msg.obj;
1599 try {
1600 Log.continueSession((Session) args.arg2,
1601 SESSION_HANDLER + SESSION_STOP_DTMF);
1602 stopDtmfTone((String) args.arg1);
1603 } finally {
1604 args.recycle();
1605 Log.endSession();
1606 }
Sailesh Nepal2a46b902014-07-04 17:21:07 -07001607 break;
Brad Ebingerb32d4f82016-10-24 16:40:49 -07001608 }
Sailesh Nepal2a46b902014-07-04 17:21:07 -07001609 case MSG_CONFERENCE: {
1610 SomeArgs args = (SomeArgs) msg.obj;
1611 try {
Brad Ebingerb32d4f82016-10-24 16:40:49 -07001612 Log.continueSession((Session) args.arg3,
1613 SESSION_HANDLER + SESSION_CONFERENCE);
Santos Cordon823fd3c2014-08-07 18:35:18 -07001614 String callId1 = (String) args.arg1;
1615 String callId2 = (String) args.arg2;
1616 conference(callId1, callId2);
Sailesh Nepal2a46b902014-07-04 17:21:07 -07001617 } finally {
1618 args.recycle();
Brad Ebingerb32d4f82016-10-24 16:40:49 -07001619 Log.endSession();
Sailesh Nepal2a46b902014-07-04 17:21:07 -07001620 }
1621 break;
1622 }
Brad Ebingerb32d4f82016-10-24 16:40:49 -07001623 case MSG_SPLIT_FROM_CONFERENCE: {
1624 SomeArgs args = (SomeArgs) msg.obj;
1625 try {
1626 Log.continueSession((Session) args.arg2,
1627 SESSION_HANDLER + SESSION_SPLIT_CONFERENCE);
1628 splitFromConference((String) args.arg1);
1629 } finally {
1630 args.recycle();
1631 Log.endSession();
1632 }
Sailesh Nepal2a46b902014-07-04 17:21:07 -07001633 break;
Brad Ebingerb32d4f82016-10-24 16:40:49 -07001634 }
1635 case MSG_MERGE_CONFERENCE: {
1636 SomeArgs args = (SomeArgs) msg.obj;
1637 try {
1638 Log.continueSession((Session) args.arg2,
1639 SESSION_HANDLER + SESSION_MERGE_CONFERENCE);
1640 mergeConference((String) args.arg1);
1641 } finally {
1642 args.recycle();
1643 Log.endSession();
1644 }
Santos Cordona4868042014-09-04 17:39:22 -07001645 break;
Brad Ebingerb32d4f82016-10-24 16:40:49 -07001646 }
1647 case MSG_SWAP_CONFERENCE: {
1648 SomeArgs args = (SomeArgs) msg.obj;
1649 try {
1650 Log.continueSession((Session) args.arg2,
1651 SESSION_HANDLER + SESSION_SWAP_CONFERENCE);
1652 swapConference((String) args.arg1);
1653 } finally {
1654 args.recycle();
1655 Log.endSession();
1656 }
Santos Cordona4868042014-09-04 17:39:22 -07001657 break;
Brad Ebingerb32d4f82016-10-24 16:40:49 -07001658 }
Ravi Paluri404babb2020-01-23 19:02:44 +05301659 case MSG_ADD_PARTICIPANT: {
1660 SomeArgs args = (SomeArgs) msg.obj;
1661 try {
1662 Log.continueSession((Session) args.arg3,
1663 SESSION_HANDLER + SESSION_ADD_PARTICIPANT);
1664 addConferenceParticipants((String) args.arg1, (List<Uri>)args.arg2);
1665 } finally {
1666 args.recycle();
1667 Log.endSession();
1668 }
1669 break;
1670 }
1671
Sailesh Nepal2a46b902014-07-04 17:21:07 -07001672 case MSG_ON_POST_DIAL_CONTINUE: {
1673 SomeArgs args = (SomeArgs) msg.obj;
1674 try {
Brad Ebingerb32d4f82016-10-24 16:40:49 -07001675 Log.continueSession((Session) args.arg2,
1676 SESSION_HANDLER + SESSION_POST_DIAL_CONT);
Sailesh Nepal2a46b902014-07-04 17:21:07 -07001677 String callId = (String) args.arg1;
1678 boolean proceed = (args.argi1 == 1);
1679 onPostDialContinue(callId, proceed);
1680 } finally {
1681 args.recycle();
Brad Ebingerb32d4f82016-10-24 16:40:49 -07001682 Log.endSession();
Sailesh Nepal2a46b902014-07-04 17:21:07 -07001683 }
1684 break;
1685 }
Tyler Gunn876dbfb2016-03-14 15:18:07 -07001686 case MSG_PULL_EXTERNAL_CALL: {
Brad Ebingerb32d4f82016-10-24 16:40:49 -07001687 SomeArgs args = (SomeArgs) msg.obj;
1688 try {
1689 Log.continueSession((Session) args.arg2,
1690 SESSION_HANDLER + SESSION_PULL_EXTERNAL_CALL);
1691 pullExternalCall((String) args.arg1);
1692 } finally {
1693 args.recycle();
1694 Log.endSession();
1695 }
Tyler Gunn876dbfb2016-03-14 15:18:07 -07001696 break;
1697 }
1698 case MSG_SEND_CALL_EVENT: {
1699 SomeArgs args = (SomeArgs) msg.obj;
1700 try {
Brad Ebingerb32d4f82016-10-24 16:40:49 -07001701 Log.continueSession((Session) args.arg4,
1702 SESSION_HANDLER + SESSION_SEND_CALL_EVENT);
Tyler Gunn876dbfb2016-03-14 15:18:07 -07001703 String callId = (String) args.arg1;
1704 String event = (String) args.arg2;
1705 Bundle extras = (Bundle) args.arg3;
1706 sendCallEvent(callId, event, extras);
1707 } finally {
1708 args.recycle();
Brad Ebingerb32d4f82016-10-24 16:40:49 -07001709 Log.endSession();
Tyler Gunn876dbfb2016-03-14 15:18:07 -07001710 }
1711 break;
1712 }
Hall Liu49cabcc2021-01-15 11:41:48 -08001713 case MSG_ON_CALL_FILTERING_COMPLETED: {
1714 SomeArgs args = (SomeArgs) msg.obj;
1715 try {
Hall Liu73903142021-02-18 18:41:41 -08001716 Log.continueSession((Session) args.arg3,
Hall Liu49cabcc2021-01-15 11:41:48 -08001717 SESSION_HANDLER + SESSION_CALL_FILTERING_COMPLETED);
1718 String callId = (String) args.arg1;
Hall Liu73903142021-02-18 18:41:41 -08001719 Connection.CallFilteringCompletionInfo completionInfo =
1720 (Connection.CallFilteringCompletionInfo) args.arg2;
1721 onCallFilteringCompleted(callId, completionInfo);
Hall Liu49cabcc2021-01-15 11:41:48 -08001722 } finally {
1723 args.recycle();
1724 Log.endSession();
1725 }
1726 break;
1727 }
Tyler Gunn79bc1ec2018-01-22 15:17:54 -08001728 case MSG_HANDOVER_COMPLETE: {
1729 SomeArgs args = (SomeArgs) msg.obj;
1730 try {
1731 Log.continueSession((Session) args.arg2,
1732 SESSION_HANDLER + SESSION_HANDOVER_COMPLETE);
1733 String callId = (String) args.arg1;
1734 notifyHandoverComplete(callId);
1735 } finally {
1736 args.recycle();
1737 Log.endSession();
1738 }
1739 break;
1740 }
Tyler Gunndee56a82016-03-23 16:06:34 -07001741 case MSG_ON_EXTRAS_CHANGED: {
1742 SomeArgs args = (SomeArgs) msg.obj;
1743 try {
Brad Ebingerb32d4f82016-10-24 16:40:49 -07001744 Log.continueSession((Session) args.arg3,
1745 SESSION_HANDLER + SESSION_EXTRAS_CHANGED);
Tyler Gunndee56a82016-03-23 16:06:34 -07001746 String callId = (String) args.arg1;
1747 Bundle extras = (Bundle) args.arg2;
1748 handleExtrasChanged(callId, extras);
1749 } finally {
1750 args.recycle();
Brad Ebingerb32d4f82016-10-24 16:40:49 -07001751 Log.endSession();
Tyler Gunndee56a82016-03-23 16:06:34 -07001752 }
1753 break;
1754 }
Hall Liub64ac4c2017-02-06 10:49:48 -08001755 case MSG_ON_START_RTT: {
1756 SomeArgs args = (SomeArgs) msg.obj;
1757 try {
1758 Log.continueSession((Session) args.arg3,
1759 SESSION_HANDLER + SESSION_START_RTT);
1760 String callId = (String) args.arg1;
1761 Connection.RttTextStream rttTextStream =
1762 (Connection.RttTextStream) args.arg2;
1763 startRtt(callId, rttTextStream);
1764 } finally {
1765 args.recycle();
1766 Log.endSession();
1767 }
1768 break;
1769 }
1770 case MSG_ON_STOP_RTT: {
1771 SomeArgs args = (SomeArgs) msg.obj;
1772 try {
1773 Log.continueSession((Session) args.arg2,
1774 SESSION_HANDLER + SESSION_STOP_RTT);
1775 String callId = (String) args.arg1;
1776 stopRtt(callId);
1777 } finally {
1778 args.recycle();
1779 Log.endSession();
1780 }
1781 break;
1782 }
1783 case MSG_RTT_UPGRADE_RESPONSE: {
1784 SomeArgs args = (SomeArgs) msg.obj;
1785 try {
1786 Log.continueSession((Session) args.arg3,
1787 SESSION_HANDLER + SESSION_RTT_UPGRADE_RESPONSE);
1788 String callId = (String) args.arg1;
1789 Connection.RttTextStream rttTextStream =
1790 (Connection.RttTextStream) args.arg2;
1791 handleRttUpgradeResponse(callId, rttTextStream);
1792 } finally {
1793 args.recycle();
1794 Log.endSession();
1795 }
1796 break;
1797 }
Pengquan Meng731c1a32017-11-21 18:01:13 -08001798 case MSG_CONNECTION_SERVICE_FOCUS_GAINED:
1799 onConnectionServiceFocusGained();
1800 break;
1801 case MSG_CONNECTION_SERVICE_FOCUS_LOST:
1802 onConnectionServiceFocusLost();
1803 break;
Junhoedf3d822022-11-24 09:26:37 +00001804 case MSG_ON_CALL_ENDPOINT_CHANGED: {
1805 SomeArgs args = (SomeArgs) msg.obj;
1806 Log.continueSession((Session) args.arg3,
1807 SESSION_HANDLER + SESSION_CALL_AUDIO_SC);
1808 try {
1809 String callId = (String) args.arg1;
1810 CallEndpoint callEndpoint = (CallEndpoint) args.arg2;
1811 onCallEndpointChanged(callId, callEndpoint);
1812 } finally {
1813 args.recycle();
1814 Log.endSession();
1815 }
1816 break;
1817 }
1818 case MSG_ON_AVAILABLE_CALL_ENDPOINTS_CHANGED: {
1819 SomeArgs args = (SomeArgs) msg.obj;
1820 Log.continueSession((Session) args.arg3,
1821 SESSION_HANDLER + SESSION_CALL_AUDIO_SC);
1822 try {
1823 String callId = (String) args.arg1;
1824 List<CallEndpoint> availableCallEndpoints = (List<CallEndpoint>) args.arg2;
1825 onAvailableCallEndpointsChanged(callId, availableCallEndpoints);
1826 } finally {
1827 args.recycle();
1828 Log.endSession();
1829 }
1830 break;
1831 }
1832 case MSG_ON_MUTE_STATE_CHANGED: {
1833 SomeArgs args = (SomeArgs) msg.obj;
1834 Log.continueSession((Session) args.arg3,
1835 SESSION_HANDLER + SESSION_CALL_AUDIO_SC);
1836 try {
1837 String callId = (String) args.arg1;
1838 boolean isMuted = (boolean) args.arg2;
1839 onMuteStateChanged(callId, isMuted);
1840 } finally {
1841 args.recycle();
1842 Log.endSession();
1843 }
1844 break;
1845 }
Sailesh Nepal2a46b902014-07-04 17:21:07 -07001846 default:
1847 break;
1848 }
1849 }
1850 };
1851
Santos Cordon823fd3c2014-08-07 18:35:18 -07001852 private final Conference.Listener mConferenceListener = new Conference.Listener() {
1853 @Override
1854 public void onStateChanged(Conference conference, int oldState, int newState) {
1855 String id = mIdByConference.get(conference);
1856 switch (newState) {
Ravi Paluri80aa2142019-12-02 11:57:37 +05301857 case Connection.STATE_RINGING:
1858 mAdapter.setRinging(id);
1859 break;
1860 case Connection.STATE_DIALING:
1861 mAdapter.setDialing(id);
1862 break;
Santos Cordon823fd3c2014-08-07 18:35:18 -07001863 case Connection.STATE_ACTIVE:
1864 mAdapter.setActive(id);
1865 break;
1866 case Connection.STATE_HOLDING:
1867 mAdapter.setOnHold(id);
1868 break;
1869 case Connection.STATE_DISCONNECTED:
1870 // handled by onDisconnected
1871 break;
1872 }
1873 }
1874
1875 @Override
Andrew Lee7f3d41f2014-09-11 17:33:16 -07001876 public void onDisconnected(Conference conference, DisconnectCause disconnectCause) {
Santos Cordon823fd3c2014-08-07 18:35:18 -07001877 String id = mIdByConference.get(conference);
Andrew Lee7f3d41f2014-09-11 17:33:16 -07001878 mAdapter.setDisconnected(id, disconnectCause);
Santos Cordon823fd3c2014-08-07 18:35:18 -07001879 }
1880
1881 @Override
1882 public void onConnectionAdded(Conference conference, Connection connection) {
1883 }
1884
1885 @Override
1886 public void onConnectionRemoved(Conference conference, Connection connection) {
1887 }
1888
1889 @Override
Ihab Awad50e35062014-09-30 09:17:03 -07001890 public void onConferenceableConnectionsChanged(
1891 Conference conference, List<Connection> conferenceableConnections) {
1892 mAdapter.setConferenceableConnections(
1893 mIdByConference.get(conference),
1894 createConnectionIdList(conferenceableConnections));
1895 }
1896
1897 @Override
Santos Cordon823fd3c2014-08-07 18:35:18 -07001898 public void onDestroyed(Conference conference) {
1899 removeConference(conference);
1900 }
1901
1902 @Override
Ihab Awad5c9c86e2014-11-12 13:41:16 -08001903 public void onConnectionCapabilitiesChanged(
1904 Conference conference,
1905 int connectionCapabilities) {
Santos Cordon823fd3c2014-08-07 18:35:18 -07001906 String id = mIdByConference.get(conference);
1907 Log.d(this, "call capabilities: conference: %s",
Ihab Awad5c9c86e2014-11-12 13:41:16 -08001908 Connection.capabilitiesToString(connectionCapabilities));
1909 mAdapter.setConnectionCapabilities(id, connectionCapabilities);
Santos Cordon823fd3c2014-08-07 18:35:18 -07001910 }
Rekha Kumar07366812015-03-24 16:42:31 -07001911
1912 @Override
Tyler Gunn720c6642016-03-22 09:02:47 -07001913 public void onConnectionPropertiesChanged(
1914 Conference conference,
1915 int connectionProperties) {
1916 String id = mIdByConference.get(conference);
1917 Log.d(this, "call capabilities: conference: %s",
1918 Connection.propertiesToString(connectionProperties));
1919 mAdapter.setConnectionProperties(id, connectionProperties);
1920 }
1921
1922 @Override
Rekha Kumar07366812015-03-24 16:42:31 -07001923 public void onVideoStateChanged(Conference c, int videoState) {
1924 String id = mIdByConference.get(c);
1925 Log.d(this, "onVideoStateChanged set video state %d", videoState);
1926 mAdapter.setVideoState(id, videoState);
1927 }
1928
1929 @Override
1930 public void onVideoProviderChanged(Conference c, Connection.VideoProvider videoProvider) {
1931 String id = mIdByConference.get(c);
1932 Log.d(this, "onVideoProviderChanged: Connection: %s, VideoProvider: %s", c,
1933 videoProvider);
1934 mAdapter.setVideoProvider(id, videoProvider);
1935 }
Andrew Lee0f51da32015-04-16 13:11:55 -07001936
1937 @Override
Andrew Leeedc625f2015-04-14 13:38:12 -07001938 public void onStatusHintsChanged(Conference conference, StatusHints statusHints) {
1939 String id = mIdByConference.get(conference);
Tyler Gunndee56a82016-03-23 16:06:34 -07001940 if (id != null) {
1941 mAdapter.setStatusHints(id, statusHints);
1942 }
Andrew Leeedc625f2015-04-14 13:38:12 -07001943 }
Santos Cordon6b7f9552015-05-27 17:21:45 -07001944
1945 @Override
Tyler Gunndee56a82016-03-23 16:06:34 -07001946 public void onExtrasChanged(Conference c, Bundle extras) {
1947 String id = mIdByConference.get(c);
1948 if (id != null) {
1949 mAdapter.putExtras(id, extras);
1950 }
1951 }
1952
1953 @Override
1954 public void onExtrasRemoved(Conference c, List<String> keys) {
1955 String id = mIdByConference.get(c);
1956 if (id != null) {
1957 mAdapter.removeExtras(id, keys);
1958 }
Santos Cordon6b7f9552015-05-27 17:21:45 -07001959 }
Tyler Gunn68a73a42018-10-03 15:38:57 -07001960
1961 @Override
1962 public void onConferenceStateChanged(Conference c, boolean isConference) {
1963 String id = mIdByConference.get(c);
1964 if (id != null) {
1965 mAdapter.setConferenceState(id, isConference);
1966 }
1967 }
1968
1969 @Override
Brad Ebingere0c12f42020-04-08 16:25:12 -07001970 public void onCallDirectionChanged(Conference c, int direction) {
1971 String id = mIdByConference.get(c);
1972 if (id != null) {
1973 mAdapter.setCallDirection(id, direction);
1974 }
1975 }
1976
1977 @Override
Tyler Gunn68a73a42018-10-03 15:38:57 -07001978 public void onAddressChanged(Conference c, Uri newAddress, int presentation) {
1979 String id = mIdByConference.get(c);
1980 if (id != null) {
1981 mAdapter.setAddress(id, newAddress, presentation);
1982 }
1983 }
1984
1985 @Override
1986 public void onCallerDisplayNameChanged(Conference c, String callerDisplayName,
1987 int presentation) {
1988 String id = mIdByConference.get(c);
1989 if (id != null) {
1990 mAdapter.setCallerDisplayName(id, callerDisplayName, presentation);
1991 }
1992 }
Hall Liuc9bc1c62019-04-16 14:00:55 -07001993
1994 @Override
1995 public void onConnectionEvent(Conference c, String event, Bundle extras) {
1996 String id = mIdByConference.get(c);
1997 if (id != null) {
1998 mAdapter.onConnectionEvent(id, event, extras);
1999 }
2000 }
Ravi Paluri80aa2142019-12-02 11:57:37 +05302001
2002 @Override
2003 public void onRingbackRequested(Conference c, boolean ringback) {
2004 String id = mIdByConference.get(c);
2005 Log.d(this, "Adapter conference onRingback %b", ringback);
2006 mAdapter.setRingbackRequested(id, ringback);
2007 }
Santos Cordon823fd3c2014-08-07 18:35:18 -07002008 };
2009
Ihab Awad542e0ea2014-05-16 10:22:16 -07002010 private final Connection.Listener mConnectionListener = new Connection.Listener() {
2011 @Override
2012 public void onStateChanged(Connection c, int state) {
2013 String id = mIdByConnection.get(c);
Ihab Awad42b30e12014-05-22 09:49:34 -07002014 Log.d(this, "Adapter set state %s %s", id, Connection.stateToString(state));
Ihab Awad542e0ea2014-05-16 10:22:16 -07002015 switch (state) {
Ihab Awadb19a0bc2014-08-07 19:46:01 -07002016 case Connection.STATE_ACTIVE:
Sailesh Nepal2a46b902014-07-04 17:21:07 -07002017 mAdapter.setActive(id);
Ihab Awad542e0ea2014-05-16 10:22:16 -07002018 break;
Ihab Awadb19a0bc2014-08-07 19:46:01 -07002019 case Connection.STATE_DIALING:
Sailesh Nepal2a46b902014-07-04 17:21:07 -07002020 mAdapter.setDialing(id);
Ihab Awad542e0ea2014-05-16 10:22:16 -07002021 break;
Tyler Gunnc96b5e02016-07-07 22:53:57 -07002022 case Connection.STATE_PULLING_CALL:
2023 mAdapter.setPulling(id);
2024 break;
Ihab Awadb19a0bc2014-08-07 19:46:01 -07002025 case Connection.STATE_DISCONNECTED:
Ihab Awad542e0ea2014-05-16 10:22:16 -07002026 // Handled in onDisconnected()
2027 break;
Ihab Awadb19a0bc2014-08-07 19:46:01 -07002028 case Connection.STATE_HOLDING:
Sailesh Nepal2a46b902014-07-04 17:21:07 -07002029 mAdapter.setOnHold(id);
Ihab Awad542e0ea2014-05-16 10:22:16 -07002030 break;
Ihab Awadb19a0bc2014-08-07 19:46:01 -07002031 case Connection.STATE_NEW:
Tyler Gunnef9f6f92014-09-12 22:16:17 -07002032 // Nothing to tell Telecom
Ihab Awad542e0ea2014-05-16 10:22:16 -07002033 break;
Ihab Awadb19a0bc2014-08-07 19:46:01 -07002034 case Connection.STATE_RINGING:
Sailesh Nepal2a46b902014-07-04 17:21:07 -07002035 mAdapter.setRinging(id);
Ihab Awad542e0ea2014-05-16 10:22:16 -07002036 break;
2037 }
2038 }
2039
2040 @Override
Andrew Lee7f3d41f2014-09-11 17:33:16 -07002041 public void onDisconnected(Connection c, DisconnectCause disconnectCause) {
Ihab Awad542e0ea2014-05-16 10:22:16 -07002042 String id = mIdByConnection.get(c);
Andrew Lee26786392014-09-16 18:14:59 -07002043 Log.d(this, "Adapter set disconnected %s", disconnectCause);
Andrew Lee7f3d41f2014-09-11 17:33:16 -07002044 mAdapter.setDisconnected(id, disconnectCause);
Ihab Awad542e0ea2014-05-16 10:22:16 -07002045 }
2046
2047 @Override
Tyler Gunnaa07df82014-07-17 07:50:22 -07002048 public void onVideoStateChanged(Connection c, int videoState) {
2049 String id = mIdByConnection.get(c);
2050 Log.d(this, "Adapter set video state %d", videoState);
2051 mAdapter.setVideoState(id, videoState);
2052 }
2053
2054 @Override
Andrew Lee100e2932014-09-08 15:34:24 -07002055 public void onAddressChanged(Connection c, Uri address, int presentation) {
Sailesh Nepal61203862014-07-11 14:50:13 -07002056 String id = mIdByConnection.get(c);
Andrew Lee100e2932014-09-08 15:34:24 -07002057 mAdapter.setAddress(id, address, presentation);
Sailesh Nepal61203862014-07-11 14:50:13 -07002058 }
2059
2060 @Override
2061 public void onCallerDisplayNameChanged(
2062 Connection c, String callerDisplayName, int presentation) {
2063 String id = mIdByConnection.get(c);
2064 mAdapter.setCallerDisplayName(id, callerDisplayName, presentation);
Ihab Awad542e0ea2014-05-16 10:22:16 -07002065 }
2066
2067 @Override
Ihab Awad542e0ea2014-05-16 10:22:16 -07002068 public void onDestroyed(Connection c) {
2069 removeConnection(c);
2070 }
Ihab Awadf8358972014-05-28 16:46:42 -07002071
2072 @Override
Sailesh Nepal2a46b902014-07-04 17:21:07 -07002073 public void onPostDialWait(Connection c, String remaining) {
Sailesh Nepal091768c2014-06-30 15:15:23 -07002074 String id = mIdByConnection.get(c);
2075 Log.d(this, "Adapter onPostDialWait %s, %s", c, remaining);
Sailesh Nepal2a46b902014-07-04 17:21:07 -07002076 mAdapter.onPostDialWait(id, remaining);
Sailesh Nepal091768c2014-06-30 15:15:23 -07002077 }
2078
2079 @Override
Nancy Chen27d1c2d2014-12-15 16:12:50 -08002080 public void onPostDialChar(Connection c, char nextChar) {
2081 String id = mIdByConnection.get(c);
2082 Log.d(this, "Adapter onPostDialChar %s, %s", c, nextChar);
2083 mAdapter.onPostDialChar(id, nextChar);
2084 }
2085
2086 @Override
Andrew Lee100e2932014-09-08 15:34:24 -07002087 public void onRingbackRequested(Connection c, boolean ringback) {
Ihab Awadf8358972014-05-28 16:46:42 -07002088 String id = mIdByConnection.get(c);
2089 Log.d(this, "Adapter onRingback %b", ringback);
Andrew Lee100e2932014-09-08 15:34:24 -07002090 mAdapter.setRingbackRequested(id, ringback);
Ihab Awadf8358972014-05-28 16:46:42 -07002091 }
Santos Cordonb6939982014-06-04 20:20:58 -07002092
2093 @Override
Ihab Awad5c9c86e2014-11-12 13:41:16 -08002094 public void onConnectionCapabilitiesChanged(Connection c, int capabilities) {
Santos Cordonb6939982014-06-04 20:20:58 -07002095 String id = mIdByConnection.get(c);
Ihab Awadb19a0bc2014-08-07 19:46:01 -07002096 Log.d(this, "capabilities: parcelableconnection: %s",
Ihab Awad5c9c86e2014-11-12 13:41:16 -08002097 Connection.capabilitiesToString(capabilities));
2098 mAdapter.setConnectionCapabilities(id, capabilities);
Santos Cordonb6939982014-06-04 20:20:58 -07002099 }
2100
Santos Cordonb6939982014-06-04 20:20:58 -07002101 @Override
Tyler Gunn720c6642016-03-22 09:02:47 -07002102 public void onConnectionPropertiesChanged(Connection c, int properties) {
2103 String id = mIdByConnection.get(c);
2104 Log.d(this, "properties: parcelableconnection: %s",
2105 Connection.propertiesToString(properties));
2106 mAdapter.setConnectionProperties(id, properties);
2107 }
2108
2109 @Override
Ihab Awadb19a0bc2014-08-07 19:46:01 -07002110 public void onVideoProviderChanged(Connection c, Connection.VideoProvider videoProvider) {
Andrew Lee5ffbe8b82014-06-20 16:29:33 -07002111 String id = mIdByConnection.get(c);
Rekha Kumar07366812015-03-24 16:42:31 -07002112 Log.d(this, "onVideoProviderChanged: Connection: %s, VideoProvider: %s", c,
2113 videoProvider);
Ihab Awadb19a0bc2014-08-07 19:46:01 -07002114 mAdapter.setVideoProvider(id, videoProvider);
Andrew Lee5ffbe8b82014-06-20 16:29:33 -07002115 }
Sailesh Nepal33aaae42014-07-07 22:49:44 -07002116
2117 @Override
Sailesh Nepal001bbbb2014-07-15 14:40:39 -07002118 public void onAudioModeIsVoipChanged(Connection c, boolean isVoip) {
Sailesh Nepal33aaae42014-07-07 22:49:44 -07002119 String id = mIdByConnection.get(c);
Andrew Lee100e2932014-09-08 15:34:24 -07002120 mAdapter.setIsVoipAudioMode(id, isVoip);
Sailesh Nepal33aaae42014-07-07 22:49:44 -07002121 }
Sailesh Nepale7ef59a2014-07-08 21:48:22 -07002122
2123 @Override
Sailesh Nepal001bbbb2014-07-15 14:40:39 -07002124 public void onStatusHintsChanged(Connection c, StatusHints statusHints) {
Sailesh Nepale7ef59a2014-07-08 21:48:22 -07002125 String id = mIdByConnection.get(c);
2126 mAdapter.setStatusHints(id, statusHints);
2127 }
Sailesh Nepal2ab88cc2014-07-18 14:49:18 -07002128
2129 @Override
Tyler Gunn6d76ca02014-11-17 15:49:51 -08002130 public void onConferenceablesChanged(
Tyler Gunndf2cbc82015-04-20 09:13:01 -07002131 Connection connection, List<Conferenceable> conferenceables) {
Ihab Awadb8e85c72014-08-23 20:34:57 -07002132 mAdapter.setConferenceableConnections(
2133 mIdByConnection.get(connection),
Tyler Gunn6d76ca02014-11-17 15:49:51 -08002134 createIdList(conferenceables));
Santos Cordon7c7bc7f2014-07-28 18:15:48 -07002135 }
Santos Cordon823fd3c2014-08-07 18:35:18 -07002136
2137 @Override
2138 public void onConferenceChanged(Connection connection, Conference conference) {
2139 String id = mIdByConnection.get(connection);
2140 if (id != null) {
2141 String conferenceId = null;
2142 if (conference != null) {
2143 conferenceId = mIdByConference.get(conference);
2144 }
2145 mAdapter.setIsConferenced(id, conferenceId);
2146 }
2147 }
Anthony Lee17455a32015-04-24 15:25:29 -07002148
2149 @Override
2150 public void onConferenceMergeFailed(Connection connection) {
2151 String id = mIdByConnection.get(connection);
2152 if (id != null) {
2153 mAdapter.onConferenceMergeFailed(id);
2154 }
2155 }
Santos Cordon6b7f9552015-05-27 17:21:45 -07002156
2157 @Override
Tyler Gunndee56a82016-03-23 16:06:34 -07002158 public void onExtrasChanged(Connection c, Bundle extras) {
2159 String id = mIdByConnection.get(c);
Santos Cordon6b7f9552015-05-27 17:21:45 -07002160 if (id != null) {
Tyler Gunndee56a82016-03-23 16:06:34 -07002161 mAdapter.putExtras(id, extras);
Santos Cordon6b7f9552015-05-27 17:21:45 -07002162 }
2163 }
Brad Ebingerb32d4f82016-10-24 16:40:49 -07002164
Tyler Gunnf5035432017-01-09 09:43:12 -08002165 @Override
Tyler Gunndee56a82016-03-23 16:06:34 -07002166 public void onExtrasRemoved(Connection c, List<String> keys) {
2167 String id = mIdByConnection.get(c);
2168 if (id != null) {
2169 mAdapter.removeExtras(id, keys);
2170 }
2171 }
2172
Tyler Gunnbd1eb1f2016-02-16 14:36:20 -08002173 @Override
Tyler Gunn876dbfb2016-03-14 15:18:07 -07002174 public void onConnectionEvent(Connection connection, String event, Bundle extras) {
Tyler Gunnbd1eb1f2016-02-16 14:36:20 -08002175 String id = mIdByConnection.get(connection);
2176 if (id != null) {
Tyler Gunn876dbfb2016-03-14 15:18:07 -07002177 mAdapter.onConnectionEvent(id, event, extras);
Tyler Gunnbd1eb1f2016-02-16 14:36:20 -08002178 }
2179 }
Tyler Gunnf5035432017-01-09 09:43:12 -08002180
2181 @Override
Hall Liua98f58b52017-11-07 17:59:28 -08002182 public void onAudioRouteChanged(Connection c, int audioRoute, String bluetoothAddress) {
Tyler Gunnf5035432017-01-09 09:43:12 -08002183 String id = mIdByConnection.get(c);
2184 if (id != null) {
Hall Liua98f58b52017-11-07 17:59:28 -08002185 mAdapter.setAudioRoute(id, audioRoute, bluetoothAddress);
Tyler Gunnf5035432017-01-09 09:43:12 -08002186 }
2187 }
Hall Liub64ac4c2017-02-06 10:49:48 -08002188
2189 @Override
2190 public void onRttInitiationSuccess(Connection c) {
2191 String id = mIdByConnection.get(c);
2192 if (id != null) {
2193 mAdapter.onRttInitiationSuccess(id);
2194 }
2195 }
2196
2197 @Override
2198 public void onRttInitiationFailure(Connection c, int reason) {
2199 String id = mIdByConnection.get(c);
2200 if (id != null) {
2201 mAdapter.onRttInitiationFailure(id, reason);
2202 }
2203 }
2204
2205 @Override
2206 public void onRttSessionRemotelyTerminated(Connection c) {
2207 String id = mIdByConnection.get(c);
2208 if (id != null) {
2209 mAdapter.onRttSessionRemotelyTerminated(id);
2210 }
2211 }
2212
2213 @Override
2214 public void onRemoteRttRequest(Connection c) {
2215 String id = mIdByConnection.get(c);
2216 if (id != null) {
2217 mAdapter.onRemoteRttRequest(id);
2218 }
2219 }
Srikanth Chintalafcb15012017-05-04 20:58:34 +05302220
2221 @Override
2222 public void onPhoneAccountChanged(Connection c, PhoneAccountHandle pHandle) {
2223 String id = mIdByConnection.get(c);
2224 if (id != null) {
2225 mAdapter.onPhoneAccountChanged(id, pHandle);
2226 }
2227 }
Mengjun Leng25707742017-07-04 11:10:37 +08002228
2229 public void onConnectionTimeReset(Connection c) {
2230 String id = mIdByConnection.get(c);
2231 if (id != null) {
2232 mAdapter.resetConnectionTime(id);
2233 }
2234 }
Junhoedf3d822022-11-24 09:26:37 +00002235
2236 @Override
2237 public void onEndpointChanged(Connection c, CallEndpoint endpoint, Executor executor,
2238 OutcomeReceiver<Void, CallEndpointException> callback) {
2239 String id = mIdByConnection.get(c);
2240 if (id != null) {
2241 mAdapter.requestCallEndpointChange(id, endpoint, executor, callback);
2242 }
2243 }
Ihab Awad542e0ea2014-05-16 10:22:16 -07002244 };
2245
Sailesh Nepal2a46b902014-07-04 17:21:07 -07002246 /** {@inheritDoc} */
Ihab Awad542e0ea2014-05-16 10:22:16 -07002247 @Override
Sailesh Nepal2a46b902014-07-04 17:21:07 -07002248 public final IBinder onBind(Intent intent) {
Hall Liueb7c9ea2021-03-09 20:24:50 -08002249 onBindClient(intent);
Sailesh Nepal2a46b902014-07-04 17:21:07 -07002250 return mBinder;
2251 }
2252
Santos Cordon29f2f2e2014-09-11 19:50:24 -07002253 /** {@inheritDoc} */
2254 @Override
2255 public boolean onUnbind(Intent intent) {
2256 endAllConnections();
2257 return super.onUnbind(intent);
2258 }
2259
Hall Liueb7c9ea2021-03-09 20:24:50 -08002260 /**
2261 * Used for testing to let the test suite know when the connection service has been bound.
2262 * @hide
2263 */
2264 @TestApi
2265 public void onBindClient(@Nullable Intent intent) {
2266 }
Ravi Paluri80aa2142019-12-02 11:57:37 +05302267
2268 /**
2269 * This can be used by telecom to either create a new outgoing conference call or attach
2270 * to an existing incoming conference call. In either case, telecom will cycle through a
2271 * set of services and call createConference until a connection service cancels the process
2272 * or completes it successfully.
2273 */
2274 private void createConference(
2275 final PhoneAccountHandle callManagerAccount,
2276 final String callId,
2277 final ConnectionRequest request,
2278 boolean isIncoming,
2279 boolean isUnknown) {
2280
2281 Conference conference = null;
2282 conference = isIncoming ? onCreateIncomingConference(callManagerAccount, request)
2283 : onCreateOutgoingConference(callManagerAccount, request);
2284
2285 Log.d(this, "createConference, conference: %s", conference);
2286 if (conference == null) {
2287 Log.i(this, "createConference, implementation returned null conference.");
2288 conference = Conference.createFailedConference(
2289 new DisconnectCause(DisconnectCause.ERROR, "IMPL_RETURNED_NULL_CONFERENCE"),
2290 request.getAccountHandle());
2291 }
Tyler Gunnc59fd0c2020-04-17 14:03:35 -07002292
2293 Bundle extras = request.getExtras();
2294 Bundle newExtras = new Bundle();
2295 newExtras.putString(Connection.EXTRA_ORIGINAL_CONNECTION_ID, callId);
2296 if (extras != null) {
2297 // If the request originated from a remote connection service, we will add some
2298 // tracking information that Telecom can use to keep informed of which package
2299 // made the remote request, and which remote connection service was used.
2300 if (extras.containsKey(Connection.EXTRA_REMOTE_CONNECTION_ORIGINATING_PACKAGE_NAME)) {
2301 newExtras.putString(
2302 Connection.EXTRA_REMOTE_CONNECTION_ORIGINATING_PACKAGE_NAME,
2303 extras.getString(
2304 Connection.EXTRA_REMOTE_CONNECTION_ORIGINATING_PACKAGE_NAME));
2305 newExtras.putParcelable(Connection.EXTRA_REMOTE_PHONE_ACCOUNT_HANDLE,
2306 request.getAccountHandle());
2307 }
Ravi Paluri80aa2142019-12-02 11:57:37 +05302308 }
Tyler Gunnc59fd0c2020-04-17 14:03:35 -07002309 conference.putExtras(newExtras);
2310
Ravi Paluri80aa2142019-12-02 11:57:37 +05302311 mConferenceById.put(callId, conference);
2312 mIdByConference.put(conference, callId);
Tyler Gunn460360d2020-07-29 10:21:45 -07002313
Ravi Paluri80aa2142019-12-02 11:57:37 +05302314 conference.addListener(mConferenceListener);
Brad Ebinger0ae44ed2020-04-09 15:30:57 -07002315 ParcelableConference parcelableConference = new ParcelableConference.Builder(
2316 request.getAccountHandle(), conference.getState())
2317 .setConnectionCapabilities(conference.getConnectionCapabilities())
2318 .setConnectionProperties(conference.getConnectionProperties())
2319 .setVideoAttributes(conference.getVideoProvider() == null
2320 ? null : conference.getVideoProvider().getInterface(),
2321 conference.getVideoState())
2322 .setConnectTimeMillis(conference.getConnectTimeMillis(),
2323 conference.getConnectionStartElapsedRealtimeMillis())
2324 .setStatusHints(conference.getStatusHints())
2325 .setExtras(conference.getExtras())
2326 .setAddress(conference.getAddress(), conference.getAddressPresentation())
2327 .setCallerDisplayName(conference.getCallerDisplayName(),
2328 conference.getCallerDisplayNamePresentation())
2329 .setDisconnectCause(conference.getDisconnectCause())
2330 .setRingbackRequested(conference.isRingbackRequested())
2331 .build();
Ravi Paluri80aa2142019-12-02 11:57:37 +05302332 if (conference.getState() != Connection.STATE_DISCONNECTED) {
2333 conference.setTelecomCallId(callId);
2334 mAdapter.setVideoProvider(callId, conference.getVideoProvider());
2335 mAdapter.setVideoState(callId, conference.getVideoState());
2336 onConferenceAdded(conference);
2337 }
2338
2339 Log.d(this, "createConference, calling handleCreateConferenceSuccessful %s", callId);
2340 mAdapter.handleCreateConferenceComplete(
2341 callId,
2342 request,
2343 parcelableConference);
2344 }
2345
Sailesh Nepalc5b01572014-07-14 16:29:44 -07002346 /**
Tyler Gunnef9f6f92014-09-12 22:16:17 -07002347 * This can be used by telecom to either create a new outgoing call or attach to an existing
2348 * incoming call. In either case, telecom will cycle through a set of services and call
Sailesh Nepalc5b01572014-07-14 16:29:44 -07002349 * createConnection util a connection service cancels the process or completes it successfully.
2350 */
Ihab Awadf8b69882014-07-25 15:14:01 -07002351 private void createConnection(
2352 final PhoneAccountHandle callManagerAccount,
Ihab Awadb19a0bc2014-08-07 19:46:01 -07002353 final String callId,
Ihab Awadf8b69882014-07-25 15:14:01 -07002354 final ConnectionRequest request,
Yorke Leec3cf9822014-10-02 09:38:39 -07002355 boolean isIncoming,
2356 boolean isUnknown) {
Tyler Gunn79bc1ec2018-01-22 15:17:54 -08002357 boolean isLegacyHandover = request.getExtras() != null &&
2358 request.getExtras().getBoolean(TelecomManager.EXTRA_IS_HANDOVER, false);
2359 boolean isHandover = request.getExtras() != null && request.getExtras().getBoolean(
2360 TelecomManager.EXTRA_IS_HANDOVER_CONNECTION, false);
Grace Jiae99fde92021-01-19 14:58:01 -08002361 boolean addSelfManaged = request.getExtras() != null && request.getExtras().getBoolean(
Grace Jia8b22bb42021-02-02 15:37:32 -08002362 PhoneAccount.EXTRA_ADD_SELF_MANAGED_CALLS_TO_INCALLSERVICE, true);
Grace Jiae99fde92021-01-19 14:58:01 -08002363 Log.i(this, "createConnection, callManagerAccount: %s, callId: %s, request: %s, "
2364 + "isIncoming: %b, isUnknown: %b, isLegacyHandover: %b, isHandover: %b, "
2365 + " addSelfManaged: %b", callManagerAccount, callId, request, isIncoming,
2366 isUnknown, isLegacyHandover, isHandover, addSelfManaged);
Ihab Awad542e0ea2014-05-16 10:22:16 -07002367
Sanket Padawee29a2662017-12-01 13:59:27 -08002368 Connection connection = null;
Tyler Gunn79bc1ec2018-01-22 15:17:54 -08002369 if (isHandover) {
2370 PhoneAccountHandle fromPhoneAccountHandle = request.getExtras() != null
2371 ? (PhoneAccountHandle) request.getExtras().getParcelable(
Hani Kazmi4f221e52022-06-20 09:38:26 +00002372 TelecomManager.EXTRA_HANDOVER_FROM_PHONE_ACCOUNT, android.telecom.PhoneAccountHandle.class) : null;
Sanket Padawee29a2662017-12-01 13:59:27 -08002373 if (!isIncoming) {
Tyler Gunn79bc1ec2018-01-22 15:17:54 -08002374 connection = onCreateOutgoingHandoverConnection(fromPhoneAccountHandle, request);
Sanket Padawee29a2662017-12-01 13:59:27 -08002375 } else {
Tyler Gunn79bc1ec2018-01-22 15:17:54 -08002376 connection = onCreateIncomingHandoverConnection(fromPhoneAccountHandle, request);
Sanket Padawee29a2662017-12-01 13:59:27 -08002377 }
2378 } else {
2379 connection = isUnknown ? onCreateUnknownConnection(callManagerAccount, request)
2380 : isIncoming ? onCreateIncomingConnection(callManagerAccount, request)
2381 : onCreateOutgoingConnection(callManagerAccount, request);
2382 }
Sailesh Nepalcf7020b2014-08-20 10:07:19 -07002383 Log.d(this, "createConnection, connection: %s", connection);
2384 if (connection == null) {
Tyler Gunnfba1a8e2017-12-19 15:23:59 -08002385 Log.i(this, "createConnection, implementation returned null connection.");
Andrew Lee7f3d41f2014-09-11 17:33:16 -07002386 connection = Connection.createFailedConnection(
Tyler Gunnfba1a8e2017-12-19 15:23:59 -08002387 new DisconnectCause(DisconnectCause.ERROR, "IMPL_RETURNED_NULL_CONNECTION"));
Tyler Gunnc59fd0c2020-04-17 14:03:35 -07002388 } else {
2389 try {
2390 Bundle extras = request.getExtras();
2391 if (extras != null) {
2392 // If the request originated from a remote connection service, we will add some
2393 // tracking information that Telecom can use to keep informed of which package
2394 // made the remote request, and which remote connection service was used.
2395 if (extras.containsKey(
2396 Connection.EXTRA_REMOTE_CONNECTION_ORIGINATING_PACKAGE_NAME)) {
2397 Bundle newExtras = new Bundle();
2398 newExtras.putString(
2399 Connection.EXTRA_REMOTE_CONNECTION_ORIGINATING_PACKAGE_NAME,
2400 extras.getString(
2401 Connection.EXTRA_REMOTE_CONNECTION_ORIGINATING_PACKAGE_NAME
2402 ));
2403 newExtras.putParcelable(Connection.EXTRA_REMOTE_PHONE_ACCOUNT_HANDLE,
2404 request.getAccountHandle());
2405 connection.putExtras(newExtras);
2406 }
2407 }
2408 } catch (UnsupportedOperationException ose) {
2409 // Do nothing; if the ConnectionService reported a failure it will be an instance
2410 // of an immutable Connection which we cannot edit, so we're out of luck.
2411 }
Sailesh Nepalc5b01572014-07-14 16:29:44 -07002412 }
Ihab Awad542e0ea2014-05-16 10:22:16 -07002413
Tyler Gunnf2e08b42018-05-24 10:44:44 -07002414 boolean isSelfManaged =
2415 (connection.getConnectionProperties() & Connection.PROPERTY_SELF_MANAGED)
2416 == Connection.PROPERTY_SELF_MANAGED;
2417 // Self-managed Connections should always use voip audio mode; we default here so that the
2418 // local state within the ConnectionService matches the default we assume in Telecom.
2419 if (isSelfManaged) {
2420 connection.setAudioModeIsVoip(true);
2421 }
Tyler Gunnf0500bd2015-09-01 10:59:48 -07002422 connection.setTelecomCallId(callId);
Sungjae7f4137452020-09-16 17:01:54 +09002423 PhoneAccountHandle phoneAccountHandle = connection.getPhoneAccountHandle() == null
2424 ? request.getAccountHandle() : connection.getPhoneAccountHandle();
Sailesh Nepalcf7020b2014-08-20 10:07:19 -07002425 if (connection.getState() != Connection.STATE_DISCONNECTED) {
Sungjae7f4137452020-09-16 17:01:54 +09002426 addConnection(phoneAccountHandle, callId, connection);
Ihab Awad6107bab2014-08-18 09:23:25 -07002427 }
2428
Andrew Lee100e2932014-09-08 15:34:24 -07002429 Uri address = connection.getAddress();
2430 String number = address == null ? "null" : address.getSchemeSpecificPart();
Tyler Gunn720c6642016-03-22 09:02:47 -07002431 Log.v(this, "createConnection, number: %s, state: %s, capabilities: %s, properties: %s",
Ihab Awadb19a0bc2014-08-07 19:46:01 -07002432 Connection.toLogSafePhoneNumber(number),
Sailesh Nepalcf7020b2014-08-20 10:07:19 -07002433 Connection.stateToString(connection.getState()),
Tyler Gunn720c6642016-03-22 09:02:47 -07002434 Connection.capabilitiesToString(connection.getConnectionCapabilities()),
2435 Connection.propertiesToString(connection.getConnectionProperties()));
Santos Cordon7c7bc7f2014-07-28 18:15:48 -07002436
Sailesh Nepalcf7020b2014-08-20 10:07:19 -07002437 Log.d(this, "createConnection, calling handleCreateConnectionSuccessful %s", callId);
Ihab Awad6107bab2014-08-18 09:23:25 -07002438 mAdapter.handleCreateConnectionComplete(
Ihab Awadb19a0bc2014-08-07 19:46:01 -07002439 callId,
Evan Charltonbf11f982014-07-20 22:06:28 -07002440 request,
2441 new ParcelableConnection(
Sungjae7f4137452020-09-16 17:01:54 +09002442 phoneAccountHandle,
Evan Charltonbf11f982014-07-20 22:06:28 -07002443 connection.getState(),
Ihab Awad5c9c86e2014-11-12 13:41:16 -08002444 connection.getConnectionCapabilities(),
Tyler Gunn720c6642016-03-22 09:02:47 -07002445 connection.getConnectionProperties(),
Christine Hallstrom2830ce92016-11-30 16:06:42 -08002446 connection.getSupportedAudioRoutes(),
Andrew Lee100e2932014-09-08 15:34:24 -07002447 connection.getAddress(),
2448 connection.getAddressPresentation(),
Evan Charltonbf11f982014-07-20 22:06:28 -07002449 connection.getCallerDisplayName(),
2450 connection.getCallerDisplayNamePresentation(),
Ihab Awadb19a0bc2014-08-07 19:46:01 -07002451 connection.getVideoProvider() == null ?
2452 null : connection.getVideoProvider().getInterface(),
Sailesh Nepal8b9d3ca2014-08-14 17:39:34 -07002453 connection.getVideoState(),
Andrew Lee100e2932014-09-08 15:34:24 -07002454 connection.isRingbackRequested(),
Sailesh Nepal8b9d3ca2014-08-14 17:39:34 -07002455 connection.getAudioModeIsVoip(),
Roshan Piuse927ec02015-07-15 15:47:21 -07002456 connection.getConnectTimeMillis(),
Tyler Gunnc9503d62020-01-27 10:30:51 -08002457 connection.getConnectionStartElapsedRealtimeMillis(),
Ihab Awad6107bab2014-08-18 09:23:25 -07002458 connection.getStatusHints(),
Sailesh Nepalcf7020b2014-08-20 10:07:19 -07002459 connection.getDisconnectCause(),
Santos Cordon6b7f9552015-05-27 17:21:45 -07002460 createIdList(connection.getConferenceables()),
Tyler Gunnd57d76c2019-09-24 14:53:23 -07002461 connection.getExtras(),
2462 connection.getCallerNumberVerificationStatus()));
Tyler Gunnf5035432017-01-09 09:43:12 -08002463
Tyler Gunnf2e08b42018-05-24 10:44:44 -07002464 if (isIncoming && request.shouldShowIncomingCallUi() && isSelfManaged) {
Tyler Gunnf5035432017-01-09 09:43:12 -08002465 // Tell ConnectionService to show its incoming call UX.
2466 connection.onShowIncomingCallUi();
2467 }
Shriram Ganesh6bf35ac2014-12-11 17:53:38 -08002468 if (isUnknown) {
2469 triggerConferenceRecalculate();
2470 }
Evan Charltonbf11f982014-07-20 22:06:28 -07002471 }
2472
Tyler Gunn159f35c2017-03-02 09:28:37 -08002473 private void createConnectionFailed(final PhoneAccountHandle callManagerAccount,
2474 final String callId, final ConnectionRequest request,
2475 boolean isIncoming) {
Tyler Gunn44e01912017-01-31 10:49:05 -08002476
2477 Log.i(this, "createConnectionFailed %s", callId);
2478 if (isIncoming) {
Tyler Gunn159f35c2017-03-02 09:28:37 -08002479 onCreateIncomingConnectionFailed(callManagerAccount, request);
Tyler Gunn44e01912017-01-31 10:49:05 -08002480 } else {
Tyler Gunn159f35c2017-03-02 09:28:37 -08002481 onCreateOutgoingConnectionFailed(callManagerAccount, request);
Tyler Gunn44e01912017-01-31 10:49:05 -08002482 }
2483 }
2484
Ravi Paluri80aa2142019-12-02 11:57:37 +05302485 private void createConferenceFailed(final PhoneAccountHandle callManagerAccount,
2486 final String callId, final ConnectionRequest request,
2487 boolean isIncoming) {
2488
2489 Log.i(this, "createConferenceFailed %s", callId);
2490 if (isIncoming) {
2491 onCreateIncomingConferenceFailed(callManagerAccount, request);
2492 } else {
2493 onCreateOutgoingConferenceFailed(callManagerAccount, request);
2494 }
2495 }
2496
Sanket Padawe4cc8ed52017-12-04 16:22:20 -08002497 private void handoverFailed(final String callId, final ConnectionRequest request,
2498 int reason) {
2499
2500 Log.i(this, "handoverFailed %s", callId);
2501 onHandoverFailed(request, reason);
2502 }
2503
Tyler Gunn041a1fe2017-05-12 10:04:49 -07002504 /**
2505 * Called by Telecom when the creation of a new Connection has completed and it is now added
2506 * to Telecom.
2507 * @param callId The ID of the connection.
2508 */
2509 private void notifyCreateConnectionComplete(final String callId) {
2510 Log.i(this, "notifyCreateConnectionComplete %s", callId);
Tyler Gunn0a88f2e2017-06-16 20:20:34 -07002511 if (callId == null) {
2512 // This could happen if the connection fails quickly and is removed from the
2513 // ConnectionService before Telecom sends the create connection complete callback.
2514 Log.w(this, "notifyCreateConnectionComplete: callId is null.");
2515 return;
2516 }
Tyler Gunn041a1fe2017-05-12 10:04:49 -07002517 onCreateConnectionComplete(findConnectionForAction(callId,
2518 "notifyCreateConnectionComplete"));
2519 }
2520
Ravi Paluri80aa2142019-12-02 11:57:37 +05302521 /**
2522 * Called by Telecom when the creation of a new Conference has completed and it is now added
2523 * to Telecom.
2524 * @param callId The ID of the connection.
2525 */
2526 private void notifyCreateConferenceComplete(final String callId) {
2527 Log.i(this, "notifyCreateConferenceComplete %s", callId);
2528 if (callId == null) {
2529 // This could happen if the conference fails quickly and is removed from the
2530 // ConnectionService before Telecom sends the create conference complete callback.
2531 Log.w(this, "notifyCreateConferenceComplete: callId is null.");
2532 return;
2533 }
2534 onCreateConferenceComplete(findConferenceForAction(callId,
2535 "notifyCreateConferenceComplete"));
2536 }
2537
2538
Sailesh Nepal2a46b902014-07-04 17:21:07 -07002539 private void abort(String callId) {
Tyler Gunnffbcd892020-05-04 15:01:59 -07002540 Log.i(this, "abort %s", callId);
Sailesh Nepal2a46b902014-07-04 17:21:07 -07002541 findConnectionForAction(callId, "abort").onAbort();
Ihab Awad542e0ea2014-05-16 10:22:16 -07002542 }
2543
Tyler Gunnbe74de02014-08-29 14:51:48 -07002544 private void answerVideo(String callId, int videoState) {
Tyler Gunnffbcd892020-05-04 15:01:59 -07002545 Log.i(this, "answerVideo %s", callId);
Ravi Paluri80aa2142019-12-02 11:57:37 +05302546 if (mConnectionById.containsKey(callId)) {
2547 findConnectionForAction(callId, "answer").onAnswer(videoState);
2548 } else {
2549 findConferenceForAction(callId, "answer").onAnswer(videoState);
2550 }
Ihab Awad542e0ea2014-05-16 10:22:16 -07002551 }
2552
Tyler Gunnbe74de02014-08-29 14:51:48 -07002553 private void answer(String callId) {
Tyler Gunnffbcd892020-05-04 15:01:59 -07002554 Log.i(this, "answer %s", callId);
Ravi Paluri80aa2142019-12-02 11:57:37 +05302555 if (mConnectionById.containsKey(callId)) {
2556 findConnectionForAction(callId, "answer").onAnswer();
2557 } else {
2558 findConferenceForAction(callId, "answer").onAnswer();
2559 }
Tyler Gunnbe74de02014-08-29 14:51:48 -07002560 }
2561
Pooja Jaind34698d2017-12-28 14:15:31 +05302562 private void deflect(String callId, Uri address) {
Tyler Gunnffbcd892020-05-04 15:01:59 -07002563 Log.i(this, "deflect %s", callId);
Pooja Jaind34698d2017-12-28 14:15:31 +05302564 findConnectionForAction(callId, "deflect").onDeflect(address);
2565 }
2566
Sailesh Nepal2a46b902014-07-04 17:21:07 -07002567 private void reject(String callId) {
Tyler Gunnffbcd892020-05-04 15:01:59 -07002568 Log.i(this, "reject %s", callId);
Ravi Paluri80aa2142019-12-02 11:57:37 +05302569 if (mConnectionById.containsKey(callId)) {
2570 findConnectionForAction(callId, "reject").onReject();
2571 } else {
2572 findConferenceForAction(callId, "reject").onReject();
2573 }
Ihab Awad542e0ea2014-05-16 10:22:16 -07002574 }
2575
Bryce Lee81901682015-08-28 16:38:02 -07002576 private void reject(String callId, String rejectWithMessage) {
Tyler Gunnffbcd892020-05-04 15:01:59 -07002577 Log.i(this, "reject %s with message", callId);
Bryce Lee81901682015-08-28 16:38:02 -07002578 findConnectionForAction(callId, "reject").onReject(rejectWithMessage);
2579 }
2580
Tyler Gunnfacfdee2020-01-23 13:10:37 -08002581 private void reject(String callId, @android.telecom.Call.RejectReason int rejectReason) {
Tyler Gunnffbcd892020-05-04 15:01:59 -07002582 Log.i(this, "reject %s with reason %d", callId, rejectReason);
Tyler Gunnfacfdee2020-01-23 13:10:37 -08002583 findConnectionForAction(callId, "reject").onReject(rejectReason);
2584 }
2585
Ravi Palurif4b38e72020-02-05 12:35:41 +05302586 private void transfer(String callId, Uri number, boolean isConfirmationRequired) {
Tyler Gunnffbcd892020-05-04 15:01:59 -07002587 Log.i(this, "transfer %s", callId);
Ravi Palurif4b38e72020-02-05 12:35:41 +05302588 findConnectionForAction(callId, "transfer").onTransfer(number, isConfirmationRequired);
2589 }
2590
2591 private void consultativeTransfer(String callId, String otherCallId) {
Tyler Gunnffbcd892020-05-04 15:01:59 -07002592 Log.i(this, "consultativeTransfer %s", callId);
Ravi Palurif4b38e72020-02-05 12:35:41 +05302593 Connection connection1 = findConnectionForAction(callId, "consultativeTransfer");
2594 Connection connection2 = findConnectionForAction(otherCallId, " consultativeTransfer");
2595 connection1.onTransfer(connection2);
2596 }
2597
Bryce Leecac50772015-11-17 15:13:29 -08002598 private void silence(String callId) {
Tyler Gunnffbcd892020-05-04 15:01:59 -07002599 Log.i(this, "silence %s", callId);
Bryce Leecac50772015-11-17 15:13:29 -08002600 findConnectionForAction(callId, "silence").onSilence();
2601 }
2602
Sailesh Nepal2a46b902014-07-04 17:21:07 -07002603 private void disconnect(String callId) {
Tyler Gunnffbcd892020-05-04 15:01:59 -07002604 Log.i(this, "disconnect %s", callId);
Santos Cordon0159ac02014-08-21 14:28:11 -07002605 if (mConnectionById.containsKey(callId)) {
2606 findConnectionForAction(callId, "disconnect").onDisconnect();
2607 } else {
2608 findConferenceForAction(callId, "disconnect").onDisconnect();
2609 }
Ihab Awad542e0ea2014-05-16 10:22:16 -07002610 }
2611
Sailesh Nepal2a46b902014-07-04 17:21:07 -07002612 private void hold(String callId) {
Tyler Gunnffbcd892020-05-04 15:01:59 -07002613 Log.i(this, "hold %s", callId);
Santos Cordon0159ac02014-08-21 14:28:11 -07002614 if (mConnectionById.containsKey(callId)) {
2615 findConnectionForAction(callId, "hold").onHold();
2616 } else {
2617 findConferenceForAction(callId, "hold").onHold();
2618 }
Ihab Awad542e0ea2014-05-16 10:22:16 -07002619 }
2620
Sailesh Nepal2a46b902014-07-04 17:21:07 -07002621 private void unhold(String callId) {
Tyler Gunnffbcd892020-05-04 15:01:59 -07002622 Log.i(this, "unhold %s", callId);
Santos Cordon0159ac02014-08-21 14:28:11 -07002623 if (mConnectionById.containsKey(callId)) {
2624 findConnectionForAction(callId, "unhold").onUnhold();
2625 } else {
2626 findConferenceForAction(callId, "unhold").onUnhold();
2627 }
Ihab Awad542e0ea2014-05-16 10:22:16 -07002628 }
2629
Yorke Lee4af59352015-05-13 14:14:54 -07002630 private void onCallAudioStateChanged(String callId, CallAudioState callAudioState) {
Tyler Gunnffbcd892020-05-04 15:01:59 -07002631 Log.i(this, "onAudioStateChanged %s %s", callId, callAudioState);
Yorke Leea0d3ca92014-09-15 19:18:13 -07002632 if (mConnectionById.containsKey(callId)) {
Yorke Lee4af59352015-05-13 14:14:54 -07002633 findConnectionForAction(callId, "onCallAudioStateChanged").setCallAudioState(
2634 callAudioState);
Yorke Leea0d3ca92014-09-15 19:18:13 -07002635 } else {
Yorke Lee4af59352015-05-13 14:14:54 -07002636 findConferenceForAction(callId, "onCallAudioStateChanged").setCallAudioState(
2637 callAudioState);
Yorke Leea0d3ca92014-09-15 19:18:13 -07002638 }
Ihab Awad542e0ea2014-05-16 10:22:16 -07002639 }
2640
Junhoedf3d822022-11-24 09:26:37 +00002641 private void onCallEndpointChanged(String callId, CallEndpoint callEndpoint) {
2642 Log.i(this, "onCallEndpointChanged %s %s", callId, callEndpoint);
2643 if (mConnectionById.containsKey(callId)) {
2644 findConnectionForAction(callId, "onCallEndpointChanged").setCallEndpoint(callEndpoint);
2645 } else {
2646 findConferenceForAction(callId, "onCallEndpointChanged").setCallEndpoint(callEndpoint);
2647 }
2648 }
2649
2650 private void onAvailableCallEndpointsChanged(String callId,
2651 List<CallEndpoint> availableCallEndpoints) {
2652 Log.i(this, "onAvailableCallEndpointsChanged %s", callId);
2653 if (mConnectionById.containsKey(callId)) {
2654 findConnectionForAction(callId, "onAvailableCallEndpointsChanged")
2655 .setAvailableCallEndpoints(availableCallEndpoints);
2656 } else {
2657 findConferenceForAction(callId, "onAvailableCallEndpointsChanged")
2658 .setAvailableCallEndpoints(availableCallEndpoints);
2659 }
2660 }
2661
2662 private void onMuteStateChanged(String callId, boolean isMuted) {
2663 Log.i(this, "onMuteStateChanged %s %s", callId, isMuted);
2664 if (mConnectionById.containsKey(callId)) {
2665 findConnectionForAction(callId, "onMuteStateChanged").setMuteState(isMuted);
2666 } else {
2667 findConferenceForAction(callId, "onMuteStateChanged").setMuteState(isMuted);
2668 }
2669 }
2670
Grace Jiae99fde92021-01-19 14:58:01 -08002671 private void onUsingAlternativeUi(String callId, boolean isUsingAlternativeUi) {
2672 Log.i(this, "onUsingAlternativeUi %s %s", callId, isUsingAlternativeUi);
2673 if (mConnectionById.containsKey(callId)) {
2674 findConnectionForAction(callId, "onUsingAlternativeUi")
2675 .onUsingAlternativeUi(isUsingAlternativeUi);
2676 }
2677 }
2678
2679 private void onTrackedByNonUiService(String callId, boolean isTracked) {
2680 Log.i(this, "onTrackedByNonUiService %s %s", callId, isTracked);
2681 if (mConnectionById.containsKey(callId)) {
2682 findConnectionForAction(callId, "onTrackedByNonUiService")
2683 .onTrackedByNonUiService(isTracked);
2684 }
2685 }
2686
Sailesh Nepal2a46b902014-07-04 17:21:07 -07002687 private void playDtmfTone(String callId, char digit) {
Tyler Gunnffbcd892020-05-04 15:01:59 -07002688 Log.i(this, "playDtmfTone %s %c", callId, digit);
Yorke Leea0d3ca92014-09-15 19:18:13 -07002689 if (mConnectionById.containsKey(callId)) {
2690 findConnectionForAction(callId, "playDtmfTone").onPlayDtmfTone(digit);
2691 } else {
2692 findConferenceForAction(callId, "playDtmfTone").onPlayDtmfTone(digit);
2693 }
Sailesh Nepal2a46b902014-07-04 17:21:07 -07002694 }
2695
2696 private void stopDtmfTone(String callId) {
Tyler Gunnffbcd892020-05-04 15:01:59 -07002697 Log.i(this, "stopDtmfTone %s", callId);
Yorke Leea0d3ca92014-09-15 19:18:13 -07002698 if (mConnectionById.containsKey(callId)) {
2699 findConnectionForAction(callId, "stopDtmfTone").onStopDtmfTone();
2700 } else {
2701 findConferenceForAction(callId, "stopDtmfTone").onStopDtmfTone();
2702 }
Sailesh Nepal2a46b902014-07-04 17:21:07 -07002703 }
2704
Santos Cordon823fd3c2014-08-07 18:35:18 -07002705 private void conference(String callId1, String callId2) {
Tyler Gunnffbcd892020-05-04 15:01:59 -07002706 Log.i(this, "conference %s, %s", callId1, callId2);
Santos Cordon980acb92014-05-31 10:31:19 -07002707
Tyler Gunn6d76ca02014-11-17 15:49:51 -08002708 // Attempt to get second connection or conference.
Santos Cordon823fd3c2014-08-07 18:35:18 -07002709 Connection connection2 = findConnectionForAction(callId2, "conference");
Tyler Gunn6d76ca02014-11-17 15:49:51 -08002710 Conference conference2 = getNullConference();
Sailesh Nepalcf7020b2014-08-20 10:07:19 -07002711 if (connection2 == getNullConnection()) {
Tyler Gunn6d76ca02014-11-17 15:49:51 -08002712 conference2 = findConferenceForAction(callId2, "conference");
2713 if (conference2 == getNullConference()) {
2714 Log.w(this, "Connection2 or Conference2 missing in conference request %s.",
2715 callId2);
2716 return;
2717 }
Santos Cordon823fd3c2014-08-07 18:35:18 -07002718 }
Santos Cordonb6939982014-06-04 20:20:58 -07002719
Tyler Gunn6d76ca02014-11-17 15:49:51 -08002720 // Attempt to get first connection or conference and perform merge.
Ihab Awad50e35062014-09-30 09:17:03 -07002721 Connection connection1 = findConnectionForAction(callId1, "conference");
2722 if (connection1 == getNullConnection()) {
2723 Conference conference1 = findConferenceForAction(callId1, "addConnection");
2724 if (conference1 == getNullConference()) {
2725 Log.w(this,
2726 "Connection1 or Conference1 missing in conference request %s.",
2727 callId1);
2728 } else {
Tyler Gunn6d76ca02014-11-17 15:49:51 -08002729 // Call 1 is a conference.
2730 if (connection2 != getNullConnection()) {
2731 // Call 2 is a connection so merge via call 1 (conference).
2732 conference1.onMerge(connection2);
2733 } else {
2734 // Call 2 is ALSO a conference; this should never happen.
2735 Log.wtf(this, "There can only be one conference and an attempt was made to " +
2736 "merge two conferences.");
2737 return;
2738 }
Ihab Awad50e35062014-09-30 09:17:03 -07002739 }
2740 } else {
Tyler Gunn6d76ca02014-11-17 15:49:51 -08002741 // Call 1 is a connection.
2742 if (conference2 != getNullConference()) {
2743 // Call 2 is a conference, so merge via call 2.
2744 conference2.onMerge(connection1);
2745 } else {
2746 // Call 2 is a connection, so merge together.
2747 onConference(connection1, connection2);
2748 }
Ihab Awad50e35062014-09-30 09:17:03 -07002749 }
Santos Cordon980acb92014-05-31 10:31:19 -07002750 }
2751
Sailesh Nepal2a46b902014-07-04 17:21:07 -07002752 private void splitFromConference(String callId) {
Tyler Gunnffbcd892020-05-04 15:01:59 -07002753 Log.i(this, "splitFromConference(%s)", callId);
Santos Cordon980acb92014-05-31 10:31:19 -07002754
2755 Connection connection = findConnectionForAction(callId, "splitFromConference");
Sailesh Nepalcf7020b2014-08-20 10:07:19 -07002756 if (connection == getNullConnection()) {
Santos Cordon980acb92014-05-31 10:31:19 -07002757 Log.w(this, "Connection missing in conference request %s.", callId);
2758 return;
2759 }
2760
Santos Cordon0159ac02014-08-21 14:28:11 -07002761 Conference conference = connection.getConference();
2762 if (conference != null) {
2763 conference.onSeparate(connection);
2764 }
Santos Cordon980acb92014-05-31 10:31:19 -07002765 }
2766
Santos Cordona4868042014-09-04 17:39:22 -07002767 private void mergeConference(String callId) {
Tyler Gunnffbcd892020-05-04 15:01:59 -07002768 Log.i(this, "mergeConference(%s)", callId);
Santos Cordona4868042014-09-04 17:39:22 -07002769 Conference conference = findConferenceForAction(callId, "mergeConference");
2770 if (conference != null) {
2771 conference.onMerge();
2772 }
2773 }
2774
2775 private void swapConference(String callId) {
Tyler Gunnffbcd892020-05-04 15:01:59 -07002776 Log.i(this, "swapConference(%s)", callId);
Santos Cordona4868042014-09-04 17:39:22 -07002777 Conference conference = findConferenceForAction(callId, "swapConference");
2778 if (conference != null) {
2779 conference.onSwap();
2780 }
2781 }
2782
Ravi Paluri404babb2020-01-23 19:02:44 +05302783 private void addConferenceParticipants(String callId, List<Uri> participants) {
Tyler Gunnffbcd892020-05-04 15:01:59 -07002784 Log.i(this, "addConferenceParticipants(%s)", callId);
Ravi Paluri404babb2020-01-23 19:02:44 +05302785 if (mConnectionById.containsKey(callId)) {
2786 findConnectionForAction(callId, "addConferenceParticipants")
2787 .onAddConferenceParticipants(participants);
2788 } else {
2789 findConferenceForAction(callId, "addConferenceParticipants")
2790 .onAddConferenceParticipants(participants);
2791 }
2792 }
2793
Tyler Gunn876dbfb2016-03-14 15:18:07 -07002794 /**
2795 * Notifies a {@link Connection} of a request to pull an external call.
2796 *
2797 * See {@link Call#pullExternalCall()}.
2798 *
2799 * @param callId The ID of the call to pull.
2800 */
2801 private void pullExternalCall(String callId) {
Tyler Gunnffbcd892020-05-04 15:01:59 -07002802 Log.i(this, "pullExternalCall(%s)", callId);
Tyler Gunn876dbfb2016-03-14 15:18:07 -07002803 Connection connection = findConnectionForAction(callId, "pullExternalCall");
2804 if (connection != null) {
2805 connection.onPullExternalCall();
2806 }
2807 }
2808
2809 /**
2810 * Notifies a {@link Connection} of a call event.
2811 *
2812 * See {@link Call#sendCallEvent(String, Bundle)}.
2813 *
2814 * @param callId The ID of the call receiving the event.
2815 * @param event The event.
2816 * @param extras Extras associated with the event.
2817 */
2818 private void sendCallEvent(String callId, String event, Bundle extras) {
Tyler Gunnffbcd892020-05-04 15:01:59 -07002819 Log.i(this, "sendCallEvent(%s, %s)", callId, event);
Tyler Gunn876dbfb2016-03-14 15:18:07 -07002820 Connection connection = findConnectionForAction(callId, "sendCallEvent");
2821 if (connection != null) {
2822 connection.onCallEvent(event, extras);
2823 }
Tyler Gunn876dbfb2016-03-14 15:18:07 -07002824 }
2825
Hall Liu73903142021-02-18 18:41:41 -08002826 private void onCallFilteringCompleted(String callId, Connection.CallFilteringCompletionInfo
2827 callFilteringCompletionInfo) {
2828 Log.i(this, "onCallFilteringCompleted(%s, %s)", callId, callFilteringCompletionInfo);
Hall Liu49cabcc2021-01-15 11:41:48 -08002829 Connection connection = findConnectionForAction(callId, "onCallFilteringCompleted");
2830 if (connection != null) {
Hall Liu73903142021-02-18 18:41:41 -08002831 connection.onCallFilteringCompleted(callFilteringCompletionInfo);
Hall Liu49cabcc2021-01-15 11:41:48 -08002832 }
2833 }
2834
Tyler Gunndee56a82016-03-23 16:06:34 -07002835 /**
Tyler Gunn79bc1ec2018-01-22 15:17:54 -08002836 * Notifies a {@link Connection} that a handover has completed.
2837 *
2838 * @param callId The ID of the call which completed handover.
2839 */
2840 private void notifyHandoverComplete(String callId) {
Tyler Gunnffbcd892020-05-04 15:01:59 -07002841 Log.i(this, "notifyHandoverComplete(%s)", callId);
Tyler Gunn79bc1ec2018-01-22 15:17:54 -08002842 Connection connection = findConnectionForAction(callId, "notifyHandoverComplete");
2843 if (connection != null) {
2844 connection.onHandoverComplete();
2845 }
2846 }
2847
2848 /**
Tyler Gunndee56a82016-03-23 16:06:34 -07002849 * Notifies a {@link Connection} or {@link Conference} of a change to the extras from Telecom.
2850 * <p>
2851 * These extra changes can originate from Telecom itself, or from an {@link InCallService} via
2852 * the {@link android.telecom.Call#putExtra(String, boolean)},
2853 * {@link android.telecom.Call#putExtra(String, int)},
2854 * {@link android.telecom.Call#putExtra(String, String)},
2855 * {@link Call#removeExtras(List)}.
2856 *
2857 * @param callId The ID of the call receiving the event.
2858 * @param extras The new extras bundle.
2859 */
2860 private void handleExtrasChanged(String callId, Bundle extras) {
Tyler Gunnffbcd892020-05-04 15:01:59 -07002861 Log.i(this, "handleExtrasChanged(%s, %s)", callId, extras);
Tyler Gunndee56a82016-03-23 16:06:34 -07002862 if (mConnectionById.containsKey(callId)) {
2863 findConnectionForAction(callId, "handleExtrasChanged").handleExtrasChanged(extras);
2864 } else if (mConferenceById.containsKey(callId)) {
2865 findConferenceForAction(callId, "handleExtrasChanged").handleExtrasChanged(extras);
2866 }
2867 }
2868
Hall Liub64ac4c2017-02-06 10:49:48 -08002869 private void startRtt(String callId, Connection.RttTextStream rttTextStream) {
Tyler Gunnffbcd892020-05-04 15:01:59 -07002870 Log.i(this, "startRtt(%s)", callId);
Hall Liub64ac4c2017-02-06 10:49:48 -08002871 if (mConnectionById.containsKey(callId)) {
2872 findConnectionForAction(callId, "startRtt").onStartRtt(rttTextStream);
2873 } else if (mConferenceById.containsKey(callId)) {
2874 Log.w(this, "startRtt called on a conference.");
2875 }
2876 }
2877
2878 private void stopRtt(String callId) {
Tyler Gunnffbcd892020-05-04 15:01:59 -07002879 Log.i(this, "stopRtt(%s)", callId);
Hall Liub64ac4c2017-02-06 10:49:48 -08002880 if (mConnectionById.containsKey(callId)) {
2881 findConnectionForAction(callId, "stopRtt").onStopRtt();
2882 } else if (mConferenceById.containsKey(callId)) {
2883 Log.w(this, "stopRtt called on a conference.");
2884 }
2885 }
2886
2887 private void handleRttUpgradeResponse(String callId, Connection.RttTextStream rttTextStream) {
Tyler Gunnffbcd892020-05-04 15:01:59 -07002888 Log.i(this, "handleRttUpgradeResponse(%s, %s)", callId, rttTextStream == null);
Hall Liub64ac4c2017-02-06 10:49:48 -08002889 if (mConnectionById.containsKey(callId)) {
2890 findConnectionForAction(callId, "handleRttUpgradeResponse")
2891 .handleRttUpgradeResponse(rttTextStream);
2892 } else if (mConferenceById.containsKey(callId)) {
2893 Log.w(this, "handleRttUpgradeResponse called on a conference.");
2894 }
2895 }
2896
Sailesh Nepal2a46b902014-07-04 17:21:07 -07002897 private void onPostDialContinue(String callId, boolean proceed) {
Tyler Gunnffbcd892020-05-04 15:01:59 -07002898 Log.i(this, "onPostDialContinue(%s)", callId);
Sailesh Nepal2a46b902014-07-04 17:21:07 -07002899 findConnectionForAction(callId, "stopDtmfTone").onPostDialContinue(proceed);
Evan Charlton6dea4ac2014-06-03 14:07:13 -07002900 }
2901
Sailesh Nepal2a46b902014-07-04 17:21:07 -07002902 private void onAdapterAttached() {
Ihab Awad9c3f1882014-06-30 21:17:13 -07002903 if (mAreAccountsInitialized) {
Santos Cordon52d8a152014-06-17 19:08:45 -07002904 // No need to query again if we already did it.
2905 return;
2906 }
2907
Tyler Gunn4c69fb32019-05-17 10:49:16 -07002908 String callingPackage = getOpPackageName();
2909
Sailesh Nepal2a46b902014-07-04 17:21:07 -07002910 mAdapter.queryRemoteConnectionServices(new RemoteServiceCallback.Stub() {
Santos Cordon52d8a152014-06-17 19:08:45 -07002911 @Override
2912 public void onResult(
2913 final List<ComponentName> componentNames,
Sailesh Nepal2a46b902014-07-04 17:21:07 -07002914 final List<IBinder> services) {
Brad Ebinger0c3541b2016-11-01 14:11:38 -07002915 mHandler.post(new android.telecom.Logging.Runnable("oAA.qRCS.oR", null /*lock*/) {
Ihab Awad6107bab2014-08-18 09:23:25 -07002916 @Override
Brad Ebinger0c3541b2016-11-01 14:11:38 -07002917 public void loggedRun() {
Sailesh Nepal2a46b902014-07-04 17:21:07 -07002918 for (int i = 0; i < componentNames.size() && i < services.size(); i++) {
Santos Cordon52d8a152014-06-17 19:08:45 -07002919 mRemoteConnectionManager.addConnectionService(
2920 componentNames.get(i),
Sailesh Nepal2a46b902014-07-04 17:21:07 -07002921 IConnectionService.Stub.asInterface(services.get(i)));
Santos Cordon52d8a152014-06-17 19:08:45 -07002922 }
Ihab Awad5d0410f2014-07-30 10:07:40 -07002923 onAccountsInitialized();
Sailesh Nepalc5b01572014-07-14 16:29:44 -07002924 Log.d(this, "remote connection services found: " + services);
Santos Cordon52d8a152014-06-17 19:08:45 -07002925 }
Brad Ebinger0c3541b2016-11-01 14:11:38 -07002926 }.prepare());
Santos Cordon52d8a152014-06-17 19:08:45 -07002927 }
2928
2929 @Override
2930 public void onError() {
Brad Ebinger0c3541b2016-11-01 14:11:38 -07002931 mHandler.post(new android.telecom.Logging.Runnable("oAA.qRCS.oE", null /*lock*/) {
Ihab Awad6107bab2014-08-18 09:23:25 -07002932 @Override
Brad Ebinger0c3541b2016-11-01 14:11:38 -07002933 public void loggedRun() {
Ihab Awad9c3f1882014-06-30 21:17:13 -07002934 mAreAccountsInitialized = true;
Santos Cordon52d8a152014-06-17 19:08:45 -07002935 }
Brad Ebinger0c3541b2016-11-01 14:11:38 -07002936 }.prepare());
Santos Cordon52d8a152014-06-17 19:08:45 -07002937 }
Tyler Gunn4c69fb32019-05-17 10:49:16 -07002938 }, callingPackage);
Santos Cordon52d8a152014-06-17 19:08:45 -07002939 }
2940
Ihab Awadf8b69882014-07-25 15:14:01 -07002941 /**
2942 * Ask some other {@code ConnectionService} to create a {@code RemoteConnection} given an
Santos Cordona663f862014-10-29 13:49:58 -07002943 * incoming request. This is used by {@code ConnectionService}s that are registered with
2944 * {@link PhoneAccount#CAPABILITY_CONNECTION_MANAGER} and want to be able to manage
2945 * SIM-based incoming calls.
Ihab Awadf8b69882014-07-25 15:14:01 -07002946 *
2947 * @param connectionManagerPhoneAccount See description at
2948 * {@link #onCreateOutgoingConnection(PhoneAccountHandle, ConnectionRequest)}.
2949 * @param request Details about the incoming call.
2950 * @return The {@code Connection} object to satisfy this call, or {@code null} to
2951 * not handle the call.
2952 */
Grace Jia41895152021-01-19 13:57:51 -08002953 public final @Nullable RemoteConnection createRemoteIncomingConnection(
2954 @NonNull PhoneAccountHandle connectionManagerPhoneAccount,
2955 @NonNull ConnectionRequest request) {
Ihab Awadf8b69882014-07-25 15:14:01 -07002956 return mRemoteConnectionManager.createRemoteConnection(
2957 connectionManagerPhoneAccount, request, true);
Santos Cordon52d8a152014-06-17 19:08:45 -07002958 }
2959
2960 /**
Ihab Awadf8b69882014-07-25 15:14:01 -07002961 * Ask some other {@code ConnectionService} to create a {@code RemoteConnection} given an
Santos Cordona663f862014-10-29 13:49:58 -07002962 * outgoing request. This is used by {@code ConnectionService}s that are registered with
2963 * {@link PhoneAccount#CAPABILITY_CONNECTION_MANAGER} and want to be able to use the
2964 * SIM-based {@code ConnectionService} to place its outgoing calls.
Ihab Awadf8b69882014-07-25 15:14:01 -07002965 *
2966 * @param connectionManagerPhoneAccount See description at
2967 * {@link #onCreateOutgoingConnection(PhoneAccountHandle, ConnectionRequest)}.
Cuihtlauac ALVARADO0b3b2a52016-09-13 14:49:41 +02002968 * @param request Details about the outgoing call.
Ihab Awadf8b69882014-07-25 15:14:01 -07002969 * @return The {@code Connection} object to satisfy this call, or {@code null} to
2970 * not handle the call.
2971 */
Grace Jia41895152021-01-19 13:57:51 -08002972 public final @Nullable RemoteConnection createRemoteOutgoingConnection(
2973 @NonNull PhoneAccountHandle connectionManagerPhoneAccount,
2974 @NonNull ConnectionRequest request) {
Ihab Awadf8b69882014-07-25 15:14:01 -07002975 return mRemoteConnectionManager.createRemoteConnection(
2976 connectionManagerPhoneAccount, request, false);
2977 }
2978
2979 /**
Grace Jia9a09c672020-08-04 12:52:09 -07002980 * Ask some other {@code ConnectionService} to create a {@code RemoteConference} given an
2981 * incoming request. This is used by {@code ConnectionService}s that are registered with
2982 * {@link PhoneAccount#CAPABILITY_ADHOC_CONFERENCE_CALLING}.
2983 *
2984 * @param connectionManagerPhoneAccount See description at
2985 * {@link #onCreateOutgoingConnection(PhoneAccountHandle, ConnectionRequest)}.
2986 * @param request Details about the incoming conference call.
2987 * @return The {@code RemoteConference} object to satisfy this call, or {@code null} to not
2988 * handle the call.
2989 */
2990 public final @Nullable RemoteConference createRemoteIncomingConference(
2991 @Nullable PhoneAccountHandle connectionManagerPhoneAccount,
2992 @Nullable ConnectionRequest request) {
2993 return mRemoteConnectionManager.createRemoteConference(connectionManagerPhoneAccount,
2994 request, true);
2995 }
2996
2997 /**
2998 * Ask some other {@code ConnectionService} to create a {@code RemoteConference} given an
2999 * outgoing request. This is used by {@code ConnectionService}s that are registered with
3000 * {@link PhoneAccount#CAPABILITY_ADHOC_CONFERENCE_CALLING}.
3001 *
3002 * @param connectionManagerPhoneAccount See description at
3003 * {@link #onCreateOutgoingConnection(PhoneAccountHandle, ConnectionRequest)}.
3004 * @param request Details about the outgoing conference call.
3005 * @return The {@code RemoteConference} object to satisfy this call, or {@code null} to not
3006 * handle the call.
3007 */
3008 public final @Nullable RemoteConference createRemoteOutgoingConference(
3009 @Nullable PhoneAccountHandle connectionManagerPhoneAccount,
3010 @Nullable ConnectionRequest request) {
3011 return mRemoteConnectionManager.createRemoteConference(connectionManagerPhoneAccount,
3012 request, false);
3013 }
3014
3015 /**
Santos Cordona663f862014-10-29 13:49:58 -07003016 * Indicates to the relevant {@code RemoteConnectionService} that the specified
3017 * {@link RemoteConnection}s should be merged into a conference call.
3018 * <p>
3019 * If the conference request is successful, the method {@link #onRemoteConferenceAdded} will
3020 * be invoked.
3021 *
3022 * @param remoteConnection1 The first of the remote connections to conference.
3023 * @param remoteConnection2 The second of the remote connections to conference.
Ihab Awadb8e85c72014-08-23 20:34:57 -07003024 */
3025 public final void conferenceRemoteConnections(
Santos Cordona663f862014-10-29 13:49:58 -07003026 RemoteConnection remoteConnection1,
3027 RemoteConnection remoteConnection2) {
3028 mRemoteConnectionManager.conferenceRemoteConnections(remoteConnection1, remoteConnection2);
Ihab Awadb8e85c72014-08-23 20:34:57 -07003029 }
3030
3031 /**
Santos Cordon823fd3c2014-08-07 18:35:18 -07003032 * Adds a new conference call. When a conference call is created either as a result of an
3033 * explicit request via {@link #onConference} or otherwise, the connection service should supply
3034 * an instance of {@link Conference} by invoking this method. A conference call provided by this
3035 * method will persist until {@link Conference#destroy} is invoked on the conference instance.
3036 *
3037 * @param conference The new conference object.
3038 */
3039 public final void addConference(Conference conference) {
Rekha Kumar07366812015-03-24 16:42:31 -07003040 Log.d(this, "addConference: conference=%s", conference);
3041
Santos Cordon823fd3c2014-08-07 18:35:18 -07003042 String id = addConferenceInternal(conference);
3043 if (id != null) {
3044 List<String> connectionIds = new ArrayList<>(2);
3045 for (Connection connection : conference.getConnections()) {
3046 if (mIdByConnection.containsKey(connection)) {
3047 connectionIds.add(mIdByConnection.get(connection));
3048 }
3049 }
Tyler Gunnf0500bd2015-09-01 10:59:48 -07003050 conference.setTelecomCallId(id);
Brad Ebinger0ae44ed2020-04-09 15:30:57 -07003051 ParcelableConference parcelableConference = new ParcelableConference.Builder(
3052 conference.getPhoneAccountHandle(), conference.getState())
3053 .setConnectionCapabilities(conference.getConnectionCapabilities())
3054 .setConnectionProperties(conference.getConnectionProperties())
3055 .setConnectionIds(connectionIds)
3056 .setVideoAttributes(conference.getVideoProvider() == null
3057 ? null : conference.getVideoProvider().getInterface(),
3058 conference.getVideoState())
3059 .setConnectTimeMillis(conference.getConnectTimeMillis(),
3060 conference.getConnectionStartElapsedRealtimeMillis())
3061 .setStatusHints(conference.getStatusHints())
3062 .setExtras(conference.getExtras())
3063 .setAddress(conference.getAddress(), conference.getAddressPresentation())
3064 .setCallerDisplayName(conference.getCallerDisplayName(),
3065 conference.getCallerDisplayNamePresentation())
3066 .setDisconnectCause(conference.getDisconnectCause())
3067 .setRingbackRequested(conference.isRingbackRequested())
3068 .setCallDirection(conference.getCallDirection())
3069 .build();
Andrew Lee0f51da32015-04-16 13:11:55 -07003070
Santos Cordon823fd3c2014-08-07 18:35:18 -07003071 mAdapter.addConferenceCall(id, parcelableConference);
Rekha Kumar07366812015-03-24 16:42:31 -07003072 mAdapter.setVideoProvider(id, conference.getVideoProvider());
3073 mAdapter.setVideoState(id, conference.getVideoState());
Tyler Gunn10362372020-04-08 13:12:30 -07003074 // In some instances a conference can start its life as a standalone call with just a
3075 // single participant; ensure we signal to Telecom in this case.
3076 if (!conference.isMultiparty()) {
3077 mAdapter.setConferenceState(id, conference.isMultiparty());
3078 }
Santos Cordon823fd3c2014-08-07 18:35:18 -07003079
3080 // Go through any child calls and set the parent.
3081 for (Connection connection : conference.getConnections()) {
3082 String connectionId = mIdByConnection.get(connection);
3083 if (connectionId != null) {
3084 mAdapter.setIsConferenced(connectionId, id);
3085 }
3086 }
Pengquan Meng70c9885332017-10-02 18:09:03 -07003087 onConferenceAdded(conference);
Santos Cordon823fd3c2014-08-07 18:35:18 -07003088 }
3089 }
3090
3091 /**
Tyler Gunn4a57b9b2014-10-30 14:27:48 -07003092 * Adds a connection created by the {@link ConnectionService} and informs telecom of the new
3093 * connection.
3094 *
3095 * @param phoneAccountHandle The phone account handle for the connection.
3096 * @param connection The connection to add.
3097 */
3098 public final void addExistingConnection(PhoneAccountHandle phoneAccountHandle,
3099 Connection connection) {
Tyler Gunn78da7812017-05-09 14:34:57 -07003100 addExistingConnection(phoneAccountHandle, connection, null /* conference */);
3101 }
3102
3103 /**
Pengquan Meng731c1a32017-11-21 18:01:13 -08003104 * Call to inform Telecom that your {@link ConnectionService} has released call resources (e.g
3105 * microphone, camera).
3106 *
Pengquan Menge3bf7e22018-02-22 17:30:04 -08003107 * <p>
3108 * The {@link ConnectionService} will be disconnected when it failed to call this method within
3109 * 5 seconds after {@link #onConnectionServiceFocusLost()} is called.
3110 *
Pengquan Meng731c1a32017-11-21 18:01:13 -08003111 * @see ConnectionService#onConnectionServiceFocusLost()
3112 */
3113 public final void connectionServiceFocusReleased() {
3114 mAdapter.onConnectionServiceFocusReleased();
3115 }
3116
3117 /**
Tyler Gunn78da7812017-05-09 14:34:57 -07003118 * Adds a connection created by the {@link ConnectionService} and informs telecom of the new
Tyler Gunn5567d742019-10-31 13:04:37 -07003119 * connection, as well as adding that connection to the specified conference.
3120 * <p>
3121 * Note: This API is intended ONLY for use by the Telephony stack to provide an easy way to add
3122 * IMS conference participants to be added to a conference in a single step; this helps ensure
3123 * UI updates happen atomically, rather than adding the connection and then adding it to
3124 * the conference in another step.
Tyler Gunn78da7812017-05-09 14:34:57 -07003125 *
3126 * @param phoneAccountHandle The phone account handle for the connection.
3127 * @param connection The connection to add.
3128 * @param conference The parent conference of the new connection.
3129 * @hide
3130 */
Tyler Gunn5567d742019-10-31 13:04:37 -07003131 @SystemApi
3132 public final void addExistingConnection(@NonNull PhoneAccountHandle phoneAccountHandle,
3133 @NonNull Connection connection, @NonNull Conference conference) {
Tyler Gunn4a57b9b2014-10-30 14:27:48 -07003134
Tyler Gunnf0500bd2015-09-01 10:59:48 -07003135 String id = addExistingConnectionInternal(phoneAccountHandle, connection);
Tyler Gunn4a57b9b2014-10-30 14:27:48 -07003136 if (id != null) {
3137 List<String> emptyList = new ArrayList<>(0);
Tyler Gunn78da7812017-05-09 14:34:57 -07003138 String conferenceId = null;
3139 if (conference != null) {
3140 conferenceId = mIdByConference.get(conference);
3141 }
Tyler Gunn4a57b9b2014-10-30 14:27:48 -07003142
3143 ParcelableConnection parcelableConnection = new ParcelableConnection(
3144 phoneAccountHandle,
3145 connection.getState(),
Ihab Awad5c9c86e2014-11-12 13:41:16 -08003146 connection.getConnectionCapabilities(),
Tyler Gunn720c6642016-03-22 09:02:47 -07003147 connection.getConnectionProperties(),
Christine Hallstrom2830ce92016-11-30 16:06:42 -08003148 connection.getSupportedAudioRoutes(),
Tyler Gunn4a57b9b2014-10-30 14:27:48 -07003149 connection.getAddress(),
3150 connection.getAddressPresentation(),
3151 connection.getCallerDisplayName(),
3152 connection.getCallerDisplayNamePresentation(),
3153 connection.getVideoProvider() == null ?
3154 null : connection.getVideoProvider().getInterface(),
3155 connection.getVideoState(),
3156 connection.isRingbackRequested(),
3157 connection.getAudioModeIsVoip(),
Roshan Piuse927ec02015-07-15 15:47:21 -07003158 connection.getConnectTimeMillis(),
Tyler Gunnc9503d62020-01-27 10:30:51 -08003159 connection.getConnectionStartElapsedRealtimeMillis(),
Tyler Gunn4a57b9b2014-10-30 14:27:48 -07003160 connection.getStatusHints(),
3161 connection.getDisconnectCause(),
Santos Cordon6b7f9552015-05-27 17:21:45 -07003162 emptyList,
Tyler Gunn78da7812017-05-09 14:34:57 -07003163 connection.getExtras(),
Tyler Gunn6986a632019-06-25 13:45:32 -07003164 conferenceId,
Tyler Gunnd57d76c2019-09-24 14:53:23 -07003165 connection.getCallDirection(),
3166 Connection.VERIFICATION_STATUS_NOT_VERIFIED);
Tyler Gunn4a57b9b2014-10-30 14:27:48 -07003167 mAdapter.addExistingConnection(id, parcelableConnection);
3168 }
3169 }
3170
3171 /**
Ihab Awadf8b69882014-07-25 15:14:01 -07003172 * Returns all the active {@code Connection}s for which this {@code ConnectionService}
3173 * has taken responsibility.
3174 *
3175 * @return A collection of {@code Connection}s created by this {@code ConnectionService}.
Santos Cordonb6939982014-06-04 20:20:58 -07003176 */
Sailesh Nepal091768c2014-06-30 15:15:23 -07003177 public final Collection<Connection> getAllConnections() {
Santos Cordonb6939982014-06-04 20:20:58 -07003178 return mConnectionById.values();
3179 }
3180
3181 /**
Santos Cordona6018b92016-02-16 14:23:12 -08003182 * Returns all the active {@code Conference}s for which this {@code ConnectionService}
3183 * has taken responsibility.
3184 *
3185 * @return A collection of {@code Conference}s created by this {@code ConnectionService}.
3186 */
3187 public final Collection<Conference> getAllConferences() {
3188 return mConferenceById.values();
3189 }
3190
3191 /**
Ihab Awadf8b69882014-07-25 15:14:01 -07003192 * Create a {@code Connection} given an incoming request. This is used to attach to existing
3193 * incoming calls.
Evan Charltonbf11f982014-07-20 22:06:28 -07003194 *
Ihab Awadf8b69882014-07-25 15:14:01 -07003195 * @param connectionManagerPhoneAccount See description at
3196 * {@link #onCreateOutgoingConnection(PhoneAccountHandle, ConnectionRequest)}.
3197 * @param request Details about the incoming call.
3198 * @return The {@code Connection} object to satisfy this call, or {@code null} to
3199 * not handle the call.
Ihab Awad542e0ea2014-05-16 10:22:16 -07003200 */
Ihab Awadf8b69882014-07-25 15:14:01 -07003201 public Connection onCreateIncomingConnection(
3202 PhoneAccountHandle connectionManagerPhoneAccount,
3203 ConnectionRequest request) {
3204 return null;
3205 }
Ravi Paluri80aa2142019-12-02 11:57:37 +05303206 /**
Grace Jia8587ee52020-07-10 15:42:32 -07003207 * Create a {@code Conference} given an incoming request. This is used to attach to an incoming
3208 * conference call initiated via
3209 * {@link TelecomManager#addNewIncomingConference(PhoneAccountHandle, Bundle)}.
Ravi Paluri80aa2142019-12-02 11:57:37 +05303210 *
3211 * @param connectionManagerPhoneAccount See description at
3212 * {@link #onCreateOutgoingConnection(PhoneAccountHandle, ConnectionRequest)}.
Grace Jia8587ee52020-07-10 15:42:32 -07003213 * @param request Details about the incoming conference call.
Grace Jia41895152021-01-19 13:57:51 -08003214 * @return The {@code Conference} object to satisfy this call. If the conference attempt is
3215 * failed, the return value will be a result of an invocation of
3216 * {@link Connection#createFailedConnection(DisconnectCause)}.
3217 * Return {@code null} if the {@link ConnectionService} cannot handle the call.
Ravi Paluri80aa2142019-12-02 11:57:37 +05303218 */
3219 public @Nullable Conference onCreateIncomingConference(
Grace Jia41895152021-01-19 13:57:51 -08003220 @NonNull PhoneAccountHandle connectionManagerPhoneAccount,
3221 @NonNull ConnectionRequest request) {
Ravi Paluri80aa2142019-12-02 11:57:37 +05303222 return null;
3223 }
Sailesh Nepalc5b01572014-07-14 16:29:44 -07003224
3225 /**
Tyler Gunn041a1fe2017-05-12 10:04:49 -07003226 * Called after the {@link Connection} returned by
3227 * {@link #onCreateIncomingConnection(PhoneAccountHandle, ConnectionRequest)}
3228 * or {@link #onCreateOutgoingConnection(PhoneAccountHandle, ConnectionRequest)} has been
3229 * added to the {@link ConnectionService} and sent to Telecom.
3230 *
3231 * @param connection the {@link Connection}.
3232 * @hide
3233 */
3234 public void onCreateConnectionComplete(Connection connection) {
3235 }
3236
3237 /**
Ravi Paluri80aa2142019-12-02 11:57:37 +05303238 * Called after the {@link Conference} returned by
3239 * {@link #onCreateIncomingConference(PhoneAccountHandle, ConnectionRequest)}
3240 * or {@link #onCreateOutgoingConference(PhoneAccountHandle, ConnectionRequest)} has been
3241 * added to the {@link ConnectionService} and sent to Telecom.
3242 *
3243 * @param conference the {@link Conference}.
3244 * @hide
3245 */
3246 public void onCreateConferenceComplete(Conference conference) {
3247 }
3248
3249
3250 /**
Tyler Gunnf5035432017-01-09 09:43:12 -08003251 * Called by Telecom to inform the {@link ConnectionService} that its request to create a new
3252 * incoming {@link Connection} was denied.
3253 * <p>
3254 * Used when a self-managed {@link ConnectionService} attempts to create a new incoming
3255 * {@link Connection}, but Telecom has determined that the call cannot be allowed at this time.
3256 * The {@link ConnectionService} is responsible for silently rejecting the new incoming
3257 * {@link Connection}.
3258 * <p>
3259 * See {@link TelecomManager#isIncomingCallPermitted(PhoneAccountHandle)} for more information.
3260 *
Tyler Gunn159f35c2017-03-02 09:28:37 -08003261 * @param connectionManagerPhoneAccount See description at
3262 * {@link #onCreateOutgoingConnection(PhoneAccountHandle, ConnectionRequest)}.
Tyler Gunnf5035432017-01-09 09:43:12 -08003263 * @param request The incoming connection request.
3264 */
Tyler Gunn159f35c2017-03-02 09:28:37 -08003265 public void onCreateIncomingConnectionFailed(PhoneAccountHandle connectionManagerPhoneAccount,
3266 ConnectionRequest request) {
Tyler Gunnf5035432017-01-09 09:43:12 -08003267 }
3268
3269 /**
3270 * Called by Telecom to inform the {@link ConnectionService} that its request to create a new
3271 * outgoing {@link Connection} was denied.
3272 * <p>
3273 * Used when a self-managed {@link ConnectionService} attempts to create a new outgoing
3274 * {@link Connection}, but Telecom has determined that the call cannot be placed at this time.
3275 * The {@link ConnectionService} is responisible for informing the user that the
3276 * {@link Connection} cannot be made at this time.
3277 * <p>
3278 * See {@link TelecomManager#isOutgoingCallPermitted(PhoneAccountHandle)} for more information.
3279 *
Tyler Gunn159f35c2017-03-02 09:28:37 -08003280 * @param connectionManagerPhoneAccount See description at
3281 * {@link #onCreateOutgoingConnection(PhoneAccountHandle, ConnectionRequest)}.
Tyler Gunnf5035432017-01-09 09:43:12 -08003282 * @param request The outgoing connection request.
3283 */
Tyler Gunn159f35c2017-03-02 09:28:37 -08003284 public void onCreateOutgoingConnectionFailed(PhoneAccountHandle connectionManagerPhoneAccount,
3285 ConnectionRequest request) {
Tyler Gunnf5035432017-01-09 09:43:12 -08003286 }
3287
3288 /**
Ravi Paluri80aa2142019-12-02 11:57:37 +05303289 * Called by Telecom to inform the {@link ConnectionService} that its request to create a new
3290 * incoming {@link Conference} was denied.
3291 * <p>
3292 * Used when a self-managed {@link ConnectionService} attempts to create a new incoming
3293 * {@link Conference}, but Telecom has determined that the call cannot be allowed at this time.
3294 * The {@link ConnectionService} is responsible for silently rejecting the new incoming
3295 * {@link Conference}.
3296 * <p>
3297 * See {@link TelecomManager#isIncomingCallPermitted(PhoneAccountHandle)} for more information.
3298 *
3299 * @param connectionManagerPhoneAccount See description at
3300 * {@link #onCreateOutgoingConnection(PhoneAccountHandle, ConnectionRequest)}.
3301 * @param request The incoming connection request.
3302 */
3303 public void onCreateIncomingConferenceFailed(
3304 @Nullable PhoneAccountHandle connectionManagerPhoneAccount,
3305 @Nullable ConnectionRequest request) {
3306 }
3307
3308 /**
3309 * Called by Telecom to inform the {@link ConnectionService} that its request to create a new
3310 * outgoing {@link Conference} was denied.
3311 * <p>
3312 * Used when a self-managed {@link ConnectionService} attempts to create a new outgoing
3313 * {@link Conference}, but Telecom has determined that the call cannot be placed at this time.
3314 * The {@link ConnectionService} is responisible for informing the user that the
3315 * {@link Conference} cannot be made at this time.
3316 * <p>
3317 * See {@link TelecomManager#isOutgoingCallPermitted(PhoneAccountHandle)} for more information.
3318 *
3319 * @param connectionManagerPhoneAccount See description at
3320 * {@link #onCreateOutgoingConnection(PhoneAccountHandle, ConnectionRequest)}.
3321 * @param request The outgoing connection request.
3322 */
3323 public void onCreateOutgoingConferenceFailed(
Grace Jia41895152021-01-19 13:57:51 -08003324 @NonNull PhoneAccountHandle connectionManagerPhoneAccount,
3325 @NonNull ConnectionRequest request) {
Ravi Paluri80aa2142019-12-02 11:57:37 +05303326 }
3327
3328
3329 /**
Shriram Ganesh6bf35ac2014-12-11 17:53:38 -08003330 * Trigger recalculate functinality for conference calls. This is used when a Telephony
3331 * Connection is part of a conference controller but is not yet added to Connection
3332 * Service and hence cannot be added to the conference call.
3333 *
3334 * @hide
3335 */
3336 public void triggerConferenceRecalculate() {
3337 }
3338
3339 /**
Ihab Awadf8b69882014-07-25 15:14:01 -07003340 * Create a {@code Connection} given an outgoing request. This is used to initiate new
3341 * outgoing calls.
Sailesh Nepalc5b01572014-07-14 16:29:44 -07003342 *
Ihab Awadf8b69882014-07-25 15:14:01 -07003343 * @param connectionManagerPhoneAccount The connection manager account to use for managing
3344 * this call.
3345 * <p>
3346 * If this parameter is not {@code null}, it means that this {@code ConnectionService}
3347 * has registered one or more {@code PhoneAccount}s having
3348 * {@link PhoneAccount#CAPABILITY_CONNECTION_MANAGER}. This parameter will contain
3349 * one of these {@code PhoneAccount}s, while the {@code request} will contain another
3350 * (usually but not always distinct) {@code PhoneAccount} to be used for actually
3351 * making the connection.
3352 * <p>
3353 * If this parameter is {@code null}, it means that this {@code ConnectionService} is
3354 * being asked to make a direct connection. The
3355 * {@link ConnectionRequest#getAccountHandle()} of parameter {@code request} will be
3356 * a {@code PhoneAccount} registered by this {@code ConnectionService} to use for
3357 * making the connection.
3358 * @param request Details about the outgoing call.
3359 * @return The {@code Connection} object to satisfy this call, or the result of an invocation
Andrew Lee7f3d41f2014-09-11 17:33:16 -07003360 * of {@link Connection#createFailedConnection(DisconnectCause)} to not handle the call.
Sailesh Nepalc5b01572014-07-14 16:29:44 -07003361 */
Ihab Awadf8b69882014-07-25 15:14:01 -07003362 public Connection onCreateOutgoingConnection(
3363 PhoneAccountHandle connectionManagerPhoneAccount,
3364 ConnectionRequest request) {
3365 return null;
3366 }
Ihab Awad542e0ea2014-05-16 10:22:16 -07003367
3368 /**
Ravi Paluri80aa2142019-12-02 11:57:37 +05303369 * Create a {@code Conference} given an outgoing request. This is used to initiate new
Grace Jia8587ee52020-07-10 15:42:32 -07003370 * outgoing conference call requested via
3371 * {@link TelecomManager#startConference(List, Bundle)}.
Ravi Paluri80aa2142019-12-02 11:57:37 +05303372 *
3373 * @param connectionManagerPhoneAccount The connection manager account to use for managing
3374 * this call.
3375 * <p>
3376 * If this parameter is not {@code null}, it means that this {@code ConnectionService}
3377 * has registered one or more {@code PhoneAccount}s having
3378 * {@link PhoneAccount#CAPABILITY_CONNECTION_MANAGER}. This parameter will contain
3379 * one of these {@code PhoneAccount}s, while the {@code request} will contain another
3380 * (usually but not always distinct) {@code PhoneAccount} to be used for actually
3381 * making the connection.
3382 * <p>
3383 * If this parameter is {@code null}, it means that this {@code ConnectionService} is
3384 * being asked to make a direct connection. The
3385 * {@link ConnectionRequest#getAccountHandle()} of parameter {@code request} will be
3386 * a {@code PhoneAccount} registered by this {@code ConnectionService} to use for
3387 * making the connection.
3388 * @param request Details about the outgoing call.
Grace Jia41895152021-01-19 13:57:51 -08003389 * @return The {@code Conference} object to satisfy this call. If the conference attempt is
3390 * failed, the return value will be a result of an invocation of
3391 * {@link Connection#createFailedConnection(DisconnectCause)}.
3392 * Return {@code null} if the {@link ConnectionService} cannot handle the call.
Ravi Paluri80aa2142019-12-02 11:57:37 +05303393 */
3394 public @Nullable Conference onCreateOutgoingConference(
Grace Jia41895152021-01-19 13:57:51 -08003395 @NonNull PhoneAccountHandle connectionManagerPhoneAccount,
3396 @NonNull ConnectionRequest request) {
Ravi Paluri80aa2142019-12-02 11:57:37 +05303397 return null;
3398 }
3399
3400
3401 /**
Tyler Gunn9d127732018-03-02 15:45:51 -08003402 * Called by Telecom to request that a {@link ConnectionService} creates an instance of an
3403 * outgoing handover {@link Connection}.
3404 * <p>
3405 * A call handover is the process where an ongoing call is transferred from one app (i.e.
3406 * {@link ConnectionService} to another app. The user could, for example, choose to continue a
3407 * mobile network call in a video calling app. The mobile network call via the Telephony stack
3408 * is referred to as the source of the handover, and the video calling app is referred to as the
3409 * destination.
3410 * <p>
3411 * When considering a handover scenario the <em>initiating</em> device is where a user initiated
3412 * the handover process (e.g. by calling {@link android.telecom.Call#handoverTo(
3413 * PhoneAccountHandle, int, Bundle)}, and the other device is considered the <em>receiving</em>
3414 * device.
3415 * <p>
3416 * This method is called on the destination {@link ConnectionService} on <em>initiating</em>
3417 * device when the user initiates a handover request from one app to another. The user request
3418 * originates in the {@link InCallService} via
3419 * {@link android.telecom.Call#handoverTo(PhoneAccountHandle, int, Bundle)}.
3420 * <p>
3421 * For a full discussion of the handover process and the APIs involved, see
3422 * {@link android.telecom.Call#handoverTo(PhoneAccountHandle, int, Bundle)}.
3423 * <p>
3424 * Implementations of this method should return an instance of {@link Connection} which
3425 * represents the handover. If your app does not wish to accept a handover to it at this time,
3426 * you can return {@code null}. The code below shows an example of how this is done.
3427 * <pre>
3428 * {@code
3429 * public Connection onCreateIncomingHandoverConnection(PhoneAccountHandle
3430 * fromPhoneAccountHandle, ConnectionRequest request) {
3431 * if (!isHandoverAvailable()) {
3432 * return null;
3433 * }
3434 * MyConnection connection = new MyConnection();
3435 * connection.setAddress(request.getAddress(), TelecomManager.PRESENTATION_ALLOWED);
3436 * connection.setVideoState(request.getVideoState());
3437 * return connection;
3438 * }
3439 * }
3440 * </pre>
3441 *
Sanket Padawea8eddd42017-11-03 11:07:35 -07003442 * @param fromPhoneAccountHandle {@link PhoneAccountHandle} associated with the
3443 * ConnectionService which needs to handover the call.
Tyler Gunn9d127732018-03-02 15:45:51 -08003444 * @param request Details about the call to handover.
3445 * @return {@link Connection} instance corresponding to the handover call.
Sanket Padawea8eddd42017-11-03 11:07:35 -07003446 */
3447 public Connection onCreateOutgoingHandoverConnection(PhoneAccountHandle fromPhoneAccountHandle,
3448 ConnectionRequest request) {
3449 return null;
3450 }
3451
3452 /**
Tyler Gunn9d127732018-03-02 15:45:51 -08003453 * Called by Telecom to request that a {@link ConnectionService} creates an instance of an
3454 * incoming handover {@link Connection}.
3455 * <p>
3456 * A call handover is the process where an ongoing call is transferred from one app (i.e.
3457 * {@link ConnectionService} to another app. The user could, for example, choose to continue a
3458 * mobile network call in a video calling app. The mobile network call via the Telephony stack
3459 * is referred to as the source of the handover, and the video calling app is referred to as the
3460 * destination.
3461 * <p>
3462 * When considering a handover scenario the <em>initiating</em> device is where a user initiated
3463 * the handover process (e.g. by calling {@link android.telecom.Call#handoverTo(
3464 * PhoneAccountHandle, int, Bundle)}, and the other device is considered the <em>receiving</em>
3465 * device.
3466 * <p>
3467 * This method is called on the destination app on the <em>receiving</em> device when the
3468 * destination app calls {@link TelecomManager#acceptHandover(Uri, int, PhoneAccountHandle)} to
3469 * accept an incoming handover from the <em>initiating</em> device.
3470 * <p>
3471 * For a full discussion of the handover process and the APIs involved, see
3472 * {@link android.telecom.Call#handoverTo(PhoneAccountHandle, int, Bundle)}.
3473 * <p>
3474 * Implementations of this method should return an instance of {@link Connection} which
3475 * represents the handover. The code below shows an example of how this is done.
3476 * <pre>
3477 * {@code
3478 * public Connection onCreateIncomingHandoverConnection(PhoneAccountHandle
3479 * fromPhoneAccountHandle, ConnectionRequest request) {
3480 * // Given that your app requested to accept the handover, you should not return null here.
3481 * MyConnection connection = new MyConnection();
3482 * connection.setAddress(request.getAddress(), TelecomManager.PRESENTATION_ALLOWED);
3483 * connection.setVideoState(request.getVideoState());
3484 * return connection;
3485 * }
3486 * }
3487 * </pre>
3488 *
Sanket Padawea8eddd42017-11-03 11:07:35 -07003489 * @param fromPhoneAccountHandle {@link PhoneAccountHandle} associated with the
3490 * ConnectionService which needs to handover the call.
3491 * @param request Details about the call which needs to be handover.
Tyler Gunn9d127732018-03-02 15:45:51 -08003492 * @return {@link Connection} instance corresponding to the handover call.
Sanket Padawea8eddd42017-11-03 11:07:35 -07003493 */
3494 public Connection onCreateIncomingHandoverConnection(PhoneAccountHandle fromPhoneAccountHandle,
3495 ConnectionRequest request) {
3496 return null;
3497 }
3498
3499 /**
3500 * Called by Telecom in response to a {@code TelecomManager#acceptHandover()}
3501 * invocation which failed.
Tyler Gunn9d127732018-03-02 15:45:51 -08003502 * <p>
3503 * For a full discussion of the handover process and the APIs involved, see
3504 * {@link android.telecom.Call#handoverTo(PhoneAccountHandle, int, Bundle)}
3505 *
3506 * @param request Details about the call which failed to handover.
3507 * @param error Reason for handover failure. Will be one of the
Sanket Padawea8eddd42017-11-03 11:07:35 -07003508 */
Tyler Gunn9d127732018-03-02 15:45:51 -08003509 public void onHandoverFailed(ConnectionRequest request,
3510 @Call.Callback.HandoverFailureErrors int error) {
Sanket Padawea8eddd42017-11-03 11:07:35 -07003511 return;
3512 }
3513
3514 /**
Roopa Sattiraju45de470c2022-01-27 21:31:35 -08003515 * Calls of this type are created using
3516 * {@link TelecomManager#addNewUnknownCall(PhoneAccountHandle, Bundle)}. Unknown calls
3517 * are used for representing calls which become known to the {@link ConnectionService}
3518 * midway through the call.
3519 *
3520 * For example, a call transferred from one device to answer would surface as an active
3521 * call in Telecom instead of going through a typical Ringing to Active transition, or
3522 * Dialing to Active transition.
3523 *
3524 * A {@link ConnectionService} can return {@code null} (the default behavior)
3525 * if it is not able to handle a request for the requested unknown connection.
3526 *
3527 * {@link TelecomManager#addNewIncomingCall(PhoneAccountHandle, android.os.Bundle)}.
Yorke Leec3cf9822014-10-02 09:38:39 -07003528 *
Etienne Ruffieuxb99333d2022-02-25 16:11:01 +00003529 * @param connectionManagerPhoneAccount The connection manager account to use for managing
3530 * this call
3531 * @param request Details about the outgoing call
3532 * @return The {@code Connection} object to satisfy this call, or the result of an invocation
3533 * of {@link Connection#createFailedConnection(DisconnectCause)} to not handle the call
Yorke Lee770ed6e2014-10-06 18:58:52 -07003534 * @hide
Yorke Leec3cf9822014-10-02 09:38:39 -07003535 */
Etienne Ruffieuxb99333d2022-02-25 16:11:01 +00003536 @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
Roopa Sattiraju45de470c2022-01-27 21:31:35 -08003537 @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
3538 public @Nullable Connection onCreateUnknownConnection(
3539 @NonNull PhoneAccountHandle connectionManagerPhoneAccount,
3540 @NonNull ConnectionRequest request) {
Brad Ebingerb32d4f82016-10-24 16:40:49 -07003541 return null;
Yorke Leec3cf9822014-10-02 09:38:39 -07003542 }
3543
3544 /**
Santos Cordon823fd3c2014-08-07 18:35:18 -07003545 * Conference two specified connections. Invoked when the user has made a request to merge the
3546 * specified connections into a conference call. In response, the connection service should
3547 * create an instance of {@link Conference} and pass it into {@link #addConference}.
Santos Cordonb6939982014-06-04 20:20:58 -07003548 *
Santos Cordon823fd3c2014-08-07 18:35:18 -07003549 * @param connection1 A connection to merge into a conference call.
3550 * @param connection2 A connection to merge into a conference call.
Santos Cordonb6939982014-06-04 20:20:58 -07003551 */
Santos Cordon823fd3c2014-08-07 18:35:18 -07003552 public void onConference(Connection connection1, Connection connection2) {}
Santos Cordonb6939982014-06-04 20:20:58 -07003553
Santos Cordona663f862014-10-29 13:49:58 -07003554 /**
Pengquan Meng70c9885332017-10-02 18:09:03 -07003555 * Called when a connection is added.
3556 * @hide
3557 */
3558 public void onConnectionAdded(Connection connection) {}
3559
3560 /**
3561 * Called when a connection is removed.
3562 * @hide
3563 */
3564 public void onConnectionRemoved(Connection connection) {}
3565
3566 /**
3567 * Called when a conference is added.
3568 * @hide
3569 */
3570 public void onConferenceAdded(Conference conference) {}
3571
3572 /**
3573 * Called when a conference is removed.
3574 * @hide
3575 */
3576 public void onConferenceRemoved(Conference conference) {}
3577
3578 /**
Santos Cordona663f862014-10-29 13:49:58 -07003579 * Indicates that a remote conference has been created for existing {@link RemoteConnection}s.
3580 * When this method is invoked, this {@link ConnectionService} should create its own
3581 * representation of the conference call and send it to telecom using {@link #addConference}.
3582 * <p>
3583 * This is only relevant to {@link ConnectionService}s which are registered with
3584 * {@link PhoneAccount#CAPABILITY_CONNECTION_MANAGER}.
3585 *
3586 * @param conference The remote conference call.
3587 */
Ihab Awadb8e85c72014-08-23 20:34:57 -07003588 public void onRemoteConferenceAdded(RemoteConference conference) {}
3589
Santos Cordon823fd3c2014-08-07 18:35:18 -07003590 /**
Tyler Gunn4a57b9b2014-10-30 14:27:48 -07003591 * Called when an existing connection is added remotely.
3592 * @param connection The existing connection which was added.
3593 */
3594 public void onRemoteExistingConnectionAdded(RemoteConnection connection) {}
3595
3596 /**
Pengquan Meng731c1a32017-11-21 18:01:13 -08003597 * Called when the {@link ConnectionService} has lost the call focus.
3598 * The {@link ConnectionService} should release the call resources and invokes
3599 * {@link ConnectionService#connectionServiceFocusReleased()} to inform telecom that it has
3600 * released the call resources.
3601 */
3602 public void onConnectionServiceFocusLost() {}
3603
3604 /**
3605 * Called when the {@link ConnectionService} has gained the call focus. The
3606 * {@link ConnectionService} can acquire the call resources at this time.
3607 */
3608 public void onConnectionServiceFocusGained() {}
3609
3610 /**
Santos Cordon823fd3c2014-08-07 18:35:18 -07003611 * @hide
3612 */
3613 public boolean containsConference(Conference conference) {
3614 return mIdByConference.containsKey(conference);
3615 }
3616
Ihab Awadb8e85c72014-08-23 20:34:57 -07003617 /** {@hide} */
3618 void addRemoteConference(RemoteConference remoteConference) {
3619 onRemoteConferenceAdded(remoteConference);
3620 }
3621
Tyler Gunn4a57b9b2014-10-30 14:27:48 -07003622 /** {@hide} */
3623 void addRemoteExistingConnection(RemoteConnection remoteConnection) {
3624 onRemoteExistingConnectionAdded(remoteConnection);
3625 }
3626
Ihab Awad5d0410f2014-07-30 10:07:40 -07003627 private void onAccountsInitialized() {
3628 mAreAccountsInitialized = true;
3629 for (Runnable r : mPreInitializationConnectionRequests) {
3630 r.run();
3631 }
3632 mPreInitializationConnectionRequests.clear();
3633 }
3634
Tyler Gunn4a57b9b2014-10-30 14:27:48 -07003635 /**
Tyler Gunnf0500bd2015-09-01 10:59:48 -07003636 * Adds an existing connection to the list of connections, identified by a new call ID unique
3637 * to this connection service.
Tyler Gunn4a57b9b2014-10-30 14:27:48 -07003638 *
3639 * @param connection The connection.
Tyler Gunnf0500bd2015-09-01 10:59:48 -07003640 * @return The ID of the connection (e.g. the call-id).
Tyler Gunn4a57b9b2014-10-30 14:27:48 -07003641 */
Tyler Gunnf0500bd2015-09-01 10:59:48 -07003642 private String addExistingConnectionInternal(PhoneAccountHandle handle, Connection connection) {
3643 String id;
Tyler Gunncd6ccfd2016-10-17 15:48:19 -07003644
3645 if (connection.getExtras() != null && connection.getExtras()
3646 .containsKey(Connection.EXTRA_ORIGINAL_CONNECTION_ID)) {
3647 id = connection.getExtras().getString(Connection.EXTRA_ORIGINAL_CONNECTION_ID);
3648 Log.d(this, "addExistingConnectionInternal - conn %s reusing original id %s",
3649 connection.getTelecomCallId(), id);
3650 } else if (handle == null) {
Tyler Gunnf0500bd2015-09-01 10:59:48 -07003651 // If no phone account handle was provided, we cannot be sure the call ID is unique,
3652 // so just use a random UUID.
3653 id = UUID.randomUUID().toString();
3654 } else {
3655 // Phone account handle was provided, so use the ConnectionService class name as a
3656 // prefix for a unique incremental call ID.
3657 id = handle.getComponentName().getClassName() + "@" + getNextCallId();
3658 }
Pengquan Meng70c9885332017-10-02 18:09:03 -07003659 addConnection(handle, id, connection);
Tyler Gunn4a57b9b2014-10-30 14:27:48 -07003660 return id;
3661 }
3662
Pengquan Meng70c9885332017-10-02 18:09:03 -07003663 private void addConnection(PhoneAccountHandle handle, String callId, Connection connection) {
Tyler Gunnf0500bd2015-09-01 10:59:48 -07003664 connection.setTelecomCallId(callId);
Ihab Awad542e0ea2014-05-16 10:22:16 -07003665 mConnectionById.put(callId, connection);
3666 mIdByConnection.put(connection, callId);
3667 connection.addConnectionListener(mConnectionListener);
Santos Cordon823fd3c2014-08-07 18:35:18 -07003668 connection.setConnectionService(this);
Pengquan Meng70c9885332017-10-02 18:09:03 -07003669 connection.setPhoneAccountHandle(handle);
3670 onConnectionAdded(connection);
Ihab Awad542e0ea2014-05-16 10:22:16 -07003671 }
3672
Anthony Lee30e65842014-11-06 16:30:53 -08003673 /** {@hide} */
3674 protected void removeConnection(Connection connection) {
Santos Cordon823fd3c2014-08-07 18:35:18 -07003675 connection.unsetConnectionService(this);
Ihab Awad542e0ea2014-05-16 10:22:16 -07003676 connection.removeConnectionListener(mConnectionListener);
Chenjie Luoe370b532016-05-12 16:59:43 -07003677 String id = mIdByConnection.get(connection);
3678 if (id != null) {
3679 mConnectionById.remove(id);
3680 mIdByConnection.remove(connection);
3681 mAdapter.removeCall(id);
Pengquan Meng70c9885332017-10-02 18:09:03 -07003682 onConnectionRemoved(connection);
Chenjie Luoe370b532016-05-12 16:59:43 -07003683 }
Ihab Awad542e0ea2014-05-16 10:22:16 -07003684 }
3685
Santos Cordon823fd3c2014-08-07 18:35:18 -07003686 private String addConferenceInternal(Conference conference) {
Tyler Gunncd6ccfd2016-10-17 15:48:19 -07003687 String originalId = null;
3688 if (conference.getExtras() != null && conference.getExtras()
3689 .containsKey(Connection.EXTRA_ORIGINAL_CONNECTION_ID)) {
3690 originalId = conference.getExtras().getString(Connection.EXTRA_ORIGINAL_CONNECTION_ID);
3691 Log.d(this, "addConferenceInternal: conf %s reusing original id %s",
3692 conference.getTelecomCallId(),
3693 originalId);
3694 }
Santos Cordon823fd3c2014-08-07 18:35:18 -07003695 if (mIdByConference.containsKey(conference)) {
3696 Log.w(this, "Re-adding an existing conference: %s.", conference);
3697 } else if (conference != null) {
Tyler Gunnf0500bd2015-09-01 10:59:48 -07003698 // Conferences do not (yet) have a PhoneAccountHandle associated with them, so we
3699 // cannot determine a ConnectionService class name to associate with the ID, so use
3700 // a unique UUID (for now).
Tyler Gunncd6ccfd2016-10-17 15:48:19 -07003701 String id = originalId == null ? UUID.randomUUID().toString() : originalId;
Santos Cordon823fd3c2014-08-07 18:35:18 -07003702 mConferenceById.put(id, conference);
3703 mIdByConference.put(conference, id);
3704 conference.addListener(mConferenceListener);
3705 return id;
3706 }
3707
3708 return null;
3709 }
3710
3711 private void removeConference(Conference conference) {
3712 if (mIdByConference.containsKey(conference)) {
3713 conference.removeListener(mConferenceListener);
3714
3715 String id = mIdByConference.get(conference);
3716 mConferenceById.remove(id);
3717 mIdByConference.remove(conference);
3718 mAdapter.removeCall(id);
Pengquan Meng70c9885332017-10-02 18:09:03 -07003719
3720 onConferenceRemoved(conference);
Santos Cordon823fd3c2014-08-07 18:35:18 -07003721 }
3722 }
3723
Ihab Awad542e0ea2014-05-16 10:22:16 -07003724 private Connection findConnectionForAction(String callId, String action) {
Tyler Gunn0a88f2e2017-06-16 20:20:34 -07003725 if (callId != null && mConnectionById.containsKey(callId)) {
Ihab Awad542e0ea2014-05-16 10:22:16 -07003726 return mConnectionById.get(callId);
3727 }
Ihab Awad60ac30b2014-05-20 22:32:12 -07003728 Log.w(this, "%s - Cannot find Connection %s", action, callId);
Sailesh Nepalcf7020b2014-08-20 10:07:19 -07003729 return getNullConnection();
3730 }
3731
3732 static synchronized Connection getNullConnection() {
3733 if (sNullConnection == null) {
3734 sNullConnection = new Connection() {};
3735 }
3736 return sNullConnection;
Santos Cordon7c7bc7f2014-07-28 18:15:48 -07003737 }
Santos Cordon0159ac02014-08-21 14:28:11 -07003738
3739 private Conference findConferenceForAction(String conferenceId, String action) {
3740 if (mConferenceById.containsKey(conferenceId)) {
3741 return mConferenceById.get(conferenceId);
3742 }
3743 Log.w(this, "%s - Cannot find conference %s", action, conferenceId);
3744 return getNullConference();
3745 }
3746
Ihab Awadb8e85c72014-08-23 20:34:57 -07003747 private List<String> createConnectionIdList(List<Connection> connections) {
3748 List<String> ids = new ArrayList<>();
3749 for (Connection c : connections) {
3750 if (mIdByConnection.containsKey(c)) {
3751 ids.add(mIdByConnection.get(c));
3752 }
3753 }
3754 Collections.sort(ids);
3755 return ids;
3756 }
3757
Tyler Gunn6d76ca02014-11-17 15:49:51 -08003758 /**
3759 * Builds a list of {@link Connection} and {@link Conference} IDs based on the list of
Tyler Gunndf2cbc82015-04-20 09:13:01 -07003760 * {@link Conferenceable}s passed in.
Tyler Gunn6d76ca02014-11-17 15:49:51 -08003761 *
Tyler Gunndf2cbc82015-04-20 09:13:01 -07003762 * @param conferenceables The {@link Conferenceable} connections and conferences.
Tyler Gunn6d76ca02014-11-17 15:49:51 -08003763 * @return List of string conference and call Ids.
3764 */
Tyler Gunndf2cbc82015-04-20 09:13:01 -07003765 private List<String> createIdList(List<Conferenceable> conferenceables) {
Tyler Gunn6d76ca02014-11-17 15:49:51 -08003766 List<String> ids = new ArrayList<>();
Tyler Gunndf2cbc82015-04-20 09:13:01 -07003767 for (Conferenceable c : conferenceables) {
Tyler Gunn6d76ca02014-11-17 15:49:51 -08003768 // Only allow Connection and Conference conferenceables.
3769 if (c instanceof Connection) {
3770 Connection connection = (Connection) c;
3771 if (mIdByConnection.containsKey(connection)) {
3772 ids.add(mIdByConnection.get(connection));
3773 }
3774 } else if (c instanceof Conference) {
3775 Conference conference = (Conference) c;
3776 if (mIdByConference.containsKey(conference)) {
3777 ids.add(mIdByConference.get(conference));
3778 }
3779 }
3780 }
3781 Collections.sort(ids);
3782 return ids;
3783 }
3784
Santos Cordon0159ac02014-08-21 14:28:11 -07003785 private Conference getNullConference() {
3786 if (sNullConference == null) {
3787 sNullConference = new Conference(null) {};
3788 }
3789 return sNullConference;
3790 }
Santos Cordon29f2f2e2014-09-11 19:50:24 -07003791
3792 private void endAllConnections() {
3793 // Unbound from telecomm. We should end all connections and conferences.
3794 for (Connection connection : mIdByConnection.keySet()) {
3795 // only operate on top-level calls. Conference calls will be removed on their own.
3796 if (connection.getConference() == null) {
3797 connection.onDisconnect();
3798 }
3799 }
3800 for (Conference conference : mIdByConference.keySet()) {
3801 conference.onDisconnect();
3802 }
3803 }
Tyler Gunnf0500bd2015-09-01 10:59:48 -07003804
3805 /**
3806 * Retrieves the next call ID as maintainted by the connection service.
3807 *
3808 * @return The call ID.
3809 */
3810 private int getNextCallId() {
Brad Ebingerb32d4f82016-10-24 16:40:49 -07003811 synchronized (mIdSyncRoot) {
Tyler Gunnf0500bd2015-09-01 10:59:48 -07003812 return ++mId;
3813 }
3814 }
Brad Ebinger99f17ce2019-09-11 18:06:51 -07003815
3816 /**
3817 * Returns this handler, ONLY FOR TESTING.
3818 * @hide
3819 */
3820 @VisibleForTesting
3821 public Handler getHandler() {
3822 return mHandler;
3823 }
Tyler Gunnc7e07b92021-04-06 11:40:57 -07003824
3825 /**
3826 * Sets this {@link ConnectionService} ready for testing purposes.
3827 * @hide
3828 */
3829 @VisibleForTesting
3830 public void setReadyForTest() {
3831 mAreAccountsInitialized = true;
3832 }
Santos Cordon980acb92014-05-31 10:31:19 -07003833}