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