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.app.Notification; 27 import android.bluetooth.BluetoothDevice; 28 import android.content.Intent; 29 import android.hardware.camera2.CameraManager; 30 import android.net.Uri; 31 import android.os.Binder; 32 import android.os.Bundle; 33 import android.os.Handler; 34 import android.os.IBinder; 35 import android.os.Looper; 36 import android.os.Message; 37 import android.os.ParcelFileDescriptor; 38 import android.os.RemoteException; 39 import android.os.SystemClock; 40 import android.util.ArraySet; 41 import android.view.Surface; 42 43 import java.io.FileInputStream; 44 import java.io.FileOutputStream; 45 import java.io.IOException; 46 import java.io.InputStreamReader; 47 import java.io.OutputStreamWriter; 48 import java.util.ArrayList; 49 import java.util.Arrays; 50 import java.util.Collections; 51 import java.util.List; 52 import java.util.Set; 53 import java.util.concurrent.ConcurrentHashMap; 54 55 /** 56 * Represents a phone call or connection to a remote endpoint that carries voice and/or video 57 * traffic. 58 * <p> 59 * Implementations create a custom subclass of {@code Connection} and return it to the framework 60 * as the return value of 61 * {@link ConnectionService#onCreateIncomingConnection(PhoneAccountHandle, ConnectionRequest)} 62 * or 63 * {@link ConnectionService#onCreateOutgoingConnection(PhoneAccountHandle, ConnectionRequest)}. 64 * Implementations are then responsible for updating the state of the {@code Connection}, and 65 * must call {@link #destroy()} to signal to the framework that the {@code Connection} is no 66 * longer used and associated resources may be recovered. 67 * <p> 68 * Subclasses of {@code Connection} override the {@code on*} methods to provide the the 69 * {@link ConnectionService}'s implementation of calling functionality. The {@code on*} methods are 70 * called by Telecom to inform an instance of a {@code Connection} of actions specific to that 71 * {@code Connection} instance. 72 * <p> 73 * Basic call support requires overriding the following methods: {@link #onAnswer()}, 74 * {@link #onDisconnect()}, {@link #onReject()}, {@link #onAbort()} 75 * <p> 76 * Where a {@code Connection} has {@link #CAPABILITY_SUPPORT_HOLD}, the {@link #onHold()} and 77 * {@link #onUnhold()} methods should be overridden to provide hold support for the 78 * {@code Connection}. 79 * <p> 80 * Where a {@code Connection} supports a variation of video calling (e.g. the 81 * {@code CAPABILITY_SUPPORTS_VT_*} capability bits), {@link #onAnswer(int)} should be overridden 82 * to support answering a call as a video call. 83 * <p> 84 * Where a {@code Connection} has {@link #PROPERTY_IS_EXTERNAL_CALL} and 85 * {@link #CAPABILITY_CAN_PULL_CALL}, {@link #onPullExternalCall()} should be overridden to provide 86 * support for pulling the external call. 87 * <p> 88 * Where a {@code Connection} supports conference calling {@link #onSeparate()} should be 89 * overridden. 90 * <p> 91 * There are a number of other {@code on*} methods which a {@code Connection} can choose to 92 * implement, depending on whether it is concerned with the associated calls from Telecom. If, 93 * for example, call events from a {@link InCallService} are handled, 94 * {@link #onCallEvent(String, Bundle)} should be overridden. Another example is 95 * {@link #onExtrasChanged(Bundle)}, which should be overridden if the {@code Connection} wishes to 96 * make use of extra information provided via the {@link Call#putExtras(Bundle)} and 97 * {@link Call#removeExtras(String...)} methods. 98 */ 99 public abstract class Connection extends Conferenceable { 100 101 /** 102 * The connection is initializing. This is generally the first state for a {@code Connection} 103 * returned by a {@link ConnectionService}. 104 */ 105 public static final int STATE_INITIALIZING = 0; 106 107 /** 108 * The connection is new and not connected. 109 */ 110 public static final int STATE_NEW = 1; 111 112 /** 113 * An incoming connection is in the ringing state. During this state, the user's ringer or 114 * vibration feature will be activated. 115 */ 116 public static final int STATE_RINGING = 2; 117 118 /** 119 * An outgoing connection is in the dialing state. In this state the other party has not yet 120 * answered the call and the user traditionally hears a ringback tone. 121 */ 122 public static final int STATE_DIALING = 3; 123 124 /** 125 * A connection is active. Both parties are connected to the call and can actively communicate. 126 */ 127 public static final int STATE_ACTIVE = 4; 128 129 /** 130 * A connection is on hold. 131 */ 132 public static final int STATE_HOLDING = 5; 133 134 /** 135 * A connection has been disconnected. This is the final state once the user has been 136 * disconnected from a call either locally, remotely or by an error in the service. 137 */ 138 public static final int STATE_DISCONNECTED = 6; 139 140 /** 141 * The state of an external connection which is in the process of being pulled from a remote 142 * device to the local device. 143 * <p> 144 * A connection can only be in this state if the {@link #PROPERTY_IS_EXTERNAL_CALL} property and 145 * {@link #CAPABILITY_CAN_PULL_CALL} capability bits are set on the connection. 146 */ 147 public static final int STATE_PULLING_CALL = 7; 148 149 /** 150 * Connection can currently be put on hold or unheld. This is distinct from 151 * {@link #CAPABILITY_SUPPORT_HOLD} in that although a connection may support 'hold' most times, 152 * it does not at the moment support the function. This can be true while the call is in the 153 * state {@link #STATE_DIALING}, for example. During this condition, an in-call UI may 154 * display a disabled 'hold' button. 155 */ 156 public static final int CAPABILITY_HOLD = 0x00000001; 157 158 /** Connection supports the hold feature. */ 159 public static final int CAPABILITY_SUPPORT_HOLD = 0x00000002; 160 161 /** 162 * Connections within a conference can be merged. A {@link ConnectionService} has the option to 163 * add a {@link Conference} before the child {@link Connection}s are merged. This is how 164 * CDMA-based {@link Connection}s are implemented. For these unmerged {@link Conference}s, this 165 * capability allows a merge button to be shown while the conference is in the foreground 166 * of the in-call UI. 167 * <p> 168 * This is only intended for use by a {@link Conference}. 169 */ 170 public static final int CAPABILITY_MERGE_CONFERENCE = 0x00000004; 171 172 /** 173 * Connections within a conference can be swapped between foreground and background. 174 * See {@link #CAPABILITY_MERGE_CONFERENCE} for additional information. 175 * <p> 176 * This is only intended for use by a {@link Conference}. 177 */ 178 public static final int CAPABILITY_SWAP_CONFERENCE = 0x00000008; 179 180 /** 181 * @hide 182 */ 183 public static final int CAPABILITY_UNUSED = 0x00000010; 184 185 /** Connection supports responding via text option. */ 186 public static final int CAPABILITY_RESPOND_VIA_TEXT = 0x00000020; 187 188 /** Connection can be muted. */ 189 public static final int CAPABILITY_MUTE = 0x00000040; 190 191 /** 192 * Connection supports conference management. This capability only applies to 193 * {@link Conference}s which can have {@link Connection}s as children. 194 */ 195 public static final int CAPABILITY_MANAGE_CONFERENCE = 0x00000080; 196 197 /** 198 * Local device supports receiving video. 199 */ 200 public static final int CAPABILITY_SUPPORTS_VT_LOCAL_RX = 0x00000100; 201 202 /** 203 * Local device supports transmitting video. 204 */ 205 public static final int CAPABILITY_SUPPORTS_VT_LOCAL_TX = 0x00000200; 206 207 /** 208 * Local device supports bidirectional video calling. 209 */ 210 public static final int CAPABILITY_SUPPORTS_VT_LOCAL_BIDIRECTIONAL = 211 CAPABILITY_SUPPORTS_VT_LOCAL_RX | CAPABILITY_SUPPORTS_VT_LOCAL_TX; 212 213 /** 214 * Remote device supports receiving video. 215 */ 216 public static final int CAPABILITY_SUPPORTS_VT_REMOTE_RX = 0x00000400; 217 218 /** 219 * Remote device supports transmitting video. 220 */ 221 public static final int CAPABILITY_SUPPORTS_VT_REMOTE_TX = 0x00000800; 222 223 /** 224 * Remote device supports bidirectional video calling. 225 */ 226 public static final int CAPABILITY_SUPPORTS_VT_REMOTE_BIDIRECTIONAL = 227 CAPABILITY_SUPPORTS_VT_REMOTE_RX | CAPABILITY_SUPPORTS_VT_REMOTE_TX; 228 229 /** 230 * Connection is able to be separated from its parent {@code Conference}, if any. 231 */ 232 public static final int CAPABILITY_SEPARATE_FROM_CONFERENCE = 0x00001000; 233 234 /** 235 * Connection is able to be individually disconnected when in a {@code Conference}. 236 */ 237 public static final int CAPABILITY_DISCONNECT_FROM_CONFERENCE = 0x00002000; 238 239 /** 240 * Un-used. 241 * @hide 242 */ 243 public static final int CAPABILITY_UNUSED_2 = 0x00004000; 244 245 /** 246 * Un-used. 247 * @hide 248 */ 249 public static final int CAPABILITY_UNUSED_3 = 0x00008000; 250 251 /** 252 * Un-used. 253 * @hide 254 */ 255 public static final int CAPABILITY_UNUSED_4 = 0x00010000; 256 257 /** 258 * Un-used. 259 * @hide 260 */ 261 public static final int CAPABILITY_UNUSED_5 = 0x00020000; 262 263 /** 264 * Speed up audio setup for MT call. 265 * @hide 266 */ 267 public static final int CAPABILITY_SPEED_UP_MT_AUDIO = 0x00040000; 268 269 /** 270 * Call can be upgraded to a video call. 271 */ 272 public static final int CAPABILITY_CAN_UPGRADE_TO_VIDEO = 0x00080000; 273 274 /** 275 * For video calls, indicates whether the outgoing video for the call can be paused using 276 * the {@link android.telecom.VideoProfile#STATE_PAUSED} VideoState. 277 */ 278 public static final int CAPABILITY_CAN_PAUSE_VIDEO = 0x00100000; 279 280 /** 281 * For a conference, indicates the conference will not have child connections. 282 * <p> 283 * An example of a conference with child connections is a GSM conference call, where the radio 284 * retains connections to the individual participants of the conference. Another example is an 285 * IMS conference call where conference event package functionality is supported; in this case 286 * the conference server ensures the radio is aware of the participants in the conference, which 287 * are represented by child connections. 288 * <p> 289 * An example of a conference with no child connections is an IMS conference call with no 290 * conference event package support. Such a conference is represented by the radio as a single 291 * connection to the IMS conference server. 292 * <p> 293 * Indicating whether a conference has children or not is important to help user interfaces 294 * visually represent a conference. A conference with no children, for example, will have the 295 * conference connection shown in the list of calls on a Bluetooth device, where if the 296 * conference has children, only the children will be shown in the list of calls on a Bluetooth 297 * device. 298 * @hide 299 */ 300 public static final int CAPABILITY_CONFERENCE_HAS_NO_CHILDREN = 0x00200000; 301 302 /** 303 * Indicates that the connection itself wants to handle any sort of reply response, rather than 304 * relying on SMS. 305 */ 306 public static final int CAPABILITY_CAN_SEND_RESPONSE_VIA_CONNECTION = 0x00400000; 307 308 /** 309 * When set, prevents a video call from being downgraded to an audio-only call. 310 * <p> 311 * Should be set when the VideoState has the {@link VideoProfile#STATE_TX_ENABLED} or 312 * {@link VideoProfile#STATE_RX_ENABLED} bits set to indicate that the connection cannot be 313 * downgraded from a video call back to a VideoState of 314 * {@link VideoProfile#STATE_AUDIO_ONLY}. 315 * <p> 316 * Intuitively, a call which can be downgraded to audio should also have local and remote 317 * video 318 * capabilities (see {@link #CAPABILITY_SUPPORTS_VT_LOCAL_BIDIRECTIONAL} and 319 * {@link #CAPABILITY_SUPPORTS_VT_REMOTE_BIDIRECTIONAL}). 320 */ 321 public static final int CAPABILITY_CANNOT_DOWNGRADE_VIDEO_TO_AUDIO = 0x00800000; 322 323 /** 324 * When set for an external connection, indicates that this {@code Connection} can be pulled 325 * from a remote device to the current device. 326 * <p> 327 * Should only be set on a {@code Connection} where {@link #PROPERTY_IS_EXTERNAL_CALL} 328 * is set. 329 */ 330 public static final int CAPABILITY_CAN_PULL_CALL = 0x01000000; 331 332 /** Call supports the deflect feature. */ 333 public static final int CAPABILITY_SUPPORT_DEFLECT = 0x02000000; 334 335 //********************************************************************************************** 336 // Next CAPABILITY value: 0x04000000 337 //********************************************************************************************** 338 339 /** 340 * Indicates that the current device callback number should be shown. 341 * 342 * @hide 343 */ 344 public static final int PROPERTY_EMERGENCY_CALLBACK_MODE = 1<<0; 345 346 /** 347 * Whether the call is a generic conference, where we do not know the precise state of 348 * participants in the conference (eg. on CDMA). 349 * 350 * @hide 351 */ 352 public static final int PROPERTY_GENERIC_CONFERENCE = 1<<1; 353 354 /** 355 * Connection is using high definition audio. 356 * @hide 357 */ 358 public static final int PROPERTY_HIGH_DEF_AUDIO = 1<<2; 359 360 /** 361 * Connection is using WIFI. 362 * @hide 363 */ 364 public static final int PROPERTY_WIFI = 1<<3; 365 366 /** 367 * When set, indicates that the {@code Connection} does not actually exist locally for the 368 * {@link ConnectionService}. 369 * <p> 370 * Consider, for example, a scenario where a user has two devices with the same phone number. 371 * When a user places a call on one devices, the telephony stack can represent that call on the 372 * other device by adding is to the {@link ConnectionService} with the 373 * {@link #PROPERTY_IS_EXTERNAL_CALL} capability set. 374 * <p> 375 * An {@link ConnectionService} should not assume that all {@link InCallService}s will handle 376 * external connections. Only those {@link InCallService}s which have the 377 * {@link TelecomManager#METADATA_INCLUDE_EXTERNAL_CALLS} metadata set to {@code true} in its 378 * manifest will see external connections. 379 */ 380 public static final int PROPERTY_IS_EXTERNAL_CALL = 1<<4; 381 382 /** 383 * Indicates that the connection has CDMA Enhanced Voice Privacy enabled. 384 */ 385 public static final int PROPERTY_HAS_CDMA_VOICE_PRIVACY = 1<<5; 386 387 /** 388 * Indicates that the connection represents a downgraded IMS conference. 389 * @hide 390 */ 391 public static final int PROPERTY_IS_DOWNGRADED_CONFERENCE = 1<<6; 392 393 /** 394 * Set by the framework to indicate that the {@link Connection} originated from a self-managed 395 * {@link ConnectionService}. 396 * <p> 397 * See {@link PhoneAccount#CAPABILITY_SELF_MANAGED}. 398 */ 399 public static final int PROPERTY_SELF_MANAGED = 1<<7; 400 401 /** 402 * Set by the framework to indicate that a connection has an active RTT session associated with 403 * it. 404 */ 405 public static final int PROPERTY_IS_RTT = 1 << 8; 406 407 /** 408 * Set by the framework to indicate that a connection is using assisted dialing. 409 * @hide 410 */ 411 public static final int PROPERTY_ASSISTED_DIALING_USED = 1 << 9; 412 413 //********************************************************************************************** 414 // Next PROPERTY value: 1<<10 415 //********************************************************************************************** 416 417 /** 418 * Connection extra key used to store the last forwarded number associated with the current 419 * connection. Used to communicate to the user interface that the connection was forwarded via 420 * the specified number. 421 */ 422 public static final String EXTRA_LAST_FORWARDED_NUMBER = 423 "android.telecom.extra.LAST_FORWARDED_NUMBER"; 424 425 /** 426 * Connection extra key used to store a child number associated with the current connection. 427 * Used to communicate to the user interface that the connection was received via 428 * a child address (i.e. phone number) associated with the {@link PhoneAccount}'s primary 429 * address. 430 */ 431 public static final String EXTRA_CHILD_ADDRESS = "android.telecom.extra.CHILD_ADDRESS"; 432 433 /** 434 * Connection extra key used to store the subject for an incoming call. The user interface can 435 * query this extra and display its contents for incoming calls. Will only be used if the 436 * {@link PhoneAccount} supports the capability {@link PhoneAccount#CAPABILITY_CALL_SUBJECT}. 437 */ 438 public static final String EXTRA_CALL_SUBJECT = "android.telecom.extra.CALL_SUBJECT"; 439 440 /** 441 * Boolean connection extra key set on a {@link Connection} in 442 * {@link Connection#STATE_RINGING} state to indicate that answering the call will cause the 443 * current active foreground call to be dropped. 444 */ 445 public static final String EXTRA_ANSWERING_DROPS_FG_CALL = 446 "android.telecom.extra.ANSWERING_DROPS_FG_CALL"; 447 448 /** 449 * String connection extra key set on a {@link Connection} in {@link Connection#STATE_RINGING} 450 * state to indicate the name of the third-party app which is responsible for the current 451 * foreground call. 452 * <p> 453 * Used when {@link #EXTRA_ANSWERING_DROPS_FG_CALL} is true to ensure that the default Phone app 454 * is able to inform the user that answering the new incoming call will cause a call owned by 455 * another app to be dropped when the incoming call is answered. 456 */ 457 public static final String EXTRA_ANSWERING_DROPS_FG_CALL_APP_NAME = 458 "android.telecom.extra.ANSWERING_DROPS_FG_CALL_APP_NAME"; 459 460 /** 461 * Boolean connection extra key on a {@link Connection} which indicates that adding an 462 * additional call is disallowed. 463 * @hide 464 */ 465 public static final String EXTRA_DISABLE_ADD_CALL = 466 "android.telecom.extra.DISABLE_ADD_CALL"; 467 468 /** 469 * String connection extra key on a {@link Connection} or {@link Conference} which contains the 470 * original Connection ID associated with the connection. Used in 471 * {@link RemoteConnectionService} to track the Connection ID which was originally assigned to a 472 * connection/conference added via 473 * {@link ConnectionService#addExistingConnection(PhoneAccountHandle, Connection)} and 474 * {@link ConnectionService#addConference(Conference)} APIs. This is important to pass to 475 * Telecom for when it deals with RemoteConnections. When the ConnectionManager wraps the 476 * {@link RemoteConnection} and {@link RemoteConference} and adds it to Telecom, there needs to 477 * be a way to ensure that we don't add the connection again as a duplicate. 478 * <p> 479 * For example, the TelephonyCS calls addExistingConnection for a Connection with ID 480 * {@code TelephonyCS@1}. The ConnectionManager learns of this via 481 * {@link ConnectionService#onRemoteExistingConnectionAdded(RemoteConnection)}, and wraps this 482 * in a new {@link Connection} which it adds to Telecom via 483 * {@link ConnectionService#addExistingConnection(PhoneAccountHandle, Connection)}. As part of 484 * this process, the wrapped RemoteConnection gets assigned a new ID (e.g. {@code ConnMan@1}). 485 * The TelephonyCS will ALSO try to add the existing connection to Telecom, except with the 486 * ID it originally referred to the connection as. Thus Telecom needs to know that the 487 * Connection with ID {@code ConnMan@1} is really the same as {@code TelephonyCS@1}. 488 * @hide 489 */ 490 public static final String EXTRA_ORIGINAL_CONNECTION_ID = 491 "android.telecom.extra.ORIGINAL_CONNECTION_ID"; 492 493 /** 494 * Connection event used to inform Telecom that it should play the on hold tone. This is used 495 * to play a tone when the peer puts the current call on hold. Sent to Telecom via 496 * {@link #sendConnectionEvent(String, Bundle)}. 497 * @hide 498 */ 499 public static final String EVENT_ON_HOLD_TONE_START = 500 "android.telecom.event.ON_HOLD_TONE_START"; 501 502 /** 503 * Connection event used to inform Telecom that it should stop the on hold tone. This is used 504 * to stop a tone when the peer puts the current call on hold. Sent to Telecom via 505 * {@link #sendConnectionEvent(String, Bundle)}. 506 * @hide 507 */ 508 public static final String EVENT_ON_HOLD_TONE_END = 509 "android.telecom.event.ON_HOLD_TONE_END"; 510 511 /** 512 * Connection event used to inform {@link InCallService}s when pulling of an external call has 513 * failed. The user interface should inform the user of the error. 514 * <p> 515 * Expected to be used by the {@link ConnectionService} when the {@link Call#pullExternalCall()} 516 * API is called on a {@link Call} with the properties 517 * {@link Call.Details#PROPERTY_IS_EXTERNAL_CALL} and 518 * {@link Call.Details#CAPABILITY_CAN_PULL_CALL}, but the {@link ConnectionService} could not 519 * pull the external call due to an error condition. 520 * <p> 521 * Sent via {@link #sendConnectionEvent(String, Bundle)}. The {@link Bundle} parameter is 522 * expected to be null when this connection event is used. 523 */ 524 public static final String EVENT_CALL_PULL_FAILED = "android.telecom.event.CALL_PULL_FAILED"; 525 526 /** 527 * Connection event used to inform {@link InCallService}s when the merging of two calls has 528 * failed. The User Interface should use this message to inform the user of the error. 529 * <p> 530 * Sent via {@link #sendConnectionEvent(String, Bundle)}. The {@link Bundle} parameter is 531 * expected to be null when this connection event is used. 532 */ 533 public static final String EVENT_CALL_MERGE_FAILED = "android.telecom.event.CALL_MERGE_FAILED"; 534 535 /** 536 * Connection event used to inform {@link InCallService}s when the process of merging a 537 * Connection into a conference has begun. 538 * <p> 539 * Sent via {@link #sendConnectionEvent(String, Bundle)}. The {@link Bundle} parameter is 540 * expected to be null when this connection event is used. 541 * @hide 542 */ 543 public static final String EVENT_MERGE_START = "android.telecom.event.MERGE_START"; 544 545 /** 546 * Connection event used to inform {@link InCallService}s when the process of merging a 547 * Connection into a conference has completed. 548 * <p> 549 * Sent via {@link #sendConnectionEvent(String, Bundle)}. The {@link Bundle} parameter is 550 * expected to be null when this connection event is used. 551 * @hide 552 */ 553 public static final String EVENT_MERGE_COMPLETE = "android.telecom.event.MERGE_COMPLETE"; 554 555 /** 556 * Connection event used to inform {@link InCallService}s when a call has been put on hold by 557 * the remote party. 558 * <p> 559 * This is different than the {@link Connection#STATE_HOLDING} state which indicates that the 560 * call is being held locally on the device. When a capable {@link ConnectionService} receives 561 * signalling to indicate that the remote party has put the call on hold, it can send this 562 * connection event. 563 * @hide 564 */ 565 public static final String EVENT_CALL_REMOTELY_HELD = 566 "android.telecom.event.CALL_REMOTELY_HELD"; 567 568 /** 569 * Connection event used to inform {@link InCallService}s when a call which was remotely held 570 * (see {@link #EVENT_CALL_REMOTELY_HELD}) has been un-held by the remote party. 571 * <p> 572 * This is different than the {@link Connection#STATE_HOLDING} state which indicates that the 573 * call is being held locally on the device. When a capable {@link ConnectionService} receives 574 * signalling to indicate that the remote party has taken the call off hold, it can send this 575 * connection event. 576 * @hide 577 */ 578 public static final String EVENT_CALL_REMOTELY_UNHELD = 579 "android.telecom.event.CALL_REMOTELY_UNHELD"; 580 581 /** 582 * Connection event used to inform an {@link InCallService} which initiated a call handover via 583 * {@link Call#EVENT_REQUEST_HANDOVER} that the handover from this {@link Connection} has 584 * successfully completed. 585 * @hide 586 */ 587 public static final String EVENT_HANDOVER_COMPLETE = 588 "android.telecom.event.HANDOVER_COMPLETE"; 589 590 /** 591 * Connection event used to inform an {@link InCallService} which initiated a call handover via 592 * {@link Call#EVENT_REQUEST_HANDOVER} that the handover from this {@link Connection} has failed 593 * to complete. 594 * @hide 595 */ 596 public static final String EVENT_HANDOVER_FAILED = 597 "android.telecom.event.HANDOVER_FAILED"; 598 599 // Flag controlling whether PII is emitted into the logs 600 private static final boolean PII_DEBUG = Log.isLoggable(android.util.Log.DEBUG); 601 602 /** 603 * Whether the given capabilities support the specified capability. 604 * 605 * @param capabilities A capability bit field. 606 * @param capability The capability to check capabilities for. 607 * @return Whether the specified capability is supported. 608 * @hide 609 */ can(int capabilities, int capability)610 public static boolean can(int capabilities, int capability) { 611 return (capabilities & capability) == capability; 612 } 613 614 /** 615 * Whether the capabilities of this {@code Connection} supports the specified capability. 616 * 617 * @param capability The capability to check capabilities for. 618 * @return Whether the specified capability is supported. 619 * @hide 620 */ can(int capability)621 public boolean can(int capability) { 622 return can(mConnectionCapabilities, capability); 623 } 624 625 /** 626 * Removes the specified capability from the set of capabilities of this {@code Connection}. 627 * 628 * @param capability The capability to remove from the set. 629 * @hide 630 */ removeCapability(int capability)631 public void removeCapability(int capability) { 632 mConnectionCapabilities &= ~capability; 633 } 634 635 /** 636 * Adds the specified capability to the set of capabilities of this {@code Connection}. 637 * 638 * @param capability The capability to add to the set. 639 * @hide 640 */ addCapability(int capability)641 public void addCapability(int capability) { 642 mConnectionCapabilities |= capability; 643 } 644 645 /** 646 * Renders a set of capability bits ({@code CAPABILITY_*}) as a human readable string. 647 * 648 * @param capabilities A capability bit field. 649 * @return A human readable string representation. 650 */ capabilitiesToString(int capabilities)651 public static String capabilitiesToString(int capabilities) { 652 return capabilitiesToStringInternal(capabilities, true /* isLong */); 653 } 654 655 /** 656 * Renders a set of capability bits ({@code CAPABILITY_*}) as a *short* human readable 657 * string. 658 * 659 * @param capabilities A capability bit field. 660 * @return A human readable string representation. 661 * @hide 662 */ capabilitiesToStringShort(int capabilities)663 public static String capabilitiesToStringShort(int capabilities) { 664 return capabilitiesToStringInternal(capabilities, false /* isLong */); 665 } 666 capabilitiesToStringInternal(int capabilities, boolean isLong)667 private static String capabilitiesToStringInternal(int capabilities, boolean isLong) { 668 StringBuilder builder = new StringBuilder(); 669 builder.append("["); 670 if (isLong) { 671 builder.append("Capabilities:"); 672 } 673 674 if (can(capabilities, CAPABILITY_HOLD)) { 675 builder.append(isLong ? " CAPABILITY_HOLD" : " hld"); 676 } 677 if (can(capabilities, CAPABILITY_SUPPORT_HOLD)) { 678 builder.append(isLong ? " CAPABILITY_SUPPORT_HOLD" : " sup_hld"); 679 } 680 if (can(capabilities, CAPABILITY_MERGE_CONFERENCE)) { 681 builder.append(isLong ? " CAPABILITY_MERGE_CONFERENCE" : " mrg_cnf"); 682 } 683 if (can(capabilities, CAPABILITY_SWAP_CONFERENCE)) { 684 builder.append(isLong ? " CAPABILITY_SWAP_CONFERENCE" : " swp_cnf"); 685 } 686 if (can(capabilities, CAPABILITY_RESPOND_VIA_TEXT)) { 687 builder.append(isLong ? " CAPABILITY_RESPOND_VIA_TEXT" : " txt"); 688 } 689 if (can(capabilities, CAPABILITY_MUTE)) { 690 builder.append(isLong ? " CAPABILITY_MUTE" : " mut"); 691 } 692 if (can(capabilities, CAPABILITY_MANAGE_CONFERENCE)) { 693 builder.append(isLong ? " CAPABILITY_MANAGE_CONFERENCE" : " mng_cnf"); 694 } 695 if (can(capabilities, CAPABILITY_SUPPORTS_VT_LOCAL_RX)) { 696 builder.append(isLong ? " CAPABILITY_SUPPORTS_VT_LOCAL_RX" : " VTlrx"); 697 } 698 if (can(capabilities, CAPABILITY_SUPPORTS_VT_LOCAL_TX)) { 699 builder.append(isLong ? " CAPABILITY_SUPPORTS_VT_LOCAL_TX" : " VTltx"); 700 } 701 if (can(capabilities, CAPABILITY_SUPPORTS_VT_LOCAL_BIDIRECTIONAL)) { 702 builder.append(isLong ? " CAPABILITY_SUPPORTS_VT_LOCAL_BIDIRECTIONAL" : " VTlbi"); 703 } 704 if (can(capabilities, CAPABILITY_SUPPORTS_VT_REMOTE_RX)) { 705 builder.append(isLong ? " CAPABILITY_SUPPORTS_VT_REMOTE_RX" : " VTrrx"); 706 } 707 if (can(capabilities, CAPABILITY_SUPPORTS_VT_REMOTE_TX)) { 708 builder.append(isLong ? " CAPABILITY_SUPPORTS_VT_REMOTE_TX" : " VTrtx"); 709 } 710 if (can(capabilities, CAPABILITY_SUPPORTS_VT_REMOTE_BIDIRECTIONAL)) { 711 builder.append(isLong ? " CAPABILITY_SUPPORTS_VT_REMOTE_BIDIRECTIONAL" : " VTrbi"); 712 } 713 if (can(capabilities, CAPABILITY_CANNOT_DOWNGRADE_VIDEO_TO_AUDIO)) { 714 builder.append(isLong ? " CAPABILITY_CANNOT_DOWNGRADE_VIDEO_TO_AUDIO" : " !v2a"); 715 } 716 if (can(capabilities, CAPABILITY_SPEED_UP_MT_AUDIO)) { 717 builder.append(isLong ? " CAPABILITY_SPEED_UP_MT_AUDIO" : " spd_aud"); 718 } 719 if (can(capabilities, CAPABILITY_CAN_UPGRADE_TO_VIDEO)) { 720 builder.append(isLong ? " CAPABILITY_CAN_UPGRADE_TO_VIDEO" : " a2v"); 721 } 722 if (can(capabilities, CAPABILITY_CAN_PAUSE_VIDEO)) { 723 builder.append(isLong ? " CAPABILITY_CAN_PAUSE_VIDEO" : " paus_VT"); 724 } 725 if (can(capabilities, CAPABILITY_CONFERENCE_HAS_NO_CHILDREN)) { 726 builder.append(isLong ? " CAPABILITY_SINGLE_PARTY_CONFERENCE" : " 1p_cnf"); 727 } 728 if (can(capabilities, CAPABILITY_CAN_SEND_RESPONSE_VIA_CONNECTION)) { 729 builder.append(isLong ? " CAPABILITY_CAN_SEND_RESPONSE_VIA_CONNECTION" : " rsp_by_con"); 730 } 731 if (can(capabilities, CAPABILITY_CAN_PULL_CALL)) { 732 builder.append(isLong ? " CAPABILITY_CAN_PULL_CALL" : " pull"); 733 } 734 if (can(capabilities, CAPABILITY_SUPPORT_DEFLECT)) { 735 builder.append(isLong ? " CAPABILITY_SUPPORT_DEFLECT" : " sup_def"); 736 } 737 738 builder.append("]"); 739 return builder.toString(); 740 } 741 742 /** 743 * Renders a set of property bits ({@code PROPERTY_*}) as a human readable string. 744 * 745 * @param properties A property bit field. 746 * @return A human readable string representation. 747 */ propertiesToString(int properties)748 public static String propertiesToString(int properties) { 749 return propertiesToStringInternal(properties, true /* isLong */); 750 } 751 752 /** 753 * Renders a set of property bits ({@code PROPERTY_*}) as a *short* human readable string. 754 * 755 * @param properties A property bit field. 756 * @return A human readable string representation. 757 * @hide 758 */ propertiesToStringShort(int properties)759 public static String propertiesToStringShort(int properties) { 760 return propertiesToStringInternal(properties, false /* isLong */); 761 } 762 propertiesToStringInternal(int properties, boolean isLong)763 private static String propertiesToStringInternal(int properties, boolean isLong) { 764 StringBuilder builder = new StringBuilder(); 765 builder.append("["); 766 if (isLong) { 767 builder.append("Properties:"); 768 } 769 770 if (can(properties, PROPERTY_SELF_MANAGED)) { 771 builder.append(isLong ? " PROPERTY_SELF_MANAGED" : " self_mng"); 772 } 773 774 if (can(properties, PROPERTY_EMERGENCY_CALLBACK_MODE)) { 775 builder.append(isLong ? " PROPERTY_EMERGENCY_CALLBACK_MODE" : " ecbm"); 776 } 777 778 if (can(properties, PROPERTY_HIGH_DEF_AUDIO)) { 779 builder.append(isLong ? " PROPERTY_HIGH_DEF_AUDIO" : " HD"); 780 } 781 782 if (can(properties, PROPERTY_WIFI)) { 783 builder.append(isLong ? " PROPERTY_WIFI" : " wifi"); 784 } 785 786 if (can(properties, PROPERTY_GENERIC_CONFERENCE)) { 787 builder.append(isLong ? " PROPERTY_GENERIC_CONFERENCE" : " gen_conf"); 788 } 789 790 if (can(properties, PROPERTY_IS_EXTERNAL_CALL)) { 791 builder.append(isLong ? " PROPERTY_IS_EXTERNAL_CALL" : " xtrnl"); 792 } 793 794 if (can(properties, PROPERTY_HAS_CDMA_VOICE_PRIVACY)) { 795 builder.append(isLong ? " PROPERTY_HAS_CDMA_VOICE_PRIVACY" : " priv"); 796 } 797 798 if (can(properties, PROPERTY_IS_RTT)) { 799 builder.append(isLong ? " PROPERTY_IS_RTT" : " rtt"); 800 } 801 802 builder.append("]"); 803 return builder.toString(); 804 } 805 806 /** @hide */ 807 public abstract static class Listener { onStateChanged(Connection c, int state)808 public void onStateChanged(Connection c, int state) {} onAddressChanged(Connection c, Uri newAddress, int presentation)809 public void onAddressChanged(Connection c, Uri newAddress, int presentation) {} onCallerDisplayNameChanged( Connection c, String callerDisplayName, int presentation)810 public void onCallerDisplayNameChanged( 811 Connection c, String callerDisplayName, int presentation) {} onVideoStateChanged(Connection c, int videoState)812 public void onVideoStateChanged(Connection c, int videoState) {} onDisconnected(Connection c, DisconnectCause disconnectCause)813 public void onDisconnected(Connection c, DisconnectCause disconnectCause) {} onPostDialWait(Connection c, String remaining)814 public void onPostDialWait(Connection c, String remaining) {} onPostDialChar(Connection c, char nextChar)815 public void onPostDialChar(Connection c, char nextChar) {} onRingbackRequested(Connection c, boolean ringback)816 public void onRingbackRequested(Connection c, boolean ringback) {} onDestroyed(Connection c)817 public void onDestroyed(Connection c) {} onConnectionCapabilitiesChanged(Connection c, int capabilities)818 public void onConnectionCapabilitiesChanged(Connection c, int capabilities) {} onConnectionPropertiesChanged(Connection c, int properties)819 public void onConnectionPropertiesChanged(Connection c, int properties) {} onSupportedAudioRoutesChanged(Connection c, int supportedAudioRoutes)820 public void onSupportedAudioRoutesChanged(Connection c, int supportedAudioRoutes) {} onVideoProviderChanged( Connection c, VideoProvider videoProvider)821 public void onVideoProviderChanged( 822 Connection c, VideoProvider videoProvider) {} onAudioModeIsVoipChanged(Connection c, boolean isVoip)823 public void onAudioModeIsVoipChanged(Connection c, boolean isVoip) {} onStatusHintsChanged(Connection c, StatusHints statusHints)824 public void onStatusHintsChanged(Connection c, StatusHints statusHints) {} onConferenceablesChanged( Connection c, List<Conferenceable> conferenceables)825 public void onConferenceablesChanged( 826 Connection c, List<Conferenceable> conferenceables) {} onConferenceChanged(Connection c, Conference conference)827 public void onConferenceChanged(Connection c, Conference conference) {} 828 /** @hide */ onConferenceParticipantsChanged(Connection c, List<ConferenceParticipant> participants)829 public void onConferenceParticipantsChanged(Connection c, 830 List<ConferenceParticipant> participants) {} onConferenceStarted()831 public void onConferenceStarted() {} onConferenceMergeFailed(Connection c)832 public void onConferenceMergeFailed(Connection c) {} onExtrasChanged(Connection c, Bundle extras)833 public void onExtrasChanged(Connection c, Bundle extras) {} onExtrasRemoved(Connection c, List<String> keys)834 public void onExtrasRemoved(Connection c, List<String> keys) {} onConnectionEvent(Connection c, String event, Bundle extras)835 public void onConnectionEvent(Connection c, String event, Bundle extras) {} 836 /** @hide */ onConferenceSupportedChanged(Connection c, boolean isConferenceSupported)837 public void onConferenceSupportedChanged(Connection c, boolean isConferenceSupported) {} onAudioRouteChanged(Connection c, int audioRoute, String bluetoothAddress)838 public void onAudioRouteChanged(Connection c, int audioRoute, String bluetoothAddress) {} onRttInitiationSuccess(Connection c)839 public void onRttInitiationSuccess(Connection c) {} onRttInitiationFailure(Connection c, int reason)840 public void onRttInitiationFailure(Connection c, int reason) {} onRttSessionRemotelyTerminated(Connection c)841 public void onRttSessionRemotelyTerminated(Connection c) {} onRemoteRttRequest(Connection c)842 public void onRemoteRttRequest(Connection c) {} 843 /** @hide */ onPhoneAccountChanged(Connection c, PhoneAccountHandle pHandle)844 public void onPhoneAccountChanged(Connection c, PhoneAccountHandle pHandle) {} 845 } 846 847 /** 848 * Provides methods to read and write RTT data to/from the in-call app. 849 */ 850 public static final class RttTextStream { 851 private static final int READ_BUFFER_SIZE = 1000; 852 private final InputStreamReader mPipeFromInCall; 853 private final OutputStreamWriter mPipeToInCall; 854 private final ParcelFileDescriptor mFdFromInCall; 855 private final ParcelFileDescriptor mFdToInCall; 856 private char[] mReadBuffer = new char[READ_BUFFER_SIZE]; 857 858 /** 859 * @hide 860 */ RttTextStream(ParcelFileDescriptor toInCall, ParcelFileDescriptor fromInCall)861 public RttTextStream(ParcelFileDescriptor toInCall, ParcelFileDescriptor fromInCall) { 862 mFdFromInCall = fromInCall; 863 mFdToInCall = toInCall; 864 mPipeFromInCall = new InputStreamReader( 865 new FileInputStream(fromInCall.getFileDescriptor())); 866 mPipeToInCall = new OutputStreamWriter( 867 new FileOutputStream(toInCall.getFileDescriptor())); 868 } 869 870 /** 871 * Writes the string {@param input} into the text stream to the UI for this RTT call. Since 872 * RTT transmits text in real-time, this method should be called as often as text snippets 873 * are received from the remote user, even if it is only one character. 874 * <p> 875 * This method is not thread-safe -- calling it from multiple threads simultaneously may 876 * lead to interleaved text. 877 * 878 * @param input The message to send to the in-call app. 879 */ write(String input)880 public void write(String input) throws IOException { 881 mPipeToInCall.write(input); 882 mPipeToInCall.flush(); 883 } 884 885 886 /** 887 * Reads a string from the in-call app, blocking if there is no data available. Returns 888 * {@code null} if the RTT conversation has been terminated and there is no further data 889 * to read. 890 * <p> 891 * This method is not thread-safe -- calling it from multiple threads simultaneously may 892 * lead to interleaved text. 893 * 894 * @return A string containing text entered by the user, or {@code null} if the 895 * conversation has been terminated or if there was an error while reading. 896 */ read()897 public String read() throws IOException { 898 int numRead = mPipeFromInCall.read(mReadBuffer, 0, READ_BUFFER_SIZE); 899 if (numRead < 0) { 900 return null; 901 } 902 return new String(mReadBuffer, 0, numRead); 903 } 904 905 /** 906 * Non-blocking version of {@link #read()}. Returns {@code null} if there is nothing to 907 * be read. 908 * 909 * @return A string containing text entered by the user, or {@code null} if the user has 910 * not entered any new text yet. 911 */ readImmediately()912 public String readImmediately() throws IOException { 913 if (mPipeFromInCall.ready()) { 914 return read(); 915 } else { 916 return null; 917 } 918 } 919 920 /** @hide */ getFdFromInCall()921 public ParcelFileDescriptor getFdFromInCall() { 922 return mFdFromInCall; 923 } 924 925 /** @hide */ getFdToInCall()926 public ParcelFileDescriptor getFdToInCall() { 927 return mFdToInCall; 928 } 929 } 930 931 /** 932 * Provides constants to represent the results of responses to session modify requests sent via 933 * {@link Call#sendRttRequest()} 934 */ 935 public static final class RttModifyStatus { RttModifyStatus()936 private RttModifyStatus() {} 937 /** 938 * Session modify request was successful. 939 */ 940 public static final int SESSION_MODIFY_REQUEST_SUCCESS = 1; 941 942 /** 943 * Session modify request failed. 944 */ 945 public static final int SESSION_MODIFY_REQUEST_FAIL = 2; 946 947 /** 948 * Session modify request ignored due to invalid parameters. 949 */ 950 public static final int SESSION_MODIFY_REQUEST_INVALID = 3; 951 952 /** 953 * Session modify request timed out. 954 */ 955 public static final int SESSION_MODIFY_REQUEST_TIMED_OUT = 4; 956 957 /** 958 * Session modify request rejected by remote user. 959 */ 960 public static final int SESSION_MODIFY_REQUEST_REJECTED_BY_REMOTE = 5; 961 } 962 963 /** 964 * Provides a means of controlling the video session associated with a {@link Connection}. 965 * <p> 966 * Implementations create a custom subclass of {@link VideoProvider} and the 967 * {@link ConnectionService} creates an instance sets it on the {@link Connection} using 968 * {@link Connection#setVideoProvider(VideoProvider)}. Any connection which supports video 969 * should set the {@link VideoProvider}. 970 * <p> 971 * The {@link VideoProvider} serves two primary purposes: it provides a means for Telecom and 972 * {@link InCallService} implementations to issue requests related to the video session; 973 * it provides a means for the {@link ConnectionService} to report events and information 974 * related to the video session to Telecom and the {@link InCallService} implementations. 975 * <p> 976 * {@link InCallService} implementations interact with the {@link VideoProvider} via 977 * {@link android.telecom.InCallService.VideoCall}. 978 */ 979 public static abstract class VideoProvider { 980 /** 981 * Video is not being received (no protocol pause was issued). 982 * @see #handleCallSessionEvent(int) 983 */ 984 public static final int SESSION_EVENT_RX_PAUSE = 1; 985 986 /** 987 * Video reception has resumed after a {@link #SESSION_EVENT_RX_PAUSE}. 988 * @see #handleCallSessionEvent(int) 989 */ 990 public static final int SESSION_EVENT_RX_RESUME = 2; 991 992 /** 993 * Video transmission has begun. This occurs after a negotiated start of video transmission 994 * when the underlying protocol has actually begun transmitting video to the remote party. 995 * @see #handleCallSessionEvent(int) 996 */ 997 public static final int SESSION_EVENT_TX_START = 3; 998 999 /** 1000 * Video transmission has stopped. This occurs after a negotiated stop of video transmission 1001 * when the underlying protocol has actually stopped transmitting video to the remote party. 1002 * @see #handleCallSessionEvent(int) 1003 */ 1004 public static final int SESSION_EVENT_TX_STOP = 4; 1005 1006 /** 1007 * A camera failure has occurred for the selected camera. The {@link VideoProvider} can use 1008 * this as a cue to inform the user the camera is not available. 1009 * @see #handleCallSessionEvent(int) 1010 */ 1011 public static final int SESSION_EVENT_CAMERA_FAILURE = 5; 1012 1013 /** 1014 * Issued after {@link #SESSION_EVENT_CAMERA_FAILURE} when the camera is once again ready 1015 * for operation. The {@link VideoProvider} can use this as a cue to inform the user that 1016 * the camera has become available again. 1017 * @see #handleCallSessionEvent(int) 1018 */ 1019 public static final int SESSION_EVENT_CAMERA_READY = 6; 1020 1021 /** 1022 * Session event raised by Telecom when 1023 * {@link android.telecom.InCallService.VideoCall#setCamera(String)} is called and the 1024 * caller does not have the necessary {@link android.Manifest.permission#CAMERA} permission. 1025 * @see #handleCallSessionEvent(int) 1026 */ 1027 public static final int SESSION_EVENT_CAMERA_PERMISSION_ERROR = 7; 1028 1029 /** 1030 * Session modify request was successful. 1031 * @see #receiveSessionModifyResponse(int, VideoProfile, VideoProfile) 1032 */ 1033 public static final int SESSION_MODIFY_REQUEST_SUCCESS = 1; 1034 1035 /** 1036 * Session modify request failed. 1037 * @see #receiveSessionModifyResponse(int, VideoProfile, VideoProfile) 1038 */ 1039 public static final int SESSION_MODIFY_REQUEST_FAIL = 2; 1040 1041 /** 1042 * Session modify request ignored due to invalid parameters. 1043 * @see #receiveSessionModifyResponse(int, VideoProfile, VideoProfile) 1044 */ 1045 public static final int SESSION_MODIFY_REQUEST_INVALID = 3; 1046 1047 /** 1048 * Session modify request timed out. 1049 * @see #receiveSessionModifyResponse(int, VideoProfile, VideoProfile) 1050 */ 1051 public static final int SESSION_MODIFY_REQUEST_TIMED_OUT = 4; 1052 1053 /** 1054 * Session modify request rejected by remote user. 1055 * @see #receiveSessionModifyResponse(int, VideoProfile, VideoProfile) 1056 */ 1057 public static final int SESSION_MODIFY_REQUEST_REJECTED_BY_REMOTE = 5; 1058 1059 private static final int MSG_ADD_VIDEO_CALLBACK = 1; 1060 private static final int MSG_SET_CAMERA = 2; 1061 private static final int MSG_SET_PREVIEW_SURFACE = 3; 1062 private static final int MSG_SET_DISPLAY_SURFACE = 4; 1063 private static final int MSG_SET_DEVICE_ORIENTATION = 5; 1064 private static final int MSG_SET_ZOOM = 6; 1065 private static final int MSG_SEND_SESSION_MODIFY_REQUEST = 7; 1066 private static final int MSG_SEND_SESSION_MODIFY_RESPONSE = 8; 1067 private static final int MSG_REQUEST_CAMERA_CAPABILITIES = 9; 1068 private static final int MSG_REQUEST_CONNECTION_DATA_USAGE = 10; 1069 private static final int MSG_SET_PAUSE_IMAGE = 11; 1070 private static final int MSG_REMOVE_VIDEO_CALLBACK = 12; 1071 1072 private static final String SESSION_EVENT_RX_PAUSE_STR = "RX_PAUSE"; 1073 private static final String SESSION_EVENT_RX_RESUME_STR = "RX_RESUME"; 1074 private static final String SESSION_EVENT_TX_START_STR = "TX_START"; 1075 private static final String SESSION_EVENT_TX_STOP_STR = "TX_STOP"; 1076 private static final String SESSION_EVENT_CAMERA_FAILURE_STR = "CAMERA_FAIL"; 1077 private static final String SESSION_EVENT_CAMERA_READY_STR = "CAMERA_READY"; 1078 private static final String SESSION_EVENT_CAMERA_PERMISSION_ERROR_STR = 1079 "CAMERA_PERMISSION_ERROR"; 1080 private static final String SESSION_EVENT_UNKNOWN_STR = "UNKNOWN"; 1081 1082 private VideoProvider.VideoProviderHandler mMessageHandler; 1083 private final VideoProvider.VideoProviderBinder mBinder; 1084 1085 /** 1086 * Stores a list of the video callbacks, keyed by IBinder. 1087 * 1088 * ConcurrentHashMap constructor params: 8 is initial table size, 0.9f is 1089 * load factor before resizing, 1 means we only expect a single thread to 1090 * access the map so make only a single shard 1091 */ 1092 private ConcurrentHashMap<IBinder, IVideoCallback> mVideoCallbacks = 1093 new ConcurrentHashMap<IBinder, IVideoCallback>(8, 0.9f, 1); 1094 1095 /** 1096 * Default handler used to consolidate binder method calls onto a single thread. 1097 */ 1098 private final class VideoProviderHandler extends Handler { VideoProviderHandler()1099 public VideoProviderHandler() { 1100 super(); 1101 } 1102 VideoProviderHandler(Looper looper)1103 public VideoProviderHandler(Looper looper) { 1104 super(looper); 1105 } 1106 1107 @Override handleMessage(Message msg)1108 public void handleMessage(Message msg) { 1109 switch (msg.what) { 1110 case MSG_ADD_VIDEO_CALLBACK: { 1111 IBinder binder = (IBinder) msg.obj; 1112 IVideoCallback callback = IVideoCallback.Stub 1113 .asInterface((IBinder) msg.obj); 1114 if (callback == null) { 1115 Log.w(this, "addVideoProvider - skipped; callback is null."); 1116 break; 1117 } 1118 1119 if (mVideoCallbacks.containsKey(binder)) { 1120 Log.i(this, "addVideoProvider - skipped; already present."); 1121 break; 1122 } 1123 mVideoCallbacks.put(binder, callback); 1124 break; 1125 } 1126 case MSG_REMOVE_VIDEO_CALLBACK: { 1127 IBinder binder = (IBinder) msg.obj; 1128 IVideoCallback callback = IVideoCallback.Stub 1129 .asInterface((IBinder) msg.obj); 1130 if (!mVideoCallbacks.containsKey(binder)) { 1131 Log.i(this, "removeVideoProvider - skipped; not present."); 1132 break; 1133 } 1134 mVideoCallbacks.remove(binder); 1135 break; 1136 } 1137 case MSG_SET_CAMERA: 1138 { 1139 SomeArgs args = (SomeArgs) msg.obj; 1140 try { 1141 onSetCamera((String) args.arg1); 1142 onSetCamera((String) args.arg1, (String) args.arg2, args.argi1, 1143 args.argi2, args.argi3); 1144 } finally { 1145 args.recycle(); 1146 } 1147 } 1148 break; 1149 case MSG_SET_PREVIEW_SURFACE: 1150 onSetPreviewSurface((Surface) msg.obj); 1151 break; 1152 case MSG_SET_DISPLAY_SURFACE: 1153 onSetDisplaySurface((Surface) msg.obj); 1154 break; 1155 case MSG_SET_DEVICE_ORIENTATION: 1156 onSetDeviceOrientation(msg.arg1); 1157 break; 1158 case MSG_SET_ZOOM: 1159 onSetZoom((Float) msg.obj); 1160 break; 1161 case MSG_SEND_SESSION_MODIFY_REQUEST: { 1162 SomeArgs args = (SomeArgs) msg.obj; 1163 try { 1164 onSendSessionModifyRequest((VideoProfile) args.arg1, 1165 (VideoProfile) args.arg2); 1166 } finally { 1167 args.recycle(); 1168 } 1169 break; 1170 } 1171 case MSG_SEND_SESSION_MODIFY_RESPONSE: 1172 onSendSessionModifyResponse((VideoProfile) msg.obj); 1173 break; 1174 case MSG_REQUEST_CAMERA_CAPABILITIES: 1175 onRequestCameraCapabilities(); 1176 break; 1177 case MSG_REQUEST_CONNECTION_DATA_USAGE: 1178 onRequestConnectionDataUsage(); 1179 break; 1180 case MSG_SET_PAUSE_IMAGE: 1181 onSetPauseImage((Uri) msg.obj); 1182 break; 1183 default: 1184 break; 1185 } 1186 } 1187 } 1188 1189 /** 1190 * IVideoProvider stub implementation. 1191 */ 1192 private final class VideoProviderBinder extends IVideoProvider.Stub { addVideoCallback(IBinder videoCallbackBinder)1193 public void addVideoCallback(IBinder videoCallbackBinder) { 1194 mMessageHandler.obtainMessage( 1195 MSG_ADD_VIDEO_CALLBACK, videoCallbackBinder).sendToTarget(); 1196 } 1197 removeVideoCallback(IBinder videoCallbackBinder)1198 public void removeVideoCallback(IBinder videoCallbackBinder) { 1199 mMessageHandler.obtainMessage( 1200 MSG_REMOVE_VIDEO_CALLBACK, videoCallbackBinder).sendToTarget(); 1201 } 1202 setCamera(String cameraId, String callingPackageName, int targetSdkVersion)1203 public void setCamera(String cameraId, String callingPackageName, 1204 int targetSdkVersion) { 1205 1206 SomeArgs args = SomeArgs.obtain(); 1207 args.arg1 = cameraId; 1208 // Propagate the calling package; originally determined in 1209 // android.telecom.InCallService.VideoCall#setCamera(String) from the calling 1210 // process. 1211 args.arg2 = callingPackageName; 1212 // Pass along the uid and pid of the calling app; this gets lost when we put the 1213 // message onto the handler. These are required for Telecom to perform a permission 1214 // check to see if the calling app is able to use the camera. 1215 args.argi1 = Binder.getCallingUid(); 1216 args.argi2 = Binder.getCallingPid(); 1217 // Pass along the target SDK version of the calling InCallService. This is used to 1218 // maintain backwards compatibility of the API for older callers. 1219 args.argi3 = targetSdkVersion; 1220 mMessageHandler.obtainMessage(MSG_SET_CAMERA, args).sendToTarget(); 1221 } 1222 setPreviewSurface(Surface surface)1223 public void setPreviewSurface(Surface surface) { 1224 mMessageHandler.obtainMessage(MSG_SET_PREVIEW_SURFACE, surface).sendToTarget(); 1225 } 1226 setDisplaySurface(Surface surface)1227 public void setDisplaySurface(Surface surface) { 1228 mMessageHandler.obtainMessage(MSG_SET_DISPLAY_SURFACE, surface).sendToTarget(); 1229 } 1230 setDeviceOrientation(int rotation)1231 public void setDeviceOrientation(int rotation) { 1232 mMessageHandler.obtainMessage( 1233 MSG_SET_DEVICE_ORIENTATION, rotation, 0).sendToTarget(); 1234 } 1235 setZoom(float value)1236 public void setZoom(float value) { 1237 mMessageHandler.obtainMessage(MSG_SET_ZOOM, value).sendToTarget(); 1238 } 1239 sendSessionModifyRequest(VideoProfile fromProfile, VideoProfile toProfile)1240 public void sendSessionModifyRequest(VideoProfile fromProfile, VideoProfile toProfile) { 1241 SomeArgs args = SomeArgs.obtain(); 1242 args.arg1 = fromProfile; 1243 args.arg2 = toProfile; 1244 mMessageHandler.obtainMessage(MSG_SEND_SESSION_MODIFY_REQUEST, args).sendToTarget(); 1245 } 1246 sendSessionModifyResponse(VideoProfile responseProfile)1247 public void sendSessionModifyResponse(VideoProfile responseProfile) { 1248 mMessageHandler.obtainMessage( 1249 MSG_SEND_SESSION_MODIFY_RESPONSE, responseProfile).sendToTarget(); 1250 } 1251 requestCameraCapabilities()1252 public void requestCameraCapabilities() { 1253 mMessageHandler.obtainMessage(MSG_REQUEST_CAMERA_CAPABILITIES).sendToTarget(); 1254 } 1255 requestCallDataUsage()1256 public void requestCallDataUsage() { 1257 mMessageHandler.obtainMessage(MSG_REQUEST_CONNECTION_DATA_USAGE).sendToTarget(); 1258 } 1259 setPauseImage(Uri uri)1260 public void setPauseImage(Uri uri) { 1261 mMessageHandler.obtainMessage(MSG_SET_PAUSE_IMAGE, uri).sendToTarget(); 1262 } 1263 } 1264 VideoProvider()1265 public VideoProvider() { 1266 mBinder = new VideoProvider.VideoProviderBinder(); 1267 mMessageHandler = new VideoProvider.VideoProviderHandler(Looper.getMainLooper()); 1268 } 1269 1270 /** 1271 * Creates an instance of the {@link VideoProvider}, specifying the looper to use. 1272 * 1273 * @param looper The looper. 1274 * @hide 1275 */ VideoProvider(Looper looper)1276 public VideoProvider(Looper looper) { 1277 mBinder = new VideoProvider.VideoProviderBinder(); 1278 mMessageHandler = new VideoProvider.VideoProviderHandler(looper); 1279 } 1280 1281 /** 1282 * Returns binder object which can be used across IPC methods. 1283 * @hide 1284 */ getInterface()1285 public final IVideoProvider getInterface() { 1286 return mBinder; 1287 } 1288 1289 /** 1290 * Sets the camera to be used for the outgoing video. 1291 * <p> 1292 * The {@link VideoProvider} should respond by communicating the capabilities of the chosen 1293 * camera via 1294 * {@link VideoProvider#changeCameraCapabilities(VideoProfile.CameraCapabilities)}. 1295 * <p> 1296 * Sent from the {@link InCallService} via 1297 * {@link InCallService.VideoCall#setCamera(String)}. 1298 * 1299 * @param cameraId The id of the camera (use ids as reported by 1300 * {@link CameraManager#getCameraIdList()}). 1301 */ onSetCamera(String cameraId)1302 public abstract void onSetCamera(String cameraId); 1303 1304 /** 1305 * Sets the camera to be used for the outgoing video. 1306 * <p> 1307 * The {@link VideoProvider} should respond by communicating the capabilities of the chosen 1308 * camera via 1309 * {@link VideoProvider#changeCameraCapabilities(VideoProfile.CameraCapabilities)}. 1310 * <p> 1311 * This prototype is used internally to ensure that the calling package name, UID and PID 1312 * are sent to Telecom so that can perform a camera permission check on the caller. 1313 * <p> 1314 * Sent from the {@link InCallService} via 1315 * {@link InCallService.VideoCall#setCamera(String)}. 1316 * 1317 * @param cameraId The id of the camera (use ids as reported by 1318 * {@link CameraManager#getCameraIdList()}). 1319 * @param callingPackageName The AppOpps package name of the caller. 1320 * @param callingUid The UID of the caller. 1321 * @param callingPid The PID of the caller. 1322 * @param targetSdkVersion The target SDK version of the caller. 1323 * @hide 1324 */ onSetCamera(String cameraId, String callingPackageName, int callingUid, int callingPid, int targetSdkVersion)1325 public void onSetCamera(String cameraId, String callingPackageName, int callingUid, 1326 int callingPid, int targetSdkVersion) {} 1327 1328 /** 1329 * Sets the surface to be used for displaying a preview of what the user's camera is 1330 * currently capturing. When video transmission is enabled, this is the video signal which 1331 * is sent to the remote device. 1332 * <p> 1333 * Sent from the {@link InCallService} via 1334 * {@link InCallService.VideoCall#setPreviewSurface(Surface)}. 1335 * 1336 * @param surface The {@link Surface}. 1337 */ onSetPreviewSurface(Surface surface)1338 public abstract void onSetPreviewSurface(Surface surface); 1339 1340 /** 1341 * Sets the surface to be used for displaying the video received from the remote device. 1342 * <p> 1343 * Sent from the {@link InCallService} via 1344 * {@link InCallService.VideoCall#setDisplaySurface(Surface)}. 1345 * 1346 * @param surface The {@link Surface}. 1347 */ onSetDisplaySurface(Surface surface)1348 public abstract void onSetDisplaySurface(Surface surface); 1349 1350 /** 1351 * Sets the device orientation, in degrees. Assumes that a standard portrait orientation of 1352 * the device is 0 degrees. 1353 * <p> 1354 * Sent from the {@link InCallService} via 1355 * {@link InCallService.VideoCall#setDeviceOrientation(int)}. 1356 * 1357 * @param rotation The device orientation, in degrees. 1358 */ onSetDeviceOrientation(int rotation)1359 public abstract void onSetDeviceOrientation(int rotation); 1360 1361 /** 1362 * Sets camera zoom ratio. 1363 * <p> 1364 * Sent from the {@link InCallService} via {@link InCallService.VideoCall#setZoom(float)}. 1365 * 1366 * @param value The camera zoom ratio. 1367 */ onSetZoom(float value)1368 public abstract void onSetZoom(float value); 1369 1370 /** 1371 * Issues a request to modify the properties of the current video session. 1372 * <p> 1373 * Example scenarios include: requesting an audio-only call to be upgraded to a 1374 * bi-directional video call, turning on or off the user's camera, sending a pause signal 1375 * when the {@link InCallService} is no longer the foreground application. 1376 * <p> 1377 * If the {@link VideoProvider} determines a request to be invalid, it should call 1378 * {@link #receiveSessionModifyResponse(int, VideoProfile, VideoProfile)} to report the 1379 * invalid request back to the {@link InCallService}. 1380 * <p> 1381 * Where a request requires confirmation from the user of the peer device, the 1382 * {@link VideoProvider} must communicate the request to the peer device and handle the 1383 * user's response. {@link #receiveSessionModifyResponse(int, VideoProfile, VideoProfile)} 1384 * is used to inform the {@link InCallService} of the result of the request. 1385 * <p> 1386 * Sent from the {@link InCallService} via 1387 * {@link InCallService.VideoCall#sendSessionModifyRequest(VideoProfile)}. 1388 * 1389 * @param fromProfile The video profile prior to the request. 1390 * @param toProfile The video profile with the requested changes made. 1391 */ onSendSessionModifyRequest(VideoProfile fromProfile, VideoProfile toProfile)1392 public abstract void onSendSessionModifyRequest(VideoProfile fromProfile, 1393 VideoProfile toProfile); 1394 1395 /** 1396 * Provides a response to a request to change the current video session properties. 1397 * <p> 1398 * For example, if the peer requests and upgrade from an audio-only call to a bi-directional 1399 * video call, could decline the request and keep the call as audio-only. 1400 * In such a scenario, the {@code responseProfile} would have a video state of 1401 * {@link VideoProfile#STATE_AUDIO_ONLY}. If the user had decided to accept the request, 1402 * the video state would be {@link VideoProfile#STATE_BIDIRECTIONAL}. 1403 * <p> 1404 * Sent from the {@link InCallService} via 1405 * {@link InCallService.VideoCall#sendSessionModifyResponse(VideoProfile)} in response to 1406 * a {@link InCallService.VideoCall.Callback#onSessionModifyRequestReceived(VideoProfile)} 1407 * callback. 1408 * 1409 * @param responseProfile The response video profile. 1410 */ onSendSessionModifyResponse(VideoProfile responseProfile)1411 public abstract void onSendSessionModifyResponse(VideoProfile responseProfile); 1412 1413 /** 1414 * Issues a request to the {@link VideoProvider} to retrieve the camera capabilities. 1415 * <p> 1416 * The {@link VideoProvider} should respond by communicating the capabilities of the chosen 1417 * camera via 1418 * {@link VideoProvider#changeCameraCapabilities(VideoProfile.CameraCapabilities)}. 1419 * <p> 1420 * Sent from the {@link InCallService} via 1421 * {@link InCallService.VideoCall#requestCameraCapabilities()}. 1422 */ onRequestCameraCapabilities()1423 public abstract void onRequestCameraCapabilities(); 1424 1425 /** 1426 * Issues a request to the {@link VideoProvider} to retrieve the current data usage for the 1427 * video component of the current {@link Connection}. 1428 * <p> 1429 * The {@link VideoProvider} should respond by communicating current data usage, in bytes, 1430 * via {@link VideoProvider#setCallDataUsage(long)}. 1431 * <p> 1432 * Sent from the {@link InCallService} via 1433 * {@link InCallService.VideoCall#requestCallDataUsage()}. 1434 */ onRequestConnectionDataUsage()1435 public abstract void onRequestConnectionDataUsage(); 1436 1437 /** 1438 * Provides the {@link VideoProvider} with the {@link Uri} of an image to be displayed to 1439 * the peer device when the video signal is paused. 1440 * <p> 1441 * Sent from the {@link InCallService} via 1442 * {@link InCallService.VideoCall#setPauseImage(Uri)}. 1443 * 1444 * @param uri URI of image to display. 1445 */ onSetPauseImage(Uri uri)1446 public abstract void onSetPauseImage(Uri uri); 1447 1448 /** 1449 * Used to inform listening {@link InCallService} implementations when the 1450 * {@link VideoProvider} receives a session modification request. 1451 * <p> 1452 * Received by the {@link InCallService} via 1453 * {@link InCallService.VideoCall.Callback#onSessionModifyRequestReceived(VideoProfile)}, 1454 * 1455 * @param videoProfile The requested video profile. 1456 * @see #onSendSessionModifyRequest(VideoProfile, VideoProfile) 1457 */ receiveSessionModifyRequest(VideoProfile videoProfile)1458 public void receiveSessionModifyRequest(VideoProfile videoProfile) { 1459 if (mVideoCallbacks != null) { 1460 for (IVideoCallback callback : mVideoCallbacks.values()) { 1461 try { 1462 callback.receiveSessionModifyRequest(videoProfile); 1463 } catch (RemoteException ignored) { 1464 Log.w(this, "receiveSessionModifyRequest callback failed", ignored); 1465 } 1466 } 1467 } 1468 } 1469 1470 /** 1471 * Used to inform listening {@link InCallService} implementations when the 1472 * {@link VideoProvider} receives a response to a session modification request. 1473 * <p> 1474 * Received by the {@link InCallService} via 1475 * {@link InCallService.VideoCall.Callback#onSessionModifyResponseReceived(int, 1476 * VideoProfile, VideoProfile)}. 1477 * 1478 * @param status Status of the session modify request. Valid values are 1479 * {@link VideoProvider#SESSION_MODIFY_REQUEST_SUCCESS}, 1480 * {@link VideoProvider#SESSION_MODIFY_REQUEST_FAIL}, 1481 * {@link VideoProvider#SESSION_MODIFY_REQUEST_INVALID}, 1482 * {@link VideoProvider#SESSION_MODIFY_REQUEST_TIMED_OUT}, 1483 * {@link VideoProvider#SESSION_MODIFY_REQUEST_REJECTED_BY_REMOTE} 1484 * @param requestedProfile The original request which was sent to the peer device. 1485 * @param responseProfile The actual profile changes agreed to by the peer device. 1486 * @see #onSendSessionModifyRequest(VideoProfile, VideoProfile) 1487 */ receiveSessionModifyResponse(int status, VideoProfile requestedProfile, VideoProfile responseProfile)1488 public void receiveSessionModifyResponse(int status, 1489 VideoProfile requestedProfile, VideoProfile responseProfile) { 1490 if (mVideoCallbacks != null) { 1491 for (IVideoCallback callback : mVideoCallbacks.values()) { 1492 try { 1493 callback.receiveSessionModifyResponse(status, requestedProfile, 1494 responseProfile); 1495 } catch (RemoteException ignored) { 1496 Log.w(this, "receiveSessionModifyResponse callback failed", ignored); 1497 } 1498 } 1499 } 1500 } 1501 1502 /** 1503 * Used to inform listening {@link InCallService} implementations when the 1504 * {@link VideoProvider} reports a call session event. 1505 * <p> 1506 * Received by the {@link InCallService} via 1507 * {@link InCallService.VideoCall.Callback#onCallSessionEvent(int)}. 1508 * 1509 * @param event The event. Valid values are: {@link VideoProvider#SESSION_EVENT_RX_PAUSE}, 1510 * {@link VideoProvider#SESSION_EVENT_RX_RESUME}, 1511 * {@link VideoProvider#SESSION_EVENT_TX_START}, 1512 * {@link VideoProvider#SESSION_EVENT_TX_STOP}, 1513 * {@link VideoProvider#SESSION_EVENT_CAMERA_FAILURE}, 1514 * {@link VideoProvider#SESSION_EVENT_CAMERA_READY}, 1515 * {@link VideoProvider#SESSION_EVENT_CAMERA_FAILURE}. 1516 */ handleCallSessionEvent(int event)1517 public void handleCallSessionEvent(int event) { 1518 if (mVideoCallbacks != null) { 1519 for (IVideoCallback callback : mVideoCallbacks.values()) { 1520 try { 1521 callback.handleCallSessionEvent(event); 1522 } catch (RemoteException ignored) { 1523 Log.w(this, "handleCallSessionEvent callback failed", ignored); 1524 } 1525 } 1526 } 1527 } 1528 1529 /** 1530 * Used to inform listening {@link InCallService} implementations when the dimensions of the 1531 * peer's video have changed. 1532 * <p> 1533 * This could occur if, for example, the peer rotates their device, changing the aspect 1534 * ratio of the video, or if the user switches between the back and front cameras. 1535 * <p> 1536 * Received by the {@link InCallService} via 1537 * {@link InCallService.VideoCall.Callback#onPeerDimensionsChanged(int, int)}. 1538 * 1539 * @param width The updated peer video width. 1540 * @param height The updated peer video height. 1541 */ changePeerDimensions(int width, int height)1542 public void changePeerDimensions(int width, int height) { 1543 if (mVideoCallbacks != null) { 1544 for (IVideoCallback callback : mVideoCallbacks.values()) { 1545 try { 1546 callback.changePeerDimensions(width, height); 1547 } catch (RemoteException ignored) { 1548 Log.w(this, "changePeerDimensions callback failed", ignored); 1549 } 1550 } 1551 } 1552 } 1553 1554 /** 1555 * Used to inform listening {@link InCallService} implementations when the data usage of the 1556 * video associated with the current {@link Connection} has changed. 1557 * <p> 1558 * This could be in response to a preview request via 1559 * {@link #onRequestConnectionDataUsage()}, or as a periodic update by the 1560 * {@link VideoProvider}. Where periodic updates of data usage are provided, they should be 1561 * provided at most for every 1 MB of data transferred and no more than once every 10 sec. 1562 * <p> 1563 * Received by the {@link InCallService} via 1564 * {@link InCallService.VideoCall.Callback#onCallDataUsageChanged(long)}. 1565 * 1566 * @param dataUsage The updated data usage (in bytes). Reported as the cumulative bytes 1567 * used since the start of the call. 1568 */ setCallDataUsage(long dataUsage)1569 public void setCallDataUsage(long dataUsage) { 1570 if (mVideoCallbacks != null) { 1571 for (IVideoCallback callback : mVideoCallbacks.values()) { 1572 try { 1573 callback.changeCallDataUsage(dataUsage); 1574 } catch (RemoteException ignored) { 1575 Log.w(this, "setCallDataUsage callback failed", ignored); 1576 } 1577 } 1578 } 1579 } 1580 1581 /** 1582 * @see #setCallDataUsage(long) 1583 * 1584 * @param dataUsage The updated data usage (in byes). 1585 * @deprecated - Use {@link #setCallDataUsage(long)} instead. 1586 * @hide 1587 */ changeCallDataUsage(long dataUsage)1588 public void changeCallDataUsage(long dataUsage) { 1589 setCallDataUsage(dataUsage); 1590 } 1591 1592 /** 1593 * Used to inform listening {@link InCallService} implementations when the capabilities of 1594 * the current camera have changed. 1595 * <p> 1596 * The {@link VideoProvider} should call this in response to 1597 * {@link VideoProvider#onRequestCameraCapabilities()}, or when the current camera is 1598 * changed via {@link VideoProvider#onSetCamera(String)}. 1599 * <p> 1600 * Received by the {@link InCallService} via 1601 * {@link InCallService.VideoCall.Callback#onCameraCapabilitiesChanged( 1602 * VideoProfile.CameraCapabilities)}. 1603 * 1604 * @param cameraCapabilities The new camera capabilities. 1605 */ changeCameraCapabilities(VideoProfile.CameraCapabilities cameraCapabilities)1606 public void changeCameraCapabilities(VideoProfile.CameraCapabilities cameraCapabilities) { 1607 if (mVideoCallbacks != null) { 1608 for (IVideoCallback callback : mVideoCallbacks.values()) { 1609 try { 1610 callback.changeCameraCapabilities(cameraCapabilities); 1611 } catch (RemoteException ignored) { 1612 Log.w(this, "changeCameraCapabilities callback failed", ignored); 1613 } 1614 } 1615 } 1616 } 1617 1618 /** 1619 * Used to inform listening {@link InCallService} implementations when the video quality 1620 * of the call has changed. 1621 * <p> 1622 * Received by the {@link InCallService} via 1623 * {@link InCallService.VideoCall.Callback#onVideoQualityChanged(int)}. 1624 * 1625 * @param videoQuality The updated video quality. Valid values: 1626 * {@link VideoProfile#QUALITY_HIGH}, 1627 * {@link VideoProfile#QUALITY_MEDIUM}, 1628 * {@link VideoProfile#QUALITY_LOW}, 1629 * {@link VideoProfile#QUALITY_DEFAULT}. 1630 */ changeVideoQuality(int videoQuality)1631 public void changeVideoQuality(int videoQuality) { 1632 if (mVideoCallbacks != null) { 1633 for (IVideoCallback callback : mVideoCallbacks.values()) { 1634 try { 1635 callback.changeVideoQuality(videoQuality); 1636 } catch (RemoteException ignored) { 1637 Log.w(this, "changeVideoQuality callback failed", ignored); 1638 } 1639 } 1640 } 1641 } 1642 1643 /** 1644 * Returns a string representation of a call session event. 1645 * 1646 * @param event A call session event passed to {@link #handleCallSessionEvent(int)}. 1647 * @return String representation of the call session event. 1648 * @hide 1649 */ sessionEventToString(int event)1650 public static String sessionEventToString(int event) { 1651 switch (event) { 1652 case SESSION_EVENT_CAMERA_FAILURE: 1653 return SESSION_EVENT_CAMERA_FAILURE_STR; 1654 case SESSION_EVENT_CAMERA_READY: 1655 return SESSION_EVENT_CAMERA_READY_STR; 1656 case SESSION_EVENT_RX_PAUSE: 1657 return SESSION_EVENT_RX_PAUSE_STR; 1658 case SESSION_EVENT_RX_RESUME: 1659 return SESSION_EVENT_RX_RESUME_STR; 1660 case SESSION_EVENT_TX_START: 1661 return SESSION_EVENT_TX_START_STR; 1662 case SESSION_EVENT_TX_STOP: 1663 return SESSION_EVENT_TX_STOP_STR; 1664 case SESSION_EVENT_CAMERA_PERMISSION_ERROR: 1665 return SESSION_EVENT_CAMERA_PERMISSION_ERROR_STR; 1666 default: 1667 return SESSION_EVENT_UNKNOWN_STR + " " + event; 1668 } 1669 } 1670 } 1671 1672 private final Listener mConnectionDeathListener = new Listener() { 1673 @Override 1674 public void onDestroyed(Connection c) { 1675 if (mConferenceables.remove(c)) { 1676 fireOnConferenceableConnectionsChanged(); 1677 } 1678 } 1679 }; 1680 1681 private final Conference.Listener mConferenceDeathListener = new Conference.Listener() { 1682 @Override 1683 public void onDestroyed(Conference c) { 1684 if (mConferenceables.remove(c)) { 1685 fireOnConferenceableConnectionsChanged(); 1686 } 1687 } 1688 }; 1689 1690 /** 1691 * ConcurrentHashMap constructor params: 8 is initial table size, 0.9f is 1692 * load factor before resizing, 1 means we only expect a single thread to 1693 * access the map so make only a single shard 1694 */ 1695 private final Set<Listener> mListeners = Collections.newSetFromMap( 1696 new ConcurrentHashMap<Listener, Boolean>(8, 0.9f, 1)); 1697 private final List<Conferenceable> mConferenceables = new ArrayList<>(); 1698 private final List<Conferenceable> mUnmodifiableConferenceables = 1699 Collections.unmodifiableList(mConferenceables); 1700 1701 // The internal telecom call ID associated with this connection. 1702 private String mTelecomCallId; 1703 // The PhoneAccountHandle associated with this connection. 1704 private PhoneAccountHandle mPhoneAccountHandle; 1705 private int mState = STATE_NEW; 1706 private CallAudioState mCallAudioState; 1707 private Uri mAddress; 1708 private int mAddressPresentation; 1709 private String mCallerDisplayName; 1710 private int mCallerDisplayNamePresentation; 1711 private boolean mRingbackRequested = false; 1712 private int mConnectionCapabilities; 1713 private int mConnectionProperties; 1714 private int mSupportedAudioRoutes = CallAudioState.ROUTE_ALL; 1715 private VideoProvider mVideoProvider; 1716 private boolean mAudioModeIsVoip; 1717 private long mConnectTimeMillis = Conference.CONNECT_TIME_NOT_SPECIFIED; 1718 private long mConnectElapsedTimeMillis = Conference.CONNECT_TIME_NOT_SPECIFIED; 1719 private StatusHints mStatusHints; 1720 private int mVideoState; 1721 private DisconnectCause mDisconnectCause; 1722 private Conference mConference; 1723 private ConnectionService mConnectionService; 1724 private Bundle mExtras; 1725 private final Object mExtrasLock = new Object(); 1726 1727 /** 1728 * Tracks the key set for the extras bundle provided on the last invocation of 1729 * {@link #setExtras(Bundle)}. Used so that on subsequent invocations we can remove any extras 1730 * keys which were set previously but are no longer present in the replacement Bundle. 1731 */ 1732 private Set<String> mPreviousExtraKeys; 1733 1734 /** 1735 * Create a new Connection. 1736 */ Connection()1737 public Connection() {} 1738 1739 /** 1740 * Returns the Telecom internal call ID associated with this connection. Should only be used 1741 * for debugging and tracing purposes. 1742 * 1743 * @return The Telecom call ID. 1744 * @hide 1745 */ getTelecomCallId()1746 public final String getTelecomCallId() { 1747 return mTelecomCallId; 1748 } 1749 1750 /** 1751 * @return The address (e.g., phone number) to which this Connection is currently communicating. 1752 */ getAddress()1753 public final Uri getAddress() { 1754 return mAddress; 1755 } 1756 1757 /** 1758 * @return The presentation requirements for the address. 1759 * See {@link TelecomManager} for valid values. 1760 */ getAddressPresentation()1761 public final int getAddressPresentation() { 1762 return mAddressPresentation; 1763 } 1764 1765 /** 1766 * @return The caller display name (CNAP). 1767 */ getCallerDisplayName()1768 public final String getCallerDisplayName() { 1769 return mCallerDisplayName; 1770 } 1771 1772 /** 1773 * @return The presentation requirements for the handle. 1774 * See {@link TelecomManager} for valid values. 1775 */ getCallerDisplayNamePresentation()1776 public final int getCallerDisplayNamePresentation() { 1777 return mCallerDisplayNamePresentation; 1778 } 1779 1780 /** 1781 * @return The state of this Connection. 1782 */ getState()1783 public final int getState() { 1784 return mState; 1785 } 1786 1787 /** 1788 * Returns the video state of the connection. 1789 * Valid values: {@link VideoProfile#STATE_AUDIO_ONLY}, 1790 * {@link VideoProfile#STATE_BIDIRECTIONAL}, 1791 * {@link VideoProfile#STATE_TX_ENABLED}, 1792 * {@link VideoProfile#STATE_RX_ENABLED}. 1793 * 1794 * @return The video state of the connection. 1795 * @hide 1796 */ getVideoState()1797 public final int getVideoState() { 1798 return mVideoState; 1799 } 1800 1801 /** 1802 * @return The audio state of the connection, describing how its audio is currently 1803 * being routed by the system. This is {@code null} if this Connection 1804 * does not directly know about its audio state. 1805 * @deprecated Use {@link #getCallAudioState()} instead. 1806 * @hide 1807 */ 1808 @SystemApi 1809 @Deprecated getAudioState()1810 public final AudioState getAudioState() { 1811 if (mCallAudioState == null) { 1812 return null; 1813 } 1814 return new AudioState(mCallAudioState); 1815 } 1816 1817 /** 1818 * @return The audio state of the connection, describing how its audio is currently 1819 * being routed by the system. This is {@code null} if this Connection 1820 * does not directly know about its audio state. 1821 */ getCallAudioState()1822 public final CallAudioState getCallAudioState() { 1823 return mCallAudioState; 1824 } 1825 1826 /** 1827 * @return The conference that this connection is a part of. Null if it is not part of any 1828 * conference. 1829 */ getConference()1830 public final Conference getConference() { 1831 return mConference; 1832 } 1833 1834 /** 1835 * Returns whether this connection is requesting that the system play a ringback tone 1836 * on its behalf. 1837 */ isRingbackRequested()1838 public final boolean isRingbackRequested() { 1839 return mRingbackRequested; 1840 } 1841 1842 /** 1843 * @return True if the connection's audio mode is VOIP. 1844 */ getAudioModeIsVoip()1845 public final boolean getAudioModeIsVoip() { 1846 return mAudioModeIsVoip; 1847 } 1848 1849 /** 1850 * Retrieves the connection start time of the {@code Connnection}, if specified. A value of 1851 * {@link Conference#CONNECT_TIME_NOT_SPECIFIED} indicates that Telecom should determine the 1852 * start time of the conference. 1853 * 1854 * @return The time at which the {@code Connnection} was connected. 1855 * 1856 * @hide 1857 */ getConnectTimeMillis()1858 public final long getConnectTimeMillis() { 1859 return mConnectTimeMillis; 1860 } 1861 1862 /** 1863 * Retrieves the connection start time of the {@link Connection}, if specified. A value of 1864 * {@link Conference#CONNECT_TIME_NOT_SPECIFIED} indicates that Telecom should determine the 1865 * start time of the conference. 1866 * 1867 * Based on the value of {@link SystemClock#elapsedRealtime()}, which ensures that wall-clock 1868 * changes do not impact the call duration. 1869 * 1870 * @return The time at which the {@link Connection} was connected. 1871 * 1872 * @hide 1873 */ getConnectElapsedTimeMillis()1874 public final long getConnectElapsedTimeMillis() { 1875 return mConnectElapsedTimeMillis; 1876 } 1877 1878 /** 1879 * @return The status hints for this connection. 1880 */ getStatusHints()1881 public final StatusHints getStatusHints() { 1882 return mStatusHints; 1883 } 1884 1885 /** 1886 * Returns the extras associated with this connection. 1887 * <p> 1888 * Extras should be updated using {@link #putExtras(Bundle)}. 1889 * <p> 1890 * Telecom or an {@link InCallService} can also update the extras via 1891 * {@link android.telecom.Call#putExtras(Bundle)}, and 1892 * {@link Call#removeExtras(List)}. 1893 * <p> 1894 * The connection is notified of changes to the extras made by Telecom or an 1895 * {@link InCallService} by {@link #onExtrasChanged(Bundle)}. 1896 * 1897 * @return The extras associated with this connection. 1898 */ getExtras()1899 public final Bundle getExtras() { 1900 Bundle extras = null; 1901 synchronized (mExtrasLock) { 1902 if (mExtras != null) { 1903 extras = new Bundle(mExtras); 1904 } 1905 } 1906 return extras; 1907 } 1908 1909 /** 1910 * Assign a listener to be notified of state changes. 1911 * 1912 * @param l A listener. 1913 * @return This Connection. 1914 * 1915 * @hide 1916 */ addConnectionListener(Listener l)1917 public final Connection addConnectionListener(Listener l) { 1918 mListeners.add(l); 1919 return this; 1920 } 1921 1922 /** 1923 * Remove a previously assigned listener that was being notified of state changes. 1924 * 1925 * @param l A Listener. 1926 * @return This Connection. 1927 * 1928 * @hide 1929 */ removeConnectionListener(Listener l)1930 public final Connection removeConnectionListener(Listener l) { 1931 if (l != null) { 1932 mListeners.remove(l); 1933 } 1934 return this; 1935 } 1936 1937 /** 1938 * @return The {@link DisconnectCause} for this connection. 1939 */ getDisconnectCause()1940 public final DisconnectCause getDisconnectCause() { 1941 return mDisconnectCause; 1942 } 1943 1944 /** 1945 * Sets the telecom call ID associated with this Connection. The Telecom Call ID should be used 1946 * ONLY for debugging purposes. 1947 * 1948 * @param callId The telecom call ID. 1949 * @hide 1950 */ setTelecomCallId(String callId)1951 public void setTelecomCallId(String callId) { 1952 mTelecomCallId = callId; 1953 } 1954 1955 /** 1956 * Inform this Connection that the state of its audio output has been changed externally. 1957 * 1958 * @param state The new audio state. 1959 * @hide 1960 */ setCallAudioState(CallAudioState state)1961 final void setCallAudioState(CallAudioState state) { 1962 checkImmutable(); 1963 Log.d(this, "setAudioState %s", state); 1964 mCallAudioState = state; 1965 onAudioStateChanged(getAudioState()); 1966 onCallAudioStateChanged(state); 1967 } 1968 1969 /** 1970 * @param state An integer value of a {@code STATE_*} constant. 1971 * @return A string representation of the value. 1972 */ stateToString(int state)1973 public static String stateToString(int state) { 1974 switch (state) { 1975 case STATE_INITIALIZING: 1976 return "INITIALIZING"; 1977 case STATE_NEW: 1978 return "NEW"; 1979 case STATE_RINGING: 1980 return "RINGING"; 1981 case STATE_DIALING: 1982 return "DIALING"; 1983 case STATE_PULLING_CALL: 1984 return "PULLING_CALL"; 1985 case STATE_ACTIVE: 1986 return "ACTIVE"; 1987 case STATE_HOLDING: 1988 return "HOLDING"; 1989 case STATE_DISCONNECTED: 1990 return "DISCONNECTED"; 1991 default: 1992 Log.wtf(Connection.class, "Unknown state %d", state); 1993 return "UNKNOWN"; 1994 } 1995 } 1996 1997 /** 1998 * Returns the connection's capabilities, as a bit mask of the {@code CAPABILITY_*} constants. 1999 */ getConnectionCapabilities()2000 public final int getConnectionCapabilities() { 2001 return mConnectionCapabilities; 2002 } 2003 2004 /** 2005 * Returns the connection's properties, as a bit mask of the {@code PROPERTY_*} constants. 2006 */ getConnectionProperties()2007 public final int getConnectionProperties() { 2008 return mConnectionProperties; 2009 } 2010 2011 /** 2012 * Returns the connection's supported audio routes. 2013 * 2014 * @hide 2015 */ getSupportedAudioRoutes()2016 public final int getSupportedAudioRoutes() { 2017 return mSupportedAudioRoutes; 2018 } 2019 2020 /** 2021 * Sets the value of the {@link #getAddress()} property. 2022 * 2023 * @param address The new address. 2024 * @param presentation The presentation requirements for the address. 2025 * See {@link TelecomManager} for valid values. 2026 */ setAddress(Uri address, int presentation)2027 public final void setAddress(Uri address, int presentation) { 2028 checkImmutable(); 2029 Log.d(this, "setAddress %s", address); 2030 mAddress = address; 2031 mAddressPresentation = presentation; 2032 for (Listener l : mListeners) { 2033 l.onAddressChanged(this, address, presentation); 2034 } 2035 } 2036 2037 /** 2038 * Sets the caller display name (CNAP). 2039 * 2040 * @param callerDisplayName The new display name. 2041 * @param presentation The presentation requirements for the handle. 2042 * See {@link TelecomManager} for valid values. 2043 */ setCallerDisplayName(String callerDisplayName, int presentation)2044 public final void setCallerDisplayName(String callerDisplayName, int presentation) { 2045 checkImmutable(); 2046 Log.d(this, "setCallerDisplayName %s", callerDisplayName); 2047 mCallerDisplayName = callerDisplayName; 2048 mCallerDisplayNamePresentation = presentation; 2049 for (Listener l : mListeners) { 2050 l.onCallerDisplayNameChanged(this, callerDisplayName, presentation); 2051 } 2052 } 2053 2054 /** 2055 * Set the video state for the connection. 2056 * Valid values: {@link VideoProfile#STATE_AUDIO_ONLY}, 2057 * {@link VideoProfile#STATE_BIDIRECTIONAL}, 2058 * {@link VideoProfile#STATE_TX_ENABLED}, 2059 * {@link VideoProfile#STATE_RX_ENABLED}. 2060 * 2061 * @param videoState The new video state. 2062 */ setVideoState(int videoState)2063 public final void setVideoState(int videoState) { 2064 checkImmutable(); 2065 Log.d(this, "setVideoState %d", videoState); 2066 mVideoState = videoState; 2067 for (Listener l : mListeners) { 2068 l.onVideoStateChanged(this, mVideoState); 2069 } 2070 } 2071 2072 /** 2073 * Sets state to active (e.g., an ongoing connection where two or more parties can actively 2074 * communicate). 2075 */ setActive()2076 public final void setActive() { 2077 checkImmutable(); 2078 setRingbackRequested(false); 2079 setState(STATE_ACTIVE); 2080 } 2081 2082 /** 2083 * Sets state to ringing (e.g., an inbound ringing connection). 2084 */ setRinging()2085 public final void setRinging() { 2086 checkImmutable(); 2087 setState(STATE_RINGING); 2088 } 2089 2090 /** 2091 * Sets state to initializing (this Connection is not yet ready to be used). 2092 */ setInitializing()2093 public final void setInitializing() { 2094 checkImmutable(); 2095 setState(STATE_INITIALIZING); 2096 } 2097 2098 /** 2099 * Sets state to initialized (the Connection has been set up and is now ready to be used). 2100 */ setInitialized()2101 public final void setInitialized() { 2102 checkImmutable(); 2103 setState(STATE_NEW); 2104 } 2105 2106 /** 2107 * Sets state to dialing (e.g., dialing an outbound connection). 2108 */ setDialing()2109 public final void setDialing() { 2110 checkImmutable(); 2111 setState(STATE_DIALING); 2112 } 2113 2114 /** 2115 * Sets state to pulling (e.g. the connection is being pulled to the local device from another 2116 * device). Only applicable for {@link Connection}s with 2117 * {@link Connection#PROPERTY_IS_EXTERNAL_CALL} and {@link Connection#CAPABILITY_CAN_PULL_CALL}. 2118 */ setPulling()2119 public final void setPulling() { 2120 checkImmutable(); 2121 setState(STATE_PULLING_CALL); 2122 } 2123 2124 /** 2125 * Sets state to be on hold. 2126 */ setOnHold()2127 public final void setOnHold() { 2128 checkImmutable(); 2129 setState(STATE_HOLDING); 2130 } 2131 2132 /** 2133 * Sets the video connection provider. 2134 * @param videoProvider The video provider. 2135 */ setVideoProvider(VideoProvider videoProvider)2136 public final void setVideoProvider(VideoProvider videoProvider) { 2137 checkImmutable(); 2138 mVideoProvider = videoProvider; 2139 for (Listener l : mListeners) { 2140 l.onVideoProviderChanged(this, videoProvider); 2141 } 2142 } 2143 getVideoProvider()2144 public final VideoProvider getVideoProvider() { 2145 return mVideoProvider; 2146 } 2147 2148 /** 2149 * Sets state to disconnected. 2150 * 2151 * @param disconnectCause The reason for the disconnection, as specified by 2152 * {@link DisconnectCause}. 2153 */ setDisconnected(DisconnectCause disconnectCause)2154 public final void setDisconnected(DisconnectCause disconnectCause) { 2155 checkImmutable(); 2156 mDisconnectCause = disconnectCause; 2157 setState(STATE_DISCONNECTED); 2158 Log.d(this, "Disconnected with cause %s", disconnectCause); 2159 for (Listener l : mListeners) { 2160 l.onDisconnected(this, disconnectCause); 2161 } 2162 } 2163 2164 /** 2165 * Informs listeners that this {@code Connection} is in a post-dial wait state. This is done 2166 * when (a) the {@code Connection} is issuing a DTMF sequence; (b) it has encountered a "wait" 2167 * character; and (c) it wishes to inform the In-Call app that it is waiting for the end-user 2168 * to send an {@link #onPostDialContinue(boolean)} signal. 2169 * 2170 * @param remaining The DTMF character sequence remaining to be emitted once the 2171 * {@link #onPostDialContinue(boolean)} is received, including any "wait" characters 2172 * that remaining sequence may contain. 2173 */ setPostDialWait(String remaining)2174 public final void setPostDialWait(String remaining) { 2175 checkImmutable(); 2176 for (Listener l : mListeners) { 2177 l.onPostDialWait(this, remaining); 2178 } 2179 } 2180 2181 /** 2182 * Informs listeners that this {@code Connection} has processed a character in the post-dial 2183 * started state. This is done when (a) the {@code Connection} is issuing a DTMF sequence; 2184 * and (b) it wishes to signal Telecom to play the corresponding DTMF tone locally. 2185 * 2186 * @param nextChar The DTMF character that was just processed by the {@code Connection}. 2187 */ setNextPostDialChar(char nextChar)2188 public final void setNextPostDialChar(char nextChar) { 2189 checkImmutable(); 2190 for (Listener l : mListeners) { 2191 l.onPostDialChar(this, nextChar); 2192 } 2193 } 2194 2195 /** 2196 * Requests that the framework play a ringback tone. This is to be invoked by implementations 2197 * that do not play a ringback tone themselves in the connection's audio stream. 2198 * 2199 * @param ringback Whether the ringback tone is to be played. 2200 */ setRingbackRequested(boolean ringback)2201 public final void setRingbackRequested(boolean ringback) { 2202 checkImmutable(); 2203 if (mRingbackRequested != ringback) { 2204 mRingbackRequested = ringback; 2205 for (Listener l : mListeners) { 2206 l.onRingbackRequested(this, ringback); 2207 } 2208 } 2209 } 2210 2211 /** 2212 * Sets the connection's capabilities as a bit mask of the {@code CAPABILITY_*} constants. 2213 * 2214 * @param connectionCapabilities The new connection capabilities. 2215 */ setConnectionCapabilities(int connectionCapabilities)2216 public final void setConnectionCapabilities(int connectionCapabilities) { 2217 checkImmutable(); 2218 if (mConnectionCapabilities != connectionCapabilities) { 2219 mConnectionCapabilities = connectionCapabilities; 2220 for (Listener l : mListeners) { 2221 l.onConnectionCapabilitiesChanged(this, mConnectionCapabilities); 2222 } 2223 } 2224 } 2225 2226 /** 2227 * Sets the connection's properties as a bit mask of the {@code PROPERTY_*} constants. 2228 * 2229 * @param connectionProperties The new connection properties. 2230 */ setConnectionProperties(int connectionProperties)2231 public final void setConnectionProperties(int connectionProperties) { 2232 checkImmutable(); 2233 if (mConnectionProperties != connectionProperties) { 2234 mConnectionProperties = connectionProperties; 2235 for (Listener l : mListeners) { 2236 l.onConnectionPropertiesChanged(this, mConnectionProperties); 2237 } 2238 } 2239 } 2240 2241 /** 2242 * Sets the supported audio routes. 2243 * 2244 * @param supportedAudioRoutes the supported audio routes as a bitmask. 2245 * See {@link CallAudioState} 2246 * @hide 2247 */ setSupportedAudioRoutes(int supportedAudioRoutes)2248 public final void setSupportedAudioRoutes(int supportedAudioRoutes) { 2249 if ((supportedAudioRoutes 2250 & (CallAudioState.ROUTE_EARPIECE | CallAudioState.ROUTE_SPEAKER)) == 0) { 2251 throw new IllegalArgumentException( 2252 "supported audio routes must include either speaker or earpiece"); 2253 } 2254 2255 if (mSupportedAudioRoutes != supportedAudioRoutes) { 2256 mSupportedAudioRoutes = supportedAudioRoutes; 2257 for (Listener l : mListeners) { 2258 l.onSupportedAudioRoutesChanged(this, mSupportedAudioRoutes); 2259 } 2260 } 2261 } 2262 2263 /** 2264 * Tears down the Connection object. 2265 */ destroy()2266 public final void destroy() { 2267 for (Listener l : mListeners) { 2268 l.onDestroyed(this); 2269 } 2270 } 2271 2272 /** 2273 * Requests that the framework use VOIP audio mode for this connection. 2274 * 2275 * @param isVoip True if the audio mode is VOIP. 2276 */ setAudioModeIsVoip(boolean isVoip)2277 public final void setAudioModeIsVoip(boolean isVoip) { 2278 checkImmutable(); 2279 mAudioModeIsVoip = isVoip; 2280 for (Listener l : mListeners) { 2281 l.onAudioModeIsVoipChanged(this, isVoip); 2282 } 2283 } 2284 2285 /** 2286 * Sets the time at which a call became active on this Connection. This is set only 2287 * when a conference call becomes active on this connection. 2288 * 2289 * @param connectTimeMillis The connection time, in milliseconds. Should be set using a value 2290 * obtained from {@link System#currentTimeMillis()}. 2291 * 2292 * @hide 2293 */ setConnectTimeMillis(long connectTimeMillis)2294 public final void setConnectTimeMillis(long connectTimeMillis) { 2295 mConnectTimeMillis = connectTimeMillis; 2296 } 2297 2298 /** 2299 * Sets the time at which a call became active on this Connection. This is set only 2300 * when a conference call becomes active on this connection. 2301 * 2302 * @param connectElapsedTimeMillis The connection time, in milliseconds. Stored in the format 2303 * {@link SystemClock#elapsedRealtime()}. 2304 * 2305 * @hide 2306 */ setConnectionStartElapsedRealTime(long connectElapsedTimeMillis)2307 public final void setConnectionStartElapsedRealTime(long connectElapsedTimeMillis) { 2308 mConnectElapsedTimeMillis = connectElapsedTimeMillis; 2309 } 2310 2311 /** 2312 * Sets the label and icon status to display in the in-call UI. 2313 * 2314 * @param statusHints The status label and icon to set. 2315 */ setStatusHints(StatusHints statusHints)2316 public final void setStatusHints(StatusHints statusHints) { 2317 checkImmutable(); 2318 mStatusHints = statusHints; 2319 for (Listener l : mListeners) { 2320 l.onStatusHintsChanged(this, statusHints); 2321 } 2322 } 2323 2324 /** 2325 * Sets the connections with which this connection can be conferenced. 2326 * 2327 * @param conferenceableConnections The set of connections this connection can conference with. 2328 */ setConferenceableConnections(List<Connection> conferenceableConnections)2329 public final void setConferenceableConnections(List<Connection> conferenceableConnections) { 2330 checkImmutable(); 2331 clearConferenceableList(); 2332 for (Connection c : conferenceableConnections) { 2333 // If statement checks for duplicates in input. It makes it N^2 but we're dealing with a 2334 // small amount of items here. 2335 if (!mConferenceables.contains(c)) { 2336 c.addConnectionListener(mConnectionDeathListener); 2337 mConferenceables.add(c); 2338 } 2339 } 2340 fireOnConferenceableConnectionsChanged(); 2341 } 2342 2343 /** 2344 * Similar to {@link #setConferenceableConnections(java.util.List)}, sets a list of connections 2345 * or conferences with which this connection can be conferenced. 2346 * 2347 * @param conferenceables The conferenceables. 2348 */ setConferenceables(List<Conferenceable> conferenceables)2349 public final void setConferenceables(List<Conferenceable> conferenceables) { 2350 clearConferenceableList(); 2351 for (Conferenceable c : conferenceables) { 2352 // If statement checks for duplicates in input. It makes it N^2 but we're dealing with a 2353 // small amount of items here. 2354 if (!mConferenceables.contains(c)) { 2355 if (c instanceof Connection) { 2356 Connection connection = (Connection) c; 2357 connection.addConnectionListener(mConnectionDeathListener); 2358 } else if (c instanceof Conference) { 2359 Conference conference = (Conference) c; 2360 conference.addListener(mConferenceDeathListener); 2361 } 2362 mConferenceables.add(c); 2363 } 2364 } 2365 fireOnConferenceableConnectionsChanged(); 2366 } 2367 2368 /** 2369 * Returns the connections or conferences with which this connection can be conferenced. 2370 */ getConferenceables()2371 public final List<Conferenceable> getConferenceables() { 2372 return mUnmodifiableConferenceables; 2373 } 2374 2375 /** 2376 * @hide 2377 */ setConnectionService(ConnectionService connectionService)2378 public final void setConnectionService(ConnectionService connectionService) { 2379 checkImmutable(); 2380 if (mConnectionService != null) { 2381 Log.e(this, new Exception(), "Trying to set ConnectionService on a connection " + 2382 "which is already associated with another ConnectionService."); 2383 } else { 2384 mConnectionService = connectionService; 2385 } 2386 } 2387 2388 /** 2389 * @hide 2390 */ unsetConnectionService(ConnectionService connectionService)2391 public final void unsetConnectionService(ConnectionService connectionService) { 2392 if (mConnectionService != connectionService) { 2393 Log.e(this, new Exception(), "Trying to remove ConnectionService from a Connection " + 2394 "that does not belong to the ConnectionService."); 2395 } else { 2396 mConnectionService = null; 2397 } 2398 } 2399 2400 /** 2401 * @hide 2402 */ getConnectionService()2403 public final ConnectionService getConnectionService() { 2404 return mConnectionService; 2405 } 2406 2407 /** 2408 * Sets the conference that this connection is a part of. This will fail if the connection is 2409 * already part of a conference. {@link #resetConference} to un-set the conference first. 2410 * 2411 * @param conference The conference. 2412 * @return {@code true} if the conference was successfully set. 2413 * @hide 2414 */ setConference(Conference conference)2415 public final boolean setConference(Conference conference) { 2416 checkImmutable(); 2417 // We check to see if it is already part of another conference. 2418 if (mConference == null) { 2419 mConference = conference; 2420 if (mConnectionService != null && mConnectionService.containsConference(conference)) { 2421 fireConferenceChanged(); 2422 } 2423 return true; 2424 } 2425 return false; 2426 } 2427 2428 /** 2429 * Resets the conference that this connection is a part of. 2430 * @hide 2431 */ resetConference()2432 public final void resetConference() { 2433 if (mConference != null) { 2434 Log.d(this, "Conference reset"); 2435 mConference = null; 2436 fireConferenceChanged(); 2437 } 2438 } 2439 2440 /** 2441 * Set some extras that can be associated with this {@code Connection}. 2442 * <p> 2443 * New or existing keys are replaced in the {@code Connection} extras. Keys which are no longer 2444 * in the new extras, but were present the last time {@code setExtras} was called are removed. 2445 * <p> 2446 * Alternatively you may use the {@link #putExtras(Bundle)}, and 2447 * {@link #removeExtras(String...)} methods to modify the extras. 2448 * <p> 2449 * No assumptions should be made as to how an In-Call UI or service will handle these extras. 2450 * Keys should be fully qualified (e.g., com.example.MY_EXTRA) to avoid conflicts. 2451 * 2452 * @param extras The extras associated with this {@code Connection}. 2453 */ setExtras(@ullable Bundle extras)2454 public final void setExtras(@Nullable Bundle extras) { 2455 checkImmutable(); 2456 2457 // Add/replace any new or changed extras values. 2458 putExtras(extras); 2459 2460 // If we have used "setExtras" in the past, compare the key set from the last invocation to 2461 // the current one and remove any keys that went away. 2462 if (mPreviousExtraKeys != null) { 2463 List<String> toRemove = new ArrayList<String>(); 2464 for (String oldKey : mPreviousExtraKeys) { 2465 if (extras == null || !extras.containsKey(oldKey)) { 2466 toRemove.add(oldKey); 2467 } 2468 } 2469 if (!toRemove.isEmpty()) { 2470 removeExtras(toRemove); 2471 } 2472 } 2473 2474 // Track the keys the last time set called setExtras. This way, the next time setExtras is 2475 // called we can see if the caller has removed any extras values. 2476 if (mPreviousExtraKeys == null) { 2477 mPreviousExtraKeys = new ArraySet<String>(); 2478 } 2479 mPreviousExtraKeys.clear(); 2480 if (extras != null) { 2481 mPreviousExtraKeys.addAll(extras.keySet()); 2482 } 2483 } 2484 2485 /** 2486 * Adds some extras to this {@code Connection}. Existing keys are replaced and new ones are 2487 * added. 2488 * <p> 2489 * No assumptions should be made as to how an In-Call UI or service will handle these extras. 2490 * Keys should be fully qualified (e.g., com.example.MY_EXTRA) to avoid conflicts. 2491 * 2492 * @param extras The extras to add. 2493 */ putExtras(@onNull Bundle extras)2494 public final void putExtras(@NonNull Bundle extras) { 2495 checkImmutable(); 2496 if (extras == null) { 2497 return; 2498 } 2499 // Creating a duplicate bundle so we don't have to synchronize on mExtrasLock while calling 2500 // the listeners. 2501 Bundle listenerExtras; 2502 synchronized (mExtrasLock) { 2503 if (mExtras == null) { 2504 mExtras = new Bundle(); 2505 } 2506 mExtras.putAll(extras); 2507 listenerExtras = new Bundle(mExtras); 2508 } 2509 for (Listener l : mListeners) { 2510 // Create a new clone of the extras for each listener so that they don't clobber 2511 // each other 2512 l.onExtrasChanged(this, new Bundle(listenerExtras)); 2513 } 2514 } 2515 2516 /** 2517 * Adds a boolean extra to this {@code Connection}. 2518 * 2519 * @param key The extra key. 2520 * @param value The value. 2521 * @hide 2522 */ putExtra(String key, boolean value)2523 public final void putExtra(String key, boolean value) { 2524 Bundle newExtras = new Bundle(); 2525 newExtras.putBoolean(key, value); 2526 putExtras(newExtras); 2527 } 2528 2529 /** 2530 * Adds an integer extra to this {@code Connection}. 2531 * 2532 * @param key The extra key. 2533 * @param value The value. 2534 * @hide 2535 */ putExtra(String key, int value)2536 public final void putExtra(String key, int value) { 2537 Bundle newExtras = new Bundle(); 2538 newExtras.putInt(key, value); 2539 putExtras(newExtras); 2540 } 2541 2542 /** 2543 * Adds a string extra to this {@code Connection}. 2544 * 2545 * @param key The extra key. 2546 * @param value The value. 2547 * @hide 2548 */ putExtra(String key, String value)2549 public final void putExtra(String key, String value) { 2550 Bundle newExtras = new Bundle(); 2551 newExtras.putString(key, value); 2552 putExtras(newExtras); 2553 } 2554 2555 /** 2556 * Removes extras from this {@code Connection}. 2557 * 2558 * @param keys The keys of the extras to remove. 2559 */ removeExtras(List<String> keys)2560 public final void removeExtras(List<String> keys) { 2561 synchronized (mExtrasLock) { 2562 if (mExtras != null) { 2563 for (String key : keys) { 2564 mExtras.remove(key); 2565 } 2566 } 2567 } 2568 List<String> unmodifiableKeys = Collections.unmodifiableList(keys); 2569 for (Listener l : mListeners) { 2570 l.onExtrasRemoved(this, unmodifiableKeys); 2571 } 2572 } 2573 2574 /** 2575 * Removes extras from this {@code Connection}. 2576 * 2577 * @param keys The keys of the extras to remove. 2578 */ removeExtras(String .... keys)2579 public final void removeExtras(String ... keys) { 2580 removeExtras(Arrays.asList(keys)); 2581 } 2582 2583 /** 2584 * Sets the audio route (speaker, bluetooth, etc...). When this request is honored, there will 2585 * be change to the {@link #getCallAudioState()}. 2586 * <p> 2587 * Used by self-managed {@link ConnectionService}s which wish to change the audio route for a 2588 * self-managed {@link Connection} (see {@link PhoneAccount#CAPABILITY_SELF_MANAGED}.) 2589 * <p> 2590 * See also {@link InCallService#setAudioRoute(int)}. 2591 * 2592 * @param route The audio route to use (one of {@link CallAudioState#ROUTE_BLUETOOTH}, 2593 * {@link CallAudioState#ROUTE_EARPIECE}, {@link CallAudioState#ROUTE_SPEAKER}, or 2594 * {@link CallAudioState#ROUTE_WIRED_HEADSET}). 2595 */ setAudioRoute(int route)2596 public final void setAudioRoute(int route) { 2597 for (Listener l : mListeners) { 2598 l.onAudioRouteChanged(this, route, null); 2599 } 2600 } 2601 2602 /** 2603 * Request audio routing to a specific bluetooth device. Calling this method may result in 2604 * the device routing audio to a different bluetooth device than the one specified if the 2605 * bluetooth stack is unable to route audio to the requested device. 2606 * A list of available devices can be obtained via 2607 * {@link CallAudioState#getSupportedBluetoothDevices()} 2608 * 2609 * <p> 2610 * Used by self-managed {@link ConnectionService}s which wish to use bluetooth audio for a 2611 * self-managed {@link Connection} (see {@link PhoneAccount#CAPABILITY_SELF_MANAGED}.) 2612 * <p> 2613 * See also {@link InCallService#requestBluetoothAudio(BluetoothDevice)} 2614 * @param bluetoothDevice The bluetooth device to connect to. 2615 */ requestBluetoothAudio(@onNull BluetoothDevice bluetoothDevice)2616 public void requestBluetoothAudio(@NonNull BluetoothDevice bluetoothDevice) { 2617 for (Listener l : mListeners) { 2618 l.onAudioRouteChanged(this, CallAudioState.ROUTE_BLUETOOTH, 2619 bluetoothDevice.getAddress()); 2620 } 2621 } 2622 2623 /** 2624 * Informs listeners that a previously requested RTT session via 2625 * {@link ConnectionRequest#isRequestingRtt()} or 2626 * {@link #onStartRtt(RttTextStream)} has succeeded. 2627 */ sendRttInitiationSuccess()2628 public final void sendRttInitiationSuccess() { 2629 mListeners.forEach((l) -> l.onRttInitiationSuccess(Connection.this)); 2630 } 2631 2632 /** 2633 * Informs listeners that a previously requested RTT session via 2634 * {@link ConnectionRequest#isRequestingRtt()} or {@link #onStartRtt(RttTextStream)} 2635 * has failed. 2636 * @param reason One of the reason codes defined in {@link RttModifyStatus}, with the 2637 * exception of {@link RttModifyStatus#SESSION_MODIFY_REQUEST_SUCCESS}. 2638 */ sendRttInitiationFailure(int reason)2639 public final void sendRttInitiationFailure(int reason) { 2640 mListeners.forEach((l) -> l.onRttInitiationFailure(Connection.this, reason)); 2641 } 2642 2643 /** 2644 * Informs listeners that a currently active RTT session has been terminated by the remote 2645 * side of the coll. 2646 */ sendRttSessionRemotelyTerminated()2647 public final void sendRttSessionRemotelyTerminated() { 2648 mListeners.forEach((l) -> l.onRttSessionRemotelyTerminated(Connection.this)); 2649 } 2650 2651 /** 2652 * Informs listeners that the remote side of the call has requested an upgrade to include an 2653 * RTT session in the call. 2654 */ sendRemoteRttRequest()2655 public final void sendRemoteRttRequest() { 2656 mListeners.forEach((l) -> l.onRemoteRttRequest(Connection.this)); 2657 } 2658 2659 /** 2660 * Notifies this Connection that the {@link #getAudioState()} property has a new value. 2661 * 2662 * @param state The new connection audio state. 2663 * @deprecated Use {@link #onCallAudioStateChanged(CallAudioState)} instead. 2664 * @hide 2665 */ 2666 @SystemApi 2667 @Deprecated onAudioStateChanged(AudioState state)2668 public void onAudioStateChanged(AudioState state) {} 2669 2670 /** 2671 * Notifies this Connection that the {@link #getCallAudioState()} property has a new value. 2672 * 2673 * @param state The new connection audio state. 2674 */ onCallAudioStateChanged(CallAudioState state)2675 public void onCallAudioStateChanged(CallAudioState state) {} 2676 2677 /** 2678 * Notifies this Connection of an internal state change. This method is called after the 2679 * state is changed. 2680 * 2681 * @param state The new state, one of the {@code STATE_*} constants. 2682 */ onStateChanged(int state)2683 public void onStateChanged(int state) {} 2684 2685 /** 2686 * Notifies this Connection of a request to play a DTMF tone. 2687 * 2688 * @param c A DTMF character. 2689 */ onPlayDtmfTone(char c)2690 public void onPlayDtmfTone(char c) {} 2691 2692 /** 2693 * Notifies this Connection of a request to stop any currently playing DTMF tones. 2694 */ onStopDtmfTone()2695 public void onStopDtmfTone() {} 2696 2697 /** 2698 * Notifies this Connection of a request to disconnect. 2699 */ onDisconnect()2700 public void onDisconnect() {} 2701 2702 /** 2703 * Notifies this Connection of a request to disconnect a participant of the conference managed 2704 * by the connection. 2705 * 2706 * @param endpoint the {@link Uri} of the participant to disconnect. 2707 * @hide 2708 */ onDisconnectConferenceParticipant(Uri endpoint)2709 public void onDisconnectConferenceParticipant(Uri endpoint) {} 2710 2711 /** 2712 * Notifies this Connection of a request to separate from its parent conference. 2713 */ onSeparate()2714 public void onSeparate() {} 2715 2716 /** 2717 * Notifies this Connection of a request to abort. 2718 */ onAbort()2719 public void onAbort() {} 2720 2721 /** 2722 * Notifies this Connection of a request to hold. 2723 */ onHold()2724 public void onHold() {} 2725 2726 /** 2727 * Notifies this Connection of a request to exit a hold state. 2728 */ onUnhold()2729 public void onUnhold() {} 2730 2731 /** 2732 * Notifies this Connection, which is in {@link #STATE_RINGING}, of 2733 * a request to accept. 2734 * <p> 2735 * For managed {@link ConnectionService}s, this will be called when the user answers a call via 2736 * the default dialer's {@link InCallService}. 2737 * <p> 2738 * Although a self-managed {@link ConnectionService} provides its own incoming call UI, the 2739 * Telecom framework may request that the call is answered in the following circumstances: 2740 * <ul> 2741 * <li>The user chooses to answer an incoming call via a Bluetooth device.</li> 2742 * <li>A car mode {@link InCallService} is in use which has declared 2743 * {@link TelecomManager#METADATA_INCLUDE_SELF_MANAGED_CALLS} in its manifest. Such an 2744 * {@link InCallService} will be able to see calls from self-managed 2745 * {@link ConnectionService}s, and will be able to display an incoming call UI on their 2746 * behalf.</li> 2747 * </ul> 2748 * @param videoState The video state in which to answer the connection. 2749 */ onAnswer(int videoState)2750 public void onAnswer(int videoState) {} 2751 2752 /** 2753 * Notifies this Connection, which is in {@link #STATE_RINGING}, of 2754 * a request to accept. 2755 * <p> 2756 * For managed {@link ConnectionService}s, this will be called when the user answers a call via 2757 * the default dialer's {@link InCallService}. 2758 * <p> 2759 * Although a self-managed {@link ConnectionService} provides its own incoming call UI, the 2760 * Telecom framework may request that the call is answered in the following circumstances: 2761 * <ul> 2762 * <li>The user chooses to answer an incoming call via a Bluetooth device.</li> 2763 * <li>A car mode {@link InCallService} is in use which has declared 2764 * {@link TelecomManager#METADATA_INCLUDE_SELF_MANAGED_CALLS} in its manifest. Such an 2765 * {@link InCallService} will be able to see calls from self-managed 2766 * {@link ConnectionService}s, and will be able to display an incoming call UI on their 2767 * behalf.</li> 2768 * </ul> 2769 */ onAnswer()2770 public void onAnswer() { 2771 onAnswer(VideoProfile.STATE_AUDIO_ONLY); 2772 } 2773 2774 /** 2775 * Notifies this Connection, which is in {@link #STATE_RINGING}, of 2776 * a request to deflect. 2777 */ onDeflect(Uri address)2778 public void onDeflect(Uri address) {} 2779 2780 /** 2781 * Notifies this Connection, which is in {@link #STATE_RINGING}, of 2782 * a request to reject. 2783 * <p> 2784 * For managed {@link ConnectionService}s, this will be called when the user rejects a call via 2785 * the default dialer's {@link InCallService}. 2786 * <p> 2787 * Although a self-managed {@link ConnectionService} provides its own incoming call UI, the 2788 * Telecom framework may request that the call is rejected in the following circumstances: 2789 * <ul> 2790 * <li>The user chooses to reject an incoming call via a Bluetooth device.</li> 2791 * <li>A car mode {@link InCallService} is in use which has declared 2792 * {@link TelecomManager#METADATA_INCLUDE_SELF_MANAGED_CALLS} in its manifest. Such an 2793 * {@link InCallService} will be able to see calls from self-managed 2794 * {@link ConnectionService}s, and will be able to display an incoming call UI on their 2795 * behalf.</li> 2796 * </ul> 2797 */ onReject()2798 public void onReject() {} 2799 2800 /** 2801 * Notifies this Connection, which is in {@link #STATE_RINGING}, of 2802 * a request to reject with a message. 2803 */ onReject(String replyMessage)2804 public void onReject(String replyMessage) {} 2805 2806 /** 2807 * Notifies the Connection of a request to silence the ringer. 2808 * 2809 * @hide 2810 */ onSilence()2811 public void onSilence() {} 2812 2813 /** 2814 * Notifies this Connection whether the user wishes to proceed with the post-dial DTMF codes. 2815 */ onPostDialContinue(boolean proceed)2816 public void onPostDialContinue(boolean proceed) {} 2817 2818 /** 2819 * Notifies this Connection of a request to pull an external call to the local device. 2820 * <p> 2821 * The {@link InCallService} issues a request to pull an external call to the local device via 2822 * {@link Call#pullExternalCall()}. 2823 * <p> 2824 * For a Connection to be pulled, both the {@link Connection#CAPABILITY_CAN_PULL_CALL} 2825 * capability and {@link Connection#PROPERTY_IS_EXTERNAL_CALL} property bits must be set. 2826 * <p> 2827 * For more information on external calls, see {@link Connection#PROPERTY_IS_EXTERNAL_CALL}. 2828 */ onPullExternalCall()2829 public void onPullExternalCall() {} 2830 2831 /** 2832 * Notifies this Connection of a {@link Call} event initiated from an {@link InCallService}. 2833 * <p> 2834 * The {@link InCallService} issues a Call event via {@link Call#sendCallEvent(String, Bundle)}. 2835 * <p> 2836 * Where possible, the Connection should make an attempt to handle {@link Call} events which 2837 * are part of the {@code android.telecom.*} namespace. The Connection should ignore any events 2838 * it does not wish to handle. Unexpected events should be handled gracefully, as it is 2839 * possible that a {@link InCallService} has defined its own Call events which a Connection is 2840 * not aware of. 2841 * <p> 2842 * See also {@link Call#sendCallEvent(String, Bundle)}. 2843 * 2844 * @param event The call event. 2845 * @param extras Extras associated with the call event. 2846 */ onCallEvent(String event, Bundle extras)2847 public void onCallEvent(String event, Bundle extras) {} 2848 2849 /** 2850 * Notifies this {@link Connection} that a handover has completed. 2851 * <p> 2852 * A handover is initiated with {@link android.telecom.Call#handoverTo(PhoneAccountHandle, int, 2853 * Bundle)} on the initiating side of the handover, and 2854 * {@link TelecomManager#acceptHandover(Uri, int, PhoneAccountHandle)}. 2855 */ onHandoverComplete()2856 public void onHandoverComplete() {} 2857 2858 /** 2859 * Notifies this {@link Connection} of a change to the extras made outside the 2860 * {@link ConnectionService}. 2861 * <p> 2862 * These extras changes can originate from Telecom itself, or from an {@link InCallService} via 2863 * the {@link android.telecom.Call#putExtras(Bundle)} and 2864 * {@link Call#removeExtras(List)}. 2865 * 2866 * @param extras The new extras bundle. 2867 */ onExtrasChanged(Bundle extras)2868 public void onExtrasChanged(Bundle extras) {} 2869 2870 /** 2871 * Notifies this {@link Connection} that its {@link ConnectionService} is responsible for 2872 * displaying its incoming call user interface for the {@link Connection}. 2873 * <p> 2874 * Will only be called for incoming calls added via a self-managed {@link ConnectionService} 2875 * (see {@link PhoneAccount#CAPABILITY_SELF_MANAGED}), where the {@link ConnectionService} 2876 * should show its own incoming call user interface. 2877 * <p> 2878 * Where there are ongoing calls in other self-managed {@link ConnectionService}s, or in a 2879 * regular {@link ConnectionService}, and it is not possible to hold these other calls, the 2880 * Telecom framework will display its own incoming call user interface to allow the user to 2881 * choose whether to answer the new incoming call and disconnect other ongoing calls, or to 2882 * reject the new incoming call. 2883 * <p> 2884 * You should trigger the display of the incoming call user interface for your application by 2885 * showing a {@link Notification} with a full-screen {@link Intent} specified. 2886 * For example: 2887 * <pre><code> 2888 * // Create an intent which triggers your fullscreen incoming call user interface. 2889 * Intent intent = new Intent(Intent.ACTION_MAIN, null); 2890 * intent.setFlags(Intent.FLAG_ACTIVITY_NO_USER_ACTION | Intent.FLAG_ACTIVITY_NEW_TASK); 2891 * intent.setClass(context, YourIncomingCallActivity.class); 2892 * PendingIntent pendingIntent = PendingIntent.getActivity(context, 1, intent, 0); 2893 * 2894 * // Build the notification as an ongoing high priority item; this ensures it will show as 2895 * // a heads up notification which slides down over top of the current content. 2896 * final Notification.Builder builder = new Notification.Builder(context); 2897 * builder.setOngoing(true); 2898 * builder.setPriority(Notification.PRIORITY_HIGH); 2899 * 2900 * // Set notification content intent to take user to fullscreen UI if user taps on the 2901 * // notification body. 2902 * builder.setContentIntent(pendingIntent); 2903 * // Set full screen intent to trigger display of the fullscreen UI when the notification 2904 * // manager deems it appropriate. 2905 * builder.setFullScreenIntent(pendingIntent, true); 2906 * 2907 * // Setup notification content. 2908 * builder.setSmallIcon( yourIconResourceId ); 2909 * builder.setContentTitle("Your notification title"); 2910 * builder.setContentText("Your notification content."); 2911 * 2912 * // Use builder.addAction(..) to add buttons to answer or reject the call. 2913 * 2914 * NotificationManager notificationManager = mContext.getSystemService( 2915 * NotificationManager.class); 2916 * notificationManager.notify(YOUR_TAG, YOUR_ID, builder.build()); 2917 * </code></pre> 2918 */ onShowIncomingCallUi()2919 public void onShowIncomingCallUi() {} 2920 2921 /** 2922 * Notifies this {@link Connection} that the user has requested an RTT session. 2923 * The connection service should call {@link #sendRttInitiationSuccess} or 2924 * {@link #sendRttInitiationFailure} to inform Telecom of the success or failure of the 2925 * request, respectively. 2926 * @param rttTextStream The object that should be used to send text to or receive text from 2927 * the in-call app. 2928 */ onStartRtt(@onNull RttTextStream rttTextStream)2929 public void onStartRtt(@NonNull RttTextStream rttTextStream) {} 2930 2931 /** 2932 * Notifies this {@link Connection} that it should terminate any existing RTT communication 2933 * channel. No response to Telecom is needed for this method. 2934 */ onStopRtt()2935 public void onStopRtt() {} 2936 2937 /** 2938 * Notifies this connection of a response to a previous remotely-initiated RTT upgrade 2939 * request sent via {@link #sendRemoteRttRequest}. Acceptance of the request is 2940 * indicated by the supplied {@link RttTextStream} being non-null, and rejection is 2941 * indicated by {@code rttTextStream} being {@code null} 2942 * @param rttTextStream The object that should be used to send text to or receive text from 2943 * the in-call app. 2944 */ handleRttUpgradeResponse(@ullable RttTextStream rttTextStream)2945 public void handleRttUpgradeResponse(@Nullable RttTextStream rttTextStream) {} 2946 toLogSafePhoneNumber(String number)2947 static String toLogSafePhoneNumber(String number) { 2948 // For unknown number, log empty string. 2949 if (number == null) { 2950 return ""; 2951 } 2952 2953 if (PII_DEBUG) { 2954 // When PII_DEBUG is true we emit PII. 2955 return number; 2956 } 2957 2958 // Do exactly same thing as Uri#toSafeString() does, which will enable us to compare 2959 // sanitized phone numbers. 2960 StringBuilder builder = new StringBuilder(); 2961 for (int i = 0; i < number.length(); i++) { 2962 char c = number.charAt(i); 2963 if (c == '-' || c == '@' || c == '.') { 2964 builder.append(c); 2965 } else { 2966 builder.append('x'); 2967 } 2968 } 2969 return builder.toString(); 2970 } 2971 setState(int state)2972 private void setState(int state) { 2973 checkImmutable(); 2974 if (mState == STATE_DISCONNECTED && mState != state) { 2975 Log.d(this, "Connection already DISCONNECTED; cannot transition out of this state."); 2976 return; 2977 } 2978 if (mState != state) { 2979 Log.d(this, "setState: %s", stateToString(state)); 2980 mState = state; 2981 onStateChanged(state); 2982 for (Listener l : mListeners) { 2983 l.onStateChanged(this, state); 2984 } 2985 } 2986 } 2987 2988 private static class FailureSignalingConnection extends Connection { 2989 private boolean mImmutable = false; FailureSignalingConnection(DisconnectCause disconnectCause)2990 public FailureSignalingConnection(DisconnectCause disconnectCause) { 2991 setDisconnected(disconnectCause); 2992 mImmutable = true; 2993 } 2994 checkImmutable()2995 public void checkImmutable() { 2996 if (mImmutable) { 2997 throw new UnsupportedOperationException("Connection is immutable"); 2998 } 2999 } 3000 } 3001 3002 /** 3003 * Return a {@code Connection} which represents a failed connection attempt. The returned 3004 * {@code Connection} will have a {@link android.telecom.DisconnectCause} and as specified, 3005 * and a {@link #getState()} of {@link #STATE_DISCONNECTED}. 3006 * <p> 3007 * The returned {@code Connection} can be assumed to {@link #destroy()} itself when appropriate, 3008 * so users of this method need not maintain a reference to its return value to destroy it. 3009 * 3010 * @param disconnectCause The disconnect cause, ({@see android.telecomm.DisconnectCause}). 3011 * @return A {@code Connection} which indicates failure. 3012 */ createFailedConnection(DisconnectCause disconnectCause)3013 public static Connection createFailedConnection(DisconnectCause disconnectCause) { 3014 return new FailureSignalingConnection(disconnectCause); 3015 } 3016 3017 /** 3018 * Override to throw an {@link UnsupportedOperationException} if this {@code Connection} is 3019 * not intended to be mutated, e.g., if it is a marker for failure. Only for framework use; 3020 * this should never be un-@hide-den. 3021 * 3022 * @hide 3023 */ checkImmutable()3024 public void checkImmutable() {} 3025 3026 /** 3027 * Return a {@code Connection} which represents a canceled connection attempt. The returned 3028 * {@code Connection} will have state {@link #STATE_DISCONNECTED}, and cannot be moved out of 3029 * that state. This connection should not be used for anything, and no other 3030 * {@code Connection}s should be attempted. 3031 * <p> 3032 * so users of this method need not maintain a reference to its return value to destroy it. 3033 * 3034 * @return A {@code Connection} which indicates that the underlying connection should 3035 * be canceled. 3036 */ createCanceledConnection()3037 public static Connection createCanceledConnection() { 3038 return new FailureSignalingConnection(new DisconnectCause(DisconnectCause.CANCELED)); 3039 } 3040 fireOnConferenceableConnectionsChanged()3041 private final void fireOnConferenceableConnectionsChanged() { 3042 for (Listener l : mListeners) { 3043 l.onConferenceablesChanged(this, getConferenceables()); 3044 } 3045 } 3046 fireConferenceChanged()3047 private final void fireConferenceChanged() { 3048 for (Listener l : mListeners) { 3049 l.onConferenceChanged(this, mConference); 3050 } 3051 } 3052 clearConferenceableList()3053 private final void clearConferenceableList() { 3054 for (Conferenceable c : mConferenceables) { 3055 if (c instanceof Connection) { 3056 Connection connection = (Connection) c; 3057 connection.removeConnectionListener(mConnectionDeathListener); 3058 } else if (c instanceof Conference) { 3059 Conference conference = (Conference) c; 3060 conference.removeListener(mConferenceDeathListener); 3061 } 3062 } 3063 mConferenceables.clear(); 3064 } 3065 3066 /** 3067 * Handles a change to extras received from Telecom. 3068 * 3069 * @param extras The new extras. 3070 * @hide 3071 */ handleExtrasChanged(Bundle extras)3072 final void handleExtrasChanged(Bundle extras) { 3073 Bundle b = null; 3074 synchronized (mExtrasLock) { 3075 mExtras = extras; 3076 if (mExtras != null) { 3077 b = new Bundle(mExtras); 3078 } 3079 } 3080 onExtrasChanged(b); 3081 } 3082 3083 /** 3084 * Notifies listeners that the merge request failed. 3085 * 3086 * @hide 3087 */ notifyConferenceMergeFailed()3088 protected final void notifyConferenceMergeFailed() { 3089 for (Listener l : mListeners) { 3090 l.onConferenceMergeFailed(this); 3091 } 3092 } 3093 3094 /** 3095 * Notifies listeners of a change to conference participant(s). 3096 * 3097 * @param conferenceParticipants The participants. 3098 * @hide 3099 */ updateConferenceParticipants( List<ConferenceParticipant> conferenceParticipants)3100 protected final void updateConferenceParticipants( 3101 List<ConferenceParticipant> conferenceParticipants) { 3102 for (Listener l : mListeners) { 3103 l.onConferenceParticipantsChanged(this, conferenceParticipants); 3104 } 3105 } 3106 3107 /** 3108 * Notifies listeners that a conference call has been started. 3109 * @hide 3110 */ notifyConferenceStarted()3111 protected void notifyConferenceStarted() { 3112 for (Listener l : mListeners) { 3113 l.onConferenceStarted(); 3114 } 3115 } 3116 3117 /** 3118 * Notifies listeners when a change has occurred to the Connection which impacts its ability to 3119 * be a part of a conference call. 3120 * @param isConferenceSupported {@code true} if the connection supports being part of a 3121 * conference call, {@code false} otherwise. 3122 * @hide 3123 */ notifyConferenceSupportedChanged(boolean isConferenceSupported)3124 protected void notifyConferenceSupportedChanged(boolean isConferenceSupported) { 3125 for (Listener l : mListeners) { 3126 l.onConferenceSupportedChanged(this, isConferenceSupported); 3127 } 3128 } 3129 3130 /** 3131 * Notifies listeners when phone account is changed. For example, when the PhoneAccount is 3132 * changed due to an emergency call being redialed. 3133 * @param pHandle The new PhoneAccountHandle for this connection. 3134 * @hide 3135 */ notifyPhoneAccountChanged(PhoneAccountHandle pHandle)3136 public void notifyPhoneAccountChanged(PhoneAccountHandle pHandle) { 3137 for (Listener l : mListeners) { 3138 l.onPhoneAccountChanged(this, pHandle); 3139 } 3140 } 3141 3142 /** 3143 * Sets the {@link PhoneAccountHandle} associated with this connection. 3144 * 3145 * @hide 3146 */ setPhoneAccountHandle(PhoneAccountHandle phoneAccountHandle)3147 public void setPhoneAccountHandle(PhoneAccountHandle phoneAccountHandle) { 3148 if (mPhoneAccountHandle != phoneAccountHandle) { 3149 mPhoneAccountHandle = phoneAccountHandle; 3150 notifyPhoneAccountChanged(phoneAccountHandle); 3151 } 3152 } 3153 3154 /** 3155 * Returns the {@link PhoneAccountHandle} associated with this connection. 3156 * 3157 * @hide 3158 */ getPhoneAccountHandle()3159 public PhoneAccountHandle getPhoneAccountHandle() { 3160 return mPhoneAccountHandle; 3161 } 3162 3163 /** 3164 * Sends an event associated with this {@code Connection} with associated event extras to the 3165 * {@link InCallService}. 3166 * <p> 3167 * Connection events are used to communicate point in time information from a 3168 * {@link ConnectionService} to a {@link InCallService} implementations. An example of a 3169 * custom connection event includes notifying the UI when a WIFI call has been handed over to 3170 * LTE, which the InCall UI might use to inform the user that billing charges may apply. The 3171 * Android Telephony framework will send the {@link #EVENT_CALL_MERGE_FAILED} connection event 3172 * when a call to {@link Call#mergeConference()} has failed to complete successfully. A 3173 * connection event could also be used to trigger UI in the {@link InCallService} which prompts 3174 * the user to make a choice (e.g. whether they want to incur roaming costs for making a call), 3175 * which is communicated back via {@link Call#sendCallEvent(String, Bundle)}. 3176 * <p> 3177 * Events are exposed to {@link InCallService} implementations via 3178 * {@link Call.Callback#onConnectionEvent(Call, String, Bundle)}. 3179 * <p> 3180 * No assumptions should be made as to how an In-Call UI or service will handle these events. 3181 * The {@link ConnectionService} must assume that the In-Call UI could even chose to ignore 3182 * some events altogether. 3183 * <p> 3184 * Events should be fully qualified (e.g. {@code com.example.event.MY_EVENT}) to avoid 3185 * conflicts between {@link ConnectionService} implementations. Further, custom 3186 * {@link ConnectionService} implementations shall not re-purpose events in the 3187 * {@code android.*} namespace, nor shall they define new event types in this namespace. When 3188 * defining a custom event type, ensure the contents of the extras {@link Bundle} is clearly 3189 * defined. Extra keys for this bundle should be named similar to the event type (e.g. 3190 * {@code com.example.extra.MY_EXTRA}). 3191 * <p> 3192 * When defining events and the associated extras, it is important to keep their behavior 3193 * consistent when the associated {@link ConnectionService} is updated. Support for deprecated 3194 * events/extras should me maintained to ensure backwards compatibility with older 3195 * {@link InCallService} implementations which were built to support the older behavior. 3196 * 3197 * @param event The connection event. 3198 * @param extras Optional bundle containing extra information associated with the event. 3199 */ sendConnectionEvent(String event, Bundle extras)3200 public void sendConnectionEvent(String event, Bundle extras) { 3201 for (Listener l : mListeners) { 3202 l.onConnectionEvent(this, event, extras); 3203 } 3204 } 3205 } 3206