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