• 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.annotation.NonNull;
21 import android.annotation.Nullable;
22 import android.content.BroadcastReceiver;
23 import android.content.ComponentName;
24 import android.content.Context;
25 import android.content.Intent;
26 import android.content.IntentFilter;
27 import android.content.pm.PackageManager;
28 import android.content.pm.ResolveInfo;
29 import android.content.pm.ServiceInfo;
30 import android.content.pm.UserInfo;
31 import android.graphics.Bitmap;
32 import android.graphics.BitmapFactory;
33 import android.graphics.drawable.Icon;
34 import android.net.Uri;
35 import android.os.Bundle;
36 import android.os.AsyncTask;
37 import android.os.PersistableBundle;
38 import android.os.Process;
39 import android.os.UserHandle;
40 import android.os.UserManager;
41 import android.provider.Settings;
42 import android.telecom.CallAudioState;
43 import android.telecom.ConnectionService;
44 import android.telecom.DefaultDialerManager;
45 import android.telecom.Log;
46 import android.telecom.PhoneAccount;
47 import android.telecom.PhoneAccountHandle;
48 import android.telephony.CarrierConfigManager;
49 import android.telephony.PhoneNumberUtils;
50 import android.telephony.SubscriptionInfo;
51 import android.telephony.SubscriptionManager;
52 import android.telephony.TelephonyManager;
53 import android.text.TextUtils;
54 import android.util.AtomicFile;
55 import android.util.Base64;
56 import android.util.EventLog;
57 import android.util.Xml;
58 
59 // TODO: Needed for move to system service: import com.android.internal.R;
60 import com.android.internal.annotations.VisibleForTesting;
61 import com.android.internal.util.FastXmlSerializer;
62 import com.android.internal.util.IndentingPrintWriter;
63 import com.android.internal.util.XmlUtils;
64 
65 import org.xmlpull.v1.XmlPullParser;
66 import org.xmlpull.v1.XmlPullParserException;
67 import org.xmlpull.v1.XmlSerializer;
68 
69 import java.io.BufferedInputStream;
70 import java.io.ByteArrayInputStream;
71 import java.io.ByteArrayOutputStream;
72 import java.io.File;
73 import java.io.FileNotFoundException;
74 import java.io.FileOutputStream;
75 import java.io.IOException;
76 import java.io.InputStream;
77 import java.lang.Integer;
78 import java.lang.SecurityException;
79 import java.lang.String;
80 import java.util.ArrayList;
81 import java.util.Collections;
82 import java.util.Comparator;
83 import java.util.HashMap;
84 import java.util.Iterator;
85 import java.util.List;
86 import java.util.Map;
87 import java.util.Objects;
88 import java.util.Optional;
89 import java.util.concurrent.ConcurrentHashMap;
90 import java.util.concurrent.CopyOnWriteArrayList;
91 import java.util.stream.Collector;
92 import java.util.stream.Collectors;
93 import java.util.stream.Stream;
94 
95 /**
96  * Handles writing and reading PhoneAccountHandle registration entries. This is a simple verbatim
97  * delegate for all the account handling methods on {@link android.telecom.TelecomManager} as
98  * implemented in {@link TelecomServiceImpl}, with the notable exception that
99  * {@link TelecomServiceImpl} is responsible for security checking to make sure that the caller has
100  * proper authority over the {@code ComponentName}s they are declaring in their
101  * {@code PhoneAccountHandle}s.
102  *
103  *
104  *  -- About Users and Phone Accounts --
105  *
106  * We store all phone accounts for all users in a single place, which means that there are three
107  * users that we have to deal with in code:
108  * 1) The Android User that is currently active on the device.
109  * 2) The user which owns/registers the phone account.
110  * 3) The user running the app that is requesting the phone account information.
111  *
112  * For example, I have a device with 2 users, primary (A) and secondary (B), and the secondary user
113  * has a work profile running as another user (B2). Each user/profile only have the visibility of
114  * phone accounts owned by them. Lets say, user B (settings) is requesting a list of phone accounts,
115  * and the list only contains phone accounts owned by user B and accounts with
116  * {@link PhoneAccount#CAPABILITY_MULTI_USER}.
117  *
118  * In practice, (2) is stored with the phone account handle and is part of the handle's ID. (1) is
119  * saved in {@link #mCurrentUserHandle} and (3) we get from Binder.getCallingUser(). We check these
120  * users for visibility before returning any phone accounts.
121  */
122 public class PhoneAccountRegistrar {
123 
124     public static final PhoneAccountHandle NO_ACCOUNT_SELECTED =
125             new PhoneAccountHandle(new ComponentName("null", "null"), "NO_ACCOUNT_SELECTED");
126 
127     public abstract static class Listener {
onAccountsChanged(PhoneAccountRegistrar registrar)128         public void onAccountsChanged(PhoneAccountRegistrar registrar) {}
onDefaultOutgoingChanged(PhoneAccountRegistrar registrar)129         public void onDefaultOutgoingChanged(PhoneAccountRegistrar registrar) {}
onSimCallManagerChanged(PhoneAccountRegistrar registrar)130         public void onSimCallManagerChanged(PhoneAccountRegistrar registrar) {}
onPhoneAccountRegistered(PhoneAccountRegistrar registrar, PhoneAccountHandle handle)131         public void onPhoneAccountRegistered(PhoneAccountRegistrar registrar,
132                                              PhoneAccountHandle handle) {}
onPhoneAccountUnRegistered(PhoneAccountRegistrar registrar, PhoneAccountHandle handle)133         public void onPhoneAccountUnRegistered(PhoneAccountRegistrar registrar,
134                                              PhoneAccountHandle handle) {}
onPhoneAccountChanged(PhoneAccountRegistrar registrar, PhoneAccount phoneAccount)135         public void onPhoneAccountChanged(PhoneAccountRegistrar registrar,
136                 PhoneAccount phoneAccount) {}
137     }
138 
139     /**
140      * Receiver for detecting when a managed profile has been removed so that PhoneAccountRegistrar
141      * can clean up orphan {@link PhoneAccount}s
142      */
143     private final BroadcastReceiver mManagedProfileReceiver = new BroadcastReceiver() {
144         @Override
145         public void onReceive(Context context, Intent intent) {
146             Log.startSession("PARbR.oR");
147             try {
148                 synchronized (mLock) {
149                     if (intent.getAction().equals(Intent.ACTION_MANAGED_PROFILE_REMOVED)) {
150                         cleanupOrphanedPhoneAccounts();
151                     }
152                 }
153             } finally {
154                 Log.endSession();
155             }
156         }
157     };
158 
159     public static final String FILE_NAME = "phone-account-registrar-state.xml";
160     @VisibleForTesting
161     public static final int EXPECTED_STATE_VERSION = 9;
162     public static final int MAX_PHONE_ACCOUNT_REGISTRATIONS = 10;
163 
164     /** Keep in sync with the same in SipSettings.java */
165     private static final String SIP_SHARED_PREFERENCES = "SIP_PREFERENCES";
166 
167     private final List<Listener> mListeners = new CopyOnWriteArrayList<>();
168     private final AtomicFile mAtomicFile;
169     private final Context mContext;
170     private final UserManager mUserManager;
171     private final TelephonyManager mTelephonyManager;
172     private final SubscriptionManager mSubscriptionManager;
173     private final DefaultDialerCache mDefaultDialerCache;
174     private final AppLabelProxy mAppLabelProxy;
175     private final TelecomSystem.SyncRoot mLock;
176     private State mState;
177     private UserHandle mCurrentUserHandle;
178     private String mTestPhoneAccountPackageNameFilter;
179     private interface PhoneAccountRegistrarWriteLock {}
180     private final PhoneAccountRegistrarWriteLock mWriteLock =
181             new PhoneAccountRegistrarWriteLock() {};
182 
183     @VisibleForTesting
PhoneAccountRegistrar(Context context, TelecomSystem.SyncRoot lock, DefaultDialerCache defaultDialerCache, AppLabelProxy appLabelProxy)184     public PhoneAccountRegistrar(Context context, TelecomSystem.SyncRoot lock,
185             DefaultDialerCache defaultDialerCache, AppLabelProxy appLabelProxy) {
186         this(context, lock, FILE_NAME, defaultDialerCache, appLabelProxy);
187     }
188 
189     @VisibleForTesting
PhoneAccountRegistrar(Context context, TelecomSystem.SyncRoot lock, String fileName, DefaultDialerCache defaultDialerCache, AppLabelProxy appLabelProxy)190     public PhoneAccountRegistrar(Context context, TelecomSystem.SyncRoot lock, String fileName,
191             DefaultDialerCache defaultDialerCache, AppLabelProxy appLabelProxy) {
192 
193         mAtomicFile = new AtomicFile(new File(context.getFilesDir(), fileName));
194 
195         mState = new State();
196         mContext = context;
197         mLock = lock;
198         mUserManager = UserManager.get(context);
199         mDefaultDialerCache = defaultDialerCache;
200         mSubscriptionManager = SubscriptionManager.from(mContext);
201         mTelephonyManager = (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE);
202         mAppLabelProxy = appLabelProxy;
203         mCurrentUserHandle = Process.myUserHandle();
204 
205         // register context based receiver to clean up orphan phone accounts
206         IntentFilter intentFilter = new IntentFilter(Intent.ACTION_MANAGED_PROFILE_REMOVED);
207         mContext.registerReceiver(mManagedProfileReceiver, intentFilter);
208 
209         read();
210     }
211 
212     /**
213      * Retrieves the subscription id for a given phone account if it exists. Subscription ids
214      * apply only to PSTN/SIM card phone accounts so all other accounts should not have a
215      * subscription id.
216      * @param accountHandle The handle for the phone account for which to retrieve the
217      * subscription id.
218      * @return The value of the subscription id or -1 if it does not exist or is not valid.
219      */
getSubscriptionIdForPhoneAccount(PhoneAccountHandle accountHandle)220     public int getSubscriptionIdForPhoneAccount(PhoneAccountHandle accountHandle) {
221         PhoneAccount account = getPhoneAccountUnchecked(accountHandle);
222 
223         if (account != null && account.hasCapabilities(PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION)) {
224             return mTelephonyManager.getSubscriptionId(accountHandle);
225         }
226         return SubscriptionManager.INVALID_SUBSCRIPTION_ID;
227     }
228 
229     /**
230      * Retrieves the default outgoing phone account supporting the specified uriScheme. Note that if
231      * {@link #mCurrentUserHandle} does not have visibility into the current default, {@code null}
232      * will be returned.
233      *
234      * @param uriScheme The URI scheme for the outgoing call.
235      * @return The {@link PhoneAccountHandle} to use.
236      */
getOutgoingPhoneAccountForScheme(String uriScheme, UserHandle userHandle)237     public PhoneAccountHandle getOutgoingPhoneAccountForScheme(String uriScheme,
238             UserHandle userHandle) {
239         final PhoneAccountHandle userSelected = getUserSelectedOutgoingPhoneAccount(userHandle);
240 
241         if (userSelected != null) {
242             // If there is a default PhoneAccount, ensure it supports calls to handles with the
243             // specified uriScheme.
244             final PhoneAccount userSelectedAccount = getPhoneAccountUnchecked(userSelected);
245             if (userSelectedAccount.supportsUriScheme(uriScheme)) {
246                 return userSelected;
247             }
248         }
249 
250         List<PhoneAccountHandle> outgoing = getCallCapablePhoneAccounts(uriScheme, false,
251                 userHandle);
252         switch (outgoing.size()) {
253             case 0:
254                 // There are no accounts, so there can be no default
255                 return null;
256             case 1:
257                 // There is only one account, which is by definition the default.
258                 return outgoing.get(0);
259             default:
260                 // There are multiple accounts with no selected default
261                 return null;
262         }
263     }
264 
getOutgoingPhoneAccountForSchemeOfCurrentUser(String uriScheme)265     public PhoneAccountHandle getOutgoingPhoneAccountForSchemeOfCurrentUser(String uriScheme) {
266         return getOutgoingPhoneAccountForScheme(uriScheme, mCurrentUserHandle);
267     }
268 
269     /**
270      * @return The user-selected outgoing {@link PhoneAccount}, or null if it hasn't been set (or
271      *      if it was set by another user).
272      */
273     @VisibleForTesting
getUserSelectedOutgoingPhoneAccount(UserHandle userHandle)274     public PhoneAccountHandle getUserSelectedOutgoingPhoneAccount(UserHandle userHandle) {
275         if (userHandle == null) {
276             return null;
277         }
278         DefaultPhoneAccountHandle defaultPhoneAccountHandle = mState.defaultOutgoingAccountHandles
279                 .get(userHandle);
280         if (defaultPhoneAccountHandle == null) {
281             return null;
282         }
283         // Make sure the account is still registered and owned by the user.
284         PhoneAccount account = getPhoneAccount(defaultPhoneAccountHandle.phoneAccountHandle,
285                 userHandle);
286 
287         if (account != null) {
288             return defaultPhoneAccountHandle.phoneAccountHandle;
289         }
290 
291         Log.v(this,
292                 "getUserSelectedOutgoingPhoneAccount: defaultPhoneAccountHandle"
293                         + ".phoneAccountHandle=[%s] is not registered or owned by %s"
294                 , defaultPhoneAccountHandle.phoneAccountHandle, userHandle);
295 
296         return null;
297     }
298 
299     /**
300      * @return The {@link DefaultPhoneAccountHandle} containing the user-selected default calling
301      * account and group Id for the {@link UserHandle} specified.
302      */
getUserSelectedDefaultPhoneAccount(UserHandle userHandle)303     private DefaultPhoneAccountHandle getUserSelectedDefaultPhoneAccount(UserHandle userHandle) {
304         if (userHandle == null) {
305             return null;
306         }
307         DefaultPhoneAccountHandle defaultPhoneAccountHandle = mState.defaultOutgoingAccountHandles
308                 .get(userHandle);
309         if (defaultPhoneAccountHandle == null) {
310             return null;
311         }
312 
313         return defaultPhoneAccountHandle;
314     }
315 
316     /**
317      * @return The currently registered PhoneAccount in Telecom that has the same group Id.
318      */
getPhoneAccountByGroupId(String groupId, ComponentName groupComponentName, UserHandle userHandle, PhoneAccountHandle excludePhoneAccountHandle)319     private PhoneAccount getPhoneAccountByGroupId(String groupId, ComponentName groupComponentName,
320             UserHandle userHandle, PhoneAccountHandle excludePhoneAccountHandle) {
321         if (groupId == null || groupId.isEmpty() || userHandle == null) {
322             return null;
323         }
324         // Get the PhoneAccount with the same group Id (and same ComponentName) that is not the
325         // newAccount that was just added
326         List<PhoneAccount> accounts = getAllPhoneAccounts(userHandle).stream()
327                 .filter(account -> groupId.equals(account.getGroupId()) &&
328                         !account.getAccountHandle().equals(excludePhoneAccountHandle) &&
329                         Objects.equals(account.getAccountHandle().getComponentName(),
330                                 groupComponentName))
331                 .collect(Collectors.toList());
332         // There should be one or no PhoneAccounts with the same group Id
333         if (accounts.size() > 1) {
334             Log.w(this, "Found multiple PhoneAccounts registered to the same Group Id!");
335         }
336         return accounts.isEmpty() ? null : accounts.get(0);
337     }
338 
339     /**
340      * Sets the phone account with which to place all calls by default. Set by the user
341      * within phone settings.
342      */
setUserSelectedOutgoingPhoneAccount(PhoneAccountHandle accountHandle, UserHandle userHandle)343     public void setUserSelectedOutgoingPhoneAccount(PhoneAccountHandle accountHandle,
344             UserHandle userHandle) {
345         if (userHandle == null) {
346             return;
347         }
348         DefaultPhoneAccountHandle currentDefaultInfo =
349                 mState.defaultOutgoingAccountHandles.get(userHandle);
350         PhoneAccountHandle currentDefaultPhoneAccount = currentDefaultInfo == null ? null :
351                 currentDefaultInfo.phoneAccountHandle;
352 
353         Log.i(this, "setUserSelectedOutgoingPhoneAccount: %s", accountHandle);
354 
355         if (Objects.equals(currentDefaultPhoneAccount, accountHandle)) {
356             Log.i(this, "setUserSelectedOutgoingPhoneAccount: "
357                     + "no change in default phoneAccountHandle.  current is same as new.");
358             return;
359         }
360 
361         boolean isSimAccount = false;
362         if (accountHandle == null) {
363             // Asking to clear the default outgoing is a valid request
364             mState.defaultOutgoingAccountHandles.remove(userHandle);
365         } else {
366             PhoneAccount account = getPhoneAccount(accountHandle, userHandle);
367             if (account == null) {
368                 Log.w(this, "Trying to set nonexistent default outgoing %s",
369                         accountHandle);
370                 return;
371             }
372 
373             if (!account.hasCapabilities(PhoneAccount.CAPABILITY_CALL_PROVIDER)) {
374                 Log.w(this, "Trying to set non-call-provider default outgoing %s",
375                         accountHandle);
376                 return;
377             }
378 
379             if (account.hasCapabilities(PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION)) {
380                 // If the account selected is a SIM account, propagate down to the subscription
381                 // record.
382                 isSimAccount = true;
383             }
384 
385             mState.defaultOutgoingAccountHandles
386                     .put(userHandle, new DefaultPhoneAccountHandle(userHandle, accountHandle,
387                             account.getGroupId()));
388         }
389 
390         // Potentially update the default voice subid in SubscriptionManager.
391         int newSubId = accountHandle == null ? SubscriptionManager.INVALID_SUBSCRIPTION_ID :
392                 getSubscriptionIdForPhoneAccount(accountHandle);
393         if (isSimAccount || accountHandle == null) {
394             int currentVoiceSubId = mSubscriptionManager.getDefaultVoiceSubscriptionId();
395             if (newSubId != currentVoiceSubId) {
396                 Log.i(this, "setUserSelectedOutgoingPhoneAccount: update voice sub; "
397                         + "account=%s, subId=%d", accountHandle, newSubId);
398                 mSubscriptionManager.setDefaultVoiceSubscriptionId(newSubId);
399             } else {
400                 Log.i(this, "setUserSelectedOutgoingPhoneAccount: no change to voice sub");
401             }
402         } else {
403             Log.i(this, "setUserSelectedOutgoingPhoneAccount: %s is not a sub", accountHandle);
404         }
405 
406         write();
407         fireDefaultOutgoingChanged();
408     }
409 
isUserSelectedSmsPhoneAccount(PhoneAccountHandle accountHandle)410     boolean isUserSelectedSmsPhoneAccount(PhoneAccountHandle accountHandle) {
411         return getSubscriptionIdForPhoneAccount(accountHandle) ==
412                 SubscriptionManager.getDefaultSmsSubscriptionId();
413     }
414 
getSystemSimCallManagerComponent()415     public ComponentName getSystemSimCallManagerComponent() {
416         return getSystemSimCallManagerComponent(SubscriptionManager.getDefaultSubscriptionId());
417     }
418 
getSystemSimCallManagerComponent(int subId)419     public ComponentName getSystemSimCallManagerComponent(int subId) {
420         String defaultSimCallManager = null;
421         CarrierConfigManager configManager = (CarrierConfigManager) mContext.getSystemService(
422                 Context.CARRIER_CONFIG_SERVICE);
423         PersistableBundle configBundle = configManager.getConfigForSubId(subId);
424         if (configBundle != null) {
425             defaultSimCallManager = configBundle.getString(
426                     CarrierConfigManager.KEY_DEFAULT_SIM_CALL_MANAGER_STRING);
427         }
428         return TextUtils.isEmpty(defaultSimCallManager)
429                 ?  null : ComponentName.unflattenFromString(defaultSimCallManager);
430     }
431 
getSimCallManagerOfCurrentUser()432     public PhoneAccountHandle getSimCallManagerOfCurrentUser() {
433         return getSimCallManager(mCurrentUserHandle);
434     }
435 
436     /**
437      * Returns the {@link PhoneAccountHandle} corresponding to the SIM Call Manager associated with
438      * the default Telephony Subscription ID (see
439      * {@link SubscriptionManager#getDefaultSubscriptionId()}). SIM Call Manager returned
440      * corresponds to the following priority order:
441      * 1. If a SIM Call Manager {@link PhoneAccount} is registered for the same package as the
442      * default dialer, then that one is returned.
443      * 2. If there is a SIM Call Manager {@link PhoneAccount} registered which matches the
444      * carrier configuration's default, then that one is returned.
445      * 3. Otherwise, we return null.
446      */
getSimCallManager(UserHandle userHandle)447     public PhoneAccountHandle getSimCallManager(UserHandle userHandle) {
448         return getSimCallManager(SubscriptionManager.getDefaultSubscriptionId(), userHandle);
449     }
450 
451     /**
452      * Queries the SIM call manager associated with a specific subscription ID.
453      *
454      * @see #getSimCallManager(UserHandle) for more information.
455      */
getSimCallManager(int subId, UserHandle userHandle)456     public PhoneAccountHandle getSimCallManager(int subId, UserHandle userHandle) {
457 
458         // Get the default dialer in case it has a connection manager associated with it.
459         String dialerPackage = mDefaultDialerCache
460                 .getDefaultDialerApplication(userHandle.getIdentifier());
461 
462         // Check carrier config.
463         ComponentName systemSimCallManagerComponent = getSystemSimCallManagerComponent(subId);
464 
465         PhoneAccountHandle dialerSimCallManager = null;
466         PhoneAccountHandle systemSimCallManager = null;
467 
468         if (!TextUtils.isEmpty(dialerPackage) || systemSimCallManagerComponent != null) {
469             // loop through and look for any connection manager in the same package.
470             List<PhoneAccountHandle> allSimCallManagers = getPhoneAccountHandles(
471                     PhoneAccount.CAPABILITY_CONNECTION_MANAGER, null, null,
472                     true /* includeDisabledAccounts */, userHandle);
473             for (PhoneAccountHandle accountHandle : allSimCallManagers) {
474                 ComponentName component = accountHandle.getComponentName();
475 
476                 // Store the system connection manager if found
477                 if (systemSimCallManager == null
478                         && Objects.equals(component, systemSimCallManagerComponent)
479                         && !resolveComponent(accountHandle).isEmpty()) {
480                     systemSimCallManager = accountHandle;
481 
482                 // Store the dialer connection manager if found
483                 } else if (dialerSimCallManager == null
484                         && Objects.equals(component.getPackageName(), dialerPackage)
485                         && !resolveComponent(accountHandle).isEmpty()) {
486                     dialerSimCallManager = accountHandle;
487                 }
488             }
489         }
490 
491         PhoneAccountHandle retval = dialerSimCallManager != null ?
492                 dialerSimCallManager : systemSimCallManager;
493         Log.i(this, "getSimCallManager: SimCallManager for subId %d queried, returning: %s",
494                 subId, retval);
495 
496         return retval;
497     }
498 
499     /**
500      * Loops through all SIM accounts ({@link #getSimPhoneAccounts}) and returns those with SIM call
501      * manager components specified in carrier config that match {@code simCallManagerHandle}.
502      *
503      * <p>Note that this will return handles even when {@code simCallManagerHandle} has not yet been
504      * registered or was recently unregistered.
505      *
506      * <p>If the given {@code simCallManagerHandle} is not the SIM call manager for any active SIMs,
507      * returns an empty list.
508      */
getSimPhoneAccountsFromSimCallManager( @onNull PhoneAccountHandle simCallManagerHandle)509     public @NonNull List<PhoneAccountHandle> getSimPhoneAccountsFromSimCallManager(
510             @NonNull PhoneAccountHandle simCallManagerHandle) {
511         List<PhoneAccountHandle> matchingSimHandles = new ArrayList<>();
512         for (PhoneAccountHandle simHandle :
513                 getSimPhoneAccounts(simCallManagerHandle.getUserHandle())) {
514             ComponentName simCallManager =
515                     getSystemSimCallManagerComponent(getSubscriptionIdForPhoneAccount(simHandle));
516             if (simCallManager == null) continue;
517             if (simCallManager.equals(simCallManagerHandle.getComponentName())) {
518                 matchingSimHandles.add(simHandle);
519             }
520         }
521         return matchingSimHandles;
522     }
523 
524     /**
525      * Sets a filter for which {@link PhoneAccount}s will be returned from
526      * {@link #filterRestrictedPhoneAccounts(List)}. If non-null, only {@link PhoneAccount}s
527      * with the package name packageNameFilter will be returned. If null, no filter is set.
528      * @param packageNameFilter The package name that will be used to filter only
529      * {@link PhoneAccount}s with the same package name.
530      */
setTestPhoneAccountPackageNameFilter(String packageNameFilter)531     public void setTestPhoneAccountPackageNameFilter(String packageNameFilter) {
532         mTestPhoneAccountPackageNameFilter = packageNameFilter;
533         Log.i(this, "filter set for PhoneAccounts, packageName=" + packageNameFilter);
534     }
535 
536     /**
537      * Filter the given {@link List<PhoneAccount>} and keep only {@link PhoneAccount}s that have the
538      * #mTestPhoneAccountPackageNameFilter.
539      * @param accounts List of {@link PhoneAccount}s to filter.
540      * @return new list of filtered {@link PhoneAccount}s.
541      */
filterRestrictedPhoneAccounts(List<PhoneAccount> accounts)542     public List<PhoneAccount> filterRestrictedPhoneAccounts(List<PhoneAccount> accounts) {
543         if (TextUtils.isEmpty(mTestPhoneAccountPackageNameFilter)) {
544             return new ArrayList<>(accounts);
545         }
546         // Remove all PhoneAccounts that do not have the same package name as the filter.
547         return accounts.stream().filter(account -> mTestPhoneAccountPackageNameFilter.equals(
548                 account.getAccountHandle().getComponentName().getPackageName()))
549                 .collect(Collectors.toList());
550     }
551 
552     /**
553      * If it is a outgoing call, sim call manager associated with the target phone account of the
554      * call is returned (if one exists).
555      * Otherwise, we return the sim call manager of the user associated with the
556      * target phone account.
557      * @return phone account handle of sim call manager based on the ongoing call.
558      */
559     @Nullable
getSimCallManagerFromCall(Call call)560     public PhoneAccountHandle getSimCallManagerFromCall(Call call) {
561         if (call == null) {
562             return null;
563         }
564         UserHandle userHandle = call.getInitiatingUser();
565         if (userHandle == null) {
566             userHandle = call.getTargetPhoneAccount().getUserHandle();
567         }
568         PhoneAccountHandle targetPhoneAccount = call.getTargetPhoneAccount();
569         Log.d(this, "getSimCallManagerFromCall: callId=%s, targetPhac=%s",
570                 call.getId(), targetPhoneAccount);
571         return getSimCallManagerFromHandle(targetPhoneAccount,userHandle);
572     }
573 
574     /**
575      * Given a target phone account and user, determines the sim call manager (if any) which is
576      * associated with that {@link PhoneAccountHandle}.
577      * @param targetPhoneAccount The target phone account to check.
578      * @param userHandle The user handle.
579      * @return The {@link PhoneAccountHandle} of the connection manager.
580      */
getSimCallManagerFromHandle(PhoneAccountHandle targetPhoneAccount, UserHandle userHandle)581     public PhoneAccountHandle getSimCallManagerFromHandle(PhoneAccountHandle targetPhoneAccount,
582             UserHandle userHandle) {
583         // First, check if the specified target phone account handle is a connection manager; if
584         // it is, then just return it.
585         PhoneAccount phoneAccount = getPhoneAccountUnchecked(targetPhoneAccount);
586         if (phoneAccount != null
587                 && phoneAccount.hasCapabilities(PhoneAccount.CAPABILITY_CONNECTION_MANAGER)) {
588             return targetPhoneAccount;
589         }
590 
591         int subId = getSubscriptionIdForPhoneAccount(targetPhoneAccount);
592         if (SubscriptionManager.isValidSubscriptionId(subId)
593                  && subId != SubscriptionManager.DEFAULT_SUBSCRIPTION_ID) {
594             PhoneAccountHandle callManagerHandle = getSimCallManager(subId, userHandle);
595             Log.d(this, "getSimCallManagerFromHandle: targetPhac=%s, subId=%d, scm=%s",
596                     targetPhoneAccount, subId, callManagerHandle);
597             return callManagerHandle;
598         } else {
599             PhoneAccountHandle callManagerHandle = getSimCallManager(userHandle);
600             Log.d(this, "getSimCallManagerFromHandle: targetPhac=%s, subId(d)=%d, scm=%s",
601                     targetPhoneAccount, subId, callManagerHandle);
602             return callManagerHandle;
603         }
604     }
605 
606     /**
607      * Update the current UserHandle to track when users are switched. This will allow the
608      * PhoneAccountRegistar to self-filter the PhoneAccounts to make sure we don't leak anything
609      * across users.
610      * We cannot simply check the calling user because that would always return the primary user for
611      * all invocations originating with the system process.
612      *
613      * @param userHandle The {@link UserHandle}, as delivered by
614      *          {@link Intent#ACTION_USER_SWITCHED}.
615      */
setCurrentUserHandle(UserHandle userHandle)616     public void setCurrentUserHandle(UserHandle userHandle) {
617         if (userHandle == null) {
618             Log.d(this, "setCurrentUserHandle, userHandle = null");
619             userHandle = Process.myUserHandle();
620         }
621         Log.d(this, "setCurrentUserHandle, %s", userHandle);
622         mCurrentUserHandle = userHandle;
623     }
624 
625     /**
626      * @return {@code true} if the phone account was successfully enabled/disabled, {@code false}
627      *         otherwise.
628      */
enablePhoneAccount(PhoneAccountHandle accountHandle, boolean isEnabled)629     public boolean enablePhoneAccount(PhoneAccountHandle accountHandle, boolean isEnabled) {
630         PhoneAccount account = getPhoneAccountUnchecked(accountHandle);
631         Log.i(this, "Phone account %s %s.", accountHandle, isEnabled ? "enabled" : "disabled");
632         if (account == null) {
633             Log.w(this, "Could not find account to enable: " + accountHandle);
634             return false;
635         } else if (account.hasCapabilities(PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION)) {
636             // We never change the enabled state of SIM-based accounts.
637             Log.w(this, "Could not change enable state of SIM account: " + accountHandle);
638             return false;
639         }
640 
641         if (account.isEnabled() != isEnabled) {
642             account.setIsEnabled(isEnabled);
643             if (!isEnabled) {
644                 // If the disabled account is the default, remove it.
645                 removeDefaultPhoneAccountHandle(accountHandle);
646             }
647             write();
648             fireAccountsChanged();
649         }
650         return true;
651     }
652 
removeDefaultPhoneAccountHandle(PhoneAccountHandle phoneAccountHandle)653     private void removeDefaultPhoneAccountHandle(PhoneAccountHandle phoneAccountHandle) {
654         Iterator<Map.Entry<UserHandle, DefaultPhoneAccountHandle>> iterator =
655                 mState.defaultOutgoingAccountHandles.entrySet().iterator();
656         while (iterator.hasNext()) {
657             Map.Entry<UserHandle, DefaultPhoneAccountHandle> entry = iterator.next();
658             if (phoneAccountHandle.equals(entry.getValue().phoneAccountHandle)) {
659                 iterator.remove();
660             }
661         }
662     }
663 
isVisibleForUser(PhoneAccount account, UserHandle userHandle, boolean acrossProfiles)664     private boolean isVisibleForUser(PhoneAccount account, UserHandle userHandle,
665             boolean acrossProfiles) {
666         if (account == null) {
667             return false;
668         }
669 
670         if (userHandle == null) {
671             Log.w(this, "userHandle is null in isVisibleForUser");
672             return false;
673         }
674 
675         // If this PhoneAccount has CAPABILITY_MULTI_USER, it should be visible to all users and
676         // all profiles. Only Telephony and SIP accounts should have this capability.
677         if (account.hasCapabilities(PhoneAccount.CAPABILITY_MULTI_USER)) {
678             return true;
679         }
680 
681         UserHandle phoneAccountUserHandle = account.getAccountHandle().getUserHandle();
682         if (phoneAccountUserHandle == null) {
683             return false;
684         }
685 
686         if (mCurrentUserHandle == null) {
687             // In case we need to have emergency phone calls from the lock screen.
688             Log.d(this, "Current user is null; assuming true");
689             return true;
690         }
691 
692         if (acrossProfiles) {
693             return UserManager.get(mContext).isSameProfileGroup(userHandle.getIdentifier(),
694                     phoneAccountUserHandle.getIdentifier());
695         } else {
696             return phoneAccountUserHandle.equals(userHandle);
697         }
698     }
699 
resolveComponent(PhoneAccountHandle phoneAccountHandle)700     private List<ResolveInfo> resolveComponent(PhoneAccountHandle phoneAccountHandle) {
701         return resolveComponent(phoneAccountHandle.getComponentName(),
702                 phoneAccountHandle.getUserHandle());
703     }
704 
resolveComponent(ComponentName componentName, UserHandle userHandle)705     private List<ResolveInfo> resolveComponent(ComponentName componentName,
706             UserHandle userHandle) {
707         PackageManager pm = mContext.getPackageManager();
708         Intent intent = new Intent(ConnectionService.SERVICE_INTERFACE);
709         intent.setComponent(componentName);
710         try {
711             if (userHandle != null) {
712                 return pm.queryIntentServicesAsUser(intent, 0, userHandle.getIdentifier());
713             } else {
714                 return pm.queryIntentServices(intent, 0);
715             }
716         } catch (SecurityException e) {
717             Log.e(this, e, "%s is not visible for the calling user", componentName);
718             return Collections.EMPTY_LIST;
719         }
720     }
721 
722     /**
723      * Retrieves a list of all {@link PhoneAccountHandle}s registered.
724      * Only returns accounts which are enabled.
725      *
726      * @return The list of {@link PhoneAccountHandle}s.
727      */
getAllPhoneAccountHandles(UserHandle userHandle)728     public List<PhoneAccountHandle> getAllPhoneAccountHandles(UserHandle userHandle) {
729         return getPhoneAccountHandles(0, null, null, false, userHandle);
730     }
731 
getAllPhoneAccounts(UserHandle userHandle)732     public List<PhoneAccount> getAllPhoneAccounts(UserHandle userHandle) {
733         return getPhoneAccounts(0, null, null, false, userHandle);
734     }
735 
getAllPhoneAccountsOfCurrentUser()736     public List<PhoneAccount> getAllPhoneAccountsOfCurrentUser() {
737         return getAllPhoneAccounts(mCurrentUserHandle);
738     }
739 
740     /**
741      * Retrieves a list of all phone account call provider phone accounts supporting the
742      * specified URI scheme.
743      *
744      * @param uriScheme The URI scheme.
745      * @param includeDisabledAccounts {@code} if disabled {@link PhoneAccount}s should be included
746      *      in the results.
747      * @param userHandle The {@link UserHandle} to retrieve the {@link PhoneAccount}s for.
748      * @return The phone account handles.
749      */
getCallCapablePhoneAccounts( String uriScheme, boolean includeDisabledAccounts, UserHandle userHandle)750     public List<PhoneAccountHandle> getCallCapablePhoneAccounts(
751             String uriScheme, boolean includeDisabledAccounts, UserHandle userHandle) {
752         return getCallCapablePhoneAccounts(uriScheme, includeDisabledAccounts, userHandle,
753                 0 /* capabilities */, PhoneAccount.CAPABILITY_EMERGENCY_CALLS_ONLY);
754     }
755 
756     /**
757      * Retrieves a list of all phone account call provider phone accounts supporting the
758      * specified URI scheme.
759      *
760      * @param uriScheme The URI scheme.
761      * @param includeDisabledAccounts {@code} if disabled {@link PhoneAccount}s should be included
762      *      in the results.
763      * @param userHandle The {@link UserHandle} to retrieve the {@link PhoneAccount}s for.
764      * @param capabilities Extra {@link PhoneAccount} capabilities which matching
765      *      {@link PhoneAccount}s must have.
766      * @return The phone account handles.
767      */
getCallCapablePhoneAccounts( String uriScheme, boolean includeDisabledAccounts, UserHandle userHandle, int capabilities, int excludedCapabilities)768     public List<PhoneAccountHandle> getCallCapablePhoneAccounts(
769             String uriScheme, boolean includeDisabledAccounts, UserHandle userHandle,
770             int capabilities, int excludedCapabilities) {
771         return getPhoneAccountHandles(
772                 PhoneAccount.CAPABILITY_CALL_PROVIDER | capabilities,
773                 excludedCapabilities /*excludedCapabilities*/,
774                 uriScheme, null, includeDisabledAccounts, userHandle);
775     }
776 
777     /**
778      * Retrieves a list of all phone accounts which have
779      * {@link PhoneAccount#CAPABILITY_SELF_MANAGED}.
780      * <p>
781      * Returns only the {@link PhoneAccount}s which are enabled as self-managed accounts are
782      * automatically enabled by default (see {@link #registerPhoneAccount(PhoneAccount)}).
783      *
784      * @param userHandle User handle of phone account owner.
785      * @return The phone account handles.
786      */
getSelfManagedPhoneAccounts(UserHandle userHandle)787     public List<PhoneAccountHandle> getSelfManagedPhoneAccounts(UserHandle userHandle) {
788         return getPhoneAccountHandles(
789                 PhoneAccount.CAPABILITY_SELF_MANAGED,
790                 PhoneAccount.CAPABILITY_EMERGENCY_CALLS_ONLY /* excludedCapabilities */,
791                 null /* uriScheme */, null /* packageName */, false /* includeDisabledAccounts */,
792                 userHandle);
793     }
794 
getCallCapablePhoneAccountsOfCurrentUser( String uriScheme, boolean includeDisabledAccounts)795     public List<PhoneAccountHandle> getCallCapablePhoneAccountsOfCurrentUser(
796             String uriScheme, boolean includeDisabledAccounts) {
797         return getCallCapablePhoneAccounts(uriScheme, includeDisabledAccounts, mCurrentUserHandle);
798     }
799 
800     /**
801      * Retrieves a list of all the SIM-based phone accounts.
802      */
getSimPhoneAccounts(UserHandle userHandle)803     public List<PhoneAccountHandle> getSimPhoneAccounts(UserHandle userHandle) {
804         return getPhoneAccountHandles(
805                 PhoneAccount.CAPABILITY_CALL_PROVIDER | PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION,
806                 null, null, false, userHandle);
807     }
808 
getSimPhoneAccountsOfCurrentUser()809     public List<PhoneAccountHandle> getSimPhoneAccountsOfCurrentUser() {
810         return getSimPhoneAccounts(mCurrentUserHandle);
811     }
812 
813         /**
814          * Retrieves a list of all phone accounts registered by a specified package.
815          *
816          * @param packageName The name of the package that registered the phone accounts.
817          * @return The phone account handles.
818          */
getPhoneAccountsForPackage(String packageName, UserHandle userHandle)819     public List<PhoneAccountHandle> getPhoneAccountsForPackage(String packageName,
820             UserHandle userHandle) {
821         return getPhoneAccountHandles(0, null, packageName, false, userHandle);
822     }
823 
824     /**
825      * Retrieves a list of all {@link PhoneAccount#CAPABILITY_SELF_MANAGED} phone accounts
826      * registered by a specified package.
827      *
828      * @param packageName The name of the package that registered the phone accounts.
829      * @return The self-managed phone account handles for the given package.
830      */
getSelfManagedPhoneAccountsForPackage(String packageName, UserHandle userHandle)831     public List<PhoneAccountHandle> getSelfManagedPhoneAccountsForPackage(String packageName,
832             UserHandle userHandle) {
833         List<PhoneAccountHandle> phoneAccountsHandles = new ArrayList<>();
834         for (PhoneAccountHandle pah : getPhoneAccountsForPackage(packageName,
835                 userHandle)) {
836             if (isSelfManagedPhoneAccount(pah)) {
837                 phoneAccountsHandles.add(pah);
838             }
839         }
840         return phoneAccountsHandles;
841     }
842 
843     /**
844      * Determines if a {@link PhoneAccountHandle} is for a self-managed {@link ConnectionService}.
845      * @param handle The handle.
846      * @return {@code true} if for a self-managed {@link ConnectionService}, {@code false}
847      * otherwise.
848      */
isSelfManagedPhoneAccount(@onNull PhoneAccountHandle handle)849     public boolean isSelfManagedPhoneAccount(@NonNull PhoneAccountHandle handle) {
850         PhoneAccount account = getPhoneAccountUnchecked(handle);
851         if (account == null) {
852             return false;
853         }
854 
855         return account.isSelfManaged();
856     }
857 
858     /**
859      * Performs checks before calling addOrReplacePhoneAccount(PhoneAccount)
860      *
861      * @param account The {@code PhoneAccount} to add or replace.
862      * @throws SecurityException if package does not have BIND_TELECOM_CONNECTION_SERVICE permission
863      * @throws IllegalArgumentException if MAX_PHONE_ACCOUNT_REGISTRATIONS are reached
864      */
registerPhoneAccount(PhoneAccount account)865     public void registerPhoneAccount(PhoneAccount account) {
866         // Enforce the requirement that a connection service for a phone account has the correct
867         // permission.
868         if (!phoneAccountRequiresBindPermission(account.getAccountHandle())) {
869             Log.w(this,
870                     "Phone account %s does not have BIND_TELECOM_CONNECTION_SERVICE permission.",
871                     account.getAccountHandle());
872             throw new SecurityException("PhoneAccount connection service requires "
873                     + "BIND_TELECOM_CONNECTION_SERVICE permission.");
874         }
875         //Enforce an upper bound on the number of PhoneAccount's a package can register.
876         // Most apps should only require 1-2.
877         if (getPhoneAccountsForPackage(
878                 account.getAccountHandle().getComponentName().getPackageName(),
879                 account.getAccountHandle().getUserHandle()).size()
880                 >= MAX_PHONE_ACCOUNT_REGISTRATIONS) {
881             Log.w(this, "Phone account %s reached max registration limit for package",
882                     account.getAccountHandle());
883             throw new IllegalArgumentException(
884                     "Error, cannot register phone account " + account.getAccountHandle()
885                             + " because the limit, " + MAX_PHONE_ACCOUNT_REGISTRATIONS
886                             + ", has been reached");
887         }
888 
889         addOrReplacePhoneAccount(account);
890     }
891 
892     /**
893      * Adds a {@code PhoneAccount}, replacing an existing one if found.
894      *
895      * @param account The {@code PhoneAccount} to add or replace.
896      */
addOrReplacePhoneAccount(PhoneAccount account)897     private void addOrReplacePhoneAccount(PhoneAccount account) {
898         Log.d(this, "addOrReplacePhoneAccount(%s -> %s)",
899                 account.getAccountHandle(), account);
900 
901         // Start _enabled_ property as false.
902         // !!! IMPORTANT !!! It is important that we do not read the enabled state that the
903         // source app provides or else an third party app could enable itself.
904         boolean isEnabled = false;
905         boolean isNewAccount;
906 
907         PhoneAccount oldAccount = getPhoneAccountUnchecked(account.getAccountHandle());
908         if (oldAccount != null) {
909             enforceSelfManagedAccountUnmodified(account, oldAccount);
910             mState.accounts.remove(oldAccount);
911             isEnabled = oldAccount.isEnabled();
912             Log.i(this, "Modify account: %s", getAccountDiffString(account, oldAccount));
913             isNewAccount = false;
914         } else {
915             Log.i(this, "New phone account registered: " + account);
916             isNewAccount = true;
917         }
918 
919         // When registering a self-managed PhoneAccount we enforce the rule that the label that the
920         // app uses is also its phone account label.  Also ensure it does not attempt to declare
921         // itself as a sim acct, call manager or call provider.
922         if (account.hasCapabilities(PhoneAccount.CAPABILITY_SELF_MANAGED)) {
923             // Turn off bits we don't want to be able to set (TelecomServiceImpl protects against
924             // this but we'll also prevent it from happening here, just to be safe).
925             int newCapabilities = account.getCapabilities() &
926                     ~(PhoneAccount.CAPABILITY_CALL_PROVIDER |
927                         PhoneAccount.CAPABILITY_CONNECTION_MANAGER |
928                         PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION);
929 
930             // Ensure name is correct.
931             CharSequence newLabel = mAppLabelProxy.getAppLabel(
932                     account.getAccountHandle().getComponentName().getPackageName());
933 
934             account = account.toBuilder()
935                     .setLabel(newLabel)
936                     .setCapabilities(newCapabilities)
937                     .build();
938         }
939 
940         mState.accounts.add(account);
941         // Set defaults and replace based on the group Id.
942         maybeReplaceOldAccount(account);
943         // Reset enabled state to whatever the value was if the account was already registered,
944         // or _true_ if this is a SIM-based account.  All SIM-based accounts are always enabled,
945         // as are all self-managed phone accounts.
946         account.setIsEnabled(
947                 isEnabled || account.hasCapabilities(PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION)
948                 || account.hasCapabilities(PhoneAccount.CAPABILITY_SELF_MANAGED));
949 
950         write();
951         fireAccountsChanged();
952         if (isNewAccount) {
953             fireAccountRegistered(account.getAccountHandle());
954         } else {
955             fireAccountChanged(account);
956         }
957         // If this is the SIM call manager, tell telephony when the voice ServiceState override
958         // needs to be updated.
959         maybeNotifyTelephonyForVoiceServiceState(account, /* registered= */ true);
960     }
961 
unregisterPhoneAccount(PhoneAccountHandle accountHandle)962     public void unregisterPhoneAccount(PhoneAccountHandle accountHandle) {
963         PhoneAccount account = getPhoneAccountUnchecked(accountHandle);
964         if (account != null) {
965             if (mState.accounts.remove(account)) {
966                 write();
967                 fireAccountsChanged();
968                 fireAccountUnRegistered(accountHandle);
969                 // If this is the SIM call manager, tell telephony when the voice ServiceState
970                 // override needs to be updated.
971                 maybeNotifyTelephonyForVoiceServiceState(account, /* registered= */ false);
972             }
973         }
974     }
975 
enforceSelfManagedAccountUnmodified(PhoneAccount newAccount, PhoneAccount oldAccount)976     private void enforceSelfManagedAccountUnmodified(PhoneAccount newAccount,
977             PhoneAccount oldAccount) {
978         if (oldAccount.hasCapabilities(PhoneAccount.CAPABILITY_SELF_MANAGED) &&
979                 (!newAccount.hasCapabilities(PhoneAccount.CAPABILITY_SELF_MANAGED))) {
980             EventLog.writeEvent(0x534e4554, "246930197");
981             Log.w(this, "Self-managed phone account %s replaced by a non self-managed one",
982                     newAccount.getAccountHandle());
983             throw new IllegalArgumentException("Error, cannot change a self-managed "
984                     + "phone account " + newAccount.getAccountHandle()
985                     + " to other kinds of phone account");
986         }
987     }
988 
989     /**
990      * Un-registers all phone accounts associated with a specified package.
991      *
992      * @param packageName The package for which phone accounts will be removed.
993      * @param userHandle The {@link UserHandle} the package is running under.
994      */
clearAccounts(String packageName, UserHandle userHandle)995     public void clearAccounts(String packageName, UserHandle userHandle) {
996         boolean accountsRemoved = false;
997         Iterator<PhoneAccount> it = mState.accounts.iterator();
998         while (it.hasNext()) {
999             PhoneAccount phoneAccount = it.next();
1000             PhoneAccountHandle handle = phoneAccount.getAccountHandle();
1001             if (Objects.equals(packageName, handle.getComponentName().getPackageName())
1002                     && Objects.equals(userHandle, handle.getUserHandle())) {
1003                 Log.i(this, "Removing phone account " + phoneAccount.getLabel());
1004                 mState.accounts.remove(phoneAccount);
1005                 accountsRemoved = true;
1006             }
1007         }
1008 
1009         if (accountsRemoved) {
1010             write();
1011             fireAccountsChanged();
1012         }
1013     }
1014 
isVoiceMailNumber(PhoneAccountHandle accountHandle, String number)1015     public boolean isVoiceMailNumber(PhoneAccountHandle accountHandle, String number) {
1016         int subId = getSubscriptionIdForPhoneAccount(accountHandle);
1017         return PhoneNumberUtils.isVoiceMailNumber(mContext, subId, number);
1018     }
1019 
addListener(Listener l)1020     public void addListener(Listener l) {
1021         mListeners.add(l);
1022     }
1023 
removeListener(Listener l)1024     public void removeListener(Listener l) {
1025         if (l != null) {
1026             mListeners.remove(l);
1027         }
1028     }
1029 
fireAccountRegistered(PhoneAccountHandle handle)1030     private void fireAccountRegistered(PhoneAccountHandle handle) {
1031         for (Listener l : mListeners) {
1032             l.onPhoneAccountRegistered(this, handle);
1033         }
1034     }
1035 
fireAccountChanged(PhoneAccount account)1036     private void fireAccountChanged(PhoneAccount account) {
1037         for (Listener l : mListeners) {
1038             l.onPhoneAccountChanged(this, account);
1039         }
1040     }
1041 
fireAccountUnRegistered(PhoneAccountHandle handle)1042     private void fireAccountUnRegistered(PhoneAccountHandle handle) {
1043         for (Listener l : mListeners) {
1044             l.onPhoneAccountUnRegistered(this, handle);
1045         }
1046     }
1047 
fireAccountsChanged()1048     private void fireAccountsChanged() {
1049         for (Listener l : mListeners) {
1050             l.onAccountsChanged(this);
1051         }
1052     }
1053 
fireDefaultOutgoingChanged()1054     private void fireDefaultOutgoingChanged() {
1055         for (Listener l : mListeners) {
1056             l.onDefaultOutgoingChanged(this);
1057         }
1058     }
1059 
getAccountDiffString(PhoneAccount account1, PhoneAccount account2)1060     private String getAccountDiffString(PhoneAccount account1, PhoneAccount account2) {
1061         if (account1 == null || account2 == null) {
1062             return "Diff: " + account1 + ", " + account2;
1063         }
1064 
1065         StringBuffer sb = new StringBuffer();
1066         sb.append("[").append(account1.getAccountHandle());
1067         appendDiff(sb, "addr", Log.piiHandle(account1.getAddress()),
1068                 Log.piiHandle(account2.getAddress()));
1069         appendDiff(sb, "cap", account1.capabilitiesToString(), account2.capabilitiesToString());
1070         appendDiff(sb, "hl", account1.getHighlightColor(), account2.getHighlightColor());
1071         appendDiff(sb, "lbl", account1.getLabel(), account2.getLabel());
1072         appendDiff(sb, "desc", account1.getShortDescription(), account2.getShortDescription());
1073         appendDiff(sb, "subAddr", Log.piiHandle(account1.getSubscriptionAddress()),
1074                 Log.piiHandle(account2.getSubscriptionAddress()));
1075         appendDiff(sb, "uris", account1.getSupportedUriSchemes(),
1076                 account2.getSupportedUriSchemes());
1077         sb.append("]");
1078         return sb.toString();
1079     }
1080 
appendDiff(StringBuffer sb, String attrName, Object obj1, Object obj2)1081     private void appendDiff(StringBuffer sb, String attrName, Object obj1, Object obj2) {
1082         if (!Objects.equals(obj1, obj2)) {
1083             sb.append("(")
1084                 .append(attrName)
1085                 .append(": ")
1086                 .append(obj1)
1087                 .append(" -> ")
1088                 .append(obj2)
1089                 .append(")");
1090         }
1091     }
1092 
maybeReplaceOldAccount(PhoneAccount newAccount)1093     private void maybeReplaceOldAccount(PhoneAccount newAccount) {
1094         UserHandle newAccountUserHandle = newAccount.getAccountHandle().getUserHandle();
1095         DefaultPhoneAccountHandle defaultHandle =
1096                 getUserSelectedDefaultPhoneAccount(newAccountUserHandle);
1097         if (defaultHandle == null || defaultHandle.groupId.isEmpty()) {
1098             Log.v(this, "maybeReplaceOldAccount: Not replacing PhoneAccount, no group Id or " +
1099                     "default.");
1100             return;
1101         }
1102         if (!defaultHandle.groupId.equals(newAccount.getGroupId())) {
1103             Log.v(this, "maybeReplaceOldAccount: group Ids are not equal.");
1104             return;
1105         }
1106         if (Objects.equals(newAccount.getAccountHandle().getComponentName(),
1107                 defaultHandle.phoneAccountHandle.getComponentName())) {
1108             // Move default calling account over to new user, since the ComponentNames and Group Ids
1109             // are the same.
1110             setUserSelectedOutgoingPhoneAccount(newAccount.getAccountHandle(),
1111                     newAccountUserHandle);
1112         } else {
1113             Log.v(this, "maybeReplaceOldAccount: group Ids are equal, but ComponentName is not" +
1114                     " the same as the default. Not replacing default PhoneAccount.");
1115         }
1116         PhoneAccount replacementAccount = getPhoneAccountByGroupId(newAccount.getGroupId(),
1117                 newAccount.getAccountHandle().getComponentName(), newAccountUserHandle,
1118                 newAccount.getAccountHandle());
1119         if (replacementAccount != null) {
1120             // Unregister the old PhoneAccount.
1121             Log.v(this, "maybeReplaceOldAccount: Unregistering old PhoneAccount: " +
1122                     replacementAccount.getAccountHandle());
1123             unregisterPhoneAccount(replacementAccount.getAccountHandle());
1124         }
1125     }
1126 
maybeNotifyTelephonyForVoiceServiceState( @onNull PhoneAccount account, boolean registered)1127     private void maybeNotifyTelephonyForVoiceServiceState(
1128             @NonNull PhoneAccount account, boolean registered) {
1129         // TODO(b/215419665) what about SIM_SUBSCRIPTION accounts? They could theoretically also use
1130         // these capabilities, but don't today. If they do start using them, then there will need to
1131         // be a kind of "or" logic between SIM_SUBSCRIPTION and CONNECTION_MANAGER accounts to get
1132         // the correct value of hasService for a given SIM.
1133         boolean hasService = false;
1134         List<PhoneAccountHandle> simHandlesToNotify;
1135         if (account.hasCapabilities(PhoneAccount.CAPABILITY_CONNECTION_MANAGER)) {
1136             // When we unregister the SIM call manager account, we always set hasService back to
1137             // false since it is no longer providing OTT calling capability once unregistered.
1138             if (registered) {
1139                 // Note: we do *not* early return when the SUPPORTS capability is not present
1140                 // because it's possible the SIM call manager could remove either capability at
1141                 // runtime and re-register. However, it is an error to use the AVAILABLE capability
1142                 // without also setting SUPPORTS.
1143                 hasService =
1144                         account.hasCapabilities(
1145                                 PhoneAccount.CAPABILITY_SUPPORTS_VOICE_CALLING_INDICATIONS
1146                                         | PhoneAccount.CAPABILITY_VOICE_CALLING_AVAILABLE);
1147             }
1148             // Notify for all SIMs that named this component as their SIM call manager in carrier
1149             // config, since there may be more than one impacted SIM here.
1150             simHandlesToNotify = getSimPhoneAccountsFromSimCallManager(account.getAccountHandle());
1151         } else if (account.hasCapabilities(PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION)) {
1152             // When new SIMs get registered, we notify them of their current voice status override.
1153             // If there is no SIM call manager for this SIM, we treat that as hasService = false and
1154             // still notify to ensure consistency.
1155             if (!registered) {
1156                 // We don't do anything when SIMs are unregistered because we won't have an active
1157                 // subId to map back to phoneId and tell telephony about; that case is handled by
1158                 // telephony internally.
1159                 return;
1160             }
1161             PhoneAccountHandle simCallManagerHandle =
1162                     getSimCallManagerFromHandle(
1163                             account.getAccountHandle(), account.getAccountHandle().getUserHandle());
1164             if (simCallManagerHandle != null) {
1165                 PhoneAccount simCallManager = getPhoneAccountUnchecked(simCallManagerHandle);
1166                 hasService =
1167                         simCallManager != null
1168                                 && simCallManager.hasCapabilities(
1169                                         PhoneAccount.CAPABILITY_SUPPORTS_VOICE_CALLING_INDICATIONS
1170                                                 | PhoneAccount.CAPABILITY_VOICE_CALLING_AVAILABLE);
1171             }
1172             simHandlesToNotify = Collections.singletonList(account.getAccountHandle());
1173         } else {
1174             // Not a relevant account - we only care about CONNECTION_MANAGER and SIM_SUBSCRIPTION.
1175             return;
1176         }
1177         if (simHandlesToNotify.isEmpty()) return;
1178         Log.i(
1179                 this,
1180                 "Notifying telephony of voice service override change for %d SIMs, hasService = %b",
1181                 simHandlesToNotify.size(),
1182                 hasService);
1183         for (PhoneAccountHandle simHandle : simHandlesToNotify) {
1184             // This may be null if there are no active SIMs but the device is still camped for
1185             // emergency calls and registered a SIM_SUBSCRIPTION for that purpose.
1186             TelephonyManager simTm = mTelephonyManager.createForPhoneAccountHandle(simHandle);
1187             if (simTm == null) continue;
1188             simTm.setVoiceServiceStateOverride(hasService);
1189         }
1190     }
1191 
1192     /**
1193      * Determines if the connection service specified by a {@link PhoneAccountHandle} requires the
1194      * {@link Manifest.permission#BIND_TELECOM_CONNECTION_SERVICE} permission.
1195      *
1196      * @param phoneAccountHandle The phone account to check.
1197      * @return {@code True} if the phone account has permission.
1198      */
phoneAccountRequiresBindPermission(PhoneAccountHandle phoneAccountHandle)1199     public boolean phoneAccountRequiresBindPermission(PhoneAccountHandle phoneAccountHandle) {
1200         List<ResolveInfo> resolveInfos = resolveComponent(phoneAccountHandle);
1201         if (resolveInfos.isEmpty()) {
1202             Log.w(this, "phoneAccount %s not found", phoneAccountHandle.getComponentName());
1203             return false;
1204         }
1205         for (ResolveInfo resolveInfo : resolveInfos) {
1206             ServiceInfo serviceInfo = resolveInfo.serviceInfo;
1207             if (serviceInfo == null) {
1208                 return false;
1209             }
1210 
1211             if (!Manifest.permission.BIND_CONNECTION_SERVICE.equals(serviceInfo.permission) &&
1212                     !Manifest.permission.BIND_TELECOM_CONNECTION_SERVICE.equals(
1213                             serviceInfo.permission)) {
1214                 // The ConnectionService must require either the deprecated BIND_CONNECTION_SERVICE,
1215                 // or the public BIND_TELECOM_CONNECTION_SERVICE permissions, both of which are
1216                 // system/signature only.
1217                 return false;
1218             }
1219         }
1220         return true;
1221     }
1222 
1223     //
1224     // Methods for retrieving PhoneAccounts and PhoneAccountHandles
1225     //
1226 
1227     /**
1228      * Returns the PhoneAccount for the specified handle.  Does no user checking.
1229      *
1230      * @param handle
1231      * @return The corresponding phone account if one exists.
1232      */
getPhoneAccountUnchecked(PhoneAccountHandle handle)1233     public PhoneAccount getPhoneAccountUnchecked(PhoneAccountHandle handle) {
1234         for (PhoneAccount m : mState.accounts) {
1235             if (Objects.equals(handle, m.getAccountHandle())) {
1236                 return m;
1237             }
1238         }
1239         return null;
1240     }
1241 
1242     /**
1243      * Like getPhoneAccount, but checks to see if the current user is allowed to see the phone
1244      * account before returning it. The current user is the active user on the actual android
1245      * device.
1246      */
getPhoneAccount(PhoneAccountHandle handle, UserHandle userHandle)1247     public PhoneAccount getPhoneAccount(PhoneAccountHandle handle, UserHandle userHandle) {
1248         return getPhoneAccount(handle, userHandle, /* acrossProfiles */ false);
1249     }
1250 
getPhoneAccount(PhoneAccountHandle handle, UserHandle userHandle, boolean acrossProfiles)1251     public PhoneAccount getPhoneAccount(PhoneAccountHandle handle,
1252             UserHandle userHandle, boolean acrossProfiles) {
1253         PhoneAccount account = getPhoneAccountUnchecked(handle);
1254         if (account != null && (isVisibleForUser(account, userHandle, acrossProfiles))) {
1255             return account;
1256         }
1257         return null;
1258     }
1259 
getPhoneAccountOfCurrentUser(PhoneAccountHandle handle)1260     public PhoneAccount getPhoneAccountOfCurrentUser(PhoneAccountHandle handle) {
1261         return getPhoneAccount(handle, mCurrentUserHandle);
1262     }
1263 
getPhoneAccountHandles( int capabilities, String uriScheme, String packageName, boolean includeDisabledAccounts, UserHandle userHandle)1264     private List<PhoneAccountHandle> getPhoneAccountHandles(
1265             int capabilities,
1266             String uriScheme,
1267             String packageName,
1268             boolean includeDisabledAccounts,
1269             UserHandle userHandle) {
1270         return getPhoneAccountHandles(capabilities, 0 /*excludedCapabilities*/, uriScheme,
1271                 packageName, includeDisabledAccounts, userHandle);
1272     }
1273 
1274     /**
1275      * Returns a list of phone account handles with the specified capabilities, uri scheme,
1276      * and package name.
1277      */
getPhoneAccountHandles( int capabilities, int excludedCapabilities, String uriScheme, String packageName, boolean includeDisabledAccounts, UserHandle userHandle)1278     private List<PhoneAccountHandle> getPhoneAccountHandles(
1279             int capabilities,
1280             int excludedCapabilities,
1281             String uriScheme,
1282             String packageName,
1283             boolean includeDisabledAccounts,
1284             UserHandle userHandle) {
1285         List<PhoneAccountHandle> handles = new ArrayList<>();
1286 
1287         for (PhoneAccount account : getPhoneAccounts(
1288                 capabilities, excludedCapabilities, uriScheme, packageName,
1289                 includeDisabledAccounts, userHandle)) {
1290             handles.add(account.getAccountHandle());
1291         }
1292         return handles;
1293     }
1294 
getPhoneAccounts( int capabilities, String uriScheme, String packageName, boolean includeDisabledAccounts, UserHandle userHandle)1295     private List<PhoneAccount> getPhoneAccounts(
1296             int capabilities,
1297             String uriScheme,
1298             String packageName,
1299             boolean includeDisabledAccounts,
1300             UserHandle userHandle) {
1301         return getPhoneAccounts(capabilities, 0 /*excludedCapabilities*/, uriScheme, packageName,
1302                 includeDisabledAccounts, userHandle);
1303     }
1304 
1305     /**
1306      * Returns a list of phone account handles with the specified flag, supporting the specified
1307      * URI scheme, within the specified package name.
1308      *
1309      * @param capabilities Capabilities which the {@code PhoneAccount} must have. Ignored if 0.
1310      * @param excludedCapabilities Capabilities which the {@code PhoneAccount} must not have.
1311      *                             Ignored if 0.
1312      * @param uriScheme URI schemes the PhoneAccount must handle.  {@code null} bypasses the
1313      *                  URI scheme check.
1314      * @param packageName Package name of the PhoneAccount. {@code null} bypasses packageName check.
1315      */
getPhoneAccounts( int capabilities, int excludedCapabilities, String uriScheme, String packageName, boolean includeDisabledAccounts, UserHandle userHandle)1316     private List<PhoneAccount> getPhoneAccounts(
1317             int capabilities,
1318             int excludedCapabilities,
1319             String uriScheme,
1320             String packageName,
1321             boolean includeDisabledAccounts,
1322             UserHandle userHandle) {
1323         List<PhoneAccount> accounts = new ArrayList<>(mState.accounts.size());
1324         for (PhoneAccount m : mState.accounts) {
1325             if (!(m.isEnabled() || includeDisabledAccounts)) {
1326                 // Do not include disabled accounts.
1327                 continue;
1328             }
1329 
1330             if ((m.getCapabilities() & excludedCapabilities) != 0) {
1331                 // If an excluded capability is present, skip.
1332                 continue;
1333             }
1334 
1335             if (capabilities != 0 && !m.hasCapabilities(capabilities)) {
1336                 // Account doesn't have the right capabilities; skip this one.
1337                 continue;
1338             }
1339             if (uriScheme != null && !m.supportsUriScheme(uriScheme)) {
1340                 // Account doesn't support this URI scheme; skip this one.
1341                 continue;
1342             }
1343             PhoneAccountHandle handle = m.getAccountHandle();
1344 
1345             if (resolveComponent(handle).isEmpty()) {
1346                 // This component cannot be resolved anymore; skip this one.
1347                 continue;
1348             }
1349             if (packageName != null &&
1350                     !packageName.equals(handle.getComponentName().getPackageName())) {
1351                 // Not the right package name; skip this one.
1352                 continue;
1353             }
1354             if (!isVisibleForUser(m, userHandle, false)) {
1355                 // Account is not visible for the current user; skip this one.
1356                 continue;
1357             }
1358             accounts.add(m);
1359         }
1360         return accounts;
1361     }
1362 
1363     /**
1364      * Clean up the orphan {@code PhoneAccount}. An orphan {@code PhoneAccount} is a phone
1365      * account that does not have a {@code UserHandle} or belongs to a deleted package.
1366      *
1367      * @return the number of orphan {@code PhoneAccount} deleted.
1368      */
cleanupOrphanedPhoneAccounts()1369     public int cleanupOrphanedPhoneAccounts() {
1370         ArrayList<PhoneAccount> badAccountsList = new ArrayList<>();
1371         HashMap<String, Boolean> packageLookup = new HashMap<>();
1372         HashMap<PhoneAccount, Boolean> userHandleLookup = new HashMap<>();
1373 
1374         // iterate over all accounts in registrar
1375         for (PhoneAccount pa : mState.accounts) {
1376             String packageName = pa.getAccountHandle().getComponentName().getPackageName();
1377 
1378             // check if the package for the PhoneAccount is uninstalled
1379             if (packageLookup.computeIfAbsent(packageName,
1380                     pn -> isPackageUninstalled(pn))) {
1381                 badAccountsList.add(pa);
1382             }
1383             // check if PhoneAccount does not have a valid UserHandle (user was deleted)
1384             else if (userHandleLookup.computeIfAbsent(pa,
1385                     a -> isUserHandleDeletedForPhoneAccount(a))) {
1386                 badAccountsList.add(pa);
1387             }
1388         }
1389 
1390         mState.accounts.removeAll(badAccountsList);
1391 
1392         return badAccountsList.size();
1393     }
1394 
isPackageUninstalled(String packageName)1395     public Boolean isPackageUninstalled(String packageName) {
1396         try {
1397             mContext.getPackageManager().getPackageInfo(packageName, 0);
1398             return false;
1399         } catch (PackageManager.NameNotFoundException e) {
1400             return true;
1401         }
1402     }
1403 
isUserHandleDeletedForPhoneAccount(PhoneAccount phoneAccount)1404     private Boolean isUserHandleDeletedForPhoneAccount(PhoneAccount phoneAccount) {
1405         UserHandle userHandle = phoneAccount.getAccountHandle().getUserHandle();
1406         return (userHandle == null) ||
1407                 (mUserManager.getSerialNumberForUser(userHandle) == -1L);
1408     }
1409 
1410     //
1411     // State Implementation for PhoneAccountRegistrar
1412     //
1413 
1414     /**
1415      * The state of this {@code PhoneAccountRegistrar}.
1416      */
1417     @VisibleForTesting
1418     public static class State {
1419         /**
1420          * Store the default phone account handle of users. If no record of a user can be found in
1421          * the map, it means that no default phone account handle is set in that user.
1422          */
1423         public final Map<UserHandle, DefaultPhoneAccountHandle> defaultOutgoingAccountHandles
1424                 = new ConcurrentHashMap<>();
1425 
1426         /**
1427          * The complete list of {@code PhoneAccount}s known to the Telecom subsystem.
1428          */
1429         public final List<PhoneAccount> accounts = new CopyOnWriteArrayList<>();
1430 
1431         /**
1432          * The version number of the State data.
1433          */
1434         public int versionNumber;
1435     }
1436 
1437     /**
1438      * The default {@link PhoneAccountHandle} of a user.
1439      */
1440     public static class DefaultPhoneAccountHandle {
1441 
1442         public final UserHandle userHandle;
1443 
1444         public PhoneAccountHandle phoneAccountHandle;
1445 
1446         public final String groupId;
1447 
DefaultPhoneAccountHandle(UserHandle userHandle, PhoneAccountHandle phoneAccountHandle, String groupId)1448         public DefaultPhoneAccountHandle(UserHandle userHandle,
1449                 PhoneAccountHandle phoneAccountHandle, String groupId) {
1450             this.userHandle = userHandle;
1451             this.phoneAccountHandle = phoneAccountHandle;
1452             this.groupId = groupId;
1453         }
1454     }
1455 
1456     /**
1457      * Dumps the state of the {@link CallsManager}.
1458      *
1459      * @param pw The {@code IndentingPrintWriter} to write the state to.
1460      */
dump(IndentingPrintWriter pw)1461     public void dump(IndentingPrintWriter pw) {
1462         if (mState != null) {
1463             pw.println("xmlVersion: " + mState.versionNumber);
1464             DefaultPhoneAccountHandle defaultPhoneAccountHandle
1465                     = mState.defaultOutgoingAccountHandles.get(Process.myUserHandle());
1466             pw.println("defaultOutgoing: " + (defaultPhoneAccountHandle == null ? "none" :
1467                     defaultPhoneAccountHandle.phoneAccountHandle));
1468             PhoneAccountHandle defaultOutgoing =
1469                     getOutgoingPhoneAccountForScheme(PhoneAccount.SCHEME_TEL, mCurrentUserHandle);
1470             pw.print("outgoingPhoneAccountForTelScheme: ");
1471             if (defaultOutgoing == null) {
1472                 pw.println("none");
1473             } else {
1474                 pw.println(defaultOutgoing);
1475             }
1476             pw.println("simCallManager: " + getSimCallManager(mCurrentUserHandle));
1477             pw.println("phoneAccounts:");
1478             pw.increaseIndent();
1479             for (PhoneAccount phoneAccount : mState.accounts) {
1480                 pw.println(phoneAccount);
1481             }
1482             pw.decreaseIndent();
1483             pw.increaseIndent();
1484             pw.println("test emergency PhoneAccount filter: " + mTestPhoneAccountPackageNameFilter);
1485             pw.decreaseIndent();
1486         }
1487     }
1488 
sortPhoneAccounts()1489     private void sortPhoneAccounts() {
1490         if (mState.accounts.size() > 1) {
1491             // Sort the phone accounts using sort order:
1492             // 1) SIM accounts first, followed by non-sim accounts
1493             // 2) Sort order, with those specifying no sort order last.
1494             // 3) Label
1495 
1496             // Comparator to sort SIM subscriptions before non-sim subscriptions.
1497             Comparator<PhoneAccount> bySimCapability = (p1, p2) -> {
1498                 if (p1.hasCapabilities(PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION)
1499                         && !p2.hasCapabilities(PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION)) {
1500                     return -1;
1501                 } else if (!p1.hasCapabilities(PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION)
1502                         && p2.hasCapabilities(PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION)) {
1503                     return 1;
1504                 } else {
1505                     return 0;
1506                 }
1507             };
1508 
1509             // Create a string comparator which will sort strings, placing nulls last.
1510             Comparator<String> nullSafeStringComparator = Comparator.nullsLast(
1511                     String::compareTo);
1512 
1513             // Comparator which places PhoneAccounts with a specified sort order first, followed by
1514             // those with no sort order.
1515             Comparator<PhoneAccount> bySortOrder = (p1, p2) -> {
1516                 int sort1 = p1.getExtras() == null ? Integer.MAX_VALUE:
1517                         p1.getExtras().getInt(PhoneAccount.EXTRA_SORT_ORDER, Integer.MAX_VALUE);
1518                 int sort2 = p2.getExtras() == null ? Integer.MAX_VALUE:
1519                         p2.getExtras().getInt(PhoneAccount.EXTRA_SORT_ORDER, Integer.MAX_VALUE);
1520                 return Integer.compare(sort1, sort2);
1521             };
1522 
1523             // Comparator which sorts PhoneAccounts by label.
1524             Comparator<PhoneAccount> byLabel = (p1, p2) -> {
1525                 String s1 = p1.getLabel() == null ? null : p1.getLabel().toString();
1526                 String s2 = p2.getLabel() == null ? null : p2.getLabel().toString();
1527                 return nullSafeStringComparator.compare(s1, s2);
1528             };
1529 
1530             // Sort the phone accounts.
1531             mState.accounts.sort(bySimCapability.thenComparing(bySortOrder.thenComparing(byLabel)));
1532         }
1533     }
1534 
1535     ////////////////////////////////////////////////////////////////////////////////////////////////
1536     //
1537     // State management
1538     //
1539 
1540     private class AsyncXmlWriter extends AsyncTask<ByteArrayOutputStream, Void, Void> {
1541         @Override
doInBackground(ByteArrayOutputStream... args)1542         public Void doInBackground(ByteArrayOutputStream... args) {
1543             final ByteArrayOutputStream buffer = args[0];
1544             FileOutputStream fileOutput = null;
1545             try {
1546                 synchronized (mWriteLock) {
1547                     fileOutput = mAtomicFile.startWrite();
1548                     buffer.writeTo(fileOutput);
1549                     mAtomicFile.finishWrite(fileOutput);
1550                 }
1551             } catch (IOException e) {
1552                 Log.e(this, e, "Writing state to XML file");
1553                 mAtomicFile.failWrite(fileOutput);
1554             }
1555             return null;
1556         }
1557     }
1558 
write()1559     private void write() {
1560         try {
1561             sortPhoneAccounts();
1562             ByteArrayOutputStream os = new ByteArrayOutputStream();
1563             XmlSerializer serializer = Xml.resolveSerializer(os);
1564             writeToXml(mState, serializer, mContext);
1565             serializer.flush();
1566             new AsyncXmlWriter().execute(os);
1567         } catch (IOException e) {
1568             Log.e(this, e, "Writing state to XML buffer");
1569         }
1570     }
1571 
read()1572     private void read() {
1573         final InputStream is;
1574         try {
1575             is = mAtomicFile.openRead();
1576         } catch (FileNotFoundException ex) {
1577             return;
1578         }
1579 
1580         boolean versionChanged = false;
1581 
1582         try {
1583             XmlPullParser parser = Xml.resolvePullParser(is);
1584             parser.nextTag();
1585             mState = readFromXml(parser, mContext);
1586             migratePhoneAccountHandle(mState);
1587             versionChanged = mState.versionNumber < EXPECTED_STATE_VERSION;
1588 
1589         } catch (IOException | XmlPullParserException e) {
1590             Log.e(this, e, "Reading state from XML file");
1591             mState = new State();
1592         } finally {
1593             try {
1594                 is.close();
1595             } catch (IOException e) {
1596                 Log.e(this, e, "Closing InputStream");
1597             }
1598         }
1599 
1600         // Verify all of the UserHandles.
1601         List<PhoneAccount> badAccounts = new ArrayList<>();
1602         for (PhoneAccount phoneAccount : mState.accounts) {
1603             UserHandle userHandle = phoneAccount.getAccountHandle().getUserHandle();
1604             if (userHandle == null) {
1605                 Log.w(this, "Missing UserHandle for %s", phoneAccount);
1606                 badAccounts.add(phoneAccount);
1607             } else if (mUserManager.getSerialNumberForUser(userHandle) == -1) {
1608                 Log.w(this, "User does not exist for %s", phoneAccount);
1609                 badAccounts.add(phoneAccount);
1610             }
1611         }
1612         mState.accounts.removeAll(badAccounts);
1613 
1614         // If an upgrade occurred, write out the changed data.
1615         if (versionChanged || !badAccounts.isEmpty()) {
1616             write();
1617         }
1618     }
1619 
1620     private static void writeToXml(State state, XmlSerializer serializer, Context context)
1621             throws IOException {
1622         sStateXml.writeToXml(state, serializer, context);
1623     }
1624 
1625     private static State readFromXml(XmlPullParser parser, Context context)
1626             throws IOException, XmlPullParserException {
1627         State s = sStateXml.readFromXml(parser, 0, context);
1628         return s != null ? s : new State();
1629     }
1630 
1631     /**
1632      * Try to migrate the ID of default phone account handle from IccId to SubId.
1633      */
1634     @VisibleForTesting
1635     public void migratePhoneAccountHandle(State state) {
1636         if (mSubscriptionManager == null) {
1637             return;
1638         }
1639         // Use getAllSubscirptionInfoList() to get the mapping between iccId and subId
1640         // from the subscription database
1641         List<SubscriptionInfo> subscriptionInfos = mSubscriptionManager
1642                 .getAllSubscriptionInfoList();
1643         Map<UserHandle, DefaultPhoneAccountHandle> defaultPhoneAccountHandles
1644                 = state.defaultOutgoingAccountHandles;
1645         for (Map.Entry<UserHandle, DefaultPhoneAccountHandle> entry
1646                 : defaultPhoneAccountHandles.entrySet()) {
1647             DefaultPhoneAccountHandle defaultPhoneAccountHandle = entry.getValue();
1648 
1649             // Migrate Telephony PhoneAccountHandle only
1650             String telephonyComponentName =
1651                     "com.android.phone/com.android.services.telephony.TelephonyConnectionService";
1652             if (!defaultPhoneAccountHandle.phoneAccountHandle.getComponentName()
1653                     .flattenToString().equals(telephonyComponentName)) {
1654                 continue;
1655             }
1656             // Migrate from IccId to SubId
1657             for (SubscriptionInfo subscriptionInfo : subscriptionInfos) {
1658                 String phoneAccountHandleId = defaultPhoneAccountHandle.phoneAccountHandle.getId();
1659                 // Some phone account handle would store phone account handle id with the IccId
1660                 // string plus "F", and the getIccId() returns IccId string itself without "F",
1661                 // so here need to use "startsWith" to match.
1662                 if (phoneAccountHandleId != null && phoneAccountHandleId.startsWith(
1663                         subscriptionInfo.getIccId())) {
1664                     Log.i(this, "Found subscription ID to migrate: "
1665                             + subscriptionInfo.getSubscriptionId());
1666                     defaultPhoneAccountHandle.phoneAccountHandle = new PhoneAccountHandle(
1667                             defaultPhoneAccountHandle.phoneAccountHandle.getComponentName(),
1668                                     Integer.toString(subscriptionInfo.getSubscriptionId()));
1669                     break;
1670                 }
1671             }
1672         }
1673     }
1674 
1675     ////////////////////////////////////////////////////////////////////////////////////////////////
1676     //
1677     // XML serialization
1678     //
1679 
1680     @VisibleForTesting
1681     public abstract static class XmlSerialization<T> {
1682         private static final String TAG_VALUE = "value";
1683         private static final String ATTRIBUTE_LENGTH = "length";
1684         private static final String ATTRIBUTE_KEY = "key";
1685         private static final String ATTRIBUTE_VALUE_TYPE = "type";
1686         private static final String VALUE_TYPE_STRING = "string";
1687         private static final String VALUE_TYPE_INTEGER = "integer";
1688         private static final String VALUE_TYPE_BOOLEAN = "boolean";
1689 
1690         /**
1691          * Write the supplied object to XML
1692          */
1693         public abstract void writeToXml(T o, XmlSerializer serializer, Context context)
1694                 throws IOException;
1695 
1696         /**
1697          * Read from the supplied XML into a new object, returning null in case of an
1698          * unrecoverable schema mismatch or other data error. 'parser' must be already
1699          * positioned at the first tag that is expected to have been emitted by this
1700          * object's writeToXml(). This object tries to fail early without modifying
1701          * 'parser' if it does not recognize the data it sees.
1702          */
1703         public abstract T readFromXml(XmlPullParser parser, int version, Context context)
1704                 throws IOException, XmlPullParserException;
1705 
1706         protected void writeTextIfNonNull(String tagName, Object value, XmlSerializer serializer)
1707                 throws IOException {
1708             if (value != null) {
1709                 serializer.startTag(null, tagName);
1710                 serializer.text(Objects.toString(value));
1711                 serializer.endTag(null, tagName);
1712             }
1713         }
1714 
1715         /**
1716          * Serializes a string array.
1717          *
1718          * @param tagName The tag name for the string array.
1719          * @param values The string values to serialize.
1720          * @param serializer The serializer.
1721          * @throws IOException
1722          */
1723         protected void writeStringList(String tagName, List<String> values,
1724                 XmlSerializer serializer)
1725                 throws IOException {
1726 
1727             serializer.startTag(null, tagName);
1728             if (values != null) {
1729                 serializer.attribute(null, ATTRIBUTE_LENGTH, Objects.toString(values.size()));
1730                 for (String toSerialize : values) {
1731                     serializer.startTag(null, TAG_VALUE);
1732                     if (toSerialize != null ){
1733                         serializer.text(toSerialize);
1734                     }
1735                     serializer.endTag(null, TAG_VALUE);
1736                 }
1737             } else {
1738                 serializer.attribute(null, ATTRIBUTE_LENGTH, "0");
1739             }
1740             serializer.endTag(null, tagName);
1741         }
1742 
1743         protected void writeBundle(String tagName, Bundle values, XmlSerializer serializer)
1744             throws IOException {
1745 
1746             serializer.startTag(null, tagName);
1747             if (values != null) {
1748                 for (String key : values.keySet()) {
1749                     Object value = values.get(key);
1750 
1751                     if (value == null) {
1752                         continue;
1753                     }
1754 
1755                     String valueType;
1756                     if (value instanceof String) {
1757                         valueType = VALUE_TYPE_STRING;
1758                     } else if (value instanceof Integer) {
1759                         valueType = VALUE_TYPE_INTEGER;
1760                     } else if (value instanceof Boolean) {
1761                         valueType = VALUE_TYPE_BOOLEAN;
1762                     } else {
1763                         Log.w(this,
1764                                 "PhoneAccounts support only string, integer and boolean extras TY.");
1765                         continue;
1766                     }
1767 
1768                     serializer.startTag(null, TAG_VALUE);
1769                     serializer.attribute(null, ATTRIBUTE_KEY, key);
1770                     serializer.attribute(null, ATTRIBUTE_VALUE_TYPE, valueType);
1771                     serializer.text(Objects.toString(value));
1772                     serializer.endTag(null, TAG_VALUE);
1773                 }
1774             }
1775             serializer.endTag(null, tagName);
1776         }
1777 
1778         protected void writeIconIfNonNull(String tagName, Icon value, XmlSerializer serializer)
1779                 throws IOException {
1780             if (value != null) {
1781                 ByteArrayOutputStream stream = new ByteArrayOutputStream();
1782                 value.writeToStream(stream);
1783                 byte[] iconByteArray = stream.toByteArray();
1784                 String text = Base64.encodeToString(iconByteArray, 0, iconByteArray.length, 0);
1785 
1786                 serializer.startTag(null, tagName);
1787                 serializer.text(text);
1788                 serializer.endTag(null, tagName);
1789             }
1790         }
1791 
1792         protected void writeLong(String tagName, long value, XmlSerializer serializer)
1793                 throws IOException {
1794             serializer.startTag(null, tagName);
1795             serializer.text(Long.valueOf(value).toString());
1796             serializer.endTag(null, tagName);
1797         }
1798 
1799         protected void writeNonNullString(String tagName, String value, XmlSerializer serializer)
1800                 throws IOException {
1801             serializer.startTag(null, tagName);
1802             serializer.text(value != null ? value : "");
1803             serializer.endTag(null, tagName);
1804         }
1805 
1806         /**
1807          * Reads a string array from the XML parser.
1808          *
1809          * @param parser The XML parser.
1810          * @return String array containing the parsed values.
1811          * @throws IOException Exception related to IO.
1812          * @throws XmlPullParserException Exception related to parsing.
1813          */
1814         protected List<String> readStringList(XmlPullParser parser)
1815                 throws IOException, XmlPullParserException {
1816 
1817             int length = Integer.parseInt(parser.getAttributeValue(null, ATTRIBUTE_LENGTH));
1818             List<String> arrayEntries = new ArrayList<String>(length);
1819             String value = null;
1820 
1821             if (length == 0) {
1822                 return arrayEntries;
1823             }
1824 
1825             int outerDepth = parser.getDepth();
1826             while (XmlUtils.nextElementWithin(parser, outerDepth)) {
1827                 if (parser.getName().equals(TAG_VALUE)) {
1828                     parser.next();
1829                     value = parser.getText();
1830                     arrayEntries.add(value);
1831                 }
1832             }
1833 
1834             return arrayEntries;
1835         }
1836 
1837         /**
1838          * Reads a bundle from the XML parser.
1839          *
1840          * @param parser The XML parser.
1841          * @return Bundle containing the parsed values.
1842          * @throws IOException Exception related to IO.
1843          * @throws XmlPullParserException Exception related to parsing.
1844          */
1845         protected Bundle readBundle(XmlPullParser parser)
1846                 throws IOException, XmlPullParserException {
1847 
1848             Bundle bundle = null;
1849             int outerDepth = parser.getDepth();
1850             while (XmlUtils.nextElementWithin(parser, outerDepth)) {
1851                 if (parser.getName().equals(TAG_VALUE)) {
1852                     String valueType = parser.getAttributeValue(null, ATTRIBUTE_VALUE_TYPE);
1853                     String key = parser.getAttributeValue(null, ATTRIBUTE_KEY);
1854                     parser.next();
1855                     String value = parser.getText();
1856 
1857                     if (bundle == null) {
1858                         bundle = new Bundle();
1859                     }
1860 
1861                     // Do not write null values to the bundle.
1862                     if (value == null) {
1863                         continue;
1864                     }
1865 
1866                     if (VALUE_TYPE_STRING.equals(valueType)) {
1867                         bundle.putString(key, value);
1868                     } else if (VALUE_TYPE_INTEGER.equals(valueType)) {
1869                         try {
1870                             int intValue = Integer.parseInt(value);
1871                             bundle.putInt(key, intValue);
1872                         } catch (NumberFormatException nfe) {
1873                             Log.w(this, "Invalid integer PhoneAccount extra.");
1874                         }
1875                     } else if (VALUE_TYPE_BOOLEAN.equals(valueType)) {
1876                         boolean boolValue = Boolean.parseBoolean(value);
1877                         bundle.putBoolean(key, boolValue);
1878                     } else {
1879                         Log.w(this, "Invalid type " + valueType + " for PhoneAccount bundle.");
1880                     }
1881                 }
1882             }
1883             return bundle;
1884         }
1885 
1886         protected Bitmap readBitmap(XmlPullParser parser) {
1887             byte[] imageByteArray = Base64.decode(parser.getText(), 0);
1888             return BitmapFactory.decodeByteArray(imageByteArray, 0, imageByteArray.length);
1889         }
1890 
1891         @Nullable
1892         protected Icon readIcon(XmlPullParser parser) throws IOException {
1893             try {
1894                 byte[] iconByteArray = Base64.decode(parser.getText(), 0);
1895                 ByteArrayInputStream stream = new ByteArrayInputStream(iconByteArray);
1896                 return Icon.createFromStream(stream);
1897             } catch (IllegalArgumentException e) {
1898                 Log.e(this, e, "Bitmap must not be null.");
1899                 return null;
1900             }
1901         }
1902     }
1903 
1904     @VisibleForTesting
1905     public static final XmlSerialization<State> sStateXml =
1906             new XmlSerialization<State>() {
1907         private static final String CLASS_STATE = "phone_account_registrar_state";
1908         private static final String DEFAULT_OUTGOING = "default_outgoing";
1909         private static final String ACCOUNTS = "accounts";
1910         private static final String VERSION = "version";
1911 
1912         @Override
1913         public void writeToXml(State o, XmlSerializer serializer, Context context)
1914                 throws IOException {
1915             if (o != null) {
1916                 serializer.startTag(null, CLASS_STATE);
1917                 serializer.attribute(null, VERSION, Objects.toString(EXPECTED_STATE_VERSION));
1918 
1919                 serializer.startTag(null, DEFAULT_OUTGOING);
1920                 for (DefaultPhoneAccountHandle defaultPhoneAccountHandle : o
1921                         .defaultOutgoingAccountHandles.values()) {
1922                     sDefaultPhoneAcountHandleXml
1923                             .writeToXml(defaultPhoneAccountHandle, serializer, context);
1924                 }
1925                 serializer.endTag(null, DEFAULT_OUTGOING);
1926 
1927                 serializer.startTag(null, ACCOUNTS);
1928                 for (PhoneAccount m : o.accounts) {
1929                     sPhoneAccountXml.writeToXml(m, serializer, context);
1930                 }
1931                 serializer.endTag(null, ACCOUNTS);
1932 
1933                 serializer.endTag(null, CLASS_STATE);
1934             }
1935         }
1936 
1937         @Override
1938         public State readFromXml(XmlPullParser parser, int version, Context context)
1939                 throws IOException, XmlPullParserException {
1940             if (parser.getName().equals(CLASS_STATE)) {
1941                 State s = new State();
1942 
1943                 String rawVersion = parser.getAttributeValue(null, VERSION);
1944                 s.versionNumber = TextUtils.isEmpty(rawVersion) ? 1 : Integer.parseInt(rawVersion);
1945 
1946                 int outerDepth = parser.getDepth();
1947                 while (XmlUtils.nextElementWithin(parser, outerDepth)) {
1948                     if (parser.getName().equals(DEFAULT_OUTGOING)) {
1949                         if (s.versionNumber < 9) {
1950                             // Migrate old default phone account handle here by assuming the
1951                             // default phone account handle belongs to the primary user. Also,
1952                             // assume there are no groups.
1953                             parser.nextTag();
1954                             PhoneAccountHandle phoneAccountHandle = sPhoneAccountHandleXml
1955                                     .readFromXml(parser, s.versionNumber, context);
1956                             UserManager userManager = UserManager.get(context);
1957                             UserInfo primaryUser = userManager.getPrimaryUser();
1958                             if (primaryUser != null) {
1959                                 UserHandle userHandle = primaryUser.getUserHandle();
1960                                 DefaultPhoneAccountHandle defaultPhoneAccountHandle
1961                                         = new DefaultPhoneAccountHandle(userHandle,
1962                                         phoneAccountHandle, "" /* groupId */);
1963                                 s.defaultOutgoingAccountHandles
1964                                         .put(userHandle, defaultPhoneAccountHandle);
1965                             }
1966                         } else {
1967                             int defaultAccountHandlesDepth = parser.getDepth();
1968                             while (XmlUtils.nextElementWithin(parser, defaultAccountHandlesDepth)) {
1969                                 DefaultPhoneAccountHandle accountHandle
1970                                         = sDefaultPhoneAcountHandleXml
1971                                         .readFromXml(parser, s.versionNumber, context);
1972                                 if (accountHandle != null && s.accounts != null) {
1973                                     s.defaultOutgoingAccountHandles
1974                                             .put(accountHandle.userHandle, accountHandle);
1975                                 }
1976                             }
1977                         }
1978                     } else if (parser.getName().equals(ACCOUNTS)) {
1979                         int accountsDepth = parser.getDepth();
1980                         while (XmlUtils.nextElementWithin(parser, accountsDepth)) {
1981                             PhoneAccount account = sPhoneAccountXml.readFromXml(parser,
1982                                     s.versionNumber, context);
1983 
1984                             if (account != null && s.accounts != null) {
1985                                 s.accounts.add(account);
1986                             }
1987                         }
1988                     }
1989                 }
1990                 return s;
1991             }
1992             return null;
1993         }
1994     };
1995 
1996     @VisibleForTesting
1997     public static final XmlSerialization<DefaultPhoneAccountHandle> sDefaultPhoneAcountHandleXml  =
1998             new XmlSerialization<DefaultPhoneAccountHandle>() {
1999                 private static final String CLASS_DEFAULT_OUTGOING_PHONE_ACCOUNT_HANDLE
2000                         = "default_outgoing_phone_account_handle";
2001                 private static final String USER_SERIAL_NUMBER = "user_serial_number";
2002                 private static final String GROUP_ID = "group_id";
2003                 private static final String ACCOUNT_HANDLE = "account_handle";
2004 
2005                 @Override
2006                 public void writeToXml(DefaultPhoneAccountHandle o, XmlSerializer serializer,
2007                         Context context) throws IOException {
2008                     if (o != null) {
2009                         final UserManager userManager = UserManager.get(context);
2010                         final long serialNumber = userManager.getSerialNumberForUser(o.userHandle);
2011                         if (serialNumber != -1) {
2012                             serializer.startTag(null, CLASS_DEFAULT_OUTGOING_PHONE_ACCOUNT_HANDLE);
2013                             writeLong(USER_SERIAL_NUMBER, serialNumber, serializer);
2014                             writeNonNullString(GROUP_ID, o.groupId, serializer);
2015                             serializer.startTag(null, ACCOUNT_HANDLE);
2016                             sPhoneAccountHandleXml.writeToXml(o.phoneAccountHandle, serializer,
2017                                     context);
2018                             serializer.endTag(null, ACCOUNT_HANDLE);
2019                             serializer.endTag(null, CLASS_DEFAULT_OUTGOING_PHONE_ACCOUNT_HANDLE);
2020                         }
2021                     }
2022                 }
2023 
2024                 @Override
2025                 public DefaultPhoneAccountHandle readFromXml(XmlPullParser parser, int version,
2026                         Context context)
2027                         throws IOException, XmlPullParserException {
2028                     if (parser.getName().equals(CLASS_DEFAULT_OUTGOING_PHONE_ACCOUNT_HANDLE)) {
2029                         int outerDepth = parser.getDepth();
2030                         PhoneAccountHandle accountHandle = null;
2031                         String userSerialNumberString = null;
2032                         String groupId = "";
2033                         while (XmlUtils.nextElementWithin(parser, outerDepth)) {
2034                             if (parser.getName().equals(ACCOUNT_HANDLE)) {
2035                                 parser.nextTag();
2036                                 accountHandle = sPhoneAccountHandleXml.readFromXml(parser, version,
2037                                         context);
2038                             } else if (parser.getName().equals(USER_SERIAL_NUMBER)) {
2039                                 parser.next();
2040                                 userSerialNumberString = parser.getText();
2041                             } else if (parser.getName().equals(GROUP_ID)) {
2042                                 if (parser.next() == XmlPullParser.TEXT) {
2043                                     groupId = parser.getText();
2044                                 }
2045                             }
2046                         }
2047                         UserHandle userHandle = null;
2048                         if (userSerialNumberString != null) {
2049                             try {
2050                                 long serialNumber = Long.parseLong(userSerialNumberString);
2051                                 userHandle = UserManager.get(context)
2052                                         .getUserForSerialNumber(serialNumber);
2053                             } catch (NumberFormatException e) {
2054                                 Log.e(this, e,
2055                                         "Could not parse UserHandle " + userSerialNumberString);
2056                             }
2057                         }
2058                         if (accountHandle != null && userHandle != null && groupId != null) {
2059                             return new DefaultPhoneAccountHandle(userHandle, accountHandle,
2060                                     groupId);
2061                         }
2062                     }
2063                     return null;
2064                 }
2065             };
2066 
2067 
2068     @VisibleForTesting
2069     public static final XmlSerialization<PhoneAccount> sPhoneAccountXml =
2070             new XmlSerialization<PhoneAccount>() {
2071         private static final String CLASS_PHONE_ACCOUNT = "phone_account";
2072         private static final String ACCOUNT_HANDLE = "account_handle";
2073         private static final String ADDRESS = "handle";
2074         private static final String SUBSCRIPTION_ADDRESS = "subscription_number";
2075         private static final String CAPABILITIES = "capabilities";
2076         private static final String SUPPORTED_AUDIO_ROUTES = "supported_audio_routes";
2077         private static final String ICON_RES_ID = "icon_res_id";
2078         private static final String ICON_PACKAGE_NAME = "icon_package_name";
2079         private static final String ICON_BITMAP = "icon_bitmap";
2080         private static final String ICON_TINT = "icon_tint";
2081         private static final String HIGHLIGHT_COLOR = "highlight_color";
2082         private static final String LABEL = "label";
2083         private static final String SHORT_DESCRIPTION = "short_description";
2084         private static final String SUPPORTED_URI_SCHEMES = "supported_uri_schemes";
2085         private static final String ICON = "icon";
2086         private static final String EXTRAS = "extras";
2087         private static final String ENABLED = "enabled";
2088 
2089         @Override
2090         public void writeToXml(PhoneAccount o, XmlSerializer serializer, Context context)
2091                 throws IOException {
2092             if (o != null) {
2093                 serializer.startTag(null, CLASS_PHONE_ACCOUNT);
2094 
2095                 if (o.getAccountHandle() != null) {
2096                     serializer.startTag(null, ACCOUNT_HANDLE);
2097                     sPhoneAccountHandleXml.writeToXml(o.getAccountHandle(), serializer, context);
2098                     serializer.endTag(null, ACCOUNT_HANDLE);
2099                 }
2100 
2101                 writeTextIfNonNull(ADDRESS, o.getAddress(), serializer);
2102                 writeTextIfNonNull(SUBSCRIPTION_ADDRESS, o.getSubscriptionAddress(), serializer);
2103                 writeTextIfNonNull(CAPABILITIES, Integer.toString(o.getCapabilities()), serializer);
2104                 writeIconIfNonNull(ICON, o.getIcon(), serializer);
2105                 writeTextIfNonNull(HIGHLIGHT_COLOR,
2106                         Integer.toString(o.getHighlightColor()), serializer);
2107                 writeTextIfNonNull(LABEL, o.getLabel(), serializer);
2108                 writeTextIfNonNull(SHORT_DESCRIPTION, o.getShortDescription(), serializer);
2109                 writeStringList(SUPPORTED_URI_SCHEMES, o.getSupportedUriSchemes(), serializer);
2110                 writeBundle(EXTRAS, o.getExtras(), serializer);
2111                 writeTextIfNonNull(ENABLED, o.isEnabled() ? "true" : "false" , serializer);
2112                 writeTextIfNonNull(SUPPORTED_AUDIO_ROUTES, Integer.toString(
2113                         o.getSupportedAudioRoutes()), serializer);
2114 
2115                 serializer.endTag(null, CLASS_PHONE_ACCOUNT);
2116             }
2117         }
2118 
2119         public PhoneAccount readFromXml(XmlPullParser parser, int version, Context context)
2120                 throws IOException, XmlPullParserException {
2121             if (parser.getName().equals(CLASS_PHONE_ACCOUNT)) {
2122                 int outerDepth = parser.getDepth();
2123                 PhoneAccountHandle accountHandle = null;
2124                 Uri address = null;
2125                 Uri subscriptionAddress = null;
2126                 int capabilities = 0;
2127                 int supportedAudioRoutes = 0;
2128                 int iconResId = PhoneAccount.NO_RESOURCE_ID;
2129                 String iconPackageName = null;
2130                 Bitmap iconBitmap = null;
2131                 int iconTint = PhoneAccount.NO_ICON_TINT;
2132                 int highlightColor = PhoneAccount.NO_HIGHLIGHT_COLOR;
2133                 String label = null;
2134                 String shortDescription = null;
2135                 List<String> supportedUriSchemes = null;
2136                 Icon icon = null;
2137                 boolean enabled = false;
2138                 Bundle extras = null;
2139 
2140                 while (XmlUtils.nextElementWithin(parser, outerDepth)) {
2141                     if (parser.getName().equals(ACCOUNT_HANDLE)) {
2142                         parser.nextTag();
2143                         accountHandle = sPhoneAccountHandleXml.readFromXml(parser, version,
2144                                 context);
2145                     } else if (parser.getName().equals(ADDRESS)) {
2146                         parser.next();
2147                         address = Uri.parse(parser.getText());
2148                     } else if (parser.getName().equals(SUBSCRIPTION_ADDRESS)) {
2149                         parser.next();
2150                         String nextText = parser.getText();
2151                         subscriptionAddress = nextText == null ? null : Uri.parse(nextText);
2152                     } else if (parser.getName().equals(CAPABILITIES)) {
2153                         parser.next();
2154                         capabilities = Integer.parseInt(parser.getText());
2155                     } else if (parser.getName().equals(ICON_RES_ID)) {
2156                         parser.next();
2157                         iconResId = Integer.parseInt(parser.getText());
2158                     } else if (parser.getName().equals(ICON_PACKAGE_NAME)) {
2159                         parser.next();
2160                         iconPackageName = parser.getText();
2161                     } else if (parser.getName().equals(ICON_BITMAP)) {
2162                         parser.next();
2163                         iconBitmap = readBitmap(parser);
2164                     } else if (parser.getName().equals(ICON_TINT)) {
2165                         parser.next();
2166                         iconTint = Integer.parseInt(parser.getText());
2167                     } else if (parser.getName().equals(HIGHLIGHT_COLOR)) {
2168                         parser.next();
2169                         highlightColor = Integer.parseInt(parser.getText());
2170                     } else if (parser.getName().equals(LABEL)) {
2171                         parser.next();
2172                         label = parser.getText();
2173                     } else if (parser.getName().equals(SHORT_DESCRIPTION)) {
2174                         parser.next();
2175                         shortDescription = parser.getText();
2176                     } else if (parser.getName().equals(SUPPORTED_URI_SCHEMES)) {
2177                         supportedUriSchemes = readStringList(parser);
2178                     } else if (parser.getName().equals(ICON)) {
2179                         parser.next();
2180                         icon = readIcon(parser);
2181                     } else if (parser.getName().equals(ENABLED)) {
2182                         parser.next();
2183                         enabled = "true".equalsIgnoreCase(parser.getText());
2184                     } else if (parser.getName().equals(EXTRAS)) {
2185                         extras = readBundle(parser);
2186                     } else if (parser.getName().equals(SUPPORTED_AUDIO_ROUTES)) {
2187                         parser.next();
2188                         supportedAudioRoutes = Integer.parseInt(parser.getText());
2189                     }
2190                 }
2191 
2192                 ComponentName pstnComponentName = new ComponentName("com.android.phone",
2193                         "com.android.services.telephony.TelephonyConnectionService");
2194                 ComponentName sipComponentName = new ComponentName("com.android.phone",
2195                         "com.android.services.telephony.sip.SipConnectionService");
2196 
2197                 // Upgrade older phone accounts to specify the supported URI schemes.
2198                 if (version < 2) {
2199                     supportedUriSchemes = new ArrayList<>();
2200 
2201                     // Handle the SIP connection service.
2202                     // Check the system settings to see if it also should handle "tel" calls.
2203                     if (accountHandle.getComponentName().equals(sipComponentName)) {
2204                         boolean useSipForPstn = useSipForPstnCalls(context);
2205                         supportedUriSchemes.add(PhoneAccount.SCHEME_SIP);
2206                         if (useSipForPstn) {
2207                             supportedUriSchemes.add(PhoneAccount.SCHEME_TEL);
2208                         }
2209                     } else {
2210                         supportedUriSchemes.add(PhoneAccount.SCHEME_TEL);
2211                         supportedUriSchemes.add(PhoneAccount.SCHEME_VOICEMAIL);
2212                     }
2213                 }
2214 
2215                 // Upgrade older phone accounts with explicit package name
2216                 if (version < 5) {
2217                     if (iconBitmap == null) {
2218                         iconPackageName = accountHandle.getComponentName().getPackageName();
2219                     }
2220                 }
2221 
2222                 if (version < 6) {
2223                     // Always enable all SIP accounts on upgrade to version 6
2224                     if (accountHandle.getComponentName().equals(sipComponentName)) {
2225                         enabled = true;
2226                     }
2227                 }
2228                 if (version < 7) {
2229                     // Always enabled all PSTN acocunts on upgrade to version 7
2230                     if (accountHandle.getComponentName().equals(pstnComponentName)) {
2231                         enabled = true;
2232                     }
2233                 }
2234                 if (version < 8) {
2235                     // Migrate the SIP account handle ids to use SIP username instead of SIP URI.
2236                     if (accountHandle.getComponentName().equals(sipComponentName)) {
2237                         Uri accountUri = Uri.parse(accountHandle.getId());
2238                         if (accountUri.getScheme() != null &&
2239                             accountUri.getScheme().equals(PhoneAccount.SCHEME_SIP)) {
2240                             accountHandle = new PhoneAccountHandle(accountHandle.getComponentName(),
2241                                     accountUri.getSchemeSpecificPart(),
2242                                     accountHandle.getUserHandle());
2243                         }
2244                     }
2245                 }
2246 
2247                 if (version < 9) {
2248                     // Set supported audio routes to all by default
2249                     supportedAudioRoutes = CallAudioState.ROUTE_ALL;
2250                 }
2251 
2252                 PhoneAccount.Builder builder = PhoneAccount.builder(accountHandle, label)
2253                         .setAddress(address)
2254                         .setSubscriptionAddress(subscriptionAddress)
2255                         .setCapabilities(capabilities)
2256                         .setSupportedAudioRoutes(supportedAudioRoutes)
2257                         .setShortDescription(shortDescription)
2258                         .setSupportedUriSchemes(supportedUriSchemes)
2259                         .setHighlightColor(highlightColor)
2260                         .setExtras(extras)
2261                         .setIsEnabled(enabled);
2262 
2263                 if (icon != null) {
2264                     builder.setIcon(icon);
2265                 } else if (iconBitmap != null) {
2266                     builder.setIcon(Icon.createWithBitmap(iconBitmap));
2267                 } else if (!TextUtils.isEmpty(iconPackageName)) {
2268                     builder.setIcon(Icon.createWithResource(iconPackageName, iconResId));
2269                     // TODO: Need to set tint.
2270                 }
2271 
2272                 return builder.build();
2273             }
2274             return null;
2275         }
2276 
2277         /**
2278          * Determines if the SIP call settings specify to use SIP for all calls, including PSTN
2279          * calls.
2280          *
2281          * @param context The context.
2282          * @return {@code True} if SIP should be used for all calls.
2283          */
2284         private boolean useSipForPstnCalls(Context context) {
2285             String option = Settings.System.getStringForUser(context.getContentResolver(),
2286                     Settings.System.SIP_CALL_OPTIONS, context.getUserId());
2287             option = (option != null) ? option : Settings.System.SIP_ADDRESS_ONLY;
2288             return option.equals(Settings.System.SIP_ALWAYS);
2289         }
2290     };
2291 
2292     @VisibleForTesting
2293     public static final XmlSerialization<PhoneAccountHandle> sPhoneAccountHandleXml =
2294             new XmlSerialization<PhoneAccountHandle>() {
2295         private static final String CLASS_PHONE_ACCOUNT_HANDLE = "phone_account_handle";
2296         private static final String COMPONENT_NAME = "component_name";
2297         private static final String ID = "id";
2298         private static final String USER_SERIAL_NUMBER = "user_serial_number";
2299 
2300         @Override
2301         public void writeToXml(PhoneAccountHandle o, XmlSerializer serializer, Context context)
2302                 throws IOException {
2303             if (o != null) {
2304                 serializer.startTag(null, CLASS_PHONE_ACCOUNT_HANDLE);
2305 
2306                 if (o.getComponentName() != null) {
2307                     writeTextIfNonNull(
2308                             COMPONENT_NAME, o.getComponentName().flattenToString(), serializer);
2309                 }
2310 
2311                 writeTextIfNonNull(ID, o.getId(), serializer);
2312 
2313                 if (o.getUserHandle() != null && context != null) {
2314                     UserManager userManager = UserManager.get(context);
2315                     writeLong(USER_SERIAL_NUMBER,
2316                             userManager.getSerialNumberForUser(o.getUserHandle()), serializer);
2317                 }
2318 
2319                 serializer.endTag(null, CLASS_PHONE_ACCOUNT_HANDLE);
2320             }
2321         }
2322 
2323         @Override
2324         public PhoneAccountHandle readFromXml(XmlPullParser parser, int version, Context context)
2325                 throws IOException, XmlPullParserException {
2326             if (parser.getName().equals(CLASS_PHONE_ACCOUNT_HANDLE)) {
2327                 String componentNameString = null;
2328                 String idString = null;
2329                 String userSerialNumberString = null;
2330                 int outerDepth = parser.getDepth();
2331 
2332                 UserManager userManager = UserManager.get(context);
2333 
2334                 while (XmlUtils.nextElementWithin(parser, outerDepth)) {
2335                     if (parser.getName().equals(COMPONENT_NAME)) {
2336                         parser.next();
2337                         componentNameString = parser.getText();
2338                     } else if (parser.getName().equals(ID)) {
2339                         parser.next();
2340                         idString = parser.getText();
2341                     } else if (parser.getName().equals(USER_SERIAL_NUMBER)) {
2342                         parser.next();
2343                         userSerialNumberString = parser.getText();
2344                     }
2345                 }
2346                 if (componentNameString != null) {
2347                     UserHandle userHandle = null;
2348                     if (userSerialNumberString != null) {
2349                         try {
2350                             long serialNumber = Long.parseLong(userSerialNumberString);
2351                             userHandle = userManager.getUserForSerialNumber(serialNumber);
2352                         } catch (NumberFormatException e) {
2353                             Log.e(this, e, "Could not parse UserHandle " + userSerialNumberString);
2354                         }
2355                     }
2356                     return new PhoneAccountHandle(
2357                             ComponentName.unflattenFromString(componentNameString),
2358                             idString,
2359                             userHandle);
2360                 }
2361             }
2362             return null;
2363         }
2364     };
2365 
2366     private String nullToEmpty(String str) {
2367         return str == null ? "" : str;
2368     }
2369 }
2370