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