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