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.app.ActivityManager;
     20 import android.Manifest;
     21 import android.content.ComponentName;
     22 import android.content.Context;
     23 import android.content.Intent;
     24 import android.content.pm.PackageManager;
     25 import android.content.pm.ResolveInfo;
     26 import android.content.pm.ServiceInfo;
     27 import android.content.pm.UserInfo;
     28 import android.graphics.Bitmap;
     29 import android.graphics.BitmapFactory;
     30 import android.graphics.drawable.Icon;
     31 import android.net.Uri;
     32 import android.os.Binder;
     33 import android.os.PersistableBundle;
     34 import android.os.Process;
     35 import android.os.UserHandle;
     36 import android.os.UserManager;
     37 import android.provider.Settings;
     38 import android.telecom.ConnectionService;
     39 import android.telecom.DefaultDialerManager;
     40 import android.telecom.PhoneAccount;
     41 import android.telecom.PhoneAccountHandle;
     42 import android.telephony.CarrierConfigManager;
     43 import android.telephony.PhoneNumberUtils;
     44 import android.telephony.SubscriptionManager;
     45 import android.telephony.TelephonyManager;
     46 import android.text.TextUtils;
     47 import android.util.AtomicFile;
     48 import android.util.Base64;
     49 import android.util.Xml;
     50 
     51 // TODO: Needed for move to system service: import com.android.internal.R;
     52 import com.android.internal.annotations.VisibleForTesting;
     53 import com.android.internal.util.FastXmlSerializer;
     54 import com.android.internal.util.IndentingPrintWriter;
     55 import com.android.internal.util.XmlUtils;
     56 
     57 import org.xmlpull.v1.XmlPullParser;
     58 import org.xmlpull.v1.XmlPullParserException;
     59 import org.xmlpull.v1.XmlSerializer;
     60 
     61 import java.io.BufferedInputStream;
     62 import java.io.BufferedOutputStream;
     63 import java.io.ByteArrayInputStream;
     64 import java.io.ByteArrayOutputStream;
     65 import java.io.File;
     66 import java.io.FileNotFoundException;
     67 import java.io.FileOutputStream;
     68 import java.io.IOException;
     69 import java.io.InputStream;
     70 import java.lang.Integer;
     71 import java.lang.SecurityException;
     72 import java.lang.String;
     73 import java.util.ArrayList;
     74 import java.util.Collections;
     75 import java.util.Iterator;
     76 import java.util.List;
     77 import java.util.Objects;
     78 import java.util.concurrent.CopyOnWriteArrayList;
     79 
     80 /**
     81  * Handles writing and reading PhoneAccountHandle registration entries. This is a simple verbatim
     82  * delegate for all the account handling methods on {@link android.telecom.TelecomManager} as
     83  * implemented in {@link TelecomServiceImpl}, with the notable exception that
     84  * {@link TelecomServiceImpl} is responsible for security checking to make sure that the caller has
     85  * proper authority over the {@code ComponentName}s they are declaring in their
     86  * {@code PhoneAccountHandle}s.
     87  *
     88  *
     89  *  -- About Users and Phone Accounts --
     90  *
     91  * We store all phone accounts for all users in a single place, which means that there are three
     92  * users that we have to deal with in code:
     93  * 1) The Android User that is currently active on the device.
     94  * 2) The user which owns/registers the phone account.
     95  * 3) The user running the app that is requesting the phone account information.
     96  *
     97  * For example, I have a device with 2 users, primary (A) and secondary (B), and the secondary user
     98  * has a work profile running as another user (B2). Lets say that user B opens the phone settings
     99  * (not currently supported, but theoretically speaking), and phone settings queries for a phone
    100  * account list. Lets also say that an app running in the work profile has registered a phone
    101  * account. This means that:
    102  *
    103  * Since phone settings always runs as the primary user, We have the following situation:
    104  * User A (settings) is requesting a list of phone accounts while the active user is User B, and
    105  * that list contains a phone account for profile User B2.
    106  *
    107  * In practice, (2) is stored with the phone account handle and is part of the handle's ID. (1) is
    108  * saved in {@link #mCurrentUserHandle} and (3) we get from Binder.getCallingUser(). We check these
    109  * users for visibility before returning any phone accounts.
    110  */
    111 public final class PhoneAccountRegistrar {
    112 
    113     public static final PhoneAccountHandle NO_ACCOUNT_SELECTED =
    114             new PhoneAccountHandle(new ComponentName("null", "null"), "NO_ACCOUNT_SELECTED");
    115 
    116     public abstract static class Listener {
    117         public void onAccountsChanged(PhoneAccountRegistrar registrar) {}
    118         public void onDefaultOutgoingChanged(PhoneAccountRegistrar registrar) {}
    119         public void onSimCallManagerChanged(PhoneAccountRegistrar registrar) {}
    120     }
    121 
    122     private static final String FILE_NAME = "phone-account-registrar-state.xml";
    123     @VisibleForTesting
    124     public static final int EXPECTED_STATE_VERSION = 8;
    125 
    126     /** Keep in sync with the same in SipSettings.java */
    127     private static final String SIP_SHARED_PREFERENCES = "SIP_PREFERENCES";
    128 
    129     private final List<Listener> mListeners = new CopyOnWriteArrayList<>();
    130     private final AtomicFile mAtomicFile;
    131     private final Context mContext;
    132     private final UserManager mUserManager;
    133     private final SubscriptionManager mSubscriptionManager;
    134     private State mState;
    135     private UserHandle mCurrentUserHandle;
    136 
    137     @VisibleForTesting
    138     public PhoneAccountRegistrar(Context context) {
    139         this(context, FILE_NAME);
    140     }
    141 
    142     @VisibleForTesting
    143     public PhoneAccountRegistrar(Context context, String fileName) {
    144         // TODO: This file path is subject to change -- it is storing the phone account registry
    145         // state file in the path /data/system/users/0/, which is likely not correct in a
    146         // multi-user setting.
    147         /** UNCOMMENT_FOR_MOVE_TO_SYSTEM_SERVICE
    148         String filePath = Environment.getUserSystemDirectory(UserHandle.myUserId()).
    149                 getAbsolutePath();
    150         mAtomicFile = new AtomicFile(new File(filePath, fileName));
    151          UNCOMMENT_FOR_MOVE_TO_SYSTEM_SERVICE */
    152         mAtomicFile = new AtomicFile(new File(context.getFilesDir(), fileName));
    153 
    154         mState = new State();
    155         mContext = context;
    156         mUserManager = UserManager.get(context);
    157         mSubscriptionManager = SubscriptionManager.from(mContext);
    158         mCurrentUserHandle = Process.myUserHandle();
    159         read();
    160     }
    161 
    162     /**
    163      * Retrieves the subscription id for a given phone account if it exists. Subscription ids
    164      * apply only to PSTN/SIM card phone accounts so all other accounts should not have a
    165      * subscription id.
    166      * @param accountHandle The handle for the phone account for which to retrieve the
    167      * subscription id.
    168      * @return The value of the subscription id or -1 if it does not exist or is not valid.
    169      */
    170     public int getSubscriptionIdForPhoneAccount(PhoneAccountHandle accountHandle) {
    171         PhoneAccount account = getPhoneAccountCheckCallingUser(accountHandle);
    172 
    173         if (account != null && account.hasCapabilities(PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION)) {
    174             TelephonyManager tm =
    175                     (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE);
    176             return tm.getSubIdForPhoneAccount(account);
    177         }
    178         return SubscriptionManager.INVALID_SUBSCRIPTION_ID;
    179     }
    180 
    181     /**
    182      * Retrieves the default outgoing phone account supporting the specified uriScheme. Note that if
    183      * {@link #mCurrentUserHandle} does not have visibility into the current default, {@code null}
    184      * will be returned.
    185      *
    186      * @param uriScheme The URI scheme for the outgoing call.
    187      * @return The {@link PhoneAccountHandle} to use.
    188      */
    189     public PhoneAccountHandle getOutgoingPhoneAccountForScheme(String uriScheme) {
    190         final PhoneAccountHandle userSelected = getUserSelectedOutgoingPhoneAccount();
    191 
    192         if (userSelected != null) {
    193             // If there is a default PhoneAccount, ensure it supports calls to handles with the
    194             // specified uriScheme.
    195             final PhoneAccount userSelectedAccount = getPhoneAccountCheckCallingUser(userSelected);
    196             if (userSelectedAccount.supportsUriScheme(uriScheme)) {
    197                 return userSelected;
    198             }
    199         }
    200 
    201         List<PhoneAccountHandle> outgoing = getCallCapablePhoneAccounts(uriScheme, false);
    202         switch (outgoing.size()) {
    203             case 0:
    204                 // There are no accounts, so there can be no default
    205                 return null;
    206             case 1:
    207                 // There is only one account, which is by definition the default.
    208                 return outgoing.get(0);
    209             default:
    210                 // There are multiple accounts with no selected default
    211                 return null;
    212         }
    213     }
    214 
    215     /**
    216      * @return The user-selected outgoing {@link PhoneAccount}, or null if it hasn't been set (or
    217      *      if it was set by another user).
    218      */
    219     PhoneAccountHandle getUserSelectedOutgoingPhoneAccount() {
    220         PhoneAccount account = getPhoneAccountCheckCallingUser(mState.defaultOutgoing);
    221         if (account != null) {
    222             return mState.defaultOutgoing;
    223         }
    224         return null;
    225     }
    226 
    227     /**
    228      * Sets the phone account with which to place all calls by default. Set by the user
    229      * within phone settings.
    230      */
    231     public void setUserSelectedOutgoingPhoneAccount(PhoneAccountHandle accountHandle) {
    232         if (accountHandle == null) {
    233             // Asking to clear the default outgoing is a valid request
    234             mState.defaultOutgoing = null;
    235         } else {
    236             // TODO: Do we really want to return for *any* user?
    237             PhoneAccount account = getPhoneAccount(accountHandle);
    238             if (account == null) {
    239                 Log.w(this, "Trying to set nonexistent default outgoing %s",
    240                         accountHandle);
    241                 return;
    242             }
    243 
    244             if (!account.hasCapabilities(PhoneAccount.CAPABILITY_CALL_PROVIDER)) {
    245                 Log.w(this, "Trying to set non-call-provider default outgoing %s",
    246                         accountHandle);
    247                 return;
    248             }
    249 
    250             if (account.hasCapabilities(PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION)) {
    251                 // If the account selected is a SIM account, propagate down to the subscription
    252                 // record.
    253                 int subId = getSubscriptionIdForPhoneAccount(accountHandle);
    254                 mSubscriptionManager.setDefaultVoiceSubId(subId);
    255             }
    256 
    257             mState.defaultOutgoing = accountHandle;
    258         }
    259 
    260         write();
    261         fireDefaultOutgoingChanged();
    262     }
    263 
    264     boolean isUserSelectedSmsPhoneAccount(PhoneAccountHandle accountHandle) {
    265         return getSubscriptionIdForPhoneAccount(accountHandle) ==
    266                 SubscriptionManager.getDefaultSmsSubId();
    267     }
    268 
    269     /**
    270      * Returns the {@link PhoneAccountHandle} corresponding to the currently active SIM Call
    271      * Manager. SIM Call Manager returned corresponds to the following priority order:
    272      * 1. If a SIM Call Manager {@link PhoneAccount} is registered for the same package as the
    273      * default dialer, then that one is returned.
    274      * 2. If there is a SIM Call Manager {@link PhoneAccount} registered which matches the
    275      * carrier configuration's default, then that one is returned.
    276      * 3. Otherwise, we return null.
    277      */
    278     public PhoneAccountHandle getSimCallManager() {
    279         long token = Binder.clearCallingIdentity();
    280         int user;
    281         try {
    282             user = ActivityManager.getCurrentUser();
    283         } finally {
    284             Binder.restoreCallingIdentity(token);
    285         }
    286         return getSimCallManager(user);
    287     }
    288 
    289     /**
    290      * Returns the {@link PhoneAccountHandle} corresponding to the currently active SIM Call
    291      * Manager. SIM Call Manager returned corresponds to the following priority order:
    292      * 1. If a SIM Call Manager {@link PhoneAccount} is registered for the same package as the
    293      * default dialer, then that one is returned.
    294      * 2. If there is a SIM Call Manager {@link PhoneAccount} registered which matches the
    295      * carrier configuration's default, then that one is returned.
    296      * 3. Otherwise, we return null.
    297      */
    298     public PhoneAccountHandle getSimCallManager(int user) {
    299         // Get the default dialer in case it has a connection manager associated with it.
    300         String dialerPackage = DefaultDialerManager.getDefaultDialerApplication(mContext, user);
    301 
    302         // Check carrier config.
    303         String defaultSimCallManager = null;
    304         CarrierConfigManager configManager = (CarrierConfigManager) mContext.getSystemService(
    305                 Context.CARRIER_CONFIG_SERVICE);
    306         PersistableBundle configBundle = configManager.getConfig();
    307         if (configBundle != null) {
    308             defaultSimCallManager = configBundle.getString(
    309                     CarrierConfigManager.KEY_DEFAULT_SIM_CALL_MANAGER_STRING);
    310         }
    311 
    312         ComponentName systemSimCallManagerComponent = TextUtils.isEmpty(defaultSimCallManager) ?
    313                 null : ComponentName.unflattenFromString(defaultSimCallManager);
    314 
    315         PhoneAccountHandle dialerSimCallManager = null;
    316         PhoneAccountHandle systemSimCallManager = null;
    317 
    318         if (!TextUtils.isEmpty(dialerPackage) || systemSimCallManagerComponent != null) {
    319             // loop through and look for any connection manager in the same package.
    320             List<PhoneAccountHandle> allSimCallManagers = getPhoneAccountHandles(
    321                     PhoneAccount.CAPABILITY_CONNECTION_MANAGER, null, null,
    322                     true /* includeDisabledAccounts */);
    323             for (PhoneAccountHandle accountHandle : allSimCallManagers) {
    324                 ComponentName component = accountHandle.getComponentName();
    325 
    326                 // Store the system connection manager if found
    327                 if (systemSimCallManager == null
    328                         && Objects.equals(component, systemSimCallManagerComponent)
    329                         && !resolveComponent(accountHandle).isEmpty()) {
    330                     systemSimCallManager = accountHandle;
    331 
    332                 // Store the dialer connection manager if found
    333                 } else if (dialerSimCallManager == null
    334                         && Objects.equals(component.getPackageName(), dialerPackage)
    335                         && !resolveComponent(accountHandle).isEmpty()) {
    336                     dialerSimCallManager = accountHandle;
    337                 }
    338             }
    339         }
    340 
    341         PhoneAccountHandle retval = dialerSimCallManager != null ?
    342                 dialerSimCallManager : systemSimCallManager;
    343 
    344         Log.i(this, "SimCallManager queried, returning: %s", retval);
    345 
    346         return retval;
    347     }
    348 
    349     /**
    350      * Update the current UserHandle to track when users are switched. This will allow the
    351      * PhoneAccountRegistar to self-filter the PhoneAccounts to make sure we don't leak anything
    352      * across users.
    353      * We cannot simply check the calling user because that would always return the primary user for
    354      * all invocations originating with the system process.
    355      *
    356      * @param userHandle The {@link UserHandle}, as delivered by
    357      *          {@link Intent#ACTION_USER_SWITCHED}.
    358      */
    359     public void setCurrentUserHandle(UserHandle userHandle) {
    360         if (userHandle == null) {
    361             Log.d(this, "setCurrentUserHandle, userHandle = null");
    362             userHandle = Process.myUserHandle();
    363         }
    364         Log.d(this, "setCurrentUserHandle, %s", userHandle);
    365         mCurrentUserHandle = userHandle;
    366     }
    367 
    368     /**
    369      * @return {@code true} if the phone account was successfully enabled/disabled, {@code false}
    370      *         otherwise.
    371      */
    372     public boolean enablePhoneAccount(PhoneAccountHandle accountHandle, boolean isEnabled) {
    373         PhoneAccount account = getPhoneAccount(accountHandle);
    374         if (account == null) {
    375             Log.w(this, "Could not find account to enable: " + accountHandle);
    376             return false;
    377         } else if (account.hasCapabilities(PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION)) {
    378             // We never change the enabled state of SIM-based accounts.
    379             Log.w(this, "Could not change enable state of SIM account: " + accountHandle);
    380             return false;
    381         }
    382 
    383         if (account.isEnabled() != isEnabled) {
    384             account.setIsEnabled(isEnabled);
    385             write();
    386             fireAccountsChanged();
    387         }
    388         return true;
    389     }
    390 
    391     private boolean isVisibleForUser(PhoneAccount account) {
    392         if (account == null) {
    393             return false;
    394         }
    395 
    396         // If this PhoneAccount has CAPABILITY_MULTI_USER, it should be visible to all users and
    397         // all profiles. Only Telephony and SIP accounts should have this capability.
    398         if (account.hasCapabilities(PhoneAccount.CAPABILITY_MULTI_USER)) {
    399             return true;
    400         }
    401 
    402         UserHandle phoneAccountUserHandle = account.getAccountHandle().getUserHandle();
    403         if (phoneAccountUserHandle == null) {
    404             return false;
    405         }
    406 
    407         if (mCurrentUserHandle == null) {
    408             Log.d(this, "Current user is null; assuming true");
    409             return true;
    410         }
    411 
    412         if (phoneAccountUserHandle.equals(Binder.getCallingUserHandle())) {
    413             return true;
    414         }
    415 
    416         // Special check for work profiles.
    417         // Unlike in TelecomServiceImpl, we only care about *profiles* here. We want to make sure
    418         // that we don't resolve PhoneAccount across *users*, but resolving across *profiles* is
    419         // fine.
    420         if (UserHandle.getCallingUserId() == UserHandle.USER_OWNER) {
    421             List<UserInfo> profileUsers =
    422                     mUserManager.getProfiles(mCurrentUserHandle.getIdentifier());
    423             for (UserInfo profileInfo : profileUsers) {
    424                 if (profileInfo.getUserHandle().equals(phoneAccountUserHandle)) {
    425                     return true;
    426                 }
    427             }
    428         }
    429 
    430         return false;
    431     }
    432 
    433     private List<ResolveInfo> resolveComponent(PhoneAccountHandle phoneAccountHandle) {
    434         return resolveComponent(phoneAccountHandle.getComponentName(),
    435                     phoneAccountHandle.getUserHandle());
    436     }
    437 
    438     private List<ResolveInfo> resolveComponent(ComponentName componentName,
    439             UserHandle userHandle) {
    440         PackageManager pm = mContext.getPackageManager();
    441         Intent intent = new Intent(ConnectionService.SERVICE_INTERFACE);
    442         intent.setComponent(componentName);
    443         try {
    444             if (userHandle != null) {
    445                 return pm.queryIntentServicesAsUser(intent, 0, userHandle.getIdentifier());
    446             } else {
    447                 return pm.queryIntentServices(intent, 0);
    448             }
    449         } catch (SecurityException e) {
    450             Log.e(this, e, "%s is not visible for the calling user", componentName);
    451             return Collections.EMPTY_LIST;
    452         }
    453     }
    454 
    455     /**
    456      * Retrieves a list of all {@link PhoneAccountHandle}s registered.
    457      * Only returns accounts which are enabled.
    458      *
    459      * @return The list of {@link PhoneAccountHandle}s.
    460      */
    461     public List<PhoneAccountHandle> getAllPhoneAccountHandles() {
    462         return getPhoneAccountHandles(0, null, null, false);
    463     }
    464 
    465     public List<PhoneAccount> getAllPhoneAccounts() {
    466         return getPhoneAccounts(0, null, null, false);
    467     }
    468 
    469     /**
    470      * Retrieves a list of all phone account call provider phone accounts supporting the
    471      * specified URI scheme.
    472      *
    473      * @param uriScheme The URI scheme.
    474      * @return The phone account handles.
    475      */
    476     public List<PhoneAccountHandle> getCallCapablePhoneAccounts(
    477             String uriScheme, boolean includeDisabledAccounts) {
    478         return getPhoneAccountHandles(
    479                 PhoneAccount.CAPABILITY_CALL_PROVIDER, uriScheme, null, includeDisabledAccounts);
    480     }
    481 
    482     /**
    483      * Retrieves a list of all the SIM-based phone accounts.
    484      */
    485     public List<PhoneAccountHandle> getSimPhoneAccounts() {
    486         return getPhoneAccountHandles(
    487                 PhoneAccount.CAPABILITY_CALL_PROVIDER | PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION,
    488                 null, null, false);
    489     }
    490 
    491     /**
    492      * Retrieves a list of all phone accounts registered by a specified package.
    493      *
    494      * @param packageName The name of the package that registered the phone accounts.
    495      * @return The phone account handles.
    496      */
    497     public List<PhoneAccountHandle> getPhoneAccountsForPackage(String packageName) {
    498         return getPhoneAccountHandles(0, null, packageName, false);
    499     }
    500 
    501     // TODO: Should we implement an artificial limit for # of accounts associated with a single
    502     // ComponentName?
    503     public void registerPhoneAccount(PhoneAccount account) {
    504         // Enforce the requirement that a connection service for a phone account has the correct
    505         // permission.
    506         if (!phoneAccountRequiresBindPermission(account.getAccountHandle())) {
    507             Log.w(this,
    508                     "Phone account %s does not have BIND_TELECOM_CONNECTION_SERVICE permission.",
    509                     account.getAccountHandle());
    510             throw new SecurityException("PhoneAccount connection service requires "
    511                     + "BIND_TELECOM_CONNECTION_SERVICE permission.");
    512         }
    513 
    514         addOrReplacePhoneAccount(account);
    515     }
    516 
    517     /**
    518      * Adds a {@code PhoneAccount}, replacing an existing one if found.
    519      *
    520      * @param account The {@code PhoneAccount} to add or replace.
    521      */
    522     private void addOrReplacePhoneAccount(PhoneAccount account) {
    523         Log.d(this, "addOrReplacePhoneAccount(%s -> %s)",
    524                 account.getAccountHandle(), account);
    525 
    526         // Start _enabled_ property as false.
    527         // !!! IMPORTANT !!! It is important that we do not read the enabled state that the
    528         // source app provides or else an third party app could enable itself.
    529         boolean isEnabled = false;
    530 
    531         PhoneAccount oldAccount = getPhoneAccount(account.getAccountHandle());
    532         if (oldAccount != null) {
    533             mState.accounts.remove(oldAccount);
    534             isEnabled = oldAccount.isEnabled();
    535             Log.i(this, getAccountDiffString(account, oldAccount));
    536         } else {
    537             Log.i(this, "New phone account registered: " + account);
    538         }
    539 
    540         mState.accounts.add(account);
    541         // Reset enabled state to whatever the value was if the account was already registered,
    542         // or _true_ if this is a SIM-based account.  All SIM-based accounts are always enabled.
    543         account.setIsEnabled(
    544                 isEnabled || account.hasCapabilities(PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION));
    545 
    546         write();
    547         fireAccountsChanged();
    548     }
    549 
    550     public void unregisterPhoneAccount(PhoneAccountHandle accountHandle) {
    551         PhoneAccount account = getPhoneAccount(accountHandle);
    552         if (account != null) {
    553             if (mState.accounts.remove(account)) {
    554                 write();
    555                 fireAccountsChanged();
    556             }
    557         }
    558     }
    559 
    560     /**
    561      * Un-registers all phone accounts associated with a specified package.
    562      *
    563      * @param packageName The package for which phone accounts will be removed.
    564      * @param userHandle The {@link UserHandle} the package is running under.
    565      */
    566     public void clearAccounts(String packageName, UserHandle userHandle) {
    567         boolean accountsRemoved = false;
    568         Iterator<PhoneAccount> it = mState.accounts.iterator();
    569         while (it.hasNext()) {
    570             PhoneAccount phoneAccount = it.next();
    571             PhoneAccountHandle handle = phoneAccount.getAccountHandle();
    572             if (Objects.equals(packageName, handle.getComponentName().getPackageName())
    573                     && Objects.equals(userHandle, handle.getUserHandle())) {
    574                 Log.i(this, "Removing phone account " + phoneAccount.getLabel());
    575                 mState.accounts.remove(phoneAccount);
    576                 accountsRemoved = true;
    577             }
    578         }
    579 
    580         if (accountsRemoved) {
    581             write();
    582             fireAccountsChanged();
    583         }
    584     }
    585 
    586     public boolean isVoiceMailNumber(PhoneAccountHandle accountHandle, String number) {
    587         int subId = getSubscriptionIdForPhoneAccount(accountHandle);
    588         return PhoneNumberUtils.isVoiceMailNumber(mContext, subId, number);
    589     }
    590 
    591     public void addListener(Listener l) {
    592         mListeners.add(l);
    593     }
    594 
    595     public void removeListener(Listener l) {
    596         if (l != null) {
    597             mListeners.remove(l);
    598         }
    599     }
    600 
    601     private void fireAccountsChanged() {
    602         for (Listener l : mListeners) {
    603             l.onAccountsChanged(this);
    604         }
    605     }
    606 
    607     private void fireDefaultOutgoingChanged() {
    608         for (Listener l : mListeners) {
    609             l.onDefaultOutgoingChanged(this);
    610         }
    611     }
    612 
    613     private void fireSimCallManagerChanged() {
    614         for (Listener l : mListeners) {
    615             l.onSimCallManagerChanged(this);
    616         }
    617     }
    618 
    619     private String getAccountDiffString(PhoneAccount account1, PhoneAccount account2) {
    620         if (account1 == null || account2 == null) {
    621             return "Diff: " + account1 + ", " + account2;
    622         }
    623 
    624         StringBuffer sb = new StringBuffer();
    625         sb.append("[").append(account1.getAccountHandle());
    626         appendDiff(sb, "addr", Log.piiHandle(account1.getAddress()),
    627                 Log.piiHandle(account2.getAddress()));
    628         appendDiff(sb, "cap", account1.getCapabilities(), account2.getCapabilities());
    629         appendDiff(sb, "hl", account1.getHighlightColor(), account2.getHighlightColor());
    630         appendDiff(sb, "icon", account1.getIcon(), account2.getIcon());
    631         appendDiff(sb, "lbl", account1.getLabel(), account2.getLabel());
    632         appendDiff(sb, "desc", account1.getShortDescription(), account2.getShortDescription());
    633         appendDiff(sb, "subAddr", Log.piiHandle(account1.getSubscriptionAddress()),
    634                 Log.piiHandle(account2.getSubscriptionAddress()));
    635         appendDiff(sb, "uris", account1.getSupportedUriSchemes(),
    636                 account2.getSupportedUriSchemes());
    637         sb.append("]");
    638         return sb.toString();
    639     }
    640 
    641     private void appendDiff(StringBuffer sb, String attrName, Object obj1, Object obj2) {
    642         if (!Objects.equals(obj1, obj2)) {
    643             sb.append("(")
    644                 .append(attrName)
    645                 .append(": ")
    646                 .append(obj1)
    647                 .append(" -> ")
    648                 .append(obj2)
    649                 .append(")");
    650         }
    651     }
    652 
    653     /**
    654      * Determines if the connection service specified by a {@link PhoneAccountHandle} requires the
    655      * {@link Manifest.permission#BIND_TELECOM_CONNECTION_SERVICE} permission.
    656      *
    657      * @param phoneAccountHandle The phone account to check.
    658      * @return {@code True} if the phone account has permission.
    659      */
    660     public boolean phoneAccountRequiresBindPermission(PhoneAccountHandle phoneAccountHandle) {
    661         List<ResolveInfo> resolveInfos = resolveComponent(phoneAccountHandle);
    662         if (resolveInfos.isEmpty()) {
    663             Log.w(this, "phoneAccount %s not found", phoneAccountHandle.getComponentName());
    664             return false;
    665         }
    666         for (ResolveInfo resolveInfo : resolveInfos) {
    667             ServiceInfo serviceInfo = resolveInfo.serviceInfo;
    668             if (serviceInfo == null) {
    669                 return false;
    670             }
    671 
    672             if (!Manifest.permission.BIND_CONNECTION_SERVICE.equals(serviceInfo.permission) &&
    673                     !Manifest.permission.BIND_TELECOM_CONNECTION_SERVICE.equals(
    674                             serviceInfo.permission)) {
    675                 // The ConnectionService must require either the deprecated BIND_CONNECTION_SERVICE,
    676                 // or the public BIND_TELECOM_CONNECTION_SERVICE permissions, both of which are
    677                 // system/signature only.
    678                 return false;
    679             }
    680         }
    681         return true;
    682     }
    683 
    684     //
    685     // Methods for retrieving PhoneAccounts and PhoneAccountHandles
    686     //
    687 
    688     /**
    689      * Returns the PhoneAccount for the specified handle.  Does no user checking.
    690      *
    691      * @param handle
    692      * @return The corresponding phone account if one exists.
    693      */
    694     PhoneAccount getPhoneAccount(PhoneAccountHandle handle) {
    695         for (PhoneAccount m : mState.accounts) {
    696             if (Objects.equals(handle, m.getAccountHandle())) {
    697                 return m;
    698             }
    699         }
    700         return null;
    701     }
    702 
    703     /**
    704      * Like getPhoneAccount, but checks to see if the current user is allowed to see the phone
    705      * account before returning it. The current user is the active user on the actual android
    706      * device.
    707      */
    708     public PhoneAccount getPhoneAccountCheckCallingUser(PhoneAccountHandle handle) {
    709         PhoneAccount account = getPhoneAccount(handle);
    710         if (account != null && isVisibleForUser(account)) {
    711             return account;
    712         }
    713         return null;
    714     }
    715 
    716     /**
    717      * Returns a list of phone account handles with the specified capabilities, uri scheme,
    718      * and package name.
    719      */
    720     private List<PhoneAccountHandle> getPhoneAccountHandles(
    721             int capabilities,
    722             String uriScheme,
    723             String packageName,
    724             boolean includeDisabledAccounts) {
    725         List<PhoneAccountHandle> handles = new ArrayList<>();
    726 
    727         for (PhoneAccount account : getPhoneAccounts(
    728                 capabilities, uriScheme, packageName, includeDisabledAccounts)) {
    729             handles.add(account.getAccountHandle());
    730         }
    731         return handles;
    732     }
    733 
    734     /**
    735      * Returns a list of phone account handles with the specified flag, supporting the specified
    736      * URI scheme, within the specified package name.
    737      *
    738      * @param capabilities Capabilities which the {@code PhoneAccount} must have. Ignored if 0.
    739      * @param uriScheme URI schemes the PhoneAccount must handle.  {@code null} bypasses the
    740      *                  URI scheme check.
    741      * @param packageName Package name of the PhoneAccount. {@code null} bypasses packageName check.
    742      */
    743     private List<PhoneAccount> getPhoneAccounts(
    744             int capabilities,
    745             String uriScheme,
    746             String packageName,
    747             boolean includeDisabledAccounts) {
    748         List<PhoneAccount> accounts = new ArrayList<>(mState.accounts.size());
    749         for (PhoneAccount m : mState.accounts) {
    750             if (!(m.isEnabled() || includeDisabledAccounts)) {
    751                 // Do not include disabled accounts.
    752                 continue;
    753             }
    754 
    755             if (capabilities != 0 && !m.hasCapabilities(capabilities)) {
    756                 // Account doesn't have the right capabilities; skip this one.
    757                 continue;
    758             }
    759             if (uriScheme != null && !m.supportsUriScheme(uriScheme)) {
    760                 // Account doesn't support this URI scheme; skip this one.
    761                 continue;
    762             }
    763             PhoneAccountHandle handle = m.getAccountHandle();
    764 
    765             if (resolveComponent(handle).isEmpty()) {
    766                 // This component cannot be resolved anymore; skip this one.
    767                 continue;
    768             }
    769             if (packageName != null &&
    770                     !packageName.equals(handle.getComponentName().getPackageName())) {
    771                 // Not the right package name; skip this one.
    772                 continue;
    773             }
    774             if (!isVisibleForUser(m)) {
    775                 // Account is not visible for the current user; skip this one.
    776                 continue;
    777             }
    778             accounts.add(m);
    779         }
    780         return accounts;
    781     }
    782 
    783     //
    784     // State Implementation for PhoneAccountRegistrar
    785     //
    786 
    787     /**
    788      * The state of this {@code PhoneAccountRegistrar}.
    789      */
    790     @VisibleForTesting
    791     public static class State {
    792         /**
    793          * The account selected by the user to be employed by default for making outgoing calls.
    794          * If the user has not made such a selection, then this is null.
    795          */
    796         public PhoneAccountHandle defaultOutgoing = null;
    797 
    798         /**
    799          * The complete list of {@code PhoneAccount}s known to the Telecom subsystem.
    800          */
    801         public final List<PhoneAccount> accounts = new CopyOnWriteArrayList<>();
    802 
    803         /**
    804          * The version number of the State data.
    805          */
    806         public int versionNumber;
    807     }
    808 
    809     /**
    810      * Dumps the state of the {@link CallsManager}.
    811      *
    812      * @param pw The {@code IndentingPrintWriter} to write the state to.
    813      */
    814     public void dump(IndentingPrintWriter pw) {
    815         if (mState != null) {
    816             pw.println("xmlVersion: " + mState.versionNumber);
    817             pw.println("defaultOutgoing: " + (mState.defaultOutgoing == null ? "none" :
    818                     mState.defaultOutgoing));
    819             pw.println("simCallManager: " + getSimCallManager());
    820             pw.println("phoneAccounts:");
    821             pw.increaseIndent();
    822             for (PhoneAccount phoneAccount : mState.accounts) {
    823                 pw.println(phoneAccount);
    824             }
    825             pw.decreaseIndent();
    826         }
    827     }
    828 
    829     ////////////////////////////////////////////////////////////////////////////////////////////////
    830     //
    831     // State management
    832     //
    833 
    834     private void write() {
    835         final FileOutputStream os;
    836         try {
    837             os = mAtomicFile.startWrite();
    838             boolean success = false;
    839             try {
    840                 XmlSerializer serializer = new FastXmlSerializer();
    841                 serializer.setOutput(new BufferedOutputStream(os), "utf-8");
    842                 writeToXml(mState, serializer, mContext);
    843                 serializer.flush();
    844                 success = true;
    845             } finally {
    846                 if (success) {
    847                     mAtomicFile.finishWrite(os);
    848                 } else {
    849                     mAtomicFile.failWrite(os);
    850                 }
    851             }
    852         } catch (IOException e) {
    853             Log.e(this, e, "Writing state to XML file");
    854         }
    855     }
    856 
    857     private void read() {
    858         final InputStream is;
    859         try {
    860             is = mAtomicFile.openRead();
    861         } catch (FileNotFoundException ex) {
    862             return;
    863         }
    864 
    865         boolean versionChanged = false;
    866 
    867         XmlPullParser parser;
    868         try {
    869             parser = Xml.newPullParser();
    870             parser.setInput(new BufferedInputStream(is), null);
    871             parser.nextTag();
    872             mState = readFromXml(parser, mContext);
    873             versionChanged = mState.versionNumber < EXPECTED_STATE_VERSION;
    874 
    875         } catch (IOException | XmlPullParserException e) {
    876             Log.e(this, e, "Reading state from XML file");
    877             mState = new State();
    878         } finally {
    879             try {
    880                 is.close();
    881             } catch (IOException e) {
    882                 Log.e(this, e, "Closing InputStream");
    883             }
    884         }
    885 
    886         // Verify all of the UserHandles.
    887         List<PhoneAccount> badAccounts = new ArrayList<>();
    888         for (PhoneAccount phoneAccount : mState.accounts) {
    889             UserHandle userHandle = phoneAccount.getAccountHandle().getUserHandle();
    890             if (userHandle == null) {
    891                 Log.w(this, "Missing UserHandle for %s", phoneAccount);
    892                 badAccounts.add(phoneAccount);
    893             } else if (mUserManager.getSerialNumberForUser(userHandle) == -1) {
    894                 Log.w(this, "User does not exist for %s", phoneAccount);
    895                 badAccounts.add(phoneAccount);
    896             }
    897         }
    898         mState.accounts.removeAll(badAccounts);
    899 
    900         // If an upgrade occurred, write out the changed data.
    901         if (versionChanged || !badAccounts.isEmpty()) {
    902             write();
    903         }
    904     }
    905 
    906     private static void writeToXml(State state, XmlSerializer serializer, Context context)
    907             throws IOException {
    908         sStateXml.writeToXml(state, serializer, context);
    909     }
    910 
    911     private static State readFromXml(XmlPullParser parser, Context context)
    912             throws IOException, XmlPullParserException {
    913         State s = sStateXml.readFromXml(parser, 0, context);
    914         return s != null ? s : new State();
    915     }
    916 
    917     ////////////////////////////////////////////////////////////////////////////////////////////////
    918     //
    919     // XML serialization
    920     //
    921 
    922     @VisibleForTesting
    923     public abstract static class XmlSerialization<T> {
    924         private static final String LENGTH_ATTRIBUTE = "length";
    925         private static final String VALUE_TAG = "value";
    926 
    927         /**
    928          * Write the supplied object to XML
    929          */
    930         public abstract void writeToXml(T o, XmlSerializer serializer, Context context)
    931                 throws IOException;
    932 
    933         /**
    934          * Read from the supplied XML into a new object, returning null in case of an
    935          * unrecoverable schema mismatch or other data error. 'parser' must be already
    936          * positioned at the first tag that is expected to have been emitted by this
    937          * object's writeToXml(). This object tries to fail early without modifying
    938          * 'parser' if it does not recognize the data it sees.
    939          */
    940         public abstract T readFromXml(XmlPullParser parser, int version, Context context)
    941                 throws IOException, XmlPullParserException;
    942 
    943         protected void writeTextIfNonNull(String tagName, Object value, XmlSerializer serializer)
    944                 throws IOException {
    945             if (value != null) {
    946                 serializer.startTag(null, tagName);
    947                 serializer.text(Objects.toString(value));
    948                 serializer.endTag(null, tagName);
    949             }
    950         }
    951 
    952         /**
    953          * Serializes a string array.
    954          *
    955          * @param tagName The tag name for the string array.
    956          * @param values The string values to serialize.
    957          * @param serializer The serializer.
    958          * @throws IOException
    959          */
    960         protected void writeStringList(String tagName, List<String> values,
    961                 XmlSerializer serializer)
    962                 throws IOException {
    963 
    964             serializer.startTag(null, tagName);
    965             if (values != null) {
    966                 serializer.attribute(null, LENGTH_ATTRIBUTE, Objects.toString(values.size()));
    967                 for (String toSerialize : values) {
    968                     serializer.startTag(null, VALUE_TAG);
    969                     if (toSerialize != null ){
    970                         serializer.text(toSerialize);
    971                     }
    972                     serializer.endTag(null, VALUE_TAG);
    973                 }
    974             } else {
    975                 serializer.attribute(null, LENGTH_ATTRIBUTE, "0");
    976             }
    977             serializer.endTag(null, tagName);
    978         }
    979 
    980         protected void writeIconIfNonNull(String tagName, Icon value, XmlSerializer serializer)
    981                 throws IOException {
    982             if (value != null) {
    983                 ByteArrayOutputStream stream = new ByteArrayOutputStream();
    984                 value.writeToStream(stream);
    985                 byte[] iconByteArray = stream.toByteArray();
    986                 String text = Base64.encodeToString(iconByteArray, 0, iconByteArray.length, 0);
    987 
    988                 serializer.startTag(null, tagName);
    989                 serializer.text(text);
    990                 serializer.endTag(null, tagName);
    991             }
    992         }
    993 
    994         protected void writeLong(String tagName, long value, XmlSerializer serializer)
    995                 throws IOException {
    996             serializer.startTag(null, tagName);
    997             serializer.text(Long.valueOf(value).toString());
    998             serializer.endTag(null, tagName);
    999         }
   1000 
   1001         /**
   1002          * Reads a string array from the XML parser.
   1003          *
   1004          * @param parser The XML parser.
   1005          * @return String array containing the parsed values.
   1006          * @throws IOException Exception related to IO.
   1007          * @throws XmlPullParserException Exception related to parsing.
   1008          */
   1009         protected List<String> readStringList(XmlPullParser parser)
   1010                 throws IOException, XmlPullParserException {
   1011 
   1012             int length = Integer.parseInt(parser.getAttributeValue(null, LENGTH_ATTRIBUTE));
   1013             List<String> arrayEntries = new ArrayList<String>(length);
   1014             String value = null;
   1015 
   1016             if (length == 0) {
   1017                 return arrayEntries;
   1018             }
   1019 
   1020             int outerDepth = parser.getDepth();
   1021             while (XmlUtils.nextElementWithin(parser, outerDepth)) {
   1022                 if (parser.getName().equals(VALUE_TAG)) {
   1023                     parser.next();
   1024                     value = parser.getText();
   1025                     arrayEntries.add(value);
   1026                 }
   1027             }
   1028 
   1029             return arrayEntries;
   1030         }
   1031 
   1032         protected Bitmap readBitmap(XmlPullParser parser) {
   1033             byte[] imageByteArray = Base64.decode(parser.getText(), 0);
   1034             return BitmapFactory.decodeByteArray(imageByteArray, 0, imageByteArray.length);
   1035         }
   1036 
   1037         protected Icon readIcon(XmlPullParser parser) throws IOException {
   1038             byte[] iconByteArray = Base64.decode(parser.getText(), 0);
   1039             ByteArrayInputStream stream = new ByteArrayInputStream(iconByteArray);
   1040             return Icon.createFromStream(stream);
   1041         }
   1042     }
   1043 
   1044     @VisibleForTesting
   1045     public static final XmlSerialization<State> sStateXml =
   1046             new XmlSerialization<State>() {
   1047         private static final String CLASS_STATE = "phone_account_registrar_state";
   1048         private static final String DEFAULT_OUTGOING = "default_outgoing";
   1049         private static final String ACCOUNTS = "accounts";
   1050         private static final String VERSION = "version";
   1051 
   1052         @Override
   1053         public void writeToXml(State o, XmlSerializer serializer, Context context)
   1054                 throws IOException {
   1055             if (o != null) {
   1056                 serializer.startTag(null, CLASS_STATE);
   1057                 serializer.attribute(null, VERSION, Objects.toString(EXPECTED_STATE_VERSION));
   1058 
   1059                 if (o.defaultOutgoing != null) {
   1060                     serializer.startTag(null, DEFAULT_OUTGOING);
   1061                     sPhoneAccountHandleXml.writeToXml(o.defaultOutgoing, serializer, context);
   1062                     serializer.endTag(null, DEFAULT_OUTGOING);
   1063                 }
   1064 
   1065                 serializer.startTag(null, ACCOUNTS);
   1066                 for (PhoneAccount m : o.accounts) {
   1067                     sPhoneAccountXml.writeToXml(m, serializer, context);
   1068                 }
   1069                 serializer.endTag(null, ACCOUNTS);
   1070 
   1071                 serializer.endTag(null, CLASS_STATE);
   1072             }
   1073         }
   1074 
   1075         @Override
   1076         public State readFromXml(XmlPullParser parser, int version, Context context)
   1077                 throws IOException, XmlPullParserException {
   1078             if (parser.getName().equals(CLASS_STATE)) {
   1079                 State s = new State();
   1080 
   1081                 String rawVersion = parser.getAttributeValue(null, VERSION);
   1082                 s.versionNumber = TextUtils.isEmpty(rawVersion) ? 1 :
   1083                         Integer.parseInt(rawVersion);
   1084 
   1085                 int outerDepth = parser.getDepth();
   1086                 while (XmlUtils.nextElementWithin(parser, outerDepth)) {
   1087                     if (parser.getName().equals(DEFAULT_OUTGOING)) {
   1088                         parser.nextTag();
   1089                         s.defaultOutgoing = sPhoneAccountHandleXml.readFromXml(parser,
   1090                                 s.versionNumber, context);
   1091                     } else if (parser.getName().equals(ACCOUNTS)) {
   1092                         int accountsDepth = parser.getDepth();
   1093                         while (XmlUtils.nextElementWithin(parser, accountsDepth)) {
   1094                             PhoneAccount account = sPhoneAccountXml.readFromXml(parser,
   1095                                     s.versionNumber, context);
   1096 
   1097                             if (account != null && s.accounts != null) {
   1098                                 s.accounts.add(account);
   1099                             }
   1100                         }
   1101                     }
   1102                 }
   1103                 return s;
   1104             }
   1105             return null;
   1106         }
   1107     };
   1108 
   1109     @VisibleForTesting
   1110     public static final XmlSerialization<PhoneAccount> sPhoneAccountXml =
   1111             new XmlSerialization<PhoneAccount>() {
   1112         private static final String CLASS_PHONE_ACCOUNT = "phone_account";
   1113         private static final String ACCOUNT_HANDLE = "account_handle";
   1114         private static final String ADDRESS = "handle";
   1115         private static final String SUBSCRIPTION_ADDRESS = "subscription_number";
   1116         private static final String CAPABILITIES = "capabilities";
   1117         private static final String ICON_RES_ID = "icon_res_id";
   1118         private static final String ICON_PACKAGE_NAME = "icon_package_name";
   1119         private static final String ICON_BITMAP = "icon_bitmap";
   1120         private static final String ICON_TINT = "icon_tint";
   1121         private static final String HIGHLIGHT_COLOR = "highlight_color";
   1122         private static final String LABEL = "label";
   1123         private static final String SHORT_DESCRIPTION = "short_description";
   1124         private static final String SUPPORTED_URI_SCHEMES = "supported_uri_schemes";
   1125         private static final String ICON = "icon";
   1126         private static final String ENABLED = "enabled";
   1127 
   1128         @Override
   1129         public void writeToXml(PhoneAccount o, XmlSerializer serializer, Context context)
   1130                 throws IOException {
   1131             if (o != null) {
   1132                 serializer.startTag(null, CLASS_PHONE_ACCOUNT);
   1133 
   1134                 if (o.getAccountHandle() != null) {
   1135                     serializer.startTag(null, ACCOUNT_HANDLE);
   1136                     sPhoneAccountHandleXml.writeToXml(o.getAccountHandle(), serializer, context);
   1137                     serializer.endTag(null, ACCOUNT_HANDLE);
   1138                 }
   1139 
   1140                 writeTextIfNonNull(ADDRESS, o.getAddress(), serializer);
   1141                 writeTextIfNonNull(SUBSCRIPTION_ADDRESS, o.getSubscriptionAddress(), serializer);
   1142                 writeTextIfNonNull(CAPABILITIES, Integer.toString(o.getCapabilities()), serializer);
   1143                 writeIconIfNonNull(ICON, o.getIcon(), serializer);
   1144                 writeTextIfNonNull(HIGHLIGHT_COLOR,
   1145                         Integer.toString(o.getHighlightColor()), serializer);
   1146                 writeTextIfNonNull(LABEL, o.getLabel(), serializer);
   1147                 writeTextIfNonNull(SHORT_DESCRIPTION, o.getShortDescription(), serializer);
   1148                 writeStringList(SUPPORTED_URI_SCHEMES, o.getSupportedUriSchemes(), serializer);
   1149                 writeTextIfNonNull(ENABLED, o.isEnabled() ? "true" : "false" , serializer);
   1150 
   1151                 serializer.endTag(null, CLASS_PHONE_ACCOUNT);
   1152             }
   1153         }
   1154 
   1155         public PhoneAccount readFromXml(XmlPullParser parser, int version, Context context)
   1156                 throws IOException, XmlPullParserException {
   1157             if (parser.getName().equals(CLASS_PHONE_ACCOUNT)) {
   1158                 int outerDepth = parser.getDepth();
   1159                 PhoneAccountHandle accountHandle = null;
   1160                 Uri address = null;
   1161                 Uri subscriptionAddress = null;
   1162                 int capabilities = 0;
   1163                 int iconResId = PhoneAccount.NO_RESOURCE_ID;
   1164                 String iconPackageName = null;
   1165                 Bitmap iconBitmap = null;
   1166                 int iconTint = PhoneAccount.NO_ICON_TINT;
   1167                 int highlightColor = PhoneAccount.NO_HIGHLIGHT_COLOR;
   1168                 String label = null;
   1169                 String shortDescription = null;
   1170                 List<String> supportedUriSchemes = null;
   1171                 Icon icon = null;
   1172                 boolean enabled = false;
   1173 
   1174                 while (XmlUtils.nextElementWithin(parser, outerDepth)) {
   1175                     if (parser.getName().equals(ACCOUNT_HANDLE)) {
   1176                         parser.nextTag();
   1177                         accountHandle = sPhoneAccountHandleXml.readFromXml(parser, version,
   1178                                 context);
   1179                     } else if (parser.getName().equals(ADDRESS)) {
   1180                         parser.next();
   1181                         address = Uri.parse(parser.getText());
   1182                     } else if (parser.getName().equals(SUBSCRIPTION_ADDRESS)) {
   1183                         parser.next();
   1184                         String nextText = parser.getText();
   1185                         subscriptionAddress = nextText == null ? null : Uri.parse(nextText);
   1186                     } else if (parser.getName().equals(CAPABILITIES)) {
   1187                         parser.next();
   1188                         capabilities = Integer.parseInt(parser.getText());
   1189                     } else if (parser.getName().equals(ICON_RES_ID)) {
   1190                         parser.next();
   1191                         iconResId = Integer.parseInt(parser.getText());
   1192                     } else if (parser.getName().equals(ICON_PACKAGE_NAME)) {
   1193                         parser.next();
   1194                         iconPackageName = parser.getText();
   1195                     } else if (parser.getName().equals(ICON_BITMAP)) {
   1196                         parser.next();
   1197                         iconBitmap = readBitmap(parser);
   1198                     } else if (parser.getName().equals(ICON_TINT)) {
   1199                         parser.next();
   1200                         iconTint = Integer.parseInt(parser.getText());
   1201                     } else if (parser.getName().equals(HIGHLIGHT_COLOR)) {
   1202                         parser.next();
   1203                         highlightColor = Integer.parseInt(parser.getText());
   1204                     } else if (parser.getName().equals(LABEL)) {
   1205                         parser.next();
   1206                         label = parser.getText();
   1207                     } else if (parser.getName().equals(SHORT_DESCRIPTION)) {
   1208                         parser.next();
   1209                         shortDescription = parser.getText();
   1210                     } else if (parser.getName().equals(SUPPORTED_URI_SCHEMES)) {
   1211                         supportedUriSchemes = readStringList(parser);
   1212                     } else if (parser.getName().equals(ICON)) {
   1213                         parser.next();
   1214                         icon = readIcon(parser);
   1215                     } else if (parser.getName().equals(ENABLED)) {
   1216                         parser.next();
   1217                         enabled = "true".equalsIgnoreCase(parser.getText());
   1218                     }
   1219                 }
   1220 
   1221                 ComponentName pstnComponentName = new ComponentName("com.android.phone",
   1222                         "com.android.services.telephony.TelephonyConnectionService");
   1223                 ComponentName sipComponentName = new ComponentName("com.android.phone",
   1224                         "com.android.services.telephony.sip.SipConnectionService");
   1225 
   1226                 // Upgrade older phone accounts to specify the supported URI schemes.
   1227                 if (version < 2) {
   1228                     supportedUriSchemes = new ArrayList<>();
   1229 
   1230                     // Handle the SIP connection service.
   1231                     // Check the system settings to see if it also should handle "tel" calls.
   1232                     if (accountHandle.getComponentName().equals(sipComponentName)) {
   1233                         boolean useSipForPstn = useSipForPstnCalls(context);
   1234                         supportedUriSchemes.add(PhoneAccount.SCHEME_SIP);
   1235                         if (useSipForPstn) {
   1236                             supportedUriSchemes.add(PhoneAccount.SCHEME_TEL);
   1237                         }
   1238                     } else {
   1239                         supportedUriSchemes.add(PhoneAccount.SCHEME_TEL);
   1240                         supportedUriSchemes.add(PhoneAccount.SCHEME_VOICEMAIL);
   1241                     }
   1242                 }
   1243 
   1244                 // Upgrade older phone accounts with explicit package name
   1245                 if (version < 5) {
   1246                     if (iconBitmap == null) {
   1247                         iconPackageName = accountHandle.getComponentName().getPackageName();
   1248                     }
   1249                 }
   1250 
   1251                 if (version < 6) {
   1252                     // Always enable all SIP accounts on upgrade to version 6
   1253                     if (accountHandle.getComponentName().equals(sipComponentName)) {
   1254                         enabled = true;
   1255                     }
   1256                 }
   1257                 if (version < 7) {
   1258                     // Always enabled all PSTN acocunts on upgrade to version 7
   1259                     if (accountHandle.getComponentName().equals(pstnComponentName)) {
   1260                         enabled = true;
   1261                     }
   1262                 }
   1263                 if (version < 8) {
   1264                     // Migrate the SIP account handle ids to use SIP username instead of SIP URI.
   1265                     if (accountHandle.getComponentName().equals(sipComponentName)) {
   1266                         Uri accountUri = Uri.parse(accountHandle.getId());
   1267                         if (accountUri.getScheme() != null &&
   1268                             accountUri.getScheme().equals(PhoneAccount.SCHEME_SIP)) {
   1269                             accountHandle = new PhoneAccountHandle(accountHandle.getComponentName(),
   1270                                     accountUri.getSchemeSpecificPart(),
   1271                                     accountHandle.getUserHandle());
   1272                         }
   1273                     }
   1274                 }
   1275 
   1276                 PhoneAccount.Builder builder = PhoneAccount.builder(accountHandle, label)
   1277                         .setAddress(address)
   1278                         .setSubscriptionAddress(subscriptionAddress)
   1279                         .setCapabilities(capabilities)
   1280                         .setShortDescription(shortDescription)
   1281                         .setSupportedUriSchemes(supportedUriSchemes)
   1282                         .setHighlightColor(highlightColor)
   1283                         .setIsEnabled(enabled);
   1284 
   1285                 if (icon != null) {
   1286                     builder.setIcon(icon);
   1287                 } else if (iconBitmap != null) {
   1288                     builder.setIcon(Icon.createWithBitmap(iconBitmap));
   1289                 } else if (!TextUtils.isEmpty(iconPackageName)) {
   1290                     builder.setIcon(Icon.createWithResource(iconPackageName, iconResId));
   1291                     // TODO: Need to set tint.
   1292                 }
   1293 
   1294                 return builder.build();
   1295             }
   1296             return null;
   1297         }
   1298 
   1299         /**
   1300          * Determines if the SIP call settings specify to use SIP for all calls, including PSTN
   1301          * calls.
   1302          *
   1303          * @param context The context.
   1304          * @return {@code True} if SIP should be used for all calls.
   1305          */
   1306         private boolean useSipForPstnCalls(Context context) {
   1307             String option = Settings.System.getString(context.getContentResolver(),
   1308                     Settings.System.SIP_CALL_OPTIONS);
   1309             option = (option != null) ? option : Settings.System.SIP_ADDRESS_ONLY;
   1310             return option.equals(Settings.System.SIP_ALWAYS);
   1311         }
   1312     };
   1313 
   1314     @VisibleForTesting
   1315     public static final XmlSerialization<PhoneAccountHandle> sPhoneAccountHandleXml =
   1316             new XmlSerialization<PhoneAccountHandle>() {
   1317         private static final String CLASS_PHONE_ACCOUNT_HANDLE = "phone_account_handle";
   1318         private static final String COMPONENT_NAME = "component_name";
   1319         private static final String ID = "id";
   1320         private static final String USER_SERIAL_NUMBER = "user_serial_number";
   1321 
   1322         @Override
   1323         public void writeToXml(PhoneAccountHandle o, XmlSerializer serializer, Context context)
   1324                 throws IOException {
   1325             if (o != null) {
   1326                 serializer.startTag(null, CLASS_PHONE_ACCOUNT_HANDLE);
   1327 
   1328                 if (o.getComponentName() != null) {
   1329                     writeTextIfNonNull(
   1330                             COMPONENT_NAME, o.getComponentName().flattenToString(), serializer);
   1331                 }
   1332 
   1333                 writeTextIfNonNull(ID, o.getId(), serializer);
   1334 
   1335                 if (o.getUserHandle() != null && context != null) {
   1336                     UserManager userManager = UserManager.get(context);
   1337                     writeLong(USER_SERIAL_NUMBER,
   1338                             userManager.getSerialNumberForUser(o.getUserHandle()), serializer);
   1339                 }
   1340 
   1341                 serializer.endTag(null, CLASS_PHONE_ACCOUNT_HANDLE);
   1342             }
   1343         }
   1344 
   1345         @Override
   1346         public PhoneAccountHandle readFromXml(XmlPullParser parser, int version, Context context)
   1347                 throws IOException, XmlPullParserException {
   1348             if (parser.getName().equals(CLASS_PHONE_ACCOUNT_HANDLE)) {
   1349                 String componentNameString = null;
   1350                 String idString = null;
   1351                 String userSerialNumberString = null;
   1352                 int outerDepth = parser.getDepth();
   1353 
   1354                 UserManager userManager = UserManager.get(context);
   1355 
   1356                 while (XmlUtils.nextElementWithin(parser, outerDepth)) {
   1357                     if (parser.getName().equals(COMPONENT_NAME)) {
   1358                         parser.next();
   1359                         componentNameString = parser.getText();
   1360                     } else if (parser.getName().equals(ID)) {
   1361                         parser.next();
   1362                         idString = parser.getText();
   1363                     } else if (parser.getName().equals(USER_SERIAL_NUMBER)) {
   1364                         parser.next();
   1365                         userSerialNumberString = parser.getText();
   1366                     }
   1367                 }
   1368                 if (componentNameString != null) {
   1369                     UserHandle userHandle = null;
   1370                     if (userSerialNumberString != null) {
   1371                         try {
   1372                             long serialNumber = Long.parseLong(userSerialNumberString);
   1373                             userHandle = userManager.getUserForSerialNumber(serialNumber);
   1374                         } catch (NumberFormatException e) {
   1375                             Log.e(this, e, "Could not parse UserHandle " + userSerialNumberString);
   1376                         }
   1377                     }
   1378                     return new PhoneAccountHandle(
   1379                             ComponentName.unflattenFromString(componentNameString),
   1380                             idString,
   1381                             userHandle);
   1382                 }
   1383             }
   1384             return null;
   1385         }
   1386     };
   1387 }
   1388