blob: 1d0e87476e3ce5fe7cd53d0e9864603b7739a98e [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) {
277 return (capabilities & capability) != 0;
278 }
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) {
359 return (properties & property) != 0;
360 }
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;
Andrew Lee50aca232014-07-22 16:41:54 -0700692 private InCallService.VideoCall mVideoCall;
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() {
905 return mVideoCall;
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 Gunn75958422015-04-15 14:23:42 -07001036 boolean videoCallChanged = parcelableCall.isVideoCallProviderChanged() &&
Tyler Gunn45382162015-05-06 08:52:27 -07001037 !Objects.equals(mVideoCall, parcelableCall.getVideoCall(this));
Andrew Lee50aca232014-07-22 16:41:54 -07001038 if (videoCallChanged) {
Tyler Gunn45382162015-05-06 08:52:27 -07001039 mVideoCall = parcelableCall.getVideoCall(this);
Ihab Awade63fadb2014-07-09 21:52:04 -07001040 }
1041
Santos Cordone3c507b2015-04-23 14:44:19 -07001042 int state = parcelableCall.getState();
Ihab Awade63fadb2014-07-09 21:52:04 -07001043 boolean stateChanged = mState != state;
1044 if (stateChanged) {
1045 mState = state;
1046 }
1047
Santos Cordon823fd3c2014-08-07 18:35:18 -07001048 String parentId = parcelableCall.getParentCallId();
1049 boolean parentChanged = !Objects.equals(mParentId, parentId);
1050 if (parentChanged) {
1051 mParentId = parentId;
Ihab Awade63fadb2014-07-09 21:52:04 -07001052 }
1053
Santos Cordon823fd3c2014-08-07 18:35:18 -07001054 List<String> childCallIds = parcelableCall.getChildCallIds();
1055 boolean childrenChanged = !Objects.equals(childCallIds, mChildrenIds);
1056 if (childrenChanged) {
1057 mChildrenIds.clear();
1058 mChildrenIds.addAll(parcelableCall.getChildCallIds());
1059 mChildrenCached = false;
Ihab Awade63fadb2014-07-09 21:52:04 -07001060 }
1061
Santos Cordon7c7bc7f2014-07-28 18:15:48 -07001062 List<String> conferenceableCallIds = parcelableCall.getConferenceableCallIds();
1063 List<Call> conferenceableCalls = new ArrayList<Call>(conferenceableCallIds.size());
1064 for (String otherId : conferenceableCallIds) {
1065 if (callIdMap.containsKey(otherId)) {
1066 conferenceableCalls.add(callIdMap.get(otherId));
1067 }
1068 }
1069
1070 if (!Objects.equals(mConferenceableCalls, conferenceableCalls)) {
1071 mConferenceableCalls.clear();
1072 mConferenceableCalls.addAll(conferenceableCalls);
1073 fireConferenceableCallsChanged();
1074 }
1075
Ihab Awade63fadb2014-07-09 21:52:04 -07001076 // Now we fire updates, ensuring that any client who listens to any of these notifications
1077 // gets the most up-to-date state.
1078
1079 if (stateChanged) {
1080 fireStateChanged(mState);
1081 }
1082 if (detailsChanged) {
1083 fireDetailsChanged(mDetails);
1084 }
1085 if (cannedTextResponsesChanged) {
1086 fireCannedTextResponsesLoaded(mCannedTextResponses);
1087 }
Andrew Lee50aca232014-07-22 16:41:54 -07001088 if (videoCallChanged) {
1089 fireVideoCallChanged(mVideoCall);
Ihab Awade63fadb2014-07-09 21:52:04 -07001090 }
Santos Cordon823fd3c2014-08-07 18:35:18 -07001091 if (parentChanged) {
1092 fireParentChanged(getParent());
1093 }
1094 if (childrenChanged) {
1095 fireChildrenChanged(getChildren());
1096 }
Ihab Awade63fadb2014-07-09 21:52:04 -07001097
1098 // If we have transitioned to DISCONNECTED, that means we need to notify clients and
1099 // remove ourselves from the Phone. Note that we do this after completing all state updates
1100 // so a client can cleanly transition all their UI to the state appropriate for a
1101 // DISCONNECTED Call while still relying on the existence of that Call in the Phone's list.
1102 if (mState == STATE_DISCONNECTED) {
1103 fireCallDestroyed();
Ihab Awade63fadb2014-07-09 21:52:04 -07001104 }
1105 }
1106
1107 /** {@hide} */
Ihab Awade63fadb2014-07-09 21:52:04 -07001108 final void internalSetPostDialWait(String remaining) {
1109 mRemainingPostDialSequence = remaining;
1110 firePostDialWait(mRemainingPostDialSequence);
1111 }
1112
Sailesh Nepal2ab88cc2014-07-18 14:49:18 -07001113 /** {@hide} */
Santos Cordonf30d7e92014-08-26 09:54:33 -07001114 final void internalSetDisconnected() {
1115 if (mState != Call.STATE_DISCONNECTED) {
1116 mState = Call.STATE_DISCONNECTED;
1117 fireStateChanged(mState);
1118 fireCallDestroyed();
Santos Cordonf30d7e92014-08-26 09:54:33 -07001119 }
1120 }
1121
Andrew Lee011728f2015-04-23 15:47:06 -07001122 private void fireStateChanged(final int newState) {
1123 for (CallbackRecord<Callback> record : mCallbackRecords) {
1124 final Call call = this;
1125 final Callback callback = record.getCallback();
1126 record.getHandler().post(new Runnable() {
1127 @Override
1128 public void run() {
1129 callback.onStateChanged(call, newState);
1130 }
1131 });
Ihab Awade63fadb2014-07-09 21:52:04 -07001132 }
1133 }
1134
Andrew Lee011728f2015-04-23 15:47:06 -07001135 private void fireParentChanged(final Call newParent) {
1136 for (CallbackRecord<Callback> record : mCallbackRecords) {
1137 final Call call = this;
1138 final Callback callback = record.getCallback();
1139 record.getHandler().post(new Runnable() {
1140 @Override
1141 public void run() {
1142 callback.onParentChanged(call, newParent);
1143 }
1144 });
Ihab Awade63fadb2014-07-09 21:52:04 -07001145 }
1146 }
1147
Andrew Lee011728f2015-04-23 15:47:06 -07001148 private void fireChildrenChanged(final List<Call> children) {
1149 for (CallbackRecord<Callback> record : mCallbackRecords) {
1150 final Call call = this;
1151 final Callback callback = record.getCallback();
1152 record.getHandler().post(new Runnable() {
1153 @Override
1154 public void run() {
1155 callback.onChildrenChanged(call, children);
1156 }
1157 });
Ihab Awade63fadb2014-07-09 21:52:04 -07001158 }
1159 }
1160
Andrew Lee011728f2015-04-23 15:47:06 -07001161 private void fireDetailsChanged(final Details details) {
1162 for (CallbackRecord<Callback> record : mCallbackRecords) {
1163 final Call call = this;
1164 final Callback callback = record.getCallback();
1165 record.getHandler().post(new Runnable() {
1166 @Override
1167 public void run() {
1168 callback.onDetailsChanged(call, details);
1169 }
1170 });
Ihab Awade63fadb2014-07-09 21:52:04 -07001171 }
1172 }
1173
Andrew Lee011728f2015-04-23 15:47:06 -07001174 private void fireCannedTextResponsesLoaded(final List<String> cannedTextResponses) {
1175 for (CallbackRecord<Callback> record : mCallbackRecords) {
1176 final Call call = this;
1177 final Callback callback = record.getCallback();
1178 record.getHandler().post(new Runnable() {
1179 @Override
1180 public void run() {
1181 callback.onCannedTextResponsesLoaded(call, cannedTextResponses);
1182 }
1183 });
Ihab Awade63fadb2014-07-09 21:52:04 -07001184 }
1185 }
1186
Andrew Lee011728f2015-04-23 15:47:06 -07001187 private void fireVideoCallChanged(final InCallService.VideoCall videoCall) {
1188 for (CallbackRecord<Callback> record : mCallbackRecords) {
1189 final Call call = this;
1190 final Callback callback = record.getCallback();
1191 record.getHandler().post(new Runnable() {
1192 @Override
1193 public void run() {
1194 callback.onVideoCallChanged(call, videoCall);
1195 }
1196 });
Ihab Awade63fadb2014-07-09 21:52:04 -07001197 }
1198 }
1199
Andrew Lee011728f2015-04-23 15:47:06 -07001200 private void firePostDialWait(final String remainingPostDialSequence) {
1201 for (CallbackRecord<Callback> record : mCallbackRecords) {
1202 final Call call = this;
1203 final Callback callback = record.getCallback();
1204 record.getHandler().post(new Runnable() {
1205 @Override
1206 public void run() {
1207 callback.onPostDialWait(call, remainingPostDialSequence);
1208 }
1209 });
Ihab Awade63fadb2014-07-09 21:52:04 -07001210 }
1211 }
1212
1213 private void fireCallDestroyed() {
Roshan Pius1ca62072015-07-07 17:34:51 -07001214 /**
1215 * To preserve the ordering of the Call's onCallDestroyed callback and Phone's
1216 * onCallRemoved callback, we remove this call from the Phone's record
1217 * only once all of the registered onCallDestroyed callbacks are executed.
1218 * All the callbacks get removed from our records as a part of this operation
1219 * since onCallDestroyed is the final callback.
1220 */
1221 final Call call = this;
1222 if (mCallbackRecords.isEmpty()) {
1223 // No callbacks registered, remove the call from Phone's record.
1224 mPhone.internalRemoveCall(call);
1225 }
1226 for (final CallbackRecord<Callback> record : mCallbackRecords) {
Andrew Lee011728f2015-04-23 15:47:06 -07001227 final Callback callback = record.getCallback();
1228 record.getHandler().post(new Runnable() {
1229 @Override
1230 public void run() {
Roshan Pius1ca62072015-07-07 17:34:51 -07001231 boolean isFinalRemoval = false;
1232 RuntimeException toThrow = null;
1233 try {
1234 callback.onCallDestroyed(call);
1235 } catch (RuntimeException e) {
1236 toThrow = e;
1237 }
1238 synchronized(Call.this) {
1239 mCallbackRecords.remove(record);
1240 if (mCallbackRecords.isEmpty()) {
1241 isFinalRemoval = true;
1242 }
1243 }
1244 if (isFinalRemoval) {
1245 mPhone.internalRemoveCall(call);
1246 }
1247 if (toThrow != null) {
1248 throw toThrow;
1249 }
Andrew Lee011728f2015-04-23 15:47:06 -07001250 }
1251 });
Ihab Awade63fadb2014-07-09 21:52:04 -07001252 }
1253 }
1254
Santos Cordon7c7bc7f2014-07-28 18:15:48 -07001255 private void fireConferenceableCallsChanged() {
Andrew Lee011728f2015-04-23 15:47:06 -07001256 for (CallbackRecord<Callback> record : mCallbackRecords) {
1257 final Call call = this;
1258 final Callback callback = record.getCallback();
1259 record.getHandler().post(new Runnable() {
1260 @Override
1261 public void run() {
1262 callback.onConferenceableCallsChanged(call, mUnmodifiableConferenceableCalls);
1263 }
1264 });
Santos Cordon7c7bc7f2014-07-28 18:15:48 -07001265 }
1266 }
Tyler Gunn1e9bfc62015-08-19 11:18:58 -07001267
1268 /**
1269 * Determines if two bundles are equal.
1270 *
1271 * @param bundle The original bundle.
1272 * @param newBundle The bundle to compare with.
1273 * @retrun {@code true} if the bundles are equal, {@code false} otherwise.
1274 */
1275 private static boolean areBundlesEqual(Bundle bundle, Bundle newBundle) {
1276 if (bundle == null || newBundle == null) {
1277 return bundle == newBundle;
1278 }
1279
1280 if (bundle.size() != newBundle.size()) {
1281 return false;
1282 }
1283
1284 for(String key : bundle.keySet()) {
1285 if (key != null) {
1286 final Object value = bundle.get(key);
1287 final Object newValue = newBundle.get(key);
1288 if (!Objects.equals(value, newValue)) {
1289 return false;
1290 }
1291 }
1292 }
1293 return true;
1294 }
Santos Cordon7c7bc7f2014-07-28 18:15:48 -07001295}