blob: 385929428a524028a8251b77c40fd05b57dc9d41 [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
Andrew Leeda80c872015-04-15 14:09:50 -070019import android.annotation.SystemApi;
Ihab Awade63fadb2014-07-09 21:52:04 -070020import android.net.Uri;
Nancy Chen10798dc2014-08-08 14:00:25 -070021import android.os.Bundle;
Andrew Lee011728f2015-04-23 15:47:06 -070022import android.os.Handler;
Ihab Awade63fadb2014-07-09 21:52:04 -070023
Andrew Lee50aca232014-07-22 16:41:54 -070024import java.lang.String;
Ihab Awade63fadb2014-07-09 21:52:04 -070025import java.util.ArrayList;
26import java.util.Collections;
27import java.util.List;
Santos Cordon7c7bc7f2014-07-28 18:15:48 -070028import java.util.Map;
Ihab Awade63fadb2014-07-09 21:52:04 -070029import java.util.Objects;
Jay Shrauner229e3822014-08-15 09:23:07 -070030import java.util.concurrent.CopyOnWriteArrayList;
Ihab Awade63fadb2014-07-09 21:52:04 -070031
32/**
33 * Represents an ongoing phone call that the in-call app should present to the user.
34 */
35public final class Call {
36 /**
37 * The state of a {@code Call} when newly created.
38 */
39 public static final int STATE_NEW = 0;
40
41 /**
42 * The state of an outgoing {@code Call} when dialing the remote number, but not yet connected.
43 */
44 public static final int STATE_DIALING = 1;
45
46 /**
47 * The state of an incoming {@code Call} when ringing locally, but not yet connected.
48 */
49 public static final int STATE_RINGING = 2;
50
51 /**
52 * The state of a {@code Call} when in a holding state.
53 */
54 public static final int STATE_HOLDING = 3;
55
56 /**
57 * The state of a {@code Call} when actively supporting conversation.
58 */
59 public static final int STATE_ACTIVE = 4;
60
61 /**
62 * The state of a {@code Call} when no further voice or other communication is being
63 * transmitted, the remote side has been or will inevitably be informed that the {@code Call}
64 * is no longer active, and the local data transport has or inevitably will release resources
65 * associated with this {@code Call}.
66 */
67 public static final int STATE_DISCONNECTED = 7;
68
Nancy Chen5da0fd52014-07-08 14:16:17 -070069 /**
Santos Cordone3c507b2015-04-23 14:44:19 -070070 * The state of an outgoing {@code Call} when waiting on user to select a
71 * {@link PhoneAccount} through which to place the call.
Nancy Chen5da0fd52014-07-08 14:16:17 -070072 */
Santos Cordone3c507b2015-04-23 14:44:19 -070073 public static final int STATE_SELECT_PHONE_ACCOUNT = 8;
74
75 /**
76 * @hide
77 * @deprecated use STATE_SELECT_PHONE_ACCOUNT.
78 */
79 @Deprecated
80 @SystemApi
81 public static final int STATE_PRE_DIAL_WAIT = STATE_SELECT_PHONE_ACCOUNT;
Nancy Chen5da0fd52014-07-08 14:16:17 -070082
Nancy Chene20930f2014-08-07 16:17:21 -070083 /**
Nancy Chene9b7a8e2014-08-08 14:26:27 -070084 * The initial state of an outgoing {@code Call}.
85 * Common transitions are to {@link #STATE_DIALING} state for a successful call or
86 * {@link #STATE_DISCONNECTED} if it failed.
Nancy Chene20930f2014-08-07 16:17:21 -070087 */
88 public static final int STATE_CONNECTING = 9;
89
Nancy Chen513c8922014-09-17 14:47:20 -070090 /**
Tyler Gunn4afc6af2014-10-07 10:14:55 -070091 * The state of a {@code Call} when the user has initiated a disconnection of the call, but the
92 * call has not yet been disconnected by the underlying {@code ConnectionService}. The next
93 * state of the call is (potentially) {@link #STATE_DISCONNECTED}.
94 */
95 public static final int STATE_DISCONNECTING = 10;
96
97 /**
Nancy Chen513c8922014-09-17 14:47:20 -070098 * The key to retrieve the optional {@code PhoneAccount}s Telecom can bundle with its Call
99 * extras. Used to pass the phone accounts to display on the front end to the user in order to
100 * select phone accounts to (for example) place a call.
Nancy Chen513c8922014-09-17 14:47:20 -0700101 */
102 public static final String AVAILABLE_PHONE_ACCOUNTS = "selectPhoneAccountAccounts";
103
Ihab Awade63fadb2014-07-09 21:52:04 -0700104 public static class Details {
Ihab Awad5c9c86e2014-11-12 13:41:16 -0800105
106 /** Call can currently be put on hold or unheld. */
107 public static final int CAPABILITY_HOLD = 0x00000001;
108
109 /** Call supports the hold feature. */
110 public static final int CAPABILITY_SUPPORT_HOLD = 0x00000002;
111
112 /**
113 * Calls within a conference can be merged. A {@link ConnectionService} has the option to
114 * add a {@link Conference} call before the child {@link Connection}s are merged. This is how
115 * CDMA-based {@link Connection}s are implemented. For these unmerged {@link Conference}s, this
116 * capability allows a merge button to be shown while the conference call is in the foreground
117 * of the in-call UI.
118 * <p>
119 * This is only intended for use by a {@link Conference}.
120 */
121 public static final int CAPABILITY_MERGE_CONFERENCE = 0x00000004;
122
123 /**
124 * Calls within a conference can be swapped between foreground and background.
125 * See {@link #CAPABILITY_MERGE_CONFERENCE} for additional information.
126 * <p>
127 * This is only intended for use by a {@link Conference}.
128 */
129 public static final int CAPABILITY_SWAP_CONFERENCE = 0x00000008;
130
131 /**
132 * @hide
133 */
Andrew Lee2378ea72015-04-29 14:38:11 -0700134 public static final int CAPABILITY_UNUSED_1 = 0x00000010;
Ihab Awad5c9c86e2014-11-12 13:41:16 -0800135
136 /** Call supports responding via text option. */
137 public static final int CAPABILITY_RESPOND_VIA_TEXT = 0x00000020;
138
139 /** Call can be muted. */
140 public static final int CAPABILITY_MUTE = 0x00000040;
141
142 /**
143 * Call supports conference call management. This capability only applies to {@link Conference}
144 * calls which can have {@link Connection}s as children.
145 */
146 public static final int CAPABILITY_MANAGE_CONFERENCE = 0x00000080;
147
148 /**
Andrew Lee5e9e8bb2015-03-10 13:58:24 -0700149 * Local device supports receiving video.
Ihab Awad5c9c86e2014-11-12 13:41:16 -0800150 */
Andrew Lee5e9e8bb2015-03-10 13:58:24 -0700151 public static final int CAPABILITY_SUPPORTS_VT_LOCAL_RX = 0x00000100;
Ihab Awad5c9c86e2014-11-12 13:41:16 -0800152
153 /**
Andrew Lee5e9e8bb2015-03-10 13:58:24 -0700154 * Local device supports transmitting video.
Ihab Awad5c9c86e2014-11-12 13:41:16 -0800155 */
Andrew Lee5e9e8bb2015-03-10 13:58:24 -0700156 public static final int CAPABILITY_SUPPORTS_VT_LOCAL_TX = 0x00000200;
Ihab Awad5c9c86e2014-11-12 13:41:16 -0800157
158 /**
Andrew Lee5e9e8bb2015-03-10 13:58:24 -0700159 * Local device supports bidirectional video calling.
Ihab Awad5c9c86e2014-11-12 13:41:16 -0800160 */
Andrew Lee9a8f9ce2015-04-10 18:09:46 -0700161 public static final int CAPABILITY_SUPPORTS_VT_LOCAL_BIDIRECTIONAL =
Andrew Lee5e9e8bb2015-03-10 13:58:24 -0700162 CAPABILITY_SUPPORTS_VT_LOCAL_RX | CAPABILITY_SUPPORTS_VT_LOCAL_TX;
Ihab Awad5c9c86e2014-11-12 13:41:16 -0800163
164 /**
Andrew Lee5e9e8bb2015-03-10 13:58:24 -0700165 * Remote device supports receiving video.
Ihab Awad5c9c86e2014-11-12 13:41:16 -0800166 */
Andrew Lee5e9e8bb2015-03-10 13:58:24 -0700167 public static final int CAPABILITY_SUPPORTS_VT_REMOTE_RX = 0x00000400;
168
169 /**
170 * Remote device supports transmitting video.
Andrew Lee5e9e8bb2015-03-10 13:58:24 -0700171 */
172 public static final int CAPABILITY_SUPPORTS_VT_REMOTE_TX = 0x00000800;
173
174 /**
175 * Remote device supports bidirectional video calling.
Andrew Lee5e9e8bb2015-03-10 13:58:24 -0700176 */
Andrew Lee9a8f9ce2015-04-10 18:09:46 -0700177 public static final int CAPABILITY_SUPPORTS_VT_REMOTE_BIDIRECTIONAL =
Andrew Lee5e9e8bb2015-03-10 13:58:24 -0700178 CAPABILITY_SUPPORTS_VT_REMOTE_RX | CAPABILITY_SUPPORTS_VT_REMOTE_TX;
Ihab Awad5c9c86e2014-11-12 13:41:16 -0800179
180 /**
181 * Call is able to be separated from its parent {@code Conference}, if any.
182 */
183 public static final int CAPABILITY_SEPARATE_FROM_CONFERENCE = 0x00001000;
184
185 /**
186 * Call is able to be individually disconnected when in a {@code Conference}.
187 */
188 public static final int CAPABILITY_DISCONNECT_FROM_CONFERENCE = 0x00002000;
189
190 /**
Dong Zhou89f41eb2015-03-15 11:59:49 -0500191 * Speed up audio setup for MT call.
192 * @hide
193 */
Tyler Gunn96d6c402015-03-18 12:39:23 -0700194 public static final int CAPABILITY_SPEED_UP_MT_AUDIO = 0x00040000;
195
Tyler Gunnb5e0cfb2015-04-07 16:10:51 -0700196 /**
197 * Call can be upgraded to a video call.
Rekha Kumar07366812015-03-24 16:42:31 -0700198 * @hide
199 */
200 public static final int CAPABILITY_CAN_UPGRADE_TO_VIDEO = 0x00080000;
201
Tyler Gunnb5e0cfb2015-04-07 16:10:51 -0700202 /**
203 * For video calls, indicates whether the outgoing video for the call can be paused using
Yorke Lee32f24732015-05-12 16:18:03 -0700204 * the {@link android.telecom.VideoProfile#STATE_PAUSED} VideoState.
Tyler Gunnb5e0cfb2015-04-07 16:10:51 -0700205 */
206 public static final int CAPABILITY_CAN_PAUSE_VIDEO = 0x00100000;
207
Bryce Lee81901682015-08-28 16:38:02 -0700208 /**
209 * Call sends responses through connection.
210 * @hide
211 */
Tyler Gunnf97a0092016-01-19 15:59:34 -0800212 public static final int CAPABILITY_CAN_SEND_RESPONSE_VIA_CONNECTION = 0x00200000;
213
214 /**
215 * When set, prevents a video {@code Call} from being downgraded to an audio-only call.
216 * <p>
217 * Should be set when the VideoState has the {@link VideoProfile#STATE_TX_ENABLED} or
218 * {@link VideoProfile#STATE_RX_ENABLED} bits set to indicate that the connection cannot be
219 * downgraded from a video call back to a VideoState of
220 * {@link VideoProfile#STATE_AUDIO_ONLY}.
221 * <p>
222 * Intuitively, a call which can be downgraded to audio should also have local and remote
223 * video
224 * capabilities (see {@link #CAPABILITY_SUPPORTS_VT_LOCAL_BIDIRECTIONAL} and
225 * {@link #CAPABILITY_SUPPORTS_VT_REMOTE_BIDIRECTIONAL}).
226 */
227 public static final int CAPABILITY_CANNOT_DOWNGRADE_VIDEO_TO_AUDIO = 0x00400000;
Bryce Lee81901682015-08-28 16:38:02 -0700228
Tyler Gunnd11a3152015-03-18 13:09:14 -0700229 //******************************************************************************************
Bryce Lee81901682015-08-28 16:38:02 -0700230 // Next CAPABILITY value: 0x00800000
Andrew Lee2378ea72015-04-29 14:38:11 -0700231 //******************************************************************************************
232
233 /**
234 * Whether the call is currently a conference.
235 */
236 public static final int PROPERTY_CONFERENCE = 0x00000001;
237
238 /**
239 * Whether the call is a generic conference, where we do not know the precise state of
240 * participants in the conference (eg. on CDMA).
241 */
242 public static final int PROPERTY_GENERIC_CONFERENCE = 0x00000002;
243
244 /**
245 * Whether the call is made while the device is in emergency callback mode.
246 */
247 public static final int PROPERTY_EMERGENCY_CALLBACK_MODE = 0x00000004;
248
249 /**
250 * Connection is using WIFI.
251 */
252 public static final int PROPERTY_WIFI = 0x00000008;
253
254 /**
255 * Call is using high definition audio.
256 */
257 public static final int PROPERTY_HIGH_DEF_AUDIO = 0x00000010;
258
Tony Maka68dcce2015-12-17 09:31:18 +0000259 /**
260 * Whether the call is associated with the work profile.
261 */
262 public static final int PROPERTY_WORK_CALL = 0x00000020;
263
Andrew Lee2378ea72015-04-29 14:38:11 -0700264 //******************************************************************************************
Tony Maka68dcce2015-12-17 09:31:18 +0000265 // Next PROPERTY value: 0x00000040
Tyler Gunnd11a3152015-03-18 13:09:14 -0700266 //******************************************************************************************
Tyler Gunn068085b2015-02-06 13:56:52 -0800267
Ihab Awade63fadb2014-07-09 21:52:04 -0700268 private final Uri mHandle;
269 private final int mHandlePresentation;
270 private final String mCallerDisplayName;
271 private final int mCallerDisplayNamePresentation;
Evan Charlton8c8a0622014-07-20 12:31:00 -0700272 private final PhoneAccountHandle mAccountHandle;
Ihab Awad5d0410f2014-07-30 10:07:40 -0700273 private final int mCallCapabilities;
Andrew Lee223ad142014-08-27 16:33:08 -0700274 private final int mCallProperties;
Andrew Lee7f3d41f2014-09-11 17:33:16 -0700275 private final DisconnectCause mDisconnectCause;
Ihab Awade63fadb2014-07-09 21:52:04 -0700276 private final long mConnectTimeMillis;
277 private final GatewayInfo mGatewayInfo;
Andrew Lee85f5d422014-07-11 17:22:03 -0700278 private final int mVideoState;
Evan Charlton5b49ade2014-07-15 17:03:20 -0700279 private final StatusHints mStatusHints;
Nancy Chen10798dc2014-08-08 14:00:25 -0700280 private final Bundle mExtras;
Santos Cordon6b7f9552015-05-27 17:21:45 -0700281 private final Bundle mIntentExtras;
Ihab Awade63fadb2014-07-09 21:52:04 -0700282
283 /**
Ihab Awad5c9c86e2014-11-12 13:41:16 -0800284 * Whether the supplied capabilities supports the specified capability.
285 *
286 * @param capabilities A bit field of capabilities.
287 * @param capability The capability to check capabilities for.
288 * @return Whether the specified capability is supported.
Ihab Awad5c9c86e2014-11-12 13:41:16 -0800289 */
290 public static boolean can(int capabilities, int capability) {
Tyler Gunn014c7112015-12-18 14:33:57 -0800291 return (capabilities & capability) == capability;
Ihab Awad5c9c86e2014-11-12 13:41:16 -0800292 }
293
294 /**
295 * Whether the capabilities of this {@code Details} supports the specified capability.
296 *
297 * @param capability The capability to check capabilities for.
298 * @return Whether the specified capability is supported.
Ihab Awad5c9c86e2014-11-12 13:41:16 -0800299 */
300 public boolean can(int capability) {
301 return can(mCallCapabilities, capability);
302 }
303
304 /**
305 * Render a set of capability bits ({@code CAPABILITY_*}) as a human readable string.
306 *
307 * @param capabilities A capability bit field.
308 * @return A human readable string representation.
309 */
310 public static String capabilitiesToString(int capabilities) {
311 StringBuilder builder = new StringBuilder();
312 builder.append("[Capabilities:");
313 if (can(capabilities, CAPABILITY_HOLD)) {
314 builder.append(" CAPABILITY_HOLD");
315 }
316 if (can(capabilities, CAPABILITY_SUPPORT_HOLD)) {
317 builder.append(" CAPABILITY_SUPPORT_HOLD");
318 }
319 if (can(capabilities, CAPABILITY_MERGE_CONFERENCE)) {
320 builder.append(" CAPABILITY_MERGE_CONFERENCE");
321 }
322 if (can(capabilities, CAPABILITY_SWAP_CONFERENCE)) {
323 builder.append(" CAPABILITY_SWAP_CONFERENCE");
324 }
325 if (can(capabilities, CAPABILITY_RESPOND_VIA_TEXT)) {
326 builder.append(" CAPABILITY_RESPOND_VIA_TEXT");
327 }
328 if (can(capabilities, CAPABILITY_MUTE)) {
329 builder.append(" CAPABILITY_MUTE");
330 }
331 if (can(capabilities, CAPABILITY_MANAGE_CONFERENCE)) {
332 builder.append(" CAPABILITY_MANAGE_CONFERENCE");
333 }
Andrew Lee5e9e8bb2015-03-10 13:58:24 -0700334 if (can(capabilities, CAPABILITY_SUPPORTS_VT_LOCAL_RX)) {
335 builder.append(" CAPABILITY_SUPPORTS_VT_LOCAL_RX");
336 }
337 if (can(capabilities, CAPABILITY_SUPPORTS_VT_LOCAL_TX)) {
338 builder.append(" CAPABILITY_SUPPORTS_VT_LOCAL_TX");
339 }
Andrew Lee9a8f9ce2015-04-10 18:09:46 -0700340 if (can(capabilities, CAPABILITY_SUPPORTS_VT_LOCAL_BIDIRECTIONAL)) {
341 builder.append(" CAPABILITY_SUPPORTS_VT_LOCAL_BIDIRECTIONAL");
Ihab Awad5c9c86e2014-11-12 13:41:16 -0800342 }
Andrew Lee5e9e8bb2015-03-10 13:58:24 -0700343 if (can(capabilities, CAPABILITY_SUPPORTS_VT_REMOTE_RX)) {
344 builder.append(" CAPABILITY_SUPPORTS_VT_REMOTE_RX");
345 }
346 if (can(capabilities, CAPABILITY_SUPPORTS_VT_REMOTE_TX)) {
347 builder.append(" CAPABILITY_SUPPORTS_VT_REMOTE_TX");
348 }
Tyler Gunnf97a0092016-01-19 15:59:34 -0800349 if (can(capabilities, CAPABILITY_CANNOT_DOWNGRADE_VIDEO_TO_AUDIO)) {
350 builder.append(" CAPABILITY_CANNOT_DOWNGRADE_VIDEO_TO_AUDIO");
351 }
Andrew Lee9a8f9ce2015-04-10 18:09:46 -0700352 if (can(capabilities, CAPABILITY_SUPPORTS_VT_REMOTE_BIDIRECTIONAL)) {
353 builder.append(" CAPABILITY_SUPPORTS_VT_REMOTE_BIDIRECTIONAL");
Ihab Awad5c9c86e2014-11-12 13:41:16 -0800354 }
Dong Zhou89f41eb2015-03-15 11:59:49 -0500355 if (can(capabilities, CAPABILITY_SPEED_UP_MT_AUDIO)) {
Tyler Gunnd11a3152015-03-18 13:09:14 -0700356 builder.append(" CAPABILITY_SPEED_UP_MT_AUDIO");
Dong Zhou89f41eb2015-03-15 11:59:49 -0500357 }
Rekha Kumar07366812015-03-24 16:42:31 -0700358 if (can(capabilities, CAPABILITY_CAN_UPGRADE_TO_VIDEO)) {
359 builder.append(" CAPABILITY_CAN_UPGRADE_TO_VIDEO");
360 }
Tyler Gunnb5e0cfb2015-04-07 16:10:51 -0700361 if (can(capabilities, CAPABILITY_CAN_PAUSE_VIDEO)) {
362 builder.append(" CAPABILITY_CAN_PAUSE_VIDEO");
363 }
Ihab Awad5c9c86e2014-11-12 13:41:16 -0800364 builder.append("]");
365 return builder.toString();
366 }
367
368 /**
Andrew Lee2378ea72015-04-29 14:38:11 -0700369 * Whether the supplied properties includes the specified property.
370 *
371 * @param properties A bit field of properties.
372 * @param property The property to check properties for.
373 * @return Whether the specified property is supported.
374 */
375 public static boolean hasProperty(int properties, int property) {
Tyler Gunn014c7112015-12-18 14:33:57 -0800376 return (properties & property) == property;
Andrew Lee2378ea72015-04-29 14:38:11 -0700377 }
378
379 /**
380 * Whether the properties of this {@code Details} includes the specified property.
381 *
382 * @param property The property to check properties for.
383 * @return Whether the specified property is supported.
384 */
385 public boolean hasProperty(int property) {
386 return hasProperty(mCallProperties, property);
387 }
388
389 /**
390 * Render a set of property bits ({@code PROPERTY_*}) as a human readable string.
391 *
392 * @param properties A property bit field.
393 * @return A human readable string representation.
394 */
395 public static String propertiesToString(int properties) {
396 StringBuilder builder = new StringBuilder();
397 builder.append("[Properties:");
398 if (hasProperty(properties, PROPERTY_CONFERENCE)) {
399 builder.append(" PROPERTY_CONFERENCE");
400 }
401 if (hasProperty(properties, PROPERTY_GENERIC_CONFERENCE)) {
402 builder.append(" PROPERTY_GENERIC_CONFERENCE");
403 }
404 if (hasProperty(properties, PROPERTY_WIFI)) {
405 builder.append(" PROPERTY_WIFI");
406 }
407 if (hasProperty(properties, PROPERTY_HIGH_DEF_AUDIO)) {
408 builder.append(" PROPERTY_HIGH_DEF_AUDIO");
409 }
410 if (hasProperty(properties, PROPERTY_EMERGENCY_CALLBACK_MODE)) {
Yorke Leebe2a4a22015-06-12 10:10:55 -0700411 builder.append(" PROPERTY_EMERGENCY_CALLBACK_MODE");
Andrew Lee2378ea72015-04-29 14:38:11 -0700412 }
413 builder.append("]");
414 return builder.toString();
415 }
416
417 /**
Ihab Awade63fadb2014-07-09 21:52:04 -0700418 * @return The handle (e.g., phone number) to which the {@code Call} is currently
419 * connected.
420 */
421 public Uri getHandle() {
422 return mHandle;
423 }
424
425 /**
426 * @return The presentation requirements for the handle. See
Tyler Gunnef9f6f92014-09-12 22:16:17 -0700427 * {@link TelecomManager} for valid values.
Ihab Awade63fadb2014-07-09 21:52:04 -0700428 */
429 public int getHandlePresentation() {
430 return mHandlePresentation;
431 }
432
433 /**
434 * @return The display name for the caller.
435 */
436 public String getCallerDisplayName() {
437 return mCallerDisplayName;
438 }
439
440 /**
441 * @return The presentation requirements for the caller display name. See
Tyler Gunnef9f6f92014-09-12 22:16:17 -0700442 * {@link TelecomManager} for valid values.
Ihab Awade63fadb2014-07-09 21:52:04 -0700443 */
444 public int getCallerDisplayNamePresentation() {
445 return mCallerDisplayNamePresentation;
446 }
447
448 /**
Evan Charlton6eb262c2014-07-19 18:18:19 -0700449 * @return The {@code PhoneAccountHandle} whereby the {@code Call} is currently being
450 * routed.
Ihab Awade63fadb2014-07-09 21:52:04 -0700451 */
Evan Charlton8c8a0622014-07-20 12:31:00 -0700452 public PhoneAccountHandle getAccountHandle() {
453 return mAccountHandle;
Ihab Awade63fadb2014-07-09 21:52:04 -0700454 }
455
456 /**
Ihab Awad5c9c86e2014-11-12 13:41:16 -0800457 * @return A bitmask of the capabilities of the {@code Call}, as defined by the various
458 * {@code CAPABILITY_*} constants in this class.
Ihab Awade63fadb2014-07-09 21:52:04 -0700459 */
Ihab Awad5d0410f2014-07-30 10:07:40 -0700460 public int getCallCapabilities() {
461 return mCallCapabilities;
Ihab Awade63fadb2014-07-09 21:52:04 -0700462 }
463
464 /**
Andrew Lee2378ea72015-04-29 14:38:11 -0700465 * @return A bitmask of the properties of the {@code Call}, as defined by the various
466 * {@code PROPERTY_*} constants in this class.
Andrew Lee223ad142014-08-27 16:33:08 -0700467 */
468 public int getCallProperties() {
469 return mCallProperties;
470 }
471
472 /**
Ihab Awade63fadb2014-07-09 21:52:04 -0700473 * @return For a {@link #STATE_DISCONNECTED} {@code Call}, the disconnect cause expressed
Nancy Chenf4cf77c2014-09-19 10:53:21 -0700474 * by {@link android.telecom.DisconnectCause}.
Ihab Awade63fadb2014-07-09 21:52:04 -0700475 */
Andrew Lee7f3d41f2014-09-11 17:33:16 -0700476 public DisconnectCause getDisconnectCause() {
477 return mDisconnectCause;
Ihab Awade63fadb2014-07-09 21:52:04 -0700478 }
479
480 /**
481 * @return The time the {@code Call} has been connected. This information is updated
482 * periodically, but user interfaces should not rely on this to display any "call time
483 * clock".
484 */
Jay Shrauner164a0ac2015-04-14 18:16:10 -0700485 public final long getConnectTimeMillis() {
Ihab Awade63fadb2014-07-09 21:52:04 -0700486 return mConnectTimeMillis;
487 }
488
489 /**
490 * @return Information about any calling gateway the {@code Call} may be using.
491 */
492 public GatewayInfo getGatewayInfo() {
493 return mGatewayInfo;
494 }
495
Andrew Lee7a341382014-07-15 17:05:08 -0700496 /**
Ihab Awad5d0410f2014-07-30 10:07:40 -0700497 * @return The video state of the {@code Call}.
Andrew Lee7a341382014-07-15 17:05:08 -0700498 */
499 public int getVideoState() {
500 return mVideoState;
501 }
502
Ihab Awad5d0410f2014-07-30 10:07:40 -0700503 /**
Tyler Gunnef9f6f92014-09-12 22:16:17 -0700504 * @return The current {@link android.telecom.StatusHints}, or {@code null} if none
Ihab Awad5d0410f2014-07-30 10:07:40 -0700505 * have been set.
Evan Charlton5b49ade2014-07-15 17:03:20 -0700506 */
507 public StatusHints getStatusHints() {
508 return mStatusHints;
509 }
510
Nancy Chen10798dc2014-08-08 14:00:25 -0700511 /**
Santos Cordon6b7f9552015-05-27 17:21:45 -0700512 * @return The extras associated with this call.
Nancy Chen10798dc2014-08-08 14:00:25 -0700513 */
514 public Bundle getExtras() {
515 return mExtras;
516 }
517
Santos Cordon6b7f9552015-05-27 17:21:45 -0700518 /**
519 * @return The extras used with the original intent to place this call.
520 */
521 public Bundle getIntentExtras() {
522 return mIntentExtras;
523 }
524
Ihab Awade63fadb2014-07-09 21:52:04 -0700525 @Override
526 public boolean equals(Object o) {
527 if (o instanceof Details) {
528 Details d = (Details) o;
529 return
530 Objects.equals(mHandle, d.mHandle) &&
531 Objects.equals(mHandlePresentation, d.mHandlePresentation) &&
532 Objects.equals(mCallerDisplayName, d.mCallerDisplayName) &&
533 Objects.equals(mCallerDisplayNamePresentation,
534 d.mCallerDisplayNamePresentation) &&
Evan Charlton8c8a0622014-07-20 12:31:00 -0700535 Objects.equals(mAccountHandle, d.mAccountHandle) &&
Ihab Awad5d0410f2014-07-30 10:07:40 -0700536 Objects.equals(mCallCapabilities, d.mCallCapabilities) &&
Andrew Lee223ad142014-08-27 16:33:08 -0700537 Objects.equals(mCallProperties, d.mCallProperties) &&
Andrew Lee7f3d41f2014-09-11 17:33:16 -0700538 Objects.equals(mDisconnectCause, d.mDisconnectCause) &&
Ihab Awade63fadb2014-07-09 21:52:04 -0700539 Objects.equals(mConnectTimeMillis, d.mConnectTimeMillis) &&
Andrew Lee85f5d422014-07-11 17:22:03 -0700540 Objects.equals(mGatewayInfo, d.mGatewayInfo) &&
Evan Charlton5b49ade2014-07-15 17:03:20 -0700541 Objects.equals(mVideoState, d.mVideoState) &&
Nancy Chen10798dc2014-08-08 14:00:25 -0700542 Objects.equals(mStatusHints, d.mStatusHints) &&
Tyler Gunn1e9bfc62015-08-19 11:18:58 -0700543 areBundlesEqual(mExtras, d.mExtras) &&
544 areBundlesEqual(mIntentExtras, d.mIntentExtras);
Ihab Awade63fadb2014-07-09 21:52:04 -0700545 }
546 return false;
547 }
548
549 @Override
550 public int hashCode() {
551 return
552 Objects.hashCode(mHandle) +
553 Objects.hashCode(mHandlePresentation) +
554 Objects.hashCode(mCallerDisplayName) +
555 Objects.hashCode(mCallerDisplayNamePresentation) +
Evan Charlton8c8a0622014-07-20 12:31:00 -0700556 Objects.hashCode(mAccountHandle) +
Ihab Awad5d0410f2014-07-30 10:07:40 -0700557 Objects.hashCode(mCallCapabilities) +
Andrew Lee223ad142014-08-27 16:33:08 -0700558 Objects.hashCode(mCallProperties) +
Andrew Lee7f3d41f2014-09-11 17:33:16 -0700559 Objects.hashCode(mDisconnectCause) +
Ihab Awade63fadb2014-07-09 21:52:04 -0700560 Objects.hashCode(mConnectTimeMillis) +
Andrew Lee85f5d422014-07-11 17:22:03 -0700561 Objects.hashCode(mGatewayInfo) +
Evan Charlton5b49ade2014-07-15 17:03:20 -0700562 Objects.hashCode(mVideoState) +
Nancy Chen10798dc2014-08-08 14:00:25 -0700563 Objects.hashCode(mStatusHints) +
Santos Cordon6b7f9552015-05-27 17:21:45 -0700564 Objects.hashCode(mExtras) +
565 Objects.hashCode(mIntentExtras);
Ihab Awade63fadb2014-07-09 21:52:04 -0700566 }
567
568 /** {@hide} */
569 public Details(
570 Uri handle,
571 int handlePresentation,
572 String callerDisplayName,
573 int callerDisplayNamePresentation,
Evan Charlton8c8a0622014-07-20 12:31:00 -0700574 PhoneAccountHandle accountHandle,
Ihab Awade63fadb2014-07-09 21:52:04 -0700575 int capabilities,
Andrew Lee223ad142014-08-27 16:33:08 -0700576 int properties,
Andrew Lee7f3d41f2014-09-11 17:33:16 -0700577 DisconnectCause disconnectCause,
Ihab Awade63fadb2014-07-09 21:52:04 -0700578 long connectTimeMillis,
Andrew Lee85f5d422014-07-11 17:22:03 -0700579 GatewayInfo gatewayInfo,
Evan Charlton5b49ade2014-07-15 17:03:20 -0700580 int videoState,
Nancy Chen10798dc2014-08-08 14:00:25 -0700581 StatusHints statusHints,
Santos Cordon6b7f9552015-05-27 17:21:45 -0700582 Bundle extras,
583 Bundle intentExtras) {
Ihab Awade63fadb2014-07-09 21:52:04 -0700584 mHandle = handle;
585 mHandlePresentation = handlePresentation;
586 mCallerDisplayName = callerDisplayName;
587 mCallerDisplayNamePresentation = callerDisplayNamePresentation;
Evan Charlton8c8a0622014-07-20 12:31:00 -0700588 mAccountHandle = accountHandle;
Ihab Awad5d0410f2014-07-30 10:07:40 -0700589 mCallCapabilities = capabilities;
Andrew Lee223ad142014-08-27 16:33:08 -0700590 mCallProperties = properties;
Andrew Lee7f3d41f2014-09-11 17:33:16 -0700591 mDisconnectCause = disconnectCause;
Ihab Awade63fadb2014-07-09 21:52:04 -0700592 mConnectTimeMillis = connectTimeMillis;
593 mGatewayInfo = gatewayInfo;
Andrew Lee85f5d422014-07-11 17:22:03 -0700594 mVideoState = videoState;
Evan Charlton5b49ade2014-07-15 17:03:20 -0700595 mStatusHints = statusHints;
Nancy Chen10798dc2014-08-08 14:00:25 -0700596 mExtras = extras;
Santos Cordon6b7f9552015-05-27 17:21:45 -0700597 mIntentExtras = intentExtras;
Ihab Awade63fadb2014-07-09 21:52:04 -0700598 }
599 }
600
Andrew Leeda80c872015-04-15 14:09:50 -0700601 public static abstract class Callback {
Ihab Awade63fadb2014-07-09 21:52:04 -0700602 /**
603 * Invoked when the state of this {@code Call} has changed. See {@link #getState()}.
604 *
Ihab Awade63fadb2014-07-09 21:52:04 -0700605 * @param call The {@code Call} invoking this method.
606 * @param state The new state of the {@code Call}.
607 */
608 public void onStateChanged(Call call, int state) {}
609
610 /**
611 * Invoked when the parent of this {@code Call} has changed. See {@link #getParent()}.
612 *
613 * @param call The {@code Call} invoking this method.
614 * @param parent The new parent of the {@code Call}.
615 */
616 public void onParentChanged(Call call, Call parent) {}
617
618 /**
619 * Invoked when the children of this {@code Call} have changed. See {@link #getChildren()}.
620 *
621 * @param call The {@code Call} invoking this method.
622 * @param children The new children of the {@code Call}.
623 */
624 public void onChildrenChanged(Call call, List<Call> children) {}
625
626 /**
627 * Invoked when the details of this {@code Call} have changed. See {@link #getDetails()}.
628 *
629 * @param call The {@code Call} invoking this method.
630 * @param details A {@code Details} object describing the {@code Call}.
631 */
632 public void onDetailsChanged(Call call, Details details) {}
633
634 /**
635 * Invoked when the text messages that can be used as responses to the incoming
636 * {@code Call} are loaded from the relevant database.
637 * See {@link #getCannedTextResponses()}.
638 *
639 * @param call The {@code Call} invoking this method.
640 * @param cannedTextResponses The text messages useable as responses.
641 */
642 public void onCannedTextResponsesLoaded(Call call, List<String> cannedTextResponses) {}
643
644 /**
Ihab Awade63fadb2014-07-09 21:52:04 -0700645 * Invoked when the post-dial sequence in the outgoing {@code Call} has reached a pause
646 * character. This causes the post-dial signals to stop pending user confirmation. An
647 * implementation should present this choice to the user and invoke
648 * {@link #postDialContinue(boolean)} when the user makes the choice.
649 *
650 * @param call The {@code Call} invoking this method.
651 * @param remainingPostDialSequence The post-dial characters that remain to be sent.
652 */
653 public void onPostDialWait(Call call, String remainingPostDialSequence) {}
654
655 /**
Andrew Lee50aca232014-07-22 16:41:54 -0700656 * Invoked when the {@code Call.VideoCall} of the {@code Call} has changed.
Ihab Awade63fadb2014-07-09 21:52:04 -0700657 *
658 * @param call The {@code Call} invoking this method.
Andrew Lee50aca232014-07-22 16:41:54 -0700659 * @param videoCall The {@code Call.VideoCall} associated with the {@code Call}.
Ihab Awade63fadb2014-07-09 21:52:04 -0700660 */
Andrew Lee50aca232014-07-22 16:41:54 -0700661 public void onVideoCallChanged(Call call, InCallService.VideoCall videoCall) {}
Ihab Awade63fadb2014-07-09 21:52:04 -0700662
663 /**
664 * Invoked when the {@code Call} is destroyed. Clients should refrain from cleaning
665 * up their UI for the {@code Call} in response to state transitions. Specifically,
666 * clients should not assume that a {@link #onStateChanged(Call, int)} with a state of
667 * {@link #STATE_DISCONNECTED} is the final notification the {@code Call} will send. Rather,
668 * clients should wait for this method to be invoked.
669 *
670 * @param call The {@code Call} being destroyed.
671 */
672 public void onCallDestroyed(Call call) {}
Santos Cordon7c7bc7f2014-07-28 18:15:48 -0700673
674 /**
675 * Invoked upon changes to the set of {@code Call}s with which this {@code Call} can be
676 * conferenced.
677 *
678 * @param call The {@code Call} being updated.
679 * @param conferenceableCalls The {@code Call}s with which this {@code Call} can be
680 * conferenced.
681 */
682 public void onConferenceableCallsChanged(Call call, List<Call> conferenceableCalls) {}
Ihab Awade63fadb2014-07-09 21:52:04 -0700683 }
684
Andrew Leeda80c872015-04-15 14:09:50 -0700685 /**
686 * @deprecated Use {@code Call.Callback} instead.
687 * @hide
688 */
689 @Deprecated
690 @SystemApi
691 public static abstract class Listener extends Callback { }
692
Ihab Awade63fadb2014-07-09 21:52:04 -0700693 private final Phone mPhone;
Tyler Gunnef9f6f92014-09-12 22:16:17 -0700694 private final String mTelecomCallId;
Ihab Awade63fadb2014-07-09 21:52:04 -0700695 private final InCallAdapter mInCallAdapter;
Santos Cordon823fd3c2014-08-07 18:35:18 -0700696 private final List<String> mChildrenIds = new ArrayList<>();
Ihab Awade63fadb2014-07-09 21:52:04 -0700697 private final List<Call> mChildren = new ArrayList<>();
698 private final List<Call> mUnmodifiableChildren = Collections.unmodifiableList(mChildren);
Andrew Lee011728f2015-04-23 15:47:06 -0700699 private final List<CallbackRecord<Callback>> mCallbackRecords = new CopyOnWriteArrayList<>();
Santos Cordon7c7bc7f2014-07-28 18:15:48 -0700700 private final List<Call> mConferenceableCalls = new ArrayList<>();
701 private final List<Call> mUnmodifiableConferenceableCalls =
702 Collections.unmodifiableList(mConferenceableCalls);
703
Santos Cordon823fd3c2014-08-07 18:35:18 -0700704 private boolean mChildrenCached;
705 private String mParentId = null;
Santos Cordon7c7bc7f2014-07-28 18:15:48 -0700706 private int mState;
Ihab Awade63fadb2014-07-09 21:52:04 -0700707 private List<String> mCannedTextResponses = null;
708 private String mRemainingPostDialSequence;
Tyler Gunn584ba6c2015-12-08 10:53:41 -0800709 private VideoCallImpl mVideoCallImpl;
Ihab Awade63fadb2014-07-09 21:52:04 -0700710 private Details mDetails;
Ihab Awade63fadb2014-07-09 21:52:04 -0700711
712 /**
713 * Obtains the post-dial sequence remaining to be emitted by this {@code Call}, if any.
714 *
715 * @return The remaining post-dial sequence, or {@code null} if there is no post-dial sequence
716 * remaining or this {@code Call} is not in a post-dial state.
717 */
718 public String getRemainingPostDialSequence() {
719 return mRemainingPostDialSequence;
720 }
721
722 /**
723 * Instructs this {@link #STATE_RINGING} {@code Call} to answer.
Andrew Lee8da4c3c2014-07-16 10:11:42 -0700724 * @param videoState The video state in which to answer the call.
Ihab Awade63fadb2014-07-09 21:52:04 -0700725 */
Andrew Lee8da4c3c2014-07-16 10:11:42 -0700726 public void answer(int videoState) {
Tyler Gunnef9f6f92014-09-12 22:16:17 -0700727 mInCallAdapter.answerCall(mTelecomCallId, videoState);
Ihab Awade63fadb2014-07-09 21:52:04 -0700728 }
729
730 /**
731 * Instructs this {@link #STATE_RINGING} {@code Call} to reject.
732 *
733 * @param rejectWithMessage Whether to reject with a text message.
734 * @param textMessage An optional text message with which to respond.
735 */
736 public void reject(boolean rejectWithMessage, String textMessage) {
Tyler Gunnef9f6f92014-09-12 22:16:17 -0700737 mInCallAdapter.rejectCall(mTelecomCallId, rejectWithMessage, textMessage);
Ihab Awade63fadb2014-07-09 21:52:04 -0700738 }
739
740 /**
741 * Instructs this {@code Call} to disconnect.
742 */
743 public void disconnect() {
Tyler Gunnef9f6f92014-09-12 22:16:17 -0700744 mInCallAdapter.disconnectCall(mTelecomCallId);
Ihab Awade63fadb2014-07-09 21:52:04 -0700745 }
746
747 /**
748 * Instructs this {@code Call} to go on hold.
749 */
750 public void hold() {
Tyler Gunnef9f6f92014-09-12 22:16:17 -0700751 mInCallAdapter.holdCall(mTelecomCallId);
Ihab Awade63fadb2014-07-09 21:52:04 -0700752 }
753
754 /**
755 * Instructs this {@link #STATE_HOLDING} call to release from hold.
756 */
757 public void unhold() {
Tyler Gunnef9f6f92014-09-12 22:16:17 -0700758 mInCallAdapter.unholdCall(mTelecomCallId);
Ihab Awade63fadb2014-07-09 21:52:04 -0700759 }
760
761 /**
762 * Instructs this {@code Call} to play a dual-tone multi-frequency signaling (DTMF) tone.
763 *
764 * Any other currently playing DTMF tone in the specified call is immediately stopped.
765 *
766 * @param digit A character representing the DTMF digit for which to play the tone. This
767 * value must be one of {@code '0'} through {@code '9'}, {@code '*'} or {@code '#'}.
768 */
769 public void playDtmfTone(char digit) {
Tyler Gunnef9f6f92014-09-12 22:16:17 -0700770 mInCallAdapter.playDtmfTone(mTelecomCallId, digit);
Ihab Awade63fadb2014-07-09 21:52:04 -0700771 }
772
773 /**
774 * Instructs this {@code Call} to stop any dual-tone multi-frequency signaling (DTMF) tone
775 * currently playing.
776 *
777 * DTMF tones are played by calling {@link #playDtmfTone(char)}. If no DTMF tone is
778 * currently playing, this method will do nothing.
779 */
780 public void stopDtmfTone() {
Tyler Gunnef9f6f92014-09-12 22:16:17 -0700781 mInCallAdapter.stopDtmfTone(mTelecomCallId);
Ihab Awade63fadb2014-07-09 21:52:04 -0700782 }
783
784 /**
785 * Instructs this {@code Call} to continue playing a post-dial DTMF string.
786 *
787 * A post-dial DTMF string is a string of digits entered after a phone number, when dialed,
788 * that are immediately sent as DTMF tones to the recipient as soon as the connection is made.
Ihab Awade63fadb2014-07-09 21:52:04 -0700789 *
Tyler Gunnef9f6f92014-09-12 22:16:17 -0700790 * If the DTMF string contains a {@link TelecomManager#DTMF_CHARACTER_PAUSE} symbol, this
Ihab Awade63fadb2014-07-09 21:52:04 -0700791 * {@code Call} will temporarily pause playing the tones for a pre-defined period of time.
792 *
Tyler Gunnef9f6f92014-09-12 22:16:17 -0700793 * If the DTMF string contains a {@link TelecomManager#DTMF_CHARACTER_WAIT} symbol, this
Andrew Leeda80c872015-04-15 14:09:50 -0700794 * {@code Call} will pause playing the tones and notify callbacks via
795 * {@link Callback#onPostDialWait(Call, String)}. At this point, the in-call app
Ihab Awade63fadb2014-07-09 21:52:04 -0700796 * should display to the user an indication of this state and an affordance to continue
797 * the postdial sequence. When the user decides to continue the postdial sequence, the in-call
798 * app should invoke the {@link #postDialContinue(boolean)} method.
799 *
800 * @param proceed Whether or not to continue with the post-dial sequence.
801 */
802 public void postDialContinue(boolean proceed) {
Tyler Gunnef9f6f92014-09-12 22:16:17 -0700803 mInCallAdapter.postDialContinue(mTelecomCallId, proceed);
Ihab Awade63fadb2014-07-09 21:52:04 -0700804 }
805
806 /**
Evan Charlton8c8a0622014-07-20 12:31:00 -0700807 * Notifies this {@code Call} that an account has been selected and to proceed with placing
Nancy Chen36c62f32014-10-21 18:36:39 -0700808 * an outgoing call. Optionally sets this account as the default account.
Nancy Chen5da0fd52014-07-08 14:16:17 -0700809 */
Nancy Chen36c62f32014-10-21 18:36:39 -0700810 public void phoneAccountSelected(PhoneAccountHandle accountHandle, boolean setDefault) {
811 mInCallAdapter.phoneAccountSelected(mTelecomCallId, accountHandle, setDefault);
Nancy Chen5da0fd52014-07-08 14:16:17 -0700812
813 }
814
815 /**
Ihab Awade63fadb2014-07-09 21:52:04 -0700816 * Instructs this {@code Call} to enter a conference.
Santos Cordon7c7bc7f2014-07-28 18:15:48 -0700817 *
818 * @param callToConferenceWith The other call with which to conference.
Ihab Awade63fadb2014-07-09 21:52:04 -0700819 */
Santos Cordon7c7bc7f2014-07-28 18:15:48 -0700820 public void conference(Call callToConferenceWith) {
821 if (callToConferenceWith != null) {
Tyler Gunnef9f6f92014-09-12 22:16:17 -0700822 mInCallAdapter.conference(mTelecomCallId, callToConferenceWith.mTelecomCallId);
Santos Cordon7c7bc7f2014-07-28 18:15:48 -0700823 }
Ihab Awade63fadb2014-07-09 21:52:04 -0700824 }
825
826 /**
827 * Instructs this {@code Call} to split from any conference call with which it may be
828 * connected.
829 */
830 public void splitFromConference() {
Tyler Gunnef9f6f92014-09-12 22:16:17 -0700831 mInCallAdapter.splitFromConference(mTelecomCallId);
Ihab Awade63fadb2014-07-09 21:52:04 -0700832 }
833
834 /**
Ihab Awad5c9c86e2014-11-12 13:41:16 -0800835 * Merges the calls within this conference. See {@link Details#CAPABILITY_MERGE_CONFERENCE}.
Santos Cordona4868042014-09-04 17:39:22 -0700836 */
837 public void mergeConference() {
Tyler Gunnef9f6f92014-09-12 22:16:17 -0700838 mInCallAdapter.mergeConference(mTelecomCallId);
Santos Cordona4868042014-09-04 17:39:22 -0700839 }
840
841 /**
Ihab Awad5c9c86e2014-11-12 13:41:16 -0800842 * Swaps the calls within this conference. See {@link Details#CAPABILITY_SWAP_CONFERENCE}.
Santos Cordona4868042014-09-04 17:39:22 -0700843 */
844 public void swapConference() {
Tyler Gunnef9f6f92014-09-12 22:16:17 -0700845 mInCallAdapter.swapConference(mTelecomCallId);
Santos Cordona4868042014-09-04 17:39:22 -0700846 }
847
848 /**
Ihab Awade63fadb2014-07-09 21:52:04 -0700849 * Obtains the parent of this {@code Call} in a conference, if any.
850 *
851 * @return The parent {@code Call}, or {@code null} if this {@code Call} is not a
852 * child of any conference {@code Call}s.
853 */
854 public Call getParent() {
Santos Cordon823fd3c2014-08-07 18:35:18 -0700855 if (mParentId != null) {
Tyler Gunnef9f6f92014-09-12 22:16:17 -0700856 return mPhone.internalGetCallByTelecomId(mParentId);
Santos Cordon823fd3c2014-08-07 18:35:18 -0700857 }
858 return null;
Ihab Awade63fadb2014-07-09 21:52:04 -0700859 }
860
861 /**
862 * Obtains the children of this conference {@code Call}, if any.
863 *
864 * @return The children of this {@code Call} if this {@code Call} is a conference, or an empty
865 * {@code List} otherwise.
866 */
867 public List<Call> getChildren() {
Santos Cordon823fd3c2014-08-07 18:35:18 -0700868 if (!mChildrenCached) {
869 mChildrenCached = true;
870 mChildren.clear();
871
872 for(String id : mChildrenIds) {
Tyler Gunnef9f6f92014-09-12 22:16:17 -0700873 Call call = mPhone.internalGetCallByTelecomId(id);
Santos Cordon823fd3c2014-08-07 18:35:18 -0700874 if (call == null) {
875 // At least one child was still not found, so do not save true for "cached"
876 mChildrenCached = false;
877 } else {
878 mChildren.add(call);
879 }
880 }
881 }
882
Ihab Awade63fadb2014-07-09 21:52:04 -0700883 return mUnmodifiableChildren;
884 }
885
886 /**
Santos Cordon7c7bc7f2014-07-28 18:15:48 -0700887 * Returns the list of {@code Call}s with which this {@code Call} is allowed to conference.
888 *
889 * @return The list of conferenceable {@code Call}s.
890 */
891 public List<Call> getConferenceableCalls() {
892 return mUnmodifiableConferenceableCalls;
893 }
894
895 /**
Ihab Awade63fadb2014-07-09 21:52:04 -0700896 * Obtains the state of this {@code Call}.
897 *
898 * @return A state value, chosen from the {@code STATE_*} constants.
899 */
900 public int getState() {
901 return mState;
902 }
903
904 /**
905 * Obtains a list of canned, pre-configured message responses to present to the user as
906 * ways of rejecting this {@code Call} using via a text message.
907 *
908 * @see #reject(boolean, String)
909 *
910 * @return A list of canned text message responses.
911 */
912 public List<String> getCannedTextResponses() {
913 return mCannedTextResponses;
914 }
915
916 /**
917 * Obtains an object that can be used to display video from this {@code Call}.
918 *
Andrew Lee50aca232014-07-22 16:41:54 -0700919 * @return An {@code Call.VideoCall}.
Ihab Awade63fadb2014-07-09 21:52:04 -0700920 */
Andrew Lee50aca232014-07-22 16:41:54 -0700921 public InCallService.VideoCall getVideoCall() {
Tyler Gunn584ba6c2015-12-08 10:53:41 -0800922 return mVideoCallImpl;
Ihab Awade63fadb2014-07-09 21:52:04 -0700923 }
924
925 /**
926 * Obtains an object containing call details.
927 *
928 * @return A {@link Details} object. Depending on the state of the {@code Call}, the
929 * result may be {@code null}.
930 */
931 public Details getDetails() {
932 return mDetails;
933 }
934
935 /**
Andrew Leeda80c872015-04-15 14:09:50 -0700936 * Registers a callback to this {@code Call}.
937 *
938 * @param callback A {@code Callback}.
939 */
940 public void registerCallback(Callback callback) {
Andrew Lee011728f2015-04-23 15:47:06 -0700941 registerCallback(callback, new Handler());
942 }
943
944 /**
945 * Registers a callback to this {@code Call}.
946 *
947 * @param callback A {@code Callback}.
948 * @param handler A handler which command and status changes will be delivered to.
949 */
950 public void registerCallback(Callback callback, Handler handler) {
951 unregisterCallback(callback);
Roshan Pius1ca62072015-07-07 17:34:51 -0700952 // Don't allow new callback registration if the call is already being destroyed.
953 if (callback != null && handler != null && mState != STATE_DISCONNECTED) {
Andrew Lee011728f2015-04-23 15:47:06 -0700954 mCallbackRecords.add(new CallbackRecord<Callback>(callback, handler));
955 }
Andrew Leeda80c872015-04-15 14:09:50 -0700956 }
957
958 /**
959 * Unregisters a callback from this {@code Call}.
960 *
961 * @param callback A {@code Callback}.
962 */
963 public void unregisterCallback(Callback callback) {
Roshan Pius1ca62072015-07-07 17:34:51 -0700964 // Don't allow callback deregistration if the call is already being destroyed.
965 if (callback != null && mState != STATE_DISCONNECTED) {
Andrew Lee011728f2015-04-23 15:47:06 -0700966 for (CallbackRecord<Callback> record : mCallbackRecords) {
967 if (record.getCallback() == callback) {
968 mCallbackRecords.remove(record);
969 break;
970 }
971 }
Andrew Leeda80c872015-04-15 14:09:50 -0700972 }
973 }
974
975 /**
Ihab Awade63fadb2014-07-09 21:52:04 -0700976 * Adds a listener to this {@code Call}.
977 *
978 * @param listener A {@code Listener}.
Andrew Leeda80c872015-04-15 14:09:50 -0700979 * @deprecated Use {@link #registerCallback} instead.
980 * @hide
Ihab Awade63fadb2014-07-09 21:52:04 -0700981 */
Andrew Leeda80c872015-04-15 14:09:50 -0700982 @Deprecated
983 @SystemApi
Ihab Awade63fadb2014-07-09 21:52:04 -0700984 public void addListener(Listener listener) {
Andrew Leeda80c872015-04-15 14:09:50 -0700985 registerCallback(listener);
Ihab Awade63fadb2014-07-09 21:52:04 -0700986 }
987
988 /**
989 * Removes a listener from this {@code Call}.
990 *
991 * @param listener A {@code Listener}.
Andrew Leeda80c872015-04-15 14:09:50 -0700992 * @deprecated Use {@link #unregisterCallback} instead.
993 * @hide
Ihab Awade63fadb2014-07-09 21:52:04 -0700994 */
Andrew Leeda80c872015-04-15 14:09:50 -0700995 @Deprecated
996 @SystemApi
Ihab Awade63fadb2014-07-09 21:52:04 -0700997 public void removeListener(Listener listener) {
Andrew Leeda80c872015-04-15 14:09:50 -0700998 unregisterCallback(listener);
Ihab Awade63fadb2014-07-09 21:52:04 -0700999 }
1000
1001 /** {@hide} */
Tyler Gunnef9f6f92014-09-12 22:16:17 -07001002 Call(Phone phone, String telecomCallId, InCallAdapter inCallAdapter) {
Ihab Awade63fadb2014-07-09 21:52:04 -07001003 mPhone = phone;
Tyler Gunnef9f6f92014-09-12 22:16:17 -07001004 mTelecomCallId = telecomCallId;
Ihab Awade63fadb2014-07-09 21:52:04 -07001005 mInCallAdapter = inCallAdapter;
1006 mState = STATE_NEW;
1007 }
1008
1009 /** {@hide} */
Shriram Ganeshddf570e2015-05-31 09:18:48 -07001010 Call(Phone phone, String telecomCallId, InCallAdapter inCallAdapter, int state) {
1011 mPhone = phone;
1012 mTelecomCallId = telecomCallId;
1013 mInCallAdapter = inCallAdapter;
1014 mState = state;
1015 }
1016
1017 /** {@hide} */
Ihab Awade63fadb2014-07-09 21:52:04 -07001018 final String internalGetCallId() {
Tyler Gunnef9f6f92014-09-12 22:16:17 -07001019 return mTelecomCallId;
Ihab Awade63fadb2014-07-09 21:52:04 -07001020 }
1021
1022 /** {@hide} */
Santos Cordon7c7bc7f2014-07-28 18:15:48 -07001023 final void internalUpdate(ParcelableCall parcelableCall, Map<String, Call> callIdMap) {
Ihab Awade63fadb2014-07-09 21:52:04 -07001024 // First, we update the internal state as far as possible before firing any updates.
Ihab Awade63fadb2014-07-09 21:52:04 -07001025 Details details = new Details(
Santos Cordon88b771d2014-07-19 13:10:40 -07001026 parcelableCall.getHandle(),
1027 parcelableCall.getHandlePresentation(),
1028 parcelableCall.getCallerDisplayName(),
1029 parcelableCall.getCallerDisplayNamePresentation(),
1030 parcelableCall.getAccountHandle(),
1031 parcelableCall.getCapabilities(),
Andrew Lee223ad142014-08-27 16:33:08 -07001032 parcelableCall.getProperties(),
Andrew Lee7f3d41f2014-09-11 17:33:16 -07001033 parcelableCall.getDisconnectCause(),
Santos Cordon88b771d2014-07-19 13:10:40 -07001034 parcelableCall.getConnectTimeMillis(),
1035 parcelableCall.getGatewayInfo(),
1036 parcelableCall.getVideoState(),
Nancy Chen10798dc2014-08-08 14:00:25 -07001037 parcelableCall.getStatusHints(),
Santos Cordon6b7f9552015-05-27 17:21:45 -07001038 parcelableCall.getExtras(),
1039 parcelableCall.getIntentExtras());
Ihab Awade63fadb2014-07-09 21:52:04 -07001040 boolean detailsChanged = !Objects.equals(mDetails, details);
1041 if (detailsChanged) {
1042 mDetails = details;
1043 }
1044
1045 boolean cannedTextResponsesChanged = false;
Santos Cordon88b771d2014-07-19 13:10:40 -07001046 if (mCannedTextResponses == null && parcelableCall.getCannedSmsResponses() != null
1047 && !parcelableCall.getCannedSmsResponses().isEmpty()) {
1048 mCannedTextResponses =
1049 Collections.unmodifiableList(parcelableCall.getCannedSmsResponses());
Yorke Leee886f632015-08-04 13:43:31 -07001050 cannedTextResponsesChanged = true;
Ihab Awade63fadb2014-07-09 21:52:04 -07001051 }
1052
Tyler Gunn584ba6c2015-12-08 10:53:41 -08001053 VideoCallImpl newVideoCallImpl = parcelableCall.getVideoCallImpl();
Tyler Gunn75958422015-04-15 14:23:42 -07001054 boolean videoCallChanged = parcelableCall.isVideoCallProviderChanged() &&
Tyler Gunn584ba6c2015-12-08 10:53:41 -08001055 !Objects.equals(mVideoCallImpl, newVideoCallImpl);
Andrew Lee50aca232014-07-22 16:41:54 -07001056 if (videoCallChanged) {
Tyler Gunn584ba6c2015-12-08 10:53:41 -08001057 mVideoCallImpl = newVideoCallImpl;
1058 }
1059 if (mVideoCallImpl != null) {
1060 mVideoCallImpl.setVideoState(getDetails().getVideoState());
Ihab Awade63fadb2014-07-09 21:52:04 -07001061 }
1062
Santos Cordone3c507b2015-04-23 14:44:19 -07001063 int state = parcelableCall.getState();
Ihab Awade63fadb2014-07-09 21:52:04 -07001064 boolean stateChanged = mState != state;
1065 if (stateChanged) {
1066 mState = state;
1067 }
1068
Santos Cordon823fd3c2014-08-07 18:35:18 -07001069 String parentId = parcelableCall.getParentCallId();
1070 boolean parentChanged = !Objects.equals(mParentId, parentId);
1071 if (parentChanged) {
1072 mParentId = parentId;
Ihab Awade63fadb2014-07-09 21:52:04 -07001073 }
1074
Santos Cordon823fd3c2014-08-07 18:35:18 -07001075 List<String> childCallIds = parcelableCall.getChildCallIds();
1076 boolean childrenChanged = !Objects.equals(childCallIds, mChildrenIds);
1077 if (childrenChanged) {
1078 mChildrenIds.clear();
1079 mChildrenIds.addAll(parcelableCall.getChildCallIds());
1080 mChildrenCached = false;
Ihab Awade63fadb2014-07-09 21:52:04 -07001081 }
1082
Santos Cordon7c7bc7f2014-07-28 18:15:48 -07001083 List<String> conferenceableCallIds = parcelableCall.getConferenceableCallIds();
1084 List<Call> conferenceableCalls = new ArrayList<Call>(conferenceableCallIds.size());
1085 for (String otherId : conferenceableCallIds) {
1086 if (callIdMap.containsKey(otherId)) {
1087 conferenceableCalls.add(callIdMap.get(otherId));
1088 }
1089 }
1090
1091 if (!Objects.equals(mConferenceableCalls, conferenceableCalls)) {
1092 mConferenceableCalls.clear();
1093 mConferenceableCalls.addAll(conferenceableCalls);
1094 fireConferenceableCallsChanged();
1095 }
1096
Ihab Awade63fadb2014-07-09 21:52:04 -07001097 // Now we fire updates, ensuring that any client who listens to any of these notifications
1098 // gets the most up-to-date state.
1099
1100 if (stateChanged) {
1101 fireStateChanged(mState);
1102 }
1103 if (detailsChanged) {
1104 fireDetailsChanged(mDetails);
1105 }
1106 if (cannedTextResponsesChanged) {
1107 fireCannedTextResponsesLoaded(mCannedTextResponses);
1108 }
Andrew Lee50aca232014-07-22 16:41:54 -07001109 if (videoCallChanged) {
Tyler Gunn584ba6c2015-12-08 10:53:41 -08001110 fireVideoCallChanged(mVideoCallImpl);
Ihab Awade63fadb2014-07-09 21:52:04 -07001111 }
Santos Cordon823fd3c2014-08-07 18:35:18 -07001112 if (parentChanged) {
1113 fireParentChanged(getParent());
1114 }
1115 if (childrenChanged) {
1116 fireChildrenChanged(getChildren());
1117 }
Ihab Awade63fadb2014-07-09 21:52:04 -07001118
1119 // If we have transitioned to DISCONNECTED, that means we need to notify clients and
1120 // remove ourselves from the Phone. Note that we do this after completing all state updates
1121 // so a client can cleanly transition all their UI to the state appropriate for a
1122 // DISCONNECTED Call while still relying on the existence of that Call in the Phone's list.
1123 if (mState == STATE_DISCONNECTED) {
1124 fireCallDestroyed();
Ihab Awade63fadb2014-07-09 21:52:04 -07001125 }
1126 }
1127
1128 /** {@hide} */
Ihab Awade63fadb2014-07-09 21:52:04 -07001129 final void internalSetPostDialWait(String remaining) {
1130 mRemainingPostDialSequence = remaining;
1131 firePostDialWait(mRemainingPostDialSequence);
1132 }
1133
Sailesh Nepal2ab88cc2014-07-18 14:49:18 -07001134 /** {@hide} */
Santos Cordonf30d7e92014-08-26 09:54:33 -07001135 final void internalSetDisconnected() {
1136 if (mState != Call.STATE_DISCONNECTED) {
1137 mState = Call.STATE_DISCONNECTED;
1138 fireStateChanged(mState);
1139 fireCallDestroyed();
Santos Cordonf30d7e92014-08-26 09:54:33 -07001140 }
1141 }
1142
Andrew Lee011728f2015-04-23 15:47:06 -07001143 private void fireStateChanged(final int newState) {
1144 for (CallbackRecord<Callback> record : mCallbackRecords) {
1145 final Call call = this;
1146 final Callback callback = record.getCallback();
1147 record.getHandler().post(new Runnable() {
1148 @Override
1149 public void run() {
1150 callback.onStateChanged(call, newState);
1151 }
1152 });
Ihab Awade63fadb2014-07-09 21:52:04 -07001153 }
1154 }
1155
Andrew Lee011728f2015-04-23 15:47:06 -07001156 private void fireParentChanged(final Call newParent) {
1157 for (CallbackRecord<Callback> record : mCallbackRecords) {
1158 final Call call = this;
1159 final Callback callback = record.getCallback();
1160 record.getHandler().post(new Runnable() {
1161 @Override
1162 public void run() {
1163 callback.onParentChanged(call, newParent);
1164 }
1165 });
Ihab Awade63fadb2014-07-09 21:52:04 -07001166 }
1167 }
1168
Andrew Lee011728f2015-04-23 15:47:06 -07001169 private void fireChildrenChanged(final List<Call> children) {
1170 for (CallbackRecord<Callback> record : mCallbackRecords) {
1171 final Call call = this;
1172 final Callback callback = record.getCallback();
1173 record.getHandler().post(new Runnable() {
1174 @Override
1175 public void run() {
1176 callback.onChildrenChanged(call, children);
1177 }
1178 });
Ihab Awade63fadb2014-07-09 21:52:04 -07001179 }
1180 }
1181
Andrew Lee011728f2015-04-23 15:47:06 -07001182 private void fireDetailsChanged(final Details details) {
1183 for (CallbackRecord<Callback> record : mCallbackRecords) {
1184 final Call call = this;
1185 final Callback callback = record.getCallback();
1186 record.getHandler().post(new Runnable() {
1187 @Override
1188 public void run() {
1189 callback.onDetailsChanged(call, details);
1190 }
1191 });
Ihab Awade63fadb2014-07-09 21:52:04 -07001192 }
1193 }
1194
Andrew Lee011728f2015-04-23 15:47:06 -07001195 private void fireCannedTextResponsesLoaded(final List<String> cannedTextResponses) {
1196 for (CallbackRecord<Callback> record : mCallbackRecords) {
1197 final Call call = this;
1198 final Callback callback = record.getCallback();
1199 record.getHandler().post(new Runnable() {
1200 @Override
1201 public void run() {
1202 callback.onCannedTextResponsesLoaded(call, cannedTextResponses);
1203 }
1204 });
Ihab Awade63fadb2014-07-09 21:52:04 -07001205 }
1206 }
1207
Andrew Lee011728f2015-04-23 15:47:06 -07001208 private void fireVideoCallChanged(final InCallService.VideoCall videoCall) {
1209 for (CallbackRecord<Callback> record : mCallbackRecords) {
1210 final Call call = this;
1211 final Callback callback = record.getCallback();
1212 record.getHandler().post(new Runnable() {
1213 @Override
1214 public void run() {
1215 callback.onVideoCallChanged(call, videoCall);
1216 }
1217 });
Ihab Awade63fadb2014-07-09 21:52:04 -07001218 }
1219 }
1220
Andrew Lee011728f2015-04-23 15:47:06 -07001221 private void firePostDialWait(final String remainingPostDialSequence) {
1222 for (CallbackRecord<Callback> record : mCallbackRecords) {
1223 final Call call = this;
1224 final Callback callback = record.getCallback();
1225 record.getHandler().post(new Runnable() {
1226 @Override
1227 public void run() {
1228 callback.onPostDialWait(call, remainingPostDialSequence);
1229 }
1230 });
Ihab Awade63fadb2014-07-09 21:52:04 -07001231 }
1232 }
1233
1234 private void fireCallDestroyed() {
Roshan Pius1ca62072015-07-07 17:34:51 -07001235 /**
1236 * To preserve the ordering of the Call's onCallDestroyed callback and Phone's
1237 * onCallRemoved callback, we remove this call from the Phone's record
1238 * only once all of the registered onCallDestroyed callbacks are executed.
1239 * All the callbacks get removed from our records as a part of this operation
1240 * since onCallDestroyed is the final callback.
1241 */
1242 final Call call = this;
1243 if (mCallbackRecords.isEmpty()) {
1244 // No callbacks registered, remove the call from Phone's record.
1245 mPhone.internalRemoveCall(call);
1246 }
1247 for (final CallbackRecord<Callback> record : mCallbackRecords) {
Andrew Lee011728f2015-04-23 15:47:06 -07001248 final Callback callback = record.getCallback();
1249 record.getHandler().post(new Runnable() {
1250 @Override
1251 public void run() {
Roshan Pius1ca62072015-07-07 17:34:51 -07001252 boolean isFinalRemoval = false;
1253 RuntimeException toThrow = null;
1254 try {
1255 callback.onCallDestroyed(call);
1256 } catch (RuntimeException e) {
1257 toThrow = e;
1258 }
1259 synchronized(Call.this) {
1260 mCallbackRecords.remove(record);
1261 if (mCallbackRecords.isEmpty()) {
1262 isFinalRemoval = true;
1263 }
1264 }
1265 if (isFinalRemoval) {
1266 mPhone.internalRemoveCall(call);
1267 }
1268 if (toThrow != null) {
1269 throw toThrow;
1270 }
Andrew Lee011728f2015-04-23 15:47:06 -07001271 }
1272 });
Ihab Awade63fadb2014-07-09 21:52:04 -07001273 }
1274 }
1275
Santos Cordon7c7bc7f2014-07-28 18:15:48 -07001276 private void fireConferenceableCallsChanged() {
Andrew Lee011728f2015-04-23 15:47:06 -07001277 for (CallbackRecord<Callback> record : mCallbackRecords) {
1278 final Call call = this;
1279 final Callback callback = record.getCallback();
1280 record.getHandler().post(new Runnable() {
1281 @Override
1282 public void run() {
1283 callback.onConferenceableCallsChanged(call, mUnmodifiableConferenceableCalls);
1284 }
1285 });
Santos Cordon7c7bc7f2014-07-28 18:15:48 -07001286 }
1287 }
Tyler Gunn1e9bfc62015-08-19 11:18:58 -07001288
1289 /**
1290 * Determines if two bundles are equal.
1291 *
1292 * @param bundle The original bundle.
1293 * @param newBundle The bundle to compare with.
1294 * @retrun {@code true} if the bundles are equal, {@code false} otherwise.
1295 */
1296 private static boolean areBundlesEqual(Bundle bundle, Bundle newBundle) {
1297 if (bundle == null || newBundle == null) {
1298 return bundle == newBundle;
1299 }
1300
1301 if (bundle.size() != newBundle.size()) {
1302 return false;
1303 }
1304
1305 for(String key : bundle.keySet()) {
1306 if (key != null) {
1307 final Object value = bundle.get(key);
1308 final Object newValue = newBundle.get(key);
1309 if (!Objects.equals(value, newValue)) {
1310 return false;
1311 }
1312 }
1313 }
1314 return true;
1315 }
Santos Cordon7c7bc7f2014-07-28 18:15:48 -07001316}