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