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 com.android.server.telecom;
     18 
     19 import android.Manifest;
     20 import android.content.ComponentName;
     21 import android.content.Context;
     22 import android.content.Intent;
     23 import android.content.pm.PackageManager;
     24 import android.content.pm.ResolveInfo;
     25 import android.content.pm.ServiceInfo;
     26 import android.content.pm.UserInfo;
     27 import android.graphics.Bitmap;
     28 import android.graphics.BitmapFactory;
     29 import android.graphics.drawable.Icon;
     30 import android.net.Uri;
     31 import android.os.Bundle;
     32 import android.os.AsyncTask;
     33 import android.os.PersistableBundle;
     34 import android.os.Process;
     35 import android.os.UserHandle;
     36 import android.os.UserManager;
     37 import android.provider.Settings;
     38 import android.telecom.ConnectionService;
     39 import android.telecom.DefaultDialerManager;
     40 import android.telecom.PhoneAccount;
     41 import android.telecom.PhoneAccountHandle;
     42 import android.telephony.CarrierConfigManager;
     43 import android.telephony.PhoneNumberUtils;
     44 import android.telephony.SubscriptionManager;
     45 import android.telephony.TelephonyManager;
     46 import android.text.TextUtils;
     47 import android.util.AtomicFile;
     48 import android.util.Base64;
     49 import android.util.Xml;
     50 
     51 // TODO: Needed for move to system service: import com.android.internal.R;
     52 import com.android.internal.annotations.VisibleForTesting;
     53 import com.android.internal.util.FastXmlSerializer;
     54 import com.android.internal.util.IndentingPrintWriter;
     55 import com.android.internal.util.XmlUtils;
     56 
     57 import org.xmlpull.v1.XmlPullParser;
     58 import org.xmlpull.v1.XmlPullParserException;
     59 import org.xmlpull.v1.XmlSerializer;
     60 
     61 import java.io.BufferedInputStream;
     62 import java.io.ByteArrayInputStream;
     63 import java.io.ByteArrayOutputStream;
     64 import java.io.File;
     65 import java.io.FileNotFoundException;
     66 import java.io.FileOutputStream;
     67 import java.io.IOException;
     68 import java.io.InputStream;
     69 import java.lang.Integer;
     70 import java.lang.SecurityException;
     71 import java.lang.String;
     72 import java.util.ArrayList;
     73 import java.util.Collections;
     74 import java.util.Iterator;
     75 import java.util.List;
     76 import java.util.Map;
     77 import java.util.Objects;
     78 import java.util.Optional;
     79 import java.util.concurrent.ConcurrentHashMap;
     80 import java.util.concurrent.CopyOnWriteArrayList;
     81 import java.util.stream.Collector;
     82 import java.util.stream.Collectors;
     83 import java.util.stream.Stream;
     84 
     85 /**
     86  * Handles writing and reading PhoneAccountHandle registration entries. This is a simple verbatim
     87  * delegate for all the account handling methods on {@link android.telecom.TelecomManager} as
     88  * implemented in {@link TelecomServiceImpl}, with the notable exception that
     89  * {@link TelecomServiceImpl} is responsible for security checking to make sure that the caller has
     90  * proper authority over the {@code ComponentName}s they are declaring in their
     91  * {@code PhoneAccountHandle}s.
     92  *
     93  *
     94  *  -- About Users and Phone Accounts --
     95  *
     96  * We store all phone accounts for all users in a single place, which means that there are three
     97  * users that we have to deal with in code:
     98  * 1) The Android User that is currently active on the device.
     99  * 2) The user which owns/registers the phone account.
    100  * 3) The user running the app that is requesting the phone account information.
    101  *
    102  * For example, I have a device with 2 users, primary (A) and secondary (B), and the secondary user
    103  * has a work profile running as another user (B2). Each user/profile only have the visibility of
    104  * phone accounts owned by them. Lets say, user B (settings) is requesting a list of phone accounts,
    105  * and the list only contains phone accounts owned by user B and accounts with
    106  * {@link PhoneAccount#CAPABILITY_MULTI_USER}.
    107  *
    108  * In practice, (2) is stored with the phone account handle and is part of the handle's ID. (1) is
    109  * saved in {@link #mCurrentUserHandle} and (3) we get from Binder.getCallingUser(). We check these
    110  * users for visibility before returning any phone accounts.
    111  */
    112 public class PhoneAccountRegistrar {
    113 
    114     public static final PhoneAccountHandle NO_ACCOUNT_SELECTED =
    115             new PhoneAccountHandle(new ComponentName("null", "null"), "NO_ACCOUNT_SELECTED");
    116 
    117     public abstract static class Listener {
    118         public void onAccountsChanged(PhoneAccountRegistrar registrar) {}
    119         public void onDefaultOutgoingChanged(PhoneAccountRegistrar registrar) {}
    120         public void onSimCallManagerChanged(PhoneAccountRegistrar registrar) {}
    121     }
    122 
    123     private static final String FILE_NAME = "phone-account-registrar-state.xml";
    124     @VisibleForTesting
    125     public static final int EXPECTED_STATE_VERSION = 9;
    126 
    127     /** Keep in sync with the same in SipSettings.java */
    128     private static final String SIP_SHARED_PREFERENCES = "SIP_PREFERENCES";
    129 
    130     private final List<Listener> mListeners = new CopyOnWriteArrayList<>();
    131     private final AtomicFile mAtomicFile;
    132     private final Context mContext;
    133     private final UserManager mUserManager;
    134     private final SubscriptionManager mSubscriptionManager;
    135     private State mState;
    136     private UserHandle mCurrentUserHandle;
    137     private interface PhoneAccountRegistrarWriteLock {}
    138     private final PhoneAccountRegistrarWriteLock mWriteLock =
    139             new PhoneAccountRegistrarWriteLock() {};
    140 
    141     @VisibleForTesting
    142     public PhoneAccountRegistrar(Context context) {
    143         this(context, FILE_NAME);
    144     }
    145 
    146     @VisibleForTesting
    147     public PhoneAccountRegistrar(Context context, String fileName) {
    148         // TODO: This file path is subject to change -- it is storing the phone account registry
    149         // state file in the path /data/system/users/0/, which is likely not correct in a
    150         // multi-user setting.
    151         /** UNCOMMENT_FOR_MOVE_TO_SYSTEM_SERVICE
    152         String filePath = Environment.getUserSystemDirectory(UserHandle.myUserId()).
    153                 getAbsolutePath();
    154         mAtomicFile = new AtomicFile(new File(filePath, fileName));
    155          UNCOMMENT_FOR_MOVE_TO_SYSTEM_SERVICE */
    156         mAtomicFile = new AtomicFile(new File(context.getFilesDir(), fileName));
    157 
    158         mState = new State();
    159         mContext = context;
    160         mUserManager = UserManager.get(context);
    161         mSubscriptionManager = SubscriptionManager.from(mContext);
    162         mCurrentUserHandle = Process.myUserHandle();
    163         read();
    164     }
    165 
    166     /**
    167      * Retrieves the subscription id for a given phone account if it exists. Subscription ids
    168      * apply only to PSTN/SIM card phone accounts so all other accounts should not have a
    169      * subscription id.
    170      * @param accountHandle The handle for the phone account for which to retrieve the
    171      * subscription id.
    172      * @return The value of the subscription id or -1 if it does not exist or is not valid.
    173      */
    174     public int getSubscriptionIdForPhoneAccount(PhoneAccountHandle accountHandle) {
    175         PhoneAccount account = getPhoneAccountUnchecked(accountHandle);
    176 
    177         if (account != null && account.hasCapabilities(PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION)) {
    178             TelephonyManager tm =
    179                     (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE);
    180             return tm.getSubIdForPhoneAccount(account);
    181         }
    182         return SubscriptionManager.INVALID_SUBSCRIPTION_ID;
    183     }
    184 
    185     /**
    186      * Retrieves the default outgoing phone account supporting the specified uriScheme. Note that if
    187      * {@link #mCurrentUserHandle} does not have visibility into the current default, {@code null}
    188      * will be returned.
    189      *
    190      * @param uriScheme The URI scheme for the outgoing call.
    191      * @return The {@link PhoneAccountHandle} to use.
    192      */
    193     public PhoneAccountHandle getOutgoingPhoneAccountForScheme(String uriScheme,
    194             UserHandle userHandle) {
    195         final PhoneAccountHandle userSelected = getUserSelectedOutgoingPhoneAccount(userHandle);
    196 
    197         if (userSelected != null) {
    198             // If there is a default PhoneAccount, ensure it supports calls to handles with the
    199             // specified uriScheme.
    200             final PhoneAccount userSelectedAccount = getPhoneAccountUnchecked(userSelected);
    201             if (userSelectedAccount.supportsUriScheme(uriScheme)) {
    202                 return userSelected;
    203             }
    204         }
    205 
    206         List<PhoneAccountHandle> outgoing = getCallCapablePhoneAccounts(uriScheme, false,
    207                 userHandle);
    208         switch (outgoing.size()) {
    209             case 0:
    210                 // There are no accounts, so there can be no default
    211                 return null;
    212             case 1:
    213                 // There is only one account, which is by definition the default.
    214                 return outgoing.get(0);
    215             default:
    216                 // There are multiple accounts with no selected default
    217                 return null;
    218         }
    219     }
    220 
    221     public PhoneAccountHandle getOutgoingPhoneAccountForSchemeOfCurrentUser(String uriScheme) {
    222         return getOutgoingPhoneAccountForScheme(uriScheme, mCurrentUserHandle);
    223     }
    224 
    225     /**
    226      * @return The user-selected outgoing {@link PhoneAccount}, or null if it hasn't been set (or
    227      *      if it was set by another user).
    228      */
    229     @VisibleForTesting
    230     public PhoneAccountHandle getUserSelectedOutgoingPhoneAccount(UserHandle userHandle) {
    231         if (userHandle == null) {
    232             return null;
    233         }
    234         DefaultPhoneAccountHandle defaultPhoneAccountHandle = mState.defaultOutgoingAccountHandles
    235                 .get(userHandle);
    236         if (defaultPhoneAccountHandle == null) {
    237             return null;
    238         }
    239         // Make sure the account is still registered and owned by the user.
    240         PhoneAccount account = getPhoneAccount(defaultPhoneAccountHandle.phoneAccountHandle,
    241                 userHandle);
    242 
    243         if (account != null) {
    244             return defaultPhoneAccountHandle.phoneAccountHandle;
    245         }
    246         return null;
    247     }
    248 
    249     /**
    250      * @return The {@link DefaultPhoneAccountHandle} containing the user-selected default calling
    251      * account and group Id for the {@link UserHandle} specified.
    252      */
    253     private DefaultPhoneAccountHandle getUserSelectedDefaultPhoneAccount(UserHandle userHandle) {
    254         if (userHandle == null) {
    255             return null;
    256         }
    257         DefaultPhoneAccountHandle defaultPhoneAccountHandle = mState.defaultOutgoingAccountHandles
    258                 .get(userHandle);
    259         if (defaultPhoneAccountHandle == null) {
    260             return null;
    261         }
    262 
    263         return defaultPhoneAccountHandle;
    264     }
    265 
    266     /**
    267      * @return The currently registered PhoneAccount in Telecom that has the same group Id.
    268      */
    269     private PhoneAccount getPhoneAccountByGroupId(String groupId, ComponentName groupComponentName,
    270             UserHandle userHandle, PhoneAccountHandle excludePhoneAccountHandle) {
    271         if (groupId == null || groupId.isEmpty() || userHandle == null) {
    272             return null;
    273         }
    274         // Get the PhoneAccount with the same group Id (and same ComponentName) that is not the
    275         // newAccount that was just added
    276         List<PhoneAccount> accounts = getAllPhoneAccounts(userHandle).stream()
    277                 .filter(account -> groupId.equals(account.getGroupId()) &&
    278                         !account.getAccountHandle().equals(excludePhoneAccountHandle) &&
    279                         Objects.equals(account.getAccountHandle().getComponentName(),
    280                                 groupComponentName))
    281                 .collect(Collectors.toList());
    282         // There should be one or no PhoneAccounts with the same group Id
    283         if (accounts.size() > 1) {
    284             Log.w(this, "Found multiple PhoneAccounts registered to the same Group Id!");
    285         }
    286         return accounts.isEmpty() ? null : accounts.get(0);
    287     }
    288 
    289     /**
    290      * Sets the phone account with which to place all calls by default. Set by the user
    291      * within phone settings.
    292      */
    293     public void setUserSelectedOutgoingPhoneAccount(PhoneAccountHandle accountHandle,
    294             UserHandle userHandle) {
    295         if (userHandle == null) {
    296             return;
    297         }
    298         if (accountHandle == null) {
    299             // Asking to clear the default outgoing is a valid request
    300             mState.defaultOutgoingAccountHandles.remove(userHandle);
    301         } else {
    302             PhoneAccount account = getPhoneAccount(accountHandle, userHandle);
    303             if (account == null) {
    304                 Log.w(this, "Trying to set nonexistent default outgoing %s",
    305                         accountHandle);
    306                 return;
    307             }
    308 
    309             if (!account.hasCapabilities(PhoneAccount.CAPABILITY_CALL_PROVIDER)) {
    310                 Log.w(this, "Trying to set non-call-provider default outgoing %s",
    311                         accountHandle);
    312                 return;
    313             }
    314 
    315             if (account.hasCapabilities(PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION)) {
    316                 // If the account selected is a SIM account, propagate down to the subscription
    317                 // record.
    318                 int subId = getSubscriptionIdForPhoneAccount(accountHandle);
    319                 mSubscriptionManager.setDefaultVoiceSubId(subId);
    320             }
    321 
    322             mState.defaultOutgoingAccountHandles
    323                     .put(userHandle, new DefaultPhoneAccountHandle(userHandle, accountHandle,
    324                             account.getGroupId()));
    325         }
    326 
    327         write();
    328         fireDefaultOutgoingChanged();
    329     }
    330 
    331     boolean isUserSelectedSmsPhoneAccount(PhoneAccountHandle accountHandle) {
    332         return getSubscriptionIdForPhoneAccount(accountHandle) ==
    333                 SubscriptionManager.getDefaultSmsSubscriptionId();
    334     }
    335 
    336     public ComponentName getSystemSimCallManagerComponent() {
    337         String defaultSimCallManager = null;
    338         CarrierConfigManager configManager = (CarrierConfigManager) mContext.getSystemService(
    339                 Context.CARRIER_CONFIG_SERVICE);
    340         PersistableBundle configBundle = configManager.getConfig();
    341         if (configBundle != null) {
    342             defaultSimCallManager = configBundle.getString(
    343                     CarrierConfigManager.KEY_DEFAULT_SIM_CALL_MANAGER_STRING);
    344         }
    345         return TextUtils.isEmpty(defaultSimCallManager)
    346             ?  null : ComponentName.unflattenFromString(defaultSimCallManager);
    347     }
    348 
    349     public PhoneAccountHandle getSimCallManagerOfCurrentUser() {
    350         return getSimCallManager(mCurrentUserHandle);
    351     }
    352 
    353     /**
    354      * Returns the {@link PhoneAccountHandle} corresponding to the currently active SIM Call
    355      * Manager. SIM Call Manager returned corresponds to the following priority order:
    356      * 1. If a SIM Call Manager {@link PhoneAccount} is registered for the same package as the
    357      * default dialer, then that one is returned.
    358      * 2. If there is a SIM Call Manager {@link PhoneAccount} registered which matches the
    359      * carrier configuration's default, then that one is returned.
    360      * 3. Otherwise, we return null.
    361      */
    362     public PhoneAccountHandle getSimCallManager(UserHandle userHandle) {
    363         // Get the default dialer in case it has a connection manager associated with it.
    364         String dialerPackage = DefaultDialerManager
    365                 .getDefaultDialerApplication(mContext, userHandle.getIdentifier());
    366 
    367         // Check carrier config.
    368         ComponentName systemSimCallManagerComponent = getSystemSimCallManagerComponent();
    369 
    370         PhoneAccountHandle dialerSimCallManager = null;
    371         PhoneAccountHandle systemSimCallManager = null;
    372 
    373         if (!TextUtils.isEmpty(dialerPackage) || systemSimCallManagerComponent != null) {
    374             // loop through and look for any connection manager in the same package.
    375             List<PhoneAccountHandle> allSimCallManagers = getPhoneAccountHandles(
    376                     PhoneAccount.CAPABILITY_CONNECTION_MANAGER, null, null,
    377                     true /* includeDisabledAccounts */, userHandle);
    378             for (PhoneAccountHandle accountHandle : allSimCallManagers) {
    379                 ComponentName component = accountHandle.getComponentName();
    380 
    381                 // Store the system connection manager if found
    382                 if (systemSimCallManager == null
    383                         && Objects.equals(component, systemSimCallManagerComponent)
    384                         && !resolveComponent(accountHandle).isEmpty()) {
    385                     systemSimCallManager = accountHandle;
    386 
    387                 // Store the dialer connection manager if found
    388                 } else if (dialerSimCallManager == null
    389                         && Objects.equals(component.getPackageName(), dialerPackage)
    390                         && !resolveComponent(accountHandle).isEmpty()) {
    391                     dialerSimCallManager = accountHandle;
    392                 }
    393             }
    394         }
    395 
    396         PhoneAccountHandle retval = dialerSimCallManager != null ?
    397                 dialerSimCallManager : systemSimCallManager;
    398 
    399         Log.i(this, "SimCallManager queried, returning: %s", retval);
    400 
    401         return retval;
    402     }
    403 
    404     /**
    405      * If it is a outgoing call, sim call manager of call-initiating user is returned.
    406      * Otherwise, we return the sim call manager of the user associated with the
    407      * target phone account.
    408      * @return phone account handle of sim call manager based on the ongoing call.
    409      */
    410     public PhoneAccountHandle getSimCallManagerFromCall(Call call) {
    411         if (call == null) {
    412             return null;
    413         }
    414         UserHandle userHandle = call.getInitiatingUser();
    415         if (userHandle == null) {
    416             userHandle = call.getTargetPhoneAccount().getUserHandle();
    417         }
    418         return getSimCallManager(userHandle);
    419     }
    420 
    421     /**
    422      * Update the current UserHandle to track when users are switched. This will allow the
    423      * PhoneAccountRegistar to self-filter the PhoneAccounts to make sure we don't leak anything
    424      * across users.
    425      * We cannot simply check the calling user because that would always return the primary user for
    426      * all invocations originating with the system process.
    427      *
    428      * @param userHandle The {@link UserHandle}, as delivered by
    429      *          {@link Intent#ACTION_USER_SWITCHED}.
    430      */
    431     public void setCurrentUserHandle(UserHandle userHandle) {
    432         if (userHandle == null) {
    433             Log.d(this, "setCurrentUserHandle, userHandle = null");
    434             userHandle = Process.myUserHandle();
    435         }
    436         Log.d(this, "setCurrentUserHandle, %s", userHandle);
    437         mCurrentUserHandle = userHandle;
    438     }
    439 
    440     /**
    441      * @return {@code true} if the phone account was successfully enabled/disabled, {@code false}
    442      *         otherwise.
    443      */
    444     public boolean enablePhoneAccount(PhoneAccountHandle accountHandle, boolean isEnabled) {
    445         PhoneAccount account = getPhoneAccountUnchecked(accountHandle);
    446         if (account == null) {
    447             Log.w(this, "Could not find account to enable: " + accountHandle);
    448             return false;
    449         } else if (account.hasCapabilities(PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION)) {
    450             // We never change the enabled state of SIM-based accounts.
    451             Log.w(this, "Could not change enable state of SIM account: " + accountHandle);
    452             return false;
    453         }
    454 
    455         if (account.isEnabled() != isEnabled) {
    456             account.setIsEnabled(isEnabled);
    457             if (!isEnabled) {
    458                 // If the disabled account is the default, remove it.
    459                 removeDefaultPhoneAccountHandle(accountHandle);
    460             }
    461             write();
    462             fireAccountsChanged();
    463         }
    464         return true;
    465     }
    466 
    467     private void removeDefaultPhoneAccountHandle(PhoneAccountHandle phoneAccountHandle) {
    468         Iterator<Map.Entry<UserHandle, DefaultPhoneAccountHandle>> iterator =
    469                 mState.defaultOutgoingAccountHandles.entrySet().iterator();
    470         while (iterator.hasNext()) {
    471             Map.Entry<UserHandle, DefaultPhoneAccountHandle> entry = iterator.next();
    472             if (phoneAccountHandle.equals(entry.getValue().phoneAccountHandle)) {
    473                 iterator.remove();
    474             }
    475         }
    476     }
    477 
    478     private boolean isVisibleForUser(PhoneAccount account, UserHandle userHandle,
    479             boolean acrossProfiles) {
    480         if (account == null) {
    481             return false;
    482         }
    483 
    484         if (userHandle == null) {
    485             Log.w(this, "userHandle is null in isVisibleForUser");
    486             return false;
    487         }
    488 
    489         // If this PhoneAccount has CAPABILITY_MULTI_USER, it should be visible to all users and
    490         // all profiles. Only Telephony and SIP accounts should have this capability.
    491         if (account.hasCapabilities(PhoneAccount.CAPABILITY_MULTI_USER)) {
    492             return true;
    493         }
    494 
    495         UserHandle phoneAccountUserHandle = account.getAccountHandle().getUserHandle();
    496         if (phoneAccountUserHandle == null) {
    497             return false;
    498         }
    499 
    500         if (mCurrentUserHandle == null) {
    501             // In case we need to have emergency phone calls from the lock screen.
    502             Log.d(this, "Current user is null; assuming true");
    503             return true;
    504         }
    505 
    506         if (acrossProfiles) {
    507             return UserManager.get(mContext).isSameProfileGroup(userHandle.getIdentifier(),
    508                     phoneAccountUserHandle.getIdentifier());
    509         } else {
    510             return phoneAccountUserHandle.equals(userHandle);
    511         }
    512     }
    513 
    514     private List<ResolveInfo> resolveComponent(PhoneAccountHandle phoneAccountHandle) {
    515         return resolveComponent(phoneAccountHandle.getComponentName(),
    516                 phoneAccountHandle.getUserHandle());
    517     }
    518 
    519     private List<ResolveInfo> resolveComponent(ComponentName componentName,
    520             UserHandle userHandle) {
    521         PackageManager pm = mContext.getPackageManager();
    522         Intent intent = new Intent(ConnectionService.SERVICE_INTERFACE);
    523         intent.setComponent(componentName);
    524         try {
    525             if (userHandle != null) {
    526                 return pm.queryIntentServicesAsUser(intent, 0, userHandle.getIdentifier());
    527             } else {
    528                 return pm.queryIntentServices(intent, 0);
    529             }
    530         } catch (SecurityException e) {
    531             Log.e(this, e, "%s is not visible for the calling user", componentName);
    532             return Collections.EMPTY_LIST;
    533         }
    534     }
    535 
    536     /**
    537      * Retrieves a list of all {@link PhoneAccountHandle}s registered.
    538      * Only returns accounts which are enabled.
    539      *
    540      * @return The list of {@link PhoneAccountHandle}s.
    541      */
    542     public List<PhoneAccountHandle> getAllPhoneAccountHandles(UserHandle userHandle) {
    543         return getPhoneAccountHandles(0, null, null, false, userHandle);
    544     }
    545 
    546     public List<PhoneAccount> getAllPhoneAccounts(UserHandle userHandle) {
    547         return getPhoneAccounts(0, null, null, false, userHandle);
    548     }
    549 
    550     public List<PhoneAccount> getAllPhoneAccountsOfCurrentUser() {
    551         return getAllPhoneAccounts(mCurrentUserHandle);
    552     }
    553 
    554     /**
    555      * Retrieves a list of all phone account call provider phone accounts supporting the
    556      * specified URI scheme.
    557      *
    558      * @param uriScheme The URI scheme.
    559      * @return The phone account handles.
    560      */
    561     public List<PhoneAccountHandle> getCallCapablePhoneAccounts(
    562             String uriScheme, boolean includeDisabledAccounts, UserHandle userHandle) {
    563         return getPhoneAccountHandles(
    564                 PhoneAccount.CAPABILITY_CALL_PROVIDER,
    565                 PhoneAccount.CAPABILITY_EMERGENCY_CALLS_ONLY /*excludedCapabilities*/,
    566                 uriScheme, null, includeDisabledAccounts, userHandle);
    567     }
    568 
    569     public List<PhoneAccountHandle> getCallCapablePhoneAccountsOfCurrentUser(
    570             String uriScheme, boolean includeDisabledAccounts) {
    571         return getCallCapablePhoneAccounts(uriScheme, includeDisabledAccounts, mCurrentUserHandle);
    572     }
    573 
    574     /**
    575      * Retrieves a list of all the SIM-based phone accounts.
    576      */
    577     public List<PhoneAccountHandle> getSimPhoneAccounts(UserHandle userHandle) {
    578         return getPhoneAccountHandles(
    579                 PhoneAccount.CAPABILITY_CALL_PROVIDER | PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION,
    580                 null, null, false, userHandle);
    581     }
    582 
    583     public List<PhoneAccountHandle> getSimPhoneAccountsOfCurrentUser() {
    584         return getSimPhoneAccounts(mCurrentUserHandle);
    585     }
    586 
    587         /**
    588          * Retrieves a list of all phone accounts registered by a specified package.
    589          *
    590          * @param packageName The name of the package that registered the phone accounts.
    591          * @return The phone account handles.
    592          */
    593     public List<PhoneAccountHandle> getPhoneAccountsForPackage(String packageName,
    594             UserHandle userHandle) {
    595         return getPhoneAccountHandles(0, null, packageName, false, userHandle);
    596     }
    597 
    598     // TODO: Should we implement an artificial limit for # of accounts associated with a single
    599     // ComponentName?
    600     public void registerPhoneAccount(PhoneAccount account) {
    601         // Enforce the requirement that a connection service for a phone account has the correct
    602         // permission.
    603         if (!phoneAccountRequiresBindPermission(account.getAccountHandle())) {
    604             Log.w(this,
    605                     "Phone account %s does not have BIND_TELECOM_CONNECTION_SERVICE permission.",
    606                     account.getAccountHandle());
    607             throw new SecurityException("PhoneAccount connection service requires "
    608                     + "BIND_TELECOM_CONNECTION_SERVICE permission.");
    609         }
    610 
    611         addOrReplacePhoneAccount(account);
    612     }
    613 
    614     /**
    615      * Adds a {@code PhoneAccount}, replacing an existing one if found.
    616      *
    617      * @param account The {@code PhoneAccount} to add or replace.
    618      */
    619     private void addOrReplacePhoneAccount(PhoneAccount account) {
    620         Log.d(this, "addOrReplacePhoneAccount(%s -> %s)",
    621                 account.getAccountHandle(), account);
    622 
    623         // Start _enabled_ property as false.
    624         // !!! IMPORTANT !!! It is important that we do not read the enabled state that the
    625         // source app provides or else an third party app could enable itself.
    626         boolean isEnabled = false;
    627 
    628         PhoneAccount oldAccount = getPhoneAccountUnchecked(account.getAccountHandle());
    629         if (oldAccount != null) {
    630             mState.accounts.remove(oldAccount);
    631             isEnabled = oldAccount.isEnabled();
    632             Log.i(this, getAccountDiffString(account, oldAccount));
    633         } else {
    634             Log.i(this, "New phone account registered: " + account);
    635         }
    636 
    637         mState.accounts.add(account);
    638         // Set defaults and replace based on the group Id.
    639         maybeReplaceOldAccount(account);
    640         // Reset enabled state to whatever the value was if the account was already registered,
    641         // or _true_ if this is a SIM-based account.  All SIM-based accounts are always enabled.
    642         account.setIsEnabled(
    643                 isEnabled || account.hasCapabilities(PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION));
    644 
    645         write();
    646         fireAccountsChanged();
    647     }
    648 
    649     public void unregisterPhoneAccount(PhoneAccountHandle accountHandle) {
    650         PhoneAccount account = getPhoneAccountUnchecked(accountHandle);
    651         if (account != null) {
    652             if (mState.accounts.remove(account)) {
    653                 write();
    654                 fireAccountsChanged();
    655             }
    656         }
    657     }
    658 
    659     /**
    660      * Un-registers all phone accounts associated with a specified package.
    661      *
    662      * @param packageName The package for which phone accounts will be removed.
    663      * @param userHandle The {@link UserHandle} the package is running under.
    664      */
    665     public void clearAccounts(String packageName, UserHandle userHandle) {
    666         boolean accountsRemoved = false;
    667         Iterator<PhoneAccount> it = mState.accounts.iterator();
    668         while (it.hasNext()) {
    669             PhoneAccount phoneAccount = it.next();
    670             PhoneAccountHandle handle = phoneAccount.getAccountHandle();
    671             if (Objects.equals(packageName, handle.getComponentName().getPackageName())
    672                     && Objects.equals(userHandle, handle.getUserHandle())) {
    673                 Log.i(this, "Removing phone account " + phoneAccount.getLabel());
    674                 mState.accounts.remove(phoneAccount);
    675                 accountsRemoved = true;
    676             }
    677         }
    678 
    679         if (accountsRemoved) {
    680             write();
    681             fireAccountsChanged();
    682         }
    683     }
    684 
    685     public boolean isVoiceMailNumber(PhoneAccountHandle accountHandle, String number) {
    686         int subId = getSubscriptionIdForPhoneAccount(accountHandle);
    687         return PhoneNumberUtils.isVoiceMailNumber(mContext, subId, number);
    688     }
    689 
    690     public void addListener(Listener l) {
    691         mListeners.add(l);
    692     }
    693 
    694     public void removeListener(Listener l) {
    695         if (l != null) {
    696             mListeners.remove(l);
    697         }
    698     }
    699 
    700     private void fireAccountsChanged() {
    701         for (Listener l : mListeners) {
    702             l.onAccountsChanged(this);
    703         }
    704     }
    705 
    706     private void fireDefaultOutgoingChanged() {
    707         for (Listener l : mListeners) {
    708             l.onDefaultOutgoingChanged(this);
    709         }
    710     }
    711 
    712     private String getAccountDiffString(PhoneAccount account1, PhoneAccount account2) {
    713         if (account1 == null || account2 == null) {
    714             return "Diff: " + account1 + ", " + account2;
    715         }
    716 
    717         StringBuffer sb = new StringBuffer();
    718         sb.append("[").append(account1.getAccountHandle());
    719         appendDiff(sb, "addr", Log.piiHandle(account1.getAddress()),
    720                 Log.piiHandle(account2.getAddress()));
    721         appendDiff(sb, "cap", account1.getCapabilities(), account2.getCapabilities());
    722         appendDiff(sb, "hl", account1.getHighlightColor(), account2.getHighlightColor());
    723         appendDiff(sb, "icon", account1.getIcon(), account2.getIcon());
    724         appendDiff(sb, "lbl", account1.getLabel(), account2.getLabel());
    725         appendDiff(sb, "desc", account1.getShortDescription(), account2.getShortDescription());
    726         appendDiff(sb, "subAddr", Log.piiHandle(account1.getSubscriptionAddress()),
    727                 Log.piiHandle(account2.getSubscriptionAddress()));
    728         appendDiff(sb, "uris", account1.getSupportedUriSchemes(),
    729                 account2.getSupportedUriSchemes());
    730         sb.append("]");
    731         return sb.toString();
    732     }
    733 
    734     private void appendDiff(StringBuffer sb, String attrName, Object obj1, Object obj2) {
    735         if (!Objects.equals(obj1, obj2)) {
    736             sb.append("(")
    737                 .append(attrName)
    738                 .append(": ")
    739                 .append(obj1)
    740                 .append(" -> ")
    741                 .append(obj2)
    742                 .append(")");
    743         }
    744     }
    745 
    746     private void maybeReplaceOldAccount(PhoneAccount newAccount) {
    747         UserHandle newAccountUserHandle = newAccount.getAccountHandle().getUserHandle();
    748         DefaultPhoneAccountHandle defaultHandle =
    749                 getUserSelectedDefaultPhoneAccount(newAccountUserHandle);
    750         if (defaultHandle == null || defaultHandle.groupId.isEmpty()) {
    751             Log.v(this, "maybeReplaceOldAccount: Not replacing PhoneAccount, no group Id or " +
    752                     "default.");
    753             return;
    754         }
    755         if (!defaultHandle.groupId.equals(newAccount.getGroupId())) {
    756             Log.v(this, "maybeReplaceOldAccount: group Ids are not equal.");
    757             return;
    758         }
    759         if (Objects.equals(newAccount.getAccountHandle().getComponentName(),
    760                 defaultHandle.phoneAccountHandle.getComponentName())) {
    761             // Move default calling account over to new user, since the ComponentNames and Group Ids
    762             // are the same.
    763             setUserSelectedOutgoingPhoneAccount(newAccount.getAccountHandle(),
    764                     newAccountUserHandle);
    765         } else {
    766             Log.v(this, "maybeReplaceOldAccount: group Ids are equal, but ComponentName is not" +
    767                     " the same as the default. Not replacing default PhoneAccount.");
    768         }
    769         PhoneAccount replacementAccount = getPhoneAccountByGroupId(newAccount.getGroupId(),
    770                 newAccount.getAccountHandle().getComponentName(), newAccountUserHandle,
    771                 newAccount.getAccountHandle());
    772         if (replacementAccount != null) {
    773             // Unregister the old PhoneAccount.
    774             Log.v(this, "maybeReplaceOldAccount: Unregistering old PhoneAccount: " +
    775                     replacementAccount.getAccountHandle());
    776             unregisterPhoneAccount(replacementAccount.getAccountHandle());
    777         }
    778     }
    779 
    780     /**
    781      * Determines if the connection service specified by a {@link PhoneAccountHandle} requires the
    782      * {@link Manifest.permission#BIND_TELECOM_CONNECTION_SERVICE} permission.
    783      *
    784      * @param phoneAccountHandle The phone account to check.
    785      * @return {@code True} if the phone account has permission.
    786      */
    787     public boolean phoneAccountRequiresBindPermission(PhoneAccountHandle phoneAccountHandle) {
    788         List<ResolveInfo> resolveInfos = resolveComponent(phoneAccountHandle);
    789         if (resolveInfos.isEmpty()) {
    790             Log.w(this, "phoneAccount %s not found", phoneAccountHandle.getComponentName());
    791             return false;
    792         }
    793         for (ResolveInfo resolveInfo : resolveInfos) {
    794             ServiceInfo serviceInfo = resolveInfo.serviceInfo;
    795             if (serviceInfo == null) {
    796                 return false;
    797             }
    798 
    799             if (!Manifest.permission.BIND_CONNECTION_SERVICE.equals(serviceInfo.permission) &&
    800                     !Manifest.permission.BIND_TELECOM_CONNECTION_SERVICE.equals(
    801                             serviceInfo.permission)) {
    802                 // The ConnectionService must require either the deprecated BIND_CONNECTION_SERVICE,
    803                 // or the public BIND_TELECOM_CONNECTION_SERVICE permissions, both of which are
    804                 // system/signature only.
    805                 return false;
    806             }
    807         }
    808         return true;
    809     }
    810 
    811     //
    812     // Methods for retrieving PhoneAccounts and PhoneAccountHandles
    813     //
    814 
    815     /**
    816      * Returns the PhoneAccount for the specified handle.  Does no user checking.
    817      *
    818      * @param handle
    819      * @return The corresponding phone account if one exists.
    820      */
    821     public PhoneAccount getPhoneAccountUnchecked(PhoneAccountHandle handle) {
    822         for (PhoneAccount m : mState.accounts) {
    823             if (Objects.equals(handle, m.getAccountHandle())) {
    824                 return m;
    825             }
    826         }
    827         return null;
    828     }
    829 
    830     /**
    831      * Like getPhoneAccount, but checks to see if the current user is allowed to see the phone
    832      * account before returning it. The current user is the active user on the actual android
    833      * device.
    834      */
    835     public PhoneAccount getPhoneAccount(PhoneAccountHandle handle, UserHandle userHandle) {
    836         return getPhoneAccount(handle, userHandle, /* acrossProfiles */ false);
    837     }
    838 
    839     public PhoneAccount getPhoneAccount(PhoneAccountHandle handle,
    840             UserHandle userHandle, boolean acrossProfiles) {
    841         PhoneAccount account = getPhoneAccountUnchecked(handle);
    842         if (account != null && (isVisibleForUser(account, userHandle, acrossProfiles))) {
    843             return account;
    844         }
    845         return null;
    846     }
    847 
    848     public PhoneAccount getPhoneAccountOfCurrentUser(PhoneAccountHandle handle) {
    849         return getPhoneAccount(handle, mCurrentUserHandle);
    850     }
    851 
    852     private List<PhoneAccountHandle> getPhoneAccountHandles(
    853             int capabilities,
    854             String uriScheme,
    855             String packageName,
    856             boolean includeDisabledAccounts,
    857             UserHandle userHandle) {
    858         return getPhoneAccountHandles(capabilities, 0 /*excludedCapabilities*/, uriScheme,
    859                 packageName, includeDisabledAccounts, userHandle);
    860     }
    861 
    862     /**
    863      * Returns a list of phone account handles with the specified capabilities, uri scheme,
    864      * and package name.
    865      */
    866     private List<PhoneAccountHandle> getPhoneAccountHandles(
    867             int capabilities,
    868             int excludedCapabilities,
    869             String uriScheme,
    870             String packageName,
    871             boolean includeDisabledAccounts,
    872             UserHandle userHandle) {
    873         List<PhoneAccountHandle> handles = new ArrayList<>();
    874 
    875         for (PhoneAccount account : getPhoneAccounts(
    876                 capabilities, excludedCapabilities, uriScheme, packageName,
    877                 includeDisabledAccounts, userHandle)) {
    878             handles.add(account.getAccountHandle());
    879         }
    880         return handles;
    881     }
    882 
    883     private List<PhoneAccount> getPhoneAccounts(
    884             int capabilities,
    885             String uriScheme,
    886             String packageName,
    887             boolean includeDisabledAccounts,
    888             UserHandle userHandle) {
    889         return getPhoneAccounts(capabilities, 0 /*excludedCapabilities*/, uriScheme, packageName,
    890                 includeDisabledAccounts, userHandle);
    891     }
    892 
    893     /**
    894      * Returns a list of phone account handles with the specified flag, supporting the specified
    895      * URI scheme, within the specified package name.
    896      *
    897      * @param capabilities Capabilities which the {@code PhoneAccount} must have. Ignored if 0.
    898      * @param excludedCapabilities Capabilities which the {@code PhoneAccount} must not have.
    899      *                             Ignored if 0.
    900      * @param uriScheme URI schemes the PhoneAccount must handle.  {@code null} bypasses the
    901      *                  URI scheme check.
    902      * @param packageName Package name of the PhoneAccount. {@code null} bypasses packageName check.
    903      */
    904     private List<PhoneAccount> getPhoneAccounts(
    905             int capabilities,
    906             int excludedCapabilities,
    907             String uriScheme,
    908             String packageName,
    909             boolean includeDisabledAccounts,
    910             UserHandle userHandle) {
    911         List<PhoneAccount> accounts = new ArrayList<>(mState.accounts.size());
    912         for (PhoneAccount m : mState.accounts) {
    913             if (!(m.isEnabled() || includeDisabledAccounts)) {
    914                 // Do not include disabled accounts.
    915                 continue;
    916             }
    917 
    918             if ((m.getCapabilities() & excludedCapabilities) != 0) {
    919                 // If an excluded capability is present, skip.
    920                 continue;
    921             }
    922 
    923             if (capabilities != 0 && !m.hasCapabilities(capabilities)) {
    924                 // Account doesn't have the right capabilities; skip this one.
    925                 continue;
    926             }
    927             if (uriScheme != null && !m.supportsUriScheme(uriScheme)) {
    928                 // Account doesn't support this URI scheme; skip this one.
    929                 continue;
    930             }
    931             PhoneAccountHandle handle = m.getAccountHandle();
    932 
    933             if (resolveComponent(handle).isEmpty()) {
    934                 // This component cannot be resolved anymore; skip this one.
    935                 continue;
    936             }
    937             if (packageName != null &&
    938                     !packageName.equals(handle.getComponentName().getPackageName())) {
    939                 // Not the right package name; skip this one.
    940                 continue;
    941             }
    942             if (!isVisibleForUser(m, userHandle, false)) {
    943                 // Account is not visible for the current user; skip this one.
    944                 continue;
    945             }
    946             accounts.add(m);
    947         }
    948         return accounts;
    949     }
    950 
    951     //
    952     // State Implementation for PhoneAccountRegistrar
    953     //
    954 
    955     /**
    956      * The state of this {@code PhoneAccountRegistrar}.
    957      */
    958     @VisibleForTesting
    959     public static class State {
    960         /**
    961          * Store the default phone account handle of users. If no record of a user can be found in
    962          * the map, it means that no default phone account handle is set in that user.
    963          */
    964         public final Map<UserHandle, DefaultPhoneAccountHandle> defaultOutgoingAccountHandles
    965                 = new ConcurrentHashMap<>();
    966 
    967         /**
    968          * The complete list of {@code PhoneAccount}s known to the Telecom subsystem.
    969          */
    970         public final List<PhoneAccount> accounts = new CopyOnWriteArrayList<>();
    971 
    972         /**
    973          * The version number of the State data.
    974          */
    975         public int versionNumber;
    976     }
    977 
    978     /**
    979      * The default {@link PhoneAccountHandle} of a user.
    980      */
    981     public static class DefaultPhoneAccountHandle {
    982 
    983         public final UserHandle userHandle;
    984 
    985         public final PhoneAccountHandle phoneAccountHandle;
    986 
    987         public final String groupId;
    988 
    989         public DefaultPhoneAccountHandle(UserHandle userHandle,
    990                 PhoneAccountHandle phoneAccountHandle, String groupId) {
    991             this.userHandle = userHandle;
    992             this.phoneAccountHandle = phoneAccountHandle;
    993             this.groupId = groupId;
    994         }
    995     }
    996 
    997     /**
    998      * Dumps the state of the {@link CallsManager}.
    999      *
   1000      * @param pw The {@code IndentingPrintWriter} to write the state to.
   1001      */
   1002     public void dump(IndentingPrintWriter pw) {
   1003         if (mState != null) {
   1004             pw.println("xmlVersion: " + mState.versionNumber);
   1005             DefaultPhoneAccountHandle defaultPhoneAccountHandle
   1006                     = mState.defaultOutgoingAccountHandles.get(Process.myUserHandle());
   1007             pw.println("defaultOutgoing: " + (defaultPhoneAccountHandle == null ? "none" :
   1008                     defaultPhoneAccountHandle.phoneAccountHandle));
   1009             pw.println("simCallManager: " + getSimCallManager(mCurrentUserHandle));
   1010             pw.println("phoneAccounts:");
   1011             pw.increaseIndent();
   1012             for (PhoneAccount phoneAccount : mState.accounts) {
   1013                 pw.println(phoneAccount);
   1014             }
   1015             pw.decreaseIndent();
   1016         }
   1017     }
   1018 
   1019     ////////////////////////////////////////////////////////////////////////////////////////////////
   1020     //
   1021     // State management
   1022     //
   1023 
   1024     private class AsyncXmlWriter extends AsyncTask<ByteArrayOutputStream, Void, Void> {
   1025         @Override
   1026         public Void doInBackground(ByteArrayOutputStream... args) {
   1027             final ByteArrayOutputStream buffer = args[0];
   1028             FileOutputStream fileOutput = null;
   1029             try {
   1030                 synchronized (mWriteLock) {
   1031                     fileOutput = mAtomicFile.startWrite();
   1032                     buffer.writeTo(fileOutput);
   1033                     mAtomicFile.finishWrite(fileOutput);
   1034                 }
   1035             } catch (IOException e) {
   1036                 Log.e(this, e, "Writing state to XML file");
   1037                 mAtomicFile.failWrite(fileOutput);
   1038             }
   1039             return null;
   1040         }
   1041     }
   1042 
   1043     private void write() {
   1044         try {
   1045             ByteArrayOutputStream os = new ByteArrayOutputStream();
   1046             XmlSerializer serializer = new FastXmlSerializer();
   1047             serializer.setOutput(os, "utf-8");
   1048             writeToXml(mState, serializer, mContext);
   1049             serializer.flush();
   1050             new AsyncXmlWriter().execute(os);
   1051         } catch (IOException e) {
   1052             Log.e(this, e, "Writing state to XML buffer");
   1053         }
   1054     }
   1055 
   1056     private void read() {
   1057         final InputStream is;
   1058         try {
   1059             is = mAtomicFile.openRead();
   1060         } catch (FileNotFoundException ex) {
   1061             return;
   1062         }
   1063 
   1064         boolean versionChanged = false;
   1065 
   1066         XmlPullParser parser;
   1067         try {
   1068             parser = Xml.newPullParser();
   1069             parser.setInput(new BufferedInputStream(is), null);
   1070             parser.nextTag();
   1071             mState = readFromXml(parser, mContext);
   1072             versionChanged = mState.versionNumber < EXPECTED_STATE_VERSION;
   1073 
   1074         } catch (IOException | XmlPullParserException e) {
   1075             Log.e(this, e, "Reading state from XML file");
   1076             mState = new State();
   1077         } finally {
   1078             try {
   1079                 is.close();
   1080             } catch (IOException e) {
   1081                 Log.e(this, e, "Closing InputStream");
   1082             }
   1083         }
   1084 
   1085         // Verify all of the UserHandles.
   1086         List<PhoneAccount> badAccounts = new ArrayList<>();
   1087         for (PhoneAccount phoneAccount : mState.accounts) {
   1088             UserHandle userHandle = phoneAccount.getAccountHandle().getUserHandle();
   1089             if (userHandle == null) {
   1090                 Log.w(this, "Missing UserHandle for %s", phoneAccount);
   1091                 badAccounts.add(phoneAccount);
   1092             } else if (mUserManager.getSerialNumberForUser(userHandle) == -1) {
   1093                 Log.w(this, "User does not exist for %s", phoneAccount);
   1094                 badAccounts.add(phoneAccount);
   1095             }
   1096         }
   1097         mState.accounts.removeAll(badAccounts);
   1098 
   1099         // If an upgrade occurred, write out the changed data.
   1100         if (versionChanged || !badAccounts.isEmpty()) {
   1101             write();
   1102         }
   1103     }
   1104 
   1105     private static void writeToXml(State state, XmlSerializer serializer, Context context)
   1106             throws IOException {
   1107         sStateXml.writeToXml(state, serializer, context);
   1108     }
   1109 
   1110     private static State readFromXml(XmlPullParser parser, Context context)
   1111             throws IOException, XmlPullParserException {
   1112         State s = sStateXml.readFromXml(parser, 0, context);
   1113         return s != null ? s : new State();
   1114     }
   1115 
   1116     ////////////////////////////////////////////////////////////////////////////////////////////////
   1117     //
   1118     // XML serialization
   1119     //
   1120 
   1121     @VisibleForTesting
   1122     public abstract static class XmlSerialization<T> {
   1123         private static final String TAG_VALUE = "value";
   1124         private static final String ATTRIBUTE_LENGTH = "length";
   1125         private static final String ATTRIBUTE_KEY = "key";
   1126         private static final String ATTRIBUTE_VALUE_TYPE = "type";
   1127         private static final String VALUE_TYPE_STRING = "string";
   1128         private static final String VALUE_TYPE_INTEGER = "integer";
   1129         private static final String VALUE_TYPE_BOOLEAN = "boolean";
   1130 
   1131         /**
   1132          * Write the supplied object to XML
   1133          */
   1134         public abstract void writeToXml(T o, XmlSerializer serializer, Context context)
   1135                 throws IOException;
   1136 
   1137         /**
   1138          * Read from the supplied XML into a new object, returning null in case of an
   1139          * unrecoverable schema mismatch or other data error. 'parser' must be already
   1140          * positioned at the first tag that is expected to have been emitted by this
   1141          * object's writeToXml(). This object tries to fail early without modifying
   1142          * 'parser' if it does not recognize the data it sees.
   1143          */
   1144         public abstract T readFromXml(XmlPullParser parser, int version, Context context)
   1145                 throws IOException, XmlPullParserException;
   1146 
   1147         protected void writeTextIfNonNull(String tagName, Object value, XmlSerializer serializer)
   1148                 throws IOException {
   1149             if (value != null) {
   1150                 serializer.startTag(null, tagName);
   1151                 serializer.text(Objects.toString(value));
   1152                 serializer.endTag(null, tagName);
   1153             }
   1154         }
   1155 
   1156         /**
   1157          * Serializes a string array.
   1158          *
   1159          * @param tagName The tag name for the string array.
   1160          * @param values The string values to serialize.
   1161          * @param serializer The serializer.
   1162          * @throws IOException
   1163          */
   1164         protected void writeStringList(String tagName, List<String> values,
   1165                 XmlSerializer serializer)
   1166                 throws IOException {
   1167 
   1168             serializer.startTag(null, tagName);
   1169             if (values != null) {
   1170                 serializer.attribute(null, ATTRIBUTE_LENGTH, Objects.toString(values.size()));
   1171                 for (String toSerialize : values) {
   1172                     serializer.startTag(null, TAG_VALUE);
   1173                     if (toSerialize != null ){
   1174                         serializer.text(toSerialize);
   1175                     }
   1176                     serializer.endTag(null, TAG_VALUE);
   1177                 }
   1178             } else {
   1179                 serializer.attribute(null, ATTRIBUTE_LENGTH, "0");
   1180             }
   1181             serializer.endTag(null, tagName);
   1182         }
   1183 
   1184         protected void writeBundle(String tagName, Bundle values, XmlSerializer serializer)
   1185             throws IOException {
   1186 
   1187             serializer.startTag(null, tagName);
   1188             if (values != null) {
   1189                 for (String key : values.keySet()) {
   1190                     Object value = values.get(key);
   1191 
   1192                     if (value == null) {
   1193                         continue;
   1194                     }
   1195 
   1196                     String valueType;
   1197                     if (value instanceof String) {
   1198                         valueType = VALUE_TYPE_STRING;
   1199                     } else if (value instanceof Integer) {
   1200                         valueType = VALUE_TYPE_INTEGER;
   1201                     } else if (value instanceof Boolean) {
   1202                         valueType = VALUE_TYPE_BOOLEAN;
   1203                     } else {
   1204                         Log.w(this,
   1205                                 "PhoneAccounts support only string, integer and boolean extras TY.");
   1206                         continue;
   1207                     }
   1208 
   1209                     serializer.startTag(null, TAG_VALUE);
   1210                     serializer.attribute(null, ATTRIBUTE_KEY, key);
   1211                     serializer.attribute(null, ATTRIBUTE_VALUE_TYPE, valueType);
   1212                     serializer.text(Objects.toString(value));
   1213                     serializer.endTag(null, TAG_VALUE);
   1214                 }
   1215             }
   1216             serializer.endTag(null, tagName);
   1217         }
   1218 
   1219         protected void writeIconIfNonNull(String tagName, Icon value, XmlSerializer serializer)
   1220                 throws IOException {
   1221             if (value != null) {
   1222                 ByteArrayOutputStream stream = new ByteArrayOutputStream();
   1223                 value.writeToStream(stream);
   1224                 byte[] iconByteArray = stream.toByteArray();
   1225                 String text = Base64.encodeToString(iconByteArray, 0, iconByteArray.length, 0);
   1226 
   1227                 serializer.startTag(null, tagName);
   1228                 serializer.text(text);
   1229                 serializer.endTag(null, tagName);
   1230             }
   1231         }
   1232 
   1233         protected void writeLong(String tagName, long value, XmlSerializer serializer)
   1234                 throws IOException {
   1235             serializer.startTag(null, tagName);
   1236             serializer.text(Long.valueOf(value).toString());
   1237             serializer.endTag(null, tagName);
   1238         }
   1239 
   1240         protected void writeNonNullString(String tagName, String value, XmlSerializer serializer)
   1241                 throws IOException {
   1242             serializer.startTag(null, tagName);
   1243             serializer.text(value != null ? value : "");
   1244             serializer.endTag(null, tagName);
   1245         }
   1246 
   1247         /**
   1248          * Reads a string array from the XML parser.
   1249          *
   1250          * @param parser The XML parser.
   1251          * @return String array containing the parsed values.
   1252          * @throws IOException Exception related to IO.
   1253          * @throws XmlPullParserException Exception related to parsing.
   1254          */
   1255         protected List<String> readStringList(XmlPullParser parser)
   1256                 throws IOException, XmlPullParserException {
   1257 
   1258             int length = Integer.parseInt(parser.getAttributeValue(null, ATTRIBUTE_LENGTH));
   1259             List<String> arrayEntries = new ArrayList<String>(length);
   1260             String value = null;
   1261 
   1262             if (length == 0) {
   1263                 return arrayEntries;
   1264             }
   1265 
   1266             int outerDepth = parser.getDepth();
   1267             while (XmlUtils.nextElementWithin(parser, outerDepth)) {
   1268                 if (parser.getName().equals(TAG_VALUE)) {
   1269                     parser.next();
   1270                     value = parser.getText();
   1271                     arrayEntries.add(value);
   1272                 }
   1273             }
   1274 
   1275             return arrayEntries;
   1276         }
   1277 
   1278         /**
   1279          * Reads a bundle from the XML parser.
   1280          *
   1281          * @param parser The XML parser.
   1282          * @return Bundle containing the parsed values.
   1283          * @throws IOException Exception related to IO.
   1284          * @throws XmlPullParserException Exception related to parsing.
   1285          */
   1286         protected Bundle readBundle(XmlPullParser parser)
   1287                 throws IOException, XmlPullParserException {
   1288 
   1289             Bundle bundle = null;
   1290             int outerDepth = parser.getDepth();
   1291             while (XmlUtils.nextElementWithin(parser, outerDepth)) {
   1292                 if (parser.getName().equals(TAG_VALUE)) {
   1293                     String valueType = parser.getAttributeValue(null, ATTRIBUTE_VALUE_TYPE);
   1294                     String key = parser.getAttributeValue(null, ATTRIBUTE_KEY);
   1295                     parser.next();
   1296                     String value = parser.getText();
   1297 
   1298                     if (bundle == null) {
   1299                         bundle = new Bundle();
   1300                     }
   1301 
   1302                     // Do not write null values to the bundle.
   1303                     if (value == null) {
   1304                         continue;
   1305                     }
   1306 
   1307                     if (VALUE_TYPE_STRING.equals(valueType)) {
   1308                         bundle.putString(key, value);
   1309                     } else if (VALUE_TYPE_INTEGER.equals(valueType)) {
   1310                         try {
   1311                             int intValue = Integer.parseInt(value);
   1312                             bundle.putInt(key, intValue);
   1313                         } catch (NumberFormatException nfe) {
   1314                             Log.w(this, "Invalid integer PhoneAccount extra.");
   1315                         }
   1316                     } else if (VALUE_TYPE_BOOLEAN.equals(valueType)) {
   1317                         boolean boolValue = Boolean.parseBoolean(value);
   1318                         bundle.putBoolean(key, boolValue);
   1319                     } else {
   1320                         Log.w(this, "Invalid type " + valueType + " for PhoneAccount bundle.");
   1321                     }
   1322                 }
   1323             }
   1324             return bundle;
   1325         }
   1326 
   1327         protected Bitmap readBitmap(XmlPullParser parser) {
   1328             byte[] imageByteArray = Base64.decode(parser.getText(), 0);
   1329             return BitmapFactory.decodeByteArray(imageByteArray, 0, imageByteArray.length);
   1330         }
   1331 
   1332         protected Icon readIcon(XmlPullParser parser) throws IOException {
   1333             byte[] iconByteArray = Base64.decode(parser.getText(), 0);
   1334             ByteArrayInputStream stream = new ByteArrayInputStream(iconByteArray);
   1335             return Icon.createFromStream(stream);
   1336         }
   1337     }
   1338 
   1339     @VisibleForTesting
   1340     public static final XmlSerialization<State> sStateXml =
   1341             new XmlSerialization<State>() {
   1342         private static final String CLASS_STATE = "phone_account_registrar_state";
   1343         private static final String DEFAULT_OUTGOING = "default_outgoing";
   1344         private static final String ACCOUNTS = "accounts";
   1345         private static final String VERSION = "version";
   1346 
   1347         @Override
   1348         public void writeToXml(State o, XmlSerializer serializer, Context context)
   1349                 throws IOException {
   1350             if (o != null) {
   1351                 serializer.startTag(null, CLASS_STATE);
   1352                 serializer.attribute(null, VERSION, Objects.toString(EXPECTED_STATE_VERSION));
   1353 
   1354                 serializer.startTag(null, DEFAULT_OUTGOING);
   1355                 for (DefaultPhoneAccountHandle defaultPhoneAccountHandle : o
   1356                         .defaultOutgoingAccountHandles.values()) {
   1357                     sDefaultPhoneAcountHandleXml
   1358                             .writeToXml(defaultPhoneAccountHandle, serializer, context);
   1359                 }
   1360                 serializer.endTag(null, DEFAULT_OUTGOING);
   1361 
   1362                 serializer.startTag(null, ACCOUNTS);
   1363                 for (PhoneAccount m : o.accounts) {
   1364                     sPhoneAccountXml.writeToXml(m, serializer, context);
   1365                 }
   1366                 serializer.endTag(null, ACCOUNTS);
   1367 
   1368                 serializer.endTag(null, CLASS_STATE);
   1369             }
   1370         }
   1371 
   1372         @Override
   1373         public State readFromXml(XmlPullParser parser, int version, Context context)
   1374                 throws IOException, XmlPullParserException {
   1375             if (parser.getName().equals(CLASS_STATE)) {
   1376                 State s = new State();
   1377 
   1378                 String rawVersion = parser.getAttributeValue(null, VERSION);
   1379                 s.versionNumber = TextUtils.isEmpty(rawVersion) ? 1 : Integer.parseInt(rawVersion);
   1380 
   1381                 int outerDepth = parser.getDepth();
   1382                 while (XmlUtils.nextElementWithin(parser, outerDepth)) {
   1383                     if (parser.getName().equals(DEFAULT_OUTGOING)) {
   1384                         if (s.versionNumber < 9) {
   1385                             // Migrate old default phone account handle here by assuming the
   1386                             // default phone account handle belongs to the primary user. Also,
   1387                             // assume there are no groups.
   1388                             parser.nextTag();
   1389                             PhoneAccountHandle phoneAccountHandle = sPhoneAccountHandleXml
   1390                                     .readFromXml(parser, s.versionNumber, context);
   1391                             UserManager userManager = UserManager.get(context);
   1392                             UserInfo primaryUser = userManager.getPrimaryUser();
   1393                             if (primaryUser != null) {
   1394                                 UserHandle userHandle = primaryUser.getUserHandle();
   1395                                 DefaultPhoneAccountHandle defaultPhoneAccountHandle
   1396                                         = new DefaultPhoneAccountHandle(userHandle,
   1397                                         phoneAccountHandle, "" /* groupId */);
   1398                                 s.defaultOutgoingAccountHandles
   1399                                         .put(userHandle, defaultPhoneAccountHandle);
   1400                             }
   1401                         } else {
   1402                             int defaultAccountHandlesDepth = parser.getDepth();
   1403                             while (XmlUtils.nextElementWithin(parser, defaultAccountHandlesDepth)) {
   1404                                 DefaultPhoneAccountHandle accountHandle
   1405                                         = sDefaultPhoneAcountHandleXml
   1406                                         .readFromXml(parser, s.versionNumber, context);
   1407                                 if (accountHandle != null && s.accounts != null) {
   1408                                     s.defaultOutgoingAccountHandles
   1409                                             .put(accountHandle.userHandle, accountHandle);
   1410                                 }
   1411                             }
   1412                         }
   1413                     } else if (parser.getName().equals(ACCOUNTS)) {
   1414                         int accountsDepth = parser.getDepth();
   1415                         while (XmlUtils.nextElementWithin(parser, accountsDepth)) {
   1416                             PhoneAccount account = sPhoneAccountXml.readFromXml(parser,
   1417                                     s.versionNumber, context);
   1418 
   1419                             if (account != null && s.accounts != null) {
   1420                                 s.accounts.add(account);
   1421                             }
   1422                         }
   1423                     }
   1424                 }
   1425                 return s;
   1426             }
   1427             return null;
   1428         }
   1429     };
   1430 
   1431     @VisibleForTesting
   1432     public static final XmlSerialization<DefaultPhoneAccountHandle> sDefaultPhoneAcountHandleXml  =
   1433             new XmlSerialization<DefaultPhoneAccountHandle>() {
   1434                 private static final String CLASS_DEFAULT_OUTGOING_PHONE_ACCOUNT_HANDLE
   1435                         = "default_outgoing_phone_account_handle";
   1436                 private static final String USER_SERIAL_NUMBER = "user_serial_number";
   1437                 private static final String GROUP_ID = "group_id";
   1438                 private static final String ACCOUNT_HANDLE = "account_handle";
   1439 
   1440                 @Override
   1441                 public void writeToXml(DefaultPhoneAccountHandle o, XmlSerializer serializer,
   1442                         Context context) throws IOException {
   1443                     if (o != null) {
   1444                         final UserManager userManager = UserManager.get(context);
   1445                         final long serialNumber = userManager.getSerialNumberForUser(o.userHandle);
   1446                         if (serialNumber != -1) {
   1447                             serializer.startTag(null, CLASS_DEFAULT_OUTGOING_PHONE_ACCOUNT_HANDLE);
   1448                             writeLong(USER_SERIAL_NUMBER, serialNumber, serializer);
   1449                             writeNonNullString(GROUP_ID, o.groupId, serializer);
   1450                             serializer.startTag(null, ACCOUNT_HANDLE);
   1451                             sPhoneAccountHandleXml.writeToXml(o.phoneAccountHandle, serializer,
   1452                                     context);
   1453                             serializer.endTag(null, ACCOUNT_HANDLE);
   1454                             serializer.endTag(null, CLASS_DEFAULT_OUTGOING_PHONE_ACCOUNT_HANDLE);
   1455                         }
   1456                     }
   1457                 }
   1458 
   1459                 @Override
   1460                 public DefaultPhoneAccountHandle readFromXml(XmlPullParser parser, int version,
   1461                         Context context)
   1462                         throws IOException, XmlPullParserException {
   1463                     if (parser.getName().equals(CLASS_DEFAULT_OUTGOING_PHONE_ACCOUNT_HANDLE)) {
   1464                         int outerDepth = parser.getDepth();
   1465                         PhoneAccountHandle accountHandle = null;
   1466                         String userSerialNumberString = null;
   1467                         String groupId = "";
   1468                         while (XmlUtils.nextElementWithin(parser, outerDepth)) {
   1469                             if (parser.getName().equals(ACCOUNT_HANDLE)) {
   1470                                 parser.nextTag();
   1471                                 accountHandle = sPhoneAccountHandleXml.readFromXml(parser, version,
   1472                                         context);
   1473                             } else if (parser.getName().equals(USER_SERIAL_NUMBER)) {
   1474                                 parser.next();
   1475                                 userSerialNumberString = parser.getText();
   1476                             } else if (parser.getName().equals(GROUP_ID)) {
   1477                                 parser.next();
   1478                                 groupId = parser.getText();
   1479                             }
   1480                         }
   1481                         UserHandle userHandle = null;
   1482                         if (userSerialNumberString != null) {
   1483                             try {
   1484                                 long serialNumber = Long.parseLong(userSerialNumberString);
   1485                                 userHandle = UserManager.get(context)
   1486                                         .getUserForSerialNumber(serialNumber);
   1487                             } catch (NumberFormatException e) {
   1488                                 Log.e(this, e,
   1489                                         "Could not parse UserHandle " + userSerialNumberString);
   1490                             }
   1491                         }
   1492                         if (accountHandle != null && userHandle != null && groupId != null) {
   1493                             return new DefaultPhoneAccountHandle(userHandle, accountHandle,
   1494                                     groupId);
   1495                         }
   1496                     }
   1497                     return null;
   1498                 }
   1499             };
   1500 
   1501 
   1502     @VisibleForTesting
   1503     public static final XmlSerialization<PhoneAccount> sPhoneAccountXml =
   1504             new XmlSerialization<PhoneAccount>() {
   1505         private static final String CLASS_PHONE_ACCOUNT = "phone_account";
   1506         private static final String ACCOUNT_HANDLE = "account_handle";
   1507         private static final String ADDRESS = "handle";
   1508         private static final String SUBSCRIPTION_ADDRESS = "subscription_number";
   1509         private static final String CAPABILITIES = "capabilities";
   1510         private static final String ICON_RES_ID = "icon_res_id";
   1511         private static final String ICON_PACKAGE_NAME = "icon_package_name";
   1512         private static final String ICON_BITMAP = "icon_bitmap";
   1513         private static final String ICON_TINT = "icon_tint";
   1514         private static final String HIGHLIGHT_COLOR = "highlight_color";
   1515         private static final String LABEL = "label";
   1516         private static final String SHORT_DESCRIPTION = "short_description";
   1517         private static final String SUPPORTED_URI_SCHEMES = "supported_uri_schemes";
   1518         private static final String ICON = "icon";
   1519         private static final String EXTRAS = "extras";
   1520         private static final String ENABLED = "enabled";
   1521 
   1522         @Override
   1523         public void writeToXml(PhoneAccount o, XmlSerializer serializer, Context context)
   1524                 throws IOException {
   1525             if (o != null) {
   1526                 serializer.startTag(null, CLASS_PHONE_ACCOUNT);
   1527 
   1528                 if (o.getAccountHandle() != null) {
   1529                     serializer.startTag(null, ACCOUNT_HANDLE);
   1530                     sPhoneAccountHandleXml.writeToXml(o.getAccountHandle(), serializer, context);
   1531                     serializer.endTag(null, ACCOUNT_HANDLE);
   1532                 }
   1533 
   1534                 writeTextIfNonNull(ADDRESS, o.getAddress(), serializer);
   1535                 writeTextIfNonNull(SUBSCRIPTION_ADDRESS, o.getSubscriptionAddress(), serializer);
   1536                 writeTextIfNonNull(CAPABILITIES, Integer.toString(o.getCapabilities()), serializer);
   1537                 writeIconIfNonNull(ICON, o.getIcon(), serializer);
   1538                 writeTextIfNonNull(HIGHLIGHT_COLOR,
   1539                         Integer.toString(o.getHighlightColor()), serializer);
   1540                 writeTextIfNonNull(LABEL, o.getLabel(), serializer);
   1541                 writeTextIfNonNull(SHORT_DESCRIPTION, o.getShortDescription(), serializer);
   1542                 writeStringList(SUPPORTED_URI_SCHEMES, o.getSupportedUriSchemes(), serializer);
   1543                 writeBundle(EXTRAS, o.getExtras(), serializer);
   1544                 writeTextIfNonNull(ENABLED, o.isEnabled() ? "true" : "false" , serializer);
   1545 
   1546                 serializer.endTag(null, CLASS_PHONE_ACCOUNT);
   1547             }
   1548         }
   1549 
   1550         public PhoneAccount readFromXml(XmlPullParser parser, int version, Context context)
   1551                 throws IOException, XmlPullParserException {
   1552             if (parser.getName().equals(CLASS_PHONE_ACCOUNT)) {
   1553                 int outerDepth = parser.getDepth();
   1554                 PhoneAccountHandle accountHandle = null;
   1555                 Uri address = null;
   1556                 Uri subscriptionAddress = null;
   1557                 int capabilities = 0;
   1558                 int iconResId = PhoneAccount.NO_RESOURCE_ID;
   1559                 String iconPackageName = null;
   1560                 Bitmap iconBitmap = null;
   1561                 int iconTint = PhoneAccount.NO_ICON_TINT;
   1562                 int highlightColor = PhoneAccount.NO_HIGHLIGHT_COLOR;
   1563                 String label = null;
   1564                 String shortDescription = null;
   1565                 List<String> supportedUriSchemes = null;
   1566                 Icon icon = null;
   1567                 boolean enabled = false;
   1568                 Bundle extras = null;
   1569 
   1570                 while (XmlUtils.nextElementWithin(parser, outerDepth)) {
   1571                     if (parser.getName().equals(ACCOUNT_HANDLE)) {
   1572                         parser.nextTag();
   1573                         accountHandle = sPhoneAccountHandleXml.readFromXml(parser, version,
   1574                                 context);
   1575                     } else if (parser.getName().equals(ADDRESS)) {
   1576                         parser.next();
   1577                         address = Uri.parse(parser.getText());
   1578                     } else if (parser.getName().equals(SUBSCRIPTION_ADDRESS)) {
   1579                         parser.next();
   1580                         String nextText = parser.getText();
   1581                         subscriptionAddress = nextText == null ? null : Uri.parse(nextText);
   1582                     } else if (parser.getName().equals(CAPABILITIES)) {
   1583                         parser.next();
   1584                         capabilities = Integer.parseInt(parser.getText());
   1585                     } else if (parser.getName().equals(ICON_RES_ID)) {
   1586                         parser.next();
   1587                         iconResId = Integer.parseInt(parser.getText());
   1588                     } else if (parser.getName().equals(ICON_PACKAGE_NAME)) {
   1589                         parser.next();
   1590                         iconPackageName = parser.getText();
   1591                     } else if (parser.getName().equals(ICON_BITMAP)) {
   1592                         parser.next();
   1593                         iconBitmap = readBitmap(parser);
   1594                     } else if (parser.getName().equals(ICON_TINT)) {
   1595                         parser.next();
   1596                         iconTint = Integer.parseInt(parser.getText());
   1597                     } else if (parser.getName().equals(HIGHLIGHT_COLOR)) {
   1598                         parser.next();
   1599                         highlightColor = Integer.parseInt(parser.getText());
   1600                     } else if (parser.getName().equals(LABEL)) {
   1601                         parser.next();
   1602                         label = parser.getText();
   1603                     } else if (parser.getName().equals(SHORT_DESCRIPTION)) {
   1604                         parser.next();
   1605                         shortDescription = parser.getText();
   1606                     } else if (parser.getName().equals(SUPPORTED_URI_SCHEMES)) {
   1607                         supportedUriSchemes = readStringList(parser);
   1608                     } else if (parser.getName().equals(ICON)) {
   1609                         parser.next();
   1610                         icon = readIcon(parser);
   1611                     } else if (parser.getName().equals(ENABLED)) {
   1612                         parser.next();
   1613                         enabled = "true".equalsIgnoreCase(parser.getText());
   1614                     } else if (parser.getName().equals(EXTRAS)) {
   1615                         extras = readBundle(parser);
   1616                     }
   1617                 }
   1618 
   1619                 ComponentName pstnComponentName = new ComponentName("com.android.phone",
   1620                         "com.android.services.telephony.TelephonyConnectionService");
   1621                 ComponentName sipComponentName = new ComponentName("com.android.phone",
   1622                         "com.android.services.telephony.sip.SipConnectionService");
   1623 
   1624                 // Upgrade older phone accounts to specify the supported URI schemes.
   1625                 if (version < 2) {
   1626                     supportedUriSchemes = new ArrayList<>();
   1627 
   1628                     // Handle the SIP connection service.
   1629                     // Check the system settings to see if it also should handle "tel" calls.
   1630                     if (accountHandle.getComponentName().equals(sipComponentName)) {
   1631                         boolean useSipForPstn = useSipForPstnCalls(context);
   1632                         supportedUriSchemes.add(PhoneAccount.SCHEME_SIP);
   1633                         if (useSipForPstn) {
   1634                             supportedUriSchemes.add(PhoneAccount.SCHEME_TEL);
   1635                         }
   1636                     } else {
   1637                         supportedUriSchemes.add(PhoneAccount.SCHEME_TEL);
   1638                         supportedUriSchemes.add(PhoneAccount.SCHEME_VOICEMAIL);
   1639                     }
   1640                 }
   1641 
   1642                 // Upgrade older phone accounts with explicit package name
   1643                 if (version < 5) {
   1644                     if (iconBitmap == null) {
   1645                         iconPackageName = accountHandle.getComponentName().getPackageName();
   1646                     }
   1647                 }
   1648 
   1649                 if (version < 6) {
   1650                     // Always enable all SIP accounts on upgrade to version 6
   1651                     if (accountHandle.getComponentName().equals(sipComponentName)) {
   1652                         enabled = true;
   1653                     }
   1654                 }
   1655                 if (version < 7) {
   1656                     // Always enabled all PSTN acocunts on upgrade to version 7
   1657                     if (accountHandle.getComponentName().equals(pstnComponentName)) {
   1658                         enabled = true;
   1659                     }
   1660                 }
   1661                 if (version < 8) {
   1662                     // Migrate the SIP account handle ids to use SIP username instead of SIP URI.
   1663                     if (accountHandle.getComponentName().equals(sipComponentName)) {
   1664                         Uri accountUri = Uri.parse(accountHandle.getId());
   1665                         if (accountUri.getScheme() != null &&
   1666                             accountUri.getScheme().equals(PhoneAccount.SCHEME_SIP)) {
   1667                             accountHandle = new PhoneAccountHandle(accountHandle.getComponentName(),
   1668                                     accountUri.getSchemeSpecificPart(),
   1669                                     accountHandle.getUserHandle());
   1670                         }
   1671                     }
   1672                 }
   1673 
   1674                 PhoneAccount.Builder builder = PhoneAccount.builder(accountHandle, label)
   1675                         .setAddress(address)
   1676                         .setSubscriptionAddress(subscriptionAddress)
   1677                         .setCapabilities(capabilities)
   1678                         .setShortDescription(shortDescription)
   1679                         .setSupportedUriSchemes(supportedUriSchemes)
   1680                         .setHighlightColor(highlightColor)
   1681                         .setExtras(extras)
   1682                         .setIsEnabled(enabled);
   1683 
   1684                 if (icon != null) {
   1685                     builder.setIcon(icon);
   1686                 } else if (iconBitmap != null) {
   1687                     builder.setIcon(Icon.createWithBitmap(iconBitmap));
   1688                 } else if (!TextUtils.isEmpty(iconPackageName)) {
   1689                     builder.setIcon(Icon.createWithResource(iconPackageName, iconResId));
   1690                     // TODO: Need to set tint.
   1691                 }
   1692 
   1693                 return builder.build();
   1694             }
   1695             return null;
   1696         }
   1697 
   1698         /**
   1699          * Determines if the SIP call settings specify to use SIP for all calls, including PSTN
   1700          * calls.
   1701          *
   1702          * @param context The context.
   1703          * @return {@code True} if SIP should be used for all calls.
   1704          */
   1705         private boolean useSipForPstnCalls(Context context) {
   1706             String option = Settings.System.getString(context.getContentResolver(),
   1707                     Settings.System.SIP_CALL_OPTIONS);
   1708             option = (option != null) ? option : Settings.System.SIP_ADDRESS_ONLY;
   1709             return option.equals(Settings.System.SIP_ALWAYS);
   1710         }
   1711     };
   1712 
   1713     @VisibleForTesting
   1714     public static final XmlSerialization<PhoneAccountHandle> sPhoneAccountHandleXml =
   1715             new XmlSerialization<PhoneAccountHandle>() {
   1716         private static final String CLASS_PHONE_ACCOUNT_HANDLE = "phone_account_handle";
   1717         private static final String COMPONENT_NAME = "component_name";
   1718         private static final String ID = "id";
   1719         private static final String USER_SERIAL_NUMBER = "user_serial_number";
   1720 
   1721         @Override
   1722         public void writeToXml(PhoneAccountHandle o, XmlSerializer serializer, Context context)
   1723                 throws IOException {
   1724             if (o != null) {
   1725                 serializer.startTag(null, CLASS_PHONE_ACCOUNT_HANDLE);
   1726 
   1727                 if (o.getComponentName() != null) {
   1728                     writeTextIfNonNull(
   1729                             COMPONENT_NAME, o.getComponentName().flattenToString(), serializer);
   1730                 }
   1731 
   1732                 writeTextIfNonNull(ID, o.getId(), serializer);
   1733 
   1734                 if (o.getUserHandle() != null && context != null) {
   1735                     UserManager userManager = UserManager.get(context);
   1736                     writeLong(USER_SERIAL_NUMBER,
   1737                             userManager.getSerialNumberForUser(o.getUserHandle()), serializer);
   1738                 }
   1739 
   1740                 serializer.endTag(null, CLASS_PHONE_ACCOUNT_HANDLE);
   1741             }
   1742         }
   1743 
   1744         @Override
   1745         public PhoneAccountHandle readFromXml(XmlPullParser parser, int version, Context context)
   1746                 throws IOException, XmlPullParserException {
   1747             if (parser.getName().equals(CLASS_PHONE_ACCOUNT_HANDLE)) {
   1748                 String componentNameString = null;
   1749                 String idString = null;
   1750                 String userSerialNumberString = null;
   1751                 int outerDepth = parser.getDepth();
   1752 
   1753                 UserManager userManager = UserManager.get(context);
   1754 
   1755                 while (XmlUtils.nextElementWithin(parser, outerDepth)) {
   1756                     if (parser.getName().equals(COMPONENT_NAME)) {
   1757                         parser.next();
   1758                         componentNameString = parser.getText();
   1759                     } else if (parser.getName().equals(ID)) {
   1760                         parser.next();
   1761                         idString = parser.getText();
   1762                     } else if (parser.getName().equals(USER_SERIAL_NUMBER)) {
   1763                         parser.next();
   1764                         userSerialNumberString = parser.getText();
   1765                     }
   1766                 }
   1767                 if (componentNameString != null) {
   1768                     UserHandle userHandle = null;
   1769                     if (userSerialNumberString != null) {
   1770                         try {
   1771                             long serialNumber = Long.parseLong(userSerialNumberString);
   1772                             userHandle = userManager.getUserForSerialNumber(serialNumber);
   1773                         } catch (NumberFormatException e) {
   1774                             Log.e(this, e, "Could not parse UserHandle " + userSerialNumberString);
   1775                         }
   1776                     }
   1777                     return new PhoneAccountHandle(
   1778                             ComponentName.unflattenFromString(componentNameString),
   1779                             idString,
   1780                             userHandle);
   1781                 }
   1782             }
   1783             return null;
   1784         }
   1785     };
   1786 }
   1787