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