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 {
onAccountsChanged(PhoneAccountRegistrar registrar)120         public void onAccountsChanged(PhoneAccountRegistrar registrar) {}
onDefaultOutgoingChanged(PhoneAccountRegistrar registrar)121         public void onDefaultOutgoingChanged(PhoneAccountRegistrar registrar) {}
onSimCallManagerChanged(PhoneAccountRegistrar registrar)122         public void onSimCallManagerChanged(PhoneAccountRegistrar registrar) {}
onPhoneAccountRegistered(PhoneAccountRegistrar registrar, PhoneAccountHandle handle)123         public void onPhoneAccountRegistered(PhoneAccountRegistrar registrar,
124                                              PhoneAccountHandle handle) {}
onPhoneAccountUnRegistered(PhoneAccountRegistrar registrar, 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 {
getAppLabel(String packageName)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
PhoneAccountRegistrar(Context context, DefaultDialerCache defaultDialerCache, AppLabelProxy appLabelProxy)158     public PhoneAccountRegistrar(Context context, DefaultDialerCache defaultDialerCache,
159                                  AppLabelProxy appLabelProxy) {
160         this(context, FILE_NAME, defaultDialerCache, appLabelProxy);
161     }
162 
163     @VisibleForTesting
PhoneAccountRegistrar(Context context, String fileName, DefaultDialerCache defaultDialerCache, AppLabelProxy appLabelProxy)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      */
getSubscriptionIdForPhoneAccount(PhoneAccountHandle accountHandle)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      */
getOutgoingPhoneAccountForScheme(String uriScheme, UserHandle userHandle)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 
getOutgoingPhoneAccountForSchemeOfCurrentUser(String uriScheme)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
getUserSelectedOutgoingPhoneAccount(UserHandle userHandle)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      */
getUserSelectedDefaultPhoneAccount(UserHandle userHandle)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      */
getPhoneAccountByGroupId(String groupId, ComponentName groupComponentName, UserHandle userHandle, PhoneAccountHandle excludePhoneAccountHandle)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      */
setUserSelectedOutgoingPhoneAccount(PhoneAccountHandle accountHandle, UserHandle userHandle)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 
isUserSelectedSmsPhoneAccount(PhoneAccountHandle accountHandle)344     boolean isUserSelectedSmsPhoneAccount(PhoneAccountHandle accountHandle) {
345         return getSubscriptionIdForPhoneAccount(accountHandle) ==
346                 SubscriptionManager.getDefaultSmsSubscriptionId();
347     }
348 
getSystemSimCallManagerComponent()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 
getSimCallManagerOfCurrentUser()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      */
getSimCallManager(UserHandle userHandle)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      */
getSimCallManagerFromCall(Call call)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      */
setCurrentUserHandle(UserHandle userHandle)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      */
enablePhoneAccount(PhoneAccountHandle accountHandle, boolean isEnabled)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 
removeDefaultPhoneAccountHandle(PhoneAccountHandle phoneAccountHandle)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 
isVisibleForUser(PhoneAccount account, UserHandle userHandle, boolean acrossProfiles)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 
resolveComponent(PhoneAccountHandle phoneAccountHandle)528     private List<ResolveInfo> resolveComponent(PhoneAccountHandle phoneAccountHandle) {
529         return resolveComponent(phoneAccountHandle.getComponentName(),
530                 phoneAccountHandle.getUserHandle());
531     }
532 
resolveComponent(ComponentName componentName, UserHandle userHandle)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      */
getAllPhoneAccountHandles(UserHandle userHandle)556     public List<PhoneAccountHandle> getAllPhoneAccountHandles(UserHandle userHandle) {
557         return getPhoneAccountHandles(0, null, null, false, userHandle);
558     }
559 
getAllPhoneAccounts(UserHandle userHandle)560     public List<PhoneAccount> getAllPhoneAccounts(UserHandle userHandle) {
561         return getPhoneAccounts(0, null, null, false, userHandle);
562     }
563 
getAllPhoneAccountsOfCurrentUser()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      */
getCallCapablePhoneAccounts( String uriScheme, boolean includeDisabledAccounts, UserHandle userHandle)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      */
getSelfManagedPhoneAccounts(UserHandle userHandle)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 
getCallCapablePhoneAccountsOfCurrentUser( String uriScheme, boolean includeDisabledAccounts)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      */
getSimPhoneAccounts(UserHandle userHandle)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 
getSimPhoneAccountsOfCurrentUser()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          */
getPhoneAccountsForPackage(String packageName, UserHandle userHandle)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?
registerPhoneAccount(PhoneAccount account)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      */
addOrReplacePhoneAccount(PhoneAccount account)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 
unregisterPhoneAccount(PhoneAccountHandle accountHandle)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      */
clearAccounts(String packageName, UserHandle userHandle)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 
isVoiceMailNumber(PhoneAccountHandle accountHandle, String number)747     public boolean isVoiceMailNumber(PhoneAccountHandle accountHandle, String number) {
748         int subId = getSubscriptionIdForPhoneAccount(accountHandle);
749         return PhoneNumberUtils.isVoiceMailNumber(mContext, subId, number);
750     }
751 
addListener(Listener l)752     public void addListener(Listener l) {
753         mListeners.add(l);
754     }
755 
removeListener(Listener l)756     public void removeListener(Listener l) {
757         if (l != null) {
758             mListeners.remove(l);
759         }
760     }
761 
fireAccountRegistered(PhoneAccountHandle handle)762     private void fireAccountRegistered(PhoneAccountHandle handle) {
763         for (Listener l : mListeners) {
764             l.onPhoneAccountRegistered(this, handle);
765         }
766     }
767 
fireAccountUnRegistered(PhoneAccountHandle handle)768     private void fireAccountUnRegistered(PhoneAccountHandle handle) {
769         for (Listener l : mListeners) {
770             l.onPhoneAccountUnRegistered(this, handle);
771         }
772     }
773 
fireAccountsChanged()774     private void fireAccountsChanged() {
775         for (Listener l : mListeners) {
776             l.onAccountsChanged(this);
777         }
778     }
779 
fireDefaultOutgoingChanged()780     private void fireDefaultOutgoingChanged() {
781         for (Listener l : mListeners) {
782             l.onDefaultOutgoingChanged(this);
783         }
784     }
785 
getAccountDiffString(PhoneAccount account1, PhoneAccount account2)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 
appendDiff(StringBuffer sb, String attrName, Object obj1, Object obj2)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 
maybeReplaceOldAccount(PhoneAccount newAccount)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      */
phoneAccountRequiresBindPermission(PhoneAccountHandle phoneAccountHandle)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      */
getPhoneAccountUnchecked(PhoneAccountHandle handle)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      */
getPhoneAccount(PhoneAccountHandle handle, UserHandle userHandle)908     public PhoneAccount getPhoneAccount(PhoneAccountHandle handle, UserHandle userHandle) {
909         return getPhoneAccount(handle, userHandle, /* acrossProfiles */ false);
910     }
911 
getPhoneAccount(PhoneAccountHandle handle, UserHandle userHandle, boolean acrossProfiles)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 
getPhoneAccountOfCurrentUser(PhoneAccountHandle handle)921     public PhoneAccount getPhoneAccountOfCurrentUser(PhoneAccountHandle handle) {
922         return getPhoneAccount(handle, mCurrentUserHandle);
923     }
924 
getPhoneAccountHandles( int capabilities, String uriScheme, String packageName, boolean includeDisabledAccounts, UserHandle userHandle)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      */
getPhoneAccountHandles( int capabilities, int excludedCapabilities, String uriScheme, String packageName, boolean includeDisabledAccounts, UserHandle userHandle)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 
getPhoneAccounts( int capabilities, String uriScheme, String packageName, boolean includeDisabledAccounts, UserHandle userHandle)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      */
getPhoneAccounts( int capabilities, int excludedCapabilities, String uriScheme, String packageName, boolean includeDisabledAccounts, UserHandle userHandle)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 
DefaultPhoneAccountHandle(UserHandle userHandle, PhoneAccountHandle phoneAccountHandle, String groupId)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      */
dump(IndentingPrintWriter pw)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
doInBackground(ByteArrayOutputStream... args)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 
write()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 
read()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