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