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