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 17 package android.telecom; 18 19 import com.android.internal.os.SomeArgs; 20 import com.android.internal.telecom.IVideoCallback; 21 import com.android.internal.telecom.IVideoProvider; 22 23 import android.annotation.NonNull; 24 import android.annotation.Nullable; 25 import android.annotation.SystemApi; 26 import android.hardware.camera2.CameraManager; 27 import android.net.Uri; 28 import android.os.Bundle; 29 import android.os.Handler; 30 import android.os.IBinder; 31 import android.os.Looper; 32 import android.os.Message; 33 import android.os.RemoteException; 34 import android.util.ArraySet; 35 import android.view.Surface; 36 37 import java.util.ArrayList; 38 import java.util.Collections; 39 import java.util.List; 40 import java.util.Set; 41 import java.util.concurrent.ConcurrentHashMap; 42 43 /** 44 * Represents a phone call or connection to a remote endpoint that carries voice and/or video 45 * traffic. 46 * <p> 47 * Implementations create a custom subclass of {@code Connection} and return it to the framework 48 * as the return value of 49 * {@link ConnectionService#onCreateIncomingConnection(PhoneAccountHandle, ConnectionRequest)} 50 * or 51 * {@link ConnectionService#onCreateOutgoingConnection(PhoneAccountHandle, ConnectionRequest)}. 52 * Implementations are then responsible for updating the state of the {@code Connection}, and 53 * must call {@link #destroy()} to signal to the framework that the {@code Connection} is no 54 * longer used and associated resources may be recovered. 55 */ 56 public abstract class Connection extends Conferenceable { 57 58 /** 59 * The connection is initializing. This is generally the first state for a {@code Connection} 60 * returned by a {@link ConnectionService}. 61 */ 62 public static final int STATE_INITIALIZING = 0; 63 64 /** 65 * The connection is new and not connected. 66 */ 67 public static final int STATE_NEW = 1; 68 69 /** 70 * An incoming connection is in the ringing state. During this state, the user's ringer or 71 * vibration feature will be activated. 72 */ 73 public static final int STATE_RINGING = 2; 74 75 /** 76 * An outgoing connection is in the dialing state. In this state the other party has not yet 77 * answered the call and the user traditionally hears a ringback tone. 78 */ 79 public static final int STATE_DIALING = 3; 80 81 /** 82 * A connection is active. Both parties are connected to the call and can actively communicate. 83 */ 84 public static final int STATE_ACTIVE = 4; 85 86 /** 87 * A connection is on hold. 88 */ 89 public static final int STATE_HOLDING = 5; 90 91 /** 92 * A connection has been disconnected. This is the final state once the user has been 93 * disconnected from a call either locally, remotely or by an error in the service. 94 */ 95 public static final int STATE_DISCONNECTED = 6; 96 97 /** 98 * The state of an external connection which is in the process of being pulled from a remote 99 * device to the local device. 100 * <p> 101 * A connection can only be in this state if the {@link #PROPERTY_IS_EXTERNAL_CALL} property and 102 * {@link #CAPABILITY_CAN_PULL_CALL} capability bits are set on the connection. 103 * @hide 104 */ 105 public static final int STATE_PULLING_CALL = 7; 106 107 /** 108 * Connection can currently be put on hold or unheld. This is distinct from 109 * {@link #CAPABILITY_SUPPORT_HOLD} in that although a connection may support 'hold' most times, 110 * it does not at the moment support the function. This can be true while the call is in the 111 * state {@link #STATE_DIALING}, for example. During this condition, an in-call UI may 112 * display a disabled 'hold' button. 113 */ 114 public static final int CAPABILITY_HOLD = 0x00000001; 115 116 /** Connection supports the hold feature. */ 117 public static final int CAPABILITY_SUPPORT_HOLD = 0x00000002; 118 119 /** 120 * Connections within a conference can be merged. A {@link ConnectionService} has the option to 121 * add a {@link Conference} before the child {@link Connection}s are merged. This is how 122 * CDMA-based {@link Connection}s are implemented. For these unmerged {@link Conference}s, this 123 * capability allows a merge button to be shown while the conference is in the foreground 124 * of the in-call UI. 125 * <p> 126 * This is only intended for use by a {@link Conference}. 127 */ 128 public static final int CAPABILITY_MERGE_CONFERENCE = 0x00000004; 129 130 /** 131 * Connections within a conference can be swapped between foreground and background. 132 * See {@link #CAPABILITY_MERGE_CONFERENCE} for additional information. 133 * <p> 134 * This is only intended for use by a {@link Conference}. 135 */ 136 public static final int CAPABILITY_SWAP_CONFERENCE = 0x00000008; 137 138 /** 139 * @hide 140 */ 141 public static final int CAPABILITY_UNUSED = 0x00000010; 142 143 /** Connection supports responding via text option. */ 144 public static final int CAPABILITY_RESPOND_VIA_TEXT = 0x00000020; 145 146 /** Connection can be muted. */ 147 public static final int CAPABILITY_MUTE = 0x00000040; 148 149 /** 150 * Connection supports conference management. This capability only applies to 151 * {@link Conference}s which can have {@link Connection}s as children. 152 */ 153 public static final int CAPABILITY_MANAGE_CONFERENCE = 0x00000080; 154 155 /** 156 * Local device supports receiving video. 157 */ 158 public static final int CAPABILITY_SUPPORTS_VT_LOCAL_RX = 0x00000100; 159 160 /** 161 * Local device supports transmitting video. 162 */ 163 public static final int CAPABILITY_SUPPORTS_VT_LOCAL_TX = 0x00000200; 164 165 /** 166 * Local device supports bidirectional video calling. 167 */ 168 public static final int CAPABILITY_SUPPORTS_VT_LOCAL_BIDIRECTIONAL = 169 CAPABILITY_SUPPORTS_VT_LOCAL_RX | CAPABILITY_SUPPORTS_VT_LOCAL_TX; 170 171 /** 172 * Remote device supports receiving video. 173 */ 174 public static final int CAPABILITY_SUPPORTS_VT_REMOTE_RX = 0x00000400; 175 176 /** 177 * Remote device supports transmitting video. 178 */ 179 public static final int CAPABILITY_SUPPORTS_VT_REMOTE_TX = 0x00000800; 180 181 /** 182 * Remote device supports bidirectional video calling. 183 */ 184 public static final int CAPABILITY_SUPPORTS_VT_REMOTE_BIDIRECTIONAL = 185 CAPABILITY_SUPPORTS_VT_REMOTE_RX | CAPABILITY_SUPPORTS_VT_REMOTE_TX; 186 187 /** 188 * Connection is able to be separated from its parent {@code Conference}, if any. 189 */ 190 public static final int CAPABILITY_SEPARATE_FROM_CONFERENCE = 0x00001000; 191 192 /** 193 * Connection is able to be individually disconnected when in a {@code Conference}. 194 */ 195 public static final int CAPABILITY_DISCONNECT_FROM_CONFERENCE = 0x00002000; 196 197 /** 198 * Un-used. 199 * @hide 200 */ 201 public static final int CAPABILITY_UNUSED_2 = 0x00004000; 202 203 /** 204 * Un-used. 205 * @hide 206 */ 207 public static final int CAPABILITY_UNUSED_3 = 0x00008000; 208 209 /** 210 * Un-used. 211 * @hide 212 */ 213 public static final int CAPABILITY_UNUSED_4 = 0x00010000; 214 215 /** 216 * Un-used. 217 * @hide 218 */ 219 public static final int CAPABILITY_UNUSED_5 = 0x00020000; 220 221 /** 222 * Speed up audio setup for MT call. 223 * @hide 224 */ 225 public static final int CAPABILITY_SPEED_UP_MT_AUDIO = 0x00040000; 226 227 /** 228 * Call can be upgraded to a video call. 229 */ 230 public static final int CAPABILITY_CAN_UPGRADE_TO_VIDEO = 0x00080000; 231 232 /** 233 * For video calls, indicates whether the outgoing video for the call can be paused using 234 * the {@link android.telecom.VideoProfile#STATE_PAUSED} VideoState. 235 */ 236 public static final int CAPABILITY_CAN_PAUSE_VIDEO = 0x00100000; 237 238 /** 239 * For a conference, indicates the conference will not have child connections. 240 * <p> 241 * An example of a conference with child connections is a GSM conference call, where the radio 242 * retains connections to the individual participants of the conference. Another example is an 243 * IMS conference call where conference event package functionality is supported; in this case 244 * the conference server ensures the radio is aware of the participants in the conference, which 245 * are represented by child connections. 246 * <p> 247 * An example of a conference with no child connections is an IMS conference call with no 248 * conference event package support. Such a conference is represented by the radio as a single 249 * connection to the IMS conference server. 250 * <p> 251 * Indicating whether a conference has children or not is important to help user interfaces 252 * visually represent a conference. A conference with no children, for example, will have the 253 * conference connection shown in the list of calls on a Bluetooth device, where if the 254 * conference has children, only the children will be shown in the list of calls on a Bluetooth 255 * device. 256 * @hide 257 */ 258 public static final int CAPABILITY_CONFERENCE_HAS_NO_CHILDREN = 0x00200000; 259 260 /** 261 * Indicates that the connection itself wants to handle any sort of reply response, rather than 262 * relying on SMS. 263 */ 264 public static final int CAPABILITY_CAN_SEND_RESPONSE_VIA_CONNECTION = 0x00400000; 265 266 /** 267 * When set, prevents a video call from being downgraded to an audio-only call. 268 * <p> 269 * Should be set when the VideoState has the {@link VideoProfile#STATE_TX_ENABLED} or 270 * {@link VideoProfile#STATE_RX_ENABLED} bits set to indicate that the connection cannot be 271 * downgraded from a video call back to a VideoState of 272 * {@link VideoProfile#STATE_AUDIO_ONLY}. 273 * <p> 274 * Intuitively, a call which can be downgraded to audio should also have local and remote 275 * video 276 * capabilities (see {@link #CAPABILITY_SUPPORTS_VT_LOCAL_BIDIRECTIONAL} and 277 * {@link #CAPABILITY_SUPPORTS_VT_REMOTE_BIDIRECTIONAL}). 278 */ 279 public static final int CAPABILITY_CANNOT_DOWNGRADE_VIDEO_TO_AUDIO = 0x00800000; 280 281 /** 282 * When set for an external connection, indicates that this {@code Connection} can be pulled 283 * from a remote device to the current device. 284 * <p> 285 * Should only be set on a {@code Connection} where {@link #PROPERTY_IS_EXTERNAL_CALL} 286 * is set. 287 * @hide 288 */ 289 public static final int CAPABILITY_CAN_PULL_CALL = 0x01000000; 290 291 //********************************************************************************************** 292 // Next CAPABILITY value: 0x02000000 293 //********************************************************************************************** 294 295 /** 296 * Indicates that the current device callback number should be shown. 297 * 298 * @hide 299 */ 300 public static final int PROPERTY_SHOW_CALLBACK_NUMBER = 1<<0; 301 302 /** 303 * Whether the call is a generic conference, where we do not know the precise state of 304 * participants in the conference (eg. on CDMA). 305 * 306 * @hide 307 */ 308 public static final int PROPERTY_GENERIC_CONFERENCE = 1<<1; 309 310 /** 311 * Connection is using high definition audio. 312 * @hide 313 */ 314 public static final int PROPERTY_HIGH_DEF_AUDIO = 1<<2; 315 316 /** 317 * Connection is using WIFI. 318 * @hide 319 */ 320 public static final int PROPERTY_WIFI = 1<<3; 321 322 /** 323 * When set, indicates that the {@code Connection} does not actually exist locally for the 324 * {@link ConnectionService}. 325 * <p> 326 * Consider, for example, a scenario where a user has two devices with the same phone number. 327 * When a user places a call on one devices, the telephony stack can represent that call on the 328 * other device by adding is to the {@link ConnectionService} with the 329 * {@link #PROPERTY_IS_EXTERNAL_CALL} capability set. 330 * <p> 331 * An {@link ConnectionService} should not assume that all {@link InCallService}s will handle 332 * external connections. Only those {@link InCallService}s which have the 333 * {@link TelecomManager#METADATA_INCLUDE_EXTERNAL_CALLS} metadata set to {@code true} in its 334 * manifest will see external connections. 335 * @hide 336 */ 337 public static final int PROPERTY_IS_EXTERNAL_CALL = 1<<4; 338 339 340 //********************************************************************************************** 341 // Next PROPERTY value: 1<<5 342 //********************************************************************************************** 343 344 /** 345 * Connection extra key used to store the last forwarded number associated with the current 346 * connection. Used to communicate to the user interface that the connection was forwarded via 347 * the specified number. 348 */ 349 public static final String EXTRA_LAST_FORWARDED_NUMBER = 350 "android.telecom.extra.LAST_FORWARDED_NUMBER"; 351 352 /** 353 * Connection extra key used to store a child number associated with the current connection. 354 * Used to communicate to the user interface that the connection was received via 355 * a child address (i.e. phone number) associated with the {@link PhoneAccount}'s primary 356 * address. 357 */ 358 public static final String EXTRA_CHILD_ADDRESS = "android.telecom.extra.CHILD_ADDRESS"; 359 360 /** 361 * Connection extra key used to store the subject for an incoming call. The user interface can 362 * query this extra and display its contents for incoming calls. Will only be used if the 363 * {@link PhoneAccount} supports the capability {@link PhoneAccount#CAPABILITY_CALL_SUBJECT}. 364 */ 365 public static final String EXTRA_CALL_SUBJECT = "android.telecom.extra.CALL_SUBJECT"; 366 367 /** 368 * Connection event used to inform Telecom that it should play the on hold tone. This is used 369 * to play a tone when the peer puts the current call on hold. Sent to Telecom via 370 * {@link #sendConnectionEvent(String)}. 371 * @hide 372 */ 373 public static final String EVENT_ON_HOLD_TONE_START = 374 "android.telecom.event.ON_HOLD_TONE_START"; 375 376 /** 377 * Connection event used to inform Telecom that it should stop the on hold tone. This is used 378 * to stop a tone when the peer puts the current call on hold. Sent to Telecom via 379 * {@link #sendConnectionEvent(String)}. 380 * @hide 381 */ 382 public static final String EVENT_ON_HOLD_TONE_END = 383 "android.telecom.event.ON_HOLD_TONE_END"; 384 385 /** 386 * Connection event used to inform {@link InCallService}s when pulling of an external call has 387 * failed. The user interface should inform the user of the error. 388 * <p> 389 * Expected to be used by the {@link ConnectionService} when the {@link Call#pullExternalCall()} 390 * API is called on a {@link Call} with the properties 391 * {@link Call.Details#PROPERTY_IS_EXTERNAL_CALL} and 392 * {@link Call.Details#CAPABILITY_CAN_PULL_CALL}, but the {@link ConnectionService} could not 393 * pull the external call due to an error condition. 394 * @hide 395 */ 396 public static final String EVENT_CALL_PULL_FAILED = "android.telecom.event.CALL_PULL_FAILED"; 397 398 // Flag controlling whether PII is emitted into the logs 399 private static final boolean PII_DEBUG = Log.isLoggable(android.util.Log.DEBUG); 400 401 /** 402 * Whether the given capabilities support the specified capability. 403 * 404 * @param capabilities A capability bit field. 405 * @param capability The capability to check capabilities for. 406 * @return Whether the specified capability is supported. 407 * @hide 408 */ 409 public static boolean can(int capabilities, int capability) { 410 return (capabilities & capability) == capability; 411 } 412 413 /** 414 * Whether the capabilities of this {@code Connection} supports the specified capability. 415 * 416 * @param capability The capability to check capabilities for. 417 * @return Whether the specified capability is supported. 418 * @hide 419 */ 420 public boolean can(int capability) { 421 return can(mConnectionCapabilities, capability); 422 } 423 424 /** 425 * Removes the specified capability from the set of capabilities of this {@code Connection}. 426 * 427 * @param capability The capability to remove from the set. 428 * @hide 429 */ 430 public void removeCapability(int capability) { 431 mConnectionCapabilities &= ~capability; 432 } 433 434 /** 435 * Adds the specified capability to the set of capabilities of this {@code Connection}. 436 * 437 * @param capability The capability to add to the set. 438 * @hide 439 */ 440 public void addCapability(int capability) { 441 mConnectionCapabilities |= capability; 442 } 443 444 445 public static String capabilitiesToString(int capabilities) { 446 StringBuilder builder = new StringBuilder(); 447 builder.append("[Capabilities:"); 448 if (can(capabilities, CAPABILITY_HOLD)) { 449 builder.append(" CAPABILITY_HOLD"); 450 } 451 if (can(capabilities, CAPABILITY_SUPPORT_HOLD)) { 452 builder.append(" CAPABILITY_SUPPORT_HOLD"); 453 } 454 if (can(capabilities, CAPABILITY_MERGE_CONFERENCE)) { 455 builder.append(" CAPABILITY_MERGE_CONFERENCE"); 456 } 457 if (can(capabilities, CAPABILITY_SWAP_CONFERENCE)) { 458 builder.append(" CAPABILITY_SWAP_CONFERENCE"); 459 } 460 if (can(capabilities, CAPABILITY_RESPOND_VIA_TEXT)) { 461 builder.append(" CAPABILITY_RESPOND_VIA_TEXT"); 462 } 463 if (can(capabilities, CAPABILITY_MUTE)) { 464 builder.append(" CAPABILITY_MUTE"); 465 } 466 if (can(capabilities, CAPABILITY_MANAGE_CONFERENCE)) { 467 builder.append(" CAPABILITY_MANAGE_CONFERENCE"); 468 } 469 if (can(capabilities, CAPABILITY_SUPPORTS_VT_LOCAL_RX)) { 470 builder.append(" CAPABILITY_SUPPORTS_VT_LOCAL_RX"); 471 } 472 if (can(capabilities, CAPABILITY_SUPPORTS_VT_LOCAL_TX)) { 473 builder.append(" CAPABILITY_SUPPORTS_VT_LOCAL_TX"); 474 } 475 if (can(capabilities, CAPABILITY_SUPPORTS_VT_LOCAL_BIDIRECTIONAL)) { 476 builder.append(" CAPABILITY_SUPPORTS_VT_LOCAL_BIDIRECTIONAL"); 477 } 478 if (can(capabilities, CAPABILITY_SUPPORTS_VT_REMOTE_RX)) { 479 builder.append(" CAPABILITY_SUPPORTS_VT_REMOTE_RX"); 480 } 481 if (can(capabilities, CAPABILITY_SUPPORTS_VT_REMOTE_TX)) { 482 builder.append(" CAPABILITY_SUPPORTS_VT_REMOTE_TX"); 483 } 484 if (can(capabilities, CAPABILITY_SUPPORTS_VT_REMOTE_BIDIRECTIONAL)) { 485 builder.append(" CAPABILITY_SUPPORTS_VT_REMOTE_BIDIRECTIONAL"); 486 } 487 if (can(capabilities, CAPABILITY_CANNOT_DOWNGRADE_VIDEO_TO_AUDIO)) { 488 builder.append(" CAPABILITY_CANNOT_DOWNGRADE_VIDEO_TO_AUDIO"); 489 } 490 if (can(capabilities, CAPABILITY_SPEED_UP_MT_AUDIO)) { 491 builder.append(" CAPABILITY_SPEED_UP_MT_AUDIO"); 492 } 493 if (can(capabilities, CAPABILITY_CAN_UPGRADE_TO_VIDEO)) { 494 builder.append(" CAPABILITY_CAN_UPGRADE_TO_VIDEO"); 495 } 496 if (can(capabilities, CAPABILITY_CAN_PAUSE_VIDEO)) { 497 builder.append(" CAPABILITY_CAN_PAUSE_VIDEO"); 498 } 499 if (can(capabilities, CAPABILITY_CONFERENCE_HAS_NO_CHILDREN)) { 500 builder.append(" CAPABILITY_SINGLE_PARTY_CONFERENCE"); 501 } 502 if (can(capabilities, CAPABILITY_CAN_SEND_RESPONSE_VIA_CONNECTION)) { 503 builder.append(" CAPABILITY_CAN_SEND_RESPONSE_VIA_CONNECTION"); 504 } 505 if (can(capabilities, CAPABILITY_CAN_PULL_CALL)) { 506 builder.append(" CAPABILITY_CAN_PULL_CALL"); 507 } 508 509 builder.append("]"); 510 return builder.toString(); 511 } 512 513 /** 514 * Builds a string representation of a properties bit-mask. 515 * 516 * @param properties The properties bit-mask. 517 * @return String representation. 518 * @hide 519 */ 520 public static String propertiesToString(int properties) { 521 StringBuilder builder = new StringBuilder(); 522 builder.append("[Properties:"); 523 524 if (can(properties, PROPERTY_SHOW_CALLBACK_NUMBER)) { 525 builder.append(" PROPERTY_SHOW_CALLBACK_NUMBER"); 526 } 527 528 if (can(properties, PROPERTY_HIGH_DEF_AUDIO)) { 529 builder.append(" PROPERTY_HIGH_DEF_AUDIO"); 530 } 531 532 if (can(properties, PROPERTY_WIFI)) { 533 builder.append(" PROPERTY_WIFI"); 534 } 535 536 if (can(properties, PROPERTY_GENERIC_CONFERENCE)) { 537 builder.append(" PROPERTY_GENERIC_CONFERENCE"); 538 } 539 540 if (can(properties, PROPERTY_IS_EXTERNAL_CALL)) { 541 builder.append(" PROPERTY_IS_EXTERNAL_CALL"); 542 } 543 544 builder.append("]"); 545 return builder.toString(); 546 } 547 548 /** @hide */ 549 public abstract static class Listener { 550 public void onStateChanged(Connection c, int state) {} 551 public void onAddressChanged(Connection c, Uri newAddress, int presentation) {} 552 public void onCallerDisplayNameChanged( 553 Connection c, String callerDisplayName, int presentation) {} 554 public void onVideoStateChanged(Connection c, int videoState) {} 555 public void onDisconnected(Connection c, DisconnectCause disconnectCause) {} 556 public void onPostDialWait(Connection c, String remaining) {} 557 public void onPostDialChar(Connection c, char nextChar) {} 558 public void onRingbackRequested(Connection c, boolean ringback) {} 559 public void onDestroyed(Connection c) {} 560 public void onConnectionCapabilitiesChanged(Connection c, int capabilities) {} 561 public void onConnectionPropertiesChanged(Connection c, int properties) {} 562 public void onVideoProviderChanged( 563 Connection c, VideoProvider videoProvider) {} 564 public void onAudioModeIsVoipChanged(Connection c, boolean isVoip) {} 565 public void onStatusHintsChanged(Connection c, StatusHints statusHints) {} 566 public void onConferenceablesChanged( 567 Connection c, List<Conferenceable> conferenceables) {} 568 public void onConferenceChanged(Connection c, Conference conference) {} 569 /** @hide */ 570 public void onConferenceParticipantsChanged(Connection c, 571 List<ConferenceParticipant> participants) {} 572 public void onConferenceStarted() {} 573 public void onConferenceMergeFailed(Connection c) {} 574 public void onExtrasChanged(Connection c, Bundle extras) {} 575 public void onExtrasRemoved(Connection c, List<String> keys) {} 576 public void onConnectionEvent(Connection c, String event, Bundle extras) {} 577 } 578 579 /** 580 * Provides a means of controlling the video session associated with a {@link Connection}. 581 * <p> 582 * Implementations create a custom subclass of {@link VideoProvider} and the 583 * {@link ConnectionService} creates an instance sets it on the {@link Connection} using 584 * {@link Connection#setVideoProvider(VideoProvider)}. Any connection which supports video 585 * should set the {@link VideoProvider}. 586 * <p> 587 * The {@link VideoProvider} serves two primary purposes: it provides a means for Telecom and 588 * {@link InCallService} implementations to issue requests related to the video session; 589 * it provides a means for the {@link ConnectionService} to report events and information 590 * related to the video session to Telecom and the {@link InCallService} implementations. 591 * <p> 592 * {@link InCallService} implementations interact with the {@link VideoProvider} via 593 * {@link android.telecom.InCallService.VideoCall}. 594 */ 595 public static abstract class VideoProvider { 596 597 /** 598 * Video is not being received (no protocol pause was issued). 599 * @see #handleCallSessionEvent(int) 600 */ 601 public static final int SESSION_EVENT_RX_PAUSE = 1; 602 603 /** 604 * Video reception has resumed after a {@link #SESSION_EVENT_RX_PAUSE}. 605 * @see #handleCallSessionEvent(int) 606 */ 607 public static final int SESSION_EVENT_RX_RESUME = 2; 608 609 /** 610 * Video transmission has begun. This occurs after a negotiated start of video transmission 611 * when the underlying protocol has actually begun transmitting video to the remote party. 612 * @see #handleCallSessionEvent(int) 613 */ 614 public static final int SESSION_EVENT_TX_START = 3; 615 616 /** 617 * Video transmission has stopped. This occurs after a negotiated stop of video transmission 618 * when the underlying protocol has actually stopped transmitting video to the remote party. 619 * @see #handleCallSessionEvent(int) 620 */ 621 public static final int SESSION_EVENT_TX_STOP = 4; 622 623 /** 624 * A camera failure has occurred for the selected camera. The {@link InCallService} can use 625 * this as a cue to inform the user the camera is not available. 626 * @see #handleCallSessionEvent(int) 627 */ 628 public static final int SESSION_EVENT_CAMERA_FAILURE = 5; 629 630 /** 631 * Issued after {@link #SESSION_EVENT_CAMERA_FAILURE} when the camera is once again ready 632 * for operation. The {@link InCallService} can use this as a cue to inform the user that 633 * the camera has become available again. 634 * @see #handleCallSessionEvent(int) 635 */ 636 public static final int SESSION_EVENT_CAMERA_READY = 6; 637 638 /** 639 * Session modify request was successful. 640 * @see #receiveSessionModifyResponse(int, VideoProfile, VideoProfile) 641 */ 642 public static final int SESSION_MODIFY_REQUEST_SUCCESS = 1; 643 644 /** 645 * Session modify request failed. 646 * @see #receiveSessionModifyResponse(int, VideoProfile, VideoProfile) 647 */ 648 public static final int SESSION_MODIFY_REQUEST_FAIL = 2; 649 650 /** 651 * Session modify request ignored due to invalid parameters. 652 * @see #receiveSessionModifyResponse(int, VideoProfile, VideoProfile) 653 */ 654 public static final int SESSION_MODIFY_REQUEST_INVALID = 3; 655 656 /** 657 * Session modify request timed out. 658 * @see #receiveSessionModifyResponse(int, VideoProfile, VideoProfile) 659 */ 660 public static final int SESSION_MODIFY_REQUEST_TIMED_OUT = 4; 661 662 /** 663 * Session modify request rejected by remote user. 664 * @see #receiveSessionModifyResponse(int, VideoProfile, VideoProfile) 665 */ 666 public static final int SESSION_MODIFY_REQUEST_REJECTED_BY_REMOTE = 5; 667 668 private static final int MSG_ADD_VIDEO_CALLBACK = 1; 669 private static final int MSG_SET_CAMERA = 2; 670 private static final int MSG_SET_PREVIEW_SURFACE = 3; 671 private static final int MSG_SET_DISPLAY_SURFACE = 4; 672 private static final int MSG_SET_DEVICE_ORIENTATION = 5; 673 private static final int MSG_SET_ZOOM = 6; 674 private static final int MSG_SEND_SESSION_MODIFY_REQUEST = 7; 675 private static final int MSG_SEND_SESSION_MODIFY_RESPONSE = 8; 676 private static final int MSG_REQUEST_CAMERA_CAPABILITIES = 9; 677 private static final int MSG_REQUEST_CONNECTION_DATA_USAGE = 10; 678 private static final int MSG_SET_PAUSE_IMAGE = 11; 679 private static final int MSG_REMOVE_VIDEO_CALLBACK = 12; 680 681 private VideoProvider.VideoProviderHandler mMessageHandler; 682 private final VideoProvider.VideoProviderBinder mBinder; 683 684 /** 685 * Stores a list of the video callbacks, keyed by IBinder. 686 * 687 * ConcurrentHashMap constructor params: 8 is initial table size, 0.9f is 688 * load factor before resizing, 1 means we only expect a single thread to 689 * access the map so make only a single shard 690 */ 691 private ConcurrentHashMap<IBinder, IVideoCallback> mVideoCallbacks = 692 new ConcurrentHashMap<IBinder, IVideoCallback>(8, 0.9f, 1); 693 694 /** 695 * Default handler used to consolidate binder method calls onto a single thread. 696 */ 697 private final class VideoProviderHandler extends Handler { 698 public VideoProviderHandler() { 699 super(); 700 } 701 702 public VideoProviderHandler(Looper looper) { 703 super(looper); 704 } 705 706 @Override 707 public void handleMessage(Message msg) { 708 switch (msg.what) { 709 case MSG_ADD_VIDEO_CALLBACK: { 710 IBinder binder = (IBinder) msg.obj; 711 IVideoCallback callback = IVideoCallback.Stub 712 .asInterface((IBinder) msg.obj); 713 if (callback == null) { 714 Log.w(this, "addVideoProvider - skipped; callback is null."); 715 break; 716 } 717 718 if (mVideoCallbacks.containsKey(binder)) { 719 Log.i(this, "addVideoProvider - skipped; already present."); 720 break; 721 } 722 mVideoCallbacks.put(binder, callback); 723 break; 724 } 725 case MSG_REMOVE_VIDEO_CALLBACK: { 726 IBinder binder = (IBinder) msg.obj; 727 IVideoCallback callback = IVideoCallback.Stub 728 .asInterface((IBinder) msg.obj); 729 if (!mVideoCallbacks.containsKey(binder)) { 730 Log.i(this, "removeVideoProvider - skipped; not present."); 731 break; 732 } 733 mVideoCallbacks.remove(binder); 734 break; 735 } 736 case MSG_SET_CAMERA: 737 onSetCamera((String) msg.obj); 738 break; 739 case MSG_SET_PREVIEW_SURFACE: 740 onSetPreviewSurface((Surface) msg.obj); 741 break; 742 case MSG_SET_DISPLAY_SURFACE: 743 onSetDisplaySurface((Surface) msg.obj); 744 break; 745 case MSG_SET_DEVICE_ORIENTATION: 746 onSetDeviceOrientation(msg.arg1); 747 break; 748 case MSG_SET_ZOOM: 749 onSetZoom((Float) msg.obj); 750 break; 751 case MSG_SEND_SESSION_MODIFY_REQUEST: { 752 SomeArgs args = (SomeArgs) msg.obj; 753 try { 754 onSendSessionModifyRequest((VideoProfile) args.arg1, 755 (VideoProfile) args.arg2); 756 } finally { 757 args.recycle(); 758 } 759 break; 760 } 761 case MSG_SEND_SESSION_MODIFY_RESPONSE: 762 onSendSessionModifyResponse((VideoProfile) msg.obj); 763 break; 764 case MSG_REQUEST_CAMERA_CAPABILITIES: 765 onRequestCameraCapabilities(); 766 break; 767 case MSG_REQUEST_CONNECTION_DATA_USAGE: 768 onRequestConnectionDataUsage(); 769 break; 770 case MSG_SET_PAUSE_IMAGE: 771 onSetPauseImage((Uri) msg.obj); 772 break; 773 default: 774 break; 775 } 776 } 777 } 778 779 /** 780 * IVideoProvider stub implementation. 781 */ 782 private final class VideoProviderBinder extends IVideoProvider.Stub { 783 public void addVideoCallback(IBinder videoCallbackBinder) { 784 mMessageHandler.obtainMessage( 785 MSG_ADD_VIDEO_CALLBACK, videoCallbackBinder).sendToTarget(); 786 } 787 788 public void removeVideoCallback(IBinder videoCallbackBinder) { 789 mMessageHandler.obtainMessage( 790 MSG_REMOVE_VIDEO_CALLBACK, videoCallbackBinder).sendToTarget(); 791 } 792 793 public void setCamera(String cameraId) { 794 mMessageHandler.obtainMessage(MSG_SET_CAMERA, cameraId).sendToTarget(); 795 } 796 797 public void setPreviewSurface(Surface surface) { 798 mMessageHandler.obtainMessage(MSG_SET_PREVIEW_SURFACE, surface).sendToTarget(); 799 } 800 801 public void setDisplaySurface(Surface surface) { 802 mMessageHandler.obtainMessage(MSG_SET_DISPLAY_SURFACE, surface).sendToTarget(); 803 } 804 805 public void setDeviceOrientation(int rotation) { 806 mMessageHandler.obtainMessage( 807 MSG_SET_DEVICE_ORIENTATION, rotation, 0).sendToTarget(); 808 } 809 810 public void setZoom(float value) { 811 mMessageHandler.obtainMessage(MSG_SET_ZOOM, value).sendToTarget(); 812 } 813 814 public void sendSessionModifyRequest(VideoProfile fromProfile, VideoProfile toProfile) { 815 SomeArgs args = SomeArgs.obtain(); 816 args.arg1 = fromProfile; 817 args.arg2 = toProfile; 818 mMessageHandler.obtainMessage(MSG_SEND_SESSION_MODIFY_REQUEST, args).sendToTarget(); 819 } 820 821 public void sendSessionModifyResponse(VideoProfile responseProfile) { 822 mMessageHandler.obtainMessage( 823 MSG_SEND_SESSION_MODIFY_RESPONSE, responseProfile).sendToTarget(); 824 } 825 826 public void requestCameraCapabilities() { 827 mMessageHandler.obtainMessage(MSG_REQUEST_CAMERA_CAPABILITIES).sendToTarget(); 828 } 829 830 public void requestCallDataUsage() { 831 mMessageHandler.obtainMessage(MSG_REQUEST_CONNECTION_DATA_USAGE).sendToTarget(); 832 } 833 834 public void setPauseImage(Uri uri) { 835 mMessageHandler.obtainMessage(MSG_SET_PAUSE_IMAGE, uri).sendToTarget(); 836 } 837 } 838 839 public VideoProvider() { 840 mBinder = new VideoProvider.VideoProviderBinder(); 841 mMessageHandler = new VideoProvider.VideoProviderHandler(Looper.getMainLooper()); 842 } 843 844 /** 845 * Creates an instance of the {@link VideoProvider}, specifying the looper to use. 846 * 847 * @param looper The looper. 848 * @hide 849 */ 850 public VideoProvider(Looper looper) { 851 mBinder = new VideoProvider.VideoProviderBinder(); 852 mMessageHandler = new VideoProvider.VideoProviderHandler(looper); 853 } 854 855 /** 856 * Returns binder object which can be used across IPC methods. 857 * @hide 858 */ 859 public final IVideoProvider getInterface() { 860 return mBinder; 861 } 862 863 /** 864 * Sets the camera to be used for the outgoing video. 865 * <p> 866 * The {@link VideoProvider} should respond by communicating the capabilities of the chosen 867 * camera via 868 * {@link VideoProvider#changeCameraCapabilities(VideoProfile.CameraCapabilities)}. 869 * <p> 870 * Sent from the {@link InCallService} via 871 * {@link InCallService.VideoCall#setCamera(String)}. 872 * 873 * @param cameraId The id of the camera (use ids as reported by 874 * {@link CameraManager#getCameraIdList()}). 875 */ 876 public abstract void onSetCamera(String cameraId); 877 878 /** 879 * Sets the surface to be used for displaying a preview of what the user's camera is 880 * currently capturing. When video transmission is enabled, this is the video signal which 881 * is sent to the remote device. 882 * <p> 883 * Sent from the {@link InCallService} via 884 * {@link InCallService.VideoCall#setPreviewSurface(Surface)}. 885 * 886 * @param surface The {@link Surface}. 887 */ 888 public abstract void onSetPreviewSurface(Surface surface); 889 890 /** 891 * Sets the surface to be used for displaying the video received from the remote device. 892 * <p> 893 * Sent from the {@link InCallService} via 894 * {@link InCallService.VideoCall#setDisplaySurface(Surface)}. 895 * 896 * @param surface The {@link Surface}. 897 */ 898 public abstract void onSetDisplaySurface(Surface surface); 899 900 /** 901 * Sets the device orientation, in degrees. Assumes that a standard portrait orientation of 902 * the device is 0 degrees. 903 * <p> 904 * Sent from the {@link InCallService} via 905 * {@link InCallService.VideoCall#setDeviceOrientation(int)}. 906 * 907 * @param rotation The device orientation, in degrees. 908 */ 909 public abstract void onSetDeviceOrientation(int rotation); 910 911 /** 912 * Sets camera zoom ratio. 913 * <p> 914 * Sent from the {@link InCallService} via {@link InCallService.VideoCall#setZoom(float)}. 915 * 916 * @param value The camera zoom ratio. 917 */ 918 public abstract void onSetZoom(float value); 919 920 /** 921 * Issues a request to modify the properties of the current video session. 922 * <p> 923 * Example scenarios include: requesting an audio-only call to be upgraded to a 924 * bi-directional video call, turning on or off the user's camera, sending a pause signal 925 * when the {@link InCallService} is no longer the foreground application. 926 * <p> 927 * If the {@link VideoProvider} determines a request to be invalid, it should call 928 * {@link #receiveSessionModifyResponse(int, VideoProfile, VideoProfile)} to report the 929 * invalid request back to the {@link InCallService}. 930 * <p> 931 * Where a request requires confirmation from the user of the peer device, the 932 * {@link VideoProvider} must communicate the request to the peer device and handle the 933 * user's response. {@link #receiveSessionModifyResponse(int, VideoProfile, VideoProfile)} 934 * is used to inform the {@link InCallService} of the result of the request. 935 * <p> 936 * Sent from the {@link InCallService} via 937 * {@link InCallService.VideoCall#sendSessionModifyRequest(VideoProfile)}. 938 * 939 * @param fromProfile The video profile prior to the request. 940 * @param toProfile The video profile with the requested changes made. 941 */ 942 public abstract void onSendSessionModifyRequest(VideoProfile fromProfile, 943 VideoProfile toProfile); 944 945 /** 946 * Provides a response to a request to change the current video session properties. 947 * <p> 948 * For example, if the peer requests and upgrade from an audio-only call to a bi-directional 949 * video call, could decline the request and keep the call as audio-only. 950 * In such a scenario, the {@code responseProfile} would have a video state of 951 * {@link VideoProfile#STATE_AUDIO_ONLY}. If the user had decided to accept the request, 952 * the video state would be {@link VideoProfile#STATE_BIDIRECTIONAL}. 953 * <p> 954 * Sent from the {@link InCallService} via 955 * {@link InCallService.VideoCall#sendSessionModifyResponse(VideoProfile)} in response to 956 * a {@link InCallService.VideoCall.Callback#onSessionModifyRequestReceived(VideoProfile)} 957 * callback. 958 * 959 * @param responseProfile The response video profile. 960 */ 961 public abstract void onSendSessionModifyResponse(VideoProfile responseProfile); 962 963 /** 964 * Issues a request to the {@link VideoProvider} to retrieve the camera capabilities. 965 * <p> 966 * The {@link VideoProvider} should respond by communicating the capabilities of the chosen 967 * camera via 968 * {@link VideoProvider#changeCameraCapabilities(VideoProfile.CameraCapabilities)}. 969 * <p> 970 * Sent from the {@link InCallService} via 971 * {@link InCallService.VideoCall#requestCameraCapabilities()}. 972 */ 973 public abstract void onRequestCameraCapabilities(); 974 975 /** 976 * Issues a request to the {@link VideoProvider} to retrieve the current data usage for the 977 * video component of the current {@link Connection}. 978 * <p> 979 * The {@link VideoProvider} should respond by communicating current data usage, in bytes, 980 * via {@link VideoProvider#setCallDataUsage(long)}. 981 * <p> 982 * Sent from the {@link InCallService} via 983 * {@link InCallService.VideoCall#requestCallDataUsage()}. 984 */ 985 public abstract void onRequestConnectionDataUsage(); 986 987 /** 988 * Provides the {@link VideoProvider} with the {@link Uri} of an image to be displayed to 989 * the peer device when the video signal is paused. 990 * <p> 991 * Sent from the {@link InCallService} via 992 * {@link InCallService.VideoCall#setPauseImage(Uri)}. 993 * 994 * @param uri URI of image to display. 995 */ 996 public abstract void onSetPauseImage(Uri uri); 997 998 /** 999 * Used to inform listening {@link InCallService} implementations when the 1000 * {@link VideoProvider} receives a session modification request. 1001 * <p> 1002 * Received by the {@link InCallService} via 1003 * {@link InCallService.VideoCall.Callback#onSessionModifyRequestReceived(VideoProfile)}, 1004 * 1005 * @param videoProfile The requested video profile. 1006 * @see #onSendSessionModifyRequest(VideoProfile, VideoProfile) 1007 */ 1008 public void receiveSessionModifyRequest(VideoProfile videoProfile) { 1009 if (mVideoCallbacks != null) { 1010 for (IVideoCallback callback : mVideoCallbacks.values()) { 1011 try { 1012 callback.receiveSessionModifyRequest(videoProfile); 1013 } catch (RemoteException ignored) { 1014 Log.w(this, "receiveSessionModifyRequest callback failed", ignored); 1015 } 1016 } 1017 } 1018 } 1019 1020 /** 1021 * Used to inform listening {@link InCallService} implementations when the 1022 * {@link VideoProvider} receives a response to a session modification request. 1023 * <p> 1024 * Received by the {@link InCallService} via 1025 * {@link InCallService.VideoCall.Callback#onSessionModifyResponseReceived(int, 1026 * VideoProfile, VideoProfile)}. 1027 * 1028 * @param status Status of the session modify request. Valid values are 1029 * {@link VideoProvider#SESSION_MODIFY_REQUEST_SUCCESS}, 1030 * {@link VideoProvider#SESSION_MODIFY_REQUEST_FAIL}, 1031 * {@link VideoProvider#SESSION_MODIFY_REQUEST_INVALID}, 1032 * {@link VideoProvider#SESSION_MODIFY_REQUEST_TIMED_OUT}, 1033 * {@link VideoProvider#SESSION_MODIFY_REQUEST_REJECTED_BY_REMOTE} 1034 * @param requestedProfile The original request which was sent to the peer device. 1035 * @param responseProfile The actual profile changes agreed to by the peer device. 1036 * @see #onSendSessionModifyRequest(VideoProfile, VideoProfile) 1037 */ 1038 public void receiveSessionModifyResponse(int status, 1039 VideoProfile requestedProfile, VideoProfile responseProfile) { 1040 if (mVideoCallbacks != null) { 1041 for (IVideoCallback callback : mVideoCallbacks.values()) { 1042 try { 1043 callback.receiveSessionModifyResponse(status, requestedProfile, 1044 responseProfile); 1045 } catch (RemoteException ignored) { 1046 Log.w(this, "receiveSessionModifyResponse callback failed", ignored); 1047 } 1048 } 1049 } 1050 } 1051 1052 /** 1053 * Used to inform listening {@link InCallService} implementations when the 1054 * {@link VideoProvider} reports a call session event. 1055 * <p> 1056 * Received by the {@link InCallService} via 1057 * {@link InCallService.VideoCall.Callback#onCallSessionEvent(int)}. 1058 * 1059 * @param event The event. Valid values are: {@link VideoProvider#SESSION_EVENT_RX_PAUSE}, 1060 * {@link VideoProvider#SESSION_EVENT_RX_RESUME}, 1061 * {@link VideoProvider#SESSION_EVENT_TX_START}, 1062 * {@link VideoProvider#SESSION_EVENT_TX_STOP}, 1063 * {@link VideoProvider#SESSION_EVENT_CAMERA_FAILURE}, 1064 * {@link VideoProvider#SESSION_EVENT_CAMERA_READY}. 1065 */ 1066 public void handleCallSessionEvent(int event) { 1067 if (mVideoCallbacks != null) { 1068 for (IVideoCallback callback : mVideoCallbacks.values()) { 1069 try { 1070 callback.handleCallSessionEvent(event); 1071 } catch (RemoteException ignored) { 1072 Log.w(this, "handleCallSessionEvent callback failed", ignored); 1073 } 1074 } 1075 } 1076 } 1077 1078 /** 1079 * Used to inform listening {@link InCallService} implementations when the dimensions of the 1080 * peer's video have changed. 1081 * <p> 1082 * This could occur if, for example, the peer rotates their device, changing the aspect 1083 * ratio of the video, or if the user switches between the back and front cameras. 1084 * <p> 1085 * Received by the {@link InCallService} via 1086 * {@link InCallService.VideoCall.Callback#onPeerDimensionsChanged(int, int)}. 1087 * 1088 * @param width The updated peer video width. 1089 * @param height The updated peer video height. 1090 */ 1091 public void changePeerDimensions(int width, int height) { 1092 if (mVideoCallbacks != null) { 1093 for (IVideoCallback callback : mVideoCallbacks.values()) { 1094 try { 1095 callback.changePeerDimensions(width, height); 1096 } catch (RemoteException ignored) { 1097 Log.w(this, "changePeerDimensions callback failed", ignored); 1098 } 1099 } 1100 } 1101 } 1102 1103 /** 1104 * Used to inform listening {@link InCallService} implementations when the data usage of the 1105 * video associated with the current {@link Connection} has changed. 1106 * <p> 1107 * This could be in response to a preview request via 1108 * {@link #onRequestConnectionDataUsage()}, or as a periodic update by the 1109 * {@link VideoProvider}. Where periodic updates of data usage are provided, they should be 1110 * provided at most for every 1 MB of data transferred and no more than once every 10 sec. 1111 * <p> 1112 * Received by the {@link InCallService} via 1113 * {@link InCallService.VideoCall.Callback#onCallDataUsageChanged(long)}. 1114 * 1115 * @param dataUsage The updated data usage (in bytes). Reported as the cumulative bytes 1116 * used since the start of the call. 1117 */ 1118 public void setCallDataUsage(long dataUsage) { 1119 if (mVideoCallbacks != null) { 1120 for (IVideoCallback callback : mVideoCallbacks.values()) { 1121 try { 1122 callback.changeCallDataUsage(dataUsage); 1123 } catch (RemoteException ignored) { 1124 Log.w(this, "setCallDataUsage callback failed", ignored); 1125 } 1126 } 1127 } 1128 } 1129 1130 /** 1131 * @see #setCallDataUsage(long) 1132 * 1133 * @param dataUsage The updated data usage (in byes). 1134 * @deprecated - Use {@link #setCallDataUsage(long)} instead. 1135 * @hide 1136 */ 1137 public void changeCallDataUsage(long dataUsage) { 1138 setCallDataUsage(dataUsage); 1139 } 1140 1141 /** 1142 * Used to inform listening {@link InCallService} implementations when the capabilities of 1143 * the current camera have changed. 1144 * <p> 1145 * The {@link VideoProvider} should call this in response to 1146 * {@link VideoProvider#onRequestCameraCapabilities()}, or when the current camera is 1147 * changed via {@link VideoProvider#onSetCamera(String)}. 1148 * <p> 1149 * Received by the {@link InCallService} via 1150 * {@link InCallService.VideoCall.Callback#onCameraCapabilitiesChanged( 1151 * VideoProfile.CameraCapabilities)}. 1152 * 1153 * @param cameraCapabilities The new camera capabilities. 1154 */ 1155 public void changeCameraCapabilities(VideoProfile.CameraCapabilities cameraCapabilities) { 1156 if (mVideoCallbacks != null) { 1157 for (IVideoCallback callback : mVideoCallbacks.values()) { 1158 try { 1159 callback.changeCameraCapabilities(cameraCapabilities); 1160 } catch (RemoteException ignored) { 1161 Log.w(this, "changeCameraCapabilities callback failed", ignored); 1162 } 1163 } 1164 } 1165 } 1166 1167 /** 1168 * Used to inform listening {@link InCallService} implementations when the video quality 1169 * of the call has changed. 1170 * <p> 1171 * Received by the {@link InCallService} via 1172 * {@link InCallService.VideoCall.Callback#onVideoQualityChanged(int)}. 1173 * 1174 * @param videoQuality The updated video quality. Valid values: 1175 * {@link VideoProfile#QUALITY_HIGH}, 1176 * {@link VideoProfile#QUALITY_MEDIUM}, 1177 * {@link VideoProfile#QUALITY_LOW}, 1178 * {@link VideoProfile#QUALITY_DEFAULT}. 1179 */ 1180 public void changeVideoQuality(int videoQuality) { 1181 if (mVideoCallbacks != null) { 1182 for (IVideoCallback callback : mVideoCallbacks.values()) { 1183 try { 1184 callback.changeVideoQuality(videoQuality); 1185 } catch (RemoteException ignored) { 1186 Log.w(this, "changeVideoQuality callback failed", ignored); 1187 } 1188 } 1189 } 1190 } 1191 } 1192 1193 private final Listener mConnectionDeathListener = new Listener() { 1194 @Override 1195 public void onDestroyed(Connection c) { 1196 if (mConferenceables.remove(c)) { 1197 fireOnConferenceableConnectionsChanged(); 1198 } 1199 } 1200 }; 1201 1202 private final Conference.Listener mConferenceDeathListener = new Conference.Listener() { 1203 @Override 1204 public void onDestroyed(Conference c) { 1205 if (mConferenceables.remove(c)) { 1206 fireOnConferenceableConnectionsChanged(); 1207 } 1208 } 1209 }; 1210 1211 /** 1212 * ConcurrentHashMap constructor params: 8 is initial table size, 0.9f is 1213 * load factor before resizing, 1 means we only expect a single thread to 1214 * access the map so make only a single shard 1215 */ 1216 private final Set<Listener> mListeners = Collections.newSetFromMap( 1217 new ConcurrentHashMap<Listener, Boolean>(8, 0.9f, 1)); 1218 private final List<Conferenceable> mConferenceables = new ArrayList<>(); 1219 private final List<Conferenceable> mUnmodifiableConferenceables = 1220 Collections.unmodifiableList(mConferenceables); 1221 1222 // The internal telecom call ID associated with this connection. 1223 private String mTelecomCallId; 1224 private int mState = STATE_NEW; 1225 private CallAudioState mCallAudioState; 1226 private Uri mAddress; 1227 private int mAddressPresentation; 1228 private String mCallerDisplayName; 1229 private int mCallerDisplayNamePresentation; 1230 private boolean mRingbackRequested = false; 1231 private int mConnectionCapabilities; 1232 private int mConnectionProperties; 1233 private VideoProvider mVideoProvider; 1234 private boolean mAudioModeIsVoip; 1235 private long mConnectTimeMillis = Conference.CONNECT_TIME_NOT_SPECIFIED; 1236 private StatusHints mStatusHints; 1237 private int mVideoState; 1238 private DisconnectCause mDisconnectCause; 1239 private Conference mConference; 1240 private ConnectionService mConnectionService; 1241 private Bundle mExtras; 1242 private final Object mExtrasLock = new Object(); 1243 1244 /** 1245 * Tracks the key set for the extras bundle provided on the last invocation of 1246 * {@link #setExtras(Bundle)}. Used so that on subsequent invocations we can remove any extras 1247 * keys which were set previously but are no longer present in the replacement Bundle. 1248 */ 1249 private Set<String> mPreviousExtraKeys; 1250 1251 /** 1252 * Create a new Connection. 1253 */ 1254 public Connection() {} 1255 1256 /** 1257 * Returns the Telecom internal call ID associated with this connection. Should only be used 1258 * for debugging and tracing purposes. 1259 * 1260 * @return The Telecom call ID. 1261 * @hide 1262 */ 1263 public final String getTelecomCallId() { 1264 return mTelecomCallId; 1265 } 1266 1267 /** 1268 * @return The address (e.g., phone number) to which this Connection is currently communicating. 1269 */ 1270 public final Uri getAddress() { 1271 return mAddress; 1272 } 1273 1274 /** 1275 * @return The presentation requirements for the address. 1276 * See {@link TelecomManager} for valid values. 1277 */ 1278 public final int getAddressPresentation() { 1279 return mAddressPresentation; 1280 } 1281 1282 /** 1283 * @return The caller display name (CNAP). 1284 */ 1285 public final String getCallerDisplayName() { 1286 return mCallerDisplayName; 1287 } 1288 1289 /** 1290 * @return The presentation requirements for the handle. 1291 * See {@link TelecomManager} for valid values. 1292 */ 1293 public final int getCallerDisplayNamePresentation() { 1294 return mCallerDisplayNamePresentation; 1295 } 1296 1297 /** 1298 * @return The state of this Connection. 1299 */ 1300 public final int getState() { 1301 return mState; 1302 } 1303 1304 /** 1305 * Returns the video state of the connection. 1306 * Valid values: {@link VideoProfile#STATE_AUDIO_ONLY}, 1307 * {@link VideoProfile#STATE_BIDIRECTIONAL}, 1308 * {@link VideoProfile#STATE_TX_ENABLED}, 1309 * {@link VideoProfile#STATE_RX_ENABLED}. 1310 * 1311 * @return The video state of the connection. 1312 * @hide 1313 */ 1314 public final int getVideoState() { 1315 return mVideoState; 1316 } 1317 1318 /** 1319 * @return The audio state of the connection, describing how its audio is currently 1320 * being routed by the system. This is {@code null} if this Connection 1321 * does not directly know about its audio state. 1322 * @deprecated Use {@link #getCallAudioState()} instead. 1323 * @hide 1324 */ 1325 @SystemApi 1326 @Deprecated 1327 public final AudioState getAudioState() { 1328 if (mCallAudioState == null) { 1329 return null; 1330 } 1331 return new AudioState(mCallAudioState); 1332 } 1333 1334 /** 1335 * @return The audio state of the connection, describing how its audio is currently 1336 * being routed by the system. This is {@code null} if this Connection 1337 * does not directly know about its audio state. 1338 */ 1339 public final CallAudioState getCallAudioState() { 1340 return mCallAudioState; 1341 } 1342 1343 /** 1344 * @return The conference that this connection is a part of. Null if it is not part of any 1345 * conference. 1346 */ 1347 public final Conference getConference() { 1348 return mConference; 1349 } 1350 1351 /** 1352 * Returns whether this connection is requesting that the system play a ringback tone 1353 * on its behalf. 1354 */ 1355 public final boolean isRingbackRequested() { 1356 return mRingbackRequested; 1357 } 1358 1359 /** 1360 * @return True if the connection's audio mode is VOIP. 1361 */ 1362 public final boolean getAudioModeIsVoip() { 1363 return mAudioModeIsVoip; 1364 } 1365 1366 /** 1367 * Retrieves the connection start time of the {@code Connnection}, if specified. A value of 1368 * {@link Conference#CONNECT_TIME_NOT_SPECIFIED} indicates that Telecom should determine the 1369 * start time of the conference. 1370 * 1371 * @return The time at which the {@code Connnection} was connected. 1372 * 1373 * @hide 1374 */ 1375 public final long getConnectTimeMillis() { 1376 return mConnectTimeMillis; 1377 } 1378 1379 /** 1380 * @return The status hints for this connection. 1381 */ 1382 public final StatusHints getStatusHints() { 1383 return mStatusHints; 1384 } 1385 1386 /** 1387 * Returns the extras associated with this connection. 1388 * 1389 * @return The extras associated with this connection. 1390 */ 1391 public final Bundle getExtras() { 1392 Bundle extras = null; 1393 synchronized (mExtrasLock) { 1394 if (mExtras != null) { 1395 extras = new Bundle(mExtras); 1396 } 1397 } 1398 return extras; 1399 } 1400 1401 /** 1402 * Assign a listener to be notified of state changes. 1403 * 1404 * @param l A listener. 1405 * @return This Connection. 1406 * 1407 * @hide 1408 */ 1409 public final Connection addConnectionListener(Listener l) { 1410 mListeners.add(l); 1411 return this; 1412 } 1413 1414 /** 1415 * Remove a previously assigned listener that was being notified of state changes. 1416 * 1417 * @param l A Listener. 1418 * @return This Connection. 1419 * 1420 * @hide 1421 */ 1422 public final Connection removeConnectionListener(Listener l) { 1423 if (l != null) { 1424 mListeners.remove(l); 1425 } 1426 return this; 1427 } 1428 1429 /** 1430 * @return The {@link DisconnectCause} for this connection. 1431 */ 1432 public final DisconnectCause getDisconnectCause() { 1433 return mDisconnectCause; 1434 } 1435 1436 /** 1437 * Sets the telecom call ID associated with this Connection. The Telecom Call ID should be used 1438 * ONLY for debugging purposes. 1439 * 1440 * @param callId The telecom call ID. 1441 * @hide 1442 */ 1443 public void setTelecomCallId(String callId) { 1444 mTelecomCallId = callId; 1445 } 1446 1447 /** 1448 * Inform this Connection that the state of its audio output has been changed externally. 1449 * 1450 * @param state The new audio state. 1451 * @hide 1452 */ 1453 final void setCallAudioState(CallAudioState state) { 1454 checkImmutable(); 1455 Log.d(this, "setAudioState %s", state); 1456 mCallAudioState = state; 1457 onAudioStateChanged(getAudioState()); 1458 onCallAudioStateChanged(state); 1459 } 1460 1461 /** 1462 * @param state An integer value of a {@code STATE_*} constant. 1463 * @return A string representation of the value. 1464 */ 1465 public static String stateToString(int state) { 1466 switch (state) { 1467 case STATE_INITIALIZING: 1468 return "INITIALIZING"; 1469 case STATE_NEW: 1470 return "NEW"; 1471 case STATE_RINGING: 1472 return "RINGING"; 1473 case STATE_DIALING: 1474 return "DIALING"; 1475 case STATE_ACTIVE: 1476 return "ACTIVE"; 1477 case STATE_HOLDING: 1478 return "HOLDING"; 1479 case STATE_DISCONNECTED: 1480 return "DISCONNECTED"; 1481 default: 1482 Log.wtf(Connection.class, "Unknown state %d", state); 1483 return "UNKNOWN"; 1484 } 1485 } 1486 1487 /** 1488 * Returns the connection's capabilities, as a bit mask of the {@code CAPABILITY_*} constants. 1489 */ 1490 public final int getConnectionCapabilities() { 1491 return mConnectionCapabilities; 1492 } 1493 1494 /** 1495 * Returns the connection's properties, as a bit mask of the {@code PROPERTY_*} constants. 1496 * @hide 1497 */ 1498 public final int getConnectionProperties() { 1499 return mConnectionProperties; 1500 } 1501 1502 /** 1503 * Sets the value of the {@link #getAddress()} property. 1504 * 1505 * @param address The new address. 1506 * @param presentation The presentation requirements for the address. 1507 * See {@link TelecomManager} for valid values. 1508 */ 1509 public final void setAddress(Uri address, int presentation) { 1510 checkImmutable(); 1511 Log.d(this, "setAddress %s", address); 1512 mAddress = address; 1513 mAddressPresentation = presentation; 1514 for (Listener l : mListeners) { 1515 l.onAddressChanged(this, address, presentation); 1516 } 1517 } 1518 1519 /** 1520 * Sets the caller display name (CNAP). 1521 * 1522 * @param callerDisplayName The new display name. 1523 * @param presentation The presentation requirements for the handle. 1524 * See {@link TelecomManager} for valid values. 1525 */ 1526 public final void setCallerDisplayName(String callerDisplayName, int presentation) { 1527 checkImmutable(); 1528 Log.d(this, "setCallerDisplayName %s", callerDisplayName); 1529 mCallerDisplayName = callerDisplayName; 1530 mCallerDisplayNamePresentation = presentation; 1531 for (Listener l : mListeners) { 1532 l.onCallerDisplayNameChanged(this, callerDisplayName, presentation); 1533 } 1534 } 1535 1536 /** 1537 * Set the video state for the connection. 1538 * Valid values: {@link VideoProfile#STATE_AUDIO_ONLY}, 1539 * {@link VideoProfile#STATE_BIDIRECTIONAL}, 1540 * {@link VideoProfile#STATE_TX_ENABLED}, 1541 * {@link VideoProfile#STATE_RX_ENABLED}. 1542 * 1543 * @param videoState The new video state. 1544 */ 1545 public final void setVideoState(int videoState) { 1546 checkImmutable(); 1547 Log.d(this, "setVideoState %d", videoState); 1548 mVideoState = videoState; 1549 for (Listener l : mListeners) { 1550 l.onVideoStateChanged(this, mVideoState); 1551 } 1552 } 1553 1554 /** 1555 * Sets state to active (e.g., an ongoing connection where two or more parties can actively 1556 * communicate). 1557 */ 1558 public final void setActive() { 1559 checkImmutable(); 1560 setRingbackRequested(false); 1561 setState(STATE_ACTIVE); 1562 } 1563 1564 /** 1565 * Sets state to ringing (e.g., an inbound ringing connection). 1566 */ 1567 public final void setRinging() { 1568 checkImmutable(); 1569 setState(STATE_RINGING); 1570 } 1571 1572 /** 1573 * Sets state to initializing (this Connection is not yet ready to be used). 1574 */ 1575 public final void setInitializing() { 1576 checkImmutable(); 1577 setState(STATE_INITIALIZING); 1578 } 1579 1580 /** 1581 * Sets state to initialized (the Connection has been set up and is now ready to be used). 1582 */ 1583 public final void setInitialized() { 1584 checkImmutable(); 1585 setState(STATE_NEW); 1586 } 1587 1588 /** 1589 * Sets state to dialing (e.g., dialing an outbound connection). 1590 */ 1591 public final void setDialing() { 1592 checkImmutable(); 1593 setState(STATE_DIALING); 1594 } 1595 1596 /** 1597 * Sets state to be on hold. 1598 */ 1599 public final void setOnHold() { 1600 checkImmutable(); 1601 setState(STATE_HOLDING); 1602 } 1603 1604 /** 1605 * Sets the video connection provider. 1606 * @param videoProvider The video provider. 1607 */ 1608 public final void setVideoProvider(VideoProvider videoProvider) { 1609 checkImmutable(); 1610 mVideoProvider = videoProvider; 1611 for (Listener l : mListeners) { 1612 l.onVideoProviderChanged(this, videoProvider); 1613 } 1614 } 1615 1616 public final VideoProvider getVideoProvider() { 1617 return mVideoProvider; 1618 } 1619 1620 /** 1621 * Sets state to disconnected. 1622 * 1623 * @param disconnectCause The reason for the disconnection, as specified by 1624 * {@link DisconnectCause}. 1625 */ 1626 public final void setDisconnected(DisconnectCause disconnectCause) { 1627 checkImmutable(); 1628 mDisconnectCause = disconnectCause; 1629 setState(STATE_DISCONNECTED); 1630 Log.d(this, "Disconnected with cause %s", disconnectCause); 1631 for (Listener l : mListeners) { 1632 l.onDisconnected(this, disconnectCause); 1633 } 1634 } 1635 1636 /** 1637 * Informs listeners that this {@code Connection} is in a post-dial wait state. This is done 1638 * when (a) the {@code Connection} is issuing a DTMF sequence; (b) it has encountered a "wait" 1639 * character; and (c) it wishes to inform the In-Call app that it is waiting for the end-user 1640 * to send an {@link #onPostDialContinue(boolean)} signal. 1641 * 1642 * @param remaining The DTMF character sequence remaining to be emitted once the 1643 * {@link #onPostDialContinue(boolean)} is received, including any "wait" characters 1644 * that remaining sequence may contain. 1645 */ 1646 public final void setPostDialWait(String remaining) { 1647 checkImmutable(); 1648 for (Listener l : mListeners) { 1649 l.onPostDialWait(this, remaining); 1650 } 1651 } 1652 1653 /** 1654 * Informs listeners that this {@code Connection} has processed a character in the post-dial 1655 * started state. This is done when (a) the {@code Connection} is issuing a DTMF sequence; 1656 * and (b) it wishes to signal Telecom to play the corresponding DTMF tone locally. 1657 * 1658 * @param nextChar The DTMF character that was just processed by the {@code Connection}. 1659 */ 1660 public final void setNextPostDialChar(char nextChar) { 1661 checkImmutable(); 1662 for (Listener l : mListeners) { 1663 l.onPostDialChar(this, nextChar); 1664 } 1665 } 1666 1667 /** 1668 * Requests that the framework play a ringback tone. This is to be invoked by implementations 1669 * that do not play a ringback tone themselves in the connection's audio stream. 1670 * 1671 * @param ringback Whether the ringback tone is to be played. 1672 */ 1673 public final void setRingbackRequested(boolean ringback) { 1674 checkImmutable(); 1675 if (mRingbackRequested != ringback) { 1676 mRingbackRequested = ringback; 1677 for (Listener l : mListeners) { 1678 l.onRingbackRequested(this, ringback); 1679 } 1680 } 1681 } 1682 1683 /** 1684 * Sets the connection's capabilities as a bit mask of the {@code CAPABILITY_*} constants. 1685 * 1686 * @param connectionCapabilities The new connection capabilities. 1687 */ 1688 public final void setConnectionCapabilities(int connectionCapabilities) { 1689 checkImmutable(); 1690 if (mConnectionCapabilities != connectionCapabilities) { 1691 mConnectionCapabilities = connectionCapabilities; 1692 for (Listener l : mListeners) { 1693 l.onConnectionCapabilitiesChanged(this, mConnectionCapabilities); 1694 } 1695 } 1696 } 1697 1698 /** 1699 * Sets the connection's properties as a bit mask of the {@code PROPERTY_*} constants. 1700 * 1701 * @param connectionProperties The new connection properties. 1702 * @hide 1703 */ 1704 public final void setConnectionProperties(int connectionProperties) { 1705 checkImmutable(); 1706 if (mConnectionProperties != connectionProperties) { 1707 mConnectionProperties = connectionProperties; 1708 for (Listener l : mListeners) { 1709 l.onConnectionPropertiesChanged(this, mConnectionProperties); 1710 } 1711 } 1712 } 1713 1714 /** 1715 * Tears down the Connection object. 1716 */ 1717 public final void destroy() { 1718 for (Listener l : mListeners) { 1719 l.onDestroyed(this); 1720 } 1721 } 1722 1723 /** 1724 * Requests that the framework use VOIP audio mode for this connection. 1725 * 1726 * @param isVoip True if the audio mode is VOIP. 1727 */ 1728 public final void setAudioModeIsVoip(boolean isVoip) { 1729 checkImmutable(); 1730 mAudioModeIsVoip = isVoip; 1731 for (Listener l : mListeners) { 1732 l.onAudioModeIsVoipChanged(this, isVoip); 1733 } 1734 } 1735 1736 /** 1737 * Sets the time at which a call became active on this Connection. This is set only 1738 * when a conference call becomes active on this connection. 1739 * 1740 * @param connectionTimeMillis The connection time, in milliseconds. 1741 * 1742 * @hide 1743 */ 1744 public final void setConnectTimeMillis(long connectTimeMillis) { 1745 mConnectTimeMillis = connectTimeMillis; 1746 } 1747 1748 /** 1749 * Sets the label and icon status to display in the in-call UI. 1750 * 1751 * @param statusHints The status label and icon to set. 1752 */ 1753 public final void setStatusHints(StatusHints statusHints) { 1754 checkImmutable(); 1755 mStatusHints = statusHints; 1756 for (Listener l : mListeners) { 1757 l.onStatusHintsChanged(this, statusHints); 1758 } 1759 } 1760 1761 /** 1762 * Sets the connections with which this connection can be conferenced. 1763 * 1764 * @param conferenceableConnections The set of connections this connection can conference with. 1765 */ 1766 public final void setConferenceableConnections(List<Connection> conferenceableConnections) { 1767 checkImmutable(); 1768 clearConferenceableList(); 1769 for (Connection c : conferenceableConnections) { 1770 // If statement checks for duplicates in input. It makes it N^2 but we're dealing with a 1771 // small amount of items here. 1772 if (!mConferenceables.contains(c)) { 1773 c.addConnectionListener(mConnectionDeathListener); 1774 mConferenceables.add(c); 1775 } 1776 } 1777 fireOnConferenceableConnectionsChanged(); 1778 } 1779 1780 /** 1781 * Similar to {@link #setConferenceableConnections(java.util.List)}, sets a list of connections 1782 * or conferences with which this connection can be conferenced. 1783 * 1784 * @param conferenceables The conferenceables. 1785 */ 1786 public final void setConferenceables(List<Conferenceable> conferenceables) { 1787 clearConferenceableList(); 1788 for (Conferenceable c : conferenceables) { 1789 // If statement checks for duplicates in input. It makes it N^2 but we're dealing with a 1790 // small amount of items here. 1791 if (!mConferenceables.contains(c)) { 1792 if (c instanceof Connection) { 1793 Connection connection = (Connection) c; 1794 connection.addConnectionListener(mConnectionDeathListener); 1795 } else if (c instanceof Conference) { 1796 Conference conference = (Conference) c; 1797 conference.addListener(mConferenceDeathListener); 1798 } 1799 mConferenceables.add(c); 1800 } 1801 } 1802 fireOnConferenceableConnectionsChanged(); 1803 } 1804 1805 /** 1806 * Returns the connections or conferences with which this connection can be conferenced. 1807 */ 1808 public final List<Conferenceable> getConferenceables() { 1809 return mUnmodifiableConferenceables; 1810 } 1811 1812 /** 1813 * @hide 1814 */ 1815 public final void setConnectionService(ConnectionService connectionService) { 1816 checkImmutable(); 1817 if (mConnectionService != null) { 1818 Log.e(this, new Exception(), "Trying to set ConnectionService on a connection " + 1819 "which is already associated with another ConnectionService."); 1820 } else { 1821 mConnectionService = connectionService; 1822 } 1823 } 1824 1825 /** 1826 * @hide 1827 */ 1828 public final void unsetConnectionService(ConnectionService connectionService) { 1829 if (mConnectionService != connectionService) { 1830 Log.e(this, new Exception(), "Trying to remove ConnectionService from a Connection " + 1831 "that does not belong to the ConnectionService."); 1832 } else { 1833 mConnectionService = null; 1834 } 1835 } 1836 1837 /** 1838 * @hide 1839 */ 1840 public final ConnectionService getConnectionService() { 1841 return mConnectionService; 1842 } 1843 1844 /** 1845 * Sets the conference that this connection is a part of. This will fail if the connection is 1846 * already part of a conference. {@link #resetConference} to un-set the conference first. 1847 * 1848 * @param conference The conference. 1849 * @return {@code true} if the conference was successfully set. 1850 * @hide 1851 */ 1852 public final boolean setConference(Conference conference) { 1853 checkImmutable(); 1854 // We check to see if it is already part of another conference. 1855 if (mConference == null) { 1856 mConference = conference; 1857 if (mConnectionService != null && mConnectionService.containsConference(conference)) { 1858 fireConferenceChanged(); 1859 } 1860 return true; 1861 } 1862 return false; 1863 } 1864 1865 /** 1866 * Resets the conference that this connection is a part of. 1867 * @hide 1868 */ 1869 public final void resetConference() { 1870 if (mConference != null) { 1871 Log.d(this, "Conference reset"); 1872 mConference = null; 1873 fireConferenceChanged(); 1874 } 1875 } 1876 1877 /** 1878 * Set some extras that can be associated with this {@code Connection}. 1879 * <p> 1880 * New or existing keys are replaced in the {@code Connection} extras. Keys which are no longer 1881 * in the new extras, but were present the last time {@code setExtras} was called are removed. 1882 * <p> 1883 * No assumptions should be made as to how an In-Call UI or service will handle these extras. 1884 * Keys should be fully qualified (e.g., com.example.MY_EXTRA) to avoid conflicts. 1885 * 1886 * @param extras The extras associated with this {@code Connection}. 1887 */ 1888 public final void setExtras(@Nullable Bundle extras) { 1889 checkImmutable(); 1890 1891 // Add/replace any new or changed extras values. 1892 putExtras(extras); 1893 1894 // If we have used "setExtras" in the past, compare the key set from the last invocation to 1895 // the current one and remove any keys that went away. 1896 if (mPreviousExtraKeys != null) { 1897 List<String> toRemove = new ArrayList<String>(); 1898 for (String oldKey : mPreviousExtraKeys) { 1899 if (extras == null || !extras.containsKey(oldKey)) { 1900 toRemove.add(oldKey); 1901 } 1902 } 1903 if (!toRemove.isEmpty()) { 1904 removeExtras(toRemove); 1905 } 1906 } 1907 1908 // Track the keys the last time set called setExtras. This way, the next time setExtras is 1909 // called we can see if the caller has removed any extras values. 1910 if (mPreviousExtraKeys == null) { 1911 mPreviousExtraKeys = new ArraySet<String>(); 1912 } 1913 mPreviousExtraKeys.clear(); 1914 if (extras != null) { 1915 mPreviousExtraKeys.addAll(extras.keySet()); 1916 } 1917 } 1918 1919 /** 1920 * Adds some extras to this {@code Connection}. Existing keys are replaced and new ones are 1921 * added. 1922 * <p> 1923 * No assumptions should be made as to how an In-Call UI or service will handle these extras. 1924 * Keys should be fully qualified (e.g., com.example.MY_EXTRA) to avoid conflicts. 1925 * 1926 * @param extras The extras to add. 1927 * @hide 1928 */ 1929 public final void putExtras(@NonNull Bundle extras) { 1930 checkImmutable(); 1931 if (extras == null) { 1932 return; 1933 } 1934 // Creating a duplicate bundle so we don't have to synchronize on mExtrasLock while calling 1935 // the listeners. 1936 Bundle listenerExtras; 1937 synchronized (mExtrasLock) { 1938 if (mExtras == null) { 1939 mExtras = new Bundle(); 1940 } 1941 mExtras.putAll(extras); 1942 listenerExtras = new Bundle(mExtras); 1943 } 1944 for (Listener l : mListeners) { 1945 // Create a new clone of the extras for each listener so that they don't clobber 1946 // each other 1947 l.onExtrasChanged(this, new Bundle(listenerExtras)); 1948 } 1949 } 1950 1951 /** 1952 * Adds a boolean extra to this {@code Connection}. 1953 * 1954 * @param key The extra key. 1955 * @param value The value. 1956 * @hide 1957 */ 1958 public final void putExtra(String key, boolean value) { 1959 Bundle newExtras = new Bundle(); 1960 newExtras.putBoolean(key, value); 1961 putExtras(newExtras); 1962 } 1963 1964 /** 1965 * Adds an integer extra to this {@code Connection}. 1966 * 1967 * @param key The extra key. 1968 * @param value The value. 1969 * @hide 1970 */ 1971 public final void putExtra(String key, int value) { 1972 Bundle newExtras = new Bundle(); 1973 newExtras.putInt(key, value); 1974 putExtras(newExtras); 1975 } 1976 1977 /** 1978 * Adds a string extra to this {@code Connection}. 1979 * 1980 * @param key The extra key. 1981 * @param value The value. 1982 * @hide 1983 */ 1984 public final void putExtra(String key, String value) { 1985 Bundle newExtras = new Bundle(); 1986 newExtras.putString(key, value); 1987 putExtras(newExtras); 1988 } 1989 1990 /** 1991 * Removes an extra from this {@code Connection}. 1992 * 1993 * @param keys The key of the extra key to remove. 1994 * @hide 1995 */ 1996 public final void removeExtras(List<String> keys) { 1997 synchronized (mExtrasLock) { 1998 if (mExtras != null) { 1999 for (String key : keys) { 2000 mExtras.remove(key); 2001 } 2002 } 2003 } 2004 List<String> unmodifiableKeys = Collections.unmodifiableList(keys); 2005 for (Listener l : mListeners) { 2006 l.onExtrasRemoved(this, unmodifiableKeys); 2007 } 2008 } 2009 2010 /** 2011 * Notifies this Connection that the {@link #getAudioState()} property has a new value. 2012 * 2013 * @param state The new connection audio state. 2014 * @deprecated Use {@link #onCallAudioStateChanged(CallAudioState)} instead. 2015 * @hide 2016 */ 2017 @SystemApi 2018 @Deprecated 2019 public void onAudioStateChanged(AudioState state) {} 2020 2021 /** 2022 * Notifies this Connection that the {@link #getCallAudioState()} property has a new value. 2023 * 2024 * @param state The new connection audio state. 2025 */ 2026 public void onCallAudioStateChanged(CallAudioState state) {} 2027 2028 /** 2029 * Notifies this Connection of an internal state change. This method is called after the 2030 * state is changed. 2031 * 2032 * @param state The new state, one of the {@code STATE_*} constants. 2033 */ 2034 public void onStateChanged(int state) {} 2035 2036 /** 2037 * Notifies this Connection of a request to play a DTMF tone. 2038 * 2039 * @param c A DTMF character. 2040 */ 2041 public void onPlayDtmfTone(char c) {} 2042 2043 /** 2044 * Notifies this Connection of a request to stop any currently playing DTMF tones. 2045 */ 2046 public void onStopDtmfTone() {} 2047 2048 /** 2049 * Notifies this Connection of a request to disconnect. 2050 */ 2051 public void onDisconnect() {} 2052 2053 /** 2054 * Notifies this Connection of a request to disconnect a participant of the conference managed 2055 * by the connection. 2056 * 2057 * @param endpoint the {@link Uri} of the participant to disconnect. 2058 * @hide 2059 */ 2060 public void onDisconnectConferenceParticipant(Uri endpoint) {} 2061 2062 /** 2063 * Notifies this Connection of a request to separate from its parent conference. 2064 */ 2065 public void onSeparate() {} 2066 2067 /** 2068 * Notifies this Connection of a request to abort. 2069 */ 2070 public void onAbort() {} 2071 2072 /** 2073 * Notifies this Connection of a request to hold. 2074 */ 2075 public void onHold() {} 2076 2077 /** 2078 * Notifies this Connection of a request to exit a hold state. 2079 */ 2080 public void onUnhold() {} 2081 2082 /** 2083 * Notifies this Connection, which is in {@link #STATE_RINGING}, of 2084 * a request to accept. 2085 * 2086 * @param videoState The video state in which to answer the connection. 2087 */ 2088 public void onAnswer(int videoState) {} 2089 2090 /** 2091 * Notifies this Connection, which is in {@link #STATE_RINGING}, of 2092 * a request to accept. 2093 */ 2094 public void onAnswer() { 2095 onAnswer(VideoProfile.STATE_AUDIO_ONLY); 2096 } 2097 2098 /** 2099 * Notifies this Connection, which is in {@link #STATE_RINGING}, of 2100 * a request to reject. 2101 */ 2102 public void onReject() {} 2103 2104 /** 2105 * Notifies this Connection, which is in {@link #STATE_RINGING}, of 2106 * a request to reject with a message. 2107 */ 2108 public void onReject(String replyMessage) {} 2109 2110 /** 2111 * Notifies the Connection of a request to silence the ringer. 2112 * 2113 * @hide 2114 */ 2115 public void onSilence() {} 2116 2117 /** 2118 * Notifies this Connection whether the user wishes to proceed with the post-dial DTMF codes. 2119 */ 2120 public void onPostDialContinue(boolean proceed) {} 2121 2122 /** 2123 * Notifies this Connection of a request to pull an external call to the local device. 2124 * <p> 2125 * The {@link InCallService} issues a request to pull an external call to the local device via 2126 * {@link Call#pullExternalCall()}. 2127 * <p> 2128 * For a Connection to be pulled, both the {@link Connection#CAPABILITY_CAN_PULL_CALL} 2129 * capability and {@link Connection#PROPERTY_IS_EXTERNAL_CALL} property bits must be set. 2130 * <p> 2131 * For more information on external calls, see {@link Connection#PROPERTY_IS_EXTERNAL_CALL}. 2132 * @hide 2133 */ 2134 public void onPullExternalCall() {} 2135 2136 /** 2137 * Notifies this Connection of a {@link Call} event initiated from an {@link InCallService}. 2138 * <p> 2139 * The {@link InCallService} issues a Call event via {@link Call#sendCallEvent(String, Bundle)}. 2140 * <p> 2141 * See also {@link Call#sendCallEvent(String, Bundle)}. 2142 * 2143 * @param event The call event. 2144 * @param extras Extras associated with the call event. 2145 * @hide 2146 */ 2147 public void onCallEvent(String event, Bundle extras) {} 2148 2149 /** 2150 * Notifies this {@link Connection} of a change to the extras made outside the 2151 * {@link ConnectionService}. 2152 * <p> 2153 * These extras changes can originate from Telecom itself, or from an {@link InCallService} via 2154 * the {@link android.telecom.Call#putExtras(Bundle)} and 2155 * {@link Call#removeExtras(List)}. 2156 * 2157 * @param extras The new extras bundle. 2158 * @hide 2159 */ 2160 public void onExtrasChanged(Bundle extras) {} 2161 2162 static String toLogSafePhoneNumber(String number) { 2163 // For unknown number, log empty string. 2164 if (number == null) { 2165 return ""; 2166 } 2167 2168 if (PII_DEBUG) { 2169 // When PII_DEBUG is true we emit PII. 2170 return number; 2171 } 2172 2173 // Do exactly same thing as Uri#toSafeString() does, which will enable us to compare 2174 // sanitized phone numbers. 2175 StringBuilder builder = new StringBuilder(); 2176 for (int i = 0; i < number.length(); i++) { 2177 char c = number.charAt(i); 2178 if (c == '-' || c == '@' || c == '.') { 2179 builder.append(c); 2180 } else { 2181 builder.append('x'); 2182 } 2183 } 2184 return builder.toString(); 2185 } 2186 2187 private void setState(int state) { 2188 checkImmutable(); 2189 if (mState == STATE_DISCONNECTED && mState != state) { 2190 Log.d(this, "Connection already DISCONNECTED; cannot transition out of this state."); 2191 return; 2192 } 2193 if (mState != state) { 2194 Log.d(this, "setState: %s", stateToString(state)); 2195 mState = state; 2196 onStateChanged(state); 2197 for (Listener l : mListeners) { 2198 l.onStateChanged(this, state); 2199 } 2200 } 2201 } 2202 2203 private static class FailureSignalingConnection extends Connection { 2204 private boolean mImmutable = false; 2205 public FailureSignalingConnection(DisconnectCause disconnectCause) { 2206 setDisconnected(disconnectCause); 2207 mImmutable = true; 2208 } 2209 2210 public void checkImmutable() { 2211 if (mImmutable) { 2212 throw new UnsupportedOperationException("Connection is immutable"); 2213 } 2214 } 2215 } 2216 2217 /** 2218 * Return a {@code Connection} which represents a failed connection attempt. The returned 2219 * {@code Connection} will have a {@link android.telecom.DisconnectCause} and as specified, 2220 * and a {@link #getState()} of {@link #STATE_DISCONNECTED}. 2221 * <p> 2222 * The returned {@code Connection} can be assumed to {@link #destroy()} itself when appropriate, 2223 * so users of this method need not maintain a reference to its return value to destroy it. 2224 * 2225 * @param disconnectCause The disconnect cause, ({@see android.telecomm.DisconnectCause}). 2226 * @return A {@code Connection} which indicates failure. 2227 */ 2228 public static Connection createFailedConnection(DisconnectCause disconnectCause) { 2229 return new FailureSignalingConnection(disconnectCause); 2230 } 2231 2232 /** 2233 * Override to throw an {@link UnsupportedOperationException} if this {@code Connection} is 2234 * not intended to be mutated, e.g., if it is a marker for failure. Only for framework use; 2235 * this should never be un-@hide-den. 2236 * 2237 * @hide 2238 */ 2239 public void checkImmutable() {} 2240 2241 /** 2242 * Return a {@code Connection} which represents a canceled connection attempt. The returned 2243 * {@code Connection} will have state {@link #STATE_DISCONNECTED}, and cannot be moved out of 2244 * that state. This connection should not be used for anything, and no other 2245 * {@code Connection}s should be attempted. 2246 * <p> 2247 * so users of this method need not maintain a reference to its return value to destroy it. 2248 * 2249 * @return A {@code Connection} which indicates that the underlying connection should 2250 * be canceled. 2251 */ 2252 public static Connection createCanceledConnection() { 2253 return new FailureSignalingConnection(new DisconnectCause(DisconnectCause.CANCELED)); 2254 } 2255 2256 private final void fireOnConferenceableConnectionsChanged() { 2257 for (Listener l : mListeners) { 2258 l.onConferenceablesChanged(this, getConferenceables()); 2259 } 2260 } 2261 2262 private final void fireConferenceChanged() { 2263 for (Listener l : mListeners) { 2264 l.onConferenceChanged(this, mConference); 2265 } 2266 } 2267 2268 private final void clearConferenceableList() { 2269 for (Conferenceable c : mConferenceables) { 2270 if (c instanceof Connection) { 2271 Connection connection = (Connection) c; 2272 connection.removeConnectionListener(mConnectionDeathListener); 2273 } else if (c instanceof Conference) { 2274 Conference conference = (Conference) c; 2275 conference.removeListener(mConferenceDeathListener); 2276 } 2277 } 2278 mConferenceables.clear(); 2279 } 2280 2281 /** 2282 * Handles a change to extras received from Telecom. 2283 * 2284 * @param extras The new extras. 2285 * @hide 2286 */ 2287 final void handleExtrasChanged(Bundle extras) { 2288 Bundle b = null; 2289 synchronized (mExtrasLock) { 2290 mExtras = extras; 2291 if (mExtras != null) { 2292 b = new Bundle(mExtras); 2293 } 2294 } 2295 onExtrasChanged(b); 2296 } 2297 2298 /** 2299 * Notifies listeners that the merge request failed. 2300 * 2301 * @hide 2302 */ 2303 protected final void notifyConferenceMergeFailed() { 2304 for (Listener l : mListeners) { 2305 l.onConferenceMergeFailed(this); 2306 } 2307 } 2308 2309 /** 2310 * Notifies listeners of a change to conference participant(s). 2311 * 2312 * @param conferenceParticipants The participants. 2313 * @hide 2314 */ 2315 protected final void updateConferenceParticipants( 2316 List<ConferenceParticipant> conferenceParticipants) { 2317 for (Listener l : mListeners) { 2318 l.onConferenceParticipantsChanged(this, conferenceParticipants); 2319 } 2320 } 2321 2322 /** 2323 * Notifies listeners that a conference call has been started. 2324 * @hide 2325 */ 2326 protected void notifyConferenceStarted() { 2327 for (Listener l : mListeners) { 2328 l.onConferenceStarted(); 2329 } 2330 } 2331 2332 /** 2333 * Sends an event associated with this {@code Connection}, with associated event extras. 2334 * 2335 * Events are exposed to {@link InCallService} implementations via the 2336 * {@link Call.Callback#onConnectionEvent(Call, String, Bundle)} API. 2337 * 2338 * No assumptions should be made as to how an In-Call UI or service will handle these events. 2339 * Events should be fully qualified (e.g., com.example.event.MY_EVENT) to avoid conflicts. 2340 * 2341 * @param event The connection event. 2342 * @param extras Bundle containing extra information associated with the event. 2343 * @hide 2344 */ 2345 public void sendConnectionEvent(String event, Bundle extras) { 2346 for (Listener l : mListeners) { 2347 l.onConnectionEvent(this, event, extras); 2348 } 2349 } 2350 } 2351