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