Connection.java revision 12ca74e2a0b26d1805b3caac9488961078b5409b
1/* 2 * Copyright (C) 2014 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package android.telecom; 18 19import com.android.internal.telecom.IVideoCallback; 20import com.android.internal.telecom.IVideoProvider; 21 22import android.annotation.SystemApi; 23import android.net.Uri; 24import android.os.Handler; 25import android.os.IBinder; 26import android.os.Message; 27import android.os.RemoteException; 28import android.view.Surface; 29 30import java.util.ArrayList; 31import java.util.Collections; 32import java.util.List; 33import java.util.Set; 34import 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 50public abstract class Connection implements IConferenceable { 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 /** Connection can currently be put on hold or unheld. */ 67 public static final int CAPABILITY_HOLD = 0x00000001; 68 69 /** Connection supports the hold feature. */ 70 public static final int CAPABILITY_SUPPORT_HOLD = 0x00000002; 71 72 /** 73 * Connections within a conference can be merged. A {@link ConnectionService} has the option to 74 * add a {@link Conference} before the child {@link Connection}s are merged. This is how 75 * CDMA-based {@link Connection}s are implemented. For these unmerged {@link Conference}s, this 76 * capability allows a merge button to be shown while the conference is in the foreground 77 * of the in-call UI. 78 * <p> 79 * This is only intended for use by a {@link Conference}. 80 */ 81 public static final int CAPABILITY_MERGE_CONFERENCE = 0x00000004; 82 83 /** 84 * Connections within a conference can be swapped between foreground and background. 85 * See {@link #CAPABILITY_MERGE_CONFERENCE} for additional information. 86 * <p> 87 * This is only intended for use by a {@link Conference}. 88 */ 89 public static final int CAPABILITY_SWAP_CONFERENCE = 0x00000008; 90 91 /** 92 * @hide 93 */ 94 public static final int CAPABILITY_UNUSED = 0x00000010; 95 96 /** Connection supports responding via text option. */ 97 public static final int CAPABILITY_RESPOND_VIA_TEXT = 0x00000020; 98 99 /** Connection can be muted. */ 100 public static final int CAPABILITY_MUTE = 0x00000040; 101 102 /** 103 * Connection supports conference management. This capability only applies to 104 * {@link Conference}s which can have {@link Connection}s as children. 105 */ 106 public static final int CAPABILITY_MANAGE_CONFERENCE = 0x00000080; 107 108 /** 109 * Local device supports video telephony. 110 * @hide 111 */ 112 public static final int CAPABILITY_SUPPORTS_VT_LOCAL = 0x00000100; 113 114 /** 115 * Remote device supports video telephony. 116 * @hide 117 */ 118 public static final int CAPABILITY_SUPPORTS_VT_REMOTE = 0x00000200; 119 120 /** 121 * Connection is using high definition audio. 122 * @hide 123 */ 124 public static final int CAPABILITY_HIGH_DEF_AUDIO = 0x00000400; 125 126 /** 127 * Connection is using voice over WIFI. 128 * @hide 129 */ 130 public static final int CAPABILITY_VoWIFI = 0x00000800; 131 132 /** 133 * Connection is able to be separated from its parent {@code Conference}, if any. 134 */ 135 public static final int CAPABILITY_SEPARATE_FROM_CONFERENCE = 0x00001000; 136 137 /** 138 * Connection is able to be individually disconnected when in a {@code Conference}. 139 */ 140 public static final int CAPABILITY_DISCONNECT_FROM_CONFERENCE = 0x00002000; 141 142 /** 143 * Whether the call is a generic conference, where we do not know the precise state of 144 * participants in the conference (eg. on CDMA). 145 * 146 * @hide 147 */ 148 public static final int CAPABILITY_GENERIC_CONFERENCE = 0x00004000; 149 150 // Flag controlling whether PII is emitted into the logs 151 private static final boolean PII_DEBUG = Log.isLoggable(android.util.Log.DEBUG); 152 153 /** 154 * Whether the given capabilities support the specified capability. 155 * 156 * @param capabilities A capability bit field. 157 * @param capability The capability to check capabilities for. 158 * @return Whether the specified capability is supported. 159 * @hide 160 */ 161 public static boolean can(int capabilities, int capability) { 162 return (capabilities & capability) != 0; 163 } 164 165 /** 166 * Whether the capabilities of this {@code Connection} supports the specified capability. 167 * 168 * @param capability The capability to check capabilities for. 169 * @return Whether the specified capability is supported. 170 * @hide 171 */ 172 public boolean can(int capability) { 173 return can(mConnectionCapabilities, capability); 174 } 175 176 /** 177 * Removes the specified capability from the set of capabilities of this {@code Connection}. 178 * 179 * @param capability The capability to remove from the set. 180 * @hide 181 */ 182 public void removeCapability(int capability) { 183 mConnectionCapabilities &= ~capability; 184 } 185 186 /** 187 * Adds the specified capability to the set of capabilities of this {@code Connection}. 188 * 189 * @param capability The capability to add to the set. 190 * @hide 191 */ 192 public void addCapability(int capability) { 193 mConnectionCapabilities |= capability; 194 } 195 196 197 public static String capabilitiesToString(int capabilities) { 198 StringBuilder builder = new StringBuilder(); 199 builder.append("[Capabilities:"); 200 if (can(capabilities, CAPABILITY_HOLD)) { 201 builder.append(" CAPABILITY_HOLD"); 202 } 203 if (can(capabilities, CAPABILITY_SUPPORT_HOLD)) { 204 builder.append(" CAPABILITY_SUPPORT_HOLD"); 205 } 206 if (can(capabilities, CAPABILITY_MERGE_CONFERENCE)) { 207 builder.append(" CAPABILITY_MERGE_CONFERENCE"); 208 } 209 if (can(capabilities, CAPABILITY_SWAP_CONFERENCE)) { 210 builder.append(" CAPABILITY_SWAP_CONFERENCE"); 211 } 212 if (can(capabilities, CAPABILITY_RESPOND_VIA_TEXT)) { 213 builder.append(" CAPABILITY_RESPOND_VIA_TEXT"); 214 } 215 if (can(capabilities, CAPABILITY_MUTE)) { 216 builder.append(" CAPABILITY_MUTE"); 217 } 218 if (can(capabilities, CAPABILITY_MANAGE_CONFERENCE)) { 219 builder.append(" CAPABILITY_MANAGE_CONFERENCE"); 220 } 221 if (can(capabilities, CAPABILITY_SUPPORTS_VT_LOCAL)) { 222 builder.append(" CAPABILITY_SUPPORTS_VT_LOCAL"); 223 } 224 if (can(capabilities, CAPABILITY_SUPPORTS_VT_REMOTE)) { 225 builder.append(" CAPABILITY_SUPPORTS_VT_REMOTE"); 226 } 227 if (can(capabilities, CAPABILITY_HIGH_DEF_AUDIO)) { 228 builder.append(" CAPABILITY_HIGH_DEF_AUDIO"); 229 } 230 if (can(capabilities, CAPABILITY_VoWIFI)) { 231 builder.append(" CAPABILITY_VoWIFI"); 232 } 233 if (can(capabilities, CAPABILITY_GENERIC_CONFERENCE)) { 234 builder.append(" CAPABILITY_GENERIC_CONFERENCE"); 235 } 236 builder.append("]"); 237 return builder.toString(); 238 } 239 240 /** @hide */ 241 public abstract static class Listener { 242 public void onStateChanged(Connection c, int state) {} 243 public void onAddressChanged(Connection c, Uri newAddress, int presentation) {} 244 public void onCallerDisplayNameChanged( 245 Connection c, String callerDisplayName, int presentation) {} 246 public void onVideoStateChanged(Connection c, int videoState) {} 247 public void onDisconnected(Connection c, DisconnectCause disconnectCause) {} 248 public void onPostDialWait(Connection c, String remaining) {} 249 public void onPostDialChar(Connection c, char nextChar) {} 250 public void onRingbackRequested(Connection c, boolean ringback) {} 251 public void onDestroyed(Connection c) {} 252 public void onConnectionCapabilitiesChanged(Connection c, int capabilities) {} 253 public void onVideoProviderChanged( 254 Connection c, VideoProvider videoProvider) {} 255 public void onAudioModeIsVoipChanged(Connection c, boolean isVoip) {} 256 public void onStatusHintsChanged(Connection c, StatusHints statusHints) {} 257 public void onConferenceablesChanged( 258 Connection c, List<IConferenceable> conferenceables) {} 259 public void onConferenceChanged(Connection c, Conference conference) {} 260 /** @hide */ 261 public void onConferenceParticipantsChanged(Connection c, 262 List<ConferenceParticipant> participants) {} 263 } 264 265 /** @hide */ 266 public static abstract class VideoProvider { 267 268 /** 269 * Video is not being received (no protocol pause was issued). 270 */ 271 public static final int SESSION_EVENT_RX_PAUSE = 1; 272 273 /** 274 * Video reception has resumed after a SESSION_EVENT_RX_PAUSE. 275 */ 276 public static final int SESSION_EVENT_RX_RESUME = 2; 277 278 /** 279 * Video transmission has begun. This occurs after a negotiated start of video transmission 280 * when the underlying protocol has actually begun transmitting video to the remote party. 281 */ 282 public static final int SESSION_EVENT_TX_START = 3; 283 284 /** 285 * Video transmission has stopped. This occurs after a negotiated stop of video transmission 286 * when the underlying protocol has actually stopped transmitting video to the remote party. 287 */ 288 public static final int SESSION_EVENT_TX_STOP = 4; 289 290 /** 291 * A camera failure has occurred for the selected camera. The In-Call UI can use this as a 292 * cue to inform the user the camera is not available. 293 */ 294 public static final int SESSION_EVENT_CAMERA_FAILURE = 5; 295 296 /** 297 * Issued after {@code SESSION_EVENT_CAMERA_FAILURE} when the camera is once again ready for 298 * operation. The In-Call UI can use this as a cue to inform the user that the camera has 299 * become available again. 300 */ 301 public static final int SESSION_EVENT_CAMERA_READY = 6; 302 303 /** 304 * Session modify request was successful. 305 */ 306 public static final int SESSION_MODIFY_REQUEST_SUCCESS = 1; 307 308 /** 309 * Session modify request failed. 310 */ 311 public static final int SESSION_MODIFY_REQUEST_FAIL = 2; 312 313 /** 314 * Session modify request ignored due to invalid parameters. 315 */ 316 public static final int SESSION_MODIFY_REQUEST_INVALID = 3; 317 318 private static final int MSG_SET_VIDEO_CALLBACK = 1; 319 private static final int MSG_SET_CAMERA = 2; 320 private static final int MSG_SET_PREVIEW_SURFACE = 3; 321 private static final int MSG_SET_DISPLAY_SURFACE = 4; 322 private static final int MSG_SET_DEVICE_ORIENTATION = 5; 323 private static final int MSG_SET_ZOOM = 6; 324 private static final int MSG_SEND_SESSION_MODIFY_REQUEST = 7; 325 private static final int MSG_SEND_SESSION_MODIFY_RESPONSE = 8; 326 private static final int MSG_REQUEST_CAMERA_CAPABILITIES = 9; 327 private static final int MSG_REQUEST_CONNECTION_DATA_USAGE = 10; 328 private static final int MSG_SET_PAUSE_IMAGE = 11; 329 330 private final VideoProvider.VideoProviderHandler 331 mMessageHandler = new VideoProvider.VideoProviderHandler(); 332 private final VideoProvider.VideoProviderBinder mBinder; 333 private IVideoCallback mVideoCallback; 334 335 /** 336 * Default handler used to consolidate binder method calls onto a single thread. 337 */ 338 private final class VideoProviderHandler extends Handler { 339 @Override 340 public void handleMessage(Message msg) { 341 switch (msg.what) { 342 case MSG_SET_VIDEO_CALLBACK: 343 mVideoCallback = IVideoCallback.Stub.asInterface((IBinder) msg.obj); 344 break; 345 case MSG_SET_CAMERA: 346 onSetCamera((String) msg.obj); 347 break; 348 case MSG_SET_PREVIEW_SURFACE: 349 onSetPreviewSurface((Surface) msg.obj); 350 break; 351 case MSG_SET_DISPLAY_SURFACE: 352 onSetDisplaySurface((Surface) msg.obj); 353 break; 354 case MSG_SET_DEVICE_ORIENTATION: 355 onSetDeviceOrientation(msg.arg1); 356 break; 357 case MSG_SET_ZOOM: 358 onSetZoom((Float) msg.obj); 359 break; 360 case MSG_SEND_SESSION_MODIFY_REQUEST: 361 onSendSessionModifyRequest((VideoProfile) msg.obj); 362 break; 363 case MSG_SEND_SESSION_MODIFY_RESPONSE: 364 onSendSessionModifyResponse((VideoProfile) msg.obj); 365 break; 366 case MSG_REQUEST_CAMERA_CAPABILITIES: 367 onRequestCameraCapabilities(); 368 break; 369 case MSG_REQUEST_CONNECTION_DATA_USAGE: 370 onRequestConnectionDataUsage(); 371 break; 372 case MSG_SET_PAUSE_IMAGE: 373 onSetPauseImage((String) msg.obj); 374 break; 375 default: 376 break; 377 } 378 } 379 } 380 381 /** 382 * IVideoProvider stub implementation. 383 */ 384 private final class VideoProviderBinder extends IVideoProvider.Stub { 385 public void setVideoCallback(IBinder videoCallbackBinder) { 386 mMessageHandler.obtainMessage( 387 MSG_SET_VIDEO_CALLBACK, videoCallbackBinder).sendToTarget(); 388 } 389 390 public void setCamera(String cameraId) { 391 mMessageHandler.obtainMessage(MSG_SET_CAMERA, cameraId).sendToTarget(); 392 } 393 394 public void setPreviewSurface(Surface surface) { 395 mMessageHandler.obtainMessage(MSG_SET_PREVIEW_SURFACE, surface).sendToTarget(); 396 } 397 398 public void setDisplaySurface(Surface surface) { 399 mMessageHandler.obtainMessage(MSG_SET_DISPLAY_SURFACE, surface).sendToTarget(); 400 } 401 402 public void setDeviceOrientation(int rotation) { 403 mMessageHandler.obtainMessage(MSG_SET_DEVICE_ORIENTATION, rotation).sendToTarget(); 404 } 405 406 public void setZoom(float value) { 407 mMessageHandler.obtainMessage(MSG_SET_ZOOM, value).sendToTarget(); 408 } 409 410 public void sendSessionModifyRequest(VideoProfile requestProfile) { 411 mMessageHandler.obtainMessage( 412 MSG_SEND_SESSION_MODIFY_REQUEST, requestProfile).sendToTarget(); 413 } 414 415 public void sendSessionModifyResponse(VideoProfile responseProfile) { 416 mMessageHandler.obtainMessage( 417 MSG_SEND_SESSION_MODIFY_RESPONSE, responseProfile).sendToTarget(); 418 } 419 420 public void requestCameraCapabilities() { 421 mMessageHandler.obtainMessage(MSG_REQUEST_CAMERA_CAPABILITIES).sendToTarget(); 422 } 423 424 public void requestCallDataUsage() { 425 mMessageHandler.obtainMessage(MSG_REQUEST_CONNECTION_DATA_USAGE).sendToTarget(); 426 } 427 428 public void setPauseImage(String uri) { 429 mMessageHandler.obtainMessage(MSG_SET_PAUSE_IMAGE, uri).sendToTarget(); 430 } 431 } 432 433 public VideoProvider() { 434 mBinder = new VideoProvider.VideoProviderBinder(); 435 } 436 437 /** 438 * Returns binder object which can be used across IPC methods. 439 * @hide 440 */ 441 public final IVideoProvider getInterface() { 442 return mBinder; 443 } 444 445 /** 446 * Sets the camera to be used for video recording in a video connection. 447 * 448 * @param cameraId The id of the camera. 449 */ 450 public abstract void onSetCamera(String cameraId); 451 452 /** 453 * Sets the surface to be used for displaying a preview of what the user's camera is 454 * currently capturing. When video transmission is enabled, this is the video signal which 455 * is sent to the remote device. 456 * 457 * @param surface The surface. 458 */ 459 public abstract void onSetPreviewSurface(Surface surface); 460 461 /** 462 * Sets the surface to be used for displaying the video received from the remote device. 463 * 464 * @param surface The surface. 465 */ 466 public abstract void onSetDisplaySurface(Surface surface); 467 468 /** 469 * Sets the device orientation, in degrees. Assumes that a standard portrait orientation of 470 * the device is 0 degrees. 471 * 472 * @param rotation The device orientation, in degrees. 473 */ 474 public abstract void onSetDeviceOrientation(int rotation); 475 476 /** 477 * Sets camera zoom ratio. 478 * 479 * @param value The camera zoom ratio. 480 */ 481 public abstract void onSetZoom(float value); 482 483 /** 484 * Issues a request to modify the properties of the current session. The request is 485 * sent to the remote device where it it handled by the In-Call UI. 486 * Some examples of session modification requests: upgrade connection from audio to video, 487 * downgrade connection from video to audio, pause video. 488 * 489 * @param requestProfile The requested connection video properties. 490 */ 491 public abstract void onSendSessionModifyRequest(VideoProfile requestProfile); 492 493 /**te 494 * Provides a response to a request to change the current connection session video 495 * properties. 496 * This is in response to a request the InCall UI has received via the InCall UI. 497 * 498 * @param responseProfile The response connection video properties. 499 */ 500 public abstract void onSendSessionModifyResponse(VideoProfile responseProfile); 501 502 /** 503 * Issues a request to the video provider to retrieve the camera capabilities. 504 * Camera capabilities are reported back to the caller via the In-Call UI. 505 */ 506 public abstract void onRequestCameraCapabilities(); 507 508 /** 509 * Issues a request to the video telephony framework to retrieve the cumulative data usage 510 * for the current connection. Data usage is reported back to the caller via the 511 * InCall UI. 512 */ 513 public abstract void onRequestConnectionDataUsage(); 514 515 /** 516 * Provides the video telephony framework with the URI of an image to be displayed to remote 517 * devices when the video signal is paused. 518 * 519 * @param uri URI of image to display. 520 */ 521 public abstract void onSetPauseImage(String uri); 522 523 /** 524 * Invokes callback method defined in In-Call UI. 525 * 526 * @param videoProfile The requested video connection profile. 527 */ 528 public void receiveSessionModifyRequest(VideoProfile videoProfile) { 529 if (mVideoCallback != null) { 530 try { 531 mVideoCallback.receiveSessionModifyRequest(videoProfile); 532 } catch (RemoteException ignored) { 533 } 534 } 535 } 536 537 /** 538 * Invokes callback method defined in In-Call UI. 539 * 540 * @param status Status of the session modify request. Valid values are 541 * {@link VideoProvider#SESSION_MODIFY_REQUEST_SUCCESS}, 542 * {@link VideoProvider#SESSION_MODIFY_REQUEST_FAIL}, 543 * {@link VideoProvider#SESSION_MODIFY_REQUEST_INVALID} 544 * @param requestedProfile The original request which was sent to the remote device. 545 * @param responseProfile The actual profile changes made by the remote device. 546 */ 547 public void receiveSessionModifyResponse(int status, 548 VideoProfile requestedProfile, VideoProfile responseProfile) { 549 if (mVideoCallback != null) { 550 try { 551 mVideoCallback.receiveSessionModifyResponse( 552 status, requestedProfile, responseProfile); 553 } catch (RemoteException ignored) { 554 } 555 } 556 } 557 558 /** 559 * Invokes callback method defined in In-Call UI. 560 * 561 * Valid values are: {@link VideoProvider#SESSION_EVENT_RX_PAUSE}, 562 * {@link VideoProvider#SESSION_EVENT_RX_RESUME}, 563 * {@link VideoProvider#SESSION_EVENT_TX_START}, 564 * {@link VideoProvider#SESSION_EVENT_TX_STOP} 565 * 566 * @param event The event. 567 */ 568 public void handleCallSessionEvent(int event) { 569 if (mVideoCallback != null) { 570 try { 571 mVideoCallback.handleCallSessionEvent(event); 572 } catch (RemoteException ignored) { 573 } 574 } 575 } 576 577 /** 578 * Invokes callback method defined in In-Call UI. 579 * 580 * @param width The updated peer video width. 581 * @param height The updated peer video height. 582 */ 583 public void changePeerDimensions(int width, int height) { 584 if (mVideoCallback != null) { 585 try { 586 mVideoCallback.changePeerDimensions(width, height); 587 } catch (RemoteException ignored) { 588 } 589 } 590 } 591 592 /** 593 * Invokes callback method defined in In-Call UI. 594 * 595 * @param dataUsage The updated data usage. 596 */ 597 public void changeCallDataUsage(int dataUsage) { 598 if (mVideoCallback != null) { 599 try { 600 mVideoCallback.changeCallDataUsage(dataUsage); 601 } catch (RemoteException ignored) { 602 } 603 } 604 } 605 606 /** 607 * Invokes callback method defined in In-Call UI. 608 * 609 * @param cameraCapabilities The changed camera capabilities. 610 */ 611 public void changeCameraCapabilities(CameraCapabilities cameraCapabilities) { 612 if (mVideoCallback != null) { 613 try { 614 mVideoCallback.changeCameraCapabilities(cameraCapabilities); 615 } catch (RemoteException ignored) { 616 } 617 } 618 } 619 } 620 621 private final Listener mConnectionDeathListener = new Listener() { 622 @Override 623 public void onDestroyed(Connection c) { 624 if (mConferenceables.remove(c)) { 625 fireOnConferenceableConnectionsChanged(); 626 } 627 } 628 }; 629 630 private final Conference.Listener mConferenceDeathListener = new Conference.Listener() { 631 @Override 632 public void onDestroyed(Conference c) { 633 if (mConferenceables.remove(c)) { 634 fireOnConferenceableConnectionsChanged(); 635 } 636 } 637 }; 638 639 /** 640 * ConcurrentHashMap constructor params: 8 is initial table size, 0.9f is 641 * load factor before resizing, 1 means we only expect a single thread to 642 * access the map so make only a single shard 643 */ 644 private final Set<Listener> mListeners = Collections.newSetFromMap( 645 new ConcurrentHashMap<Listener, Boolean>(8, 0.9f, 1)); 646 private final List<IConferenceable> mConferenceables = new ArrayList<>(); 647 private final List<IConferenceable> mUnmodifiableConferenceables = 648 Collections.unmodifiableList(mConferenceables); 649 650 private int mState = STATE_NEW; 651 private AudioState mAudioState; 652 private Uri mAddress; 653 private int mAddressPresentation; 654 private String mCallerDisplayName; 655 private int mCallerDisplayNamePresentation; 656 private boolean mRingbackRequested = false; 657 private int mConnectionCapabilities; 658 private VideoProvider mVideoProvider; 659 private boolean mAudioModeIsVoip; 660 private StatusHints mStatusHints; 661 private int mVideoState; 662 private DisconnectCause mDisconnectCause; 663 private Conference mConference; 664 private ConnectionService mConnectionService; 665 666 /** 667 * Create a new Connection. 668 */ 669 public Connection() {} 670 671 /** 672 * @return The address (e.g., phone number) to which this Connection is currently communicating. 673 */ 674 public final Uri getAddress() { 675 return mAddress; 676 } 677 678 /** 679 * @return The presentation requirements for the address. 680 * See {@link TelecomManager} for valid values. 681 */ 682 public final int getAddressPresentation() { 683 return mAddressPresentation; 684 } 685 686 /** 687 * @return The caller display name (CNAP). 688 */ 689 public final String getCallerDisplayName() { 690 return mCallerDisplayName; 691 } 692 693 /** 694 * @return The presentation requirements for the handle. 695 * See {@link TelecomManager} for valid values. 696 */ 697 public final int getCallerDisplayNamePresentation() { 698 return mCallerDisplayNamePresentation; 699 } 700 701 /** 702 * @return The state of this Connection. 703 */ 704 public final int getState() { 705 return mState; 706 } 707 708 /** 709 * Returns the video state of the connection. 710 * Valid values: {@link VideoProfile.VideoState#AUDIO_ONLY}, 711 * {@link VideoProfile.VideoState#BIDIRECTIONAL}, 712 * {@link VideoProfile.VideoState#TX_ENABLED}, 713 * {@link VideoProfile.VideoState#RX_ENABLED}. 714 * 715 * @return The video state of the connection. 716 * @hide 717 */ 718 public final int getVideoState() { 719 return mVideoState; 720 } 721 722 /** 723 * @return The audio state of the connection, describing how its audio is currently 724 * being routed by the system. This is {@code null} if this Connection 725 * does not directly know about its audio state. 726 */ 727 public final AudioState getAudioState() { 728 return mAudioState; 729 } 730 731 /** 732 * @return The conference that this connection is a part of. Null if it is not part of any 733 * conference. 734 */ 735 public final Conference getConference() { 736 return mConference; 737 } 738 739 /** 740 * Returns whether this connection is requesting that the system play a ringback tone 741 * on its behalf. 742 */ 743 public final boolean isRingbackRequested() { 744 return mRingbackRequested; 745 } 746 747 /** 748 * @return True if the connection's audio mode is VOIP. 749 */ 750 public final boolean getAudioModeIsVoip() { 751 return mAudioModeIsVoip; 752 } 753 754 /** 755 * @return The status hints for this connection. 756 */ 757 public final StatusHints getStatusHints() { 758 return mStatusHints; 759 } 760 761 /** 762 * Assign a listener to be notified of state changes. 763 * 764 * @param l A listener. 765 * @return This Connection. 766 * 767 * @hide 768 */ 769 public final Connection addConnectionListener(Listener l) { 770 mListeners.add(l); 771 return this; 772 } 773 774 /** 775 * Remove a previously assigned listener that was being notified of state changes. 776 * 777 * @param l A Listener. 778 * @return This Connection. 779 * 780 * @hide 781 */ 782 public final Connection removeConnectionListener(Listener l) { 783 if (l != null) { 784 mListeners.remove(l); 785 } 786 return this; 787 } 788 789 /** 790 * @return The {@link DisconnectCause} for this connection. 791 */ 792 public final DisconnectCause getDisconnectCause() { 793 return mDisconnectCause; 794 } 795 796 /** 797 * Inform this Connection that the state of its audio output has been changed externally. 798 * 799 * @param state The new audio state. 800 * @hide 801 */ 802 final void setAudioState(AudioState state) { 803 checkImmutable(); 804 Log.d(this, "setAudioState %s", state); 805 mAudioState = state; 806 onAudioStateChanged(state); 807 } 808 809 /** 810 * @param state An integer value of a {@code STATE_*} constant. 811 * @return A string representation of the value. 812 */ 813 public static String stateToString(int state) { 814 switch (state) { 815 case STATE_INITIALIZING: 816 return "STATE_INITIALIZING"; 817 case STATE_NEW: 818 return "STATE_NEW"; 819 case STATE_RINGING: 820 return "STATE_RINGING"; 821 case STATE_DIALING: 822 return "STATE_DIALING"; 823 case STATE_ACTIVE: 824 return "STATE_ACTIVE"; 825 case STATE_HOLDING: 826 return "STATE_HOLDING"; 827 case STATE_DISCONNECTED: 828 return "DISCONNECTED"; 829 default: 830 Log.wtf(Connection.class, "Unknown state %d", state); 831 return "UNKNOWN"; 832 } 833 } 834 835 /** 836 * Returns the connection's capabilities, as a bit mask of the {@code CAPABILITY_*} constants. 837 */ 838 public final int getConnectionCapabilities() { 839 return mConnectionCapabilities; 840 } 841 842 /** @hide */ 843 @SystemApi @Deprecated public final int getCallCapabilities() { 844 return getConnectionCapabilities(); 845 } 846 847 /** 848 * Sets the value of the {@link #getAddress()} property. 849 * 850 * @param address The new address. 851 * @param presentation The presentation requirements for the address. 852 * See {@link TelecomManager} for valid values. 853 */ 854 public final void setAddress(Uri address, int presentation) { 855 checkImmutable(); 856 Log.d(this, "setAddress %s", address); 857 mAddress = address; 858 mAddressPresentation = presentation; 859 for (Listener l : mListeners) { 860 l.onAddressChanged(this, address, presentation); 861 } 862 } 863 864 /** 865 * Sets the caller display name (CNAP). 866 * 867 * @param callerDisplayName The new display name. 868 * @param presentation The presentation requirements for the handle. 869 * See {@link TelecomManager} for valid values. 870 */ 871 public final void setCallerDisplayName(String callerDisplayName, int presentation) { 872 checkImmutable(); 873 Log.d(this, "setCallerDisplayName %s", callerDisplayName); 874 mCallerDisplayName = callerDisplayName; 875 mCallerDisplayNamePresentation = presentation; 876 for (Listener l : mListeners) { 877 l.onCallerDisplayNameChanged(this, callerDisplayName, presentation); 878 } 879 } 880 881 /** 882 * Set the video state for the connection. 883 * Valid values: {@link VideoProfile.VideoState#AUDIO_ONLY}, 884 * {@link VideoProfile.VideoState#BIDIRECTIONAL}, 885 * {@link VideoProfile.VideoState#TX_ENABLED}, 886 * {@link VideoProfile.VideoState#RX_ENABLED}. 887 * 888 * @param videoState The new video state. 889 * @hide 890 */ 891 public final void setVideoState(int videoState) { 892 checkImmutable(); 893 Log.d(this, "setVideoState %d", videoState); 894 mVideoState = videoState; 895 for (Listener l : mListeners) { 896 l.onVideoStateChanged(this, mVideoState); 897 } 898 } 899 900 /** 901 * Sets state to active (e.g., an ongoing connection where two or more parties can actively 902 * communicate). 903 */ 904 public final void setActive() { 905 checkImmutable(); 906 setRingbackRequested(false); 907 setState(STATE_ACTIVE); 908 } 909 910 /** 911 * Sets state to ringing (e.g., an inbound ringing connection). 912 */ 913 public final void setRinging() { 914 checkImmutable(); 915 setState(STATE_RINGING); 916 } 917 918 /** 919 * Sets state to initializing (this Connection is not yet ready to be used). 920 */ 921 public final void setInitializing() { 922 checkImmutable(); 923 setState(STATE_INITIALIZING); 924 } 925 926 /** 927 * Sets state to initialized (the Connection has been set up and is now ready to be used). 928 */ 929 public final void setInitialized() { 930 checkImmutable(); 931 setState(STATE_NEW); 932 } 933 934 /** 935 * Sets state to dialing (e.g., dialing an outbound connection). 936 */ 937 public final void setDialing() { 938 checkImmutable(); 939 setState(STATE_DIALING); 940 } 941 942 /** 943 * Sets state to be on hold. 944 */ 945 public final void setOnHold() { 946 checkImmutable(); 947 setState(STATE_HOLDING); 948 } 949 950 /** 951 * Sets the video connection provider. 952 * @param videoProvider The video provider. 953 * @hide 954 */ 955 public final void setVideoProvider(VideoProvider videoProvider) { 956 checkImmutable(); 957 mVideoProvider = videoProvider; 958 for (Listener l : mListeners) { 959 l.onVideoProviderChanged(this, videoProvider); 960 } 961 } 962 963 /** @hide */ 964 public final VideoProvider getVideoProvider() { 965 return mVideoProvider; 966 } 967 968 /** 969 * Sets state to disconnected. 970 * 971 * @param disconnectCause The reason for the disconnection, as specified by 972 * {@link DisconnectCause}. 973 */ 974 public final void setDisconnected(DisconnectCause disconnectCause) { 975 checkImmutable(); 976 mDisconnectCause = disconnectCause; 977 setState(STATE_DISCONNECTED); 978 Log.d(this, "Disconnected with cause %s", disconnectCause); 979 for (Listener l : mListeners) { 980 l.onDisconnected(this, disconnectCause); 981 } 982 } 983 984 /** 985 * Informs listeners that this {@code Connection} is in a post-dial wait state. This is done 986 * when (a) the {@code Connection} is issuing a DTMF sequence; (b) it has encountered a "wait" 987 * character; and (c) it wishes to inform the In-Call app that it is waiting for the end-user 988 * to send an {@link #onPostDialContinue(boolean)} signal. 989 * 990 * @param remaining The DTMF character sequence remaining to be emitted once the 991 * {@link #onPostDialContinue(boolean)} is received, including any "wait" characters 992 * that remaining sequence may contain. 993 */ 994 public final void setPostDialWait(String remaining) { 995 checkImmutable(); 996 for (Listener l : mListeners) { 997 l.onPostDialWait(this, remaining); 998 } 999 } 1000 1001 /** 1002 * Informs listeners that this {@code Connection} has processed a character in the post-dial 1003 * started state. This is done when (a) the {@code Connection} is issuing a DTMF sequence; 1004 * (b) it has encountered a "wait" character; and (c) it wishes to signal Telecom to play 1005 * the corresponding DTMF tone locally. 1006 * 1007 * @param nextChar The DTMF character that was just processed by the {@code Connection}. 1008 * 1009 * @hide 1010 */ 1011 public final void setNextPostDialWaitChar(char nextChar) { 1012 checkImmutable(); 1013 for (Listener l : mListeners) { 1014 l.onPostDialChar(this, nextChar); 1015 } 1016 } 1017 1018 /** 1019 * Requests that the framework play a ringback tone. This is to be invoked by implementations 1020 * that do not play a ringback tone themselves in the connection's audio stream. 1021 * 1022 * @param ringback Whether the ringback tone is to be played. 1023 */ 1024 public final void setRingbackRequested(boolean ringback) { 1025 checkImmutable(); 1026 if (mRingbackRequested != ringback) { 1027 mRingbackRequested = ringback; 1028 for (Listener l : mListeners) { 1029 l.onRingbackRequested(this, ringback); 1030 } 1031 } 1032 } 1033 1034 /** @hide */ 1035 @SystemApi @Deprecated public final void setCallCapabilities(int connectionCapabilities) { 1036 setConnectionCapabilities(connectionCapabilities); 1037 } 1038 1039 /** 1040 * Sets the connection's capabilities as a bit mask of the {@code CAPABILITY_*} constants. 1041 * 1042 * @param connectionCapabilities The new connection capabilities. 1043 */ 1044 public final void setConnectionCapabilities(int connectionCapabilities) { 1045 checkImmutable(); 1046 if (mConnectionCapabilities != connectionCapabilities) { 1047 mConnectionCapabilities = connectionCapabilities; 1048 for (Listener l : mListeners) { 1049 l.onConnectionCapabilitiesChanged(this, mConnectionCapabilities); 1050 } 1051 } 1052 } 1053 1054 /** 1055 * Tears down the Connection object. 1056 */ 1057 public final void destroy() { 1058 for (Listener l : mListeners) { 1059 l.onDestroyed(this); 1060 } 1061 } 1062 1063 /** 1064 * Requests that the framework use VOIP audio mode for this connection. 1065 * 1066 * @param isVoip True if the audio mode is VOIP. 1067 */ 1068 public final void setAudioModeIsVoip(boolean isVoip) { 1069 checkImmutable(); 1070 mAudioModeIsVoip = isVoip; 1071 for (Listener l : mListeners) { 1072 l.onAudioModeIsVoipChanged(this, isVoip); 1073 } 1074 } 1075 1076 /** 1077 * Sets the label and icon status to display in the in-call UI. 1078 * 1079 * @param statusHints The status label and icon to set. 1080 */ 1081 public final void setStatusHints(StatusHints statusHints) { 1082 checkImmutable(); 1083 mStatusHints = statusHints; 1084 for (Listener l : mListeners) { 1085 l.onStatusHintsChanged(this, statusHints); 1086 } 1087 } 1088 1089 /** 1090 * Sets the connections with which this connection can be conferenced. 1091 * 1092 * @param conferenceableConnections The set of connections this connection can conference with. 1093 */ 1094 public final void setConferenceableConnections(List<Connection> conferenceableConnections) { 1095 checkImmutable(); 1096 clearConferenceableList(); 1097 for (Connection c : conferenceableConnections) { 1098 // If statement checks for duplicates in input. It makes it N^2 but we're dealing with a 1099 // small amount of items here. 1100 if (!mConferenceables.contains(c)) { 1101 c.addConnectionListener(mConnectionDeathListener); 1102 mConferenceables.add(c); 1103 } 1104 } 1105 fireOnConferenceableConnectionsChanged(); 1106 } 1107 1108 /** 1109 * Similar to {@link #setConferenceableConnections(java.util.List)}, sets a list of connections 1110 * or conferences with which this connection can be conferenced. 1111 * 1112 * @param conferenceables The conferenceables. 1113 */ 1114 public final void setConferenceables(List<IConferenceable> conferenceables) { 1115 clearConferenceableList(); 1116 for (IConferenceable c : conferenceables) { 1117 // If statement checks for duplicates in input. It makes it N^2 but we're dealing with a 1118 // small amount of items here. 1119 if (!mConferenceables.contains(c)) { 1120 if (c instanceof Connection) { 1121 Connection connection = (Connection) c; 1122 connection.addConnectionListener(mConnectionDeathListener); 1123 } else if (c instanceof Conference) { 1124 Conference conference = (Conference) c; 1125 conference.addListener(mConferenceDeathListener); 1126 } 1127 mConferenceables.add(c); 1128 } 1129 } 1130 fireOnConferenceableConnectionsChanged(); 1131 } 1132 1133 /** 1134 * Returns the connections or conferences with which this connection can be conferenced. 1135 */ 1136 public final List<IConferenceable> getConferenceables() { 1137 return mUnmodifiableConferenceables; 1138 } 1139 1140 /* 1141 * @hide 1142 */ 1143 public final void setConnectionService(ConnectionService connectionService) { 1144 checkImmutable(); 1145 if (mConnectionService != null) { 1146 Log.e(this, new Exception(), "Trying to set ConnectionService on a connection " + 1147 "which is already associated with another ConnectionService."); 1148 } else { 1149 mConnectionService = connectionService; 1150 } 1151 } 1152 1153 /** 1154 * @hide 1155 */ 1156 public final void unsetConnectionService(ConnectionService connectionService) { 1157 if (mConnectionService != connectionService) { 1158 Log.e(this, new Exception(), "Trying to remove ConnectionService from a Connection " + 1159 "that does not belong to the ConnectionService."); 1160 } else { 1161 mConnectionService = null; 1162 } 1163 } 1164 1165 /** 1166 * @hide 1167 */ 1168 public final ConnectionService getConnectionService() { 1169 return mConnectionService; 1170 } 1171 1172 /** 1173 * Sets the conference that this connection is a part of. This will fail if the connection is 1174 * already part of a conference. {@link #resetConference} to un-set the conference first. 1175 * 1176 * @param conference The conference. 1177 * @return {@code true} if the conference was successfully set. 1178 * @hide 1179 */ 1180 public final boolean setConference(Conference conference) { 1181 checkImmutable(); 1182 // We check to see if it is already part of another conference. 1183 if (mConference == null) { 1184 mConference = conference; 1185 if (mConnectionService != null && mConnectionService.containsConference(conference)) { 1186 fireConferenceChanged(); 1187 } 1188 return true; 1189 } 1190 return false; 1191 } 1192 1193 /** 1194 * Resets the conference that this connection is a part of. 1195 * @hide 1196 */ 1197 public final void resetConference() { 1198 if (mConference != null) { 1199 Log.d(this, "Conference reset"); 1200 mConference = null; 1201 fireConferenceChanged(); 1202 } 1203 } 1204 1205 /** 1206 * Notifies this Connection that the {@link #getAudioState()} property has a new value. 1207 * 1208 * @param state The new connection audio state. 1209 */ 1210 public void onAudioStateChanged(AudioState state) {} 1211 1212 /** 1213 * Notifies this Connection of an internal state change. This method is called after the 1214 * state is changed. 1215 * 1216 * @param state The new state, one of the {@code STATE_*} constants. 1217 */ 1218 public void onStateChanged(int state) {} 1219 1220 /** 1221 * Notifies this Connection of a request to play a DTMF tone. 1222 * 1223 * @param c A DTMF character. 1224 */ 1225 public void onPlayDtmfTone(char c) {} 1226 1227 /** 1228 * Notifies this Connection of a request to stop any currently playing DTMF tones. 1229 */ 1230 public void onStopDtmfTone() {} 1231 1232 /** 1233 * Notifies this Connection of a request to disconnect. 1234 */ 1235 public void onDisconnect() {} 1236 1237 /** 1238 * Notifies this Connection of a request to disconnect a participant of the conference managed 1239 * by the connection. 1240 * 1241 * @param endpoint the {@link Uri} of the participant to disconnect. 1242 * @hide 1243 */ 1244 public void onDisconnectConferenceParticipant(Uri endpoint) {} 1245 1246 /** 1247 * Notifies this Connection of a request to separate from its parent conference. 1248 */ 1249 public void onSeparate() {} 1250 1251 /** 1252 * Notifies this Connection of a request to abort. 1253 */ 1254 public void onAbort() {} 1255 1256 /** 1257 * Notifies this Connection of a request to hold. 1258 */ 1259 public void onHold() {} 1260 1261 /** 1262 * Notifies this Connection of a request to exit a hold state. 1263 */ 1264 public void onUnhold() {} 1265 1266 /** 1267 * Notifies this Connection, which is in {@link #STATE_RINGING}, of 1268 * a request to accept. 1269 * 1270 * @param videoState The video state in which to answer the connection. 1271 * @hide 1272 */ 1273 public void onAnswer(int videoState) {} 1274 1275 /** 1276 * Notifies this Connection, which is in {@link #STATE_RINGING}, of 1277 * a request to accept. 1278 */ 1279 public void onAnswer() { 1280 onAnswer(VideoProfile.VideoState.AUDIO_ONLY); 1281 } 1282 1283 /** 1284 * Notifies this Connection, which is in {@link #STATE_RINGING}, of 1285 * a request to reject. 1286 */ 1287 public void onReject() {} 1288 1289 /** 1290 * Notifies this Connection whether the user wishes to proceed with the post-dial DTMF codes. 1291 */ 1292 public void onPostDialContinue(boolean proceed) {} 1293 1294 static String toLogSafePhoneNumber(String number) { 1295 // For unknown number, log empty string. 1296 if (number == null) { 1297 return ""; 1298 } 1299 1300 if (PII_DEBUG) { 1301 // When PII_DEBUG is true we emit PII. 1302 return number; 1303 } 1304 1305 // Do exactly same thing as Uri#toSafeString() does, which will enable us to compare 1306 // sanitized phone numbers. 1307 StringBuilder builder = new StringBuilder(); 1308 for (int i = 0; i < number.length(); i++) { 1309 char c = number.charAt(i); 1310 if (c == '-' || c == '@' || c == '.') { 1311 builder.append(c); 1312 } else { 1313 builder.append('x'); 1314 } 1315 } 1316 return builder.toString(); 1317 } 1318 1319 private void setState(int state) { 1320 checkImmutable(); 1321 if (mState == STATE_DISCONNECTED && mState != state) { 1322 Log.d(this, "Connection already DISCONNECTED; cannot transition out of this state."); 1323 return; 1324 } 1325 if (mState != state) { 1326 Log.d(this, "setState: %s", stateToString(state)); 1327 mState = state; 1328 onStateChanged(state); 1329 for (Listener l : mListeners) { 1330 l.onStateChanged(this, state); 1331 } 1332 } 1333 } 1334 1335 private static class FailureSignalingConnection extends Connection { 1336 private boolean mImmutable = false; 1337 public FailureSignalingConnection(DisconnectCause disconnectCause) { 1338 setDisconnected(disconnectCause); 1339 mImmutable = true; 1340 } 1341 1342 public void checkImmutable() { 1343 if (mImmutable) { 1344 throw new UnsupportedOperationException("Connection is immutable"); 1345 } 1346 } 1347 } 1348 1349 /** 1350 * Return a {@code Connection} which represents a failed connection attempt. The returned 1351 * {@code Connection} will have a {@link android.telecom.DisconnectCause} and as specified, 1352 * and a {@link #getState()} of {@link #STATE_DISCONNECTED}. 1353 * <p> 1354 * The returned {@code Connection} can be assumed to {@link #destroy()} itself when appropriate, 1355 * so users of this method need not maintain a reference to its return value to destroy it. 1356 * 1357 * @param disconnectCause The disconnect cause, ({@see android.telecomm.DisconnectCause}). 1358 * @return A {@code Connection} which indicates failure. 1359 */ 1360 public static Connection createFailedConnection(DisconnectCause disconnectCause) { 1361 return new FailureSignalingConnection(disconnectCause); 1362 } 1363 1364 /** 1365 * Override to throw an {@link UnsupportedOperationException} if this {@code Connection} is 1366 * not intended to be mutated, e.g., if it is a marker for failure. Only for framework use; 1367 * this should never be un-@hide-den. 1368 * 1369 * @hide 1370 */ 1371 public void checkImmutable() {} 1372 1373 /** 1374 * Return a {@code Connection} which represents a canceled connection attempt. The returned 1375 * {@code Connection} will have state {@link #STATE_DISCONNECTED}, and cannot be moved out of 1376 * that state. This connection should not be used for anything, and no other 1377 * {@code Connection}s should be attempted. 1378 * <p> 1379 * so users of this method need not maintain a reference to its return value to destroy it. 1380 * 1381 * @return A {@code Connection} which indicates that the underlying connection should 1382 * be canceled. 1383 */ 1384 public static Connection createCanceledConnection() { 1385 return new FailureSignalingConnection(new DisconnectCause(DisconnectCause.CANCELED)); 1386 } 1387 1388 private final void fireOnConferenceableConnectionsChanged() { 1389 for (Listener l : mListeners) { 1390 l.onConferenceablesChanged(this, getConferenceables()); 1391 } 1392 } 1393 1394 private final void fireConferenceChanged() { 1395 for (Listener l : mListeners) { 1396 l.onConferenceChanged(this, mConference); 1397 } 1398 } 1399 1400 private final void clearConferenceableList() { 1401 for (IConferenceable c : mConferenceables) { 1402 if (c instanceof Connection) { 1403 Connection connection = (Connection) c; 1404 connection.removeConnectionListener(mConnectionDeathListener); 1405 } else if (c instanceof Conference) { 1406 Conference conference = (Conference) c; 1407 conference.removeListener(mConferenceDeathListener); 1408 } 1409 } 1410 mConferenceables.clear(); 1411 } 1412 1413 /** 1414 * Notifies listeners of a change to conference participant(s). 1415 * 1416 * @param conferenceParticipants The participants. 1417 * @hide 1418 */ 1419 protected final void updateConferenceParticipants( 1420 List<ConferenceParticipant> conferenceParticipants) { 1421 for (Listener l : mListeners) { 1422 l.onConferenceParticipantsChanged(this, conferenceParticipants); 1423 } 1424 } 1425} 1426