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