1 /* 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 17 package android.telecom; 18 19 import android.annotation.FlaggedApi; 20 import android.annotation.IntDef; 21 import android.annotation.NonNull; 22 import android.annotation.Nullable; 23 import android.annotation.SystemApi; 24 import android.annotation.TestApi; 25 import android.compat.annotation.UnsupportedAppUsage; 26 import android.content.pm.ServiceInfo; 27 import android.net.Uri; 28 import android.os.BadParcelableException; 29 import android.os.Build; 30 import android.os.Bundle; 31 import android.os.Handler; 32 import android.os.ParcelFileDescriptor; 33 import android.os.UserHandle; 34 35 import com.android.internal.telecom.IVideoProvider; 36 import com.android.server.telecom.flags.Flags; 37 38 import java.io.IOException; 39 import java.io.InputStreamReader; 40 import java.io.OutputStreamWriter; 41 import java.lang.annotation.Retention; 42 import java.lang.annotation.RetentionPolicy; 43 import java.nio.charset.StandardCharsets; 44 import java.util.ArrayList; 45 import java.util.Arrays; 46 import java.util.Collections; 47 import java.util.List; 48 import java.util.Map; 49 import java.util.Objects; 50 import java.util.concurrent.CopyOnWriteArrayList; 51 52 /** 53 * Represents an ongoing phone call that the in-call app should present to the user. 54 */ 55 public final class Call { 56 private static final String LOG_TAG = "TelecomCall"; 57 58 /** 59 * The state of a {@code Call} when newly created. 60 */ 61 public static final int STATE_NEW = 0; 62 63 /** 64 * The state of an outgoing {@code Call} when dialing the remote number, but not yet connected. 65 */ 66 public static final int STATE_DIALING = 1; 67 68 /** 69 * The state of an incoming {@code Call} when ringing locally, but not yet connected. 70 */ 71 public static final int STATE_RINGING = 2; 72 73 /** 74 * The state of a {@code Call} when in a holding state. 75 */ 76 public static final int STATE_HOLDING = 3; 77 78 /** 79 * The state of a {@code Call} when actively supporting conversation. 80 */ 81 public static final int STATE_ACTIVE = 4; 82 83 /** 84 * The state of a {@code Call} when no further voice or other communication is being 85 * transmitted, the remote side has been or will inevitably be informed that the {@code Call} 86 * is no longer active, and the local data transport has or inevitably will release resources 87 * associated with this {@code Call}. 88 */ 89 public static final int STATE_DISCONNECTED = 7; 90 91 /** 92 * The state of an outgoing {@code Call} when waiting on user to select a 93 * {@link PhoneAccount} through which to place the call. 94 */ 95 public static final int STATE_SELECT_PHONE_ACCOUNT = 8; 96 97 /** 98 * @hide 99 * @deprecated use STATE_SELECT_PHONE_ACCOUNT. 100 */ 101 @Deprecated 102 @SystemApi 103 public static final int STATE_PRE_DIAL_WAIT = STATE_SELECT_PHONE_ACCOUNT; 104 105 /** 106 * The initial state of an outgoing {@code Call}. 107 * Common transitions are to {@link #STATE_DIALING} state for a successful call or 108 * {@link #STATE_DISCONNECTED} if it failed. 109 */ 110 public static final int STATE_CONNECTING = 9; 111 112 /** 113 * The state of a {@code Call} when the user has initiated a disconnection of the call, but the 114 * call has not yet been disconnected by the underlying {@code ConnectionService}. The next 115 * state of the call is (potentially) {@link #STATE_DISCONNECTED}. 116 */ 117 public static final int STATE_DISCONNECTING = 10; 118 119 /** 120 * The state of an external call which is in the process of being pulled from a remote device to 121 * the local device. 122 * <p> 123 * A call can only be in this state if the {@link Details#PROPERTY_IS_EXTERNAL_CALL} property 124 * and {@link Details#CAPABILITY_CAN_PULL_CALL} capability are set on the call. 125 * <p> 126 * An {@link InCallService} will only see this state if it has the 127 * {@link TelecomManager#METADATA_INCLUDE_EXTERNAL_CALLS} metadata set to {@code true} in its 128 * manifest. 129 */ 130 public static final int STATE_PULLING_CALL = 11; 131 132 /** 133 * The state of a call that is active with the network, but the audio from the call is 134 * being intercepted by an app on the local device. Telecom does not hold audio focus in this 135 * state, and the call will be invisible to the user except for a persistent notification. 136 */ 137 public static final int STATE_AUDIO_PROCESSING = 12; 138 139 /** 140 * The state of a call that is being presented to the user after being in 141 * {@link #STATE_AUDIO_PROCESSING}. The call is still active with the network in this case, and 142 * Telecom will hold audio focus and play a ringtone if appropriate. 143 */ 144 public static final int STATE_SIMULATED_RINGING = 13; 145 146 /** 147 * @hide 148 */ 149 @IntDef(prefix = { "STATE_" }, 150 value = { 151 STATE_NEW, 152 STATE_DIALING, 153 STATE_RINGING, 154 STATE_HOLDING, 155 STATE_ACTIVE, 156 STATE_DISCONNECTED, 157 STATE_SELECT_PHONE_ACCOUNT, 158 STATE_CONNECTING, 159 STATE_DISCONNECTING, 160 STATE_PULLING_CALL, 161 STATE_AUDIO_PROCESSING, 162 STATE_SIMULATED_RINGING 163 }) 164 @Retention(RetentionPolicy.SOURCE) 165 public @interface CallState {}; 166 167 /** 168 * The key to retrieve the optional {@code PhoneAccount}s Telecom can bundle with its Call 169 * extras. Used to pass the phone accounts to display on the front end to the user in order to 170 * select phone accounts to (for example) place a call. 171 * @deprecated Use the list from {@link #EXTRA_SUGGESTED_PHONE_ACCOUNTS} instead. 172 */ 173 @Deprecated 174 public static final String AVAILABLE_PHONE_ACCOUNTS = "selectPhoneAccountAccounts"; 175 176 /** 177 * Extra key intended for {@link InCallService}s that notify the user of an incoming call. When 178 * EXTRA_IS_SUPPRESSED_BY_DO_NOT_DISTURB returns true, the {@link InCallService} should not 179 * interrupt the user of the incoming call because the call is being suppressed by Do Not 180 * Disturb settings. 181 * 182 * This extra will be removed from the {@link Call} object for {@link InCallService}s that do 183 * not hold the {@link android.Manifest.permission#READ_CONTACTS} permission. 184 */ 185 public static final String EXTRA_IS_SUPPRESSED_BY_DO_NOT_DISTURB = 186 "android.telecom.extra.IS_SUPPRESSED_BY_DO_NOT_DISTURB"; 187 188 /** 189 * Key for extra used to pass along a list of {@link PhoneAccountSuggestion}s to the in-call 190 * UI when a call enters the {@link #STATE_SELECT_PHONE_ACCOUNT} state. The list included here 191 * will have the same length and be in the same order as the list passed with 192 * {@link #AVAILABLE_PHONE_ACCOUNTS}. 193 */ 194 public static final String EXTRA_SUGGESTED_PHONE_ACCOUNTS = 195 "android.telecom.extra.SUGGESTED_PHONE_ACCOUNTS"; 196 197 /** 198 * Extra key used to indicate the time (in milliseconds since midnight, January 1, 1970 UTC) 199 * when the last outgoing emergency call was made. This is used to identify potential emergency 200 * callbacks. 201 */ 202 public static final String EXTRA_LAST_EMERGENCY_CALLBACK_TIME_MILLIS = 203 "android.telecom.extra.LAST_EMERGENCY_CALLBACK_TIME_MILLIS"; 204 205 206 /** 207 * Extra key used to indicate whether a {@link CallScreeningService} has requested to silence 208 * the ringtone for a call. If the {@link InCallService} declares 209 * {@link TelecomManager#METADATA_IN_CALL_SERVICE_RINGING} in its manifest, it should not 210 * play a ringtone for an incoming call with this extra key set. 211 */ 212 public static final String EXTRA_SILENT_RINGING_REQUESTED = 213 "android.telecom.extra.SILENT_RINGING_REQUESTED"; 214 215 /** 216 * Event reported from the Telecom stack to report an in-call diagnostic message which the 217 * dialer app may opt to display to the user. A diagnostic message is used to communicate 218 * scenarios the device has detected which may impact the quality of the ongoing call. 219 * <p> 220 * For example a problem with a bluetooth headset may generate a recommendation for the user to 221 * try using the speakerphone instead, or if the device detects it has entered a poor service 222 * area, the user might be warned so that they can finish their call prior to it dropping. 223 * <p> 224 * A diagnostic message is considered persistent in nature. When the user enters a poor service 225 * area, for example, the accompanying diagnostic message persists until they leave the area 226 * of poor service. Each message is accompanied with a {@link #EXTRA_DIAGNOSTIC_MESSAGE_ID} 227 * which uniquely identifies the diagnostic condition being reported. The framework raises a 228 * call event of type {@link #EVENT_CLEAR_DIAGNOSTIC_MESSAGE} when the condition reported has 229 * been cleared. The dialer app should display the diagnostic message until it is cleared. 230 * If multiple diagnostic messages are sent with different IDs (which have not yet been cleared) 231 * the dialer app should prioritize the most recently received message, but still provide the 232 * user with a means to review past messages. 233 * <p> 234 * The text of the message is found in {@link #EXTRA_DIAGNOSTIC_MESSAGE} in the form of a human 235 * readable {@link CharSequence} which is intended for display in the call UX. 236 * <p> 237 * The telecom framework audibly notifies the user of the presence of a diagnostic message, so 238 * the dialer app needs only to concern itself with visually displaying the message. 239 * <p> 240 * The dialer app receives this event via 241 * {@link Call.Callback#onConnectionEvent(Call, String, Bundle)}. 242 */ 243 public static final String EVENT_DISPLAY_DIAGNOSTIC_MESSAGE = 244 "android.telecom.event.DISPLAY_DIAGNOSTIC_MESSAGE"; 245 246 /** 247 * Event reported from the telecom framework when a diagnostic message previously raised with 248 * {@link #EVENT_DISPLAY_DIAGNOSTIC_MESSAGE} has cleared and is no longer pertinent. 249 * <p> 250 * The {@link #EXTRA_DIAGNOSTIC_MESSAGE_ID} indicates the diagnostic message which has been 251 * cleared. 252 * <p> 253 * The dialer app receives this event via 254 * {@link Call.Callback#onConnectionEvent(Call, String, Bundle)}. 255 */ 256 public static final String EVENT_CLEAR_DIAGNOSTIC_MESSAGE = 257 "android.telecom.event.CLEAR_DIAGNOSTIC_MESSAGE"; 258 259 /** 260 * Integer extra representing a message ID for a message posted via 261 * {@link #EVENT_DISPLAY_DIAGNOSTIC_MESSAGE}. Used to ensure that the dialer app knows when 262 * the message in question has cleared via {@link #EVENT_CLEAR_DIAGNOSTIC_MESSAGE}. 263 */ 264 public static final String EXTRA_DIAGNOSTIC_MESSAGE_ID = 265 "android.telecom.extra.DIAGNOSTIC_MESSAGE_ID"; 266 267 /** 268 * {@link CharSequence} extra used with {@link #EVENT_DISPLAY_DIAGNOSTIC_MESSAGE}. This is the 269 * diagnostic message the dialer app should display. 270 */ 271 public static final String EXTRA_DIAGNOSTIC_MESSAGE = 272 "android.telecom.extra.DIAGNOSTIC_MESSAGE"; 273 274 /** 275 * Boolean indicating that the call is a verified business call. 276 * 277 * {@link Connection#setExtras(Bundle)} or {@link Connection#putExtras(Bundle)} 278 * should be used to notify Telecom this extra has been set. 279 */ 280 @FlaggedApi(Flags.FLAG_BUSINESS_CALL_COMPOSER) 281 public static final String EXTRA_IS_BUSINESS_CALL = 282 "android.telecom.extra.IS_BUSINESS_CALL"; 283 284 /** 285 * String value indicating the asserted display name reported via 286 * ImsCallProfile#EXTRA_ASSERTED_DISPLAY_NAME. 287 * 288 * {@link Connection#setExtras(Bundle)} or {@link Connection#putExtras(Bundle)} 289 * should be used to notify Telecom this extra has been set. 290 */ 291 @FlaggedApi(Flags.FLAG_BUSINESS_CALL_COMPOSER) 292 public static final String EXTRA_ASSERTED_DISPLAY_NAME = 293 "android.telecom.extra.ASSERTED_DISPLAY_NAME"; 294 295 /** 296 * Reject reason used with {@link #reject(int)} to indicate that the user is rejecting this 297 * call because they have declined to answer it. This typically means that they are unable 298 * to answer the call at this time and would prefer it be sent to voicemail. 299 */ 300 public static final int REJECT_REASON_DECLINED = 1; 301 302 /** 303 * Reject reason used with {@link #reject(int)} to indicate that the user is rejecting this 304 * call because it is an unwanted call. This allows the user to indicate that they are 305 * rejecting a call because it is likely a nuisance call. 306 */ 307 public static final int REJECT_REASON_UNWANTED = 2; 308 309 /** 310 * @hide 311 */ 312 @IntDef(prefix = { "REJECT_REASON_" }, 313 value = {REJECT_REASON_DECLINED, REJECT_REASON_UNWANTED}) 314 @Retention(RetentionPolicy.SOURCE) 315 public @interface RejectReason {}; 316 317 public static class Details { 318 /** @hide */ 319 @Retention(RetentionPolicy.SOURCE) 320 @IntDef( 321 prefix = { "DIRECTION_" }, 322 value = {DIRECTION_UNKNOWN, DIRECTION_INCOMING, DIRECTION_OUTGOING}) 323 public @interface CallDirection {} 324 325 /** 326 * Indicates that the call is neither and incoming nor an outgoing call. This can be the 327 * case for calls reported directly by a {@link ConnectionService} in special cases such as 328 * call handovers. 329 */ 330 public static final int DIRECTION_UNKNOWN = -1; 331 332 /** 333 * Indicates that the call is an incoming call. 334 */ 335 public static final int DIRECTION_INCOMING = 0; 336 337 /** 338 * Indicates that the call is an outgoing call. 339 */ 340 public static final int DIRECTION_OUTGOING = 1; 341 342 /** Call can currently be put on hold or unheld. */ 343 public static final int CAPABILITY_HOLD = 0x00000001; 344 345 /** Call supports the hold feature. */ 346 public static final int CAPABILITY_SUPPORT_HOLD = 0x00000002; 347 348 /** 349 * Calls within a conference can be merged. A {@link ConnectionService} has the option to 350 * add a {@link Conference} call before the child {@link Connection}s are merged. This is how 351 * CDMA-based {@link Connection}s are implemented. For these unmerged {@link Conference}s, this 352 * capability allows a merge button to be shown while the conference call is in the foreground 353 * of the in-call UI. 354 * <p> 355 * This is only intended for use by a {@link Conference}. 356 */ 357 public static final int CAPABILITY_MERGE_CONFERENCE = 0x00000004; 358 359 /** 360 * Calls within a conference can be swapped between foreground and background. 361 * See {@link #CAPABILITY_MERGE_CONFERENCE} for additional information. 362 * <p> 363 * This is only intended for use by a {@link Conference}. 364 */ 365 public static final int CAPABILITY_SWAP_CONFERENCE = 0x00000008; 366 367 /** 368 * @hide 369 */ 370 public static final int CAPABILITY_UNUSED_1 = 0x00000010; 371 372 /** Call supports responding via text option. */ 373 public static final int CAPABILITY_RESPOND_VIA_TEXT = 0x00000020; 374 375 /** Call can be muted. */ 376 public static final int CAPABILITY_MUTE = 0x00000040; 377 378 /** 379 * Call supports conference call management. This capability only applies to {@link Conference} 380 * calls which can have {@link Connection}s as children. 381 */ 382 public static final int CAPABILITY_MANAGE_CONFERENCE = 0x00000080; 383 384 /** 385 * Local device supports receiving video. 386 */ 387 public static final int CAPABILITY_SUPPORTS_VT_LOCAL_RX = 0x00000100; 388 389 /** 390 * Local device supports transmitting video. 391 */ 392 public static final int CAPABILITY_SUPPORTS_VT_LOCAL_TX = 0x00000200; 393 394 /** 395 * Local device supports bidirectional video calling. 396 */ 397 public static final int CAPABILITY_SUPPORTS_VT_LOCAL_BIDIRECTIONAL = 398 CAPABILITY_SUPPORTS_VT_LOCAL_RX | CAPABILITY_SUPPORTS_VT_LOCAL_TX; 399 400 /** 401 * Remote device supports receiving video. 402 */ 403 public static final int CAPABILITY_SUPPORTS_VT_REMOTE_RX = 0x00000400; 404 405 /** 406 * Remote device supports transmitting video. 407 */ 408 public static final int CAPABILITY_SUPPORTS_VT_REMOTE_TX = 0x00000800; 409 410 /** 411 * Remote device supports bidirectional video calling. 412 */ 413 public static final int CAPABILITY_SUPPORTS_VT_REMOTE_BIDIRECTIONAL = 414 CAPABILITY_SUPPORTS_VT_REMOTE_RX | CAPABILITY_SUPPORTS_VT_REMOTE_TX; 415 416 /** 417 * Call is able to be separated from its parent {@code Conference}, if any. 418 */ 419 public static final int CAPABILITY_SEPARATE_FROM_CONFERENCE = 0x00001000; 420 421 /** 422 * Call is able to be individually disconnected when in a {@code Conference}. 423 */ 424 public static final int CAPABILITY_DISCONNECT_FROM_CONFERENCE = 0x00002000; 425 426 /** 427 * Speed up audio setup for MT call. 428 * @hide 429 */ 430 public static final int CAPABILITY_SPEED_UP_MT_AUDIO = 0x00040000; 431 432 /** 433 * Call can be upgraded to a video call. 434 * @hide 435 * @deprecated Use {@link #CAPABILITY_SUPPORTS_VT_LOCAL_BIDIRECTIONAL} and 436 * {@link #CAPABILITY_SUPPORTS_VT_REMOTE_BIDIRECTIONAL} to indicate for a call 437 * whether or not video calling is supported. 438 */ 439 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 119305590) 440 public static final int CAPABILITY_CAN_UPGRADE_TO_VIDEO = 0x00080000; 441 442 /** 443 * For video calls, indicates whether the outgoing video for the call can be paused using 444 * the {@link android.telecom.VideoProfile#STATE_PAUSED} VideoState. 445 */ 446 public static final int CAPABILITY_CAN_PAUSE_VIDEO = 0x00100000; 447 448 /** 449 * Call sends responses through connection. 450 * @hide 451 */ 452 public static final int CAPABILITY_CAN_SEND_RESPONSE_VIA_CONNECTION = 0x00200000; 453 454 /** 455 * When set, prevents a video {@code Call} from being downgraded to an audio-only call. 456 * <p> 457 * Should be set when the VideoState has the {@link VideoProfile#STATE_TX_ENABLED} or 458 * {@link VideoProfile#STATE_RX_ENABLED} bits set to indicate that the connection cannot be 459 * downgraded from a video call back to a VideoState of 460 * {@link VideoProfile#STATE_AUDIO_ONLY}. 461 * <p> 462 * Intuitively, a call which can be downgraded to audio should also have local and remote 463 * video 464 * capabilities (see {@link #CAPABILITY_SUPPORTS_VT_LOCAL_BIDIRECTIONAL} and 465 * {@link #CAPABILITY_SUPPORTS_VT_REMOTE_BIDIRECTIONAL}). 466 */ 467 public static final int CAPABILITY_CANNOT_DOWNGRADE_VIDEO_TO_AUDIO = 0x00400000; 468 469 /** 470 * When set for an external call, indicates that this {@code Call} can be pulled from a 471 * remote device to the current device. 472 * <p> 473 * Should only be set on a {@code Call} where {@link #PROPERTY_IS_EXTERNAL_CALL} is set. 474 * <p> 475 * An {@link InCallService} will only see calls with this capability if it has the 476 * {@link TelecomManager#METADATA_INCLUDE_EXTERNAL_CALLS} metadata set to {@code true} 477 * in its manifest. 478 * <p> 479 * See {@link Connection#CAPABILITY_CAN_PULL_CALL} and 480 * {@link Connection#PROPERTY_IS_EXTERNAL_CALL}. 481 */ 482 public static final int CAPABILITY_CAN_PULL_CALL = 0x00800000; 483 484 /** Call supports the deflect feature. */ 485 public static final int CAPABILITY_SUPPORT_DEFLECT = 0x01000000; 486 487 /** 488 * Call supports adding participants to the call via 489 * {@link #addConferenceParticipants(List)}. Once participants are added, the call becomes 490 * an adhoc conference call ({@link #PROPERTY_IS_ADHOC_CONFERENCE}). 491 */ 492 public static final int CAPABILITY_ADD_PARTICIPANT = 0x02000000; 493 494 /** 495 * When set for a call, indicates that this {@code Call} can be transferred to another 496 * number. 497 * Call supports the confirmed and unconfirmed call transfer feature. 498 * 499 * @hide 500 */ 501 public static final int CAPABILITY_TRANSFER = 0x04000000; 502 503 /** 504 * When set for a call, indicates that this {@code Call} can be transferred to another 505 * ongoing call. 506 * Call supports the consultative call transfer feature. 507 * 508 * @hide 509 */ 510 public static final int CAPABILITY_TRANSFER_CONSULTATIVE = 0x08000000; 511 512 /** 513 * Indicates whether the remote party supports RTT or not to the UI. 514 */ 515 516 public static final int CAPABILITY_REMOTE_PARTY_SUPPORTS_RTT = 0x10000000; 517 518 //****************************************************************************************** 519 // Next CAPABILITY value: 0x20000000 520 //****************************************************************************************** 521 522 /** 523 * Whether the call is currently a conference. 524 */ 525 public static final int PROPERTY_CONFERENCE = 0x00000001; 526 527 /** 528 * Whether the call is a generic conference, where we do not know the precise state of 529 * participants in the conference (eg. on CDMA). 530 */ 531 public static final int PROPERTY_GENERIC_CONFERENCE = 0x00000002; 532 533 /** 534 * Whether the call is made while the device is in emergency callback mode. 535 */ 536 public static final int PROPERTY_EMERGENCY_CALLBACK_MODE = 0x00000004; 537 538 /** 539 * Connection is using WIFI. 540 */ 541 public static final int PROPERTY_WIFI = 0x00000008; 542 543 /** 544 * When set, the UI should indicate to the user that a call is using high definition 545 * audio. 546 * <p> 547 * The underlying {@link ConnectionService} is responsible for reporting this 548 * property. It is important to note that this property is not intended to report the 549 * actual audio codec being used for a Call, but whether the call should be indicated 550 * to the user as high definition. 551 * <p> 552 * The Android Telephony stack reports this property for calls based on a number 553 * of factors, including which audio codec is used and whether a call is using an HD 554 * codec end-to-end. Some mobile operators choose to suppress display of an HD indication, 555 * and in these cases this property will not be set for a call even if the underlying audio 556 * codec is in fact "high definition". 557 */ 558 public static final int PROPERTY_HIGH_DEF_AUDIO = 0x00000010; 559 560 /** 561 * Whether the call is associated with the work profile. 562 */ 563 public static final int PROPERTY_ENTERPRISE_CALL = 0x00000020; 564 565 /** 566 * When set, indicates that this {@code Call} does not actually exist locally for the 567 * {@link ConnectionService}. 568 * <p> 569 * Consider, for example, a scenario where a user has two phones with the same phone number. 570 * When a user places a call on one device, the telephony stack can represent that call on 571 * the other device by adding it to the {@link ConnectionService} with the 572 * {@link Connection#PROPERTY_IS_EXTERNAL_CALL} property set. 573 * <p> 574 * An {@link InCallService} will only see calls with this property if it has the 575 * {@link TelecomManager#METADATA_INCLUDE_EXTERNAL_CALLS} metadata set to {@code true} 576 * in its manifest. 577 * <p> 578 * See {@link Connection#PROPERTY_IS_EXTERNAL_CALL}. 579 */ 580 public static final int PROPERTY_IS_EXTERNAL_CALL = 0x00000040; 581 582 /** 583 * Indicates that the call has CDMA Enhanced Voice Privacy enabled. 584 */ 585 public static final int PROPERTY_HAS_CDMA_VOICE_PRIVACY = 0x00000080; 586 587 /** 588 * Indicates that the call is from a self-managed {@link ConnectionService}. 589 * <p> 590 * See also {@link Connection#PROPERTY_SELF_MANAGED} 591 */ 592 public static final int PROPERTY_SELF_MANAGED = 0x00000100; 593 594 /** 595 * Indicates the call used Assisted Dialing. 596 * 597 * @see TelecomManager#EXTRA_USE_ASSISTED_DIALING 598 */ 599 public static final int PROPERTY_ASSISTED_DIALING = 0x00000200; 600 601 /** 602 * Indicates that the call is an RTT call. Use {@link #getRttCall()} to get the 603 * {@link RttCall} object that is used to send and receive text. 604 */ 605 public static final int PROPERTY_RTT = 0x00000400; 606 607 /** 608 * Indicates that the call has been identified as the network as an emergency call. This 609 * property may be set for both incoming and outgoing calls which the network identifies as 610 * emergency calls. 611 */ 612 public static final int PROPERTY_NETWORK_IDENTIFIED_EMERGENCY_CALL = 0x00000800; 613 614 /** 615 * Indicates that the call is using VoIP audio mode. 616 * <p> 617 * When this property is set, the {@link android.media.AudioManager} audio mode for this 618 * call will be {@link android.media.AudioManager#MODE_IN_COMMUNICATION}. When this 619 * property is not set, the audio mode for this call will be 620 * {@link android.media.AudioManager#MODE_IN_CALL}. 621 * <p> 622 * This property reflects changes made using {@link Connection#setAudioModeIsVoip(boolean)}. 623 * <p> 624 * You can use this property to determine whether an un-answered incoming call or a held 625 * call will use VoIP audio mode (if the call does not currently have focus, the system 626 * audio mode may not reflect the mode the call will use). 627 */ 628 public static final int PROPERTY_VOIP_AUDIO_MODE = 0x00001000; 629 630 /** 631 * Indicates that the call is an adhoc conference call. This property can be set for both 632 * incoming and outgoing calls. An adhoc conference call is formed using 633 * {@link #addConferenceParticipants(List)}, 634 * {@link TelecomManager#addNewIncomingConference(PhoneAccountHandle, Bundle)}, or 635 * {@link TelecomManager#startConference(List, Bundle)}, rather than by merging existing 636 * call using {@link #conference(Call)}. 637 */ 638 public static final int PROPERTY_IS_ADHOC_CONFERENCE = 0x00002000; 639 640 /** 641 * Connection is using cross sim technology. 642 * <p> 643 * Indicates that the {@link Connection} is using a cross sim technology which would 644 * register IMS over internet APN of default data subscription. 645 * <p> 646 */ 647 public static final int PROPERTY_CROSS_SIM = 0x00004000; 648 649 /** 650 * The connection is using transactional call APIs. 651 * <p> 652 * The underlying connection was added as a transactional call via the 653 * {@link TelecomManager#addCall} API. 654 */ 655 @FlaggedApi(Flags.FLAG_VOIP_APP_ACTIONS_SUPPORT) 656 public static final int PROPERTY_IS_TRANSACTIONAL = 0x00008000; 657 658 //****************************************************************************************** 659 // Next PROPERTY value: 0x00010000 660 //****************************************************************************************** 661 662 private final @CallState int mState; 663 private final String mTelecomCallId; 664 private final Uri mHandle; 665 private final int mHandlePresentation; 666 private final String mCallerDisplayName; 667 private final int mCallerDisplayNamePresentation; 668 private final PhoneAccountHandle mAccountHandle; 669 private final int mCallCapabilities; 670 private final int mCallProperties; 671 private final int mSupportedAudioRoutes = CallAudioState.ROUTE_ALL; 672 private final DisconnectCause mDisconnectCause; 673 private final long mConnectTimeMillis; 674 private final GatewayInfo mGatewayInfo; 675 private final int mVideoState; 676 private final StatusHints mStatusHints; 677 private final Bundle mExtras; 678 private final Bundle mIntentExtras; 679 private final long mCreationTimeMillis; 680 private final String mContactDisplayName; 681 private final @CallDirection int mCallDirection; 682 private final @Connection.VerificationStatus int mCallerNumberVerificationStatus; 683 private final Uri mContactPhotoUri; 684 private final UserHandle mAssociatedUser; 685 686 /** 687 * Whether the supplied capabilities supports the specified capability. 688 * 689 * @param capabilities A bit field of capabilities. 690 * @param capability The capability to check capabilities for. 691 * @return Whether the specified capability is supported. 692 */ can(int capabilities, int capability)693 public static boolean can(int capabilities, int capability) { 694 return (capabilities & capability) == capability; 695 } 696 697 /** 698 * Whether the capabilities of this {@code Details} supports the specified capability. 699 * 700 * @param capability The capability to check capabilities for. 701 * @return Whether the specified capability is supported. 702 */ can(int capability)703 public boolean can(int capability) { 704 return can(mCallCapabilities, capability); 705 } 706 707 /** 708 * Render a set of capability bits ({@code CAPABILITY_*}) as a human readable string. 709 * 710 * @param capabilities A capability bit field. 711 * @return A human readable string representation. 712 */ capabilitiesToString(int capabilities)713 public static String capabilitiesToString(int capabilities) { 714 StringBuilder builder = new StringBuilder(); 715 builder.append("[Capabilities:"); 716 if (can(capabilities, CAPABILITY_HOLD)) { 717 builder.append(" CAPABILITY_HOLD"); 718 } 719 if (can(capabilities, CAPABILITY_SUPPORT_HOLD)) { 720 builder.append(" CAPABILITY_SUPPORT_HOLD"); 721 } 722 if (can(capabilities, CAPABILITY_MERGE_CONFERENCE)) { 723 builder.append(" CAPABILITY_MERGE_CONFERENCE"); 724 } 725 if (can(capabilities, CAPABILITY_SWAP_CONFERENCE)) { 726 builder.append(" CAPABILITY_SWAP_CONFERENCE"); 727 } 728 if (can(capabilities, CAPABILITY_RESPOND_VIA_TEXT)) { 729 builder.append(" CAPABILITY_RESPOND_VIA_TEXT"); 730 } 731 if (can(capabilities, CAPABILITY_MUTE)) { 732 builder.append(" CAPABILITY_MUTE"); 733 } 734 if (can(capabilities, CAPABILITY_MANAGE_CONFERENCE)) { 735 builder.append(" CAPABILITY_MANAGE_CONFERENCE"); 736 } 737 if (can(capabilities, CAPABILITY_SUPPORTS_VT_LOCAL_RX)) { 738 builder.append(" CAPABILITY_SUPPORTS_VT_LOCAL_RX"); 739 } 740 if (can(capabilities, CAPABILITY_SUPPORTS_VT_LOCAL_TX)) { 741 builder.append(" CAPABILITY_SUPPORTS_VT_LOCAL_TX"); 742 } 743 if (can(capabilities, CAPABILITY_SUPPORTS_VT_LOCAL_BIDIRECTIONAL)) { 744 builder.append(" CAPABILITY_SUPPORTS_VT_LOCAL_BIDIRECTIONAL"); 745 } 746 if (can(capabilities, CAPABILITY_SUPPORTS_VT_REMOTE_RX)) { 747 builder.append(" CAPABILITY_SUPPORTS_VT_REMOTE_RX"); 748 } 749 if (can(capabilities, CAPABILITY_SUPPORTS_VT_REMOTE_TX)) { 750 builder.append(" CAPABILITY_SUPPORTS_VT_REMOTE_TX"); 751 } 752 if (can(capabilities, CAPABILITY_CANNOT_DOWNGRADE_VIDEO_TO_AUDIO)) { 753 builder.append(" CAPABILITY_CANNOT_DOWNGRADE_VIDEO_TO_AUDIO"); 754 } 755 if (can(capabilities, CAPABILITY_SUPPORTS_VT_REMOTE_BIDIRECTIONAL)) { 756 builder.append(" CAPABILITY_SUPPORTS_VT_REMOTE_BIDIRECTIONAL"); 757 } 758 if (can(capabilities, CAPABILITY_SPEED_UP_MT_AUDIO)) { 759 builder.append(" CAPABILITY_SPEED_UP_MT_AUDIO"); 760 } 761 if (can(capabilities, CAPABILITY_CAN_UPGRADE_TO_VIDEO)) { 762 builder.append(" CAPABILITY_CAN_UPGRADE_TO_VIDEO"); 763 } 764 if (can(capabilities, CAPABILITY_CAN_PAUSE_VIDEO)) { 765 builder.append(" CAPABILITY_CAN_PAUSE_VIDEO"); 766 } 767 if (can(capabilities, CAPABILITY_CAN_PULL_CALL)) { 768 builder.append(" CAPABILITY_CAN_PULL_CALL"); 769 } 770 if (can(capabilities, CAPABILITY_SUPPORT_DEFLECT)) { 771 builder.append(" CAPABILITY_SUPPORT_DEFLECT"); 772 } 773 if (can(capabilities, CAPABILITY_ADD_PARTICIPANT)) { 774 builder.append(" CAPABILITY_ADD_PARTICIPANT"); 775 } 776 if (can(capabilities, CAPABILITY_TRANSFER)) { 777 builder.append(" CAPABILITY_TRANSFER"); 778 } 779 if (can(capabilities, CAPABILITY_TRANSFER_CONSULTATIVE)) { 780 builder.append(" CAPABILITY_TRANSFER_CONSULTATIVE"); 781 } 782 if (can(capabilities, CAPABILITY_REMOTE_PARTY_SUPPORTS_RTT)) { 783 builder.append(" CAPABILITY_REMOTE_PARTY_SUPPORTS_RTT"); 784 } 785 builder.append("]"); 786 return builder.toString(); 787 } 788 789 /** 790 * Whether the supplied properties includes the specified property. 791 * 792 * @param properties A bit field of properties. 793 * @param property The property to check properties for. 794 * @return Whether the specified property is supported. 795 */ hasProperty(int properties, int property)796 public static boolean hasProperty(int properties, int property) { 797 return (properties & property) == property; 798 } 799 800 /** 801 * Whether the properties of this {@code Details} includes the specified property. 802 * 803 * @param property The property to check properties for. 804 * @return Whether the specified property is supported. 805 */ hasProperty(int property)806 public boolean hasProperty(int property) { 807 return hasProperty(mCallProperties, property); 808 } 809 810 /** 811 * Render a set of property bits ({@code PROPERTY_*}) as a human readable string. 812 * 813 * @param properties A property bit field. 814 * @return A human readable string representation. 815 */ propertiesToString(int properties)816 public static String propertiesToString(int properties) { 817 StringBuilder builder = new StringBuilder(); 818 builder.append("[Properties:"); 819 if (hasProperty(properties, PROPERTY_CONFERENCE)) { 820 builder.append(" PROPERTY_CONFERENCE"); 821 } 822 if (hasProperty(properties, PROPERTY_GENERIC_CONFERENCE)) { 823 builder.append(" PROPERTY_GENERIC_CONFERENCE"); 824 } 825 if (hasProperty(properties, PROPERTY_WIFI)) { 826 builder.append(" PROPERTY_WIFI"); 827 } 828 if (hasProperty(properties, PROPERTY_HIGH_DEF_AUDIO)) { 829 builder.append(" PROPERTY_HIGH_DEF_AUDIO"); 830 } 831 if (hasProperty(properties, PROPERTY_EMERGENCY_CALLBACK_MODE)) { 832 builder.append(" PROPERTY_EMERGENCY_CALLBACK_MODE"); 833 } 834 if (hasProperty(properties, PROPERTY_IS_EXTERNAL_CALL)) { 835 builder.append(" PROPERTY_IS_EXTERNAL_CALL"); 836 } 837 if (hasProperty(properties, PROPERTY_HAS_CDMA_VOICE_PRIVACY)) { 838 builder.append(" PROPERTY_HAS_CDMA_VOICE_PRIVACY"); 839 } 840 if (hasProperty(properties, PROPERTY_ASSISTED_DIALING)) { 841 builder.append(" PROPERTY_ASSISTED_DIALING_USED"); 842 } 843 if (hasProperty(properties, PROPERTY_NETWORK_IDENTIFIED_EMERGENCY_CALL)) { 844 builder.append(" PROPERTY_NETWORK_IDENTIFIED_EMERGENCY_CALL"); 845 } 846 if (hasProperty(properties, PROPERTY_RTT)) { 847 builder.append(" PROPERTY_RTT"); 848 } 849 if (hasProperty(properties, PROPERTY_VOIP_AUDIO_MODE)) { 850 builder.append(" PROPERTY_VOIP_AUDIO_MODE"); 851 } 852 if (hasProperty(properties, PROPERTY_IS_ADHOC_CONFERENCE)) { 853 builder.append(" PROPERTY_IS_ADHOC_CONFERENCE"); 854 } 855 if (hasProperty(properties, PROPERTY_CROSS_SIM)) { 856 builder.append(" PROPERTY_CROSS_SIM"); 857 } 858 if (hasProperty(properties, PROPERTY_IS_TRANSACTIONAL)) { 859 builder.append(" PROPERTY_IS_TRANSACTIONAL"); 860 } 861 builder.append("]"); 862 return builder.toString(); 863 } 864 865 /** 866 * @return the state of the {@link Call} represented by this {@link Call.Details}. 867 */ getState()868 public final @CallState int getState() { 869 return mState; 870 } 871 872 /** 873 * @return the Telecom identifier associated with this {@link Call} . This is not a stable 874 * identifier and is not guaranteed to be unique across device reboots. 875 */ 876 @FlaggedApi(Flags.FLAG_CALL_DETAILS_ID_CHANGES) getId()877 public @NonNull String getId() { return mTelecomCallId; } 878 879 /** {@hide} */ 880 @TestApi getTelecomCallId()881 public String getTelecomCallId() { 882 return mTelecomCallId; 883 } 884 885 /** 886 * @return The handle (e.g., phone number) to which the {@code Call} is currently 887 * connected. 888 */ getHandle()889 public Uri getHandle() { 890 return mHandle; 891 } 892 893 /** 894 * @return The presentation requirements for the handle. See 895 * {@link TelecomManager} for valid values. 896 */ getHandlePresentation()897 public int getHandlePresentation() { 898 return mHandlePresentation; 899 } 900 901 /** 902 * @return The contact photo URI which corresponds to 903 * {@link android.provider.ContactsContract.PhoneLookup#PHOTO_URI}, or {@code null} if the 904 * lookup is not yet complete, if there's no contacts entry for the caller, 905 * or if the {@link InCallService} does not hold the 906 * {@link android.Manifest.permission#READ_CONTACTS} permission. 907 */ getContactPhotoUri()908 public @Nullable Uri getContactPhotoUri() { 909 return mContactPhotoUri; 910 } 911 912 /** 913 * The display name for the caller. 914 * <p> 915 * This is the name as reported by the {@link ConnectionService} associated with this call. 916 * 917 * @return The display name for the caller. 918 */ getCallerDisplayName()919 public String getCallerDisplayName() { 920 return mCallerDisplayName; 921 } 922 923 /** 924 * @return The presentation requirements for the caller display name. See 925 * {@link TelecomManager} for valid values. 926 */ getCallerDisplayNamePresentation()927 public int getCallerDisplayNamePresentation() { 928 return mCallerDisplayNamePresentation; 929 } 930 931 /** 932 * @return The {@code PhoneAccountHandle} whereby the {@code Call} is currently being 933 * routed. 934 */ getAccountHandle()935 public PhoneAccountHandle getAccountHandle() { 936 return mAccountHandle; 937 } 938 939 /** 940 * @return A bitmask of the capabilities of the {@code Call}, as defined by the various 941 * {@code CAPABILITY_*} constants in this class. 942 */ getCallCapabilities()943 public int getCallCapabilities() { 944 return mCallCapabilities; 945 } 946 947 /** 948 * @return A bitmask of the properties of the {@code Call}, as defined by the various 949 * {@code PROPERTY_*} constants in this class. 950 */ getCallProperties()951 public int getCallProperties() { 952 return mCallProperties; 953 } 954 955 /** 956 * @return a bitmask of the audio routes available for the call. 957 * 958 * @hide 959 */ getSupportedAudioRoutes()960 public int getSupportedAudioRoutes() { 961 return mSupportedAudioRoutes; 962 } 963 964 /** 965 * @return For a {@link #STATE_DISCONNECTED} {@code Call}, the disconnect cause expressed 966 * by {@link android.telecom.DisconnectCause}. 967 */ getDisconnectCause()968 public DisconnectCause getDisconnectCause() { 969 return mDisconnectCause; 970 } 971 972 /** 973 * Returns the time the {@link Call} connected (i.e. became active). This information is 974 * updated periodically, but user interfaces should not rely on this to display the "call 975 * time clock". For the time when the call was first added to Telecom, see 976 * {@link #getCreationTimeMillis()}. 977 * 978 * @return The time the {@link Call} connected in milliseconds since the epoch. 979 */ getConnectTimeMillis()980 public final long getConnectTimeMillis() { 981 return mConnectTimeMillis; 982 } 983 984 /** 985 * @return Information about any calling gateway the {@code Call} may be using. 986 */ getGatewayInfo()987 public GatewayInfo getGatewayInfo() { 988 return mGatewayInfo; 989 } 990 991 /** 992 * @return The video state of the {@code Call}. 993 */ getVideoState()994 public int getVideoState() { 995 return mVideoState; 996 } 997 998 /** 999 * @return The current {@link android.telecom.StatusHints}, or {@code null} if none 1000 * have been set. 1001 */ getStatusHints()1002 public StatusHints getStatusHints() { 1003 return mStatusHints; 1004 } 1005 1006 /** 1007 * @return The extras associated with this call. 1008 */ getExtras()1009 public Bundle getExtras() { 1010 return mExtras; 1011 } 1012 1013 /** 1014 * @return The extras used with the original intent to place this call. 1015 */ getIntentExtras()1016 public Bundle getIntentExtras() { 1017 return mIntentExtras; 1018 } 1019 1020 /** 1021 * Returns the time when the call was first created and added to Telecom. This is the same 1022 * time that is logged as the start time in the Call Log (see 1023 * {@link android.provider.CallLog.Calls#DATE}). To determine when the call was connected 1024 * (became active), see {@link #getConnectTimeMillis()}. 1025 * 1026 * @return The creation time of the call, in millis since the epoch. 1027 */ getCreationTimeMillis()1028 public long getCreationTimeMillis() { 1029 return mCreationTimeMillis; 1030 } 1031 1032 /** 1033 * Returns the name of the caller on the remote end, as derived from a 1034 * {@link android.provider.ContactsContract} lookup of the call's handle. 1035 * @return The name of the caller, or {@code null} if the lookup is not yet complete, if 1036 * there's no contacts entry for the caller, or if the {@link InCallService} does 1037 * not hold the {@link android.Manifest.permission#READ_CONTACTS} permission. 1038 */ getContactDisplayName()1039 public @Nullable String getContactDisplayName() { 1040 return mContactDisplayName; 1041 } 1042 1043 /** 1044 * Indicates whether the call is an incoming or outgoing call. 1045 * @return The call's direction. 1046 */ getCallDirection()1047 public @CallDirection int getCallDirection() { 1048 return mCallDirection; 1049 } 1050 1051 /** 1052 * Gets the verification status for the phone number of an incoming call as identified in 1053 * ATIS-1000082. 1054 * <p> 1055 * For incoming calls, the number verification status indicates whether the device was 1056 * able to verify the authenticity of the calling number using the STIR process outlined 1057 * in ATIS-1000082. {@link Connection#VERIFICATION_STATUS_NOT_VERIFIED} indicates that 1058 * the network was not able to use STIR to verify the caller's number (i.e. nothing is 1059 * known regarding the authenticity of the number. 1060 * {@link Connection#VERIFICATION_STATUS_PASSED} indicates that the network was able to 1061 * use STIR to verify the caller's number. This indicates that the network has a high 1062 * degree of confidence that the incoming call actually originated from the indicated 1063 * number. {@link Connection#VERIFICATION_STATUS_FAILED} indicates that the network's 1064 * STIR verification did not pass. This indicates that the incoming call may not 1065 * actually be from the indicated number. This could occur if, for example, the caller 1066 * is using an impersonated phone number. 1067 * <p> 1068 * A {@link CallScreeningService} can use this information to help determine if an 1069 * incoming call is potentially an unwanted call. A verification status of 1070 * {@link Connection#VERIFICATION_STATUS_FAILED} indicates that an incoming call may not 1071 * actually be from the number indicated on the call (i.e. impersonated number) and that it 1072 * should potentially be blocked. Likewise, 1073 * {@link Connection#VERIFICATION_STATUS_PASSED} can be used as a positive signal to 1074 * help clarify that the incoming call is originating from the indicated number and it 1075 * is less likely to be an undesirable call. 1076 * <p> 1077 * An {@link InCallService} can use this information to provide a visual indicator to the 1078 * user regarding the verification status of a call and to help identify calls from 1079 * potentially impersonated numbers. 1080 * @return the verification status. 1081 */ getCallerNumberVerificationStatus()1082 public @Connection.VerificationStatus int getCallerNumberVerificationStatus() { 1083 return mCallerNumberVerificationStatus; 1084 } 1085 1086 /** 1087 * Gets the user that originated the call 1088 * @return The user 1089 * 1090 * @hide 1091 */ getAssociatedUser()1092 public UserHandle getAssociatedUser() { 1093 return mAssociatedUser; 1094 } 1095 1096 @Override equals(Object o)1097 public boolean equals(Object o) { 1098 if (o instanceof Details) { 1099 Details d = (Details) o; 1100 return 1101 Objects.equals(mState, d.mState) && 1102 Objects.equals(mHandle, d.mHandle) && 1103 Objects.equals(mHandlePresentation, d.mHandlePresentation) && 1104 Objects.equals(mCallerDisplayName, d.mCallerDisplayName) && 1105 Objects.equals(mCallerDisplayNamePresentation, 1106 d.mCallerDisplayNamePresentation) && 1107 Objects.equals(mAccountHandle, d.mAccountHandle) && 1108 Objects.equals(mCallCapabilities, d.mCallCapabilities) && 1109 Objects.equals(mCallProperties, d.mCallProperties) && 1110 Objects.equals(mDisconnectCause, d.mDisconnectCause) && 1111 Objects.equals(mConnectTimeMillis, d.mConnectTimeMillis) && 1112 Objects.equals(mGatewayInfo, d.mGatewayInfo) && 1113 Objects.equals(mVideoState, d.mVideoState) && 1114 Objects.equals(mStatusHints, d.mStatusHints) && 1115 areBundlesEqual(mExtras, d.mExtras) && 1116 areBundlesEqual(mIntentExtras, d.mIntentExtras) && 1117 Objects.equals(mCreationTimeMillis, d.mCreationTimeMillis) && 1118 Objects.equals(mContactDisplayName, d.mContactDisplayName) && 1119 Objects.equals(mCallDirection, d.mCallDirection) && 1120 Objects.equals(mCallerNumberVerificationStatus, 1121 d.mCallerNumberVerificationStatus) && 1122 Objects.equals(mContactPhotoUri, d.mContactPhotoUri) && 1123 Objects.equals(mAssociatedUser, d.mAssociatedUser); 1124 } 1125 return false; 1126 } 1127 1128 @Override hashCode()1129 public int hashCode() { 1130 return Objects.hash(mState, 1131 mHandle, 1132 mHandlePresentation, 1133 mCallerDisplayName, 1134 mCallerDisplayNamePresentation, 1135 mAccountHandle, 1136 mCallCapabilities, 1137 mCallProperties, 1138 mDisconnectCause, 1139 mConnectTimeMillis, 1140 mGatewayInfo, 1141 mVideoState, 1142 mStatusHints, 1143 mExtras, 1144 mIntentExtras, 1145 mCreationTimeMillis, 1146 mContactDisplayName, 1147 mCallDirection, 1148 mCallerNumberVerificationStatus, 1149 mContactPhotoUri, 1150 mAssociatedUser); 1151 } 1152 1153 /** {@hide} */ Details( @allState int state, String telecomCallId, Uri handle, int handlePresentation, String callerDisplayName, int callerDisplayNamePresentation, PhoneAccountHandle accountHandle, int capabilities, int properties, DisconnectCause disconnectCause, long connectTimeMillis, GatewayInfo gatewayInfo, int videoState, StatusHints statusHints, Bundle extras, Bundle intentExtras, long creationTimeMillis, String contactDisplayName, int callDirection, int callerNumberVerificationStatus, Uri contactPhotoUri, UserHandle originatingUser)1154 public Details( 1155 @CallState int state, 1156 String telecomCallId, 1157 Uri handle, 1158 int handlePresentation, 1159 String callerDisplayName, 1160 int callerDisplayNamePresentation, 1161 PhoneAccountHandle accountHandle, 1162 int capabilities, 1163 int properties, 1164 DisconnectCause disconnectCause, 1165 long connectTimeMillis, 1166 GatewayInfo gatewayInfo, 1167 int videoState, 1168 StatusHints statusHints, 1169 Bundle extras, 1170 Bundle intentExtras, 1171 long creationTimeMillis, 1172 String contactDisplayName, 1173 int callDirection, 1174 int callerNumberVerificationStatus, 1175 Uri contactPhotoUri, 1176 UserHandle originatingUser) { 1177 mState = state; 1178 mTelecomCallId = telecomCallId; 1179 mHandle = handle; 1180 mHandlePresentation = handlePresentation; 1181 mCallerDisplayName = callerDisplayName; 1182 mCallerDisplayNamePresentation = callerDisplayNamePresentation; 1183 mAccountHandle = accountHandle; 1184 mCallCapabilities = capabilities; 1185 mCallProperties = properties; 1186 mDisconnectCause = disconnectCause; 1187 mConnectTimeMillis = connectTimeMillis; 1188 mGatewayInfo = gatewayInfo; 1189 mVideoState = videoState; 1190 mStatusHints = statusHints; 1191 mExtras = extras; 1192 mIntentExtras = intentExtras; 1193 mCreationTimeMillis = creationTimeMillis; 1194 mContactDisplayName = contactDisplayName; 1195 mCallDirection = callDirection; 1196 mCallerNumberVerificationStatus = callerNumberVerificationStatus; 1197 mContactPhotoUri = contactPhotoUri; 1198 mAssociatedUser = originatingUser; 1199 } 1200 1201 /** {@hide} */ createFromParcelableCall(ParcelableCall parcelableCall)1202 public static Details createFromParcelableCall(ParcelableCall parcelableCall) { 1203 return new Details( 1204 parcelableCall.getState(), 1205 parcelableCall.getId(), 1206 parcelableCall.getHandle(), 1207 parcelableCall.getHandlePresentation(), 1208 parcelableCall.getCallerDisplayName(), 1209 parcelableCall.getCallerDisplayNamePresentation(), 1210 parcelableCall.getAccountHandle(), 1211 parcelableCall.getCapabilities(), 1212 parcelableCall.getProperties(), 1213 parcelableCall.getDisconnectCause(), 1214 parcelableCall.getConnectTimeMillis(), 1215 parcelableCall.getGatewayInfo(), 1216 parcelableCall.getVideoState(), 1217 parcelableCall.getStatusHints(), 1218 parcelableCall.getExtras(), 1219 parcelableCall.getIntentExtras(), 1220 parcelableCall.getCreationTimeMillis(), 1221 parcelableCall.getContactDisplayName(), 1222 parcelableCall.getCallDirection(), 1223 parcelableCall.getCallerNumberVerificationStatus(), 1224 parcelableCall.getContactPhotoUri(), 1225 parcelableCall.getAssociatedUser() 1226 ); 1227 } 1228 1229 @Override toString()1230 public String toString() { 1231 StringBuilder sb = new StringBuilder(); 1232 sb.append("[id: "); 1233 sb.append(mTelecomCallId); 1234 sb.append(", state: "); 1235 sb.append(Call.stateToString(mState)); 1236 sb.append(", pa: "); 1237 sb.append(mAccountHandle); 1238 sb.append(", hdl: "); 1239 sb.append(Log.piiHandle(mHandle)); 1240 sb.append(", hdlPres: "); 1241 sb.append(mHandlePresentation); 1242 sb.append(", videoState: "); 1243 sb.append(VideoProfile.videoStateToString(mVideoState)); 1244 sb.append(", caps: "); 1245 sb.append(capabilitiesToString(mCallCapabilities)); 1246 sb.append(", props: "); 1247 sb.append(propertiesToString(mCallProperties)); 1248 sb.append("]"); 1249 return sb.toString(); 1250 } 1251 } 1252 1253 /** 1254 * Defines callbacks which inform the {@link InCallService} of changes to a {@link Call}. 1255 * These callbacks can originate from the Telecom framework, or a {@link ConnectionService} 1256 * implementation. 1257 * <p> 1258 * You can handle these callbacks by extending the {@link Callback} class and overriding the 1259 * callbacks that your {@link InCallService} is interested in. The callback methods include the 1260 * {@link Call} for which the callback applies, allowing reuse of a single instance of your 1261 * {@link Callback} implementation, if desired. 1262 * <p> 1263 * Use {@link Call#registerCallback(Callback)} to register your callback(s). Ensure 1264 * {@link Call#unregisterCallback(Callback)} is called when you no longer require callbacks 1265 * (typically in {@link InCallService#onCallRemoved(Call)}). 1266 * Note: Callbacks which occur before you call {@link Call#registerCallback(Callback)} will not 1267 * reach your implementation of {@link Callback}, so it is important to register your callback 1268 * as soon as your {@link InCallService} is notified of a new call via 1269 * {@link InCallService#onCallAdded(Call)}. 1270 */ 1271 public static abstract class Callback { 1272 /** 1273 * @hide 1274 */ 1275 @IntDef(prefix = { "HANDOVER_" }, 1276 value = {HANDOVER_FAILURE_DEST_APP_REJECTED, HANDOVER_FAILURE_NOT_SUPPORTED, 1277 HANDOVER_FAILURE_USER_REJECTED, HANDOVER_FAILURE_ONGOING_EMERGENCY_CALL, 1278 HANDOVER_FAILURE_UNKNOWN}) 1279 @Retention(RetentionPolicy.SOURCE) 1280 public @interface HandoverFailureErrors {} 1281 1282 /** 1283 * Handover failure reason returned via {@link #onHandoverFailed(Call, int)} when the app 1284 * to handover the call to rejects the handover request. 1285 * <p> 1286 * Will be returned when {@link Call#handoverTo(PhoneAccountHandle, int, Bundle)} is called 1287 * and the destination {@link PhoneAccountHandle}'s {@link ConnectionService} returns a 1288 * {@code null} {@link Connection} from 1289 * {@link ConnectionService#onCreateOutgoingHandoverConnection(PhoneAccountHandle, 1290 * ConnectionRequest)}. 1291 * <p> 1292 * For more information on call handovers, see 1293 * {@link #handoverTo(PhoneAccountHandle, int, Bundle)}. 1294 */ 1295 public static final int HANDOVER_FAILURE_DEST_APP_REJECTED = 1; 1296 1297 /** 1298 * Handover failure reason returned via {@link #onHandoverFailed(Call, int)} when a handover 1299 * is initiated but the source or destination app does not support handover. 1300 * <p> 1301 * Will be returned when a handover is requested via 1302 * {@link #handoverTo(PhoneAccountHandle, int, Bundle)} and the destination 1303 * {@link PhoneAccountHandle} does not declare 1304 * {@link PhoneAccount#EXTRA_SUPPORTS_HANDOVER_TO}. May also be returned when a handover is 1305 * requested at the {@link PhoneAccountHandle} for the current call (i.e. the source call's 1306 * {@link Details#getAccountHandle()}) does not declare 1307 * {@link PhoneAccount#EXTRA_SUPPORTS_HANDOVER_FROM}. 1308 * <p> 1309 * For more information on call handovers, see 1310 * {@link #handoverTo(PhoneAccountHandle, int, Bundle)}. 1311 */ 1312 public static final int HANDOVER_FAILURE_NOT_SUPPORTED = 2; 1313 1314 /** 1315 * Handover failure reason returned via {@link #onHandoverFailed(Call, int)} when the remote 1316 * user rejects the handover request. 1317 * <p> 1318 * For more information on call handovers, see 1319 * {@link #handoverTo(PhoneAccountHandle, int, Bundle)}. 1320 */ 1321 public static final int HANDOVER_FAILURE_USER_REJECTED = 3; 1322 1323 /** 1324 * Handover failure reason returned via {@link #onHandoverFailed(Call, int)} when there 1325 * is ongoing emergency call. 1326 * <p> 1327 * This error code is returned when {@link #handoverTo(PhoneAccountHandle, int, Bundle)} is 1328 * called on an emergency call, or if any other call is an emergency call. 1329 * <p> 1330 * Handovers are not permitted while there are ongoing emergency calls. 1331 * <p> 1332 * For more information on call handovers, see 1333 * {@link #handoverTo(PhoneAccountHandle, int, Bundle)}. 1334 */ 1335 public static final int HANDOVER_FAILURE_ONGOING_EMERGENCY_CALL = 4; 1336 1337 /** 1338 * Handover failure reason returned via {@link #onHandoverFailed(Call, int)} when a handover 1339 * fails for an unknown reason. 1340 * <p> 1341 * For more information on call handovers, see 1342 * {@link #handoverTo(PhoneAccountHandle, int, Bundle)}. 1343 */ 1344 public static final int HANDOVER_FAILURE_UNKNOWN = 5; 1345 1346 /** 1347 * Invoked when the state of this {@code Call} has changed. See {@link #getState()}. 1348 * 1349 * @param call The {@code Call} invoking this method. 1350 * @param state The new state of the {@code Call}. 1351 */ onStateChanged(Call call, @CallState int state)1352 public void onStateChanged(Call call, @CallState int state) {} 1353 1354 /** 1355 * Invoked when the parent of this {@code Call} has changed. See {@link #getParent()}. 1356 * 1357 * @param call The {@code Call} invoking this method. 1358 * @param parent The new parent of the {@code Call}. 1359 */ onParentChanged(Call call, Call parent)1360 public void onParentChanged(Call call, Call parent) {} 1361 1362 /** 1363 * Invoked when the children of this {@code Call} have changed. See {@link #getChildren()}. 1364 * 1365 * @param call The {@code Call} invoking this method. 1366 * @param children The new children of the {@code Call}. 1367 */ onChildrenChanged(Call call, List<Call> children)1368 public void onChildrenChanged(Call call, List<Call> children) {} 1369 1370 /** 1371 * Invoked when the details of this {@code Call} have changed. See {@link #getDetails()}. 1372 * 1373 * @param call The {@code Call} invoking this method. 1374 * @param details A {@code Details} object describing the {@code Call}. 1375 */ onDetailsChanged(Call call, Details details)1376 public void onDetailsChanged(Call call, Details details) {} 1377 1378 /** 1379 * Invoked when the text messages that can be used as responses to the incoming 1380 * {@code Call} are loaded from the relevant database. 1381 * See {@link #getCannedTextResponses()}. 1382 * 1383 * @param call The {@code Call} invoking this method. 1384 * @param cannedTextResponses The text messages useable as responses. 1385 */ onCannedTextResponsesLoaded(Call call, List<String> cannedTextResponses)1386 public void onCannedTextResponsesLoaded(Call call, List<String> cannedTextResponses) {} 1387 1388 /** 1389 * Invoked when the post-dial sequence in the outgoing {@code Call} has reached a pause 1390 * character. This causes the post-dial signals to stop pending user confirmation. An 1391 * implementation should present this choice to the user and invoke 1392 * {@link #postDialContinue(boolean)} when the user makes the choice. 1393 * 1394 * @param call The {@code Call} invoking this method. 1395 * @param remainingPostDialSequence The post-dial characters that remain to be sent. 1396 */ onPostDialWait(Call call, String remainingPostDialSequence)1397 public void onPostDialWait(Call call, String remainingPostDialSequence) {} 1398 1399 /** 1400 * Invoked when the {@code Call.VideoCall} of the {@code Call} has changed. 1401 * 1402 * @param call The {@code Call} invoking this method. 1403 * @param videoCall The {@code Call.VideoCall} associated with the {@code Call}. 1404 */ onVideoCallChanged(Call call, InCallService.VideoCall videoCall)1405 public void onVideoCallChanged(Call call, InCallService.VideoCall videoCall) {} 1406 1407 /** 1408 * Invoked when the {@code Call} is destroyed. Clients should refrain from cleaning 1409 * up their UI for the {@code Call} in response to state transitions. Specifically, 1410 * clients should not assume that a {@link #onStateChanged(Call, int)} with a state of 1411 * {@link #STATE_DISCONNECTED} is the final notification the {@code Call} will send. Rather, 1412 * clients should wait for this method to be invoked. 1413 * 1414 * @param call The {@code Call} being destroyed. 1415 */ onCallDestroyed(Call call)1416 public void onCallDestroyed(Call call) {} 1417 1418 /** 1419 * Invoked upon changes to the set of {@code Call}s with which this {@code Call} can be 1420 * conferenced. 1421 * 1422 * @param call The {@code Call} being updated. 1423 * @param conferenceableCalls The {@code Call}s with which this {@code Call} can be 1424 * conferenced. 1425 */ onConferenceableCallsChanged(Call call, List<Call> conferenceableCalls)1426 public void onConferenceableCallsChanged(Call call, List<Call> conferenceableCalls) {} 1427 1428 /** 1429 * Invoked when a {@link Call} receives an event from its associated {@link Connection} or 1430 * {@link Conference}. 1431 * <p> 1432 * Where possible, the Call should make an attempt to handle {@link Connection} events which 1433 * are part of the {@code android.telecom.*} namespace. The Call should ignore any events 1434 * it does not wish to handle. Unexpected events should be handled gracefully, as it is 1435 * possible that a {@link ConnectionService} has defined its own Connection events which a 1436 * Call is not aware of. 1437 * <p> 1438 * See {@link Connection#sendConnectionEvent(String, Bundle)}, 1439 * {@link Conference#sendConferenceEvent(String, Bundle)}. 1440 * 1441 * @param call The {@code Call} receiving the event. 1442 * @param event The event. 1443 * @param extras Extras associated with the connection event. 1444 */ onConnectionEvent(Call call, String event, Bundle extras)1445 public void onConnectionEvent(Call call, String event, Bundle extras) {} 1446 1447 /** 1448 * Invoked when the RTT mode changes for this call. 1449 * @param call The call whose RTT mode has changed. 1450 * @param mode the new RTT mode, one of 1451 * {@link RttCall#RTT_MODE_FULL}, {@link RttCall#RTT_MODE_HCO}, 1452 * or {@link RttCall#RTT_MODE_VCO} 1453 */ onRttModeChanged(Call call, int mode)1454 public void onRttModeChanged(Call call, int mode) {} 1455 1456 /** 1457 * Invoked when the call's RTT status changes, either from off to on or from on to off. 1458 * @param call The call whose RTT status has changed. 1459 * @param enabled whether RTT is now enabled or disabled 1460 * @param rttCall the {@link RttCall} object to use for reading and writing if RTT is now 1461 * on, null otherwise. 1462 */ onRttStatusChanged(Call call, boolean enabled, RttCall rttCall)1463 public void onRttStatusChanged(Call call, boolean enabled, RttCall rttCall) {} 1464 1465 /** 1466 * Invoked when the remote end of the connection has requested that an RTT communication 1467 * channel be opened. A response to this should be sent via {@link #respondToRttRequest} 1468 * with the same ID that this method is invoked with. 1469 * @param call The call which the RTT request was placed on 1470 * @param id The ID of the request. 1471 */ onRttRequest(Call call, int id)1472 public void onRttRequest(Call call, int id) {} 1473 1474 /** 1475 * Invoked when the RTT session failed to initiate for some reason, including rejection 1476 * by the remote party. 1477 * <p> 1478 * This callback will ONLY be invoked to report a failure related to a user initiated 1479 * session modification request (i.e. {@link Call#sendRttRequest()}). 1480 * <p> 1481 * If a call is initiated with {@link TelecomManager#EXTRA_START_CALL_WITH_RTT} specified, 1482 * the availability of RTT can be determined by checking {@link Details#PROPERTY_RTT} 1483 * once the call enters state {@link Details#STATE_ACTIVE}. 1484 * 1485 * @param call The call which the RTT initiation failure occurred on. 1486 * @param reason One of the status codes defined in 1487 * {@link android.telecom.Connection.RttModifyStatus}, with the exception of 1488 * {@link android.telecom.Connection.RttModifyStatus#SESSION_MODIFY_REQUEST_SUCCESS}. 1489 */ onRttInitiationFailure(Call call, @android.telecom.Connection.RttModifyStatus.RttSessionModifyStatus int reason)1490 public void onRttInitiationFailure(Call call, 1491 @android.telecom.Connection.RttModifyStatus.RttSessionModifyStatus int reason) {} 1492 1493 /** 1494 * Invoked when Call handover from one {@link PhoneAccount} to other {@link PhoneAccount} 1495 * has completed successfully. 1496 * <p> 1497 * For a full discussion of the handover process and the APIs involved, see 1498 * {@link android.telecom.Call#handoverTo(PhoneAccountHandle, int, Bundle)}. 1499 * 1500 * @param call The call which had initiated handover. 1501 */ onHandoverComplete(Call call)1502 public void onHandoverComplete(Call call) {} 1503 1504 /** 1505 * Invoked when Call handover from one {@link PhoneAccount} to other {@link PhoneAccount} 1506 * has failed. 1507 * <p> 1508 * For a full discussion of the handover process and the APIs involved, see 1509 * {@link android.telecom.Call#handoverTo(PhoneAccountHandle, int, Bundle)}. 1510 * 1511 * @param call The call which had initiated handover. 1512 * @param failureReason Error reason for failure. 1513 */ onHandoverFailed(Call call, @HandoverFailureErrors int failureReason)1514 public void onHandoverFailed(Call call, @HandoverFailureErrors int failureReason) {} 1515 } 1516 1517 /** 1518 * A class that holds the state that describes the state of the RTT channel to the remote 1519 * party, if it is active. 1520 */ 1521 public static final class RttCall { 1522 /** @hide */ 1523 @Retention(RetentionPolicy.SOURCE) 1524 @IntDef({RTT_MODE_INVALID, RTT_MODE_FULL, RTT_MODE_HCO, RTT_MODE_VCO}) 1525 public @interface RttAudioMode {} 1526 1527 /** 1528 * For metrics use. Default value in the proto. 1529 * @hide 1530 */ 1531 public static final int RTT_MODE_INVALID = 0; 1532 1533 /** 1534 * Indicates that there should be a bidirectional audio stream between the two parties 1535 * on the call. 1536 */ 1537 public static final int RTT_MODE_FULL = 1; 1538 1539 /** 1540 * Indicates that the local user should be able to hear the audio stream from the remote 1541 * user, but not vice versa. Equivalent to muting the microphone. 1542 */ 1543 public static final int RTT_MODE_HCO = 2; 1544 1545 /** 1546 * Indicates that the remote user should be able to hear the audio stream from the local 1547 * user, but not vice versa. Equivalent to setting the volume to zero. 1548 */ 1549 public static final int RTT_MODE_VCO = 3; 1550 1551 private static final int READ_BUFFER_SIZE = 1000; 1552 1553 private InputStreamReader mReceiveStream; 1554 private OutputStreamWriter mTransmitStream; 1555 private int mRttMode; 1556 private final InCallAdapter mInCallAdapter; 1557 private final String mTelecomCallId; 1558 private char[] mReadBuffer = new char[READ_BUFFER_SIZE]; 1559 1560 /** 1561 * @hide 1562 */ RttCall(String telecomCallId, InputStreamReader receiveStream, OutputStreamWriter transmitStream, int mode, InCallAdapter inCallAdapter)1563 public RttCall(String telecomCallId, InputStreamReader receiveStream, 1564 OutputStreamWriter transmitStream, int mode, InCallAdapter inCallAdapter) { 1565 mTelecomCallId = telecomCallId; 1566 mReceiveStream = receiveStream; 1567 mTransmitStream = transmitStream; 1568 mRttMode = mode; 1569 mInCallAdapter = inCallAdapter; 1570 } 1571 1572 /** 1573 * Returns the current RTT audio mode. 1574 * @return Current RTT audio mode. One of {@link #RTT_MODE_FULL}, {@link #RTT_MODE_VCO}, or 1575 * {@link #RTT_MODE_HCO}. 1576 */ getRttAudioMode()1577 public int getRttAudioMode() { 1578 return mRttMode; 1579 } 1580 1581 /** 1582 * Sets the RTT audio mode. The requested mode change will be communicated through 1583 * {@link Callback#onRttModeChanged(Call, int)}. 1584 * @param mode The desired RTT audio mode, one of {@link #RTT_MODE_FULL}, 1585 * {@link #RTT_MODE_VCO}, or {@link #RTT_MODE_HCO}. 1586 */ setRttMode(@ttAudioMode int mode)1587 public void setRttMode(@RttAudioMode int mode) { 1588 mInCallAdapter.setRttMode(mTelecomCallId, mode); 1589 } 1590 1591 /** 1592 * Writes the string {@param input} into the outgoing text stream for this RTT call. Since 1593 * RTT transmits text in real-time, this method should be called once for each user action. 1594 * For example, when the user enters text as discrete characters using the keyboard, this 1595 * method should be called once for each character. However, if the user enters text by 1596 * pasting or autocomplete, the entire contents of the pasted or autocompleted text should 1597 * be sent in one call to this method. 1598 * 1599 * This method is not thread-safe -- calling it from multiple threads simultaneously may 1600 * lead to interleaved text. 1601 * @param input The message to send to the remote user. 1602 */ write(String input)1603 public void write(String input) throws IOException { 1604 mTransmitStream.write(input); 1605 mTransmitStream.flush(); 1606 } 1607 1608 /** 1609 * Reads a string from the remote user, blocking if there is no data available. Returns 1610 * {@code null} if the RTT conversation has been terminated and there is no further data 1611 * to read. 1612 * 1613 * This method is not thread-safe -- calling it from multiple threads simultaneously may 1614 * lead to interleaved text. 1615 * @return A string containing text sent by the remote user, or {@code null} if the 1616 * conversation has been terminated or if there was an error while reading. 1617 */ read()1618 public String read() { 1619 try { 1620 int numRead = mReceiveStream.read(mReadBuffer, 0, READ_BUFFER_SIZE); 1621 if (numRead < 0) { 1622 return null; 1623 } 1624 return new String(mReadBuffer, 0, numRead); 1625 } catch (IOException e) { 1626 Log.w(this, "Exception encountered when reading from InputStreamReader: %s", e); 1627 return null; 1628 } 1629 } 1630 1631 /** 1632 * Non-blocking version of {@link #read()}. Returns {@code null} if there is nothing to 1633 * be read. 1634 * @return A string containing text entered by the user, or {@code null} if the user has 1635 * not entered any new text yet. 1636 */ readImmediately()1637 public String readImmediately() throws IOException { 1638 if (mReceiveStream.ready()) { 1639 int numRead = mReceiveStream.read(mReadBuffer, 0, READ_BUFFER_SIZE); 1640 if (numRead < 0) { 1641 return null; 1642 } 1643 return new String(mReadBuffer, 0, numRead); 1644 } else { 1645 return null; 1646 } 1647 } 1648 1649 /** 1650 * Closes the underlying file descriptors 1651 * @hide 1652 */ close()1653 public void close() { 1654 try { 1655 mReceiveStream.close(); 1656 } catch (IOException e) { 1657 // ignore 1658 } 1659 try { 1660 mTransmitStream.close(); 1661 } catch (IOException e) { 1662 // ignore 1663 } 1664 } 1665 } 1666 1667 /** 1668 * @deprecated Use {@code Call.Callback} instead. 1669 * @hide 1670 */ 1671 @Deprecated 1672 @SystemApi 1673 public static abstract class Listener extends Callback { } 1674 1675 private final Phone mPhone; 1676 private final String mTelecomCallId; 1677 private final InCallAdapter mInCallAdapter; 1678 private final List<String> mChildrenIds = new ArrayList<>(); 1679 private final List<Call> mChildren = new ArrayList<>(); 1680 private final List<Call> mUnmodifiableChildren = Collections.unmodifiableList(mChildren); 1681 private final List<CallbackRecord<Callback>> mCallbackRecords = new CopyOnWriteArrayList<>(); 1682 private final List<Call> mConferenceableCalls = new ArrayList<>(); 1683 private final List<Call> mUnmodifiableConferenceableCalls = 1684 Collections.unmodifiableList(mConferenceableCalls); 1685 1686 private boolean mChildrenCached; 1687 private String mParentId = null; 1688 private String mActiveGenericConferenceChild = null; 1689 private int mState; 1690 private List<String> mCannedTextResponses = null; 1691 private String mCallingPackage; 1692 private int mTargetSdkVersion; 1693 private String mRemainingPostDialSequence; 1694 private VideoCallImpl mVideoCallImpl; 1695 private RttCall mRttCall; 1696 private Details mDetails; 1697 private Bundle mExtras; 1698 1699 /** 1700 * Obtains the post-dial sequence remaining to be emitted by this {@code Call}, if any. 1701 * 1702 * @return The remaining post-dial sequence, or {@code null} if there is no post-dial sequence 1703 * remaining or this {@code Call} is not in a post-dial state. 1704 */ getRemainingPostDialSequence()1705 public String getRemainingPostDialSequence() { 1706 return mRemainingPostDialSequence; 1707 } 1708 1709 /** 1710 * Instructs this {@link #STATE_RINGING} {@code Call} to answer. 1711 * @param videoState The video state in which to answer the call. 1712 */ answer(@ideoProfile.VideoState int videoState)1713 public void answer(@VideoProfile.VideoState int videoState) { 1714 mInCallAdapter.answerCall(mTelecomCallId, videoState); 1715 } 1716 1717 /** 1718 * Instructs this {@link #STATE_RINGING} {@code Call} to deflect. 1719 * 1720 * @param address The address to which the call will be deflected. 1721 */ deflect(Uri address)1722 public void deflect(Uri address) { 1723 mInCallAdapter.deflectCall(mTelecomCallId, address); 1724 } 1725 1726 /** 1727 * Instructs this {@link #STATE_RINGING} {@code Call} to reject. 1728 * 1729 * @param rejectWithMessage Whether to reject with a text message. 1730 * @param textMessage An optional text message with which to respond. 1731 */ reject(boolean rejectWithMessage, String textMessage)1732 public void reject(boolean rejectWithMessage, String textMessage) { 1733 mInCallAdapter.rejectCall(mTelecomCallId, rejectWithMessage, textMessage); 1734 } 1735 1736 /** 1737 * Instructs the {@link ConnectionService} providing this {@link #STATE_RINGING} call that the 1738 * user has chosen to reject the call and has indicated a reason why the call is being rejected. 1739 * 1740 * @param rejectReason the reason the call is being rejected. 1741 */ reject(@ejectReason int rejectReason)1742 public void reject(@RejectReason int rejectReason) { 1743 mInCallAdapter.rejectCall(mTelecomCallId, rejectReason); 1744 } 1745 1746 /** 1747 * Instructs this {@code Call} to be transferred to another number. 1748 * 1749 * @param targetNumber The address to which the call will be transferred. 1750 * @param isConfirmationRequired if {@code true} it will initiate a confirmed transfer, 1751 * if {@code false}, it will initiate an unconfirmed transfer. 1752 * 1753 * @hide 1754 */ transfer(@onNull Uri targetNumber, boolean isConfirmationRequired)1755 public void transfer(@NonNull Uri targetNumber, boolean isConfirmationRequired) { 1756 mInCallAdapter.transferCall(mTelecomCallId, targetNumber, isConfirmationRequired); 1757 } 1758 1759 /** 1760 * Instructs this {@code Call} to be transferred to another ongoing call. 1761 * This will initiate CONSULTATIVE transfer. 1762 * @param toCall The other ongoing {@code Call} to which this call will be transferred. 1763 * 1764 * @hide 1765 */ transfer(@onNull android.telecom.Call toCall)1766 public void transfer(@NonNull android.telecom.Call toCall) { 1767 mInCallAdapter.transferCall(mTelecomCallId, toCall.mTelecomCallId); 1768 } 1769 1770 /** 1771 * Instructs this {@code Call} to disconnect. 1772 */ disconnect()1773 public void disconnect() { 1774 mInCallAdapter.disconnectCall(mTelecomCallId); 1775 } 1776 1777 /** 1778 * Instructs this {@code Call} to go on hold. 1779 */ hold()1780 public void hold() { 1781 mInCallAdapter.holdCall(mTelecomCallId); 1782 } 1783 1784 /** 1785 * Instructs this {@link #STATE_HOLDING} call to release from hold. 1786 */ unhold()1787 public void unhold() { 1788 mInCallAdapter.unholdCall(mTelecomCallId); 1789 } 1790 1791 /** 1792 * Instructs Telecom to put the call into the background audio processing state. 1793 * <p> 1794 * This method can be called either when the call is in {@link #STATE_RINGING} or 1795 * {@link #STATE_ACTIVE}. After Telecom acknowledges the request by setting the call's state to 1796 * {@link #STATE_AUDIO_PROCESSING}, your app may setup the audio paths with the audio stack in 1797 * order to capture and play audio on the call stream. 1798 * <p> 1799 * This method can only be called by the default dialer app. 1800 * <p> 1801 * Apps built with SDK version {@link android.os.Build.VERSION_CODES#R} or later which are using 1802 * the microphone as part of audio processing should specify the foreground service type using 1803 * the attribute {@link android.R.attr#foregroundServiceType} in the {@link InCallService} 1804 * service element of the app's manifest file. 1805 * The {@link ServiceInfo#FOREGROUND_SERVICE_TYPE_MICROPHONE} attribute should be specified. 1806 * @see <a href="https://developer.android.com/preview/privacy/foreground-service-types"> 1807 * the Android Developer Site</a> for more information. 1808 * @hide 1809 */ 1810 @SystemApi enterBackgroundAudioProcessing()1811 public void enterBackgroundAudioProcessing() { 1812 if (mState != STATE_ACTIVE && mState != STATE_RINGING) { 1813 throw new IllegalStateException("Call must be active or ringing"); 1814 } 1815 mInCallAdapter.enterBackgroundAudioProcessing(mTelecomCallId); 1816 } 1817 1818 /** 1819 * Instructs Telecom to come out of the background audio processing state requested by 1820 * {@link #enterBackgroundAudioProcessing()} or from the call screening service. 1821 * 1822 * This method can only be called when the call is in {@link #STATE_AUDIO_PROCESSING}. 1823 * 1824 * @param shouldRing If true, Telecom will put the call into the 1825 * {@link #STATE_SIMULATED_RINGING} state and notify other apps that there is 1826 * a ringing call. Otherwise, the call will go into {@link #STATE_ACTIVE} 1827 * immediately. 1828 * @hide 1829 */ 1830 @SystemApi exitBackgroundAudioProcessing(boolean shouldRing)1831 public void exitBackgroundAudioProcessing(boolean shouldRing) { 1832 if (mState != STATE_AUDIO_PROCESSING) { 1833 throw new IllegalStateException("Call must in the audio processing state"); 1834 } 1835 mInCallAdapter.exitBackgroundAudioProcessing(mTelecomCallId, shouldRing); 1836 } 1837 1838 /** 1839 * Instructs this {@code Call} to play a dual-tone multi-frequency signaling (DTMF) tone. 1840 * <p> 1841 * Tones are both played locally for the user to hear and sent to the network to be relayed 1842 * to the remote device. 1843 * <p> 1844 * You must ensure that any call to {@link #playDtmfTone(char)} is followed by a matching 1845 * call to {@link #stopDtmfTone()} and that each tone is stopped before a new one is started. 1846 * The play and stop commands are relayed to the underlying 1847 * {@link android.telecom.ConnectionService} as executed; implementations may not correctly 1848 * handle out of order commands. 1849 * 1850 * @param digit A character representing the DTMF digit for which to play the tone. This 1851 * value must be one of {@code '0'} through {@code '9'}, {@code '*'} or {@code '#'}. 1852 */ playDtmfTone(char digit)1853 public void playDtmfTone(char digit) { 1854 mInCallAdapter.playDtmfTone(mTelecomCallId, digit); 1855 } 1856 1857 /** 1858 * Instructs this {@code Call} to stop any dual-tone multi-frequency signaling (DTMF) tone 1859 * currently playing. 1860 * 1861 * DTMF tones are played by calling {@link #playDtmfTone(char)}. If no DTMF tone is 1862 * currently playing, this method will do nothing. 1863 */ stopDtmfTone()1864 public void stopDtmfTone() { 1865 mInCallAdapter.stopDtmfTone(mTelecomCallId); 1866 } 1867 1868 /** 1869 * Instructs this {@code Call} to continue playing a post-dial DTMF string. 1870 * 1871 * A post-dial DTMF string is a string of digits entered after a phone number, when dialed, 1872 * that are immediately sent as DTMF tones to the recipient as soon as the connection is made. 1873 * 1874 * If the DTMF string contains a {@link TelecomManager#DTMF_CHARACTER_PAUSE} symbol, this 1875 * {@code Call} will temporarily pause playing the tones for a pre-defined period of time. 1876 * 1877 * If the DTMF string contains a {@link TelecomManager#DTMF_CHARACTER_WAIT} symbol, this 1878 * {@code Call} will pause playing the tones and notify callbacks via 1879 * {@link Callback#onPostDialWait(Call, String)}. At this point, the in-call app 1880 * should display to the user an indication of this state and an affordance to continue 1881 * the postdial sequence. When the user decides to continue the postdial sequence, the in-call 1882 * app should invoke the {@link #postDialContinue(boolean)} method. 1883 * 1884 * @param proceed Whether or not to continue with the post-dial sequence. 1885 */ postDialContinue(boolean proceed)1886 public void postDialContinue(boolean proceed) { 1887 mInCallAdapter.postDialContinue(mTelecomCallId, proceed); 1888 } 1889 1890 /** 1891 * Notifies this {@code Call} that an account has been selected and to proceed with placing 1892 * an outgoing call. Optionally sets this account as the default account. 1893 */ phoneAccountSelected(PhoneAccountHandle accountHandle, boolean setDefault)1894 public void phoneAccountSelected(PhoneAccountHandle accountHandle, boolean setDefault) { 1895 mInCallAdapter.phoneAccountSelected(mTelecomCallId, accountHandle, setDefault); 1896 1897 } 1898 1899 /** 1900 * Instructs this {@code Call} to enter a conference. 1901 * 1902 * @param callToConferenceWith The other call with which to conference. 1903 */ conference(Call callToConferenceWith)1904 public void conference(Call callToConferenceWith) { 1905 if (callToConferenceWith != null) { 1906 mInCallAdapter.conference(mTelecomCallId, callToConferenceWith.mTelecomCallId); 1907 } 1908 } 1909 1910 /** 1911 * Instructs this {@code Call} to split from any conference call with which it may be 1912 * connected. 1913 */ splitFromConference()1914 public void splitFromConference() { 1915 mInCallAdapter.splitFromConference(mTelecomCallId); 1916 } 1917 1918 /** 1919 * Merges the calls within this conference. See {@link Details#CAPABILITY_MERGE_CONFERENCE}. 1920 */ mergeConference()1921 public void mergeConference() { 1922 mInCallAdapter.mergeConference(mTelecomCallId); 1923 } 1924 1925 /** 1926 * Swaps the calls within this conference. See {@link Details#CAPABILITY_SWAP_CONFERENCE}. 1927 */ swapConference()1928 public void swapConference() { 1929 mInCallAdapter.swapConference(mTelecomCallId); 1930 } 1931 1932 /** 1933 * Pulls participants to existing call by forming a conference call. 1934 * See {@link Details#CAPABILITY_ADD_PARTICIPANT}. 1935 * 1936 * @param participants participants to be pulled to existing call. 1937 */ addConferenceParticipants(@onNull List<Uri> participants)1938 public void addConferenceParticipants(@NonNull List<Uri> participants) { 1939 mInCallAdapter.addConferenceParticipants(mTelecomCallId, participants); 1940 } 1941 1942 /** 1943 * Initiates a request to the {@link ConnectionService} to pull an external call to the local 1944 * device. 1945 * <p> 1946 * Calls to this method are ignored if the call does not have the 1947 * {@link Call.Details#PROPERTY_IS_EXTERNAL_CALL} property set. 1948 * <p> 1949 * An {@link InCallService} will only see calls which support this method if it has the 1950 * {@link TelecomManager#METADATA_INCLUDE_EXTERNAL_CALLS} metadata set to {@code true} 1951 * in its manifest. 1952 */ pullExternalCall()1953 public void pullExternalCall() { 1954 // If this isn't an external call, ignore the request. 1955 if (!mDetails.hasProperty(Details.PROPERTY_IS_EXTERNAL_CALL)) { 1956 return; 1957 } 1958 1959 mInCallAdapter.pullExternalCall(mTelecomCallId); 1960 } 1961 1962 /** 1963 * Sends a {@code Call} event from this {@code Call} to the associated {@link Connection} in 1964 * the {@link ConnectionService}. 1965 * <p> 1966 * Call events are used to communicate point in time information from an {@link InCallService} 1967 * to a {@link ConnectionService}. A {@link ConnectionService} implementation could define 1968 * events which enable the {@link InCallService}, for example, toggle a unique feature of the 1969 * {@link ConnectionService}. 1970 * <p> 1971 * A {@link ConnectionService} can communicate to the {@link InCallService} using 1972 * {@link Connection#sendConnectionEvent(String, Bundle)}. 1973 * <p> 1974 * Events are exposed to {@link ConnectionService} implementations via 1975 * {@link android.telecom.Connection#onCallEvent(String, Bundle)}. 1976 * <p> 1977 * No assumptions should be made as to how a {@link ConnectionService} will handle these events. 1978 * The {@link InCallService} must assume that the {@link ConnectionService} could chose to 1979 * ignore some events altogether. 1980 * <p> 1981 * Events should be fully qualified (e.g., {@code com.example.event.MY_EVENT}) to avoid 1982 * conflicts between {@link InCallService} implementations. Further, {@link InCallService} 1983 * implementations shall not re-purpose events in the {@code android.*} namespace, nor shall 1984 * they define their own event types in this namespace. When defining a custom event type, 1985 * ensure the contents of the extras {@link Bundle} is clearly defined. Extra keys for this 1986 * bundle should be named similar to the event type (e.g. {@code com.example.extra.MY_EXTRA}). 1987 * <p> 1988 * When defining events and the associated extras, it is important to keep their behavior 1989 * consistent when the associated {@link InCallService} is updated. Support for deprecated 1990 * events/extras should me maintained to ensure backwards compatibility with older 1991 * {@link ConnectionService} implementations which were built to support the older behavior. 1992 * 1993 * @param event The connection event. 1994 * @param extras Bundle containing extra information associated with the event. 1995 */ sendCallEvent(String event, Bundle extras)1996 public void sendCallEvent(String event, Bundle extras) { 1997 mInCallAdapter.sendCallEvent(mTelecomCallId, event, mTargetSdkVersion, extras); 1998 } 1999 2000 /** 2001 * Sends an RTT upgrade request to the remote end of the connection. Success is not 2002 * guaranteed, and notification of success will be via the 2003 * {@link Callback#onRttStatusChanged(Call, boolean, RttCall)} callback. 2004 */ sendRttRequest()2005 public void sendRttRequest() { 2006 mInCallAdapter.sendRttRequest(mTelecomCallId); 2007 } 2008 2009 /** 2010 * Responds to an RTT request received via the {@link Callback#onRttRequest(Call, int)} )} 2011 * callback. 2012 * The ID used here should be the same as the ID that was received via the callback. 2013 * @param id The request ID received via {@link Callback#onRttRequest(Call, int)} 2014 * @param accept {@code true} if the RTT request should be accepted, {@code false} otherwise. 2015 */ respondToRttRequest(int id, boolean accept)2016 public void respondToRttRequest(int id, boolean accept) { 2017 mInCallAdapter.respondToRttRequest(mTelecomCallId, id, accept); 2018 } 2019 2020 /** 2021 * Initiates a handover of this {@link Call} to the {@link ConnectionService} identified 2022 * by {@code toHandle}. The videoState specified indicates the desired video state after the 2023 * handover. 2024 * <p> 2025 * A call handover is the process where an ongoing call is transferred from one app (i.e. 2026 * {@link ConnectionService} to another app. The user could, for example, choose to continue a 2027 * mobile network call in a video calling app. The mobile network call via the Telephony stack 2028 * is referred to as the source of the handover, and the video calling app is referred to as the 2029 * destination. 2030 * <p> 2031 * When considering a handover scenario the device this method is called on is considered the 2032 * <em>initiating</em> device (since the user initiates the handover from this device), and the 2033 * other device is considered the <em>receiving</em> device. 2034 * <p> 2035 * When this method is called on the <em>initiating</em> device, the Telecom framework will bind 2036 * to the {@link ConnectionService} defined by the {@code toHandle} {@link PhoneAccountHandle} 2037 * and invoke 2038 * {@link ConnectionService#onCreateOutgoingHandoverConnection(PhoneAccountHandle, 2039 * ConnectionRequest)} to inform the destination app that a request has been made to handover a 2040 * call to it. The app returns an instance of {@link Connection} to represent the handover call 2041 * At this point the app should display UI to indicate to the user that a call 2042 * handover is in process. 2043 * <p> 2044 * The destination app is responsible for communicating the handover request from the 2045 * <em>initiating</em> device to the <em>receiving</em> device. 2046 * <p> 2047 * When the app on the <em>receiving</em> device receives the handover request, it calls 2048 * {@link TelecomManager#acceptHandover(Uri, int, PhoneAccountHandle)} to continue the handover 2049 * process from the <em>initiating</em> device to the <em>receiving</em> device. At this point 2050 * the destination app on the <em>receiving</em> device should show UI to allow the user to 2051 * choose whether they want to continue their call in the destination app. 2052 * <p> 2053 * When the destination app on the <em>receiving</em> device calls 2054 * {@link TelecomManager#acceptHandover(Uri, int, PhoneAccountHandle)}, Telecom will bind to its 2055 * {@link ConnectionService} and call 2056 * {@link ConnectionService#onCreateIncomingHandoverConnection(PhoneAccountHandle, 2057 * ConnectionRequest)} to inform it of the handover request. The app returns an instance of 2058 * {@link Connection} to represent the handover call. 2059 * <p> 2060 * If the user of the <em>receiving</em> device accepts the handover, the app calls 2061 * {@link Connection#setActive()} to complete the handover process; Telecom will disconnect the 2062 * original call. If the user rejects the handover, the app calls 2063 * {@link Connection#setDisconnected(DisconnectCause)} and specifies a {@link DisconnectCause} 2064 * of {@link DisconnectCause#CANCELED} to indicate that the handover has been cancelled. 2065 * <p> 2066 * Telecom will only allow handovers from {@link PhoneAccount}s which declare 2067 * {@link PhoneAccount#EXTRA_SUPPORTS_HANDOVER_FROM}. Similarly, the {@link PhoneAccount} 2068 * specified by {@code toHandle} must declare {@link PhoneAccount#EXTRA_SUPPORTS_HANDOVER_TO}. 2069 * <p> 2070 * Errors in the handover process are reported to the {@link InCallService} via 2071 * {@link Callback#onHandoverFailed(Call, int)}. Errors in the handover process are reported to 2072 * the involved {@link ConnectionService}s via 2073 * {@link ConnectionService#onHandoverFailed(ConnectionRequest, int)}. 2074 * 2075 * @param toHandle {@link PhoneAccountHandle} of the {@link ConnectionService} to handover 2076 * this call to. 2077 * @param videoState Indicates the video state desired after the handover (see the 2078 * {@code STATE_*} constants defined in {@link VideoProfile}). 2079 * @param extras Bundle containing extra information to be passed to the 2080 * {@link ConnectionService} 2081 */ handoverTo(PhoneAccountHandle toHandle, @VideoProfile.VideoState int videoState, Bundle extras)2082 public void handoverTo(PhoneAccountHandle toHandle, @VideoProfile.VideoState int videoState, 2083 Bundle extras) { 2084 mInCallAdapter.handoverTo(mTelecomCallId, toHandle, videoState, extras); 2085 } 2086 2087 /** 2088 * Terminate the RTT session on this call. The resulting state change will be notified via 2089 * the {@link Callback#onRttStatusChanged(Call, boolean, RttCall)} callback. 2090 */ stopRtt()2091 public void stopRtt() { 2092 mInCallAdapter.stopRtt(mTelecomCallId); 2093 } 2094 2095 /** 2096 * Adds some extras to this {@link Call}. Existing keys are replaced and new ones are 2097 * added. 2098 * <p> 2099 * No assumptions should be made as to how an In-Call UI or service will handle these 2100 * extras. Keys should be fully qualified (e.g., com.example.MY_EXTRA) to avoid conflicts. 2101 * <p> 2102 * Extras added using this method will be made available to the {@link ConnectionService} 2103 * associated with this {@link Call} and notified via 2104 * {@link Connection#onExtrasChanged(Bundle)}. 2105 * <p> 2106 * Extras added using this method will also be available to other running {@link InCallService}s 2107 * and notified via {@link Call.Callback#onDetailsChanged(Call, Details)}. The extras can be 2108 * accessed via {@link Details#getExtras()}. 2109 * 2110 * @param extras The extras to add. 2111 */ putExtras(Bundle extras)2112 public final void putExtras(Bundle extras) { 2113 if (extras == null) { 2114 return; 2115 } 2116 2117 if (mExtras == null) { 2118 mExtras = new Bundle(); 2119 } 2120 mExtras.putAll(extras); 2121 mInCallAdapter.putExtras(mTelecomCallId, extras); 2122 } 2123 2124 /** 2125 * Adds a boolean extra to this {@link Call}. 2126 * 2127 * @param key The extra key. 2128 * @param value The value. 2129 * @hide 2130 */ putExtra(String key, boolean value)2131 public final void putExtra(String key, boolean value) { 2132 if (mExtras == null) { 2133 mExtras = new Bundle(); 2134 } 2135 mExtras.putBoolean(key, value); 2136 mInCallAdapter.putExtra(mTelecomCallId, key, value); 2137 } 2138 2139 /** 2140 * Adds an integer extra to this {@link Call}. 2141 * 2142 * @param key The extra key. 2143 * @param value The value. 2144 * @hide 2145 */ putExtra(String key, int value)2146 public final void putExtra(String key, int value) { 2147 if (mExtras == null) { 2148 mExtras = new Bundle(); 2149 } 2150 mExtras.putInt(key, value); 2151 mInCallAdapter.putExtra(mTelecomCallId, key, value); 2152 } 2153 2154 /** 2155 * Adds a string extra to this {@link Call}. 2156 * 2157 * @param key The extra key. 2158 * @param value The value. 2159 * @hide 2160 */ putExtra(String key, String value)2161 public final void putExtra(String key, String value) { 2162 if (mExtras == null) { 2163 mExtras = new Bundle(); 2164 } 2165 mExtras.putString(key, value); 2166 mInCallAdapter.putExtra(mTelecomCallId, key, value); 2167 } 2168 2169 /** 2170 * Removes extras from this {@link Call}. 2171 * 2172 * @param keys The keys of the extras to remove. 2173 */ removeExtras(List<String> keys)2174 public final void removeExtras(List<String> keys) { 2175 if (mExtras != null) { 2176 for (String key : keys) { 2177 mExtras.remove(key); 2178 } 2179 if (mExtras.size() == 0) { 2180 mExtras = null; 2181 } 2182 } 2183 mInCallAdapter.removeExtras(mTelecomCallId, keys); 2184 } 2185 2186 /** 2187 * Removes extras from this {@link Call}. 2188 * 2189 * @param keys The keys of the extras to remove. 2190 */ removeExtras(String .... keys)2191 public final void removeExtras(String ... keys) { 2192 removeExtras(Arrays.asList(keys)); 2193 } 2194 2195 /** 2196 * Obtains the parent of this {@code Call} in a conference, if any. 2197 * 2198 * @return The parent {@code Call}, or {@code null} if this {@code Call} is not a 2199 * child of any conference {@code Call}s. 2200 */ getParent()2201 public Call getParent() { 2202 if (mParentId != null) { 2203 return mPhone.internalGetCallByTelecomId(mParentId); 2204 } 2205 return null; 2206 } 2207 2208 /** 2209 * Obtains the children of this conference {@code Call}, if any. 2210 * 2211 * @return The children of this {@code Call} if this {@code Call} is a conference, or an empty 2212 * {@code List} otherwise. 2213 */ getChildren()2214 public List<Call> getChildren() { 2215 if (!mChildrenCached) { 2216 mChildrenCached = true; 2217 mChildren.clear(); 2218 2219 for(String id : mChildrenIds) { 2220 Call call = mPhone.internalGetCallByTelecomId(id); 2221 if (call == null) { 2222 // At least one child was still not found, so do not save true for "cached" 2223 mChildrenCached = false; 2224 } else { 2225 mChildren.add(call); 2226 } 2227 } 2228 } 2229 2230 return mUnmodifiableChildren; 2231 } 2232 2233 /** 2234 * Returns the list of {@code Call}s with which this {@code Call} is allowed to conference. 2235 * 2236 * @return The list of conferenceable {@code Call}s. 2237 */ getConferenceableCalls()2238 public List<Call> getConferenceableCalls() { 2239 return mUnmodifiableConferenceableCalls; 2240 } 2241 2242 /** 2243 * Obtains the state of this {@code Call}. 2244 * 2245 * @return The call state. 2246 * @deprecated The call state is available via {@link Call.Details#getState()}. 2247 */ 2248 @Deprecated getState()2249 public @CallState int getState() { 2250 return mState; 2251 } 2252 2253 /** 2254 * Returns the child {@link Call} in a generic conference that is currently active. 2255 * 2256 * A "generic conference" is the mechanism used to support two simultaneous calls on a device 2257 * in CDMA networks. It is effectively equivalent to having one call active and one call on hold 2258 * in GSM or IMS calls. This method returns the currently active call. 2259 * 2260 * In a generic conference, the network exposes the conference to us as a single call, and we 2261 * switch between talking to the two participants using a CDMA flash command. Since the network 2262 * exposes no additional information about the call, the only way we know which caller we're 2263 * currently talking to is by keeping track of the flash commands that we've sent to the 2264 * network. 2265 * 2266 * For calls that are not generic conferences, or when the generic conference has more than 2267 * 2 children, returns {@code null}. 2268 * @see Details#PROPERTY_GENERIC_CONFERENCE 2269 * @return The active child call. 2270 */ getGenericConferenceActiveChildCall()2271 public @Nullable Call getGenericConferenceActiveChildCall() { 2272 if (mActiveGenericConferenceChild != null) { 2273 return mPhone.internalGetCallByTelecomId(mActiveGenericConferenceChild); 2274 } 2275 return null; 2276 } 2277 2278 /** 2279 * Obtains a list of canned, pre-configured message responses to present to the user as 2280 * ways of rejecting an incoming {@code Call} using via a text message. 2281 * <p> 2282 * <em>Note:</em> Since canned responses may be loaded from the file system, they are not 2283 * guaranteed to be present when this {@link Call} is first added to the {@link InCallService} 2284 * via {@link InCallService#onCallAdded(Call)}. The callback 2285 * {@link Call.Callback#onCannedTextResponsesLoaded(Call, List)} will be called when/if canned 2286 * responses for the call become available. 2287 * 2288 * @see #reject(boolean, String) 2289 * 2290 * @return A list of canned text message responses. 2291 */ getCannedTextResponses()2292 public List<String> getCannedTextResponses() { 2293 return mCannedTextResponses; 2294 } 2295 2296 /** 2297 * Obtains an object that can be used to display video from this {@code Call}. 2298 * 2299 * @return An {@code Call.VideoCall}. 2300 */ getVideoCall()2301 public InCallService.VideoCall getVideoCall() { 2302 return mVideoCallImpl; 2303 } 2304 2305 /** 2306 * Obtains an object containing call details. 2307 * 2308 * @return A {@link Details} object. Depending on the state of the {@code Call}, the 2309 * result may be {@code null}. 2310 */ getDetails()2311 public Details getDetails() { 2312 return mDetails; 2313 } 2314 2315 /** 2316 * Returns this call's RttCall object. The {@link RttCall} instance is used to send and 2317 * receive RTT text data, as well as to change the RTT mode. 2318 * @return A {@link Call.RttCall}. {@code null} if there is no active RTT connection. 2319 */ getRttCall()2320 public @Nullable RttCall getRttCall() { 2321 return mRttCall; 2322 } 2323 2324 /** 2325 * Returns whether this call has an active RTT connection. 2326 * @return true if there is a connection, false otherwise. 2327 */ isRttActive()2328 public boolean isRttActive() { 2329 return mRttCall != null && mDetails.hasProperty(Details.PROPERTY_RTT); 2330 } 2331 2332 /** 2333 * Registers a callback to this {@code Call}. 2334 * 2335 * @param callback A {@code Callback}. 2336 */ registerCallback(Callback callback)2337 public void registerCallback(Callback callback) { 2338 registerCallback(callback, new Handler()); 2339 } 2340 2341 /** 2342 * Registers a callback to this {@code Call}. 2343 * 2344 * @param callback A {@code Callback}. 2345 * @param handler A handler which command and status changes will be delivered to. 2346 */ registerCallback(Callback callback, Handler handler)2347 public void registerCallback(Callback callback, Handler handler) { 2348 unregisterCallback(callback); 2349 // Don't allow new callback registration if the call is already being destroyed. 2350 if (callback != null && handler != null && mState != STATE_DISCONNECTED) { 2351 mCallbackRecords.add(new CallbackRecord<Callback>(callback, handler)); 2352 } 2353 } 2354 2355 /** 2356 * Unregisters a callback from this {@code Call}. 2357 * 2358 * @param callback A {@code Callback}. 2359 */ unregisterCallback(Callback callback)2360 public void unregisterCallback(Callback callback) { 2361 // Don't allow callback deregistration if the call is already being destroyed. 2362 if (callback != null && mState != STATE_DISCONNECTED) { 2363 for (CallbackRecord<Callback> record : mCallbackRecords) { 2364 if (record.getCallback() == callback) { 2365 mCallbackRecords.remove(record); 2366 break; 2367 } 2368 } 2369 } 2370 } 2371 2372 @Override toString()2373 public String toString() { 2374 return new StringBuilder(). 2375 append("Call [id: "). 2376 append(mTelecomCallId). 2377 append(", state: "). 2378 append(stateToString(mState)). 2379 append(", details: "). 2380 append(mDetails). 2381 append("]").toString(); 2382 } 2383 2384 /** 2385 * @param state An integer value of a {@code STATE_*} constant. 2386 * @return A string representation of the value. 2387 */ stateToString(int state)2388 private static String stateToString(int state) { 2389 switch (state) { 2390 case STATE_NEW: 2391 return "NEW"; 2392 case STATE_RINGING: 2393 return "RINGING"; 2394 case STATE_DIALING: 2395 return "DIALING"; 2396 case STATE_ACTIVE: 2397 return "ACTIVE"; 2398 case STATE_HOLDING: 2399 return "HOLDING"; 2400 case STATE_DISCONNECTED: 2401 return "DISCONNECTED"; 2402 case STATE_CONNECTING: 2403 return "CONNECTING"; 2404 case STATE_DISCONNECTING: 2405 return "DISCONNECTING"; 2406 case STATE_SELECT_PHONE_ACCOUNT: 2407 return "SELECT_PHONE_ACCOUNT"; 2408 case STATE_SIMULATED_RINGING: 2409 return "SIMULATED_RINGING"; 2410 case STATE_AUDIO_PROCESSING: 2411 return "AUDIO_PROCESSING"; 2412 default: 2413 Log.w(Call.class, "Unknown state %d", state); 2414 return "UNKNOWN"; 2415 } 2416 } 2417 2418 /** 2419 * Adds a listener to this {@code Call}. 2420 * 2421 * @param listener A {@code Listener}. 2422 * @deprecated Use {@link #registerCallback} instead. 2423 * @hide 2424 */ 2425 @Deprecated 2426 @SystemApi addListener(Listener listener)2427 public void addListener(Listener listener) { 2428 registerCallback(listener); 2429 } 2430 2431 /** 2432 * Removes a listener from this {@code Call}. 2433 * 2434 * @param listener A {@code Listener}. 2435 * @deprecated Use {@link #unregisterCallback} instead. 2436 * @hide 2437 */ 2438 @Deprecated 2439 @SystemApi removeListener(Listener listener)2440 public void removeListener(Listener listener) { 2441 unregisterCallback(listener); 2442 } 2443 2444 /** {@hide} */ Call(Phone phone, String telecomCallId, InCallAdapter inCallAdapter, String callingPackage, int targetSdkVersion)2445 Call(Phone phone, String telecomCallId, InCallAdapter inCallAdapter, String callingPackage, 2446 int targetSdkVersion) { 2447 mPhone = phone; 2448 mTelecomCallId = telecomCallId; 2449 mInCallAdapter = inCallAdapter; 2450 mState = STATE_NEW; 2451 mCallingPackage = callingPackage; 2452 mTargetSdkVersion = targetSdkVersion; 2453 } 2454 2455 /** {@hide} */ Call(Phone phone, String telecomCallId, InCallAdapter inCallAdapter, int state, String callingPackage, int targetSdkVersion)2456 Call(Phone phone, String telecomCallId, InCallAdapter inCallAdapter, int state, 2457 String callingPackage, int targetSdkVersion) { 2458 mPhone = phone; 2459 mTelecomCallId = telecomCallId; 2460 mInCallAdapter = inCallAdapter; 2461 mState = state; 2462 mCallingPackage = callingPackage; 2463 mTargetSdkVersion = targetSdkVersion; 2464 } 2465 2466 /** {@hide} */ internalGetCallId()2467 final String internalGetCallId() { 2468 return mTelecomCallId; 2469 } 2470 2471 /** {@hide} */ internalUpdate(ParcelableCall parcelableCall, Map<String, Call> callIdMap)2472 final void internalUpdate(ParcelableCall parcelableCall, Map<String, Call> callIdMap) { 2473 2474 // First, we update the internal state as far as possible before firing any updates. 2475 Details details = Details.createFromParcelableCall(parcelableCall); 2476 boolean detailsChanged = !Objects.equals(mDetails, details); 2477 if (detailsChanged) { 2478 mDetails = details; 2479 } 2480 2481 boolean cannedTextResponsesChanged = false; 2482 if (mCannedTextResponses == null && parcelableCall.getCannedSmsResponses() != null 2483 && !parcelableCall.getCannedSmsResponses().isEmpty()) { 2484 mCannedTextResponses = 2485 Collections.unmodifiableList(parcelableCall.getCannedSmsResponses()); 2486 cannedTextResponsesChanged = true; 2487 } 2488 2489 IVideoProvider previousVideoProvider = mVideoCallImpl == null ? null : 2490 mVideoCallImpl.getVideoProvider(); 2491 IVideoProvider newVideoProvider = parcelableCall.getVideoProvider(); 2492 2493 // parcelableCall.isVideoCallProviderChanged is only true when we have a video provider 2494 // specified; so we should check if the actual IVideoProvider changes as well. 2495 boolean videoCallChanged = parcelableCall.isVideoCallProviderChanged() 2496 && !Objects.equals(previousVideoProvider, newVideoProvider); 2497 if (videoCallChanged) { 2498 if (mVideoCallImpl != null) { 2499 mVideoCallImpl.destroy(); 2500 } 2501 mVideoCallImpl = parcelableCall.isVideoCallProviderChanged() ? 2502 parcelableCall.getVideoCallImpl(mCallingPackage, mTargetSdkVersion) : null; 2503 } 2504 2505 if (mVideoCallImpl != null) { 2506 mVideoCallImpl.setVideoState(getDetails().getVideoState()); 2507 } 2508 2509 int state = parcelableCall.getState(); 2510 if (mTargetSdkVersion < Phone.SDK_VERSION_R && state == Call.STATE_SIMULATED_RINGING) { 2511 state = Call.STATE_RINGING; 2512 } 2513 boolean stateChanged = mState != state; 2514 if (stateChanged) { 2515 mState = state; 2516 } 2517 2518 String parentId = parcelableCall.getParentCallId(); 2519 boolean parentChanged = !Objects.equals(mParentId, parentId); 2520 if (parentChanged) { 2521 mParentId = parentId; 2522 } 2523 2524 List<String> childCallIds = parcelableCall.getChildCallIds(); 2525 boolean childrenChanged = !Objects.equals(childCallIds, mChildrenIds); 2526 if (childrenChanged) { 2527 mChildrenIds.clear(); 2528 mChildrenIds.addAll(parcelableCall.getChildCallIds()); 2529 mChildrenCached = false; 2530 } 2531 2532 String activeChildCallId = parcelableCall.getActiveChildCallId(); 2533 boolean activeChildChanged = !Objects.equals(activeChildCallId, 2534 mActiveGenericConferenceChild); 2535 if (activeChildChanged) { 2536 mActiveGenericConferenceChild = activeChildCallId; 2537 } 2538 2539 List<String> conferenceableCallIds = parcelableCall.getConferenceableCallIds(); 2540 List<Call> conferenceableCalls = new ArrayList<Call>(conferenceableCallIds.size()); 2541 for (String otherId : conferenceableCallIds) { 2542 if (callIdMap.containsKey(otherId)) { 2543 conferenceableCalls.add(callIdMap.get(otherId)); 2544 } 2545 } 2546 2547 if (!Objects.equals(mConferenceableCalls, conferenceableCalls)) { 2548 mConferenceableCalls.clear(); 2549 mConferenceableCalls.addAll(conferenceableCalls); 2550 fireConferenceableCallsChanged(); 2551 } 2552 2553 boolean isRttChanged = false; 2554 boolean rttModeChanged = false; 2555 if (parcelableCall.getIsRttCallChanged() 2556 && mDetails.hasProperty(Details.PROPERTY_RTT)) { 2557 ParcelableRttCall parcelableRttCall = parcelableCall.getParcelableRttCall(); 2558 InputStreamReader receiveStream = new InputStreamReader( 2559 new ParcelFileDescriptor.AutoCloseInputStream( 2560 parcelableRttCall.getReceiveStream()), 2561 StandardCharsets.UTF_8); 2562 OutputStreamWriter transmitStream = new OutputStreamWriter( 2563 new ParcelFileDescriptor.AutoCloseOutputStream( 2564 parcelableRttCall.getTransmitStream()), 2565 StandardCharsets.UTF_8); 2566 RttCall newRttCall = new Call.RttCall(mTelecomCallId, 2567 receiveStream, transmitStream, parcelableRttCall.getRttMode(), mInCallAdapter); 2568 if (mRttCall == null) { 2569 isRttChanged = true; 2570 } else if (mRttCall.getRttAudioMode() != newRttCall.getRttAudioMode()) { 2571 rttModeChanged = true; 2572 } 2573 mRttCall = newRttCall; 2574 } else if (mRttCall != null && parcelableCall.getParcelableRttCall() == null 2575 && parcelableCall.getIsRttCallChanged()) { 2576 isRttChanged = true; 2577 mRttCall.close(); 2578 mRttCall = null; 2579 } 2580 2581 // Now we fire updates, ensuring that any client who listens to any of these notifications 2582 // gets the most up-to-date state. 2583 2584 if (stateChanged) { 2585 fireStateChanged(mState); 2586 } 2587 if (detailsChanged) { 2588 fireDetailsChanged(mDetails); 2589 } 2590 if (cannedTextResponsesChanged) { 2591 fireCannedTextResponsesLoaded(mCannedTextResponses); 2592 } 2593 if (videoCallChanged) { 2594 fireVideoCallChanged(mVideoCallImpl); 2595 } 2596 if (parentChanged) { 2597 fireParentChanged(getParent()); 2598 } 2599 if (childrenChanged || activeChildChanged) { 2600 fireChildrenChanged(getChildren()); 2601 } 2602 if (isRttChanged) { 2603 fireOnIsRttChanged(mRttCall != null, mRttCall); 2604 } 2605 if (rttModeChanged) { 2606 fireOnRttModeChanged(mRttCall.getRttAudioMode()); 2607 } 2608 2609 // If we have transitioned to DISCONNECTED, that means we need to notify clients and 2610 // remove ourselves from the Phone. Note that we do this after completing all state updates 2611 // so a client can cleanly transition all their UI to the state appropriate for a 2612 // DISCONNECTED Call while still relying on the existence of that Call in the Phone's list. 2613 // Check if the original state is already disconnected, otherwise onCallRemoved will be 2614 // triggered before onCallAdded. 2615 if (mState == STATE_DISCONNECTED && stateChanged) { 2616 fireCallDestroyed(); 2617 } 2618 } 2619 2620 /** {@hide} */ internalSetPostDialWait(String remaining)2621 final void internalSetPostDialWait(String remaining) { 2622 mRemainingPostDialSequence = remaining; 2623 firePostDialWait(mRemainingPostDialSequence); 2624 } 2625 2626 /** {@hide} */ internalSetDisconnected()2627 final void internalSetDisconnected() { 2628 if (mState != Call.STATE_DISCONNECTED) { 2629 mState = Call.STATE_DISCONNECTED; 2630 if (mDetails != null) { 2631 mDetails = new Details(mState, 2632 mDetails.getTelecomCallId(), 2633 mDetails.getHandle(), 2634 mDetails.getHandlePresentation(), 2635 mDetails.getCallerDisplayName(), 2636 mDetails.getCallerDisplayNamePresentation(), 2637 mDetails.getAccountHandle(), 2638 mDetails.getCallCapabilities(), 2639 mDetails.getCallProperties(), 2640 mDetails.getDisconnectCause(), 2641 mDetails.getConnectTimeMillis(), 2642 mDetails.getGatewayInfo(), 2643 mDetails.getVideoState(), 2644 mDetails.getStatusHints(), 2645 mDetails.getExtras(), 2646 mDetails.getIntentExtras(), 2647 mDetails.getCreationTimeMillis(), 2648 mDetails.getContactDisplayName(), 2649 mDetails.getCallDirection(), 2650 mDetails.getCallerNumberVerificationStatus(), 2651 mDetails.getContactPhotoUri(), 2652 mDetails.getAssociatedUser() 2653 ); 2654 fireDetailsChanged(mDetails); 2655 } 2656 fireStateChanged(mState); 2657 fireCallDestroyed(); 2658 } 2659 } 2660 2661 /** {@hide} */ internalOnConnectionEvent(String event, Bundle extras)2662 final void internalOnConnectionEvent(String event, Bundle extras) { 2663 fireOnConnectionEvent(event, extras); 2664 } 2665 2666 /** {@hide} */ internalOnRttUpgradeRequest(final int requestId)2667 final void internalOnRttUpgradeRequest(final int requestId) { 2668 for (CallbackRecord<Callback> record : mCallbackRecords) { 2669 final Call call = this; 2670 final Callback callback = record.getCallback(); 2671 record.getHandler().post(() -> callback.onRttRequest(call, requestId)); 2672 } 2673 } 2674 2675 /** @hide */ internalOnRttInitiationFailure(int reason)2676 final void internalOnRttInitiationFailure(int reason) { 2677 for (CallbackRecord<Callback> record : mCallbackRecords) { 2678 final Call call = this; 2679 final Callback callback = record.getCallback(); 2680 record.getHandler().post(() -> callback.onRttInitiationFailure(call, reason)); 2681 } 2682 } 2683 2684 /** {@hide} */ internalOnHandoverFailed(int error)2685 final void internalOnHandoverFailed(int error) { 2686 for (CallbackRecord<Callback> record : mCallbackRecords) { 2687 final Call call = this; 2688 final Callback callback = record.getCallback(); 2689 record.getHandler().post(() -> callback.onHandoverFailed(call, error)); 2690 } 2691 } 2692 2693 /** {@hide} */ internalOnHandoverComplete()2694 final void internalOnHandoverComplete() { 2695 for (CallbackRecord<Callback> record : mCallbackRecords) { 2696 final Call call = this; 2697 final Callback callback = record.getCallback(); 2698 record.getHandler().post(() -> callback.onHandoverComplete(call)); 2699 } 2700 } 2701 fireStateChanged(final int newState)2702 private void fireStateChanged(final int newState) { 2703 for (CallbackRecord<Callback> record : mCallbackRecords) { 2704 final Call call = this; 2705 final Callback callback = record.getCallback(); 2706 record.getHandler().post(new Runnable() { 2707 @Override 2708 public void run() { 2709 callback.onStateChanged(call, newState); 2710 } 2711 }); 2712 } 2713 } 2714 fireParentChanged(final Call newParent)2715 private void fireParentChanged(final Call newParent) { 2716 for (CallbackRecord<Callback> record : mCallbackRecords) { 2717 final Call call = this; 2718 final Callback callback = record.getCallback(); 2719 record.getHandler().post(new Runnable() { 2720 @Override 2721 public void run() { 2722 callback.onParentChanged(call, newParent); 2723 } 2724 }); 2725 } 2726 } 2727 fireChildrenChanged(final List<Call> children)2728 private void fireChildrenChanged(final List<Call> children) { 2729 for (CallbackRecord<Callback> record : mCallbackRecords) { 2730 final Call call = this; 2731 final Callback callback = record.getCallback(); 2732 record.getHandler().post(new Runnable() { 2733 @Override 2734 public void run() { 2735 callback.onChildrenChanged(call, children); 2736 } 2737 }); 2738 } 2739 } 2740 fireDetailsChanged(final Details details)2741 private void fireDetailsChanged(final Details details) { 2742 for (CallbackRecord<Callback> record : mCallbackRecords) { 2743 final Call call = this; 2744 final Callback callback = record.getCallback(); 2745 record.getHandler().post(new Runnable() { 2746 @Override 2747 public void run() { 2748 callback.onDetailsChanged(call, details); 2749 } 2750 }); 2751 } 2752 } 2753 fireCannedTextResponsesLoaded(final List<String> cannedTextResponses)2754 private void fireCannedTextResponsesLoaded(final List<String> cannedTextResponses) { 2755 for (CallbackRecord<Callback> record : mCallbackRecords) { 2756 final Call call = this; 2757 final Callback callback = record.getCallback(); 2758 record.getHandler().post(new Runnable() { 2759 @Override 2760 public void run() { 2761 callback.onCannedTextResponsesLoaded(call, cannedTextResponses); 2762 } 2763 }); 2764 } 2765 } 2766 fireVideoCallChanged(final InCallService.VideoCall videoCall)2767 private void fireVideoCallChanged(final InCallService.VideoCall videoCall) { 2768 for (CallbackRecord<Callback> record : mCallbackRecords) { 2769 final Call call = this; 2770 final Callback callback = record.getCallback(); 2771 record.getHandler().post(new Runnable() { 2772 @Override 2773 public void run() { 2774 callback.onVideoCallChanged(call, videoCall); 2775 } 2776 }); 2777 } 2778 } 2779 firePostDialWait(final String remainingPostDialSequence)2780 private void firePostDialWait(final String remainingPostDialSequence) { 2781 for (CallbackRecord<Callback> record : mCallbackRecords) { 2782 final Call call = this; 2783 final Callback callback = record.getCallback(); 2784 record.getHandler().post(new Runnable() { 2785 @Override 2786 public void run() { 2787 callback.onPostDialWait(call, remainingPostDialSequence); 2788 } 2789 }); 2790 } 2791 } 2792 fireCallDestroyed()2793 private void fireCallDestroyed() { 2794 /** 2795 * To preserve the ordering of the Call's onCallDestroyed callback and Phone's 2796 * onCallRemoved callback, we remove this call from the Phone's record 2797 * only once all of the registered onCallDestroyed callbacks are executed. 2798 * All the callbacks get removed from our records as a part of this operation 2799 * since onCallDestroyed is the final callback. 2800 */ 2801 final Call call = this; 2802 if (mCallbackRecords.isEmpty()) { 2803 // No callbacks registered, remove the call from Phone's record. 2804 mPhone.internalRemoveCall(call); 2805 } 2806 for (final CallbackRecord<Callback> record : mCallbackRecords) { 2807 final Callback callback = record.getCallback(); 2808 record.getHandler().post(new Runnable() { 2809 @Override 2810 public void run() { 2811 boolean isFinalRemoval = false; 2812 RuntimeException toThrow = null; 2813 try { 2814 callback.onCallDestroyed(call); 2815 } catch (RuntimeException e) { 2816 toThrow = e; 2817 } 2818 synchronized(Call.this) { 2819 mCallbackRecords.remove(record); 2820 if (mCallbackRecords.isEmpty()) { 2821 isFinalRemoval = true; 2822 } 2823 } 2824 if (isFinalRemoval) { 2825 mPhone.internalRemoveCall(call); 2826 } 2827 if (toThrow != null) { 2828 throw toThrow; 2829 } 2830 } 2831 }); 2832 } 2833 } 2834 fireConferenceableCallsChanged()2835 private void fireConferenceableCallsChanged() { 2836 for (CallbackRecord<Callback> record : mCallbackRecords) { 2837 final Call call = this; 2838 final Callback callback = record.getCallback(); 2839 record.getHandler().post(new Runnable() { 2840 @Override 2841 public void run() { 2842 callback.onConferenceableCallsChanged(call, mUnmodifiableConferenceableCalls); 2843 } 2844 }); 2845 } 2846 } 2847 2848 /** 2849 * Notifies listeners of an incoming connection event. 2850 * <p> 2851 * Connection events are issued via {@link Connection#sendConnectionEvent(String, Bundle)}. 2852 * 2853 * @param event 2854 * @param extras 2855 */ fireOnConnectionEvent(final String event, final Bundle extras)2856 private void fireOnConnectionEvent(final String event, final Bundle extras) { 2857 for (CallbackRecord<Callback> record : mCallbackRecords) { 2858 final Call call = this; 2859 final Callback callback = record.getCallback(); 2860 record.getHandler().post(new Runnable() { 2861 @Override 2862 public void run() { 2863 callback.onConnectionEvent(call, event, extras); 2864 } 2865 }); 2866 } 2867 } 2868 2869 /** 2870 * Notifies listeners of an RTT on/off change 2871 * 2872 * @param enabled True if RTT is now enabled, false otherwise 2873 */ fireOnIsRttChanged(final boolean enabled, final RttCall rttCall)2874 private void fireOnIsRttChanged(final boolean enabled, final RttCall rttCall) { 2875 for (CallbackRecord<Callback> record : mCallbackRecords) { 2876 final Call call = this; 2877 final Callback callback = record.getCallback(); 2878 record.getHandler().post(() -> callback.onRttStatusChanged(call, enabled, rttCall)); 2879 } 2880 } 2881 2882 /** 2883 * Notifies listeners of a RTT mode change 2884 * 2885 * @param mode The new RTT mode 2886 */ fireOnRttModeChanged(final int mode)2887 private void fireOnRttModeChanged(final int mode) { 2888 for (CallbackRecord<Callback> record : mCallbackRecords) { 2889 final Call call = this; 2890 final Callback callback = record.getCallback(); 2891 record.getHandler().post(() -> callback.onRttModeChanged(call, mode)); 2892 } 2893 } 2894 2895 /** 2896 * Determines if two bundles are equal. 2897 * 2898 * @param bundle The original bundle. 2899 * @param newBundle The bundle to compare with. 2900 * @retrun {@code true} if the bundles are equal, {@code false} otherwise. 2901 */ areBundlesEqual(Bundle bundle, Bundle newBundle)2902 private static boolean areBundlesEqual(Bundle bundle, Bundle newBundle) { 2903 if (bundle == null || newBundle == null) { 2904 return bundle == newBundle; 2905 } 2906 2907 if (bundle.size() != newBundle.size()) { 2908 return false; 2909 } 2910 try { 2911 for (String key : bundle.keySet()) { 2912 if (key != null) { 2913 if (!newBundle.containsKey(key)) { 2914 return false; 2915 } 2916 // In case new call extra contains non-framework class objects, return false to 2917 // force update the call extra 2918 try { 2919 final Object value = bundle.get(key); 2920 final Object newValue = newBundle.get(key); 2921 if (value instanceof Bundle && newValue instanceof Bundle) { 2922 if (!areBundlesEqual((Bundle) value, (Bundle) newValue)) { 2923 return false; 2924 } 2925 } 2926 if (value instanceof byte[] && newValue instanceof byte[]) { 2927 if (!Arrays.equals((byte[]) value, (byte[]) newValue)) { 2928 return false; 2929 } 2930 } else if (!Objects.equals(value, newValue)) { 2931 return false; 2932 } 2933 } catch (BadParcelableException e) { 2934 return false; 2935 } 2936 } 2937 } 2938 } catch (ClassCastException | ArrayIndexOutOfBoundsException e) { 2939 // Unfortunately this may get raised when accessing the bundle's keyset, so we cannot 2940 // determine WHY a class cast exception is happening. We had tried in the past to do 2941 // this down in the for loop so we could figure out which key is causing an issue. 2942 // Bundles are not thread safe, so the most likely issue here is that the InCallService 2943 // implementation is accessing the Bundle WHILE an incoming Telecom update comes in to 2944 // potentially replace the Bundle. We call "areBundlesEqual" to see if the newly 2945 // unparceled Call.Details is the same as what is already in the current Call instance. 2946 // If those two operations overleave, I can see the potential for concurrent 2947 // modification and edit of the Bundle. So we'll just catch here and assume the Bundles 2948 // are not the same. This means a Call.CallBack may fire the onCallDetails changed 2949 // callback when the Bundle didn't actually change. 2950 Log.e(LOG_TAG, e, "areBundlesEqual: failed!"); 2951 return false; 2952 } 2953 return true; 2954 } 2955 } 2956