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