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