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