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