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