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