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