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