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