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