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