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.Binder;
36 import android.os.Bundle;
37 import android.os.AsyncTask;
38 import android.os.PersistableBundle;
39 import android.os.Process;
40 import android.os.UserHandle;
41 import android.os.UserManager;
42 import android.provider.Settings;
43 import android.telecom.CallAudioState;
44 import android.telecom.ConnectionService;
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.telephony.flags.FeatureFlags;
62 import com.android.internal.util.IndentingPrintWriter;
63 import com.android.internal.util.XmlUtils;
64 import com.android.modules.utils.ModifiedUtf8;
65 import com.android.server.telecom.flags.Flags;
66 
67 import org.xmlpull.v1.XmlPullParser;
68 import org.xmlpull.v1.XmlPullParserException;
69 import org.xmlpull.v1.XmlSerializer;
70 
71 import java.io.ByteArrayInputStream;
72 import java.io.ByteArrayOutputStream;
73 import java.io.File;
74 import java.io.FileNotFoundException;
75 import java.io.FileOutputStream;
76 import java.io.IOException;
77 import java.io.InputStream;
78 import java.lang.Integer;
79 import java.lang.SecurityException;
80 import java.lang.String;
81 import java.util.ArrayList;
82 import java.util.Collections;
83 import java.util.Comparator;
84 import java.util.HashMap;
85 import java.util.HashSet;
86 import java.util.Iterator;
87 import java.util.List;
88 import java.util.Map;
89 import java.util.Objects;
90 import java.util.Set;
91 import java.util.concurrent.ConcurrentHashMap;
92 import java.util.concurrent.CopyOnWriteArrayList;
93 import java.util.stream.Collectors;
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     public static final String ICON_ERROR_MSG =
161             "Icon cannot be written to memory. Try compressing or downsizing";
162     @VisibleForTesting
163     public static final int EXPECTED_STATE_VERSION = 9;
164     public static final int MAX_PHONE_ACCOUNT_REGISTRATIONS = 10;
165     public static final int MAX_PHONE_ACCOUNT_EXTRAS_KEY_PAIR_LIMIT = 100;
166     public static final int MAX_PHONE_ACCOUNT_FIELD_CHAR_LIMIT = 256;
167     public static final int MAX_SCHEMES_PER_ACCOUNT = 10;
168 
169     /** Keep in sync with the same in SipSettings.java */
170     private static final String SIP_SHARED_PREFERENCES = "SIP_PREFERENCES";
171 
172     private final List<Listener> mListeners = new CopyOnWriteArrayList<>();
173     private final AtomicFile mAtomicFile;
174     private final Context mContext;
175     private final UserManager mUserManager;
176     private final TelephonyManager mTelephonyManager;
177     private final SubscriptionManager mSubscriptionManager;
178     private final DefaultDialerCache mDefaultDialerCache;
179     private final AppLabelProxy mAppLabelProxy;
180     private final TelecomSystem.SyncRoot mLock;
181     private State mState;
182     private UserHandle mCurrentUserHandle;
183     private String mTestPhoneAccountPackageNameFilter;
184     private interface PhoneAccountRegistrarWriteLock {}
185     private final PhoneAccountRegistrarWriteLock mWriteLock =
186             new PhoneAccountRegistrarWriteLock() {};
187     private final FeatureFlags mTelephonyFeatureFlags;
188     private final com.android.server.telecom.flags.FeatureFlags mTelecomFeatureFlags;
189 
190     @VisibleForTesting
PhoneAccountRegistrar(Context context, TelecomSystem.SyncRoot lock, DefaultDialerCache defaultDialerCache, AppLabelProxy appLabelProxy, FeatureFlags telephonyFeatureFlags, com.android.server.telecom.flags.FeatureFlags telecomFeatureFlags)191     public PhoneAccountRegistrar(Context context, TelecomSystem.SyncRoot lock,
192             DefaultDialerCache defaultDialerCache, AppLabelProxy appLabelProxy,
193             FeatureFlags telephonyFeatureFlags,
194             com.android.server.telecom.flags.FeatureFlags telecomFeatureFlags) {
195         this(context, lock, FILE_NAME, defaultDialerCache, appLabelProxy,
196                 telephonyFeatureFlags, telecomFeatureFlags);
197     }
198 
199     @VisibleForTesting
PhoneAccountRegistrar(Context context, TelecomSystem.SyncRoot lock, String fileName, DefaultDialerCache defaultDialerCache, AppLabelProxy appLabelProxy, FeatureFlags telephonyFeatureFlags, com.android.server.telecom.flags.FeatureFlags telecomFeatureFlags)200     public PhoneAccountRegistrar(Context context, TelecomSystem.SyncRoot lock, String fileName,
201             DefaultDialerCache defaultDialerCache, AppLabelProxy appLabelProxy,
202             FeatureFlags telephonyFeatureFlags,
203             com.android.server.telecom.flags.FeatureFlags telecomFeatureFlags) {
204 
205         mAtomicFile = new AtomicFile(new File(context.getFilesDir(), fileName));
206 
207         mState = new State();
208         mContext = context;
209         mLock = lock;
210         mUserManager = context.getSystemService(UserManager.class);
211         mDefaultDialerCache = defaultDialerCache;
212         mSubscriptionManager = SubscriptionManager.from(mContext);
213         mTelephonyManager = (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE);
214         mAppLabelProxy = appLabelProxy;
215         mCurrentUserHandle = Process.myUserHandle();
216         mTelecomFeatureFlags = telecomFeatureFlags;
217 
218         if (telephonyFeatureFlags != null) {
219             mTelephonyFeatureFlags = telephonyFeatureFlags;
220         } else {
221             mTelephonyFeatureFlags =
222                     new com.android.internal.telephony.flags.FeatureFlagsImpl();
223         }
224 
225         // register context based receiver to clean up orphan phone accounts
226         IntentFilter intentFilter = new IntentFilter(Intent.ACTION_MANAGED_PROFILE_REMOVED);
227         intentFilter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
228         mContext.registerReceiver(mManagedProfileReceiver, intentFilter);
229 
230         read();
231     }
232 
233     /**
234      * Retrieves the subscription id for a given phone account if it exists. Subscription ids
235      * apply only to PSTN/SIM card phone accounts so all other accounts should not have a
236      * subscription id.
237      * @param accountHandle The handle for the phone account for which to retrieve the
238      * subscription id.
239      * @return The value of the subscription id or -1 if it does not exist or is not valid.
240      */
getSubscriptionIdForPhoneAccount(PhoneAccountHandle accountHandle)241     public int getSubscriptionIdForPhoneAccount(PhoneAccountHandle accountHandle) {
242         PhoneAccount account = getPhoneAccountUnchecked(accountHandle);
243 
244         if (account != null && account.hasCapabilities(PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION)) {
245             try {
246                 return mTelephonyManager.getSubscriptionId(accountHandle);
247             } catch (UnsupportedOperationException ignored) {
248                 // Ignore; fall back to invalid below.
249             }
250         }
251         return SubscriptionManager.INVALID_SUBSCRIPTION_ID;
252     }
253 
254     /**
255      * Retrieves the default outgoing phone account supporting the specified uriScheme. Note that if
256      * {@link #mCurrentUserHandle} does not have visibility into the current default, {@code null}
257      * will be returned.
258      *
259      * @param uriScheme The URI scheme for the outgoing call.
260      * @return The {@link PhoneAccountHandle} to use.
261      */
getOutgoingPhoneAccountForScheme(String uriScheme, UserHandle userHandle)262     public PhoneAccountHandle getOutgoingPhoneAccountForScheme(String uriScheme,
263             UserHandle userHandle) {
264         final PhoneAccountHandle userSelected = getUserSelectedOutgoingPhoneAccount(userHandle);
265 
266         if (userSelected != null) {
267             // If there is a default PhoneAccount, ensure it supports calls to handles with the
268             // specified uriScheme.
269             final PhoneAccount userSelectedAccount = getPhoneAccountUnchecked(userSelected);
270             if (userSelectedAccount.supportsUriScheme(uriScheme)) {
271                 return userSelected;
272             }
273         }
274 
275         List<PhoneAccountHandle> outgoing = getCallCapablePhoneAccounts(uriScheme, false,
276                 userHandle, false);
277         switch (outgoing.size()) {
278             case 0:
279                 // There are no accounts, so there can be no default
280                 return null;
281             case 1:
282                 // There is only one account, which is by definition the default.
283                 return outgoing.get(0);
284             default:
285                 // There are multiple accounts with no selected default
286                 return null;
287         }
288     }
289 
getOutgoingPhoneAccountForSchemeOfCurrentUser(String uriScheme)290     public PhoneAccountHandle getOutgoingPhoneAccountForSchemeOfCurrentUser(String uriScheme) {
291         return getOutgoingPhoneAccountForScheme(uriScheme, mCurrentUserHandle);
292     }
293 
294     /**
295      * @return The user-selected outgoing {@link PhoneAccount}, or null if it hasn't been set (or
296      *      if it was set by another user).
297      */
298     @VisibleForTesting
getUserSelectedOutgoingPhoneAccount(UserHandle userHandle)299     public PhoneAccountHandle getUserSelectedOutgoingPhoneAccount(UserHandle userHandle) {
300         if (userHandle == null) {
301             return null;
302         }
303         DefaultPhoneAccountHandle defaultPhoneAccountHandle = mState.defaultOutgoingAccountHandles
304                 .get(userHandle);
305         if (defaultPhoneAccountHandle == null) {
306             return null;
307         }
308         // Make sure the account is still registered and owned by the user.
309         PhoneAccount account = getPhoneAccount(defaultPhoneAccountHandle.phoneAccountHandle,
310                 userHandle);
311 
312         if (account != null) {
313             return defaultPhoneAccountHandle.phoneAccountHandle;
314         }
315 
316         Log.v(this,
317                 "getUserSelectedOutgoingPhoneAccount: defaultPhoneAccountHandle"
318                         + ".phoneAccountHandle=[%s] is not registered or owned by %s"
319                 , defaultPhoneAccountHandle.phoneAccountHandle, userHandle);
320 
321         return null;
322     }
323 
324     /**
325      * @return The {@link DefaultPhoneAccountHandle} containing the user-selected default calling
326      * account and group Id for the {@link UserHandle} specified.
327      */
getUserSelectedDefaultPhoneAccount(UserHandle userHandle)328     private DefaultPhoneAccountHandle getUserSelectedDefaultPhoneAccount(UserHandle userHandle) {
329         if (userHandle == null) {
330             return null;
331         }
332         DefaultPhoneAccountHandle defaultPhoneAccountHandle = mState.defaultOutgoingAccountHandles
333                 .get(userHandle);
334         if (defaultPhoneAccountHandle == null) {
335             return null;
336         }
337 
338         return defaultPhoneAccountHandle;
339     }
340 
341     /**
342      * @return The currently registered PhoneAccount in Telecom that has the same group Id.
343      */
getPhoneAccountByGroupId(String groupId, ComponentName groupComponentName, UserHandle userHandle, PhoneAccountHandle excludePhoneAccountHandle)344     private PhoneAccount getPhoneAccountByGroupId(String groupId, ComponentName groupComponentName,
345             UserHandle userHandle, PhoneAccountHandle excludePhoneAccountHandle) {
346         if (groupId == null || groupId.isEmpty() || userHandle == null) {
347             return null;
348         }
349         // Get the PhoneAccount with the same group Id (and same ComponentName) that is not the
350         // newAccount that was just added
351         List<PhoneAccount> accounts = getAllPhoneAccounts(userHandle, false).stream()
352                 .filter(account -> groupId.equals(account.getGroupId()) &&
353                         !account.getAccountHandle().equals(excludePhoneAccountHandle) &&
354                         Objects.equals(account.getAccountHandle().getComponentName(),
355                                 groupComponentName))
356                 .collect(Collectors.toList());
357         // There should be one or no PhoneAccounts with the same group Id
358         if (accounts.size() > 1) {
359             Log.w(this, "Found multiple PhoneAccounts registered to the same Group Id!");
360         }
361         return accounts.isEmpty() ? null : accounts.get(0);
362     }
363 
364     /**
365      * Sets the phone account with which to place all calls by default. Set by the user
366      * within phone settings.
367      */
setUserSelectedOutgoingPhoneAccount(PhoneAccountHandle accountHandle, UserHandle userHandle)368     public void setUserSelectedOutgoingPhoneAccount(PhoneAccountHandle accountHandle,
369             UserHandle userHandle) {
370         if (userHandle == null) {
371             return;
372         }
373         DefaultPhoneAccountHandle currentDefaultInfo =
374                 mState.defaultOutgoingAccountHandles.get(userHandle);
375         PhoneAccountHandle currentDefaultPhoneAccount = currentDefaultInfo == null ? null :
376                 currentDefaultInfo.phoneAccountHandle;
377 
378         Log.i(this, "setUserSelectedOutgoingPhoneAccount: %s", accountHandle);
379 
380         if (Objects.equals(currentDefaultPhoneAccount, accountHandle)) {
381             Log.i(this, "setUserSelectedOutgoingPhoneAccount: "
382                     + "no change in default phoneAccountHandle.  current is same as new.");
383             return;
384         }
385 
386         boolean isSimAccount = false;
387         if (accountHandle == null) {
388             // Asking to clear the default outgoing is a valid request
389             mState.defaultOutgoingAccountHandles.remove(userHandle);
390         } else {
391             PhoneAccount account = getPhoneAccount(accountHandle, userHandle);
392             if (account == null) {
393                 Log.w(this, "Trying to set nonexistent default outgoing %s",
394                         accountHandle);
395                 return;
396             }
397 
398             if (!account.hasCapabilities(PhoneAccount.CAPABILITY_CALL_PROVIDER)) {
399                 Log.w(this, "Trying to set non-call-provider default outgoing %s",
400                         accountHandle);
401                 return;
402             }
403 
404             if (account.hasCapabilities(PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION)) {
405                 // If the account selected is a SIM account, propagate down to the subscription
406                 // record.
407                 isSimAccount = true;
408             }
409 
410             mState.defaultOutgoingAccountHandles
411                     .put(userHandle, new DefaultPhoneAccountHandle(userHandle, accountHandle,
412                             account.getGroupId()));
413         }
414 
415         // Potentially update the default voice subid in SubscriptionManager so that Telephony and
416         // Telecom are in sync.
417         int newSubId = accountHandle == null ? SubscriptionManager.INVALID_SUBSCRIPTION_ID :
418                 getSubscriptionIdForPhoneAccount(accountHandle);
419         if (Flags.onlyUpdateTelephonyOnValidSubIds()) {
420             if (shouldUpdateTelephonyDefaultVoiceSubId(accountHandle, isSimAccount, newSubId)) {
421                 updateDefaultVoiceSubId(newSubId, accountHandle);
422             } else {
423                 Log.i(this, "setUserSelectedOutgoingPhoneAccount: %s is not a sub", accountHandle);
424             }
425         } else {
426             if (isSimAccount || accountHandle == null) {
427                 updateDefaultVoiceSubId(newSubId, accountHandle);
428             } else {
429                 Log.i(this, "setUserSelectedOutgoingPhoneAccount: %s is not a sub", accountHandle);
430             }
431         }
432 
433         write();
434         fireDefaultOutgoingChanged();
435     }
436 
updateDefaultVoiceSubId(int newSubId, PhoneAccountHandle accountHandle)437     private void updateDefaultVoiceSubId(int newSubId, PhoneAccountHandle accountHandle){
438         try {
439             int currentVoiceSubId = mSubscriptionManager.getDefaultVoiceSubscriptionId();
440             if (newSubId != currentVoiceSubId) {
441                 Log.i(this, "setUserSelectedOutgoingPhoneAccount: update voice sub; "
442                         + "account=%s, subId=%d", accountHandle, newSubId);
443                 mSubscriptionManager.setDefaultVoiceSubscriptionId(newSubId);
444             } else {
445                 Log.i(this, "setUserSelectedOutgoingPhoneAccount: no change to voice sub");
446             }
447         } catch (UnsupportedOperationException uoe) {
448             Log.w(this, "setUserSelectedOutgoingPhoneAccount: no telephony");
449         }
450     }
451 
452     // This helper is important for CTS testing.  [PhoneAccount]s created by Telecom in CTS are
453     // assigned a  subId value of INVALID_SUBSCRIPTION_ID (-1) by Telephony.  However, when
454     // Telephony has a default outgoing calling voice account of -1, that translates to no default
455     // account (user should be prompted to select an acct when making MOs).  In order to avoid
456     // Telephony clearing out the newly changed default [PhoneAccount] in Telecom, Telephony should
457     // not be updated. This situation will never occur in production since [PhoneAccount]s in
458     // production are assigned non-negative subId values.
shouldUpdateTelephonyDefaultVoiceSubId(PhoneAccountHandle phoneAccountHandle, boolean isSimAccount, int newSubId)459     private boolean shouldUpdateTelephonyDefaultVoiceSubId(PhoneAccountHandle phoneAccountHandle,
460             boolean isSimAccount, int newSubId) {
461         // user requests no call preference
462         if (phoneAccountHandle == null) {
463             return true;
464         }
465         // do not update Telephony if the newSubId is invalid
466         if (newSubId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
467             Log.w(this, "shouldUpdateTelephonyDefaultVoiceSubId: "
468                             + "invalid subId scenario, not updating Telephony. "
469                             + "phoneAccountHandle=[%s], isSimAccount=[%b], newSubId=[%s]",
470                     phoneAccountHandle, isSimAccount, newSubId);
471             return false;
472         }
473         return isSimAccount;
474     }
475 
isUserSelectedSmsPhoneAccount(PhoneAccountHandle accountHandle)476     boolean isUserSelectedSmsPhoneAccount(PhoneAccountHandle accountHandle) {
477         try {
478             return getSubscriptionIdForPhoneAccount(accountHandle) ==
479                     SubscriptionManager.getDefaultSmsSubscriptionId();
480         } catch (UnsupportedOperationException uoe) {
481             Log.w(this, "isUserSelectedSmsPhoneAccount: no telephony");
482             return false;
483         }
484     }
485 
getSystemSimCallManagerComponent()486     public ComponentName getSystemSimCallManagerComponent() {
487         return getSystemSimCallManagerComponent(SubscriptionManager.getDefaultSubscriptionId());
488     }
489 
getSystemSimCallManagerComponent(int subId)490     public ComponentName getSystemSimCallManagerComponent(int subId) {
491         String defaultSimCallManager = null;
492         try {
493             CarrierConfigManager configManager = (CarrierConfigManager) mContext.getSystemService(
494                     Context.CARRIER_CONFIG_SERVICE);
495             if (configManager == null) return null;
496             PersistableBundle configBundle = configManager.getConfigForSubId(subId);
497             if (configBundle != null) {
498                 defaultSimCallManager = configBundle.getString(
499                         CarrierConfigManager.KEY_DEFAULT_SIM_CALL_MANAGER_STRING);
500             }
501         } catch (UnsupportedOperationException ignored) {
502             Log.w(this, "getSystemSimCallManagerComponent: no telephony");
503             // Fall through to empty below.
504         }
505         return TextUtils.isEmpty(defaultSimCallManager)
506                 ?  null : ComponentName.unflattenFromString(defaultSimCallManager);
507     }
508 
getSimCallManagerOfCurrentUser()509     public PhoneAccountHandle getSimCallManagerOfCurrentUser() {
510         return getSimCallManager(mCurrentUserHandle);
511     }
512 
513     /**
514      * Returns the {@link PhoneAccountHandle} corresponding to the SIM Call Manager associated with
515      * the default Telephony Subscription ID (see
516      * {@link SubscriptionManager#getDefaultSubscriptionId()}). SIM Call Manager returned
517      * corresponds to the following priority order:
518      * 1. If a SIM Call Manager {@link PhoneAccount} is registered for the same package as the
519      * default dialer, then that one is returned.
520      * 2. If there is a SIM Call Manager {@link PhoneAccount} registered which matches the
521      * carrier configuration's default, then that one is returned.
522      * 3. Otherwise, we return null.
523      */
getSimCallManager(UserHandle userHandle)524     public PhoneAccountHandle getSimCallManager(UserHandle userHandle) {
525         return getSimCallManager(SubscriptionManager.getDefaultSubscriptionId(), userHandle);
526     }
527 
528     /**
529      * Queries the SIM call manager associated with a specific subscription ID.
530      *
531      * @see #getSimCallManager(UserHandle) for more information.
532      */
getSimCallManager(int subId, UserHandle userHandle)533     public PhoneAccountHandle getSimCallManager(int subId, UserHandle userHandle) {
534 
535         // Get the default dialer in case it has a connection manager associated with it.
536         String dialerPackage = mDefaultDialerCache
537                 .getDefaultDialerApplication(userHandle.getIdentifier());
538 
539         // Check carrier config.
540         ComponentName systemSimCallManagerComponent = getSystemSimCallManagerComponent(subId);
541 
542         PhoneAccountHandle dialerSimCallManager = null;
543         PhoneAccountHandle systemSimCallManager = null;
544 
545         if (!TextUtils.isEmpty(dialerPackage) || systemSimCallManagerComponent != null) {
546             // loop through and look for any connection manager in the same package.
547             List<PhoneAccountHandle> allSimCallManagers = getPhoneAccountHandles(
548                     PhoneAccount.CAPABILITY_CONNECTION_MANAGER, null, null,
549                     true /* includeDisabledAccounts */, userHandle, false);
550             for (PhoneAccountHandle accountHandle : allSimCallManagers) {
551                 ComponentName component = accountHandle.getComponentName();
552 
553                 // Store the system connection manager if found
554                 if (systemSimCallManager == null
555                         && Objects.equals(component, systemSimCallManagerComponent)
556                         && !resolveComponent(accountHandle).isEmpty()) {
557                     systemSimCallManager = accountHandle;
558 
559                 // Store the dialer connection manager if found
560                 } else if (dialerSimCallManager == null
561                         && Objects.equals(component.getPackageName(), dialerPackage)
562                         && !resolveComponent(accountHandle).isEmpty()) {
563                     dialerSimCallManager = accountHandle;
564                 }
565             }
566         }
567 
568         PhoneAccountHandle retval = dialerSimCallManager != null ?
569                 dialerSimCallManager : systemSimCallManager;
570         Log.i(this, "getSimCallManager: SimCallManager for subId %d queried, returning: %s",
571                 subId, retval);
572 
573         return retval;
574     }
575 
576     /**
577      * Loops through all SIM accounts ({@link #getSimPhoneAccounts}) and returns those with SIM call
578      * manager components specified in carrier config that match {@code simCallManagerHandle}.
579      *
580      * <p>Note that this will return handles even when {@code simCallManagerHandle} has not yet been
581      * registered or was recently unregistered.
582      *
583      * <p>If the given {@code simCallManagerHandle} is not the SIM call manager for any active SIMs,
584      * returns an empty list.
585      */
getSimPhoneAccountsFromSimCallManager( @onNull PhoneAccountHandle simCallManagerHandle)586     public @NonNull List<PhoneAccountHandle> getSimPhoneAccountsFromSimCallManager(
587             @NonNull PhoneAccountHandle simCallManagerHandle) {
588         List<PhoneAccountHandle> matchingSimHandles = new ArrayList<>();
589         for (PhoneAccountHandle simHandle :
590                 getSimPhoneAccounts(simCallManagerHandle.getUserHandle())) {
591             ComponentName simCallManager =
592                     getSystemSimCallManagerComponent(getSubscriptionIdForPhoneAccount(simHandle));
593             if (simCallManager == null) continue;
594             if (simCallManager.equals(simCallManagerHandle.getComponentName())) {
595                 matchingSimHandles.add(simHandle);
596             }
597         }
598         return matchingSimHandles;
599     }
600 
601     /**
602      * Sets a filter for which {@link PhoneAccount}s will be returned from
603      * {@link #filterRestrictedPhoneAccounts(List)}. If non-null, only {@link PhoneAccount}s
604      * with the package name packageNameFilter will be returned. If null, no filter is set.
605      * @param packageNameFilter The package name that will be used to filter only
606      * {@link PhoneAccount}s with the same package name.
607      */
setTestPhoneAccountPackageNameFilter(String packageNameFilter)608     public void setTestPhoneAccountPackageNameFilter(String packageNameFilter) {
609         mTestPhoneAccountPackageNameFilter = packageNameFilter;
610         Log.i(this, "filter set for PhoneAccounts, packageName=" + packageNameFilter);
611     }
612 
613     /**
614      * Filter the given {@link List<PhoneAccount>} and keep only {@link PhoneAccount}s that have the
615      * #mTestPhoneAccountPackageNameFilter.
616      * @param accounts List of {@link PhoneAccount}s to filter.
617      * @return new list of filtered {@link PhoneAccount}s.
618      */
filterRestrictedPhoneAccounts(List<PhoneAccount> accounts)619     public List<PhoneAccount> filterRestrictedPhoneAccounts(List<PhoneAccount> accounts) {
620         if (TextUtils.isEmpty(mTestPhoneAccountPackageNameFilter)) {
621             return new ArrayList<>(accounts);
622         }
623         // Remove all PhoneAccounts that do not have the same package name as the filter.
624         return accounts.stream().filter(account -> mTestPhoneAccountPackageNameFilter.equals(
625                 account.getAccountHandle().getComponentName().getPackageName()))
626                 .collect(Collectors.toList());
627     }
628 
629     /**
630      * If it is a outgoing call, sim call manager associated with the target phone account of the
631      * call is returned (if one exists).
632      * Otherwise, we return the sim call manager of the user associated with the
633      * target phone account.
634      * @return phone account handle of sim call manager based on the ongoing call.
635      */
636     @Nullable
getSimCallManagerFromCall(Call call)637     public PhoneAccountHandle getSimCallManagerFromCall(Call call) {
638         if (call == null) {
639             return null;
640         }
641         UserHandle userHandle = call.getAssociatedUser();
642         PhoneAccountHandle targetPhoneAccount = call.getTargetPhoneAccount();
643         Log.d(this, "getSimCallManagerFromCall: callId=%s, targetPhac=%s",
644                 call.getId(), targetPhoneAccount);
645         return getSimCallManagerFromHandle(targetPhoneAccount,userHandle);
646     }
647 
648     /**
649      * Given a target phone account and user, determines the sim call manager (if any) which is
650      * associated with that {@link PhoneAccountHandle}.
651      * @param targetPhoneAccount The target phone account to check.
652      * @param userHandle The user handle.
653      * @return The {@link PhoneAccountHandle} of the connection manager.
654      */
getSimCallManagerFromHandle(PhoneAccountHandle targetPhoneAccount, UserHandle userHandle)655     public PhoneAccountHandle getSimCallManagerFromHandle(PhoneAccountHandle targetPhoneAccount,
656             UserHandle userHandle) {
657         // First, check if the specified target phone account handle is a connection manager; if
658         // it is, then just return it.
659         PhoneAccount phoneAccount = getPhoneAccountUnchecked(targetPhoneAccount);
660         if (phoneAccount != null
661                 && phoneAccount.hasCapabilities(PhoneAccount.CAPABILITY_CONNECTION_MANAGER)) {
662             return targetPhoneAccount;
663         }
664 
665         int subId = getSubscriptionIdForPhoneAccount(targetPhoneAccount);
666         if (SubscriptionManager.isValidSubscriptionId(subId)
667                  && subId != SubscriptionManager.DEFAULT_SUBSCRIPTION_ID) {
668             PhoneAccountHandle callManagerHandle = getSimCallManager(subId, userHandle);
669             Log.d(this, "getSimCallManagerFromHandle: targetPhac=%s, subId=%d, scm=%s",
670                     targetPhoneAccount, subId, callManagerHandle);
671             return callManagerHandle;
672         } else {
673             PhoneAccountHandle callManagerHandle = getSimCallManager(userHandle);
674             Log.d(this, "getSimCallManagerFromHandle: targetPhac=%s, subId(d)=%d, scm=%s",
675                     targetPhoneAccount, subId, callManagerHandle);
676             return callManagerHandle;
677         }
678     }
679 
680     /**
681      * Update the current UserHandle to track when users are switched. This will allow the
682      * PhoneAccountRegistar to self-filter the PhoneAccounts to make sure we don't leak anything
683      * across users.
684      * We cannot simply check the calling user because that would always return the primary user for
685      * all invocations originating with the system process.
686      *
687      * @param userHandle The {@link UserHandle}, as delivered by
688      *          {@link Intent#ACTION_USER_SWITCHED}.
689      */
setCurrentUserHandle(UserHandle userHandle)690     public void setCurrentUserHandle(UserHandle userHandle) {
691         if (userHandle == null) {
692             Log.d(this, "setCurrentUserHandle, userHandle = null");
693             userHandle = Process.myUserHandle();
694         }
695         Log.d(this, "setCurrentUserHandle, %s", userHandle);
696         mCurrentUserHandle = userHandle;
697     }
698 
699     /**
700      * @return {@code true} if the phone account was successfully enabled/disabled, {@code false}
701      *         otherwise.
702      */
enablePhoneAccount(PhoneAccountHandle accountHandle, boolean isEnabled)703     public boolean enablePhoneAccount(PhoneAccountHandle accountHandle, boolean isEnabled) {
704         PhoneAccount account = getPhoneAccountUnchecked(accountHandle);
705         Log.i(this, "Phone account %s %s.", accountHandle, isEnabled ? "enabled" : "disabled");
706         if (account == null) {
707             Log.w(this, "Could not find account to enable: " + accountHandle);
708             return false;
709         } else if (account.hasCapabilities(PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION)) {
710             // We never change the enabled state of SIM-based accounts.
711             Log.w(this, "Could not change enable state of SIM account: " + accountHandle);
712             return false;
713         }
714 
715         if (account.isEnabled() != isEnabled) {
716             account.setIsEnabled(isEnabled);
717             if (!isEnabled) {
718                 // If the disabled account is the default, remove it.
719                 removeDefaultPhoneAccountHandle(accountHandle);
720             }
721             write();
722             fireAccountsChanged();
723         }
724         return true;
725     }
726 
removeDefaultPhoneAccountHandle(PhoneAccountHandle phoneAccountHandle)727     private void removeDefaultPhoneAccountHandle(PhoneAccountHandle phoneAccountHandle) {
728         Iterator<Map.Entry<UserHandle, DefaultPhoneAccountHandle>> iterator =
729                 mState.defaultOutgoingAccountHandles.entrySet().iterator();
730         while (iterator.hasNext()) {
731             Map.Entry<UserHandle, DefaultPhoneAccountHandle> entry = iterator.next();
732             if (phoneAccountHandle.equals(entry.getValue().phoneAccountHandle)) {
733                 iterator.remove();
734             }
735         }
736     }
737 
isMatchedUser(PhoneAccount account, UserHandle userHandle)738     private boolean isMatchedUser(PhoneAccount account, UserHandle userHandle) {
739         if (account == null) {
740             return false;
741         }
742 
743         if (userHandle == null) {
744             Log.w(this, "userHandle is null in isVisibleForUser");
745             return false;
746         }
747 
748         UserHandle phoneAccountUserHandle = account.getAccountHandle().getUserHandle();
749         if (phoneAccountUserHandle == null) {
750             return false;
751         }
752 
753         return phoneAccountUserHandle.equals(userHandle);
754     }
755 
isVisibleForUser(PhoneAccount account, UserHandle userHandle, boolean acrossProfiles)756     private boolean isVisibleForUser(PhoneAccount account, UserHandle userHandle,
757             boolean acrossProfiles) {
758         if (account == null) {
759             return false;
760         }
761 
762         if (userHandle == null) {
763             Log.w(this, "userHandle is null in isVisibleForUser");
764             return false;
765         }
766 
767         // If this PhoneAccount has CAPABILITY_MULTI_USER, it should be visible to all users and
768         // all profiles. Only Telephony and SIP accounts should have this capability.
769         if (account.hasCapabilities(PhoneAccount.CAPABILITY_MULTI_USER)) {
770             return true;
771         }
772 
773         UserHandle phoneAccountUserHandle = account.getAccountHandle().getUserHandle();
774         if (phoneAccountUserHandle == null) {
775             return false;
776         }
777 
778         if (mCurrentUserHandle == null) {
779             // In case we need to have emergency phone calls from the lock screen.
780             Log.d(this, "Current user is null; assuming true");
781             return true;
782         }
783 
784         if (acrossProfiles) {
785             UserManager um = mContext.getSystemService(UserManager.class);
786             return mTelecomFeatureFlags.telecomResolveHiddenDependencies()
787                     ? um.isSameProfileGroup(userHandle, phoneAccountUserHandle)
788                     : um.isSameProfileGroup(userHandle.getIdentifier(),
789                             phoneAccountUserHandle.getIdentifier());
790         } else {
791             return phoneAccountUserHandle.equals(userHandle);
792         }
793     }
794 
resolveComponent(PhoneAccountHandle phoneAccountHandle)795     private List<ResolveInfo> resolveComponent(PhoneAccountHandle phoneAccountHandle) {
796         return resolveComponent(phoneAccountHandle.getComponentName(),
797                 phoneAccountHandle.getUserHandle());
798     }
799 
resolveComponent(ComponentName componentName, UserHandle userHandle)800     private List<ResolveInfo> resolveComponent(ComponentName componentName,
801             UserHandle userHandle) {
802         PackageManager pm = mContext.getPackageManager();
803         Intent intent = new Intent(ConnectionService.SERVICE_INTERFACE);
804         intent.setComponent(componentName);
805         try {
806             if (userHandle != null) {
807                 return pm.queryIntentServicesAsUser(intent, 0, userHandle.getIdentifier());
808             } else {
809                 return pm.queryIntentServices(intent, 0);
810             }
811         } catch (SecurityException e) {
812             Log.e(this, e, "%s is not visible for the calling user", componentName);
813             return Collections.EMPTY_LIST;
814         }
815     }
816 
817     /**
818      * Retrieves a list of all {@link PhoneAccountHandle}s registered.
819      * Only returns accounts which are enabled.
820      *
821      * @return The list of {@link PhoneAccountHandle}s.
822      */
getAllPhoneAccountHandles(UserHandle userHandle, boolean crossUserAccess)823     public List<PhoneAccountHandle> getAllPhoneAccountHandles(UserHandle userHandle,
824             boolean crossUserAccess) {
825         return getPhoneAccountHandles(0, null, null, false, userHandle, crossUserAccess, true);
826     }
827 
getAllPhoneAccounts(UserHandle userHandle, boolean crossUserAccess)828     public List<PhoneAccount> getAllPhoneAccounts(UserHandle userHandle, boolean crossUserAccess) {
829         return getPhoneAccounts(0, null, null, false, mCurrentUserHandle, crossUserAccess, true);
830     }
831 
832     /**
833      * Retrieves a list of all phone account call provider phone accounts supporting the
834      * specified URI scheme.
835      *
836      * @param uriScheme The URI scheme.
837      * @param includeDisabledAccounts {@code} if disabled {@link PhoneAccount}s should be included
838      *      in the results.
839      * @param userHandle The {@link UserHandle} to retrieve the {@link PhoneAccount}s for.
840      * @return The phone account handles.
841      */
getCallCapablePhoneAccounts( String uriScheme, boolean includeDisabledAccounts, UserHandle userHandle, boolean crossUserAccess)842     public List<PhoneAccountHandle> getCallCapablePhoneAccounts(
843             String uriScheme, boolean includeDisabledAccounts,
844             UserHandle userHandle, boolean crossUserAccess) {
845         return getCallCapablePhoneAccounts(uriScheme, includeDisabledAccounts, userHandle,
846                 0 /* capabilities */, PhoneAccount.CAPABILITY_EMERGENCY_CALLS_ONLY,
847                 crossUserAccess);
848     }
849 
850     /**
851      * Retrieves a list of all phone account call provider phone accounts supporting the
852      * specified URI scheme.
853      *
854      * @param uriScheme The URI scheme.
855      * @param includeDisabledAccounts {@code} if disabled {@link PhoneAccount}s should be included
856      *      in the results.
857      * @param userHandle The {@link UserHandle} to retrieve the {@link PhoneAccount}s for.
858      * @param capabilities Extra {@link PhoneAccount} capabilities which matching
859      *      {@link PhoneAccount}s must have.
860      * @return The phone account handles.
861      */
getCallCapablePhoneAccounts( String uriScheme, boolean includeDisabledAccounts, UserHandle userHandle, int capabilities, int excludedCapabilities, boolean crossUserAccess)862     public List<PhoneAccountHandle> getCallCapablePhoneAccounts(
863             String uriScheme, boolean includeDisabledAccounts, UserHandle userHandle,
864             int capabilities, int excludedCapabilities, boolean crossUserAccess) {
865         return getPhoneAccountHandles(
866                 PhoneAccount.CAPABILITY_CALL_PROVIDER | capabilities,
867                 excludedCapabilities /*excludedCapabilities*/,
868                 uriScheme, null, includeDisabledAccounts, userHandle, crossUserAccess);
869     }
870 
871     /**
872      * Retrieves a list of all phone accounts which have
873      * {@link PhoneAccount#CAPABILITY_SELF_MANAGED}.
874      * <p>
875      * Returns only the {@link PhoneAccount}s which are enabled as self-managed accounts are
876      * automatically enabled by default (see {@link #registerPhoneAccount(PhoneAccount)}).
877      *
878      * @param userHandle User handle of phone account owner.
879      * @return The phone account handles.
880      */
getSelfManagedPhoneAccounts(UserHandle userHandle)881     public List<PhoneAccountHandle> getSelfManagedPhoneAccounts(UserHandle userHandle) {
882         return getPhoneAccountHandles(
883                 PhoneAccount.CAPABILITY_SELF_MANAGED,
884                 PhoneAccount.CAPABILITY_EMERGENCY_CALLS_ONLY /* excludedCapabilities */,
885                 null /* uriScheme */, null /* packageName */, false /* includeDisabledAccounts */,
886                 userHandle, false);
887     }
888 
889     /**
890      * Retrieves a list of all the SIM-based phone accounts.
891      */
getSimPhoneAccounts(UserHandle userHandle)892     public List<PhoneAccountHandle> getSimPhoneAccounts(UserHandle userHandle) {
893         return getPhoneAccountHandles(
894                 PhoneAccount.CAPABILITY_CALL_PROVIDER | PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION,
895                 null, null, false, userHandle, false);
896     }
897 
getSimPhoneAccountsOfCurrentUser()898     public List<PhoneAccountHandle> getSimPhoneAccountsOfCurrentUser() {
899         return getSimPhoneAccounts(mCurrentUserHandle);
900     }
901 
902         /**
903          * Retrieves a list of all phone accounts registered by a specified package.
904          *
905          * @param packageName The name of the package that registered the phone accounts.
906          * @return The phone account handles.
907          */
getPhoneAccountsForPackage(String packageName, UserHandle userHandle)908     public List<PhoneAccountHandle> getPhoneAccountsForPackage(String packageName,
909             UserHandle userHandle) {
910         return getPhoneAccountHandles(0, null, packageName, false, userHandle, false);
911     }
912 
913 
914     /**
915      * includes disabled, includes crossUserAccess
916      */
getAllPhoneAccountHandlesForPackage(UserHandle userHandle, String packageName)917     public List<PhoneAccountHandle> getAllPhoneAccountHandlesForPackage(UserHandle userHandle,
918             String packageName) {
919         return getPhoneAccountHandles(0, null, packageName, true /* includeDisabled */, userHandle,
920                 true /* crossUserAccess */, true);
921     }
922 
923     /**
924      * Retrieves a list of all {@link PhoneAccount#CAPABILITY_SELF_MANAGED} phone accounts
925      * registered by a specified package.
926      *
927      * @param packageName The name of the package that registered the phone accounts.
928      * @return The self-managed phone account handles for the given package.
929      */
getSelfManagedPhoneAccountsForPackage(String packageName, UserHandle userHandle)930     public List<PhoneAccountHandle> getSelfManagedPhoneAccountsForPackage(String packageName,
931             UserHandle userHandle) {
932         List<PhoneAccountHandle> phoneAccountsHandles = new ArrayList<>();
933         for (PhoneAccountHandle pah : getPhoneAccountsForPackage(packageName,
934                 userHandle)) {
935             if (isSelfManagedPhoneAccount(pah)) {
936                 phoneAccountsHandles.add(pah);
937             }
938         }
939         return phoneAccountsHandles;
940     }
941 
942     /**
943      * Determines if a {@link PhoneAccountHandle} is for a self-managed {@link ConnectionService}.
944      * @param handle The handle.
945      * @return {@code true} if for a self-managed {@link ConnectionService}, {@code false}
946      * otherwise.
947      */
isSelfManagedPhoneAccount(@onNull PhoneAccountHandle handle)948     public boolean isSelfManagedPhoneAccount(@NonNull PhoneAccountHandle handle) {
949         PhoneAccount account = getPhoneAccountUnchecked(handle);
950         if (account == null) {
951             return false;
952         }
953 
954         return account.isSelfManaged();
955     }
956 
957     /**
958      * Performs checks before calling addOrReplacePhoneAccount(PhoneAccount)
959      *
960      * @param account The {@code PhoneAccount} to add or replace.
961      * @throws SecurityException        if package does not have BIND_TELECOM_CONNECTION_SERVICE
962      *                                  permission
963      * @throws IllegalArgumentException if MAX_PHONE_ACCOUNT_REGISTRATIONS are reached
964      * @throws IllegalArgumentException if MAX_PHONE_ACCOUNT_FIELD_CHAR_LIMIT is reached
965      * @throws IllegalArgumentException if writing the Icon to memory will cause an Exception
966      */
registerPhoneAccount(PhoneAccount account)967     public void registerPhoneAccount(PhoneAccount account) {
968         // Enforce the requirement that a connection service for a phone account has the correct
969         // permission.
970         if (!hasTransactionalCallCapabilities(account) &&
971                 !phoneAccountRequiresBindPermission(account.getAccountHandle())) {
972             Log.w(this,
973                     "Phone account %s does not have BIND_TELECOM_CONNECTION_SERVICE permission.",
974                     account.getAccountHandle());
975             throw new SecurityException("Registering a PhoneAccount requires either: "
976                     + "(1) The Service definition requires that the ConnectionService is guarded"
977                     + " with the BIND_TELECOM_CONNECTION_SERVICE, which can be defined using the"
978                     + " android:permission tag as part of the Service definition. "
979                     + "(2) The PhoneAccount capability called"
980                     + " CAPABILITY_SUPPORTS_TRANSACTIONAL_OPERATIONS.");
981         }
982         enforceCharacterLimit(account);
983         enforceIconSizeLimit(account);
984         if (mTelecomFeatureFlags.unregisterUnresolvableAccounts()) {
985             enforcePhoneAccountTargetService(account);
986         }
987         enforceMaxPhoneAccountLimit(account);
988         if (mTelephonyFeatureFlags.simultaneousCallingIndications()) {
989             enforceSimultaneousCallingRestrictionLimit(account);
990         }
991         addOrReplacePhoneAccount(account);
992     }
993 
994     /**
995      * This method ensures that {@link PhoneAccount}s that have the {@link
996      * PhoneAccount#CAPABILITY_SUPPORTS_TRANSACTIONAL_OPERATIONS} capability are not
997      * backed by a {@link ConnectionService}
998      *
999      * @param account enforce the check on
1000      */
enforcePhoneAccountTargetService(PhoneAccount account)1001     private void enforcePhoneAccountTargetService(PhoneAccount account) {
1002         if (phoneAccountRequiresBindPermission(account.getAccountHandle()) &&
1003                 hasTransactionalCallCapabilities(account)) {
1004             throw new IllegalArgumentException(
1005                     "Error, the PhoneAccount you are registering has"
1006                             + " CAPABILITY_SUPPORTS_TRANSACTIONAL_OPERATIONS and the"
1007                             + " PhoneAccountHandle's ComponentName#ClassName points to a"
1008                             + " ConnectionService class.  Either remove the capability or use a"
1009                             + " different ClassName in the PhoneAccountHandle.");
1010         }
1011     }
1012 
1013     /**
1014      * Enforce an upper bound on the number of PhoneAccount's a package can register.
1015      * Most apps should only require 1-2.  * Include disabled accounts.
1016      *
1017      * @param account to enforce check on
1018      * @throws IllegalArgumentException if MAX_PHONE_ACCOUNT_REGISTRATIONS are reached
1019      */
enforceMaxPhoneAccountLimit(@onNull PhoneAccount account)1020     private void enforceMaxPhoneAccountLimit(@NonNull PhoneAccount account) {
1021         int numOfAcctsRegisteredForPackage = mTelecomFeatureFlags.unregisterUnresolvableAccounts()
1022                 ? cleanupAndGetVerifiedAccounts(account).size()
1023                 : getPhoneAccountHandles(
1024                         0/* capabilities */,
1025                         null /* uriScheme */,
1026                         account.getAccountHandle().getComponentName().getPackageName(),
1027                         true /* includeDisabled */,
1028                         account.getAccountHandle().getUserHandle(),
1029                         false /* crossUserAccess */).size();
1030         // enforce the max phone account limit for the application registering accounts
1031         if (numOfAcctsRegisteredForPackage >= MAX_PHONE_ACCOUNT_REGISTRATIONS) {
1032             EventLog.writeEvent(0x534e4554, "259064622", Binder.getCallingUid(),
1033                     "enforceMaxPhoneAccountLimit");
1034             throw new IllegalArgumentException(
1035                     "Error, cannot register phone account " + account.getAccountHandle()
1036                             + " because the limit, " + MAX_PHONE_ACCOUNT_REGISTRATIONS
1037                             + ", has been reached");
1038         }
1039     }
1040 
1041     @VisibleForTesting
getRegisteredAccountsForPackageName(String packageName, UserHandle userHandle)1042     public List<PhoneAccount> getRegisteredAccountsForPackageName(String packageName,
1043             UserHandle userHandle) {
1044         if (packageName == null) {
1045             return new ArrayList<>();
1046         }
1047         List<PhoneAccount> accounts = new ArrayList<>(mState.accounts.size());
1048         for (PhoneAccount m : mState.accounts) {
1049             PhoneAccountHandle handle = m.getAccountHandle();
1050             if (!packageName.equals(handle.getComponentName().getPackageName())) {
1051                 // Not the right package name; skip this one.
1052                 continue;
1053             }
1054             // Do not count accounts registered under different users on the device. Otherwise, an
1055             // application can only have MAX_PHONE_ACCOUNT_REGISTRATIONS across all users. If the
1056             // DUT has multiple users, they should each get to register 10 accounts. Also, 3rd
1057             // party applications cannot create new UserHandles without highly privileged
1058             // permissions.
1059             if (!isVisibleForUser(m, userHandle, false)) {
1060                 // Account is not visible for the current user; skip this one.
1061                 continue;
1062             }
1063             accounts.add(m);
1064         }
1065         return accounts;
1066     }
1067 
1068     /**
1069      * Unregister {@link ConnectionService} accounts that no longer have a resolvable Service. This
1070      * means the Service has been disabled or died.  Skip the verification for transactional
1071      * accounts.
1072      *
1073      * @param newAccount being registered
1074      * @return all the verified accounts. These accounts are now guaranteed to be backed by a
1075      * {@link ConnectionService} or do not need one (transactional accounts).
1076      */
1077     @VisibleForTesting
cleanupAndGetVerifiedAccounts(PhoneAccount newAccount)1078     public List<PhoneAccount> cleanupAndGetVerifiedAccounts(PhoneAccount newAccount) {
1079         ArrayList<PhoneAccount> verifiedAccounts = new ArrayList<>();
1080         List<PhoneAccount> unverifiedAccounts = getRegisteredAccountsForPackageName(
1081                 newAccount.getAccountHandle().getComponentName().getPackageName(),
1082                 newAccount.getAccountHandle().getUserHandle());
1083         for (PhoneAccount account : unverifiedAccounts) {
1084             PhoneAccountHandle handle = account.getAccountHandle();
1085             if (/* skip for transactional accounts since they don't require a ConnectionService */
1086                     !hasTransactionalCallCapabilities(account) &&
1087                     /* check if the {@link ConnectionService} has been disabled or can longer be
1088                        found */ resolveComponent(handle).isEmpty()) {
1089                 Log.i(this, " cAGVA: Cannot resolve the ConnectionService for"
1090                         + " handle=[%s]; unregistering account", handle);
1091                 unregisterPhoneAccount(handle);
1092             } else {
1093                 verifiedAccounts.add(account);
1094             }
1095         }
1096         return verifiedAccounts;
1097     }
1098 
1099     /**
1100      * determine if there will be an issue writing the icon to memory
1101      *
1102      * @param account to enforce check on
1103      * @throws IllegalArgumentException if writing the Icon to memory will cause an Exception
1104      */
1105     @VisibleForTesting
enforceIconSizeLimit(PhoneAccount account)1106     public void enforceIconSizeLimit(PhoneAccount account) {
1107         if (account.getIcon() == null) {
1108             return;
1109         }
1110         String text = "";
1111         // convert the icon into a Base64 String
1112         try {
1113             text = XmlSerialization.writeIconToBase64String(account.getIcon());
1114         } catch (IOException e) {
1115             EventLog.writeEvent(0x534e4554, "259064622", Binder.getCallingUid(),
1116                     "enforceIconSizeLimit");
1117             throw new IllegalArgumentException(ICON_ERROR_MSG);
1118         }
1119         // enforce the max bytes check in com.android.modules.utils.FastDataOutput#writeUTF(string)
1120         try {
1121             final int len = (int) ModifiedUtf8.countBytes(text, false);
1122             if (len > 65_535 /* MAX_UNSIGNED_SHORT */) {
1123                 EventLog.writeEvent(0x534e4554, "259064622", Binder.getCallingUid(),
1124                         "enforceIconSizeLimit");
1125                 throw new IllegalArgumentException(ICON_ERROR_MSG);
1126             }
1127         } catch (IOException e) {
1128             EventLog.writeEvent(0x534e4554, "259064622", Binder.getCallingUid(),
1129                     "enforceIconSizeLimit");
1130             throw new IllegalArgumentException(ICON_ERROR_MSG);
1131         }
1132     }
1133 
1134     /**
1135      * All {@link PhoneAccount} and{@link PhoneAccountHandle} String and Char-Sequence fields
1136      * should be restricted to character limit of MAX_PHONE_ACCOUNT_CHAR_LIMIT to prevent exceptions
1137      * when writing large character streams to XML-Serializer.
1138      *
1139      * @param account to enforce character limit checks on
1140      * @throws IllegalArgumentException if MAX_PHONE_ACCOUNT_FIELD_CHAR_LIMIT reached
1141      */
enforceCharacterLimit(PhoneAccount account)1142     public void enforceCharacterLimit(PhoneAccount account) {
1143         if (account == null) {
1144             return;
1145         }
1146         PhoneAccountHandle handle = account.getAccountHandle();
1147 
1148         String[] fields =
1149                 {"Package Name", "Class Name", "PhoneAccountHandle Id", "Label", "ShortDescription",
1150                         "GroupId", "Address", "SubscriptionAddress"};
1151         CharSequence[] args = {handle.getComponentName().getPackageName(),
1152                 handle.getComponentName().getClassName(), handle.getId(), account.getLabel(),
1153                 account.getShortDescription(), account.getGroupId(),
1154                 (account.getAddress() != null ? account.getAddress().toString() : ""),
1155                 (account.getSubscriptionAddress() != null ?
1156                         account.getSubscriptionAddress().toString() : "")};
1157 
1158         for (int i = 0; i < fields.length; i++) {
1159             if (args[i] != null && args[i].length() > MAX_PHONE_ACCOUNT_FIELD_CHAR_LIMIT) {
1160                 EventLog.writeEvent(0x534e4554, "259064622", Binder.getCallingUid(),
1161                         "enforceCharacterLimit");
1162                 throw new IllegalArgumentException("The PhoneAccount or PhoneAccountHandle ["
1163                         + fields[i] + "] field has an invalid character count. PhoneAccount and "
1164                         + "PhoneAccountHandle String and Char-Sequence fields are limited to "
1165                         + MAX_PHONE_ACCOUNT_FIELD_CHAR_LIMIT + " characters.");
1166             }
1167         }
1168 
1169         // Enforce limits on the URI Schemes provided
1170         enforceLimitsOnSchemes(account);
1171 
1172         // Enforce limit on the PhoneAccount#mExtras
1173         Bundle extras = account.getExtras();
1174         if (extras != null) {
1175             if (extras.keySet().size() > MAX_PHONE_ACCOUNT_EXTRAS_KEY_PAIR_LIMIT) {
1176                 EventLog.writeEvent(0x534e4554, "259064622", Binder.getCallingUid(),
1177                         "enforceCharacterLimit");
1178                 throw new IllegalArgumentException("The PhoneAccount#mExtras is limited to " +
1179                         MAX_PHONE_ACCOUNT_EXTRAS_KEY_PAIR_LIMIT + " (key,value) pairs.");
1180             }
1181 
1182             for (String key : extras.keySet()) {
1183                 Object value = extras.get(key);
1184 
1185                 if ((key != null && key.length() > MAX_PHONE_ACCOUNT_FIELD_CHAR_LIMIT) ||
1186                         (value instanceof String &&
1187                                 ((String) value).length() > MAX_PHONE_ACCOUNT_FIELD_CHAR_LIMIT)) {
1188                     EventLog.writeEvent(0x534e4554, "259064622", Binder.getCallingUid(),
1189                             "enforceCharacterLimit");
1190                     throw new IllegalArgumentException("The PhoneAccount#mExtras contains a String"
1191                             + " key or value that has an invalid character count. PhoneAccount and "
1192                             + "PhoneAccountHandle String and Char-Sequence fields are limited to "
1193                             + MAX_PHONE_ACCOUNT_FIELD_CHAR_LIMIT + " characters.");
1194                 }
1195             }
1196         }
1197     }
1198 
1199     /**
1200      * Enforce size limits on the simultaneous calling restriction of a PhoneAccount.
1201      * If a PhoneAccount has a simultaneous calling restriction on it, enforce the following: the
1202      * number of PhoneAccountHandles in the Set can not exceed the per app restriction on
1203      * PhoneAccounts registered and each PhoneAccountHandle's fields must not exceed the per field
1204      * character limit.
1205      * @param account The PhoneAccount to enforce simultaneous calling restrictions on.
1206      * @throws IllegalArgumentException if the PhoneAccount exceeds size limits.
1207      */
enforceSimultaneousCallingRestrictionLimit(@onNull PhoneAccount account)1208     public void enforceSimultaneousCallingRestrictionLimit(@NonNull PhoneAccount account) {
1209         if (!account.hasSimultaneousCallingRestriction()) return;
1210         Set<PhoneAccountHandle> restrictions = account.getSimultaneousCallingRestriction();
1211         if (restrictions.size() > MAX_PHONE_ACCOUNT_REGISTRATIONS) {
1212             throw new IllegalArgumentException("Can not register a PhoneAccount with a number"
1213                     + "of simultaneous calling restrictions that is greater than "
1214                     + MAX_PHONE_ACCOUNT_REGISTRATIONS);
1215         }
1216         for (PhoneAccountHandle handle : restrictions) {
1217             ComponentName component = handle.getComponentName();
1218             if (component.getPackageName().length() > MAX_PHONE_ACCOUNT_FIELD_CHAR_LIMIT) {
1219                 throw new IllegalArgumentException("A PhoneAccountHandle added as part of "
1220                         + "a simultaneous calling restriction has a package name that has exceeded "
1221                         + "the character limit of " + MAX_PHONE_ACCOUNT_FIELD_CHAR_LIMIT);
1222             }
1223             if (component.getClassName().length() > MAX_PHONE_ACCOUNT_FIELD_CHAR_LIMIT) {
1224                 throw new IllegalArgumentException("A PhoneAccountHandle added as part of "
1225                         + "a simultaneous calling restriction has a class name that has exceeded "
1226                         + "the character limit of " + MAX_PHONE_ACCOUNT_FIELD_CHAR_LIMIT);
1227             }
1228             if (handle.getId().length() > MAX_PHONE_ACCOUNT_FIELD_CHAR_LIMIT) {
1229                 throw new IllegalArgumentException("A PhoneAccountHandle added as part of "
1230                         + "a simultaneous calling restriction has an ID that has exceeded "
1231                         + "the character limit of " + MAX_PHONE_ACCOUNT_FIELD_CHAR_LIMIT);
1232             }
1233         }
1234     }
1235 
1236     /**
1237      * Enforce a character limit on all PA and PAH string or char-sequence fields.
1238      *
1239      * @param account to enforce check on
1240      * @throws IllegalArgumentException if MAX_PHONE_ACCOUNT_FIELD_CHAR_LIMIT reached
1241      */
1242     @VisibleForTesting
enforceLimitsOnSchemes(@onNull PhoneAccount account)1243     public void enforceLimitsOnSchemes(@NonNull PhoneAccount account) {
1244         List<String> schemes = account.getSupportedUriSchemes();
1245 
1246         if (schemes == null) {
1247             return;
1248         }
1249 
1250         if (schemes.size() > MAX_SCHEMES_PER_ACCOUNT) {
1251             EventLog.writeEvent(0x534e4554, "259064622", Binder.getCallingUid(),
1252                     "enforceLimitsOnSchemes");
1253             throw new IllegalArgumentException(
1254                     "Error, cannot register phone account " + account.getAccountHandle()
1255                             + " because the URI scheme limit of "
1256                             + MAX_SCHEMES_PER_ACCOUNT + " has been reached");
1257         }
1258 
1259         for (String scheme : schemes) {
1260             if (scheme.length() > MAX_PHONE_ACCOUNT_FIELD_CHAR_LIMIT) {
1261                 EventLog.writeEvent(0x534e4554, "259064622", Binder.getCallingUid(),
1262                         "enforceLimitsOnSchemes");
1263                 throw new IllegalArgumentException(
1264                         "Error, cannot register phone account " + account.getAccountHandle()
1265                                 + " because the max scheme limit of "
1266                                 + MAX_PHONE_ACCOUNT_FIELD_CHAR_LIMIT + " has been reached");
1267             }
1268         }
1269     }
1270 
1271     /**
1272      * Adds a {@code PhoneAccount}, replacing an existing one if found.
1273      *
1274      * @param account The {@code PhoneAccount} to add or replace.
1275      */
addOrReplacePhoneAccount(PhoneAccount account)1276     private void addOrReplacePhoneAccount(PhoneAccount account) {
1277         Log.d(this, "addOrReplacePhoneAccount(%s -> %s)",
1278                 account.getAccountHandle(), account);
1279 
1280         // Start _enabled_ property as false.
1281         // !!! IMPORTANT !!! It is important that we do not read the enabled state that the
1282         // source app provides or else an third party app could enable itself.
1283         boolean isEnabled = false;
1284         boolean isNewAccount;
1285 
1286         // add self-managed capability for transactional accounts that are missing it
1287         if (hasTransactionalCallCapabilities(account) &&
1288                 !account.hasCapabilities(PhoneAccount.CAPABILITY_SELF_MANAGED)) {
1289             account = account.toBuilder()
1290                     .setCapabilities(account.getCapabilities()
1291                             | PhoneAccount.CAPABILITY_SELF_MANAGED)
1292                     .build();
1293         }
1294 
1295         PhoneAccount oldAccount = getPhoneAccountUnchecked(account.getAccountHandle());
1296         if (oldAccount != null) {
1297             enforceSelfManagedAccountUnmodified(account, oldAccount);
1298             mState.accounts.remove(oldAccount);
1299             isEnabled = oldAccount.isEnabled();
1300             Log.i(this, "Modify account: %s", getAccountDiffString(account, oldAccount));
1301             isNewAccount = false;
1302         } else {
1303             Log.i(this, "New phone account registered: " + account);
1304             isNewAccount = true;
1305         }
1306 
1307         // When registering a self-managed PhoneAccount we enforce the rule that the label that the
1308         // app uses is also its phone account label.  Also ensure it does not attempt to declare
1309         // itself as a sim acct, call manager or call provider.
1310         if (account.hasCapabilities(PhoneAccount.CAPABILITY_SELF_MANAGED)) {
1311             // Turn off bits we don't want to be able to set (TelecomServiceImpl protects against
1312             // this but we'll also prevent it from happening here, just to be safe).
1313             int newCapabilities = account.getCapabilities() &
1314                     ~(PhoneAccount.CAPABILITY_CALL_PROVIDER |
1315                         PhoneAccount.CAPABILITY_CONNECTION_MANAGER |
1316                         PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION);
1317 
1318             // Ensure name is correct.
1319             CharSequence newLabel = mAppLabelProxy.getAppLabel(
1320                     account.getAccountHandle().getComponentName().getPackageName());
1321 
1322             account = account.toBuilder()
1323                     .setLabel(newLabel)
1324                     .setCapabilities(newCapabilities)
1325                     .build();
1326         }
1327 
1328         mState.accounts.add(account);
1329         // Set defaults and replace based on the group Id.
1330         maybeReplaceOldAccount(account);
1331         // Reset enabled state to whatever the value was if the account was already registered,
1332         // or _true_ if this is a SIM-based account.  All SIM-based accounts are always enabled,
1333         // as are all self-managed phone accounts.
1334         account.setIsEnabled(
1335                 isEnabled || account.hasCapabilities(PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION)
1336                 || account.hasCapabilities(PhoneAccount.CAPABILITY_SELF_MANAGED));
1337 
1338         write();
1339         fireAccountsChanged();
1340         if (isNewAccount) {
1341             fireAccountRegistered(account.getAccountHandle());
1342         } else {
1343             fireAccountChanged(account);
1344         }
1345         // If this is the SIM call manager, tell telephony when the voice ServiceState override
1346         // needs to be updated.
1347         maybeNotifyTelephonyForVoiceServiceState(account, /* registered= */ true);
1348     }
1349 
unregisterPhoneAccount(PhoneAccountHandle accountHandle)1350     public void unregisterPhoneAccount(PhoneAccountHandle accountHandle) {
1351         PhoneAccount account = getPhoneAccountUnchecked(accountHandle);
1352         if (account != null) {
1353             if (mState.accounts.remove(account)) {
1354                 write();
1355                 fireAccountsChanged();
1356                 fireAccountUnRegistered(accountHandle);
1357                 // If this is the SIM call manager, tell telephony when the voice ServiceState
1358                 // override needs to be updated.
1359                 maybeNotifyTelephonyForVoiceServiceState(account, /* registered= */ false);
1360             }
1361         }
1362     }
1363 
enforceSelfManagedAccountUnmodified(PhoneAccount newAccount, PhoneAccount oldAccount)1364     private void enforceSelfManagedAccountUnmodified(PhoneAccount newAccount,
1365             PhoneAccount oldAccount) {
1366         if (oldAccount.hasCapabilities(PhoneAccount.CAPABILITY_SELF_MANAGED) &&
1367                 (!newAccount.hasCapabilities(PhoneAccount.CAPABILITY_SELF_MANAGED))) {
1368             EventLog.writeEvent(0x534e4554, "246930197");
1369             Log.w(this, "Self-managed phone account %s replaced by a non self-managed one",
1370                     newAccount.getAccountHandle());
1371             throw new IllegalArgumentException("Error, cannot change a self-managed "
1372                     + "phone account " + newAccount.getAccountHandle()
1373                     + " to other kinds of phone account");
1374         }
1375     }
1376 
1377     /**
1378      * Un-registers all phone accounts associated with a specified package.
1379      *
1380      * @param packageName The package for which phone accounts will be removed.
1381      * @param userHandle The {@link UserHandle} the package is running under.
1382      */
clearAccounts(String packageName, UserHandle userHandle)1383     public void clearAccounts(String packageName, UserHandle userHandle) {
1384         boolean accountsRemoved = false;
1385         Iterator<PhoneAccount> it = mState.accounts.iterator();
1386         while (it.hasNext()) {
1387             PhoneAccount phoneAccount = it.next();
1388             PhoneAccountHandle handle = phoneAccount.getAccountHandle();
1389             if (Objects.equals(packageName, handle.getComponentName().getPackageName())
1390                     && Objects.equals(userHandle, handle.getUserHandle())) {
1391                 Log.i(this, "Removing phone account " + phoneAccount.getLabel());
1392                 mState.accounts.remove(phoneAccount);
1393                 accountsRemoved = true;
1394             }
1395         }
1396 
1397         if (accountsRemoved) {
1398             write();
1399             fireAccountsChanged();
1400         }
1401     }
1402 
isVoiceMailNumber(PhoneAccountHandle accountHandle, String number)1403     public boolean isVoiceMailNumber(PhoneAccountHandle accountHandle, String number) {
1404         int subId = getSubscriptionIdForPhoneAccount(accountHandle);
1405         return PhoneNumberUtils.isVoiceMailNumber(mContext, subId, number);
1406     }
1407 
addListener(Listener l)1408     public void addListener(Listener l) {
1409         mListeners.add(l);
1410     }
1411 
removeListener(Listener l)1412     public void removeListener(Listener l) {
1413         if (l != null) {
1414             mListeners.remove(l);
1415         }
1416     }
1417 
fireAccountRegistered(PhoneAccountHandle handle)1418     private void fireAccountRegistered(PhoneAccountHandle handle) {
1419         for (Listener l : mListeners) {
1420             l.onPhoneAccountRegistered(this, handle);
1421         }
1422     }
1423 
fireAccountChanged(PhoneAccount account)1424     private void fireAccountChanged(PhoneAccount account) {
1425         for (Listener l : mListeners) {
1426             l.onPhoneAccountChanged(this, account);
1427         }
1428     }
1429 
fireAccountUnRegistered(PhoneAccountHandle handle)1430     private void fireAccountUnRegistered(PhoneAccountHandle handle) {
1431         for (Listener l : mListeners) {
1432             l.onPhoneAccountUnRegistered(this, handle);
1433         }
1434     }
1435 
fireAccountsChanged()1436     private void fireAccountsChanged() {
1437         for (Listener l : mListeners) {
1438             l.onAccountsChanged(this);
1439         }
1440     }
1441 
fireDefaultOutgoingChanged()1442     private void fireDefaultOutgoingChanged() {
1443         for (Listener l : mListeners) {
1444             l.onDefaultOutgoingChanged(this);
1445         }
1446     }
1447 
getAccountDiffString(PhoneAccount account1, PhoneAccount account2)1448     private String getAccountDiffString(PhoneAccount account1, PhoneAccount account2) {
1449         if (account1 == null || account2 == null) {
1450             return "Diff: " + account1 + ", " + account2;
1451         }
1452 
1453         StringBuffer sb = new StringBuffer();
1454         sb.append("[").append(account1.getAccountHandle());
1455         appendDiff(sb, "addr", Log.piiHandle(account1.getAddress()),
1456                 Log.piiHandle(account2.getAddress()));
1457         appendDiff(sb, "cap", account1.capabilitiesToString(), account2.capabilitiesToString());
1458         appendDiff(sb, "hl", account1.getHighlightColor(), account2.getHighlightColor());
1459         appendDiff(sb, "lbl", account1.getLabel(), account2.getLabel());
1460         appendDiff(sb, "desc", account1.getShortDescription(), account2.getShortDescription());
1461         appendDiff(sb, "subAddr", Log.piiHandle(account1.getSubscriptionAddress()),
1462                 Log.piiHandle(account2.getSubscriptionAddress()));
1463         appendDiff(sb, "uris", account1.getSupportedUriSchemes(),
1464                 account2.getSupportedUriSchemes());
1465         sb.append("]");
1466         return sb.toString();
1467     }
1468 
appendDiff(StringBuffer sb, String attrName, Object obj1, Object obj2)1469     private void appendDiff(StringBuffer sb, String attrName, Object obj1, Object obj2) {
1470         if (!Objects.equals(obj1, obj2)) {
1471             sb.append("(")
1472                 .append(attrName)
1473                 .append(": ")
1474                 .append(obj1)
1475                 .append(" -> ")
1476                 .append(obj2)
1477                 .append(")");
1478         }
1479     }
1480 
maybeReplaceOldAccount(PhoneAccount newAccount)1481     private void maybeReplaceOldAccount(PhoneAccount newAccount) {
1482         UserHandle newAccountUserHandle = newAccount.getAccountHandle().getUserHandle();
1483         DefaultPhoneAccountHandle defaultHandle =
1484                 getUserSelectedDefaultPhoneAccount(newAccountUserHandle);
1485         if (defaultHandle == null || defaultHandle.groupId.isEmpty()) {
1486             Log.v(this, "maybeReplaceOldAccount: Not replacing PhoneAccount, no group Id or " +
1487                     "default.");
1488             return;
1489         }
1490         if (!defaultHandle.groupId.equals(newAccount.getGroupId())) {
1491             Log.v(this, "maybeReplaceOldAccount: group Ids are not equal.");
1492             return;
1493         }
1494         if (Objects.equals(newAccount.getAccountHandle().getComponentName(),
1495                 defaultHandle.phoneAccountHandle.getComponentName())) {
1496             // Move default calling account over to new user, since the ComponentNames and Group Ids
1497             // are the same.
1498             setUserSelectedOutgoingPhoneAccount(newAccount.getAccountHandle(),
1499                     newAccountUserHandle);
1500         } else {
1501             Log.v(this, "maybeReplaceOldAccount: group Ids are equal, but ComponentName is not" +
1502                     " the same as the default. Not replacing default PhoneAccount.");
1503         }
1504         PhoneAccount replacementAccount = getPhoneAccountByGroupId(newAccount.getGroupId(),
1505                 newAccount.getAccountHandle().getComponentName(), newAccountUserHandle,
1506                 newAccount.getAccountHandle());
1507         if (replacementAccount != null) {
1508             // Unregister the old PhoneAccount.
1509             Log.v(this, "maybeReplaceOldAccount: Unregistering old PhoneAccount: " +
1510                     replacementAccount.getAccountHandle());
1511             unregisterPhoneAccount(replacementAccount.getAccountHandle());
1512         }
1513     }
1514 
maybeNotifyTelephonyForVoiceServiceState( @onNull PhoneAccount account, boolean registered)1515     private void maybeNotifyTelephonyForVoiceServiceState(
1516             @NonNull PhoneAccount account, boolean registered) {
1517         // TODO(b/215419665) what about SIM_SUBSCRIPTION accounts? They could theoretically also use
1518         // these capabilities, but don't today. If they do start using them, then there will need to
1519         // be a kind of "or" logic between SIM_SUBSCRIPTION and CONNECTION_MANAGER accounts to get
1520         // the correct value of hasService for a given SIM.
1521         boolean hasService = false;
1522         List<PhoneAccountHandle> simHandlesToNotify;
1523         if (account.hasCapabilities(PhoneAccount.CAPABILITY_CONNECTION_MANAGER)) {
1524             // When we unregister the SIM call manager account, we always set hasService back to
1525             // false since it is no longer providing OTT calling capability once unregistered.
1526             if (registered) {
1527                 // Note: we do *not* early return when the SUPPORTS capability is not present
1528                 // because it's possible the SIM call manager could remove either capability at
1529                 // runtime and re-register. However, it is an error to use the AVAILABLE capability
1530                 // without also setting SUPPORTS.
1531                 hasService =
1532                         account.hasCapabilities(
1533                                 PhoneAccount.CAPABILITY_SUPPORTS_VOICE_CALLING_INDICATIONS
1534                                         | PhoneAccount.CAPABILITY_VOICE_CALLING_AVAILABLE);
1535             }
1536             // Notify for all SIMs that named this component as their SIM call manager in carrier
1537             // config, since there may be more than one impacted SIM here.
1538             simHandlesToNotify = getSimPhoneAccountsFromSimCallManager(account.getAccountHandle());
1539         } else if (account.hasCapabilities(PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION)) {
1540             // When new SIMs get registered, we notify them of their current voice status override.
1541             // If there is no SIM call manager for this SIM, we treat that as hasService = false and
1542             // still notify to ensure consistency.
1543             if (!registered) {
1544                 // We don't do anything when SIMs are unregistered because we won't have an active
1545                 // subId to map back to phoneId and tell telephony about; that case is handled by
1546                 // telephony internally.
1547                 return;
1548             }
1549             PhoneAccountHandle simCallManagerHandle =
1550                     getSimCallManagerFromHandle(
1551                             account.getAccountHandle(), account.getAccountHandle().getUserHandle());
1552             if (simCallManagerHandle != null) {
1553                 PhoneAccount simCallManager = getPhoneAccountUnchecked(simCallManagerHandle);
1554                 hasService =
1555                         simCallManager != null
1556                                 && simCallManager.hasCapabilities(
1557                                         PhoneAccount.CAPABILITY_SUPPORTS_VOICE_CALLING_INDICATIONS
1558                                                 | PhoneAccount.CAPABILITY_VOICE_CALLING_AVAILABLE);
1559             }
1560             simHandlesToNotify = Collections.singletonList(account.getAccountHandle());
1561         } else {
1562             // Not a relevant account - we only care about CONNECTION_MANAGER and SIM_SUBSCRIPTION.
1563             return;
1564         }
1565         if (simHandlesToNotify.isEmpty()) return;
1566         Log.i(
1567                 this,
1568                 "Notifying telephony of voice service override change for %d SIMs, hasService = %b",
1569                 simHandlesToNotify.size(),
1570                 hasService);
1571         try {
1572             for (PhoneAccountHandle simHandle : simHandlesToNotify) {
1573                 // This may be null if there are no active SIMs but the device is still camped for
1574                 // emergency calls and registered a SIM_SUBSCRIPTION for that purpose.
1575                 TelephonyManager simTm = mTelephonyManager.createForPhoneAccountHandle(simHandle);
1576                 if (simTm == null) {
1577                     Log.i(this, "maybeNotifyTelephonyForVoiceServiceState: "
1578                             + "simTm is null.");
1579                     continue;
1580                 }
1581                 simTm.setVoiceServiceStateOverride(hasService);
1582             }
1583         } catch (UnsupportedOperationException ignored) {
1584             // No telephony, so we can't override the sim service state.
1585             // Realistically we shouldn't get here because there should be no sim subs in this case.
1586             Log.w(this, "maybeNotifyTelephonyForVoiceServiceState: no telephony");
1587         }
1588     }
1589 
1590     /**
1591      * Determines if the connection service specified by a {@link PhoneAccountHandle} requires the
1592      * {@link Manifest.permission#BIND_TELECOM_CONNECTION_SERVICE} permission.
1593      *
1594      * @param phoneAccountHandle The phone account to check.
1595      * @return {@code True} if the phone account has permission.
1596      */
phoneAccountRequiresBindPermission(PhoneAccountHandle phoneAccountHandle)1597     public boolean phoneAccountRequiresBindPermission(PhoneAccountHandle phoneAccountHandle) {
1598         List<ResolveInfo> resolveInfos = resolveComponent(phoneAccountHandle);
1599         if (resolveInfos.isEmpty()) {
1600             Log.w(this, "phoneAccount %s not found", phoneAccountHandle.getComponentName());
1601             return false;
1602         }
1603 
1604         for (ResolveInfo resolveInfo : resolveInfos) {
1605             ServiceInfo serviceInfo = resolveInfo.serviceInfo;
1606             if (serviceInfo == null) {
1607                 return false;
1608             }
1609 
1610             if (!Manifest.permission.BIND_CONNECTION_SERVICE.equals(serviceInfo.permission) &&
1611                     !Manifest.permission.BIND_TELECOM_CONNECTION_SERVICE.equals(
1612                             serviceInfo.permission)) {
1613                 // The ConnectionService must require either the deprecated BIND_CONNECTION_SERVICE,
1614                 // or the public BIND_TELECOM_CONNECTION_SERVICE permissions, both of which are
1615                 // system/signature only.
1616                 return false;
1617             }
1618         }
1619         return true;
1620     }
1621 
1622     @VisibleForTesting
hasTransactionalCallCapabilities(PhoneAccount phoneAccount)1623     public boolean hasTransactionalCallCapabilities(PhoneAccount phoneAccount) {
1624         if (phoneAccount == null) {
1625             return false;
1626         }
1627         return phoneAccount.hasCapabilities(
1628                 PhoneAccount.CAPABILITY_SUPPORTS_TRANSACTIONAL_OPERATIONS);
1629     }
1630 
1631     //
1632     // Methods for retrieving PhoneAccounts and PhoneAccountHandles
1633     //
1634 
1635     /**
1636      * Returns the PhoneAccount for the specified handle.  Does no user checking.
1637      *
1638      * @param handle
1639      * @return The corresponding phone account if one exists.
1640      */
getPhoneAccountUnchecked(PhoneAccountHandle handle)1641     public PhoneAccount getPhoneAccountUnchecked(PhoneAccountHandle handle) {
1642         for (PhoneAccount m : mState.accounts) {
1643             if (Objects.equals(handle, m.getAccountHandle())) {
1644                 return m;
1645             }
1646         }
1647         return null;
1648     }
1649 
1650     /**
1651      * Like getPhoneAccount, but checks to see if the current user is allowed to see the phone
1652      * account before returning it. The current user is the active user on the actual android
1653      * device.
1654      */
getPhoneAccount(PhoneAccountHandle handle, UserHandle userHandle)1655     public PhoneAccount getPhoneAccount(PhoneAccountHandle handle, UserHandle userHandle) {
1656         return getPhoneAccount(handle, userHandle, /* acrossProfiles */ false);
1657     }
1658 
getPhoneAccount(PhoneAccountHandle handle, UserHandle userHandle, boolean acrossProfiles)1659     public PhoneAccount getPhoneAccount(PhoneAccountHandle handle,
1660             UserHandle userHandle, boolean acrossProfiles) {
1661         PhoneAccount account = getPhoneAccountUnchecked(handle);
1662         if (account != null && (isVisibleForUser(account, userHandle, acrossProfiles))) {
1663             return account;
1664         }
1665         return null;
1666     }
1667 
getPhoneAccountOfCurrentUser(PhoneAccountHandle handle)1668     public PhoneAccount getPhoneAccountOfCurrentUser(PhoneAccountHandle handle) {
1669         return getPhoneAccount(handle, mCurrentUserHandle);
1670     }
1671 
getPhoneAccountHandles( int capabilities, String uriScheme, String packageName, boolean includeDisabledAccounts, UserHandle userHandle, boolean crossUserAccess)1672     private List<PhoneAccountHandle> getPhoneAccountHandles(
1673             int capabilities,
1674             String uriScheme,
1675             String packageName,
1676             boolean includeDisabledAccounts,
1677             UserHandle userHandle,
1678             boolean crossUserAccess) {
1679         return getPhoneAccountHandles(capabilities, 0 /*excludedCapabilities*/, uriScheme,
1680                 packageName, includeDisabledAccounts, userHandle, crossUserAccess, false);
1681     }
1682 
getPhoneAccountHandles( int capabilities, String uriScheme, String packageName, boolean includeDisabledAccounts, UserHandle userHandle, boolean crossUserAccess, boolean includeAll)1683     private List<PhoneAccountHandle> getPhoneAccountHandles(
1684             int capabilities,
1685             String uriScheme,
1686             String packageName,
1687             boolean includeDisabledAccounts,
1688             UserHandle userHandle,
1689             boolean crossUserAccess,
1690             boolean includeAll) {
1691         return getPhoneAccountHandles(capabilities, 0 /*excludedCapabilities*/, uriScheme,
1692                 packageName, includeDisabledAccounts, userHandle, crossUserAccess, includeAll);
1693     }
1694 
1695     /**
1696      * Returns a list of phone account handles with the specified capabilities, uri scheme,
1697      * and package name.
1698      */
getPhoneAccountHandles( int capabilities, int excludedCapabilities, String uriScheme, String packageName, boolean includeDisabledAccounts, UserHandle userHandle, boolean crossUserAccess)1699     private List<PhoneAccountHandle> getPhoneAccountHandles(
1700             int capabilities,
1701             int excludedCapabilities,
1702             String uriScheme,
1703             String packageName,
1704             boolean includeDisabledAccounts,
1705             UserHandle userHandle,
1706             boolean crossUserAccess) {
1707         return getPhoneAccountHandles(capabilities, excludedCapabilities, uriScheme, packageName,
1708                 includeDisabledAccounts, userHandle, crossUserAccess, false);
1709     }
1710 
getPhoneAccountHandles( int capabilities, int excludedCapabilities, String uriScheme, String packageName, boolean includeDisabledAccounts, UserHandle userHandle, boolean crossUserAccess, boolean includeAll)1711     private List<PhoneAccountHandle> getPhoneAccountHandles(
1712             int capabilities,
1713             int excludedCapabilities,
1714             String uriScheme,
1715             String packageName,
1716             boolean includeDisabledAccounts,
1717             UserHandle userHandle,
1718             boolean crossUserAccess,
1719             boolean includeAll) {
1720         List<PhoneAccountHandle> handles = new ArrayList<>();
1721 
1722         for (PhoneAccount account : getPhoneAccounts(
1723                 capabilities, excludedCapabilities, uriScheme, packageName,
1724                 includeDisabledAccounts, userHandle, crossUserAccess, includeAll)) {
1725             handles.add(account.getAccountHandle());
1726         }
1727         return handles;
1728     }
1729 
getPhoneAccounts( int capabilities, String uriScheme, String packageName, boolean includeDisabledAccounts, UserHandle userHandle, boolean crossUserAccess)1730     private List<PhoneAccount> getPhoneAccounts(
1731             int capabilities,
1732             String uriScheme,
1733             String packageName,
1734             boolean includeDisabledAccounts,
1735             UserHandle userHandle,
1736             boolean crossUserAccess) {
1737         return getPhoneAccounts(capabilities, 0 /*excludedCapabilities*/, uriScheme, packageName,
1738                 includeDisabledAccounts, userHandle, crossUserAccess, false);
1739     }
1740 
getPhoneAccounts( int capabilities, String uriScheme, String packageName, boolean includeDisabledAccounts, UserHandle userHandle, boolean crossUserAccess, boolean includeAll)1741     private List<PhoneAccount> getPhoneAccounts(
1742             int capabilities,
1743             String uriScheme,
1744             String packageName,
1745             boolean includeDisabledAccounts,
1746             UserHandle userHandle,
1747             boolean crossUserAccess,
1748             boolean includeAll) {
1749         return getPhoneAccounts(capabilities, 0 /*excludedCapabilities*/, uriScheme, packageName,
1750                 includeDisabledAccounts, userHandle, crossUserAccess, includeAll);
1751     }
1752 
1753     /**
1754      * Returns a list of phone account handles with the specified flag, supporting the specified
1755      * URI scheme, within the specified package name.
1756      *
1757      * @param capabilities Capabilities which the {@code PhoneAccount} must have. Ignored if 0.
1758      * @param excludedCapabilities Capabilities which the {@code PhoneAccount} must not have.
1759      *                             Ignored if 0.
1760      * @param uriScheme URI schemes the PhoneAccount must handle.  {@code null} bypasses the
1761      *                  URI scheme check.
1762      * @param packageName Package name of the PhoneAccount. {@code null} bypasses packageName check.
1763      */
getPhoneAccounts( int capabilities, int excludedCapabilities, String uriScheme, String packageName, boolean includeDisabledAccounts, UserHandle userHandle, boolean crossUserAccess)1764     private List<PhoneAccount> getPhoneAccounts(
1765             int capabilities,
1766             int excludedCapabilities,
1767             String uriScheme,
1768             String packageName,
1769             boolean includeDisabledAccounts,
1770             UserHandle userHandle,
1771             boolean crossUserAccess) {
1772         return getPhoneAccounts(capabilities, excludedCapabilities, uriScheme, packageName,
1773                 includeDisabledAccounts, userHandle, crossUserAccess, false);
1774     }
1775 
1776     @VisibleForTesting
getPhoneAccounts( int capabilities, int excludedCapabilities, String uriScheme, String packageName, boolean includeDisabledAccounts, UserHandle userHandle, boolean crossUserAccess, boolean includeAll)1777     public List<PhoneAccount> getPhoneAccounts(
1778             int capabilities,
1779             int excludedCapabilities,
1780             String uriScheme,
1781             String packageName,
1782             boolean includeDisabledAccounts,
1783             UserHandle userHandle,
1784             boolean crossUserAccess,
1785             boolean includeAll) {
1786         List<PhoneAccount> accounts = new ArrayList<>(mState.accounts.size());
1787         List<PhoneAccount> matchedAccounts = new ArrayList<>(mState.accounts.size());
1788         for (PhoneAccount m : mState.accounts) {
1789             if (!(m.isEnabled() || includeDisabledAccounts)) {
1790                 // Do not include disabled accounts.
1791                 continue;
1792             }
1793 
1794             if ((m.getCapabilities() & excludedCapabilities) != 0) {
1795                 // If an excluded capability is present, skip.
1796                 continue;
1797             }
1798 
1799             if (capabilities != 0 && !m.hasCapabilities(capabilities)) {
1800                 // Account doesn't have the right capabilities; skip this one.
1801                 continue;
1802             }
1803             if (uriScheme != null && !m.supportsUriScheme(uriScheme)) {
1804                 // Account doesn't support this URI scheme; skip this one.
1805                 continue;
1806             }
1807             PhoneAccountHandle handle = m.getAccountHandle();
1808 
1809             // PhoneAccounts with CAPABILITY_SUPPORTS_TRANSACTIONAL_OPERATIONS do not require a
1810             // ConnectionService and will fail [resolveComponent(PhoneAccountHandle)]. Bypass
1811             // the [resolveComponent(PhoneAccountHandle)] for transactional accounts.
1812             if (!hasTransactionalCallCapabilities(m) && resolveComponent(handle).isEmpty()) {
1813                 // This component cannot be resolved anymore; skip this one.
1814                 continue;
1815             }
1816             if (packageName != null &&
1817                     !packageName.equals(handle.getComponentName().getPackageName())) {
1818                 // Not the right package name; skip this one.
1819                 continue;
1820             }
1821             if (isMatchedUser(m, userHandle)) {
1822                 matchedAccounts.add(m);
1823             }
1824             if (!crossUserAccess && !isVisibleForUser(m, userHandle, false)) {
1825                 // Account is not visible for the current user; skip this one.
1826                 continue;
1827             }
1828             accounts.add(m);
1829         }
1830 
1831         // Return the account if it exactly matches. Otherwise, return any account that's visible
1832         if (mTelephonyFeatureFlags.workProfileApiSplit() && !crossUserAccess && !includeAll
1833                 && !matchedAccounts.isEmpty()) {
1834             return matchedAccounts;
1835         }
1836 
1837         return accounts;
1838     }
1839 
1840     /**
1841      * Clean up the orphan {@code PhoneAccount}. An orphan {@code PhoneAccount} is a phone
1842      * account that does not have a {@code UserHandle} or belongs to a deleted package.
1843      *
1844      * @return the number of orphan {@code PhoneAccount} deleted.
1845      */
cleanupOrphanedPhoneAccounts()1846     public int cleanupOrphanedPhoneAccounts() {
1847         ArrayList<PhoneAccount> badAccountsList = new ArrayList<>();
1848         HashMap<String, Boolean> packageLookup = new HashMap<>();
1849         HashMap<PhoneAccount, Boolean> userHandleLookup = new HashMap<>();
1850 
1851         // iterate over all accounts in registrar
1852         for (PhoneAccount pa : mState.accounts) {
1853             String packageName = pa.getAccountHandle().getComponentName().getPackageName();
1854 
1855             // check if the package for the PhoneAccount is uninstalled
1856             if (packageLookup.computeIfAbsent(packageName,
1857                     pn -> isPackageUninstalled(pn))) {
1858                 badAccountsList.add(pa);
1859             }
1860             // check if PhoneAccount does not have a valid UserHandle (user was deleted)
1861             else if (userHandleLookup.computeIfAbsent(pa,
1862                     a -> isUserHandleDeletedForPhoneAccount(a))) {
1863                 badAccountsList.add(pa);
1864             }
1865         }
1866 
1867         mState.accounts.removeAll(badAccountsList);
1868 
1869         return badAccountsList.size();
1870     }
1871 
isPackageUninstalled(String packageName)1872     public Boolean isPackageUninstalled(String packageName) {
1873         try {
1874             mContext.getPackageManager().getPackageInfo(packageName, 0);
1875             return false;
1876         } catch (PackageManager.NameNotFoundException e) {
1877             return true;
1878         }
1879     }
1880 
isUserHandleDeletedForPhoneAccount(PhoneAccount phoneAccount)1881     private Boolean isUserHandleDeletedForPhoneAccount(PhoneAccount phoneAccount) {
1882         UserHandle userHandle = phoneAccount.getAccountHandle().getUserHandle();
1883         return (userHandle == null) ||
1884                 (mUserManager.getSerialNumberForUser(userHandle) == -1L);
1885     }
1886 
1887     //
1888     // State Implementation for PhoneAccountRegistrar
1889     //
1890 
1891     /**
1892      * The state of this {@code PhoneAccountRegistrar}.
1893      */
1894     @VisibleForTesting
1895     public static class State {
1896         /**
1897          * Store the default phone account handle of users. If no record of a user can be found in
1898          * the map, it means that no default phone account handle is set in that user.
1899          */
1900         public final Map<UserHandle, DefaultPhoneAccountHandle> defaultOutgoingAccountHandles
1901                 = new ConcurrentHashMap<>();
1902 
1903         /**
1904          * The complete list of {@code PhoneAccount}s known to the Telecom subsystem.
1905          */
1906         public final List<PhoneAccount> accounts = new CopyOnWriteArrayList<>();
1907 
1908         /**
1909          * The version number of the State data.
1910          */
1911         public int versionNumber;
1912     }
1913 
1914     /**
1915      * The default {@link PhoneAccountHandle} of a user.
1916      */
1917     public static class DefaultPhoneAccountHandle {
1918 
1919         public final UserHandle userHandle;
1920 
1921         public PhoneAccountHandle phoneAccountHandle;
1922 
1923         public final String groupId;
1924 
DefaultPhoneAccountHandle(UserHandle userHandle, PhoneAccountHandle phoneAccountHandle, String groupId)1925         public DefaultPhoneAccountHandle(UserHandle userHandle,
1926                 PhoneAccountHandle phoneAccountHandle, String groupId) {
1927             this.userHandle = userHandle;
1928             this.phoneAccountHandle = phoneAccountHandle;
1929             this.groupId = groupId;
1930         }
1931     }
1932 
1933     /**
1934      * Dumps the state of the {@link CallsManager}.
1935      *
1936      * @param pw The {@code IndentingPrintWriter} to write the state to.
1937      */
dump(IndentingPrintWriter pw)1938     public void dump(IndentingPrintWriter pw) {
1939         if (mState != null) {
1940             pw.println("xmlVersion: " + mState.versionNumber);
1941             DefaultPhoneAccountHandle defaultPhoneAccountHandle
1942                     = mState.defaultOutgoingAccountHandles.get(Process.myUserHandle());
1943             pw.println("defaultOutgoing: " + (defaultPhoneAccountHandle == null ? "none" :
1944                     defaultPhoneAccountHandle.phoneAccountHandle));
1945             PhoneAccountHandle defaultOutgoing =
1946                     getOutgoingPhoneAccountForScheme(PhoneAccount.SCHEME_TEL, mCurrentUserHandle);
1947             pw.print("outgoingPhoneAccountForTelScheme: ");
1948             if (defaultOutgoing == null) {
1949                 pw.println("none");
1950             } else {
1951                 pw.println(defaultOutgoing);
1952             }
1953             // SubscriptionManager will throw if FEATURE_TELEPHONY_SUBSCRIPTION is not present.
1954             if (mContext.getPackageManager().hasSystemFeature(
1955                     PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION)) {
1956                 pw.println("defaultVoiceSubId: "
1957                         + SubscriptionManager.getDefaultVoiceSubscriptionId());
1958             }
1959             pw.println("simCallManager: " + getSimCallManager(mCurrentUserHandle));
1960             pw.println("phoneAccounts:");
1961             pw.increaseIndent();
1962             for (PhoneAccount phoneAccount : mState.accounts) {
1963                 pw.println(phoneAccount);
1964             }
1965             pw.decreaseIndent();
1966             pw.increaseIndent();
1967             pw.println("test emergency PhoneAccount filter: " + mTestPhoneAccountPackageNameFilter);
1968             pw.decreaseIndent();
1969         }
1970     }
1971 
sortPhoneAccounts()1972     private void sortPhoneAccounts() {
1973         if (mState.accounts.size() > 1) {
1974             // Sort the phone accounts using sort order:
1975             // 1) SIM accounts first, followed by non-sim accounts
1976             // 2) Sort order, with those specifying no sort order last.
1977             // 3) Label
1978 
1979             // Comparator to sort SIM subscriptions before non-sim subscriptions.
1980             Comparator<PhoneAccount> bySimCapability = (p1, p2) -> {
1981                 if (p1.hasCapabilities(PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION)
1982                         && !p2.hasCapabilities(PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION)) {
1983                     return -1;
1984                 } else if (!p1.hasCapabilities(PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION)
1985                         && p2.hasCapabilities(PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION)) {
1986                     return 1;
1987                 } else {
1988                     return 0;
1989                 }
1990             };
1991 
1992             // Create a string comparator which will sort strings, placing nulls last.
1993             Comparator<String> nullSafeStringComparator = Comparator.nullsLast(
1994                     String::compareTo);
1995 
1996             // Comparator which places PhoneAccounts with a specified sort order first, followed by
1997             // those with no sort order.
1998             Comparator<PhoneAccount> bySortOrder = (p1, p2) -> {
1999                 int sort1 = p1.getExtras() == null ? Integer.MAX_VALUE:
2000                         p1.getExtras().getInt(PhoneAccount.EXTRA_SORT_ORDER, Integer.MAX_VALUE);
2001                 int sort2 = p2.getExtras() == null ? Integer.MAX_VALUE:
2002                         p2.getExtras().getInt(PhoneAccount.EXTRA_SORT_ORDER, Integer.MAX_VALUE);
2003                 return Integer.compare(sort1, sort2);
2004             };
2005 
2006             // Comparator which sorts PhoneAccounts by label.
2007             Comparator<PhoneAccount> byLabel = (p1, p2) -> {
2008                 String s1 = p1.getLabel() == null ? null : p1.getLabel().toString();
2009                 String s2 = p2.getLabel() == null ? null : p2.getLabel().toString();
2010                 return nullSafeStringComparator.compare(s1, s2);
2011             };
2012 
2013             // Sort the phone accounts.
2014             mState.accounts.sort(bySimCapability.thenComparing(bySortOrder.thenComparing(byLabel)));
2015         }
2016     }
2017 
2018     ////////////////////////////////////////////////////////////////////////////////////////////////
2019     //
2020     // State management
2021     //
2022 
2023     private class AsyncXmlWriter extends AsyncTask<ByteArrayOutputStream, Void, Void> {
2024         @Override
doInBackground(ByteArrayOutputStream... args)2025         public Void doInBackground(ByteArrayOutputStream... args) {
2026             final ByteArrayOutputStream buffer = args[0];
2027             FileOutputStream fileOutput = null;
2028             try {
2029                 synchronized (mWriteLock) {
2030                     fileOutput = mAtomicFile.startWrite();
2031                     buffer.writeTo(fileOutput);
2032                     mAtomicFile.finishWrite(fileOutput);
2033                 }
2034             } catch (IOException e) {
2035                 Log.e(this, e, "Writing state to XML file");
2036                 mAtomicFile.failWrite(fileOutput);
2037             }
2038             return null;
2039         }
2040     }
2041 
write()2042     private void write() {
2043         try {
2044             sortPhoneAccounts();
2045             ByteArrayOutputStream os = new ByteArrayOutputStream();
2046             XmlSerializer serializer = Xml.resolveSerializer(os);
2047             writeToXml(mState, serializer, mContext, mTelephonyFeatureFlags);
2048             serializer.flush();
2049             new AsyncXmlWriter().execute(os);
2050         } catch (IOException e) {
2051             Log.e(this, e, "Writing state to XML buffer");
2052         }
2053     }
2054 
read()2055     private void read() {
2056         final InputStream is;
2057         try {
2058             is = mAtomicFile.openRead();
2059         } catch (FileNotFoundException ex) {
2060             return;
2061         }
2062 
2063         boolean versionChanged = false;
2064 
2065         try {
2066             XmlPullParser parser = Xml.resolvePullParser(is);
2067             parser.nextTag();
2068             mState = readFromXml(parser, mContext, mTelephonyFeatureFlags, mTelecomFeatureFlags);
2069             migratePhoneAccountHandle(mState);
2070             versionChanged = mState.versionNumber < EXPECTED_STATE_VERSION;
2071 
2072         } catch (IOException | XmlPullParserException e) {
2073             Log.e(this, e, "Reading state from XML file");
2074             mState = new State();
2075         } finally {
2076             try {
2077                 is.close();
2078             } catch (IOException e) {
2079                 Log.e(this, e, "Closing InputStream");
2080             }
2081         }
2082 
2083         // Verify all of the UserHandles.
2084         List<PhoneAccount> badAccounts = new ArrayList<>();
2085         for (PhoneAccount phoneAccount : mState.accounts) {
2086             UserHandle userHandle = phoneAccount.getAccountHandle().getUserHandle();
2087             if (userHandle == null) {
2088                 Log.w(this, "Missing UserHandle for %s", phoneAccount);
2089                 badAccounts.add(phoneAccount);
2090             } else if (mUserManager.getSerialNumberForUser(userHandle) == -1) {
2091                 Log.w(this, "User does not exist for %s", phoneAccount);
2092                 badAccounts.add(phoneAccount);
2093             }
2094         }
2095         mState.accounts.removeAll(badAccounts);
2096 
2097         // If an upgrade occurred, write out the changed data.
2098         if (versionChanged || !badAccounts.isEmpty()) {
2099             write();
2100         }
2101     }
2102 
2103     private static void writeToXml(State state, XmlSerializer serializer, Context context,
2104             FeatureFlags telephonyFeatureFlags) throws IOException {
2105         sStateXml.writeToXml(state, serializer, context, telephonyFeatureFlags);
2106     }
2107 
2108     private static State readFromXml(XmlPullParser parser, Context context,
2109             FeatureFlags telephonyFeatureFlags,
2110             com.android.server.telecom.flags.FeatureFlags telecomFeatureFlags)
2111             throws IOException, XmlPullParserException {
2112         State s = sStateXml.readFromXml(parser, 0, context,
2113                 telephonyFeatureFlags, telecomFeatureFlags);
2114         return s != null ? s : new State();
2115     }
2116 
2117     /**
2118      * Try to migrate the ID of default phone account handle from IccId to SubId.
2119      */
2120     @VisibleForTesting
2121     public void migratePhoneAccountHandle(State state) {
2122         if (mSubscriptionManager == null) {
2123             return;
2124         }
2125         // Use getAllSubscirptionInfoList() to get the mapping between iccId and subId
2126         // from the subscription database
2127         List<SubscriptionInfo> subscriptionInfos = mSubscriptionManager
2128                 .getAllSubscriptionInfoList();
2129         Map<UserHandle, DefaultPhoneAccountHandle> defaultPhoneAccountHandles
2130                 = state.defaultOutgoingAccountHandles;
2131         for (Map.Entry<UserHandle, DefaultPhoneAccountHandle> entry
2132                 : defaultPhoneAccountHandles.entrySet()) {
2133             DefaultPhoneAccountHandle defaultPhoneAccountHandle = entry.getValue();
2134 
2135             // Migrate Telephony PhoneAccountHandle only
2136             String telephonyComponentName =
2137                     "com.android.phone/com.android.services.telephony.TelephonyConnectionService";
2138             if (!defaultPhoneAccountHandle.phoneAccountHandle.getComponentName()
2139                     .flattenToString().equals(telephonyComponentName)) {
2140                 continue;
2141             }
2142             // Migrate from IccId to SubId
2143             for (SubscriptionInfo subscriptionInfo : subscriptionInfos) {
2144                 String phoneAccountHandleId = defaultPhoneAccountHandle.phoneAccountHandle.getId();
2145                 // Some phone account handle would store phone account handle id with the IccId
2146                 // string plus "F", and the getIccId() returns IccId string itself without "F",
2147                 // so here need to use "startsWith" to match.
2148                 if (phoneAccountHandleId != null && phoneAccountHandleId.startsWith(
2149                         subscriptionInfo.getIccId())) {
2150                     Log.i(this, "Found subscription ID to migrate: "
2151                             + subscriptionInfo.getSubscriptionId());
2152                     defaultPhoneAccountHandle.phoneAccountHandle = new PhoneAccountHandle(
2153                             defaultPhoneAccountHandle.phoneAccountHandle.getComponentName(),
2154                                     Integer.toString(subscriptionInfo.getSubscriptionId()));
2155                     break;
2156                 }
2157             }
2158         }
2159     }
2160 
2161     ////////////////////////////////////////////////////////////////////////////////////////////////
2162     //
2163     // XML serialization
2164     //
2165 
2166     @VisibleForTesting
2167     public abstract static class XmlSerialization<T> {
2168         private static final String TAG_VALUE = "value";
2169         private static final String ATTRIBUTE_LENGTH = "length";
2170         private static final String ATTRIBUTE_KEY = "key";
2171         private static final String ATTRIBUTE_VALUE_TYPE = "type";
2172         private static final String VALUE_TYPE_STRING = "string";
2173         private static final String VALUE_TYPE_INTEGER = "integer";
2174         private static final String VALUE_TYPE_BOOLEAN = "boolean";
2175 
2176         /**
2177          * Write the supplied object to XML
2178          */
2179         public abstract void writeToXml(T o, XmlSerializer serializer, Context context,
2180                 FeatureFlags telephonyFeatureFlags) throws IOException;
2181 
2182         /**
2183          * Read from the supplied XML into a new object, returning null in case of an
2184          * unrecoverable schema mismatch or other data error. 'parser' must be already
2185          * positioned at the first tag that is expected to have been emitted by this
2186          * object's writeToXml(). This object tries to fail early without modifying
2187          * 'parser' if it does not recognize the data it sees.
2188          */
2189         public abstract T readFromXml(XmlPullParser parser, int version, Context context,
2190                 FeatureFlags telephonyFeatureFlags,
2191                 com.android.server.telecom.flags.FeatureFlags featureFlags)
2192                 throws IOException, XmlPullParserException;
2193 
2194         protected void writeTextIfNonNull(String tagName, Object value, XmlSerializer serializer)
2195                 throws IOException {
2196             if (value != null) {
2197                 serializer.startTag(null, tagName);
2198                 serializer.text(Objects.toString(value));
2199                 serializer.endTag(null, tagName);
2200             }
2201         }
2202 
2203         /**
2204          * Serializes a List of PhoneAccountHandles.
2205          * @param tagName The tag for the List
2206          * @param handles The List of PhoneAccountHandles to serialize
2207          * @param serializer The serializer
2208          * @throws IOException if serialization fails.
2209          */
2210         protected void writePhoneAccountHandleSet(String tagName, Set<PhoneAccountHandle> handles,
2211                 XmlSerializer serializer, Context context, FeatureFlags telephonyFeatureFlags)
2212                 throws IOException {
2213             serializer.startTag(null, tagName);
2214             if (handles != null) {
2215                 serializer.attribute(null, ATTRIBUTE_LENGTH, Objects.toString(handles.size()));
2216                 for (PhoneAccountHandle handle : handles) {
2217                     sPhoneAccountHandleXml.writeToXml(handle, serializer, context,
2218                             telephonyFeatureFlags);
2219                 }
2220             } else {
2221                 serializer.attribute(null, ATTRIBUTE_LENGTH, "0");
2222             }
2223             serializer.endTag(null, tagName);
2224         }
2225 
2226         /**
2227          * Serializes a string array.
2228          *
2229          * @param tagName The tag name for the string array.
2230          * @param values The string values to serialize.
2231          * @param serializer The serializer.
2232          * @throws IOException
2233          */
2234         protected void writeStringList(String tagName, List<String> values,
2235                 XmlSerializer serializer)
2236                 throws IOException {
2237 
2238             serializer.startTag(null, tagName);
2239             if (values != null) {
2240                 serializer.attribute(null, ATTRIBUTE_LENGTH, Objects.toString(values.size()));
2241                 for (String toSerialize : values) {
2242                     serializer.startTag(null, TAG_VALUE);
2243                     if (toSerialize != null ){
2244                         serializer.text(toSerialize);
2245                     }
2246                     serializer.endTag(null, TAG_VALUE);
2247                 }
2248             } else {
2249                 serializer.attribute(null, ATTRIBUTE_LENGTH, "0");
2250             }
2251             serializer.endTag(null, tagName);
2252         }
2253 
2254         protected void writeBundle(String tagName, Bundle values, XmlSerializer serializer)
2255             throws IOException {
2256 
2257             serializer.startTag(null, tagName);
2258             if (values != null) {
2259                 for (String key : values.keySet()) {
2260                     Object value = values.get(key);
2261 
2262                     if (value == null) {
2263                         continue;
2264                     }
2265 
2266                     String valueType;
2267                     if (value instanceof String) {
2268                         valueType = VALUE_TYPE_STRING;
2269                     } else if (value instanceof Integer) {
2270                         valueType = VALUE_TYPE_INTEGER;
2271                     } else if (value instanceof Boolean) {
2272                         valueType = VALUE_TYPE_BOOLEAN;
2273                     } else {
2274                         Log.w(this,
2275                                 "PhoneAccounts support only string, integer and boolean extras TY.");
2276                         continue;
2277                     }
2278 
2279                     serializer.startTag(null, TAG_VALUE);
2280                     serializer.attribute(null, ATTRIBUTE_KEY, key);
2281                     serializer.attribute(null, ATTRIBUTE_VALUE_TYPE, valueType);
2282                     serializer.text(Objects.toString(value));
2283                     serializer.endTag(null, TAG_VALUE);
2284                 }
2285             }
2286             serializer.endTag(null, tagName);
2287         }
2288 
2289         protected void writeIconIfNonNull(String tagName, Icon value, XmlSerializer serializer)
2290                 throws IOException {
2291             if (value != null) {
2292                 String text = writeIconToBase64String(value);
2293                 serializer.startTag(null, tagName);
2294                 serializer.text(text);
2295                 serializer.endTag(null, tagName);
2296             }
2297         }
2298 
2299         public static String writeIconToBase64String(Icon icon) throws IOException {
2300             ByteArrayOutputStream stream = new ByteArrayOutputStream();
2301             icon.writeToStream(stream);
2302             byte[] iconByteArray = stream.toByteArray();
2303             return Base64.encodeToString(iconByteArray, 0, iconByteArray.length, 0);
2304         }
2305 
2306         protected void writeLong(String tagName, long value, XmlSerializer serializer)
2307                 throws IOException {
2308             serializer.startTag(null, tagName);
2309             serializer.text(Long.valueOf(value).toString());
2310             serializer.endTag(null, tagName);
2311         }
2312 
2313         protected void writeNonNullString(String tagName, String value, XmlSerializer serializer)
2314                 throws IOException {
2315             serializer.startTag(null, tagName);
2316             serializer.text(value != null ? value : "");
2317             serializer.endTag(null, tagName);
2318         }
2319 
2320         protected Set<PhoneAccountHandle> readPhoneAccountHandleSet(XmlPullParser parser,
2321                 int version, Context context, FeatureFlags telephonyFeatureFlags,
2322                 com.android.server.telecom.flags.FeatureFlags telecomFeatureFlags)
2323                 throws IOException, XmlPullParserException {
2324             int length = Integer.parseInt(parser.getAttributeValue(null, ATTRIBUTE_LENGTH));
2325             Set<PhoneAccountHandle> handles = new HashSet<>(length);
2326             if (length == 0) return handles;
2327 
2328             int outerDepth = parser.getDepth();
2329             while (XmlUtils.nextElementWithin(parser, outerDepth)) {
2330                 handles.add(sPhoneAccountHandleXml.readFromXml(parser, version, context,
2331                         telephonyFeatureFlags, telecomFeatureFlags));
2332             }
2333             return handles;
2334         }
2335 
2336         /**
2337          * Reads a string array from the XML parser.
2338          *
2339          * @param parser The XML parser.
2340          * @return String array containing the parsed values.
2341          * @throws IOException Exception related to IO.
2342          * @throws XmlPullParserException Exception related to parsing.
2343          */
2344         protected List<String> readStringList(XmlPullParser parser)
2345                 throws IOException, XmlPullParserException {
2346 
2347             int length = Integer.parseInt(parser.getAttributeValue(null, ATTRIBUTE_LENGTH));
2348             List<String> arrayEntries = new ArrayList<String>(length);
2349             String value = null;
2350 
2351             if (length == 0) {
2352                 return arrayEntries;
2353             }
2354 
2355             int outerDepth = parser.getDepth();
2356             while (XmlUtils.nextElementWithin(parser, outerDepth)) {
2357                 if (parser.getName().equals(TAG_VALUE)) {
2358                     parser.next();
2359                     value = parser.getText();
2360                     arrayEntries.add(value);
2361                 }
2362             }
2363 
2364             return arrayEntries;
2365         }
2366 
2367         /**
2368          * Reads a bundle from the XML parser.
2369          *
2370          * @param parser The XML parser.
2371          * @return Bundle containing the parsed values.
2372          * @throws IOException Exception related to IO.
2373          * @throws XmlPullParserException Exception related to parsing.
2374          */
2375         protected Bundle readBundle(XmlPullParser parser)
2376                 throws IOException, XmlPullParserException {
2377 
2378             Bundle bundle = null;
2379             int outerDepth = parser.getDepth();
2380             while (XmlUtils.nextElementWithin(parser, outerDepth)) {
2381                 if (parser.getName().equals(TAG_VALUE)) {
2382                     String valueType = parser.getAttributeValue(null, ATTRIBUTE_VALUE_TYPE);
2383                     String key = parser.getAttributeValue(null, ATTRIBUTE_KEY);
2384                     parser.next();
2385                     String value = parser.getText();
2386 
2387                     if (bundle == null) {
2388                         bundle = new Bundle();
2389                     }
2390 
2391                     // Do not write null values to the bundle.
2392                     if (value == null) {
2393                         continue;
2394                     }
2395 
2396                     if (VALUE_TYPE_STRING.equals(valueType)) {
2397                         bundle.putString(key, value);
2398                     } else if (VALUE_TYPE_INTEGER.equals(valueType)) {
2399                         try {
2400                             int intValue = Integer.parseInt(value);
2401                             bundle.putInt(key, intValue);
2402                         } catch (NumberFormatException nfe) {
2403                             Log.w(this, "Invalid integer PhoneAccount extra.");
2404                         }
2405                     } else if (VALUE_TYPE_BOOLEAN.equals(valueType)) {
2406                         boolean boolValue = Boolean.parseBoolean(value);
2407                         bundle.putBoolean(key, boolValue);
2408                     } else {
2409                         Log.w(this, "Invalid type " + valueType + " for PhoneAccount bundle.");
2410                     }
2411                 }
2412             }
2413             return bundle;
2414         }
2415 
2416         protected Bitmap readBitmap(XmlPullParser parser) {
2417             byte[] imageByteArray = Base64.decode(parser.getText(), 0);
2418             return BitmapFactory.decodeByteArray(imageByteArray, 0, imageByteArray.length);
2419         }
2420 
2421         @Nullable
2422         protected Icon readIcon(XmlPullParser parser) throws IOException {
2423             try {
2424                 byte[] iconByteArray = Base64.decode(parser.getText(), 0);
2425                 ByteArrayInputStream stream = new ByteArrayInputStream(iconByteArray);
2426                 return Icon.createFromStream(stream);
2427             } catch (IllegalArgumentException e) {
2428                 Log.e(this, e, "Bitmap must not be null.");
2429                 return null;
2430             }
2431         }
2432     }
2433 
2434     @VisibleForTesting
2435     public static final XmlSerialization<State> sStateXml =
2436             new XmlSerialization<State>() {
2437         private static final String CLASS_STATE = "phone_account_registrar_state";
2438         private static final String DEFAULT_OUTGOING = "default_outgoing";
2439         private static final String ACCOUNTS = "accounts";
2440         private static final String VERSION = "version";
2441 
2442         @Override
2443         public void writeToXml(State o, XmlSerializer serializer, Context context,
2444                 FeatureFlags telephonyFeatureFlags) throws IOException {
2445             if (o != null) {
2446                 serializer.startTag(null, CLASS_STATE);
2447                 serializer.attribute(null, VERSION, Objects.toString(EXPECTED_STATE_VERSION));
2448 
2449                 serializer.startTag(null, DEFAULT_OUTGOING);
2450                 for (DefaultPhoneAccountHandle defaultPhoneAccountHandle : o
2451                         .defaultOutgoingAccountHandles.values()) {
2452                     sDefaultPhoneAccountHandleXml
2453                             .writeToXml(defaultPhoneAccountHandle, serializer, context,
2454                                     telephonyFeatureFlags);
2455                 }
2456                 serializer.endTag(null, DEFAULT_OUTGOING);
2457 
2458                 serializer.startTag(null, ACCOUNTS);
2459                 for (PhoneAccount m : o.accounts) {
2460                     sPhoneAccountXml.writeToXml(m, serializer, context, telephonyFeatureFlags);
2461                 }
2462                 serializer.endTag(null, ACCOUNTS);
2463 
2464                 serializer.endTag(null, CLASS_STATE);
2465             }
2466         }
2467 
2468         @Override
2469         public State readFromXml(XmlPullParser parser, int version, Context context,
2470                 FeatureFlags telephonyFeatureFlags,
2471                 com.android.server.telecom.flags.FeatureFlags telecomFeatureFlags)
2472                 throws IOException, XmlPullParserException {
2473             if (parser.getName().equals(CLASS_STATE)) {
2474                 State s = new State();
2475 
2476                 String rawVersion = parser.getAttributeValue(null, VERSION);
2477                 s.versionNumber = TextUtils.isEmpty(rawVersion) ? 1 : Integer.parseInt(rawVersion);
2478 
2479                 int outerDepth = parser.getDepth();
2480                 while (XmlUtils.nextElementWithin(parser, outerDepth)) {
2481                     if (parser.getName().equals(DEFAULT_OUTGOING)) {
2482                         if (s.versionNumber < 9) {
2483                             // Migrate old default phone account handle here by assuming the
2484                             // default phone account handle belongs to the primary user. Also,
2485                             // assume there are no groups.
2486                             parser.nextTag();
2487                             PhoneAccountHandle phoneAccountHandle = sPhoneAccountHandleXml
2488                                     .readFromXml(parser, s.versionNumber, context,
2489                                             telephonyFeatureFlags, telecomFeatureFlags);
2490                             UserManager userManager = context.getSystemService(UserManager.class);
2491                             // UserManager#getMainUser requires either the MANAGE_USERS,
2492                             // CREATE_USERS, or QUERY_USERS permission.
2493                             UserHandle primaryUser = userManager.getMainUser();
2494                             UserInfo primaryUserInfo = userManager.getPrimaryUser();
2495                             if (!telecomFeatureFlags.telecomResolveHiddenDependencies()) {
2496                                 primaryUser = primaryUserInfo != null
2497                                         ? primaryUserInfo.getUserHandle()
2498                                         : null;
2499                             }
2500                             if (primaryUser != null) {
2501                                 DefaultPhoneAccountHandle defaultPhoneAccountHandle
2502                                         = new DefaultPhoneAccountHandle(primaryUser,
2503                                         phoneAccountHandle, "" /* groupId */);
2504                                 s.defaultOutgoingAccountHandles
2505                                         .put(primaryUser, defaultPhoneAccountHandle);
2506                             }
2507                         } else {
2508                             int defaultAccountHandlesDepth = parser.getDepth();
2509                             while (XmlUtils.nextElementWithin(parser, defaultAccountHandlesDepth)) {
2510                                 DefaultPhoneAccountHandle accountHandle
2511                                         = sDefaultPhoneAccountHandleXml
2512                                         .readFromXml(parser, s.versionNumber, context,
2513                                                 telephonyFeatureFlags, telecomFeatureFlags);
2514                                 if (accountHandle != null && s.accounts != null) {
2515                                     s.defaultOutgoingAccountHandles
2516                                             .put(accountHandle.userHandle, accountHandle);
2517                                 }
2518                             }
2519                         }
2520                     } else if (parser.getName().equals(ACCOUNTS)) {
2521                         int accountsDepth = parser.getDepth();
2522                         while (XmlUtils.nextElementWithin(parser, accountsDepth)) {
2523                             PhoneAccount account = sPhoneAccountXml.readFromXml(parser,
2524                                     s.versionNumber, context, telephonyFeatureFlags,
2525                                     telecomFeatureFlags);
2526 
2527                             if (account != null && s.accounts != null) {
2528                                 s.accounts.add(account);
2529                             }
2530                         }
2531                     }
2532                 }
2533                 return s;
2534             }
2535             return null;
2536         }
2537     };
2538 
2539     @VisibleForTesting
2540     public static final XmlSerialization<DefaultPhoneAccountHandle> sDefaultPhoneAccountHandleXml =
2541             new XmlSerialization<DefaultPhoneAccountHandle>() {
2542                 private static final String CLASS_DEFAULT_OUTGOING_PHONE_ACCOUNT_HANDLE
2543                         = "default_outgoing_phone_account_handle";
2544                 private static final String USER_SERIAL_NUMBER = "user_serial_number";
2545                 private static final String GROUP_ID = "group_id";
2546                 private static final String ACCOUNT_HANDLE = "account_handle";
2547 
2548                 @Override
2549                 public void writeToXml(DefaultPhoneAccountHandle o, XmlSerializer serializer,
2550                         Context context, FeatureFlags telephonyFeatureFlags) throws IOException {
2551                     if (o != null) {
2552                         final UserManager userManager = context.getSystemService(UserManager.class);
2553                         final long serialNumber = userManager.getSerialNumberForUser(o.userHandle);
2554                         if (serialNumber != -1) {
2555                             serializer.startTag(null, CLASS_DEFAULT_OUTGOING_PHONE_ACCOUNT_HANDLE);
2556                             writeLong(USER_SERIAL_NUMBER, serialNumber, serializer);
2557                             writeNonNullString(GROUP_ID, o.groupId, serializer);
2558                             serializer.startTag(null, ACCOUNT_HANDLE);
2559                             sPhoneAccountHandleXml.writeToXml(o.phoneAccountHandle, serializer,
2560                                     context, telephonyFeatureFlags);
2561                             serializer.endTag(null, ACCOUNT_HANDLE);
2562                             serializer.endTag(null, CLASS_DEFAULT_OUTGOING_PHONE_ACCOUNT_HANDLE);
2563                         }
2564                     }
2565                 }
2566 
2567                 @Override
2568                 public DefaultPhoneAccountHandle readFromXml(XmlPullParser parser, int version,
2569                         Context context, FeatureFlags telephonyFeatureFlags,
2570                         com.android.server.telecom.flags.FeatureFlags telecomFeatureFlags)
2571                         throws IOException, XmlPullParserException {
2572                     if (parser.getName().equals(CLASS_DEFAULT_OUTGOING_PHONE_ACCOUNT_HANDLE)) {
2573                         int outerDepth = parser.getDepth();
2574                         PhoneAccountHandle accountHandle = null;
2575                         String userSerialNumberString = null;
2576                         String groupId = "";
2577                         while (XmlUtils.nextElementWithin(parser, outerDepth)) {
2578                             if (parser.getName().equals(ACCOUNT_HANDLE)) {
2579                                 parser.nextTag();
2580                                 accountHandle = sPhoneAccountHandleXml.readFromXml(parser, version,
2581                                         context, telephonyFeatureFlags, telecomFeatureFlags);
2582                             } else if (parser.getName().equals(USER_SERIAL_NUMBER)) {
2583                                 parser.next();
2584                                 userSerialNumberString = parser.getText();
2585                             } else if (parser.getName().equals(GROUP_ID)) {
2586                                 if (parser.next() == XmlPullParser.TEXT) {
2587                                     groupId = parser.getText();
2588                                 }
2589                             }
2590                         }
2591                         UserHandle userHandle = null;
2592                         if (userSerialNumberString != null) {
2593                             try {
2594                                 long serialNumber = Long.parseLong(userSerialNumberString);
2595                                 userHandle = context.getSystemService(UserManager.class)
2596                                         .getUserForSerialNumber(serialNumber);
2597                             } catch (NumberFormatException e) {
2598                                 Log.e(this, e,
2599                                         "Could not parse UserHandle " + userSerialNumberString);
2600                             }
2601                         }
2602                         if (accountHandle != null && userHandle != null && groupId != null) {
2603                             return new DefaultPhoneAccountHandle(userHandle, accountHandle,
2604                                     groupId);
2605                         }
2606                     }
2607                     return null;
2608                 }
2609             };
2610 
2611 
2612     @VisibleForTesting
2613     public static final XmlSerialization<PhoneAccount> sPhoneAccountXml =
2614             new XmlSerialization<PhoneAccount>() {
2615         private static final String CLASS_PHONE_ACCOUNT = "phone_account";
2616         private static final String ACCOUNT_HANDLE = "account_handle";
2617         private static final String ADDRESS = "handle";
2618         private static final String SUBSCRIPTION_ADDRESS = "subscription_number";
2619         private static final String CAPABILITIES = "capabilities";
2620         private static final String SUPPORTED_AUDIO_ROUTES = "supported_audio_routes";
2621         private static final String ICON_RES_ID = "icon_res_id";
2622         private static final String ICON_PACKAGE_NAME = "icon_package_name";
2623         private static final String ICON_BITMAP = "icon_bitmap";
2624         private static final String ICON_TINT = "icon_tint";
2625         private static final String HIGHLIGHT_COLOR = "highlight_color";
2626         private static final String LABEL = "label";
2627         private static final String SHORT_DESCRIPTION = "short_description";
2628         private static final String SUPPORTED_URI_SCHEMES = "supported_uri_schemes";
2629         private static final String ICON = "icon";
2630         private static final String EXTRAS = "extras";
2631         private static final String ENABLED = "enabled";
2632         private static final String SIMULTANEOUS_CALLING_RESTRICTION
2633                 = "simultaneous_calling_restriction";
2634 
2635         @Override
2636         public void writeToXml(PhoneAccount o, XmlSerializer serializer, Context context,
2637                 FeatureFlags telephonyFeatureFlags) throws IOException {
2638             if (o != null) {
2639                 serializer.startTag(null, CLASS_PHONE_ACCOUNT);
2640 
2641                 if (o.getAccountHandle() != null) {
2642                     serializer.startTag(null, ACCOUNT_HANDLE);
2643                     sPhoneAccountHandleXml.writeToXml(o.getAccountHandle(), serializer, context,
2644                             telephonyFeatureFlags);
2645                     serializer.endTag(null, ACCOUNT_HANDLE);
2646                 }
2647 
2648                 writeTextIfNonNull(ADDRESS, o.getAddress(), serializer);
2649                 writeTextIfNonNull(SUBSCRIPTION_ADDRESS, o.getSubscriptionAddress(), serializer);
2650                 writeTextIfNonNull(CAPABILITIES, Integer.toString(o.getCapabilities()), serializer);
2651                 writeIconIfNonNull(ICON, o.getIcon(), serializer);
2652                 writeTextIfNonNull(HIGHLIGHT_COLOR,
2653                         Integer.toString(o.getHighlightColor()), serializer);
2654                 writeTextIfNonNull(LABEL, o.getLabel(), serializer);
2655                 writeTextIfNonNull(SHORT_DESCRIPTION, o.getShortDescription(), serializer);
2656                 writeStringList(SUPPORTED_URI_SCHEMES, o.getSupportedUriSchemes(), serializer);
2657                 writeBundle(EXTRAS, o.getExtras(), serializer);
2658                 writeTextIfNonNull(ENABLED, o.isEnabled() ? "true" : "false" , serializer);
2659                 writeTextIfNonNull(SUPPORTED_AUDIO_ROUTES, Integer.toString(
2660                         o.getSupportedAudioRoutes()), serializer);
2661                 if (o.hasSimultaneousCallingRestriction()
2662                         && telephonyFeatureFlags.simultaneousCallingIndications()) {
2663                     writePhoneAccountHandleSet(SIMULTANEOUS_CALLING_RESTRICTION,
2664                             o.getSimultaneousCallingRestriction(), serializer, context,
2665                             telephonyFeatureFlags);
2666                 }
2667 
2668                 serializer.endTag(null, CLASS_PHONE_ACCOUNT);
2669             }
2670         }
2671 
2672         public PhoneAccount readFromXml(XmlPullParser parser, int version, Context context,
2673                 FeatureFlags telephonyFeatureFlags,
2674                 com.android.server.telecom.flags.FeatureFlags telecomFeatureFlags) throws IOException, XmlPullParserException {
2675             if (parser.getName().equals(CLASS_PHONE_ACCOUNT)) {
2676                 int outerDepth = parser.getDepth();
2677                 PhoneAccountHandle accountHandle = null;
2678                 Uri address = null;
2679                 Uri subscriptionAddress = null;
2680                 int capabilities = 0;
2681                 int supportedAudioRoutes = 0;
2682                 int iconResId = PhoneAccount.NO_RESOURCE_ID;
2683                 String iconPackageName = null;
2684                 Bitmap iconBitmap = null;
2685                 int iconTint = PhoneAccount.NO_ICON_TINT;
2686                 int highlightColor = PhoneAccount.NO_HIGHLIGHT_COLOR;
2687                 String label = null;
2688                 String shortDescription = null;
2689                 List<String> supportedUriSchemes = null;
2690                 Icon icon = null;
2691                 boolean enabled = false;
2692                 Bundle extras = null;
2693                 Set<PhoneAccountHandle> simultaneousCallingRestriction = null;
2694 
2695                 while (XmlUtils.nextElementWithin(parser, outerDepth)) {
2696                     if (parser.getName().equals(ACCOUNT_HANDLE)) {
2697                         parser.nextTag();
2698                         accountHandle = sPhoneAccountHandleXml.readFromXml(parser, version,
2699                                 context, telephonyFeatureFlags, telecomFeatureFlags);
2700                     } else if (parser.getName().equals(ADDRESS)) {
2701                         parser.next();
2702                         address = Uri.parse(parser.getText());
2703                     } else if (parser.getName().equals(SUBSCRIPTION_ADDRESS)) {
2704                         parser.next();
2705                         String nextText = parser.getText();
2706                         subscriptionAddress = nextText == null ? null : Uri.parse(nextText);
2707                     } else if (parser.getName().equals(CAPABILITIES)) {
2708                         parser.next();
2709                         capabilities = Integer.parseInt(parser.getText());
2710                     } else if (parser.getName().equals(ICON_RES_ID)) {
2711                         parser.next();
2712                         iconResId = Integer.parseInt(parser.getText());
2713                     } else if (parser.getName().equals(ICON_PACKAGE_NAME)) {
2714                         parser.next();
2715                         iconPackageName = parser.getText();
2716                     } else if (parser.getName().equals(ICON_BITMAP)) {
2717                         parser.next();
2718                         iconBitmap = readBitmap(parser);
2719                     } else if (parser.getName().equals(ICON_TINT)) {
2720                         parser.next();
2721                         iconTint = Integer.parseInt(parser.getText());
2722                     } else if (parser.getName().equals(HIGHLIGHT_COLOR)) {
2723                         parser.next();
2724                         highlightColor = Integer.parseInt(parser.getText());
2725                     } else if (parser.getName().equals(LABEL)) {
2726                         parser.next();
2727                         label = parser.getText();
2728                     } else if (parser.getName().equals(SHORT_DESCRIPTION)) {
2729                         parser.next();
2730                         shortDescription = parser.getText();
2731                     } else if (parser.getName().equals(SUPPORTED_URI_SCHEMES)) {
2732                         supportedUriSchemes = readStringList(parser);
2733                     } else if (parser.getName().equals(ICON)) {
2734                         parser.next();
2735                         icon = readIcon(parser);
2736                     } else if (parser.getName().equals(ENABLED)) {
2737                         parser.next();
2738                         enabled = "true".equalsIgnoreCase(parser.getText());
2739                     } else if (parser.getName().equals(EXTRAS)) {
2740                         extras = readBundle(parser);
2741                     } else if (parser.getName().equals(SUPPORTED_AUDIO_ROUTES)) {
2742                         parser.next();
2743                         supportedAudioRoutes = Integer.parseInt(parser.getText());
2744                     } else if (parser.getName().equals(SIMULTANEOUS_CALLING_RESTRICTION)) {
2745                         // We can not flag this because we always need to handle the case where
2746                         // this info is in the XML for parsing reasons. We only flag setting the
2747                         // parsed value below based on the flag.
2748                         simultaneousCallingRestriction = readPhoneAccountHandleSet(parser, version,
2749                                 context, telephonyFeatureFlags, telecomFeatureFlags);
2750                     }
2751                 }
2752 
2753                 ComponentName pstnComponentName = new ComponentName("com.android.phone",
2754                         "com.android.services.telephony.TelephonyConnectionService");
2755                 ComponentName sipComponentName = new ComponentName("com.android.phone",
2756                         "com.android.services.telephony.sip.SipConnectionService");
2757 
2758                 // Upgrade older phone accounts to specify the supported URI schemes.
2759                 if (version < 2) {
2760                     supportedUriSchemes = new ArrayList<>();
2761 
2762                     // Handle the SIP connection service.
2763                     // Check the system settings to see if it also should handle "tel" calls.
2764                     if (accountHandle.getComponentName().equals(sipComponentName)) {
2765                         boolean useSipForPstn = useSipForPstnCalls(context);
2766                         supportedUriSchemes.add(PhoneAccount.SCHEME_SIP);
2767                         if (useSipForPstn) {
2768                             supportedUriSchemes.add(PhoneAccount.SCHEME_TEL);
2769                         }
2770                     } else {
2771                         supportedUriSchemes.add(PhoneAccount.SCHEME_TEL);
2772                         supportedUriSchemes.add(PhoneAccount.SCHEME_VOICEMAIL);
2773                     }
2774                 }
2775 
2776                 // Upgrade older phone accounts with explicit package name
2777                 if (version < 5) {
2778                     if (iconBitmap == null) {
2779                         iconPackageName = accountHandle.getComponentName().getPackageName();
2780                     }
2781                 }
2782 
2783                 if (version < 6) {
2784                     // Always enable all SIP accounts on upgrade to version 6
2785                     if (accountHandle.getComponentName().equals(sipComponentName)) {
2786                         enabled = true;
2787                     }
2788                 }
2789                 if (version < 7) {
2790                     // Always enabled all PSTN acocunts on upgrade to version 7
2791                     if (accountHandle.getComponentName().equals(pstnComponentName)) {
2792                         enabled = true;
2793                     }
2794                 }
2795                 if (version < 8) {
2796                     // Migrate the SIP account handle ids to use SIP username instead of SIP URI.
2797                     if (accountHandle.getComponentName().equals(sipComponentName)) {
2798                         Uri accountUri = Uri.parse(accountHandle.getId());
2799                         if (accountUri.getScheme() != null &&
2800                             accountUri.getScheme().equals(PhoneAccount.SCHEME_SIP)) {
2801                             accountHandle = new PhoneAccountHandle(accountHandle.getComponentName(),
2802                                     accountUri.getSchemeSpecificPart(),
2803                                     accountHandle.getUserHandle());
2804                         }
2805                     }
2806                 }
2807 
2808                 if (version < 9) {
2809                     // Set supported audio routes to all by default
2810                     supportedAudioRoutes = CallAudioState.ROUTE_ALL;
2811                 }
2812 
2813                 PhoneAccount.Builder builder = PhoneAccount.builder(accountHandle, label)
2814                         .setAddress(address)
2815                         .setSubscriptionAddress(subscriptionAddress)
2816                         .setCapabilities(capabilities)
2817                         .setSupportedAudioRoutes(supportedAudioRoutes)
2818                         .setShortDescription(shortDescription)
2819                         .setSupportedUriSchemes(supportedUriSchemes)
2820                         .setHighlightColor(highlightColor)
2821                         .setExtras(extras)
2822                         .setIsEnabled(enabled);
2823 
2824                 if (icon != null) {
2825                     builder.setIcon(icon);
2826                 } else if (iconBitmap != null) {
2827                     builder.setIcon(Icon.createWithBitmap(iconBitmap));
2828                 } else if (!TextUtils.isEmpty(iconPackageName)) {
2829                     builder.setIcon(Icon.createWithResource(iconPackageName, iconResId));
2830                     // TODO: Need to set tint.
2831                 } else if (simultaneousCallingRestriction != null
2832                         && telephonyFeatureFlags.simultaneousCallingIndications()) {
2833                     builder.setSimultaneousCallingRestriction(simultaneousCallingRestriction);
2834                 }
2835 
2836                 return builder.build();
2837             }
2838             return null;
2839         }
2840 
2841         /**
2842          * Determines if the SIP call settings specify to use SIP for all calls, including PSTN
2843          * calls.
2844          *
2845          * @param context The context.
2846          * @return {@code True} if SIP should be used for all calls.
2847          */
2848         private boolean useSipForPstnCalls(Context context) {
2849             String option = Settings.System.getStringForUser(context.getContentResolver(),
2850                     Settings.System.SIP_CALL_OPTIONS, context.getUserId());
2851             option = (option != null) ? option : Settings.System.SIP_ADDRESS_ONLY;
2852             return option.equals(Settings.System.SIP_ALWAYS);
2853         }
2854     };
2855 
2856     @VisibleForTesting
2857     public static final XmlSerialization<PhoneAccountHandle> sPhoneAccountHandleXml =
2858             new XmlSerialization<PhoneAccountHandle>() {
2859         private static final String CLASS_PHONE_ACCOUNT_HANDLE = "phone_account_handle";
2860         private static final String COMPONENT_NAME = "component_name";
2861         private static final String ID = "id";
2862         private static final String USER_SERIAL_NUMBER = "user_serial_number";
2863 
2864         @Override
2865         public void writeToXml(PhoneAccountHandle o, XmlSerializer serializer, Context context,
2866                 FeatureFlags telephonyFeatureFlags) throws IOException {
2867             if (o != null) {
2868                 serializer.startTag(null, CLASS_PHONE_ACCOUNT_HANDLE);
2869 
2870                 if (o.getComponentName() != null) {
2871                     writeTextIfNonNull(
2872                             COMPONENT_NAME, o.getComponentName().flattenToString(), serializer);
2873                 }
2874 
2875                 writeTextIfNonNull(ID, o.getId(), serializer);
2876 
2877                 if (o.getUserHandle() != null && context != null) {
2878                     UserManager userManager = context.getSystemService(UserManager.class);
2879                     writeLong(USER_SERIAL_NUMBER,
2880                             userManager.getSerialNumberForUser(o.getUserHandle()), serializer);
2881                 }
2882 
2883                 serializer.endTag(null, CLASS_PHONE_ACCOUNT_HANDLE);
2884             }
2885         }
2886 
2887         @Override
2888         public PhoneAccountHandle readFromXml(XmlPullParser parser, int version, Context context,
2889                 FeatureFlags telephonyFeatureFlags,
2890                 com.android.server.telecom.flags.FeatureFlags telecomFeatureFlags)
2891                 throws IOException, XmlPullParserException {
2892             if (parser.getName().equals(CLASS_PHONE_ACCOUNT_HANDLE)) {
2893                 String componentNameString = null;
2894                 String idString = null;
2895                 String userSerialNumberString = null;
2896                 int outerDepth = parser.getDepth();
2897 
2898                 UserManager userManager = context.getSystemService(UserManager.class);
2899 
2900                 while (XmlUtils.nextElementWithin(parser, outerDepth)) {
2901                     if (parser.getName().equals(COMPONENT_NAME)) {
2902                         parser.next();
2903                         componentNameString = parser.getText();
2904                     } else if (parser.getName().equals(ID)) {
2905                         parser.next();
2906                         idString = parser.getText();
2907                     } else if (parser.getName().equals(USER_SERIAL_NUMBER)) {
2908                         parser.next();
2909                         userSerialNumberString = parser.getText();
2910                     }
2911                 }
2912                 if (componentNameString != null) {
2913                     UserHandle userHandle = null;
2914                     if (userSerialNumberString != null) {
2915                         try {
2916                             long serialNumber = Long.parseLong(userSerialNumberString);
2917                             userHandle = userManager.getUserForSerialNumber(serialNumber);
2918                         } catch (NumberFormatException e) {
2919                             Log.e(this, e, "Could not parse UserHandle " + userSerialNumberString);
2920                         }
2921                     }
2922                     return new PhoneAccountHandle(
2923                             ComponentName.unflattenFromString(componentNameString),
2924                             idString,
2925                             userHandle);
2926                 }
2927             }
2928             return null;
2929         }
2930     };
2931 }
2932