blob: 65117055045ced0bcbc09f3bfe967506b874a294 [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
245 //******************************************************************************************
246 // Next PROPERTY value: 0x00000020
Tyler Gunnd11a3152015-03-18 13:09:14 -0700247 //******************************************************************************************
Tyler Gunn068085b2015-02-06 13:56:52 -0800248
Ihab Awade63fadb2014-07-09 21:52:04 -0700249 private final Uri mHandle;
250 private final int mHandlePresentation;
251 private final String mCallerDisplayName;
252 private final int mCallerDisplayNamePresentation;
Evan Charlton8c8a0622014-07-20 12:31:00 -0700253 private final PhoneAccountHandle mAccountHandle;
Ihab Awad5d0410f2014-07-30 10:07:40 -0700254 private final int mCallCapabilities;
Andrew Lee223ad142014-08-27 16:33:08 -0700255 private final int mCallProperties;
Andrew Lee7f3d41f2014-09-11 17:33:16 -0700256 private final DisconnectCause mDisconnectCause;
Ihab Awade63fadb2014-07-09 21:52:04 -0700257 private final long mConnectTimeMillis;
258 private final GatewayInfo mGatewayInfo;
Andrew Lee85f5d422014-07-11 17:22:03 -0700259 private final int mVideoState;
Evan Charlton5b49ade2014-07-15 17:03:20 -0700260 private final StatusHints mStatusHints;
Nancy Chen10798dc2014-08-08 14:00:25 -0700261 private final Bundle mExtras;
Santos Cordon6b7f9552015-05-27 17:21:45 -0700262 private final Bundle mIntentExtras;
Ihab Awade63fadb2014-07-09 21:52:04 -0700263
264 /**
Ihab Awad5c9c86e2014-11-12 13:41:16 -0800265 * Whether the supplied capabilities supports the specified capability.
266 *
267 * @param capabilities A bit field of capabilities.
268 * @param capability The capability to check capabilities for.
269 * @return Whether the specified capability is supported.
Ihab Awad5c9c86e2014-11-12 13:41:16 -0800270 */
271 public static boolean can(int capabilities, int capability) {
272 return (capabilities & capability) != 0;
273 }
274
275 /**
276 * Whether the capabilities of this {@code Details} supports the specified capability.
277 *
278 * @param capability The capability to check capabilities for.
279 * @return Whether the specified capability is supported.
Ihab Awad5c9c86e2014-11-12 13:41:16 -0800280 */
281 public boolean can(int capability) {
282 return can(mCallCapabilities, capability);
283 }
284
285 /**
286 * Render a set of capability bits ({@code CAPABILITY_*}) as a human readable string.
287 *
288 * @param capabilities A capability bit field.
289 * @return A human readable string representation.
290 */
291 public static String capabilitiesToString(int capabilities) {
292 StringBuilder builder = new StringBuilder();
293 builder.append("[Capabilities:");
294 if (can(capabilities, CAPABILITY_HOLD)) {
295 builder.append(" CAPABILITY_HOLD");
296 }
297 if (can(capabilities, CAPABILITY_SUPPORT_HOLD)) {
298 builder.append(" CAPABILITY_SUPPORT_HOLD");
299 }
300 if (can(capabilities, CAPABILITY_MERGE_CONFERENCE)) {
301 builder.append(" CAPABILITY_MERGE_CONFERENCE");
302 }
303 if (can(capabilities, CAPABILITY_SWAP_CONFERENCE)) {
304 builder.append(" CAPABILITY_SWAP_CONFERENCE");
305 }
306 if (can(capabilities, CAPABILITY_RESPOND_VIA_TEXT)) {
307 builder.append(" CAPABILITY_RESPOND_VIA_TEXT");
308 }
309 if (can(capabilities, CAPABILITY_MUTE)) {
310 builder.append(" CAPABILITY_MUTE");
311 }
312 if (can(capabilities, CAPABILITY_MANAGE_CONFERENCE)) {
313 builder.append(" CAPABILITY_MANAGE_CONFERENCE");
314 }
Andrew Lee5e9e8bb2015-03-10 13:58:24 -0700315 if (can(capabilities, CAPABILITY_SUPPORTS_VT_LOCAL_RX)) {
316 builder.append(" CAPABILITY_SUPPORTS_VT_LOCAL_RX");
317 }
318 if (can(capabilities, CAPABILITY_SUPPORTS_VT_LOCAL_TX)) {
319 builder.append(" CAPABILITY_SUPPORTS_VT_LOCAL_TX");
320 }
Andrew Lee9a8f9ce2015-04-10 18:09:46 -0700321 if (can(capabilities, CAPABILITY_SUPPORTS_VT_LOCAL_BIDIRECTIONAL)) {
322 builder.append(" CAPABILITY_SUPPORTS_VT_LOCAL_BIDIRECTIONAL");
Ihab Awad5c9c86e2014-11-12 13:41:16 -0800323 }
Andrew Lee5e9e8bb2015-03-10 13:58:24 -0700324 if (can(capabilities, CAPABILITY_SUPPORTS_VT_REMOTE_RX)) {
325 builder.append(" CAPABILITY_SUPPORTS_VT_REMOTE_RX");
326 }
327 if (can(capabilities, CAPABILITY_SUPPORTS_VT_REMOTE_TX)) {
328 builder.append(" CAPABILITY_SUPPORTS_VT_REMOTE_TX");
329 }
Andrew Lee9a8f9ce2015-04-10 18:09:46 -0700330 if (can(capabilities, CAPABILITY_SUPPORTS_VT_REMOTE_BIDIRECTIONAL)) {
331 builder.append(" CAPABILITY_SUPPORTS_VT_REMOTE_BIDIRECTIONAL");
Ihab Awad5c9c86e2014-11-12 13:41:16 -0800332 }
Dong Zhou89f41eb2015-03-15 11:59:49 -0500333 if (can(capabilities, CAPABILITY_SPEED_UP_MT_AUDIO)) {
Tyler Gunnd11a3152015-03-18 13:09:14 -0700334 builder.append(" CAPABILITY_SPEED_UP_MT_AUDIO");
Dong Zhou89f41eb2015-03-15 11:59:49 -0500335 }
Rekha Kumar07366812015-03-24 16:42:31 -0700336 if (can(capabilities, CAPABILITY_CAN_UPGRADE_TO_VIDEO)) {
337 builder.append(" CAPABILITY_CAN_UPGRADE_TO_VIDEO");
338 }
Tyler Gunnb5e0cfb2015-04-07 16:10:51 -0700339 if (can(capabilities, CAPABILITY_CAN_PAUSE_VIDEO)) {
340 builder.append(" CAPABILITY_CAN_PAUSE_VIDEO");
341 }
Ihab Awad5c9c86e2014-11-12 13:41:16 -0800342 builder.append("]");
343 return builder.toString();
344 }
345
346 /**
Andrew Lee2378ea72015-04-29 14:38:11 -0700347 * Whether the supplied properties includes the specified property.
348 *
349 * @param properties A bit field of properties.
350 * @param property The property to check properties for.
351 * @return Whether the specified property is supported.
352 */
353 public static boolean hasProperty(int properties, int property) {
354 return (properties & property) != 0;
355 }
356
357 /**
358 * Whether the properties of this {@code Details} includes the specified property.
359 *
360 * @param property The property to check properties for.
361 * @return Whether the specified property is supported.
362 */
363 public boolean hasProperty(int property) {
364 return hasProperty(mCallProperties, property);
365 }
366
367 /**
368 * Render a set of property bits ({@code PROPERTY_*}) as a human readable string.
369 *
370 * @param properties A property bit field.
371 * @return A human readable string representation.
372 */
373 public static String propertiesToString(int properties) {
374 StringBuilder builder = new StringBuilder();
375 builder.append("[Properties:");
376 if (hasProperty(properties, PROPERTY_CONFERENCE)) {
377 builder.append(" PROPERTY_CONFERENCE");
378 }
379 if (hasProperty(properties, PROPERTY_GENERIC_CONFERENCE)) {
380 builder.append(" PROPERTY_GENERIC_CONFERENCE");
381 }
382 if (hasProperty(properties, PROPERTY_WIFI)) {
383 builder.append(" PROPERTY_WIFI");
384 }
385 if (hasProperty(properties, PROPERTY_HIGH_DEF_AUDIO)) {
386 builder.append(" PROPERTY_HIGH_DEF_AUDIO");
387 }
388 if (hasProperty(properties, PROPERTY_EMERGENCY_CALLBACK_MODE)) {
Yorke Leebe2a4a22015-06-12 10:10:55 -0700389 builder.append(" PROPERTY_EMERGENCY_CALLBACK_MODE");
Andrew Lee2378ea72015-04-29 14:38:11 -0700390 }
391 builder.append("]");
392 return builder.toString();
393 }
394
395 /**
Ihab Awade63fadb2014-07-09 21:52:04 -0700396 * @return The handle (e.g., phone number) to which the {@code Call} is currently
397 * connected.
398 */
399 public Uri getHandle() {
400 return mHandle;
401 }
402
403 /**
404 * @return The presentation requirements for the handle. See
Tyler Gunnef9f6f92014-09-12 22:16:17 -0700405 * {@link TelecomManager} for valid values.
Ihab Awade63fadb2014-07-09 21:52:04 -0700406 */
407 public int getHandlePresentation() {
408 return mHandlePresentation;
409 }
410
411 /**
412 * @return The display name for the caller.
413 */
414 public String getCallerDisplayName() {
415 return mCallerDisplayName;
416 }
417
418 /**
419 * @return The presentation requirements for the caller display name. See
Tyler Gunnef9f6f92014-09-12 22:16:17 -0700420 * {@link TelecomManager} for valid values.
Ihab Awade63fadb2014-07-09 21:52:04 -0700421 */
422 public int getCallerDisplayNamePresentation() {
423 return mCallerDisplayNamePresentation;
424 }
425
426 /**
Evan Charlton6eb262c2014-07-19 18:18:19 -0700427 * @return The {@code PhoneAccountHandle} whereby the {@code Call} is currently being
428 * routed.
Ihab Awade63fadb2014-07-09 21:52:04 -0700429 */
Evan Charlton8c8a0622014-07-20 12:31:00 -0700430 public PhoneAccountHandle getAccountHandle() {
431 return mAccountHandle;
Ihab Awade63fadb2014-07-09 21:52:04 -0700432 }
433
434 /**
Ihab Awad5c9c86e2014-11-12 13:41:16 -0800435 * @return A bitmask of the capabilities of the {@code Call}, as defined by the various
436 * {@code CAPABILITY_*} constants in this class.
Ihab Awade63fadb2014-07-09 21:52:04 -0700437 */
Ihab Awad5d0410f2014-07-30 10:07:40 -0700438 public int getCallCapabilities() {
439 return mCallCapabilities;
Ihab Awade63fadb2014-07-09 21:52:04 -0700440 }
441
442 /**
Andrew Lee2378ea72015-04-29 14:38:11 -0700443 * @return A bitmask of the properties of the {@code Call}, as defined by the various
444 * {@code PROPERTY_*} constants in this class.
Andrew Lee223ad142014-08-27 16:33:08 -0700445 */
446 public int getCallProperties() {
447 return mCallProperties;
448 }
449
450 /**
Ihab Awade63fadb2014-07-09 21:52:04 -0700451 * @return For a {@link #STATE_DISCONNECTED} {@code Call}, the disconnect cause expressed
Nancy Chenf4cf77c2014-09-19 10:53:21 -0700452 * by {@link android.telecom.DisconnectCause}.
Ihab Awade63fadb2014-07-09 21:52:04 -0700453 */
Andrew Lee7f3d41f2014-09-11 17:33:16 -0700454 public DisconnectCause getDisconnectCause() {
455 return mDisconnectCause;
Ihab Awade63fadb2014-07-09 21:52:04 -0700456 }
457
458 /**
459 * @return The time the {@code Call} has been connected. This information is updated
460 * periodically, but user interfaces should not rely on this to display any "call time
461 * clock".
462 */
Jay Shrauner164a0ac2015-04-14 18:16:10 -0700463 public final long getConnectTimeMillis() {
Ihab Awade63fadb2014-07-09 21:52:04 -0700464 return mConnectTimeMillis;
465 }
466
467 /**
468 * @return Information about any calling gateway the {@code Call} may be using.
469 */
470 public GatewayInfo getGatewayInfo() {
471 return mGatewayInfo;
472 }
473
Andrew Lee7a341382014-07-15 17:05:08 -0700474 /**
Ihab Awad5d0410f2014-07-30 10:07:40 -0700475 * @return The video state of the {@code Call}.
Andrew Lee7a341382014-07-15 17:05:08 -0700476 */
477 public int getVideoState() {
478 return mVideoState;
479 }
480
Ihab Awad5d0410f2014-07-30 10:07:40 -0700481 /**
Tyler Gunnef9f6f92014-09-12 22:16:17 -0700482 * @return The current {@link android.telecom.StatusHints}, or {@code null} if none
Ihab Awad5d0410f2014-07-30 10:07:40 -0700483 * have been set.
Evan Charlton5b49ade2014-07-15 17:03:20 -0700484 */
485 public StatusHints getStatusHints() {
486 return mStatusHints;
487 }
488
Nancy Chen10798dc2014-08-08 14:00:25 -0700489 /**
Santos Cordon6b7f9552015-05-27 17:21:45 -0700490 * @return The extras associated with this call.
Nancy Chen10798dc2014-08-08 14:00:25 -0700491 */
492 public Bundle getExtras() {
493 return mExtras;
494 }
495
Santos Cordon6b7f9552015-05-27 17:21:45 -0700496 /**
497 * @return The extras used with the original intent to place this call.
498 */
499 public Bundle getIntentExtras() {
500 return mIntentExtras;
501 }
502
Ihab Awade63fadb2014-07-09 21:52:04 -0700503 @Override
504 public boolean equals(Object o) {
505 if (o instanceof Details) {
506 Details d = (Details) o;
507 return
508 Objects.equals(mHandle, d.mHandle) &&
509 Objects.equals(mHandlePresentation, d.mHandlePresentation) &&
510 Objects.equals(mCallerDisplayName, d.mCallerDisplayName) &&
511 Objects.equals(mCallerDisplayNamePresentation,
512 d.mCallerDisplayNamePresentation) &&
Evan Charlton8c8a0622014-07-20 12:31:00 -0700513 Objects.equals(mAccountHandle, d.mAccountHandle) &&
Ihab Awad5d0410f2014-07-30 10:07:40 -0700514 Objects.equals(mCallCapabilities, d.mCallCapabilities) &&
Andrew Lee223ad142014-08-27 16:33:08 -0700515 Objects.equals(mCallProperties, d.mCallProperties) &&
Andrew Lee7f3d41f2014-09-11 17:33:16 -0700516 Objects.equals(mDisconnectCause, d.mDisconnectCause) &&
Ihab Awade63fadb2014-07-09 21:52:04 -0700517 Objects.equals(mConnectTimeMillis, d.mConnectTimeMillis) &&
Andrew Lee85f5d422014-07-11 17:22:03 -0700518 Objects.equals(mGatewayInfo, d.mGatewayInfo) &&
Evan Charlton5b49ade2014-07-15 17:03:20 -0700519 Objects.equals(mVideoState, d.mVideoState) &&
Nancy Chen10798dc2014-08-08 14:00:25 -0700520 Objects.equals(mStatusHints, d.mStatusHints) &&
Tyler Gunn1e9bfc62015-08-19 11:18:58 -0700521 areBundlesEqual(mExtras, d.mExtras) &&
522 areBundlesEqual(mIntentExtras, d.mIntentExtras);
Ihab Awade63fadb2014-07-09 21:52:04 -0700523 }
524 return false;
525 }
526
527 @Override
528 public int hashCode() {
529 return
530 Objects.hashCode(mHandle) +
531 Objects.hashCode(mHandlePresentation) +
532 Objects.hashCode(mCallerDisplayName) +
533 Objects.hashCode(mCallerDisplayNamePresentation) +
Evan Charlton8c8a0622014-07-20 12:31:00 -0700534 Objects.hashCode(mAccountHandle) +
Ihab Awad5d0410f2014-07-30 10:07:40 -0700535 Objects.hashCode(mCallCapabilities) +
Andrew Lee223ad142014-08-27 16:33:08 -0700536 Objects.hashCode(mCallProperties) +
Andrew Lee7f3d41f2014-09-11 17:33:16 -0700537 Objects.hashCode(mDisconnectCause) +
Ihab Awade63fadb2014-07-09 21:52:04 -0700538 Objects.hashCode(mConnectTimeMillis) +
Andrew Lee85f5d422014-07-11 17:22:03 -0700539 Objects.hashCode(mGatewayInfo) +
Evan Charlton5b49ade2014-07-15 17:03:20 -0700540 Objects.hashCode(mVideoState) +
Nancy Chen10798dc2014-08-08 14:00:25 -0700541 Objects.hashCode(mStatusHints) +
Santos Cordon6b7f9552015-05-27 17:21:45 -0700542 Objects.hashCode(mExtras) +
543 Objects.hashCode(mIntentExtras);
Ihab Awade63fadb2014-07-09 21:52:04 -0700544 }
545
546 /** {@hide} */
547 public Details(
548 Uri handle,
549 int handlePresentation,
550 String callerDisplayName,
551 int callerDisplayNamePresentation,
Evan Charlton8c8a0622014-07-20 12:31:00 -0700552 PhoneAccountHandle accountHandle,
Ihab Awade63fadb2014-07-09 21:52:04 -0700553 int capabilities,
Andrew Lee223ad142014-08-27 16:33:08 -0700554 int properties,
Andrew Lee7f3d41f2014-09-11 17:33:16 -0700555 DisconnectCause disconnectCause,
Ihab Awade63fadb2014-07-09 21:52:04 -0700556 long connectTimeMillis,
Andrew Lee85f5d422014-07-11 17:22:03 -0700557 GatewayInfo gatewayInfo,
Evan Charlton5b49ade2014-07-15 17:03:20 -0700558 int videoState,
Nancy Chen10798dc2014-08-08 14:00:25 -0700559 StatusHints statusHints,
Santos Cordon6b7f9552015-05-27 17:21:45 -0700560 Bundle extras,
561 Bundle intentExtras) {
Ihab Awade63fadb2014-07-09 21:52:04 -0700562 mHandle = handle;
563 mHandlePresentation = handlePresentation;
564 mCallerDisplayName = callerDisplayName;
565 mCallerDisplayNamePresentation = callerDisplayNamePresentation;
Evan Charlton8c8a0622014-07-20 12:31:00 -0700566 mAccountHandle = accountHandle;
Ihab Awad5d0410f2014-07-30 10:07:40 -0700567 mCallCapabilities = capabilities;
Andrew Lee223ad142014-08-27 16:33:08 -0700568 mCallProperties = properties;
Andrew Lee7f3d41f2014-09-11 17:33:16 -0700569 mDisconnectCause = disconnectCause;
Ihab Awade63fadb2014-07-09 21:52:04 -0700570 mConnectTimeMillis = connectTimeMillis;
571 mGatewayInfo = gatewayInfo;
Andrew Lee85f5d422014-07-11 17:22:03 -0700572 mVideoState = videoState;
Evan Charlton5b49ade2014-07-15 17:03:20 -0700573 mStatusHints = statusHints;
Nancy Chen10798dc2014-08-08 14:00:25 -0700574 mExtras = extras;
Santos Cordon6b7f9552015-05-27 17:21:45 -0700575 mIntentExtras = intentExtras;
Ihab Awade63fadb2014-07-09 21:52:04 -0700576 }
577 }
578
Andrew Leeda80c872015-04-15 14:09:50 -0700579 public static abstract class Callback {
Ihab Awade63fadb2014-07-09 21:52:04 -0700580 /**
581 * Invoked when the state of this {@code Call} has changed. See {@link #getState()}.
582 *
Ihab Awade63fadb2014-07-09 21:52:04 -0700583 * @param call The {@code Call} invoking this method.
584 * @param state The new state of the {@code Call}.
585 */
586 public void onStateChanged(Call call, int state) {}
587
588 /**
589 * Invoked when the parent of this {@code Call} has changed. See {@link #getParent()}.
590 *
591 * @param call The {@code Call} invoking this method.
592 * @param parent The new parent of the {@code Call}.
593 */
594 public void onParentChanged(Call call, Call parent) {}
595
596 /**
597 * Invoked when the children of this {@code Call} have changed. See {@link #getChildren()}.
598 *
599 * @param call The {@code Call} invoking this method.
600 * @param children The new children of the {@code Call}.
601 */
602 public void onChildrenChanged(Call call, List<Call> children) {}
603
604 /**
605 * Invoked when the details of this {@code Call} have changed. See {@link #getDetails()}.
606 *
607 * @param call The {@code Call} invoking this method.
608 * @param details A {@code Details} object describing the {@code Call}.
609 */
610 public void onDetailsChanged(Call call, Details details) {}
611
612 /**
613 * Invoked when the text messages that can be used as responses to the incoming
614 * {@code Call} are loaded from the relevant database.
615 * See {@link #getCannedTextResponses()}.
616 *
617 * @param call The {@code Call} invoking this method.
618 * @param cannedTextResponses The text messages useable as responses.
619 */
620 public void onCannedTextResponsesLoaded(Call call, List<String> cannedTextResponses) {}
621
622 /**
Ihab Awade63fadb2014-07-09 21:52:04 -0700623 * Invoked when the post-dial sequence in the outgoing {@code Call} has reached a pause
624 * character. This causes the post-dial signals to stop pending user confirmation. An
625 * implementation should present this choice to the user and invoke
626 * {@link #postDialContinue(boolean)} when the user makes the choice.
627 *
628 * @param call The {@code Call} invoking this method.
629 * @param remainingPostDialSequence The post-dial characters that remain to be sent.
630 */
631 public void onPostDialWait(Call call, String remainingPostDialSequence) {}
632
633 /**
Andrew Lee50aca232014-07-22 16:41:54 -0700634 * Invoked when the {@code Call.VideoCall} of the {@code Call} has changed.
Ihab Awade63fadb2014-07-09 21:52:04 -0700635 *
636 * @param call The {@code Call} invoking this method.
Andrew Lee50aca232014-07-22 16:41:54 -0700637 * @param videoCall The {@code Call.VideoCall} associated with the {@code Call}.
Ihab Awade63fadb2014-07-09 21:52:04 -0700638 */
Andrew Lee50aca232014-07-22 16:41:54 -0700639 public void onVideoCallChanged(Call call, InCallService.VideoCall videoCall) {}
Ihab Awade63fadb2014-07-09 21:52:04 -0700640
641 /**
642 * Invoked when the {@code Call} is destroyed. Clients should refrain from cleaning
643 * up their UI for the {@code Call} in response to state transitions. Specifically,
644 * clients should not assume that a {@link #onStateChanged(Call, int)} with a state of
645 * {@link #STATE_DISCONNECTED} is the final notification the {@code Call} will send. Rather,
646 * clients should wait for this method to be invoked.
647 *
648 * @param call The {@code Call} being destroyed.
649 */
650 public void onCallDestroyed(Call call) {}
Santos Cordon7c7bc7f2014-07-28 18:15:48 -0700651
652 /**
653 * Invoked upon changes to the set of {@code Call}s with which this {@code Call} can be
654 * conferenced.
655 *
656 * @param call The {@code Call} being updated.
657 * @param conferenceableCalls The {@code Call}s with which this {@code Call} can be
658 * conferenced.
659 */
660 public void onConferenceableCallsChanged(Call call, List<Call> conferenceableCalls) {}
Ihab Awade63fadb2014-07-09 21:52:04 -0700661 }
662
Andrew Leeda80c872015-04-15 14:09:50 -0700663 /**
664 * @deprecated Use {@code Call.Callback} instead.
665 * @hide
666 */
667 @Deprecated
668 @SystemApi
669 public static abstract class Listener extends Callback { }
670
Ihab Awade63fadb2014-07-09 21:52:04 -0700671 private final Phone mPhone;
Tyler Gunnef9f6f92014-09-12 22:16:17 -0700672 private final String mTelecomCallId;
Ihab Awade63fadb2014-07-09 21:52:04 -0700673 private final InCallAdapter mInCallAdapter;
Santos Cordon823fd3c2014-08-07 18:35:18 -0700674 private final List<String> mChildrenIds = new ArrayList<>();
Ihab Awade63fadb2014-07-09 21:52:04 -0700675 private final List<Call> mChildren = new ArrayList<>();
676 private final List<Call> mUnmodifiableChildren = Collections.unmodifiableList(mChildren);
Andrew Lee011728f2015-04-23 15:47:06 -0700677 private final List<CallbackRecord<Callback>> mCallbackRecords = new CopyOnWriteArrayList<>();
Santos Cordon7c7bc7f2014-07-28 18:15:48 -0700678 private final List<Call> mConferenceableCalls = new ArrayList<>();
679 private final List<Call> mUnmodifiableConferenceableCalls =
680 Collections.unmodifiableList(mConferenceableCalls);
681
Santos Cordon823fd3c2014-08-07 18:35:18 -0700682 private boolean mChildrenCached;
683 private String mParentId = null;
Santos Cordon7c7bc7f2014-07-28 18:15:48 -0700684 private int mState;
Ihab Awade63fadb2014-07-09 21:52:04 -0700685 private List<String> mCannedTextResponses = null;
686 private String mRemainingPostDialSequence;
Andrew Lee50aca232014-07-22 16:41:54 -0700687 private InCallService.VideoCall mVideoCall;
Ihab Awade63fadb2014-07-09 21:52:04 -0700688 private Details mDetails;
Ihab Awade63fadb2014-07-09 21:52:04 -0700689
690 /**
691 * Obtains the post-dial sequence remaining to be emitted by this {@code Call}, if any.
692 *
693 * @return The remaining post-dial sequence, or {@code null} if there is no post-dial sequence
694 * remaining or this {@code Call} is not in a post-dial state.
695 */
696 public String getRemainingPostDialSequence() {
697 return mRemainingPostDialSequence;
698 }
699
700 /**
701 * Instructs this {@link #STATE_RINGING} {@code Call} to answer.
Andrew Lee8da4c3c2014-07-16 10:11:42 -0700702 * @param videoState The video state in which to answer the call.
Ihab Awade63fadb2014-07-09 21:52:04 -0700703 */
Andrew Lee8da4c3c2014-07-16 10:11:42 -0700704 public void answer(int videoState) {
Tyler Gunnef9f6f92014-09-12 22:16:17 -0700705 mInCallAdapter.answerCall(mTelecomCallId, videoState);
Ihab Awade63fadb2014-07-09 21:52:04 -0700706 }
707
708 /**
709 * Instructs this {@link #STATE_RINGING} {@code Call} to reject.
710 *
711 * @param rejectWithMessage Whether to reject with a text message.
712 * @param textMessage An optional text message with which to respond.
713 */
714 public void reject(boolean rejectWithMessage, String textMessage) {
Tyler Gunnef9f6f92014-09-12 22:16:17 -0700715 mInCallAdapter.rejectCall(mTelecomCallId, rejectWithMessage, textMessage);
Ihab Awade63fadb2014-07-09 21:52:04 -0700716 }
717
718 /**
719 * Instructs this {@code Call} to disconnect.
720 */
721 public void disconnect() {
Tyler Gunnef9f6f92014-09-12 22:16:17 -0700722 mInCallAdapter.disconnectCall(mTelecomCallId);
Ihab Awade63fadb2014-07-09 21:52:04 -0700723 }
724
725 /**
726 * Instructs this {@code Call} to go on hold.
727 */
728 public void hold() {
Tyler Gunnef9f6f92014-09-12 22:16:17 -0700729 mInCallAdapter.holdCall(mTelecomCallId);
Ihab Awade63fadb2014-07-09 21:52:04 -0700730 }
731
732 /**
733 * Instructs this {@link #STATE_HOLDING} call to release from hold.
734 */
735 public void unhold() {
Tyler Gunnef9f6f92014-09-12 22:16:17 -0700736 mInCallAdapter.unholdCall(mTelecomCallId);
Ihab Awade63fadb2014-07-09 21:52:04 -0700737 }
738
739 /**
740 * Instructs this {@code Call} to play a dual-tone multi-frequency signaling (DTMF) tone.
741 *
742 * Any other currently playing DTMF tone in the specified call is immediately stopped.
743 *
744 * @param digit A character representing the DTMF digit for which to play the tone. This
745 * value must be one of {@code '0'} through {@code '9'}, {@code '*'} or {@code '#'}.
746 */
747 public void playDtmfTone(char digit) {
Tyler Gunnef9f6f92014-09-12 22:16:17 -0700748 mInCallAdapter.playDtmfTone(mTelecomCallId, digit);
Ihab Awade63fadb2014-07-09 21:52:04 -0700749 }
750
751 /**
752 * Instructs this {@code Call} to stop any dual-tone multi-frequency signaling (DTMF) tone
753 * currently playing.
754 *
755 * DTMF tones are played by calling {@link #playDtmfTone(char)}. If no DTMF tone is
756 * currently playing, this method will do nothing.
757 */
758 public void stopDtmfTone() {
Tyler Gunnef9f6f92014-09-12 22:16:17 -0700759 mInCallAdapter.stopDtmfTone(mTelecomCallId);
Ihab Awade63fadb2014-07-09 21:52:04 -0700760 }
761
762 /**
763 * Instructs this {@code Call} to continue playing a post-dial DTMF string.
764 *
765 * A post-dial DTMF string is a string of digits entered after a phone number, when dialed,
766 * that are immediately sent as DTMF tones to the recipient as soon as the connection is made.
Ihab Awade63fadb2014-07-09 21:52:04 -0700767 *
Tyler Gunnef9f6f92014-09-12 22:16:17 -0700768 * If the DTMF string contains a {@link TelecomManager#DTMF_CHARACTER_PAUSE} symbol, this
Ihab Awade63fadb2014-07-09 21:52:04 -0700769 * {@code Call} will temporarily pause playing the tones for a pre-defined period of time.
770 *
Tyler Gunnef9f6f92014-09-12 22:16:17 -0700771 * If the DTMF string contains a {@link TelecomManager#DTMF_CHARACTER_WAIT} symbol, this
Andrew Leeda80c872015-04-15 14:09:50 -0700772 * {@code Call} will pause playing the tones and notify callbacks via
773 * {@link Callback#onPostDialWait(Call, String)}. At this point, the in-call app
Ihab Awade63fadb2014-07-09 21:52:04 -0700774 * should display to the user an indication of this state and an affordance to continue
775 * the postdial sequence. When the user decides to continue the postdial sequence, the in-call
776 * app should invoke the {@link #postDialContinue(boolean)} method.
777 *
778 * @param proceed Whether or not to continue with the post-dial sequence.
779 */
780 public void postDialContinue(boolean proceed) {
Tyler Gunnef9f6f92014-09-12 22:16:17 -0700781 mInCallAdapter.postDialContinue(mTelecomCallId, proceed);
Ihab Awade63fadb2014-07-09 21:52:04 -0700782 }
783
784 /**
Evan Charlton8c8a0622014-07-20 12:31:00 -0700785 * Notifies this {@code Call} that an account has been selected and to proceed with placing
Nancy Chen36c62f32014-10-21 18:36:39 -0700786 * an outgoing call. Optionally sets this account as the default account.
Nancy Chen5da0fd52014-07-08 14:16:17 -0700787 */
Nancy Chen36c62f32014-10-21 18:36:39 -0700788 public void phoneAccountSelected(PhoneAccountHandle accountHandle, boolean setDefault) {
789 mInCallAdapter.phoneAccountSelected(mTelecomCallId, accountHandle, setDefault);
Nancy Chen5da0fd52014-07-08 14:16:17 -0700790
791 }
792
793 /**
Ihab Awade63fadb2014-07-09 21:52:04 -0700794 * Instructs this {@code Call} to enter a conference.
Santos Cordon7c7bc7f2014-07-28 18:15:48 -0700795 *
796 * @param callToConferenceWith The other call with which to conference.
Ihab Awade63fadb2014-07-09 21:52:04 -0700797 */
Santos Cordon7c7bc7f2014-07-28 18:15:48 -0700798 public void conference(Call callToConferenceWith) {
799 if (callToConferenceWith != null) {
Tyler Gunnef9f6f92014-09-12 22:16:17 -0700800 mInCallAdapter.conference(mTelecomCallId, callToConferenceWith.mTelecomCallId);
Santos Cordon7c7bc7f2014-07-28 18:15:48 -0700801 }
Ihab Awade63fadb2014-07-09 21:52:04 -0700802 }
803
804 /**
805 * Instructs this {@code Call} to split from any conference call with which it may be
806 * connected.
807 */
808 public void splitFromConference() {
Tyler Gunnef9f6f92014-09-12 22:16:17 -0700809 mInCallAdapter.splitFromConference(mTelecomCallId);
Ihab Awade63fadb2014-07-09 21:52:04 -0700810 }
811
812 /**
Ihab Awad5c9c86e2014-11-12 13:41:16 -0800813 * Merges the calls within this conference. See {@link Details#CAPABILITY_MERGE_CONFERENCE}.
Santos Cordona4868042014-09-04 17:39:22 -0700814 */
815 public void mergeConference() {
Tyler Gunnef9f6f92014-09-12 22:16:17 -0700816 mInCallAdapter.mergeConference(mTelecomCallId);
Santos Cordona4868042014-09-04 17:39:22 -0700817 }
818
819 /**
Ihab Awad5c9c86e2014-11-12 13:41:16 -0800820 * Swaps the calls within this conference. See {@link Details#CAPABILITY_SWAP_CONFERENCE}.
Santos Cordona4868042014-09-04 17:39:22 -0700821 */
822 public void swapConference() {
Tyler Gunnef9f6f92014-09-12 22:16:17 -0700823 mInCallAdapter.swapConference(mTelecomCallId);
Santos Cordona4868042014-09-04 17:39:22 -0700824 }
825
826 /**
Ihab Awade63fadb2014-07-09 21:52:04 -0700827 * Obtains the parent of this {@code Call} in a conference, if any.
828 *
829 * @return The parent {@code Call}, or {@code null} if this {@code Call} is not a
830 * child of any conference {@code Call}s.
831 */
832 public Call getParent() {
Santos Cordon823fd3c2014-08-07 18:35:18 -0700833 if (mParentId != null) {
Tyler Gunnef9f6f92014-09-12 22:16:17 -0700834 return mPhone.internalGetCallByTelecomId(mParentId);
Santos Cordon823fd3c2014-08-07 18:35:18 -0700835 }
836 return null;
Ihab Awade63fadb2014-07-09 21:52:04 -0700837 }
838
839 /**
840 * Obtains the children of this conference {@code Call}, if any.
841 *
842 * @return The children of this {@code Call} if this {@code Call} is a conference, or an empty
843 * {@code List} otherwise.
844 */
845 public List<Call> getChildren() {
Santos Cordon823fd3c2014-08-07 18:35:18 -0700846 if (!mChildrenCached) {
847 mChildrenCached = true;
848 mChildren.clear();
849
850 for(String id : mChildrenIds) {
Tyler Gunnef9f6f92014-09-12 22:16:17 -0700851 Call call = mPhone.internalGetCallByTelecomId(id);
Santos Cordon823fd3c2014-08-07 18:35:18 -0700852 if (call == null) {
853 // At least one child was still not found, so do not save true for "cached"
854 mChildrenCached = false;
855 } else {
856 mChildren.add(call);
857 }
858 }
859 }
860
Ihab Awade63fadb2014-07-09 21:52:04 -0700861 return mUnmodifiableChildren;
862 }
863
864 /**
Santos Cordon7c7bc7f2014-07-28 18:15:48 -0700865 * Returns the list of {@code Call}s with which this {@code Call} is allowed to conference.
866 *
867 * @return The list of conferenceable {@code Call}s.
868 */
869 public List<Call> getConferenceableCalls() {
870 return mUnmodifiableConferenceableCalls;
871 }
872
873 /**
Ihab Awade63fadb2014-07-09 21:52:04 -0700874 * Obtains the state of this {@code Call}.
875 *
876 * @return A state value, chosen from the {@code STATE_*} constants.
877 */
878 public int getState() {
879 return mState;
880 }
881
882 /**
883 * Obtains a list of canned, pre-configured message responses to present to the user as
884 * ways of rejecting this {@code Call} using via a text message.
885 *
886 * @see #reject(boolean, String)
887 *
888 * @return A list of canned text message responses.
889 */
890 public List<String> getCannedTextResponses() {
891 return mCannedTextResponses;
892 }
893
894 /**
895 * Obtains an object that can be used to display video from this {@code Call}.
896 *
Andrew Lee50aca232014-07-22 16:41:54 -0700897 * @return An {@code Call.VideoCall}.
Ihab Awade63fadb2014-07-09 21:52:04 -0700898 */
Andrew Lee50aca232014-07-22 16:41:54 -0700899 public InCallService.VideoCall getVideoCall() {
900 return mVideoCall;
Ihab Awade63fadb2014-07-09 21:52:04 -0700901 }
902
903 /**
904 * Obtains an object containing call details.
905 *
906 * @return A {@link Details} object. Depending on the state of the {@code Call}, the
907 * result may be {@code null}.
908 */
909 public Details getDetails() {
910 return mDetails;
911 }
912
913 /**
Andrew Leeda80c872015-04-15 14:09:50 -0700914 * Registers a callback to this {@code Call}.
915 *
916 * @param callback A {@code Callback}.
917 */
918 public void registerCallback(Callback callback) {
Andrew Lee011728f2015-04-23 15:47:06 -0700919 registerCallback(callback, new Handler());
920 }
921
922 /**
923 * Registers a callback to this {@code Call}.
924 *
925 * @param callback A {@code Callback}.
926 * @param handler A handler which command and status changes will be delivered to.
927 */
928 public void registerCallback(Callback callback, Handler handler) {
929 unregisterCallback(callback);
Roshan Pius1ca62072015-07-07 17:34:51 -0700930 // Don't allow new callback registration if the call is already being destroyed.
931 if (callback != null && handler != null && mState != STATE_DISCONNECTED) {
Andrew Lee011728f2015-04-23 15:47:06 -0700932 mCallbackRecords.add(new CallbackRecord<Callback>(callback, handler));
933 }
Andrew Leeda80c872015-04-15 14:09:50 -0700934 }
935
936 /**
937 * Unregisters a callback from this {@code Call}.
938 *
939 * @param callback A {@code Callback}.
940 */
941 public void unregisterCallback(Callback callback) {
Roshan Pius1ca62072015-07-07 17:34:51 -0700942 // Don't allow callback deregistration if the call is already being destroyed.
943 if (callback != null && mState != STATE_DISCONNECTED) {
Andrew Lee011728f2015-04-23 15:47:06 -0700944 for (CallbackRecord<Callback> record : mCallbackRecords) {
945 if (record.getCallback() == callback) {
946 mCallbackRecords.remove(record);
947 break;
948 }
949 }
Andrew Leeda80c872015-04-15 14:09:50 -0700950 }
951 }
952
953 /**
Ihab Awade63fadb2014-07-09 21:52:04 -0700954 * Adds a listener to this {@code Call}.
955 *
956 * @param listener A {@code Listener}.
Andrew Leeda80c872015-04-15 14:09:50 -0700957 * @deprecated Use {@link #registerCallback} instead.
958 * @hide
Ihab Awade63fadb2014-07-09 21:52:04 -0700959 */
Andrew Leeda80c872015-04-15 14:09:50 -0700960 @Deprecated
961 @SystemApi
Ihab Awade63fadb2014-07-09 21:52:04 -0700962 public void addListener(Listener listener) {
Andrew Leeda80c872015-04-15 14:09:50 -0700963 registerCallback(listener);
Ihab Awade63fadb2014-07-09 21:52:04 -0700964 }
965
966 /**
967 * Removes a listener from this {@code Call}.
968 *
969 * @param listener A {@code Listener}.
Andrew Leeda80c872015-04-15 14:09:50 -0700970 * @deprecated Use {@link #unregisterCallback} instead.
971 * @hide
Ihab Awade63fadb2014-07-09 21:52:04 -0700972 */
Andrew Leeda80c872015-04-15 14:09:50 -0700973 @Deprecated
974 @SystemApi
Ihab Awade63fadb2014-07-09 21:52:04 -0700975 public void removeListener(Listener listener) {
Andrew Leeda80c872015-04-15 14:09:50 -0700976 unregisterCallback(listener);
Ihab Awade63fadb2014-07-09 21:52:04 -0700977 }
978
979 /** {@hide} */
Tyler Gunnef9f6f92014-09-12 22:16:17 -0700980 Call(Phone phone, String telecomCallId, InCallAdapter inCallAdapter) {
Ihab Awade63fadb2014-07-09 21:52:04 -0700981 mPhone = phone;
Tyler Gunnef9f6f92014-09-12 22:16:17 -0700982 mTelecomCallId = telecomCallId;
Ihab Awade63fadb2014-07-09 21:52:04 -0700983 mInCallAdapter = inCallAdapter;
984 mState = STATE_NEW;
985 }
986
987 /** {@hide} */
Shriram Ganeshddf570e2015-05-31 09:18:48 -0700988 Call(Phone phone, String telecomCallId, InCallAdapter inCallAdapter, int state) {
989 mPhone = phone;
990 mTelecomCallId = telecomCallId;
991 mInCallAdapter = inCallAdapter;
992 mState = state;
993 }
994
995 /** {@hide} */
Ihab Awade63fadb2014-07-09 21:52:04 -0700996 final String internalGetCallId() {
Tyler Gunnef9f6f92014-09-12 22:16:17 -0700997 return mTelecomCallId;
Ihab Awade63fadb2014-07-09 21:52:04 -0700998 }
999
1000 /** {@hide} */
Santos Cordon7c7bc7f2014-07-28 18:15:48 -07001001 final void internalUpdate(ParcelableCall parcelableCall, Map<String, Call> callIdMap) {
Ihab Awade63fadb2014-07-09 21:52:04 -07001002 // First, we update the internal state as far as possible before firing any updates.
Ihab Awade63fadb2014-07-09 21:52:04 -07001003 Details details = new Details(
Santos Cordon88b771d2014-07-19 13:10:40 -07001004 parcelableCall.getHandle(),
1005 parcelableCall.getHandlePresentation(),
1006 parcelableCall.getCallerDisplayName(),
1007 parcelableCall.getCallerDisplayNamePresentation(),
1008 parcelableCall.getAccountHandle(),
1009 parcelableCall.getCapabilities(),
Andrew Lee223ad142014-08-27 16:33:08 -07001010 parcelableCall.getProperties(),
Andrew Lee7f3d41f2014-09-11 17:33:16 -07001011 parcelableCall.getDisconnectCause(),
Santos Cordon88b771d2014-07-19 13:10:40 -07001012 parcelableCall.getConnectTimeMillis(),
1013 parcelableCall.getGatewayInfo(),
1014 parcelableCall.getVideoState(),
Nancy Chen10798dc2014-08-08 14:00:25 -07001015 parcelableCall.getStatusHints(),
Santos Cordon6b7f9552015-05-27 17:21:45 -07001016 parcelableCall.getExtras(),
1017 parcelableCall.getIntentExtras());
Ihab Awade63fadb2014-07-09 21:52:04 -07001018 boolean detailsChanged = !Objects.equals(mDetails, details);
1019 if (detailsChanged) {
1020 mDetails = details;
1021 }
1022
1023 boolean cannedTextResponsesChanged = false;
Santos Cordon88b771d2014-07-19 13:10:40 -07001024 if (mCannedTextResponses == null && parcelableCall.getCannedSmsResponses() != null
1025 && !parcelableCall.getCannedSmsResponses().isEmpty()) {
1026 mCannedTextResponses =
1027 Collections.unmodifiableList(parcelableCall.getCannedSmsResponses());
Ihab Awade63fadb2014-07-09 21:52:04 -07001028 }
1029
Tyler Gunn75958422015-04-15 14:23:42 -07001030 boolean videoCallChanged = parcelableCall.isVideoCallProviderChanged() &&
Tyler Gunn45382162015-05-06 08:52:27 -07001031 !Objects.equals(mVideoCall, parcelableCall.getVideoCall(this));
Andrew Lee50aca232014-07-22 16:41:54 -07001032 if (videoCallChanged) {
Tyler Gunn45382162015-05-06 08:52:27 -07001033 mVideoCall = parcelableCall.getVideoCall(this);
Ihab Awade63fadb2014-07-09 21:52:04 -07001034 }
1035
Santos Cordone3c507b2015-04-23 14:44:19 -07001036 int state = parcelableCall.getState();
Ihab Awade63fadb2014-07-09 21:52:04 -07001037 boolean stateChanged = mState != state;
1038 if (stateChanged) {
1039 mState = state;
1040 }
1041
Santos Cordon823fd3c2014-08-07 18:35:18 -07001042 String parentId = parcelableCall.getParentCallId();
1043 boolean parentChanged = !Objects.equals(mParentId, parentId);
1044 if (parentChanged) {
1045 mParentId = parentId;
Ihab Awade63fadb2014-07-09 21:52:04 -07001046 }
1047
Santos Cordon823fd3c2014-08-07 18:35:18 -07001048 List<String> childCallIds = parcelableCall.getChildCallIds();
1049 boolean childrenChanged = !Objects.equals(childCallIds, mChildrenIds);
1050 if (childrenChanged) {
1051 mChildrenIds.clear();
1052 mChildrenIds.addAll(parcelableCall.getChildCallIds());
1053 mChildrenCached = false;
Ihab Awade63fadb2014-07-09 21:52:04 -07001054 }
1055
Santos Cordon7c7bc7f2014-07-28 18:15:48 -07001056 List<String> conferenceableCallIds = parcelableCall.getConferenceableCallIds();
1057 List<Call> conferenceableCalls = new ArrayList<Call>(conferenceableCallIds.size());
1058 for (String otherId : conferenceableCallIds) {
1059 if (callIdMap.containsKey(otherId)) {
1060 conferenceableCalls.add(callIdMap.get(otherId));
1061 }
1062 }
1063
1064 if (!Objects.equals(mConferenceableCalls, conferenceableCalls)) {
1065 mConferenceableCalls.clear();
1066 mConferenceableCalls.addAll(conferenceableCalls);
1067 fireConferenceableCallsChanged();
1068 }
1069
Ihab Awade63fadb2014-07-09 21:52:04 -07001070 // Now we fire updates, ensuring that any client who listens to any of these notifications
1071 // gets the most up-to-date state.
1072
1073 if (stateChanged) {
1074 fireStateChanged(mState);
1075 }
1076 if (detailsChanged) {
1077 fireDetailsChanged(mDetails);
1078 }
1079 if (cannedTextResponsesChanged) {
1080 fireCannedTextResponsesLoaded(mCannedTextResponses);
1081 }
Andrew Lee50aca232014-07-22 16:41:54 -07001082 if (videoCallChanged) {
1083 fireVideoCallChanged(mVideoCall);
Ihab Awade63fadb2014-07-09 21:52:04 -07001084 }
Santos Cordon823fd3c2014-08-07 18:35:18 -07001085 if (parentChanged) {
1086 fireParentChanged(getParent());
1087 }
1088 if (childrenChanged) {
1089 fireChildrenChanged(getChildren());
1090 }
Ihab Awade63fadb2014-07-09 21:52:04 -07001091
1092 // If we have transitioned to DISCONNECTED, that means we need to notify clients and
1093 // remove ourselves from the Phone. Note that we do this after completing all state updates
1094 // so a client can cleanly transition all their UI to the state appropriate for a
1095 // DISCONNECTED Call while still relying on the existence of that Call in the Phone's list.
1096 if (mState == STATE_DISCONNECTED) {
1097 fireCallDestroyed();
Ihab Awade63fadb2014-07-09 21:52:04 -07001098 }
1099 }
1100
1101 /** {@hide} */
Ihab Awade63fadb2014-07-09 21:52:04 -07001102 final void internalSetPostDialWait(String remaining) {
1103 mRemainingPostDialSequence = remaining;
1104 firePostDialWait(mRemainingPostDialSequence);
1105 }
1106
Sailesh Nepal2ab88cc2014-07-18 14:49:18 -07001107 /** {@hide} */
Santos Cordonf30d7e92014-08-26 09:54:33 -07001108 final void internalSetDisconnected() {
1109 if (mState != Call.STATE_DISCONNECTED) {
1110 mState = Call.STATE_DISCONNECTED;
1111 fireStateChanged(mState);
1112 fireCallDestroyed();
Santos Cordonf30d7e92014-08-26 09:54:33 -07001113 }
1114 }
1115
Andrew Lee011728f2015-04-23 15:47:06 -07001116 private void fireStateChanged(final int newState) {
1117 for (CallbackRecord<Callback> record : mCallbackRecords) {
1118 final Call call = this;
1119 final Callback callback = record.getCallback();
1120 record.getHandler().post(new Runnable() {
1121 @Override
1122 public void run() {
1123 callback.onStateChanged(call, newState);
1124 }
1125 });
Ihab Awade63fadb2014-07-09 21:52:04 -07001126 }
1127 }
1128
Andrew Lee011728f2015-04-23 15:47:06 -07001129 private void fireParentChanged(final Call newParent) {
1130 for (CallbackRecord<Callback> record : mCallbackRecords) {
1131 final Call call = this;
1132 final Callback callback = record.getCallback();
1133 record.getHandler().post(new Runnable() {
1134 @Override
1135 public void run() {
1136 callback.onParentChanged(call, newParent);
1137 }
1138 });
Ihab Awade63fadb2014-07-09 21:52:04 -07001139 }
1140 }
1141
Andrew Lee011728f2015-04-23 15:47:06 -07001142 private void fireChildrenChanged(final List<Call> children) {
1143 for (CallbackRecord<Callback> record : mCallbackRecords) {
1144 final Call call = this;
1145 final Callback callback = record.getCallback();
1146 record.getHandler().post(new Runnable() {
1147 @Override
1148 public void run() {
1149 callback.onChildrenChanged(call, children);
1150 }
1151 });
Ihab Awade63fadb2014-07-09 21:52:04 -07001152 }
1153 }
1154
Andrew Lee011728f2015-04-23 15:47:06 -07001155 private void fireDetailsChanged(final Details details) {
1156 for (CallbackRecord<Callback> record : mCallbackRecords) {
1157 final Call call = this;
1158 final Callback callback = record.getCallback();
1159 record.getHandler().post(new Runnable() {
1160 @Override
1161 public void run() {
1162 callback.onDetailsChanged(call, details);
1163 }
1164 });
Ihab Awade63fadb2014-07-09 21:52:04 -07001165 }
1166 }
1167
Andrew Lee011728f2015-04-23 15:47:06 -07001168 private void fireCannedTextResponsesLoaded(final List<String> cannedTextResponses) {
1169 for (CallbackRecord<Callback> record : mCallbackRecords) {
1170 final Call call = this;
1171 final Callback callback = record.getCallback();
1172 record.getHandler().post(new Runnable() {
1173 @Override
1174 public void run() {
1175 callback.onCannedTextResponsesLoaded(call, cannedTextResponses);
1176 }
1177 });
Ihab Awade63fadb2014-07-09 21:52:04 -07001178 }
1179 }
1180
Andrew Lee011728f2015-04-23 15:47:06 -07001181 private void fireVideoCallChanged(final InCallService.VideoCall videoCall) {
1182 for (CallbackRecord<Callback> record : mCallbackRecords) {
1183 final Call call = this;
1184 final Callback callback = record.getCallback();
1185 record.getHandler().post(new Runnable() {
1186 @Override
1187 public void run() {
1188 callback.onVideoCallChanged(call, videoCall);
1189 }
1190 });
Ihab Awade63fadb2014-07-09 21:52:04 -07001191 }
1192 }
1193
Andrew Lee011728f2015-04-23 15:47:06 -07001194 private void firePostDialWait(final String remainingPostDialSequence) {
1195 for (CallbackRecord<Callback> record : mCallbackRecords) {
1196 final Call call = this;
1197 final Callback callback = record.getCallback();
1198 record.getHandler().post(new Runnable() {
1199 @Override
1200 public void run() {
1201 callback.onPostDialWait(call, remainingPostDialSequence);
1202 }
1203 });
Ihab Awade63fadb2014-07-09 21:52:04 -07001204 }
1205 }
1206
1207 private void fireCallDestroyed() {
Roshan Pius1ca62072015-07-07 17:34:51 -07001208 /**
1209 * To preserve the ordering of the Call's onCallDestroyed callback and Phone's
1210 * onCallRemoved callback, we remove this call from the Phone's record
1211 * only once all of the registered onCallDestroyed callbacks are executed.
1212 * All the callbacks get removed from our records as a part of this operation
1213 * since onCallDestroyed is the final callback.
1214 */
1215 final Call call = this;
1216 if (mCallbackRecords.isEmpty()) {
1217 // No callbacks registered, remove the call from Phone's record.
1218 mPhone.internalRemoveCall(call);
1219 }
1220 for (final CallbackRecord<Callback> record : mCallbackRecords) {
Andrew Lee011728f2015-04-23 15:47:06 -07001221 final Callback callback = record.getCallback();
1222 record.getHandler().post(new Runnable() {
1223 @Override
1224 public void run() {
Roshan Pius1ca62072015-07-07 17:34:51 -07001225 boolean isFinalRemoval = false;
1226 RuntimeException toThrow = null;
1227 try {
1228 callback.onCallDestroyed(call);
1229 } catch (RuntimeException e) {
1230 toThrow = e;
1231 }
1232 synchronized(Call.this) {
1233 mCallbackRecords.remove(record);
1234 if (mCallbackRecords.isEmpty()) {
1235 isFinalRemoval = true;
1236 }
1237 }
1238 if (isFinalRemoval) {
1239 mPhone.internalRemoveCall(call);
1240 }
1241 if (toThrow != null) {
1242 throw toThrow;
1243 }
Andrew Lee011728f2015-04-23 15:47:06 -07001244 }
1245 });
Ihab Awade63fadb2014-07-09 21:52:04 -07001246 }
1247 }
1248
Santos Cordon7c7bc7f2014-07-28 18:15:48 -07001249 private void fireConferenceableCallsChanged() {
Andrew Lee011728f2015-04-23 15:47:06 -07001250 for (CallbackRecord<Callback> record : mCallbackRecords) {
1251 final Call call = this;
1252 final Callback callback = record.getCallback();
1253 record.getHandler().post(new Runnable() {
1254 @Override
1255 public void run() {
1256 callback.onConferenceableCallsChanged(call, mUnmodifiableConferenceableCalls);
1257 }
1258 });
Santos Cordon7c7bc7f2014-07-28 18:15:48 -07001259 }
1260 }
Tyler Gunn1e9bfc62015-08-19 11:18:58 -07001261
1262 /**
1263 * Determines if two bundles are equal.
1264 *
1265 * @param bundle The original bundle.
1266 * @param newBundle The bundle to compare with.
1267 * @retrun {@code true} if the bundles are equal, {@code false} otherwise.
1268 */
1269 private static boolean areBundlesEqual(Bundle bundle, Bundle newBundle) {
1270 if (bundle == null || newBundle == null) {
1271 return bundle == newBundle;
1272 }
1273
1274 if (bundle.size() != newBundle.size()) {
1275 return false;
1276 }
1277
1278 for(String key : bundle.keySet()) {
1279 if (key != null) {
1280 final Object value = bundle.get(key);
1281 final Object newValue = newBundle.get(key);
1282 if (!Objects.equals(value, newValue)) {
1283 return false;
1284 }
1285 }
1286 }
1287 return true;
1288 }
Santos Cordon7c7bc7f2014-07-28 18:15:48 -07001289}