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