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