Call.java revision 32f24731604fd81289a39619bbc925b65184b505
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 17package android.telecom; 18 19import android.annotation.SystemApi; 20import android.net.Uri; 21import android.os.Bundle; 22import android.os.Handler; 23 24import java.lang.String; 25import java.util.ArrayList; 26import java.util.Collections; 27import java.util.LinkedList; 28import java.util.List; 29import java.util.Map; 30import java.util.Objects; 31import java.util.concurrent.CopyOnWriteArrayList; 32 33/** 34 * Represents an ongoing phone call that the in-call app should present to the user. 35 */ 36public 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 key to retrieve the optional {@code PhoneAccount}s Telecom can bundle with its Call 100 * extras. Used to pass the phone accounts to display on the front end to the user in order to 101 * select phone accounts to (for example) place a call. 102 */ 103 public static final String AVAILABLE_PHONE_ACCOUNTS = "selectPhoneAccountAccounts"; 104 105 public static class Details { 106 107 /** Call can currently be put on hold or unheld. */ 108 public static final int CAPABILITY_HOLD = 0x00000001; 109 110 /** Call supports the hold feature. */ 111 public static final int CAPABILITY_SUPPORT_HOLD = 0x00000002; 112 113 /** 114 * Calls within a conference can be merged. A {@link ConnectionService} has the option to 115 * add a {@link Conference} call before the child {@link Connection}s are merged. This is how 116 * CDMA-based {@link Connection}s are implemented. For these unmerged {@link Conference}s, this 117 * capability allows a merge button to be shown while the conference call is in the foreground 118 * of the in-call UI. 119 * <p> 120 * This is only intended for use by a {@link Conference}. 121 */ 122 public static final int CAPABILITY_MERGE_CONFERENCE = 0x00000004; 123 124 /** 125 * Calls within a conference can be swapped between foreground and background. 126 * See {@link #CAPABILITY_MERGE_CONFERENCE} for additional information. 127 * <p> 128 * This is only intended for use by a {@link Conference}. 129 */ 130 public static final int CAPABILITY_SWAP_CONFERENCE = 0x00000008; 131 132 /** 133 * @hide 134 */ 135 public static final int CAPABILITY_UNUSED_1 = 0x00000010; 136 137 /** Call supports responding via text option. */ 138 public static final int CAPABILITY_RESPOND_VIA_TEXT = 0x00000020; 139 140 /** Call can be muted. */ 141 public static final int CAPABILITY_MUTE = 0x00000040; 142 143 /** 144 * Call supports conference call management. This capability only applies to {@link Conference} 145 * calls which can have {@link Connection}s as children. 146 */ 147 public static final int CAPABILITY_MANAGE_CONFERENCE = 0x00000080; 148 149 /** 150 * Local device supports receiving video. 151 */ 152 public static final int CAPABILITY_SUPPORTS_VT_LOCAL_RX = 0x00000100; 153 154 /** 155 * Local device supports transmitting video. 156 */ 157 public static final int CAPABILITY_SUPPORTS_VT_LOCAL_TX = 0x00000200; 158 159 /** 160 * Local device supports bidirectional video calling. 161 */ 162 public static final int CAPABILITY_SUPPORTS_VT_LOCAL_BIDIRECTIONAL = 163 CAPABILITY_SUPPORTS_VT_LOCAL_RX | CAPABILITY_SUPPORTS_VT_LOCAL_TX; 164 165 /** 166 * Remote device supports receiving video. 167 */ 168 public static final int CAPABILITY_SUPPORTS_VT_REMOTE_RX = 0x00000400; 169 170 /** 171 * Remote device supports transmitting video. 172 */ 173 public static final int CAPABILITY_SUPPORTS_VT_REMOTE_TX = 0x00000800; 174 175 /** 176 * Remote device supports bidirectional video calling. 177 */ 178 public static final int CAPABILITY_SUPPORTS_VT_REMOTE_BIDIRECTIONAL = 179 CAPABILITY_SUPPORTS_VT_REMOTE_RX | CAPABILITY_SUPPORTS_VT_REMOTE_TX; 180 181 /** 182 * Call is able to be separated from its parent {@code Conference}, if any. 183 */ 184 public static final int CAPABILITY_SEPARATE_FROM_CONFERENCE = 0x00001000; 185 186 /** 187 * Call is able to be individually disconnected when in a {@code Conference}. 188 */ 189 public static final int CAPABILITY_DISCONNECT_FROM_CONFERENCE = 0x00002000; 190 191 /** 192 * Speed up audio setup for MT call. 193 * @hide 194 */ 195 public static final int CAPABILITY_SPEED_UP_MT_AUDIO = 0x00040000; 196 197 /** 198 * Call can be upgraded to a video call. 199 * @hide 200 */ 201 public static final int CAPABILITY_CAN_UPGRADE_TO_VIDEO = 0x00080000; 202 203 /** 204 * For video calls, indicates whether the outgoing video for the call can be paused using 205 * the {@link android.telecom.VideoProfile#STATE_PAUSED} VideoState. 206 */ 207 public static final int CAPABILITY_CAN_PAUSE_VIDEO = 0x00100000; 208 209 //****************************************************************************************** 210 // Next CAPABILITY value: 0x00004000 211 //****************************************************************************************** 212 213 /** 214 * Whether the call is currently a conference. 215 */ 216 public static final int PROPERTY_CONFERENCE = 0x00000001; 217 218 /** 219 * Whether the call is a generic conference, where we do not know the precise state of 220 * participants in the conference (eg. on CDMA). 221 */ 222 public static final int PROPERTY_GENERIC_CONFERENCE = 0x00000002; 223 224 /** 225 * Whether the call is made while the device is in emergency callback mode. 226 */ 227 public static final int PROPERTY_EMERGENCY_CALLBACK_MODE = 0x00000004; 228 229 /** 230 * Connection is using WIFI. 231 */ 232 public static final int PROPERTY_WIFI = 0x00000008; 233 234 /** 235 * Call is using high definition audio. 236 */ 237 public static final int PROPERTY_HIGH_DEF_AUDIO = 0x00000010; 238 239 //****************************************************************************************** 240 // Next PROPERTY value: 0x00000020 241 //****************************************************************************************** 242 243 private final Uri mHandle; 244 private final int mHandlePresentation; 245 private final String mCallerDisplayName; 246 private final int mCallerDisplayNamePresentation; 247 private final PhoneAccountHandle mAccountHandle; 248 private final int mCallCapabilities; 249 private final int mCallProperties; 250 private final DisconnectCause mDisconnectCause; 251 private final long mConnectTimeMillis; 252 private final GatewayInfo mGatewayInfo; 253 private final int mVideoState; 254 private final StatusHints mStatusHints; 255 private final Bundle mExtras; 256 257 /** 258 * Whether the supplied capabilities supports the specified capability. 259 * 260 * @param capabilities A bit field of capabilities. 261 * @param capability The capability to check capabilities for. 262 * @return Whether the specified capability is supported. 263 */ 264 public static boolean can(int capabilities, int capability) { 265 return (capabilities & capability) != 0; 266 } 267 268 /** 269 * Whether the capabilities of this {@code Details} supports the specified capability. 270 * 271 * @param capability The capability to check capabilities for. 272 * @return Whether the specified capability is supported. 273 */ 274 public boolean can(int capability) { 275 return can(mCallCapabilities, capability); 276 } 277 278 /** 279 * Render a set of capability bits ({@code CAPABILITY_*}) as a human readable string. 280 * 281 * @param capabilities A capability bit field. 282 * @return A human readable string representation. 283 */ 284 public static String capabilitiesToString(int capabilities) { 285 StringBuilder builder = new StringBuilder(); 286 builder.append("[Capabilities:"); 287 if (can(capabilities, CAPABILITY_HOLD)) { 288 builder.append(" CAPABILITY_HOLD"); 289 } 290 if (can(capabilities, CAPABILITY_SUPPORT_HOLD)) { 291 builder.append(" CAPABILITY_SUPPORT_HOLD"); 292 } 293 if (can(capabilities, CAPABILITY_MERGE_CONFERENCE)) { 294 builder.append(" CAPABILITY_MERGE_CONFERENCE"); 295 } 296 if (can(capabilities, CAPABILITY_SWAP_CONFERENCE)) { 297 builder.append(" CAPABILITY_SWAP_CONFERENCE"); 298 } 299 if (can(capabilities, CAPABILITY_RESPOND_VIA_TEXT)) { 300 builder.append(" CAPABILITY_RESPOND_VIA_TEXT"); 301 } 302 if (can(capabilities, CAPABILITY_MUTE)) { 303 builder.append(" CAPABILITY_MUTE"); 304 } 305 if (can(capabilities, CAPABILITY_MANAGE_CONFERENCE)) { 306 builder.append(" CAPABILITY_MANAGE_CONFERENCE"); 307 } 308 if (can(capabilities, CAPABILITY_SUPPORTS_VT_LOCAL_RX)) { 309 builder.append(" CAPABILITY_SUPPORTS_VT_LOCAL_RX"); 310 } 311 if (can(capabilities, CAPABILITY_SUPPORTS_VT_LOCAL_TX)) { 312 builder.append(" CAPABILITY_SUPPORTS_VT_LOCAL_TX"); 313 } 314 if (can(capabilities, CAPABILITY_SUPPORTS_VT_LOCAL_BIDIRECTIONAL)) { 315 builder.append(" CAPABILITY_SUPPORTS_VT_LOCAL_BIDIRECTIONAL"); 316 } 317 if (can(capabilities, CAPABILITY_SUPPORTS_VT_REMOTE_RX)) { 318 builder.append(" CAPABILITY_SUPPORTS_VT_REMOTE_RX"); 319 } 320 if (can(capabilities, CAPABILITY_SUPPORTS_VT_REMOTE_TX)) { 321 builder.append(" CAPABILITY_SUPPORTS_VT_REMOTE_TX"); 322 } 323 if (can(capabilities, CAPABILITY_SUPPORTS_VT_REMOTE_BIDIRECTIONAL)) { 324 builder.append(" CAPABILITY_SUPPORTS_VT_REMOTE_BIDIRECTIONAL"); 325 } 326 if (can(capabilities, CAPABILITY_SPEED_UP_MT_AUDIO)) { 327 builder.append(" CAPABILITY_SPEED_UP_MT_AUDIO"); 328 } 329 if (can(capabilities, CAPABILITY_CAN_UPGRADE_TO_VIDEO)) { 330 builder.append(" CAPABILITY_CAN_UPGRADE_TO_VIDEO"); 331 } 332 if (can(capabilities, CAPABILITY_CAN_PAUSE_VIDEO)) { 333 builder.append(" CAPABILITY_CAN_PAUSE_VIDEO"); 334 } 335 builder.append("]"); 336 return builder.toString(); 337 } 338 339 /** 340 * Whether the supplied properties includes the specified property. 341 * 342 * @param properties A bit field of properties. 343 * @param property The property to check properties for. 344 * @return Whether the specified property is supported. 345 */ 346 public static boolean hasProperty(int properties, int property) { 347 return (properties & property) != 0; 348 } 349 350 /** 351 * Whether the properties of this {@code Details} includes the specified property. 352 * 353 * @param property The property to check properties for. 354 * @return Whether the specified property is supported. 355 */ 356 public boolean hasProperty(int property) { 357 return hasProperty(mCallProperties, property); 358 } 359 360 /** 361 * Render a set of property bits ({@code PROPERTY_*}) as a human readable string. 362 * 363 * @param properties A property bit field. 364 * @return A human readable string representation. 365 */ 366 public static String propertiesToString(int properties) { 367 StringBuilder builder = new StringBuilder(); 368 builder.append("[Properties:"); 369 if (hasProperty(properties, PROPERTY_CONFERENCE)) { 370 builder.append(" PROPERTY_CONFERENCE"); 371 } 372 if (hasProperty(properties, PROPERTY_GENERIC_CONFERENCE)) { 373 builder.append(" PROPERTY_GENERIC_CONFERENCE"); 374 } 375 if (hasProperty(properties, PROPERTY_WIFI)) { 376 builder.append(" PROPERTY_WIFI"); 377 } 378 if (hasProperty(properties, PROPERTY_HIGH_DEF_AUDIO)) { 379 builder.append(" PROPERTY_HIGH_DEF_AUDIO"); 380 } 381 if (hasProperty(properties, PROPERTY_EMERGENCY_CALLBACK_MODE)) { 382 builder.append(" EMERGENCY_CALLBACK_MODE"); 383 } 384 builder.append("]"); 385 return builder.toString(); 386 } 387 388 /** 389 * @return The handle (e.g., phone number) to which the {@code Call} is currently 390 * connected. 391 */ 392 public Uri getHandle() { 393 return mHandle; 394 } 395 396 /** 397 * @return The presentation requirements for the handle. See 398 * {@link TelecomManager} for valid values. 399 */ 400 public int getHandlePresentation() { 401 return mHandlePresentation; 402 } 403 404 /** 405 * @return The display name for the caller. 406 */ 407 public String getCallerDisplayName() { 408 return mCallerDisplayName; 409 } 410 411 /** 412 * @return The presentation requirements for the caller display name. See 413 * {@link TelecomManager} for valid values. 414 */ 415 public int getCallerDisplayNamePresentation() { 416 return mCallerDisplayNamePresentation; 417 } 418 419 /** 420 * @return The {@code PhoneAccountHandle} whereby the {@code Call} is currently being 421 * routed. 422 */ 423 public PhoneAccountHandle getAccountHandle() { 424 return mAccountHandle; 425 } 426 427 /** 428 * @return A bitmask of the capabilities of the {@code Call}, as defined by the various 429 * {@code CAPABILITY_*} constants in this class. 430 */ 431 public int getCallCapabilities() { 432 return mCallCapabilities; 433 } 434 435 /** 436 * @return A bitmask of the properties of the {@code Call}, as defined by the various 437 * {@code PROPERTY_*} constants in this class. 438 */ 439 public int getCallProperties() { 440 return mCallProperties; 441 } 442 443 /** 444 * @return For a {@link #STATE_DISCONNECTED} {@code Call}, the disconnect cause expressed 445 * by {@link android.telecom.DisconnectCause}. 446 */ 447 public DisconnectCause getDisconnectCause() { 448 return mDisconnectCause; 449 } 450 451 /** 452 * @return The time the {@code Call} has been connected. This information is updated 453 * periodically, but user interfaces should not rely on this to display any "call time 454 * clock". 455 */ 456 public final long getConnectTimeMillis() { 457 return mConnectTimeMillis; 458 } 459 460 /** 461 * @return Information about any calling gateway the {@code Call} may be using. 462 */ 463 public GatewayInfo getGatewayInfo() { 464 return mGatewayInfo; 465 } 466 467 /** 468 * @return The video state of the {@code Call}. 469 */ 470 public int getVideoState() { 471 return mVideoState; 472 } 473 474 /** 475 * @return The current {@link android.telecom.StatusHints}, or {@code null} if none 476 * have been set. 477 */ 478 public StatusHints getStatusHints() { 479 return mStatusHints; 480 } 481 482 /** 483 * @return A bundle extras to pass with the call 484 */ 485 public Bundle getExtras() { 486 return mExtras; 487 } 488 489 @Override 490 public boolean equals(Object o) { 491 if (o instanceof Details) { 492 Details d = (Details) o; 493 return 494 Objects.equals(mHandle, d.mHandle) && 495 Objects.equals(mHandlePresentation, d.mHandlePresentation) && 496 Objects.equals(mCallerDisplayName, d.mCallerDisplayName) && 497 Objects.equals(mCallerDisplayNamePresentation, 498 d.mCallerDisplayNamePresentation) && 499 Objects.equals(mAccountHandle, d.mAccountHandle) && 500 Objects.equals(mCallCapabilities, d.mCallCapabilities) && 501 Objects.equals(mCallProperties, d.mCallProperties) && 502 Objects.equals(mDisconnectCause, d.mDisconnectCause) && 503 Objects.equals(mConnectTimeMillis, d.mConnectTimeMillis) && 504 Objects.equals(mGatewayInfo, d.mGatewayInfo) && 505 Objects.equals(mVideoState, d.mVideoState) && 506 Objects.equals(mStatusHints, d.mStatusHints) && 507 Objects.equals(mExtras, d.mExtras); 508 } 509 return false; 510 } 511 512 @Override 513 public int hashCode() { 514 return 515 Objects.hashCode(mHandle) + 516 Objects.hashCode(mHandlePresentation) + 517 Objects.hashCode(mCallerDisplayName) + 518 Objects.hashCode(mCallerDisplayNamePresentation) + 519 Objects.hashCode(mAccountHandle) + 520 Objects.hashCode(mCallCapabilities) + 521 Objects.hashCode(mCallProperties) + 522 Objects.hashCode(mDisconnectCause) + 523 Objects.hashCode(mConnectTimeMillis) + 524 Objects.hashCode(mGatewayInfo) + 525 Objects.hashCode(mVideoState) + 526 Objects.hashCode(mStatusHints) + 527 Objects.hashCode(mExtras); 528 } 529 530 /** {@hide} */ 531 public Details( 532 Uri handle, 533 int handlePresentation, 534 String callerDisplayName, 535 int callerDisplayNamePresentation, 536 PhoneAccountHandle accountHandle, 537 int capabilities, 538 int properties, 539 DisconnectCause disconnectCause, 540 long connectTimeMillis, 541 GatewayInfo gatewayInfo, 542 int videoState, 543 StatusHints statusHints, 544 Bundle extras) { 545 mHandle = handle; 546 mHandlePresentation = handlePresentation; 547 mCallerDisplayName = callerDisplayName; 548 mCallerDisplayNamePresentation = callerDisplayNamePresentation; 549 mAccountHandle = accountHandle; 550 mCallCapabilities = capabilities; 551 mCallProperties = properties; 552 mDisconnectCause = disconnectCause; 553 mConnectTimeMillis = connectTimeMillis; 554 mGatewayInfo = gatewayInfo; 555 mVideoState = videoState; 556 mStatusHints = statusHints; 557 mExtras = extras; 558 } 559 } 560 561 public static abstract class Callback { 562 /** 563 * Invoked when the state of this {@code Call} has changed. See {@link #getState()}. 564 * 565 * @param call The {@code Call} invoking this method. 566 * @param state The new state of the {@code Call}. 567 */ 568 public void onStateChanged(Call call, int state) {} 569 570 /** 571 * Invoked when the parent of this {@code Call} has changed. See {@link #getParent()}. 572 * 573 * @param call The {@code Call} invoking this method. 574 * @param parent The new parent of the {@code Call}. 575 */ 576 public void onParentChanged(Call call, Call parent) {} 577 578 /** 579 * Invoked when the children of this {@code Call} have changed. See {@link #getChildren()}. 580 * 581 * @param call The {@code Call} invoking this method. 582 * @param children The new children of the {@code Call}. 583 */ 584 public void onChildrenChanged(Call call, List<Call> children) {} 585 586 /** 587 * Invoked when the details of this {@code Call} have changed. See {@link #getDetails()}. 588 * 589 * @param call The {@code Call} invoking this method. 590 * @param details A {@code Details} object describing the {@code Call}. 591 */ 592 public void onDetailsChanged(Call call, Details details) {} 593 594 /** 595 * Invoked when the text messages that can be used as responses to the incoming 596 * {@code Call} are loaded from the relevant database. 597 * See {@link #getCannedTextResponses()}. 598 * 599 * @param call The {@code Call} invoking this method. 600 * @param cannedTextResponses The text messages useable as responses. 601 */ 602 public void onCannedTextResponsesLoaded(Call call, List<String> cannedTextResponses) {} 603 604 /** 605 * Invoked when the post-dial sequence in the outgoing {@code Call} has reached a pause 606 * character. This causes the post-dial signals to stop pending user confirmation. An 607 * implementation should present this choice to the user and invoke 608 * {@link #postDialContinue(boolean)} when the user makes the choice. 609 * 610 * @param call The {@code Call} invoking this method. 611 * @param remainingPostDialSequence The post-dial characters that remain to be sent. 612 */ 613 public void onPostDialWait(Call call, String remainingPostDialSequence) {} 614 615 /** 616 * Invoked when the {@code Call.VideoCall} of the {@code Call} has changed. 617 * 618 * @param call The {@code Call} invoking this method. 619 * @param videoCall The {@code Call.VideoCall} associated with the {@code Call}. 620 */ 621 public void onVideoCallChanged(Call call, InCallService.VideoCall videoCall) {} 622 623 /** 624 * Invoked when the {@code Call} is destroyed. Clients should refrain from cleaning 625 * up their UI for the {@code Call} in response to state transitions. Specifically, 626 * clients should not assume that a {@link #onStateChanged(Call, int)} with a state of 627 * {@link #STATE_DISCONNECTED} is the final notification the {@code Call} will send. Rather, 628 * clients should wait for this method to be invoked. 629 * 630 * @param call The {@code Call} being destroyed. 631 */ 632 public void onCallDestroyed(Call call) {} 633 634 /** 635 * Invoked upon changes to the set of {@code Call}s with which this {@code Call} can be 636 * conferenced. 637 * 638 * @param call The {@code Call} being updated. 639 * @param conferenceableCalls The {@code Call}s with which this {@code Call} can be 640 * conferenced. 641 */ 642 public void onConferenceableCallsChanged(Call call, List<Call> conferenceableCalls) {} 643 } 644 645 /** 646 * @deprecated Use {@code Call.Callback} instead. 647 * @hide 648 */ 649 @Deprecated 650 @SystemApi 651 public static abstract class Listener extends Callback { } 652 653 private final Phone mPhone; 654 private final String mTelecomCallId; 655 private final InCallAdapter mInCallAdapter; 656 private final List<String> mChildrenIds = new ArrayList<>(); 657 private final List<Call> mChildren = new ArrayList<>(); 658 private final List<Call> mUnmodifiableChildren = Collections.unmodifiableList(mChildren); 659 private final List<CallbackRecord<Callback>> mCallbackRecords = new CopyOnWriteArrayList<>(); 660 private final List<Call> mConferenceableCalls = new ArrayList<>(); 661 private final List<Call> mUnmodifiableConferenceableCalls = 662 Collections.unmodifiableList(mConferenceableCalls); 663 664 private boolean mChildrenCached; 665 private String mParentId = null; 666 private int mState; 667 private List<String> mCannedTextResponses = null; 668 private String mRemainingPostDialSequence; 669 private InCallService.VideoCall mVideoCall; 670 private Details mDetails; 671 672 /** 673 * Obtains the post-dial sequence remaining to be emitted by this {@code Call}, if any. 674 * 675 * @return The remaining post-dial sequence, or {@code null} if there is no post-dial sequence 676 * remaining or this {@code Call} is not in a post-dial state. 677 */ 678 public String getRemainingPostDialSequence() { 679 return mRemainingPostDialSequence; 680 } 681 682 /** 683 * Instructs this {@link #STATE_RINGING} {@code Call} to answer. 684 * @param videoState The video state in which to answer the call. 685 */ 686 public void answer(int videoState) { 687 mInCallAdapter.answerCall(mTelecomCallId, videoState); 688 } 689 690 /** 691 * Instructs this {@link #STATE_RINGING} {@code Call} to reject. 692 * 693 * @param rejectWithMessage Whether to reject with a text message. 694 * @param textMessage An optional text message with which to respond. 695 */ 696 public void reject(boolean rejectWithMessage, String textMessage) { 697 mInCallAdapter.rejectCall(mTelecomCallId, rejectWithMessage, textMessage); 698 } 699 700 /** 701 * Instructs this {@code Call} to disconnect. 702 */ 703 public void disconnect() { 704 mInCallAdapter.disconnectCall(mTelecomCallId); 705 } 706 707 /** 708 * Instructs this {@code Call} to go on hold. 709 */ 710 public void hold() { 711 mInCallAdapter.holdCall(mTelecomCallId); 712 } 713 714 /** 715 * Instructs this {@link #STATE_HOLDING} call to release from hold. 716 */ 717 public void unhold() { 718 mInCallAdapter.unholdCall(mTelecomCallId); 719 } 720 721 /** 722 * Instructs this {@code Call} to play a dual-tone multi-frequency signaling (DTMF) tone. 723 * 724 * Any other currently playing DTMF tone in the specified call is immediately stopped. 725 * 726 * @param digit A character representing the DTMF digit for which to play the tone. This 727 * value must be one of {@code '0'} through {@code '9'}, {@code '*'} or {@code '#'}. 728 */ 729 public void playDtmfTone(char digit) { 730 mInCallAdapter.playDtmfTone(mTelecomCallId, digit); 731 } 732 733 /** 734 * Instructs this {@code Call} to stop any dual-tone multi-frequency signaling (DTMF) tone 735 * currently playing. 736 * 737 * DTMF tones are played by calling {@link #playDtmfTone(char)}. If no DTMF tone is 738 * currently playing, this method will do nothing. 739 */ 740 public void stopDtmfTone() { 741 mInCallAdapter.stopDtmfTone(mTelecomCallId); 742 } 743 744 /** 745 * Instructs this {@code Call} to continue playing a post-dial DTMF string. 746 * 747 * A post-dial DTMF string is a string of digits entered after a phone number, when dialed, 748 * that are immediately sent as DTMF tones to the recipient as soon as the connection is made. 749 * 750 * If the DTMF string contains a {@link TelecomManager#DTMF_CHARACTER_PAUSE} symbol, this 751 * {@code Call} will temporarily pause playing the tones for a pre-defined period of time. 752 * 753 * If the DTMF string contains a {@link TelecomManager#DTMF_CHARACTER_WAIT} symbol, this 754 * {@code Call} will pause playing the tones and notify callbacks via 755 * {@link Callback#onPostDialWait(Call, String)}. At this point, the in-call app 756 * should display to the user an indication of this state and an affordance to continue 757 * the postdial sequence. When the user decides to continue the postdial sequence, the in-call 758 * app should invoke the {@link #postDialContinue(boolean)} method. 759 * 760 * @param proceed Whether or not to continue with the post-dial sequence. 761 */ 762 public void postDialContinue(boolean proceed) { 763 mInCallAdapter.postDialContinue(mTelecomCallId, proceed); 764 } 765 766 /** 767 * Notifies this {@code Call} that an account has been selected and to proceed with placing 768 * an outgoing call. Optionally sets this account as the default account. 769 */ 770 public void phoneAccountSelected(PhoneAccountHandle accountHandle, boolean setDefault) { 771 mInCallAdapter.phoneAccountSelected(mTelecomCallId, accountHandle, setDefault); 772 773 } 774 775 /** 776 * Instructs this {@code Call} to enter a conference. 777 * 778 * @param callToConferenceWith The other call with which to conference. 779 */ 780 public void conference(Call callToConferenceWith) { 781 if (callToConferenceWith != null) { 782 mInCallAdapter.conference(mTelecomCallId, callToConferenceWith.mTelecomCallId); 783 } 784 } 785 786 /** 787 * Instructs this {@code Call} to split from any conference call with which it may be 788 * connected. 789 */ 790 public void splitFromConference() { 791 mInCallAdapter.splitFromConference(mTelecomCallId); 792 } 793 794 /** 795 * Merges the calls within this conference. See {@link Details#CAPABILITY_MERGE_CONFERENCE}. 796 */ 797 public void mergeConference() { 798 mInCallAdapter.mergeConference(mTelecomCallId); 799 } 800 801 /** 802 * Swaps the calls within this conference. See {@link Details#CAPABILITY_SWAP_CONFERENCE}. 803 */ 804 public void swapConference() { 805 mInCallAdapter.swapConference(mTelecomCallId); 806 } 807 808 /** 809 * Obtains the parent of this {@code Call} in a conference, if any. 810 * 811 * @return The parent {@code Call}, or {@code null} if this {@code Call} is not a 812 * child of any conference {@code Call}s. 813 */ 814 public Call getParent() { 815 if (mParentId != null) { 816 return mPhone.internalGetCallByTelecomId(mParentId); 817 } 818 return null; 819 } 820 821 /** 822 * Obtains the children of this conference {@code Call}, if any. 823 * 824 * @return The children of this {@code Call} if this {@code Call} is a conference, or an empty 825 * {@code List} otherwise. 826 */ 827 public List<Call> getChildren() { 828 if (!mChildrenCached) { 829 mChildrenCached = true; 830 mChildren.clear(); 831 832 for(String id : mChildrenIds) { 833 Call call = mPhone.internalGetCallByTelecomId(id); 834 if (call == null) { 835 // At least one child was still not found, so do not save true for "cached" 836 mChildrenCached = false; 837 } else { 838 mChildren.add(call); 839 } 840 } 841 } 842 843 return mUnmodifiableChildren; 844 } 845 846 /** 847 * Returns the list of {@code Call}s with which this {@code Call} is allowed to conference. 848 * 849 * @return The list of conferenceable {@code Call}s. 850 */ 851 public List<Call> getConferenceableCalls() { 852 return mUnmodifiableConferenceableCalls; 853 } 854 855 /** 856 * Obtains the state of this {@code Call}. 857 * 858 * @return A state value, chosen from the {@code STATE_*} constants. 859 */ 860 public int getState() { 861 return mState; 862 } 863 864 /** 865 * Obtains a list of canned, pre-configured message responses to present to the user as 866 * ways of rejecting this {@code Call} using via a text message. 867 * 868 * @see #reject(boolean, String) 869 * 870 * @return A list of canned text message responses. 871 */ 872 public List<String> getCannedTextResponses() { 873 return mCannedTextResponses; 874 } 875 876 /** 877 * Obtains an object that can be used to display video from this {@code Call}. 878 * 879 * @return An {@code Call.VideoCall}. 880 */ 881 public InCallService.VideoCall getVideoCall() { 882 return mVideoCall; 883 } 884 885 /** 886 * Obtains an object containing call details. 887 * 888 * @return A {@link Details} object. Depending on the state of the {@code Call}, the 889 * result may be {@code null}. 890 */ 891 public Details getDetails() { 892 return mDetails; 893 } 894 895 /** 896 * Registers a callback to this {@code Call}. 897 * 898 * @param callback A {@code Callback}. 899 */ 900 public void registerCallback(Callback callback) { 901 registerCallback(callback, new Handler()); 902 } 903 904 /** 905 * Registers a callback to this {@code Call}. 906 * 907 * @param callback A {@code Callback}. 908 * @param handler A handler which command and status changes will be delivered to. 909 */ 910 public void registerCallback(Callback callback, Handler handler) { 911 unregisterCallback(callback); 912 if (callback != null && handler != null) { 913 mCallbackRecords.add(new CallbackRecord<Callback>(callback, handler)); 914 } 915 } 916 917 /** 918 * Unregisters a callback from this {@code Call}. 919 * 920 * @param callback A {@code Callback}. 921 */ 922 public void unregisterCallback(Callback callback) { 923 if (callback != null) { 924 for (CallbackRecord<Callback> record : mCallbackRecords) { 925 if (record.getCallback() == callback) { 926 mCallbackRecords.remove(record); 927 break; 928 } 929 } 930 } 931 } 932 933 /** 934 * Adds a listener to this {@code Call}. 935 * 936 * @param listener A {@code Listener}. 937 * @deprecated Use {@link #registerCallback} instead. 938 * @hide 939 */ 940 @Deprecated 941 @SystemApi 942 public void addListener(Listener listener) { 943 registerCallback(listener); 944 } 945 946 /** 947 * Removes a listener from this {@code Call}. 948 * 949 * @param listener A {@code Listener}. 950 * @deprecated Use {@link #unregisterCallback} instead. 951 * @hide 952 */ 953 @Deprecated 954 @SystemApi 955 public void removeListener(Listener listener) { 956 unregisterCallback(listener); 957 } 958 959 960 /** {@hide} */ 961 Call(Phone phone, String telecomCallId, InCallAdapter inCallAdapter) { 962 mPhone = phone; 963 mTelecomCallId = telecomCallId; 964 mInCallAdapter = inCallAdapter; 965 mState = STATE_NEW; 966 } 967 968 /** {@hide} */ 969 final String internalGetCallId() { 970 return mTelecomCallId; 971 } 972 973 /** {@hide} */ 974 final void internalUpdate(ParcelableCall parcelableCall, Map<String, Call> callIdMap) { 975 // First, we update the internal state as far as possible before firing any updates. 976 Details details = new Details( 977 parcelableCall.getHandle(), 978 parcelableCall.getHandlePresentation(), 979 parcelableCall.getCallerDisplayName(), 980 parcelableCall.getCallerDisplayNamePresentation(), 981 parcelableCall.getAccountHandle(), 982 parcelableCall.getCapabilities(), 983 parcelableCall.getProperties(), 984 parcelableCall.getDisconnectCause(), 985 parcelableCall.getConnectTimeMillis(), 986 parcelableCall.getGatewayInfo(), 987 parcelableCall.getVideoState(), 988 parcelableCall.getStatusHints(), 989 parcelableCall.getExtras()); 990 boolean detailsChanged = !Objects.equals(mDetails, details); 991 if (detailsChanged) { 992 mDetails = details; 993 } 994 995 boolean cannedTextResponsesChanged = false; 996 if (mCannedTextResponses == null && parcelableCall.getCannedSmsResponses() != null 997 && !parcelableCall.getCannedSmsResponses().isEmpty()) { 998 mCannedTextResponses = 999 Collections.unmodifiableList(parcelableCall.getCannedSmsResponses()); 1000 } 1001 1002 boolean videoCallChanged = parcelableCall.isVideoCallProviderChanged() && 1003 !Objects.equals(mVideoCall, parcelableCall.getVideoCall(this)); 1004 if (videoCallChanged) { 1005 mVideoCall = parcelableCall.getVideoCall(this); 1006 } 1007 1008 int state = parcelableCall.getState(); 1009 boolean stateChanged = mState != state; 1010 if (stateChanged) { 1011 mState = state; 1012 } 1013 1014 String parentId = parcelableCall.getParentCallId(); 1015 boolean parentChanged = !Objects.equals(mParentId, parentId); 1016 if (parentChanged) { 1017 mParentId = parentId; 1018 } 1019 1020 List<String> childCallIds = parcelableCall.getChildCallIds(); 1021 boolean childrenChanged = !Objects.equals(childCallIds, mChildrenIds); 1022 if (childrenChanged) { 1023 mChildrenIds.clear(); 1024 mChildrenIds.addAll(parcelableCall.getChildCallIds()); 1025 mChildrenCached = false; 1026 } 1027 1028 List<String> conferenceableCallIds = parcelableCall.getConferenceableCallIds(); 1029 List<Call> conferenceableCalls = new ArrayList<Call>(conferenceableCallIds.size()); 1030 for (String otherId : conferenceableCallIds) { 1031 if (callIdMap.containsKey(otherId)) { 1032 conferenceableCalls.add(callIdMap.get(otherId)); 1033 } 1034 } 1035 1036 if (!Objects.equals(mConferenceableCalls, conferenceableCalls)) { 1037 mConferenceableCalls.clear(); 1038 mConferenceableCalls.addAll(conferenceableCalls); 1039 fireConferenceableCallsChanged(); 1040 } 1041 1042 // Now we fire updates, ensuring that any client who listens to any of these notifications 1043 // gets the most up-to-date state. 1044 1045 if (stateChanged) { 1046 fireStateChanged(mState); 1047 } 1048 if (detailsChanged) { 1049 fireDetailsChanged(mDetails); 1050 } 1051 if (cannedTextResponsesChanged) { 1052 fireCannedTextResponsesLoaded(mCannedTextResponses); 1053 } 1054 if (videoCallChanged) { 1055 fireVideoCallChanged(mVideoCall); 1056 } 1057 if (parentChanged) { 1058 fireParentChanged(getParent()); 1059 } 1060 if (childrenChanged) { 1061 fireChildrenChanged(getChildren()); 1062 } 1063 1064 // If we have transitioned to DISCONNECTED, that means we need to notify clients and 1065 // remove ourselves from the Phone. Note that we do this after completing all state updates 1066 // so a client can cleanly transition all their UI to the state appropriate for a 1067 // DISCONNECTED Call while still relying on the existence of that Call in the Phone's list. 1068 if (mState == STATE_DISCONNECTED) { 1069 fireCallDestroyed(); 1070 mPhone.internalRemoveCall(this); 1071 } 1072 } 1073 1074 /** {@hide} */ 1075 final void internalSetPostDialWait(String remaining) { 1076 mRemainingPostDialSequence = remaining; 1077 firePostDialWait(mRemainingPostDialSequence); 1078 } 1079 1080 /** {@hide} */ 1081 final void internalSetDisconnected() { 1082 if (mState != Call.STATE_DISCONNECTED) { 1083 mState = Call.STATE_DISCONNECTED; 1084 fireStateChanged(mState); 1085 fireCallDestroyed(); 1086 mPhone.internalRemoveCall(this); 1087 } 1088 } 1089 1090 private void fireStateChanged(final int newState) { 1091 for (CallbackRecord<Callback> record : mCallbackRecords) { 1092 final Call call = this; 1093 final Callback callback = record.getCallback(); 1094 record.getHandler().post(new Runnable() { 1095 @Override 1096 public void run() { 1097 callback.onStateChanged(call, newState); 1098 } 1099 }); 1100 } 1101 } 1102 1103 private void fireParentChanged(final Call newParent) { 1104 for (CallbackRecord<Callback> record : mCallbackRecords) { 1105 final Call call = this; 1106 final Callback callback = record.getCallback(); 1107 record.getHandler().post(new Runnable() { 1108 @Override 1109 public void run() { 1110 callback.onParentChanged(call, newParent); 1111 } 1112 }); 1113 } 1114 } 1115 1116 private void fireChildrenChanged(final List<Call> children) { 1117 for (CallbackRecord<Callback> record : mCallbackRecords) { 1118 final Call call = this; 1119 final Callback callback = record.getCallback(); 1120 record.getHandler().post(new Runnable() { 1121 @Override 1122 public void run() { 1123 callback.onChildrenChanged(call, children); 1124 } 1125 }); 1126 } 1127 } 1128 1129 private void fireDetailsChanged(final Details details) { 1130 for (CallbackRecord<Callback> record : mCallbackRecords) { 1131 final Call call = this; 1132 final Callback callback = record.getCallback(); 1133 record.getHandler().post(new Runnable() { 1134 @Override 1135 public void run() { 1136 callback.onDetailsChanged(call, details); 1137 } 1138 }); 1139 } 1140 } 1141 1142 private void fireCannedTextResponsesLoaded(final List<String> cannedTextResponses) { 1143 for (CallbackRecord<Callback> record : mCallbackRecords) { 1144 final Call call = this; 1145 final Callback callback = record.getCallback(); 1146 record.getHandler().post(new Runnable() { 1147 @Override 1148 public void run() { 1149 callback.onCannedTextResponsesLoaded(call, cannedTextResponses); 1150 } 1151 }); 1152 } 1153 } 1154 1155 private void fireVideoCallChanged(final InCallService.VideoCall videoCall) { 1156 for (CallbackRecord<Callback> record : mCallbackRecords) { 1157 final Call call = this; 1158 final Callback callback = record.getCallback(); 1159 record.getHandler().post(new Runnable() { 1160 @Override 1161 public void run() { 1162 callback.onVideoCallChanged(call, videoCall); 1163 } 1164 }); 1165 } 1166 } 1167 1168 private void firePostDialWait(final String remainingPostDialSequence) { 1169 for (CallbackRecord<Callback> record : mCallbackRecords) { 1170 final Call call = this; 1171 final Callback callback = record.getCallback(); 1172 record.getHandler().post(new Runnable() { 1173 @Override 1174 public void run() { 1175 callback.onPostDialWait(call, remainingPostDialSequence); 1176 } 1177 }); 1178 } 1179 } 1180 1181 private void fireCallDestroyed() { 1182 for (CallbackRecord<Callback> record: mCallbackRecords) { 1183 final Call call = this; 1184 final Callback callback = record.getCallback(); 1185 record.getHandler().post(new Runnable() { 1186 @Override 1187 public void run() { 1188 callback.onCallDestroyed(call); 1189 } 1190 }); 1191 } 1192 } 1193 1194 private void fireConferenceableCallsChanged() { 1195 for (CallbackRecord<Callback> record : mCallbackRecords) { 1196 final Call call = this; 1197 final Callback callback = record.getCallback(); 1198 record.getHandler().post(new Runnable() { 1199 @Override 1200 public void run() { 1201 callback.onConferenceableCallsChanged(call, mUnmodifiableConferenceableCalls); 1202 } 1203 }); 1204 } 1205 } 1206} 1207