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