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