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 17 package android.telecom; 18 19 import com.android.internal.telecom.IVideoCallback; 20 import com.android.internal.telecom.IVideoProvider; 21 22 import android.annotation.SystemApi; 23 import android.net.Uri; 24 import android.os.Handler; 25 import android.os.IBinder; 26 import android.os.Message; 27 import android.os.RemoteException; 28 import android.view.Surface; 29 30 import java.util.ArrayList; 31 import java.util.Collections; 32 import java.util.List; 33 import java.util.Set; 34 import java.util.concurrent.ConcurrentHashMap; 35 36 /** 37 * Represents a connection to a remote endpoint that carries voice traffic. 38 * <p> 39 * Implementations create a custom subclass of {@code Connection} and return it to the framework 40 * as the return value of 41 * {@link ConnectionService#onCreateIncomingConnection(PhoneAccountHandle, ConnectionRequest)} 42 * or 43 * {@link ConnectionService#onCreateOutgoingConnection(PhoneAccountHandle, ConnectionRequest)}. 44 * Implementations are then responsible for updating the state of the {@code Connection}, and 45 * must call {@link #destroy()} to signal to the framework that the {@code Connection} is no 46 * longer used and associated resources may be recovered. 47 * @hide 48 */ 49 @SystemApi 50 public abstract class Connection { 51 52 public static final int STATE_INITIALIZING = 0; 53 54 public static final int STATE_NEW = 1; 55 56 public static final int STATE_RINGING = 2; 57 58 public static final int STATE_DIALING = 3; 59 60 public static final int STATE_ACTIVE = 4; 61 62 public static final int STATE_HOLDING = 5; 63 64 public static final int STATE_DISCONNECTED = 6; 65 66 // Flag controlling whether PII is emitted into the logs 67 private static final boolean PII_DEBUG = Log.isLoggable(android.util.Log.DEBUG); 68 69 /** @hide */ 70 public abstract static class Listener { onStateChanged(Connection c, int state)71 public void onStateChanged(Connection c, int state) {} onAddressChanged(Connection c, Uri newAddress, int presentation)72 public void onAddressChanged(Connection c, Uri newAddress, int presentation) {} onCallerDisplayNameChanged( Connection c, String callerDisplayName, int presentation)73 public void onCallerDisplayNameChanged( 74 Connection c, String callerDisplayName, int presentation) {} onVideoStateChanged(Connection c, int videoState)75 public void onVideoStateChanged(Connection c, int videoState) {} onDisconnected(Connection c, DisconnectCause disconnectCause)76 public void onDisconnected(Connection c, DisconnectCause disconnectCause) {} onPostDialWait(Connection c, String remaining)77 public void onPostDialWait(Connection c, String remaining) {} onRingbackRequested(Connection c, boolean ringback)78 public void onRingbackRequested(Connection c, boolean ringback) {} onDestroyed(Connection c)79 public void onDestroyed(Connection c) {} onCallCapabilitiesChanged(Connection c, int callCapabilities)80 public void onCallCapabilitiesChanged(Connection c, int callCapabilities) {} onVideoProviderChanged( Connection c, VideoProvider videoProvider)81 public void onVideoProviderChanged( 82 Connection c, VideoProvider videoProvider) {} onAudioModeIsVoipChanged(Connection c, boolean isVoip)83 public void onAudioModeIsVoipChanged(Connection c, boolean isVoip) {} onStatusHintsChanged(Connection c, StatusHints statusHints)84 public void onStatusHintsChanged(Connection c, StatusHints statusHints) {} onConferenceableConnectionsChanged( Connection c, List<Connection> conferenceableConnections)85 public void onConferenceableConnectionsChanged( 86 Connection c, List<Connection> conferenceableConnections) {} onConferenceChanged(Connection c, Conference conference)87 public void onConferenceChanged(Connection c, Conference conference) {} 88 } 89 90 /** @hide */ 91 public static abstract class VideoProvider { 92 93 /** 94 * Video is not being received (no protocol pause was issued). 95 */ 96 public static final int SESSION_EVENT_RX_PAUSE = 1; 97 98 /** 99 * Video reception has resumed after a SESSION_EVENT_RX_PAUSE. 100 */ 101 public static final int SESSION_EVENT_RX_RESUME = 2; 102 103 /** 104 * Video transmission has begun. This occurs after a negotiated start of video transmission 105 * when the underlying protocol has actually begun transmitting video to the remote party. 106 */ 107 public static final int SESSION_EVENT_TX_START = 3; 108 109 /** 110 * Video transmission has stopped. This occurs after a negotiated stop of video transmission 111 * when the underlying protocol has actually stopped transmitting video to the remote party. 112 */ 113 public static final int SESSION_EVENT_TX_STOP = 4; 114 115 /** 116 * A camera failure has occurred for the selected camera. The In-Call UI can use this as a 117 * cue to inform the user the camera is not available. 118 */ 119 public static final int SESSION_EVENT_CAMERA_FAILURE = 5; 120 121 /** 122 * Issued after {@code SESSION_EVENT_CAMERA_FAILURE} when the camera is once again ready for 123 * operation. The In-Call UI can use this as a cue to inform the user that the camera has 124 * become available again. 125 */ 126 public static final int SESSION_EVENT_CAMERA_READY = 6; 127 128 /** 129 * Session modify request was successful. 130 */ 131 public static final int SESSION_MODIFY_REQUEST_SUCCESS = 1; 132 133 /** 134 * Session modify request failed. 135 */ 136 public static final int SESSION_MODIFY_REQUEST_FAIL = 2; 137 138 /** 139 * Session modify request ignored due to invalid parameters. 140 */ 141 public static final int SESSION_MODIFY_REQUEST_INVALID = 3; 142 143 private static final int MSG_SET_VIDEO_CALLBACK = 1; 144 private static final int MSG_SET_CAMERA = 2; 145 private static final int MSG_SET_PREVIEW_SURFACE = 3; 146 private static final int MSG_SET_DISPLAY_SURFACE = 4; 147 private static final int MSG_SET_DEVICE_ORIENTATION = 5; 148 private static final int MSG_SET_ZOOM = 6; 149 private static final int MSG_SEND_SESSION_MODIFY_REQUEST = 7; 150 private static final int MSG_SEND_SESSION_MODIFY_RESPONSE = 8; 151 private static final int MSG_REQUEST_CAMERA_CAPABILITIES = 9; 152 private static final int MSG_REQUEST_CALL_DATA_USAGE = 10; 153 private static final int MSG_SET_PAUSE_IMAGE = 11; 154 155 private final VideoProvider.VideoProviderHandler 156 mMessageHandler = new VideoProvider.VideoProviderHandler(); 157 private final VideoProvider.VideoProviderBinder mBinder; 158 private IVideoCallback mVideoCallback; 159 160 /** 161 * Default handler used to consolidate binder method calls onto a single thread. 162 */ 163 private final class VideoProviderHandler extends Handler { 164 @Override handleMessage(Message msg)165 public void handleMessage(Message msg) { 166 switch (msg.what) { 167 case MSG_SET_VIDEO_CALLBACK: 168 mVideoCallback = IVideoCallback.Stub.asInterface((IBinder) msg.obj); 169 break; 170 case MSG_SET_CAMERA: 171 onSetCamera((String) msg.obj); 172 break; 173 case MSG_SET_PREVIEW_SURFACE: 174 onSetPreviewSurface((Surface) msg.obj); 175 break; 176 case MSG_SET_DISPLAY_SURFACE: 177 onSetDisplaySurface((Surface) msg.obj); 178 break; 179 case MSG_SET_DEVICE_ORIENTATION: 180 onSetDeviceOrientation(msg.arg1); 181 break; 182 case MSG_SET_ZOOM: 183 onSetZoom((Float) msg.obj); 184 break; 185 case MSG_SEND_SESSION_MODIFY_REQUEST: 186 onSendSessionModifyRequest((VideoProfile) msg.obj); 187 break; 188 case MSG_SEND_SESSION_MODIFY_RESPONSE: 189 onSendSessionModifyResponse((VideoProfile) msg.obj); 190 break; 191 case MSG_REQUEST_CAMERA_CAPABILITIES: 192 onRequestCameraCapabilities(); 193 break; 194 case MSG_REQUEST_CALL_DATA_USAGE: 195 onRequestCallDataUsage(); 196 break; 197 case MSG_SET_PAUSE_IMAGE: 198 onSetPauseImage((String) msg.obj); 199 break; 200 default: 201 break; 202 } 203 } 204 } 205 206 /** 207 * IVideoProvider stub implementation. 208 */ 209 private final class VideoProviderBinder extends IVideoProvider.Stub { setVideoCallback(IBinder videoCallbackBinder)210 public void setVideoCallback(IBinder videoCallbackBinder) { 211 mMessageHandler.obtainMessage( 212 MSG_SET_VIDEO_CALLBACK, videoCallbackBinder).sendToTarget(); 213 } 214 setCamera(String cameraId)215 public void setCamera(String cameraId) { 216 mMessageHandler.obtainMessage(MSG_SET_CAMERA, cameraId).sendToTarget(); 217 } 218 setPreviewSurface(Surface surface)219 public void setPreviewSurface(Surface surface) { 220 mMessageHandler.obtainMessage(MSG_SET_PREVIEW_SURFACE, surface).sendToTarget(); 221 } 222 setDisplaySurface(Surface surface)223 public void setDisplaySurface(Surface surface) { 224 mMessageHandler.obtainMessage(MSG_SET_DISPLAY_SURFACE, surface).sendToTarget(); 225 } 226 setDeviceOrientation(int rotation)227 public void setDeviceOrientation(int rotation) { 228 mMessageHandler.obtainMessage(MSG_SET_DEVICE_ORIENTATION, rotation).sendToTarget(); 229 } 230 setZoom(float value)231 public void setZoom(float value) { 232 mMessageHandler.obtainMessage(MSG_SET_ZOOM, value).sendToTarget(); 233 } 234 sendSessionModifyRequest(VideoProfile requestProfile)235 public void sendSessionModifyRequest(VideoProfile requestProfile) { 236 mMessageHandler.obtainMessage( 237 MSG_SEND_SESSION_MODIFY_REQUEST, requestProfile).sendToTarget(); 238 } 239 sendSessionModifyResponse(VideoProfile responseProfile)240 public void sendSessionModifyResponse(VideoProfile responseProfile) { 241 mMessageHandler.obtainMessage( 242 MSG_SEND_SESSION_MODIFY_RESPONSE, responseProfile).sendToTarget(); 243 } 244 requestCameraCapabilities()245 public void requestCameraCapabilities() { 246 mMessageHandler.obtainMessage(MSG_REQUEST_CAMERA_CAPABILITIES).sendToTarget(); 247 } 248 requestCallDataUsage()249 public void requestCallDataUsage() { 250 mMessageHandler.obtainMessage(MSG_REQUEST_CALL_DATA_USAGE).sendToTarget(); 251 } 252 setPauseImage(String uri)253 public void setPauseImage(String uri) { 254 mMessageHandler.obtainMessage(MSG_SET_PAUSE_IMAGE, uri).sendToTarget(); 255 } 256 } 257 VideoProvider()258 public VideoProvider() { 259 mBinder = new VideoProvider.VideoProviderBinder(); 260 } 261 262 /** 263 * Returns binder object which can be used across IPC methods. 264 * @hide 265 */ getInterface()266 public final IVideoProvider getInterface() { 267 return mBinder; 268 } 269 270 /** 271 * Sets the camera to be used for video recording in a video call. 272 * 273 * @param cameraId The id of the camera. 274 */ onSetCamera(String cameraId)275 public abstract void onSetCamera(String cameraId); 276 277 /** 278 * Sets the surface to be used for displaying a preview of what the user's camera is 279 * currently capturing. When video transmission is enabled, this is the video signal which 280 * is sent to the remote device. 281 * 282 * @param surface The surface. 283 */ onSetPreviewSurface(Surface surface)284 public abstract void onSetPreviewSurface(Surface surface); 285 286 /** 287 * Sets the surface to be used for displaying the video received from the remote device. 288 * 289 * @param surface The surface. 290 */ onSetDisplaySurface(Surface surface)291 public abstract void onSetDisplaySurface(Surface surface); 292 293 /** 294 * Sets the device orientation, in degrees. Assumes that a standard portrait orientation of 295 * the device is 0 degrees. 296 * 297 * @param rotation The device orientation, in degrees. 298 */ onSetDeviceOrientation(int rotation)299 public abstract void onSetDeviceOrientation(int rotation); 300 301 /** 302 * Sets camera zoom ratio. 303 * 304 * @param value The camera zoom ratio. 305 */ onSetZoom(float value)306 public abstract void onSetZoom(float value); 307 308 /** 309 * Issues a request to modify the properties of the current session. The request is 310 * sent to the remote device where it it handled by the In-Call UI. 311 * Some examples of session modification requests: upgrade call from audio to video, 312 * downgrade call from video to audio, pause video. 313 * 314 * @param requestProfile The requested call video properties. 315 */ onSendSessionModifyRequest(VideoProfile requestProfile)316 public abstract void onSendSessionModifyRequest(VideoProfile requestProfile); 317 318 /**te 319 * Provides a response to a request to change the current call session video 320 * properties. 321 * This is in response to a request the InCall UI has received via the InCall UI. 322 * 323 * @param responseProfile The response call video properties. 324 */ onSendSessionModifyResponse(VideoProfile responseProfile)325 public abstract void onSendSessionModifyResponse(VideoProfile responseProfile); 326 327 /** 328 * Issues a request to the video provider to retrieve the camera capabilities. 329 * Camera capabilities are reported back to the caller via the In-Call UI. 330 */ onRequestCameraCapabilities()331 public abstract void onRequestCameraCapabilities(); 332 333 /** 334 * Issues a request to the video telephony framework to retrieve the cumulative data usage 335 * for the current call. Data usage is reported back to the caller via the 336 * InCall UI. 337 */ onRequestCallDataUsage()338 public abstract void onRequestCallDataUsage(); 339 340 /** 341 * Provides the video telephony framework with the URI of an image to be displayed to remote 342 * devices when the video signal is paused. 343 * 344 * @param uri URI of image to display. 345 */ onSetPauseImage(String uri)346 public abstract void onSetPauseImage(String uri); 347 348 /** 349 * Invokes callback method defined in In-Call UI. 350 * 351 * @param videoProfile The requested video call profile. 352 */ receiveSessionModifyRequest(VideoProfile videoProfile)353 public void receiveSessionModifyRequest(VideoProfile videoProfile) { 354 if (mVideoCallback != null) { 355 try { 356 mVideoCallback.receiveSessionModifyRequest(videoProfile); 357 } catch (RemoteException ignored) { 358 } 359 } 360 } 361 362 /** 363 * Invokes callback method defined in In-Call UI. 364 * 365 * @param status Status of the session modify request. Valid values are 366 * {@link VideoProvider#SESSION_MODIFY_REQUEST_SUCCESS}, 367 * {@link VideoProvider#SESSION_MODIFY_REQUEST_FAIL}, 368 * {@link VideoProvider#SESSION_MODIFY_REQUEST_INVALID} 369 * @param requestedProfile The original request which was sent to the remote device. 370 * @param responseProfile The actual profile changes made by the remote device. 371 */ receiveSessionModifyResponse(int status, VideoProfile requestedProfile, VideoProfile responseProfile)372 public void receiveSessionModifyResponse(int status, 373 VideoProfile requestedProfile, VideoProfile responseProfile) { 374 if (mVideoCallback != null) { 375 try { 376 mVideoCallback.receiveSessionModifyResponse( 377 status, requestedProfile, responseProfile); 378 } catch (RemoteException ignored) { 379 } 380 } 381 } 382 383 /** 384 * Invokes callback method defined in In-Call UI. 385 * 386 * Valid values are: {@link VideoProvider#SESSION_EVENT_RX_PAUSE}, 387 * {@link VideoProvider#SESSION_EVENT_RX_RESUME}, 388 * {@link VideoProvider#SESSION_EVENT_TX_START}, 389 * {@link VideoProvider#SESSION_EVENT_TX_STOP} 390 * 391 * @param event The event. 392 */ handleCallSessionEvent(int event)393 public void handleCallSessionEvent(int event) { 394 if (mVideoCallback != null) { 395 try { 396 mVideoCallback.handleCallSessionEvent(event); 397 } catch (RemoteException ignored) { 398 } 399 } 400 } 401 402 /** 403 * Invokes callback method defined in In-Call UI. 404 * 405 * @param width The updated peer video width. 406 * @param height The updated peer video height. 407 */ changePeerDimensions(int width, int height)408 public void changePeerDimensions(int width, int height) { 409 if (mVideoCallback != null) { 410 try { 411 mVideoCallback.changePeerDimensions(width, height); 412 } catch (RemoteException ignored) { 413 } 414 } 415 } 416 417 /** 418 * Invokes callback method defined in In-Call UI. 419 * 420 * @param dataUsage The updated data usage. 421 */ changeCallDataUsage(int dataUsage)422 public void changeCallDataUsage(int dataUsage) { 423 if (mVideoCallback != null) { 424 try { 425 mVideoCallback.changeCallDataUsage(dataUsage); 426 } catch (RemoteException ignored) { 427 } 428 } 429 } 430 431 /** 432 * Invokes callback method defined in In-Call UI. 433 * 434 * @param cameraCapabilities The changed camera capabilities. 435 */ changeCameraCapabilities(CameraCapabilities cameraCapabilities)436 public void changeCameraCapabilities(CameraCapabilities cameraCapabilities) { 437 if (mVideoCallback != null) { 438 try { 439 mVideoCallback.changeCameraCapabilities(cameraCapabilities); 440 } catch (RemoteException ignored) { 441 } 442 } 443 } 444 } 445 446 private final Listener mConnectionDeathListener = new Listener() { 447 @Override 448 public void onDestroyed(Connection c) { 449 if (mConferenceableConnections.remove(c)) { 450 fireOnConferenceableConnectionsChanged(); 451 } 452 } 453 }; 454 455 /** 456 * ConcurrentHashMap constructor params: 8 is initial table size, 0.9f is 457 * load factor before resizing, 1 means we only expect a single thread to 458 * access the map so make only a single shard 459 */ 460 private final Set<Listener> mListeners = Collections.newSetFromMap( 461 new ConcurrentHashMap<Listener, Boolean>(8, 0.9f, 1)); 462 private final List<Connection> mConferenceableConnections = new ArrayList<>(); 463 private final List<Connection> mUnmodifiableConferenceableConnections = 464 Collections.unmodifiableList(mConferenceableConnections); 465 466 private int mState = STATE_NEW; 467 private AudioState mAudioState; 468 private Uri mAddress; 469 private int mAddressPresentation; 470 private String mCallerDisplayName; 471 private int mCallerDisplayNamePresentation; 472 private boolean mRingbackRequested = false; 473 private int mCallCapabilities; 474 private VideoProvider mVideoProvider; 475 private boolean mAudioModeIsVoip; 476 private StatusHints mStatusHints; 477 private int mVideoState; 478 private DisconnectCause mDisconnectCause; 479 private Conference mConference; 480 private ConnectionService mConnectionService; 481 482 /** 483 * Create a new Connection. 484 */ Connection()485 public Connection() {} 486 487 /** 488 * @return The address (e.g., phone number) to which this Connection is currently communicating. 489 */ getAddress()490 public final Uri getAddress() { 491 return mAddress; 492 } 493 494 /** 495 * @return The presentation requirements for the address. 496 * See {@link TelecomManager} for valid values. 497 */ getAddressPresentation()498 public final int getAddressPresentation() { 499 return mAddressPresentation; 500 } 501 502 /** 503 * @return The caller display name (CNAP). 504 */ getCallerDisplayName()505 public final String getCallerDisplayName() { 506 return mCallerDisplayName; 507 } 508 509 /** 510 * @return The presentation requirements for the handle. 511 * See {@link TelecomManager} for valid values. 512 */ getCallerDisplayNamePresentation()513 public final int getCallerDisplayNamePresentation() { 514 return mCallerDisplayNamePresentation; 515 } 516 517 /** 518 * @return The state of this Connection. 519 */ getState()520 public final int getState() { 521 return mState; 522 } 523 524 /** 525 * Returns the video state of the call. 526 * Valid values: {@link VideoProfile.VideoState#AUDIO_ONLY}, 527 * {@link VideoProfile.VideoState#BIDIRECTIONAL}, 528 * {@link VideoProfile.VideoState#TX_ENABLED}, 529 * {@link VideoProfile.VideoState#RX_ENABLED}. 530 * 531 * @return The video state of the call. 532 * @hide 533 */ getVideoState()534 public final int getVideoState() { 535 return mVideoState; 536 } 537 538 /** 539 * @return The audio state of the call, describing how its audio is currently 540 * being routed by the system. This is {@code null} if this Connection 541 * does not directly know about its audio state. 542 */ getAudioState()543 public final AudioState getAudioState() { 544 return mAudioState; 545 } 546 547 /** 548 * @return The conference that this connection is a part of. Null if it is not part of any 549 * conference. 550 */ getConference()551 public final Conference getConference() { 552 return mConference; 553 } 554 555 /** 556 * Returns whether this connection is requesting that the system play a ringback tone 557 * on its behalf. 558 */ isRingbackRequested()559 public final boolean isRingbackRequested() { 560 return mRingbackRequested; 561 } 562 563 /** 564 * @return True if the connection's audio mode is VOIP. 565 */ getAudioModeIsVoip()566 public final boolean getAudioModeIsVoip() { 567 return mAudioModeIsVoip; 568 } 569 570 /** 571 * @return The status hints for this connection. 572 */ getStatusHints()573 public final StatusHints getStatusHints() { 574 return mStatusHints; 575 } 576 577 /** 578 * Assign a listener to be notified of state changes. 579 * 580 * @param l A listener. 581 * @return This Connection. 582 * 583 * @hide 584 */ addConnectionListener(Listener l)585 public final Connection addConnectionListener(Listener l) { 586 mListeners.add(l); 587 return this; 588 } 589 590 /** 591 * Remove a previously assigned listener that was being notified of state changes. 592 * 593 * @param l A Listener. 594 * @return This Connection. 595 * 596 * @hide 597 */ removeConnectionListener(Listener l)598 public final Connection removeConnectionListener(Listener l) { 599 if (l != null) { 600 mListeners.remove(l); 601 } 602 return this; 603 } 604 605 /** 606 * @return The {@link DisconnectCause} for this connection. 607 */ getDisconnectCause()608 public final DisconnectCause getDisconnectCause() { 609 return mDisconnectCause; 610 } 611 612 /** 613 * Inform this Connection that the state of its audio output has been changed externally. 614 * 615 * @param state The new audio state. 616 * @hide 617 */ setAudioState(AudioState state)618 final void setAudioState(AudioState state) { 619 Log.d(this, "setAudioState %s", state); 620 mAudioState = state; 621 onAudioStateChanged(state); 622 } 623 624 /** 625 * @param state An integer value of a {@code STATE_*} constant. 626 * @return A string representation of the value. 627 */ stateToString(int state)628 public static String stateToString(int state) { 629 switch (state) { 630 case STATE_INITIALIZING: 631 return "STATE_INITIALIZING"; 632 case STATE_NEW: 633 return "STATE_NEW"; 634 case STATE_RINGING: 635 return "STATE_RINGING"; 636 case STATE_DIALING: 637 return "STATE_DIALING"; 638 case STATE_ACTIVE: 639 return "STATE_ACTIVE"; 640 case STATE_HOLDING: 641 return "STATE_HOLDING"; 642 case STATE_DISCONNECTED: 643 return "DISCONNECTED"; 644 default: 645 Log.wtf(Connection.class, "Unknown state %d", state); 646 return "UNKNOWN"; 647 } 648 } 649 650 /** 651 * Returns the connection's {@link PhoneCapabilities} 652 */ getCallCapabilities()653 public final int getCallCapabilities() { 654 return mCallCapabilities; 655 } 656 657 /** 658 * Sets the value of the {@link #getAddress()} property. 659 * 660 * @param address The new address. 661 * @param presentation The presentation requirements for the address. 662 * See {@link TelecomManager} for valid values. 663 */ setAddress(Uri address, int presentation)664 public final void setAddress(Uri address, int presentation) { 665 Log.d(this, "setAddress %s", address); 666 mAddress = address; 667 mAddressPresentation = presentation; 668 for (Listener l : mListeners) { 669 l.onAddressChanged(this, address, presentation); 670 } 671 } 672 673 /** 674 * Sets the caller display name (CNAP). 675 * 676 * @param callerDisplayName The new display name. 677 * @param presentation The presentation requirements for the handle. 678 * See {@link TelecomManager} for valid values. 679 */ setCallerDisplayName(String callerDisplayName, int presentation)680 public final void setCallerDisplayName(String callerDisplayName, int presentation) { 681 Log.d(this, "setCallerDisplayName %s", callerDisplayName); 682 mCallerDisplayName = callerDisplayName; 683 mCallerDisplayNamePresentation = presentation; 684 for (Listener l : mListeners) { 685 l.onCallerDisplayNameChanged(this, callerDisplayName, presentation); 686 } 687 } 688 689 /** 690 * Set the video state for the connection. 691 * Valid values: {@link VideoProfile.VideoState#AUDIO_ONLY}, 692 * {@link VideoProfile.VideoState#BIDIRECTIONAL}, 693 * {@link VideoProfile.VideoState#TX_ENABLED}, 694 * {@link VideoProfile.VideoState#RX_ENABLED}. 695 * 696 * @param videoState The new video state. 697 * @hide 698 */ setVideoState(int videoState)699 public final void setVideoState(int videoState) { 700 Log.d(this, "setVideoState %d", videoState); 701 mVideoState = videoState; 702 for (Listener l : mListeners) { 703 l.onVideoStateChanged(this, mVideoState); 704 } 705 } 706 707 /** 708 * Sets state to active (e.g., an ongoing call where two or more parties can actively 709 * communicate). 710 */ setActive()711 public final void setActive() { 712 setRingbackRequested(false); 713 setState(STATE_ACTIVE); 714 } 715 716 /** 717 * Sets state to ringing (e.g., an inbound ringing call). 718 */ setRinging()719 public final void setRinging() { 720 setState(STATE_RINGING); 721 } 722 723 /** 724 * Sets state to initializing (this Connection is not yet ready to be used). 725 */ setInitializing()726 public final void setInitializing() { 727 setState(STATE_INITIALIZING); 728 } 729 730 /** 731 * Sets state to initialized (the Connection has been set up and is now ready to be used). 732 */ setInitialized()733 public final void setInitialized() { 734 setState(STATE_NEW); 735 } 736 737 /** 738 * Sets state to dialing (e.g., dialing an outbound call). 739 */ setDialing()740 public final void setDialing() { 741 setState(STATE_DIALING); 742 } 743 744 /** 745 * Sets state to be on hold. 746 */ setOnHold()747 public final void setOnHold() { 748 setState(STATE_HOLDING); 749 } 750 751 /** 752 * Sets the video call provider. 753 * @param videoProvider The video provider. 754 * @hide 755 */ setVideoProvider(VideoProvider videoProvider)756 public final void setVideoProvider(VideoProvider videoProvider) { 757 mVideoProvider = videoProvider; 758 for (Listener l : mListeners) { 759 l.onVideoProviderChanged(this, videoProvider); 760 } 761 } 762 763 /** @hide */ getVideoProvider()764 public final VideoProvider getVideoProvider() { 765 return mVideoProvider; 766 } 767 768 /** 769 * Sets state to disconnected. 770 * 771 * @param disconnectCause The reason for the disconnection, as specified by 772 * {@link DisconnectCause}. 773 */ setDisconnected(DisconnectCause disconnectCause)774 public final void setDisconnected(DisconnectCause disconnectCause) { 775 mDisconnectCause = disconnectCause; 776 setState(STATE_DISCONNECTED); 777 Log.d(this, "Disconnected with cause %s", disconnectCause); 778 for (Listener l : mListeners) { 779 l.onDisconnected(this, disconnectCause); 780 } 781 } 782 783 /** 784 * TODO: Needs documentation. 785 */ setPostDialWait(String remaining)786 public final void setPostDialWait(String remaining) { 787 for (Listener l : mListeners) { 788 l.onPostDialWait(this, remaining); 789 } 790 } 791 792 /** 793 * Requests that the framework play a ringback tone. This is to be invoked by implementations 794 * that do not play a ringback tone themselves in the call's audio stream. 795 * 796 * @param ringback Whether the ringback tone is to be played. 797 */ setRingbackRequested(boolean ringback)798 public final void setRingbackRequested(boolean ringback) { 799 if (mRingbackRequested != ringback) { 800 mRingbackRequested = ringback; 801 for (Listener l : mListeners) { 802 l.onRingbackRequested(this, ringback); 803 } 804 } 805 } 806 807 /** 808 * Sets the connection's {@link PhoneCapabilities}. 809 * 810 * @param callCapabilities The new call capabilities. 811 */ setCallCapabilities(int callCapabilities)812 public final void setCallCapabilities(int callCapabilities) { 813 if (mCallCapabilities != callCapabilities) { 814 mCallCapabilities = callCapabilities; 815 for (Listener l : mListeners) { 816 l.onCallCapabilitiesChanged(this, mCallCapabilities); 817 } 818 } 819 } 820 821 /** 822 * Tears down the Connection object. 823 */ destroy()824 public final void destroy() { 825 for (Listener l : mListeners) { 826 l.onDestroyed(this); 827 } 828 } 829 830 /** 831 * Requests that the framework use VOIP audio mode for this connection. 832 * 833 * @param isVoip True if the audio mode is VOIP. 834 */ setAudioModeIsVoip(boolean isVoip)835 public final void setAudioModeIsVoip(boolean isVoip) { 836 mAudioModeIsVoip = isVoip; 837 for (Listener l : mListeners) { 838 l.onAudioModeIsVoipChanged(this, isVoip); 839 } 840 } 841 842 /** 843 * Sets the label and icon status to display in the in-call UI. 844 * 845 * @param statusHints The status label and icon to set. 846 */ setStatusHints(StatusHints statusHints)847 public final void setStatusHints(StatusHints statusHints) { 848 mStatusHints = statusHints; 849 for (Listener l : mListeners) { 850 l.onStatusHintsChanged(this, statusHints); 851 } 852 } 853 854 /** 855 * Sets the connections with which this connection can be conferenced. 856 * 857 * @param conferenceableConnections The set of connections this connection can conference with. 858 */ setConferenceableConnections(List<Connection> conferenceableConnections)859 public final void setConferenceableConnections(List<Connection> conferenceableConnections) { 860 clearConferenceableList(); 861 for (Connection c : conferenceableConnections) { 862 // If statement checks for duplicates in input. It makes it N^2 but we're dealing with a 863 // small amount of items here. 864 if (!mConferenceableConnections.contains(c)) { 865 c.addConnectionListener(mConnectionDeathListener); 866 mConferenceableConnections.add(c); 867 } 868 } 869 fireOnConferenceableConnectionsChanged(); 870 } 871 872 /** 873 * Returns the connections with which this connection can be conferenced. 874 */ getConferenceableConnections()875 public final List<Connection> getConferenceableConnections() { 876 return mUnmodifiableConferenceableConnections; 877 } 878 879 /** 880 * @hide 881 */ setConnectionService(ConnectionService connectionService)882 public final void setConnectionService(ConnectionService connectionService) { 883 if (mConnectionService != null) { 884 Log.e(this, new Exception(), "Trying to set ConnectionService on a connection " + 885 "which is already associated with another ConnectionService."); 886 } else { 887 mConnectionService = connectionService; 888 } 889 } 890 891 /** 892 * @hide 893 */ unsetConnectionService(ConnectionService connectionService)894 public final void unsetConnectionService(ConnectionService connectionService) { 895 if (mConnectionService != connectionService) { 896 Log.e(this, new Exception(), "Trying to remove ConnectionService from a Connection " + 897 "that does not belong to the ConnectionService."); 898 } else { 899 mConnectionService = null; 900 } 901 } 902 903 /** 904 * @hide 905 */ getConnectionService()906 public final ConnectionService getConnectionService() { 907 return mConnectionService; 908 } 909 910 /** 911 * Sets the conference that this connection is a part of. This will fail if the connection is 912 * already part of a conference call. {@link #resetConference} to un-set the conference first. 913 * 914 * @param conference The conference. 915 * @return {@code true} if the conference was successfully set. 916 * @hide 917 */ setConference(Conference conference)918 public final boolean setConference(Conference conference) { 919 // We check to see if it is already part of another conference. 920 if (mConference == null) { 921 mConference = conference; 922 if (mConnectionService != null && mConnectionService.containsConference(conference)) { 923 fireConferenceChanged(); 924 } 925 return true; 926 } 927 return false; 928 } 929 930 /** 931 * Resets the conference that this connection is a part of. 932 * @hide 933 */ resetConference()934 public final void resetConference() { 935 if (mConference != null) { 936 Log.d(this, "Conference reset"); 937 mConference = null; 938 fireConferenceChanged(); 939 } 940 } 941 942 /** 943 * Notifies this Connection that the {@link #getAudioState()} property has a new value. 944 * 945 * @param state The new call audio state. 946 */ onAudioStateChanged(AudioState state)947 public void onAudioStateChanged(AudioState state) {} 948 949 /** 950 * Notifies this Connection of an internal state change. This method is called after the 951 * state is changed. 952 * 953 * @param state The new state, one of the {@code STATE_*} constants. 954 */ onStateChanged(int state)955 public void onStateChanged(int state) {} 956 957 /** 958 * Notifies this Connection of a request to play a DTMF tone. 959 * 960 * @param c A DTMF character. 961 */ onPlayDtmfTone(char c)962 public void onPlayDtmfTone(char c) {} 963 964 /** 965 * Notifies this Connection of a request to stop any currently playing DTMF tones. 966 */ onStopDtmfTone()967 public void onStopDtmfTone() {} 968 969 /** 970 * Notifies this Connection of a request to disconnect. 971 */ onDisconnect()972 public void onDisconnect() {} 973 974 /** 975 * Notifies this Connection of a request to separate from its parent conference. 976 */ onSeparate()977 public void onSeparate() {} 978 979 /** 980 * Notifies this Connection of a request to abort. 981 */ onAbort()982 public void onAbort() {} 983 984 /** 985 * Notifies this Connection of a request to hold. 986 */ onHold()987 public void onHold() {} 988 989 /** 990 * Notifies this Connection of a request to exit a hold state. 991 */ onUnhold()992 public void onUnhold() {} 993 994 /** 995 * Notifies this Connection, which is in {@link #STATE_RINGING}, of 996 * a request to accept. 997 * 998 * @param videoState The video state in which to answer the call. 999 * @hide 1000 */ onAnswer(int videoState)1001 public void onAnswer(int videoState) {} 1002 1003 /** 1004 * Notifies this Connection, which is in {@link #STATE_RINGING}, of 1005 * a request to accept. 1006 */ onAnswer()1007 public void onAnswer() { 1008 onAnswer(VideoProfile.VideoState.AUDIO_ONLY); 1009 } 1010 1011 /** 1012 * Notifies this Connection, which is in {@link #STATE_RINGING}, of 1013 * a request to reject. 1014 */ onReject()1015 public void onReject() {} 1016 1017 /** 1018 * Notifies this Connection whether the user wishes to proceed with the post-dial DTMF codes. 1019 */ onPostDialContinue(boolean proceed)1020 public void onPostDialContinue(boolean proceed) {} 1021 1022 /** 1023 * Merge this connection and the specified connection into a conference call. Once the 1024 * connections are merged, the calls should be added to the an existing or new 1025 * {@code Conference} instance. For new {@code Conference} instances, use 1026 * {@code ConnectionService#addConference}. 1027 * 1028 * @param otherConnection The connection with which this connection should be conferenced. 1029 */ onConferenceWith(Connection otherConnection)1030 public void onConferenceWith(Connection otherConnection) {} 1031 toLogSafePhoneNumber(String number)1032 static String toLogSafePhoneNumber(String number) { 1033 // For unknown number, log empty string. 1034 if (number == null) { 1035 return ""; 1036 } 1037 1038 if (PII_DEBUG) { 1039 // When PII_DEBUG is true we emit PII. 1040 return number; 1041 } 1042 1043 // Do exactly same thing as Uri#toSafeString() does, which will enable us to compare 1044 // sanitized phone numbers. 1045 StringBuilder builder = new StringBuilder(); 1046 for (int i = 0; i < number.length(); i++) { 1047 char c = number.charAt(i); 1048 if (c == '-' || c == '@' || c == '.') { 1049 builder.append(c); 1050 } else { 1051 builder.append('x'); 1052 } 1053 } 1054 return builder.toString(); 1055 } 1056 setState(int state)1057 private void setState(int state) { 1058 if (mState == STATE_DISCONNECTED && mState != state) { 1059 Log.d(this, "Connection already DISCONNECTED; cannot transition out of this state."); 1060 return; 1061 } 1062 if (mState != state) { 1063 Log.d(this, "setState: %s", stateToString(state)); 1064 mState = state; 1065 onStateChanged(state); 1066 for (Listener l : mListeners) { 1067 l.onStateChanged(this, state); 1068 } 1069 } 1070 } 1071 1072 private static class FailureSignalingConnection extends Connection { FailureSignalingConnection(DisconnectCause disconnectCause)1073 public FailureSignalingConnection(DisconnectCause disconnectCause) { 1074 setDisconnected(disconnectCause); 1075 } 1076 } 1077 1078 /** 1079 * Return a {@code Connection} which represents a failed connection attempt. The returned 1080 * {@code Connection} will have a {@link android.telecom.DisconnectCause} and as specified, 1081 * and a {@link #getState()} of {@link #STATE_DISCONNECTED}. 1082 * <p> 1083 * The returned {@code Connection} can be assumed to {@link #destroy()} itself when appropriate, 1084 * so users of this method need not maintain a reference to its return value to destroy it. 1085 * 1086 * @param disconnectCause The disconnect cause, ({@see android.telecomm.DisconnectCause}). 1087 * @return A {@code Connection} which indicates failure. 1088 */ createFailedConnection(DisconnectCause disconnectCause)1089 public static Connection createFailedConnection(DisconnectCause disconnectCause) { 1090 return new FailureSignalingConnection(disconnectCause); 1091 } 1092 1093 /** 1094 * Return a {@code Connection} which represents a canceled connection attempt. The returned 1095 * {@code Connection} will have state {@link #STATE_DISCONNECTED}, and cannot be moved out of 1096 * that state. This connection should not be used for anything, and no other 1097 * {@code Connection}s should be attempted. 1098 * <p> 1099 * The returned {@code Connection} can be assumed to {@link #destroy()} itself when appropriate, 1100 * so users of this method need not maintain a reference to its return value to destroy it. 1101 * 1102 * @return A {@code Connection} which indicates that the underlying call should be canceled. 1103 */ createCanceledConnection()1104 public static Connection createCanceledConnection() { 1105 return new FailureSignalingConnection(new DisconnectCause(DisconnectCause.CANCELED)); 1106 } 1107 fireOnConferenceableConnectionsChanged()1108 private final void fireOnConferenceableConnectionsChanged() { 1109 for (Listener l : mListeners) { 1110 l.onConferenceableConnectionsChanged(this, getConferenceableConnections()); 1111 } 1112 } 1113 fireConferenceChanged()1114 private final void fireConferenceChanged() { 1115 for (Listener l : mListeners) { 1116 l.onConferenceChanged(this, mConference); 1117 } 1118 } 1119 clearConferenceableList()1120 private final void clearConferenceableList() { 1121 for (Connection c : mConferenceableConnections) { 1122 c.removeConnectionListener(mConnectionDeathListener); 1123 } 1124 mConferenceableConnections.clear(); 1125 } 1126 } 1127