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.SystemApi; 20 import android.net.Uri; 21 import android.os.Bundle; 22 import android.os.Handler; 23 24 import java.lang.String; 25 import java.util.ArrayList; 26 import java.util.Arrays; 27 import java.util.Collections; 28 import java.util.List; 29 import java.util.Map; 30 import java.util.Objects; 31 import java.util.concurrent.CopyOnWriteArrayList; 32 33 /** 34 * Represents an ongoing phone call that the in-call app should present to the user. 35 */ 36 public final class Call { 37 /** 38 * The state of a {@code Call} when newly created. 39 */ 40 public static final int STATE_NEW = 0; 41 42 /** 43 * The state of an outgoing {@code Call} when dialing the remote number, but not yet connected. 44 */ 45 public static final int STATE_DIALING = 1; 46 47 /** 48 * The state of an incoming {@code Call} when ringing locally, but not yet connected. 49 */ 50 public static final int STATE_RINGING = 2; 51 52 /** 53 * The state of a {@code Call} when in a holding state. 54 */ 55 public static final int STATE_HOLDING = 3; 56 57 /** 58 * The state of a {@code Call} when actively supporting conversation. 59 */ 60 public static final int STATE_ACTIVE = 4; 61 62 /** 63 * The state of a {@code Call} when no further voice or other communication is being 64 * transmitted, the remote side has been or will inevitably be informed that the {@code Call} 65 * is no longer active, and the local data transport has or inevitably will release resources 66 * associated with this {@code Call}. 67 */ 68 public static final int STATE_DISCONNECTED = 7; 69 70 /** 71 * The state of an outgoing {@code Call} when waiting on user to select a 72 * {@link PhoneAccount} through which to place the call. 73 */ 74 public static final int STATE_SELECT_PHONE_ACCOUNT = 8; 75 76 /** 77 * @hide 78 * @deprecated use STATE_SELECT_PHONE_ACCOUNT. 79 */ 80 @Deprecated 81 @SystemApi 82 public static final int STATE_PRE_DIAL_WAIT = STATE_SELECT_PHONE_ACCOUNT; 83 84 /** 85 * The initial state of an outgoing {@code Call}. 86 * Common transitions are to {@link #STATE_DIALING} state for a successful call or 87 * {@link #STATE_DISCONNECTED} if it failed. 88 */ 89 public static final int STATE_CONNECTING = 9; 90 91 /** 92 * The state of a {@code Call} when the user has initiated a disconnection of the call, but the 93 * call has not yet been disconnected by the underlying {@code ConnectionService}. The next 94 * state of the call is (potentially) {@link #STATE_DISCONNECTED}. 95 */ 96 public static final int STATE_DISCONNECTING = 10; 97 98 /** 99 * The state of an external call which is in the process of being pulled from a remote device to 100 * the local device. 101 * <p> 102 * A call can only be in this state if the {@link Details#PROPERTY_IS_EXTERNAL_CALL} property 103 * and {@link Details#CAPABILITY_CAN_PULL_CALL} capability are set on the call. 104 * <p> 105 * An {@link InCallService} will only see this state if it has the 106 * {@link TelecomManager#METADATA_INCLUDE_EXTERNAL_CALLS} metadata set to {@code true} in its 107 * manifest. 108 */ 109 public static final int STATE_PULLING_CALL = 11; 110 111 /** 112 * The key to retrieve the optional {@code PhoneAccount}s Telecom can bundle with its Call 113 * extras. Used to pass the phone accounts to display on the front end to the user in order to 114 * select phone accounts to (for example) place a call. 115 */ 116 public static final String AVAILABLE_PHONE_ACCOUNTS = "selectPhoneAccountAccounts"; 117 118 public static class Details { 119 120 /** Call can currently be put on hold or unheld. */ 121 public static final int CAPABILITY_HOLD = 0x00000001; 122 123 /** Call supports the hold feature. */ 124 public static final int CAPABILITY_SUPPORT_HOLD = 0x00000002; 125 126 /** 127 * Calls within a conference can be merged. A {@link ConnectionService} has the option to 128 * add a {@link Conference} call before the child {@link Connection}s are merged. This is how 129 * CDMA-based {@link Connection}s are implemented. For these unmerged {@link Conference}s, this 130 * capability allows a merge button to be shown while the conference call is in the foreground 131 * of the in-call UI. 132 * <p> 133 * This is only intended for use by a {@link Conference}. 134 */ 135 public static final int CAPABILITY_MERGE_CONFERENCE = 0x00000004; 136 137 /** 138 * Calls within a conference can be swapped between foreground and background. 139 * See {@link #CAPABILITY_MERGE_CONFERENCE} for additional information. 140 * <p> 141 * This is only intended for use by a {@link Conference}. 142 */ 143 public static final int CAPABILITY_SWAP_CONFERENCE = 0x00000008; 144 145 /** 146 * @hide 147 */ 148 public static final int CAPABILITY_UNUSED_1 = 0x00000010; 149 150 /** Call supports responding via text option. */ 151 public static final int CAPABILITY_RESPOND_VIA_TEXT = 0x00000020; 152 153 /** Call can be muted. */ 154 public static final int CAPABILITY_MUTE = 0x00000040; 155 156 /** 157 * Call supports conference call management. This capability only applies to {@link Conference} 158 * calls which can have {@link Connection}s as children. 159 */ 160 public static final int CAPABILITY_MANAGE_CONFERENCE = 0x00000080; 161 162 /** 163 * Local device supports receiving video. 164 */ 165 public static final int CAPABILITY_SUPPORTS_VT_LOCAL_RX = 0x00000100; 166 167 /** 168 * Local device supports transmitting video. 169 */ 170 public static final int CAPABILITY_SUPPORTS_VT_LOCAL_TX = 0x00000200; 171 172 /** 173 * Local device supports bidirectional video calling. 174 */ 175 public static final int CAPABILITY_SUPPORTS_VT_LOCAL_BIDIRECTIONAL = 176 CAPABILITY_SUPPORTS_VT_LOCAL_RX | CAPABILITY_SUPPORTS_VT_LOCAL_TX; 177 178 /** 179 * Remote device supports receiving video. 180 */ 181 public static final int CAPABILITY_SUPPORTS_VT_REMOTE_RX = 0x00000400; 182 183 /** 184 * Remote device supports transmitting video. 185 */ 186 public static final int CAPABILITY_SUPPORTS_VT_REMOTE_TX = 0x00000800; 187 188 /** 189 * Remote device supports bidirectional video calling. 190 */ 191 public static final int CAPABILITY_SUPPORTS_VT_REMOTE_BIDIRECTIONAL = 192 CAPABILITY_SUPPORTS_VT_REMOTE_RX | CAPABILITY_SUPPORTS_VT_REMOTE_TX; 193 194 /** 195 * Call is able to be separated from its parent {@code Conference}, if any. 196 */ 197 public static final int CAPABILITY_SEPARATE_FROM_CONFERENCE = 0x00001000; 198 199 /** 200 * Call is able to be individually disconnected when in a {@code Conference}. 201 */ 202 public static final int CAPABILITY_DISCONNECT_FROM_CONFERENCE = 0x00002000; 203 204 /** 205 * Speed up audio setup for MT call. 206 * @hide 207 */ 208 public static final int CAPABILITY_SPEED_UP_MT_AUDIO = 0x00040000; 209 210 /** 211 * Call can be upgraded to a video call. 212 * @hide 213 */ 214 public static final int CAPABILITY_CAN_UPGRADE_TO_VIDEO = 0x00080000; 215 216 /** 217 * For video calls, indicates whether the outgoing video for the call can be paused using 218 * the {@link android.telecom.VideoProfile#STATE_PAUSED} VideoState. 219 */ 220 public static final int CAPABILITY_CAN_PAUSE_VIDEO = 0x00100000; 221 222 /** 223 * Call sends responses through connection. 224 * @hide 225 */ 226 public static final int CAPABILITY_CAN_SEND_RESPONSE_VIA_CONNECTION = 0x00200000; 227 228 /** 229 * When set, prevents a video {@code Call} from being downgraded to an audio-only call. 230 * <p> 231 * Should be set when the VideoState has the {@link VideoProfile#STATE_TX_ENABLED} or 232 * {@link VideoProfile#STATE_RX_ENABLED} bits set to indicate that the connection cannot be 233 * downgraded from a video call back to a VideoState of 234 * {@link VideoProfile#STATE_AUDIO_ONLY}. 235 * <p> 236 * Intuitively, a call which can be downgraded to audio should also have local and remote 237 * video 238 * capabilities (see {@link #CAPABILITY_SUPPORTS_VT_LOCAL_BIDIRECTIONAL} and 239 * {@link #CAPABILITY_SUPPORTS_VT_REMOTE_BIDIRECTIONAL}). 240 */ 241 public static final int CAPABILITY_CANNOT_DOWNGRADE_VIDEO_TO_AUDIO = 0x00400000; 242 243 /** 244 * When set for an external call, indicates that this {@code Call} can be pulled from a 245 * remote device to the current device. 246 * <p> 247 * Should only be set on a {@code Call} where {@link #PROPERTY_IS_EXTERNAL_CALL} is set. 248 * <p> 249 * An {@link InCallService} will only see calls with this capability if it has the 250 * {@link TelecomManager#METADATA_INCLUDE_EXTERNAL_CALLS} metadata set to {@code true} 251 * in its manifest. 252 * <p> 253 * See {@link Connection#CAPABILITY_CAN_PULL_CALL} and 254 * {@link Connection#PROPERTY_IS_EXTERNAL_CALL}. 255 */ 256 public static final int CAPABILITY_CAN_PULL_CALL = 0x00800000; 257 258 //****************************************************************************************** 259 // Next CAPABILITY value: 0x01000000 260 //****************************************************************************************** 261 262 /** 263 * Whether the call is currently a conference. 264 */ 265 public static final int PROPERTY_CONFERENCE = 0x00000001; 266 267 /** 268 * Whether the call is a generic conference, where we do not know the precise state of 269 * participants in the conference (eg. on CDMA). 270 */ 271 public static final int PROPERTY_GENERIC_CONFERENCE = 0x00000002; 272 273 /** 274 * Whether the call is made while the device is in emergency callback mode. 275 */ 276 public static final int PROPERTY_EMERGENCY_CALLBACK_MODE = 0x00000004; 277 278 /** 279 * Connection is using WIFI. 280 */ 281 public static final int PROPERTY_WIFI = 0x00000008; 282 283 /** 284 * Call is using high definition audio. 285 */ 286 public static final int PROPERTY_HIGH_DEF_AUDIO = 0x00000010; 287 288 /** 289 * Whether the call is associated with the work profile. 290 */ 291 public static final int PROPERTY_ENTERPRISE_CALL = 0x00000020; 292 293 /** 294 * When set, indicates that this {@code Call} does not actually exist locally for the 295 * {@link ConnectionService}. 296 * <p> 297 * Consider, for example, a scenario where a user has two phones with the same phone number. 298 * When a user places a call on one device, the telephony stack can represent that call on 299 * the other device by adding it to the {@link ConnectionService} with the 300 * {@link Connection#PROPERTY_IS_EXTERNAL_CALL} property set. 301 * <p> 302 * An {@link InCallService} will only see calls with this property if it has the 303 * {@link TelecomManager#METADATA_INCLUDE_EXTERNAL_CALLS} metadata set to {@code true} 304 * in its manifest. 305 * <p> 306 * See {@link Connection#PROPERTY_IS_EXTERNAL_CALL}. 307 */ 308 public static final int PROPERTY_IS_EXTERNAL_CALL = 0x00000040; 309 310 /** 311 * Indicates that the call has CDMA Enhanced Voice Privacy enabled. 312 */ 313 public static final int PROPERTY_HAS_CDMA_VOICE_PRIVACY = 0x00000080; 314 315 //****************************************************************************************** 316 // Next PROPERTY value: 0x00000100 317 //****************************************************************************************** 318 319 private final String mTelecomCallId; 320 private final Uri mHandle; 321 private final int mHandlePresentation; 322 private final String mCallerDisplayName; 323 private final int mCallerDisplayNamePresentation; 324 private final PhoneAccountHandle mAccountHandle; 325 private final int mCallCapabilities; 326 private final int mCallProperties; 327 private final int mSupportedAudioRoutes = CallAudioState.ROUTE_ALL; 328 private final DisconnectCause mDisconnectCause; 329 private final long mConnectTimeMillis; 330 private final GatewayInfo mGatewayInfo; 331 private final int mVideoState; 332 private final StatusHints mStatusHints; 333 private final Bundle mExtras; 334 private final Bundle mIntentExtras; 335 336 /** 337 * Whether the supplied capabilities supports the specified capability. 338 * 339 * @param capabilities A bit field of capabilities. 340 * @param capability The capability to check capabilities for. 341 * @return Whether the specified capability is supported. 342 */ can(int capabilities, int capability)343 public static boolean can(int capabilities, int capability) { 344 return (capabilities & capability) == capability; 345 } 346 347 /** 348 * Whether the capabilities of this {@code Details} supports the specified capability. 349 * 350 * @param capability The capability to check capabilities for. 351 * @return Whether the specified capability is supported. 352 */ can(int capability)353 public boolean can(int capability) { 354 return can(mCallCapabilities, capability); 355 } 356 357 /** 358 * Render a set of capability bits ({@code CAPABILITY_*}) as a human readable string. 359 * 360 * @param capabilities A capability bit field. 361 * @return A human readable string representation. 362 */ capabilitiesToString(int capabilities)363 public static String capabilitiesToString(int capabilities) { 364 StringBuilder builder = new StringBuilder(); 365 builder.append("[Capabilities:"); 366 if (can(capabilities, CAPABILITY_HOLD)) { 367 builder.append(" CAPABILITY_HOLD"); 368 } 369 if (can(capabilities, CAPABILITY_SUPPORT_HOLD)) { 370 builder.append(" CAPABILITY_SUPPORT_HOLD"); 371 } 372 if (can(capabilities, CAPABILITY_MERGE_CONFERENCE)) { 373 builder.append(" CAPABILITY_MERGE_CONFERENCE"); 374 } 375 if (can(capabilities, CAPABILITY_SWAP_CONFERENCE)) { 376 builder.append(" CAPABILITY_SWAP_CONFERENCE"); 377 } 378 if (can(capabilities, CAPABILITY_RESPOND_VIA_TEXT)) { 379 builder.append(" CAPABILITY_RESPOND_VIA_TEXT"); 380 } 381 if (can(capabilities, CAPABILITY_MUTE)) { 382 builder.append(" CAPABILITY_MUTE"); 383 } 384 if (can(capabilities, CAPABILITY_MANAGE_CONFERENCE)) { 385 builder.append(" CAPABILITY_MANAGE_CONFERENCE"); 386 } 387 if (can(capabilities, CAPABILITY_SUPPORTS_VT_LOCAL_RX)) { 388 builder.append(" CAPABILITY_SUPPORTS_VT_LOCAL_RX"); 389 } 390 if (can(capabilities, CAPABILITY_SUPPORTS_VT_LOCAL_TX)) { 391 builder.append(" CAPABILITY_SUPPORTS_VT_LOCAL_TX"); 392 } 393 if (can(capabilities, CAPABILITY_SUPPORTS_VT_LOCAL_BIDIRECTIONAL)) { 394 builder.append(" CAPABILITY_SUPPORTS_VT_LOCAL_BIDIRECTIONAL"); 395 } 396 if (can(capabilities, CAPABILITY_SUPPORTS_VT_REMOTE_RX)) { 397 builder.append(" CAPABILITY_SUPPORTS_VT_REMOTE_RX"); 398 } 399 if (can(capabilities, CAPABILITY_SUPPORTS_VT_REMOTE_TX)) { 400 builder.append(" CAPABILITY_SUPPORTS_VT_REMOTE_TX"); 401 } 402 if (can(capabilities, CAPABILITY_CANNOT_DOWNGRADE_VIDEO_TO_AUDIO)) { 403 builder.append(" CAPABILITY_CANNOT_DOWNGRADE_VIDEO_TO_AUDIO"); 404 } 405 if (can(capabilities, CAPABILITY_SUPPORTS_VT_REMOTE_BIDIRECTIONAL)) { 406 builder.append(" CAPABILITY_SUPPORTS_VT_REMOTE_BIDIRECTIONAL"); 407 } 408 if (can(capabilities, CAPABILITY_SPEED_UP_MT_AUDIO)) { 409 builder.append(" CAPABILITY_SPEED_UP_MT_AUDIO"); 410 } 411 if (can(capabilities, CAPABILITY_CAN_UPGRADE_TO_VIDEO)) { 412 builder.append(" CAPABILITY_CAN_UPGRADE_TO_VIDEO"); 413 } 414 if (can(capabilities, CAPABILITY_CAN_PAUSE_VIDEO)) { 415 builder.append(" CAPABILITY_CAN_PAUSE_VIDEO"); 416 } 417 if (can(capabilities, CAPABILITY_CAN_PULL_CALL)) { 418 builder.append(" CAPABILITY_CAN_PULL_CALL"); 419 } 420 builder.append("]"); 421 return builder.toString(); 422 } 423 424 /** 425 * Whether the supplied properties includes the specified property. 426 * 427 * @param properties A bit field of properties. 428 * @param property The property to check properties for. 429 * @return Whether the specified property is supported. 430 */ hasProperty(int properties, int property)431 public static boolean hasProperty(int properties, int property) { 432 return (properties & property) == property; 433 } 434 435 /** 436 * Whether the properties of this {@code Details} includes the specified property. 437 * 438 * @param property The property to check properties for. 439 * @return Whether the specified property is supported. 440 */ hasProperty(int property)441 public boolean hasProperty(int property) { 442 return hasProperty(mCallProperties, property); 443 } 444 445 /** 446 * Render a set of property bits ({@code PROPERTY_*}) as a human readable string. 447 * 448 * @param properties A property bit field. 449 * @return A human readable string representation. 450 */ propertiesToString(int properties)451 public static String propertiesToString(int properties) { 452 StringBuilder builder = new StringBuilder(); 453 builder.append("[Properties:"); 454 if (hasProperty(properties, PROPERTY_CONFERENCE)) { 455 builder.append(" PROPERTY_CONFERENCE"); 456 } 457 if (hasProperty(properties, PROPERTY_GENERIC_CONFERENCE)) { 458 builder.append(" PROPERTY_GENERIC_CONFERENCE"); 459 } 460 if (hasProperty(properties, PROPERTY_WIFI)) { 461 builder.append(" PROPERTY_WIFI"); 462 } 463 if (hasProperty(properties, PROPERTY_HIGH_DEF_AUDIO)) { 464 builder.append(" PROPERTY_HIGH_DEF_AUDIO"); 465 } 466 if (hasProperty(properties, PROPERTY_EMERGENCY_CALLBACK_MODE)) { 467 builder.append(" PROPERTY_EMERGENCY_CALLBACK_MODE"); 468 } 469 if (hasProperty(properties, PROPERTY_IS_EXTERNAL_CALL)) { 470 builder.append(" PROPERTY_IS_EXTERNAL_CALL"); 471 } 472 if(hasProperty(properties, PROPERTY_HAS_CDMA_VOICE_PRIVACY)) { 473 builder.append(" PROPERTY_HAS_CDMA_VOICE_PRIVACY"); 474 } 475 builder.append("]"); 476 return builder.toString(); 477 } 478 479 /** {@hide} */ getTelecomCallId()480 public String getTelecomCallId() { 481 return mTelecomCallId; 482 } 483 484 /** 485 * @return The handle (e.g., phone number) to which the {@code Call} is currently 486 * connected. 487 */ getHandle()488 public Uri getHandle() { 489 return mHandle; 490 } 491 492 /** 493 * @return The presentation requirements for the handle. See 494 * {@link TelecomManager} for valid values. 495 */ getHandlePresentation()496 public int getHandlePresentation() { 497 return mHandlePresentation; 498 } 499 500 /** 501 * @return The display name for the caller. 502 */ getCallerDisplayName()503 public String getCallerDisplayName() { 504 return mCallerDisplayName; 505 } 506 507 /** 508 * @return The presentation requirements for the caller display name. See 509 * {@link TelecomManager} for valid values. 510 */ getCallerDisplayNamePresentation()511 public int getCallerDisplayNamePresentation() { 512 return mCallerDisplayNamePresentation; 513 } 514 515 /** 516 * @return The {@code PhoneAccountHandle} whereby the {@code Call} is currently being 517 * routed. 518 */ getAccountHandle()519 public PhoneAccountHandle getAccountHandle() { 520 return mAccountHandle; 521 } 522 523 /** 524 * @return A bitmask of the capabilities of the {@code Call}, as defined by the various 525 * {@code CAPABILITY_*} constants in this class. 526 */ getCallCapabilities()527 public int getCallCapabilities() { 528 return mCallCapabilities; 529 } 530 531 /** 532 * @return A bitmask of the properties of the {@code Call}, as defined by the various 533 * {@code PROPERTY_*} constants in this class. 534 */ getCallProperties()535 public int getCallProperties() { 536 return mCallProperties; 537 } 538 539 /** 540 * @return a bitmask of the audio routes available for the call. 541 * 542 * @hide 543 */ getSupportedAudioRoutes()544 public int getSupportedAudioRoutes() { 545 return mSupportedAudioRoutes; 546 } 547 548 /** 549 * @return For a {@link #STATE_DISCONNECTED} {@code Call}, the disconnect cause expressed 550 * by {@link android.telecom.DisconnectCause}. 551 */ getDisconnectCause()552 public DisconnectCause getDisconnectCause() { 553 return mDisconnectCause; 554 } 555 556 /** 557 * @return The time the {@code Call} has been connected. This information is updated 558 * periodically, but user interfaces should not rely on this to display any "call time 559 * clock". 560 */ getConnectTimeMillis()561 public final long getConnectTimeMillis() { 562 return mConnectTimeMillis; 563 } 564 565 /** 566 * @return Information about any calling gateway the {@code Call} may be using. 567 */ getGatewayInfo()568 public GatewayInfo getGatewayInfo() { 569 return mGatewayInfo; 570 } 571 572 /** 573 * @return The video state of the {@code Call}. 574 */ getVideoState()575 public int getVideoState() { 576 return mVideoState; 577 } 578 579 /** 580 * @return The current {@link android.telecom.StatusHints}, or {@code null} if none 581 * have been set. 582 */ getStatusHints()583 public StatusHints getStatusHints() { 584 return mStatusHints; 585 } 586 587 /** 588 * @return The extras associated with this call. 589 */ getExtras()590 public Bundle getExtras() { 591 return mExtras; 592 } 593 594 /** 595 * @return The extras used with the original intent to place this call. 596 */ getIntentExtras()597 public Bundle getIntentExtras() { 598 return mIntentExtras; 599 } 600 601 @Override equals(Object o)602 public boolean equals(Object o) { 603 if (o instanceof Details) { 604 Details d = (Details) o; 605 return 606 Objects.equals(mHandle, d.mHandle) && 607 Objects.equals(mHandlePresentation, d.mHandlePresentation) && 608 Objects.equals(mCallerDisplayName, d.mCallerDisplayName) && 609 Objects.equals(mCallerDisplayNamePresentation, 610 d.mCallerDisplayNamePresentation) && 611 Objects.equals(mAccountHandle, d.mAccountHandle) && 612 Objects.equals(mCallCapabilities, d.mCallCapabilities) && 613 Objects.equals(mCallProperties, d.mCallProperties) && 614 Objects.equals(mDisconnectCause, d.mDisconnectCause) && 615 Objects.equals(mConnectTimeMillis, d.mConnectTimeMillis) && 616 Objects.equals(mGatewayInfo, d.mGatewayInfo) && 617 Objects.equals(mVideoState, d.mVideoState) && 618 Objects.equals(mStatusHints, d.mStatusHints) && 619 areBundlesEqual(mExtras, d.mExtras) && 620 areBundlesEqual(mIntentExtras, d.mIntentExtras); 621 } 622 return false; 623 } 624 625 @Override hashCode()626 public int hashCode() { 627 return 628 Objects.hashCode(mHandle) + 629 Objects.hashCode(mHandlePresentation) + 630 Objects.hashCode(mCallerDisplayName) + 631 Objects.hashCode(mCallerDisplayNamePresentation) + 632 Objects.hashCode(mAccountHandle) + 633 Objects.hashCode(mCallCapabilities) + 634 Objects.hashCode(mCallProperties) + 635 Objects.hashCode(mDisconnectCause) + 636 Objects.hashCode(mConnectTimeMillis) + 637 Objects.hashCode(mGatewayInfo) + 638 Objects.hashCode(mVideoState) + 639 Objects.hashCode(mStatusHints) + 640 Objects.hashCode(mExtras) + 641 Objects.hashCode(mIntentExtras); 642 } 643 644 /** {@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)645 public Details( 646 String telecomCallId, 647 Uri handle, 648 int handlePresentation, 649 String callerDisplayName, 650 int callerDisplayNamePresentation, 651 PhoneAccountHandle accountHandle, 652 int capabilities, 653 int properties, 654 DisconnectCause disconnectCause, 655 long connectTimeMillis, 656 GatewayInfo gatewayInfo, 657 int videoState, 658 StatusHints statusHints, 659 Bundle extras, 660 Bundle intentExtras) { 661 mTelecomCallId = telecomCallId; 662 mHandle = handle; 663 mHandlePresentation = handlePresentation; 664 mCallerDisplayName = callerDisplayName; 665 mCallerDisplayNamePresentation = callerDisplayNamePresentation; 666 mAccountHandle = accountHandle; 667 mCallCapabilities = capabilities; 668 mCallProperties = properties; 669 mDisconnectCause = disconnectCause; 670 mConnectTimeMillis = connectTimeMillis; 671 mGatewayInfo = gatewayInfo; 672 mVideoState = videoState; 673 mStatusHints = statusHints; 674 mExtras = extras; 675 mIntentExtras = intentExtras; 676 } 677 678 /** {@hide} */ createFromParcelableCall(ParcelableCall parcelableCall)679 public static Details createFromParcelableCall(ParcelableCall parcelableCall) { 680 return new Details( 681 parcelableCall.getId(), 682 parcelableCall.getHandle(), 683 parcelableCall.getHandlePresentation(), 684 parcelableCall.getCallerDisplayName(), 685 parcelableCall.getCallerDisplayNamePresentation(), 686 parcelableCall.getAccountHandle(), 687 parcelableCall.getCapabilities(), 688 parcelableCall.getProperties(), 689 parcelableCall.getDisconnectCause(), 690 parcelableCall.getConnectTimeMillis(), 691 parcelableCall.getGatewayInfo(), 692 parcelableCall.getVideoState(), 693 parcelableCall.getStatusHints(), 694 parcelableCall.getExtras(), 695 parcelableCall.getIntentExtras()); 696 } 697 698 @Override toString()699 public String toString() { 700 StringBuilder sb = new StringBuilder(); 701 sb.append("[pa: "); 702 sb.append(mAccountHandle); 703 sb.append(", hdl: "); 704 sb.append(Log.pii(mHandle)); 705 sb.append(", caps: "); 706 sb.append(capabilitiesToString(mCallCapabilities)); 707 sb.append(", props: "); 708 sb.append(propertiesToString(mCallProperties)); 709 sb.append("]"); 710 return sb.toString(); 711 } 712 } 713 714 /** 715 * Defines callbacks which inform the {@link InCallService} of changes to a {@link Call}. 716 * These callbacks can originate from the Telecom framework, or a {@link ConnectionService} 717 * implementation. 718 * <p> 719 * You can handle these callbacks by extending the {@link Callback} class and overriding the 720 * callbacks that your {@link InCallService} is interested in. The callback methods include the 721 * {@link Call} for which the callback applies, allowing reuse of a single instance of your 722 * {@link Callback} implementation, if desired. 723 * <p> 724 * Use {@link Call#registerCallback(Callback)} to register your callback(s). Ensure 725 * {@link Call#unregisterCallback(Callback)} is called when you no longer require callbacks 726 * (typically in {@link InCallService#onCallRemoved(Call)}). 727 * Note: Callbacks which occur before you call {@link Call#registerCallback(Callback)} will not 728 * reach your implementation of {@link Callback}, so it is important to register your callback 729 * as soon as your {@link InCallService} is notified of a new call via 730 * {@link InCallService#onCallAdded(Call)}. 731 */ 732 public static abstract class Callback { 733 /** 734 * Invoked when the state of this {@code Call} has changed. See {@link #getState()}. 735 * 736 * @param call The {@code Call} invoking this method. 737 * @param state The new state of the {@code Call}. 738 */ onStateChanged(Call call, int state)739 public void onStateChanged(Call call, int state) {} 740 741 /** 742 * Invoked when the parent of this {@code Call} has changed. See {@link #getParent()}. 743 * 744 * @param call The {@code Call} invoking this method. 745 * @param parent The new parent of the {@code Call}. 746 */ onParentChanged(Call call, Call parent)747 public void onParentChanged(Call call, Call parent) {} 748 749 /** 750 * Invoked when the children of this {@code Call} have changed. See {@link #getChildren()}. 751 * 752 * @param call The {@code Call} invoking this method. 753 * @param children The new children of the {@code Call}. 754 */ onChildrenChanged(Call call, List<Call> children)755 public void onChildrenChanged(Call call, List<Call> children) {} 756 757 /** 758 * Invoked when the details of this {@code Call} have changed. See {@link #getDetails()}. 759 * 760 * @param call The {@code Call} invoking this method. 761 * @param details A {@code Details} object describing the {@code Call}. 762 */ onDetailsChanged(Call call, Details details)763 public void onDetailsChanged(Call call, Details details) {} 764 765 /** 766 * Invoked when the text messages that can be used as responses to the incoming 767 * {@code Call} are loaded from the relevant database. 768 * See {@link #getCannedTextResponses()}. 769 * 770 * @param call The {@code Call} invoking this method. 771 * @param cannedTextResponses The text messages useable as responses. 772 */ onCannedTextResponsesLoaded(Call call, List<String> cannedTextResponses)773 public void onCannedTextResponsesLoaded(Call call, List<String> cannedTextResponses) {} 774 775 /** 776 * Invoked when the post-dial sequence in the outgoing {@code Call} has reached a pause 777 * character. This causes the post-dial signals to stop pending user confirmation. An 778 * implementation should present this choice to the user and invoke 779 * {@link #postDialContinue(boolean)} when the user makes the choice. 780 * 781 * @param call The {@code Call} invoking this method. 782 * @param remainingPostDialSequence The post-dial characters that remain to be sent. 783 */ onPostDialWait(Call call, String remainingPostDialSequence)784 public void onPostDialWait(Call call, String remainingPostDialSequence) {} 785 786 /** 787 * Invoked when the {@code Call.VideoCall} of the {@code Call} has changed. 788 * 789 * @param call The {@code Call} invoking this method. 790 * @param videoCall The {@code Call.VideoCall} associated with the {@code Call}. 791 */ onVideoCallChanged(Call call, InCallService.VideoCall videoCall)792 public void onVideoCallChanged(Call call, InCallService.VideoCall videoCall) {} 793 794 /** 795 * Invoked when the {@code Call} is destroyed. Clients should refrain from cleaning 796 * up their UI for the {@code Call} in response to state transitions. Specifically, 797 * clients should not assume that a {@link #onStateChanged(Call, int)} with a state of 798 * {@link #STATE_DISCONNECTED} is the final notification the {@code Call} will send. Rather, 799 * clients should wait for this method to be invoked. 800 * 801 * @param call The {@code Call} being destroyed. 802 */ onCallDestroyed(Call call)803 public void onCallDestroyed(Call call) {} 804 805 /** 806 * Invoked upon changes to the set of {@code Call}s with which this {@code Call} can be 807 * conferenced. 808 * 809 * @param call The {@code Call} being updated. 810 * @param conferenceableCalls The {@code Call}s with which this {@code Call} can be 811 * conferenced. 812 */ onConferenceableCallsChanged(Call call, List<Call> conferenceableCalls)813 public void onConferenceableCallsChanged(Call call, List<Call> conferenceableCalls) {} 814 815 /** 816 * Invoked when a {@link Call} receives an event from its associated {@link Connection}. 817 * <p> 818 * Where possible, the Call should make an attempt to handle {@link Connection} events which 819 * are part of the {@code android.telecom.*} namespace. The Call should ignore any events 820 * it does not wish to handle. Unexpected events should be handled gracefully, as it is 821 * possible that a {@link ConnectionService} has defined its own Connection events which a 822 * Call is not aware of. 823 * <p> 824 * See {@link Connection#sendConnectionEvent(String, Bundle)}. 825 * 826 * @param call The {@code Call} receiving the event. 827 * @param event The event. 828 * @param extras Extras associated with the connection event. 829 */ onConnectionEvent(Call call, String event, Bundle extras)830 public void onConnectionEvent(Call call, String event, Bundle extras) {} 831 } 832 833 /** 834 * @deprecated Use {@code Call.Callback} instead. 835 * @hide 836 */ 837 @Deprecated 838 @SystemApi 839 public static abstract class Listener extends Callback { } 840 841 private final Phone mPhone; 842 private final String mTelecomCallId; 843 private final InCallAdapter mInCallAdapter; 844 private final List<String> mChildrenIds = new ArrayList<>(); 845 private final List<Call> mChildren = new ArrayList<>(); 846 private final List<Call> mUnmodifiableChildren = Collections.unmodifiableList(mChildren); 847 private final List<CallbackRecord<Callback>> mCallbackRecords = new CopyOnWriteArrayList<>(); 848 private final List<Call> mConferenceableCalls = new ArrayList<>(); 849 private final List<Call> mUnmodifiableConferenceableCalls = 850 Collections.unmodifiableList(mConferenceableCalls); 851 852 private boolean mChildrenCached; 853 private String mParentId = null; 854 private int mState; 855 private List<String> mCannedTextResponses = null; 856 private String mRemainingPostDialSequence; 857 private VideoCallImpl mVideoCallImpl; 858 private Details mDetails; 859 private Bundle mExtras; 860 861 /** 862 * Obtains the post-dial sequence remaining to be emitted by this {@code Call}, if any. 863 * 864 * @return The remaining post-dial sequence, or {@code null} if there is no post-dial sequence 865 * remaining or this {@code Call} is not in a post-dial state. 866 */ getRemainingPostDialSequence()867 public String getRemainingPostDialSequence() { 868 return mRemainingPostDialSequence; 869 } 870 871 /** 872 * Instructs this {@link #STATE_RINGING} {@code Call} to answer. 873 * @param videoState The video state in which to answer the call. 874 */ answer(int videoState)875 public void answer(int videoState) { 876 mInCallAdapter.answerCall(mTelecomCallId, videoState); 877 } 878 879 /** 880 * Instructs this {@link #STATE_RINGING} {@code Call} to reject. 881 * 882 * @param rejectWithMessage Whether to reject with a text message. 883 * @param textMessage An optional text message with which to respond. 884 */ reject(boolean rejectWithMessage, String textMessage)885 public void reject(boolean rejectWithMessage, String textMessage) { 886 mInCallAdapter.rejectCall(mTelecomCallId, rejectWithMessage, textMessage); 887 } 888 889 /** 890 * Instructs this {@code Call} to disconnect. 891 */ disconnect()892 public void disconnect() { 893 mInCallAdapter.disconnectCall(mTelecomCallId); 894 } 895 896 /** 897 * Instructs this {@code Call} to go on hold. 898 */ hold()899 public void hold() { 900 mInCallAdapter.holdCall(mTelecomCallId); 901 } 902 903 /** 904 * Instructs this {@link #STATE_HOLDING} call to release from hold. 905 */ unhold()906 public void unhold() { 907 mInCallAdapter.unholdCall(mTelecomCallId); 908 } 909 910 /** 911 * Instructs this {@code Call} to play a dual-tone multi-frequency signaling (DTMF) tone. 912 * 913 * Any other currently playing DTMF tone in the specified call is immediately stopped. 914 * 915 * @param digit A character representing the DTMF digit for which to play the tone. This 916 * value must be one of {@code '0'} through {@code '9'}, {@code '*'} or {@code '#'}. 917 */ playDtmfTone(char digit)918 public void playDtmfTone(char digit) { 919 mInCallAdapter.playDtmfTone(mTelecomCallId, digit); 920 } 921 922 /** 923 * Instructs this {@code Call} to stop any dual-tone multi-frequency signaling (DTMF) tone 924 * currently playing. 925 * 926 * DTMF tones are played by calling {@link #playDtmfTone(char)}. If no DTMF tone is 927 * currently playing, this method will do nothing. 928 */ stopDtmfTone()929 public void stopDtmfTone() { 930 mInCallAdapter.stopDtmfTone(mTelecomCallId); 931 } 932 933 /** 934 * Instructs this {@code Call} to continue playing a post-dial DTMF string. 935 * 936 * A post-dial DTMF string is a string of digits entered after a phone number, when dialed, 937 * that are immediately sent as DTMF tones to the recipient as soon as the connection is made. 938 * 939 * If the DTMF string contains a {@link TelecomManager#DTMF_CHARACTER_PAUSE} symbol, this 940 * {@code Call} will temporarily pause playing the tones for a pre-defined period of time. 941 * 942 * If the DTMF string contains a {@link TelecomManager#DTMF_CHARACTER_WAIT} symbol, this 943 * {@code Call} will pause playing the tones and notify callbacks via 944 * {@link Callback#onPostDialWait(Call, String)}. At this point, the in-call app 945 * should display to the user an indication of this state and an affordance to continue 946 * the postdial sequence. When the user decides to continue the postdial sequence, the in-call 947 * app should invoke the {@link #postDialContinue(boolean)} method. 948 * 949 * @param proceed Whether or not to continue with the post-dial sequence. 950 */ postDialContinue(boolean proceed)951 public void postDialContinue(boolean proceed) { 952 mInCallAdapter.postDialContinue(mTelecomCallId, proceed); 953 } 954 955 /** 956 * Notifies this {@code Call} that an account has been selected and to proceed with placing 957 * an outgoing call. Optionally sets this account as the default account. 958 */ phoneAccountSelected(PhoneAccountHandle accountHandle, boolean setDefault)959 public void phoneAccountSelected(PhoneAccountHandle accountHandle, boolean setDefault) { 960 mInCallAdapter.phoneAccountSelected(mTelecomCallId, accountHandle, setDefault); 961 962 } 963 964 /** 965 * Instructs this {@code Call} to enter a conference. 966 * 967 * @param callToConferenceWith The other call with which to conference. 968 */ conference(Call callToConferenceWith)969 public void conference(Call callToConferenceWith) { 970 if (callToConferenceWith != null) { 971 mInCallAdapter.conference(mTelecomCallId, callToConferenceWith.mTelecomCallId); 972 } 973 } 974 975 /** 976 * Instructs this {@code Call} to split from any conference call with which it may be 977 * connected. 978 */ splitFromConference()979 public void splitFromConference() { 980 mInCallAdapter.splitFromConference(mTelecomCallId); 981 } 982 983 /** 984 * Merges the calls within this conference. See {@link Details#CAPABILITY_MERGE_CONFERENCE}. 985 */ mergeConference()986 public void mergeConference() { 987 mInCallAdapter.mergeConference(mTelecomCallId); 988 } 989 990 /** 991 * Swaps the calls within this conference. See {@link Details#CAPABILITY_SWAP_CONFERENCE}. 992 */ swapConference()993 public void swapConference() { 994 mInCallAdapter.swapConference(mTelecomCallId); 995 } 996 997 /** 998 * Initiates a request to the {@link ConnectionService} to pull an external call to the local 999 * device. 1000 * <p> 1001 * Calls to this method are ignored if the call does not have the 1002 * {@link Call.Details#PROPERTY_IS_EXTERNAL_CALL} property set. 1003 * <p> 1004 * An {@link InCallService} will only see calls which support this method if it has the 1005 * {@link TelecomManager#METADATA_INCLUDE_EXTERNAL_CALLS} metadata set to {@code true} 1006 * in its manifest. 1007 */ pullExternalCall()1008 public void pullExternalCall() { 1009 // If this isn't an external call, ignore the request. 1010 if (!mDetails.hasProperty(Details.PROPERTY_IS_EXTERNAL_CALL)) { 1011 return; 1012 } 1013 1014 mInCallAdapter.pullExternalCall(mTelecomCallId); 1015 } 1016 1017 /** 1018 * Sends a {@code Call} event from this {@code Call} to the associated {@link Connection} in 1019 * the {@link ConnectionService}. 1020 * <p> 1021 * Call events are used to communicate point in time information from an {@link InCallService} 1022 * to a {@link ConnectionService}. A {@link ConnectionService} implementation could define 1023 * events which enable the {@link InCallService}, for example, toggle a unique feature of the 1024 * {@link ConnectionService}. 1025 * <p> 1026 * A {@link ConnectionService} can communicate to the {@link InCallService} using 1027 * {@link Connection#sendConnectionEvent(String, Bundle)}. 1028 * <p> 1029 * Events are exposed to {@link ConnectionService} implementations via 1030 * {@link android.telecom.Connection#onCallEvent(String, Bundle)}. 1031 * <p> 1032 * No assumptions should be made as to how a {@link ConnectionService} will handle these events. 1033 * The {@link InCallService} must assume that the {@link ConnectionService} could chose to 1034 * ignore some events altogether. 1035 * <p> 1036 * Events should be fully qualified (e.g., {@code com.example.event.MY_EVENT}) to avoid 1037 * conflicts between {@link InCallService} implementations. Further, {@link InCallService} 1038 * implementations shall not re-purpose events in the {@code android.*} namespace, nor shall 1039 * they define their own event types in this namespace. When defining a custom event type, 1040 * ensure the contents of the extras {@link Bundle} is clearly defined. Extra keys for this 1041 * bundle should be named similar to the event type (e.g. {@code com.example.extra.MY_EXTRA}). 1042 * <p> 1043 * When defining events and the associated extras, it is important to keep their behavior 1044 * consistent when the associated {@link InCallService} is updated. Support for deprecated 1045 * events/extras should me maintained to ensure backwards compatibility with older 1046 * {@link ConnectionService} implementations which were built to support the older behavior. 1047 * 1048 * @param event The connection event. 1049 * @param extras Bundle containing extra information associated with the event. 1050 */ sendCallEvent(String event, Bundle extras)1051 public void sendCallEvent(String event, Bundle extras) { 1052 mInCallAdapter.sendCallEvent(mTelecomCallId, event, extras); 1053 } 1054 1055 /** 1056 * Adds some extras to this {@link Call}. Existing keys are replaced and new ones are 1057 * added. 1058 * <p> 1059 * No assumptions should be made as to how an In-Call UI or service will handle these 1060 * extras. Keys should be fully qualified (e.g., com.example.MY_EXTRA) to avoid conflicts. 1061 * 1062 * @param extras The extras to add. 1063 */ putExtras(Bundle extras)1064 public final void putExtras(Bundle extras) { 1065 if (extras == null) { 1066 return; 1067 } 1068 1069 if (mExtras == null) { 1070 mExtras = new Bundle(); 1071 } 1072 mExtras.putAll(extras); 1073 mInCallAdapter.putExtras(mTelecomCallId, extras); 1074 } 1075 1076 /** 1077 * Adds a boolean extra to this {@link Call}. 1078 * 1079 * @param key The extra key. 1080 * @param value The value. 1081 * @hide 1082 */ putExtra(String key, boolean value)1083 public final void putExtra(String key, boolean value) { 1084 if (mExtras == null) { 1085 mExtras = new Bundle(); 1086 } 1087 mExtras.putBoolean(key, value); 1088 mInCallAdapter.putExtra(mTelecomCallId, key, value); 1089 } 1090 1091 /** 1092 * Adds an integer extra to this {@link Call}. 1093 * 1094 * @param key The extra key. 1095 * @param value The value. 1096 * @hide 1097 */ putExtra(String key, int value)1098 public final void putExtra(String key, int value) { 1099 if (mExtras == null) { 1100 mExtras = new Bundle(); 1101 } 1102 mExtras.putInt(key, value); 1103 mInCallAdapter.putExtra(mTelecomCallId, key, value); 1104 } 1105 1106 /** 1107 * Adds a string extra to this {@link Call}. 1108 * 1109 * @param key The extra key. 1110 * @param value The value. 1111 * @hide 1112 */ putExtra(String key, String value)1113 public final void putExtra(String key, String value) { 1114 if (mExtras == null) { 1115 mExtras = new Bundle(); 1116 } 1117 mExtras.putString(key, value); 1118 mInCallAdapter.putExtra(mTelecomCallId, key, value); 1119 } 1120 1121 /** 1122 * Removes extras from this {@link Call}. 1123 * 1124 * @param keys The keys of the extras to remove. 1125 */ removeExtras(List<String> keys)1126 public final void removeExtras(List<String> keys) { 1127 if (mExtras != null) { 1128 for (String key : keys) { 1129 mExtras.remove(key); 1130 } 1131 if (mExtras.size() == 0) { 1132 mExtras = null; 1133 } 1134 } 1135 mInCallAdapter.removeExtras(mTelecomCallId, keys); 1136 } 1137 1138 /** 1139 * Removes extras from this {@link Call}. 1140 * 1141 * @param keys The keys of the extras to remove. 1142 */ removeExtras(String .... keys)1143 public final void removeExtras(String ... keys) { 1144 removeExtras(Arrays.asList(keys)); 1145 } 1146 1147 /** 1148 * Obtains the parent of this {@code Call} in a conference, if any. 1149 * 1150 * @return The parent {@code Call}, or {@code null} if this {@code Call} is not a 1151 * child of any conference {@code Call}s. 1152 */ getParent()1153 public Call getParent() { 1154 if (mParentId != null) { 1155 return mPhone.internalGetCallByTelecomId(mParentId); 1156 } 1157 return null; 1158 } 1159 1160 /** 1161 * Obtains the children of this conference {@code Call}, if any. 1162 * 1163 * @return The children of this {@code Call} if this {@code Call} is a conference, or an empty 1164 * {@code List} otherwise. 1165 */ getChildren()1166 public List<Call> getChildren() { 1167 if (!mChildrenCached) { 1168 mChildrenCached = true; 1169 mChildren.clear(); 1170 1171 for(String id : mChildrenIds) { 1172 Call call = mPhone.internalGetCallByTelecomId(id); 1173 if (call == null) { 1174 // At least one child was still not found, so do not save true for "cached" 1175 mChildrenCached = false; 1176 } else { 1177 mChildren.add(call); 1178 } 1179 } 1180 } 1181 1182 return mUnmodifiableChildren; 1183 } 1184 1185 /** 1186 * Returns the list of {@code Call}s with which this {@code Call} is allowed to conference. 1187 * 1188 * @return The list of conferenceable {@code Call}s. 1189 */ getConferenceableCalls()1190 public List<Call> getConferenceableCalls() { 1191 return mUnmodifiableConferenceableCalls; 1192 } 1193 1194 /** 1195 * Obtains the state of this {@code Call}. 1196 * 1197 * @return A state value, chosen from the {@code STATE_*} constants. 1198 */ getState()1199 public int getState() { 1200 return mState; 1201 } 1202 1203 /** 1204 * Obtains a list of canned, pre-configured message responses to present to the user as 1205 * ways of rejecting this {@code Call} using via a text message. 1206 * 1207 * @see #reject(boolean, String) 1208 * 1209 * @return A list of canned text message responses. 1210 */ getCannedTextResponses()1211 public List<String> getCannedTextResponses() { 1212 return mCannedTextResponses; 1213 } 1214 1215 /** 1216 * Obtains an object that can be used to display video from this {@code Call}. 1217 * 1218 * @return An {@code Call.VideoCall}. 1219 */ getVideoCall()1220 public InCallService.VideoCall getVideoCall() { 1221 return mVideoCallImpl; 1222 } 1223 1224 /** 1225 * Obtains an object containing call details. 1226 * 1227 * @return A {@link Details} object. Depending on the state of the {@code Call}, the 1228 * result may be {@code null}. 1229 */ getDetails()1230 public Details getDetails() { 1231 return mDetails; 1232 } 1233 1234 /** 1235 * Registers a callback to this {@code Call}. 1236 * 1237 * @param callback A {@code Callback}. 1238 */ registerCallback(Callback callback)1239 public void registerCallback(Callback callback) { 1240 registerCallback(callback, new Handler()); 1241 } 1242 1243 /** 1244 * Registers a callback to this {@code Call}. 1245 * 1246 * @param callback A {@code Callback}. 1247 * @param handler A handler which command and status changes will be delivered to. 1248 */ registerCallback(Callback callback, Handler handler)1249 public void registerCallback(Callback callback, Handler handler) { 1250 unregisterCallback(callback); 1251 // Don't allow new callback registration if the call is already being destroyed. 1252 if (callback != null && handler != null && mState != STATE_DISCONNECTED) { 1253 mCallbackRecords.add(new CallbackRecord<Callback>(callback, handler)); 1254 } 1255 } 1256 1257 /** 1258 * Unregisters a callback from this {@code Call}. 1259 * 1260 * @param callback A {@code Callback}. 1261 */ unregisterCallback(Callback callback)1262 public void unregisterCallback(Callback callback) { 1263 // Don't allow callback deregistration if the call is already being destroyed. 1264 if (callback != null && mState != STATE_DISCONNECTED) { 1265 for (CallbackRecord<Callback> record : mCallbackRecords) { 1266 if (record.getCallback() == callback) { 1267 mCallbackRecords.remove(record); 1268 break; 1269 } 1270 } 1271 } 1272 } 1273 1274 @Override toString()1275 public String toString() { 1276 return new StringBuilder(). 1277 append("Call [id: "). 1278 append(mTelecomCallId). 1279 append(", state: "). 1280 append(stateToString(mState)). 1281 append(", details: "). 1282 append(mDetails). 1283 append("]").toString(); 1284 } 1285 1286 /** 1287 * @param state An integer value of a {@code STATE_*} constant. 1288 * @return A string representation of the value. 1289 */ stateToString(int state)1290 private static String stateToString(int state) { 1291 switch (state) { 1292 case STATE_NEW: 1293 return "NEW"; 1294 case STATE_RINGING: 1295 return "RINGING"; 1296 case STATE_DIALING: 1297 return "DIALING"; 1298 case STATE_ACTIVE: 1299 return "ACTIVE"; 1300 case STATE_HOLDING: 1301 return "HOLDING"; 1302 case STATE_DISCONNECTED: 1303 return "DISCONNECTED"; 1304 case STATE_CONNECTING: 1305 return "CONNECTING"; 1306 case STATE_DISCONNECTING: 1307 return "DISCONNECTING"; 1308 case STATE_SELECT_PHONE_ACCOUNT: 1309 return "SELECT_PHONE_ACCOUNT"; 1310 default: 1311 Log.w(Call.class, "Unknown state %d", state); 1312 return "UNKNOWN"; 1313 } 1314 } 1315 1316 /** 1317 * Adds a listener to this {@code Call}. 1318 * 1319 * @param listener A {@code Listener}. 1320 * @deprecated Use {@link #registerCallback} instead. 1321 * @hide 1322 */ 1323 @Deprecated 1324 @SystemApi addListener(Listener listener)1325 public void addListener(Listener listener) { 1326 registerCallback(listener); 1327 } 1328 1329 /** 1330 * Removes a listener from this {@code Call}. 1331 * 1332 * @param listener A {@code Listener}. 1333 * @deprecated Use {@link #unregisterCallback} instead. 1334 * @hide 1335 */ 1336 @Deprecated 1337 @SystemApi removeListener(Listener listener)1338 public void removeListener(Listener listener) { 1339 unregisterCallback(listener); 1340 } 1341 1342 /** {@hide} */ Call(Phone phone, String telecomCallId, InCallAdapter inCallAdapter)1343 Call(Phone phone, String telecomCallId, InCallAdapter inCallAdapter) { 1344 mPhone = phone; 1345 mTelecomCallId = telecomCallId; 1346 mInCallAdapter = inCallAdapter; 1347 mState = STATE_NEW; 1348 } 1349 1350 /** {@hide} */ Call(Phone phone, String telecomCallId, InCallAdapter inCallAdapter, int state)1351 Call(Phone phone, String telecomCallId, InCallAdapter inCallAdapter, int state) { 1352 mPhone = phone; 1353 mTelecomCallId = telecomCallId; 1354 mInCallAdapter = inCallAdapter; 1355 mState = state; 1356 } 1357 1358 /** {@hide} */ internalGetCallId()1359 final String internalGetCallId() { 1360 return mTelecomCallId; 1361 } 1362 1363 /** {@hide} */ internalUpdate(ParcelableCall parcelableCall, Map<String, Call> callIdMap)1364 final void internalUpdate(ParcelableCall parcelableCall, Map<String, Call> callIdMap) { 1365 // First, we update the internal state as far as possible before firing any updates. 1366 Details details = Details.createFromParcelableCall(parcelableCall); 1367 boolean detailsChanged = !Objects.equals(mDetails, details); 1368 if (detailsChanged) { 1369 mDetails = details; 1370 } 1371 1372 boolean cannedTextResponsesChanged = false; 1373 if (mCannedTextResponses == null && parcelableCall.getCannedSmsResponses() != null 1374 && !parcelableCall.getCannedSmsResponses().isEmpty()) { 1375 mCannedTextResponses = 1376 Collections.unmodifiableList(parcelableCall.getCannedSmsResponses()); 1377 cannedTextResponsesChanged = true; 1378 } 1379 1380 VideoCallImpl newVideoCallImpl = parcelableCall.getVideoCallImpl(); 1381 boolean videoCallChanged = parcelableCall.isVideoCallProviderChanged() && 1382 !Objects.equals(mVideoCallImpl, newVideoCallImpl); 1383 if (videoCallChanged) { 1384 mVideoCallImpl = newVideoCallImpl; 1385 } 1386 if (mVideoCallImpl != null) { 1387 mVideoCallImpl.setVideoState(getDetails().getVideoState()); 1388 } 1389 1390 int state = parcelableCall.getState(); 1391 boolean stateChanged = mState != state; 1392 if (stateChanged) { 1393 mState = state; 1394 } 1395 1396 String parentId = parcelableCall.getParentCallId(); 1397 boolean parentChanged = !Objects.equals(mParentId, parentId); 1398 if (parentChanged) { 1399 mParentId = parentId; 1400 } 1401 1402 List<String> childCallIds = parcelableCall.getChildCallIds(); 1403 boolean childrenChanged = !Objects.equals(childCallIds, mChildrenIds); 1404 if (childrenChanged) { 1405 mChildrenIds.clear(); 1406 mChildrenIds.addAll(parcelableCall.getChildCallIds()); 1407 mChildrenCached = false; 1408 } 1409 1410 List<String> conferenceableCallIds = parcelableCall.getConferenceableCallIds(); 1411 List<Call> conferenceableCalls = new ArrayList<Call>(conferenceableCallIds.size()); 1412 for (String otherId : conferenceableCallIds) { 1413 if (callIdMap.containsKey(otherId)) { 1414 conferenceableCalls.add(callIdMap.get(otherId)); 1415 } 1416 } 1417 1418 if (!Objects.equals(mConferenceableCalls, conferenceableCalls)) { 1419 mConferenceableCalls.clear(); 1420 mConferenceableCalls.addAll(conferenceableCalls); 1421 fireConferenceableCallsChanged(); 1422 } 1423 1424 // Now we fire updates, ensuring that any client who listens to any of these notifications 1425 // gets the most up-to-date state. 1426 1427 if (stateChanged) { 1428 fireStateChanged(mState); 1429 } 1430 if (detailsChanged) { 1431 fireDetailsChanged(mDetails); 1432 } 1433 if (cannedTextResponsesChanged) { 1434 fireCannedTextResponsesLoaded(mCannedTextResponses); 1435 } 1436 if (videoCallChanged) { 1437 fireVideoCallChanged(mVideoCallImpl); 1438 } 1439 if (parentChanged) { 1440 fireParentChanged(getParent()); 1441 } 1442 if (childrenChanged) { 1443 fireChildrenChanged(getChildren()); 1444 } 1445 1446 // If we have transitioned to DISCONNECTED, that means we need to notify clients and 1447 // remove ourselves from the Phone. Note that we do this after completing all state updates 1448 // so a client can cleanly transition all their UI to the state appropriate for a 1449 // DISCONNECTED Call while still relying on the existence of that Call in the Phone's list. 1450 if (mState == STATE_DISCONNECTED) { 1451 fireCallDestroyed(); 1452 } 1453 } 1454 1455 /** {@hide} */ internalSetPostDialWait(String remaining)1456 final void internalSetPostDialWait(String remaining) { 1457 mRemainingPostDialSequence = remaining; 1458 firePostDialWait(mRemainingPostDialSequence); 1459 } 1460 1461 /** {@hide} */ internalSetDisconnected()1462 final void internalSetDisconnected() { 1463 if (mState != Call.STATE_DISCONNECTED) { 1464 mState = Call.STATE_DISCONNECTED; 1465 fireStateChanged(mState); 1466 fireCallDestroyed(); 1467 } 1468 } 1469 1470 /** {@hide} */ internalOnConnectionEvent(String event, Bundle extras)1471 final void internalOnConnectionEvent(String event, Bundle extras) { 1472 fireOnConnectionEvent(event, extras); 1473 } 1474 fireStateChanged(final int newState)1475 private void fireStateChanged(final int newState) { 1476 for (CallbackRecord<Callback> record : mCallbackRecords) { 1477 final Call call = this; 1478 final Callback callback = record.getCallback(); 1479 record.getHandler().post(new Runnable() { 1480 @Override 1481 public void run() { 1482 callback.onStateChanged(call, newState); 1483 } 1484 }); 1485 } 1486 } 1487 fireParentChanged(final Call newParent)1488 private void fireParentChanged(final Call newParent) { 1489 for (CallbackRecord<Callback> record : mCallbackRecords) { 1490 final Call call = this; 1491 final Callback callback = record.getCallback(); 1492 record.getHandler().post(new Runnable() { 1493 @Override 1494 public void run() { 1495 callback.onParentChanged(call, newParent); 1496 } 1497 }); 1498 } 1499 } 1500 fireChildrenChanged(final List<Call> children)1501 private void fireChildrenChanged(final List<Call> children) { 1502 for (CallbackRecord<Callback> record : mCallbackRecords) { 1503 final Call call = this; 1504 final Callback callback = record.getCallback(); 1505 record.getHandler().post(new Runnable() { 1506 @Override 1507 public void run() { 1508 callback.onChildrenChanged(call, children); 1509 } 1510 }); 1511 } 1512 } 1513 fireDetailsChanged(final Details details)1514 private void fireDetailsChanged(final Details details) { 1515 for (CallbackRecord<Callback> record : mCallbackRecords) { 1516 final Call call = this; 1517 final Callback callback = record.getCallback(); 1518 record.getHandler().post(new Runnable() { 1519 @Override 1520 public void run() { 1521 callback.onDetailsChanged(call, details); 1522 } 1523 }); 1524 } 1525 } 1526 fireCannedTextResponsesLoaded(final List<String> cannedTextResponses)1527 private void fireCannedTextResponsesLoaded(final List<String> cannedTextResponses) { 1528 for (CallbackRecord<Callback> record : mCallbackRecords) { 1529 final Call call = this; 1530 final Callback callback = record.getCallback(); 1531 record.getHandler().post(new Runnable() { 1532 @Override 1533 public void run() { 1534 callback.onCannedTextResponsesLoaded(call, cannedTextResponses); 1535 } 1536 }); 1537 } 1538 } 1539 fireVideoCallChanged(final InCallService.VideoCall videoCall)1540 private void fireVideoCallChanged(final InCallService.VideoCall videoCall) { 1541 for (CallbackRecord<Callback> record : mCallbackRecords) { 1542 final Call call = this; 1543 final Callback callback = record.getCallback(); 1544 record.getHandler().post(new Runnable() { 1545 @Override 1546 public void run() { 1547 callback.onVideoCallChanged(call, videoCall); 1548 } 1549 }); 1550 } 1551 } 1552 firePostDialWait(final String remainingPostDialSequence)1553 private void firePostDialWait(final String remainingPostDialSequence) { 1554 for (CallbackRecord<Callback> record : mCallbackRecords) { 1555 final Call call = this; 1556 final Callback callback = record.getCallback(); 1557 record.getHandler().post(new Runnable() { 1558 @Override 1559 public void run() { 1560 callback.onPostDialWait(call, remainingPostDialSequence); 1561 } 1562 }); 1563 } 1564 } 1565 fireCallDestroyed()1566 private void fireCallDestroyed() { 1567 /** 1568 * To preserve the ordering of the Call's onCallDestroyed callback and Phone's 1569 * onCallRemoved callback, we remove this call from the Phone's record 1570 * only once all of the registered onCallDestroyed callbacks are executed. 1571 * All the callbacks get removed from our records as a part of this operation 1572 * since onCallDestroyed is the final callback. 1573 */ 1574 final Call call = this; 1575 if (mCallbackRecords.isEmpty()) { 1576 // No callbacks registered, remove the call from Phone's record. 1577 mPhone.internalRemoveCall(call); 1578 } 1579 for (final CallbackRecord<Callback> record : mCallbackRecords) { 1580 final Callback callback = record.getCallback(); 1581 record.getHandler().post(new Runnable() { 1582 @Override 1583 public void run() { 1584 boolean isFinalRemoval = false; 1585 RuntimeException toThrow = null; 1586 try { 1587 callback.onCallDestroyed(call); 1588 } catch (RuntimeException e) { 1589 toThrow = e; 1590 } 1591 synchronized(Call.this) { 1592 mCallbackRecords.remove(record); 1593 if (mCallbackRecords.isEmpty()) { 1594 isFinalRemoval = true; 1595 } 1596 } 1597 if (isFinalRemoval) { 1598 mPhone.internalRemoveCall(call); 1599 } 1600 if (toThrow != null) { 1601 throw toThrow; 1602 } 1603 } 1604 }); 1605 } 1606 } 1607 fireConferenceableCallsChanged()1608 private void fireConferenceableCallsChanged() { 1609 for (CallbackRecord<Callback> record : mCallbackRecords) { 1610 final Call call = this; 1611 final Callback callback = record.getCallback(); 1612 record.getHandler().post(new Runnable() { 1613 @Override 1614 public void run() { 1615 callback.onConferenceableCallsChanged(call, mUnmodifiableConferenceableCalls); 1616 } 1617 }); 1618 } 1619 } 1620 1621 /** 1622 * Notifies listeners of an incoming connection event. 1623 * <p> 1624 * Connection events are issued via {@link Connection#sendConnectionEvent(String, Bundle)}. 1625 * 1626 * @param event 1627 * @param extras 1628 */ fireOnConnectionEvent(final String event, final Bundle extras)1629 private void fireOnConnectionEvent(final String event, final Bundle extras) { 1630 for (CallbackRecord<Callback> record : mCallbackRecords) { 1631 final Call call = this; 1632 final Callback callback = record.getCallback(); 1633 record.getHandler().post(new Runnable() { 1634 @Override 1635 public void run() { 1636 callback.onConnectionEvent(call, event, extras); 1637 } 1638 }); 1639 } 1640 } 1641 1642 /** 1643 * Determines if two bundles are equal. 1644 * 1645 * @param bundle The original bundle. 1646 * @param newBundle The bundle to compare with. 1647 * @retrun {@code true} if the bundles are equal, {@code false} otherwise. 1648 */ areBundlesEqual(Bundle bundle, Bundle newBundle)1649 private static boolean areBundlesEqual(Bundle bundle, Bundle newBundle) { 1650 if (bundle == null || newBundle == null) { 1651 return bundle == newBundle; 1652 } 1653 1654 if (bundle.size() != newBundle.size()) { 1655 return false; 1656 } 1657 1658 for(String key : bundle.keySet()) { 1659 if (key != null) { 1660 final Object value = bundle.get(key); 1661 final Object newValue = newBundle.get(key); 1662 if (!Objects.equals(value, newValue)) { 1663 return false; 1664 } 1665 } 1666 } 1667 return true; 1668 } 1669 } 1670