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