Call.java revision cb43ebb3604d45da8677b8d19c935f0ace08ea53
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 private final int mCallSubstate; 237 238 /** 239 * Whether the supplied capabilities supports the specified capability. 240 * 241 * @param capabilities A bit field of capabilities. 242 * @param capability The capability to check capabilities for. 243 * @return Whether the specified capability is supported. 244 */ 245 public static boolean can(int capabilities, int capability) { 246 return (capabilities & capability) != 0; 247 } 248 249 /** 250 * Whether the capabilities of this {@code Details} supports the specified capability. 251 * 252 * @param capability The capability to check capabilities for. 253 * @return Whether the specified capability is supported. 254 */ 255 public boolean can(int capability) { 256 return can(mCallCapabilities, capability); 257 } 258 259 /** 260 * Render a set of capability bits ({@code CAPABILITY_*}) as a human readable string. 261 * 262 * @param capabilities A capability bit field. 263 * @return A human readable string representation. 264 */ 265 public static String capabilitiesToString(int capabilities) { 266 StringBuilder builder = new StringBuilder(); 267 builder.append("[Capabilities:"); 268 if (can(capabilities, CAPABILITY_HOLD)) { 269 builder.append(" CAPABILITY_HOLD"); 270 } 271 if (can(capabilities, CAPABILITY_SUPPORT_HOLD)) { 272 builder.append(" CAPABILITY_SUPPORT_HOLD"); 273 } 274 if (can(capabilities, CAPABILITY_MERGE_CONFERENCE)) { 275 builder.append(" CAPABILITY_MERGE_CONFERENCE"); 276 } 277 if (can(capabilities, CAPABILITY_SWAP_CONFERENCE)) { 278 builder.append(" CAPABILITY_SWAP_CONFERENCE"); 279 } 280 if (can(capabilities, CAPABILITY_RESPOND_VIA_TEXT)) { 281 builder.append(" CAPABILITY_RESPOND_VIA_TEXT"); 282 } 283 if (can(capabilities, CAPABILITY_MUTE)) { 284 builder.append(" CAPABILITY_MUTE"); 285 } 286 if (can(capabilities, CAPABILITY_MANAGE_CONFERENCE)) { 287 builder.append(" CAPABILITY_MANAGE_CONFERENCE"); 288 } 289 if (can(capabilities, CAPABILITY_SUPPORTS_VT_LOCAL_RX)) { 290 builder.append(" CAPABILITY_SUPPORTS_VT_LOCAL_RX"); 291 } 292 if (can(capabilities, CAPABILITY_SUPPORTS_VT_LOCAL_TX)) { 293 builder.append(" CAPABILITY_SUPPORTS_VT_LOCAL_TX"); 294 } 295 if (can(capabilities, CAPABILITY_SUPPORTS_VT_LOCAL_BIDIRECTIONAL)) { 296 builder.append(" CAPABILITY_SUPPORTS_VT_LOCAL_BIDIRECTIONAL"); 297 } 298 if (can(capabilities, CAPABILITY_SUPPORTS_VT_REMOTE_RX)) { 299 builder.append(" CAPABILITY_SUPPORTS_VT_REMOTE_RX"); 300 } 301 if (can(capabilities, CAPABILITY_SUPPORTS_VT_REMOTE_TX)) { 302 builder.append(" CAPABILITY_SUPPORTS_VT_REMOTE_TX"); 303 } 304 if (can(capabilities, CAPABILITY_SUPPORTS_VT_REMOTE_BIDIRECTIONAL)) { 305 builder.append(" CAPABILITY_SUPPORTS_VT_REMOTE_BIDIRECTIONAL"); 306 } 307 if (can(capabilities, CAPABILITY_HIGH_DEF_AUDIO)) { 308 builder.append(" CAPABILITY_HIGH_DEF_AUDIO"); 309 } 310 if (can(capabilities, CAPABILITY_WIFI)) { 311 builder.append(" CAPABILITY_WIFI"); 312 } 313 if (can(capabilities, CAPABILITY_GENERIC_CONFERENCE)) { 314 builder.append(" CAPABILITY_GENERIC_CONFERENCE"); 315 } 316 if (can(capabilities, CAPABILITY_SHOW_CALLBACK_NUMBER)) { 317 builder.append(" CAPABILITY_SHOW_CALLBACK_NUMBER"); 318 } 319 if (can(capabilities, CAPABILITY_SPEED_UP_MT_AUDIO)) { 320 builder.append(" CAPABILITY_SPEED_UP_MT_AUDIO"); 321 } 322 if (can(capabilities, CAPABILITY_CAN_UPGRADE_TO_VIDEO)) { 323 builder.append(" CAPABILITY_CAN_UPGRADE_TO_VIDEO"); 324 } 325 if (can(capabilities, CAPABILITY_CAN_PAUSE_VIDEO)) { 326 builder.append(" CAPABILITY_CAN_PAUSE_VIDEO"); 327 } 328 builder.append("]"); 329 return builder.toString(); 330 } 331 332 /** 333 * @return The handle (e.g., phone number) to which the {@code Call} is currently 334 * connected. 335 */ 336 public Uri getHandle() { 337 return mHandle; 338 } 339 340 /** 341 * @return The presentation requirements for the handle. See 342 * {@link TelecomManager} for valid values. 343 */ 344 public int getHandlePresentation() { 345 return mHandlePresentation; 346 } 347 348 /** 349 * @return The display name for the caller. 350 */ 351 public String getCallerDisplayName() { 352 return mCallerDisplayName; 353 } 354 355 /** 356 * @return The presentation requirements for the caller display name. See 357 * {@link TelecomManager} for valid values. 358 */ 359 public int getCallerDisplayNamePresentation() { 360 return mCallerDisplayNamePresentation; 361 } 362 363 /** 364 * @return The {@code PhoneAccountHandle} whereby the {@code Call} is currently being 365 * routed. 366 */ 367 public PhoneAccountHandle getAccountHandle() { 368 return mAccountHandle; 369 } 370 371 /** 372 * @return A bitmask of the capabilities of the {@code Call}, as defined by the various 373 * {@code CAPABILITY_*} constants in this class. 374 */ 375 public int getCallCapabilities() { 376 return mCallCapabilities; 377 } 378 379 /** 380 * @return A bitmask of the properties of the {@code Call}, as defined in 381 * {@link CallProperties}. 382 */ 383 public int getCallProperties() { 384 return mCallProperties; 385 } 386 387 /** 388 * @return For a {@link #STATE_DISCONNECTED} {@code Call}, the disconnect cause expressed 389 * by {@link android.telecom.DisconnectCause}. 390 */ 391 public DisconnectCause getDisconnectCause() { 392 return mDisconnectCause; 393 } 394 395 /** 396 * @return The time the {@code Call} has been connected. This information is updated 397 * periodically, but user interfaces should not rely on this to display any "call time 398 * clock". 399 */ 400 public final long getConnectTimeMillis() { 401 return mConnectTimeMillis; 402 } 403 404 /** 405 * @return Information about any calling gateway the {@code Call} may be using. 406 */ 407 public GatewayInfo getGatewayInfo() { 408 return mGatewayInfo; 409 } 410 411 /** 412 * @return The video state of the {@code Call}. 413 */ 414 public int getVideoState() { 415 return mVideoState; 416 } 417 418 /** 419 * @return The current {@link android.telecom.StatusHints}, or {@code null} if none 420 * have been set. 421 */ 422 public StatusHints getStatusHints() { 423 return mStatusHints; 424 } 425 426 /** 427 * @return A bundle extras to pass with the call 428 */ 429 public Bundle getExtras() { 430 return mExtras; 431 } 432 433 /** 434 * @return The substate of the {@code Call}. 435 * @hide 436 */ 437 public int getCallSubstate() { 438 return mCallSubstate; 439 } 440 441 @Override 442 public boolean equals(Object o) { 443 if (o instanceof Details) { 444 Details d = (Details) o; 445 return 446 Objects.equals(mHandle, d.mHandle) && 447 Objects.equals(mHandlePresentation, d.mHandlePresentation) && 448 Objects.equals(mCallerDisplayName, d.mCallerDisplayName) && 449 Objects.equals(mCallerDisplayNamePresentation, 450 d.mCallerDisplayNamePresentation) && 451 Objects.equals(mAccountHandle, d.mAccountHandle) && 452 Objects.equals(mCallCapabilities, d.mCallCapabilities) && 453 Objects.equals(mCallProperties, d.mCallProperties) && 454 Objects.equals(mDisconnectCause, d.mDisconnectCause) && 455 Objects.equals(mConnectTimeMillis, d.mConnectTimeMillis) && 456 Objects.equals(mGatewayInfo, d.mGatewayInfo) && 457 Objects.equals(mVideoState, d.mVideoState) && 458 Objects.equals(mStatusHints, d.mStatusHints) && 459 Objects.equals(mExtras, d.mExtras) && 460 Objects.equals(mCallSubstate, d.mCallSubstate); 461 } 462 return false; 463 } 464 465 @Override 466 public int hashCode() { 467 return 468 Objects.hashCode(mHandle) + 469 Objects.hashCode(mHandlePresentation) + 470 Objects.hashCode(mCallerDisplayName) + 471 Objects.hashCode(mCallerDisplayNamePresentation) + 472 Objects.hashCode(mAccountHandle) + 473 Objects.hashCode(mCallCapabilities) + 474 Objects.hashCode(mCallProperties) + 475 Objects.hashCode(mDisconnectCause) + 476 Objects.hashCode(mConnectTimeMillis) + 477 Objects.hashCode(mGatewayInfo) + 478 Objects.hashCode(mVideoState) + 479 Objects.hashCode(mStatusHints) + 480 Objects.hashCode(mExtras) + 481 Objects.hashCode(mCallSubstate); 482 } 483 484 /** {@hide} */ 485 public Details( 486 Uri handle, 487 int handlePresentation, 488 String callerDisplayName, 489 int callerDisplayNamePresentation, 490 PhoneAccountHandle accountHandle, 491 int capabilities, 492 int properties, 493 DisconnectCause disconnectCause, 494 long connectTimeMillis, 495 GatewayInfo gatewayInfo, 496 int videoState, 497 StatusHints statusHints, 498 Bundle extras, 499 int callSubstate) { 500 mHandle = handle; 501 mHandlePresentation = handlePresentation; 502 mCallerDisplayName = callerDisplayName; 503 mCallerDisplayNamePresentation = callerDisplayNamePresentation; 504 mAccountHandle = accountHandle; 505 mCallCapabilities = capabilities; 506 mCallProperties = properties; 507 mDisconnectCause = disconnectCause; 508 mConnectTimeMillis = connectTimeMillis; 509 mGatewayInfo = gatewayInfo; 510 mVideoState = videoState; 511 mStatusHints = statusHints; 512 mExtras = extras; 513 mCallSubstate = callSubstate; 514 } 515 } 516 517 public static abstract class Listener { 518 /** 519 * Invoked when the state of this {@code Call} has changed. See {@link #getState()}. 520 * 521 * @param call The {@code Call} invoking this method. 522 * @param state The new state of the {@code Call}. 523 */ 524 public void onStateChanged(Call call, int state) {} 525 526 /** 527 * Invoked when the parent of this {@code Call} has changed. See {@link #getParent()}. 528 * 529 * @param call The {@code Call} invoking this method. 530 * @param parent The new parent of the {@code Call}. 531 */ 532 public void onParentChanged(Call call, Call parent) {} 533 534 /** 535 * Invoked when the children of this {@code Call} have changed. See {@link #getChildren()}. 536 * 537 * @param call The {@code Call} invoking this method. 538 * @param children The new children of the {@code Call}. 539 */ 540 public void onChildrenChanged(Call call, List<Call> children) {} 541 542 /** 543 * Invoked when the details of this {@code Call} have changed. See {@link #getDetails()}. 544 * 545 * @param call The {@code Call} invoking this method. 546 * @param details A {@code Details} object describing the {@code Call}. 547 */ 548 public void onDetailsChanged(Call call, Details details) {} 549 550 /** 551 * Invoked when the text messages that can be used as responses to the incoming 552 * {@code Call} are loaded from the relevant database. 553 * See {@link #getCannedTextResponses()}. 554 * 555 * @param call The {@code Call} invoking this method. 556 * @param cannedTextResponses The text messages useable as responses. 557 */ 558 public void onCannedTextResponsesLoaded(Call call, List<String> cannedTextResponses) {} 559 560 /** 561 * Invoked when the post-dial sequence in the outgoing {@code Call} has reached a pause 562 * character. This causes the post-dial signals to stop pending user confirmation. An 563 * implementation should present this choice to the user and invoke 564 * {@link #postDialContinue(boolean)} when the user makes the choice. 565 * 566 * @param call The {@code Call} invoking this method. 567 * @param remainingPostDialSequence The post-dial characters that remain to be sent. 568 */ 569 public void onPostDialWait(Call call, String remainingPostDialSequence) {} 570 571 /** 572 * Invoked when the {@code Call.VideoCall} of the {@code Call} has changed. 573 * 574 * @param call The {@code Call} invoking this method. 575 * @param videoCall The {@code Call.VideoCall} associated with the {@code Call}. 576 */ 577 public void onVideoCallChanged(Call call, InCallService.VideoCall videoCall) {} 578 579 /** 580 * Invoked when the {@code Call} is destroyed. Clients should refrain from cleaning 581 * up their UI for the {@code Call} in response to state transitions. Specifically, 582 * clients should not assume that a {@link #onStateChanged(Call, int)} with a state of 583 * {@link #STATE_DISCONNECTED} is the final notification the {@code Call} will send. Rather, 584 * clients should wait for this method to be invoked. 585 * 586 * @param call The {@code Call} being destroyed. 587 */ 588 public void onCallDestroyed(Call call) {} 589 590 /** 591 * Invoked upon changes to the set of {@code Call}s with which this {@code Call} can be 592 * conferenced. 593 * 594 * @param call The {@code Call} being updated. 595 * @param conferenceableCalls The {@code Call}s with which this {@code Call} can be 596 * conferenced. 597 */ 598 public void onConferenceableCallsChanged(Call call, List<Call> conferenceableCalls) {} 599 } 600 601 private final Phone mPhone; 602 private final String mTelecomCallId; 603 private final InCallAdapter mInCallAdapter; 604 private final List<String> mChildrenIds = new ArrayList<>(); 605 private final List<Call> mChildren = new ArrayList<>(); 606 private final List<Call> mUnmodifiableChildren = Collections.unmodifiableList(mChildren); 607 private final List<Listener> mListeners = new CopyOnWriteArrayList<>(); 608 private final List<Call> mConferenceableCalls = new ArrayList<>(); 609 private final List<Call> mUnmodifiableConferenceableCalls = 610 Collections.unmodifiableList(mConferenceableCalls); 611 612 private boolean mChildrenCached; 613 private String mParentId = null; 614 private int mState; 615 private List<String> mCannedTextResponses = null; 616 private String mRemainingPostDialSequence; 617 private InCallService.VideoCall mVideoCall; 618 private Details mDetails; 619 620 /** 621 * Obtains the post-dial sequence remaining to be emitted by this {@code Call}, if any. 622 * 623 * @return The remaining post-dial sequence, or {@code null} if there is no post-dial sequence 624 * remaining or this {@code Call} is not in a post-dial state. 625 */ 626 public String getRemainingPostDialSequence() { 627 return mRemainingPostDialSequence; 628 } 629 630 /** 631 * Instructs this {@link #STATE_RINGING} {@code Call} to answer. 632 * @param videoState The video state in which to answer the call. 633 */ 634 public void answer(int videoState) { 635 mInCallAdapter.answerCall(mTelecomCallId, videoState); 636 } 637 638 /** 639 * Instructs this {@link #STATE_RINGING} {@code Call} to reject. 640 * 641 * @param rejectWithMessage Whether to reject with a text message. 642 * @param textMessage An optional text message with which to respond. 643 */ 644 public void reject(boolean rejectWithMessage, String textMessage) { 645 mInCallAdapter.rejectCall(mTelecomCallId, rejectWithMessage, textMessage); 646 } 647 648 /** 649 * Instructs this {@code Call} to disconnect. 650 */ 651 public void disconnect() { 652 mInCallAdapter.disconnectCall(mTelecomCallId); 653 } 654 655 /** 656 * Instructs this {@code Call} to go on hold. 657 */ 658 public void hold() { 659 mInCallAdapter.holdCall(mTelecomCallId); 660 } 661 662 /** 663 * Instructs this {@link #STATE_HOLDING} call to release from hold. 664 */ 665 public void unhold() { 666 mInCallAdapter.unholdCall(mTelecomCallId); 667 } 668 669 /** 670 * Instructs this {@code Call} to play a dual-tone multi-frequency signaling (DTMF) tone. 671 * 672 * Any other currently playing DTMF tone in the specified call is immediately stopped. 673 * 674 * @param digit A character representing the DTMF digit for which to play the tone. This 675 * value must be one of {@code '0'} through {@code '9'}, {@code '*'} or {@code '#'}. 676 */ 677 public void playDtmfTone(char digit) { 678 mInCallAdapter.playDtmfTone(mTelecomCallId, digit); 679 } 680 681 /** 682 * Instructs this {@code Call} to stop any dual-tone multi-frequency signaling (DTMF) tone 683 * currently playing. 684 * 685 * DTMF tones are played by calling {@link #playDtmfTone(char)}. If no DTMF tone is 686 * currently playing, this method will do nothing. 687 */ 688 public void stopDtmfTone() { 689 mInCallAdapter.stopDtmfTone(mTelecomCallId); 690 } 691 692 /** 693 * Instructs this {@code Call} to continue playing a post-dial DTMF string. 694 * 695 * A post-dial DTMF string is a string of digits entered after a phone number, when dialed, 696 * that are immediately sent as DTMF tones to the recipient as soon as the connection is made. 697 * 698 * If the DTMF string contains a {@link TelecomManager#DTMF_CHARACTER_PAUSE} symbol, this 699 * {@code Call} will temporarily pause playing the tones for a pre-defined period of time. 700 * 701 * If the DTMF string contains a {@link TelecomManager#DTMF_CHARACTER_WAIT} symbol, this 702 * {@code Call} will pause playing the tones and notify listeners via 703 * {@link Listener#onPostDialWait(Call, String)}. At this point, the in-call app 704 * should display to the user an indication of this state and an affordance to continue 705 * the postdial sequence. When the user decides to continue the postdial sequence, the in-call 706 * app should invoke the {@link #postDialContinue(boolean)} method. 707 * 708 * @param proceed Whether or not to continue with the post-dial sequence. 709 */ 710 public void postDialContinue(boolean proceed) { 711 mInCallAdapter.postDialContinue(mTelecomCallId, proceed); 712 } 713 714 /** 715 * Notifies this {@code Call} that an account has been selected and to proceed with placing 716 * an outgoing call. Optionally sets this account as the default account. 717 */ 718 public void phoneAccountSelected(PhoneAccountHandle accountHandle, boolean setDefault) { 719 mInCallAdapter.phoneAccountSelected(mTelecomCallId, accountHandle, setDefault); 720 721 } 722 723 /** 724 * Instructs this {@code Call} to enter a conference. 725 * 726 * @param callToConferenceWith The other call with which to conference. 727 */ 728 public void conference(Call callToConferenceWith) { 729 if (callToConferenceWith != null) { 730 mInCallAdapter.conference(mTelecomCallId, callToConferenceWith.mTelecomCallId); 731 } 732 } 733 734 /** 735 * Instructs this {@code Call} to split from any conference call with which it may be 736 * connected. 737 */ 738 public void splitFromConference() { 739 mInCallAdapter.splitFromConference(mTelecomCallId); 740 } 741 742 /** 743 * Merges the calls within this conference. See {@link Details#CAPABILITY_MERGE_CONFERENCE}. 744 */ 745 public void mergeConference() { 746 mInCallAdapter.mergeConference(mTelecomCallId); 747 } 748 749 /** 750 * Swaps the calls within this conference. See {@link Details#CAPABILITY_SWAP_CONFERENCE}. 751 */ 752 public void swapConference() { 753 mInCallAdapter.swapConference(mTelecomCallId); 754 } 755 756 /** 757 * Obtains the parent of this {@code Call} in a conference, if any. 758 * 759 * @return The parent {@code Call}, or {@code null} if this {@code Call} is not a 760 * child of any conference {@code Call}s. 761 */ 762 public Call getParent() { 763 if (mParentId != null) { 764 return mPhone.internalGetCallByTelecomId(mParentId); 765 } 766 return null; 767 } 768 769 /** 770 * Obtains the children of this conference {@code Call}, if any. 771 * 772 * @return The children of this {@code Call} if this {@code Call} is a conference, or an empty 773 * {@code List} otherwise. 774 */ 775 public List<Call> getChildren() { 776 if (!mChildrenCached) { 777 mChildrenCached = true; 778 mChildren.clear(); 779 780 for(String id : mChildrenIds) { 781 Call call = mPhone.internalGetCallByTelecomId(id); 782 if (call == null) { 783 // At least one child was still not found, so do not save true for "cached" 784 mChildrenCached = false; 785 } else { 786 mChildren.add(call); 787 } 788 } 789 } 790 791 return mUnmodifiableChildren; 792 } 793 794 /** 795 * Returns the list of {@code Call}s with which this {@code Call} is allowed to conference. 796 * 797 * @return The list of conferenceable {@code Call}s. 798 */ 799 public List<Call> getConferenceableCalls() { 800 return mUnmodifiableConferenceableCalls; 801 } 802 803 /** 804 * Obtains the state of this {@code Call}. 805 * 806 * @return A state value, chosen from the {@code STATE_*} constants. 807 */ 808 public int getState() { 809 return mState; 810 } 811 812 /** 813 * Obtains a list of canned, pre-configured message responses to present to the user as 814 * ways of rejecting this {@code Call} using via a text message. 815 * 816 * @see #reject(boolean, String) 817 * 818 * @return A list of canned text message responses. 819 */ 820 public List<String> getCannedTextResponses() { 821 return mCannedTextResponses; 822 } 823 824 /** 825 * Obtains an object that can be used to display video from this {@code Call}. 826 * 827 * @return An {@code Call.VideoCall}. 828 */ 829 public InCallService.VideoCall getVideoCall() { 830 return mVideoCall; 831 } 832 833 /** 834 * Obtains an object containing call details. 835 * 836 * @return A {@link Details} object. Depending on the state of the {@code Call}, the 837 * result may be {@code null}. 838 */ 839 public Details getDetails() { 840 return mDetails; 841 } 842 843 /** 844 * Adds a listener to this {@code Call}. 845 * 846 * @param listener A {@code Listener}. 847 */ 848 public void addListener(Listener listener) { 849 mListeners.add(listener); 850 } 851 852 /** 853 * Removes a listener from this {@code Call}. 854 * 855 * @param listener A {@code Listener}. 856 */ 857 public void removeListener(Listener listener) { 858 if (listener != null) { 859 mListeners.remove(listener); 860 } 861 } 862 863 /** {@hide} */ 864 Call(Phone phone, String telecomCallId, InCallAdapter inCallAdapter) { 865 mPhone = phone; 866 mTelecomCallId = telecomCallId; 867 mInCallAdapter = inCallAdapter; 868 mState = STATE_NEW; 869 } 870 871 /** {@hide} */ 872 final String internalGetCallId() { 873 return mTelecomCallId; 874 } 875 876 /** {@hide} */ 877 final void internalUpdate(ParcelableCall parcelableCall, Map<String, Call> callIdMap) { 878 // First, we update the internal state as far as possible before firing any updates. 879 Details details = new Details( 880 parcelableCall.getHandle(), 881 parcelableCall.getHandlePresentation(), 882 parcelableCall.getCallerDisplayName(), 883 parcelableCall.getCallerDisplayNamePresentation(), 884 parcelableCall.getAccountHandle(), 885 parcelableCall.getCapabilities(), 886 parcelableCall.getProperties(), 887 parcelableCall.getDisconnectCause(), 888 parcelableCall.getConnectTimeMillis(), 889 parcelableCall.getGatewayInfo(), 890 parcelableCall.getVideoState(), 891 parcelableCall.getStatusHints(), 892 parcelableCall.getExtras(), 893 parcelableCall.getCallSubstate()); 894 boolean detailsChanged = !Objects.equals(mDetails, details); 895 if (detailsChanged) { 896 mDetails = details; 897 } 898 899 boolean cannedTextResponsesChanged = false; 900 if (mCannedTextResponses == null && parcelableCall.getCannedSmsResponses() != null 901 && !parcelableCall.getCannedSmsResponses().isEmpty()) { 902 mCannedTextResponses = 903 Collections.unmodifiableList(parcelableCall.getCannedSmsResponses()); 904 } 905 906 boolean videoCallChanged = !Objects.equals(mVideoCall, parcelableCall.getVideoCall()); 907 if (videoCallChanged) { 908 mVideoCall = parcelableCall.getVideoCall(); 909 } 910 911 int state = stateFromParcelableCallState(parcelableCall.getState()); 912 boolean stateChanged = mState != state; 913 if (stateChanged) { 914 mState = state; 915 } 916 917 String parentId = parcelableCall.getParentCallId(); 918 boolean parentChanged = !Objects.equals(mParentId, parentId); 919 if (parentChanged) { 920 mParentId = parentId; 921 } 922 923 List<String> childCallIds = parcelableCall.getChildCallIds(); 924 boolean childrenChanged = !Objects.equals(childCallIds, mChildrenIds); 925 if (childrenChanged) { 926 mChildrenIds.clear(); 927 mChildrenIds.addAll(parcelableCall.getChildCallIds()); 928 mChildrenCached = false; 929 } 930 931 List<String> conferenceableCallIds = parcelableCall.getConferenceableCallIds(); 932 List<Call> conferenceableCalls = new ArrayList<Call>(conferenceableCallIds.size()); 933 for (String otherId : conferenceableCallIds) { 934 if (callIdMap.containsKey(otherId)) { 935 conferenceableCalls.add(callIdMap.get(otherId)); 936 } 937 } 938 939 if (!Objects.equals(mConferenceableCalls, conferenceableCalls)) { 940 mConferenceableCalls.clear(); 941 mConferenceableCalls.addAll(conferenceableCalls); 942 fireConferenceableCallsChanged(); 943 } 944 945 // Now we fire updates, ensuring that any client who listens to any of these notifications 946 // gets the most up-to-date state. 947 948 if (stateChanged) { 949 fireStateChanged(mState); 950 } 951 if (detailsChanged) { 952 fireDetailsChanged(mDetails); 953 } 954 if (cannedTextResponsesChanged) { 955 fireCannedTextResponsesLoaded(mCannedTextResponses); 956 } 957 if (videoCallChanged) { 958 fireVideoCallChanged(mVideoCall); 959 } 960 if (parentChanged) { 961 fireParentChanged(getParent()); 962 } 963 if (childrenChanged) { 964 fireChildrenChanged(getChildren()); 965 } 966 967 // If we have transitioned to DISCONNECTED, that means we need to notify clients and 968 // remove ourselves from the Phone. Note that we do this after completing all state updates 969 // so a client can cleanly transition all their UI to the state appropriate for a 970 // DISCONNECTED Call while still relying on the existence of that Call in the Phone's list. 971 if (mState == STATE_DISCONNECTED) { 972 fireCallDestroyed(); 973 mPhone.internalRemoveCall(this); 974 } 975 } 976 977 /** {@hide} */ 978 final void internalSetPostDialWait(String remaining) { 979 mRemainingPostDialSequence = remaining; 980 firePostDialWait(mRemainingPostDialSequence); 981 } 982 983 /** {@hide} */ 984 final void internalSetDisconnected() { 985 if (mState != Call.STATE_DISCONNECTED) { 986 mState = Call.STATE_DISCONNECTED; 987 fireStateChanged(mState); 988 fireCallDestroyed(); 989 mPhone.internalRemoveCall(this); 990 } 991 } 992 993 private void fireStateChanged(int newState) { 994 for (Listener listener : mListeners) { 995 listener.onStateChanged(this, newState); 996 } 997 } 998 999 private void fireParentChanged(Call newParent) { 1000 for (Listener listener : mListeners) { 1001 listener.onParentChanged(this, newParent); 1002 } 1003 } 1004 1005 private void fireChildrenChanged(List<Call> children) { 1006 for (Listener listener : mListeners) { 1007 listener.onChildrenChanged(this, children); 1008 } 1009 } 1010 1011 private void fireDetailsChanged(Details details) { 1012 for (Listener listener : mListeners) { 1013 listener.onDetailsChanged(this, details); 1014 } 1015 } 1016 1017 private void fireCannedTextResponsesLoaded(List<String> cannedTextResponses) { 1018 for (Listener listener : mListeners) { 1019 listener.onCannedTextResponsesLoaded(this, cannedTextResponses); 1020 } 1021 } 1022 1023 private void fireVideoCallChanged(InCallService.VideoCall videoCall) { 1024 for (Listener listener : mListeners) { 1025 listener.onVideoCallChanged(this, videoCall); 1026 } 1027 } 1028 1029 private void firePostDialWait(String remainingPostDialSequence) { 1030 for (Listener listener : mListeners) { 1031 listener.onPostDialWait(this, remainingPostDialSequence); 1032 } 1033 } 1034 1035 private void fireCallDestroyed() { 1036 for (Listener listener : mListeners) { 1037 listener.onCallDestroyed(this); 1038 } 1039 } 1040 1041 private void fireConferenceableCallsChanged() { 1042 for (Listener listener : mListeners) { 1043 listener.onConferenceableCallsChanged(this, mUnmodifiableConferenceableCalls); 1044 } 1045 } 1046 1047 private int stateFromParcelableCallState(int parcelableCallState) { 1048 switch (parcelableCallState) { 1049 case CallState.NEW: 1050 return STATE_NEW; 1051 case CallState.CONNECTING: 1052 return STATE_CONNECTING; 1053 case CallState.PRE_DIAL_WAIT: 1054 return STATE_PRE_DIAL_WAIT; 1055 case CallState.DIALING: 1056 return STATE_DIALING; 1057 case CallState.RINGING: 1058 return STATE_RINGING; 1059 case CallState.ACTIVE: 1060 return STATE_ACTIVE; 1061 case CallState.ON_HOLD: 1062 return STATE_HOLDING; 1063 case CallState.DISCONNECTED: 1064 return STATE_DISCONNECTED; 1065 case CallState.ABORTED: 1066 return STATE_DISCONNECTED; 1067 case CallState.DISCONNECTING: 1068 return STATE_DISCONNECTING; 1069 default: 1070 Log.wtf(this, "Unrecognized CallState %s", parcelableCallState); 1071 return STATE_NEW; 1072 } 1073 } 1074} 1075