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.os.SystemClock; 20 import android.telephony.Rlog; 21 import android.util.Log; 22 23 import java.lang.Override; 24 import java.util.ArrayList; 25 import java.util.List; 26 import java.util.Set; 27 import java.util.concurrent.CopyOnWriteArraySet; 28 29 /** 30 * {@hide} 31 */ 32 public abstract class Connection { 33 public interface PostDialListener { 34 void onPostDialWait(); 35 } 36 37 /** 38 * Listener interface for events related to the connection which should be reported to the 39 * {@link android.telecom.Connection}. 40 */ 41 public interface Listener { 42 public void onVideoStateChanged(int videoState); 43 public void onLocalVideoCapabilityChanged(boolean capable); 44 public void onRemoteVideoCapabilityChanged(boolean capable); 45 public void onVideoProviderChanged( 46 android.telecom.Connection.VideoProvider videoProvider); 47 public void onAudioQualityChanged(int audioQuality); 48 } 49 50 /** 51 * Base listener implementation. 52 */ 53 public abstract static class ListenerBase implements Listener { 54 @Override 55 public void onVideoStateChanged(int videoState) {} 56 @Override 57 public void onLocalVideoCapabilityChanged(boolean capable) {} 58 @Override 59 public void onRemoteVideoCapabilityChanged(boolean capable) {} 60 @Override 61 public void onVideoProviderChanged( 62 android.telecom.Connection.VideoProvider videoProvider) {} 63 @Override 64 public void onAudioQualityChanged(int audioQuality) {} 65 } 66 67 public static final int AUDIO_QUALITY_STANDARD = 1; 68 public static final int AUDIO_QUALITY_HIGH_DEFINITION = 2; 69 70 //Caller Name Display 71 protected String mCnapName; 72 protected int mCnapNamePresentation = PhoneConstants.PRESENTATION_ALLOWED; 73 protected String mAddress; // MAY BE NULL!!! 74 protected String mDialString; // outgoing calls only 75 protected int mNumberPresentation = PhoneConstants.PRESENTATION_ALLOWED; 76 protected boolean mIsIncoming; 77 /* 78 * These time/timespan values are based on System.currentTimeMillis(), 79 * i.e., "wall clock" time. 80 */ 81 protected long mCreateTime; 82 protected long mConnectTime; 83 /* 84 * These time/timespan values are based on SystemClock.elapsedRealTime(), 85 * i.e., time since boot. They are appropriate for comparison and 86 * calculating deltas. 87 */ 88 protected long mConnectTimeReal; 89 protected long mDuration; 90 protected long mHoldingStartTime; // The time when the Connection last transitioned 91 // into HOLDING 92 protected Connection mOrigConnection; 93 private List<PostDialListener> mPostDialListeners = new ArrayList<>(); 94 public Set<Listener> mListeners = new CopyOnWriteArraySet<>(); 95 96 protected boolean mNumberConverted = false; 97 protected String mConvertedNumber; 98 99 private static String LOG_TAG = "Connection"; 100 101 Object mUserData; 102 private int mVideoState; 103 private boolean mLocalVideoCapable; 104 private boolean mRemoteVideoCapable; 105 private int mAudioQuality; 106 private android.telecom.Connection.VideoProvider mVideoProvider; 107 108 /* Instance Methods */ 109 110 /** 111 * Gets address (e.g. phone number) associated with connection. 112 * TODO: distinguish reasons for unavailability 113 * 114 * @return address or null if unavailable 115 */ 116 117 public String getAddress() { 118 return mAddress; 119 } 120 121 /** 122 * Gets CNAP name associated with connection. 123 * @return cnap name or null if unavailable 124 */ 125 public String getCnapName() { 126 return mCnapName; 127 } 128 129 /** 130 * Get original dial string. 131 * @return original dial string or null if unavailable 132 */ 133 public String getOrigDialString(){ 134 return null; 135 } 136 137 /** 138 * Gets CNAP presentation associated with connection. 139 * @return cnap name or null if unavailable 140 */ 141 142 public int getCnapNamePresentation() { 143 return mCnapNamePresentation; 144 } 145 146 /** 147 * @return Call that owns this Connection, or null if none 148 */ 149 public abstract Call getCall(); 150 151 /** 152 * Connection create time in currentTimeMillis() format 153 * Basically, set when object is created. 154 * Effectively, when an incoming call starts ringing or an 155 * outgoing call starts dialing 156 */ 157 public long getCreateTime() { 158 return mCreateTime; 159 } 160 161 /** 162 * Connection connect time in currentTimeMillis() format. 163 * For outgoing calls: Begins at (DIALING|ALERTING) -> ACTIVE transition. 164 * For incoming calls: Begins at (INCOMING|WAITING) -> ACTIVE transition. 165 * Returns 0 before then. 166 */ 167 public long getConnectTime() { 168 return mConnectTime; 169 } 170 171 /** 172 * Connection connect time in elapsedRealtime() format. 173 * For outgoing calls: Begins at (DIALING|ALERTING) -> ACTIVE transition. 174 * For incoming calls: Begins at (INCOMING|WAITING) -> ACTIVE transition. 175 * Returns 0 before then. 176 */ 177 public long getConnectTimeReal() { 178 return mConnectTimeReal; 179 } 180 181 /** 182 * Disconnect time in currentTimeMillis() format. 183 * The time when this Connection makes a transition into ENDED or FAIL. 184 * Returns 0 before then. 185 */ 186 public abstract long getDisconnectTime(); 187 188 /** 189 * Returns the number of milliseconds the call has been connected, 190 * or 0 if the call has never connected. 191 * If the call is still connected, then returns the elapsed 192 * time since connect. 193 */ 194 public long getDurationMillis() { 195 if (mConnectTimeReal == 0) { 196 return 0; 197 } else if (mDuration == 0) { 198 return SystemClock.elapsedRealtime() - mConnectTimeReal; 199 } else { 200 return mDuration; 201 } 202 } 203 204 /** 205 * The time when this Connection last transitioned into HOLDING 206 * in elapsedRealtime() format. 207 * Returns 0, if it has never made a transition into HOLDING. 208 */ 209 public long getHoldingStartTime() { 210 return mHoldingStartTime; 211 } 212 213 /** 214 * If this connection is HOLDING, return the number of milliseconds 215 * that it has been on hold for (approximately). 216 * If this connection is in any other state, return 0. 217 */ 218 219 public abstract long getHoldDurationMillis(); 220 221 /** 222 * Returns call disconnect cause. Values are defined in 223 * {@link android.telephony.DisconnectCause}. If the call is not yet 224 * disconnected, NOT_DISCONNECTED is returned. 225 */ 226 public abstract int getDisconnectCause(); 227 228 /** 229 * Returns true of this connection originated elsewhere 230 * ("MT" or mobile terminated; another party called this terminal) 231 * or false if this call originated here (MO or mobile originated). 232 */ 233 public boolean isIncoming() { 234 return mIsIncoming; 235 } 236 237 /** 238 * If this Connection is connected, then it is associated with 239 * a Call. 240 * 241 * Returns getCall().getState() or Call.State.IDLE if not 242 * connected 243 */ 244 public Call.State getState() { 245 Call c; 246 247 c = getCall(); 248 249 if (c == null) { 250 return Call.State.IDLE; 251 } else { 252 return c.getState(); 253 } 254 } 255 256 /** 257 * isAlive() 258 * 259 * @return true if the connection isn't disconnected 260 * (could be active, holding, ringing, dialing, etc) 261 */ 262 public boolean 263 isAlive() { 264 return getState().isAlive(); 265 } 266 267 /** 268 * Returns true if Connection is connected and is INCOMING or WAITING 269 */ 270 public boolean 271 isRinging() { 272 return getState().isRinging(); 273 } 274 275 /** 276 * 277 * @return the userdata set in setUserData() 278 */ 279 public Object getUserData() { 280 return mUserData; 281 } 282 283 /** 284 * 285 * @param userdata user can store an any userdata in the Connection object. 286 */ 287 public void setUserData(Object userdata) { 288 mUserData = userdata; 289 } 290 291 /** 292 * Hangup individual Connection 293 */ 294 public abstract void hangup() throws CallStateException; 295 296 /** 297 * Separate this call from its owner Call and assigns it to a new Call 298 * (eg if it is currently part of a Conference call 299 * TODO: Throw exception? Does GSM require error display on failure here? 300 */ 301 public abstract void separate() throws CallStateException; 302 303 public enum PostDialState { 304 NOT_STARTED, /* The post dial string playback hasn't 305 been started, or this call is not yet 306 connected, or this is an incoming call */ 307 STARTED, /* The post dial string playback has begun */ 308 WAIT, /* The post dial string playback is waiting for a 309 call to proceedAfterWaitChar() */ 310 WILD, /* The post dial string playback is waiting for a 311 call to proceedAfterWildChar() */ 312 COMPLETE, /* The post dial string playback is complete */ 313 CANCELLED, /* The post dial string playback was cancelled 314 with cancelPostDial() */ 315 PAUSE /* The post dial string playback is pausing for a 316 call to processNextPostDialChar*/ 317 } 318 319 public void clearUserData(){ 320 mUserData = null; 321 } 322 323 public final void addPostDialListener(PostDialListener listener) { 324 if (!mPostDialListeners.contains(listener)) { 325 mPostDialListeners.add(listener); 326 } 327 } 328 329 protected final void clearPostDialListeners() { 330 mPostDialListeners.clear(); 331 } 332 333 protected final void notifyPostDialListeners() { 334 if (getPostDialState() == PostDialState.WAIT) { 335 for (PostDialListener listener : new ArrayList<>(mPostDialListeners)) { 336 listener.onPostDialWait(); 337 } 338 } 339 } 340 341 public abstract PostDialState getPostDialState(); 342 343 /** 344 * Returns the portion of the post dial string that has not 345 * yet been dialed, or "" if none 346 */ 347 public abstract String getRemainingPostDialString(); 348 349 /** 350 * See Phone.setOnPostDialWaitCharacter() 351 */ 352 353 public abstract void proceedAfterWaitChar(); 354 355 /** 356 * See Phone.setOnPostDialWildCharacter() 357 */ 358 public abstract void proceedAfterWildChar(String str); 359 /** 360 * Cancel any post 361 */ 362 public abstract void cancelPostDial(); 363 364 /** 365 * Returns the caller id presentation type for incoming and waiting calls 366 * @return one of PRESENTATION_* 367 */ 368 public abstract int getNumberPresentation(); 369 370 /** 371 * Returns the User to User Signaling (UUS) information associated with 372 * incoming and waiting calls 373 * @return UUSInfo containing the UUS userdata. 374 */ 375 public abstract UUSInfo getUUSInfo(); 376 377 /** 378 * Returns the CallFail reason provided by the RIL with the result of 379 * RIL_REQUEST_LAST_CALL_FAIL_CAUSE 380 */ 381 public abstract int getPreciseDisconnectCause(); 382 383 /** 384 * Returns the original Connection instance associated with 385 * this Connection 386 */ 387 public Connection getOrigConnection() { 388 return mOrigConnection; 389 } 390 391 /** 392 * Returns whether the original ImsPhoneConnection was a member 393 * of a conference call 394 * @return valid only when getOrigConnection() is not null 395 */ 396 public abstract boolean isMultiparty(); 397 398 public void migrateFrom(Connection c) { 399 if (c == null) return; 400 mListeners = c.mListeners; 401 mAddress = c.getAddress(); 402 mNumberPresentation = c.getNumberPresentation(); 403 mDialString = c.getOrigDialString(); 404 mCnapName = c.getCnapName(); 405 mCnapNamePresentation = c.getCnapNamePresentation(); 406 mIsIncoming = c.isIncoming(); 407 mCreateTime = c.getCreateTime(); 408 mConnectTime = c.getConnectTime(); 409 mConnectTimeReal = c.getConnectTimeReal(); 410 mHoldingStartTime = c.getHoldingStartTime(); 411 mOrigConnection = c.getOrigConnection(); 412 } 413 414 /** 415 * Assign a listener to be notified of state changes. 416 * 417 * @param listener A listener. 418 */ 419 public final void addListener(Listener listener) { 420 mListeners.add(listener); 421 } 422 423 /** 424 * Removes a listener. 425 * 426 * @param listener A listener. 427 */ 428 public final void removeListener(Listener listener) { 429 mListeners.remove(listener); 430 } 431 432 /** 433 * Returns the current video state of the connection. 434 * 435 * @return The video state of the connection. 436 */ 437 public int getVideoState() { 438 return mVideoState; 439 } 440 441 /** 442 * Returns the local video capability state for the connection. 443 * 444 * @return {@code True} if the connection has local video capabilities. 445 */ 446 public boolean isLocalVideoCapable() { 447 return mLocalVideoCapable; 448 } 449 450 /** 451 * Returns the remote video capability state for the connection. 452 * 453 * @return {@code True} if the connection has remote video capabilities. 454 */ 455 public boolean isRemoteVideoCapable() { 456 return mRemoteVideoCapable; 457 } 458 459 /** 460 * Returns the {@link android.telecom.Connection.VideoProvider} for the connection. 461 * 462 * @return The {@link android.telecom.Connection.VideoProvider}. 463 */ 464 public android.telecom.Connection.VideoProvider getVideoProvider() { 465 return mVideoProvider; 466 } 467 468 /** 469 * Returns the audio-quality for the connection. 470 * 471 * @return The audio quality for the connection. 472 */ 473 public int getAudioQuality() { 474 return mAudioQuality; 475 } 476 477 /** 478 * Sets the videoState for the current connection and reports the changes to all listeners. 479 * Valid video states are defined in {@link android.telecom.VideoProfile}. 480 * 481 * @return The video state. 482 */ 483 public void setVideoState(int videoState) { 484 mVideoState = videoState; 485 for (Listener l : mListeners) { 486 l.onVideoStateChanged(mVideoState); 487 } 488 } 489 490 /** 491 * Sets whether video capability is present locally. 492 * 493 * @param capable {@code True} if video capable. 494 */ 495 public void setLocalVideoCapable(boolean capable) { 496 mLocalVideoCapable = capable; 497 for (Listener l : mListeners) { 498 l.onLocalVideoCapabilityChanged(mLocalVideoCapable); 499 } 500 } 501 502 /** 503 * Sets whether video capability is present remotely. 504 * 505 * @param capable {@code True} if video capable. 506 */ 507 public void setRemoteVideoCapable(boolean capable) { 508 mRemoteVideoCapable = capable; 509 for (Listener l : mListeners) { 510 l.onRemoteVideoCapabilityChanged(mRemoteVideoCapable); 511 } 512 } 513 514 /** 515 * Set the audio quality for the connection. 516 * 517 * @param audioQuality The audio quality. 518 */ 519 public void setAudioQuality(int audioQuality) { 520 mAudioQuality = audioQuality; 521 for (Listener l : mListeners) { 522 l.onAudioQualityChanged(mAudioQuality); 523 } 524 } 525 526 /** 527 * Sets the {@link android.telecom.Connection.VideoProvider} for the connection. 528 * 529 * @param videoProvider The video call provider. 530 */ 531 public void setVideoProvider(android.telecom.Connection.VideoProvider videoProvider) { 532 mVideoProvider = videoProvider; 533 for (Listener l : mListeners) { 534 l.onVideoProviderChanged(mVideoProvider); 535 } 536 } 537 538 public void setConverted(String oriNumber) { 539 mNumberConverted = true; 540 mConvertedNumber = mAddress; 541 mAddress = oriNumber; 542 mDialString = oriNumber; 543 } 544 545 /** 546 * Build a human representation of a connection instance, suitable for debugging. 547 * Don't log personal stuff unless in debug mode. 548 * @return a string representing the internal state of this connection. 549 */ 550 public String toString() { 551 StringBuilder str = new StringBuilder(128); 552 553 if (Rlog.isLoggable(LOG_TAG, Log.DEBUG)) { 554 str.append("addr: " + getAddress()) 555 .append(" pres.: " + getNumberPresentation()) 556 .append(" dial: " + getOrigDialString()) 557 .append(" postdial: " + getRemainingPostDialString()) 558 .append(" cnap name: " + getCnapName()) 559 .append("(" + getCnapNamePresentation() + ")"); 560 } 561 str.append(" incoming: " + isIncoming()) 562 .append(" state: " + getState()) 563 .append(" post dial state: " + getPostDialState()); 564 return str.toString(); 565 } 566 } 567