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