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