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