blob: 39a12070a69bd792a8ebd8c294398e0c4ef7a033 [file] [log] [blame]
Ihab Awade63fadb2014-07-09 21:52:04 -07001/*
2 * Copyright (C) 2014 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
Tyler Gunnef9f6f92014-09-12 22:16:17 -070017package android.telecom;
Ihab Awade63fadb2014-07-09 21:52:04 -070018
Andrew Leeda80c872015-04-15 14:09:50 -070019import android.annotation.SystemApi;
Ihab Awade63fadb2014-07-09 21:52:04 -070020import android.net.Uri;
Nancy Chen10798dc2014-08-08 14:00:25 -070021import android.os.Bundle;
Andrew Lee011728f2015-04-23 15:47:06 -070022import android.os.Handler;
Ihab Awade63fadb2014-07-09 21:52:04 -070023
Andrew Lee50aca232014-07-22 16:41:54 -070024import java.lang.String;
Ihab Awade63fadb2014-07-09 21:52:04 -070025import java.util.ArrayList;
26import java.util.Collections;
27import java.util.List;
Santos Cordon7c7bc7f2014-07-28 18:15:48 -070028import java.util.Map;
Ihab Awade63fadb2014-07-09 21:52:04 -070029import java.util.Objects;
Jay Shrauner229e3822014-08-15 09:23:07 -070030import java.util.concurrent.CopyOnWriteArrayList;
Ihab Awade63fadb2014-07-09 21:52:04 -070031
32/**
33 * Represents an ongoing phone call that the in-call app should present to the user.
34 */
35public final class Call {
36 /**
37 * The state of a {@code Call} when newly created.
38 */
39 public static final int STATE_NEW = 0;
40
41 /**
42 * The state of an outgoing {@code Call} when dialing the remote number, but not yet connected.
43 */
44 public static final int STATE_DIALING = 1;
45
46 /**
47 * The state of an incoming {@code Call} when ringing locally, but not yet connected.
48 */
49 public static final int STATE_RINGING = 2;
50
51 /**
52 * The state of a {@code Call} when in a holding state.
53 */
54 public static final int STATE_HOLDING = 3;
55
56 /**
57 * The state of a {@code Call} when actively supporting conversation.
58 */
59 public static final int STATE_ACTIVE = 4;
60
61 /**
62 * The state of a {@code Call} when no further voice or other communication is being
63 * transmitted, the remote side has been or will inevitably be informed that the {@code Call}
64 * is no longer active, and the local data transport has or inevitably will release resources
65 * associated with this {@code Call}.
66 */
67 public static final int STATE_DISCONNECTED = 7;
68
Nancy Chen5da0fd52014-07-08 14:16:17 -070069 /**
Santos Cordone3c507b2015-04-23 14:44:19 -070070 * The state of an outgoing {@code Call} when waiting on user to select a
71 * {@link PhoneAccount} through which to place the call.
Nancy Chen5da0fd52014-07-08 14:16:17 -070072 */
Santos Cordone3c507b2015-04-23 14:44:19 -070073 public static final int STATE_SELECT_PHONE_ACCOUNT = 8;
74
75 /**
76 * @hide
77 * @deprecated use STATE_SELECT_PHONE_ACCOUNT.
78 */
79 @Deprecated
80 @SystemApi
81 public static final int STATE_PRE_DIAL_WAIT = STATE_SELECT_PHONE_ACCOUNT;
Nancy Chen5da0fd52014-07-08 14:16:17 -070082
Nancy Chene20930f2014-08-07 16:17:21 -070083 /**
Nancy Chene9b7a8e2014-08-08 14:26:27 -070084 * The initial state of an outgoing {@code Call}.
85 * Common transitions are to {@link #STATE_DIALING} state for a successful call or
86 * {@link #STATE_DISCONNECTED} if it failed.
Nancy Chene20930f2014-08-07 16:17:21 -070087 */
88 public static final int STATE_CONNECTING = 9;
89
Nancy Chen513c8922014-09-17 14:47:20 -070090 /**
Tyler Gunn4afc6af2014-10-07 10:14:55 -070091 * The state of a {@code Call} when the user has initiated a disconnection of the call, but the
92 * call has not yet been disconnected by the underlying {@code ConnectionService}. The next
93 * state of the call is (potentially) {@link #STATE_DISCONNECTED}.
94 */
95 public static final int STATE_DISCONNECTING = 10;
96
97 /**
Tyler Gunn876dbfb2016-03-14 15:18:07 -070098 * The state of an external call which is in the process of being pulled from a remote device to
99 * the local device.
100 * <p>
101 * A call can only be in this state if the {@link Details#PROPERTY_IS_EXTERNAL_CALL} property
102 * and {@link Details#CAPABILITY_CAN_PULL_CALL} capability are set on the call.
103 * <p>
104 * An {@link InCallService} will only see this state if it has the
105 * {@link TelecomManager#METADATA_INCLUDE_EXTERNAL_CALLS} metadata set to {@code true} in its
106 * manifest.
Tyler Gunn1bf206b2016-04-15 11:28:44 -0700107 * @hide
Tyler Gunn876dbfb2016-03-14 15:18:07 -0700108 */
109 public static final int STATE_PULLING_CALL = 11;
110
111 /**
Nancy Chen513c8922014-09-17 14:47:20 -0700112 * The key to retrieve the optional {@code PhoneAccount}s Telecom can bundle with its Call
113 * extras. Used to pass the phone accounts to display on the front end to the user in order to
114 * select phone accounts to (for example) place a call.
Nancy Chen513c8922014-09-17 14:47:20 -0700115 */
116 public static final String AVAILABLE_PHONE_ACCOUNTS = "selectPhoneAccountAccounts";
117
Ihab Awade63fadb2014-07-09 21:52:04 -0700118 public static class Details {
Ihab Awad5c9c86e2014-11-12 13:41:16 -0800119
120 /** Call can currently be put on hold or unheld. */
121 public static final int CAPABILITY_HOLD = 0x00000001;
122
123 /** Call supports the hold feature. */
124 public static final int CAPABILITY_SUPPORT_HOLD = 0x00000002;
125
126 /**
127 * Calls within a conference can be merged. A {@link ConnectionService} has the option to
128 * add a {@link Conference} call before the child {@link Connection}s are merged. This is how
129 * CDMA-based {@link Connection}s are implemented. For these unmerged {@link Conference}s, this
130 * capability allows a merge button to be shown while the conference call is in the foreground
131 * of the in-call UI.
132 * <p>
133 * This is only intended for use by a {@link Conference}.
134 */
135 public static final int CAPABILITY_MERGE_CONFERENCE = 0x00000004;
136
137 /**
138 * Calls within a conference can be swapped between foreground and background.
139 * See {@link #CAPABILITY_MERGE_CONFERENCE} for additional information.
140 * <p>
141 * This is only intended for use by a {@link Conference}.
142 */
143 public static final int CAPABILITY_SWAP_CONFERENCE = 0x00000008;
144
145 /**
146 * @hide
147 */
Andrew Lee2378ea72015-04-29 14:38:11 -0700148 public static final int CAPABILITY_UNUSED_1 = 0x00000010;
Ihab Awad5c9c86e2014-11-12 13:41:16 -0800149
150 /** Call supports responding via text option. */
151 public static final int CAPABILITY_RESPOND_VIA_TEXT = 0x00000020;
152
153 /** Call can be muted. */
154 public static final int CAPABILITY_MUTE = 0x00000040;
155
156 /**
157 * Call supports conference call management. This capability only applies to {@link Conference}
158 * calls which can have {@link Connection}s as children.
159 */
160 public static final int CAPABILITY_MANAGE_CONFERENCE = 0x00000080;
161
162 /**
Andrew Lee5e9e8bb2015-03-10 13:58:24 -0700163 * Local device supports receiving video.
Ihab Awad5c9c86e2014-11-12 13:41:16 -0800164 */
Andrew Lee5e9e8bb2015-03-10 13:58:24 -0700165 public static final int CAPABILITY_SUPPORTS_VT_LOCAL_RX = 0x00000100;
Ihab Awad5c9c86e2014-11-12 13:41:16 -0800166
167 /**
Andrew Lee5e9e8bb2015-03-10 13:58:24 -0700168 * Local device supports transmitting video.
Ihab Awad5c9c86e2014-11-12 13:41:16 -0800169 */
Andrew Lee5e9e8bb2015-03-10 13:58:24 -0700170 public static final int CAPABILITY_SUPPORTS_VT_LOCAL_TX = 0x00000200;
Ihab Awad5c9c86e2014-11-12 13:41:16 -0800171
172 /**
Andrew Lee5e9e8bb2015-03-10 13:58:24 -0700173 * Local device supports bidirectional video calling.
Ihab Awad5c9c86e2014-11-12 13:41:16 -0800174 */
Andrew Lee9a8f9ce2015-04-10 18:09:46 -0700175 public static final int CAPABILITY_SUPPORTS_VT_LOCAL_BIDIRECTIONAL =
Andrew Lee5e9e8bb2015-03-10 13:58:24 -0700176 CAPABILITY_SUPPORTS_VT_LOCAL_RX | CAPABILITY_SUPPORTS_VT_LOCAL_TX;
Ihab Awad5c9c86e2014-11-12 13:41:16 -0800177
178 /**
Andrew Lee5e9e8bb2015-03-10 13:58:24 -0700179 * Remote device supports receiving video.
Ihab Awad5c9c86e2014-11-12 13:41:16 -0800180 */
Andrew Lee5e9e8bb2015-03-10 13:58:24 -0700181 public static final int CAPABILITY_SUPPORTS_VT_REMOTE_RX = 0x00000400;
182
183 /**
184 * Remote device supports transmitting video.
Andrew Lee5e9e8bb2015-03-10 13:58:24 -0700185 */
186 public static final int CAPABILITY_SUPPORTS_VT_REMOTE_TX = 0x00000800;
187
188 /**
189 * Remote device supports bidirectional video calling.
Andrew Lee5e9e8bb2015-03-10 13:58:24 -0700190 */
Andrew Lee9a8f9ce2015-04-10 18:09:46 -0700191 public static final int CAPABILITY_SUPPORTS_VT_REMOTE_BIDIRECTIONAL =
Andrew Lee5e9e8bb2015-03-10 13:58:24 -0700192 CAPABILITY_SUPPORTS_VT_REMOTE_RX | CAPABILITY_SUPPORTS_VT_REMOTE_TX;
Ihab Awad5c9c86e2014-11-12 13:41:16 -0800193
194 /**
195 * Call is able to be separated from its parent {@code Conference}, if any.
196 */
197 public static final int CAPABILITY_SEPARATE_FROM_CONFERENCE = 0x00001000;
198
199 /**
200 * Call is able to be individually disconnected when in a {@code Conference}.
201 */
202 public static final int CAPABILITY_DISCONNECT_FROM_CONFERENCE = 0x00002000;
203
204 /**
Dong Zhou89f41eb2015-03-15 11:59:49 -0500205 * Speed up audio setup for MT call.
206 * @hide
207 */
Tyler Gunn96d6c402015-03-18 12:39:23 -0700208 public static final int CAPABILITY_SPEED_UP_MT_AUDIO = 0x00040000;
209
Tyler Gunnb5e0cfb2015-04-07 16:10:51 -0700210 /**
211 * Call can be upgraded to a video call.
Rekha Kumar07366812015-03-24 16:42:31 -0700212 * @hide
213 */
214 public static final int CAPABILITY_CAN_UPGRADE_TO_VIDEO = 0x00080000;
215
Tyler Gunnb5e0cfb2015-04-07 16:10:51 -0700216 /**
217 * For video calls, indicates whether the outgoing video for the call can be paused using
Yorke Lee32f24732015-05-12 16:18:03 -0700218 * the {@link android.telecom.VideoProfile#STATE_PAUSED} VideoState.
Tyler Gunnb5e0cfb2015-04-07 16:10:51 -0700219 */
220 public static final int CAPABILITY_CAN_PAUSE_VIDEO = 0x00100000;
221
Bryce Lee81901682015-08-28 16:38:02 -0700222 /**
223 * Call sends responses through connection.
224 * @hide
225 */
Tyler Gunnf97a0092016-01-19 15:59:34 -0800226 public static final int CAPABILITY_CAN_SEND_RESPONSE_VIA_CONNECTION = 0x00200000;
227
228 /**
229 * When set, prevents a video {@code Call} from being downgraded to an audio-only call.
230 * <p>
231 * Should be set when the VideoState has the {@link VideoProfile#STATE_TX_ENABLED} or
232 * {@link VideoProfile#STATE_RX_ENABLED} bits set to indicate that the connection cannot be
233 * downgraded from a video call back to a VideoState of
234 * {@link VideoProfile#STATE_AUDIO_ONLY}.
235 * <p>
236 * Intuitively, a call which can be downgraded to audio should also have local and remote
237 * video
238 * capabilities (see {@link #CAPABILITY_SUPPORTS_VT_LOCAL_BIDIRECTIONAL} and
239 * {@link #CAPABILITY_SUPPORTS_VT_REMOTE_BIDIRECTIONAL}).
240 */
241 public static final int CAPABILITY_CANNOT_DOWNGRADE_VIDEO_TO_AUDIO = 0x00400000;
Bryce Lee81901682015-08-28 16:38:02 -0700242
Tyler Gunn876dbfb2016-03-14 15:18:07 -0700243 /**
244 * When set for an external call, indicates that this {@code Call} can be pulled from a
245 * remote device to the current device.
246 * <p>
247 * Should only be set on a {@code Call} where {@link #PROPERTY_IS_EXTERNAL_CALL} is set.
248 * <p>
249 * An {@link InCallService} will only see calls with this capability if it has the
250 * {@link TelecomManager#METADATA_INCLUDE_EXTERNAL_CALLS} metadata set to {@code true}
251 * in its manifest.
252 * <p>
253 * See {@link Connection#CAPABILITY_CAN_PULL_CALL} and
Tyler Gunn720c6642016-03-22 09:02:47 -0700254 * {@link Connection#PROPERTY_IS_EXTERNAL_CALL}.
Tyler Gunn1bf206b2016-04-15 11:28:44 -0700255 * @hide
Tyler Gunn876dbfb2016-03-14 15:18:07 -0700256 */
257 public static final int CAPABILITY_CAN_PULL_CALL = 0x00800000;
258
Tyler Gunnd11a3152015-03-18 13:09:14 -0700259 //******************************************************************************************
Tyler Gunn876dbfb2016-03-14 15:18:07 -0700260 // Next CAPABILITY value: 0x01000000
Andrew Lee2378ea72015-04-29 14:38:11 -0700261 //******************************************************************************************
262
263 /**
264 * Whether the call is currently a conference.
265 */
266 public static final int PROPERTY_CONFERENCE = 0x00000001;
267
268 /**
269 * Whether the call is a generic conference, where we do not know the precise state of
270 * participants in the conference (eg. on CDMA).
271 */
272 public static final int PROPERTY_GENERIC_CONFERENCE = 0x00000002;
273
274 /**
275 * Whether the call is made while the device is in emergency callback mode.
276 */
277 public static final int PROPERTY_EMERGENCY_CALLBACK_MODE = 0x00000004;
278
279 /**
280 * Connection is using WIFI.
281 */
282 public static final int PROPERTY_WIFI = 0x00000008;
283
284 /**
285 * Call is using high definition audio.
286 */
287 public static final int PROPERTY_HIGH_DEF_AUDIO = 0x00000010;
288
Tony Maka68dcce2015-12-17 09:31:18 +0000289 /**
290 * Whether the call is associated with the work profile.
291 */
292 public static final int PROPERTY_WORK_CALL = 0x00000020;
293
Tyler Gunn876dbfb2016-03-14 15:18:07 -0700294 /**
295 * When set, indicates that this {@code Call} does not actually exist locally for the
296 * {@link ConnectionService}.
297 * <p>
298 * Consider, for example, a scenario where a user has two phones with the same phone number.
299 * When a user places a call on one device, the telephony stack can represent that call on
300 * the other device by adding it to the {@link ConnectionService} with the
Tyler Gunn720c6642016-03-22 09:02:47 -0700301 * {@link Connection#PROPERTY_IS_EXTERNAL_CALL} property set.
Tyler Gunn876dbfb2016-03-14 15:18:07 -0700302 * <p>
303 * An {@link InCallService} will only see calls with this property if it has the
304 * {@link TelecomManager#METADATA_INCLUDE_EXTERNAL_CALLS} metadata set to {@code true}
305 * in its manifest.
306 * <p>
Tyler Gunn720c6642016-03-22 09:02:47 -0700307 * See {@link Connection#PROPERTY_IS_EXTERNAL_CALL}.
Tyler Gunn1bf206b2016-04-15 11:28:44 -0700308 * @hide
Tyler Gunn876dbfb2016-03-14 15:18:07 -0700309 */
310 public static final int PROPERTY_IS_EXTERNAL_CALL = 0x00000040;
311
Andrew Lee2378ea72015-04-29 14:38:11 -0700312 //******************************************************************************************
Tyler Gunn876dbfb2016-03-14 15:18:07 -0700313 // Next PROPERTY value: 0x00000100
Tyler Gunnd11a3152015-03-18 13:09:14 -0700314 //******************************************************************************************
Tyler Gunn068085b2015-02-06 13:56:52 -0800315
Sailesh Nepal1bef3392016-01-24 18:21:53 -0800316 private final String mTelecomCallId;
Ihab Awade63fadb2014-07-09 21:52:04 -0700317 private final Uri mHandle;
318 private final int mHandlePresentation;
319 private final String mCallerDisplayName;
320 private final int mCallerDisplayNamePresentation;
Evan Charlton8c8a0622014-07-20 12:31:00 -0700321 private final PhoneAccountHandle mAccountHandle;
Ihab Awad5d0410f2014-07-30 10:07:40 -0700322 private final int mCallCapabilities;
Andrew Lee223ad142014-08-27 16:33:08 -0700323 private final int mCallProperties;
Andrew Lee7f3d41f2014-09-11 17:33:16 -0700324 private final DisconnectCause mDisconnectCause;
Ihab Awade63fadb2014-07-09 21:52:04 -0700325 private final long mConnectTimeMillis;
326 private final GatewayInfo mGatewayInfo;
Andrew Lee85f5d422014-07-11 17:22:03 -0700327 private final int mVideoState;
Evan Charlton5b49ade2014-07-15 17:03:20 -0700328 private final StatusHints mStatusHints;
Nancy Chen10798dc2014-08-08 14:00:25 -0700329 private final Bundle mExtras;
Santos Cordon6b7f9552015-05-27 17:21:45 -0700330 private final Bundle mIntentExtras;
Ihab Awade63fadb2014-07-09 21:52:04 -0700331
332 /**
Ihab Awad5c9c86e2014-11-12 13:41:16 -0800333 * Whether the supplied capabilities supports the specified capability.
334 *
335 * @param capabilities A bit field of capabilities.
336 * @param capability The capability to check capabilities for.
337 * @return Whether the specified capability is supported.
Ihab Awad5c9c86e2014-11-12 13:41:16 -0800338 */
339 public static boolean can(int capabilities, int capability) {
Tyler Gunn014c7112015-12-18 14:33:57 -0800340 return (capabilities & capability) == capability;
Ihab Awad5c9c86e2014-11-12 13:41:16 -0800341 }
342
343 /**
344 * Whether the capabilities of this {@code Details} supports the specified capability.
345 *
346 * @param capability The capability to check capabilities for.
347 * @return Whether the specified capability is supported.
Ihab Awad5c9c86e2014-11-12 13:41:16 -0800348 */
349 public boolean can(int capability) {
350 return can(mCallCapabilities, capability);
351 }
352
353 /**
354 * Render a set of capability bits ({@code CAPABILITY_*}) as a human readable string.
355 *
356 * @param capabilities A capability bit field.
357 * @return A human readable string representation.
358 */
359 public static String capabilitiesToString(int capabilities) {
360 StringBuilder builder = new StringBuilder();
361 builder.append("[Capabilities:");
362 if (can(capabilities, CAPABILITY_HOLD)) {
363 builder.append(" CAPABILITY_HOLD");
364 }
365 if (can(capabilities, CAPABILITY_SUPPORT_HOLD)) {
366 builder.append(" CAPABILITY_SUPPORT_HOLD");
367 }
368 if (can(capabilities, CAPABILITY_MERGE_CONFERENCE)) {
369 builder.append(" CAPABILITY_MERGE_CONFERENCE");
370 }
371 if (can(capabilities, CAPABILITY_SWAP_CONFERENCE)) {
372 builder.append(" CAPABILITY_SWAP_CONFERENCE");
373 }
374 if (can(capabilities, CAPABILITY_RESPOND_VIA_TEXT)) {
375 builder.append(" CAPABILITY_RESPOND_VIA_TEXT");
376 }
377 if (can(capabilities, CAPABILITY_MUTE)) {
378 builder.append(" CAPABILITY_MUTE");
379 }
380 if (can(capabilities, CAPABILITY_MANAGE_CONFERENCE)) {
381 builder.append(" CAPABILITY_MANAGE_CONFERENCE");
382 }
Andrew Lee5e9e8bb2015-03-10 13:58:24 -0700383 if (can(capabilities, CAPABILITY_SUPPORTS_VT_LOCAL_RX)) {
384 builder.append(" CAPABILITY_SUPPORTS_VT_LOCAL_RX");
385 }
386 if (can(capabilities, CAPABILITY_SUPPORTS_VT_LOCAL_TX)) {
387 builder.append(" CAPABILITY_SUPPORTS_VT_LOCAL_TX");
388 }
Andrew Lee9a8f9ce2015-04-10 18:09:46 -0700389 if (can(capabilities, CAPABILITY_SUPPORTS_VT_LOCAL_BIDIRECTIONAL)) {
390 builder.append(" CAPABILITY_SUPPORTS_VT_LOCAL_BIDIRECTIONAL");
Ihab Awad5c9c86e2014-11-12 13:41:16 -0800391 }
Andrew Lee5e9e8bb2015-03-10 13:58:24 -0700392 if (can(capabilities, CAPABILITY_SUPPORTS_VT_REMOTE_RX)) {
393 builder.append(" CAPABILITY_SUPPORTS_VT_REMOTE_RX");
394 }
395 if (can(capabilities, CAPABILITY_SUPPORTS_VT_REMOTE_TX)) {
396 builder.append(" CAPABILITY_SUPPORTS_VT_REMOTE_TX");
397 }
Tyler Gunnf97a0092016-01-19 15:59:34 -0800398 if (can(capabilities, CAPABILITY_CANNOT_DOWNGRADE_VIDEO_TO_AUDIO)) {
399 builder.append(" CAPABILITY_CANNOT_DOWNGRADE_VIDEO_TO_AUDIO");
400 }
Andrew Lee9a8f9ce2015-04-10 18:09:46 -0700401 if (can(capabilities, CAPABILITY_SUPPORTS_VT_REMOTE_BIDIRECTIONAL)) {
402 builder.append(" CAPABILITY_SUPPORTS_VT_REMOTE_BIDIRECTIONAL");
Ihab Awad5c9c86e2014-11-12 13:41:16 -0800403 }
Dong Zhou89f41eb2015-03-15 11:59:49 -0500404 if (can(capabilities, CAPABILITY_SPEED_UP_MT_AUDIO)) {
Tyler Gunnd11a3152015-03-18 13:09:14 -0700405 builder.append(" CAPABILITY_SPEED_UP_MT_AUDIO");
Dong Zhou89f41eb2015-03-15 11:59:49 -0500406 }
Rekha Kumar07366812015-03-24 16:42:31 -0700407 if (can(capabilities, CAPABILITY_CAN_UPGRADE_TO_VIDEO)) {
408 builder.append(" CAPABILITY_CAN_UPGRADE_TO_VIDEO");
409 }
Tyler Gunnb5e0cfb2015-04-07 16:10:51 -0700410 if (can(capabilities, CAPABILITY_CAN_PAUSE_VIDEO)) {
411 builder.append(" CAPABILITY_CAN_PAUSE_VIDEO");
412 }
Tyler Gunn876dbfb2016-03-14 15:18:07 -0700413 if (can(capabilities, CAPABILITY_CAN_PULL_CALL)) {
414 builder.append(" CAPABILITY_CAN_PULL_CALL");
415 }
Ihab Awad5c9c86e2014-11-12 13:41:16 -0800416 builder.append("]");
417 return builder.toString();
418 }
419
420 /**
Andrew Lee2378ea72015-04-29 14:38:11 -0700421 * Whether the supplied properties includes the specified property.
422 *
423 * @param properties A bit field of properties.
424 * @param property The property to check properties for.
425 * @return Whether the specified property is supported.
426 */
427 public static boolean hasProperty(int properties, int property) {
Tyler Gunn014c7112015-12-18 14:33:57 -0800428 return (properties & property) == property;
Andrew Lee2378ea72015-04-29 14:38:11 -0700429 }
430
431 /**
432 * Whether the properties of this {@code Details} includes the specified property.
433 *
434 * @param property The property to check properties for.
435 * @return Whether the specified property is supported.
436 */
437 public boolean hasProperty(int property) {
438 return hasProperty(mCallProperties, property);
439 }
440
441 /**
442 * Render a set of property bits ({@code PROPERTY_*}) as a human readable string.
443 *
444 * @param properties A property bit field.
445 * @return A human readable string representation.
446 */
447 public static String propertiesToString(int properties) {
448 StringBuilder builder = new StringBuilder();
449 builder.append("[Properties:");
450 if (hasProperty(properties, PROPERTY_CONFERENCE)) {
451 builder.append(" PROPERTY_CONFERENCE");
452 }
453 if (hasProperty(properties, PROPERTY_GENERIC_CONFERENCE)) {
454 builder.append(" PROPERTY_GENERIC_CONFERENCE");
455 }
456 if (hasProperty(properties, PROPERTY_WIFI)) {
457 builder.append(" PROPERTY_WIFI");
458 }
459 if (hasProperty(properties, PROPERTY_HIGH_DEF_AUDIO)) {
460 builder.append(" PROPERTY_HIGH_DEF_AUDIO");
461 }
462 if (hasProperty(properties, PROPERTY_EMERGENCY_CALLBACK_MODE)) {
Yorke Leebe2a4a22015-06-12 10:10:55 -0700463 builder.append(" PROPERTY_EMERGENCY_CALLBACK_MODE");
Andrew Lee2378ea72015-04-29 14:38:11 -0700464 }
Tyler Gunn876dbfb2016-03-14 15:18:07 -0700465 if (hasProperty(properties, PROPERTY_IS_EXTERNAL_CALL)) {
466 builder.append(" PROPERTY_IS_EXTERNAL_CALL");
467 }
Andrew Lee2378ea72015-04-29 14:38:11 -0700468 builder.append("]");
469 return builder.toString();
470 }
471
Sailesh Nepal1bef3392016-01-24 18:21:53 -0800472 /** {@hide} */
473 public String getTelecomCallId() {
474 return mTelecomCallId;
475 }
476
Andrew Lee2378ea72015-04-29 14:38:11 -0700477 /**
Ihab Awade63fadb2014-07-09 21:52:04 -0700478 * @return The handle (e.g., phone number) to which the {@code Call} is currently
479 * connected.
480 */
481 public Uri getHandle() {
482 return mHandle;
483 }
484
485 /**
486 * @return The presentation requirements for the handle. See
Tyler Gunnef9f6f92014-09-12 22:16:17 -0700487 * {@link TelecomManager} for valid values.
Ihab Awade63fadb2014-07-09 21:52:04 -0700488 */
489 public int getHandlePresentation() {
490 return mHandlePresentation;
491 }
492
493 /**
494 * @return The display name for the caller.
495 */
496 public String getCallerDisplayName() {
497 return mCallerDisplayName;
498 }
499
500 /**
501 * @return The presentation requirements for the caller display name. See
Tyler Gunnef9f6f92014-09-12 22:16:17 -0700502 * {@link TelecomManager} for valid values.
Ihab Awade63fadb2014-07-09 21:52:04 -0700503 */
504 public int getCallerDisplayNamePresentation() {
505 return mCallerDisplayNamePresentation;
506 }
507
508 /**
Evan Charlton6eb262c2014-07-19 18:18:19 -0700509 * @return The {@code PhoneAccountHandle} whereby the {@code Call} is currently being
510 * routed.
Ihab Awade63fadb2014-07-09 21:52:04 -0700511 */
Evan Charlton8c8a0622014-07-20 12:31:00 -0700512 public PhoneAccountHandle getAccountHandle() {
513 return mAccountHandle;
Ihab Awade63fadb2014-07-09 21:52:04 -0700514 }
515
516 /**
Ihab Awad5c9c86e2014-11-12 13:41:16 -0800517 * @return A bitmask of the capabilities of the {@code Call}, as defined by the various
518 * {@code CAPABILITY_*} constants in this class.
Ihab Awade63fadb2014-07-09 21:52:04 -0700519 */
Ihab Awad5d0410f2014-07-30 10:07:40 -0700520 public int getCallCapabilities() {
521 return mCallCapabilities;
Ihab Awade63fadb2014-07-09 21:52:04 -0700522 }
523
524 /**
Andrew Lee2378ea72015-04-29 14:38:11 -0700525 * @return A bitmask of the properties of the {@code Call}, as defined by the various
526 * {@code PROPERTY_*} constants in this class.
Andrew Lee223ad142014-08-27 16:33:08 -0700527 */
528 public int getCallProperties() {
529 return mCallProperties;
530 }
531
532 /**
Ihab Awade63fadb2014-07-09 21:52:04 -0700533 * @return For a {@link #STATE_DISCONNECTED} {@code Call}, the disconnect cause expressed
Nancy Chenf4cf77c2014-09-19 10:53:21 -0700534 * by {@link android.telecom.DisconnectCause}.
Ihab Awade63fadb2014-07-09 21:52:04 -0700535 */
Andrew Lee7f3d41f2014-09-11 17:33:16 -0700536 public DisconnectCause getDisconnectCause() {
537 return mDisconnectCause;
Ihab Awade63fadb2014-07-09 21:52:04 -0700538 }
539
540 /**
541 * @return The time the {@code Call} has been connected. This information is updated
542 * periodically, but user interfaces should not rely on this to display any "call time
543 * clock".
544 */
Jay Shrauner164a0ac2015-04-14 18:16:10 -0700545 public final long getConnectTimeMillis() {
Ihab Awade63fadb2014-07-09 21:52:04 -0700546 return mConnectTimeMillis;
547 }
548
549 /**
550 * @return Information about any calling gateway the {@code Call} may be using.
551 */
552 public GatewayInfo getGatewayInfo() {
553 return mGatewayInfo;
554 }
555
Andrew Lee7a341382014-07-15 17:05:08 -0700556 /**
Ihab Awad5d0410f2014-07-30 10:07:40 -0700557 * @return The video state of the {@code Call}.
Andrew Lee7a341382014-07-15 17:05:08 -0700558 */
559 public int getVideoState() {
560 return mVideoState;
561 }
562
Ihab Awad5d0410f2014-07-30 10:07:40 -0700563 /**
Tyler Gunnef9f6f92014-09-12 22:16:17 -0700564 * @return The current {@link android.telecom.StatusHints}, or {@code null} if none
Ihab Awad5d0410f2014-07-30 10:07:40 -0700565 * have been set.
Evan Charlton5b49ade2014-07-15 17:03:20 -0700566 */
567 public StatusHints getStatusHints() {
568 return mStatusHints;
569 }
570
Nancy Chen10798dc2014-08-08 14:00:25 -0700571 /**
Santos Cordon6b7f9552015-05-27 17:21:45 -0700572 * @return The extras associated with this call.
Nancy Chen10798dc2014-08-08 14:00:25 -0700573 */
574 public Bundle getExtras() {
575 return mExtras;
576 }
577
Santos Cordon6b7f9552015-05-27 17:21:45 -0700578 /**
579 * @return The extras used with the original intent to place this call.
580 */
581 public Bundle getIntentExtras() {
582 return mIntentExtras;
583 }
584
Ihab Awade63fadb2014-07-09 21:52:04 -0700585 @Override
586 public boolean equals(Object o) {
587 if (o instanceof Details) {
588 Details d = (Details) o;
589 return
590 Objects.equals(mHandle, d.mHandle) &&
591 Objects.equals(mHandlePresentation, d.mHandlePresentation) &&
592 Objects.equals(mCallerDisplayName, d.mCallerDisplayName) &&
593 Objects.equals(mCallerDisplayNamePresentation,
594 d.mCallerDisplayNamePresentation) &&
Evan Charlton8c8a0622014-07-20 12:31:00 -0700595 Objects.equals(mAccountHandle, d.mAccountHandle) &&
Ihab Awad5d0410f2014-07-30 10:07:40 -0700596 Objects.equals(mCallCapabilities, d.mCallCapabilities) &&
Andrew Lee223ad142014-08-27 16:33:08 -0700597 Objects.equals(mCallProperties, d.mCallProperties) &&
Andrew Lee7f3d41f2014-09-11 17:33:16 -0700598 Objects.equals(mDisconnectCause, d.mDisconnectCause) &&
Ihab Awade63fadb2014-07-09 21:52:04 -0700599 Objects.equals(mConnectTimeMillis, d.mConnectTimeMillis) &&
Andrew Lee85f5d422014-07-11 17:22:03 -0700600 Objects.equals(mGatewayInfo, d.mGatewayInfo) &&
Evan Charlton5b49ade2014-07-15 17:03:20 -0700601 Objects.equals(mVideoState, d.mVideoState) &&
Nancy Chen10798dc2014-08-08 14:00:25 -0700602 Objects.equals(mStatusHints, d.mStatusHints) &&
Tyler Gunn1e9bfc62015-08-19 11:18:58 -0700603 areBundlesEqual(mExtras, d.mExtras) &&
604 areBundlesEqual(mIntentExtras, d.mIntentExtras);
Ihab Awade63fadb2014-07-09 21:52:04 -0700605 }
606 return false;
607 }
608
609 @Override
610 public int hashCode() {
611 return
612 Objects.hashCode(mHandle) +
613 Objects.hashCode(mHandlePresentation) +
614 Objects.hashCode(mCallerDisplayName) +
615 Objects.hashCode(mCallerDisplayNamePresentation) +
Evan Charlton8c8a0622014-07-20 12:31:00 -0700616 Objects.hashCode(mAccountHandle) +
Ihab Awad5d0410f2014-07-30 10:07:40 -0700617 Objects.hashCode(mCallCapabilities) +
Andrew Lee223ad142014-08-27 16:33:08 -0700618 Objects.hashCode(mCallProperties) +
Andrew Lee7f3d41f2014-09-11 17:33:16 -0700619 Objects.hashCode(mDisconnectCause) +
Ihab Awade63fadb2014-07-09 21:52:04 -0700620 Objects.hashCode(mConnectTimeMillis) +
Andrew Lee85f5d422014-07-11 17:22:03 -0700621 Objects.hashCode(mGatewayInfo) +
Evan Charlton5b49ade2014-07-15 17:03:20 -0700622 Objects.hashCode(mVideoState) +
Nancy Chen10798dc2014-08-08 14:00:25 -0700623 Objects.hashCode(mStatusHints) +
Santos Cordon6b7f9552015-05-27 17:21:45 -0700624 Objects.hashCode(mExtras) +
625 Objects.hashCode(mIntentExtras);
Ihab Awade63fadb2014-07-09 21:52:04 -0700626 }
627
628 /** {@hide} */
629 public Details(
Sailesh Nepal1bef3392016-01-24 18:21:53 -0800630 String telecomCallId,
Ihab Awade63fadb2014-07-09 21:52:04 -0700631 Uri handle,
632 int handlePresentation,
633 String callerDisplayName,
634 int callerDisplayNamePresentation,
Evan Charlton8c8a0622014-07-20 12:31:00 -0700635 PhoneAccountHandle accountHandle,
Ihab Awade63fadb2014-07-09 21:52:04 -0700636 int capabilities,
Andrew Lee223ad142014-08-27 16:33:08 -0700637 int properties,
Andrew Lee7f3d41f2014-09-11 17:33:16 -0700638 DisconnectCause disconnectCause,
Ihab Awade63fadb2014-07-09 21:52:04 -0700639 long connectTimeMillis,
Andrew Lee85f5d422014-07-11 17:22:03 -0700640 GatewayInfo gatewayInfo,
Evan Charlton5b49ade2014-07-15 17:03:20 -0700641 int videoState,
Nancy Chen10798dc2014-08-08 14:00:25 -0700642 StatusHints statusHints,
Santos Cordon6b7f9552015-05-27 17:21:45 -0700643 Bundle extras,
644 Bundle intentExtras) {
Sailesh Nepal1bef3392016-01-24 18:21:53 -0800645 mTelecomCallId = telecomCallId;
Ihab Awade63fadb2014-07-09 21:52:04 -0700646 mHandle = handle;
647 mHandlePresentation = handlePresentation;
648 mCallerDisplayName = callerDisplayName;
649 mCallerDisplayNamePresentation = callerDisplayNamePresentation;
Evan Charlton8c8a0622014-07-20 12:31:00 -0700650 mAccountHandle = accountHandle;
Ihab Awad5d0410f2014-07-30 10:07:40 -0700651 mCallCapabilities = capabilities;
Andrew Lee223ad142014-08-27 16:33:08 -0700652 mCallProperties = properties;
Andrew Lee7f3d41f2014-09-11 17:33:16 -0700653 mDisconnectCause = disconnectCause;
Ihab Awade63fadb2014-07-09 21:52:04 -0700654 mConnectTimeMillis = connectTimeMillis;
655 mGatewayInfo = gatewayInfo;
Andrew Lee85f5d422014-07-11 17:22:03 -0700656 mVideoState = videoState;
Evan Charlton5b49ade2014-07-15 17:03:20 -0700657 mStatusHints = statusHints;
Nancy Chen10798dc2014-08-08 14:00:25 -0700658 mExtras = extras;
Santos Cordon6b7f9552015-05-27 17:21:45 -0700659 mIntentExtras = intentExtras;
Ihab Awade63fadb2014-07-09 21:52:04 -0700660 }
Sailesh Nepal1bef3392016-01-24 18:21:53 -0800661
662 /** {@hide} */
663 public static Details createFromParcelableCall(ParcelableCall parcelableCall) {
664 return new Details(
665 parcelableCall.getId(),
666 parcelableCall.getHandle(),
667 parcelableCall.getHandlePresentation(),
668 parcelableCall.getCallerDisplayName(),
669 parcelableCall.getCallerDisplayNamePresentation(),
670 parcelableCall.getAccountHandle(),
671 parcelableCall.getCapabilities(),
672 parcelableCall.getProperties(),
673 parcelableCall.getDisconnectCause(),
674 parcelableCall.getConnectTimeMillis(),
675 parcelableCall.getGatewayInfo(),
676 parcelableCall.getVideoState(),
677 parcelableCall.getStatusHints(),
678 parcelableCall.getExtras(),
679 parcelableCall.getIntentExtras());
680 }
Santos Cordon3c20d632016-02-25 16:12:35 -0800681
682 @Override
683 public String toString() {
684 StringBuilder sb = new StringBuilder();
685 sb.append("[pa: ");
686 sb.append(mAccountHandle);
687 sb.append(", hdl: ");
688 sb.append(Log.pii(mHandle));
689 sb.append(", caps: ");
690 sb.append(capabilitiesToString(mCallCapabilities));
691 sb.append(", props: ");
Tyler Gunn720c6642016-03-22 09:02:47 -0700692 sb.append(propertiesToString(mCallProperties));
Santos Cordon3c20d632016-02-25 16:12:35 -0800693 sb.append("]");
694 return sb.toString();
695 }
Ihab Awade63fadb2014-07-09 21:52:04 -0700696 }
697
Andrew Leeda80c872015-04-15 14:09:50 -0700698 public static abstract class Callback {
Ihab Awade63fadb2014-07-09 21:52:04 -0700699 /**
700 * Invoked when the state of this {@code Call} has changed. See {@link #getState()}.
701 *
Ihab Awade63fadb2014-07-09 21:52:04 -0700702 * @param call The {@code Call} invoking this method.
703 * @param state The new state of the {@code Call}.
704 */
705 public void onStateChanged(Call call, int state) {}
706
707 /**
708 * Invoked when the parent of this {@code Call} has changed. See {@link #getParent()}.
709 *
710 * @param call The {@code Call} invoking this method.
711 * @param parent The new parent of the {@code Call}.
712 */
713 public void onParentChanged(Call call, Call parent) {}
714
715 /**
716 * Invoked when the children of this {@code Call} have changed. See {@link #getChildren()}.
717 *
718 * @param call The {@code Call} invoking this method.
719 * @param children The new children of the {@code Call}.
720 */
721 public void onChildrenChanged(Call call, List<Call> children) {}
722
723 /**
724 * Invoked when the details of this {@code Call} have changed. See {@link #getDetails()}.
725 *
726 * @param call The {@code Call} invoking this method.
727 * @param details A {@code Details} object describing the {@code Call}.
728 */
729 public void onDetailsChanged(Call call, Details details) {}
730
731 /**
732 * Invoked when the text messages that can be used as responses to the incoming
733 * {@code Call} are loaded from the relevant database.
734 * See {@link #getCannedTextResponses()}.
735 *
736 * @param call The {@code Call} invoking this method.
737 * @param cannedTextResponses The text messages useable as responses.
738 */
739 public void onCannedTextResponsesLoaded(Call call, List<String> cannedTextResponses) {}
740
741 /**
Ihab Awade63fadb2014-07-09 21:52:04 -0700742 * Invoked when the post-dial sequence in the outgoing {@code Call} has reached a pause
743 * character. This causes the post-dial signals to stop pending user confirmation. An
744 * implementation should present this choice to the user and invoke
745 * {@link #postDialContinue(boolean)} when the user makes the choice.
746 *
747 * @param call The {@code Call} invoking this method.
748 * @param remainingPostDialSequence The post-dial characters that remain to be sent.
749 */
750 public void onPostDialWait(Call call, String remainingPostDialSequence) {}
751
752 /**
Andrew Lee50aca232014-07-22 16:41:54 -0700753 * Invoked when the {@code Call.VideoCall} of the {@code Call} has changed.
Ihab Awade63fadb2014-07-09 21:52:04 -0700754 *
755 * @param call The {@code Call} invoking this method.
Andrew Lee50aca232014-07-22 16:41:54 -0700756 * @param videoCall The {@code Call.VideoCall} associated with the {@code Call}.
Ihab Awade63fadb2014-07-09 21:52:04 -0700757 */
Andrew Lee50aca232014-07-22 16:41:54 -0700758 public void onVideoCallChanged(Call call, InCallService.VideoCall videoCall) {}
Ihab Awade63fadb2014-07-09 21:52:04 -0700759
760 /**
761 * Invoked when the {@code Call} is destroyed. Clients should refrain from cleaning
762 * up their UI for the {@code Call} in response to state transitions. Specifically,
763 * clients should not assume that a {@link #onStateChanged(Call, int)} with a state of
764 * {@link #STATE_DISCONNECTED} is the final notification the {@code Call} will send. Rather,
765 * clients should wait for this method to be invoked.
766 *
767 * @param call The {@code Call} being destroyed.
768 */
769 public void onCallDestroyed(Call call) {}
Santos Cordon7c7bc7f2014-07-28 18:15:48 -0700770
771 /**
772 * Invoked upon changes to the set of {@code Call}s with which this {@code Call} can be
773 * conferenced.
774 *
775 * @param call The {@code Call} being updated.
776 * @param conferenceableCalls The {@code Call}s with which this {@code Call} can be
777 * conferenced.
778 */
779 public void onConferenceableCallsChanged(Call call, List<Call> conferenceableCalls) {}
Tyler Gunn876dbfb2016-03-14 15:18:07 -0700780
781 /**
782 * Invoked when a call receives an event from its associated {@link Connection}.
783 * <p>
784 * See {@link Connection#sendConnectionEvent(String, Bundle)}.
785 *
786 * @param call The {@code Call} receiving the event.
787 * @param event The event.
788 * @param extras Extras associated with the connection event.
Tyler Gunn1bf206b2016-04-15 11:28:44 -0700789 * @hide
Tyler Gunn876dbfb2016-03-14 15:18:07 -0700790 */
791 public void onConnectionEvent(Call call, String event, Bundle extras) {}
Ihab Awade63fadb2014-07-09 21:52:04 -0700792 }
793
Andrew Leeda80c872015-04-15 14:09:50 -0700794 /**
795 * @deprecated Use {@code Call.Callback} instead.
796 * @hide
797 */
798 @Deprecated
799 @SystemApi
800 public static abstract class Listener extends Callback { }
801
Ihab Awade63fadb2014-07-09 21:52:04 -0700802 private final Phone mPhone;
Tyler Gunnef9f6f92014-09-12 22:16:17 -0700803 private final String mTelecomCallId;
Ihab Awade63fadb2014-07-09 21:52:04 -0700804 private final InCallAdapter mInCallAdapter;
Santos Cordon823fd3c2014-08-07 18:35:18 -0700805 private final List<String> mChildrenIds = new ArrayList<>();
Ihab Awade63fadb2014-07-09 21:52:04 -0700806 private final List<Call> mChildren = new ArrayList<>();
807 private final List<Call> mUnmodifiableChildren = Collections.unmodifiableList(mChildren);
Andrew Lee011728f2015-04-23 15:47:06 -0700808 private final List<CallbackRecord<Callback>> mCallbackRecords = new CopyOnWriteArrayList<>();
Santos Cordon7c7bc7f2014-07-28 18:15:48 -0700809 private final List<Call> mConferenceableCalls = new ArrayList<>();
810 private final List<Call> mUnmodifiableConferenceableCalls =
811 Collections.unmodifiableList(mConferenceableCalls);
812
Santos Cordon823fd3c2014-08-07 18:35:18 -0700813 private boolean mChildrenCached;
814 private String mParentId = null;
Santos Cordon7c7bc7f2014-07-28 18:15:48 -0700815 private int mState;
Ihab Awade63fadb2014-07-09 21:52:04 -0700816 private List<String> mCannedTextResponses = null;
817 private String mRemainingPostDialSequence;
Tyler Gunn584ba6c2015-12-08 10:53:41 -0800818 private VideoCallImpl mVideoCallImpl;
Ihab Awade63fadb2014-07-09 21:52:04 -0700819 private Details mDetails;
Tyler Gunndee56a82016-03-23 16:06:34 -0700820 private Bundle mExtras;
Ihab Awade63fadb2014-07-09 21:52:04 -0700821
822 /**
823 * Obtains the post-dial sequence remaining to be emitted by this {@code Call}, if any.
824 *
825 * @return The remaining post-dial sequence, or {@code null} if there is no post-dial sequence
826 * remaining or this {@code Call} is not in a post-dial state.
827 */
828 public String getRemainingPostDialSequence() {
829 return mRemainingPostDialSequence;
830 }
831
832 /**
833 * Instructs this {@link #STATE_RINGING} {@code Call} to answer.
Andrew Lee8da4c3c2014-07-16 10:11:42 -0700834 * @param videoState The video state in which to answer the call.
Ihab Awade63fadb2014-07-09 21:52:04 -0700835 */
Andrew Lee8da4c3c2014-07-16 10:11:42 -0700836 public void answer(int videoState) {
Tyler Gunnef9f6f92014-09-12 22:16:17 -0700837 mInCallAdapter.answerCall(mTelecomCallId, videoState);
Ihab Awade63fadb2014-07-09 21:52:04 -0700838 }
839
840 /**
841 * Instructs this {@link #STATE_RINGING} {@code Call} to reject.
842 *
843 * @param rejectWithMessage Whether to reject with a text message.
844 * @param textMessage An optional text message with which to respond.
845 */
846 public void reject(boolean rejectWithMessage, String textMessage) {
Tyler Gunnef9f6f92014-09-12 22:16:17 -0700847 mInCallAdapter.rejectCall(mTelecomCallId, rejectWithMessage, textMessage);
Ihab Awade63fadb2014-07-09 21:52:04 -0700848 }
849
850 /**
851 * Instructs this {@code Call} to disconnect.
852 */
853 public void disconnect() {
Tyler Gunnef9f6f92014-09-12 22:16:17 -0700854 mInCallAdapter.disconnectCall(mTelecomCallId);
Ihab Awade63fadb2014-07-09 21:52:04 -0700855 }
856
857 /**
858 * Instructs this {@code Call} to go on hold.
859 */
860 public void hold() {
Tyler Gunnef9f6f92014-09-12 22:16:17 -0700861 mInCallAdapter.holdCall(mTelecomCallId);
Ihab Awade63fadb2014-07-09 21:52:04 -0700862 }
863
864 /**
865 * Instructs this {@link #STATE_HOLDING} call to release from hold.
866 */
867 public void unhold() {
Tyler Gunnef9f6f92014-09-12 22:16:17 -0700868 mInCallAdapter.unholdCall(mTelecomCallId);
Ihab Awade63fadb2014-07-09 21:52:04 -0700869 }
870
871 /**
872 * Instructs this {@code Call} to play a dual-tone multi-frequency signaling (DTMF) tone.
873 *
874 * Any other currently playing DTMF tone in the specified call is immediately stopped.
875 *
876 * @param digit A character representing the DTMF digit for which to play the tone. This
877 * value must be one of {@code '0'} through {@code '9'}, {@code '*'} or {@code '#'}.
878 */
879 public void playDtmfTone(char digit) {
Tyler Gunnef9f6f92014-09-12 22:16:17 -0700880 mInCallAdapter.playDtmfTone(mTelecomCallId, digit);
Ihab Awade63fadb2014-07-09 21:52:04 -0700881 }
882
883 /**
884 * Instructs this {@code Call} to stop any dual-tone multi-frequency signaling (DTMF) tone
885 * currently playing.
886 *
887 * DTMF tones are played by calling {@link #playDtmfTone(char)}. If no DTMF tone is
888 * currently playing, this method will do nothing.
889 */
890 public void stopDtmfTone() {
Tyler Gunnef9f6f92014-09-12 22:16:17 -0700891 mInCallAdapter.stopDtmfTone(mTelecomCallId);
Ihab Awade63fadb2014-07-09 21:52:04 -0700892 }
893
894 /**
895 * Instructs this {@code Call} to continue playing a post-dial DTMF string.
896 *
897 * A post-dial DTMF string is a string of digits entered after a phone number, when dialed,
898 * that are immediately sent as DTMF tones to the recipient as soon as the connection is made.
Ihab Awade63fadb2014-07-09 21:52:04 -0700899 *
Tyler Gunnef9f6f92014-09-12 22:16:17 -0700900 * If the DTMF string contains a {@link TelecomManager#DTMF_CHARACTER_PAUSE} symbol, this
Ihab Awade63fadb2014-07-09 21:52:04 -0700901 * {@code Call} will temporarily pause playing the tones for a pre-defined period of time.
902 *
Tyler Gunnef9f6f92014-09-12 22:16:17 -0700903 * If the DTMF string contains a {@link TelecomManager#DTMF_CHARACTER_WAIT} symbol, this
Andrew Leeda80c872015-04-15 14:09:50 -0700904 * {@code Call} will pause playing the tones and notify callbacks via
905 * {@link Callback#onPostDialWait(Call, String)}. At this point, the in-call app
Ihab Awade63fadb2014-07-09 21:52:04 -0700906 * should display to the user an indication of this state and an affordance to continue
907 * the postdial sequence. When the user decides to continue the postdial sequence, the in-call
908 * app should invoke the {@link #postDialContinue(boolean)} method.
909 *
910 * @param proceed Whether or not to continue with the post-dial sequence.
911 */
912 public void postDialContinue(boolean proceed) {
Tyler Gunnef9f6f92014-09-12 22:16:17 -0700913 mInCallAdapter.postDialContinue(mTelecomCallId, proceed);
Ihab Awade63fadb2014-07-09 21:52:04 -0700914 }
915
916 /**
Evan Charlton8c8a0622014-07-20 12:31:00 -0700917 * Notifies this {@code Call} that an account has been selected and to proceed with placing
Nancy Chen36c62f32014-10-21 18:36:39 -0700918 * an outgoing call. Optionally sets this account as the default account.
Nancy Chen5da0fd52014-07-08 14:16:17 -0700919 */
Nancy Chen36c62f32014-10-21 18:36:39 -0700920 public void phoneAccountSelected(PhoneAccountHandle accountHandle, boolean setDefault) {
921 mInCallAdapter.phoneAccountSelected(mTelecomCallId, accountHandle, setDefault);
Nancy Chen5da0fd52014-07-08 14:16:17 -0700922
923 }
924
925 /**
Ihab Awade63fadb2014-07-09 21:52:04 -0700926 * Instructs this {@code Call} to enter a conference.
Santos Cordon7c7bc7f2014-07-28 18:15:48 -0700927 *
928 * @param callToConferenceWith The other call with which to conference.
Ihab Awade63fadb2014-07-09 21:52:04 -0700929 */
Santos Cordon7c7bc7f2014-07-28 18:15:48 -0700930 public void conference(Call callToConferenceWith) {
931 if (callToConferenceWith != null) {
Tyler Gunnef9f6f92014-09-12 22:16:17 -0700932 mInCallAdapter.conference(mTelecomCallId, callToConferenceWith.mTelecomCallId);
Santos Cordon7c7bc7f2014-07-28 18:15:48 -0700933 }
Ihab Awade63fadb2014-07-09 21:52:04 -0700934 }
935
936 /**
937 * Instructs this {@code Call} to split from any conference call with which it may be
938 * connected.
939 */
940 public void splitFromConference() {
Tyler Gunnef9f6f92014-09-12 22:16:17 -0700941 mInCallAdapter.splitFromConference(mTelecomCallId);
Ihab Awade63fadb2014-07-09 21:52:04 -0700942 }
943
944 /**
Ihab Awad5c9c86e2014-11-12 13:41:16 -0800945 * Merges the calls within this conference. See {@link Details#CAPABILITY_MERGE_CONFERENCE}.
Santos Cordona4868042014-09-04 17:39:22 -0700946 */
947 public void mergeConference() {
Tyler Gunnef9f6f92014-09-12 22:16:17 -0700948 mInCallAdapter.mergeConference(mTelecomCallId);
Santos Cordona4868042014-09-04 17:39:22 -0700949 }
950
951 /**
Ihab Awad5c9c86e2014-11-12 13:41:16 -0800952 * Swaps the calls within this conference. See {@link Details#CAPABILITY_SWAP_CONFERENCE}.
Santos Cordona4868042014-09-04 17:39:22 -0700953 */
954 public void swapConference() {
Tyler Gunnef9f6f92014-09-12 22:16:17 -0700955 mInCallAdapter.swapConference(mTelecomCallId);
Santos Cordona4868042014-09-04 17:39:22 -0700956 }
957
958 /**
Tyler Gunn876dbfb2016-03-14 15:18:07 -0700959 * Initiates a request to the {@link ConnectionService} to pull an external call to the local
960 * device.
961 * <p>
962 * Calls to this method are ignored if the call does not have the
963 * {@link Call.Details#PROPERTY_IS_EXTERNAL_CALL} property set.
964 * <p>
965 * An {@link InCallService} will only see calls which support this method if it has the
966 * {@link TelecomManager#METADATA_INCLUDE_EXTERNAL_CALLS} metadata set to {@code true}
967 * in its manifest.
Tyler Gunn1bf206b2016-04-15 11:28:44 -0700968 * @hide
Tyler Gunn876dbfb2016-03-14 15:18:07 -0700969 */
970 public void pullExternalCall() {
971 // If this isn't an external call, ignore the request.
972 if (!mDetails.hasProperty(Details.PROPERTY_IS_EXTERNAL_CALL)) {
973 return;
974 }
975
976 mInCallAdapter.pullExternalCall(mTelecomCallId);
977 }
978
979 /**
980 * Sends a {@code Call} event from this {@code Call} to the associated {@link Connection} in
981 * the {@link ConnectionService}.
982 * <p>
983 * Events are exposed to {@link ConnectionService} implementations via
984 * {@link android.telecom.Connection#onCallEvent(String, Bundle)}.
985 * <p>
986 * No assumptions should be made as to how a {@link ConnectionService} will handle these events.
987 * Events should be fully qualified (e.g., com.example.event.MY_EVENT) to avoid conflicts.
988 *
989 * @param event The connection event.
990 * @param extras Bundle containing extra information associated with the event.
Tyler Gunn1bf206b2016-04-15 11:28:44 -0700991 * @hide
Tyler Gunn876dbfb2016-03-14 15:18:07 -0700992 */
993 public void sendCallEvent(String event, Bundle extras) {
994 mInCallAdapter.sendCallEvent(mTelecomCallId, event, extras);
995 }
996
997 /**
Tyler Gunndee56a82016-03-23 16:06:34 -0700998 * Adds some extras to this {@link Call}. Existing keys are replaced and new ones are
999 * added.
1000 * <p>
1001 * No assumptions should be made as to how an In-Call UI or service will handle these
1002 * extras. Keys should be fully qualified (e.g., com.example.MY_EXTRA) to avoid conflicts.
1003 *
1004 * @param extras The extras to add.
Tyler Gunn1bf206b2016-04-15 11:28:44 -07001005 * @hide
Tyler Gunndee56a82016-03-23 16:06:34 -07001006 */
1007 public final void putExtras(Bundle extras) {
1008 if (extras == null) {
1009 return;
1010 }
1011
1012 if (mExtras == null) {
1013 mExtras = new Bundle();
1014 }
1015 mExtras.putAll(extras);
1016 mInCallAdapter.putExtras(mTelecomCallId, extras);
1017 }
1018
1019 /**
1020 * Adds a boolean extra to this {@link Call}.
1021 *
1022 * @param key The extra key.
1023 * @param value The value.
1024 * @hide
1025 */
1026 public final void putExtra(String key, boolean value) {
1027 if (mExtras == null) {
1028 mExtras = new Bundle();
1029 }
1030 mExtras.putBoolean(key, value);
1031 mInCallAdapter.putExtra(mTelecomCallId, key, value);
1032 }
1033
1034 /**
1035 * Adds an integer extra to this {@code Connection}.
1036 *
1037 * @param key The extra key.
1038 * @param value The value.
1039 * @hide
1040 */
1041 public final void putExtra(String key, int value) {
1042 if (mExtras == null) {
1043 mExtras = new Bundle();
1044 }
1045 mExtras.putInt(key, value);
1046 mInCallAdapter.putExtra(mTelecomCallId, key, value);
1047 }
1048
1049 /**
1050 * Adds a string extra to this {@code Connection}.
1051 *
1052 * @param key The extra key.
1053 * @param value The value.
1054 * @hide
1055 */
1056 public final void putExtra(String key, String value) {
1057 if (mExtras == null) {
1058 mExtras = new Bundle();
1059 }
1060 mExtras.putString(key, value);
1061 mInCallAdapter.putExtra(mTelecomCallId, key, value);
1062 }
1063
1064 /**
1065 * Removes extras from this {@code Connection}.
1066 *
1067 * @param keys The keys of the extras to remove.
Tyler Gunn1bf206b2016-04-15 11:28:44 -07001068 * @hide
Tyler Gunndee56a82016-03-23 16:06:34 -07001069 */
1070 public final void removeExtras(List<String> keys) {
1071 if (mExtras != null) {
1072 for (String key : keys) {
1073 mExtras.remove(key);
1074 }
1075 if (mExtras.size() == 0) {
1076 mExtras = null;
1077 }
1078 }
1079 mInCallAdapter.removeExtras(mTelecomCallId, keys);
1080 }
1081
1082 /**
Ihab Awade63fadb2014-07-09 21:52:04 -07001083 * Obtains the parent of this {@code Call} in a conference, if any.
1084 *
1085 * @return The parent {@code Call}, or {@code null} if this {@code Call} is not a
1086 * child of any conference {@code Call}s.
1087 */
1088 public Call getParent() {
Santos Cordon823fd3c2014-08-07 18:35:18 -07001089 if (mParentId != null) {
Tyler Gunnef9f6f92014-09-12 22:16:17 -07001090 return mPhone.internalGetCallByTelecomId(mParentId);
Santos Cordon823fd3c2014-08-07 18:35:18 -07001091 }
1092 return null;
Ihab Awade63fadb2014-07-09 21:52:04 -07001093 }
1094
1095 /**
1096 * Obtains the children of this conference {@code Call}, if any.
1097 *
1098 * @return The children of this {@code Call} if this {@code Call} is a conference, or an empty
1099 * {@code List} otherwise.
1100 */
1101 public List<Call> getChildren() {
Santos Cordon823fd3c2014-08-07 18:35:18 -07001102 if (!mChildrenCached) {
1103 mChildrenCached = true;
1104 mChildren.clear();
1105
1106 for(String id : mChildrenIds) {
Tyler Gunnef9f6f92014-09-12 22:16:17 -07001107 Call call = mPhone.internalGetCallByTelecomId(id);
Santos Cordon823fd3c2014-08-07 18:35:18 -07001108 if (call == null) {
1109 // At least one child was still not found, so do not save true for "cached"
1110 mChildrenCached = false;
1111 } else {
1112 mChildren.add(call);
1113 }
1114 }
1115 }
1116
Ihab Awade63fadb2014-07-09 21:52:04 -07001117 return mUnmodifiableChildren;
1118 }
1119
1120 /**
Santos Cordon7c7bc7f2014-07-28 18:15:48 -07001121 * Returns the list of {@code Call}s with which this {@code Call} is allowed to conference.
1122 *
1123 * @return The list of conferenceable {@code Call}s.
1124 */
1125 public List<Call> getConferenceableCalls() {
1126 return mUnmodifiableConferenceableCalls;
1127 }
1128
1129 /**
Ihab Awade63fadb2014-07-09 21:52:04 -07001130 * Obtains the state of this {@code Call}.
1131 *
1132 * @return A state value, chosen from the {@code STATE_*} constants.
1133 */
1134 public int getState() {
1135 return mState;
1136 }
1137
1138 /**
1139 * Obtains a list of canned, pre-configured message responses to present to the user as
1140 * ways of rejecting this {@code Call} using via a text message.
1141 *
1142 * @see #reject(boolean, String)
1143 *
1144 * @return A list of canned text message responses.
1145 */
1146 public List<String> getCannedTextResponses() {
1147 return mCannedTextResponses;
1148 }
1149
1150 /**
1151 * Obtains an object that can be used to display video from this {@code Call}.
1152 *
Andrew Lee50aca232014-07-22 16:41:54 -07001153 * @return An {@code Call.VideoCall}.
Ihab Awade63fadb2014-07-09 21:52:04 -07001154 */
Andrew Lee50aca232014-07-22 16:41:54 -07001155 public InCallService.VideoCall getVideoCall() {
Tyler Gunn584ba6c2015-12-08 10:53:41 -08001156 return mVideoCallImpl;
Ihab Awade63fadb2014-07-09 21:52:04 -07001157 }
1158
1159 /**
1160 * Obtains an object containing call details.
1161 *
1162 * @return A {@link Details} object. Depending on the state of the {@code Call}, the
1163 * result may be {@code null}.
1164 */
1165 public Details getDetails() {
1166 return mDetails;
1167 }
1168
1169 /**
Andrew Leeda80c872015-04-15 14:09:50 -07001170 * Registers a callback to this {@code Call}.
1171 *
1172 * @param callback A {@code Callback}.
1173 */
1174 public void registerCallback(Callback callback) {
Andrew Lee011728f2015-04-23 15:47:06 -07001175 registerCallback(callback, new Handler());
1176 }
1177
1178 /**
1179 * Registers a callback to this {@code Call}.
1180 *
1181 * @param callback A {@code Callback}.
1182 * @param handler A handler which command and status changes will be delivered to.
1183 */
1184 public void registerCallback(Callback callback, Handler handler) {
1185 unregisterCallback(callback);
Roshan Pius1ca62072015-07-07 17:34:51 -07001186 // Don't allow new callback registration if the call is already being destroyed.
1187 if (callback != null && handler != null && mState != STATE_DISCONNECTED) {
Andrew Lee011728f2015-04-23 15:47:06 -07001188 mCallbackRecords.add(new CallbackRecord<Callback>(callback, handler));
1189 }
Andrew Leeda80c872015-04-15 14:09:50 -07001190 }
1191
1192 /**
1193 * Unregisters a callback from this {@code Call}.
1194 *
1195 * @param callback A {@code Callback}.
1196 */
1197 public void unregisterCallback(Callback callback) {
Roshan Pius1ca62072015-07-07 17:34:51 -07001198 // Don't allow callback deregistration if the call is already being destroyed.
1199 if (callback != null && mState != STATE_DISCONNECTED) {
Andrew Lee011728f2015-04-23 15:47:06 -07001200 for (CallbackRecord<Callback> record : mCallbackRecords) {
1201 if (record.getCallback() == callback) {
1202 mCallbackRecords.remove(record);
1203 break;
1204 }
1205 }
Andrew Leeda80c872015-04-15 14:09:50 -07001206 }
1207 }
1208
Santos Cordon3c20d632016-02-25 16:12:35 -08001209 @Override
1210 public String toString() {
1211 return new StringBuilder().
1212 append("Call [id: ").
1213 append(mTelecomCallId).
1214 append(", state: ").
1215 append(stateToString(mState)).
1216 append(", details: ").
1217 append(mDetails).
1218 append("]").toString();
1219 }
1220
1221 /**
1222 * @param state An integer value of a {@code STATE_*} constant.
1223 * @return A string representation of the value.
1224 */
1225 private static String stateToString(int state) {
1226 switch (state) {
1227 case STATE_NEW:
1228 return "NEW";
1229 case STATE_RINGING:
1230 return "RINGING";
1231 case STATE_DIALING:
1232 return "DIALING";
1233 case STATE_ACTIVE:
1234 return "ACTIVE";
1235 case STATE_HOLDING:
1236 return "HOLDING";
1237 case STATE_DISCONNECTED:
1238 return "DISCONNECTED";
1239 case STATE_CONNECTING:
1240 return "CONNECTING";
1241 case STATE_DISCONNECTING:
1242 return "DISCONNECTING";
1243 case STATE_SELECT_PHONE_ACCOUNT:
1244 return "SELECT_PHONE_ACCOUNT";
1245 default:
1246 Log.w(Call.class, "Unknown state %d", state);
1247 return "UNKNOWN";
1248 }
1249 }
1250
Andrew Leeda80c872015-04-15 14:09:50 -07001251 /**
Ihab Awade63fadb2014-07-09 21:52:04 -07001252 * Adds a listener to this {@code Call}.
1253 *
1254 * @param listener A {@code Listener}.
Andrew Leeda80c872015-04-15 14:09:50 -07001255 * @deprecated Use {@link #registerCallback} instead.
1256 * @hide
Ihab Awade63fadb2014-07-09 21:52:04 -07001257 */
Andrew Leeda80c872015-04-15 14:09:50 -07001258 @Deprecated
1259 @SystemApi
Ihab Awade63fadb2014-07-09 21:52:04 -07001260 public void addListener(Listener listener) {
Andrew Leeda80c872015-04-15 14:09:50 -07001261 registerCallback(listener);
Ihab Awade63fadb2014-07-09 21:52:04 -07001262 }
1263
1264 /**
1265 * Removes a listener from this {@code Call}.
1266 *
1267 * @param listener A {@code Listener}.
Andrew Leeda80c872015-04-15 14:09:50 -07001268 * @deprecated Use {@link #unregisterCallback} instead.
1269 * @hide
Ihab Awade63fadb2014-07-09 21:52:04 -07001270 */
Andrew Leeda80c872015-04-15 14:09:50 -07001271 @Deprecated
1272 @SystemApi
Ihab Awade63fadb2014-07-09 21:52:04 -07001273 public void removeListener(Listener listener) {
Andrew Leeda80c872015-04-15 14:09:50 -07001274 unregisterCallback(listener);
Ihab Awade63fadb2014-07-09 21:52:04 -07001275 }
1276
1277 /** {@hide} */
Tyler Gunnef9f6f92014-09-12 22:16:17 -07001278 Call(Phone phone, String telecomCallId, InCallAdapter inCallAdapter) {
Ihab Awade63fadb2014-07-09 21:52:04 -07001279 mPhone = phone;
Tyler Gunnef9f6f92014-09-12 22:16:17 -07001280 mTelecomCallId = telecomCallId;
Ihab Awade63fadb2014-07-09 21:52:04 -07001281 mInCallAdapter = inCallAdapter;
1282 mState = STATE_NEW;
1283 }
1284
1285 /** {@hide} */
Shriram Ganeshddf570e2015-05-31 09:18:48 -07001286 Call(Phone phone, String telecomCallId, InCallAdapter inCallAdapter, int state) {
1287 mPhone = phone;
1288 mTelecomCallId = telecomCallId;
1289 mInCallAdapter = inCallAdapter;
1290 mState = state;
1291 }
1292
1293 /** {@hide} */
Ihab Awade63fadb2014-07-09 21:52:04 -07001294 final String internalGetCallId() {
Tyler Gunnef9f6f92014-09-12 22:16:17 -07001295 return mTelecomCallId;
Ihab Awade63fadb2014-07-09 21:52:04 -07001296 }
1297
1298 /** {@hide} */
Santos Cordon7c7bc7f2014-07-28 18:15:48 -07001299 final void internalUpdate(ParcelableCall parcelableCall, Map<String, Call> callIdMap) {
Ihab Awade63fadb2014-07-09 21:52:04 -07001300 // First, we update the internal state as far as possible before firing any updates.
Sailesh Nepal1bef3392016-01-24 18:21:53 -08001301 Details details = Details.createFromParcelableCall(parcelableCall);
Ihab Awade63fadb2014-07-09 21:52:04 -07001302 boolean detailsChanged = !Objects.equals(mDetails, details);
1303 if (detailsChanged) {
1304 mDetails = details;
1305 }
1306
1307 boolean cannedTextResponsesChanged = false;
Santos Cordon88b771d2014-07-19 13:10:40 -07001308 if (mCannedTextResponses == null && parcelableCall.getCannedSmsResponses() != null
1309 && !parcelableCall.getCannedSmsResponses().isEmpty()) {
1310 mCannedTextResponses =
1311 Collections.unmodifiableList(parcelableCall.getCannedSmsResponses());
Yorke Leee886f632015-08-04 13:43:31 -07001312 cannedTextResponsesChanged = true;
Ihab Awade63fadb2014-07-09 21:52:04 -07001313 }
1314
Tyler Gunn584ba6c2015-12-08 10:53:41 -08001315 VideoCallImpl newVideoCallImpl = parcelableCall.getVideoCallImpl();
Tyler Gunn75958422015-04-15 14:23:42 -07001316 boolean videoCallChanged = parcelableCall.isVideoCallProviderChanged() &&
Tyler Gunn584ba6c2015-12-08 10:53:41 -08001317 !Objects.equals(mVideoCallImpl, newVideoCallImpl);
Andrew Lee50aca232014-07-22 16:41:54 -07001318 if (videoCallChanged) {
Tyler Gunn584ba6c2015-12-08 10:53:41 -08001319 mVideoCallImpl = newVideoCallImpl;
1320 }
1321 if (mVideoCallImpl != null) {
1322 mVideoCallImpl.setVideoState(getDetails().getVideoState());
Ihab Awade63fadb2014-07-09 21:52:04 -07001323 }
1324
Santos Cordone3c507b2015-04-23 14:44:19 -07001325 int state = parcelableCall.getState();
Ihab Awade63fadb2014-07-09 21:52:04 -07001326 boolean stateChanged = mState != state;
1327 if (stateChanged) {
1328 mState = state;
1329 }
1330
Santos Cordon823fd3c2014-08-07 18:35:18 -07001331 String parentId = parcelableCall.getParentCallId();
1332 boolean parentChanged = !Objects.equals(mParentId, parentId);
1333 if (parentChanged) {
1334 mParentId = parentId;
Ihab Awade63fadb2014-07-09 21:52:04 -07001335 }
1336
Santos Cordon823fd3c2014-08-07 18:35:18 -07001337 List<String> childCallIds = parcelableCall.getChildCallIds();
1338 boolean childrenChanged = !Objects.equals(childCallIds, mChildrenIds);
1339 if (childrenChanged) {
1340 mChildrenIds.clear();
1341 mChildrenIds.addAll(parcelableCall.getChildCallIds());
1342 mChildrenCached = false;
Ihab Awade63fadb2014-07-09 21:52:04 -07001343 }
1344
Santos Cordon7c7bc7f2014-07-28 18:15:48 -07001345 List<String> conferenceableCallIds = parcelableCall.getConferenceableCallIds();
1346 List<Call> conferenceableCalls = new ArrayList<Call>(conferenceableCallIds.size());
1347 for (String otherId : conferenceableCallIds) {
1348 if (callIdMap.containsKey(otherId)) {
1349 conferenceableCalls.add(callIdMap.get(otherId));
1350 }
1351 }
1352
1353 if (!Objects.equals(mConferenceableCalls, conferenceableCalls)) {
1354 mConferenceableCalls.clear();
1355 mConferenceableCalls.addAll(conferenceableCalls);
1356 fireConferenceableCallsChanged();
1357 }
1358
Ihab Awade63fadb2014-07-09 21:52:04 -07001359 // Now we fire updates, ensuring that any client who listens to any of these notifications
1360 // gets the most up-to-date state.
1361
1362 if (stateChanged) {
1363 fireStateChanged(mState);
1364 }
1365 if (detailsChanged) {
1366 fireDetailsChanged(mDetails);
1367 }
1368 if (cannedTextResponsesChanged) {
1369 fireCannedTextResponsesLoaded(mCannedTextResponses);
1370 }
Andrew Lee50aca232014-07-22 16:41:54 -07001371 if (videoCallChanged) {
Tyler Gunn584ba6c2015-12-08 10:53:41 -08001372 fireVideoCallChanged(mVideoCallImpl);
Ihab Awade63fadb2014-07-09 21:52:04 -07001373 }
Santos Cordon823fd3c2014-08-07 18:35:18 -07001374 if (parentChanged) {
1375 fireParentChanged(getParent());
1376 }
1377 if (childrenChanged) {
1378 fireChildrenChanged(getChildren());
1379 }
Ihab Awade63fadb2014-07-09 21:52:04 -07001380
1381 // If we have transitioned to DISCONNECTED, that means we need to notify clients and
1382 // remove ourselves from the Phone. Note that we do this after completing all state updates
1383 // so a client can cleanly transition all their UI to the state appropriate for a
1384 // DISCONNECTED Call while still relying on the existence of that Call in the Phone's list.
1385 if (mState == STATE_DISCONNECTED) {
1386 fireCallDestroyed();
Ihab Awade63fadb2014-07-09 21:52:04 -07001387 }
1388 }
1389
1390 /** {@hide} */
Ihab Awade63fadb2014-07-09 21:52:04 -07001391 final void internalSetPostDialWait(String remaining) {
1392 mRemainingPostDialSequence = remaining;
1393 firePostDialWait(mRemainingPostDialSequence);
1394 }
1395
Sailesh Nepal2ab88cc2014-07-18 14:49:18 -07001396 /** {@hide} */
Santos Cordonf30d7e92014-08-26 09:54:33 -07001397 final void internalSetDisconnected() {
1398 if (mState != Call.STATE_DISCONNECTED) {
1399 mState = Call.STATE_DISCONNECTED;
1400 fireStateChanged(mState);
1401 fireCallDestroyed();
Santos Cordonf30d7e92014-08-26 09:54:33 -07001402 }
1403 }
1404
Tyler Gunn876dbfb2016-03-14 15:18:07 -07001405 /** {@hide} */
1406 final void internalOnConnectionEvent(String event, Bundle extras) {
1407 fireOnConnectionEvent(event, extras);
1408 }
1409
Andrew Lee011728f2015-04-23 15:47:06 -07001410 private void fireStateChanged(final int newState) {
1411 for (CallbackRecord<Callback> record : mCallbackRecords) {
1412 final Call call = this;
1413 final Callback callback = record.getCallback();
1414 record.getHandler().post(new Runnable() {
1415 @Override
1416 public void run() {
1417 callback.onStateChanged(call, newState);
1418 }
1419 });
Ihab Awade63fadb2014-07-09 21:52:04 -07001420 }
1421 }
1422
Andrew Lee011728f2015-04-23 15:47:06 -07001423 private void fireParentChanged(final Call newParent) {
1424 for (CallbackRecord<Callback> record : mCallbackRecords) {
1425 final Call call = this;
1426 final Callback callback = record.getCallback();
1427 record.getHandler().post(new Runnable() {
1428 @Override
1429 public void run() {
1430 callback.onParentChanged(call, newParent);
1431 }
1432 });
Ihab Awade63fadb2014-07-09 21:52:04 -07001433 }
1434 }
1435
Andrew Lee011728f2015-04-23 15:47:06 -07001436 private void fireChildrenChanged(final List<Call> children) {
1437 for (CallbackRecord<Callback> record : mCallbackRecords) {
1438 final Call call = this;
1439 final Callback callback = record.getCallback();
1440 record.getHandler().post(new Runnable() {
1441 @Override
1442 public void run() {
1443 callback.onChildrenChanged(call, children);
1444 }
1445 });
Ihab Awade63fadb2014-07-09 21:52:04 -07001446 }
1447 }
1448
Andrew Lee011728f2015-04-23 15:47:06 -07001449 private void fireDetailsChanged(final Details details) {
1450 for (CallbackRecord<Callback> record : mCallbackRecords) {
1451 final Call call = this;
1452 final Callback callback = record.getCallback();
1453 record.getHandler().post(new Runnable() {
1454 @Override
1455 public void run() {
1456 callback.onDetailsChanged(call, details);
1457 }
1458 });
Ihab Awade63fadb2014-07-09 21:52:04 -07001459 }
1460 }
1461
Andrew Lee011728f2015-04-23 15:47:06 -07001462 private void fireCannedTextResponsesLoaded(final List<String> cannedTextResponses) {
1463 for (CallbackRecord<Callback> record : mCallbackRecords) {
1464 final Call call = this;
1465 final Callback callback = record.getCallback();
1466 record.getHandler().post(new Runnable() {
1467 @Override
1468 public void run() {
1469 callback.onCannedTextResponsesLoaded(call, cannedTextResponses);
1470 }
1471 });
Ihab Awade63fadb2014-07-09 21:52:04 -07001472 }
1473 }
1474
Andrew Lee011728f2015-04-23 15:47:06 -07001475 private void fireVideoCallChanged(final InCallService.VideoCall videoCall) {
1476 for (CallbackRecord<Callback> record : mCallbackRecords) {
1477 final Call call = this;
1478 final Callback callback = record.getCallback();
1479 record.getHandler().post(new Runnable() {
1480 @Override
1481 public void run() {
1482 callback.onVideoCallChanged(call, videoCall);
1483 }
1484 });
Ihab Awade63fadb2014-07-09 21:52:04 -07001485 }
1486 }
1487
Andrew Lee011728f2015-04-23 15:47:06 -07001488 private void firePostDialWait(final String remainingPostDialSequence) {
1489 for (CallbackRecord<Callback> record : mCallbackRecords) {
1490 final Call call = this;
1491 final Callback callback = record.getCallback();
1492 record.getHandler().post(new Runnable() {
1493 @Override
1494 public void run() {
1495 callback.onPostDialWait(call, remainingPostDialSequence);
1496 }
1497 });
Ihab Awade63fadb2014-07-09 21:52:04 -07001498 }
1499 }
1500
1501 private void fireCallDestroyed() {
Roshan Pius1ca62072015-07-07 17:34:51 -07001502 /**
1503 * To preserve the ordering of the Call's onCallDestroyed callback and Phone's
1504 * onCallRemoved callback, we remove this call from the Phone's record
1505 * only once all of the registered onCallDestroyed callbacks are executed.
1506 * All the callbacks get removed from our records as a part of this operation
1507 * since onCallDestroyed is the final callback.
1508 */
1509 final Call call = this;
1510 if (mCallbackRecords.isEmpty()) {
1511 // No callbacks registered, remove the call from Phone's record.
1512 mPhone.internalRemoveCall(call);
1513 }
1514 for (final CallbackRecord<Callback> record : mCallbackRecords) {
Andrew Lee011728f2015-04-23 15:47:06 -07001515 final Callback callback = record.getCallback();
1516 record.getHandler().post(new Runnable() {
1517 @Override
1518 public void run() {
Roshan Pius1ca62072015-07-07 17:34:51 -07001519 boolean isFinalRemoval = false;
1520 RuntimeException toThrow = null;
1521 try {
1522 callback.onCallDestroyed(call);
1523 } catch (RuntimeException e) {
1524 toThrow = e;
1525 }
1526 synchronized(Call.this) {
1527 mCallbackRecords.remove(record);
1528 if (mCallbackRecords.isEmpty()) {
1529 isFinalRemoval = true;
1530 }
1531 }
1532 if (isFinalRemoval) {
1533 mPhone.internalRemoveCall(call);
1534 }
1535 if (toThrow != null) {
1536 throw toThrow;
1537 }
Andrew Lee011728f2015-04-23 15:47:06 -07001538 }
1539 });
Ihab Awade63fadb2014-07-09 21:52:04 -07001540 }
1541 }
1542
Santos Cordon7c7bc7f2014-07-28 18:15:48 -07001543 private void fireConferenceableCallsChanged() {
Andrew Lee011728f2015-04-23 15:47:06 -07001544 for (CallbackRecord<Callback> record : mCallbackRecords) {
1545 final Call call = this;
1546 final Callback callback = record.getCallback();
1547 record.getHandler().post(new Runnable() {
1548 @Override
1549 public void run() {
1550 callback.onConferenceableCallsChanged(call, mUnmodifiableConferenceableCalls);
1551 }
1552 });
Santos Cordon7c7bc7f2014-07-28 18:15:48 -07001553 }
1554 }
Tyler Gunn1e9bfc62015-08-19 11:18:58 -07001555
1556 /**
Tyler Gunn876dbfb2016-03-14 15:18:07 -07001557 * Notifies listeners of an incoming connection event.
1558 * <p>
1559 * Connection events are issued via {@link Connection#sendConnectionEvent(String, Bundle)}.
1560 *
1561 * @param event
1562 * @param extras
1563 */
1564 private void fireOnConnectionEvent(final String event, final Bundle extras) {
1565 for (CallbackRecord<Callback> record : mCallbackRecords) {
1566 final Call call = this;
1567 final Callback callback = record.getCallback();
1568 record.getHandler().post(new Runnable() {
1569 @Override
1570 public void run() {
1571 callback.onConnectionEvent(call, event, extras);
1572 }
1573 });
1574 }
1575 }
1576
1577 /**
Tyler Gunn1e9bfc62015-08-19 11:18:58 -07001578 * Determines if two bundles are equal.
1579 *
1580 * @param bundle The original bundle.
1581 * @param newBundle The bundle to compare with.
1582 * @retrun {@code true} if the bundles are equal, {@code false} otherwise.
1583 */
1584 private static boolean areBundlesEqual(Bundle bundle, Bundle newBundle) {
1585 if (bundle == null || newBundle == null) {
1586 return bundle == newBundle;
1587 }
1588
1589 if (bundle.size() != newBundle.size()) {
1590 return false;
1591 }
1592
1593 for(String key : bundle.keySet()) {
1594 if (key != null) {
1595 final Object value = bundle.get(key);
1596 final Object newValue = newBundle.get(key);
1597 if (!Objects.equals(value, newValue)) {
1598 return false;
1599 }
1600 }
1601 }
1602 return true;
1603 }
Santos Cordon7c7bc7f2014-07-28 18:15:48 -07001604}