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.telecom.IConnectionService; 20 import com.android.internal.telecom.IVideoCallback; 21 import com.android.internal.telecom.IVideoProvider; 22 23 import android.annotation.NonNull; 24 import android.annotation.Nullable; 25 import android.annotation.SystemApi; 26 import android.hardware.camera2.CameraManager; 27 import android.net.Uri; 28 import android.os.BadParcelableException; 29 import android.os.Bundle; 30 import android.os.Handler; 31 import android.os.IBinder; 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 * A connection provided to a {@link ConnectionService} by another {@code ConnectionService} 43 * running in a different process. 44 * 45 * @see ConnectionService#createRemoteOutgoingConnection(PhoneAccountHandle, ConnectionRequest) 46 * @see ConnectionService#createRemoteIncomingConnection(PhoneAccountHandle, ConnectionRequest) 47 */ 48 public final class RemoteConnection { 49 50 /** 51 * Callback base class for {@link RemoteConnection}. 52 */ 53 public static abstract class Callback { 54 /** 55 * Invoked when the state of this {@code RemoteConnection} has changed. See 56 * {@link #getState()}. 57 * 58 * @param connection The {@code RemoteConnection} invoking this method. 59 * @param state The new state of the {@code RemoteConnection}. 60 */ onStateChanged(RemoteConnection connection, int state)61 public void onStateChanged(RemoteConnection connection, int state) {} 62 63 /** 64 * Invoked when this {@code RemoteConnection} is disconnected. 65 * 66 * @param connection The {@code RemoteConnection} invoking this method. 67 * @param disconnectCause The ({@see DisconnectCause}) associated with this failed 68 * connection. 69 */ onDisconnected( RemoteConnection connection, DisconnectCause disconnectCause)70 public void onDisconnected( 71 RemoteConnection connection, 72 DisconnectCause disconnectCause) {} 73 74 /** 75 * Invoked when this {@code RemoteConnection} is requesting ringback. See 76 * {@link #isRingbackRequested()}. 77 * 78 * @param connection The {@code RemoteConnection} invoking this method. 79 * @param ringback Whether the {@code RemoteConnection} is requesting ringback. 80 */ onRingbackRequested(RemoteConnection connection, boolean ringback)81 public void onRingbackRequested(RemoteConnection connection, boolean ringback) {} 82 83 /** 84 * Indicates that the call capabilities of this {@code RemoteConnection} have changed. 85 * See {@link #getConnectionCapabilities()}. 86 * 87 * @param connection The {@code RemoteConnection} invoking this method. 88 * @param connectionCapabilities The new capabilities of the {@code RemoteConnection}. 89 */ onConnectionCapabilitiesChanged( RemoteConnection connection, int connectionCapabilities)90 public void onConnectionCapabilitiesChanged( 91 RemoteConnection connection, 92 int connectionCapabilities) {} 93 94 /** 95 * Indicates that the call properties of this {@code RemoteConnection} have changed. 96 * See {@link #getConnectionProperties()}. 97 * 98 * @param connection The {@code RemoteConnection} invoking this method. 99 * @param connectionProperties The new properties of the {@code RemoteConnection}. 100 */ onConnectionPropertiesChanged( RemoteConnection connection, int connectionProperties)101 public void onConnectionPropertiesChanged( 102 RemoteConnection connection, 103 int connectionProperties) {} 104 105 /** 106 * Invoked when the post-dial sequence in the outgoing {@code Connection} has reached a 107 * pause character. This causes the post-dial signals to stop pending user confirmation. An 108 * implementation should present this choice to the user and invoke 109 * {@link RemoteConnection#postDialContinue(boolean)} when the user makes the choice. 110 * 111 * @param connection The {@code RemoteConnection} invoking this method. 112 * @param remainingPostDialSequence The post-dial characters that remain to be sent. 113 */ onPostDialWait(RemoteConnection connection, String remainingPostDialSequence)114 public void onPostDialWait(RemoteConnection connection, String remainingPostDialSequence) {} 115 116 /** 117 * Invoked when the post-dial sequence in the outgoing {@code Connection} has processed 118 * a character. 119 * 120 * @param connection The {@code RemoteConnection} invoking this method. 121 * @param nextChar The character being processed. 122 */ onPostDialChar(RemoteConnection connection, char nextChar)123 public void onPostDialChar(RemoteConnection connection, char nextChar) {} 124 125 /** 126 * Indicates that the VOIP audio status of this {@code RemoteConnection} has changed. 127 * See {@link #isVoipAudioMode()}. 128 * 129 * @param connection The {@code RemoteConnection} invoking this method. 130 * @param isVoip Whether the new audio state of the {@code RemoteConnection} is VOIP. 131 */ onVoipAudioChanged(RemoteConnection connection, boolean isVoip)132 public void onVoipAudioChanged(RemoteConnection connection, boolean isVoip) {} 133 134 /** 135 * Indicates that the status hints of this {@code RemoteConnection} have changed. See 136 * {@link #getStatusHints()} ()}. 137 * 138 * @param connection The {@code RemoteConnection} invoking this method. 139 * @param statusHints The new status hints of the {@code RemoteConnection}. 140 */ onStatusHintsChanged(RemoteConnection connection, StatusHints statusHints)141 public void onStatusHintsChanged(RemoteConnection connection, StatusHints statusHints) {} 142 143 /** 144 * Indicates that the address (e.g., phone number) of this {@code RemoteConnection} has 145 * changed. See {@link #getAddress()} and {@link #getAddressPresentation()}. 146 * 147 * @param connection The {@code RemoteConnection} invoking this method. 148 * @param address The new address of the {@code RemoteConnection}. 149 * @param presentation The presentation requirements for the address. 150 * See {@link TelecomManager} for valid values. 151 */ onAddressChanged(RemoteConnection connection, Uri address, int presentation)152 public void onAddressChanged(RemoteConnection connection, Uri address, int presentation) {} 153 154 /** 155 * Indicates that the caller display name of this {@code RemoteConnection} has changed. 156 * See {@link #getCallerDisplayName()} and {@link #getCallerDisplayNamePresentation()}. 157 * 158 * @param connection The {@code RemoteConnection} invoking this method. 159 * @param callerDisplayName The new caller display name of the {@code RemoteConnection}. 160 * @param presentation The presentation requirements for the handle. 161 * See {@link TelecomManager} for valid values. 162 */ onCallerDisplayNameChanged( RemoteConnection connection, String callerDisplayName, int presentation)163 public void onCallerDisplayNameChanged( 164 RemoteConnection connection, String callerDisplayName, int presentation) {} 165 166 /** 167 * Indicates that the video state of this {@code RemoteConnection} has changed. 168 * See {@link #getVideoState()}. 169 * 170 * @param connection The {@code RemoteConnection} invoking this method. 171 * @param videoState The new video state of the {@code RemoteConnection}. 172 */ onVideoStateChanged(RemoteConnection connection, int videoState)173 public void onVideoStateChanged(RemoteConnection connection, int videoState) {} 174 175 /** 176 * Indicates that this {@code RemoteConnection} has been destroyed. No further requests 177 * should be made to the {@code RemoteConnection}, and references to it should be cleared. 178 * 179 * @param connection The {@code RemoteConnection} invoking this method. 180 */ onDestroyed(RemoteConnection connection)181 public void onDestroyed(RemoteConnection connection) {} 182 183 /** 184 * Indicates that the {@code RemoteConnection}s with which this {@code RemoteConnection} 185 * may be asked to create a conference has changed. 186 * 187 * @param connection The {@code RemoteConnection} invoking this method. 188 * @param conferenceableConnections The {@code RemoteConnection}s with which this 189 * {@code RemoteConnection} may be asked to create a conference. 190 */ onConferenceableConnectionsChanged( RemoteConnection connection, List<RemoteConnection> conferenceableConnections)191 public void onConferenceableConnectionsChanged( 192 RemoteConnection connection, 193 List<RemoteConnection> conferenceableConnections) {} 194 195 /** 196 * Indicates that the {@code VideoProvider} associated with this {@code RemoteConnection} 197 * has changed. 198 * 199 * @param connection The {@code RemoteConnection} invoking this method. 200 * @param videoProvider The new {@code VideoProvider} associated with this 201 * {@code RemoteConnection}. 202 */ onVideoProviderChanged( RemoteConnection connection, VideoProvider videoProvider)203 public void onVideoProviderChanged( 204 RemoteConnection connection, VideoProvider videoProvider) {} 205 206 /** 207 * Indicates that the {@code RemoteConference} that this {@code RemoteConnection} is a part 208 * of has changed. 209 * 210 * @param connection The {@code RemoteConnection} invoking this method. 211 * @param conference The {@code RemoteConference} of which this {@code RemoteConnection} is 212 * a part, which may be {@code null}. 213 */ onConferenceChanged( RemoteConnection connection, RemoteConference conference)214 public void onConferenceChanged( 215 RemoteConnection connection, 216 RemoteConference conference) {} 217 218 /** 219 * Handles changes to the {@code RemoteConnection} extras. 220 * 221 * @param connection The {@code RemoteConnection} invoking this method. 222 * @param extras The extras containing other information associated with the connection. 223 */ onExtrasChanged(RemoteConnection connection, @Nullable Bundle extras)224 public void onExtrasChanged(RemoteConnection connection, @Nullable Bundle extras) {} 225 226 /** 227 * Handles a connection event propagated to this {@link RemoteConnection}. 228 * <p> 229 * Connection events originate from {@link Connection#sendConnectionEvent(String, Bundle)}. 230 * 231 * @param connection The {@code RemoteConnection} invoking this method. 232 * @param event The connection event. 233 * @param extras Extras associated with the event. 234 */ onConnectionEvent(RemoteConnection connection, String event, Bundle extras)235 public void onConnectionEvent(RemoteConnection connection, String event, Bundle extras) {} 236 237 /** 238 * Indicates that a RTT session was successfully established on this 239 * {@link RemoteConnection}. See {@link Connection#sendRttInitiationSuccess()}. 240 * @hide 241 * @param connection The {@code RemoteConnection} invoking this method. 242 */ onRttInitiationSuccess(RemoteConnection connection)243 public void onRttInitiationSuccess(RemoteConnection connection) {} 244 245 /** 246 * Indicates that a RTT session failed to be established on this 247 * {@link RemoteConnection}. See {@link Connection#sendRttInitiationFailure()}. 248 * @hide 249 * @param connection The {@code RemoteConnection} invoking this method. 250 * @param reason One of the reason codes defined in {@link Connection.RttModifyStatus}, 251 * with the exception of 252 * {@link Connection.RttModifyStatus#SESSION_MODIFY_REQUEST_SUCCESS}. 253 */ onRttInitiationFailure(RemoteConnection connection, int reason)254 public void onRttInitiationFailure(RemoteConnection connection, int reason) {} 255 256 /** 257 * Indicates that an established RTT session was terminated remotely on this 258 * {@link RemoteConnection}. See {@link Connection#sendRttSessionRemotelyTerminated()} 259 * @hide 260 * @param connection The {@code RemoteConnection} invoking this method. 261 */ onRttSessionRemotelyTerminated(RemoteConnection connection)262 public void onRttSessionRemotelyTerminated(RemoteConnection connection) {} 263 264 /** 265 * Indicates that the remote user on this {@link RemoteConnection} has requested an upgrade 266 * to an RTT session. See {@link Connection#sendRemoteRttRequest()} 267 * @hide 268 * @param connection The {@code RemoteConnection} invoking this method. 269 */ onRemoteRttRequest(RemoteConnection connection)270 public void onRemoteRttRequest(RemoteConnection connection) {} 271 } 272 273 /** 274 * {@link RemoteConnection.VideoProvider} associated with a {@link RemoteConnection}. Used to 275 * receive video related events and control the video associated with a 276 * {@link RemoteConnection}. 277 * 278 * @see Connection.VideoProvider 279 */ 280 public static class VideoProvider { 281 282 /** 283 * Callback class used by the {@link RemoteConnection.VideoProvider} to relay events from 284 * the {@link Connection.VideoProvider}. 285 */ 286 public abstract static class Callback { 287 /** 288 * Reports a session modification request received from the 289 * {@link Connection.VideoProvider} associated with a {@link RemoteConnection}. 290 * 291 * @param videoProvider The {@link RemoteConnection.VideoProvider} invoking this method. 292 * @param videoProfile The requested video call profile. 293 * @see InCallService.VideoCall.Callback#onSessionModifyRequestReceived(VideoProfile) 294 * @see Connection.VideoProvider#receiveSessionModifyRequest(VideoProfile) 295 */ onSessionModifyRequestReceived( VideoProvider videoProvider, VideoProfile videoProfile)296 public void onSessionModifyRequestReceived( 297 VideoProvider videoProvider, 298 VideoProfile videoProfile) {} 299 300 /** 301 * Reports a session modification response received from the 302 * {@link Connection.VideoProvider} associated with a {@link RemoteConnection}. 303 * 304 * @param videoProvider The {@link RemoteConnection.VideoProvider} invoking this method. 305 * @param status Status of the session modify request. 306 * @param requestedProfile The original request which was sent to the peer device. 307 * @param responseProfile The actual profile changes made by the peer device. 308 * @see InCallService.VideoCall.Callback#onSessionModifyResponseReceived(int, 309 * VideoProfile, VideoProfile) 310 * @see Connection.VideoProvider#receiveSessionModifyResponse(int, VideoProfile, 311 * VideoProfile) 312 */ onSessionModifyResponseReceived( VideoProvider videoProvider, int status, VideoProfile requestedProfile, VideoProfile responseProfile)313 public void onSessionModifyResponseReceived( 314 VideoProvider videoProvider, 315 int status, 316 VideoProfile requestedProfile, 317 VideoProfile responseProfile) {} 318 319 /** 320 * Reports a call session event received from the {@link Connection.VideoProvider} 321 * associated with a {@link RemoteConnection}. 322 * 323 * @param videoProvider The {@link RemoteConnection.VideoProvider} invoking this method. 324 * @param event The event. 325 * @see InCallService.VideoCall.Callback#onCallSessionEvent(int) 326 * @see Connection.VideoProvider#handleCallSessionEvent(int) 327 */ onCallSessionEvent(VideoProvider videoProvider, int event)328 public void onCallSessionEvent(VideoProvider videoProvider, int event) {} 329 330 /** 331 * Reports a change in the peer video dimensions received from the 332 * {@link Connection.VideoProvider} associated with a {@link RemoteConnection}. 333 * 334 * @param videoProvider The {@link RemoteConnection.VideoProvider} invoking this method. 335 * @param width The updated peer video width. 336 * @param height The updated peer video height. 337 * @see InCallService.VideoCall.Callback#onPeerDimensionsChanged(int, int) 338 * @see Connection.VideoProvider#changePeerDimensions(int, int) 339 */ onPeerDimensionsChanged(VideoProvider videoProvider, int width, int height)340 public void onPeerDimensionsChanged(VideoProvider videoProvider, int width, 341 int height) {} 342 343 /** 344 * Reports a change in the data usage (in bytes) received from the 345 * {@link Connection.VideoProvider} associated with a {@link RemoteConnection}. 346 * 347 * @param videoProvider The {@link RemoteConnection.VideoProvider} invoking this method. 348 * @param dataUsage The updated data usage (in bytes). 349 * @see InCallService.VideoCall.Callback#onCallDataUsageChanged(long) 350 * @see Connection.VideoProvider#setCallDataUsage(long) 351 */ onCallDataUsageChanged(VideoProvider videoProvider, long dataUsage)352 public void onCallDataUsageChanged(VideoProvider videoProvider, long dataUsage) {} 353 354 /** 355 * Reports a change in the capabilities of the current camera, received from the 356 * {@link Connection.VideoProvider} associated with a {@link RemoteConnection}. 357 * 358 * @param videoProvider The {@link RemoteConnection.VideoProvider} invoking this method. 359 * @param cameraCapabilities The changed camera capabilities. 360 * @see InCallService.VideoCall.Callback#onCameraCapabilitiesChanged( 361 * VideoProfile.CameraCapabilities) 362 * @see Connection.VideoProvider#changeCameraCapabilities( 363 * VideoProfile.CameraCapabilities) 364 */ onCameraCapabilitiesChanged( VideoProvider videoProvider, VideoProfile.CameraCapabilities cameraCapabilities)365 public void onCameraCapabilitiesChanged( 366 VideoProvider videoProvider, 367 VideoProfile.CameraCapabilities cameraCapabilities) {} 368 369 /** 370 * Reports a change in the video quality received from the 371 * {@link Connection.VideoProvider} associated with a {@link RemoteConnection}. 372 * 373 * @param videoProvider The {@link RemoteConnection.VideoProvider} invoking this method. 374 * @param videoQuality The updated peer video quality. 375 * @see InCallService.VideoCall.Callback#onVideoQualityChanged(int) 376 * @see Connection.VideoProvider#changeVideoQuality(int) 377 */ onVideoQualityChanged(VideoProvider videoProvider, int videoQuality)378 public void onVideoQualityChanged(VideoProvider videoProvider, int videoQuality) {} 379 } 380 381 private final IVideoCallback mVideoCallbackDelegate = new IVideoCallback() { 382 @Override 383 public void receiveSessionModifyRequest(VideoProfile videoProfile) { 384 for (Callback l : mCallbacks) { 385 l.onSessionModifyRequestReceived(VideoProvider.this, videoProfile); 386 } 387 } 388 389 @Override 390 public void receiveSessionModifyResponse(int status, VideoProfile requestedProfile, 391 VideoProfile responseProfile) { 392 for (Callback l : mCallbacks) { 393 l.onSessionModifyResponseReceived( 394 VideoProvider.this, 395 status, 396 requestedProfile, 397 responseProfile); 398 } 399 } 400 401 @Override 402 public void handleCallSessionEvent(int event) { 403 for (Callback l : mCallbacks) { 404 l.onCallSessionEvent(VideoProvider.this, event); 405 } 406 } 407 408 @Override 409 public void changePeerDimensions(int width, int height) { 410 for (Callback l : mCallbacks) { 411 l.onPeerDimensionsChanged(VideoProvider.this, width, height); 412 } 413 } 414 415 @Override 416 public void changeCallDataUsage(long dataUsage) { 417 for (Callback l : mCallbacks) { 418 l.onCallDataUsageChanged(VideoProvider.this, dataUsage); 419 } 420 } 421 422 @Override 423 public void changeCameraCapabilities( 424 VideoProfile.CameraCapabilities cameraCapabilities) { 425 for (Callback l : mCallbacks) { 426 l.onCameraCapabilitiesChanged(VideoProvider.this, cameraCapabilities); 427 } 428 } 429 430 @Override 431 public void changeVideoQuality(int videoQuality) { 432 for (Callback l : mCallbacks) { 433 l.onVideoQualityChanged(VideoProvider.this, videoQuality); 434 } 435 } 436 437 @Override 438 public IBinder asBinder() { 439 return null; 440 } 441 }; 442 443 private final VideoCallbackServant mVideoCallbackServant = 444 new VideoCallbackServant(mVideoCallbackDelegate); 445 446 private final IVideoProvider mVideoProviderBinder; 447 448 private final String mCallingPackage; 449 450 private final int mTargetSdkVersion; 451 452 /** 453 * ConcurrentHashMap constructor params: 8 is initial table size, 0.9f is 454 * load factor before resizing, 1 means we only expect a single thread to 455 * access the map so make only a single shard 456 */ 457 private final Set<Callback> mCallbacks = Collections.newSetFromMap( 458 new ConcurrentHashMap<Callback, Boolean>(8, 0.9f, 1)); 459 VideoProvider(IVideoProvider videoProviderBinder, String callingPackage, int targetSdkVersion)460 VideoProvider(IVideoProvider videoProviderBinder, String callingPackage, 461 int targetSdkVersion) { 462 463 mVideoProviderBinder = videoProviderBinder; 464 mCallingPackage = callingPackage; 465 mTargetSdkVersion = targetSdkVersion; 466 try { 467 mVideoProviderBinder.addVideoCallback(mVideoCallbackServant.getStub().asBinder()); 468 } catch (RemoteException e) { 469 } 470 } 471 472 /** 473 * Registers a callback to receive commands and state changes for video calls. 474 * 475 * @param l The video call callback. 476 */ registerCallback(Callback l)477 public void registerCallback(Callback l) { 478 mCallbacks.add(l); 479 } 480 481 /** 482 * Clears the video call callback set via {@link #registerCallback}. 483 * 484 * @param l The video call callback to clear. 485 */ unregisterCallback(Callback l)486 public void unregisterCallback(Callback l) { 487 mCallbacks.remove(l); 488 } 489 490 /** 491 * Sets the camera to be used for the outgoing video for the 492 * {@link RemoteConnection.VideoProvider}. 493 * 494 * @param cameraId The id of the camera (use ids as reported by 495 * {@link CameraManager#getCameraIdList()}). 496 * @see Connection.VideoProvider#onSetCamera(String) 497 */ setCamera(String cameraId)498 public void setCamera(String cameraId) { 499 try { 500 mVideoProviderBinder.setCamera(cameraId, mCallingPackage, mTargetSdkVersion); 501 } catch (RemoteException e) { 502 } 503 } 504 505 /** 506 * Sets the surface to be used for displaying a preview of what the user's camera is 507 * currently capturing for the {@link RemoteConnection.VideoProvider}. 508 * 509 * @param surface The {@link Surface}. 510 * @see Connection.VideoProvider#onSetPreviewSurface(Surface) 511 */ setPreviewSurface(Surface surface)512 public void setPreviewSurface(Surface surface) { 513 try { 514 mVideoProviderBinder.setPreviewSurface(surface); 515 } catch (RemoteException e) { 516 } 517 } 518 519 /** 520 * Sets the surface to be used for displaying the video received from the remote device for 521 * the {@link RemoteConnection.VideoProvider}. 522 * 523 * @param surface The {@link Surface}. 524 * @see Connection.VideoProvider#onSetDisplaySurface(Surface) 525 */ setDisplaySurface(Surface surface)526 public void setDisplaySurface(Surface surface) { 527 try { 528 mVideoProviderBinder.setDisplaySurface(surface); 529 } catch (RemoteException e) { 530 } 531 } 532 533 /** 534 * Sets the device orientation, in degrees, for the {@link RemoteConnection.VideoProvider}. 535 * Assumes that a standard portrait orientation of the device is 0 degrees. 536 * 537 * @param rotation The device orientation, in degrees. 538 * @see Connection.VideoProvider#onSetDeviceOrientation(int) 539 */ setDeviceOrientation(int rotation)540 public void setDeviceOrientation(int rotation) { 541 try { 542 mVideoProviderBinder.setDeviceOrientation(rotation); 543 } catch (RemoteException e) { 544 } 545 } 546 547 /** 548 * Sets camera zoom ratio for the {@link RemoteConnection.VideoProvider}. 549 * 550 * @param value The camera zoom ratio. 551 * @see Connection.VideoProvider#onSetZoom(float) 552 */ setZoom(float value)553 public void setZoom(float value) { 554 try { 555 mVideoProviderBinder.setZoom(value); 556 } catch (RemoteException e) { 557 } 558 } 559 560 /** 561 * Issues a request to modify the properties of the current video session for the 562 * {@link RemoteConnection.VideoProvider}. 563 * 564 * @param fromProfile The video profile prior to the request. 565 * @param toProfile The video profile with the requested changes made. 566 * @see Connection.VideoProvider#onSendSessionModifyRequest(VideoProfile, VideoProfile) 567 */ sendSessionModifyRequest(VideoProfile fromProfile, VideoProfile toProfile)568 public void sendSessionModifyRequest(VideoProfile fromProfile, VideoProfile toProfile) { 569 try { 570 mVideoProviderBinder.sendSessionModifyRequest(fromProfile, toProfile); 571 } catch (RemoteException e) { 572 } 573 } 574 575 /** 576 * Provides a response to a request to change the current call video session 577 * properties for the {@link RemoteConnection.VideoProvider}. 578 * 579 * @param responseProfile The response call video properties. 580 * @see Connection.VideoProvider#onSendSessionModifyResponse(VideoProfile) 581 */ sendSessionModifyResponse(VideoProfile responseProfile)582 public void sendSessionModifyResponse(VideoProfile responseProfile) { 583 try { 584 mVideoProviderBinder.sendSessionModifyResponse(responseProfile); 585 } catch (RemoteException e) { 586 } 587 } 588 589 /** 590 * Issues a request to retrieve the capabilities of the current camera for the 591 * {@link RemoteConnection.VideoProvider}. 592 * 593 * @see Connection.VideoProvider#onRequestCameraCapabilities() 594 */ requestCameraCapabilities()595 public void requestCameraCapabilities() { 596 try { 597 mVideoProviderBinder.requestCameraCapabilities(); 598 } catch (RemoteException e) { 599 } 600 } 601 602 /** 603 * Issues a request to retrieve the data usage (in bytes) of the video portion of the 604 * {@link RemoteConnection} for the {@link RemoteConnection.VideoProvider}. 605 * 606 * @see Connection.VideoProvider#onRequestConnectionDataUsage() 607 */ requestCallDataUsage()608 public void requestCallDataUsage() { 609 try { 610 mVideoProviderBinder.requestCallDataUsage(); 611 } catch (RemoteException e) { 612 } 613 } 614 615 /** 616 * Sets the {@link Uri} of an image to be displayed to the peer device when the video signal 617 * is paused, for the {@link RemoteConnection.VideoProvider}. 618 * 619 * @see Connection.VideoProvider#onSetPauseImage(Uri) 620 */ setPauseImage(Uri uri)621 public void setPauseImage(Uri uri) { 622 try { 623 mVideoProviderBinder.setPauseImage(uri); 624 } catch (RemoteException e) { 625 } 626 } 627 } 628 629 private IConnectionService mConnectionService; 630 private final String mConnectionId; 631 /** 632 * ConcurrentHashMap constructor params: 8 is initial table size, 0.9f is 633 * load factor before resizing, 1 means we only expect a single thread to 634 * access the map so make only a single shard 635 */ 636 private final Set<CallbackRecord> mCallbackRecords = Collections.newSetFromMap( 637 new ConcurrentHashMap<CallbackRecord, Boolean>(8, 0.9f, 1)); 638 private final List<RemoteConnection> mConferenceableConnections = new ArrayList<>(); 639 private final List<RemoteConnection> mUnmodifiableconferenceableConnections = 640 Collections.unmodifiableList(mConferenceableConnections); 641 642 private int mState = Connection.STATE_NEW; 643 private DisconnectCause mDisconnectCause; 644 private boolean mRingbackRequested; 645 private boolean mConnected; 646 private int mConnectionCapabilities; 647 private int mConnectionProperties; 648 private int mVideoState; 649 private VideoProvider mVideoProvider; 650 private boolean mIsVoipAudioMode; 651 private StatusHints mStatusHints; 652 private Uri mAddress; 653 private int mAddressPresentation; 654 private String mCallerDisplayName; 655 private int mCallerDisplayNamePresentation; 656 private RemoteConference mConference; 657 private Bundle mExtras; 658 659 /** 660 * @hide 661 */ RemoteConnection( String id, IConnectionService connectionService, ConnectionRequest request)662 RemoteConnection( 663 String id, 664 IConnectionService connectionService, 665 ConnectionRequest request) { 666 mConnectionId = id; 667 mConnectionService = connectionService; 668 mConnected = true; 669 mState = Connection.STATE_INITIALIZING; 670 } 671 672 /** 673 * @hide 674 */ RemoteConnection(String callId, IConnectionService connectionService, ParcelableConnection connection, String callingPackage, int targetSdkVersion)675 RemoteConnection(String callId, IConnectionService connectionService, 676 ParcelableConnection connection, String callingPackage, int targetSdkVersion) { 677 mConnectionId = callId; 678 mConnectionService = connectionService; 679 mConnected = true; 680 mState = connection.getState(); 681 mDisconnectCause = connection.getDisconnectCause(); 682 mRingbackRequested = connection.isRingbackRequested(); 683 mConnectionCapabilities = connection.getConnectionCapabilities(); 684 mConnectionProperties = connection.getConnectionProperties(); 685 mVideoState = connection.getVideoState(); 686 IVideoProvider videoProvider = connection.getVideoProvider(); 687 if (videoProvider != null) { 688 mVideoProvider = new RemoteConnection.VideoProvider(videoProvider, callingPackage, 689 targetSdkVersion); 690 } else { 691 mVideoProvider = null; 692 } 693 mIsVoipAudioMode = connection.getIsVoipAudioMode(); 694 mStatusHints = connection.getStatusHints(); 695 mAddress = connection.getHandle(); 696 mAddressPresentation = connection.getHandlePresentation(); 697 mCallerDisplayName = connection.getCallerDisplayName(); 698 mCallerDisplayNamePresentation = connection.getCallerDisplayNamePresentation(); 699 mConference = null; 700 putExtras(connection.getExtras()); 701 702 // Stash the original connection ID as it exists in the source ConnectionService. 703 // Telecom will use this to avoid adding duplicates later. 704 // See comments on Connection.EXTRA_ORIGINAL_CONNECTION_ID for more information. 705 Bundle newExtras = new Bundle(); 706 newExtras.putString(Connection.EXTRA_ORIGINAL_CONNECTION_ID, callId); 707 putExtras(newExtras); 708 } 709 710 /** 711 * Create a RemoteConnection which is used for failed connections. Note that using it for any 712 * "real" purpose will almost certainly fail. Callers should note the failure and act 713 * accordingly (moving on to another RemoteConnection, for example) 714 * 715 * @param disconnectCause The reason for the failed connection. 716 * @hide 717 */ RemoteConnection(DisconnectCause disconnectCause)718 RemoteConnection(DisconnectCause disconnectCause) { 719 mConnectionId = "NULL"; 720 mConnected = false; 721 mState = Connection.STATE_DISCONNECTED; 722 mDisconnectCause = disconnectCause; 723 } 724 725 /** 726 * Adds a callback to this {@code RemoteConnection}. 727 * 728 * @param callback A {@code Callback}. 729 */ registerCallback(Callback callback)730 public void registerCallback(Callback callback) { 731 registerCallback(callback, new Handler()); 732 } 733 734 /** 735 * Adds a callback to this {@code RemoteConnection}. 736 * 737 * @param callback A {@code Callback}. 738 * @param handler A {@code Handler} which command and status changes will be delivered to. 739 */ registerCallback(Callback callback, Handler handler)740 public void registerCallback(Callback callback, Handler handler) { 741 unregisterCallback(callback); 742 if (callback != null && handler != null) { 743 mCallbackRecords.add(new CallbackRecord(callback, handler)); 744 } 745 } 746 747 /** 748 * Removes a callback from this {@code RemoteConnection}. 749 * 750 * @param callback A {@code Callback}. 751 */ unregisterCallback(Callback callback)752 public void unregisterCallback(Callback callback) { 753 if (callback != null) { 754 for (CallbackRecord record : mCallbackRecords) { 755 if (record.getCallback() == callback) { 756 mCallbackRecords.remove(record); 757 break; 758 } 759 } 760 } 761 } 762 763 /** 764 * Obtains the state of this {@code RemoteConnection}. 765 * 766 * @return A state value, chosen from the {@code STATE_*} constants. 767 */ getState()768 public int getState() { 769 return mState; 770 } 771 772 /** 773 * Obtains the reason why this {@code RemoteConnection} may have been disconnected. 774 * 775 * @return For a {@link Connection#STATE_DISCONNECTED} {@code RemoteConnection}, the 776 * disconnect cause expressed as a code chosen from among those declared in 777 * {@link DisconnectCause}. 778 */ getDisconnectCause()779 public DisconnectCause getDisconnectCause() { 780 return mDisconnectCause; 781 } 782 783 /** 784 * Obtains the capabilities of this {@code RemoteConnection}. 785 * 786 * @return A bitmask of the capabilities of the {@code RemoteConnection}, as defined in 787 * the {@code CAPABILITY_*} constants in class {@link Connection}. 788 */ getConnectionCapabilities()789 public int getConnectionCapabilities() { 790 return mConnectionCapabilities; 791 } 792 793 /** 794 * Obtains the properties of this {@code RemoteConnection}. 795 * 796 * @return A bitmask of the properties of the {@code RemoteConnection}, as defined in the 797 * {@code PROPERTY_*} constants in class {@link Connection}. 798 */ getConnectionProperties()799 public int getConnectionProperties() { 800 return mConnectionProperties; 801 } 802 803 /** 804 * Determines if the audio mode of this {@code RemoteConnection} is VOIP. 805 * 806 * @return {@code true} if the {@code RemoteConnection}'s current audio mode is VOIP. 807 */ isVoipAudioMode()808 public boolean isVoipAudioMode() { 809 return mIsVoipAudioMode; 810 } 811 812 /** 813 * Obtains status hints pertaining to this {@code RemoteConnection}. 814 * 815 * @return The current {@link StatusHints} of this {@code RemoteConnection}, 816 * or {@code null} if none have been set. 817 */ getStatusHints()818 public StatusHints getStatusHints() { 819 return mStatusHints; 820 } 821 822 /** 823 * Obtains the address of this {@code RemoteConnection}. 824 * 825 * @return The address (e.g., phone number) to which the {@code RemoteConnection} 826 * is currently connected. 827 */ getAddress()828 public Uri getAddress() { 829 return mAddress; 830 } 831 832 /** 833 * Obtains the presentation requirements for the address of this {@code RemoteConnection}. 834 * 835 * @return The presentation requirements for the address. See 836 * {@link TelecomManager} for valid values. 837 */ getAddressPresentation()838 public int getAddressPresentation() { 839 return mAddressPresentation; 840 } 841 842 /** 843 * Obtains the display name for this {@code RemoteConnection}'s caller. 844 * 845 * @return The display name for the caller. 846 */ getCallerDisplayName()847 public CharSequence getCallerDisplayName() { 848 return mCallerDisplayName; 849 } 850 851 /** 852 * Obtains the presentation requirements for this {@code RemoteConnection}'s 853 * caller's display name. 854 * 855 * @return The presentation requirements for the caller display name. See 856 * {@link TelecomManager} for valid values. 857 */ getCallerDisplayNamePresentation()858 public int getCallerDisplayNamePresentation() { 859 return mCallerDisplayNamePresentation; 860 } 861 862 /** 863 * Obtains the video state of this {@code RemoteConnection}. 864 * 865 * @return The video state of the {@code RemoteConnection}. See {@link VideoProfile}. 866 */ getVideoState()867 public int getVideoState() { 868 return mVideoState; 869 } 870 871 /** 872 * Obtains the video provider of this {@code RemoteConnection}. 873 * @return The video provider associated with this {@code RemoteConnection}. 874 */ getVideoProvider()875 public final VideoProvider getVideoProvider() { 876 return mVideoProvider; 877 } 878 879 /** 880 * Obtain the extras associated with this {@code RemoteConnection}. 881 * 882 * @return The extras for this connection. 883 */ getExtras()884 public final Bundle getExtras() { 885 return mExtras; 886 } 887 888 /** 889 * Determines whether this {@code RemoteConnection} is requesting ringback. 890 * 891 * @return Whether the {@code RemoteConnection} is requesting that the framework play a 892 * ringback tone on its behalf. 893 */ isRingbackRequested()894 public boolean isRingbackRequested() { 895 return mRingbackRequested; 896 } 897 898 /** 899 * Instructs this {@code RemoteConnection} to abort. 900 */ abort()901 public void abort() { 902 try { 903 if (mConnected) { 904 mConnectionService.abort(mConnectionId, null /*Session.Info*/); 905 } 906 } catch (RemoteException ignored) { 907 } 908 } 909 910 /** 911 * Instructs this {@link Connection#STATE_RINGING} {@code RemoteConnection} to answer. 912 */ answer()913 public void answer() { 914 try { 915 if (mConnected) { 916 mConnectionService.answer(mConnectionId, null /*Session.Info*/); 917 } 918 } catch (RemoteException ignored) { 919 } 920 } 921 922 /** 923 * Instructs this {@link Connection#STATE_RINGING} {@code RemoteConnection} to answer. 924 * @param videoState The video state in which to answer the call. 925 * @hide 926 */ answer(int videoState)927 public void answer(int videoState) { 928 try { 929 if (mConnected) { 930 mConnectionService.answerVideo(mConnectionId, videoState, null /*Session.Info*/); 931 } 932 } catch (RemoteException ignored) { 933 } 934 } 935 936 /** 937 * Instructs this {@link Connection#STATE_RINGING} {@code RemoteConnection} to reject. 938 */ reject()939 public void reject() { 940 try { 941 if (mConnected) { 942 mConnectionService.reject(mConnectionId, null /*Session.Info*/); 943 } 944 } catch (RemoteException ignored) { 945 } 946 } 947 948 /** 949 * Instructs this {@code RemoteConnection} to go on hold. 950 */ hold()951 public void hold() { 952 try { 953 if (mConnected) { 954 mConnectionService.hold(mConnectionId, null /*Session.Info*/); 955 } 956 } catch (RemoteException ignored) { 957 } 958 } 959 960 /** 961 * Instructs this {@link Connection#STATE_HOLDING} call to release from hold. 962 */ unhold()963 public void unhold() { 964 try { 965 if (mConnected) { 966 mConnectionService.unhold(mConnectionId, null /*Session.Info*/); 967 } 968 } catch (RemoteException ignored) { 969 } 970 } 971 972 /** 973 * Instructs this {@code RemoteConnection} to disconnect. 974 */ disconnect()975 public void disconnect() { 976 try { 977 if (mConnected) { 978 mConnectionService.disconnect(mConnectionId, null /*Session.Info*/); 979 } 980 } catch (RemoteException ignored) { 981 } 982 } 983 984 /** 985 * Instructs this {@code RemoteConnection} to play a dual-tone multi-frequency signaling 986 * (DTMF) tone. 987 * 988 * Any other currently playing DTMF tone in the specified call is immediately stopped. 989 * 990 * @param digit A character representing the DTMF digit for which to play the tone. This 991 * value must be one of {@code '0'} through {@code '9'}, {@code '*'} or {@code '#'}. 992 */ playDtmfTone(char digit)993 public void playDtmfTone(char digit) { 994 try { 995 if (mConnected) { 996 mConnectionService.playDtmfTone(mConnectionId, digit, null /*Session.Info*/); 997 } 998 } catch (RemoteException ignored) { 999 } 1000 } 1001 1002 /** 1003 * Instructs this {@code RemoteConnection} to stop any dual-tone multi-frequency signaling 1004 * (DTMF) tone currently playing. 1005 * 1006 * DTMF tones are played by calling {@link #playDtmfTone(char)}. If no DTMF tone is 1007 * currently playing, this method will do nothing. 1008 */ stopDtmfTone()1009 public void stopDtmfTone() { 1010 try { 1011 if (mConnected) { 1012 mConnectionService.stopDtmfTone(mConnectionId, null /*Session.Info*/); 1013 } 1014 } catch (RemoteException ignored) { 1015 } 1016 } 1017 1018 /** 1019 * Instructs this {@code RemoteConnection} to continue playing a post-dial DTMF string. 1020 * 1021 * A post-dial DTMF string is a string of digits following the first instance of either 1022 * {@link TelecomManager#DTMF_CHARACTER_WAIT} or {@link TelecomManager#DTMF_CHARACTER_PAUSE}. 1023 * These digits are immediately sent as DTMF tones to the recipient as soon as the 1024 * connection is made. 1025 * 1026 * If the DTMF string contains a {@link TelecomManager#DTMF_CHARACTER_PAUSE} symbol, this 1027 * {@code RemoteConnection} will temporarily pause playing the tones for a pre-defined period 1028 * of time. 1029 * 1030 * If the DTMF string contains a {@link TelecomManager#DTMF_CHARACTER_WAIT} symbol, this 1031 * {@code RemoteConnection} will pause playing the tones and notify callbacks via 1032 * {@link Callback#onPostDialWait(RemoteConnection, String)}. At this point, the in-call app 1033 * should display to the user an indication of this state and an affordance to continue 1034 * the postdial sequence. When the user decides to continue the postdial sequence, the in-call 1035 * app should invoke the {@link #postDialContinue(boolean)} method. 1036 * 1037 * @param proceed Whether or not to continue with the post-dial sequence. 1038 */ postDialContinue(boolean proceed)1039 public void postDialContinue(boolean proceed) { 1040 try { 1041 if (mConnected) { 1042 mConnectionService.onPostDialContinue(mConnectionId, proceed, 1043 null /*Session.Info*/); 1044 } 1045 } catch (RemoteException ignored) { 1046 } 1047 } 1048 1049 /** 1050 * Instructs this {@link RemoteConnection} to pull itself to the local device. 1051 * <p> 1052 * See {@link Call#pullExternalCall()} for more information. 1053 */ pullExternalCall()1054 public void pullExternalCall() { 1055 try { 1056 if (mConnected) { 1057 mConnectionService.pullExternalCall(mConnectionId, null /*Session.Info*/); 1058 } 1059 } catch (RemoteException ignored) { 1060 } 1061 } 1062 1063 /** 1064 * Set the audio state of this {@code RemoteConnection}. 1065 * 1066 * @param state The audio state of this {@code RemoteConnection}. 1067 * @hide 1068 * @deprecated Use {@link #setCallAudioState(CallAudioState)} instead. 1069 */ 1070 @SystemApi 1071 @Deprecated setAudioState(AudioState state)1072 public void setAudioState(AudioState state) { 1073 setCallAudioState(new CallAudioState(state)); 1074 } 1075 1076 /** 1077 * Set the audio state of this {@code RemoteConnection}. 1078 * 1079 * @param state The audio state of this {@code RemoteConnection}. 1080 */ setCallAudioState(CallAudioState state)1081 public void setCallAudioState(CallAudioState state) { 1082 try { 1083 if (mConnected) { 1084 mConnectionService.onCallAudioStateChanged(mConnectionId, state, 1085 null /*Session.Info*/); 1086 } 1087 } catch (RemoteException ignored) { 1088 } 1089 } 1090 1091 /** 1092 * Notifies this {@link RemoteConnection} that the user has requested an RTT session. 1093 * @param rttTextStream The object that should be used to send text to or receive text from 1094 * the in-call app. 1095 * @hide 1096 */ startRtt(@onNull Connection.RttTextStream rttTextStream)1097 public void startRtt(@NonNull Connection.RttTextStream rttTextStream) { 1098 try { 1099 if (mConnected) { 1100 mConnectionService.startRtt(mConnectionId, rttTextStream.getFdFromInCall(), 1101 rttTextStream.getFdToInCall(), null /*Session.Info*/); 1102 } 1103 } catch (RemoteException ignored) { 1104 } 1105 } 1106 1107 /** 1108 * Notifies this {@link RemoteConnection} that it should terminate any existing RTT 1109 * session. No response to Telecom is needed for this method. 1110 * @hide 1111 */ stopRtt()1112 public void stopRtt() { 1113 try { 1114 if (mConnected) { 1115 mConnectionService.stopRtt(mConnectionId, null /*Session.Info*/); 1116 } 1117 } catch (RemoteException ignored) { 1118 } 1119 } 1120 1121 /** 1122 * Notifies this {@link RemoteConnection} of a response to a previous remotely-initiated RTT 1123 * upgrade request sent via {@link Connection#sendRemoteRttRequest}. 1124 * Acceptance of the request is indicated by the supplied {@link RttTextStream} being non-null, 1125 * and rejection is indicated by {@code rttTextStream} being {@code null} 1126 * @hide 1127 * @param rttTextStream The object that should be used to send text to or receive text from 1128 * the in-call app. 1129 */ sendRttUpgradeResponse(@ullable Connection.RttTextStream rttTextStream)1130 public void sendRttUpgradeResponse(@Nullable Connection.RttTextStream rttTextStream) { 1131 try { 1132 if (mConnected) { 1133 if (rttTextStream == null) { 1134 mConnectionService.respondToRttUpgradeRequest(mConnectionId, 1135 null, null, null /*Session.Info*/); 1136 } else { 1137 mConnectionService.respondToRttUpgradeRequest(mConnectionId, 1138 rttTextStream.getFdFromInCall(), rttTextStream.getFdToInCall(), 1139 null /*Session.Info*/); 1140 } 1141 } 1142 } catch (RemoteException ignored) { 1143 } 1144 } 1145 1146 /** 1147 * Obtain the {@code RemoteConnection}s with which this {@code RemoteConnection} may be 1148 * successfully asked to create a conference with. 1149 * 1150 * @return The {@code RemoteConnection}s with which this {@code RemoteConnection} may be 1151 * merged into a {@link RemoteConference}. 1152 */ getConferenceableConnections()1153 public List<RemoteConnection> getConferenceableConnections() { 1154 return mUnmodifiableconferenceableConnections; 1155 } 1156 1157 /** 1158 * Obtain the {@code RemoteConference} that this {@code RemoteConnection} may be a part 1159 * of, or {@code null} if there is no such {@code RemoteConference}. 1160 * 1161 * @return A {@code RemoteConference} or {@code null}; 1162 */ getConference()1163 public RemoteConference getConference() { 1164 return mConference; 1165 } 1166 1167 /** {@hide} */ getId()1168 String getId() { 1169 return mConnectionId; 1170 } 1171 1172 /** {@hide} */ getConnectionService()1173 IConnectionService getConnectionService() { 1174 return mConnectionService; 1175 } 1176 1177 /** 1178 * @hide 1179 */ setState(final int state)1180 void setState(final int state) { 1181 if (mState != state) { 1182 mState = state; 1183 for (CallbackRecord record: mCallbackRecords) { 1184 final RemoteConnection connection = this; 1185 final Callback callback = record.getCallback(); 1186 record.getHandler().post(new Runnable() { 1187 @Override 1188 public void run() { 1189 callback.onStateChanged(connection, state); 1190 } 1191 }); 1192 } 1193 } 1194 } 1195 1196 /** 1197 * @hide 1198 */ setDisconnected(final DisconnectCause disconnectCause)1199 void setDisconnected(final DisconnectCause disconnectCause) { 1200 if (mState != Connection.STATE_DISCONNECTED) { 1201 mState = Connection.STATE_DISCONNECTED; 1202 mDisconnectCause = disconnectCause; 1203 1204 for (CallbackRecord record : mCallbackRecords) { 1205 final RemoteConnection connection = this; 1206 final Callback callback = record.getCallback(); 1207 record.getHandler().post(new Runnable() { 1208 @Override 1209 public void run() { 1210 callback.onDisconnected(connection, disconnectCause); 1211 } 1212 }); 1213 } 1214 } 1215 } 1216 1217 /** 1218 * @hide 1219 */ setRingbackRequested(final boolean ringback)1220 void setRingbackRequested(final boolean ringback) { 1221 if (mRingbackRequested != ringback) { 1222 mRingbackRequested = ringback; 1223 for (CallbackRecord record : mCallbackRecords) { 1224 final RemoteConnection connection = this; 1225 final Callback callback = record.getCallback(); 1226 record.getHandler().post(new Runnable() { 1227 @Override 1228 public void run() { 1229 callback.onRingbackRequested(connection, ringback); 1230 } 1231 }); 1232 } 1233 } 1234 } 1235 1236 /** 1237 * @hide 1238 */ setConnectionCapabilities(final int connectionCapabilities)1239 void setConnectionCapabilities(final int connectionCapabilities) { 1240 mConnectionCapabilities = connectionCapabilities; 1241 for (CallbackRecord record : mCallbackRecords) { 1242 final RemoteConnection connection = this; 1243 final Callback callback = record.getCallback(); 1244 record.getHandler().post(new Runnable() { 1245 @Override 1246 public void run() { 1247 callback.onConnectionCapabilitiesChanged(connection, connectionCapabilities); 1248 } 1249 }); 1250 } 1251 } 1252 1253 /** 1254 * @hide 1255 */ setConnectionProperties(final int connectionProperties)1256 void setConnectionProperties(final int connectionProperties) { 1257 mConnectionProperties = connectionProperties; 1258 for (CallbackRecord record : mCallbackRecords) { 1259 final RemoteConnection connection = this; 1260 final Callback callback = record.getCallback(); 1261 record.getHandler().post(new Runnable() { 1262 @Override 1263 public void run() { 1264 callback.onConnectionPropertiesChanged(connection, connectionProperties); 1265 } 1266 }); 1267 } 1268 } 1269 1270 /** 1271 * @hide 1272 */ setDestroyed()1273 void setDestroyed() { 1274 if (!mCallbackRecords.isEmpty()) { 1275 // Make sure that the callbacks are notified that the call is destroyed first. 1276 if (mState != Connection.STATE_DISCONNECTED) { 1277 setDisconnected( 1278 new DisconnectCause(DisconnectCause.ERROR, "Connection destroyed.")); 1279 } 1280 1281 for (CallbackRecord record : mCallbackRecords) { 1282 final RemoteConnection connection = this; 1283 final Callback callback = record.getCallback(); 1284 record.getHandler().post(new Runnable() { 1285 @Override 1286 public void run() { 1287 callback.onDestroyed(connection); 1288 } 1289 }); 1290 } 1291 mCallbackRecords.clear(); 1292 1293 mConnected = false; 1294 } 1295 } 1296 1297 /** 1298 * @hide 1299 */ setPostDialWait(final String remainingDigits)1300 void setPostDialWait(final String remainingDigits) { 1301 for (CallbackRecord record : mCallbackRecords) { 1302 final RemoteConnection connection = this; 1303 final Callback callback = record.getCallback(); 1304 record.getHandler().post(new Runnable() { 1305 @Override 1306 public void run() { 1307 callback.onPostDialWait(connection, remainingDigits); 1308 } 1309 }); 1310 } 1311 } 1312 1313 /** 1314 * @hide 1315 */ onPostDialChar(final char nextChar)1316 void onPostDialChar(final char nextChar) { 1317 for (CallbackRecord record : mCallbackRecords) { 1318 final RemoteConnection connection = this; 1319 final Callback callback = record.getCallback(); 1320 record.getHandler().post(new Runnable() { 1321 @Override 1322 public void run() { 1323 callback.onPostDialChar(connection, nextChar); 1324 } 1325 }); 1326 } 1327 } 1328 1329 /** 1330 * @hide 1331 */ setVideoState(final int videoState)1332 void setVideoState(final int videoState) { 1333 mVideoState = videoState; 1334 for (CallbackRecord record : mCallbackRecords) { 1335 final RemoteConnection connection = this; 1336 final Callback callback = record.getCallback(); 1337 record.getHandler().post(new Runnable() { 1338 @Override 1339 public void run() { 1340 callback.onVideoStateChanged(connection, videoState); 1341 } 1342 }); 1343 } 1344 } 1345 1346 /** 1347 * @hide 1348 */ setVideoProvider(final VideoProvider videoProvider)1349 void setVideoProvider(final VideoProvider videoProvider) { 1350 mVideoProvider = videoProvider; 1351 for (CallbackRecord record : mCallbackRecords) { 1352 final RemoteConnection connection = this; 1353 final Callback callback = record.getCallback(); 1354 record.getHandler().post(new Runnable() { 1355 @Override 1356 public void run() { 1357 callback.onVideoProviderChanged(connection, videoProvider); 1358 } 1359 }); 1360 } 1361 } 1362 1363 /** @hide */ setIsVoipAudioMode(final boolean isVoip)1364 void setIsVoipAudioMode(final boolean isVoip) { 1365 mIsVoipAudioMode = isVoip; 1366 for (CallbackRecord record : mCallbackRecords) { 1367 final RemoteConnection connection = this; 1368 final Callback callback = record.getCallback(); 1369 record.getHandler().post(new Runnable() { 1370 @Override 1371 public void run() { 1372 callback.onVoipAudioChanged(connection, isVoip); 1373 } 1374 }); 1375 } 1376 } 1377 1378 /** @hide */ setStatusHints(final StatusHints statusHints)1379 void setStatusHints(final StatusHints statusHints) { 1380 mStatusHints = statusHints; 1381 for (CallbackRecord record : mCallbackRecords) { 1382 final RemoteConnection connection = this; 1383 final Callback callback = record.getCallback(); 1384 record.getHandler().post(new Runnable() { 1385 @Override 1386 public void run() { 1387 callback.onStatusHintsChanged(connection, statusHints); 1388 } 1389 }); 1390 } 1391 } 1392 1393 /** @hide */ setAddress(final Uri address, final int presentation)1394 void setAddress(final Uri address, final int presentation) { 1395 mAddress = address; 1396 mAddressPresentation = presentation; 1397 for (CallbackRecord record : mCallbackRecords) { 1398 final RemoteConnection connection = this; 1399 final Callback callback = record.getCallback(); 1400 record.getHandler().post(new Runnable() { 1401 @Override 1402 public void run() { 1403 callback.onAddressChanged(connection, address, presentation); 1404 } 1405 }); 1406 } 1407 } 1408 1409 /** @hide */ setCallerDisplayName(final String callerDisplayName, final int presentation)1410 void setCallerDisplayName(final String callerDisplayName, final int presentation) { 1411 mCallerDisplayName = callerDisplayName; 1412 mCallerDisplayNamePresentation = presentation; 1413 for (CallbackRecord record : mCallbackRecords) { 1414 final RemoteConnection connection = this; 1415 final Callback callback = record.getCallback(); 1416 record.getHandler().post(new Runnable() { 1417 @Override 1418 public void run() { 1419 callback.onCallerDisplayNameChanged( 1420 connection, callerDisplayName, presentation); 1421 } 1422 }); 1423 } 1424 } 1425 1426 /** @hide */ setConferenceableConnections(final List<RemoteConnection> conferenceableConnections)1427 void setConferenceableConnections(final List<RemoteConnection> conferenceableConnections) { 1428 mConferenceableConnections.clear(); 1429 mConferenceableConnections.addAll(conferenceableConnections); 1430 for (CallbackRecord record : mCallbackRecords) { 1431 final RemoteConnection connection = this; 1432 final Callback callback = record.getCallback(); 1433 record.getHandler().post(new Runnable() { 1434 @Override 1435 public void run() { 1436 callback.onConferenceableConnectionsChanged( 1437 connection, mUnmodifiableconferenceableConnections); 1438 } 1439 }); 1440 } 1441 } 1442 1443 /** @hide */ setConference(final RemoteConference conference)1444 void setConference(final RemoteConference conference) { 1445 if (mConference != conference) { 1446 mConference = conference; 1447 for (CallbackRecord record : mCallbackRecords) { 1448 final RemoteConnection connection = this; 1449 final Callback callback = record.getCallback(); 1450 record.getHandler().post(new Runnable() { 1451 @Override 1452 public void run() { 1453 callback.onConferenceChanged(connection, conference); 1454 } 1455 }); 1456 } 1457 } 1458 } 1459 1460 /** @hide */ putExtras(final Bundle extras)1461 void putExtras(final Bundle extras) { 1462 if (extras == null) { 1463 return; 1464 } 1465 if (mExtras == null) { 1466 mExtras = new Bundle(); 1467 } 1468 try { 1469 mExtras.putAll(extras); 1470 } catch (BadParcelableException bpe) { 1471 Log.w(this, "putExtras: could not unmarshal extras; exception = " + bpe); 1472 } 1473 1474 notifyExtrasChanged(); 1475 } 1476 1477 /** @hide */ removeExtras(List<String> keys)1478 void removeExtras(List<String> keys) { 1479 if (mExtras == null || keys == null || keys.isEmpty()) { 1480 return; 1481 } 1482 for (String key : keys) { 1483 mExtras.remove(key); 1484 } 1485 1486 notifyExtrasChanged(); 1487 } 1488 notifyExtrasChanged()1489 private void notifyExtrasChanged() { 1490 for (CallbackRecord record : mCallbackRecords) { 1491 final RemoteConnection connection = this; 1492 final Callback callback = record.getCallback(); 1493 record.getHandler().post(new Runnable() { 1494 @Override 1495 public void run() { 1496 callback.onExtrasChanged(connection, mExtras); 1497 } 1498 }); 1499 } 1500 } 1501 1502 /** @hide */ onConnectionEvent(final String event, final Bundle extras)1503 void onConnectionEvent(final String event, final Bundle extras) { 1504 for (CallbackRecord record : mCallbackRecords) { 1505 final RemoteConnection connection = this; 1506 final Callback callback = record.getCallback(); 1507 record.getHandler().post(new Runnable() { 1508 @Override 1509 public void run() { 1510 callback.onConnectionEvent(connection, event, extras); 1511 } 1512 }); 1513 } 1514 } 1515 1516 /** @hide */ onRttInitiationSuccess()1517 void onRttInitiationSuccess() { 1518 for (CallbackRecord record : mCallbackRecords) { 1519 final RemoteConnection connection = this; 1520 final Callback callback = record.getCallback(); 1521 record.getHandler().post( 1522 () -> callback.onRttInitiationSuccess(connection)); 1523 } 1524 } 1525 1526 /** @hide */ onRttInitiationFailure(int reason)1527 void onRttInitiationFailure(int reason) { 1528 for (CallbackRecord record : mCallbackRecords) { 1529 final RemoteConnection connection = this; 1530 final Callback callback = record.getCallback(); 1531 record.getHandler().post( 1532 () -> callback.onRttInitiationFailure(connection, reason)); 1533 } 1534 } 1535 1536 /** @hide */ onRttSessionRemotelyTerminated()1537 void onRttSessionRemotelyTerminated() { 1538 for (CallbackRecord record : mCallbackRecords) { 1539 final RemoteConnection connection = this; 1540 final Callback callback = record.getCallback(); 1541 record.getHandler().post( 1542 () -> callback.onRttSessionRemotelyTerminated(connection)); 1543 } 1544 } 1545 1546 /** @hide */ onRemoteRttRequest()1547 void onRemoteRttRequest() { 1548 for (CallbackRecord record : mCallbackRecords) { 1549 final RemoteConnection connection = this; 1550 final Callback callback = record.getCallback(); 1551 record.getHandler().post( 1552 () -> callback.onRemoteRttRequest(connection)); 1553 } 1554 } 1555 1556 /** 1557 /** 1558 * Create a RemoteConnection represents a failure, and which will be in 1559 * {@link Connection#STATE_DISCONNECTED}. Attempting to use it for anything will almost 1560 * certainly result in bad things happening. Do not do this. 1561 * 1562 * @return a failed {@link RemoteConnection} 1563 * 1564 * @hide 1565 */ failure(DisconnectCause disconnectCause)1566 public static RemoteConnection failure(DisconnectCause disconnectCause) { 1567 return new RemoteConnection(disconnectCause); 1568 } 1569 1570 private static final class CallbackRecord extends Callback { 1571 private final Callback mCallback; 1572 private final Handler mHandler; 1573 CallbackRecord(Callback callback, Handler handler)1574 public CallbackRecord(Callback callback, Handler handler) { 1575 mCallback = callback; 1576 mHandler = handler; 1577 } 1578 getCallback()1579 public Callback getCallback() { 1580 return mCallback; 1581 } 1582 getHandler()1583 public Handler getHandler() { 1584 return mHandler; 1585 } 1586 } 1587 } 1588