blob: aa95e1d69a10e738830cf7c432819fcb5495b129 [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;
Andrew Lee011728f2015-04-23 15:47:06 -070027import java.util.LinkedList;
Ihab Awade63fadb2014-07-09 21:52:04 -070028import java.util.List;
Santos Cordon7c7bc7f2014-07-28 18:15:48 -070029import java.util.Map;
Ihab Awade63fadb2014-07-09 21:52:04 -070030import java.util.Objects;
Jay Shrauner229e3822014-08-15 09:23:07 -070031import java.util.concurrent.CopyOnWriteArrayList;
Ihab Awade63fadb2014-07-09 21:52:04 -070032
33/**
34 * Represents an ongoing phone call that the in-call app should present to the user.
35 */
36public final class Call {
37 /**
38 * The state of a {@code Call} when newly created.
39 */
40 public static final int STATE_NEW = 0;
41
42 /**
43 * The state of an outgoing {@code Call} when dialing the remote number, but not yet connected.
44 */
45 public static final int STATE_DIALING = 1;
46
47 /**
48 * The state of an incoming {@code Call} when ringing locally, but not yet connected.
49 */
50 public static final int STATE_RINGING = 2;
51
52 /**
53 * The state of a {@code Call} when in a holding state.
54 */
55 public static final int STATE_HOLDING = 3;
56
57 /**
58 * The state of a {@code Call} when actively supporting conversation.
59 */
60 public static final int STATE_ACTIVE = 4;
61
62 /**
63 * The state of a {@code Call} when no further voice or other communication is being
64 * transmitted, the remote side has been or will inevitably be informed that the {@code Call}
65 * is no longer active, and the local data transport has or inevitably will release resources
66 * associated with this {@code Call}.
67 */
68 public static final int STATE_DISCONNECTED = 7;
69
Nancy Chen5da0fd52014-07-08 14:16:17 -070070 /**
Santos Cordone3c507b2015-04-23 14:44:19 -070071 * The state of an outgoing {@code Call} when waiting on user to select a
72 * {@link PhoneAccount} through which to place the call.
Nancy Chen5da0fd52014-07-08 14:16:17 -070073 */
Santos Cordone3c507b2015-04-23 14:44:19 -070074 public static final int STATE_SELECT_PHONE_ACCOUNT = 8;
75
76 /**
77 * @hide
78 * @deprecated use STATE_SELECT_PHONE_ACCOUNT.
79 */
80 @Deprecated
81 @SystemApi
82 public static final int STATE_PRE_DIAL_WAIT = STATE_SELECT_PHONE_ACCOUNT;
Nancy Chen5da0fd52014-07-08 14:16:17 -070083
Nancy Chene20930f2014-08-07 16:17:21 -070084 /**
Nancy Chene9b7a8e2014-08-08 14:26:27 -070085 * The initial state of an outgoing {@code Call}.
86 * Common transitions are to {@link #STATE_DIALING} state for a successful call or
87 * {@link #STATE_DISCONNECTED} if it failed.
Nancy Chene20930f2014-08-07 16:17:21 -070088 */
89 public static final int STATE_CONNECTING = 9;
90
Nancy Chen513c8922014-09-17 14:47:20 -070091 /**
Tyler Gunn4afc6af2014-10-07 10:14:55 -070092 * The state of a {@code Call} when the user has initiated a disconnection of the call, but the
93 * call has not yet been disconnected by the underlying {@code ConnectionService}. The next
94 * state of the call is (potentially) {@link #STATE_DISCONNECTED}.
95 */
96 public static final int STATE_DISCONNECTING = 10;
97
98 /**
Nancy Chen513c8922014-09-17 14:47:20 -070099 * The key to retrieve the optional {@code PhoneAccount}s Telecom can bundle with its Call
100 * extras. Used to pass the phone accounts to display on the front end to the user in order to
101 * select phone accounts to (for example) place a call.
Nancy Chen513c8922014-09-17 14:47:20 -0700102 */
103 public static final String AVAILABLE_PHONE_ACCOUNTS = "selectPhoneAccountAccounts";
104
Ihab Awade63fadb2014-07-09 21:52:04 -0700105 public static class Details {
Ihab Awad5c9c86e2014-11-12 13:41:16 -0800106
107 /** Call can currently be put on hold or unheld. */
108 public static final int CAPABILITY_HOLD = 0x00000001;
109
110 /** Call supports the hold feature. */
111 public static final int CAPABILITY_SUPPORT_HOLD = 0x00000002;
112
113 /**
114 * Calls within a conference can be merged. A {@link ConnectionService} has the option to
115 * add a {@link Conference} call before the child {@link Connection}s are merged. This is how
116 * CDMA-based {@link Connection}s are implemented. For these unmerged {@link Conference}s, this
117 * capability allows a merge button to be shown while the conference call is in the foreground
118 * of the in-call UI.
119 * <p>
120 * This is only intended for use by a {@link Conference}.
121 */
122 public static final int CAPABILITY_MERGE_CONFERENCE = 0x00000004;
123
124 /**
125 * Calls within a conference can be swapped between foreground and background.
126 * See {@link #CAPABILITY_MERGE_CONFERENCE} for additional information.
127 * <p>
128 * This is only intended for use by a {@link Conference}.
129 */
130 public static final int CAPABILITY_SWAP_CONFERENCE = 0x00000008;
131
132 /**
133 * @hide
134 */
Andrew Lee2378ea72015-04-29 14:38:11 -0700135 public static final int CAPABILITY_UNUSED_1 = 0x00000010;
Ihab Awad5c9c86e2014-11-12 13:41:16 -0800136
137 /** Call supports responding via text option. */
138 public static final int CAPABILITY_RESPOND_VIA_TEXT = 0x00000020;
139
140 /** Call can be muted. */
141 public static final int CAPABILITY_MUTE = 0x00000040;
142
143 /**
144 * Call supports conference call management. This capability only applies to {@link Conference}
145 * calls which can have {@link Connection}s as children.
146 */
147 public static final int CAPABILITY_MANAGE_CONFERENCE = 0x00000080;
148
149 /**
Andrew Lee5e9e8bb2015-03-10 13:58:24 -0700150 * Local device supports receiving video.
Ihab Awad5c9c86e2014-11-12 13:41:16 -0800151 */
Andrew Lee5e9e8bb2015-03-10 13:58:24 -0700152 public static final int CAPABILITY_SUPPORTS_VT_LOCAL_RX = 0x00000100;
Ihab Awad5c9c86e2014-11-12 13:41:16 -0800153
154 /**
Andrew Lee5e9e8bb2015-03-10 13:58:24 -0700155 * Local device supports transmitting video.
Ihab Awad5c9c86e2014-11-12 13:41:16 -0800156 */
Andrew Lee5e9e8bb2015-03-10 13:58:24 -0700157 public static final int CAPABILITY_SUPPORTS_VT_LOCAL_TX = 0x00000200;
Ihab Awad5c9c86e2014-11-12 13:41:16 -0800158
159 /**
Andrew Lee5e9e8bb2015-03-10 13:58:24 -0700160 * Local device supports bidirectional video calling.
Ihab Awad5c9c86e2014-11-12 13:41:16 -0800161 */
Andrew Lee9a8f9ce2015-04-10 18:09:46 -0700162 public static final int CAPABILITY_SUPPORTS_VT_LOCAL_BIDIRECTIONAL =
Andrew Lee5e9e8bb2015-03-10 13:58:24 -0700163 CAPABILITY_SUPPORTS_VT_LOCAL_RX | CAPABILITY_SUPPORTS_VT_LOCAL_TX;
Ihab Awad5c9c86e2014-11-12 13:41:16 -0800164
165 /**
Andrew Lee5e9e8bb2015-03-10 13:58:24 -0700166 * Remote device supports receiving video.
Ihab Awad5c9c86e2014-11-12 13:41:16 -0800167 */
Andrew Lee5e9e8bb2015-03-10 13:58:24 -0700168 public static final int CAPABILITY_SUPPORTS_VT_REMOTE_RX = 0x00000400;
169
170 /**
171 * Remote device supports transmitting video.
Andrew Lee5e9e8bb2015-03-10 13:58:24 -0700172 */
173 public static final int CAPABILITY_SUPPORTS_VT_REMOTE_TX = 0x00000800;
174
175 /**
176 * Remote device supports bidirectional video calling.
Andrew Lee5e9e8bb2015-03-10 13:58:24 -0700177 */
Andrew Lee9a8f9ce2015-04-10 18:09:46 -0700178 public static final int CAPABILITY_SUPPORTS_VT_REMOTE_BIDIRECTIONAL =
Andrew Lee5e9e8bb2015-03-10 13:58:24 -0700179 CAPABILITY_SUPPORTS_VT_REMOTE_RX | CAPABILITY_SUPPORTS_VT_REMOTE_TX;
Ihab Awad5c9c86e2014-11-12 13:41:16 -0800180
181 /**
182 * Call is able to be separated from its parent {@code Conference}, if any.
183 */
184 public static final int CAPABILITY_SEPARATE_FROM_CONFERENCE = 0x00001000;
185
186 /**
187 * Call is able to be individually disconnected when in a {@code Conference}.
188 */
189 public static final int CAPABILITY_DISCONNECT_FROM_CONFERENCE = 0x00002000;
190
191 /**
Dong Zhou89f41eb2015-03-15 11:59:49 -0500192 * Speed up audio setup for MT call.
193 * @hide
194 */
Tyler Gunn96d6c402015-03-18 12:39:23 -0700195 public static final int CAPABILITY_SPEED_UP_MT_AUDIO = 0x00040000;
196
Tyler Gunnb5e0cfb2015-04-07 16:10:51 -0700197 /**
198 * Call can be upgraded to a video call.
Rekha Kumar07366812015-03-24 16:42:31 -0700199 * @hide
200 */
201 public static final int CAPABILITY_CAN_UPGRADE_TO_VIDEO = 0x00080000;
202
Tyler Gunnb5e0cfb2015-04-07 16:10:51 -0700203 /**
204 * For video calls, indicates whether the outgoing video for the call can be paused using
Yorke Lee32f24732015-05-12 16:18:03 -0700205 * the {@link android.telecom.VideoProfile#STATE_PAUSED} VideoState.
Tyler Gunnb5e0cfb2015-04-07 16:10:51 -0700206 */
207 public static final int CAPABILITY_CAN_PAUSE_VIDEO = 0x00100000;
208
Bryce Lee81901682015-08-28 16:38:02 -0700209 /**
210 * Call sends responses through connection.
211 * @hide
212 */
213 public static final int CAPABILITY_CAN_SEND_RESPONSE_VIA_CONNECTION = 0x00400000;
214
Tyler Gunnd11a3152015-03-18 13:09:14 -0700215 //******************************************************************************************
Bryce Lee81901682015-08-28 16:38:02 -0700216 // Next CAPABILITY value: 0x00800000
Andrew Lee2378ea72015-04-29 14:38:11 -0700217 //******************************************************************************************
218
219 /**
220 * Whether the call is currently a conference.
221 */
222 public static final int PROPERTY_CONFERENCE = 0x00000001;
223
224 /**
225 * Whether the call is a generic conference, where we do not know the precise state of
226 * participants in the conference (eg. on CDMA).
227 */
228 public static final int PROPERTY_GENERIC_CONFERENCE = 0x00000002;
229
230 /**
231 * Whether the call is made while the device is in emergency callback mode.
232 */
233 public static final int PROPERTY_EMERGENCY_CALLBACK_MODE = 0x00000004;
234
235 /**
236 * Connection is using WIFI.
237 */
238 public static final int PROPERTY_WIFI = 0x00000008;
239
240 /**
241 * Call is using high definition audio.
242 */
243 public static final int PROPERTY_HIGH_DEF_AUDIO = 0x00000010;
244
Tony Maka68dcce2015-12-17 09:31:18 +0000245 /**
246 * Whether the call is associated with the work profile.
247 */
248 public static final int PROPERTY_WORK_CALL = 0x00000020;
249
Andrew Lee2378ea72015-04-29 14:38:11 -0700250 //******************************************************************************************
Tony Maka68dcce2015-12-17 09:31:18 +0000251 // Next PROPERTY value: 0x00000040
Tyler Gunnd11a3152015-03-18 13:09:14 -0700252 //******************************************************************************************
Tyler Gunn068085b2015-02-06 13:56:52 -0800253
Ihab Awade63fadb2014-07-09 21:52:04 -0700254 private final Uri mHandle;
255 private final int mHandlePresentation;
256 private final String mCallerDisplayName;
257 private final int mCallerDisplayNamePresentation;
Evan Charlton8c8a0622014-07-20 12:31:00 -0700258 private final PhoneAccountHandle mAccountHandle;
Ihab Awad5d0410f2014-07-30 10:07:40 -0700259 private final int mCallCapabilities;
Andrew Lee223ad142014-08-27 16:33:08 -0700260 private final int mCallProperties;
Andrew Lee7f3d41f2014-09-11 17:33:16 -0700261 private final DisconnectCause mDisconnectCause;
Ihab Awade63fadb2014-07-09 21:52:04 -0700262 private final long mConnectTimeMillis;
263 private final GatewayInfo mGatewayInfo;
Andrew Lee85f5d422014-07-11 17:22:03 -0700264 private final int mVideoState;
Evan Charlton5b49ade2014-07-15 17:03:20 -0700265 private final StatusHints mStatusHints;
Nancy Chen10798dc2014-08-08 14:00:25 -0700266 private final Bundle mExtras;
Santos Cordon6b7f9552015-05-27 17:21:45 -0700267 private final Bundle mIntentExtras;
Ihab Awade63fadb2014-07-09 21:52:04 -0700268
269 /**
Ihab Awad5c9c86e2014-11-12 13:41:16 -0800270 * Whether the supplied capabilities supports the specified capability.
271 *
272 * @param capabilities A bit field of capabilities.
273 * @param capability The capability to check capabilities for.
274 * @return Whether the specified capability is supported.
Ihab Awad5c9c86e2014-11-12 13:41:16 -0800275 */
276 public static boolean can(int capabilities, int capability) {
Tyler Gunn014c7112015-12-18 14:33:57 -0800277 return (capabilities & capability) == capability;
Ihab Awad5c9c86e2014-11-12 13:41:16 -0800278 }
279
280 /**
281 * Whether the capabilities of this {@code Details} supports the specified capability.
282 *
283 * @param capability The capability to check capabilities for.
284 * @return Whether the specified capability is supported.
Ihab Awad5c9c86e2014-11-12 13:41:16 -0800285 */
286 public boolean can(int capability) {
287 return can(mCallCapabilities, capability);
288 }
289
290 /**
291 * Render a set of capability bits ({@code CAPABILITY_*}) as a human readable string.
292 *
293 * @param capabilities A capability bit field.
294 * @return A human readable string representation.
295 */
296 public static String capabilitiesToString(int capabilities) {
297 StringBuilder builder = new StringBuilder();
298 builder.append("[Capabilities:");
299 if (can(capabilities, CAPABILITY_HOLD)) {
300 builder.append(" CAPABILITY_HOLD");
301 }
302 if (can(capabilities, CAPABILITY_SUPPORT_HOLD)) {
303 builder.append(" CAPABILITY_SUPPORT_HOLD");
304 }
305 if (can(capabilities, CAPABILITY_MERGE_CONFERENCE)) {
306 builder.append(" CAPABILITY_MERGE_CONFERENCE");
307 }
308 if (can(capabilities, CAPABILITY_SWAP_CONFERENCE)) {
309 builder.append(" CAPABILITY_SWAP_CONFERENCE");
310 }
311 if (can(capabilities, CAPABILITY_RESPOND_VIA_TEXT)) {
312 builder.append(" CAPABILITY_RESPOND_VIA_TEXT");
313 }
314 if (can(capabilities, CAPABILITY_MUTE)) {
315 builder.append(" CAPABILITY_MUTE");
316 }
317 if (can(capabilities, CAPABILITY_MANAGE_CONFERENCE)) {
318 builder.append(" CAPABILITY_MANAGE_CONFERENCE");
319 }
Andrew Lee5e9e8bb2015-03-10 13:58:24 -0700320 if (can(capabilities, CAPABILITY_SUPPORTS_VT_LOCAL_RX)) {
321 builder.append(" CAPABILITY_SUPPORTS_VT_LOCAL_RX");
322 }
323 if (can(capabilities, CAPABILITY_SUPPORTS_VT_LOCAL_TX)) {
324 builder.append(" CAPABILITY_SUPPORTS_VT_LOCAL_TX");
325 }
Andrew Lee9a8f9ce2015-04-10 18:09:46 -0700326 if (can(capabilities, CAPABILITY_SUPPORTS_VT_LOCAL_BIDIRECTIONAL)) {
327 builder.append(" CAPABILITY_SUPPORTS_VT_LOCAL_BIDIRECTIONAL");
Ihab Awad5c9c86e2014-11-12 13:41:16 -0800328 }
Andrew Lee5e9e8bb2015-03-10 13:58:24 -0700329 if (can(capabilities, CAPABILITY_SUPPORTS_VT_REMOTE_RX)) {
330 builder.append(" CAPABILITY_SUPPORTS_VT_REMOTE_RX");
331 }
332 if (can(capabilities, CAPABILITY_SUPPORTS_VT_REMOTE_TX)) {
333 builder.append(" CAPABILITY_SUPPORTS_VT_REMOTE_TX");
334 }
Andrew Lee9a8f9ce2015-04-10 18:09:46 -0700335 if (can(capabilities, CAPABILITY_SUPPORTS_VT_REMOTE_BIDIRECTIONAL)) {
336 builder.append(" CAPABILITY_SUPPORTS_VT_REMOTE_BIDIRECTIONAL");
Ihab Awad5c9c86e2014-11-12 13:41:16 -0800337 }
Dong Zhou89f41eb2015-03-15 11:59:49 -0500338 if (can(capabilities, CAPABILITY_SPEED_UP_MT_AUDIO)) {
Tyler Gunnd11a3152015-03-18 13:09:14 -0700339 builder.append(" CAPABILITY_SPEED_UP_MT_AUDIO");
Dong Zhou89f41eb2015-03-15 11:59:49 -0500340 }
Rekha Kumar07366812015-03-24 16:42:31 -0700341 if (can(capabilities, CAPABILITY_CAN_UPGRADE_TO_VIDEO)) {
342 builder.append(" CAPABILITY_CAN_UPGRADE_TO_VIDEO");
343 }
Tyler Gunnb5e0cfb2015-04-07 16:10:51 -0700344 if (can(capabilities, CAPABILITY_CAN_PAUSE_VIDEO)) {
345 builder.append(" CAPABILITY_CAN_PAUSE_VIDEO");
346 }
Ihab Awad5c9c86e2014-11-12 13:41:16 -0800347 builder.append("]");
348 return builder.toString();
349 }
350
351 /**
Andrew Lee2378ea72015-04-29 14:38:11 -0700352 * Whether the supplied properties includes the specified property.
353 *
354 * @param properties A bit field of properties.
355 * @param property The property to check properties for.
356 * @return Whether the specified property is supported.
357 */
358 public static boolean hasProperty(int properties, int property) {
Tyler Gunn014c7112015-12-18 14:33:57 -0800359 return (properties & property) == property;
Andrew Lee2378ea72015-04-29 14:38:11 -0700360 }
361
362 /**
363 * Whether the properties of this {@code Details} includes the specified property.
364 *
365 * @param property The property to check properties for.
366 * @return Whether the specified property is supported.
367 */
368 public boolean hasProperty(int property) {
369 return hasProperty(mCallProperties, property);
370 }
371
372 /**
373 * Render a set of property bits ({@code PROPERTY_*}) as a human readable string.
374 *
375 * @param properties A property bit field.
376 * @return A human readable string representation.
377 */
378 public static String propertiesToString(int properties) {
379 StringBuilder builder = new StringBuilder();
380 builder.append("[Properties:");
381 if (hasProperty(properties, PROPERTY_CONFERENCE)) {
382 builder.append(" PROPERTY_CONFERENCE");
383 }
384 if (hasProperty(properties, PROPERTY_GENERIC_CONFERENCE)) {
385 builder.append(" PROPERTY_GENERIC_CONFERENCE");
386 }
387 if (hasProperty(properties, PROPERTY_WIFI)) {
388 builder.append(" PROPERTY_WIFI");
389 }
390 if (hasProperty(properties, PROPERTY_HIGH_DEF_AUDIO)) {
391 builder.append(" PROPERTY_HIGH_DEF_AUDIO");
392 }
393 if (hasProperty(properties, PROPERTY_EMERGENCY_CALLBACK_MODE)) {
Yorke Leebe2a4a22015-06-12 10:10:55 -0700394 builder.append(" PROPERTY_EMERGENCY_CALLBACK_MODE");
Andrew Lee2378ea72015-04-29 14:38:11 -0700395 }
396 builder.append("]");
397 return builder.toString();
398 }
399
400 /**
Ihab Awade63fadb2014-07-09 21:52:04 -0700401 * @return The handle (e.g., phone number) to which the {@code Call} is currently
402 * connected.
403 */
404 public Uri getHandle() {
405 return mHandle;
406 }
407
408 /**
409 * @return The presentation requirements for the handle. See
Tyler Gunnef9f6f92014-09-12 22:16:17 -0700410 * {@link TelecomManager} for valid values.
Ihab Awade63fadb2014-07-09 21:52:04 -0700411 */
412 public int getHandlePresentation() {
413 return mHandlePresentation;
414 }
415
416 /**
417 * @return The display name for the caller.
418 */
419 public String getCallerDisplayName() {
420 return mCallerDisplayName;
421 }
422
423 /**
424 * @return The presentation requirements for the caller display name. See
Tyler Gunnef9f6f92014-09-12 22:16:17 -0700425 * {@link TelecomManager} for valid values.
Ihab Awade63fadb2014-07-09 21:52:04 -0700426 */
427 public int getCallerDisplayNamePresentation() {
428 return mCallerDisplayNamePresentation;
429 }
430
431 /**
Evan Charlton6eb262c2014-07-19 18:18:19 -0700432 * @return The {@code PhoneAccountHandle} whereby the {@code Call} is currently being
433 * routed.
Ihab Awade63fadb2014-07-09 21:52:04 -0700434 */
Evan Charlton8c8a0622014-07-20 12:31:00 -0700435 public PhoneAccountHandle getAccountHandle() {
436 return mAccountHandle;
Ihab Awade63fadb2014-07-09 21:52:04 -0700437 }
438
439 /**
Ihab Awad5c9c86e2014-11-12 13:41:16 -0800440 * @return A bitmask of the capabilities of the {@code Call}, as defined by the various
441 * {@code CAPABILITY_*} constants in this class.
Ihab Awade63fadb2014-07-09 21:52:04 -0700442 */
Ihab Awad5d0410f2014-07-30 10:07:40 -0700443 public int getCallCapabilities() {
444 return mCallCapabilities;
Ihab Awade63fadb2014-07-09 21:52:04 -0700445 }
446
447 /**
Andrew Lee2378ea72015-04-29 14:38:11 -0700448 * @return A bitmask of the properties of the {@code Call}, as defined by the various
449 * {@code PROPERTY_*} constants in this class.
Andrew Lee223ad142014-08-27 16:33:08 -0700450 */
451 public int getCallProperties() {
452 return mCallProperties;
453 }
454
455 /**
Ihab Awade63fadb2014-07-09 21:52:04 -0700456 * @return For a {@link #STATE_DISCONNECTED} {@code Call}, the disconnect cause expressed
Nancy Chenf4cf77c2014-09-19 10:53:21 -0700457 * by {@link android.telecom.DisconnectCause}.
Ihab Awade63fadb2014-07-09 21:52:04 -0700458 */
Andrew Lee7f3d41f2014-09-11 17:33:16 -0700459 public DisconnectCause getDisconnectCause() {
460 return mDisconnectCause;
Ihab Awade63fadb2014-07-09 21:52:04 -0700461 }
462
463 /**
464 * @return The time the {@code Call} has been connected. This information is updated
465 * periodically, but user interfaces should not rely on this to display any "call time
466 * clock".
467 */
Jay Shrauner164a0ac2015-04-14 18:16:10 -0700468 public final long getConnectTimeMillis() {
Ihab Awade63fadb2014-07-09 21:52:04 -0700469 return mConnectTimeMillis;
470 }
471
472 /**
473 * @return Information about any calling gateway the {@code Call} may be using.
474 */
475 public GatewayInfo getGatewayInfo() {
476 return mGatewayInfo;
477 }
478
Andrew Lee7a341382014-07-15 17:05:08 -0700479 /**
Ihab Awad5d0410f2014-07-30 10:07:40 -0700480 * @return The video state of the {@code Call}.
Andrew Lee7a341382014-07-15 17:05:08 -0700481 */
482 public int getVideoState() {
483 return mVideoState;
484 }
485
Ihab Awad5d0410f2014-07-30 10:07:40 -0700486 /**
Tyler Gunnef9f6f92014-09-12 22:16:17 -0700487 * @return The current {@link android.telecom.StatusHints}, or {@code null} if none
Ihab Awad5d0410f2014-07-30 10:07:40 -0700488 * have been set.
Evan Charlton5b49ade2014-07-15 17:03:20 -0700489 */
490 public StatusHints getStatusHints() {
491 return mStatusHints;
492 }
493
Nancy Chen10798dc2014-08-08 14:00:25 -0700494 /**
Santos Cordon6b7f9552015-05-27 17:21:45 -0700495 * @return The extras associated with this call.
Nancy Chen10798dc2014-08-08 14:00:25 -0700496 */
497 public Bundle getExtras() {
498 return mExtras;
499 }
500
Santos Cordon6b7f9552015-05-27 17:21:45 -0700501 /**
502 * @return The extras used with the original intent to place this call.
503 */
504 public Bundle getIntentExtras() {
505 return mIntentExtras;
506 }
507
Ihab Awade63fadb2014-07-09 21:52:04 -0700508 @Override
509 public boolean equals(Object o) {
510 if (o instanceof Details) {
511 Details d = (Details) o;
512 return
513 Objects.equals(mHandle, d.mHandle) &&
514 Objects.equals(mHandlePresentation, d.mHandlePresentation) &&
515 Objects.equals(mCallerDisplayName, d.mCallerDisplayName) &&
516 Objects.equals(mCallerDisplayNamePresentation,
517 d.mCallerDisplayNamePresentation) &&
Evan Charlton8c8a0622014-07-20 12:31:00 -0700518 Objects.equals(mAccountHandle, d.mAccountHandle) &&
Ihab Awad5d0410f2014-07-30 10:07:40 -0700519 Objects.equals(mCallCapabilities, d.mCallCapabilities) &&
Andrew Lee223ad142014-08-27 16:33:08 -0700520 Objects.equals(mCallProperties, d.mCallProperties) &&
Andrew Lee7f3d41f2014-09-11 17:33:16 -0700521 Objects.equals(mDisconnectCause, d.mDisconnectCause) &&
Ihab Awade63fadb2014-07-09 21:52:04 -0700522 Objects.equals(mConnectTimeMillis, d.mConnectTimeMillis) &&
Andrew Lee85f5d422014-07-11 17:22:03 -0700523 Objects.equals(mGatewayInfo, d.mGatewayInfo) &&
Evan Charlton5b49ade2014-07-15 17:03:20 -0700524 Objects.equals(mVideoState, d.mVideoState) &&
Nancy Chen10798dc2014-08-08 14:00:25 -0700525 Objects.equals(mStatusHints, d.mStatusHints) &&
Tyler Gunn1e9bfc62015-08-19 11:18:58 -0700526 areBundlesEqual(mExtras, d.mExtras) &&
527 areBundlesEqual(mIntentExtras, d.mIntentExtras);
Ihab Awade63fadb2014-07-09 21:52:04 -0700528 }
529 return false;
530 }
531
532 @Override
533 public int hashCode() {
534 return
535 Objects.hashCode(mHandle) +
536 Objects.hashCode(mHandlePresentation) +
537 Objects.hashCode(mCallerDisplayName) +
538 Objects.hashCode(mCallerDisplayNamePresentation) +
Evan Charlton8c8a0622014-07-20 12:31:00 -0700539 Objects.hashCode(mAccountHandle) +
Ihab Awad5d0410f2014-07-30 10:07:40 -0700540 Objects.hashCode(mCallCapabilities) +
Andrew Lee223ad142014-08-27 16:33:08 -0700541 Objects.hashCode(mCallProperties) +
Andrew Lee7f3d41f2014-09-11 17:33:16 -0700542 Objects.hashCode(mDisconnectCause) +
Ihab Awade63fadb2014-07-09 21:52:04 -0700543 Objects.hashCode(mConnectTimeMillis) +
Andrew Lee85f5d422014-07-11 17:22:03 -0700544 Objects.hashCode(mGatewayInfo) +
Evan Charlton5b49ade2014-07-15 17:03:20 -0700545 Objects.hashCode(mVideoState) +
Nancy Chen10798dc2014-08-08 14:00:25 -0700546 Objects.hashCode(mStatusHints) +
Santos Cordon6b7f9552015-05-27 17:21:45 -0700547 Objects.hashCode(mExtras) +
548 Objects.hashCode(mIntentExtras);
Ihab Awade63fadb2014-07-09 21:52:04 -0700549 }
550
551 /** {@hide} */
552 public Details(
553 Uri handle,
554 int handlePresentation,
555 String callerDisplayName,
556 int callerDisplayNamePresentation,
Evan Charlton8c8a0622014-07-20 12:31:00 -0700557 PhoneAccountHandle accountHandle,
Ihab Awade63fadb2014-07-09 21:52:04 -0700558 int capabilities,
Andrew Lee223ad142014-08-27 16:33:08 -0700559 int properties,
Andrew Lee7f3d41f2014-09-11 17:33:16 -0700560 DisconnectCause disconnectCause,
Ihab Awade63fadb2014-07-09 21:52:04 -0700561 long connectTimeMillis,
Andrew Lee85f5d422014-07-11 17:22:03 -0700562 GatewayInfo gatewayInfo,
Evan Charlton5b49ade2014-07-15 17:03:20 -0700563 int videoState,
Nancy Chen10798dc2014-08-08 14:00:25 -0700564 StatusHints statusHints,
Santos Cordon6b7f9552015-05-27 17:21:45 -0700565 Bundle extras,
566 Bundle intentExtras) {
Ihab Awade63fadb2014-07-09 21:52:04 -0700567 mHandle = handle;
568 mHandlePresentation = handlePresentation;
569 mCallerDisplayName = callerDisplayName;
570 mCallerDisplayNamePresentation = callerDisplayNamePresentation;
Evan Charlton8c8a0622014-07-20 12:31:00 -0700571 mAccountHandle = accountHandle;
Ihab Awad5d0410f2014-07-30 10:07:40 -0700572 mCallCapabilities = capabilities;
Andrew Lee223ad142014-08-27 16:33:08 -0700573 mCallProperties = properties;
Andrew Lee7f3d41f2014-09-11 17:33:16 -0700574 mDisconnectCause = disconnectCause;
Ihab Awade63fadb2014-07-09 21:52:04 -0700575 mConnectTimeMillis = connectTimeMillis;
576 mGatewayInfo = gatewayInfo;
Andrew Lee85f5d422014-07-11 17:22:03 -0700577 mVideoState = videoState;
Evan Charlton5b49ade2014-07-15 17:03:20 -0700578 mStatusHints = statusHints;
Nancy Chen10798dc2014-08-08 14:00:25 -0700579 mExtras = extras;
Santos Cordon6b7f9552015-05-27 17:21:45 -0700580 mIntentExtras = intentExtras;
Ihab Awade63fadb2014-07-09 21:52:04 -0700581 }
582 }
583
Andrew Leeda80c872015-04-15 14:09:50 -0700584 public static abstract class Callback {
Ihab Awade63fadb2014-07-09 21:52:04 -0700585 /**
586 * Invoked when the state of this {@code Call} has changed. See {@link #getState()}.
587 *
Ihab Awade63fadb2014-07-09 21:52:04 -0700588 * @param call The {@code Call} invoking this method.
589 * @param state The new state of the {@code Call}.
590 */
591 public void onStateChanged(Call call, int state) {}
592
593 /**
594 * Invoked when the parent of this {@code Call} has changed. See {@link #getParent()}.
595 *
596 * @param call The {@code Call} invoking this method.
597 * @param parent The new parent of the {@code Call}.
598 */
599 public void onParentChanged(Call call, Call parent) {}
600
601 /**
602 * Invoked when the children of this {@code Call} have changed. See {@link #getChildren()}.
603 *
604 * @param call The {@code Call} invoking this method.
605 * @param children The new children of the {@code Call}.
606 */
607 public void onChildrenChanged(Call call, List<Call> children) {}
608
609 /**
610 * Invoked when the details of this {@code Call} have changed. See {@link #getDetails()}.
611 *
612 * @param call The {@code Call} invoking this method.
613 * @param details A {@code Details} object describing the {@code Call}.
614 */
615 public void onDetailsChanged(Call call, Details details) {}
616
617 /**
618 * Invoked when the text messages that can be used as responses to the incoming
619 * {@code Call} are loaded from the relevant database.
620 * See {@link #getCannedTextResponses()}.
621 *
622 * @param call The {@code Call} invoking this method.
623 * @param cannedTextResponses The text messages useable as responses.
624 */
625 public void onCannedTextResponsesLoaded(Call call, List<String> cannedTextResponses) {}
626
627 /**
Ihab Awade63fadb2014-07-09 21:52:04 -0700628 * Invoked when the post-dial sequence in the outgoing {@code Call} has reached a pause
629 * character. This causes the post-dial signals to stop pending user confirmation. An
630 * implementation should present this choice to the user and invoke
631 * {@link #postDialContinue(boolean)} when the user makes the choice.
632 *
633 * @param call The {@code Call} invoking this method.
634 * @param remainingPostDialSequence The post-dial characters that remain to be sent.
635 */
636 public void onPostDialWait(Call call, String remainingPostDialSequence) {}
637
638 /**
Andrew Lee50aca232014-07-22 16:41:54 -0700639 * Invoked when the {@code Call.VideoCall} of the {@code Call} has changed.
Ihab Awade63fadb2014-07-09 21:52:04 -0700640 *
641 * @param call The {@code Call} invoking this method.
Andrew Lee50aca232014-07-22 16:41:54 -0700642 * @param videoCall The {@code Call.VideoCall} associated with the {@code Call}.
Ihab Awade63fadb2014-07-09 21:52:04 -0700643 */
Andrew Lee50aca232014-07-22 16:41:54 -0700644 public void onVideoCallChanged(Call call, InCallService.VideoCall videoCall) {}
Ihab Awade63fadb2014-07-09 21:52:04 -0700645
646 /**
647 * Invoked when the {@code Call} is destroyed. Clients should refrain from cleaning
648 * up their UI for the {@code Call} in response to state transitions. Specifically,
649 * clients should not assume that a {@link #onStateChanged(Call, int)} with a state of
650 * {@link #STATE_DISCONNECTED} is the final notification the {@code Call} will send. Rather,
651 * clients should wait for this method to be invoked.
652 *
653 * @param call The {@code Call} being destroyed.
654 */
655 public void onCallDestroyed(Call call) {}
Santos Cordon7c7bc7f2014-07-28 18:15:48 -0700656
657 /**
658 * Invoked upon changes to the set of {@code Call}s with which this {@code Call} can be
659 * conferenced.
660 *
661 * @param call The {@code Call} being updated.
662 * @param conferenceableCalls The {@code Call}s with which this {@code Call} can be
663 * conferenced.
664 */
665 public void onConferenceableCallsChanged(Call call, List<Call> conferenceableCalls) {}
Ihab Awade63fadb2014-07-09 21:52:04 -0700666 }
667
Andrew Leeda80c872015-04-15 14:09:50 -0700668 /**
669 * @deprecated Use {@code Call.Callback} instead.
670 * @hide
671 */
672 @Deprecated
673 @SystemApi
674 public static abstract class Listener extends Callback { }
675
Ihab Awade63fadb2014-07-09 21:52:04 -0700676 private final Phone mPhone;
Tyler Gunnef9f6f92014-09-12 22:16:17 -0700677 private final String mTelecomCallId;
Ihab Awade63fadb2014-07-09 21:52:04 -0700678 private final InCallAdapter mInCallAdapter;
Santos Cordon823fd3c2014-08-07 18:35:18 -0700679 private final List<String> mChildrenIds = new ArrayList<>();
Ihab Awade63fadb2014-07-09 21:52:04 -0700680 private final List<Call> mChildren = new ArrayList<>();
681 private final List<Call> mUnmodifiableChildren = Collections.unmodifiableList(mChildren);
Andrew Lee011728f2015-04-23 15:47:06 -0700682 private final List<CallbackRecord<Callback>> mCallbackRecords = new CopyOnWriteArrayList<>();
Santos Cordon7c7bc7f2014-07-28 18:15:48 -0700683 private final List<Call> mConferenceableCalls = new ArrayList<>();
684 private final List<Call> mUnmodifiableConferenceableCalls =
685 Collections.unmodifiableList(mConferenceableCalls);
686
Santos Cordon823fd3c2014-08-07 18:35:18 -0700687 private boolean mChildrenCached;
688 private String mParentId = null;
Santos Cordon7c7bc7f2014-07-28 18:15:48 -0700689 private int mState;
Ihab Awade63fadb2014-07-09 21:52:04 -0700690 private List<String> mCannedTextResponses = null;
691 private String mRemainingPostDialSequence;
Tyler Gunn584ba6c2015-12-08 10:53:41 -0800692 private VideoCallImpl mVideoCallImpl;
Ihab Awade63fadb2014-07-09 21:52:04 -0700693 private Details mDetails;
Ihab Awade63fadb2014-07-09 21:52:04 -0700694
695 /**
696 * Obtains the post-dial sequence remaining to be emitted by this {@code Call}, if any.
697 *
698 * @return The remaining post-dial sequence, or {@code null} if there is no post-dial sequence
699 * remaining or this {@code Call} is not in a post-dial state.
700 */
701 public String getRemainingPostDialSequence() {
702 return mRemainingPostDialSequence;
703 }
704
705 /**
706 * Instructs this {@link #STATE_RINGING} {@code Call} to answer.
Andrew Lee8da4c3c2014-07-16 10:11:42 -0700707 * @param videoState The video state in which to answer the call.
Ihab Awade63fadb2014-07-09 21:52:04 -0700708 */
Andrew Lee8da4c3c2014-07-16 10:11:42 -0700709 public void answer(int videoState) {
Tyler Gunnef9f6f92014-09-12 22:16:17 -0700710 mInCallAdapter.answerCall(mTelecomCallId, videoState);
Ihab Awade63fadb2014-07-09 21:52:04 -0700711 }
712
713 /**
714 * Instructs this {@link #STATE_RINGING} {@code Call} to reject.
715 *
716 * @param rejectWithMessage Whether to reject with a text message.
717 * @param textMessage An optional text message with which to respond.
718 */
719 public void reject(boolean rejectWithMessage, String textMessage) {
Tyler Gunnef9f6f92014-09-12 22:16:17 -0700720 mInCallAdapter.rejectCall(mTelecomCallId, rejectWithMessage, textMessage);
Ihab Awade63fadb2014-07-09 21:52:04 -0700721 }
722
723 /**
724 * Instructs this {@code Call} to disconnect.
725 */
726 public void disconnect() {
Tyler Gunnef9f6f92014-09-12 22:16:17 -0700727 mInCallAdapter.disconnectCall(mTelecomCallId);
Ihab Awade63fadb2014-07-09 21:52:04 -0700728 }
729
730 /**
731 * Instructs this {@code Call} to go on hold.
732 */
733 public void hold() {
Tyler Gunnef9f6f92014-09-12 22:16:17 -0700734 mInCallAdapter.holdCall(mTelecomCallId);
Ihab Awade63fadb2014-07-09 21:52:04 -0700735 }
736
737 /**
738 * Instructs this {@link #STATE_HOLDING} call to release from hold.
739 */
740 public void unhold() {
Tyler Gunnef9f6f92014-09-12 22:16:17 -0700741 mInCallAdapter.unholdCall(mTelecomCallId);
Ihab Awade63fadb2014-07-09 21:52:04 -0700742 }
743
744 /**
745 * Instructs this {@code Call} to play a dual-tone multi-frequency signaling (DTMF) tone.
746 *
747 * Any other currently playing DTMF tone in the specified call is immediately stopped.
748 *
749 * @param digit A character representing the DTMF digit for which to play the tone. This
750 * value must be one of {@code '0'} through {@code '9'}, {@code '*'} or {@code '#'}.
751 */
752 public void playDtmfTone(char digit) {
Tyler Gunnef9f6f92014-09-12 22:16:17 -0700753 mInCallAdapter.playDtmfTone(mTelecomCallId, digit);
Ihab Awade63fadb2014-07-09 21:52:04 -0700754 }
755
756 /**
757 * Instructs this {@code Call} to stop any dual-tone multi-frequency signaling (DTMF) tone
758 * currently playing.
759 *
760 * DTMF tones are played by calling {@link #playDtmfTone(char)}. If no DTMF tone is
761 * currently playing, this method will do nothing.
762 */
763 public void stopDtmfTone() {
Tyler Gunnef9f6f92014-09-12 22:16:17 -0700764 mInCallAdapter.stopDtmfTone(mTelecomCallId);
Ihab Awade63fadb2014-07-09 21:52:04 -0700765 }
766
767 /**
768 * Instructs this {@code Call} to continue playing a post-dial DTMF string.
769 *
770 * A post-dial DTMF string is a string of digits entered after a phone number, when dialed,
771 * that are immediately sent as DTMF tones to the recipient as soon as the connection is made.
Ihab Awade63fadb2014-07-09 21:52:04 -0700772 *
Tyler Gunnef9f6f92014-09-12 22:16:17 -0700773 * If the DTMF string contains a {@link TelecomManager#DTMF_CHARACTER_PAUSE} symbol, this
Ihab Awade63fadb2014-07-09 21:52:04 -0700774 * {@code Call} will temporarily pause playing the tones for a pre-defined period of time.
775 *
Tyler Gunnef9f6f92014-09-12 22:16:17 -0700776 * If the DTMF string contains a {@link TelecomManager#DTMF_CHARACTER_WAIT} symbol, this
Andrew Leeda80c872015-04-15 14:09:50 -0700777 * {@code Call} will pause playing the tones and notify callbacks via
778 * {@link Callback#onPostDialWait(Call, String)}. At this point, the in-call app
Ihab Awade63fadb2014-07-09 21:52:04 -0700779 * should display to the user an indication of this state and an affordance to continue
780 * the postdial sequence. When the user decides to continue the postdial sequence, the in-call
781 * app should invoke the {@link #postDialContinue(boolean)} method.
782 *
783 * @param proceed Whether or not to continue with the post-dial sequence.
784 */
785 public void postDialContinue(boolean proceed) {
Tyler Gunnef9f6f92014-09-12 22:16:17 -0700786 mInCallAdapter.postDialContinue(mTelecomCallId, proceed);
Ihab Awade63fadb2014-07-09 21:52:04 -0700787 }
788
789 /**
Evan Charlton8c8a0622014-07-20 12:31:00 -0700790 * Notifies this {@code Call} that an account has been selected and to proceed with placing
Nancy Chen36c62f32014-10-21 18:36:39 -0700791 * an outgoing call. Optionally sets this account as the default account.
Nancy Chen5da0fd52014-07-08 14:16:17 -0700792 */
Nancy Chen36c62f32014-10-21 18:36:39 -0700793 public void phoneAccountSelected(PhoneAccountHandle accountHandle, boolean setDefault) {
794 mInCallAdapter.phoneAccountSelected(mTelecomCallId, accountHandle, setDefault);
Nancy Chen5da0fd52014-07-08 14:16:17 -0700795
796 }
797
798 /**
Ihab Awade63fadb2014-07-09 21:52:04 -0700799 * Instructs this {@code Call} to enter a conference.
Santos Cordon7c7bc7f2014-07-28 18:15:48 -0700800 *
801 * @param callToConferenceWith The other call with which to conference.
Ihab Awade63fadb2014-07-09 21:52:04 -0700802 */
Santos Cordon7c7bc7f2014-07-28 18:15:48 -0700803 public void conference(Call callToConferenceWith) {
804 if (callToConferenceWith != null) {
Tyler Gunnef9f6f92014-09-12 22:16:17 -0700805 mInCallAdapter.conference(mTelecomCallId, callToConferenceWith.mTelecomCallId);
Santos Cordon7c7bc7f2014-07-28 18:15:48 -0700806 }
Ihab Awade63fadb2014-07-09 21:52:04 -0700807 }
808
809 /**
810 * Instructs this {@code Call} to split from any conference call with which it may be
811 * connected.
812 */
813 public void splitFromConference() {
Tyler Gunnef9f6f92014-09-12 22:16:17 -0700814 mInCallAdapter.splitFromConference(mTelecomCallId);
Ihab Awade63fadb2014-07-09 21:52:04 -0700815 }
816
817 /**
Ihab Awad5c9c86e2014-11-12 13:41:16 -0800818 * Merges the calls within this conference. See {@link Details#CAPABILITY_MERGE_CONFERENCE}.
Santos Cordona4868042014-09-04 17:39:22 -0700819 */
820 public void mergeConference() {
Tyler Gunnef9f6f92014-09-12 22:16:17 -0700821 mInCallAdapter.mergeConference(mTelecomCallId);
Santos Cordona4868042014-09-04 17:39:22 -0700822 }
823
824 /**
Ihab Awad5c9c86e2014-11-12 13:41:16 -0800825 * Swaps the calls within this conference. See {@link Details#CAPABILITY_SWAP_CONFERENCE}.
Santos Cordona4868042014-09-04 17:39:22 -0700826 */
827 public void swapConference() {
Tyler Gunnef9f6f92014-09-12 22:16:17 -0700828 mInCallAdapter.swapConference(mTelecomCallId);
Santos Cordona4868042014-09-04 17:39:22 -0700829 }
830
831 /**
Ihab Awade63fadb2014-07-09 21:52:04 -0700832 * Obtains the parent of this {@code Call} in a conference, if any.
833 *
834 * @return The parent {@code Call}, or {@code null} if this {@code Call} is not a
835 * child of any conference {@code Call}s.
836 */
837 public Call getParent() {
Santos Cordon823fd3c2014-08-07 18:35:18 -0700838 if (mParentId != null) {
Tyler Gunnef9f6f92014-09-12 22:16:17 -0700839 return mPhone.internalGetCallByTelecomId(mParentId);
Santos Cordon823fd3c2014-08-07 18:35:18 -0700840 }
841 return null;
Ihab Awade63fadb2014-07-09 21:52:04 -0700842 }
843
844 /**
845 * Obtains the children of this conference {@code Call}, if any.
846 *
847 * @return The children of this {@code Call} if this {@code Call} is a conference, or an empty
848 * {@code List} otherwise.
849 */
850 public List<Call> getChildren() {
Santos Cordon823fd3c2014-08-07 18:35:18 -0700851 if (!mChildrenCached) {
852 mChildrenCached = true;
853 mChildren.clear();
854
855 for(String id : mChildrenIds) {
Tyler Gunnef9f6f92014-09-12 22:16:17 -0700856 Call call = mPhone.internalGetCallByTelecomId(id);
Santos Cordon823fd3c2014-08-07 18:35:18 -0700857 if (call == null) {
858 // At least one child was still not found, so do not save true for "cached"
859 mChildrenCached = false;
860 } else {
861 mChildren.add(call);
862 }
863 }
864 }
865
Ihab Awade63fadb2014-07-09 21:52:04 -0700866 return mUnmodifiableChildren;
867 }
868
869 /**
Santos Cordon7c7bc7f2014-07-28 18:15:48 -0700870 * Returns the list of {@code Call}s with which this {@code Call} is allowed to conference.
871 *
872 * @return The list of conferenceable {@code Call}s.
873 */
874 public List<Call> getConferenceableCalls() {
875 return mUnmodifiableConferenceableCalls;
876 }
877
878 /**
Ihab Awade63fadb2014-07-09 21:52:04 -0700879 * Obtains the state of this {@code Call}.
880 *
881 * @return A state value, chosen from the {@code STATE_*} constants.
882 */
883 public int getState() {
884 return mState;
885 }
886
887 /**
888 * Obtains a list of canned, pre-configured message responses to present to the user as
889 * ways of rejecting this {@code Call} using via a text message.
890 *
891 * @see #reject(boolean, String)
892 *
893 * @return A list of canned text message responses.
894 */
895 public List<String> getCannedTextResponses() {
896 return mCannedTextResponses;
897 }
898
899 /**
900 * Obtains an object that can be used to display video from this {@code Call}.
901 *
Andrew Lee50aca232014-07-22 16:41:54 -0700902 * @return An {@code Call.VideoCall}.
Ihab Awade63fadb2014-07-09 21:52:04 -0700903 */
Andrew Lee50aca232014-07-22 16:41:54 -0700904 public InCallService.VideoCall getVideoCall() {
Tyler Gunn584ba6c2015-12-08 10:53:41 -0800905 return mVideoCallImpl;
Ihab Awade63fadb2014-07-09 21:52:04 -0700906 }
907
908 /**
909 * Obtains an object containing call details.
910 *
911 * @return A {@link Details} object. Depending on the state of the {@code Call}, the
912 * result may be {@code null}.
913 */
914 public Details getDetails() {
915 return mDetails;
916 }
917
918 /**
Andrew Leeda80c872015-04-15 14:09:50 -0700919 * Registers a callback to this {@code Call}.
920 *
921 * @param callback A {@code Callback}.
922 */
923 public void registerCallback(Callback callback) {
Andrew Lee011728f2015-04-23 15:47:06 -0700924 registerCallback(callback, new Handler());
925 }
926
927 /**
928 * Registers a callback to this {@code Call}.
929 *
930 * @param callback A {@code Callback}.
931 * @param handler A handler which command and status changes will be delivered to.
932 */
933 public void registerCallback(Callback callback, Handler handler) {
934 unregisterCallback(callback);
Roshan Pius1ca62072015-07-07 17:34:51 -0700935 // Don't allow new callback registration if the call is already being destroyed.
936 if (callback != null && handler != null && mState != STATE_DISCONNECTED) {
Andrew Lee011728f2015-04-23 15:47:06 -0700937 mCallbackRecords.add(new CallbackRecord<Callback>(callback, handler));
938 }
Andrew Leeda80c872015-04-15 14:09:50 -0700939 }
940
941 /**
942 * Unregisters a callback from this {@code Call}.
943 *
944 * @param callback A {@code Callback}.
945 */
946 public void unregisterCallback(Callback callback) {
Roshan Pius1ca62072015-07-07 17:34:51 -0700947 // Don't allow callback deregistration if the call is already being destroyed.
948 if (callback != null && mState != STATE_DISCONNECTED) {
Andrew Lee011728f2015-04-23 15:47:06 -0700949 for (CallbackRecord<Callback> record : mCallbackRecords) {
950 if (record.getCallback() == callback) {
951 mCallbackRecords.remove(record);
952 break;
953 }
954 }
Andrew Leeda80c872015-04-15 14:09:50 -0700955 }
956 }
957
958 /**
Ihab Awade63fadb2014-07-09 21:52:04 -0700959 * Adds a listener to this {@code Call}.
960 *
961 * @param listener A {@code Listener}.
Andrew Leeda80c872015-04-15 14:09:50 -0700962 * @deprecated Use {@link #registerCallback} instead.
963 * @hide
Ihab Awade63fadb2014-07-09 21:52:04 -0700964 */
Andrew Leeda80c872015-04-15 14:09:50 -0700965 @Deprecated
966 @SystemApi
Ihab Awade63fadb2014-07-09 21:52:04 -0700967 public void addListener(Listener listener) {
Andrew Leeda80c872015-04-15 14:09:50 -0700968 registerCallback(listener);
Ihab Awade63fadb2014-07-09 21:52:04 -0700969 }
970
971 /**
972 * Removes a listener from this {@code Call}.
973 *
974 * @param listener A {@code Listener}.
Andrew Leeda80c872015-04-15 14:09:50 -0700975 * @deprecated Use {@link #unregisterCallback} instead.
976 * @hide
Ihab Awade63fadb2014-07-09 21:52:04 -0700977 */
Andrew Leeda80c872015-04-15 14:09:50 -0700978 @Deprecated
979 @SystemApi
Ihab Awade63fadb2014-07-09 21:52:04 -0700980 public void removeListener(Listener listener) {
Andrew Leeda80c872015-04-15 14:09:50 -0700981 unregisterCallback(listener);
Ihab Awade63fadb2014-07-09 21:52:04 -0700982 }
983
984 /** {@hide} */
Tyler Gunnef9f6f92014-09-12 22:16:17 -0700985 Call(Phone phone, String telecomCallId, InCallAdapter inCallAdapter) {
Ihab Awade63fadb2014-07-09 21:52:04 -0700986 mPhone = phone;
Tyler Gunnef9f6f92014-09-12 22:16:17 -0700987 mTelecomCallId = telecomCallId;
Ihab Awade63fadb2014-07-09 21:52:04 -0700988 mInCallAdapter = inCallAdapter;
989 mState = STATE_NEW;
990 }
991
992 /** {@hide} */
Shriram Ganeshddf570e2015-05-31 09:18:48 -0700993 Call(Phone phone, String telecomCallId, InCallAdapter inCallAdapter, int state) {
994 mPhone = phone;
995 mTelecomCallId = telecomCallId;
996 mInCallAdapter = inCallAdapter;
997 mState = state;
998 }
999
1000 /** {@hide} */
Ihab Awade63fadb2014-07-09 21:52:04 -07001001 final String internalGetCallId() {
Tyler Gunnef9f6f92014-09-12 22:16:17 -07001002 return mTelecomCallId;
Ihab Awade63fadb2014-07-09 21:52:04 -07001003 }
1004
1005 /** {@hide} */
Santos Cordon7c7bc7f2014-07-28 18:15:48 -07001006 final void internalUpdate(ParcelableCall parcelableCall, Map<String, Call> callIdMap) {
Ihab Awade63fadb2014-07-09 21:52:04 -07001007 // First, we update the internal state as far as possible before firing any updates.
Ihab Awade63fadb2014-07-09 21:52:04 -07001008 Details details = new Details(
Santos Cordon88b771d2014-07-19 13:10:40 -07001009 parcelableCall.getHandle(),
1010 parcelableCall.getHandlePresentation(),
1011 parcelableCall.getCallerDisplayName(),
1012 parcelableCall.getCallerDisplayNamePresentation(),
1013 parcelableCall.getAccountHandle(),
1014 parcelableCall.getCapabilities(),
Andrew Lee223ad142014-08-27 16:33:08 -07001015 parcelableCall.getProperties(),
Andrew Lee7f3d41f2014-09-11 17:33:16 -07001016 parcelableCall.getDisconnectCause(),
Santos Cordon88b771d2014-07-19 13:10:40 -07001017 parcelableCall.getConnectTimeMillis(),
1018 parcelableCall.getGatewayInfo(),
1019 parcelableCall.getVideoState(),
Nancy Chen10798dc2014-08-08 14:00:25 -07001020 parcelableCall.getStatusHints(),
Santos Cordon6b7f9552015-05-27 17:21:45 -07001021 parcelableCall.getExtras(),
1022 parcelableCall.getIntentExtras());
Ihab Awade63fadb2014-07-09 21:52:04 -07001023 boolean detailsChanged = !Objects.equals(mDetails, details);
1024 if (detailsChanged) {
1025 mDetails = details;
1026 }
1027
1028 boolean cannedTextResponsesChanged = false;
Santos Cordon88b771d2014-07-19 13:10:40 -07001029 if (mCannedTextResponses == null && parcelableCall.getCannedSmsResponses() != null
1030 && !parcelableCall.getCannedSmsResponses().isEmpty()) {
1031 mCannedTextResponses =
1032 Collections.unmodifiableList(parcelableCall.getCannedSmsResponses());
Yorke Leee886f632015-08-04 13:43:31 -07001033 cannedTextResponsesChanged = true;
Ihab Awade63fadb2014-07-09 21:52:04 -07001034 }
1035
Tyler Gunn584ba6c2015-12-08 10:53:41 -08001036 VideoCallImpl newVideoCallImpl = parcelableCall.getVideoCallImpl();
Tyler Gunn75958422015-04-15 14:23:42 -07001037 boolean videoCallChanged = parcelableCall.isVideoCallProviderChanged() &&
Tyler Gunn584ba6c2015-12-08 10:53:41 -08001038 !Objects.equals(mVideoCallImpl, newVideoCallImpl);
Andrew Lee50aca232014-07-22 16:41:54 -07001039 if (videoCallChanged) {
Tyler Gunn584ba6c2015-12-08 10:53:41 -08001040 mVideoCallImpl = newVideoCallImpl;
1041 }
1042 if (mVideoCallImpl != null) {
1043 mVideoCallImpl.setVideoState(getDetails().getVideoState());
Ihab Awade63fadb2014-07-09 21:52:04 -07001044 }
1045
Santos Cordone3c507b2015-04-23 14:44:19 -07001046 int state = parcelableCall.getState();
Ihab Awade63fadb2014-07-09 21:52:04 -07001047 boolean stateChanged = mState != state;
1048 if (stateChanged) {
1049 mState = state;
1050 }
1051
Santos Cordon823fd3c2014-08-07 18:35:18 -07001052 String parentId = parcelableCall.getParentCallId();
1053 boolean parentChanged = !Objects.equals(mParentId, parentId);
1054 if (parentChanged) {
1055 mParentId = parentId;
Ihab Awade63fadb2014-07-09 21:52:04 -07001056 }
1057
Santos Cordon823fd3c2014-08-07 18:35:18 -07001058 List<String> childCallIds = parcelableCall.getChildCallIds();
1059 boolean childrenChanged = !Objects.equals(childCallIds, mChildrenIds);
1060 if (childrenChanged) {
1061 mChildrenIds.clear();
1062 mChildrenIds.addAll(parcelableCall.getChildCallIds());
1063 mChildrenCached = false;
Ihab Awade63fadb2014-07-09 21:52:04 -07001064 }
1065
Santos Cordon7c7bc7f2014-07-28 18:15:48 -07001066 List<String> conferenceableCallIds = parcelableCall.getConferenceableCallIds();
1067 List<Call> conferenceableCalls = new ArrayList<Call>(conferenceableCallIds.size());
1068 for (String otherId : conferenceableCallIds) {
1069 if (callIdMap.containsKey(otherId)) {
1070 conferenceableCalls.add(callIdMap.get(otherId));
1071 }
1072 }
1073
1074 if (!Objects.equals(mConferenceableCalls, conferenceableCalls)) {
1075 mConferenceableCalls.clear();
1076 mConferenceableCalls.addAll(conferenceableCalls);
1077 fireConferenceableCallsChanged();
1078 }
1079
Ihab Awade63fadb2014-07-09 21:52:04 -07001080 // Now we fire updates, ensuring that any client who listens to any of these notifications
1081 // gets the most up-to-date state.
1082
1083 if (stateChanged) {
1084 fireStateChanged(mState);
1085 }
1086 if (detailsChanged) {
1087 fireDetailsChanged(mDetails);
1088 }
1089 if (cannedTextResponsesChanged) {
1090 fireCannedTextResponsesLoaded(mCannedTextResponses);
1091 }
Andrew Lee50aca232014-07-22 16:41:54 -07001092 if (videoCallChanged) {
Tyler Gunn584ba6c2015-12-08 10:53:41 -08001093 fireVideoCallChanged(mVideoCallImpl);
Ihab Awade63fadb2014-07-09 21:52:04 -07001094 }
Santos Cordon823fd3c2014-08-07 18:35:18 -07001095 if (parentChanged) {
1096 fireParentChanged(getParent());
1097 }
1098 if (childrenChanged) {
1099 fireChildrenChanged(getChildren());
1100 }
Ihab Awade63fadb2014-07-09 21:52:04 -07001101
1102 // If we have transitioned to DISCONNECTED, that means we need to notify clients and
1103 // remove ourselves from the Phone. Note that we do this after completing all state updates
1104 // so a client can cleanly transition all their UI to the state appropriate for a
1105 // DISCONNECTED Call while still relying on the existence of that Call in the Phone's list.
1106 if (mState == STATE_DISCONNECTED) {
1107 fireCallDestroyed();
Ihab Awade63fadb2014-07-09 21:52:04 -07001108 }
1109 }
1110
1111 /** {@hide} */
Ihab Awade63fadb2014-07-09 21:52:04 -07001112 final void internalSetPostDialWait(String remaining) {
1113 mRemainingPostDialSequence = remaining;
1114 firePostDialWait(mRemainingPostDialSequence);
1115 }
1116
Sailesh Nepal2ab88cc2014-07-18 14:49:18 -07001117 /** {@hide} */
Santos Cordonf30d7e92014-08-26 09:54:33 -07001118 final void internalSetDisconnected() {
1119 if (mState != Call.STATE_DISCONNECTED) {
1120 mState = Call.STATE_DISCONNECTED;
1121 fireStateChanged(mState);
1122 fireCallDestroyed();
Santos Cordonf30d7e92014-08-26 09:54:33 -07001123 }
1124 }
1125
Andrew Lee011728f2015-04-23 15:47:06 -07001126 private void fireStateChanged(final int newState) {
1127 for (CallbackRecord<Callback> record : mCallbackRecords) {
1128 final Call call = this;
1129 final Callback callback = record.getCallback();
1130 record.getHandler().post(new Runnable() {
1131 @Override
1132 public void run() {
1133 callback.onStateChanged(call, newState);
1134 }
1135 });
Ihab Awade63fadb2014-07-09 21:52:04 -07001136 }
1137 }
1138
Andrew Lee011728f2015-04-23 15:47:06 -07001139 private void fireParentChanged(final Call newParent) {
1140 for (CallbackRecord<Callback> record : mCallbackRecords) {
1141 final Call call = this;
1142 final Callback callback = record.getCallback();
1143 record.getHandler().post(new Runnable() {
1144 @Override
1145 public void run() {
1146 callback.onParentChanged(call, newParent);
1147 }
1148 });
Ihab Awade63fadb2014-07-09 21:52:04 -07001149 }
1150 }
1151
Andrew Lee011728f2015-04-23 15:47:06 -07001152 private void fireChildrenChanged(final List<Call> children) {
1153 for (CallbackRecord<Callback> record : mCallbackRecords) {
1154 final Call call = this;
1155 final Callback callback = record.getCallback();
1156 record.getHandler().post(new Runnable() {
1157 @Override
1158 public void run() {
1159 callback.onChildrenChanged(call, children);
1160 }
1161 });
Ihab Awade63fadb2014-07-09 21:52:04 -07001162 }
1163 }
1164
Andrew Lee011728f2015-04-23 15:47:06 -07001165 private void fireDetailsChanged(final Details details) {
1166 for (CallbackRecord<Callback> record : mCallbackRecords) {
1167 final Call call = this;
1168 final Callback callback = record.getCallback();
1169 record.getHandler().post(new Runnable() {
1170 @Override
1171 public void run() {
1172 callback.onDetailsChanged(call, details);
1173 }
1174 });
Ihab Awade63fadb2014-07-09 21:52:04 -07001175 }
1176 }
1177
Andrew Lee011728f2015-04-23 15:47:06 -07001178 private void fireCannedTextResponsesLoaded(final List<String> cannedTextResponses) {
1179 for (CallbackRecord<Callback> record : mCallbackRecords) {
1180 final Call call = this;
1181 final Callback callback = record.getCallback();
1182 record.getHandler().post(new Runnable() {
1183 @Override
1184 public void run() {
1185 callback.onCannedTextResponsesLoaded(call, cannedTextResponses);
1186 }
1187 });
Ihab Awade63fadb2014-07-09 21:52:04 -07001188 }
1189 }
1190
Andrew Lee011728f2015-04-23 15:47:06 -07001191 private void fireVideoCallChanged(final InCallService.VideoCall videoCall) {
1192 for (CallbackRecord<Callback> record : mCallbackRecords) {
1193 final Call call = this;
1194 final Callback callback = record.getCallback();
1195 record.getHandler().post(new Runnable() {
1196 @Override
1197 public void run() {
1198 callback.onVideoCallChanged(call, videoCall);
1199 }
1200 });
Ihab Awade63fadb2014-07-09 21:52:04 -07001201 }
1202 }
1203
Andrew Lee011728f2015-04-23 15:47:06 -07001204 private void firePostDialWait(final String remainingPostDialSequence) {
1205 for (CallbackRecord<Callback> record : mCallbackRecords) {
1206 final Call call = this;
1207 final Callback callback = record.getCallback();
1208 record.getHandler().post(new Runnable() {
1209 @Override
1210 public void run() {
1211 callback.onPostDialWait(call, remainingPostDialSequence);
1212 }
1213 });
Ihab Awade63fadb2014-07-09 21:52:04 -07001214 }
1215 }
1216
1217 private void fireCallDestroyed() {
Roshan Pius1ca62072015-07-07 17:34:51 -07001218 /**
1219 * To preserve the ordering of the Call's onCallDestroyed callback and Phone's
1220 * onCallRemoved callback, we remove this call from the Phone's record
1221 * only once all of the registered onCallDestroyed callbacks are executed.
1222 * All the callbacks get removed from our records as a part of this operation
1223 * since onCallDestroyed is the final callback.
1224 */
1225 final Call call = this;
1226 if (mCallbackRecords.isEmpty()) {
1227 // No callbacks registered, remove the call from Phone's record.
1228 mPhone.internalRemoveCall(call);
1229 }
1230 for (final CallbackRecord<Callback> record : mCallbackRecords) {
Andrew Lee011728f2015-04-23 15:47:06 -07001231 final Callback callback = record.getCallback();
1232 record.getHandler().post(new Runnable() {
1233 @Override
1234 public void run() {
Roshan Pius1ca62072015-07-07 17:34:51 -07001235 boolean isFinalRemoval = false;
1236 RuntimeException toThrow = null;
1237 try {
1238 callback.onCallDestroyed(call);
1239 } catch (RuntimeException e) {
1240 toThrow = e;
1241 }
1242 synchronized(Call.this) {
1243 mCallbackRecords.remove(record);
1244 if (mCallbackRecords.isEmpty()) {
1245 isFinalRemoval = true;
1246 }
1247 }
1248 if (isFinalRemoval) {
1249 mPhone.internalRemoveCall(call);
1250 }
1251 if (toThrow != null) {
1252 throw toThrow;
1253 }
Andrew Lee011728f2015-04-23 15:47:06 -07001254 }
1255 });
Ihab Awade63fadb2014-07-09 21:52:04 -07001256 }
1257 }
1258
Santos Cordon7c7bc7f2014-07-28 18:15:48 -07001259 private void fireConferenceableCallsChanged() {
Andrew Lee011728f2015-04-23 15:47:06 -07001260 for (CallbackRecord<Callback> record : mCallbackRecords) {
1261 final Call call = this;
1262 final Callback callback = record.getCallback();
1263 record.getHandler().post(new Runnable() {
1264 @Override
1265 public void run() {
1266 callback.onConferenceableCallsChanged(call, mUnmodifiableConferenceableCalls);
1267 }
1268 });
Santos Cordon7c7bc7f2014-07-28 18:15:48 -07001269 }
1270 }
Tyler Gunn1e9bfc62015-08-19 11:18:58 -07001271
1272 /**
1273 * Determines if two bundles are equal.
1274 *
1275 * @param bundle The original bundle.
1276 * @param newBundle The bundle to compare with.
1277 * @retrun {@code true} if the bundles are equal, {@code false} otherwise.
1278 */
1279 private static boolean areBundlesEqual(Bundle bundle, Bundle newBundle) {
1280 if (bundle == null || newBundle == null) {
1281 return bundle == newBundle;
1282 }
1283
1284 if (bundle.size() != newBundle.size()) {
1285 return false;
1286 }
1287
1288 for(String key : bundle.keySet()) {
1289 if (key != null) {
1290 final Object value = bundle.get(key);
1291 final Object newValue = newBundle.get(key);
1292 if (!Objects.equals(value, newValue)) {
1293 return false;
1294 }
1295 }
1296 }
1297 return true;
1298 }
Santos Cordon7c7bc7f2014-07-28 18:15:48 -07001299}