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.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