Connection.java revision 87b73f370e2b8a76b0540580f43edba6ec21c6cf
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.os.SomeArgs; 20import com.android.internal.telecom.IVideoCallback; 21import com.android.internal.telecom.IVideoProvider; 22 23import android.annotation.Nullable; 24import android.annotation.SystemApi; 25import android.hardware.camera2.CameraManager; 26import android.net.Uri; 27import android.os.Bundle; 28import android.os.Handler; 29import android.os.IBinder; 30import android.os.Message; 31import android.os.RemoteException; 32import android.view.Surface; 33 34import java.util.ArrayList; 35import java.util.Collections; 36import java.util.HashMap; 37import java.util.List; 38import java.util.Set; 39import java.util.concurrent.ConcurrentHashMap; 40 41/** 42 * Represents a connection to a remote endpoint that carries voice traffic. 43 * <p> 44 * Implementations create a custom subclass of {@code Connection} and return it to the framework 45 * as the return value of 46 * {@link ConnectionService#onCreateIncomingConnection(PhoneAccountHandle, ConnectionRequest)} 47 * or 48 * {@link ConnectionService#onCreateOutgoingConnection(PhoneAccountHandle, ConnectionRequest)}. 49 * Implementations are then responsible for updating the state of the {@code Connection}, and 50 * must call {@link #destroy()} to signal to the framework that the {@code Connection} is no 51 * longer used and associated resources may be recovered. 52 */ 53public abstract class Connection extends Conferenceable { 54 55 public static final int STATE_INITIALIZING = 0; 56 57 public static final int STATE_NEW = 1; 58 59 public static final int STATE_RINGING = 2; 60 61 public static final int STATE_DIALING = 3; 62 63 public static final int STATE_ACTIVE = 4; 64 65 public static final int STATE_HOLDING = 5; 66 67 public static final int STATE_DISCONNECTED = 6; 68 69 /** Connection can currently be put on hold or unheld. */ 70 public static final int CAPABILITY_HOLD = 0x00000001; 71 72 /** Connection supports the hold feature. */ 73 public static final int CAPABILITY_SUPPORT_HOLD = 0x00000002; 74 75 /** 76 * Connections within a conference can be merged. A {@link ConnectionService} has the option to 77 * add a {@link Conference} before the child {@link Connection}s are merged. This is how 78 * CDMA-based {@link Connection}s are implemented. For these unmerged {@link Conference}s, this 79 * capability allows a merge button to be shown while the conference is in the foreground 80 * of the in-call UI. 81 * <p> 82 * This is only intended for use by a {@link Conference}. 83 */ 84 public static final int CAPABILITY_MERGE_CONFERENCE = 0x00000004; 85 86 /** 87 * Connections within a conference can be swapped between foreground and background. 88 * See {@link #CAPABILITY_MERGE_CONFERENCE} for additional information. 89 * <p> 90 * This is only intended for use by a {@link Conference}. 91 */ 92 public static final int CAPABILITY_SWAP_CONFERENCE = 0x00000008; 93 94 /** 95 * @hide 96 */ 97 public static final int CAPABILITY_UNUSED = 0x00000010; 98 99 /** Connection supports responding via text option. */ 100 public static final int CAPABILITY_RESPOND_VIA_TEXT = 0x00000020; 101 102 /** Connection can be muted. */ 103 public static final int CAPABILITY_MUTE = 0x00000040; 104 105 /** 106 * Connection supports conference management. This capability only applies to 107 * {@link Conference}s which can have {@link Connection}s as children. 108 */ 109 public static final int CAPABILITY_MANAGE_CONFERENCE = 0x00000080; 110 111 /** 112 * Local device supports receiving video. 113 */ 114 public static final int CAPABILITY_SUPPORTS_VT_LOCAL_RX = 0x00000100; 115 116 /** 117 * Local device supports transmitting video. 118 */ 119 public static final int CAPABILITY_SUPPORTS_VT_LOCAL_TX = 0x00000200; 120 121 /** 122 * Local device supports bidirectional video calling. 123 */ 124 public static final int CAPABILITY_SUPPORTS_VT_LOCAL_BIDIRECTIONAL = 125 CAPABILITY_SUPPORTS_VT_LOCAL_RX | CAPABILITY_SUPPORTS_VT_LOCAL_TX; 126 127 /** 128 * Remote device supports receiving video. 129 */ 130 public static final int CAPABILITY_SUPPORTS_VT_REMOTE_RX = 0x00000400; 131 132 /** 133 * Remote device supports transmitting video. 134 */ 135 public static final int CAPABILITY_SUPPORTS_VT_REMOTE_TX = 0x00000800; 136 137 /** 138 * Remote device supports bidirectional video calling. 139 */ 140 public static final int CAPABILITY_SUPPORTS_VT_REMOTE_BIDIRECTIONAL = 141 CAPABILITY_SUPPORTS_VT_REMOTE_RX | CAPABILITY_SUPPORTS_VT_REMOTE_TX; 142 143 /** 144 * Connection is able to be separated from its parent {@code Conference}, if any. 145 */ 146 public static final int CAPABILITY_SEPARATE_FROM_CONFERENCE = 0x00001000; 147 148 /** 149 * Connection is able to be individually disconnected when in a {@code Conference}. 150 */ 151 public static final int CAPABILITY_DISCONNECT_FROM_CONFERENCE = 0x00002000; 152 153 /** 154 * Whether the call is a generic conference, where we do not know the precise state of 155 * participants in the conference (eg. on CDMA). 156 * 157 * @hide 158 */ 159 public static final int CAPABILITY_GENERIC_CONFERENCE = 0x00004000; 160 161 /** 162 * Connection is using high definition audio. 163 * @hide 164 */ 165 public static final int CAPABILITY_HIGH_DEF_AUDIO = 0x00008000; 166 167 /** 168 * Connection is using WIFI. 169 * @hide 170 */ 171 public static final int CAPABILITY_WIFI = 0x00010000; 172 173 /** 174 * Indicates that the current device callback number should be shown. 175 * 176 * @hide 177 */ 178 public static final int CAPABILITY_SHOW_CALLBACK_NUMBER = 0x00020000; 179 180 /** 181 * Speed up audio setup for MT call. 182 * @hide 183 */ 184 public static final int CAPABILITY_SPEED_UP_MT_AUDIO = 0x00040000; 185 186 /** 187 * Call can be upgraded to a video call. 188 */ 189 public static final int CAPABILITY_CAN_UPGRADE_TO_VIDEO = 0x00080000; 190 191 /** 192 * For video calls, indicates whether the outgoing video for the call can be paused using 193 * the {@link android.telecom.VideoProfile#STATE_PAUSED} VideoState. 194 */ 195 public static final int CAPABILITY_CAN_PAUSE_VIDEO = 0x00100000; 196 197 //********************************************************************************************** 198 // Next CAPABILITY value: 0x00200000 199 //********************************************************************************************** 200 201 // Flag controlling whether PII is emitted into the logs 202 private static final boolean PII_DEBUG = Log.isLoggable(android.util.Log.DEBUG); 203 204 /** 205 * Whether the given capabilities support the specified capability. 206 * 207 * @param capabilities A capability bit field. 208 * @param capability The capability to check capabilities for. 209 * @return Whether the specified capability is supported. 210 * @hide 211 */ 212 public static boolean can(int capabilities, int capability) { 213 return (capabilities & capability) != 0; 214 } 215 216 /** 217 * Whether the capabilities of this {@code Connection} supports the specified capability. 218 * 219 * @param capability The capability to check capabilities for. 220 * @return Whether the specified capability is supported. 221 * @hide 222 */ 223 public boolean can(int capability) { 224 return can(mConnectionCapabilities, capability); 225 } 226 227 /** 228 * Removes the specified capability from the set of capabilities of this {@code Connection}. 229 * 230 * @param capability The capability to remove from the set. 231 * @hide 232 */ 233 public void removeCapability(int capability) { 234 mConnectionCapabilities &= ~capability; 235 } 236 237 /** 238 * Adds the specified capability to the set of capabilities of this {@code Connection}. 239 * 240 * @param capability The capability to add to the set. 241 * @hide 242 */ 243 public void addCapability(int capability) { 244 mConnectionCapabilities |= capability; 245 } 246 247 248 public static String capabilitiesToString(int capabilities) { 249 StringBuilder builder = new StringBuilder(); 250 builder.append("[Capabilities:"); 251 if (can(capabilities, CAPABILITY_HOLD)) { 252 builder.append(" CAPABILITY_HOLD"); 253 } 254 if (can(capabilities, CAPABILITY_SUPPORT_HOLD)) { 255 builder.append(" CAPABILITY_SUPPORT_HOLD"); 256 } 257 if (can(capabilities, CAPABILITY_MERGE_CONFERENCE)) { 258 builder.append(" CAPABILITY_MERGE_CONFERENCE"); 259 } 260 if (can(capabilities, CAPABILITY_SWAP_CONFERENCE)) { 261 builder.append(" CAPABILITY_SWAP_CONFERENCE"); 262 } 263 if (can(capabilities, CAPABILITY_RESPOND_VIA_TEXT)) { 264 builder.append(" CAPABILITY_RESPOND_VIA_TEXT"); 265 } 266 if (can(capabilities, CAPABILITY_MUTE)) { 267 builder.append(" CAPABILITY_MUTE"); 268 } 269 if (can(capabilities, CAPABILITY_MANAGE_CONFERENCE)) { 270 builder.append(" CAPABILITY_MANAGE_CONFERENCE"); 271 } 272 if (can(capabilities, CAPABILITY_SUPPORTS_VT_LOCAL_RX)) { 273 builder.append(" CAPABILITY_SUPPORTS_VT_LOCAL_RX"); 274 } 275 if (can(capabilities, CAPABILITY_SUPPORTS_VT_LOCAL_TX)) { 276 builder.append(" CAPABILITY_SUPPORTS_VT_LOCAL_TX"); 277 } 278 if (can(capabilities, CAPABILITY_SUPPORTS_VT_LOCAL_BIDIRECTIONAL)) { 279 builder.append(" CAPABILITY_SUPPORTS_VT_LOCAL_BIDIRECTIONAL"); 280 } 281 if (can(capabilities, CAPABILITY_SUPPORTS_VT_REMOTE_RX)) { 282 builder.append(" CAPABILITY_SUPPORTS_VT_REMOTE_RX"); 283 } 284 if (can(capabilities, CAPABILITY_SUPPORTS_VT_REMOTE_TX)) { 285 builder.append(" CAPABILITY_SUPPORTS_VT_REMOTE_TX"); 286 } 287 if (can(capabilities, CAPABILITY_SUPPORTS_VT_REMOTE_BIDIRECTIONAL)) { 288 builder.append(" CAPABILITY_SUPPORTS_VT_REMOTE_BIDIRECTIONAL"); 289 } 290 if (can(capabilities, CAPABILITY_HIGH_DEF_AUDIO)) { 291 builder.append(" CAPABILITY_HIGH_DEF_AUDIO"); 292 } 293 if (can(capabilities, CAPABILITY_WIFI)) { 294 builder.append(" CAPABILITY_WIFI"); 295 } 296 if (can(capabilities, CAPABILITY_GENERIC_CONFERENCE)) { 297 builder.append(" CAPABILITY_GENERIC_CONFERENCE"); 298 } 299 if (can(capabilities, CAPABILITY_SHOW_CALLBACK_NUMBER)) { 300 builder.append(" CAPABILITY_SHOW_CALLBACK_NUMBER"); 301 } 302 if (can(capabilities, CAPABILITY_SPEED_UP_MT_AUDIO)) { 303 builder.append(" CAPABILITY_SPEED_UP_MT_AUDIO"); 304 } 305 if (can(capabilities, CAPABILITY_CAN_UPGRADE_TO_VIDEO)) { 306 builder.append(" CAPABILITY_CAN_UPGRADE_TO_VIDEO"); 307 } 308 if (can(capabilities, CAPABILITY_CAN_PAUSE_VIDEO)) { 309 builder.append(" CAPABILITY_CAN_PAUSE_VIDEO"); 310 } 311 builder.append("]"); 312 return builder.toString(); 313 } 314 315 /** @hide */ 316 public abstract static class Listener { 317 public void onStateChanged(Connection c, int state) {} 318 public void onAddressChanged(Connection c, Uri newAddress, int presentation) {} 319 public void onCallerDisplayNameChanged( 320 Connection c, String callerDisplayName, int presentation) {} 321 public void onVideoStateChanged(Connection c, int videoState) {} 322 public void onDisconnected(Connection c, DisconnectCause disconnectCause) {} 323 public void onPostDialWait(Connection c, String remaining) {} 324 public void onPostDialChar(Connection c, char nextChar) {} 325 public void onRingbackRequested(Connection c, boolean ringback) {} 326 public void onDestroyed(Connection c) {} 327 public void onConnectionCapabilitiesChanged(Connection c, int capabilities) {} 328 public void onVideoProviderChanged( 329 Connection c, VideoProvider videoProvider) {} 330 public void onAudioModeIsVoipChanged(Connection c, boolean isVoip) {} 331 public void onStatusHintsChanged(Connection c, StatusHints statusHints) {} 332 public void onConferenceablesChanged( 333 Connection c, List<Conferenceable> conferenceables) {} 334 public void onConferenceChanged(Connection c, Conference conference) {} 335 /** @hide */ 336 public void onConferenceParticipantsChanged(Connection c, 337 List<ConferenceParticipant> participants) {} 338 public void onConferenceStarted() {} 339 public void onConferenceMergeFailed(Connection c) {} 340 public void onExtrasChanged(Connection c, Bundle extras) {} 341 } 342 343 /** 344 * Provides a means of controlling the video session associated with a {@link Connection}. 345 * <p> 346 * Implementations create a custom subclass of {@link VideoProvider} and the 347 * {@link ConnectionService} creates an instance sets it on the {@link Connection} using 348 * {@link Connection#setVideoProvider(VideoProvider)}. Any connection which supports video 349 * should set the {@link VideoProvider}. 350 * <p> 351 * The {@link VideoProvider} serves two primary purposes: it provides a means for Telecom and 352 * {@link InCallService} implementations to issue requests related to the video session; 353 * it provides a means for the {@link ConnectionService} to report events and information 354 * related to the video session to Telecom and the {@link InCallService} implementations. 355 * <p> 356 * {@link InCallService} implementations interact with the {@link VideoProvider} via 357 * {@link android.telecom.InCallService.VideoCall}. 358 */ 359 public static abstract class VideoProvider { 360 361 /** 362 * Video is not being received (no protocol pause was issued). 363 * @see #handleCallSessionEvent(int) 364 */ 365 public static final int SESSION_EVENT_RX_PAUSE = 1; 366 367 /** 368 * Video reception has resumed after a {@link #SESSION_EVENT_RX_PAUSE}. 369 * @see #handleCallSessionEvent(int) 370 */ 371 public static final int SESSION_EVENT_RX_RESUME = 2; 372 373 /** 374 * Video transmission has begun. This occurs after a negotiated start of video transmission 375 * when the underlying protocol has actually begun transmitting video to the remote party. 376 * @see #handleCallSessionEvent(int) 377 */ 378 public static final int SESSION_EVENT_TX_START = 3; 379 380 /** 381 * Video transmission has stopped. This occurs after a negotiated stop of video transmission 382 * when the underlying protocol has actually stopped transmitting video to the remote party. 383 * @see #handleCallSessionEvent(int) 384 */ 385 public static final int SESSION_EVENT_TX_STOP = 4; 386 387 /** 388 * A camera failure has occurred for the selected camera. The {@link InCallService} can use 389 * this as a cue to inform the user the camera is not available. 390 * @see #handleCallSessionEvent(int) 391 */ 392 public static final int SESSION_EVENT_CAMERA_FAILURE = 5; 393 394 /** 395 * Issued after {@link #SESSION_EVENT_CAMERA_FAILURE} when the camera is once again ready 396 * for operation. The {@link InCallService} can use this as a cue to inform the user that 397 * the camera has become available again. 398 * @see #handleCallSessionEvent(int) 399 */ 400 public static final int SESSION_EVENT_CAMERA_READY = 6; 401 402 /** 403 * Session modify request was successful. 404 * @see #receiveSessionModifyResponse(int, VideoProfile, VideoProfile) 405 */ 406 public static final int SESSION_MODIFY_REQUEST_SUCCESS = 1; 407 408 /** 409 * Session modify request failed. 410 * @see #receiveSessionModifyResponse(int, VideoProfile, VideoProfile) 411 */ 412 public static final int SESSION_MODIFY_REQUEST_FAIL = 2; 413 414 /** 415 * Session modify request ignored due to invalid parameters. 416 * @see #receiveSessionModifyResponse(int, VideoProfile, VideoProfile) 417 */ 418 public static final int SESSION_MODIFY_REQUEST_INVALID = 3; 419 420 /** 421 * Session modify request timed out. 422 * @see #receiveSessionModifyResponse(int, VideoProfile, VideoProfile) 423 */ 424 public static final int SESSION_MODIFY_REQUEST_TIMED_OUT = 4; 425 426 /** 427 * Session modify request rejected by remote user. 428 * @see #receiveSessionModifyResponse(int, VideoProfile, VideoProfile) 429 */ 430 public static final int SESSION_MODIFY_REQUEST_REJECTED_BY_REMOTE = 5; 431 432 private static final int MSG_ADD_VIDEO_CALLBACK = 1; 433 private static final int MSG_SET_CAMERA = 2; 434 private static final int MSG_SET_PREVIEW_SURFACE = 3; 435 private static final int MSG_SET_DISPLAY_SURFACE = 4; 436 private static final int MSG_SET_DEVICE_ORIENTATION = 5; 437 private static final int MSG_SET_ZOOM = 6; 438 private static final int MSG_SEND_SESSION_MODIFY_REQUEST = 7; 439 private static final int MSG_SEND_SESSION_MODIFY_RESPONSE = 8; 440 private static final int MSG_REQUEST_CAMERA_CAPABILITIES = 9; 441 private static final int MSG_REQUEST_CONNECTION_DATA_USAGE = 10; 442 private static final int MSG_SET_PAUSE_IMAGE = 11; 443 private static final int MSG_REMOVE_VIDEO_CALLBACK = 12; 444 445 private final VideoProvider.VideoProviderHandler 446 mMessageHandler = new VideoProvider.VideoProviderHandler(); 447 private final VideoProvider.VideoProviderBinder mBinder; 448 449 /** 450 * Stores a list of the video callbacks, keyed by IBinder. 451 */ 452 private HashMap<IBinder, IVideoCallback> mVideoCallbacks = new HashMap<>(); 453 454 /** 455 * Default handler used to consolidate binder method calls onto a single thread. 456 */ 457 private final class VideoProviderHandler extends Handler { 458 @Override 459 public void handleMessage(Message msg) { 460 switch (msg.what) { 461 case MSG_ADD_VIDEO_CALLBACK: { 462 IBinder binder = (IBinder) msg.obj; 463 IVideoCallback callback = IVideoCallback.Stub 464 .asInterface((IBinder) msg.obj); 465 if (mVideoCallbacks.containsKey(binder)) { 466 Log.i(this, "addVideoProvider - skipped; already present."); 467 break; 468 } 469 mVideoCallbacks.put(binder, callback); 470 Log.i(this, "addVideoProvider "+ mVideoCallbacks.size()); 471 break; 472 } 473 case MSG_REMOVE_VIDEO_CALLBACK: { 474 IBinder binder = (IBinder) msg.obj; 475 IVideoCallback callback = IVideoCallback.Stub 476 .asInterface((IBinder) msg.obj); 477 if (!mVideoCallbacks.containsKey(binder)) { 478 Log.i(this, "removeVideoProvider - skipped; not present."); 479 break; 480 } 481 mVideoCallbacks.remove(binder); 482 break; 483 } 484 case MSG_SET_CAMERA: 485 onSetCamera((String) msg.obj); 486 break; 487 case MSG_SET_PREVIEW_SURFACE: 488 onSetPreviewSurface((Surface) msg.obj); 489 break; 490 case MSG_SET_DISPLAY_SURFACE: 491 onSetDisplaySurface((Surface) msg.obj); 492 break; 493 case MSG_SET_DEVICE_ORIENTATION: 494 onSetDeviceOrientation(msg.arg1); 495 break; 496 case MSG_SET_ZOOM: 497 onSetZoom((Float) msg.obj); 498 break; 499 case MSG_SEND_SESSION_MODIFY_REQUEST: { 500 SomeArgs args = (SomeArgs) msg.obj; 501 try { 502 onSendSessionModifyRequest((VideoProfile) args.arg1, 503 (VideoProfile) args.arg2); 504 } finally { 505 args.recycle(); 506 } 507 break; 508 } 509 case MSG_SEND_SESSION_MODIFY_RESPONSE: 510 onSendSessionModifyResponse((VideoProfile) msg.obj); 511 break; 512 case MSG_REQUEST_CAMERA_CAPABILITIES: 513 onRequestCameraCapabilities(); 514 break; 515 case MSG_REQUEST_CONNECTION_DATA_USAGE: 516 onRequestConnectionDataUsage(); 517 break; 518 case MSG_SET_PAUSE_IMAGE: 519 onSetPauseImage((Uri) msg.obj); 520 break; 521 default: 522 break; 523 } 524 } 525 } 526 527 /** 528 * IVideoProvider stub implementation. 529 */ 530 private final class VideoProviderBinder extends IVideoProvider.Stub { 531 public void addVideoCallback(IBinder videoCallbackBinder) { 532 mMessageHandler.obtainMessage( 533 MSG_ADD_VIDEO_CALLBACK, videoCallbackBinder).sendToTarget(); 534 } 535 536 public void removeVideoCallback(IBinder videoCallbackBinder) { 537 mMessageHandler.obtainMessage( 538 MSG_REMOVE_VIDEO_CALLBACK, videoCallbackBinder).sendToTarget(); 539 } 540 541 public void setCamera(String cameraId) { 542 mMessageHandler.obtainMessage(MSG_SET_CAMERA, cameraId).sendToTarget(); 543 } 544 545 public void setPreviewSurface(Surface surface) { 546 mMessageHandler.obtainMessage(MSG_SET_PREVIEW_SURFACE, surface).sendToTarget(); 547 } 548 549 public void setDisplaySurface(Surface surface) { 550 mMessageHandler.obtainMessage(MSG_SET_DISPLAY_SURFACE, surface).sendToTarget(); 551 } 552 553 public void setDeviceOrientation(int rotation) { 554 mMessageHandler.obtainMessage( 555 MSG_SET_DEVICE_ORIENTATION, rotation, 0).sendToTarget(); 556 } 557 558 public void setZoom(float value) { 559 mMessageHandler.obtainMessage(MSG_SET_ZOOM, value).sendToTarget(); 560 } 561 562 public void sendSessionModifyRequest(VideoProfile fromProfile, VideoProfile toProfile) { 563 SomeArgs args = SomeArgs.obtain(); 564 args.arg1 = fromProfile; 565 args.arg2 = toProfile; 566 mMessageHandler.obtainMessage(MSG_SEND_SESSION_MODIFY_REQUEST, args).sendToTarget(); 567 } 568 569 public void sendSessionModifyResponse(VideoProfile responseProfile) { 570 mMessageHandler.obtainMessage( 571 MSG_SEND_SESSION_MODIFY_RESPONSE, responseProfile).sendToTarget(); 572 } 573 574 public void requestCameraCapabilities() { 575 mMessageHandler.obtainMessage(MSG_REQUEST_CAMERA_CAPABILITIES).sendToTarget(); 576 } 577 578 public void requestCallDataUsage() { 579 mMessageHandler.obtainMessage(MSG_REQUEST_CONNECTION_DATA_USAGE).sendToTarget(); 580 } 581 582 public void setPauseImage(Uri uri) { 583 mMessageHandler.obtainMessage(MSG_SET_PAUSE_IMAGE, uri).sendToTarget(); 584 } 585 } 586 587 public VideoProvider() { 588 mBinder = new VideoProvider.VideoProviderBinder(); 589 } 590 591 /** 592 * Returns binder object which can be used across IPC methods. 593 * @hide 594 */ 595 public final IVideoProvider getInterface() { 596 return mBinder; 597 } 598 599 /** 600 * Sets the camera to be used for the outgoing video. 601 * <p> 602 * The {@link VideoProvider} should respond by communicating the capabilities of the chosen 603 * camera via 604 * {@link VideoProvider#changeCameraCapabilities(VideoProfile.CameraCapabilities)}. 605 * <p> 606 * Sent from the {@link InCallService} via 607 * {@link InCallService.VideoCall#setCamera(String)}. 608 * 609 * @param cameraId The id of the camera (use ids as reported by 610 * {@link CameraManager#getCameraIdList()}). 611 */ 612 public abstract void onSetCamera(String cameraId); 613 614 /** 615 * Sets the surface to be used for displaying a preview of what the user's camera is 616 * currently capturing. When video transmission is enabled, this is the video signal which 617 * is sent to the remote device. 618 * <p> 619 * Sent from the {@link InCallService} via 620 * {@link InCallService.VideoCall#setPreviewSurface(Surface)}. 621 * 622 * @param surface The {@link Surface}. 623 */ 624 public abstract void onSetPreviewSurface(Surface surface); 625 626 /** 627 * Sets the surface to be used for displaying the video received from the remote device. 628 * <p> 629 * Sent from the {@link InCallService} via 630 * {@link InCallService.VideoCall#setDisplaySurface(Surface)}. 631 * 632 * @param surface The {@link Surface}. 633 */ 634 public abstract void onSetDisplaySurface(Surface surface); 635 636 /** 637 * Sets the device orientation, in degrees. Assumes that a standard portrait orientation of 638 * the device is 0 degrees. 639 * <p> 640 * Sent from the {@link InCallService} via 641 * {@link InCallService.VideoCall#setDeviceOrientation(int)}. 642 * 643 * @param rotation The device orientation, in degrees. 644 */ 645 public abstract void onSetDeviceOrientation(int rotation); 646 647 /** 648 * Sets camera zoom ratio. 649 * <p> 650 * Sent from the {@link InCallService} via {@link InCallService.VideoCall#setZoom(float)}. 651 * 652 * @param value The camera zoom ratio. 653 */ 654 public abstract void onSetZoom(float value); 655 656 /** 657 * Issues a request to modify the properties of the current video session. 658 * <p> 659 * Example scenarios include: requesting an audio-only call to be upgraded to a 660 * bi-directional video call, turning on or off the user's camera, sending a pause signal 661 * when the {@link InCallService} is no longer the foreground application. 662 * <p> 663 * If the {@link VideoProvider} determines a request to be invalid, it should call 664 * {@link #receiveSessionModifyResponse(int, VideoProfile, VideoProfile)} to report the 665 * invalid request back to the {@link InCallService}. 666 * <p> 667 * Where a request requires confirmation from the user of the peer device, the 668 * {@link VideoProvider} must communicate the request to the peer device and handle the 669 * user's response. {@link #receiveSessionModifyResponse(int, VideoProfile, VideoProfile)} 670 * is used to inform the {@link InCallService} of the result of the request. 671 * <p> 672 * Sent from the {@link InCallService} via 673 * {@link InCallService.VideoCall#sendSessionModifyRequest(VideoProfile)}. 674 * 675 * @param fromProfile The video profile prior to the request. 676 * @param toProfile The video profile with the requested changes made. 677 */ 678 public abstract void onSendSessionModifyRequest(VideoProfile fromProfile, 679 VideoProfile toProfile); 680 681 /** 682 * Provides a response to a request to change the current video session properties. 683 * <p> 684 * For example, if the peer requests and upgrade from an audio-only call to a bi-directional 685 * video call, could decline the request and keep the call as audio-only. 686 * In such a scenario, the {@code responseProfile} would have a video state of 687 * {@link VideoProfile#STATE_AUDIO_ONLY}. If the user had decided to accept the request, 688 * the video state would be {@link VideoProfile#STATE_BIDIRECTIONAL}. 689 * <p> 690 * Sent from the {@link InCallService} via 691 * {@link InCallService.VideoCall#sendSessionModifyResponse(VideoProfile)} in response to 692 * a {@link InCallService.VideoCall.Callback#onSessionModifyRequestReceived(VideoProfile)} 693 * callback. 694 * 695 * @param responseProfile The response video profile. 696 */ 697 public abstract void onSendSessionModifyResponse(VideoProfile responseProfile); 698 699 /** 700 * Issues a request to the {@link VideoProvider} to retrieve the camera capabilities. 701 * <p> 702 * The {@link VideoProvider} should respond by communicating the capabilities of the chosen 703 * camera via 704 * {@link VideoProvider#changeCameraCapabilities(VideoProfile.CameraCapabilities)}. 705 * <p> 706 * Sent from the {@link InCallService} via 707 * {@link InCallService.VideoCall#requestCameraCapabilities()}. 708 */ 709 public abstract void onRequestCameraCapabilities(); 710 711 /** 712 * Issues a request to the {@link VideoProvider} to retrieve the current data usage for the 713 * video component of the current {@link Connection}. 714 * <p> 715 * The {@link VideoProvider} should respond by communicating current data usage, in bytes, 716 * via {@link VideoProvider#setCallDataUsage(long)}. 717 * <p> 718 * Sent from the {@link InCallService} via 719 * {@link InCallService.VideoCall#requestCallDataUsage()}. 720 */ 721 public abstract void onRequestConnectionDataUsage(); 722 723 /** 724 * Provides the {@link VideoProvider} with the {@link Uri} of an image to be displayed to 725 * the peer device when the video signal is paused. 726 * <p> 727 * Sent from the {@link InCallService} via 728 * {@link InCallService.VideoCall#setPauseImage(Uri)}. 729 * 730 * @param uri URI of image to display. 731 */ 732 public abstract void onSetPauseImage(Uri uri); 733 734 /** 735 * Used to inform listening {@link InCallService} implementations when the 736 * {@link VideoProvider} receives a session modification request. 737 * <p> 738 * Received by the {@link InCallService} via 739 * {@link InCallService.VideoCall.Callback#onSessionModifyRequestReceived(VideoProfile)}, 740 * 741 * @param videoProfile The requested video profile. 742 * @see #onSendSessionModifyRequest(VideoProfile, VideoProfile) 743 */ 744 public void receiveSessionModifyRequest(VideoProfile videoProfile) { 745 if (mVideoCallbacks != null) { 746 try { 747 for (IVideoCallback callback : mVideoCallbacks.values()) { 748 callback.receiveSessionModifyRequest(videoProfile); 749 } 750 } catch (RemoteException ignored) { 751 } 752 } 753 } 754 755 /** 756 * Used to inform listening {@link InCallService} implementations when the 757 * {@link VideoProvider} receives a response to a session modification request. 758 * <p> 759 * Received by the {@link InCallService} via 760 * {@link InCallService.VideoCall.Callback#onSessionModifyResponseReceived(int, 761 * VideoProfile, VideoProfile)}. 762 * 763 * @param status Status of the session modify request. Valid values are 764 * {@link VideoProvider#SESSION_MODIFY_REQUEST_SUCCESS}, 765 * {@link VideoProvider#SESSION_MODIFY_REQUEST_FAIL}, 766 * {@link VideoProvider#SESSION_MODIFY_REQUEST_INVALID}, 767 * {@link VideoProvider#SESSION_MODIFY_REQUEST_TIMED_OUT}, 768 * {@link VideoProvider#SESSION_MODIFY_REQUEST_REJECTED_BY_REMOTE} 769 * @param requestedProfile The original request which was sent to the peer device. 770 * @param responseProfile The actual profile changes agreed to by the peer device. 771 * @see #onSendSessionModifyRequest(VideoProfile, VideoProfile) 772 */ 773 public void receiveSessionModifyResponse(int status, 774 VideoProfile requestedProfile, VideoProfile responseProfile) { 775 if (mVideoCallbacks != null) { 776 try { 777 for (IVideoCallback callback : mVideoCallbacks.values()) { 778 callback.receiveSessionModifyResponse(status, requestedProfile, 779 responseProfile); 780 } 781 } catch (RemoteException ignored) { 782 } 783 } 784 } 785 786 /** 787 * Used to inform listening {@link InCallService} implementations when the 788 * {@link VideoProvider} reports a call session event. 789 * <p> 790 * Received by the {@link InCallService} via 791 * {@link InCallService.VideoCall.Callback#onCallSessionEvent(int)}. 792 * 793 * @param event The event. Valid values are: {@link VideoProvider#SESSION_EVENT_RX_PAUSE}, 794 * {@link VideoProvider#SESSION_EVENT_RX_RESUME}, 795 * {@link VideoProvider#SESSION_EVENT_TX_START}, 796 * {@link VideoProvider#SESSION_EVENT_TX_STOP}, 797 * {@link VideoProvider#SESSION_EVENT_CAMERA_FAILURE}, 798 * {@link VideoProvider#SESSION_EVENT_CAMERA_READY}. 799 */ 800 public void handleCallSessionEvent(int event) { 801 if (mVideoCallbacks != null) { 802 try { 803 for (IVideoCallback callback : mVideoCallbacks.values()) { 804 callback.handleCallSessionEvent(event); 805 } 806 } catch (RemoteException ignored) { 807 } 808 } 809 } 810 811 /** 812 * Used to inform listening {@link InCallService} implementations when the dimensions of the 813 * peer's video have changed. 814 * <p> 815 * This could occur if, for example, the peer rotates their device, changing the aspect 816 * ratio of the video, or if the user switches between the back and front cameras. 817 * <p> 818 * Received by the {@link InCallService} via 819 * {@link InCallService.VideoCall.Callback#onPeerDimensionsChanged(int, int)}. 820 * 821 * @param width The updated peer video width. 822 * @param height The updated peer video height. 823 */ 824 public void changePeerDimensions(int width, int height) { 825 if (mVideoCallbacks != null) { 826 try { 827 for (IVideoCallback callback : mVideoCallbacks.values()) { 828 callback.changePeerDimensions(width, height); 829 } 830 } catch (RemoteException ignored) { 831 } 832 } 833 } 834 835 /** 836 * Used to inform listening {@link InCallService} implementations when the data usage of the 837 * video associated with the current {@link Connection} has changed. 838 * <p> 839 * This could be in response to a preview request via 840 * {@link #onRequestConnectionDataUsage()}, or as a periodic update by the 841 * {@link VideoProvider}. 842 * <p> 843 * Received by the {@link InCallService} via 844 * {@link InCallService.VideoCall.Callback#onCallDataUsageChanged(long)}. 845 * 846 * @param dataUsage The updated data usage (in bytes). Reported as the cumulative bytes 847 * used since the start of the call. 848 */ 849 public void setCallDataUsage(long dataUsage) { 850 if (mVideoCallbacks != null) { 851 try { 852 for (IVideoCallback callback : mVideoCallbacks.values()) { 853 callback.changeCallDataUsage(dataUsage); 854 } 855 } catch (RemoteException ignored) { 856 } 857 } 858 } 859 860 /** 861 * @see #setCallDataUsage(long) 862 * 863 * @param dataUsage The updated data usage (in byes). 864 * @deprecated - Use {@link #setCallDataUsage(long)} instead. 865 * @hide 866 */ 867 public void changeCallDataUsage(long dataUsage) { 868 setCallDataUsage(dataUsage); 869 } 870 871 /** 872 * Used to inform listening {@link InCallService} implementations when the capabilities of 873 * the current camera have changed. 874 * <p> 875 * The {@link VideoProvider} should call this in response to 876 * {@link VideoProvider#onRequestCameraCapabilities()}, or when the current camera is 877 * changed via {@link VideoProvider#onSetCamera(String)}. 878 * <p> 879 * Received by the {@link InCallService} via 880 * {@link InCallService.VideoCall.Callback#onCameraCapabilitiesChanged( 881 * VideoProfile.CameraCapabilities)}. 882 * 883 * @param cameraCapabilities The new camera capabilities. 884 */ 885 public void changeCameraCapabilities(VideoProfile.CameraCapabilities cameraCapabilities) { 886 if (mVideoCallbacks != null) { 887 try { 888 for (IVideoCallback callback : mVideoCallbacks.values()) { 889 callback.changeCameraCapabilities(cameraCapabilities); 890 } 891 } catch (RemoteException ignored) { 892 } 893 } 894 } 895 896 /** 897 * Used to inform listening {@link InCallService} implementations when the video quality 898 * of the call has changed. 899 * <p> 900 * Received by the {@link InCallService} via 901 * {@link InCallService.VideoCall.Callback#onVideoQualityChanged(int)}. 902 * 903 * @param videoQuality The updated video quality. Valid values: 904 * {@link VideoProfile#QUALITY_HIGH}, 905 * {@link VideoProfile#QUALITY_MEDIUM}, 906 * {@link VideoProfile#QUALITY_LOW}, 907 * {@link VideoProfile#QUALITY_DEFAULT}. 908 */ 909 public void changeVideoQuality(int videoQuality) { 910 if (mVideoCallbacks != null) { 911 try { 912 for (IVideoCallback callback : mVideoCallbacks.values()) { 913 callback.changeVideoQuality(videoQuality); 914 } 915 } catch (RemoteException ignored) { 916 } 917 } 918 } 919 } 920 921 private final Listener mConnectionDeathListener = new Listener() { 922 @Override 923 public void onDestroyed(Connection c) { 924 if (mConferenceables.remove(c)) { 925 fireOnConferenceableConnectionsChanged(); 926 } 927 } 928 }; 929 930 private final Conference.Listener mConferenceDeathListener = new Conference.Listener() { 931 @Override 932 public void onDestroyed(Conference c) { 933 if (mConferenceables.remove(c)) { 934 fireOnConferenceableConnectionsChanged(); 935 } 936 } 937 }; 938 939 /** 940 * ConcurrentHashMap constructor params: 8 is initial table size, 0.9f is 941 * load factor before resizing, 1 means we only expect a single thread to 942 * access the map so make only a single shard 943 */ 944 private final Set<Listener> mListeners = Collections.newSetFromMap( 945 new ConcurrentHashMap<Listener, Boolean>(8, 0.9f, 1)); 946 private final List<Conferenceable> mConferenceables = new ArrayList<>(); 947 private final List<Conferenceable> mUnmodifiableConferenceables = 948 Collections.unmodifiableList(mConferenceables); 949 950 private int mState = STATE_NEW; 951 private CallAudioState mCallAudioState; 952 private Uri mAddress; 953 private int mAddressPresentation; 954 private String mCallerDisplayName; 955 private int mCallerDisplayNamePresentation; 956 private boolean mRingbackRequested = false; 957 private int mConnectionCapabilities; 958 private VideoProvider mVideoProvider; 959 private boolean mAudioModeIsVoip; 960 private StatusHints mStatusHints; 961 private int mVideoState; 962 private DisconnectCause mDisconnectCause; 963 private Conference mConference; 964 private ConnectionService mConnectionService; 965 private Bundle mExtras; 966 967 /** 968 * Create a new Connection. 969 */ 970 public Connection() {} 971 972 /** 973 * @return The address (e.g., phone number) to which this Connection is currently communicating. 974 */ 975 public final Uri getAddress() { 976 return mAddress; 977 } 978 979 /** 980 * @return The presentation requirements for the address. 981 * See {@link TelecomManager} for valid values. 982 */ 983 public final int getAddressPresentation() { 984 return mAddressPresentation; 985 } 986 987 /** 988 * @return The caller display name (CNAP). 989 */ 990 public final String getCallerDisplayName() { 991 return mCallerDisplayName; 992 } 993 994 /** 995 * @return The presentation requirements for the handle. 996 * See {@link TelecomManager} for valid values. 997 */ 998 public final int getCallerDisplayNamePresentation() { 999 return mCallerDisplayNamePresentation; 1000 } 1001 1002 /** 1003 * @return The state of this Connection. 1004 */ 1005 public final int getState() { 1006 return mState; 1007 } 1008 1009 /** 1010 * Returns the video state of the connection. 1011 * Valid values: {@link VideoProfile#STATE_AUDIO_ONLY}, 1012 * {@link VideoProfile#STATE_BIDIRECTIONAL}, 1013 * {@link VideoProfile#STATE_TX_ENABLED}, 1014 * {@link VideoProfile#STATE_RX_ENABLED}. 1015 * 1016 * @return The video state of the connection. 1017 * @hide 1018 */ 1019 public final int getVideoState() { 1020 return mVideoState; 1021 } 1022 1023 /** 1024 * @return The audio state of the connection, describing how its audio is currently 1025 * being routed by the system. This is {@code null} if this Connection 1026 * does not directly know about its audio state. 1027 * @deprecated Use {@link #getCallAudioState()} instead. 1028 * @hide 1029 */ 1030 @SystemApi 1031 @Deprecated 1032 public final AudioState getAudioState() { 1033 return new AudioState(mCallAudioState); 1034 } 1035 1036 /** 1037 * @return The audio state of the connection, describing how its audio is currently 1038 * being routed by the system. This is {@code null} if this Connection 1039 * does not directly know about its audio state. 1040 */ 1041 public final CallAudioState getCallAudioState() { 1042 return mCallAudioState; 1043 } 1044 1045 /** 1046 * @return The conference that this connection is a part of. Null if it is not part of any 1047 * conference. 1048 */ 1049 public final Conference getConference() { 1050 return mConference; 1051 } 1052 1053 /** 1054 * Returns whether this connection is requesting that the system play a ringback tone 1055 * on its behalf. 1056 */ 1057 public final boolean isRingbackRequested() { 1058 return mRingbackRequested; 1059 } 1060 1061 /** 1062 * @return True if the connection's audio mode is VOIP. 1063 */ 1064 public final boolean getAudioModeIsVoip() { 1065 return mAudioModeIsVoip; 1066 } 1067 1068 /** 1069 * @return The status hints for this connection. 1070 */ 1071 public final StatusHints getStatusHints() { 1072 return mStatusHints; 1073 } 1074 1075 /** 1076 * @return The extras associated with this connection. 1077 */ 1078 public final Bundle getExtras() { 1079 return mExtras; 1080 } 1081 1082 /** 1083 * Assign a listener to be notified of state changes. 1084 * 1085 * @param l A listener. 1086 * @return This Connection. 1087 * 1088 * @hide 1089 */ 1090 public final Connection addConnectionListener(Listener l) { 1091 mListeners.add(l); 1092 return this; 1093 } 1094 1095 /** 1096 * Remove a previously assigned listener that was being notified of state changes. 1097 * 1098 * @param l A Listener. 1099 * @return This Connection. 1100 * 1101 * @hide 1102 */ 1103 public final Connection removeConnectionListener(Listener l) { 1104 if (l != null) { 1105 mListeners.remove(l); 1106 } 1107 return this; 1108 } 1109 1110 /** 1111 * @return The {@link DisconnectCause} for this connection. 1112 */ 1113 public final DisconnectCause getDisconnectCause() { 1114 return mDisconnectCause; 1115 } 1116 1117 /** 1118 * Inform this Connection that the state of its audio output has been changed externally. 1119 * 1120 * @param state The new audio state. 1121 * @hide 1122 */ 1123 final void setCallAudioState(CallAudioState state) { 1124 checkImmutable(); 1125 Log.d(this, "setAudioState %s", state); 1126 mCallAudioState = state; 1127 onAudioStateChanged(getAudioState()); 1128 onCallAudioStateChanged(state); 1129 } 1130 1131 /** 1132 * @param state An integer value of a {@code STATE_*} constant. 1133 * @return A string representation of the value. 1134 */ 1135 public static String stateToString(int state) { 1136 switch (state) { 1137 case STATE_INITIALIZING: 1138 return "STATE_INITIALIZING"; 1139 case STATE_NEW: 1140 return "STATE_NEW"; 1141 case STATE_RINGING: 1142 return "STATE_RINGING"; 1143 case STATE_DIALING: 1144 return "STATE_DIALING"; 1145 case STATE_ACTIVE: 1146 return "STATE_ACTIVE"; 1147 case STATE_HOLDING: 1148 return "STATE_HOLDING"; 1149 case STATE_DISCONNECTED: 1150 return "DISCONNECTED"; 1151 default: 1152 Log.wtf(Connection.class, "Unknown state %d", state); 1153 return "UNKNOWN"; 1154 } 1155 } 1156 1157 /** 1158 * Returns the connection's capabilities, as a bit mask of the {@code CAPABILITY_*} constants. 1159 */ 1160 public final int getConnectionCapabilities() { 1161 return mConnectionCapabilities; 1162 } 1163 1164 /** 1165 * Sets the value of the {@link #getAddress()} property. 1166 * 1167 * @param address The new address. 1168 * @param presentation The presentation requirements for the address. 1169 * See {@link TelecomManager} for valid values. 1170 */ 1171 public final void setAddress(Uri address, int presentation) { 1172 checkImmutable(); 1173 Log.d(this, "setAddress %s", address); 1174 mAddress = address; 1175 mAddressPresentation = presentation; 1176 for (Listener l : mListeners) { 1177 l.onAddressChanged(this, address, presentation); 1178 } 1179 } 1180 1181 /** 1182 * Sets the caller display name (CNAP). 1183 * 1184 * @param callerDisplayName The new display name. 1185 * @param presentation The presentation requirements for the handle. 1186 * See {@link TelecomManager} for valid values. 1187 */ 1188 public final void setCallerDisplayName(String callerDisplayName, int presentation) { 1189 checkImmutable(); 1190 Log.d(this, "setCallerDisplayName %s", callerDisplayName); 1191 mCallerDisplayName = callerDisplayName; 1192 mCallerDisplayNamePresentation = presentation; 1193 for (Listener l : mListeners) { 1194 l.onCallerDisplayNameChanged(this, callerDisplayName, presentation); 1195 } 1196 } 1197 1198 /** 1199 * Set the video state for the connection. 1200 * Valid values: {@link VideoProfile#STATE_AUDIO_ONLY}, 1201 * {@link VideoProfile#STATE_BIDIRECTIONAL}, 1202 * {@link VideoProfile#STATE_TX_ENABLED}, 1203 * {@link VideoProfile#STATE_RX_ENABLED}. 1204 * 1205 * @param videoState The new video state. 1206 */ 1207 public final void setVideoState(int videoState) { 1208 checkImmutable(); 1209 Log.d(this, "setVideoState %d", videoState); 1210 mVideoState = videoState; 1211 for (Listener l : mListeners) { 1212 l.onVideoStateChanged(this, mVideoState); 1213 } 1214 } 1215 1216 /** 1217 * Sets state to active (e.g., an ongoing connection where two or more parties can actively 1218 * communicate). 1219 */ 1220 public final void setActive() { 1221 checkImmutable(); 1222 setRingbackRequested(false); 1223 setState(STATE_ACTIVE); 1224 } 1225 1226 /** 1227 * Sets state to ringing (e.g., an inbound ringing connection). 1228 */ 1229 public final void setRinging() { 1230 checkImmutable(); 1231 setState(STATE_RINGING); 1232 } 1233 1234 /** 1235 * Sets state to initializing (this Connection is not yet ready to be used). 1236 */ 1237 public final void setInitializing() { 1238 checkImmutable(); 1239 setState(STATE_INITIALIZING); 1240 } 1241 1242 /** 1243 * Sets state to initialized (the Connection has been set up and is now ready to be used). 1244 */ 1245 public final void setInitialized() { 1246 checkImmutable(); 1247 setState(STATE_NEW); 1248 } 1249 1250 /** 1251 * Sets state to dialing (e.g., dialing an outbound connection). 1252 */ 1253 public final void setDialing() { 1254 checkImmutable(); 1255 setState(STATE_DIALING); 1256 } 1257 1258 /** 1259 * Sets state to be on hold. 1260 */ 1261 public final void setOnHold() { 1262 checkImmutable(); 1263 setState(STATE_HOLDING); 1264 } 1265 1266 /** 1267 * Sets the video connection provider. 1268 * @param videoProvider The video provider. 1269 */ 1270 public final void setVideoProvider(VideoProvider videoProvider) { 1271 checkImmutable(); 1272 mVideoProvider = videoProvider; 1273 for (Listener l : mListeners) { 1274 l.onVideoProviderChanged(this, videoProvider); 1275 } 1276 } 1277 1278 public final VideoProvider getVideoProvider() { 1279 return mVideoProvider; 1280 } 1281 1282 /** 1283 * Sets state to disconnected. 1284 * 1285 * @param disconnectCause The reason for the disconnection, as specified by 1286 * {@link DisconnectCause}. 1287 */ 1288 public final void setDisconnected(DisconnectCause disconnectCause) { 1289 checkImmutable(); 1290 mDisconnectCause = disconnectCause; 1291 setState(STATE_DISCONNECTED); 1292 Log.d(this, "Disconnected with cause %s", disconnectCause); 1293 for (Listener l : mListeners) { 1294 l.onDisconnected(this, disconnectCause); 1295 } 1296 } 1297 1298 /** 1299 * Informs listeners that this {@code Connection} is in a post-dial wait state. This is done 1300 * when (a) the {@code Connection} is issuing a DTMF sequence; (b) it has encountered a "wait" 1301 * character; and (c) it wishes to inform the In-Call app that it is waiting for the end-user 1302 * to send an {@link #onPostDialContinue(boolean)} signal. 1303 * 1304 * @param remaining The DTMF character sequence remaining to be emitted once the 1305 * {@link #onPostDialContinue(boolean)} is received, including any "wait" characters 1306 * that remaining sequence may contain. 1307 */ 1308 public final void setPostDialWait(String remaining) { 1309 checkImmutable(); 1310 for (Listener l : mListeners) { 1311 l.onPostDialWait(this, remaining); 1312 } 1313 } 1314 1315 /** 1316 * Informs listeners that this {@code Connection} has processed a character in the post-dial 1317 * started state. This is done when (a) the {@code Connection} is issuing a DTMF sequence; 1318 * and (b) it wishes to signal Telecom to play the corresponding DTMF tone locally. 1319 * 1320 * @param nextChar The DTMF character that was just processed by the {@code Connection}. 1321 */ 1322 public final void setNextPostDialChar(char nextChar) { 1323 checkImmutable(); 1324 for (Listener l : mListeners) { 1325 l.onPostDialChar(this, nextChar); 1326 } 1327 } 1328 1329 /** 1330 * Requests that the framework play a ringback tone. This is to be invoked by implementations 1331 * that do not play a ringback tone themselves in the connection's audio stream. 1332 * 1333 * @param ringback Whether the ringback tone is to be played. 1334 */ 1335 public final void setRingbackRequested(boolean ringback) { 1336 checkImmutable(); 1337 if (mRingbackRequested != ringback) { 1338 mRingbackRequested = ringback; 1339 for (Listener l : mListeners) { 1340 l.onRingbackRequested(this, ringback); 1341 } 1342 } 1343 } 1344 1345 /** 1346 * Sets the connection's capabilities as a bit mask of the {@code CAPABILITY_*} constants. 1347 * 1348 * @param connectionCapabilities The new connection capabilities. 1349 */ 1350 public final void setConnectionCapabilities(int connectionCapabilities) { 1351 checkImmutable(); 1352 if (mConnectionCapabilities != connectionCapabilities) { 1353 mConnectionCapabilities = connectionCapabilities; 1354 for (Listener l : mListeners) { 1355 l.onConnectionCapabilitiesChanged(this, mConnectionCapabilities); 1356 } 1357 } 1358 } 1359 1360 /** 1361 * Tears down the Connection object. 1362 */ 1363 public final void destroy() { 1364 for (Listener l : mListeners) { 1365 l.onDestroyed(this); 1366 } 1367 } 1368 1369 /** 1370 * Requests that the framework use VOIP audio mode for this connection. 1371 * 1372 * @param isVoip True if the audio mode is VOIP. 1373 */ 1374 public final void setAudioModeIsVoip(boolean isVoip) { 1375 checkImmutable(); 1376 mAudioModeIsVoip = isVoip; 1377 for (Listener l : mListeners) { 1378 l.onAudioModeIsVoipChanged(this, isVoip); 1379 } 1380 } 1381 1382 /** 1383 * Sets the label and icon status to display in the in-call UI. 1384 * 1385 * @param statusHints The status label and icon to set. 1386 */ 1387 public final void setStatusHints(StatusHints statusHints) { 1388 checkImmutable(); 1389 mStatusHints = statusHints; 1390 for (Listener l : mListeners) { 1391 l.onStatusHintsChanged(this, statusHints); 1392 } 1393 } 1394 1395 /** 1396 * Sets the connections with which this connection can be conferenced. 1397 * 1398 * @param conferenceableConnections The set of connections this connection can conference with. 1399 */ 1400 public final void setConferenceableConnections(List<Connection> conferenceableConnections) { 1401 checkImmutable(); 1402 clearConferenceableList(); 1403 for (Connection c : conferenceableConnections) { 1404 // If statement checks for duplicates in input. It makes it N^2 but we're dealing with a 1405 // small amount of items here. 1406 if (!mConferenceables.contains(c)) { 1407 c.addConnectionListener(mConnectionDeathListener); 1408 mConferenceables.add(c); 1409 } 1410 } 1411 fireOnConferenceableConnectionsChanged(); 1412 } 1413 1414 /** 1415 * Similar to {@link #setConferenceableConnections(java.util.List)}, sets a list of connections 1416 * or conferences with which this connection can be conferenced. 1417 * 1418 * @param conferenceables The conferenceables. 1419 */ 1420 public final void setConferenceables(List<Conferenceable> conferenceables) { 1421 clearConferenceableList(); 1422 for (Conferenceable c : conferenceables) { 1423 // If statement checks for duplicates in input. It makes it N^2 but we're dealing with a 1424 // small amount of items here. 1425 if (!mConferenceables.contains(c)) { 1426 if (c instanceof Connection) { 1427 Connection connection = (Connection) c; 1428 connection.addConnectionListener(mConnectionDeathListener); 1429 } else if (c instanceof Conference) { 1430 Conference conference = (Conference) c; 1431 conference.addListener(mConferenceDeathListener); 1432 } 1433 mConferenceables.add(c); 1434 } 1435 } 1436 fireOnConferenceableConnectionsChanged(); 1437 } 1438 1439 /** 1440 * Returns the connections or conferences with which this connection can be conferenced. 1441 */ 1442 public final List<Conferenceable> getConferenceables() { 1443 return mUnmodifiableConferenceables; 1444 } 1445 1446 /* 1447 * @hide 1448 */ 1449 public final void setConnectionService(ConnectionService connectionService) { 1450 checkImmutable(); 1451 if (mConnectionService != null) { 1452 Log.e(this, new Exception(), "Trying to set ConnectionService on a connection " + 1453 "which is already associated with another ConnectionService."); 1454 } else { 1455 mConnectionService = connectionService; 1456 } 1457 } 1458 1459 /** 1460 * @hide 1461 */ 1462 public final void unsetConnectionService(ConnectionService connectionService) { 1463 if (mConnectionService != connectionService) { 1464 Log.e(this, new Exception(), "Trying to remove ConnectionService from a Connection " + 1465 "that does not belong to the ConnectionService."); 1466 } else { 1467 mConnectionService = null; 1468 } 1469 } 1470 1471 /** 1472 * @hide 1473 */ 1474 public final ConnectionService getConnectionService() { 1475 return mConnectionService; 1476 } 1477 1478 /** 1479 * Sets the conference that this connection is a part of. This will fail if the connection is 1480 * already part of a conference. {@link #resetConference} to un-set the conference first. 1481 * 1482 * @param conference The conference. 1483 * @return {@code true} if the conference was successfully set. 1484 * @hide 1485 */ 1486 public final boolean setConference(Conference conference) { 1487 checkImmutable(); 1488 // We check to see if it is already part of another conference. 1489 if (mConference == null) { 1490 mConference = conference; 1491 if (mConnectionService != null && mConnectionService.containsConference(conference)) { 1492 fireConferenceChanged(); 1493 } 1494 return true; 1495 } 1496 return false; 1497 } 1498 1499 /** 1500 * Resets the conference that this connection is a part of. 1501 * @hide 1502 */ 1503 public final void resetConference() { 1504 if (mConference != null) { 1505 Log.d(this, "Conference reset"); 1506 mConference = null; 1507 fireConferenceChanged(); 1508 } 1509 } 1510 1511 /** 1512 * Set some extras that can be associated with this {@code Connection}. No assumptions should 1513 * be made as to how an In-Call UI or service will handle these extras. 1514 * Keys should be fully qualified (e.g., com.example.MY_EXTRA) to avoid conflicts. 1515 * 1516 * @param extras The extras associated with this {@code Connection}. 1517 */ 1518 public final void setExtras(@Nullable Bundle extras) { 1519 checkImmutable(); 1520 mExtras = extras; 1521 for (Listener l : mListeners) { 1522 l.onExtrasChanged(this, extras); 1523 } 1524 } 1525 1526 /** 1527 * Notifies this Connection that the {@link #getAudioState()} property has a new value. 1528 * 1529 * @param state The new connection audio state. 1530 * @deprecated Use {@link #onCallAudioStateChanged(CallAudioState)} instead. 1531 * @hide 1532 */ 1533 @SystemApi 1534 @Deprecated 1535 public void onAudioStateChanged(AudioState state) {} 1536 1537 /** 1538 * Notifies this Connection that the {@link #getCallAudioState()} property has a new value. 1539 * 1540 * @param state The new connection audio state. 1541 */ 1542 public void onCallAudioStateChanged(CallAudioState state) {} 1543 1544 /** 1545 * Notifies this Connection of an internal state change. This method is called after the 1546 * state is changed. 1547 * 1548 * @param state The new state, one of the {@code STATE_*} constants. 1549 */ 1550 public void onStateChanged(int state) {} 1551 1552 /** 1553 * Notifies this Connection of a request to play a DTMF tone. 1554 * 1555 * @param c A DTMF character. 1556 */ 1557 public void onPlayDtmfTone(char c) {} 1558 1559 /** 1560 * Notifies this Connection of a request to stop any currently playing DTMF tones. 1561 */ 1562 public void onStopDtmfTone() {} 1563 1564 /** 1565 * Notifies this Connection of a request to disconnect. 1566 */ 1567 public void onDisconnect() {} 1568 1569 /** 1570 * Notifies this Connection of a request to disconnect a participant of the conference managed 1571 * by the connection. 1572 * 1573 * @param endpoint the {@link Uri} of the participant to disconnect. 1574 * @hide 1575 */ 1576 public void onDisconnectConferenceParticipant(Uri endpoint) {} 1577 1578 /** 1579 * Notifies this Connection of a request to separate from its parent conference. 1580 */ 1581 public void onSeparate() {} 1582 1583 /** 1584 * Notifies this Connection of a request to abort. 1585 */ 1586 public void onAbort() {} 1587 1588 /** 1589 * Notifies this Connection of a request to hold. 1590 */ 1591 public void onHold() {} 1592 1593 /** 1594 * Notifies this Connection of a request to exit a hold state. 1595 */ 1596 public void onUnhold() {} 1597 1598 /** 1599 * Notifies this Connection, which is in {@link #STATE_RINGING}, of 1600 * a request to accept. 1601 * 1602 * @param videoState The video state in which to answer the connection. 1603 */ 1604 public void onAnswer(int videoState) {} 1605 1606 /** 1607 * Notifies this Connection, which is in {@link #STATE_RINGING}, of 1608 * a request to accept. 1609 */ 1610 public void onAnswer() { 1611 onAnswer(VideoProfile.STATE_AUDIO_ONLY); 1612 } 1613 1614 /** 1615 * Notifies this Connection, which is in {@link #STATE_RINGING}, of 1616 * a request to reject. 1617 */ 1618 public void onReject() {} 1619 1620 /** 1621 * Notifies this Connection whether the user wishes to proceed with the post-dial DTMF codes. 1622 */ 1623 public void onPostDialContinue(boolean proceed) {} 1624 1625 static String toLogSafePhoneNumber(String number) { 1626 // For unknown number, log empty string. 1627 if (number == null) { 1628 return ""; 1629 } 1630 1631 if (PII_DEBUG) { 1632 // When PII_DEBUG is true we emit PII. 1633 return number; 1634 } 1635 1636 // Do exactly same thing as Uri#toSafeString() does, which will enable us to compare 1637 // sanitized phone numbers. 1638 StringBuilder builder = new StringBuilder(); 1639 for (int i = 0; i < number.length(); i++) { 1640 char c = number.charAt(i); 1641 if (c == '-' || c == '@' || c == '.') { 1642 builder.append(c); 1643 } else { 1644 builder.append('x'); 1645 } 1646 } 1647 return builder.toString(); 1648 } 1649 1650 private void setState(int state) { 1651 checkImmutable(); 1652 if (mState == STATE_DISCONNECTED && mState != state) { 1653 Log.d(this, "Connection already DISCONNECTED; cannot transition out of this state."); 1654 return; 1655 } 1656 if (mState != state) { 1657 Log.d(this, "setState: %s", stateToString(state)); 1658 mState = state; 1659 onStateChanged(state); 1660 for (Listener l : mListeners) { 1661 l.onStateChanged(this, state); 1662 } 1663 } 1664 } 1665 1666 private static class FailureSignalingConnection extends Connection { 1667 private boolean mImmutable = false; 1668 public FailureSignalingConnection(DisconnectCause disconnectCause) { 1669 setDisconnected(disconnectCause); 1670 mImmutable = true; 1671 } 1672 1673 public void checkImmutable() { 1674 if (mImmutable) { 1675 throw new UnsupportedOperationException("Connection is immutable"); 1676 } 1677 } 1678 } 1679 1680 /** 1681 * Return a {@code Connection} which represents a failed connection attempt. The returned 1682 * {@code Connection} will have a {@link android.telecom.DisconnectCause} and as specified, 1683 * and a {@link #getState()} of {@link #STATE_DISCONNECTED}. 1684 * <p> 1685 * The returned {@code Connection} can be assumed to {@link #destroy()} itself when appropriate, 1686 * so users of this method need not maintain a reference to its return value to destroy it. 1687 * 1688 * @param disconnectCause The disconnect cause, ({@see android.telecomm.DisconnectCause}). 1689 * @return A {@code Connection} which indicates failure. 1690 */ 1691 public static Connection createFailedConnection(DisconnectCause disconnectCause) { 1692 return new FailureSignalingConnection(disconnectCause); 1693 } 1694 1695 /** 1696 * Override to throw an {@link UnsupportedOperationException} if this {@code Connection} is 1697 * not intended to be mutated, e.g., if it is a marker for failure. Only for framework use; 1698 * this should never be un-@hide-den. 1699 * 1700 * @hide 1701 */ 1702 public void checkImmutable() {} 1703 1704 /** 1705 * Return a {@code Connection} which represents a canceled connection attempt. The returned 1706 * {@code Connection} will have state {@link #STATE_DISCONNECTED}, and cannot be moved out of 1707 * that state. This connection should not be used for anything, and no other 1708 * {@code Connection}s should be attempted. 1709 * <p> 1710 * so users of this method need not maintain a reference to its return value to destroy it. 1711 * 1712 * @return A {@code Connection} which indicates that the underlying connection should 1713 * be canceled. 1714 */ 1715 public static Connection createCanceledConnection() { 1716 return new FailureSignalingConnection(new DisconnectCause(DisconnectCause.CANCELED)); 1717 } 1718 1719 private final void fireOnConferenceableConnectionsChanged() { 1720 for (Listener l : mListeners) { 1721 l.onConferenceablesChanged(this, getConferenceables()); 1722 } 1723 } 1724 1725 private final void fireConferenceChanged() { 1726 for (Listener l : mListeners) { 1727 l.onConferenceChanged(this, mConference); 1728 } 1729 } 1730 1731 private final void clearConferenceableList() { 1732 for (Conferenceable c : mConferenceables) { 1733 if (c instanceof Connection) { 1734 Connection connection = (Connection) c; 1735 connection.removeConnectionListener(mConnectionDeathListener); 1736 } else if (c instanceof Conference) { 1737 Conference conference = (Conference) c; 1738 conference.removeListener(mConferenceDeathListener); 1739 } 1740 } 1741 mConferenceables.clear(); 1742 } 1743 1744 /** 1745 * Notifies listeners that the merge request failed. 1746 * 1747 * @hide 1748 */ 1749 protected final void notifyConferenceMergeFailed() { 1750 for (Listener l : mListeners) { 1751 l.onConferenceMergeFailed(this); 1752 } 1753 } 1754 1755 /** 1756 * Notifies listeners of a change to conference participant(s). 1757 * 1758 * @param conferenceParticipants The participants. 1759 * @hide 1760 */ 1761 protected final void updateConferenceParticipants( 1762 List<ConferenceParticipant> conferenceParticipants) { 1763 for (Listener l : mListeners) { 1764 l.onConferenceParticipantsChanged(this, conferenceParticipants); 1765 } 1766 } 1767 1768 /** 1769 * Notifies listeners that a conference call has been started. 1770 * @hide 1771 */ 1772 protected void notifyConferenceStarted() { 1773 for (Listener l : mListeners) { 1774 l.onConferenceStarted(); 1775 } 1776 } 1777} 1778