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