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