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