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