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 static android.Manifest.permission.MODIFY_PHONE_STATE; 20 21 import android.annotation.NonNull; 22 import android.annotation.RequiresPermission; 23 import android.annotation.SystemApi; 24 import android.annotation.TestApi; 25 import android.content.Intent; 26 import android.graphics.drawable.Icon; 27 import android.net.Uri; 28 import android.os.Bundle; 29 import android.os.Parcel; 30 import android.os.Parcelable; 31 import android.text.TextUtils; 32 33 import java.util.ArrayList; 34 import java.util.Collections; 35 import java.util.List; 36 import java.util.Objects; 37 38 /** 39 * Represents a distinct method to place or receive a phone call. Apps which can place calls and 40 * want those calls to be integrated into the dialer and in-call UI should build an instance of 41 * this class and register it with the system using {@link TelecomManager}. 42 * <p> 43 * {@link TelecomManager} uses registered {@link PhoneAccount}s to present the user with 44 * alternative options when placing a phone call. When building a {@link PhoneAccount}, the app 45 * should supply a valid {@link PhoneAccountHandle} that references the connection service 46 * implementation Telecom will use to interact with the app. 47 */ 48 public final class PhoneAccount implements Parcelable { 49 50 /** 51 * {@link PhoneAccount} extras key (see {@link PhoneAccount#getExtras()}) which determines the 52 * sort order for {@link PhoneAccount}s from the same 53 * {@link android.telecom.ConnectionService}. 54 * @hide 55 */ 56 public static final String EXTRA_SORT_ORDER = 57 "android.telecom.extra.SORT_ORDER"; 58 59 /** 60 * {@link PhoneAccount} extras key (see {@link PhoneAccount#getExtras()}) which determines the 61 * maximum permitted length of a call subject specified via the 62 * {@link TelecomManager#EXTRA_CALL_SUBJECT} extra on an 63 * {@link android.content.Intent#ACTION_CALL} intent. Ultimately a {@link ConnectionService} is 64 * responsible for enforcing the maximum call subject length when sending the message, however 65 * this extra is provided so that the user interface can proactively limit the length of the 66 * call subject as the user types it. 67 */ 68 public static final String EXTRA_CALL_SUBJECT_MAX_LENGTH = 69 "android.telecom.extra.CALL_SUBJECT_MAX_LENGTH"; 70 71 /** 72 * {@link PhoneAccount} extras key (see {@link PhoneAccount#getExtras()}) which determines the 73 * character encoding to be used when determining the length of messages. 74 * The user interface can use this when determining the number of characters the user may type 75 * in a call subject. If empty-string, the call subject message size limit will be enforced on 76 * a 1:1 basis. That is, each character will count towards the messages size limit as a single 77 * character. If a character encoding is specified, the message size limit will be based on the 78 * number of bytes in the message per the specified encoding. See 79 * {@link #EXTRA_CALL_SUBJECT_MAX_LENGTH} for more information on the call subject maximum 80 * length. 81 */ 82 public static final String EXTRA_CALL_SUBJECT_CHARACTER_ENCODING = 83 "android.telecom.extra.CALL_SUBJECT_CHARACTER_ENCODING"; 84 85 /** 86 * Boolean {@link PhoneAccount} extras key (see {@link PhoneAccount#getExtras()}) which 87 * indicates that all calls from this {@link PhoneAccount} should be treated as VoIP calls 88 * rather than cellular calls. 89 * @hide 90 */ 91 public static final String EXTRA_ALWAYS_USE_VOIP_AUDIO_MODE = 92 "android.telecom.extra.ALWAYS_USE_VOIP_AUDIO_MODE"; 93 94 /** 95 * Boolean {@link PhoneAccount} extras key (see {@link PhoneAccount#getExtras()}) which 96 * indicates whether this {@link PhoneAccount} is capable of supporting a request to handover a 97 * connection (see {@code android.telecom.Call#handoverTo()}) to this {@link PhoneAccount} from 98 * a {@link PhoneAccount} specifying {@link #EXTRA_SUPPORTS_HANDOVER_FROM}. 99 * <p> 100 * A handover request is initiated by the user from the default dialer app to indicate a desire 101 * to handover a call from one {@link PhoneAccount}/{@link ConnectionService} to another. 102 */ 103 public static final String EXTRA_SUPPORTS_HANDOVER_TO = 104 "android.telecom.extra.SUPPORTS_HANDOVER_TO"; 105 106 /** 107 * Boolean {@link PhoneAccount} extras key (see {@link PhoneAccount#getExtras()}) which 108 * indicates whether this {@link PhoneAccount} supports using a fallback if video calling is 109 * not available. This extra is for device level support, {@link 110 * android.telephony.CarrierConfigManager#KEY_ALLOW_VIDEO_CALLING_FALLBACK_BOOL} should also 111 * be checked to ensure it is not disabled by individual carrier. 112 * 113 * @hide 114 */ 115 public static final String EXTRA_SUPPORTS_VIDEO_CALLING_FALLBACK = 116 "android.telecom.extra.SUPPORTS_VIDEO_CALLING_FALLBACK"; 117 118 /** 119 * Boolean {@link PhoneAccount} extras key (see {@link PhoneAccount#getExtras()}) which 120 * indicates whether this {@link PhoneAccount} is capable of supporting a request to handover a 121 * connection from this {@link PhoneAccount} to another {@link PhoneAccount}. 122 * (see {@code android.telecom.Call#handoverTo()}) which specifies 123 * {@link #EXTRA_SUPPORTS_HANDOVER_TO}. 124 * <p> 125 * A handover request is initiated by the user from the default dialer app to indicate a desire 126 * to handover a call from one {@link PhoneAccount}/{@link ConnectionService} to another. 127 */ 128 public static final String EXTRA_SUPPORTS_HANDOVER_FROM = 129 "android.telecom.extra.SUPPORTS_HANDOVER_FROM"; 130 131 132 /** 133 * Boolean {@link PhoneAccount} extras key (see {@link PhoneAccount#getExtras()}) which 134 * indicates whether a Self-Managed {@link PhoneAccount} should log its calls to the call log. 135 * Self-Managed {@link PhoneAccount}s are responsible for their own notifications, so the system 136 * will not create a notification when a missed call is logged. 137 * <p> 138 * By default, Self-Managed {@link PhoneAccount}s do not log their calls to the call log. 139 * Setting this extra to {@code true} provides a means for them to log their calls. 140 * <p> 141 * Note: Only calls where the {@link Call.Details#getHandle()} {@link Uri#getScheme()} is 142 * {@link #SCHEME_SIP} or {@link #SCHEME_TEL} will be logged at the current time. 143 */ 144 public static final String EXTRA_LOG_SELF_MANAGED_CALLS = 145 "android.telecom.extra.LOG_SELF_MANAGED_CALLS"; 146 147 /** 148 * Boolean {@link PhoneAccount} extras key (see {@link PhoneAccount#getExtras()}) which 149 * indicates whether calls for a {@link PhoneAccount} should generate a "call recording tone" 150 * when the user is recording audio on the device. 151 * <p> 152 * The call recording tone is played over the telephony audio stream so that the remote party 153 * has an audible indication that it is possible their call is being recorded using a call 154 * recording app on the device. 155 * <p> 156 * This extra only has an effect for calls placed via Telephony (e.g. 157 * {@link #CAPABILITY_SIM_SUBSCRIPTION}). 158 * <p> 159 * The call recording tone is a 1400 hz tone which repeats every 15 seconds while recording is 160 * in progress. 161 * @hide 162 */ 163 public static final String EXTRA_PLAY_CALL_RECORDING_TONE = 164 "android.telecom.extra.PLAY_CALL_RECORDING_TONE"; 165 166 /** 167 * Boolean {@link PhoneAccount} extras key (see {@link PhoneAccount#getExtras()} which 168 * indicates whether calls for a {@link PhoneAccount} should skip call filtering. 169 * <p> 170 * If not specified, this will default to false; all calls will undergo call filtering unless 171 * specifically exempted (e.g. {@link Connection#PROPERTY_EMERGENCY_CALLBACK_MODE}.) However, 172 * this may be used to skip call filtering when it has already been performed on another device. 173 * @hide 174 */ 175 public static final String EXTRA_SKIP_CALL_FILTERING = 176 "android.telecom.extra.SKIP_CALL_FILTERING"; 177 178 /** 179 * Flag indicating that this {@code PhoneAccount} can act as a connection manager for 180 * other connections. The {@link ConnectionService} associated with this {@code PhoneAccount} 181 * will be allowed to manage phone calls including using its own proprietary phone-call 182 * implementation (like VoIP calling) to make calls instead of the telephony stack. 183 * <p> 184 * When a user opts to place a call using the SIM-based telephony stack, the 185 * {@link ConnectionService} associated with this {@code PhoneAccount} will be attempted first 186 * if the user has explicitly selected it to be used as the default connection manager. 187 * <p> 188 * See {@link #getCapabilities} 189 */ 190 public static final int CAPABILITY_CONNECTION_MANAGER = 0x1; 191 192 /** 193 * Flag indicating that this {@code PhoneAccount} can make phone calls in place of 194 * traditional SIM-based telephony calls. This account will be treated as a distinct method 195 * for placing calls alongside the traditional SIM-based telephony stack. This flag is 196 * distinct from {@link #CAPABILITY_CONNECTION_MANAGER} in that it is not allowed to manage 197 * or place calls from the built-in telephony stack. 198 * <p> 199 * See {@link #getCapabilities} 200 * <p> 201 */ 202 public static final int CAPABILITY_CALL_PROVIDER = 0x2; 203 204 /** 205 * Flag indicating that this {@code PhoneAccount} represents a built-in PSTN SIM 206 * subscription. 207 * <p> 208 * Only the Android framework can register a {@code PhoneAccount} having this capability. 209 * <p> 210 * See {@link #getCapabilities} 211 */ 212 public static final int CAPABILITY_SIM_SUBSCRIPTION = 0x4; 213 214 /** 215 * Flag indicating that this {@code PhoneAccount} is currently able to place video calls. 216 * <p> 217 * See also {@link #CAPABILITY_SUPPORTS_VIDEO_CALLING} which indicates whether the 218 * {@code PhoneAccount} supports placing video calls. 219 * <p> 220 * See {@link #getCapabilities} 221 */ 222 public static final int CAPABILITY_VIDEO_CALLING = 0x8; 223 224 /** 225 * Flag indicating that this {@code PhoneAccount} is capable of placing emergency calls. 226 * By default all PSTN {@code PhoneAccount}s are capable of placing emergency calls. 227 * <p> 228 * See {@link #getCapabilities} 229 */ 230 public static final int CAPABILITY_PLACE_EMERGENCY_CALLS = 0x10; 231 232 /** 233 * Flag indicating that this {@code PhoneAccount} is capable of being used by all users. This 234 * should only be used by system apps (and will be ignored for all other apps trying to use it). 235 * <p> 236 * See {@link #getCapabilities} 237 * @hide 238 */ 239 @SystemApi 240 public static final int CAPABILITY_MULTI_USER = 0x20; 241 242 /** 243 * Flag indicating that this {@code PhoneAccount} supports a subject for Calls. This means a 244 * caller is able to specify a short subject line for an outgoing call. A capable receiving 245 * device displays the call subject on the incoming call screen. 246 * <p> 247 * See {@link #getCapabilities} 248 */ 249 public static final int CAPABILITY_CALL_SUBJECT = 0x40; 250 251 /** 252 * Flag indicating that this {@code PhoneAccount} should only be used for emergency calls. 253 * <p> 254 * See {@link #getCapabilities} 255 * @hide 256 */ 257 public static final int CAPABILITY_EMERGENCY_CALLS_ONLY = 0x80; 258 259 /** 260 * Flag indicating that for this {@code PhoneAccount}, the ability to make a video call to a 261 * number relies on presence. Should only be set if the {@code PhoneAccount} also has 262 * {@link #CAPABILITY_VIDEO_CALLING}. 263 * <p> 264 * When set, the {@link ConnectionService} is responsible for toggling the 265 * {@link android.provider.ContactsContract.Data#CARRIER_PRESENCE_VT_CAPABLE} bit on the 266 * {@link android.provider.ContactsContract.Data#CARRIER_PRESENCE} column to indicate whether 267 * a contact's phone number supports video calling. 268 * <p> 269 * See {@link #getCapabilities} 270 */ 271 public static final int CAPABILITY_VIDEO_CALLING_RELIES_ON_PRESENCE = 0x100; 272 273 /** 274 * Flag indicating that for this {@link PhoneAccount}, emergency video calling is allowed. 275 * <p> 276 * When set, Telecom will allow emergency video calls to be placed. When not set, Telecom will 277 * convert all outgoing video calls to emergency numbers to audio-only. 278 * @hide 279 */ 280 public static final int CAPABILITY_EMERGENCY_VIDEO_CALLING = 0x200; 281 282 /** 283 * Flag indicating that this {@link PhoneAccount} supports video calling. 284 * This is not an indication that the {@link PhoneAccount} is currently able to make a video 285 * call, but rather that it has the ability to make video calls (but not necessarily at this 286 * time). 287 * <p> 288 * Whether a {@link PhoneAccount} can make a video call is ultimately controlled by 289 * {@link #CAPABILITY_VIDEO_CALLING}, which indicates whether the {@link PhoneAccount} is 290 * currently capable of making a video call. Consider a case where, for example, a 291 * {@link PhoneAccount} supports making video calls (e.g. 292 * {@link #CAPABILITY_SUPPORTS_VIDEO_CALLING}), but a current lack of network connectivity 293 * prevents video calls from being made (e.g. {@link #CAPABILITY_VIDEO_CALLING}). 294 * <p> 295 * See {@link #getCapabilities} 296 */ 297 public static final int CAPABILITY_SUPPORTS_VIDEO_CALLING = 0x400; 298 299 /** 300 * Flag indicating that this {@link PhoneAccount} is responsible for managing its own 301 * {@link Connection}s. This type of {@link PhoneAccount} is ideal for use with standalone 302 * calling apps which do not wish to use the default phone app for {@link Connection} UX, 303 * but which want to leverage the call and audio routing capabilities of the Telecom framework. 304 * <p> 305 * When set, {@link Connection}s created by the self-managed {@link ConnectionService} will not 306 * be surfaced to implementations of the {@link InCallService} API. Thus it is the 307 * responsibility of a self-managed {@link ConnectionService} to provide a user interface for 308 * its {@link Connection}s. 309 * <p> 310 * Self-managed {@link Connection}s will, however, be displayed on connected Bluetooth devices. 311 */ 312 public static final int CAPABILITY_SELF_MANAGED = 0x800; 313 314 /** 315 * Flag indicating that this {@link PhoneAccount} is capable of making a call with an 316 * RTT (Real-time text) session. 317 * When set, Telecom will attempt to open an RTT session on outgoing calls that specify 318 * that they should be placed with an RTT session , and the in-call app will be displayed 319 * with text entry fields for RTT. Likewise, the in-call app can request that an RTT 320 * session be opened during a call if this bit is set. 321 */ 322 public static final int CAPABILITY_RTT = 0x1000; 323 324 /** 325 * Flag indicating that this {@link PhoneAccount} is the preferred SIM subscription for 326 * emergency calls. A {@link PhoneAccount} that sets this capabilitiy must also 327 * set the {@link #CAPABILITY_SIM_SUBSCRIPTION} and {@link #CAPABILITY_PLACE_EMERGENCY_CALLS} 328 * capabilities. There should only be one emergency preferred {@link PhoneAccount}. 329 * <p> 330 * When set, Telecom will prefer this {@link PhoneAccount} over others for emergency calling, 331 * even if the emergency call was placed with a specific {@link PhoneAccount} set using the 332 * extra{@link TelecomManager#EXTRA_PHONE_ACCOUNT_HANDLE} in 333 * {@link Intent#ACTION_CALL_EMERGENCY} or {@link TelecomManager#placeCall(Uri, Bundle)}. 334 * 335 * @hide 336 */ 337 public static final int CAPABILITY_EMERGENCY_PREFERRED = 0x2000; 338 339 /** 340 * An adhoc conference call is established by providing a list of addresses to 341 * {@code TelecomManager#startConference(List<Uri>, int videoState)} where the 342 * {@link ConnectionService} is responsible for connecting all indicated participants 343 * to a conference simultaneously. 344 * This is in contrast to conferences formed by merging calls together (e.g. using 345 * {@link android.telecom.Call#mergeConference()}). 346 */ 347 public static final int CAPABILITY_ADHOC_CONFERENCE_CALLING = 0x4000; 348 349 /* NEXT CAPABILITY: 0x8000 */ 350 351 /** 352 * URI scheme for telephone number URIs. 353 */ 354 public static final String SCHEME_TEL = "tel"; 355 356 /** 357 * URI scheme for voicemail URIs. 358 */ 359 public static final String SCHEME_VOICEMAIL = "voicemail"; 360 361 /** 362 * URI scheme for SIP URIs. 363 */ 364 public static final String SCHEME_SIP = "sip"; 365 366 /** 367 * Indicating no icon tint is set. 368 * @hide 369 */ 370 public static final int NO_ICON_TINT = 0; 371 372 /** 373 * Indicating no hightlight color is set. 374 */ 375 public static final int NO_HIGHLIGHT_COLOR = 0; 376 377 /** 378 * Indicating no resource ID is set. 379 */ 380 public static final int NO_RESOURCE_ID = -1; 381 382 private final PhoneAccountHandle mAccountHandle; 383 private final Uri mAddress; 384 private final Uri mSubscriptionAddress; 385 private final int mCapabilities; 386 private final int mHighlightColor; 387 private final CharSequence mLabel; 388 private final CharSequence mShortDescription; 389 private final List<String> mSupportedUriSchemes; 390 private final int mSupportedAudioRoutes; 391 private final Icon mIcon; 392 private final Bundle mExtras; 393 private boolean mIsEnabled; 394 private String mGroupId; 395 396 @Override equals(Object o)397 public boolean equals(Object o) { 398 if (this == o) return true; 399 if (o == null || getClass() != o.getClass()) return false; 400 PhoneAccount that = (PhoneAccount) o; 401 return mCapabilities == that.mCapabilities && 402 mHighlightColor == that.mHighlightColor && 403 mSupportedAudioRoutes == that.mSupportedAudioRoutes && 404 mIsEnabled == that.mIsEnabled && 405 Objects.equals(mAccountHandle, that.mAccountHandle) && 406 Objects.equals(mAddress, that.mAddress) && 407 Objects.equals(mSubscriptionAddress, that.mSubscriptionAddress) && 408 Objects.equals(mLabel, that.mLabel) && 409 Objects.equals(mShortDescription, that.mShortDescription) && 410 Objects.equals(mSupportedUriSchemes, that.mSupportedUriSchemes) && 411 areBundlesEqual(mExtras, that.mExtras) && 412 Objects.equals(mGroupId, that.mGroupId); 413 } 414 415 @Override hashCode()416 public int hashCode() { 417 return Objects.hash(mAccountHandle, mAddress, mSubscriptionAddress, mCapabilities, 418 mHighlightColor, mLabel, mShortDescription, mSupportedUriSchemes, 419 mSupportedAudioRoutes, 420 mExtras, mIsEnabled, mGroupId); 421 } 422 423 /** 424 * Helper class for creating a {@link PhoneAccount}. 425 */ 426 public static class Builder { 427 428 private PhoneAccountHandle mAccountHandle; 429 private Uri mAddress; 430 private Uri mSubscriptionAddress; 431 private int mCapabilities; 432 private int mSupportedAudioRoutes = CallAudioState.ROUTE_ALL; 433 private int mHighlightColor = NO_HIGHLIGHT_COLOR; 434 private CharSequence mLabel; 435 private CharSequence mShortDescription; 436 private List<String> mSupportedUriSchemes = new ArrayList<String>(); 437 private Icon mIcon; 438 private Bundle mExtras; 439 private boolean mIsEnabled = false; 440 private String mGroupId = ""; 441 442 /** 443 * Creates a builder with the specified {@link PhoneAccountHandle} and label. 444 */ Builder(PhoneAccountHandle accountHandle, CharSequence label)445 public Builder(PhoneAccountHandle accountHandle, CharSequence label) { 446 this.mAccountHandle = accountHandle; 447 this.mLabel = label; 448 } 449 450 /** 451 * Creates an instance of the {@link PhoneAccount.Builder} from an existing 452 * {@link PhoneAccount}. 453 * 454 * @param phoneAccount The {@link PhoneAccount} used to initialize the builder. 455 */ Builder(PhoneAccount phoneAccount)456 public Builder(PhoneAccount phoneAccount) { 457 mAccountHandle = phoneAccount.getAccountHandle(); 458 mAddress = phoneAccount.getAddress(); 459 mSubscriptionAddress = phoneAccount.getSubscriptionAddress(); 460 mCapabilities = phoneAccount.getCapabilities(); 461 mHighlightColor = phoneAccount.getHighlightColor(); 462 mLabel = phoneAccount.getLabel(); 463 mShortDescription = phoneAccount.getShortDescription(); 464 mSupportedUriSchemes.addAll(phoneAccount.getSupportedUriSchemes()); 465 mIcon = phoneAccount.getIcon(); 466 mIsEnabled = phoneAccount.isEnabled(); 467 mExtras = phoneAccount.getExtras(); 468 mGroupId = phoneAccount.getGroupId(); 469 mSupportedAudioRoutes = phoneAccount.getSupportedAudioRoutes(); 470 } 471 472 /** 473 * Sets the label. See {@link PhoneAccount#getLabel()}. 474 * 475 * @param label The label of the phone account. 476 * @return The builder. 477 * @hide 478 */ setLabel(CharSequence label)479 public Builder setLabel(CharSequence label) { 480 this.mLabel = label; 481 return this; 482 } 483 484 /** 485 * Sets the address. See {@link PhoneAccount#getAddress}. 486 * 487 * @param value The address of the phone account. 488 * @return The builder. 489 */ setAddress(Uri value)490 public Builder setAddress(Uri value) { 491 this.mAddress = value; 492 return this; 493 } 494 495 /** 496 * Sets the subscription address. See {@link PhoneAccount#getSubscriptionAddress}. 497 * 498 * @param value The subscription address. 499 * @return The builder. 500 */ setSubscriptionAddress(Uri value)501 public Builder setSubscriptionAddress(Uri value) { 502 this.mSubscriptionAddress = value; 503 return this; 504 } 505 506 /** 507 * Sets the capabilities. See {@link PhoneAccount#getCapabilities}. 508 * 509 * @param value The capabilities to set. 510 * @return The builder. 511 */ setCapabilities(int value)512 public Builder setCapabilities(int value) { 513 this.mCapabilities = value; 514 return this; 515 } 516 517 /** 518 * Sets the icon. See {@link PhoneAccount#getIcon}. 519 * 520 * @param icon The icon to set. 521 */ setIcon(Icon icon)522 public Builder setIcon(Icon icon) { 523 mIcon = icon; 524 return this; 525 } 526 527 /** 528 * Sets the highlight color. See {@link PhoneAccount#getHighlightColor}. 529 * 530 * @param value The highlight color. 531 * @return The builder. 532 */ setHighlightColor(int value)533 public Builder setHighlightColor(int value) { 534 this.mHighlightColor = value; 535 return this; 536 } 537 538 /** 539 * Sets the short description. See {@link PhoneAccount#getShortDescription}. 540 * 541 * @param value The short description. 542 * @return The builder. 543 */ setShortDescription(CharSequence value)544 public Builder setShortDescription(CharSequence value) { 545 this.mShortDescription = value; 546 return this; 547 } 548 549 /** 550 * Specifies an additional URI scheme supported by the {@link PhoneAccount}. 551 * 552 * @param uriScheme The URI scheme. 553 * @return The builder. 554 */ addSupportedUriScheme(String uriScheme)555 public Builder addSupportedUriScheme(String uriScheme) { 556 if (!TextUtils.isEmpty(uriScheme) && !mSupportedUriSchemes.contains(uriScheme)) { 557 this.mSupportedUriSchemes.add(uriScheme); 558 } 559 return this; 560 } 561 562 /** 563 * Specifies the URI schemes supported by the {@link PhoneAccount}. 564 * 565 * @param uriSchemes The URI schemes. 566 * @return The builder. 567 */ setSupportedUriSchemes(List<String> uriSchemes)568 public Builder setSupportedUriSchemes(List<String> uriSchemes) { 569 mSupportedUriSchemes.clear(); 570 571 if (uriSchemes != null && !uriSchemes.isEmpty()) { 572 for (String uriScheme : uriSchemes) { 573 addSupportedUriScheme(uriScheme); 574 } 575 } 576 return this; 577 } 578 579 /** 580 * Specifies the extras associated with the {@link PhoneAccount}. 581 * <p> 582 * {@code PhoneAccount}s only support extra values of type: {@link String}, {@link Integer}, 583 * and {@link Boolean}. Extras which are not of these types are ignored. 584 * 585 * @param extras 586 * @return 587 */ setExtras(Bundle extras)588 public Builder setExtras(Bundle extras) { 589 mExtras = extras; 590 return this; 591 } 592 593 /** 594 * Sets the enabled state of the phone account. 595 * 596 * @param isEnabled The enabled state. 597 * @return The builder. 598 * @hide 599 */ setIsEnabled(boolean isEnabled)600 public Builder setIsEnabled(boolean isEnabled) { 601 mIsEnabled = isEnabled; 602 return this; 603 } 604 605 /** 606 * Sets the group Id of the {@link PhoneAccount}. When a new {@link PhoneAccount} is 607 * registered to Telecom, it will replace another {@link PhoneAccount} that is already 608 * registered in Telecom and take on the current user defaults and enabled status. There can 609 * only be one {@link PhoneAccount} with a non-empty group number registered to Telecom at a 610 * time. By default, there is no group Id for a {@link PhoneAccount} (an empty String). Only 611 * grouped {@link PhoneAccount}s with the same {@link ConnectionService} can be replaced. 612 * <p> 613 * Note: This is an API specific to the Telephony stack; the group Id will be ignored for 614 * callers not holding the correct permission. 615 * 616 * @param groupId The group Id of the {@link PhoneAccount} that will replace any other 617 * registered {@link PhoneAccount} in Telecom with the same Group Id. 618 * @return The builder 619 * @hide 620 */ 621 @SystemApi 622 @TestApi 623 @RequiresPermission(MODIFY_PHONE_STATE) setGroupId(@onNull String groupId)624 public @NonNull Builder setGroupId(@NonNull String groupId) { 625 if (groupId != null) { 626 mGroupId = groupId; 627 } else { 628 mGroupId = ""; 629 } 630 return this; 631 } 632 633 /** 634 * Sets the audio routes supported by this {@link PhoneAccount}. 635 * 636 * @param routes bit mask of available routes. 637 * @return The builder. 638 * @hide 639 */ setSupportedAudioRoutes(int routes)640 public Builder setSupportedAudioRoutes(int routes) { 641 mSupportedAudioRoutes = routes; 642 return this; 643 } 644 645 /** 646 * Creates an instance of a {@link PhoneAccount} based on the current builder settings. 647 * 648 * @return The {@link PhoneAccount}. 649 */ build()650 public PhoneAccount build() { 651 // If no supported URI schemes were defined, assume "tel" is supported. 652 if (mSupportedUriSchemes.isEmpty()) { 653 addSupportedUriScheme(SCHEME_TEL); 654 } 655 656 return new PhoneAccount( 657 mAccountHandle, 658 mAddress, 659 mSubscriptionAddress, 660 mCapabilities, 661 mIcon, 662 mHighlightColor, 663 mLabel, 664 mShortDescription, 665 mSupportedUriSchemes, 666 mExtras, 667 mSupportedAudioRoutes, 668 mIsEnabled, 669 mGroupId); 670 } 671 } 672 PhoneAccount( PhoneAccountHandle account, Uri address, Uri subscriptionAddress, int capabilities, Icon icon, int highlightColor, CharSequence label, CharSequence shortDescription, List<String> supportedUriSchemes, Bundle extras, int supportedAudioRoutes, boolean isEnabled, String groupId)673 private PhoneAccount( 674 PhoneAccountHandle account, 675 Uri address, 676 Uri subscriptionAddress, 677 int capabilities, 678 Icon icon, 679 int highlightColor, 680 CharSequence label, 681 CharSequence shortDescription, 682 List<String> supportedUriSchemes, 683 Bundle extras, 684 int supportedAudioRoutes, 685 boolean isEnabled, 686 String groupId) { 687 mAccountHandle = account; 688 mAddress = address; 689 mSubscriptionAddress = subscriptionAddress; 690 mCapabilities = capabilities; 691 mIcon = icon; 692 mHighlightColor = highlightColor; 693 mLabel = label; 694 mShortDescription = shortDescription; 695 mSupportedUriSchemes = Collections.unmodifiableList(supportedUriSchemes); 696 mExtras = extras; 697 mSupportedAudioRoutes = supportedAudioRoutes; 698 mIsEnabled = isEnabled; 699 mGroupId = groupId; 700 } 701 builder( PhoneAccountHandle accountHandle, CharSequence label)702 public static Builder builder( 703 PhoneAccountHandle accountHandle, 704 CharSequence label) { 705 return new Builder(accountHandle, label); 706 } 707 708 /** 709 * Returns a builder initialized with the current {@link PhoneAccount} instance. 710 * 711 * @return The builder. 712 */ toBuilder()713 public Builder toBuilder() { return new Builder(this); } 714 715 /** 716 * The unique identifier of this {@code PhoneAccount}. 717 * 718 * @return A {@code PhoneAccountHandle}. 719 */ getAccountHandle()720 public PhoneAccountHandle getAccountHandle() { 721 return mAccountHandle; 722 } 723 724 /** 725 * The address (e.g., a phone number) associated with this {@code PhoneAccount}. This 726 * represents the destination from which outgoing calls using this {@code PhoneAccount} 727 * will appear to come, if applicable, and the destination to which incoming calls using this 728 * {@code PhoneAccount} may be addressed. 729 * 730 * @return A address expressed as a {@code Uri}, for example, a phone number. 731 */ getAddress()732 public Uri getAddress() { 733 return mAddress; 734 } 735 736 /** 737 * The raw callback number used for this {@code PhoneAccount}, as distinct from 738 * {@link #getAddress()}. For the majority of {@code PhoneAccount}s this should be registered 739 * as {@code null}. It is used by the system for SIM-based {@code PhoneAccount} registration 740 * where {@link android.telephony.TelephonyManager#setLine1NumberForDisplay(String, String)} 741 * has been used to alter the callback number. 742 * <p> 743 * 744 * @return The subscription number, suitable for display to the user. 745 */ getSubscriptionAddress()746 public Uri getSubscriptionAddress() { 747 return mSubscriptionAddress; 748 } 749 750 /** 751 * The capabilities of this {@code PhoneAccount}. 752 * 753 * @return A bit field of flags describing this {@code PhoneAccount}'s capabilities. 754 */ getCapabilities()755 public int getCapabilities() { 756 return mCapabilities; 757 } 758 759 /** 760 * Determines if this {@code PhoneAccount} has a capabilities specified by the passed in 761 * bit mask. 762 * 763 * @param capability The capabilities to check. 764 * @return {@code true} if the phone account has the capability. 765 */ hasCapabilities(int capability)766 public boolean hasCapabilities(int capability) { 767 return (mCapabilities & capability) == capability; 768 } 769 770 /** 771 * Determines if this {@code PhoneAccount} has routes specified by the passed in bit mask. 772 * 773 * @param route The routes to check. 774 * @return {@code true} if the phone account has the routes. 775 * @hide 776 */ hasAudioRoutes(int routes)777 public boolean hasAudioRoutes(int routes) { 778 return (mSupportedAudioRoutes & routes) == routes; 779 } 780 781 /** 782 * A short label describing a {@code PhoneAccount}. 783 * 784 * @return A label for this {@code PhoneAccount}. 785 */ getLabel()786 public CharSequence getLabel() { 787 return mLabel; 788 } 789 790 /** 791 * A short paragraph describing this {@code PhoneAccount}. 792 * 793 * @return A description for this {@code PhoneAccount}. 794 */ getShortDescription()795 public CharSequence getShortDescription() { 796 return mShortDescription; 797 } 798 799 /** 800 * The URI schemes supported by this {@code PhoneAccount}. 801 * 802 * @return The URI schemes. 803 */ getSupportedUriSchemes()804 public List<String> getSupportedUriSchemes() { 805 return mSupportedUriSchemes; 806 } 807 808 /** 809 * The extras associated with this {@code PhoneAccount}. 810 * <p> 811 * A {@link ConnectionService} may provide implementation specific information about the 812 * {@link PhoneAccount} via the extras. 813 * 814 * @return The extras. 815 */ getExtras()816 public Bundle getExtras() { 817 return mExtras; 818 } 819 820 /** 821 * The audio routes supported by this {@code PhoneAccount}. 822 * 823 * @hide 824 */ getSupportedAudioRoutes()825 public int getSupportedAudioRoutes() { 826 return mSupportedAudioRoutes; 827 } 828 829 /** 830 * The icon to represent this {@code PhoneAccount}. 831 * 832 * @return The icon. 833 */ getIcon()834 public Icon getIcon() { 835 return mIcon; 836 } 837 838 /** 839 * Indicates whether the user has enabled this {@code PhoneAccount} or not. This value is only 840 * populated for {@code PhoneAccount}s returned by {@link TelecomManager#getPhoneAccount}. 841 * 842 * @return {@code true} if the account is enabled by the user, {@code false} otherwise. 843 */ isEnabled()844 public boolean isEnabled() { 845 return mIsEnabled; 846 } 847 848 /** 849 * A non-empty {@link String} representing the group that A {@link PhoneAccount} is in or an 850 * empty {@link String} if the {@link PhoneAccount} is not in a group. If this 851 * {@link PhoneAccount} is in a group, this new {@link PhoneAccount} will replace a registered 852 * {@link PhoneAccount} that is in the same group. When the {@link PhoneAccount} is replaced, 853 * its user defined defaults and enabled status will also pass to this new {@link PhoneAccount}. 854 * Only {@link PhoneAccount}s that share the same {@link ConnectionService} can be replaced. 855 * 856 * @return A non-empty String Id if this {@link PhoneAccount} belongs to a group. 857 * @hide 858 */ getGroupId()859 public String getGroupId() { 860 return mGroupId; 861 } 862 863 /** 864 * Determines if the {@link PhoneAccount} supports calls to/from addresses with a specified URI 865 * scheme. 866 * 867 * @param uriScheme The URI scheme to check. 868 * @return {@code true} if the {@code PhoneAccount} supports calls to/from addresses with the 869 * specified URI scheme. 870 */ supportsUriScheme(String uriScheme)871 public boolean supportsUriScheme(String uriScheme) { 872 if (mSupportedUriSchemes == null || uriScheme == null) { 873 return false; 874 } 875 876 for (String scheme : mSupportedUriSchemes) { 877 if (scheme != null && scheme.equals(uriScheme)) { 878 return true; 879 } 880 } 881 return false; 882 } 883 884 /** 885 * A highlight color to use in displaying information about this {@code PhoneAccount}. 886 * 887 * @return A hexadecimal color value. 888 */ getHighlightColor()889 public int getHighlightColor() { 890 return mHighlightColor; 891 } 892 893 /** 894 * Sets the enabled state of the phone account. 895 * @hide 896 */ setIsEnabled(boolean isEnabled)897 public void setIsEnabled(boolean isEnabled) { 898 mIsEnabled = isEnabled; 899 } 900 901 /** 902 * @return {@code true} if the {@link PhoneAccount} is self-managed, {@code false} otherwise. 903 * @hide 904 */ isSelfManaged()905 public boolean isSelfManaged() { 906 return (mCapabilities & CAPABILITY_SELF_MANAGED) == CAPABILITY_SELF_MANAGED; 907 } 908 909 // 910 // Parcelable implementation 911 // 912 913 @Override describeContents()914 public int describeContents() { 915 return 0; 916 } 917 918 @Override writeToParcel(Parcel out, int flags)919 public void writeToParcel(Parcel out, int flags) { 920 if (mAccountHandle == null) { 921 out.writeInt(0); 922 } else { 923 out.writeInt(1); 924 mAccountHandle.writeToParcel(out, flags); 925 } 926 if (mAddress == null) { 927 out.writeInt(0); 928 } else { 929 out.writeInt(1); 930 mAddress.writeToParcel(out, flags); 931 } 932 if (mSubscriptionAddress == null) { 933 out.writeInt(0); 934 } else { 935 out.writeInt(1); 936 mSubscriptionAddress.writeToParcel(out, flags); 937 } 938 out.writeInt(mCapabilities); 939 out.writeInt(mHighlightColor); 940 out.writeCharSequence(mLabel); 941 out.writeCharSequence(mShortDescription); 942 out.writeStringList(mSupportedUriSchemes); 943 944 if (mIcon == null) { 945 out.writeInt(0); 946 } else { 947 out.writeInt(1); 948 mIcon.writeToParcel(out, flags); 949 } 950 out.writeByte((byte) (mIsEnabled ? 1 : 0)); 951 out.writeBundle(mExtras); 952 out.writeString(mGroupId); 953 out.writeInt(mSupportedAudioRoutes); 954 } 955 956 public static final @android.annotation.NonNull Creator<PhoneAccount> CREATOR 957 = new Creator<PhoneAccount>() { 958 @Override 959 public PhoneAccount createFromParcel(Parcel in) { 960 return new PhoneAccount(in); 961 } 962 963 @Override 964 public PhoneAccount[] newArray(int size) { 965 return new PhoneAccount[size]; 966 } 967 }; 968 PhoneAccount(Parcel in)969 private PhoneAccount(Parcel in) { 970 if (in.readInt() > 0) { 971 mAccountHandle = PhoneAccountHandle.CREATOR.createFromParcel(in); 972 } else { 973 mAccountHandle = null; 974 } 975 if (in.readInt() > 0) { 976 mAddress = Uri.CREATOR.createFromParcel(in); 977 } else { 978 mAddress = null; 979 } 980 if (in.readInt() > 0) { 981 mSubscriptionAddress = Uri.CREATOR.createFromParcel(in); 982 } else { 983 mSubscriptionAddress = null; 984 } 985 mCapabilities = in.readInt(); 986 mHighlightColor = in.readInt(); 987 mLabel = in.readCharSequence(); 988 mShortDescription = in.readCharSequence(); 989 mSupportedUriSchemes = Collections.unmodifiableList(in.createStringArrayList()); 990 if (in.readInt() > 0) { 991 mIcon = Icon.CREATOR.createFromParcel(in); 992 } else { 993 mIcon = null; 994 } 995 mIsEnabled = in.readByte() == 1; 996 mExtras = in.readBundle(); 997 mGroupId = in.readString(); 998 mSupportedAudioRoutes = in.readInt(); 999 } 1000 1001 @Override toString()1002 public String toString() { 1003 StringBuilder sb = new StringBuilder().append("[[") 1004 .append(mIsEnabled ? 'X' : ' ') 1005 .append("] PhoneAccount: ") 1006 .append(mAccountHandle) 1007 .append(" Capabilities: ") 1008 .append(capabilitiesToString()) 1009 .append(" Audio Routes: ") 1010 .append(audioRoutesToString()) 1011 .append(" Schemes: "); 1012 for (String scheme : mSupportedUriSchemes) { 1013 sb.append(scheme) 1014 .append(" "); 1015 } 1016 sb.append(" Extras: "); 1017 sb.append(mExtras); 1018 sb.append(" GroupId: "); 1019 sb.append(Log.pii(mGroupId)); 1020 sb.append("]"); 1021 return sb.toString(); 1022 } 1023 1024 /** 1025 * Generates a string representation of a capabilities bitmask. 1026 * 1027 * @return String representation of the capabilities bitmask. 1028 * @hide 1029 */ capabilitiesToString()1030 public String capabilitiesToString() { 1031 StringBuilder sb = new StringBuilder(); 1032 if (hasCapabilities(CAPABILITY_SELF_MANAGED)) { 1033 sb.append("SelfManaged "); 1034 } 1035 if (hasCapabilities(CAPABILITY_SUPPORTS_VIDEO_CALLING)) { 1036 sb.append("SuppVideo "); 1037 } 1038 if (hasCapabilities(CAPABILITY_VIDEO_CALLING)) { 1039 sb.append("Video "); 1040 } 1041 if (hasCapabilities(CAPABILITY_VIDEO_CALLING_RELIES_ON_PRESENCE)) { 1042 sb.append("Presence "); 1043 } 1044 if (hasCapabilities(CAPABILITY_CALL_PROVIDER)) { 1045 sb.append("CallProvider "); 1046 } 1047 if (hasCapabilities(CAPABILITY_CALL_SUBJECT)) { 1048 sb.append("CallSubject "); 1049 } 1050 if (hasCapabilities(CAPABILITY_CONNECTION_MANAGER)) { 1051 sb.append("ConnectionMgr "); 1052 } 1053 if (hasCapabilities(CAPABILITY_EMERGENCY_CALLS_ONLY)) { 1054 sb.append("EmergOnly "); 1055 } 1056 if (hasCapabilities(CAPABILITY_MULTI_USER)) { 1057 sb.append("MultiUser "); 1058 } 1059 if (hasCapabilities(CAPABILITY_PLACE_EMERGENCY_CALLS)) { 1060 sb.append("PlaceEmerg "); 1061 } 1062 if (hasCapabilities(CAPABILITY_EMERGENCY_PREFERRED)) { 1063 sb.append("EmerPrefer "); 1064 } 1065 if (hasCapabilities(CAPABILITY_EMERGENCY_VIDEO_CALLING)) { 1066 sb.append("EmergVideo "); 1067 } 1068 if (hasCapabilities(CAPABILITY_SIM_SUBSCRIPTION)) { 1069 sb.append("SimSub "); 1070 } 1071 if (hasCapabilities(CAPABILITY_RTT)) { 1072 sb.append("Rtt"); 1073 } 1074 if (hasCapabilities(CAPABILITY_ADHOC_CONFERENCE_CALLING)) { 1075 sb.append("AdhocConf"); 1076 } 1077 return sb.toString(); 1078 } 1079 audioRoutesToString()1080 private String audioRoutesToString() { 1081 StringBuilder sb = new StringBuilder(); 1082 1083 if (hasAudioRoutes(CallAudioState.ROUTE_BLUETOOTH)) { 1084 sb.append("B"); 1085 } 1086 if (hasAudioRoutes(CallAudioState.ROUTE_EARPIECE)) { 1087 sb.append("E"); 1088 } 1089 if (hasAudioRoutes(CallAudioState.ROUTE_SPEAKER)) { 1090 sb.append("S"); 1091 } 1092 if (hasAudioRoutes(CallAudioState.ROUTE_WIRED_HEADSET)) { 1093 sb.append("W"); 1094 } 1095 1096 return sb.toString(); 1097 } 1098 1099 /** 1100 * Determines if two {@link Bundle}s are equal. 1101 * @param extras First {@link Bundle} to check. 1102 * @param newExtras {@link Bundle} to compare against. 1103 * @return {@code true} if the {@link Bundle}s are equal, {@code false} otherwise. 1104 */ areBundlesEqual(Bundle extras, Bundle newExtras)1105 private static boolean areBundlesEqual(Bundle extras, Bundle newExtras) { 1106 if (extras == null || newExtras == null) { 1107 return extras == newExtras; 1108 } 1109 1110 if (extras.size() != newExtras.size()) { 1111 return false; 1112 } 1113 1114 for(String key : extras.keySet()) { 1115 if (key != null) { 1116 final Object value = extras.get(key); 1117 final Object newValue = newExtras.get(key); 1118 if (!Objects.equals(value, newValue)) { 1119 return false; 1120 } 1121 } 1122 } 1123 return true; 1124 } 1125 } 1126