Home | History | Annotate | Download | only in telecom
      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.ComponentName;
     21 import android.content.Context;
     22 import android.content.pm.PackageManager;
     23 import android.content.res.Resources.NotFoundException;
     24 import android.graphics.Bitmap;
     25 import android.graphics.Color;
     26 import android.graphics.drawable.BitmapDrawable;
     27 import android.graphics.drawable.ColorDrawable;
     28 import android.graphics.drawable.Drawable;
     29 import android.graphics.drawable.Icon;
     30 import android.net.Uri;
     31 import android.os.Bundle;
     32 import android.os.Parcel;
     33 import android.os.Parcelable;
     34 import android.text.TextUtils;
     35 
     36 import java.lang.String;
     37 import java.util.ArrayList;
     38 import java.util.Collections;
     39 import java.util.List;
     40 import java.util.MissingResourceException;
     41 
     42 /**
     43  * Represents a distinct method to place or receive a phone call. Apps which can place calls and
     44  * want those calls to be integrated into the dialer and in-call UI should build an instance of
     45  * this class and register it with the system using {@link TelecomManager}.
     46  * <p>
     47  * {@link TelecomManager} uses registered {@link PhoneAccount}s to present the user with
     48  * alternative options when placing a phone call. When building a {@link PhoneAccount}, the app
     49  * should supply a valid {@link PhoneAccountHandle} that references the connection service
     50  * implementation Telecom will use to interact with the app.
     51  */
     52 public final class PhoneAccount implements Parcelable {
     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      * Flag indicating that this {@code PhoneAccount} can act as a connection manager for
     82      * other connections. The {@link ConnectionService} associated with this {@code PhoneAccount}
     83      * will be allowed to manage phone calls including using its own proprietary phone-call
     84      * implementation (like VoIP calling) to make calls instead of the telephony stack.
     85      * <p>
     86      * When a user opts to place a call using the SIM-based telephony stack, the
     87      * {@link ConnectionService} associated with this {@code PhoneAccount} will be attempted first
     88      * if the user has explicitly selected it to be used as the default connection manager.
     89      * <p>
     90      * See {@link #getCapabilities}
     91      */
     92     public static final int CAPABILITY_CONNECTION_MANAGER = 0x1;
     93 
     94     /**
     95      * Flag indicating that this {@code PhoneAccount} can make phone calls in place of
     96      * traditional SIM-based telephony calls. This account will be treated as a distinct method
     97      * for placing calls alongside the traditional SIM-based telephony stack. This flag is
     98      * distinct from {@link #CAPABILITY_CONNECTION_MANAGER} in that it is not allowed to manage
     99      * or place calls from the built-in telephony stack.
    100      * <p>
    101      * See {@link #getCapabilities}
    102      * <p>
    103      */
    104     public static final int CAPABILITY_CALL_PROVIDER = 0x2;
    105 
    106     /**
    107      * Flag indicating that this {@code PhoneAccount} represents a built-in PSTN SIM
    108      * subscription.
    109      * <p>
    110      * Only the Android framework can register a {@code PhoneAccount} having this capability.
    111      * <p>
    112      * See {@link #getCapabilities}
    113      */
    114     public static final int CAPABILITY_SIM_SUBSCRIPTION = 0x4;
    115 
    116     /**
    117      * Flag indicating that this {@code PhoneAccount} is capable of placing video calls.
    118      * <p>
    119      * See {@link #getCapabilities}
    120      */
    121     public static final int CAPABILITY_VIDEO_CALLING = 0x8;
    122 
    123     /**
    124      * Flag indicating that this {@code PhoneAccount} is capable of placing emergency calls.
    125      * By default all PSTN {@code PhoneAccount}s are capable of placing emergency calls.
    126      * <p>
    127      * See {@link #getCapabilities}
    128      */
    129     public static final int CAPABILITY_PLACE_EMERGENCY_CALLS = 0x10;
    130 
    131     /**
    132      * Flag indicating that this {@code PhoneAccount} is capable of being used by all users. This
    133      * should only be used by system apps (and will be ignored for all other apps trying to use it).
    134      * <p>
    135      * See {@link #getCapabilities}
    136      * @hide
    137      */
    138     @SystemApi
    139     public static final int CAPABILITY_MULTI_USER = 0x20;
    140 
    141     /**
    142      * Flag indicating that this {@code PhoneAccount} supports a subject for Calls.  This means a
    143      * caller is able to specify a short subject line for an outgoing call.  A capable receiving
    144      * device displays the call subject on the incoming call screen.
    145      * <p>
    146      * See {@link #getCapabilities}
    147      */
    148     public static final int CAPABILITY_CALL_SUBJECT = 0x40;
    149 
    150     /**
    151      * Flag indicating that this {@code PhoneAccount} should only be used for emergency calls.
    152      * <p>
    153      * See {@link #getCapabilities}
    154      * @hide
    155      */
    156     public static final int CAPABILITY_EMERGENCY_CALLS_ONLY = 0x80;
    157 
    158     /**
    159      * Flag indicating that for this {@code PhoneAccount}, the ability to make a video call to a
    160      * number relies on presence.  Should only be set if the {@code PhoneAccount} also has
    161      * {@link #CAPABILITY_VIDEO_CALLING}.
    162      * <p>
    163      * When set, the {@link ConnectionService} is responsible for toggling the
    164      * {@link android.provider.ContactsContract.Data#CARRIER_PRESENCE_VT_CAPABLE} bit on the
    165      * {@link android.provider.ContactsContract.Data#CARRIER_PRESENCE} column to indicate whether
    166      * a contact's phone number supports video calling.
    167      * <p>
    168      * See {@link #getCapabilities}
    169      */
    170     public static final int CAPABILITY_VIDEO_CALLING_RELIES_ON_PRESENCE = 0x100;
    171 
    172     /**
    173      * Flag indicating that for this {@link PhoneAccount}, emergency video calling is allowed.
    174      * <p>
    175      * When set, Telecom will allow emergency video calls to be placed.  When not set, Telecom will
    176      * convert all outgoing video calls to emergency numbers to audio-only.
    177      * @hide
    178      */
    179     public static final int CAPABILITY_EMERGENCY_VIDEO_CALLING = 0x200;
    180 
    181     /**
    182      * URI scheme for telephone number URIs.
    183      */
    184     public static final String SCHEME_TEL = "tel";
    185 
    186     /**
    187      * URI scheme for voicemail URIs.
    188      */
    189     public static final String SCHEME_VOICEMAIL = "voicemail";
    190 
    191     /**
    192      * URI scheme for SIP URIs.
    193      */
    194     public static final String SCHEME_SIP = "sip";
    195 
    196     /**
    197      * Indicating no icon tint is set.
    198      * @hide
    199      */
    200     public static final int NO_ICON_TINT = 0;
    201 
    202     /**
    203      * Indicating no hightlight color is set.
    204      */
    205     public static final int NO_HIGHLIGHT_COLOR = 0;
    206 
    207     /**
    208      * Indicating no resource ID is set.
    209      */
    210     public static final int NO_RESOURCE_ID = -1;
    211 
    212     private final PhoneAccountHandle mAccountHandle;
    213     private final Uri mAddress;
    214     private final Uri mSubscriptionAddress;
    215     private final int mCapabilities;
    216     private final int mHighlightColor;
    217     private final CharSequence mLabel;
    218     private final CharSequence mShortDescription;
    219     private final List<String> mSupportedUriSchemes;
    220     private final Icon mIcon;
    221     private final Bundle mExtras;
    222     private boolean mIsEnabled;
    223 
    224     /**
    225      * Helper class for creating a {@link PhoneAccount}.
    226      */
    227     public static class Builder {
    228         private PhoneAccountHandle mAccountHandle;
    229         private Uri mAddress;
    230         private Uri mSubscriptionAddress;
    231         private int mCapabilities;
    232         private int mHighlightColor = NO_HIGHLIGHT_COLOR;
    233         private CharSequence mLabel;
    234         private CharSequence mShortDescription;
    235         private List<String> mSupportedUriSchemes = new ArrayList<String>();
    236         private Icon mIcon;
    237         private Bundle mExtras;
    238         private boolean mIsEnabled = false;
    239 
    240         /**
    241          * Creates a builder with the specified {@link PhoneAccountHandle} and label.
    242          */
    243         public Builder(PhoneAccountHandle accountHandle, CharSequence label) {
    244             this.mAccountHandle = accountHandle;
    245             this.mLabel = label;
    246         }
    247 
    248         /**
    249          * Creates an instance of the {@link PhoneAccount.Builder} from an existing
    250          * {@link PhoneAccount}.
    251          *
    252          * @param phoneAccount The {@link PhoneAccount} used to initialize the builder.
    253          */
    254         public Builder(PhoneAccount phoneAccount) {
    255             mAccountHandle = phoneAccount.getAccountHandle();
    256             mAddress = phoneAccount.getAddress();
    257             mSubscriptionAddress = phoneAccount.getSubscriptionAddress();
    258             mCapabilities = phoneAccount.getCapabilities();
    259             mHighlightColor = phoneAccount.getHighlightColor();
    260             mLabel = phoneAccount.getLabel();
    261             mShortDescription = phoneAccount.getShortDescription();
    262             mSupportedUriSchemes.addAll(phoneAccount.getSupportedUriSchemes());
    263             mIcon = phoneAccount.getIcon();
    264             mIsEnabled = phoneAccount.isEnabled();
    265             mExtras = phoneAccount.getExtras();
    266         }
    267 
    268         /**
    269          * Sets the address. See {@link PhoneAccount#getAddress}.
    270          *
    271          * @param value The address of the phone account.
    272          * @return The builder.
    273          */
    274         public Builder setAddress(Uri value) {
    275             this.mAddress = value;
    276             return this;
    277         }
    278 
    279         /**
    280          * Sets the subscription address. See {@link PhoneAccount#getSubscriptionAddress}.
    281          *
    282          * @param value The subscription address.
    283          * @return The builder.
    284          */
    285         public Builder setSubscriptionAddress(Uri value) {
    286             this.mSubscriptionAddress = value;
    287             return this;
    288         }
    289 
    290         /**
    291          * Sets the capabilities. See {@link PhoneAccount#getCapabilities}.
    292          *
    293          * @param value The capabilities to set.
    294          * @return The builder.
    295          */
    296         public Builder setCapabilities(int value) {
    297             this.mCapabilities = value;
    298             return this;
    299         }
    300 
    301         /**
    302          * Sets the icon. See {@link PhoneAccount#getIcon}.
    303          *
    304          * @param icon The icon to set.
    305          */
    306         public Builder setIcon(Icon icon) {
    307             mIcon = icon;
    308             return this;
    309         }
    310 
    311         /**
    312          * Sets the highlight color. See {@link PhoneAccount#getHighlightColor}.
    313          *
    314          * @param value The highlight color.
    315          * @return The builder.
    316          */
    317         public Builder setHighlightColor(int value) {
    318             this.mHighlightColor = value;
    319             return this;
    320         }
    321 
    322         /**
    323          * Sets the short description. See {@link PhoneAccount#getShortDescription}.
    324          *
    325          * @param value The short description.
    326          * @return The builder.
    327          */
    328         public Builder setShortDescription(CharSequence value) {
    329             this.mShortDescription = value;
    330             return this;
    331         }
    332 
    333         /**
    334          * Specifies an additional URI scheme supported by the {@link PhoneAccount}.
    335          *
    336          * @param uriScheme The URI scheme.
    337          * @return The builder.
    338          */
    339         public Builder addSupportedUriScheme(String uriScheme) {
    340             if (!TextUtils.isEmpty(uriScheme) && !mSupportedUriSchemes.contains(uriScheme)) {
    341                 this.mSupportedUriSchemes.add(uriScheme);
    342             }
    343             return this;
    344         }
    345 
    346         /**
    347          * Specifies the URI schemes supported by the {@link PhoneAccount}.
    348          *
    349          * @param uriSchemes The URI schemes.
    350          * @return The builder.
    351          */
    352         public Builder setSupportedUriSchemes(List<String> uriSchemes) {
    353             mSupportedUriSchemes.clear();
    354 
    355             if (uriSchemes != null && !uriSchemes.isEmpty()) {
    356                 for (String uriScheme : uriSchemes) {
    357                     addSupportedUriScheme(uriScheme);
    358                 }
    359             }
    360             return this;
    361         }
    362 
    363         /**
    364          * Specifies the extras associated with the {@link PhoneAccount}.
    365          * <p>
    366          * {@code PhoneAccount}s only support extra values of type: {@link String}, {@link Integer},
    367          * and {@link Boolean}.  Extras which are not of these types are ignored.
    368          *
    369          * @param extras
    370          * @return
    371          */
    372         public Builder setExtras(Bundle extras) {
    373             mExtras = extras;
    374             return this;
    375         }
    376 
    377         /**
    378          * Sets the enabled state of the phone account.
    379          *
    380          * @param isEnabled The enabled state.
    381          * @return The builder.
    382          * @hide
    383          */
    384         public Builder setIsEnabled(boolean isEnabled) {
    385             mIsEnabled = isEnabled;
    386             return this;
    387         }
    388 
    389         /**
    390          * Creates an instance of a {@link PhoneAccount} based on the current builder settings.
    391          *
    392          * @return The {@link PhoneAccount}.
    393          */
    394         public PhoneAccount build() {
    395             // If no supported URI schemes were defined, assume "tel" is supported.
    396             if (mSupportedUriSchemes.isEmpty()) {
    397                 addSupportedUriScheme(SCHEME_TEL);
    398             }
    399 
    400             return new PhoneAccount(
    401                     mAccountHandle,
    402                     mAddress,
    403                     mSubscriptionAddress,
    404                     mCapabilities,
    405                     mIcon,
    406                     mHighlightColor,
    407                     mLabel,
    408                     mShortDescription,
    409                     mSupportedUriSchemes,
    410                     mExtras,
    411                     mIsEnabled);
    412         }
    413     }
    414 
    415     private PhoneAccount(
    416             PhoneAccountHandle account,
    417             Uri address,
    418             Uri subscriptionAddress,
    419             int capabilities,
    420             Icon icon,
    421             int highlightColor,
    422             CharSequence label,
    423             CharSequence shortDescription,
    424             List<String> supportedUriSchemes,
    425             Bundle extras,
    426             boolean isEnabled) {
    427         mAccountHandle = account;
    428         mAddress = address;
    429         mSubscriptionAddress = subscriptionAddress;
    430         mCapabilities = capabilities;
    431         mIcon = icon;
    432         mHighlightColor = highlightColor;
    433         mLabel = label;
    434         mShortDescription = shortDescription;
    435         mSupportedUriSchemes = Collections.unmodifiableList(supportedUriSchemes);
    436         mExtras = extras;
    437         mIsEnabled = isEnabled;
    438     }
    439 
    440     public static Builder builder(
    441             PhoneAccountHandle accountHandle,
    442             CharSequence label) {
    443         return new Builder(accountHandle, label);
    444     }
    445 
    446     /**
    447      * Returns a builder initialized with the current {@link PhoneAccount} instance.
    448      *
    449      * @return The builder.
    450      */
    451     public Builder toBuilder() { return new Builder(this); }
    452 
    453     /**
    454      * The unique identifier of this {@code PhoneAccount}.
    455      *
    456      * @return A {@code PhoneAccountHandle}.
    457      */
    458     public PhoneAccountHandle getAccountHandle() {
    459         return mAccountHandle;
    460     }
    461 
    462     /**
    463      * The address (e.g., a phone number) associated with this {@code PhoneAccount}. This
    464      * represents the destination from which outgoing calls using this {@code PhoneAccount}
    465      * will appear to come, if applicable, and the destination to which incoming calls using this
    466      * {@code PhoneAccount} may be addressed.
    467      *
    468      * @return A address expressed as a {@code Uri}, for example, a phone number.
    469      */
    470     public Uri getAddress() {
    471         return mAddress;
    472     }
    473 
    474     /**
    475      * The raw callback number used for this {@code PhoneAccount}, as distinct from
    476      * {@link #getAddress()}. For the majority of {@code PhoneAccount}s this should be registered
    477      * as {@code null}.  It is used by the system for SIM-based {@code PhoneAccount} registration
    478      * where {@link android.telephony.TelephonyManager#setLine1NumberForDisplay(String, String)}
    479      * has been used to alter the callback number.
    480      * <p>
    481      *
    482      * @return The subscription number, suitable for display to the user.
    483      */
    484     public Uri getSubscriptionAddress() {
    485         return mSubscriptionAddress;
    486     }
    487 
    488     /**
    489      * The capabilities of this {@code PhoneAccount}.
    490      *
    491      * @return A bit field of flags describing this {@code PhoneAccount}'s capabilities.
    492      */
    493     public int getCapabilities() {
    494         return mCapabilities;
    495     }
    496 
    497     /**
    498      * Determines if this {@code PhoneAccount} has a capabilities specified by the passed in
    499      * bit mask.
    500      *
    501      * @param capability The capabilities to check.
    502      * @return {@code true} if the phone account has the capability.
    503      */
    504     public boolean hasCapabilities(int capability) {
    505         return (mCapabilities & capability) == capability;
    506     }
    507 
    508     /**
    509      * A short label describing a {@code PhoneAccount}.
    510      *
    511      * @return A label for this {@code PhoneAccount}.
    512      */
    513     public CharSequence getLabel() {
    514         return mLabel;
    515     }
    516 
    517     /**
    518      * A short paragraph describing this {@code PhoneAccount}.
    519      *
    520      * @return A description for this {@code PhoneAccount}.
    521      */
    522     public CharSequence getShortDescription() {
    523         return mShortDescription;
    524     }
    525 
    526     /**
    527      * The URI schemes supported by this {@code PhoneAccount}.
    528      *
    529      * @return The URI schemes.
    530      */
    531     public List<String> getSupportedUriSchemes() {
    532         return mSupportedUriSchemes;
    533     }
    534 
    535     /**
    536      * The extras associated with this {@code PhoneAccount}.
    537      * <p>
    538      * A {@link ConnectionService} may provide implementation specific information about the
    539      * {@link PhoneAccount} via the extras.
    540      *
    541      * @return The extras.
    542      */
    543     public Bundle getExtras() {
    544         return mExtras;
    545     }
    546 
    547     /**
    548      * The icon to represent this {@code PhoneAccount}.
    549      *
    550      * @return The icon.
    551      */
    552     public Icon getIcon() {
    553         return mIcon;
    554     }
    555 
    556     /**
    557      * Indicates whether the user has enabled this {@code PhoneAccount} or not. This value is only
    558      * populated for {@code PhoneAccount}s returned by {@link TelecomManager#getPhoneAccount}.
    559      *
    560      * @return {@code true} if the account is enabled by the user, {@code false} otherwise.
    561      */
    562     public boolean isEnabled() {
    563         return mIsEnabled;
    564     }
    565 
    566     /**
    567      * Determines if the {@link PhoneAccount} supports calls to/from addresses with a specified URI
    568      * scheme.
    569      *
    570      * @param uriScheme The URI scheme to check.
    571      * @return {@code true} if the {@code PhoneAccount} supports calls to/from addresses with the
    572      * specified URI scheme.
    573      */
    574     public boolean supportsUriScheme(String uriScheme) {
    575         if (mSupportedUriSchemes == null || uriScheme == null) {
    576             return false;
    577         }
    578 
    579         for (String scheme : mSupportedUriSchemes) {
    580             if (scheme != null && scheme.equals(uriScheme)) {
    581                 return true;
    582             }
    583         }
    584         return false;
    585     }
    586 
    587     /**
    588      * A highlight color to use in displaying information about this {@code PhoneAccount}.
    589      *
    590      * @return A hexadecimal color value.
    591      */
    592     public int getHighlightColor() {
    593         return mHighlightColor;
    594     }
    595 
    596     /**
    597      * Sets the enabled state of the phone account.
    598      * @hide
    599      */
    600     public void setIsEnabled(boolean isEnabled) {
    601         mIsEnabled = isEnabled;
    602     }
    603 
    604     //
    605     // Parcelable implementation
    606     //
    607 
    608     @Override
    609     public int describeContents() {
    610         return 0;
    611     }
    612 
    613     @Override
    614     public void writeToParcel(Parcel out, int flags) {
    615         if (mAccountHandle == null) {
    616             out.writeInt(0);
    617         } else {
    618             out.writeInt(1);
    619             mAccountHandle.writeToParcel(out, flags);
    620         }
    621         if (mAddress == null) {
    622             out.writeInt(0);
    623         } else {
    624             out.writeInt(1);
    625             mAddress.writeToParcel(out, flags);
    626         }
    627         if (mSubscriptionAddress == null) {
    628             out.writeInt(0);
    629         } else {
    630             out.writeInt(1);
    631             mSubscriptionAddress.writeToParcel(out, flags);
    632         }
    633         out.writeInt(mCapabilities);
    634         out.writeInt(mHighlightColor);
    635         out.writeCharSequence(mLabel);
    636         out.writeCharSequence(mShortDescription);
    637         out.writeStringList(mSupportedUriSchemes);
    638 
    639         if (mIcon == null) {
    640             out.writeInt(0);
    641         } else {
    642             out.writeInt(1);
    643             mIcon.writeToParcel(out, flags);
    644         }
    645         out.writeByte((byte) (mIsEnabled ? 1 : 0));
    646         out.writeBundle(mExtras);
    647     }
    648 
    649     public static final Creator<PhoneAccount> CREATOR
    650             = new Creator<PhoneAccount>() {
    651         @Override
    652         public PhoneAccount createFromParcel(Parcel in) {
    653             return new PhoneAccount(in);
    654         }
    655 
    656         @Override
    657         public PhoneAccount[] newArray(int size) {
    658             return new PhoneAccount[size];
    659         }
    660     };
    661 
    662     private PhoneAccount(Parcel in) {
    663         if (in.readInt() > 0) {
    664             mAccountHandle = PhoneAccountHandle.CREATOR.createFromParcel(in);
    665         } else {
    666             mAccountHandle = null;
    667         }
    668         if (in.readInt() > 0) {
    669             mAddress = Uri.CREATOR.createFromParcel(in);
    670         } else {
    671             mAddress = null;
    672         }
    673         if (in.readInt() > 0) {
    674             mSubscriptionAddress = Uri.CREATOR.createFromParcel(in);
    675         } else {
    676             mSubscriptionAddress = null;
    677         }
    678         mCapabilities = in.readInt();
    679         mHighlightColor = in.readInt();
    680         mLabel = in.readCharSequence();
    681         mShortDescription = in.readCharSequence();
    682         mSupportedUriSchemes = Collections.unmodifiableList(in.createStringArrayList());
    683         if (in.readInt() > 0) {
    684             mIcon = Icon.CREATOR.createFromParcel(in);
    685         } else {
    686             mIcon = null;
    687         }
    688         mIsEnabled = in.readByte() == 1;
    689         mExtras = in.readBundle();
    690     }
    691 
    692     @Override
    693     public String toString() {
    694         StringBuilder sb = new StringBuilder().append("[[")
    695                 .append(mIsEnabled ? 'X' : ' ')
    696                 .append("] PhoneAccount: ")
    697                 .append(mAccountHandle)
    698                 .append(" Capabilities: ")
    699                 .append(capabilitiesToString(mCapabilities))
    700                 .append(" Schemes: ");
    701         for (String scheme : mSupportedUriSchemes) {
    702             sb.append(scheme)
    703                     .append(" ");
    704         }
    705         sb.append(" Extras: ");
    706         sb.append(mExtras);
    707         sb.append("]");
    708         return sb.toString();
    709     }
    710 
    711     /**
    712      * Generates a string representation of a capabilities bitmask.
    713      *
    714      * @param capabilities The capabilities bitmask.
    715      * @return String representation of the capabilities bitmask.
    716      */
    717     private String capabilitiesToString(int capabilities) {
    718         StringBuilder sb = new StringBuilder();
    719         if (hasCapabilities(CAPABILITY_VIDEO_CALLING)) {
    720             sb.append("Video ");
    721         }
    722         if (hasCapabilities(CAPABILITY_VIDEO_CALLING_RELIES_ON_PRESENCE)) {
    723             sb.append("Presence ");
    724         }
    725         if (hasCapabilities(CAPABILITY_CALL_PROVIDER)) {
    726             sb.append("CallProvider ");
    727         }
    728         if (hasCapabilities(CAPABILITY_CALL_SUBJECT)) {
    729             sb.append("CallSubject ");
    730         }
    731         if (hasCapabilities(CAPABILITY_CONNECTION_MANAGER)) {
    732             sb.append("ConnectionMgr ");
    733         }
    734         if (hasCapabilities(CAPABILITY_EMERGENCY_CALLS_ONLY)) {
    735             sb.append("EmergOnly ");
    736         }
    737         if (hasCapabilities(CAPABILITY_MULTI_USER)) {
    738             sb.append("MultiUser ");
    739         }
    740         if (hasCapabilities(CAPABILITY_PLACE_EMERGENCY_CALLS)) {
    741             sb.append("PlaceEmerg ");
    742         }
    743         if (hasCapabilities(CAPABILITY_EMERGENCY_VIDEO_CALLING)) {
    744             sb.append("EmergVideo ");
    745         }
    746         if (hasCapabilities(CAPABILITY_SIM_SUBSCRIPTION)) {
    747             sb.append("SimSub ");
    748         }
    749         return sb.toString();
    750     }
    751 }
    752