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