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