Call.java revision 7f3d41fd124dd7c4a8b72c1d48df08a8ee7209ec
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; 22 23import java.lang.String; 24import java.util.ArrayList; 25import java.util.Collections; 26import java.util.List; 27import java.util.Map; 28import java.util.Objects; 29import java.util.concurrent.CopyOnWriteArrayList; 30 31/** 32 * Represents an ongoing phone call that the in-call app should present to the user. 33 * 34 * {@hide} 35 */ 36@SystemApi 37public final class Call { 38 /** 39 * The state of a {@code Call} when newly created. 40 */ 41 public static final int STATE_NEW = 0; 42 43 /** 44 * The state of an outgoing {@code Call} when dialing the remote number, but not yet connected. 45 */ 46 public static final int STATE_DIALING = 1; 47 48 /** 49 * The state of an incoming {@code Call} when ringing locally, but not yet connected. 50 */ 51 public static final int STATE_RINGING = 2; 52 53 /** 54 * The state of a {@code Call} when in a holding state. 55 */ 56 public static final int STATE_HOLDING = 3; 57 58 /** 59 * The state of a {@code Call} when actively supporting conversation. 60 */ 61 public static final int STATE_ACTIVE = 4; 62 63 /** 64 * The state of a {@code Call} when no further voice or other communication is being 65 * transmitted, the remote side has been or will inevitably be informed that the {@code Call} 66 * is no longer active, and the local data transport has or inevitably will release resources 67 * associated with this {@code Call}. 68 */ 69 public static final int STATE_DISCONNECTED = 7; 70 71 /** 72 * The state of an outgoing {@code Call}, but waiting for user input before proceeding. 73 */ 74 public static final int STATE_PRE_DIAL_WAIT = 8; 75 76 /** 77 * The initial state of an outgoing {@code Call}. 78 * Common transitions are to {@link #STATE_DIALING} state for a successful call or 79 * {@link #STATE_DISCONNECTED} if it failed. 80 */ 81 public static final int STATE_CONNECTING = 9; 82 83 public static class Details { 84 private final Uri mHandle; 85 private final int mHandlePresentation; 86 private final String mCallerDisplayName; 87 private final int mCallerDisplayNamePresentation; 88 private final PhoneAccountHandle mAccountHandle; 89 private final int mCallCapabilities; 90 private final int mCallProperties; 91 private final DisconnectCause mDisconnectCause; 92 private final long mConnectTimeMillis; 93 private final GatewayInfo mGatewayInfo; 94 private final int mVideoState; 95 private final StatusHints mStatusHints; 96 private final Bundle mExtras; 97 98 /** 99 * @return The handle (e.g., phone number) to which the {@code Call} is currently 100 * connected. 101 */ 102 public Uri getHandle() { 103 return mHandle; 104 } 105 106 /** 107 * @return The presentation requirements for the handle. See 108 * {@link TelecomManager} for valid values. 109 */ 110 public int getHandlePresentation() { 111 return mHandlePresentation; 112 } 113 114 /** 115 * @return The display name for the caller. 116 */ 117 public String getCallerDisplayName() { 118 return mCallerDisplayName; 119 } 120 121 /** 122 * @return The presentation requirements for the caller display name. See 123 * {@link TelecomManager} for valid values. 124 */ 125 public int getCallerDisplayNamePresentation() { 126 return mCallerDisplayNamePresentation; 127 } 128 129 /** 130 * @return The {@code PhoneAccountHandle} whereby the {@code Call} is currently being 131 * routed. 132 */ 133 public PhoneAccountHandle getAccountHandle() { 134 return mAccountHandle; 135 } 136 137 /** 138 * @return A bitmask of the capabilities of the {@code Call}, as defined in 139 * {@link PhoneCapabilities}. 140 */ 141 public int getCallCapabilities() { 142 return mCallCapabilities; 143 } 144 145 /** 146 * @return A bitmask of the properties of the {@code Call}, as defined in 147 * {@link CallProperties}. 148 */ 149 public int getCallProperties() { 150 return mCallProperties; 151 } 152 153 /** 154 * @return For a {@link #STATE_DISCONNECTED} {@code Call}, the disconnect cause expressed 155 * by {@link android.telecomm.DisconnectCause}. 156 */ 157 public DisconnectCause getDisconnectCause() { 158 return mDisconnectCause; 159 } 160 161 /** 162 * @return The time the {@code Call} has been connected. This information is updated 163 * periodically, but user interfaces should not rely on this to display any "call time 164 * clock". 165 */ 166 public long getConnectTimeMillis() { 167 return mConnectTimeMillis; 168 } 169 170 /** 171 * @return Information about any calling gateway the {@code Call} may be using. 172 */ 173 public GatewayInfo getGatewayInfo() { 174 return mGatewayInfo; 175 } 176 177 /** 178 * @return The video state of the {@code Call}. 179 */ 180 public int getVideoState() { 181 return mVideoState; 182 } 183 184 /** 185 * @return The current {@link android.telecom.StatusHints}, or {@code null} if none 186 * have been set. 187 */ 188 public StatusHints getStatusHints() { 189 return mStatusHints; 190 } 191 192 /** 193 * @return A bundle extras to pass with the call 194 */ 195 public Bundle getExtras() { 196 return mExtras; 197 } 198 199 @Override 200 public boolean equals(Object o) { 201 if (o instanceof Details) { 202 Details d = (Details) o; 203 return 204 Objects.equals(mHandle, d.mHandle) && 205 Objects.equals(mHandlePresentation, d.mHandlePresentation) && 206 Objects.equals(mCallerDisplayName, d.mCallerDisplayName) && 207 Objects.equals(mCallerDisplayNamePresentation, 208 d.mCallerDisplayNamePresentation) && 209 Objects.equals(mAccountHandle, d.mAccountHandle) && 210 Objects.equals(mCallCapabilities, d.mCallCapabilities) && 211 Objects.equals(mCallProperties, d.mCallProperties) && 212 Objects.equals(mDisconnectCause, d.mDisconnectCause) && 213 Objects.equals(mConnectTimeMillis, d.mConnectTimeMillis) && 214 Objects.equals(mGatewayInfo, d.mGatewayInfo) && 215 Objects.equals(mVideoState, d.mVideoState) && 216 Objects.equals(mStatusHints, d.mStatusHints) && 217 Objects.equals(mExtras, d.mExtras); 218 } 219 return false; 220 } 221 222 @Override 223 public int hashCode() { 224 return 225 Objects.hashCode(mHandle) + 226 Objects.hashCode(mHandlePresentation) + 227 Objects.hashCode(mCallerDisplayName) + 228 Objects.hashCode(mCallerDisplayNamePresentation) + 229 Objects.hashCode(mAccountHandle) + 230 Objects.hashCode(mCallCapabilities) + 231 Objects.hashCode(mCallProperties) + 232 Objects.hashCode(mDisconnectCause) + 233 Objects.hashCode(mConnectTimeMillis) + 234 Objects.hashCode(mGatewayInfo) + 235 Objects.hashCode(mVideoState) + 236 Objects.hashCode(mStatusHints) + 237 Objects.hashCode(mExtras); 238 } 239 240 /** {@hide} */ 241 public Details( 242 Uri handle, 243 int handlePresentation, 244 String callerDisplayName, 245 int callerDisplayNamePresentation, 246 PhoneAccountHandle accountHandle, 247 int capabilities, 248 int properties, 249 DisconnectCause disconnectCause, 250 long connectTimeMillis, 251 GatewayInfo gatewayInfo, 252 int videoState, 253 StatusHints statusHints, 254 Bundle extras) { 255 mHandle = handle; 256 mHandlePresentation = handlePresentation; 257 mCallerDisplayName = callerDisplayName; 258 mCallerDisplayNamePresentation = callerDisplayNamePresentation; 259 mAccountHandle = accountHandle; 260 mCallCapabilities = capabilities; 261 mCallProperties = properties; 262 mDisconnectCause = disconnectCause; 263 mConnectTimeMillis = connectTimeMillis; 264 mGatewayInfo = gatewayInfo; 265 mVideoState = videoState; 266 mStatusHints = statusHints; 267 mExtras = extras; 268 } 269 } 270 271 public static abstract class Listener { 272 /** 273 * Invoked when the state of this {@code Call} has changed. See {@link #getState()}. 274 * 275 * @param call The {@code Call} invoking this method. 276 * @param state The new state of the {@code Call}. 277 */ 278 public void onStateChanged(Call call, int state) {} 279 280 /** 281 * Invoked when the parent of this {@code Call} has changed. See {@link #getParent()}. 282 * 283 * @param call The {@code Call} invoking this method. 284 * @param parent The new parent of the {@code Call}. 285 */ 286 public void onParentChanged(Call call, Call parent) {} 287 288 /** 289 * Invoked when the children of this {@code Call} have changed. See {@link #getChildren()}. 290 * 291 * @param call The {@code Call} invoking this method. 292 * @param children The new children of the {@code Call}. 293 */ 294 public void onChildrenChanged(Call call, List<Call> children) {} 295 296 /** 297 * Invoked when the details of this {@code Call} have changed. See {@link #getDetails()}. 298 * 299 * @param call The {@code Call} invoking this method. 300 * @param details A {@code Details} object describing the {@code Call}. 301 */ 302 public void onDetailsChanged(Call call, Details details) {} 303 304 /** 305 * Invoked when the text messages that can be used as responses to the incoming 306 * {@code Call} are loaded from the relevant database. 307 * See {@link #getCannedTextResponses()}. 308 * 309 * @param call The {@code Call} invoking this method. 310 * @param cannedTextResponses The text messages useable as responses. 311 */ 312 public void onCannedTextResponsesLoaded(Call call, List<String> cannedTextResponses) {} 313 314 /** 315 * Invoked when the post-dial sequence in the outgoing {@code Call} has reached a pause 316 * character. This causes the post-dial signals to stop pending user confirmation. An 317 * implementation should present this choice to the user and invoke 318 * {@link #postDialContinue(boolean)} when the user makes the choice. 319 * 320 * @param call The {@code Call} invoking this method. 321 * @param remainingPostDialSequence The post-dial characters that remain to be sent. 322 */ 323 public void onPostDialWait(Call call, String remainingPostDialSequence) {} 324 325 /** 326 * Invoked when the {@code Call.VideoCall} of the {@code Call} has changed. 327 * 328 * @param call The {@code Call} invoking this method. 329 * @param videoCall The {@code Call.VideoCall} associated with the {@code Call}. 330 * @hide 331 */ 332 public void onVideoCallChanged(Call call, InCallService.VideoCall videoCall) {} 333 334 /** 335 * Invoked when the {@code Call} is destroyed. Clients should refrain from cleaning 336 * up their UI for the {@code Call} in response to state transitions. Specifically, 337 * clients should not assume that a {@link #onStateChanged(Call, int)} with a state of 338 * {@link #STATE_DISCONNECTED} is the final notification the {@code Call} will send. Rather, 339 * clients should wait for this method to be invoked. 340 * 341 * @param call The {@code Call} being destroyed. 342 */ 343 public void onCallDestroyed(Call call) {} 344 345 /** 346 * Invoked upon changes to the set of {@code Call}s with which this {@code Call} can be 347 * conferenced. 348 * 349 * @param call The {@code Call} being updated. 350 * @param conferenceableCalls The {@code Call}s with which this {@code Call} can be 351 * conferenced. 352 */ 353 public void onConferenceableCallsChanged(Call call, List<Call> conferenceableCalls) {} 354 } 355 356 private final Phone mPhone; 357 private final String mTelecomCallId; 358 private final InCallAdapter mInCallAdapter; 359 private final List<String> mChildrenIds = new ArrayList<>(); 360 private final List<Call> mChildren = new ArrayList<>(); 361 private final List<Call> mUnmodifiableChildren = Collections.unmodifiableList(mChildren); 362 private final List<Listener> mListeners = new CopyOnWriteArrayList<>(); 363 private final List<Call> mConferenceableCalls = new ArrayList<>(); 364 private final List<Call> mUnmodifiableConferenceableCalls = 365 Collections.unmodifiableList(mConferenceableCalls); 366 367 private boolean mChildrenCached; 368 private String mParentId = null; 369 private int mState; 370 private List<String> mCannedTextResponses = null; 371 private String mRemainingPostDialSequence; 372 private InCallService.VideoCall mVideoCall; 373 private Details mDetails; 374 375 /** 376 * Obtains the post-dial sequence remaining to be emitted by this {@code Call}, if any. 377 * 378 * @return The remaining post-dial sequence, or {@code null} if there is no post-dial sequence 379 * remaining or this {@code Call} is not in a post-dial state. 380 */ 381 public String getRemainingPostDialSequence() { 382 return mRemainingPostDialSequence; 383 } 384 385 /** 386 * Instructs this {@link #STATE_RINGING} {@code Call} to answer. 387 * @param videoState The video state in which to answer the call. 388 */ 389 public void answer(int videoState) { 390 mInCallAdapter.answerCall(mTelecomCallId, videoState); 391 } 392 393 /** 394 * Instructs this {@link #STATE_RINGING} {@code Call} to reject. 395 * 396 * @param rejectWithMessage Whether to reject with a text message. 397 * @param textMessage An optional text message with which to respond. 398 */ 399 public void reject(boolean rejectWithMessage, String textMessage) { 400 mInCallAdapter.rejectCall(mTelecomCallId, rejectWithMessage, textMessage); 401 } 402 403 /** 404 * Instructs this {@code Call} to disconnect. 405 */ 406 public void disconnect() { 407 mInCallAdapter.disconnectCall(mTelecomCallId); 408 } 409 410 /** 411 * Instructs this {@code Call} to go on hold. 412 */ 413 public void hold() { 414 mInCallAdapter.holdCall(mTelecomCallId); 415 } 416 417 /** 418 * Instructs this {@link #STATE_HOLDING} call to release from hold. 419 */ 420 public void unhold() { 421 mInCallAdapter.unholdCall(mTelecomCallId); 422 } 423 424 /** 425 * Instructs this {@code Call} to play a dual-tone multi-frequency signaling (DTMF) tone. 426 * 427 * Any other currently playing DTMF tone in the specified call is immediately stopped. 428 * 429 * @param digit A character representing the DTMF digit for which to play the tone. This 430 * value must be one of {@code '0'} through {@code '9'}, {@code '*'} or {@code '#'}. 431 */ 432 public void playDtmfTone(char digit) { 433 mInCallAdapter.playDtmfTone(mTelecomCallId, digit); 434 } 435 436 /** 437 * Instructs this {@code Call} to stop any dual-tone multi-frequency signaling (DTMF) tone 438 * currently playing. 439 * 440 * DTMF tones are played by calling {@link #playDtmfTone(char)}. If no DTMF tone is 441 * currently playing, this method will do nothing. 442 */ 443 public void stopDtmfTone() { 444 mInCallAdapter.stopDtmfTone(mTelecomCallId); 445 } 446 447 /** 448 * Instructs this {@code Call} to continue playing a post-dial DTMF string. 449 * 450 * A post-dial DTMF string is a string of digits entered after a phone number, when dialed, 451 * that are immediately sent as DTMF tones to the recipient as soon as the connection is made. 452 * 453 * If the DTMF string contains a {@link TelecomManager#DTMF_CHARACTER_PAUSE} symbol, this 454 * {@code Call} will temporarily pause playing the tones for a pre-defined period of time. 455 * 456 * If the DTMF string contains a {@link TelecomManager#DTMF_CHARACTER_WAIT} symbol, this 457 * {@code Call} will pause playing the tones and notify listeners via 458 * {@link Listener#onPostDialWait(Call, String)}. At this point, the in-call app 459 * should display to the user an indication of this state and an affordance to continue 460 * the postdial sequence. When the user decides to continue the postdial sequence, the in-call 461 * app should invoke the {@link #postDialContinue(boolean)} method. 462 * 463 * @param proceed Whether or not to continue with the post-dial sequence. 464 */ 465 public void postDialContinue(boolean proceed) { 466 mInCallAdapter.postDialContinue(mTelecomCallId, proceed); 467 } 468 469 /** 470 * Notifies this {@code Call} that an account has been selected and to proceed with placing 471 * an outgoing call. 472 */ 473 public void phoneAccountSelected(PhoneAccountHandle accountHandle) { 474 mInCallAdapter.phoneAccountSelected(mTelecomCallId, accountHandle); 475 476 } 477 478 /** 479 * Instructs this {@code Call} to enter a conference. 480 * 481 * @param callToConferenceWith The other call with which to conference. 482 */ 483 public void conference(Call callToConferenceWith) { 484 if (callToConferenceWith != null) { 485 mInCallAdapter.conference(mTelecomCallId, callToConferenceWith.mTelecomCallId); 486 } 487 } 488 489 /** 490 * Instructs this {@code Call} to split from any conference call with which it may be 491 * connected. 492 */ 493 public void splitFromConference() { 494 mInCallAdapter.splitFromConference(mTelecomCallId); 495 } 496 497 /** 498 * Merges the calls within this conference. See {@link PhoneCapabilities#MERGE_CONFERENCE}. 499 */ 500 public void mergeConference() { 501 mInCallAdapter.mergeConference(mTelecomCallId); 502 } 503 504 /** 505 * Swaps the calls within this conference. See {@link PhoneCapabilities#SWAP_CONFERENCE}. 506 */ 507 public void swapConference() { 508 mInCallAdapter.swapConference(mTelecomCallId); 509 } 510 511 /** 512 * Obtains the parent of this {@code Call} in a conference, if any. 513 * 514 * @return The parent {@code Call}, or {@code null} if this {@code Call} is not a 515 * child of any conference {@code Call}s. 516 */ 517 public Call getParent() { 518 if (mParentId != null) { 519 return mPhone.internalGetCallByTelecomId(mParentId); 520 } 521 return null; 522 } 523 524 /** 525 * Obtains the children of this conference {@code Call}, if any. 526 * 527 * @return The children of this {@code Call} if this {@code Call} is a conference, or an empty 528 * {@code List} otherwise. 529 */ 530 public List<Call> getChildren() { 531 if (!mChildrenCached) { 532 mChildrenCached = true; 533 mChildren.clear(); 534 535 for(String id : mChildrenIds) { 536 Call call = mPhone.internalGetCallByTelecomId(id); 537 if (call == null) { 538 // At least one child was still not found, so do not save true for "cached" 539 mChildrenCached = false; 540 } else { 541 mChildren.add(call); 542 } 543 } 544 } 545 546 return mUnmodifiableChildren; 547 } 548 549 /** 550 * Returns the list of {@code Call}s with which this {@code Call} is allowed to conference. 551 * 552 * @return The list of conferenceable {@code Call}s. 553 */ 554 public List<Call> getConferenceableCalls() { 555 return mUnmodifiableConferenceableCalls; 556 } 557 558 /** 559 * Obtains the state of this {@code Call}. 560 * 561 * @return A state value, chosen from the {@code STATE_*} constants. 562 */ 563 public int getState() { 564 return mState; 565 } 566 567 /** 568 * Obtains a list of canned, pre-configured message responses to present to the user as 569 * ways of rejecting this {@code Call} using via a text message. 570 * 571 * @see #reject(boolean, String) 572 * 573 * @return A list of canned text message responses. 574 */ 575 public List<String> getCannedTextResponses() { 576 return mCannedTextResponses; 577 } 578 579 /** 580 * Obtains an object that can be used to display video from this {@code Call}. 581 * 582 * @return An {@code Call.VideoCall}. 583 * @hide 584 */ 585 public InCallService.VideoCall getVideoCall() { 586 return mVideoCall; 587 } 588 589 /** 590 * Obtains an object containing call details. 591 * 592 * @return A {@link Details} object. Depending on the state of the {@code Call}, the 593 * result may be {@code null}. 594 */ 595 public Details getDetails() { 596 return mDetails; 597 } 598 599 /** 600 * Adds a listener to this {@code Call}. 601 * 602 * @param listener A {@code Listener}. 603 */ 604 public void addListener(Listener listener) { 605 mListeners.add(listener); 606 } 607 608 /** 609 * Removes a listener from this {@code Call}. 610 * 611 * @param listener A {@code Listener}. 612 */ 613 public void removeListener(Listener listener) { 614 if (listener != null) { 615 mListeners.remove(listener); 616 } 617 } 618 619 /** {@hide} */ 620 Call(Phone phone, String telecomCallId, InCallAdapter inCallAdapter) { 621 mPhone = phone; 622 mTelecomCallId = telecomCallId; 623 mInCallAdapter = inCallAdapter; 624 mState = STATE_NEW; 625 } 626 627 /** {@hide} */ 628 final String internalGetCallId() { 629 return mTelecomCallId; 630 } 631 632 /** {@hide} */ 633 final void internalUpdate(ParcelableCall parcelableCall, Map<String, Call> callIdMap) { 634 // First, we update the internal state as far as possible before firing any updates. 635 Details details = new Details( 636 parcelableCall.getHandle(), 637 parcelableCall.getHandlePresentation(), 638 parcelableCall.getCallerDisplayName(), 639 parcelableCall.getCallerDisplayNamePresentation(), 640 parcelableCall.getAccountHandle(), 641 parcelableCall.getCapabilities(), 642 parcelableCall.getProperties(), 643 parcelableCall.getDisconnectCause(), 644 parcelableCall.getConnectTimeMillis(), 645 parcelableCall.getGatewayInfo(), 646 parcelableCall.getVideoState(), 647 parcelableCall.getStatusHints(), 648 parcelableCall.getExtras()); 649 boolean detailsChanged = !Objects.equals(mDetails, details); 650 if (detailsChanged) { 651 mDetails = details; 652 } 653 654 boolean cannedTextResponsesChanged = false; 655 if (mCannedTextResponses == null && parcelableCall.getCannedSmsResponses() != null 656 && !parcelableCall.getCannedSmsResponses().isEmpty()) { 657 mCannedTextResponses = 658 Collections.unmodifiableList(parcelableCall.getCannedSmsResponses()); 659 } 660 661 boolean videoCallChanged = !Objects.equals(mVideoCall, parcelableCall.getVideoCall()); 662 if (videoCallChanged) { 663 mVideoCall = parcelableCall.getVideoCall(); 664 } 665 666 int state = stateFromParcelableCallState(parcelableCall.getState()); 667 boolean stateChanged = mState != state; 668 if (stateChanged) { 669 mState = state; 670 } 671 672 String parentId = parcelableCall.getParentCallId(); 673 boolean parentChanged = !Objects.equals(mParentId, parentId); 674 if (parentChanged) { 675 mParentId = parentId; 676 } 677 678 List<String> childCallIds = parcelableCall.getChildCallIds(); 679 boolean childrenChanged = !Objects.equals(childCallIds, mChildrenIds); 680 if (childrenChanged) { 681 mChildrenIds.clear(); 682 mChildrenIds.addAll(parcelableCall.getChildCallIds()); 683 mChildrenCached = false; 684 } 685 686 List<String> conferenceableCallIds = parcelableCall.getConferenceableCallIds(); 687 List<Call> conferenceableCalls = new ArrayList<Call>(conferenceableCallIds.size()); 688 for (String otherId : conferenceableCallIds) { 689 if (callIdMap.containsKey(otherId)) { 690 conferenceableCalls.add(callIdMap.get(otherId)); 691 } 692 } 693 694 if (!Objects.equals(mConferenceableCalls, conferenceableCalls)) { 695 mConferenceableCalls.clear(); 696 mConferenceableCalls.addAll(conferenceableCalls); 697 fireConferenceableCallsChanged(); 698 } 699 700 // Now we fire updates, ensuring that any client who listens to any of these notifications 701 // gets the most up-to-date state. 702 703 if (stateChanged) { 704 fireStateChanged(mState); 705 } 706 if (detailsChanged) { 707 fireDetailsChanged(mDetails); 708 } 709 if (cannedTextResponsesChanged) { 710 fireCannedTextResponsesLoaded(mCannedTextResponses); 711 } 712 if (videoCallChanged) { 713 fireVideoCallChanged(mVideoCall); 714 } 715 if (parentChanged) { 716 fireParentChanged(getParent()); 717 } 718 if (childrenChanged) { 719 fireChildrenChanged(getChildren()); 720 } 721 722 // If we have transitioned to DISCONNECTED, that means we need to notify clients and 723 // remove ourselves from the Phone. Note that we do this after completing all state updates 724 // so a client can cleanly transition all their UI to the state appropriate for a 725 // DISCONNECTED Call while still relying on the existence of that Call in the Phone's list. 726 if (mState == STATE_DISCONNECTED) { 727 fireCallDestroyed(); 728 mPhone.internalRemoveCall(this); 729 } 730 } 731 732 /** {@hide} */ 733 final void internalSetPostDialWait(String remaining) { 734 mRemainingPostDialSequence = remaining; 735 firePostDialWait(mRemainingPostDialSequence); 736 } 737 738 /** {@hide} */ 739 final void internalSetDisconnected() { 740 if (mState != Call.STATE_DISCONNECTED) { 741 mState = Call.STATE_DISCONNECTED; 742 fireStateChanged(mState); 743 fireCallDestroyed(); 744 mPhone.internalRemoveCall(this); 745 } 746 } 747 748 private void fireStateChanged(int newState) { 749 for (Listener listener : mListeners) { 750 listener.onStateChanged(this, newState); 751 } 752 } 753 754 private void fireParentChanged(Call newParent) { 755 for (Listener listener : mListeners) { 756 listener.onParentChanged(this, newParent); 757 } 758 } 759 760 private void fireChildrenChanged(List<Call> children) { 761 for (Listener listener : mListeners) { 762 listener.onChildrenChanged(this, children); 763 } 764 } 765 766 private void fireDetailsChanged(Details details) { 767 for (Listener listener : mListeners) { 768 listener.onDetailsChanged(this, details); 769 } 770 } 771 772 private void fireCannedTextResponsesLoaded(List<String> cannedTextResponses) { 773 for (Listener listener : mListeners) { 774 listener.onCannedTextResponsesLoaded(this, cannedTextResponses); 775 } 776 } 777 778 private void fireVideoCallChanged(InCallService.VideoCall videoCall) { 779 for (Listener listener : mListeners) { 780 listener.onVideoCallChanged(this, videoCall); 781 } 782 } 783 784 private void firePostDialWait(String remainingPostDialSequence) { 785 for (Listener listener : mListeners) { 786 listener.onPostDialWait(this, remainingPostDialSequence); 787 } 788 } 789 790 private void fireCallDestroyed() { 791 for (Listener listener : mListeners) { 792 listener.onCallDestroyed(this); 793 } 794 } 795 796 private void fireConferenceableCallsChanged() { 797 for (Listener listener : mListeners) { 798 listener.onConferenceableCallsChanged(this, mUnmodifiableConferenceableCalls); 799 } 800 } 801 802 private int stateFromParcelableCallState(int parcelableCallState) { 803 switch (parcelableCallState) { 804 case CallState.NEW: 805 return STATE_NEW; 806 case CallState.CONNECTING: 807 return STATE_CONNECTING; 808 case CallState.PRE_DIAL_WAIT: 809 return STATE_PRE_DIAL_WAIT; 810 case CallState.DIALING: 811 return STATE_DIALING; 812 case CallState.RINGING: 813 return STATE_RINGING; 814 case CallState.ACTIVE: 815 return STATE_ACTIVE; 816 case CallState.ON_HOLD: 817 return STATE_HOLDING; 818 case CallState.DISCONNECTED: 819 return STATE_DISCONNECTED; 820 case CallState.ABORTED: 821 return STATE_DISCONNECTED; 822 default: 823 Log.wtf(this, "Unrecognized CallState %s", parcelableCallState); 824 return STATE_NEW; 825 } 826 } 827} 828