1/* 2 * Copyright (C) 2006 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 com.android.internal.telephony; 18 19import android.net.Uri; 20import android.os.Bundle; 21import android.os.SystemClock; 22import android.telecom.ConferenceParticipant; 23import android.telephony.Rlog; 24import android.util.Log; 25 26import java.lang.Override; 27import java.util.ArrayList; 28import java.util.List; 29import java.util.Set; 30import java.util.concurrent.CopyOnWriteArraySet; 31 32/** 33 * {@hide} 34 */ 35public abstract class Connection { 36 public interface PostDialListener { 37 void onPostDialWait(); 38 void onPostDialChar(char c); 39 } 40 41 /** 42 * Listener interface for events related to the connection which should be reported to the 43 * {@link android.telecom.Connection}. 44 */ 45 public interface Listener { 46 public void onVideoStateChanged(int videoState); 47 public void onLocalVideoCapabilityChanged(boolean capable); 48 public void onRemoteVideoCapabilityChanged(boolean capable); 49 public void onWifiChanged(boolean isWifi); 50 public void onVideoProviderChanged( 51 android.telecom.Connection.VideoProvider videoProvider); 52 public void onAudioQualityChanged(int audioQuality); 53 public void onConferenceParticipantsChanged(List<ConferenceParticipant> participants); 54 public void onCallSubstateChanged(int callSubstate); 55 public void onMultipartyStateChanged(boolean isMultiParty); 56 public void onConferenceMergedFailed(); 57 public void onExtrasChanged(Bundle extras); 58 } 59 60 /** 61 * Base listener implementation. 62 */ 63 public abstract static class ListenerBase implements Listener { 64 @Override 65 public void onVideoStateChanged(int videoState) {} 66 @Override 67 public void onLocalVideoCapabilityChanged(boolean capable) {} 68 @Override 69 public void onRemoteVideoCapabilityChanged(boolean capable) {} 70 @Override 71 public void onWifiChanged(boolean isWifi) {} 72 @Override 73 public void onVideoProviderChanged( 74 android.telecom.Connection.VideoProvider videoProvider) {} 75 @Override 76 public void onAudioQualityChanged(int audioQuality) {} 77 @Override 78 public void onConferenceParticipantsChanged(List<ConferenceParticipant> participants) {} 79 @Override 80 public void onCallSubstateChanged(int callSubstate) {} 81 @Override 82 public void onMultipartyStateChanged(boolean isMultiParty) {} 83 @Override 84 public void onConferenceMergedFailed() {} 85 @Override 86 public void onExtrasChanged(Bundle extras) {} 87 } 88 89 public static final int AUDIO_QUALITY_STANDARD = 1; 90 public static final int AUDIO_QUALITY_HIGH_DEFINITION = 2; 91 92 //Caller Name Display 93 protected String mCnapName; 94 protected int mCnapNamePresentation = PhoneConstants.PRESENTATION_ALLOWED; 95 protected String mAddress; // MAY BE NULL!!! 96 protected String mDialString; // outgoing calls only 97 protected int mNumberPresentation = PhoneConstants.PRESENTATION_ALLOWED; 98 protected boolean mIsIncoming; 99 /* 100 * These time/timespan values are based on System.currentTimeMillis(), 101 * i.e., "wall clock" time. 102 */ 103 protected long mCreateTime; 104 protected long mConnectTime; 105 /* 106 * These time/timespan values are based on SystemClock.elapsedRealTime(), 107 * i.e., time since boot. They are appropriate for comparison and 108 * calculating deltas. 109 */ 110 protected long mConnectTimeReal; 111 protected long mDuration; 112 protected long mHoldingStartTime; // The time when the Connection last transitioned 113 // into HOLDING 114 protected Connection mOrigConnection; 115 private List<PostDialListener> mPostDialListeners = new ArrayList<>(); 116 public Set<Listener> mListeners = new CopyOnWriteArraySet<>(); 117 118 protected boolean mNumberConverted = false; 119 protected String mConvertedNumber; 120 121 private static String LOG_TAG = "Connection"; 122 123 Object mUserData; 124 private int mVideoState; 125 private boolean mLocalVideoCapable; 126 private boolean mRemoteVideoCapable; 127 private boolean mIsWifi; 128 private int mAudioQuality; 129 private int mCallSubstate; 130 private android.telecom.Connection.VideoProvider mVideoProvider; 131 public Call.State mPreHandoverState = Call.State.IDLE; 132 private Bundle mExtras; 133 134 /* Instance Methods */ 135 136 /** 137 * Gets address (e.g. phone number) associated with connection. 138 * TODO: distinguish reasons for unavailability 139 * 140 * @return address or null if unavailable 141 */ 142 143 public String getAddress() { 144 return mAddress; 145 } 146 147 /** 148 * Gets CNAP name associated with connection. 149 * @return cnap name or null if unavailable 150 */ 151 public String getCnapName() { 152 return mCnapName; 153 } 154 155 /** 156 * Get original dial string. 157 * @return original dial string or null if unavailable 158 */ 159 public String getOrigDialString(){ 160 return null; 161 } 162 163 /** 164 * Gets CNAP presentation associated with connection. 165 * @return cnap name or null if unavailable 166 */ 167 168 public int getCnapNamePresentation() { 169 return mCnapNamePresentation; 170 } 171 172 /** 173 * @return Call that owns this Connection, or null if none 174 */ 175 public abstract Call getCall(); 176 177 /** 178 * Connection create time in currentTimeMillis() format 179 * Basically, set when object is created. 180 * Effectively, when an incoming call starts ringing or an 181 * outgoing call starts dialing 182 */ 183 public long getCreateTime() { 184 return mCreateTime; 185 } 186 187 /** 188 * Connection connect time in currentTimeMillis() format. 189 * For outgoing calls: Begins at (DIALING|ALERTING) -> ACTIVE transition. 190 * For incoming calls: Begins at (INCOMING|WAITING) -> ACTIVE transition. 191 * Returns 0 before then. 192 */ 193 public long getConnectTime() { 194 return mConnectTime; 195 } 196 197 /** 198 * Sets the Connection connect time in currentTimeMillis() format. 199 * 200 * @param connectTime the new connect time. 201 */ 202 public void setConnectTime(long connectTime) { 203 mConnectTime = connectTime; 204 } 205 206 /** 207 * Connection connect time in elapsedRealtime() format. 208 * For outgoing calls: Begins at (DIALING|ALERTING) -> ACTIVE transition. 209 * For incoming calls: Begins at (INCOMING|WAITING) -> ACTIVE transition. 210 * Returns 0 before then. 211 */ 212 public long getConnectTimeReal() { 213 return mConnectTimeReal; 214 } 215 216 /** 217 * Disconnect time in currentTimeMillis() format. 218 * The time when this Connection makes a transition into ENDED or FAIL. 219 * Returns 0 before then. 220 */ 221 public abstract long getDisconnectTime(); 222 223 /** 224 * Returns the number of milliseconds the call has been connected, 225 * or 0 if the call has never connected. 226 * If the call is still connected, then returns the elapsed 227 * time since connect. 228 */ 229 public long getDurationMillis() { 230 if (mConnectTimeReal == 0) { 231 return 0; 232 } else if (mDuration == 0) { 233 return SystemClock.elapsedRealtime() - mConnectTimeReal; 234 } else { 235 return mDuration; 236 } 237 } 238 239 /** 240 * The time when this Connection last transitioned into HOLDING 241 * in elapsedRealtime() format. 242 * Returns 0, if it has never made a transition into HOLDING. 243 */ 244 public long getHoldingStartTime() { 245 return mHoldingStartTime; 246 } 247 248 /** 249 * If this connection is HOLDING, return the number of milliseconds 250 * that it has been on hold for (approximately). 251 * If this connection is in any other state, return 0. 252 */ 253 254 public abstract long getHoldDurationMillis(); 255 256 /** 257 * Returns call disconnect cause. Values are defined in 258 * {@link android.telephony.DisconnectCause}. If the call is not yet 259 * disconnected, NOT_DISCONNECTED is returned. 260 */ 261 public abstract int getDisconnectCause(); 262 263 /** 264 * Returns a string disconnect cause which is from vendor. 265 * Vendors may use this string to explain the underline causes of failed calls. 266 * There is no guarantee that it is non-null nor it'll have meaningful stable values. 267 * Only use it when getDisconnectCause() returns a value that is not specific enough, like 268 * ERROR_UNSPECIFIED. 269 */ 270 public abstract String getVendorDisconnectCause(); 271 272 /** 273 * Returns true of this connection originated elsewhere 274 * ("MT" or mobile terminated; another party called this terminal) 275 * or false if this call originated here (MO or mobile originated). 276 */ 277 public boolean isIncoming() { 278 return mIsIncoming; 279 } 280 281 /** 282 * If this Connection is connected, then it is associated with 283 * a Call. 284 * 285 * Returns getCall().getState() or Call.State.IDLE if not 286 * connected 287 */ 288 public Call.State getState() { 289 Call c; 290 291 c = getCall(); 292 293 if (c == null) { 294 return Call.State.IDLE; 295 } else { 296 return c.getState(); 297 } 298 } 299 300 /** 301 * If this connection went through handover return the state of the 302 * call that contained this connection before handover. 303 */ 304 public Call.State getStateBeforeHandover() { 305 return mPreHandoverState; 306 } 307 308 /** 309 * Get the details of conference participants. Expected to be 310 * overwritten by the Connection subclasses. 311 */ 312 public List<ConferenceParticipant> getConferenceParticipants() { 313 Call c; 314 315 c = getCall(); 316 317 if (c == null) { 318 return null; 319 } else { 320 return c.getConferenceParticipants(); 321 } 322 } 323 324 /** 325 * isAlive() 326 * 327 * @return true if the connection isn't disconnected 328 * (could be active, holding, ringing, dialing, etc) 329 */ 330 public boolean 331 isAlive() { 332 return getState().isAlive(); 333 } 334 335 /** 336 * Returns true if Connection is connected and is INCOMING or WAITING 337 */ 338 public boolean 339 isRinging() { 340 return getState().isRinging(); 341 } 342 343 /** 344 * 345 * @return the userdata set in setUserData() 346 */ 347 public Object getUserData() { 348 return mUserData; 349 } 350 351 /** 352 * 353 * @param userdata user can store an any userdata in the Connection object. 354 */ 355 public void setUserData(Object userdata) { 356 mUserData = userdata; 357 } 358 359 /** 360 * Hangup individual Connection 361 */ 362 public abstract void hangup() throws CallStateException; 363 364 /** 365 * Separate this call from its owner Call and assigns it to a new Call 366 * (eg if it is currently part of a Conference call 367 * TODO: Throw exception? Does GSM require error display on failure here? 368 */ 369 public abstract void separate() throws CallStateException; 370 371 public enum PostDialState { 372 NOT_STARTED, /* The post dial string playback hasn't 373 been started, or this call is not yet 374 connected, or this is an incoming call */ 375 STARTED, /* The post dial string playback has begun */ 376 WAIT, /* The post dial string playback is waiting for a 377 call to proceedAfterWaitChar() */ 378 WILD, /* The post dial string playback is waiting for a 379 call to proceedAfterWildChar() */ 380 COMPLETE, /* The post dial string playback is complete */ 381 CANCELLED, /* The post dial string playback was cancelled 382 with cancelPostDial() */ 383 PAUSE /* The post dial string playback is pausing for a 384 call to processNextPostDialChar*/ 385 } 386 387 public void clearUserData(){ 388 mUserData = null; 389 } 390 391 public final void addPostDialListener(PostDialListener listener) { 392 if (!mPostDialListeners.contains(listener)) { 393 mPostDialListeners.add(listener); 394 } 395 } 396 397 public final void removePostDialListener(PostDialListener listener) { 398 mPostDialListeners.remove(listener); 399 } 400 401 protected final void clearPostDialListeners() { 402 mPostDialListeners.clear(); 403 } 404 405 protected final void notifyPostDialListeners() { 406 if (getPostDialState() == PostDialState.WAIT) { 407 for (PostDialListener listener : new ArrayList<>(mPostDialListeners)) { 408 listener.onPostDialWait(); 409 } 410 } 411 } 412 413 protected final void notifyPostDialListenersNextChar(char c) { 414 for (PostDialListener listener : new ArrayList<>(mPostDialListeners)) { 415 listener.onPostDialChar(c); 416 } 417 } 418 419 public abstract PostDialState getPostDialState(); 420 421 /** 422 * Returns the portion of the post dial string that has not 423 * yet been dialed, or "" if none 424 */ 425 public abstract String getRemainingPostDialString(); 426 427 /** 428 * See Phone.setOnPostDialWaitCharacter() 429 */ 430 431 public abstract void proceedAfterWaitChar(); 432 433 /** 434 * See Phone.setOnPostDialWildCharacter() 435 */ 436 public abstract void proceedAfterWildChar(String str); 437 /** 438 * Cancel any post 439 */ 440 public abstract void cancelPostDial(); 441 442 /** 443 * Returns the caller id presentation type for incoming and waiting calls 444 * @return one of PRESENTATION_* 445 */ 446 public abstract int getNumberPresentation(); 447 448 /** 449 * Returns the User to User Signaling (UUS) information associated with 450 * incoming and waiting calls 451 * @return UUSInfo containing the UUS userdata. 452 */ 453 public abstract UUSInfo getUUSInfo(); 454 455 /** 456 * Returns the CallFail reason provided by the RIL with the result of 457 * RIL_REQUEST_LAST_CALL_FAIL_CAUSE 458 */ 459 public abstract int getPreciseDisconnectCause(); 460 461 /** 462 * Returns the original Connection instance associated with 463 * this Connection 464 */ 465 public Connection getOrigConnection() { 466 return mOrigConnection; 467 } 468 469 /** 470 * Returns whether the original ImsPhoneConnection was a member 471 * of a conference call 472 * @return valid only when getOrigConnection() is not null 473 */ 474 public abstract boolean isMultiparty(); 475 476 public void migrateFrom(Connection c) { 477 if (c == null) return; 478 mListeners = c.mListeners; 479 mDialString = c.getOrigDialString(); 480 mCreateTime = c.getCreateTime(); 481 mConnectTime = c.getConnectTime(); 482 mConnectTimeReal = c.getConnectTimeReal(); 483 mHoldingStartTime = c.getHoldingStartTime(); 484 mOrigConnection = c.getOrigConnection(); 485 } 486 487 /** 488 * Assign a listener to be notified of state changes. 489 * 490 * @param listener A listener. 491 */ 492 public final void addListener(Listener listener) { 493 mListeners.add(listener); 494 } 495 496 /** 497 * Removes a listener. 498 * 499 * @param listener A listener. 500 */ 501 public final void removeListener(Listener listener) { 502 mListeners.remove(listener); 503 } 504 505 /** 506 * Returns the current video state of the connection. 507 * 508 * @return The video state of the connection. 509 */ 510 public int getVideoState() { 511 return mVideoState; 512 } 513 514 /** 515 * Returns the local video capability state for the connection. 516 * 517 * @return {@code True} if the connection has local video capabilities. 518 */ 519 public boolean isLocalVideoCapable() { 520 return mLocalVideoCapable; 521 } 522 523 /** 524 * Returns the remote video capability state for the connection. 525 * 526 * @return {@code True} if the connection has remote video capabilities. 527 */ 528 public boolean isRemoteVideoCapable() { 529 return mRemoteVideoCapable; 530 } 531 532 /** 533 * Returns whether the connection is using a wifi network. 534 * 535 * @return {@code True} if the connection is using a wifi network. 536 */ 537 public boolean isWifi() { 538 return mIsWifi; 539 } 540 541 /** 542 * Returns the {@link android.telecom.Connection.VideoProvider} for the connection. 543 * 544 * @return The {@link android.telecom.Connection.VideoProvider}. 545 */ 546 public android.telecom.Connection.VideoProvider getVideoProvider() { 547 return mVideoProvider; 548 } 549 550 /** 551 * Returns the audio-quality for the connection. 552 * 553 * @return The audio quality for the connection. 554 */ 555 public int getAudioQuality() { 556 return mAudioQuality; 557 } 558 559 560 /** 561 * Returns the current call substate of the connection. 562 * 563 * @return The call substate of the connection. 564 */ 565 public int getCallSubstate() { 566 return mCallSubstate; 567 } 568 569 570 /** 571 * Sets the videoState for the current connection and reports the changes to all listeners. 572 * Valid video states are defined in {@link android.telecom.VideoProfile}. 573 * 574 * @return The video state. 575 */ 576 public void setVideoState(int videoState) { 577 mVideoState = videoState; 578 for (Listener l : mListeners) { 579 l.onVideoStateChanged(mVideoState); 580 } 581 } 582 583 /** 584 * Sets whether video capability is present locally. 585 * 586 * @param capable {@code True} if video capable. 587 */ 588 public void setLocalVideoCapable(boolean capable) { 589 mLocalVideoCapable = capable; 590 for (Listener l : mListeners) { 591 l.onLocalVideoCapabilityChanged(mLocalVideoCapable); 592 } 593 } 594 595 /** 596 * Sets whether video capability is present remotely. 597 * 598 * @param capable {@code True} if video capable. 599 */ 600 public void setRemoteVideoCapable(boolean capable) { 601 mRemoteVideoCapable = capable; 602 for (Listener l : mListeners) { 603 l.onRemoteVideoCapabilityChanged(mRemoteVideoCapable); 604 } 605 } 606 607 /** 608 * Sets whether a wifi network is used for the connection. 609 * 610 * @param isWifi {@code True} if wifi is being used. 611 */ 612 public void setWifi(boolean isWifi) { 613 mIsWifi = isWifi; 614 for (Listener l : mListeners) { 615 l.onWifiChanged(mIsWifi); 616 } 617 } 618 619 /** 620 * Set the audio quality for the connection. 621 * 622 * @param audioQuality The audio quality. 623 */ 624 public void setAudioQuality(int audioQuality) { 625 mAudioQuality = audioQuality; 626 for (Listener l : mListeners) { 627 l.onAudioQualityChanged(mAudioQuality); 628 } 629 } 630 631 /** 632 * Notifies listeners that connection extras has changed. 633 * @param extras New connection extras. 634 */ 635 public void setConnectionExtras(Bundle extras) { 636 mExtras = extras; 637 for (Listener l : mListeners) { 638 l.onExtrasChanged(extras); 639 } 640 } 641 642 /** 643 * Retrieves the current connection extras. 644 * @return the connection extras. 645 */ 646 public Bundle getConnectionExtras() { 647 return mExtras; 648 } 649 650 /** 651 * Sets the call substate for the current connection and reports the changes to all listeners. 652 * Valid call substates are defined in {@link android.telecom.Connection}. 653 * 654 * @return The call substate. 655 */ 656 public void setCallSubstate(int callSubstate) { 657 mCallSubstate = callSubstate; 658 for (Listener l : mListeners) { 659 l.onCallSubstateChanged(mCallSubstate); 660 } 661 } 662 663 /** 664 * Sets the {@link android.telecom.Connection.VideoProvider} for the connection. 665 * 666 * @param videoProvider The video call provider. 667 */ 668 public void setVideoProvider(android.telecom.Connection.VideoProvider videoProvider) { 669 mVideoProvider = videoProvider; 670 for (Listener l : mListeners) { 671 l.onVideoProviderChanged(mVideoProvider); 672 } 673 } 674 675 public void setConverted(String oriNumber) { 676 mNumberConverted = true; 677 mConvertedNumber = mAddress; 678 mAddress = oriNumber; 679 mDialString = oriNumber; 680 } 681 682 /** 683 * Notifies listeners of a change to conference participant(s). 684 * 685 * @param conferenceParticipants The participant(s). 686 */ 687 public void updateConferenceParticipants(List<ConferenceParticipant> conferenceParticipants) { 688 for (Listener l : mListeners) { 689 l.onConferenceParticipantsChanged(conferenceParticipants); 690 } 691 } 692 693 /** 694 * Notifies listeners of a change to the multiparty state of the connection. 695 * 696 * @param isMultiparty The participant(s). 697 */ 698 public void updateMultipartyState(boolean isMultiparty) { 699 for (Listener l : mListeners) { 700 l.onMultipartyStateChanged(isMultiparty); 701 } 702 } 703 704 /** 705 * Notifies listeners of a failure in merging this connection with the background connection. 706 */ 707 public void onConferenceMergeFailed() { 708 for (Listener l : mListeners) { 709 l.onConferenceMergedFailed(); 710 } 711 } 712 713 /** 714 * Notifies this Connection of a request to disconnect a participant of the conference managed 715 * by the connection. 716 * 717 * @param endpoint the {@link Uri} of the participant to disconnect. 718 */ 719 public void onDisconnectConferenceParticipant(Uri endpoint) { 720 } 721 722 /** 723 * Build a human representation of a connection instance, suitable for debugging. 724 * Don't log personal stuff unless in debug mode. 725 * @return a string representing the internal state of this connection. 726 */ 727 public String toString() { 728 StringBuilder str = new StringBuilder(128); 729 730 if (Rlog.isLoggable(LOG_TAG, Log.DEBUG)) { 731 str.append("addr: " + getAddress()) 732 .append(" pres.: " + getNumberPresentation()) 733 .append(" dial: " + getOrigDialString()) 734 .append(" postdial: " + getRemainingPostDialString()) 735 .append(" cnap name: " + getCnapName()) 736 .append("(" + getCnapNamePresentation() + ")"); 737 } 738 str.append(" incoming: " + isIncoming()) 739 .append(" state: " + getState()) 740 .append(" post dial state: " + getPostDialState()); 741 return str.toString(); 742 } 743} 744