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.Collections; 40 import java.util.List; 41 import java.util.Set; 42 import java.util.concurrent.ConcurrentHashMap; 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 * Instructs this {@link RemoteConnection} to initiate a conference with a list of 1118 * participants. 1119 * <p> 1120 * 1121 * @param participants with which conference call will be formed. 1122 */ addConferenceParticipants(@onNull List<Uri> participants)1123 public void addConferenceParticipants(@NonNull List<Uri> participants) { 1124 try { 1125 if (mConnected) { 1126 mConnectionService.addConferenceParticipants(mConnectionId, participants, 1127 null /*Session.Info*/); 1128 } 1129 } catch (RemoteException ignored) { 1130 } 1131 } 1132 1133 /** 1134 * Set the audio state of this {@code RemoteConnection}. 1135 * 1136 * @param state The audio state of this {@code RemoteConnection}. 1137 * @hide 1138 * @deprecated Use {@link #setCallAudioState(CallAudioState)} instead. 1139 */ 1140 @SystemApi 1141 @Deprecated setAudioState(AudioState state)1142 public void setAudioState(AudioState state) { 1143 setCallAudioState(new CallAudioState(state)); 1144 } 1145 1146 /** 1147 * Set the audio state of this {@code RemoteConnection}. 1148 * 1149 * @param state The audio state of this {@code RemoteConnection}. 1150 */ setCallAudioState(CallAudioState state)1151 public void setCallAudioState(CallAudioState state) { 1152 Log.startSession("RC.sCAS", getActiveOwnerInfo()); 1153 try { 1154 if (mConnected) { 1155 mConnectionService.onCallAudioStateChanged(mConnectionId, state, 1156 null /*Session.Info*/); 1157 } 1158 } catch (RemoteException ignored) { 1159 } finally { 1160 Log.endSession(); 1161 } 1162 } 1163 1164 /** 1165 * Notifies this {@link RemoteConnection} that the user has requested an RTT session. 1166 * @param rttTextStream The object that should be used to send text to or receive text from 1167 * the in-call app. 1168 * @hide 1169 */ startRtt(@onNull Connection.RttTextStream rttTextStream)1170 public void startRtt(@NonNull Connection.RttTextStream rttTextStream) { 1171 Log.startSession("RC.sR", getActiveOwnerInfo()); 1172 try { 1173 if (mConnected) { 1174 mConnectionService.startRtt(mConnectionId, rttTextStream.getFdFromInCall(), 1175 rttTextStream.getFdToInCall(), null /*Session.Info*/); 1176 } 1177 } catch (RemoteException ignored) { 1178 } finally { 1179 Log.endSession(); 1180 } 1181 } 1182 1183 /** 1184 * Notifies this {@link RemoteConnection} that it should terminate any existing RTT 1185 * session. No response to Telecom is needed for this method. 1186 * @hide 1187 */ stopRtt()1188 public void stopRtt() { 1189 Log.startSession("RC.stR", getActiveOwnerInfo()); 1190 try { 1191 if (mConnected) { 1192 mConnectionService.stopRtt(mConnectionId, null /*Session.Info*/); 1193 } 1194 } catch (RemoteException ignored) { 1195 } finally { 1196 Log.endSession(); 1197 } 1198 } 1199 1200 /** 1201 * Notifies this {@link RemoteConnection} that call filtering has completed, as well as 1202 * the results of a contacts lookup for the remote party. 1203 * 1204 * @param completionInfo Info provided by Telecom on the results of call filtering. 1205 * @hide 1206 */ 1207 @SystemApi 1208 @RequiresPermission(Manifest.permission.READ_CONTACTS) onCallFilteringCompleted( @onNull Connection.CallFilteringCompletionInfo completionInfo)1209 public void onCallFilteringCompleted( 1210 @NonNull Connection.CallFilteringCompletionInfo completionInfo) { 1211 Log.startSession("RC.oCFC", getActiveOwnerInfo()); 1212 try { 1213 if (mConnected) { 1214 mConnectionService.onCallFilteringCompleted(mConnectionId, completionInfo, 1215 null /*Session.Info*/); 1216 } 1217 } catch (RemoteException ignored) { 1218 } finally { 1219 Log.endSession(); 1220 } 1221 } 1222 1223 /** 1224 * Notifies this {@link RemoteConnection} of a response to a previous remotely-initiated RTT 1225 * upgrade request sent via {@link Connection#sendRemoteRttRequest}. 1226 * Acceptance of the request is indicated by the supplied {@link RttTextStream} being non-null, 1227 * and rejection is indicated by {@code rttTextStream} being {@code null} 1228 * @hide 1229 * @param rttTextStream The object that should be used to send text to or receive text from 1230 * the in-call app. 1231 */ sendRttUpgradeResponse(@ullable Connection.RttTextStream rttTextStream)1232 public void sendRttUpgradeResponse(@Nullable Connection.RttTextStream rttTextStream) { 1233 Log.startSession("RC.sRUR", getActiveOwnerInfo()); 1234 try { 1235 if (mConnected) { 1236 if (rttTextStream == null) { 1237 mConnectionService.respondToRttUpgradeRequest(mConnectionId, 1238 null, null, null /*Session.Info*/); 1239 } else { 1240 mConnectionService.respondToRttUpgradeRequest(mConnectionId, 1241 rttTextStream.getFdFromInCall(), rttTextStream.getFdToInCall(), 1242 null /*Session.Info*/); 1243 } 1244 } 1245 } catch (RemoteException ignored) { 1246 } finally { 1247 Log.endSession(); 1248 } 1249 } 1250 1251 /** 1252 * Obtain the {@code RemoteConnection}s with which this {@code RemoteConnection} may be 1253 * successfully asked to create a conference with. 1254 * 1255 * @return The {@code RemoteConnection}s with which this {@code RemoteConnection} may be 1256 * merged into a {@link RemoteConference}. 1257 */ getConferenceableConnections()1258 public List<RemoteConnection> getConferenceableConnections() { 1259 return mUnmodifiableconferenceableConnections; 1260 } 1261 1262 /** 1263 * Obtain the {@code RemoteConference} that this {@code RemoteConnection} may be a part 1264 * of, or {@code null} if there is no such {@code RemoteConference}. 1265 * 1266 * @return A {@code RemoteConference} or {@code null}; 1267 */ getConference()1268 public RemoteConference getConference() { 1269 return mConference; 1270 } 1271 1272 /** 1273 * Get the owner info for the currently active session. We want to make sure that any owner 1274 * info from the original call into the connection manager gets retained so that the full 1275 * context of the calls can be traced down to Telephony. 1276 * Example: Telecom will provide owner info in it's external session info that indicates 1277 * 'cast' as the calling owner. 1278 * @return The active owner 1279 */ getActiveOwnerInfo()1280 private String getActiveOwnerInfo() { 1281 Session.Info info = Log.getExternalSession(); 1282 if (info == null) { 1283 return null; 1284 } 1285 return info.ownerInfo; 1286 } 1287 1288 /** {@hide} */ getId()1289 String getId() { 1290 return mConnectionId; 1291 } 1292 1293 /** {@hide} */ getConnectionService()1294 IConnectionService getConnectionService() { 1295 return mConnectionService; 1296 } 1297 1298 /** 1299 * @hide 1300 */ setState(final int state)1301 void setState(final int state) { 1302 if (mState != state) { 1303 mState = state; 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.onStateChanged(connection, state); 1311 } 1312 }); 1313 } 1314 } 1315 } 1316 1317 /** 1318 * @hide 1319 */ setDisconnected(final DisconnectCause disconnectCause)1320 void setDisconnected(final DisconnectCause disconnectCause) { 1321 if (mState != Connection.STATE_DISCONNECTED) { 1322 mState = Connection.STATE_DISCONNECTED; 1323 mDisconnectCause = disconnectCause; 1324 1325 for (CallbackRecord record : mCallbackRecords) { 1326 final RemoteConnection connection = this; 1327 final Callback callback = record.getCallback(); 1328 record.getHandler().post(new Runnable() { 1329 @Override 1330 public void run() { 1331 callback.onDisconnected(connection, disconnectCause); 1332 } 1333 }); 1334 } 1335 } 1336 } 1337 1338 /** 1339 * @hide 1340 */ setRingbackRequested(final boolean ringback)1341 void setRingbackRequested(final boolean ringback) { 1342 if (mRingbackRequested != ringback) { 1343 mRingbackRequested = ringback; 1344 for (CallbackRecord record : mCallbackRecords) { 1345 final RemoteConnection connection = this; 1346 final Callback callback = record.getCallback(); 1347 record.getHandler().post(new Runnable() { 1348 @Override 1349 public void run() { 1350 callback.onRingbackRequested(connection, ringback); 1351 } 1352 }); 1353 } 1354 } 1355 } 1356 1357 /** 1358 * @hide 1359 */ setConnectionCapabilities(final int connectionCapabilities)1360 void setConnectionCapabilities(final int connectionCapabilities) { 1361 mConnectionCapabilities = connectionCapabilities; 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.onConnectionCapabilitiesChanged(connection, connectionCapabilities); 1369 } 1370 }); 1371 } 1372 } 1373 1374 /** 1375 * @hide 1376 */ setConnectionProperties(final int connectionProperties)1377 void setConnectionProperties(final int connectionProperties) { 1378 mConnectionProperties = connectionProperties; 1379 for (CallbackRecord record : mCallbackRecords) { 1380 final RemoteConnection connection = this; 1381 final Callback callback = record.getCallback(); 1382 record.getHandler().post(new Runnable() { 1383 @Override 1384 public void run() { 1385 callback.onConnectionPropertiesChanged(connection, connectionProperties); 1386 } 1387 }); 1388 } 1389 } 1390 1391 /** 1392 * @hide 1393 */ setDestroyed()1394 void setDestroyed() { 1395 if (!mCallbackRecords.isEmpty()) { 1396 // Make sure that the callbacks are notified that the call is destroyed first. 1397 if (mState != Connection.STATE_DISCONNECTED) { 1398 setDisconnected( 1399 new DisconnectCause(DisconnectCause.ERROR, "Connection destroyed.")); 1400 } 1401 1402 for (CallbackRecord record : mCallbackRecords) { 1403 final RemoteConnection connection = this; 1404 final Callback callback = record.getCallback(); 1405 record.getHandler().post(new Runnable() { 1406 @Override 1407 public void run() { 1408 callback.onDestroyed(connection); 1409 } 1410 }); 1411 } 1412 mCallbackRecords.clear(); 1413 1414 mConnected = false; 1415 } 1416 } 1417 1418 /** 1419 * @hide 1420 */ setPostDialWait(final String remainingDigits)1421 void setPostDialWait(final String remainingDigits) { 1422 for (CallbackRecord record : mCallbackRecords) { 1423 final RemoteConnection connection = this; 1424 final Callback callback = record.getCallback(); 1425 record.getHandler().post(new Runnable() { 1426 @Override 1427 public void run() { 1428 callback.onPostDialWait(connection, remainingDigits); 1429 } 1430 }); 1431 } 1432 } 1433 1434 /** 1435 * @hide 1436 */ onPostDialChar(final char nextChar)1437 void onPostDialChar(final char nextChar) { 1438 for (CallbackRecord record : mCallbackRecords) { 1439 final RemoteConnection connection = this; 1440 final Callback callback = record.getCallback(); 1441 record.getHandler().post(new Runnable() { 1442 @Override 1443 public void run() { 1444 callback.onPostDialChar(connection, nextChar); 1445 } 1446 }); 1447 } 1448 } 1449 1450 /** 1451 * @hide 1452 */ setVideoState(final int videoState)1453 void setVideoState(final int videoState) { 1454 mVideoState = videoState; 1455 for (CallbackRecord record : mCallbackRecords) { 1456 final RemoteConnection connection = this; 1457 final Callback callback = record.getCallback(); 1458 record.getHandler().post(new Runnable() { 1459 @Override 1460 public void run() { 1461 callback.onVideoStateChanged(connection, videoState); 1462 } 1463 }); 1464 } 1465 } 1466 1467 /** 1468 * @hide 1469 */ setVideoProvider(final VideoProvider videoProvider)1470 void setVideoProvider(final VideoProvider videoProvider) { 1471 mVideoProvider = videoProvider; 1472 for (CallbackRecord record : mCallbackRecords) { 1473 final RemoteConnection connection = this; 1474 final Callback callback = record.getCallback(); 1475 record.getHandler().post(new Runnable() { 1476 @Override 1477 public void run() { 1478 callback.onVideoProviderChanged(connection, videoProvider); 1479 } 1480 }); 1481 } 1482 } 1483 1484 /** @hide */ setIsVoipAudioMode(final boolean isVoip)1485 void setIsVoipAudioMode(final boolean isVoip) { 1486 mIsVoipAudioMode = isVoip; 1487 for (CallbackRecord record : mCallbackRecords) { 1488 final RemoteConnection connection = this; 1489 final Callback callback = record.getCallback(); 1490 record.getHandler().post(new Runnable() { 1491 @Override 1492 public void run() { 1493 callback.onVoipAudioChanged(connection, isVoip); 1494 } 1495 }); 1496 } 1497 } 1498 1499 /** @hide */ setStatusHints(final StatusHints statusHints)1500 void setStatusHints(final StatusHints statusHints) { 1501 mStatusHints = statusHints; 1502 for (CallbackRecord record : mCallbackRecords) { 1503 final RemoteConnection connection = this; 1504 final Callback callback = record.getCallback(); 1505 record.getHandler().post(new Runnable() { 1506 @Override 1507 public void run() { 1508 callback.onStatusHintsChanged(connection, statusHints); 1509 } 1510 }); 1511 } 1512 } 1513 1514 /** @hide */ setAddress(final Uri address, final int presentation)1515 void setAddress(final Uri address, final int presentation) { 1516 mAddress = address; 1517 mAddressPresentation = presentation; 1518 for (CallbackRecord record : mCallbackRecords) { 1519 final RemoteConnection connection = this; 1520 final Callback callback = record.getCallback(); 1521 record.getHandler().post(new Runnable() { 1522 @Override 1523 public void run() { 1524 callback.onAddressChanged(connection, address, presentation); 1525 } 1526 }); 1527 } 1528 } 1529 1530 /** @hide */ setCallerDisplayName(final String callerDisplayName, final int presentation)1531 void setCallerDisplayName(final String callerDisplayName, final int presentation) { 1532 mCallerDisplayName = callerDisplayName; 1533 mCallerDisplayNamePresentation = presentation; 1534 for (CallbackRecord record : mCallbackRecords) { 1535 final RemoteConnection connection = this; 1536 final Callback callback = record.getCallback(); 1537 record.getHandler().post(new Runnable() { 1538 @Override 1539 public void run() { 1540 callback.onCallerDisplayNameChanged( 1541 connection, callerDisplayName, presentation); 1542 } 1543 }); 1544 } 1545 } 1546 1547 /** @hide */ setConferenceableConnections(final List<RemoteConnection> conferenceableConnections)1548 void setConferenceableConnections(final List<RemoteConnection> conferenceableConnections) { 1549 mConferenceableConnections.clear(); 1550 mConferenceableConnections.addAll(conferenceableConnections); 1551 for (CallbackRecord record : mCallbackRecords) { 1552 final RemoteConnection connection = this; 1553 final Callback callback = record.getCallback(); 1554 record.getHandler().post(new Runnable() { 1555 @Override 1556 public void run() { 1557 callback.onConferenceableConnectionsChanged( 1558 connection, mUnmodifiableconferenceableConnections); 1559 } 1560 }); 1561 } 1562 } 1563 1564 /** @hide */ setConference(final RemoteConference conference)1565 void setConference(final RemoteConference conference) { 1566 if (mConference != conference) { 1567 mConference = conference; 1568 for (CallbackRecord record : mCallbackRecords) { 1569 final RemoteConnection connection = this; 1570 final Callback callback = record.getCallback(); 1571 record.getHandler().post(new Runnable() { 1572 @Override 1573 public void run() { 1574 callback.onConferenceChanged(connection, conference); 1575 } 1576 }); 1577 } 1578 } 1579 } 1580 1581 /** @hide */ putExtras(final Bundle extras)1582 void putExtras(final Bundle extras) { 1583 if (extras == null) { 1584 return; 1585 } 1586 if (mExtras == null) { 1587 mExtras = new Bundle(); 1588 } 1589 try { 1590 mExtras.putAll(extras); 1591 } catch (BadParcelableException bpe) { 1592 Log.w(this, "putExtras: could not unmarshal extras; exception = " + bpe); 1593 } 1594 1595 notifyExtrasChanged(); 1596 } 1597 1598 /** @hide */ removeExtras(List<String> keys)1599 void removeExtras(List<String> keys) { 1600 if (mExtras == null || keys == null || keys.isEmpty()) { 1601 return; 1602 } 1603 for (String key : keys) { 1604 mExtras.remove(key); 1605 } 1606 1607 notifyExtrasChanged(); 1608 } 1609 notifyExtrasChanged()1610 private void notifyExtrasChanged() { 1611 for (CallbackRecord record : mCallbackRecords) { 1612 final RemoteConnection connection = this; 1613 final Callback callback = record.getCallback(); 1614 record.getHandler().post(new Runnable() { 1615 @Override 1616 public void run() { 1617 callback.onExtrasChanged(connection, mExtras); 1618 } 1619 }); 1620 } 1621 } 1622 1623 /** @hide */ onConnectionEvent(final String event, final Bundle extras)1624 void onConnectionEvent(final String event, final Bundle extras) { 1625 for (CallbackRecord record : mCallbackRecords) { 1626 final RemoteConnection connection = this; 1627 final Callback callback = record.getCallback(); 1628 record.getHandler().post(new Runnable() { 1629 @Override 1630 public void run() { 1631 callback.onConnectionEvent(connection, event, extras); 1632 } 1633 }); 1634 } 1635 } 1636 1637 /** @hide */ onRttInitiationSuccess()1638 void onRttInitiationSuccess() { 1639 for (CallbackRecord record : mCallbackRecords) { 1640 final RemoteConnection connection = this; 1641 final Callback callback = record.getCallback(); 1642 record.getHandler().post( 1643 () -> callback.onRttInitiationSuccess(connection)); 1644 } 1645 } 1646 1647 /** @hide */ onRttInitiationFailure(int reason)1648 void onRttInitiationFailure(int reason) { 1649 for (CallbackRecord record : mCallbackRecords) { 1650 final RemoteConnection connection = this; 1651 final Callback callback = record.getCallback(); 1652 record.getHandler().post( 1653 () -> callback.onRttInitiationFailure(connection, reason)); 1654 } 1655 } 1656 1657 /** @hide */ onRttSessionRemotelyTerminated()1658 void onRttSessionRemotelyTerminated() { 1659 for (CallbackRecord record : mCallbackRecords) { 1660 final RemoteConnection connection = this; 1661 final Callback callback = record.getCallback(); 1662 record.getHandler().post( 1663 () -> callback.onRttSessionRemotelyTerminated(connection)); 1664 } 1665 } 1666 1667 /** @hide */ onRemoteRttRequest()1668 void onRemoteRttRequest() { 1669 for (CallbackRecord record : mCallbackRecords) { 1670 final RemoteConnection connection = this; 1671 final Callback callback = record.getCallback(); 1672 record.getHandler().post( 1673 () -> callback.onRemoteRttRequest(connection)); 1674 } 1675 } 1676 1677 /** 1678 /** 1679 * Create a RemoteConnection represents a failure, and which will be in 1680 * {@link Connection#STATE_DISCONNECTED}. Attempting to use it for anything will almost 1681 * certainly result in bad things happening. Do not do this. 1682 * 1683 * @return a failed {@link RemoteConnection} 1684 * 1685 * @hide 1686 */ failure(DisconnectCause disconnectCause)1687 public static RemoteConnection failure(DisconnectCause disconnectCause) { 1688 return new RemoteConnection(disconnectCause); 1689 } 1690 1691 private static final class CallbackRecord extends Callback { 1692 private final Callback mCallback; 1693 private final Handler mHandler; 1694 CallbackRecord(Callback callback, Handler handler)1695 public CallbackRecord(Callback callback, Handler handler) { 1696 mCallback = callback; 1697 mHandler = handler; 1698 } 1699 getCallback()1700 public Callback getCallback() { 1701 return mCallback; 1702 } 1703 getHandler()1704 public Handler getHandler() { 1705 return mHandler; 1706 } 1707 } 1708 } 1709