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.services.telephony; 18 19 import android.content.ComponentName; 20 import android.content.Context; 21 import android.content.res.Resources; 22 import android.graphics.Bitmap; 23 import android.graphics.Canvas; 24 import android.graphics.PorterDuff; 25 import android.graphics.drawable.Drawable; 26 import android.graphics.drawable.Icon; 27 import android.net.Uri; 28 import android.os.Bundle; 29 import android.os.PersistableBundle; 30 import android.os.ServiceManager; 31 import android.telecom.PhoneAccount; 32 import android.telecom.PhoneAccountHandle; 33 import android.telecom.TelecomManager; 34 import android.telephony.CarrierConfigManager; 35 import android.telephony.PhoneStateListener; 36 import android.telephony.ServiceState; 37 import android.telephony.SubscriptionInfo; 38 import android.telephony.SubscriptionManager; 39 import android.telephony.SubscriptionManager.OnSubscriptionsChangedListener; 40 import android.telephony.TelephonyManager; 41 import android.text.TextUtils; 42 43 import com.android.internal.telephony.IPhoneSubInfo; 44 import com.android.internal.telephony.Phone; 45 import com.android.internal.telephony.PhoneFactory; 46 import com.android.phone.PhoneGlobals; 47 import com.android.phone.PhoneUtils; 48 import com.android.phone.R; 49 50 import java.util.Arrays; 51 import java.util.LinkedList; 52 import java.util.List; 53 54 /** 55 * Owns all data we have registered with Telecom including handling dynamic addition and 56 * removal of SIMs and SIP accounts. 57 */ 58 final class TelecomAccountRegistry { 59 private static final boolean DBG = false; /* STOP SHIP if true */ 60 61 // This icon is the one that is used when the Slot ID that we have for a particular SIM 62 // is not supported, i.e. SubscriptionManager.INVALID_SLOT_ID or the 5th SIM in a phone. 63 private final static int DEFAULT_SIM_ICON = R.drawable.ic_multi_sim; 64 65 final class AccountEntry implements PstnPhoneCapabilitiesNotifier.Listener { 66 private final Phone mPhone; 67 private final PhoneAccount mAccount; 68 private final PstnIncomingCallNotifier mIncomingCallNotifier; 69 private final PstnPhoneCapabilitiesNotifier mPhoneCapabilitiesNotifier; 70 private boolean mIsVideoCapable; 71 private boolean mIsVideoPresenceSupported; 72 private boolean mIsVideoPauseSupported; 73 private boolean mIsMergeCallSupported; 74 AccountEntry(Phone phone, boolean isEmergency, boolean isDummy)75 AccountEntry(Phone phone, boolean isEmergency, boolean isDummy) { 76 mPhone = phone; 77 mAccount = registerPstnPhoneAccount(isEmergency, isDummy); 78 Log.i(this, "Registered phoneAccount: %s with handle: %s", 79 mAccount, mAccount.getAccountHandle()); 80 mIncomingCallNotifier = new PstnIncomingCallNotifier((Phone) mPhone); 81 mPhoneCapabilitiesNotifier = new PstnPhoneCapabilitiesNotifier((Phone) mPhone, 82 this); 83 } 84 teardown()85 void teardown() { 86 mIncomingCallNotifier.teardown(); 87 mPhoneCapabilitiesNotifier.teardown(); 88 } 89 90 /** 91 * Registers the specified account with Telecom as a PhoneAccountHandle. 92 */ registerPstnPhoneAccount(boolean isEmergency, boolean isDummyAccount)93 private PhoneAccount registerPstnPhoneAccount(boolean isEmergency, boolean isDummyAccount) { 94 String dummyPrefix = isDummyAccount ? "Dummy " : ""; 95 96 // Build the Phone account handle. 97 PhoneAccountHandle phoneAccountHandle = 98 PhoneUtils.makePstnPhoneAccountHandleWithPrefix( 99 mPhone, dummyPrefix, isEmergency); 100 101 // Populate the phone account data. 102 int subId = mPhone.getSubId(); 103 int color = PhoneAccount.NO_HIGHLIGHT_COLOR; 104 int slotId = SubscriptionManager.INVALID_SIM_SLOT_INDEX; 105 String line1Number = mTelephonyManager.getLine1Number(subId); 106 if (line1Number == null) { 107 line1Number = ""; 108 } 109 String subNumber = mPhone.getLine1Number(); 110 if (subNumber == null) { 111 subNumber = ""; 112 } 113 114 String label; 115 String description; 116 Icon icon = null; 117 118 // We can only get the real slotId from the SubInfoRecord, we can't calculate the 119 // slotId from the subId or the phoneId in all instances. 120 SubscriptionInfo record = 121 mSubscriptionManager.getActiveSubscriptionInfo(subId); 122 123 if (isEmergency) { 124 label = mContext.getResources().getString(R.string.sim_label_emergency_calls); 125 description = 126 mContext.getResources().getString(R.string.sim_description_emergency_calls); 127 } else if (mTelephonyManager.getPhoneCount() == 1) { 128 // For single-SIM devices, we show the label and description as whatever the name of 129 // the network is. 130 description = label = mTelephonyManager.getNetworkOperatorName(); 131 } else { 132 CharSequence subDisplayName = null; 133 134 if (record != null) { 135 subDisplayName = record.getDisplayName(); 136 slotId = record.getSimSlotIndex(); 137 color = record.getIconTint(); 138 icon = Icon.createWithBitmap(record.createIconBitmap(mContext)); 139 } 140 141 String slotIdString; 142 if (SubscriptionManager.isValidSlotId(slotId)) { 143 slotIdString = Integer.toString(slotId); 144 } else { 145 slotIdString = mContext.getResources().getString(R.string.unknown); 146 } 147 148 if (TextUtils.isEmpty(subDisplayName)) { 149 // Either the sub record is not there or it has an empty display name. 150 Log.w(this, "Could not get a display name for subid: %d", subId); 151 subDisplayName = mContext.getResources().getString( 152 R.string.sim_description_default, slotIdString); 153 } 154 155 // The label is user-visible so let's use the display name that the user may 156 // have set in Settings->Sim cards. 157 label = dummyPrefix + subDisplayName; 158 description = dummyPrefix + mContext.getResources().getString( 159 R.string.sim_description_default, slotIdString); 160 } 161 162 // By default all SIM phone accounts can place emergency calls. 163 int capabilities = PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION | 164 PhoneAccount.CAPABILITY_CALL_PROVIDER | 165 PhoneAccount.CAPABILITY_MULTI_USER; 166 167 if (mContext.getResources().getBoolean(R.bool.config_pstnCanPlaceEmergencyCalls)) { 168 capabilities |= PhoneAccount.CAPABILITY_PLACE_EMERGENCY_CALLS; 169 } 170 171 mIsVideoCapable = mPhone.isVideoEnabled(); 172 if (mIsVideoCapable) { 173 capabilities |= PhoneAccount.CAPABILITY_VIDEO_CALLING; 174 } 175 176 mIsVideoPresenceSupported = isCarrierVideoPresenceSupported(); 177 if (mIsVideoCapable && mIsVideoPresenceSupported) { 178 capabilities |= PhoneAccount.CAPABILITY_VIDEO_CALLING_RELIES_ON_PRESENCE; 179 } 180 181 if (mIsVideoCapable && isCarrierEmergencyVideoCallsAllowed()) { 182 capabilities |= PhoneAccount.CAPABILITY_EMERGENCY_VIDEO_CALLING; 183 } 184 185 mIsVideoPauseSupported = isCarrierVideoPauseSupported(); 186 Bundle instantLetteringExtras = null; 187 if (isCarrierInstantLetteringSupported()) { 188 capabilities |= PhoneAccount.CAPABILITY_CALL_SUBJECT; 189 instantLetteringExtras = getPhoneAccountExtras(); 190 } 191 mIsMergeCallSupported = isCarrierMergeCallSupported(); 192 193 if (isEmergency && mContext.getResources().getBoolean( 194 R.bool.config_emergency_account_emergency_calls_only)) { 195 capabilities |= PhoneAccount.CAPABILITY_EMERGENCY_CALLS_ONLY; 196 } 197 198 if (icon == null) { 199 // TODO: Switch to using Icon.createWithResource() once that supports tinting. 200 Resources res = mContext.getResources(); 201 Drawable drawable = res.getDrawable(DEFAULT_SIM_ICON, null); 202 drawable.setTint(res.getColor(R.color.default_sim_icon_tint_color, null)); 203 drawable.setTintMode(PorterDuff.Mode.SRC_ATOP); 204 205 int width = drawable.getIntrinsicWidth(); 206 int height = drawable.getIntrinsicHeight(); 207 Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); 208 Canvas canvas = new Canvas(bitmap); 209 drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight()); 210 drawable.draw(canvas); 211 212 icon = Icon.createWithBitmap(bitmap); 213 } 214 215 PhoneAccount account = PhoneAccount.builder(phoneAccountHandle, label) 216 .setAddress(Uri.fromParts(PhoneAccount.SCHEME_TEL, line1Number, null)) 217 .setSubscriptionAddress( 218 Uri.fromParts(PhoneAccount.SCHEME_TEL, subNumber, null)) 219 .setCapabilities(capabilities) 220 .setIcon(icon) 221 .setHighlightColor(color) 222 .setShortDescription(description) 223 .setSupportedUriSchemes(Arrays.asList( 224 PhoneAccount.SCHEME_TEL, PhoneAccount.SCHEME_VOICEMAIL)) 225 .setExtras(instantLetteringExtras) 226 .build(); 227 228 // Register with Telecom and put into the account entry. 229 mTelecomManager.registerPhoneAccount(account); 230 231 return account; 232 } 233 getPhoneAccountHandle()234 public PhoneAccountHandle getPhoneAccountHandle() { 235 return mAccount != null ? mAccount.getAccountHandle() : null; 236 } 237 238 /** 239 * Determines from carrier configuration whether pausing of IMS video calls is supported. 240 * 241 * @return {@code true} if pausing IMS video calls is supported. 242 */ isCarrierVideoPauseSupported()243 private boolean isCarrierVideoPauseSupported() { 244 // Check if IMS video pause is supported. 245 PersistableBundle b = 246 PhoneGlobals.getInstance().getCarrierConfigForSubId(mPhone.getSubId()); 247 return b.getBoolean(CarrierConfigManager.KEY_SUPPORT_PAUSE_IMS_VIDEO_CALLS_BOOL); 248 } 249 250 /** 251 * Determines from carrier configuration whether RCS presence indication for video calls is 252 * supported. 253 * 254 * @return {@code true} if RCS presence indication for video calls is supported. 255 */ isCarrierVideoPresenceSupported()256 private boolean isCarrierVideoPresenceSupported() { 257 PersistableBundle b = 258 PhoneGlobals.getInstance().getCarrierConfigForSubId(mPhone.getSubId()); 259 return b.getBoolean(CarrierConfigManager.KEY_USE_RCS_PRESENCE_BOOL); 260 } 261 262 /** 263 * Determines from carrier config whether instant lettering is supported. 264 * 265 * @return {@code true} if instant lettering is supported, {@code false} otherwise. 266 */ isCarrierInstantLetteringSupported()267 private boolean isCarrierInstantLetteringSupported() { 268 PersistableBundle b = 269 PhoneGlobals.getInstance().getCarrierConfigForSubId(mPhone.getSubId()); 270 return b.getBoolean(CarrierConfigManager.KEY_CARRIER_INSTANT_LETTERING_AVAILABLE_BOOL); 271 } 272 273 /** 274 * Determines from carrier config whether merging calls is supported. 275 * 276 * @return {@code true} if merging calls is supported, {@code false} otherwise. 277 */ isCarrierMergeCallSupported()278 private boolean isCarrierMergeCallSupported() { 279 PersistableBundle b = 280 PhoneGlobals.getInstance().getCarrierConfigForSubId(mPhone.getSubId()); 281 return b.getBoolean(CarrierConfigManager.KEY_SUPPORT_CONFERENCE_CALL_BOOL); 282 } 283 284 /** 285 * Determines from carrier config whether emergency video calls are supported. 286 * 287 * @return {@code true} if emergency video calls are allowed, {@code false} otherwise. 288 */ isCarrierEmergencyVideoCallsAllowed()289 private boolean isCarrierEmergencyVideoCallsAllowed() { 290 PersistableBundle b = 291 PhoneGlobals.getInstance().getCarrierConfigForSubId(mPhone.getSubId()); 292 return b.getBoolean(CarrierConfigManager.KEY_ALLOW_EMERGENCY_VIDEO_CALLS_BOOL); 293 } 294 295 /** 296 * @return The {@linke PhoneAccount} extras associated with the current subscription. 297 */ getPhoneAccountExtras()298 private Bundle getPhoneAccountExtras() { 299 PersistableBundle b = 300 PhoneGlobals.getInstance().getCarrierConfigForSubId(mPhone.getSubId()); 301 302 int instantLetteringMaxLength = b.getInt( 303 CarrierConfigManager.KEY_CARRIER_INSTANT_LETTERING_LENGTH_LIMIT_INT); 304 String instantLetteringEncoding = b.getString( 305 CarrierConfigManager.KEY_CARRIER_INSTANT_LETTERING_ENCODING_STRING); 306 307 Bundle phoneAccountExtras = new Bundle(); 308 phoneAccountExtras.putInt(PhoneAccount.EXTRA_CALL_SUBJECT_MAX_LENGTH, 309 instantLetteringMaxLength); 310 phoneAccountExtras.putString(PhoneAccount.EXTRA_CALL_SUBJECT_CHARACTER_ENCODING, 311 instantLetteringEncoding); 312 return phoneAccountExtras; 313 } 314 315 /** 316 * Receives callback from {@link PstnPhoneCapabilitiesNotifier} when the video capabilities 317 * have changed. 318 * 319 * @param isVideoCapable {@code true} if video is capable. 320 */ 321 @Override onVideoCapabilitiesChanged(boolean isVideoCapable)322 public void onVideoCapabilitiesChanged(boolean isVideoCapable) { 323 mIsVideoCapable = isVideoCapable; 324 } 325 326 /** 327 * Indicates whether this account supports pausing video calls. 328 * @return {@code true} if the account supports pausing video calls, {@code false} 329 * otherwise. 330 */ isVideoPauseSupported()331 public boolean isVideoPauseSupported() { 332 return mIsVideoCapable && mIsVideoPauseSupported; 333 } 334 335 /** 336 * Indicates whether this account supports merging calls (i.e. conferencing). 337 * @return {@code true} if the account supports merging calls, {@code false} otherwise. 338 */ isMergeCallSupported()339 public boolean isMergeCallSupported() { 340 return mIsMergeCallSupported; 341 } 342 } 343 344 private OnSubscriptionsChangedListener mOnSubscriptionsChangedListener = 345 new OnSubscriptionsChangedListener() { 346 @Override 347 public void onSubscriptionsChanged() { 348 // Any time the SubscriptionInfo changes...rerun the setup 349 tearDownAccounts(); 350 setupAccounts(); 351 } 352 }; 353 354 private final PhoneStateListener mPhoneStateListener = new PhoneStateListener() { 355 @Override 356 public void onServiceStateChanged(ServiceState serviceState) { 357 int newState = serviceState.getState(); 358 if (newState == ServiceState.STATE_IN_SERVICE && mServiceState != newState) { 359 tearDownAccounts(); 360 setupAccounts(); 361 } 362 mServiceState = newState; 363 } 364 }; 365 366 private static TelecomAccountRegistry sInstance; 367 private final Context mContext; 368 private final TelecomManager mTelecomManager; 369 private final TelephonyManager mTelephonyManager; 370 private final SubscriptionManager mSubscriptionManager; 371 private List<AccountEntry> mAccounts = new LinkedList<AccountEntry>(); 372 private int mServiceState = ServiceState.STATE_POWER_OFF; 373 374 // TODO: Remove back-pointer from app singleton to Service, since this is not a preferred 375 // pattern; redesign. This was added to fix a late release bug. 376 private TelephonyConnectionService mTelephonyConnectionService; 377 TelecomAccountRegistry(Context context)378 TelecomAccountRegistry(Context context) { 379 mContext = context; 380 mTelecomManager = TelecomManager.from(context); 381 mTelephonyManager = TelephonyManager.from(context); 382 mSubscriptionManager = SubscriptionManager.from(context); 383 } 384 getInstance(Context context)385 static synchronized final TelecomAccountRegistry getInstance(Context context) { 386 if (sInstance == null && context != null) { 387 sInstance = new TelecomAccountRegistry(context); 388 } 389 return sInstance; 390 } 391 setTelephonyConnectionService(TelephonyConnectionService telephonyConnectionService)392 void setTelephonyConnectionService(TelephonyConnectionService telephonyConnectionService) { 393 this.mTelephonyConnectionService = telephonyConnectionService; 394 } 395 getTelephonyConnectionService()396 TelephonyConnectionService getTelephonyConnectionService() { 397 return mTelephonyConnectionService; 398 } 399 400 /** 401 * Determines if the {@link AccountEntry} associated with a {@link PhoneAccountHandle} supports 402 * pausing video calls. 403 * 404 * @param handle The {@link PhoneAccountHandle}. 405 * @return {@code True} if video pausing is supported. 406 */ isVideoPauseSupported(PhoneAccountHandle handle)407 boolean isVideoPauseSupported(PhoneAccountHandle handle) { 408 for (AccountEntry entry : mAccounts) { 409 if (entry.getPhoneAccountHandle().equals(handle)) { 410 return entry.isVideoPauseSupported(); 411 } 412 } 413 return false; 414 } 415 416 /** 417 * Determines if the {@link AccountEntry} associated with a {@link PhoneAccountHandle} supports 418 * merging calls. 419 * 420 * @param handle The {@link PhoneAccountHandle}. 421 * @return {@code True} if merging calls is supported. 422 */ isMergeCallSupported(PhoneAccountHandle handle)423 boolean isMergeCallSupported(PhoneAccountHandle handle) { 424 for (AccountEntry entry : mAccounts) { 425 if (entry.getPhoneAccountHandle().equals(handle)) { 426 return entry.isMergeCallSupported(); 427 } 428 } 429 return false; 430 } 431 432 /** 433 * @return Reference to the {@code TelecomAccountRegistry}'s subscription manager. 434 */ getSubscriptionManager()435 SubscriptionManager getSubscriptionManager() { 436 return mSubscriptionManager; 437 } 438 439 /** 440 * Returns the address (e.g. the phone number) associated with a subscription. 441 * 442 * @param handle The phone account handle to find the subscription address for. 443 * @return The address. 444 */ getAddress(PhoneAccountHandle handle)445 Uri getAddress(PhoneAccountHandle handle) { 446 for (AccountEntry entry : mAccounts) { 447 if (entry.getPhoneAccountHandle().equals(handle)) { 448 return entry.mAccount.getAddress(); 449 } 450 } 451 return null; 452 } 453 454 /** 455 * Sets up all the phone accounts for SIMs on first boot. 456 */ setupOnBoot()457 void setupOnBoot() { 458 // TODO: When this object "finishes" we should unregister by invoking 459 // SubscriptionManager.getInstance(mContext).unregister(mOnSubscriptionsChangedListener); 460 // This is not strictly necessary because it will be unregistered if the 461 // notification fails but it is good form. 462 463 // Register for SubscriptionInfo list changes which is guaranteed 464 // to invoke onSubscriptionsChanged the first time. 465 SubscriptionManager.from(mContext).addOnSubscriptionsChangedListener( 466 mOnSubscriptionsChangedListener); 467 468 // We also need to listen for changes to the service state (e.g. emergency -> in service) 469 // because this could signal a removal or addition of a SIM in a single SIM phone. 470 mTelephonyManager.listen(mPhoneStateListener, PhoneStateListener.LISTEN_SERVICE_STATE); 471 } 472 473 /** 474 * Determines if the list of {@link AccountEntry}(s) contains an {@link AccountEntry} with a 475 * specified {@link PhoneAccountHandle}. 476 * 477 * @param handle The {@link PhoneAccountHandle}. 478 * @return {@code True} if an entry exists. 479 */ hasAccountEntryForPhoneAccount(PhoneAccountHandle handle)480 boolean hasAccountEntryForPhoneAccount(PhoneAccountHandle handle) { 481 for (AccountEntry entry : mAccounts) { 482 if (entry.getPhoneAccountHandle().equals(handle)) { 483 return true; 484 } 485 } 486 return false; 487 } 488 489 /** 490 * Un-registers any {@link PhoneAccount}s which are no longer present in the list 491 * {@code AccountEntry}(s). 492 */ cleanupPhoneAccounts()493 private void cleanupPhoneAccounts() { 494 ComponentName telephonyComponentName = 495 new ComponentName(mContext, TelephonyConnectionService.class); 496 // This config indicates whether the emergency account was flagged as emergency calls only 497 // in which case we need to consider all phone accounts, not just the call capable ones. 498 final boolean emergencyCallsOnlyEmergencyAccount = mContext.getResources().getBoolean( 499 R.bool.config_emergency_account_emergency_calls_only); 500 List<PhoneAccountHandle> accountHandles = emergencyCallsOnlyEmergencyAccount 501 ? mTelecomManager.getAllPhoneAccountHandles() 502 : mTelecomManager.getCallCapablePhoneAccounts(true /* includeDisabled */); 503 504 for (PhoneAccountHandle handle : accountHandles) { 505 if (telephonyComponentName.equals(handle.getComponentName()) && 506 !hasAccountEntryForPhoneAccount(handle)) { 507 Log.i(this, "Unregistering phone account %s.", handle); 508 mTelecomManager.unregisterPhoneAccount(handle); 509 } 510 } 511 } 512 setupAccounts()513 private void setupAccounts() { 514 // Go through SIM-based phones and register ourselves -- registering an existing account 515 // will cause the existing entry to be replaced. 516 Phone[] phones = PhoneFactory.getPhones(); 517 Log.d(this, "Found %d phones. Attempting to register.", phones.length); 518 519 final boolean phoneAccountsEnabled = mContext.getResources().getBoolean( 520 R.bool.config_pstn_phone_accounts_enabled); 521 522 if (phoneAccountsEnabled) { 523 for (Phone phone : phones) { 524 int subscriptionId = phone.getSubId(); 525 Log.d(this, "Phone with subscription id %d", subscriptionId); 526 if (subscriptionId >= 0) { 527 mAccounts.add(new AccountEntry(phone, false /* emergency */, 528 false /* isDummy */)); 529 } 530 } 531 } 532 533 // If we did not list ANY accounts, we need to provide a "default" SIM account 534 // for emergency numbers since no actual SIM is needed for dialing emergency 535 // numbers but a phone account is. 536 if (mAccounts.isEmpty()) { 537 mAccounts.add(new AccountEntry(PhoneFactory.getDefaultPhone(), true /* emergency */, 538 false /* isDummy */)); 539 } 540 541 // Add a fake account entry. 542 if (DBG && phones.length > 0 && "TRUE".equals(System.getProperty("dummy_sim"))) { 543 mAccounts.add(new AccountEntry(phones[0], false /* emergency */, true /* isDummy */)); 544 } 545 546 // Clean up any PhoneAccounts that are no longer relevant 547 cleanupPhoneAccounts(); 548 549 // At some point, the phone account ID was switched from the subId to the iccId. 550 // If there is a default account, check if this is the case, and upgrade the default account 551 // from using the subId to iccId if so. 552 PhoneAccountHandle defaultPhoneAccount = 553 mTelecomManager.getUserSelectedOutgoingPhoneAccount(); 554 ComponentName telephonyComponentName = 555 new ComponentName(mContext, TelephonyConnectionService.class); 556 557 if (defaultPhoneAccount != null && 558 telephonyComponentName.equals(defaultPhoneAccount.getComponentName()) && 559 !hasAccountEntryForPhoneAccount(defaultPhoneAccount)) { 560 561 String phoneAccountId = defaultPhoneAccount.getId(); 562 if (!TextUtils.isEmpty(phoneAccountId) && TextUtils.isDigitsOnly(phoneAccountId)) { 563 PhoneAccountHandle upgradedPhoneAccount = 564 PhoneUtils.makePstnPhoneAccountHandle( 565 PhoneGlobals.getPhone(Integer.parseInt(phoneAccountId))); 566 567 if (hasAccountEntryForPhoneAccount(upgradedPhoneAccount)) { 568 mTelecomManager.setUserSelectedOutgoingPhoneAccount(upgradedPhoneAccount); 569 } 570 } 571 } 572 } 573 tearDownAccounts()574 private void tearDownAccounts() { 575 for (AccountEntry entry : mAccounts) { 576 entry.teardown(); 577 } 578 mAccounts.clear(); 579 } 580 } 581