blob: 92233b1fed3925d61fec9d507d91fdda98e28d27 [file] [log] [blame]
Ihab Awade63fadb2014-07-09 21:52:04 -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 Awade63fadb2014-07-09 21:52:04 -070018
Hall Liu95d55872017-01-25 17:12:49 -080019import android.annotation.IntDef;
20import android.annotation.Nullable;
Andrew Leeda80c872015-04-15 14:09:50 -070021import android.annotation.SystemApi;
Ihab Awade63fadb2014-07-09 21:52:04 -070022import android.net.Uri;
Nancy Chen10798dc2014-08-08 14:00:25 -070023import android.os.Bundle;
Andrew Lee011728f2015-04-23 15:47:06 -070024import android.os.Handler;
Hall Liu95d55872017-01-25 17:12:49 -080025import android.os.ParcelFileDescriptor;
Ihab Awade63fadb2014-07-09 21:52:04 -070026
Hall Liu95d55872017-01-25 17:12:49 -080027import java.io.IOException;
28import java.io.InputStreamReader;
29import java.io.OutputStreamWriter;
Andrew Lee50aca232014-07-22 16:41:54 -070030import java.lang.String;
Hall Liu95d55872017-01-25 17:12:49 -080031import java.lang.annotation.Retention;
32import java.lang.annotation.RetentionPolicy;
33import java.nio.charset.StandardCharsets;
Ihab Awade63fadb2014-07-09 21:52:04 -070034import java.util.ArrayList;
Tyler Gunn071be6f2016-05-10 14:52:33 -070035import java.util.Arrays;
Ihab Awade63fadb2014-07-09 21:52:04 -070036import java.util.Collections;
37import java.util.List;
Santos Cordon7c7bc7f2014-07-28 18:15:48 -070038import java.util.Map;
Ihab Awade63fadb2014-07-09 21:52:04 -070039import java.util.Objects;
Jay Shrauner229e3822014-08-15 09:23:07 -070040import java.util.concurrent.CopyOnWriteArrayList;
Ihab Awade63fadb2014-07-09 21:52:04 -070041
42/**
43 * Represents an ongoing phone call that the in-call app should present to the user.
44 */
45public final class Call {
46 /**
47 * The state of a {@code Call} when newly created.
48 */
49 public static final int STATE_NEW = 0;
50
51 /**
52 * The state of an outgoing {@code Call} when dialing the remote number, but not yet connected.
53 */
54 public static final int STATE_DIALING = 1;
55
56 /**
57 * The state of an incoming {@code Call} when ringing locally, but not yet connected.
58 */
59 public static final int STATE_RINGING = 2;
60
61 /**
62 * The state of a {@code Call} when in a holding state.
63 */
64 public static final int STATE_HOLDING = 3;
65
66 /**
67 * The state of a {@code Call} when actively supporting conversation.
68 */
69 public static final int STATE_ACTIVE = 4;
70
71 /**
72 * The state of a {@code Call} when no further voice or other communication is being
73 * transmitted, the remote side has been or will inevitably be informed that the {@code Call}
74 * is no longer active, and the local data transport has or inevitably will release resources
75 * associated with this {@code Call}.
76 */
77 public static final int STATE_DISCONNECTED = 7;
78
Nancy Chen5da0fd52014-07-08 14:16:17 -070079 /**
Santos Cordone3c507b2015-04-23 14:44:19 -070080 * The state of an outgoing {@code Call} when waiting on user to select a
81 * {@link PhoneAccount} through which to place the call.
Nancy Chen5da0fd52014-07-08 14:16:17 -070082 */
Santos Cordone3c507b2015-04-23 14:44:19 -070083 public static final int STATE_SELECT_PHONE_ACCOUNT = 8;
84
85 /**
86 * @hide
87 * @deprecated use STATE_SELECT_PHONE_ACCOUNT.
88 */
89 @Deprecated
90 @SystemApi
91 public static final int STATE_PRE_DIAL_WAIT = STATE_SELECT_PHONE_ACCOUNT;
Nancy Chen5da0fd52014-07-08 14:16:17 -070092
Nancy Chene20930f2014-08-07 16:17:21 -070093 /**
Nancy Chene9b7a8e2014-08-08 14:26:27 -070094 * The initial state of an outgoing {@code Call}.
95 * Common transitions are to {@link #STATE_DIALING} state for a successful call or
96 * {@link #STATE_DISCONNECTED} if it failed.
Nancy Chene20930f2014-08-07 16:17:21 -070097 */
98 public static final int STATE_CONNECTING = 9;
99
Nancy Chen513c8922014-09-17 14:47:20 -0700100 /**
Tyler Gunn4afc6af2014-10-07 10:14:55 -0700101 * The state of a {@code Call} when the user has initiated a disconnection of the call, but the
102 * call has not yet been disconnected by the underlying {@code ConnectionService}. The next
103 * state of the call is (potentially) {@link #STATE_DISCONNECTED}.
104 */
105 public static final int STATE_DISCONNECTING = 10;
106
107 /**
Tyler Gunn876dbfb2016-03-14 15:18:07 -0700108 * The state of an external call which is in the process of being pulled from a remote device to
109 * the local device.
110 * <p>
111 * A call can only be in this state if the {@link Details#PROPERTY_IS_EXTERNAL_CALL} property
112 * and {@link Details#CAPABILITY_CAN_PULL_CALL} capability are set on the call.
113 * <p>
114 * An {@link InCallService} will only see this state if it has the
115 * {@link TelecomManager#METADATA_INCLUDE_EXTERNAL_CALLS} metadata set to {@code true} in its
116 * manifest.
117 */
118 public static final int STATE_PULLING_CALL = 11;
119
120 /**
Nancy Chen513c8922014-09-17 14:47:20 -0700121 * The key to retrieve the optional {@code PhoneAccount}s Telecom can bundle with its Call
122 * extras. Used to pass the phone accounts to display on the front end to the user in order to
123 * select phone accounts to (for example) place a call.
Nancy Chen513c8922014-09-17 14:47:20 -0700124 */
125 public static final String AVAILABLE_PHONE_ACCOUNTS = "selectPhoneAccountAccounts";
126
mike dooley4af561f2016-12-20 08:55:17 -0800127 /**
mike dooley91217422017-03-09 12:58:42 -0800128 * Extra key used to indicate the time (in milliseconds since midnight, January 1, 1970 UTC)
129 * when the last outgoing emergency call was made. This is used to identify potential emergency
130 * callbacks.
mike dooley4af561f2016-12-20 08:55:17 -0800131 */
132 public static final String EXTRA_LAST_EMERGENCY_CALLBACK_TIME_MILLIS =
133 "android.telecom.extra.LAST_EMERGENCY_CALLBACK_TIME_MILLIS";
134
Ihab Awade63fadb2014-07-09 21:52:04 -0700135 public static class Details {
Ihab Awad5c9c86e2014-11-12 13:41:16 -0800136
137 /** Call can currently be put on hold or unheld. */
138 public static final int CAPABILITY_HOLD = 0x00000001;
139
140 /** Call supports the hold feature. */
141 public static final int CAPABILITY_SUPPORT_HOLD = 0x00000002;
142
143 /**
144 * Calls within a conference can be merged. A {@link ConnectionService} has the option to
145 * add a {@link Conference} call before the child {@link Connection}s are merged. This is how
146 * CDMA-based {@link Connection}s are implemented. For these unmerged {@link Conference}s, this
147 * capability allows a merge button to be shown while the conference call is in the foreground
148 * of the in-call UI.
149 * <p>
150 * This is only intended for use by a {@link Conference}.
151 */
152 public static final int CAPABILITY_MERGE_CONFERENCE = 0x00000004;
153
154 /**
155 * Calls within a conference can be swapped between foreground and background.
156 * See {@link #CAPABILITY_MERGE_CONFERENCE} for additional information.
157 * <p>
158 * This is only intended for use by a {@link Conference}.
159 */
160 public static final int CAPABILITY_SWAP_CONFERENCE = 0x00000008;
161
162 /**
163 * @hide
164 */
Andrew Lee2378ea72015-04-29 14:38:11 -0700165 public static final int CAPABILITY_UNUSED_1 = 0x00000010;
Ihab Awad5c9c86e2014-11-12 13:41:16 -0800166
167 /** Call supports responding via text option. */
168 public static final int CAPABILITY_RESPOND_VIA_TEXT = 0x00000020;
169
170 /** Call can be muted. */
171 public static final int CAPABILITY_MUTE = 0x00000040;
172
173 /**
174 * Call supports conference call management. This capability only applies to {@link Conference}
175 * calls which can have {@link Connection}s as children.
176 */
177 public static final int CAPABILITY_MANAGE_CONFERENCE = 0x00000080;
178
179 /**
Andrew Lee5e9e8bb2015-03-10 13:58:24 -0700180 * Local device supports receiving video.
Ihab Awad5c9c86e2014-11-12 13:41:16 -0800181 */
Andrew Lee5e9e8bb2015-03-10 13:58:24 -0700182 public static final int CAPABILITY_SUPPORTS_VT_LOCAL_RX = 0x00000100;
Ihab Awad5c9c86e2014-11-12 13:41:16 -0800183
184 /**
Andrew Lee5e9e8bb2015-03-10 13:58:24 -0700185 * Local device supports transmitting video.
Ihab Awad5c9c86e2014-11-12 13:41:16 -0800186 */
Andrew Lee5e9e8bb2015-03-10 13:58:24 -0700187 public static final int CAPABILITY_SUPPORTS_VT_LOCAL_TX = 0x00000200;
Ihab Awad5c9c86e2014-11-12 13:41:16 -0800188
189 /**
Andrew Lee5e9e8bb2015-03-10 13:58:24 -0700190 * Local device supports bidirectional video calling.
Ihab Awad5c9c86e2014-11-12 13:41:16 -0800191 */
Andrew Lee9a8f9ce2015-04-10 18:09:46 -0700192 public static final int CAPABILITY_SUPPORTS_VT_LOCAL_BIDIRECTIONAL =
Andrew Lee5e9e8bb2015-03-10 13:58:24 -0700193 CAPABILITY_SUPPORTS_VT_LOCAL_RX | CAPABILITY_SUPPORTS_VT_LOCAL_TX;
Ihab Awad5c9c86e2014-11-12 13:41:16 -0800194
195 /**
Andrew Lee5e9e8bb2015-03-10 13:58:24 -0700196 * Remote device supports receiving video.
Ihab Awad5c9c86e2014-11-12 13:41:16 -0800197 */
Andrew Lee5e9e8bb2015-03-10 13:58:24 -0700198 public static final int CAPABILITY_SUPPORTS_VT_REMOTE_RX = 0x00000400;
199
200 /**
201 * Remote device supports transmitting video.
Andrew Lee5e9e8bb2015-03-10 13:58:24 -0700202 */
203 public static final int CAPABILITY_SUPPORTS_VT_REMOTE_TX = 0x00000800;
204
205 /**
206 * Remote device supports bidirectional video calling.
Andrew Lee5e9e8bb2015-03-10 13:58:24 -0700207 */
Andrew Lee9a8f9ce2015-04-10 18:09:46 -0700208 public static final int CAPABILITY_SUPPORTS_VT_REMOTE_BIDIRECTIONAL =
Andrew Lee5e9e8bb2015-03-10 13:58:24 -0700209 CAPABILITY_SUPPORTS_VT_REMOTE_RX | CAPABILITY_SUPPORTS_VT_REMOTE_TX;
Ihab Awad5c9c86e2014-11-12 13:41:16 -0800210
211 /**
212 * Call is able to be separated from its parent {@code Conference}, if any.
213 */
214 public static final int CAPABILITY_SEPARATE_FROM_CONFERENCE = 0x00001000;
215
216 /**
217 * Call is able to be individually disconnected when in a {@code Conference}.
218 */
219 public static final int CAPABILITY_DISCONNECT_FROM_CONFERENCE = 0x00002000;
220
221 /**
Dong Zhou89f41eb2015-03-15 11:59:49 -0500222 * Speed up audio setup for MT call.
223 * @hide
224 */
Tyler Gunn96d6c402015-03-18 12:39:23 -0700225 public static final int CAPABILITY_SPEED_UP_MT_AUDIO = 0x00040000;
226
Tyler Gunnb5e0cfb2015-04-07 16:10:51 -0700227 /**
228 * Call can be upgraded to a video call.
Rekha Kumar07366812015-03-24 16:42:31 -0700229 * @hide
230 */
231 public static final int CAPABILITY_CAN_UPGRADE_TO_VIDEO = 0x00080000;
232
Tyler Gunnb5e0cfb2015-04-07 16:10:51 -0700233 /**
234 * For video calls, indicates whether the outgoing video for the call can be paused using
Yorke Lee32f24732015-05-12 16:18:03 -0700235 * the {@link android.telecom.VideoProfile#STATE_PAUSED} VideoState.
Tyler Gunnb5e0cfb2015-04-07 16:10:51 -0700236 */
237 public static final int CAPABILITY_CAN_PAUSE_VIDEO = 0x00100000;
238
Bryce Lee81901682015-08-28 16:38:02 -0700239 /**
240 * Call sends responses through connection.
241 * @hide
242 */
Tyler Gunnf97a0092016-01-19 15:59:34 -0800243 public static final int CAPABILITY_CAN_SEND_RESPONSE_VIA_CONNECTION = 0x00200000;
244
245 /**
246 * When set, prevents a video {@code Call} from being downgraded to an audio-only call.
247 * <p>
248 * Should be set when the VideoState has the {@link VideoProfile#STATE_TX_ENABLED} or
249 * {@link VideoProfile#STATE_RX_ENABLED} bits set to indicate that the connection cannot be
250 * downgraded from a video call back to a VideoState of
251 * {@link VideoProfile#STATE_AUDIO_ONLY}.
252 * <p>
253 * Intuitively, a call which can be downgraded to audio should also have local and remote
254 * video
255 * capabilities (see {@link #CAPABILITY_SUPPORTS_VT_LOCAL_BIDIRECTIONAL} and
256 * {@link #CAPABILITY_SUPPORTS_VT_REMOTE_BIDIRECTIONAL}).
257 */
258 public static final int CAPABILITY_CANNOT_DOWNGRADE_VIDEO_TO_AUDIO = 0x00400000;
Bryce Lee81901682015-08-28 16:38:02 -0700259
Tyler Gunn876dbfb2016-03-14 15:18:07 -0700260 /**
261 * When set for an external call, indicates that this {@code Call} can be pulled from a
262 * remote device to the current device.
263 * <p>
264 * Should only be set on a {@code Call} where {@link #PROPERTY_IS_EXTERNAL_CALL} is set.
265 * <p>
266 * An {@link InCallService} will only see calls with this capability if it has the
267 * {@link TelecomManager#METADATA_INCLUDE_EXTERNAL_CALLS} metadata set to {@code true}
268 * in its manifest.
269 * <p>
270 * See {@link Connection#CAPABILITY_CAN_PULL_CALL} and
Tyler Gunn720c6642016-03-22 09:02:47 -0700271 * {@link Connection#PROPERTY_IS_EXTERNAL_CALL}.
Tyler Gunn876dbfb2016-03-14 15:18:07 -0700272 */
273 public static final int CAPABILITY_CAN_PULL_CALL = 0x00800000;
274
Tyler Gunnd11a3152015-03-18 13:09:14 -0700275 //******************************************************************************************
Tyler Gunn876dbfb2016-03-14 15:18:07 -0700276 // Next CAPABILITY value: 0x01000000
Andrew Lee2378ea72015-04-29 14:38:11 -0700277 //******************************************************************************************
278
279 /**
280 * Whether the call is currently a conference.
281 */
282 public static final int PROPERTY_CONFERENCE = 0x00000001;
283
284 /**
285 * Whether the call is a generic conference, where we do not know the precise state of
286 * participants in the conference (eg. on CDMA).
287 */
288 public static final int PROPERTY_GENERIC_CONFERENCE = 0x00000002;
289
290 /**
291 * Whether the call is made while the device is in emergency callback mode.
292 */
293 public static final int PROPERTY_EMERGENCY_CALLBACK_MODE = 0x00000004;
294
295 /**
296 * Connection is using WIFI.
297 */
298 public static final int PROPERTY_WIFI = 0x00000008;
299
300 /**
301 * Call is using high definition audio.
302 */
303 public static final int PROPERTY_HIGH_DEF_AUDIO = 0x00000010;
304
Tony Maka68dcce2015-12-17 09:31:18 +0000305 /**
Tony Mak53b5df42016-05-19 13:40:38 +0100306 * Whether the call is associated with the work profile.
307 */
308 public static final int PROPERTY_ENTERPRISE_CALL = 0x00000020;
309
310 /**
Tyler Gunn876dbfb2016-03-14 15:18:07 -0700311 * When set, indicates that this {@code Call} does not actually exist locally for the
312 * {@link ConnectionService}.
313 * <p>
314 * Consider, for example, a scenario where a user has two phones with the same phone number.
315 * When a user places a call on one device, the telephony stack can represent that call on
316 * the other device by adding it to the {@link ConnectionService} with the
Tyler Gunn720c6642016-03-22 09:02:47 -0700317 * {@link Connection#PROPERTY_IS_EXTERNAL_CALL} property set.
Tyler Gunn876dbfb2016-03-14 15:18:07 -0700318 * <p>
319 * An {@link InCallService} will only see calls with this property if it has the
320 * {@link TelecomManager#METADATA_INCLUDE_EXTERNAL_CALLS} metadata set to {@code true}
321 * in its manifest.
322 * <p>
Tyler Gunn720c6642016-03-22 09:02:47 -0700323 * See {@link Connection#PROPERTY_IS_EXTERNAL_CALL}.
Tyler Gunn876dbfb2016-03-14 15:18:07 -0700324 */
325 public static final int PROPERTY_IS_EXTERNAL_CALL = 0x00000040;
326
Brad Ebinger15847072016-05-18 11:08:36 -0700327 /**
328 * Indicates that the call has CDMA Enhanced Voice Privacy enabled.
329 */
330 public static final int PROPERTY_HAS_CDMA_VOICE_PRIVACY = 0x00000080;
331
Tyler Gunn24e18332017-02-10 09:42:49 -0800332 /**
333 * Indicates that the call is from a self-managed {@link ConnectionService}.
334 * <p>
335 * See also {@link Connection#PROPERTY_SELF_MANAGED}
336 */
337 public static final int PROPERTY_SELF_MANAGED = 0x00000100;
338
Andrew Lee2378ea72015-04-29 14:38:11 -0700339 //******************************************************************************************
Tyler Gunn24e18332017-02-10 09:42:49 -0800340 // Next PROPERTY value: 0x00000200
Tyler Gunnd11a3152015-03-18 13:09:14 -0700341 //******************************************************************************************
Tyler Gunn068085b2015-02-06 13:56:52 -0800342
Sailesh Nepal1bef3392016-01-24 18:21:53 -0800343 private final String mTelecomCallId;
Ihab Awade63fadb2014-07-09 21:52:04 -0700344 private final Uri mHandle;
345 private final int mHandlePresentation;
346 private final String mCallerDisplayName;
347 private final int mCallerDisplayNamePresentation;
Evan Charlton8c8a0622014-07-20 12:31:00 -0700348 private final PhoneAccountHandle mAccountHandle;
Ihab Awad5d0410f2014-07-30 10:07:40 -0700349 private final int mCallCapabilities;
Andrew Lee223ad142014-08-27 16:33:08 -0700350 private final int mCallProperties;
Christine Hallstrom4e22d6d2016-11-30 16:06:42 -0800351 private final int mSupportedAudioRoutes = CallAudioState.ROUTE_ALL;
Andrew Lee7f3d41f2014-09-11 17:33:16 -0700352 private final DisconnectCause mDisconnectCause;
Ihab Awade63fadb2014-07-09 21:52:04 -0700353 private final long mConnectTimeMillis;
354 private final GatewayInfo mGatewayInfo;
Andrew Lee85f5d422014-07-11 17:22:03 -0700355 private final int mVideoState;
Evan Charlton5b49ade2014-07-15 17:03:20 -0700356 private final StatusHints mStatusHints;
Nancy Chen10798dc2014-08-08 14:00:25 -0700357 private final Bundle mExtras;
Santos Cordon6b7f9552015-05-27 17:21:45 -0700358 private final Bundle mIntentExtras;
Ihab Awade63fadb2014-07-09 21:52:04 -0700359
360 /**
Ihab Awad5c9c86e2014-11-12 13:41:16 -0800361 * Whether the supplied capabilities supports the specified capability.
362 *
363 * @param capabilities A bit field of capabilities.
364 * @param capability The capability to check capabilities for.
365 * @return Whether the specified capability is supported.
Ihab Awad5c9c86e2014-11-12 13:41:16 -0800366 */
367 public static boolean can(int capabilities, int capability) {
Tyler Gunn014c7112015-12-18 14:33:57 -0800368 return (capabilities & capability) == capability;
Ihab Awad5c9c86e2014-11-12 13:41:16 -0800369 }
370
371 /**
372 * Whether the capabilities of this {@code Details} supports the specified capability.
373 *
374 * @param capability The capability to check capabilities for.
375 * @return Whether the specified capability is supported.
Ihab Awad5c9c86e2014-11-12 13:41:16 -0800376 */
377 public boolean can(int capability) {
378 return can(mCallCapabilities, capability);
379 }
380
381 /**
382 * Render a set of capability bits ({@code CAPABILITY_*}) as a human readable string.
383 *
384 * @param capabilities A capability bit field.
385 * @return A human readable string representation.
386 */
387 public static String capabilitiesToString(int capabilities) {
388 StringBuilder builder = new StringBuilder();
389 builder.append("[Capabilities:");
390 if (can(capabilities, CAPABILITY_HOLD)) {
391 builder.append(" CAPABILITY_HOLD");
392 }
393 if (can(capabilities, CAPABILITY_SUPPORT_HOLD)) {
394 builder.append(" CAPABILITY_SUPPORT_HOLD");
395 }
396 if (can(capabilities, CAPABILITY_MERGE_CONFERENCE)) {
397 builder.append(" CAPABILITY_MERGE_CONFERENCE");
398 }
399 if (can(capabilities, CAPABILITY_SWAP_CONFERENCE)) {
400 builder.append(" CAPABILITY_SWAP_CONFERENCE");
401 }
402 if (can(capabilities, CAPABILITY_RESPOND_VIA_TEXT)) {
403 builder.append(" CAPABILITY_RESPOND_VIA_TEXT");
404 }
405 if (can(capabilities, CAPABILITY_MUTE)) {
406 builder.append(" CAPABILITY_MUTE");
407 }
408 if (can(capabilities, CAPABILITY_MANAGE_CONFERENCE)) {
409 builder.append(" CAPABILITY_MANAGE_CONFERENCE");
410 }
Andrew Lee5e9e8bb2015-03-10 13:58:24 -0700411 if (can(capabilities, CAPABILITY_SUPPORTS_VT_LOCAL_RX)) {
412 builder.append(" CAPABILITY_SUPPORTS_VT_LOCAL_RX");
413 }
414 if (can(capabilities, CAPABILITY_SUPPORTS_VT_LOCAL_TX)) {
415 builder.append(" CAPABILITY_SUPPORTS_VT_LOCAL_TX");
416 }
Andrew Lee9a8f9ce2015-04-10 18:09:46 -0700417 if (can(capabilities, CAPABILITY_SUPPORTS_VT_LOCAL_BIDIRECTIONAL)) {
418 builder.append(" CAPABILITY_SUPPORTS_VT_LOCAL_BIDIRECTIONAL");
Ihab Awad5c9c86e2014-11-12 13:41:16 -0800419 }
Andrew Lee5e9e8bb2015-03-10 13:58:24 -0700420 if (can(capabilities, CAPABILITY_SUPPORTS_VT_REMOTE_RX)) {
421 builder.append(" CAPABILITY_SUPPORTS_VT_REMOTE_RX");
422 }
423 if (can(capabilities, CAPABILITY_SUPPORTS_VT_REMOTE_TX)) {
424 builder.append(" CAPABILITY_SUPPORTS_VT_REMOTE_TX");
425 }
Tyler Gunnf97a0092016-01-19 15:59:34 -0800426 if (can(capabilities, CAPABILITY_CANNOT_DOWNGRADE_VIDEO_TO_AUDIO)) {
427 builder.append(" CAPABILITY_CANNOT_DOWNGRADE_VIDEO_TO_AUDIO");
428 }
Andrew Lee9a8f9ce2015-04-10 18:09:46 -0700429 if (can(capabilities, CAPABILITY_SUPPORTS_VT_REMOTE_BIDIRECTIONAL)) {
430 builder.append(" CAPABILITY_SUPPORTS_VT_REMOTE_BIDIRECTIONAL");
Ihab Awad5c9c86e2014-11-12 13:41:16 -0800431 }
Dong Zhou89f41eb2015-03-15 11:59:49 -0500432 if (can(capabilities, CAPABILITY_SPEED_UP_MT_AUDIO)) {
Tyler Gunnd11a3152015-03-18 13:09:14 -0700433 builder.append(" CAPABILITY_SPEED_UP_MT_AUDIO");
Dong Zhou89f41eb2015-03-15 11:59:49 -0500434 }
Rekha Kumar07366812015-03-24 16:42:31 -0700435 if (can(capabilities, CAPABILITY_CAN_UPGRADE_TO_VIDEO)) {
436 builder.append(" CAPABILITY_CAN_UPGRADE_TO_VIDEO");
437 }
Tyler Gunnb5e0cfb2015-04-07 16:10:51 -0700438 if (can(capabilities, CAPABILITY_CAN_PAUSE_VIDEO)) {
439 builder.append(" CAPABILITY_CAN_PAUSE_VIDEO");
440 }
Tyler Gunn876dbfb2016-03-14 15:18:07 -0700441 if (can(capabilities, CAPABILITY_CAN_PULL_CALL)) {
442 builder.append(" CAPABILITY_CAN_PULL_CALL");
443 }
Ihab Awad5c9c86e2014-11-12 13:41:16 -0800444 builder.append("]");
445 return builder.toString();
446 }
447
448 /**
Andrew Lee2378ea72015-04-29 14:38:11 -0700449 * Whether the supplied properties includes the specified property.
450 *
451 * @param properties A bit field of properties.
452 * @param property The property to check properties for.
453 * @return Whether the specified property is supported.
454 */
455 public static boolean hasProperty(int properties, int property) {
Tyler Gunn014c7112015-12-18 14:33:57 -0800456 return (properties & property) == property;
Andrew Lee2378ea72015-04-29 14:38:11 -0700457 }
458
459 /**
460 * Whether the properties of this {@code Details} includes the specified property.
461 *
462 * @param property The property to check properties for.
463 * @return Whether the specified property is supported.
464 */
465 public boolean hasProperty(int property) {
466 return hasProperty(mCallProperties, property);
467 }
468
469 /**
470 * Render a set of property bits ({@code PROPERTY_*}) as a human readable string.
471 *
472 * @param properties A property bit field.
473 * @return A human readable string representation.
474 */
475 public static String propertiesToString(int properties) {
476 StringBuilder builder = new StringBuilder();
477 builder.append("[Properties:");
478 if (hasProperty(properties, PROPERTY_CONFERENCE)) {
479 builder.append(" PROPERTY_CONFERENCE");
480 }
481 if (hasProperty(properties, PROPERTY_GENERIC_CONFERENCE)) {
482 builder.append(" PROPERTY_GENERIC_CONFERENCE");
483 }
484 if (hasProperty(properties, PROPERTY_WIFI)) {
485 builder.append(" PROPERTY_WIFI");
486 }
487 if (hasProperty(properties, PROPERTY_HIGH_DEF_AUDIO)) {
488 builder.append(" PROPERTY_HIGH_DEF_AUDIO");
489 }
490 if (hasProperty(properties, PROPERTY_EMERGENCY_CALLBACK_MODE)) {
Yorke Leebe2a4a22015-06-12 10:10:55 -0700491 builder.append(" PROPERTY_EMERGENCY_CALLBACK_MODE");
Andrew Lee2378ea72015-04-29 14:38:11 -0700492 }
Tyler Gunn876dbfb2016-03-14 15:18:07 -0700493 if (hasProperty(properties, PROPERTY_IS_EXTERNAL_CALL)) {
494 builder.append(" PROPERTY_IS_EXTERNAL_CALL");
495 }
Brad Ebinger15847072016-05-18 11:08:36 -0700496 if(hasProperty(properties, PROPERTY_HAS_CDMA_VOICE_PRIVACY)) {
497 builder.append(" PROPERTY_HAS_CDMA_VOICE_PRIVACY");
498 }
Andrew Lee2378ea72015-04-29 14:38:11 -0700499 builder.append("]");
500 return builder.toString();
501 }
502
Sailesh Nepal1bef3392016-01-24 18:21:53 -0800503 /** {@hide} */
504 public String getTelecomCallId() {
505 return mTelecomCallId;
506 }
507
Andrew Lee2378ea72015-04-29 14:38:11 -0700508 /**
Ihab Awade63fadb2014-07-09 21:52:04 -0700509 * @return The handle (e.g., phone number) to which the {@code Call} is currently
510 * connected.
511 */
512 public Uri getHandle() {
513 return mHandle;
514 }
515
516 /**
517 * @return The presentation requirements for the handle. See
Tyler Gunnef9f6f92014-09-12 22:16:17 -0700518 * {@link TelecomManager} for valid values.
Ihab Awade63fadb2014-07-09 21:52:04 -0700519 */
520 public int getHandlePresentation() {
521 return mHandlePresentation;
522 }
523
524 /**
525 * @return The display name for the caller.
526 */
527 public String getCallerDisplayName() {
528 return mCallerDisplayName;
529 }
530
531 /**
532 * @return The presentation requirements for the caller display name. See
Tyler Gunnef9f6f92014-09-12 22:16:17 -0700533 * {@link TelecomManager} for valid values.
Ihab Awade63fadb2014-07-09 21:52:04 -0700534 */
535 public int getCallerDisplayNamePresentation() {
536 return mCallerDisplayNamePresentation;
537 }
538
539 /**
Evan Charlton6eb262c2014-07-19 18:18:19 -0700540 * @return The {@code PhoneAccountHandle} whereby the {@code Call} is currently being
541 * routed.
Ihab Awade63fadb2014-07-09 21:52:04 -0700542 */
Evan Charlton8c8a0622014-07-20 12:31:00 -0700543 public PhoneAccountHandle getAccountHandle() {
544 return mAccountHandle;
Ihab Awade63fadb2014-07-09 21:52:04 -0700545 }
546
547 /**
Ihab Awad5c9c86e2014-11-12 13:41:16 -0800548 * @return A bitmask of the capabilities of the {@code Call}, as defined by the various
549 * {@code CAPABILITY_*} constants in this class.
Ihab Awade63fadb2014-07-09 21:52:04 -0700550 */
Ihab Awad5d0410f2014-07-30 10:07:40 -0700551 public int getCallCapabilities() {
552 return mCallCapabilities;
Ihab Awade63fadb2014-07-09 21:52:04 -0700553 }
554
555 /**
Andrew Lee2378ea72015-04-29 14:38:11 -0700556 * @return A bitmask of the properties of the {@code Call}, as defined by the various
557 * {@code PROPERTY_*} constants in this class.
Andrew Lee223ad142014-08-27 16:33:08 -0700558 */
559 public int getCallProperties() {
560 return mCallProperties;
561 }
562
563 /**
Christine Hallstrom4e22d6d2016-11-30 16:06:42 -0800564 * @return a bitmask of the audio routes available for the call.
565 *
566 * @hide
567 */
568 public int getSupportedAudioRoutes() {
569 return mSupportedAudioRoutes;
570 }
571
572 /**
Ihab Awade63fadb2014-07-09 21:52:04 -0700573 * @return For a {@link #STATE_DISCONNECTED} {@code Call}, the disconnect cause expressed
Nancy Chenf4cf77c2014-09-19 10:53:21 -0700574 * by {@link android.telecom.DisconnectCause}.
Ihab Awade63fadb2014-07-09 21:52:04 -0700575 */
Andrew Lee7f3d41f2014-09-11 17:33:16 -0700576 public DisconnectCause getDisconnectCause() {
577 return mDisconnectCause;
Ihab Awade63fadb2014-07-09 21:52:04 -0700578 }
579
580 /**
581 * @return The time the {@code Call} has been connected. This information is updated
582 * periodically, but user interfaces should not rely on this to display any "call time
583 * clock".
584 */
Jay Shrauner164a0ac2015-04-14 18:16:10 -0700585 public final long getConnectTimeMillis() {
Ihab Awade63fadb2014-07-09 21:52:04 -0700586 return mConnectTimeMillis;
587 }
588
589 /**
590 * @return Information about any calling gateway the {@code Call} may be using.
591 */
592 public GatewayInfo getGatewayInfo() {
593 return mGatewayInfo;
594 }
595
Andrew Lee7a341382014-07-15 17:05:08 -0700596 /**
Ihab Awad5d0410f2014-07-30 10:07:40 -0700597 * @return The video state of the {@code Call}.
Andrew Lee7a341382014-07-15 17:05:08 -0700598 */
599 public int getVideoState() {
600 return mVideoState;
601 }
602
Ihab Awad5d0410f2014-07-30 10:07:40 -0700603 /**
Tyler Gunnef9f6f92014-09-12 22:16:17 -0700604 * @return The current {@link android.telecom.StatusHints}, or {@code null} if none
Ihab Awad5d0410f2014-07-30 10:07:40 -0700605 * have been set.
Evan Charlton5b49ade2014-07-15 17:03:20 -0700606 */
607 public StatusHints getStatusHints() {
608 return mStatusHints;
609 }
610
Nancy Chen10798dc2014-08-08 14:00:25 -0700611 /**
Santos Cordon6b7f9552015-05-27 17:21:45 -0700612 * @return The extras associated with this call.
Nancy Chen10798dc2014-08-08 14:00:25 -0700613 */
614 public Bundle getExtras() {
615 return mExtras;
616 }
617
Santos Cordon6b7f9552015-05-27 17:21:45 -0700618 /**
619 * @return The extras used with the original intent to place this call.
620 */
621 public Bundle getIntentExtras() {
622 return mIntentExtras;
623 }
624
Ihab Awade63fadb2014-07-09 21:52:04 -0700625 @Override
626 public boolean equals(Object o) {
627 if (o instanceof Details) {
628 Details d = (Details) o;
629 return
630 Objects.equals(mHandle, d.mHandle) &&
631 Objects.equals(mHandlePresentation, d.mHandlePresentation) &&
632 Objects.equals(mCallerDisplayName, d.mCallerDisplayName) &&
633 Objects.equals(mCallerDisplayNamePresentation,
634 d.mCallerDisplayNamePresentation) &&
Evan Charlton8c8a0622014-07-20 12:31:00 -0700635 Objects.equals(mAccountHandle, d.mAccountHandle) &&
Ihab Awad5d0410f2014-07-30 10:07:40 -0700636 Objects.equals(mCallCapabilities, d.mCallCapabilities) &&
Andrew Lee223ad142014-08-27 16:33:08 -0700637 Objects.equals(mCallProperties, d.mCallProperties) &&
Andrew Lee7f3d41f2014-09-11 17:33:16 -0700638 Objects.equals(mDisconnectCause, d.mDisconnectCause) &&
Ihab Awade63fadb2014-07-09 21:52:04 -0700639 Objects.equals(mConnectTimeMillis, d.mConnectTimeMillis) &&
Andrew Lee85f5d422014-07-11 17:22:03 -0700640 Objects.equals(mGatewayInfo, d.mGatewayInfo) &&
Evan Charlton5b49ade2014-07-15 17:03:20 -0700641 Objects.equals(mVideoState, d.mVideoState) &&
Nancy Chen10798dc2014-08-08 14:00:25 -0700642 Objects.equals(mStatusHints, d.mStatusHints) &&
Tyler Gunn1e9bfc62015-08-19 11:18:58 -0700643 areBundlesEqual(mExtras, d.mExtras) &&
644 areBundlesEqual(mIntentExtras, d.mIntentExtras);
Ihab Awade63fadb2014-07-09 21:52:04 -0700645 }
646 return false;
647 }
648
649 @Override
650 public int hashCode() {
651 return
652 Objects.hashCode(mHandle) +
653 Objects.hashCode(mHandlePresentation) +
654 Objects.hashCode(mCallerDisplayName) +
655 Objects.hashCode(mCallerDisplayNamePresentation) +
Evan Charlton8c8a0622014-07-20 12:31:00 -0700656 Objects.hashCode(mAccountHandle) +
Ihab Awad5d0410f2014-07-30 10:07:40 -0700657 Objects.hashCode(mCallCapabilities) +
Andrew Lee223ad142014-08-27 16:33:08 -0700658 Objects.hashCode(mCallProperties) +
Andrew Lee7f3d41f2014-09-11 17:33:16 -0700659 Objects.hashCode(mDisconnectCause) +
Ihab Awade63fadb2014-07-09 21:52:04 -0700660 Objects.hashCode(mConnectTimeMillis) +
Andrew Lee85f5d422014-07-11 17:22:03 -0700661 Objects.hashCode(mGatewayInfo) +
Evan Charlton5b49ade2014-07-15 17:03:20 -0700662 Objects.hashCode(mVideoState) +
Nancy Chen10798dc2014-08-08 14:00:25 -0700663 Objects.hashCode(mStatusHints) +
Santos Cordon6b7f9552015-05-27 17:21:45 -0700664 Objects.hashCode(mExtras) +
665 Objects.hashCode(mIntentExtras);
Ihab Awade63fadb2014-07-09 21:52:04 -0700666 }
667
668 /** {@hide} */
669 public Details(
Sailesh Nepal1bef3392016-01-24 18:21:53 -0800670 String telecomCallId,
Ihab Awade63fadb2014-07-09 21:52:04 -0700671 Uri handle,
672 int handlePresentation,
673 String callerDisplayName,
674 int callerDisplayNamePresentation,
Evan Charlton8c8a0622014-07-20 12:31:00 -0700675 PhoneAccountHandle accountHandle,
Ihab Awade63fadb2014-07-09 21:52:04 -0700676 int capabilities,
Andrew Lee223ad142014-08-27 16:33:08 -0700677 int properties,
Andrew Lee7f3d41f2014-09-11 17:33:16 -0700678 DisconnectCause disconnectCause,
Ihab Awade63fadb2014-07-09 21:52:04 -0700679 long connectTimeMillis,
Andrew Lee85f5d422014-07-11 17:22:03 -0700680 GatewayInfo gatewayInfo,
Evan Charlton5b49ade2014-07-15 17:03:20 -0700681 int videoState,
Nancy Chen10798dc2014-08-08 14:00:25 -0700682 StatusHints statusHints,
Santos Cordon6b7f9552015-05-27 17:21:45 -0700683 Bundle extras,
684 Bundle intentExtras) {
Sailesh Nepal1bef3392016-01-24 18:21:53 -0800685 mTelecomCallId = telecomCallId;
Ihab Awade63fadb2014-07-09 21:52:04 -0700686 mHandle = handle;
687 mHandlePresentation = handlePresentation;
688 mCallerDisplayName = callerDisplayName;
689 mCallerDisplayNamePresentation = callerDisplayNamePresentation;
Evan Charlton8c8a0622014-07-20 12:31:00 -0700690 mAccountHandle = accountHandle;
Ihab Awad5d0410f2014-07-30 10:07:40 -0700691 mCallCapabilities = capabilities;
Andrew Lee223ad142014-08-27 16:33:08 -0700692 mCallProperties = properties;
Andrew Lee7f3d41f2014-09-11 17:33:16 -0700693 mDisconnectCause = disconnectCause;
Ihab Awade63fadb2014-07-09 21:52:04 -0700694 mConnectTimeMillis = connectTimeMillis;
695 mGatewayInfo = gatewayInfo;
Andrew Lee85f5d422014-07-11 17:22:03 -0700696 mVideoState = videoState;
Evan Charlton5b49ade2014-07-15 17:03:20 -0700697 mStatusHints = statusHints;
Nancy Chen10798dc2014-08-08 14:00:25 -0700698 mExtras = extras;
Santos Cordon6b7f9552015-05-27 17:21:45 -0700699 mIntentExtras = intentExtras;
Ihab Awade63fadb2014-07-09 21:52:04 -0700700 }
Sailesh Nepal1bef3392016-01-24 18:21:53 -0800701
702 /** {@hide} */
703 public static Details createFromParcelableCall(ParcelableCall parcelableCall) {
704 return new Details(
705 parcelableCall.getId(),
706 parcelableCall.getHandle(),
707 parcelableCall.getHandlePresentation(),
708 parcelableCall.getCallerDisplayName(),
709 parcelableCall.getCallerDisplayNamePresentation(),
710 parcelableCall.getAccountHandle(),
711 parcelableCall.getCapabilities(),
712 parcelableCall.getProperties(),
713 parcelableCall.getDisconnectCause(),
714 parcelableCall.getConnectTimeMillis(),
715 parcelableCall.getGatewayInfo(),
716 parcelableCall.getVideoState(),
717 parcelableCall.getStatusHints(),
718 parcelableCall.getExtras(),
719 parcelableCall.getIntentExtras());
720 }
Santos Cordon3c20d632016-02-25 16:12:35 -0800721
722 @Override
723 public String toString() {
724 StringBuilder sb = new StringBuilder();
725 sb.append("[pa: ");
726 sb.append(mAccountHandle);
727 sb.append(", hdl: ");
728 sb.append(Log.pii(mHandle));
729 sb.append(", caps: ");
730 sb.append(capabilitiesToString(mCallCapabilities));
731 sb.append(", props: ");
Tyler Gunn720c6642016-03-22 09:02:47 -0700732 sb.append(propertiesToString(mCallProperties));
Santos Cordon3c20d632016-02-25 16:12:35 -0800733 sb.append("]");
734 return sb.toString();
735 }
Ihab Awade63fadb2014-07-09 21:52:04 -0700736 }
737
Tyler Gunn9c0eb0b2016-06-29 11:23:25 -0700738 /**
739 * Defines callbacks which inform the {@link InCallService} of changes to a {@link Call}.
740 * These callbacks can originate from the Telecom framework, or a {@link ConnectionService}
741 * implementation.
742 * <p>
743 * You can handle these callbacks by extending the {@link Callback} class and overriding the
744 * callbacks that your {@link InCallService} is interested in. The callback methods include the
745 * {@link Call} for which the callback applies, allowing reuse of a single instance of your
746 * {@link Callback} implementation, if desired.
747 * <p>
748 * Use {@link Call#registerCallback(Callback)} to register your callback(s). Ensure
749 * {@link Call#unregisterCallback(Callback)} is called when you no longer require callbacks
750 * (typically in {@link InCallService#onCallRemoved(Call)}).
751 * Note: Callbacks which occur before you call {@link Call#registerCallback(Callback)} will not
752 * reach your implementation of {@link Callback}, so it is important to register your callback
753 * as soon as your {@link InCallService} is notified of a new call via
754 * {@link InCallService#onCallAdded(Call)}.
755 */
Andrew Leeda80c872015-04-15 14:09:50 -0700756 public static abstract class Callback {
Ihab Awade63fadb2014-07-09 21:52:04 -0700757 /**
758 * Invoked when the state of this {@code Call} has changed. See {@link #getState()}.
759 *
Ihab Awade63fadb2014-07-09 21:52:04 -0700760 * @param call The {@code Call} invoking this method.
761 * @param state The new state of the {@code Call}.
762 */
763 public void onStateChanged(Call call, int state) {}
764
765 /**
766 * Invoked when the parent of this {@code Call} has changed. See {@link #getParent()}.
767 *
768 * @param call The {@code Call} invoking this method.
769 * @param parent The new parent of the {@code Call}.
770 */
771 public void onParentChanged(Call call, Call parent) {}
772
773 /**
774 * Invoked when the children of this {@code Call} have changed. See {@link #getChildren()}.
775 *
776 * @param call The {@code Call} invoking this method.
777 * @param children The new children of the {@code Call}.
778 */
779 public void onChildrenChanged(Call call, List<Call> children) {}
780
781 /**
782 * Invoked when the details of this {@code Call} have changed. See {@link #getDetails()}.
783 *
784 * @param call The {@code Call} invoking this method.
785 * @param details A {@code Details} object describing the {@code Call}.
786 */
787 public void onDetailsChanged(Call call, Details details) {}
788
789 /**
790 * Invoked when the text messages that can be used as responses to the incoming
791 * {@code Call} are loaded from the relevant database.
792 * See {@link #getCannedTextResponses()}.
793 *
794 * @param call The {@code Call} invoking this method.
795 * @param cannedTextResponses The text messages useable as responses.
796 */
797 public void onCannedTextResponsesLoaded(Call call, List<String> cannedTextResponses) {}
798
799 /**
Ihab Awade63fadb2014-07-09 21:52:04 -0700800 * Invoked when the post-dial sequence in the outgoing {@code Call} has reached a pause
801 * character. This causes the post-dial signals to stop pending user confirmation. An
802 * implementation should present this choice to the user and invoke
803 * {@link #postDialContinue(boolean)} when the user makes the choice.
804 *
805 * @param call The {@code Call} invoking this method.
806 * @param remainingPostDialSequence The post-dial characters that remain to be sent.
807 */
808 public void onPostDialWait(Call call, String remainingPostDialSequence) {}
809
810 /**
Andrew Lee50aca232014-07-22 16:41:54 -0700811 * Invoked when the {@code Call.VideoCall} of the {@code Call} has changed.
Ihab Awade63fadb2014-07-09 21:52:04 -0700812 *
813 * @param call The {@code Call} invoking this method.
Andrew Lee50aca232014-07-22 16:41:54 -0700814 * @param videoCall The {@code Call.VideoCall} associated with the {@code Call}.
Ihab Awade63fadb2014-07-09 21:52:04 -0700815 */
Andrew Lee50aca232014-07-22 16:41:54 -0700816 public void onVideoCallChanged(Call call, InCallService.VideoCall videoCall) {}
Ihab Awade63fadb2014-07-09 21:52:04 -0700817
818 /**
819 * Invoked when the {@code Call} is destroyed. Clients should refrain from cleaning
820 * up their UI for the {@code Call} in response to state transitions. Specifically,
821 * clients should not assume that a {@link #onStateChanged(Call, int)} with a state of
822 * {@link #STATE_DISCONNECTED} is the final notification the {@code Call} will send. Rather,
823 * clients should wait for this method to be invoked.
824 *
825 * @param call The {@code Call} being destroyed.
826 */
827 public void onCallDestroyed(Call call) {}
Santos Cordon7c7bc7f2014-07-28 18:15:48 -0700828
829 /**
830 * Invoked upon changes to the set of {@code Call}s with which this {@code Call} can be
831 * conferenced.
832 *
833 * @param call The {@code Call} being updated.
834 * @param conferenceableCalls The {@code Call}s with which this {@code Call} can be
835 * conferenced.
836 */
837 public void onConferenceableCallsChanged(Call call, List<Call> conferenceableCalls) {}
Tyler Gunn876dbfb2016-03-14 15:18:07 -0700838
839 /**
Tyler Gunn9c0eb0b2016-06-29 11:23:25 -0700840 * Invoked when a {@link Call} receives an event from its associated {@link Connection}.
841 * <p>
842 * Where possible, the Call should make an attempt to handle {@link Connection} events which
843 * are part of the {@code android.telecom.*} namespace. The Call should ignore any events
844 * it does not wish to handle. Unexpected events should be handled gracefully, as it is
845 * possible that a {@link ConnectionService} has defined its own Connection events which a
846 * Call is not aware of.
Tyler Gunn876dbfb2016-03-14 15:18:07 -0700847 * <p>
848 * See {@link Connection#sendConnectionEvent(String, Bundle)}.
849 *
850 * @param call The {@code Call} receiving the event.
851 * @param event The event.
852 * @param extras Extras associated with the connection event.
853 */
854 public void onConnectionEvent(Call call, String event, Bundle extras) {}
Hall Liu95d55872017-01-25 17:12:49 -0800855
856 /**
857 * Invoked when the RTT mode changes for this call.
858 * @param call The call whose RTT mode has changed.
859 * @param mode the new RTT mode, one of
860 * {@link RttCall#RTT_MODE_FULL}, {@link RttCall#RTT_MODE_HCO},
861 * or {@link RttCall#RTT_MODE_VCO}
862 */
863 public void onRttModeChanged(Call call, int mode) {}
864
865 /**
866 * Invoked when the call's RTT status changes, either from off to on or from on to off.
867 * @param call The call whose RTT status has changed.
868 * @param enabled whether RTT is now enabled or disabled
869 * @param rttCall the {@link RttCall} object to use for reading and writing if RTT is now
870 * on, null otherwise.
871 */
872 public void onRttStatusChanged(Call call, boolean enabled, RttCall rttCall) {}
873
874 /**
875 * Invoked when the remote end of the connection has requested that an RTT communication
876 * channel be opened. A response to this should be sent via {@link #respondToRttRequest}
877 * with the same ID that this method is invoked with.
878 * @param call The call which the RTT request was placed on
879 * @param id The ID of the request.
880 */
881 public void onRttRequest(Call call, int id) {}
Hall Liu57006aa2017-02-06 10:49:48 -0800882
883 /**
884 * Invoked when the RTT session failed to initiate for some reason, including rejection
885 * by the remote party.
886 * @param call The call which the RTT initiation failure occurred on.
887 * @param reason One of the status codes defined in
888 * {@link android.telecom.Connection.RttModifyStatus}, with the exception of
889 * {@link android.telecom.Connection.RttModifyStatus#SESSION_MODIFY_REQUEST_SUCCESS}.
890 */
891 public void onRttInitiationFailure(Call call, int reason) {}
Hall Liu95d55872017-01-25 17:12:49 -0800892 }
893
894 /**
895 * A class that holds the state that describes the state of the RTT channel to the remote
896 * party, if it is active.
897 */
898 public static final class RttCall {
Hall Liu07094df2017-02-28 15:17:44 -0800899 /** @hide */
Hall Liu95d55872017-01-25 17:12:49 -0800900 @Retention(RetentionPolicy.SOURCE)
901 @IntDef({RTT_MODE_INVALID, RTT_MODE_FULL, RTT_MODE_HCO, RTT_MODE_VCO})
902 public @interface RttAudioMode {}
903
904 /**
905 * For metrics use. Default value in the proto.
906 * @hide
907 */
908 public static final int RTT_MODE_INVALID = 0;
909
910 /**
911 * Indicates that there should be a bidirectional audio stream between the two parties
912 * on the call.
913 */
914 public static final int RTT_MODE_FULL = 1;
915
916 /**
917 * Indicates that the local user should be able to hear the audio stream from the remote
918 * user, but not vice versa. Equivalent to muting the microphone.
919 */
920 public static final int RTT_MODE_HCO = 2;
921
922 /**
923 * Indicates that the remote user should be able to hear the audio stream from the local
924 * user, but not vice versa. Equivalent to setting the volume to zero.
925 */
926 public static final int RTT_MODE_VCO = 3;
927
928 private static final int READ_BUFFER_SIZE = 1000;
929
930 private InputStreamReader mReceiveStream;
931 private OutputStreamWriter mTransmitStream;
932 private int mRttMode;
933 private final InCallAdapter mInCallAdapter;
Hall Liu57006aa2017-02-06 10:49:48 -0800934 private final String mTelecomCallId;
Hall Liu95d55872017-01-25 17:12:49 -0800935 private char[] mReadBuffer = new char[READ_BUFFER_SIZE];
936
937 /**
938 * @hide
939 */
Hall Liu57006aa2017-02-06 10:49:48 -0800940 public RttCall(String telecomCallId, InputStreamReader receiveStream,
941 OutputStreamWriter transmitStream, int mode, InCallAdapter inCallAdapter) {
942 mTelecomCallId = telecomCallId;
Hall Liu95d55872017-01-25 17:12:49 -0800943 mReceiveStream = receiveStream;
944 mTransmitStream = transmitStream;
945 mRttMode = mode;
946 mInCallAdapter = inCallAdapter;
947 }
948
949 /**
950 * Returns the current RTT audio mode.
951 * @return Current RTT audio mode. One of {@link #RTT_MODE_FULL}, {@link #RTT_MODE_VCO}, or
952 * {@link #RTT_MODE_HCO}.
953 */
954 public int getRttAudioMode() {
955 return mRttMode;
956 }
957
958 /**
959 * Sets the RTT audio mode. The requested mode change will be communicated through
960 * {@link Callback#onRttModeChanged(Call, int)}.
961 * @param mode The desired RTT audio mode, one of {@link #RTT_MODE_FULL},
962 * {@link #RTT_MODE_VCO}, or {@link #RTT_MODE_HCO}.
963 */
964 public void setRttMode(@RttAudioMode int mode) {
Hall Liu57006aa2017-02-06 10:49:48 -0800965 mInCallAdapter.setRttMode(mTelecomCallId, mode);
Hall Liu95d55872017-01-25 17:12:49 -0800966 }
967
968 /**
969 * Writes the string {@param input} into the outgoing text stream for this RTT call. Since
970 * RTT transmits text in real-time, this method should be called once for each character
971 * the user enters into the device.
972 *
973 * This method is not thread-safe -- calling it from multiple threads simultaneously may
974 * lead to interleaved text.
975 * @param input The message to send to the remote user.
976 */
977 public void write(String input) throws IOException {
978 mTransmitStream.write(input);
979 mTransmitStream.flush();
980 }
981
982 /**
983 * Reads a string from the remote user, blocking if there is no data available. Returns
984 * {@code null} if the RTT conversation has been terminated and there is no further data
985 * to read.
986 *
987 * This method is not thread-safe -- calling it from multiple threads simultaneously may
988 * lead to interleaved text.
989 * @return A string containing text sent by the remote user, or {@code null} if the
990 * conversation has been terminated or if there was an error while reading.
991 */
992 public String read() {
993 try {
994 int numRead = mReceiveStream.read(mReadBuffer, 0, READ_BUFFER_SIZE);
995 if (numRead < 0) {
996 return null;
997 }
998 return new String(mReadBuffer, 0, numRead);
999 } catch (IOException e) {
1000 Log.w(this, "Exception encountered when reading from InputStreamReader: %s", e);
1001 return null;
1002 }
1003 }
Ihab Awade63fadb2014-07-09 21:52:04 -07001004 }
1005
Andrew Leeda80c872015-04-15 14:09:50 -07001006 /**
1007 * @deprecated Use {@code Call.Callback} instead.
1008 * @hide
1009 */
1010 @Deprecated
1011 @SystemApi
1012 public static abstract class Listener extends Callback { }
1013
Ihab Awade63fadb2014-07-09 21:52:04 -07001014 private final Phone mPhone;
Tyler Gunnef9f6f92014-09-12 22:16:17 -07001015 private final String mTelecomCallId;
Ihab Awade63fadb2014-07-09 21:52:04 -07001016 private final InCallAdapter mInCallAdapter;
Santos Cordon823fd3c2014-08-07 18:35:18 -07001017 private final List<String> mChildrenIds = new ArrayList<>();
Ihab Awade63fadb2014-07-09 21:52:04 -07001018 private final List<Call> mChildren = new ArrayList<>();
1019 private final List<Call> mUnmodifiableChildren = Collections.unmodifiableList(mChildren);
Andrew Lee011728f2015-04-23 15:47:06 -07001020 private final List<CallbackRecord<Callback>> mCallbackRecords = new CopyOnWriteArrayList<>();
Santos Cordon7c7bc7f2014-07-28 18:15:48 -07001021 private final List<Call> mConferenceableCalls = new ArrayList<>();
1022 private final List<Call> mUnmodifiableConferenceableCalls =
1023 Collections.unmodifiableList(mConferenceableCalls);
1024
Santos Cordon823fd3c2014-08-07 18:35:18 -07001025 private boolean mChildrenCached;
1026 private String mParentId = null;
Santos Cordon7c7bc7f2014-07-28 18:15:48 -07001027 private int mState;
Ihab Awade63fadb2014-07-09 21:52:04 -07001028 private List<String> mCannedTextResponses = null;
Tyler Gunnb88b3112016-11-09 10:19:23 -08001029 private String mCallingPackage;
Tyler Gunn159f35c2017-03-02 09:28:37 -08001030 private int mTargetSdkVersion;
Ihab Awade63fadb2014-07-09 21:52:04 -07001031 private String mRemainingPostDialSequence;
Tyler Gunn584ba6c2015-12-08 10:53:41 -08001032 private VideoCallImpl mVideoCallImpl;
Hall Liu95d55872017-01-25 17:12:49 -08001033 private RttCall mRttCall;
Ihab Awade63fadb2014-07-09 21:52:04 -07001034 private Details mDetails;
Tyler Gunndee56a82016-03-23 16:06:34 -07001035 private Bundle mExtras;
Ihab Awade63fadb2014-07-09 21:52:04 -07001036
1037 /**
1038 * Obtains the post-dial sequence remaining to be emitted by this {@code Call}, if any.
1039 *
1040 * @return The remaining post-dial sequence, or {@code null} if there is no post-dial sequence
1041 * remaining or this {@code Call} is not in a post-dial state.
1042 */
1043 public String getRemainingPostDialSequence() {
1044 return mRemainingPostDialSequence;
1045 }
1046
1047 /**
1048 * Instructs this {@link #STATE_RINGING} {@code Call} to answer.
Andrew Lee8da4c3c2014-07-16 10:11:42 -07001049 * @param videoState The video state in which to answer the call.
Ihab Awade63fadb2014-07-09 21:52:04 -07001050 */
Andrew Lee8da4c3c2014-07-16 10:11:42 -07001051 public void answer(int videoState) {
Tyler Gunnef9f6f92014-09-12 22:16:17 -07001052 mInCallAdapter.answerCall(mTelecomCallId, videoState);
Ihab Awade63fadb2014-07-09 21:52:04 -07001053 }
1054
1055 /**
1056 * Instructs this {@link #STATE_RINGING} {@code Call} to reject.
1057 *
1058 * @param rejectWithMessage Whether to reject with a text message.
1059 * @param textMessage An optional text message with which to respond.
1060 */
1061 public void reject(boolean rejectWithMessage, String textMessage) {
Tyler Gunnef9f6f92014-09-12 22:16:17 -07001062 mInCallAdapter.rejectCall(mTelecomCallId, rejectWithMessage, textMessage);
Ihab Awade63fadb2014-07-09 21:52:04 -07001063 }
1064
1065 /**
1066 * Instructs this {@code Call} to disconnect.
1067 */
1068 public void disconnect() {
Tyler Gunnef9f6f92014-09-12 22:16:17 -07001069 mInCallAdapter.disconnectCall(mTelecomCallId);
Ihab Awade63fadb2014-07-09 21:52:04 -07001070 }
1071
1072 /**
1073 * Instructs this {@code Call} to go on hold.
1074 */
1075 public void hold() {
Tyler Gunnef9f6f92014-09-12 22:16:17 -07001076 mInCallAdapter.holdCall(mTelecomCallId);
Ihab Awade63fadb2014-07-09 21:52:04 -07001077 }
1078
1079 /**
1080 * Instructs this {@link #STATE_HOLDING} call to release from hold.
1081 */
1082 public void unhold() {
Tyler Gunnef9f6f92014-09-12 22:16:17 -07001083 mInCallAdapter.unholdCall(mTelecomCallId);
Ihab Awade63fadb2014-07-09 21:52:04 -07001084 }
1085
1086 /**
1087 * Instructs this {@code Call} to play a dual-tone multi-frequency signaling (DTMF) tone.
1088 *
1089 * Any other currently playing DTMF tone in the specified call is immediately stopped.
1090 *
1091 * @param digit A character representing the DTMF digit for which to play the tone. This
1092 * value must be one of {@code '0'} through {@code '9'}, {@code '*'} or {@code '#'}.
1093 */
1094 public void playDtmfTone(char digit) {
Tyler Gunnef9f6f92014-09-12 22:16:17 -07001095 mInCallAdapter.playDtmfTone(mTelecomCallId, digit);
Ihab Awade63fadb2014-07-09 21:52:04 -07001096 }
1097
1098 /**
1099 * Instructs this {@code Call} to stop any dual-tone multi-frequency signaling (DTMF) tone
1100 * currently playing.
1101 *
1102 * DTMF tones are played by calling {@link #playDtmfTone(char)}. If no DTMF tone is
1103 * currently playing, this method will do nothing.
1104 */
1105 public void stopDtmfTone() {
Tyler Gunnef9f6f92014-09-12 22:16:17 -07001106 mInCallAdapter.stopDtmfTone(mTelecomCallId);
Ihab Awade63fadb2014-07-09 21:52:04 -07001107 }
1108
1109 /**
1110 * Instructs this {@code Call} to continue playing a post-dial DTMF string.
1111 *
1112 * A post-dial DTMF string is a string of digits entered after a phone number, when dialed,
1113 * that are immediately sent as DTMF tones to the recipient as soon as the connection is made.
Ihab Awade63fadb2014-07-09 21:52:04 -07001114 *
Tyler Gunnef9f6f92014-09-12 22:16:17 -07001115 * If the DTMF string contains a {@link TelecomManager#DTMF_CHARACTER_PAUSE} symbol, this
Ihab Awade63fadb2014-07-09 21:52:04 -07001116 * {@code Call} will temporarily pause playing the tones for a pre-defined period of time.
1117 *
Tyler Gunnef9f6f92014-09-12 22:16:17 -07001118 * If the DTMF string contains a {@link TelecomManager#DTMF_CHARACTER_WAIT} symbol, this
Andrew Leeda80c872015-04-15 14:09:50 -07001119 * {@code Call} will pause playing the tones and notify callbacks via
1120 * {@link Callback#onPostDialWait(Call, String)}. At this point, the in-call app
Ihab Awade63fadb2014-07-09 21:52:04 -07001121 * should display to the user an indication of this state and an affordance to continue
1122 * the postdial sequence. When the user decides to continue the postdial sequence, the in-call
1123 * app should invoke the {@link #postDialContinue(boolean)} method.
1124 *
1125 * @param proceed Whether or not to continue with the post-dial sequence.
1126 */
1127 public void postDialContinue(boolean proceed) {
Tyler Gunnef9f6f92014-09-12 22:16:17 -07001128 mInCallAdapter.postDialContinue(mTelecomCallId, proceed);
Ihab Awade63fadb2014-07-09 21:52:04 -07001129 }
1130
1131 /**
Evan Charlton8c8a0622014-07-20 12:31:00 -07001132 * Notifies this {@code Call} that an account has been selected and to proceed with placing
Nancy Chen36c62f32014-10-21 18:36:39 -07001133 * an outgoing call. Optionally sets this account as the default account.
Nancy Chen5da0fd52014-07-08 14:16:17 -07001134 */
Nancy Chen36c62f32014-10-21 18:36:39 -07001135 public void phoneAccountSelected(PhoneAccountHandle accountHandle, boolean setDefault) {
1136 mInCallAdapter.phoneAccountSelected(mTelecomCallId, accountHandle, setDefault);
Nancy Chen5da0fd52014-07-08 14:16:17 -07001137
1138 }
1139
1140 /**
Ihab Awade63fadb2014-07-09 21:52:04 -07001141 * Instructs this {@code Call} to enter a conference.
Santos Cordon7c7bc7f2014-07-28 18:15:48 -07001142 *
1143 * @param callToConferenceWith The other call with which to conference.
Ihab Awade63fadb2014-07-09 21:52:04 -07001144 */
Santos Cordon7c7bc7f2014-07-28 18:15:48 -07001145 public void conference(Call callToConferenceWith) {
1146 if (callToConferenceWith != null) {
Tyler Gunnef9f6f92014-09-12 22:16:17 -07001147 mInCallAdapter.conference(mTelecomCallId, callToConferenceWith.mTelecomCallId);
Santos Cordon7c7bc7f2014-07-28 18:15:48 -07001148 }
Ihab Awade63fadb2014-07-09 21:52:04 -07001149 }
1150
1151 /**
1152 * Instructs this {@code Call} to split from any conference call with which it may be
1153 * connected.
1154 */
1155 public void splitFromConference() {
Tyler Gunnef9f6f92014-09-12 22:16:17 -07001156 mInCallAdapter.splitFromConference(mTelecomCallId);
Ihab Awade63fadb2014-07-09 21:52:04 -07001157 }
1158
1159 /**
Ihab Awad5c9c86e2014-11-12 13:41:16 -08001160 * Merges the calls within this conference. See {@link Details#CAPABILITY_MERGE_CONFERENCE}.
Santos Cordona4868042014-09-04 17:39:22 -07001161 */
1162 public void mergeConference() {
Tyler Gunnef9f6f92014-09-12 22:16:17 -07001163 mInCallAdapter.mergeConference(mTelecomCallId);
Santos Cordona4868042014-09-04 17:39:22 -07001164 }
1165
1166 /**
Ihab Awad5c9c86e2014-11-12 13:41:16 -08001167 * Swaps the calls within this conference. See {@link Details#CAPABILITY_SWAP_CONFERENCE}.
Santos Cordona4868042014-09-04 17:39:22 -07001168 */
1169 public void swapConference() {
Tyler Gunnef9f6f92014-09-12 22:16:17 -07001170 mInCallAdapter.swapConference(mTelecomCallId);
Santos Cordona4868042014-09-04 17:39:22 -07001171 }
1172
1173 /**
Tyler Gunn876dbfb2016-03-14 15:18:07 -07001174 * Initiates a request to the {@link ConnectionService} to pull an external call to the local
1175 * device.
1176 * <p>
1177 * Calls to this method are ignored if the call does not have the
1178 * {@link Call.Details#PROPERTY_IS_EXTERNAL_CALL} property set.
1179 * <p>
1180 * An {@link InCallService} will only see calls which support this method if it has the
1181 * {@link TelecomManager#METADATA_INCLUDE_EXTERNAL_CALLS} metadata set to {@code true}
1182 * in its manifest.
1183 */
1184 public void pullExternalCall() {
1185 // If this isn't an external call, ignore the request.
1186 if (!mDetails.hasProperty(Details.PROPERTY_IS_EXTERNAL_CALL)) {
1187 return;
1188 }
1189
1190 mInCallAdapter.pullExternalCall(mTelecomCallId);
1191 }
1192
1193 /**
1194 * Sends a {@code Call} event from this {@code Call} to the associated {@link Connection} in
1195 * the {@link ConnectionService}.
1196 * <p>
Tyler Gunn9c0eb0b2016-06-29 11:23:25 -07001197 * Call events are used to communicate point in time information from an {@link InCallService}
1198 * to a {@link ConnectionService}. A {@link ConnectionService} implementation could define
1199 * events which enable the {@link InCallService}, for example, toggle a unique feature of the
1200 * {@link ConnectionService}.
1201 * <p>
1202 * A {@link ConnectionService} can communicate to the {@link InCallService} using
1203 * {@link Connection#sendConnectionEvent(String, Bundle)}.
1204 * <p>
Tyler Gunn876dbfb2016-03-14 15:18:07 -07001205 * Events are exposed to {@link ConnectionService} implementations via
1206 * {@link android.telecom.Connection#onCallEvent(String, Bundle)}.
1207 * <p>
1208 * No assumptions should be made as to how a {@link ConnectionService} will handle these events.
Tyler Gunn9c0eb0b2016-06-29 11:23:25 -07001209 * The {@link InCallService} must assume that the {@link ConnectionService} could chose to
1210 * ignore some events altogether.
1211 * <p>
1212 * Events should be fully qualified (e.g., {@code com.example.event.MY_EVENT}) to avoid
1213 * conflicts between {@link InCallService} implementations. Further, {@link InCallService}
1214 * implementations shall not re-purpose events in the {@code android.*} namespace, nor shall
1215 * they define their own event types in this namespace. When defining a custom event type,
1216 * ensure the contents of the extras {@link Bundle} is clearly defined. Extra keys for this
1217 * bundle should be named similar to the event type (e.g. {@code com.example.extra.MY_EXTRA}).
1218 * <p>
1219 * When defining events and the associated extras, it is important to keep their behavior
1220 * consistent when the associated {@link InCallService} is updated. Support for deprecated
1221 * events/extras should me maintained to ensure backwards compatibility with older
1222 * {@link ConnectionService} implementations which were built to support the older behavior.
Tyler Gunn876dbfb2016-03-14 15:18:07 -07001223 *
1224 * @param event The connection event.
1225 * @param extras Bundle containing extra information associated with the event.
1226 */
1227 public void sendCallEvent(String event, Bundle extras) {
1228 mInCallAdapter.sendCallEvent(mTelecomCallId, event, extras);
1229 }
1230
1231 /**
Hall Liu95d55872017-01-25 17:12:49 -08001232 * Sends an RTT upgrade request to the remote end of the connection. Success is not
1233 * guaranteed, and notification of success will be via the
1234 * {@link Callback#onRttStatusChanged(Call, boolean, RttCall)} callback.
1235 */
1236 public void sendRttRequest() {
Hall Liu57006aa2017-02-06 10:49:48 -08001237 mInCallAdapter.sendRttRequest(mTelecomCallId);
Hall Liu95d55872017-01-25 17:12:49 -08001238 }
1239
1240 /**
1241 * Responds to an RTT request received via the {@link Callback#onRttRequest(Call, int)} )}
1242 * callback.
1243 * The ID used here should be the same as the ID that was received via the callback.
1244 * @param id The request ID received via {@link Callback#onRttRequest(Call, int)}
1245 * @param accept {@code true} if the RTT request should be accepted, {@code false} otherwise.
1246 */
1247 public void respondToRttRequest(int id, boolean accept) {
Hall Liu57006aa2017-02-06 10:49:48 -08001248 mInCallAdapter.respondToRttRequest(mTelecomCallId, id, accept);
Hall Liu95d55872017-01-25 17:12:49 -08001249 }
1250
1251 /**
1252 * Terminate the RTT session on this call. The resulting state change will be notified via
1253 * the {@link Callback#onRttStatusChanged(Call, boolean, RttCall)} callback.
1254 */
1255 public void stopRtt() {
Hall Liu57006aa2017-02-06 10:49:48 -08001256 mInCallAdapter.stopRtt(mTelecomCallId);
Hall Liu95d55872017-01-25 17:12:49 -08001257 }
1258
1259 /**
Tyler Gunndee56a82016-03-23 16:06:34 -07001260 * Adds some extras to this {@link Call}. Existing keys are replaced and new ones are
1261 * added.
1262 * <p>
1263 * No assumptions should be made as to how an In-Call UI or service will handle these
1264 * extras. Keys should be fully qualified (e.g., com.example.MY_EXTRA) to avoid conflicts.
1265 *
1266 * @param extras The extras to add.
1267 */
1268 public final void putExtras(Bundle extras) {
1269 if (extras == null) {
1270 return;
1271 }
1272
1273 if (mExtras == null) {
1274 mExtras = new Bundle();
1275 }
1276 mExtras.putAll(extras);
1277 mInCallAdapter.putExtras(mTelecomCallId, extras);
1278 }
1279
1280 /**
1281 * Adds a boolean extra to this {@link Call}.
1282 *
1283 * @param key The extra key.
1284 * @param value The value.
1285 * @hide
1286 */
1287 public final void putExtra(String key, boolean value) {
1288 if (mExtras == null) {
1289 mExtras = new Bundle();
1290 }
1291 mExtras.putBoolean(key, value);
1292 mInCallAdapter.putExtra(mTelecomCallId, key, value);
1293 }
1294
1295 /**
Tyler Gunn071be6f2016-05-10 14:52:33 -07001296 * Adds an integer extra to this {@link Call}.
Tyler Gunndee56a82016-03-23 16:06:34 -07001297 *
1298 * @param key The extra key.
1299 * @param value The value.
1300 * @hide
1301 */
1302 public final void putExtra(String key, int value) {
1303 if (mExtras == null) {
1304 mExtras = new Bundle();
1305 }
1306 mExtras.putInt(key, value);
1307 mInCallAdapter.putExtra(mTelecomCallId, key, value);
1308 }
1309
1310 /**
Tyler Gunn071be6f2016-05-10 14:52:33 -07001311 * Adds a string extra to this {@link Call}.
Tyler Gunndee56a82016-03-23 16:06:34 -07001312 *
1313 * @param key The extra key.
1314 * @param value The value.
1315 * @hide
1316 */
1317 public final void putExtra(String key, String value) {
1318 if (mExtras == null) {
1319 mExtras = new Bundle();
1320 }
1321 mExtras.putString(key, value);
1322 mInCallAdapter.putExtra(mTelecomCallId, key, value);
1323 }
1324
1325 /**
Tyler Gunn071be6f2016-05-10 14:52:33 -07001326 * Removes extras from this {@link Call}.
Tyler Gunndee56a82016-03-23 16:06:34 -07001327 *
1328 * @param keys The keys of the extras to remove.
1329 */
1330 public final void removeExtras(List<String> keys) {
1331 if (mExtras != null) {
1332 for (String key : keys) {
1333 mExtras.remove(key);
1334 }
1335 if (mExtras.size() == 0) {
1336 mExtras = null;
1337 }
1338 }
1339 mInCallAdapter.removeExtras(mTelecomCallId, keys);
1340 }
1341
1342 /**
Tyler Gunn071be6f2016-05-10 14:52:33 -07001343 * Removes extras from this {@link Call}.
1344 *
1345 * @param keys The keys of the extras to remove.
1346 */
1347 public final void removeExtras(String ... keys) {
1348 removeExtras(Arrays.asList(keys));
1349 }
1350
1351 /**
Ihab Awade63fadb2014-07-09 21:52:04 -07001352 * Obtains the parent of this {@code Call} in a conference, if any.
1353 *
1354 * @return The parent {@code Call}, or {@code null} if this {@code Call} is not a
1355 * child of any conference {@code Call}s.
1356 */
1357 public Call getParent() {
Santos Cordon823fd3c2014-08-07 18:35:18 -07001358 if (mParentId != null) {
Tyler Gunnef9f6f92014-09-12 22:16:17 -07001359 return mPhone.internalGetCallByTelecomId(mParentId);
Santos Cordon823fd3c2014-08-07 18:35:18 -07001360 }
1361 return null;
Ihab Awade63fadb2014-07-09 21:52:04 -07001362 }
1363
1364 /**
1365 * Obtains the children of this conference {@code Call}, if any.
1366 *
1367 * @return The children of this {@code Call} if this {@code Call} is a conference, or an empty
1368 * {@code List} otherwise.
1369 */
1370 public List<Call> getChildren() {
Santos Cordon823fd3c2014-08-07 18:35:18 -07001371 if (!mChildrenCached) {
1372 mChildrenCached = true;
1373 mChildren.clear();
1374
1375 for(String id : mChildrenIds) {
Tyler Gunnef9f6f92014-09-12 22:16:17 -07001376 Call call = mPhone.internalGetCallByTelecomId(id);
Santos Cordon823fd3c2014-08-07 18:35:18 -07001377 if (call == null) {
1378 // At least one child was still not found, so do not save true for "cached"
1379 mChildrenCached = false;
1380 } else {
1381 mChildren.add(call);
1382 }
1383 }
1384 }
1385
Ihab Awade63fadb2014-07-09 21:52:04 -07001386 return mUnmodifiableChildren;
1387 }
1388
1389 /**
Santos Cordon7c7bc7f2014-07-28 18:15:48 -07001390 * Returns the list of {@code Call}s with which this {@code Call} is allowed to conference.
1391 *
1392 * @return The list of conferenceable {@code Call}s.
1393 */
1394 public List<Call> getConferenceableCalls() {
1395 return mUnmodifiableConferenceableCalls;
1396 }
1397
1398 /**
Ihab Awade63fadb2014-07-09 21:52:04 -07001399 * Obtains the state of this {@code Call}.
1400 *
1401 * @return A state value, chosen from the {@code STATE_*} constants.
1402 */
1403 public int getState() {
1404 return mState;
1405 }
1406
1407 /**
1408 * Obtains a list of canned, pre-configured message responses to present to the user as
1409 * ways of rejecting this {@code Call} using via a text message.
1410 *
1411 * @see #reject(boolean, String)
1412 *
1413 * @return A list of canned text message responses.
1414 */
1415 public List<String> getCannedTextResponses() {
1416 return mCannedTextResponses;
1417 }
1418
1419 /**
1420 * Obtains an object that can be used to display video from this {@code Call}.
1421 *
Andrew Lee50aca232014-07-22 16:41:54 -07001422 * @return An {@code Call.VideoCall}.
Ihab Awade63fadb2014-07-09 21:52:04 -07001423 */
Andrew Lee50aca232014-07-22 16:41:54 -07001424 public InCallService.VideoCall getVideoCall() {
Tyler Gunn584ba6c2015-12-08 10:53:41 -08001425 return mVideoCallImpl;
Ihab Awade63fadb2014-07-09 21:52:04 -07001426 }
1427
1428 /**
1429 * Obtains an object containing call details.
1430 *
1431 * @return A {@link Details} object. Depending on the state of the {@code Call}, the
1432 * result may be {@code null}.
1433 */
1434 public Details getDetails() {
1435 return mDetails;
1436 }
1437
1438 /**
Hall Liu95d55872017-01-25 17:12:49 -08001439 * Returns this call's RttCall object. The {@link RttCall} instance is used to send and
1440 * receive RTT text data, as well as to change the RTT mode.
1441 * @return A {@link Call.RttCall}. {@code null} if there is no active RTT connection.
1442 */
1443 public @Nullable RttCall getRttCall() {
1444 return mRttCall;
1445 }
1446
1447 /**
1448 * Returns whether this call has an active RTT connection.
1449 * @return true if there is a connection, false otherwise.
1450 */
1451 public boolean isRttActive() {
1452 return mRttCall != null;
1453 }
1454
1455 /**
Andrew Leeda80c872015-04-15 14:09:50 -07001456 * Registers a callback to this {@code Call}.
1457 *
1458 * @param callback A {@code Callback}.
1459 */
1460 public void registerCallback(Callback callback) {
Andrew Lee011728f2015-04-23 15:47:06 -07001461 registerCallback(callback, new Handler());
1462 }
1463
1464 /**
1465 * Registers a callback to this {@code Call}.
1466 *
1467 * @param callback A {@code Callback}.
1468 * @param handler A handler which command and status changes will be delivered to.
1469 */
1470 public void registerCallback(Callback callback, Handler handler) {
1471 unregisterCallback(callback);
Roshan Pius1ca62072015-07-07 17:34:51 -07001472 // Don't allow new callback registration if the call is already being destroyed.
1473 if (callback != null && handler != null && mState != STATE_DISCONNECTED) {
Andrew Lee011728f2015-04-23 15:47:06 -07001474 mCallbackRecords.add(new CallbackRecord<Callback>(callback, handler));
1475 }
Andrew Leeda80c872015-04-15 14:09:50 -07001476 }
1477
1478 /**
1479 * Unregisters a callback from this {@code Call}.
1480 *
1481 * @param callback A {@code Callback}.
1482 */
1483 public void unregisterCallback(Callback callback) {
Roshan Pius1ca62072015-07-07 17:34:51 -07001484 // Don't allow callback deregistration if the call is already being destroyed.
1485 if (callback != null && mState != STATE_DISCONNECTED) {
Andrew Lee011728f2015-04-23 15:47:06 -07001486 for (CallbackRecord<Callback> record : mCallbackRecords) {
1487 if (record.getCallback() == callback) {
1488 mCallbackRecords.remove(record);
1489 break;
1490 }
1491 }
Andrew Leeda80c872015-04-15 14:09:50 -07001492 }
1493 }
1494
Santos Cordon3c20d632016-02-25 16:12:35 -08001495 @Override
1496 public String toString() {
1497 return new StringBuilder().
1498 append("Call [id: ").
1499 append(mTelecomCallId).
1500 append(", state: ").
1501 append(stateToString(mState)).
1502 append(", details: ").
1503 append(mDetails).
1504 append("]").toString();
1505 }
1506
1507 /**
1508 * @param state An integer value of a {@code STATE_*} constant.
1509 * @return A string representation of the value.
1510 */
1511 private static String stateToString(int state) {
1512 switch (state) {
1513 case STATE_NEW:
1514 return "NEW";
1515 case STATE_RINGING:
1516 return "RINGING";
1517 case STATE_DIALING:
1518 return "DIALING";
1519 case STATE_ACTIVE:
1520 return "ACTIVE";
1521 case STATE_HOLDING:
1522 return "HOLDING";
1523 case STATE_DISCONNECTED:
1524 return "DISCONNECTED";
1525 case STATE_CONNECTING:
1526 return "CONNECTING";
1527 case STATE_DISCONNECTING:
1528 return "DISCONNECTING";
1529 case STATE_SELECT_PHONE_ACCOUNT:
1530 return "SELECT_PHONE_ACCOUNT";
1531 default:
1532 Log.w(Call.class, "Unknown state %d", state);
1533 return "UNKNOWN";
1534 }
1535 }
1536
Andrew Leeda80c872015-04-15 14:09:50 -07001537 /**
Ihab Awade63fadb2014-07-09 21:52:04 -07001538 * Adds a listener to this {@code Call}.
1539 *
1540 * @param listener A {@code Listener}.
Andrew Leeda80c872015-04-15 14:09:50 -07001541 * @deprecated Use {@link #registerCallback} instead.
1542 * @hide
Ihab Awade63fadb2014-07-09 21:52:04 -07001543 */
Andrew Leeda80c872015-04-15 14:09:50 -07001544 @Deprecated
1545 @SystemApi
Ihab Awade63fadb2014-07-09 21:52:04 -07001546 public void addListener(Listener listener) {
Andrew Leeda80c872015-04-15 14:09:50 -07001547 registerCallback(listener);
Ihab Awade63fadb2014-07-09 21:52:04 -07001548 }
1549
1550 /**
1551 * Removes a listener from this {@code Call}.
1552 *
1553 * @param listener A {@code Listener}.
Andrew Leeda80c872015-04-15 14:09:50 -07001554 * @deprecated Use {@link #unregisterCallback} instead.
1555 * @hide
Ihab Awade63fadb2014-07-09 21:52:04 -07001556 */
Andrew Leeda80c872015-04-15 14:09:50 -07001557 @Deprecated
1558 @SystemApi
Ihab Awade63fadb2014-07-09 21:52:04 -07001559 public void removeListener(Listener listener) {
Andrew Leeda80c872015-04-15 14:09:50 -07001560 unregisterCallback(listener);
Ihab Awade63fadb2014-07-09 21:52:04 -07001561 }
1562
1563 /** {@hide} */
Tyler Gunn159f35c2017-03-02 09:28:37 -08001564 Call(Phone phone, String telecomCallId, InCallAdapter inCallAdapter, String callingPackage,
1565 int targetSdkVersion) {
Ihab Awade63fadb2014-07-09 21:52:04 -07001566 mPhone = phone;
Tyler Gunnef9f6f92014-09-12 22:16:17 -07001567 mTelecomCallId = telecomCallId;
Ihab Awade63fadb2014-07-09 21:52:04 -07001568 mInCallAdapter = inCallAdapter;
1569 mState = STATE_NEW;
Tyler Gunnb88b3112016-11-09 10:19:23 -08001570 mCallingPackage = callingPackage;
Tyler Gunn159f35c2017-03-02 09:28:37 -08001571 mTargetSdkVersion = targetSdkVersion;
Ihab Awade63fadb2014-07-09 21:52:04 -07001572 }
1573
1574 /** {@hide} */
Tyler Gunnb88b3112016-11-09 10:19:23 -08001575 Call(Phone phone, String telecomCallId, InCallAdapter inCallAdapter, int state,
Tyler Gunn159f35c2017-03-02 09:28:37 -08001576 String callingPackage, int targetSdkVersion) {
Shriram Ganeshddf570e2015-05-31 09:18:48 -07001577 mPhone = phone;
1578 mTelecomCallId = telecomCallId;
1579 mInCallAdapter = inCallAdapter;
1580 mState = state;
Tyler Gunnb88b3112016-11-09 10:19:23 -08001581 mCallingPackage = callingPackage;
Tyler Gunn159f35c2017-03-02 09:28:37 -08001582 mTargetSdkVersion = targetSdkVersion;
Shriram Ganeshddf570e2015-05-31 09:18:48 -07001583 }
1584
1585 /** {@hide} */
Ihab Awade63fadb2014-07-09 21:52:04 -07001586 final String internalGetCallId() {
Tyler Gunnef9f6f92014-09-12 22:16:17 -07001587 return mTelecomCallId;
Ihab Awade63fadb2014-07-09 21:52:04 -07001588 }
1589
1590 /** {@hide} */
Santos Cordon7c7bc7f2014-07-28 18:15:48 -07001591 final void internalUpdate(ParcelableCall parcelableCall, Map<String, Call> callIdMap) {
Tyler Gunnb88b3112016-11-09 10:19:23 -08001592
Ihab Awade63fadb2014-07-09 21:52:04 -07001593 // First, we update the internal state as far as possible before firing any updates.
Sailesh Nepal1bef3392016-01-24 18:21:53 -08001594 Details details = Details.createFromParcelableCall(parcelableCall);
Ihab Awade63fadb2014-07-09 21:52:04 -07001595 boolean detailsChanged = !Objects.equals(mDetails, details);
1596 if (detailsChanged) {
1597 mDetails = details;
1598 }
1599
1600 boolean cannedTextResponsesChanged = false;
Santos Cordon88b771d2014-07-19 13:10:40 -07001601 if (mCannedTextResponses == null && parcelableCall.getCannedSmsResponses() != null
1602 && !parcelableCall.getCannedSmsResponses().isEmpty()) {
1603 mCannedTextResponses =
1604 Collections.unmodifiableList(parcelableCall.getCannedSmsResponses());
Yorke Leee886f632015-08-04 13:43:31 -07001605 cannedTextResponsesChanged = true;
Ihab Awade63fadb2014-07-09 21:52:04 -07001606 }
1607
Tyler Gunn159f35c2017-03-02 09:28:37 -08001608 VideoCallImpl newVideoCallImpl = parcelableCall.getVideoCallImpl(mCallingPackage,
1609 mTargetSdkVersion);
Tyler Gunn75958422015-04-15 14:23:42 -07001610 boolean videoCallChanged = parcelableCall.isVideoCallProviderChanged() &&
Tyler Gunn584ba6c2015-12-08 10:53:41 -08001611 !Objects.equals(mVideoCallImpl, newVideoCallImpl);
Andrew Lee50aca232014-07-22 16:41:54 -07001612 if (videoCallChanged) {
Tyler Gunn584ba6c2015-12-08 10:53:41 -08001613 mVideoCallImpl = newVideoCallImpl;
1614 }
1615 if (mVideoCallImpl != null) {
1616 mVideoCallImpl.setVideoState(getDetails().getVideoState());
Ihab Awade63fadb2014-07-09 21:52:04 -07001617 }
1618
Santos Cordone3c507b2015-04-23 14:44:19 -07001619 int state = parcelableCall.getState();
Ihab Awade63fadb2014-07-09 21:52:04 -07001620 boolean stateChanged = mState != state;
1621 if (stateChanged) {
1622 mState = state;
1623 }
1624
Santos Cordon823fd3c2014-08-07 18:35:18 -07001625 String parentId = parcelableCall.getParentCallId();
1626 boolean parentChanged = !Objects.equals(mParentId, parentId);
1627 if (parentChanged) {
1628 mParentId = parentId;
Ihab Awade63fadb2014-07-09 21:52:04 -07001629 }
1630
Santos Cordon823fd3c2014-08-07 18:35:18 -07001631 List<String> childCallIds = parcelableCall.getChildCallIds();
1632 boolean childrenChanged = !Objects.equals(childCallIds, mChildrenIds);
1633 if (childrenChanged) {
1634 mChildrenIds.clear();
1635 mChildrenIds.addAll(parcelableCall.getChildCallIds());
1636 mChildrenCached = false;
Ihab Awade63fadb2014-07-09 21:52:04 -07001637 }
1638
Santos Cordon7c7bc7f2014-07-28 18:15:48 -07001639 List<String> conferenceableCallIds = parcelableCall.getConferenceableCallIds();
1640 List<Call> conferenceableCalls = new ArrayList<Call>(conferenceableCallIds.size());
1641 for (String otherId : conferenceableCallIds) {
1642 if (callIdMap.containsKey(otherId)) {
1643 conferenceableCalls.add(callIdMap.get(otherId));
1644 }
1645 }
1646
1647 if (!Objects.equals(mConferenceableCalls, conferenceableCalls)) {
1648 mConferenceableCalls.clear();
1649 mConferenceableCalls.addAll(conferenceableCalls);
1650 fireConferenceableCallsChanged();
1651 }
1652
Hall Liu95d55872017-01-25 17:12:49 -08001653 boolean isRttChanged = false;
1654 boolean rttModeChanged = false;
1655 if (parcelableCall.getParcelableRttCall() != null && parcelableCall.getIsRttCallChanged()) {
1656 ParcelableRttCall parcelableRttCall = parcelableCall.getParcelableRttCall();
1657 InputStreamReader receiveStream = new InputStreamReader(
1658 new ParcelFileDescriptor.AutoCloseInputStream(
1659 parcelableRttCall.getReceiveStream()),
1660 StandardCharsets.UTF_8);
1661 OutputStreamWriter transmitStream = new OutputStreamWriter(
1662 new ParcelFileDescriptor.AutoCloseOutputStream(
1663 parcelableRttCall.getTransmitStream()),
1664 StandardCharsets.UTF_8);
Hall Liu57006aa2017-02-06 10:49:48 -08001665 RttCall newRttCall = new Call.RttCall(mTelecomCallId,
Hall Liu95d55872017-01-25 17:12:49 -08001666 receiveStream, transmitStream, parcelableRttCall.getRttMode(), mInCallAdapter);
1667 if (mRttCall == null) {
1668 isRttChanged = true;
1669 } else if (mRttCall.getRttAudioMode() != newRttCall.getRttAudioMode()) {
1670 rttModeChanged = true;
1671 }
1672 mRttCall = newRttCall;
1673 } else if (mRttCall != null && parcelableCall.getParcelableRttCall() == null
1674 && parcelableCall.getIsRttCallChanged()) {
1675 isRttChanged = true;
1676 mRttCall = null;
1677 }
1678
Ihab Awade63fadb2014-07-09 21:52:04 -07001679 // Now we fire updates, ensuring that any client who listens to any of these notifications
1680 // gets the most up-to-date state.
1681
1682 if (stateChanged) {
1683 fireStateChanged(mState);
1684 }
1685 if (detailsChanged) {
1686 fireDetailsChanged(mDetails);
1687 }
1688 if (cannedTextResponsesChanged) {
1689 fireCannedTextResponsesLoaded(mCannedTextResponses);
1690 }
Andrew Lee50aca232014-07-22 16:41:54 -07001691 if (videoCallChanged) {
Tyler Gunn584ba6c2015-12-08 10:53:41 -08001692 fireVideoCallChanged(mVideoCallImpl);
Ihab Awade63fadb2014-07-09 21:52:04 -07001693 }
Santos Cordon823fd3c2014-08-07 18:35:18 -07001694 if (parentChanged) {
1695 fireParentChanged(getParent());
1696 }
1697 if (childrenChanged) {
1698 fireChildrenChanged(getChildren());
1699 }
Hall Liu95d55872017-01-25 17:12:49 -08001700 if (isRttChanged) {
1701 fireOnIsRttChanged(mRttCall != null, mRttCall);
1702 }
1703 if (rttModeChanged) {
1704 fireOnRttModeChanged(mRttCall.getRttAudioMode());
1705 }
Ihab Awade63fadb2014-07-09 21:52:04 -07001706
1707 // If we have transitioned to DISCONNECTED, that means we need to notify clients and
1708 // remove ourselves from the Phone. Note that we do this after completing all state updates
1709 // so a client can cleanly transition all their UI to the state appropriate for a
1710 // DISCONNECTED Call while still relying on the existence of that Call in the Phone's list.
1711 if (mState == STATE_DISCONNECTED) {
1712 fireCallDestroyed();
Ihab Awade63fadb2014-07-09 21:52:04 -07001713 }
1714 }
1715
1716 /** {@hide} */
Ihab Awade63fadb2014-07-09 21:52:04 -07001717 final void internalSetPostDialWait(String remaining) {
1718 mRemainingPostDialSequence = remaining;
1719 firePostDialWait(mRemainingPostDialSequence);
1720 }
1721
Sailesh Nepal2ab88cc2014-07-18 14:49:18 -07001722 /** {@hide} */
Santos Cordonf30d7e92014-08-26 09:54:33 -07001723 final void internalSetDisconnected() {
1724 if (mState != Call.STATE_DISCONNECTED) {
1725 mState = Call.STATE_DISCONNECTED;
1726 fireStateChanged(mState);
1727 fireCallDestroyed();
Santos Cordonf30d7e92014-08-26 09:54:33 -07001728 }
1729 }
1730
Tyler Gunn876dbfb2016-03-14 15:18:07 -07001731 /** {@hide} */
1732 final void internalOnConnectionEvent(String event, Bundle extras) {
1733 fireOnConnectionEvent(event, extras);
1734 }
1735
Hall Liu95d55872017-01-25 17:12:49 -08001736 /** {@hide} */
1737 final void internalOnRttUpgradeRequest(final int requestId) {
1738 for (CallbackRecord<Callback> record : mCallbackRecords) {
1739 final Call call = this;
1740 final Callback callback = record.getCallback();
1741 record.getHandler().post(() -> callback.onRttRequest(call, requestId));
1742 }
1743 }
1744
Hall Liu57006aa2017-02-06 10:49:48 -08001745 /** @hide */
1746 final void internalOnRttInitiationFailure(int reason) {
1747 for (CallbackRecord<Callback> record : mCallbackRecords) {
1748 final Call call = this;
1749 final Callback callback = record.getCallback();
1750 record.getHandler().post(() -> callback.onRttInitiationFailure(call, reason));
1751 }
1752 }
1753
Andrew Lee011728f2015-04-23 15:47:06 -07001754 private void fireStateChanged(final int newState) {
1755 for (CallbackRecord<Callback> record : mCallbackRecords) {
1756 final Call call = this;
1757 final Callback callback = record.getCallback();
1758 record.getHandler().post(new Runnable() {
1759 @Override
1760 public void run() {
1761 callback.onStateChanged(call, newState);
1762 }
1763 });
Ihab Awade63fadb2014-07-09 21:52:04 -07001764 }
1765 }
1766
Andrew Lee011728f2015-04-23 15:47:06 -07001767 private void fireParentChanged(final Call newParent) {
1768 for (CallbackRecord<Callback> record : mCallbackRecords) {
1769 final Call call = this;
1770 final Callback callback = record.getCallback();
1771 record.getHandler().post(new Runnable() {
1772 @Override
1773 public void run() {
1774 callback.onParentChanged(call, newParent);
1775 }
1776 });
Ihab Awade63fadb2014-07-09 21:52:04 -07001777 }
1778 }
1779
Andrew Lee011728f2015-04-23 15:47:06 -07001780 private void fireChildrenChanged(final List<Call> children) {
1781 for (CallbackRecord<Callback> record : mCallbackRecords) {
1782 final Call call = this;
1783 final Callback callback = record.getCallback();
1784 record.getHandler().post(new Runnable() {
1785 @Override
1786 public void run() {
1787 callback.onChildrenChanged(call, children);
1788 }
1789 });
Ihab Awade63fadb2014-07-09 21:52:04 -07001790 }
1791 }
1792
Andrew Lee011728f2015-04-23 15:47:06 -07001793 private void fireDetailsChanged(final Details details) {
1794 for (CallbackRecord<Callback> record : mCallbackRecords) {
1795 final Call call = this;
1796 final Callback callback = record.getCallback();
1797 record.getHandler().post(new Runnable() {
1798 @Override
1799 public void run() {
1800 callback.onDetailsChanged(call, details);
1801 }
1802 });
Ihab Awade63fadb2014-07-09 21:52:04 -07001803 }
1804 }
1805
Andrew Lee011728f2015-04-23 15:47:06 -07001806 private void fireCannedTextResponsesLoaded(final List<String> cannedTextResponses) {
1807 for (CallbackRecord<Callback> record : mCallbackRecords) {
1808 final Call call = this;
1809 final Callback callback = record.getCallback();
1810 record.getHandler().post(new Runnable() {
1811 @Override
1812 public void run() {
1813 callback.onCannedTextResponsesLoaded(call, cannedTextResponses);
1814 }
1815 });
Ihab Awade63fadb2014-07-09 21:52:04 -07001816 }
1817 }
1818
Andrew Lee011728f2015-04-23 15:47:06 -07001819 private void fireVideoCallChanged(final InCallService.VideoCall videoCall) {
1820 for (CallbackRecord<Callback> record : mCallbackRecords) {
1821 final Call call = this;
1822 final Callback callback = record.getCallback();
1823 record.getHandler().post(new Runnable() {
1824 @Override
1825 public void run() {
1826 callback.onVideoCallChanged(call, videoCall);
1827 }
1828 });
Ihab Awade63fadb2014-07-09 21:52:04 -07001829 }
1830 }
1831
Andrew Lee011728f2015-04-23 15:47:06 -07001832 private void firePostDialWait(final String remainingPostDialSequence) {
1833 for (CallbackRecord<Callback> record : mCallbackRecords) {
1834 final Call call = this;
1835 final Callback callback = record.getCallback();
1836 record.getHandler().post(new Runnable() {
1837 @Override
1838 public void run() {
1839 callback.onPostDialWait(call, remainingPostDialSequence);
1840 }
1841 });
Ihab Awade63fadb2014-07-09 21:52:04 -07001842 }
1843 }
1844
1845 private void fireCallDestroyed() {
Roshan Pius1ca62072015-07-07 17:34:51 -07001846 /**
1847 * To preserve the ordering of the Call's onCallDestroyed callback and Phone's
1848 * onCallRemoved callback, we remove this call from the Phone's record
1849 * only once all of the registered onCallDestroyed callbacks are executed.
1850 * All the callbacks get removed from our records as a part of this operation
1851 * since onCallDestroyed is the final callback.
1852 */
1853 final Call call = this;
1854 if (mCallbackRecords.isEmpty()) {
1855 // No callbacks registered, remove the call from Phone's record.
1856 mPhone.internalRemoveCall(call);
1857 }
1858 for (final CallbackRecord<Callback> record : mCallbackRecords) {
Andrew Lee011728f2015-04-23 15:47:06 -07001859 final Callback callback = record.getCallback();
1860 record.getHandler().post(new Runnable() {
1861 @Override
1862 public void run() {
Roshan Pius1ca62072015-07-07 17:34:51 -07001863 boolean isFinalRemoval = false;
1864 RuntimeException toThrow = null;
1865 try {
1866 callback.onCallDestroyed(call);
1867 } catch (RuntimeException e) {
1868 toThrow = e;
1869 }
1870 synchronized(Call.this) {
1871 mCallbackRecords.remove(record);
1872 if (mCallbackRecords.isEmpty()) {
1873 isFinalRemoval = true;
1874 }
1875 }
1876 if (isFinalRemoval) {
1877 mPhone.internalRemoveCall(call);
1878 }
1879 if (toThrow != null) {
1880 throw toThrow;
1881 }
Andrew Lee011728f2015-04-23 15:47:06 -07001882 }
1883 });
Ihab Awade63fadb2014-07-09 21:52:04 -07001884 }
1885 }
1886
Santos Cordon7c7bc7f2014-07-28 18:15:48 -07001887 private void fireConferenceableCallsChanged() {
Andrew Lee011728f2015-04-23 15:47:06 -07001888 for (CallbackRecord<Callback> record : mCallbackRecords) {
1889 final Call call = this;
1890 final Callback callback = record.getCallback();
1891 record.getHandler().post(new Runnable() {
1892 @Override
1893 public void run() {
1894 callback.onConferenceableCallsChanged(call, mUnmodifiableConferenceableCalls);
1895 }
1896 });
Santos Cordon7c7bc7f2014-07-28 18:15:48 -07001897 }
1898 }
Tyler Gunn1e9bfc62015-08-19 11:18:58 -07001899
1900 /**
Tyler Gunn876dbfb2016-03-14 15:18:07 -07001901 * Notifies listeners of an incoming connection event.
1902 * <p>
1903 * Connection events are issued via {@link Connection#sendConnectionEvent(String, Bundle)}.
1904 *
1905 * @param event
1906 * @param extras
1907 */
1908 private void fireOnConnectionEvent(final String event, final Bundle extras) {
1909 for (CallbackRecord<Callback> record : mCallbackRecords) {
1910 final Call call = this;
1911 final Callback callback = record.getCallback();
1912 record.getHandler().post(new Runnable() {
1913 @Override
1914 public void run() {
1915 callback.onConnectionEvent(call, event, extras);
1916 }
1917 });
1918 }
1919 }
1920
1921 /**
Hall Liu95d55872017-01-25 17:12:49 -08001922 * Notifies listeners of an RTT on/off change
1923 *
1924 * @param enabled True if RTT is now enabled, false otherwise
1925 */
1926 private void fireOnIsRttChanged(final boolean enabled, final RttCall rttCall) {
1927 for (CallbackRecord<Callback> record : mCallbackRecords) {
1928 final Call call = this;
1929 final Callback callback = record.getCallback();
1930 record.getHandler().post(() -> callback.onRttStatusChanged(call, enabled, rttCall));
1931 }
1932 }
1933
1934 /**
1935 * Notifies listeners of a RTT mode change
1936 *
1937 * @param mode The new RTT mode
1938 */
1939 private void fireOnRttModeChanged(final int mode) {
1940 for (CallbackRecord<Callback> record : mCallbackRecords) {
1941 final Call call = this;
1942 final Callback callback = record.getCallback();
1943 record.getHandler().post(() -> callback.onRttModeChanged(call, mode));
1944 }
1945 }
1946
1947 /**
Tyler Gunn1e9bfc62015-08-19 11:18:58 -07001948 * Determines if two bundles are equal.
1949 *
1950 * @param bundle The original bundle.
1951 * @param newBundle The bundle to compare with.
1952 * @retrun {@code true} if the bundles are equal, {@code false} otherwise.
1953 */
1954 private static boolean areBundlesEqual(Bundle bundle, Bundle newBundle) {
1955 if (bundle == null || newBundle == null) {
1956 return bundle == newBundle;
1957 }
1958
1959 if (bundle.size() != newBundle.size()) {
1960 return false;
1961 }
1962
1963 for(String key : bundle.keySet()) {
1964 if (key != null) {
1965 final Object value = bundle.get(key);
1966 final Object newValue = newBundle.get(key);
1967 if (!Objects.equals(value, newValue)) {
1968 return false;
1969 }
1970 }
1971 }
1972 return true;
1973 }
Santos Cordon7c7bc7f2014-07-28 18:15:48 -07001974}