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