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.BroadcastReceiver; 20 import android.content.ComponentName; 21 import android.content.Context; 22 import android.content.Intent; 23 import android.content.IntentFilter; 24 import android.content.pm.PackageManager; 25 import android.content.res.Resources; 26 import android.database.ContentObserver; 27 import android.graphics.Bitmap; 28 import android.graphics.Canvas; 29 import android.graphics.PorterDuff; 30 import android.graphics.drawable.Drawable; 31 import android.graphics.drawable.Icon; 32 import android.net.Uri; 33 import android.os.Bundle; 34 import android.os.Handler; 35 import android.os.Looper; 36 import android.os.PersistableBundle; 37 import android.os.UserHandle; 38 import android.os.UserManager; 39 import android.provider.Settings; 40 import android.telecom.PhoneAccount; 41 import android.telecom.PhoneAccountHandle; 42 import android.telecom.TelecomManager; 43 import android.telephony.CarrierConfigManager; 44 import android.telephony.PhoneStateListener; 45 import android.telephony.ServiceState; 46 import android.telephony.SubscriptionInfo; 47 import android.telephony.SubscriptionManager; 48 import android.telephony.SubscriptionManager.OnSubscriptionsChangedListener; 49 import android.telephony.TelephonyManager; 50 import android.telephony.ims.ImsException; 51 import android.telephony.ims.ImsMmTelManager; 52 import android.telephony.ims.feature.MmTelFeature; 53 import android.telephony.ims.stub.ImsRegistrationImplBase; 54 import android.text.TextUtils; 55 56 import com.android.ims.ImsManager; 57 import com.android.internal.telephony.Phone; 58 import com.android.internal.telephony.PhoneFactory; 59 import com.android.internal.telephony.SubscriptionController; 60 import com.android.phone.PhoneGlobals; 61 import com.android.phone.PhoneUtils; 62 import com.android.phone.R; 63 64 import java.util.Arrays; 65 import java.util.LinkedList; 66 import java.util.List; 67 import java.util.Optional; 68 69 /** 70 * Owns all data we have registered with Telecom including handling dynamic addition and 71 * removal of SIMs and SIP accounts. 72 */ 73 public class TelecomAccountRegistry { 74 private static final boolean DBG = false; /* STOP SHIP if true */ 75 76 // This icon is the one that is used when the Slot ID that we have for a particular SIM 77 // is not supported, i.e. SubscriptionManager.INVALID_SLOT_ID or the 5th SIM in a phone. 78 private final static int DEFAULT_SIM_ICON = R.drawable.ic_multi_sim; 79 private final static String GROUP_PREFIX = "group_"; 80 81 final class AccountEntry implements PstnPhoneCapabilitiesNotifier.Listener { 82 private final Phone mPhone; 83 private PhoneAccount mAccount; 84 private final PstnIncomingCallNotifier mIncomingCallNotifier; 85 private final PstnPhoneCapabilitiesNotifier mPhoneCapabilitiesNotifier; 86 private boolean mIsEmergency; 87 private boolean mIsRttCapable; 88 private boolean mIsEmergencyPreferred; 89 private MmTelFeature.MmTelCapabilities mMmTelCapabilities; 90 private ImsMmTelManager.CapabilityCallback mMmtelCapabilityCallback; 91 private ImsMmTelManager mMmTelManager; 92 private final boolean mIsDummy; 93 private boolean mIsVideoCapable; 94 private boolean mIsVideoPresenceSupported; 95 private boolean mIsVideoPauseSupported; 96 private boolean mIsMergeCallSupported; 97 private boolean mIsMergeImsCallSupported; 98 private boolean mIsVideoConferencingSupported; 99 private boolean mIsMergeOfWifiCallsAllowedWhenVoWifiOff; 100 private boolean mIsManageImsConferenceCallSupported; 101 private boolean mIsUsingSimCallManager; 102 private boolean mIsShowPreciseFailedCause; 103 AccountEntry(Phone phone, boolean isEmergency, boolean isDummy)104 AccountEntry(Phone phone, boolean isEmergency, boolean isDummy) { 105 mPhone = phone; 106 mIsEmergency = isEmergency; 107 mIsDummy = isDummy; 108 mAccount = registerPstnPhoneAccount(isEmergency, isDummy); 109 Log.i(this, "Registered phoneAccount: %s with handle: %s", 110 mAccount, mAccount.getAccountHandle()); 111 mIncomingCallNotifier = new PstnIncomingCallNotifier((Phone) mPhone); 112 mPhoneCapabilitiesNotifier = new PstnPhoneCapabilitiesNotifier((Phone) mPhone, 113 this); 114 115 if (mIsDummy || isEmergency) { 116 // For dummy and emergency entries, there is no sub ID that can be assigned, so do 117 // not register for capabilities callbacks. 118 return; 119 } 120 121 try { 122 if (mPhone.getContext().getPackageManager().hasSystemFeature( 123 PackageManager.FEATURE_TELEPHONY_IMS)) { 124 mMmTelManager = ImsMmTelManager.createForSubscriptionId(getSubId()); 125 } 126 } catch (IllegalArgumentException e) { 127 Log.i(this, "Not registering MmTel capabilities listener because the subid '" 128 + getSubId() + "' is invalid: " + e.getMessage()); 129 return; 130 } 131 132 mMmtelCapabilityCallback = new ImsMmTelManager.CapabilityCallback() { 133 @Override 134 public void onCapabilitiesStatusChanged( 135 MmTelFeature.MmTelCapabilities capabilities) { 136 mMmTelCapabilities = capabilities; 137 updateRttCapability(); 138 } 139 }; 140 141 registerMmTelCapabilityCallback(); 142 } 143 teardown()144 void teardown() { 145 mIncomingCallNotifier.teardown(); 146 mPhoneCapabilitiesNotifier.teardown(); 147 if (mMmTelManager != null && mMmtelCapabilityCallback != null) { 148 mMmTelManager.unregisterMmTelCapabilityCallback(mMmtelCapabilityCallback); 149 } 150 } 151 registerMmTelCapabilityCallback()152 private void registerMmTelCapabilityCallback() { 153 if (mMmTelManager == null || mMmtelCapabilityCallback == null) { 154 // The subscription id associated with this account is invalid or not associated 155 // with a subscription. Do not register in this case. 156 return; 157 } 158 159 try { 160 mMmTelManager.registerMmTelCapabilityCallback(mContext.getMainExecutor(), 161 mMmtelCapabilityCallback); 162 } catch (ImsException e) { 163 Log.w(this, "registerMmTelCapabilityCallback: registration failed, no ImsService" 164 + " available. Exception: " + e.getMessage()); 165 return; 166 } catch (IllegalArgumentException e) { 167 Log.w(this, "registerMmTelCapabilityCallback: registration failed, invalid" 168 + " subscription, Exception" + e.getMessage()); 169 return; 170 } 171 } 172 173 /** 174 * Trigger re-registration of this account. 175 */ reRegisterPstnPhoneAccount()176 public void reRegisterPstnPhoneAccount() { 177 PhoneAccount newAccount = buildPstnPhoneAccount(mIsEmergency, mIsDummy); 178 if (!newAccount.equals(mAccount)) { 179 Log.i(this, "reRegisterPstnPhoneAccount: subId: " + getSubId() 180 + " - re-register due to account change."); 181 mTelecomManager.registerPhoneAccount(newAccount); 182 mAccount = newAccount; 183 } else { 184 Log.i(this, "reRegisterPstnPhoneAccount: subId: " + getSubId() + " - no change"); 185 } 186 } 187 registerPstnPhoneAccount(boolean isEmergency, boolean isDummyAccount)188 private PhoneAccount registerPstnPhoneAccount(boolean isEmergency, boolean isDummyAccount) { 189 PhoneAccount account = buildPstnPhoneAccount(mIsEmergency, mIsDummy); 190 // Register with Telecom and put into the account entry. 191 mTelecomManager.registerPhoneAccount(account); 192 return account; 193 } 194 195 /** 196 * Registers the specified account with Telecom as a PhoneAccountHandle. 197 */ buildPstnPhoneAccount(boolean isEmergency, boolean isDummyAccount)198 private PhoneAccount buildPstnPhoneAccount(boolean isEmergency, boolean isDummyAccount) { 199 String dummyPrefix = isDummyAccount ? "Dummy " : ""; 200 201 // Build the Phone account handle. 202 PhoneAccountHandle phoneAccountHandle = 203 PhoneUtils.makePstnPhoneAccountHandleWithPrefix( 204 mPhone, dummyPrefix, isEmergency); 205 206 // Populate the phone account data. 207 int subId = mPhone.getSubId(); 208 String subscriberId = mPhone.getSubscriberId(); 209 int color = PhoneAccount.NO_HIGHLIGHT_COLOR; 210 int slotId = SubscriptionManager.INVALID_SIM_SLOT_INDEX; 211 String line1Number = mTelephonyManager.getLine1Number(subId); 212 if (line1Number == null) { 213 line1Number = ""; 214 } 215 String subNumber = mPhone.getLine1Number(); 216 if (subNumber == null) { 217 subNumber = ""; 218 } 219 220 String label; 221 String description; 222 Icon icon = null; 223 224 // We can only get the real slotId from the SubInfoRecord, we can't calculate the 225 // slotId from the subId or the phoneId in all instances. 226 SubscriptionInfo record = 227 mSubscriptionManager.getActiveSubscriptionInfo(subId); 228 229 if (isEmergency) { 230 label = mContext.getResources().getString(R.string.sim_label_emergency_calls); 231 description = 232 mContext.getResources().getString(R.string.sim_description_emergency_calls); 233 } else if (mTelephonyManager.getPhoneCount() == 1) { 234 // For single-SIM devices, we show the label and description as whatever the name of 235 // the network is. 236 description = label = mTelephonyManager.getNetworkOperatorName(); 237 } else { 238 CharSequence subDisplayName = null; 239 240 if (record != null) { 241 subDisplayName = record.getDisplayName(); 242 slotId = record.getSimSlotIndex(); 243 color = record.getIconTint(); 244 icon = Icon.createWithBitmap(record.createIconBitmap(mContext)); 245 } 246 247 String slotIdString; 248 if (SubscriptionManager.isValidSlotIndex(slotId)) { 249 slotIdString = Integer.toString(slotId); 250 } else { 251 slotIdString = mContext.getResources().getString(R.string.unknown); 252 } 253 254 if (TextUtils.isEmpty(subDisplayName)) { 255 // Either the sub record is not there or it has an empty display name. 256 Log.w(this, "Could not get a display name for subid: %d", subId); 257 subDisplayName = mContext.getResources().getString( 258 R.string.sim_description_default, slotIdString); 259 } 260 261 // The label is user-visible so let's use the display name that the user may 262 // have set in Settings->Sim cards. 263 label = dummyPrefix + subDisplayName; 264 description = dummyPrefix + mContext.getResources().getString( 265 R.string.sim_description_default, slotIdString); 266 } 267 268 // By default all SIM phone accounts can place emergency calls. 269 int capabilities = PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION | 270 PhoneAccount.CAPABILITY_CALL_PROVIDER | 271 PhoneAccount.CAPABILITY_MULTI_USER; 272 273 if (mContext.getResources().getBoolean(R.bool.config_pstnCanPlaceEmergencyCalls)) { 274 capabilities |= PhoneAccount.CAPABILITY_PLACE_EMERGENCY_CALLS; 275 } 276 277 mIsEmergencyPreferred = isEmergencyPreferredAccount(subId, mActiveDataSubscriptionId); 278 if (mIsEmergencyPreferred) { 279 capabilities |= PhoneAccount.CAPABILITY_EMERGENCY_PREFERRED; 280 } 281 282 if (isRttCurrentlySupported()) { 283 capabilities |= PhoneAccount.CAPABILITY_RTT; 284 mIsRttCapable = true; 285 } else { 286 mIsRttCapable = false; 287 } 288 289 mIsVideoCapable = mPhone.isVideoEnabled() && !mIsRttCapable; 290 boolean isVideoEnabledByPlatform = ImsManager.getInstance(mPhone.getContext(), 291 mPhone.getPhoneId()).isVtEnabledByPlatform(); 292 293 if (!mIsPrimaryUser) { 294 Log.i(this, "Disabling video calling for secondary user."); 295 mIsVideoCapable = false; 296 isVideoEnabledByPlatform = false; 297 } 298 299 if (mIsVideoCapable) { 300 capabilities |= PhoneAccount.CAPABILITY_VIDEO_CALLING; 301 } 302 303 if (isVideoEnabledByPlatform) { 304 capabilities |= PhoneAccount.CAPABILITY_SUPPORTS_VIDEO_CALLING; 305 } 306 307 mIsVideoPresenceSupported = isCarrierVideoPresenceSupported(); 308 if (mIsVideoCapable && mIsVideoPresenceSupported) { 309 capabilities |= PhoneAccount.CAPABILITY_VIDEO_CALLING_RELIES_ON_PRESENCE; 310 } 311 312 if (mIsVideoCapable && isCarrierEmergencyVideoCallsAllowed()) { 313 capabilities |= PhoneAccount.CAPABILITY_EMERGENCY_VIDEO_CALLING; 314 } 315 316 mIsVideoPauseSupported = isCarrierVideoPauseSupported(); 317 Bundle extras = new Bundle(); 318 if (isCarrierInstantLetteringSupported()) { 319 capabilities |= PhoneAccount.CAPABILITY_CALL_SUBJECT; 320 extras.putAll(getPhoneAccountExtras()); 321 } 322 323 final boolean isHandoverFromSupported = mContext.getResources().getBoolean( 324 R.bool.config_support_handover_from); 325 if (isHandoverFromSupported && !isEmergency) { 326 // Only set the extra is handover is supported and this isn't the emergency-only 327 // acct. 328 extras.putBoolean(PhoneAccount.EXTRA_SUPPORTS_HANDOVER_FROM, 329 isHandoverFromSupported); 330 } 331 332 final boolean isTelephonyAudioDeviceSupported = mContext.getResources().getBoolean( 333 R.bool.config_support_telephony_audio_device); 334 if (isTelephonyAudioDeviceSupported && !isEmergency 335 && isCarrierUseCallRecordingTone()) { 336 extras.putBoolean(PhoneAccount.EXTRA_PLAY_CALL_RECORDING_TONE, true); 337 } 338 339 extras.putBoolean(PhoneAccount.EXTRA_SUPPORTS_VIDEO_CALLING_FALLBACK, 340 mContext.getResources() 341 .getBoolean(R.bool.config_support_video_calling_fallback)); 342 343 if (slotId != SubscriptionManager.INVALID_SIM_SLOT_INDEX) { 344 extras.putString(PhoneAccount.EXTRA_SORT_ORDER, 345 String.valueOf(slotId)); 346 } 347 348 mIsMergeCallSupported = isCarrierMergeCallSupported(); 349 mIsMergeImsCallSupported = isCarrierMergeImsCallSupported(); 350 mIsVideoConferencingSupported = isCarrierVideoConferencingSupported(); 351 mIsMergeOfWifiCallsAllowedWhenVoWifiOff = 352 isCarrierMergeOfWifiCallsAllowedWhenVoWifiOff(); 353 mIsManageImsConferenceCallSupported = isCarrierManageImsConferenceCallSupported(); 354 mIsUsingSimCallManager = isCarrierUsingSimCallManager(); 355 mIsShowPreciseFailedCause = isCarrierShowPreciseFailedCause(); 356 357 if (isEmergency && mContext.getResources().getBoolean( 358 R.bool.config_emergency_account_emergency_calls_only)) { 359 capabilities |= PhoneAccount.CAPABILITY_EMERGENCY_CALLS_ONLY; 360 } 361 362 if (icon == null) { 363 // TODO: Switch to using Icon.createWithResource() once that supports tinting. 364 Resources res = mContext.getResources(); 365 Drawable drawable = res.getDrawable(DEFAULT_SIM_ICON, null); 366 drawable.setTint(res.getColor(R.color.default_sim_icon_tint_color, null)); 367 drawable.setTintMode(PorterDuff.Mode.SRC_ATOP); 368 369 int width = drawable.getIntrinsicWidth(); 370 int height = drawable.getIntrinsicHeight(); 371 Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); 372 Canvas canvas = new Canvas(bitmap); 373 drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight()); 374 drawable.draw(canvas); 375 376 icon = Icon.createWithBitmap(bitmap); 377 } 378 379 // Check to see if the newly registered account should replace the old account. 380 String groupId = ""; 381 String[] mergedImsis = mTelephonyManager.getMergedSubscriberIds(); 382 boolean isMergedSim = false; 383 if (mergedImsis != null && subscriberId != null && !isEmergency) { 384 for (String imsi : mergedImsis) { 385 if (imsi.equals(subscriberId)) { 386 isMergedSim = true; 387 break; 388 } 389 } 390 } 391 if(isMergedSim) { 392 groupId = GROUP_PREFIX + line1Number; 393 Log.i(this, "Adding Merged Account with group: " + Log.pii(groupId)); 394 } 395 396 PhoneAccount account = PhoneAccount.builder(phoneAccountHandle, label) 397 .setAddress(Uri.fromParts(PhoneAccount.SCHEME_TEL, line1Number, null)) 398 .setSubscriptionAddress( 399 Uri.fromParts(PhoneAccount.SCHEME_TEL, subNumber, null)) 400 .setCapabilities(capabilities) 401 .setIcon(icon) 402 .setHighlightColor(color) 403 .setShortDescription(description) 404 .setSupportedUriSchemes(Arrays.asList( 405 PhoneAccount.SCHEME_TEL, PhoneAccount.SCHEME_VOICEMAIL)) 406 .setExtras(extras) 407 .setGroupId(groupId) 408 .build(); 409 410 return account; 411 } 412 getPhoneAccountHandle()413 public PhoneAccountHandle getPhoneAccountHandle() { 414 return mAccount != null ? mAccount.getAccountHandle() : null; 415 } 416 getSubId()417 public int getSubId() { 418 return mPhone.getSubId(); 419 } 420 421 /** 422 * In some cases, we need to try sending the emergency call over this PhoneAccount due to 423 * restrictions and limitations in MSIM configured devices. This includes the following: 424 * 1) The device does not support GNSS SUPL requests on the non-DDS subscription due to 425 * modem limitations. If the device does not support SUPL on non-DDS, we need to try the 426 * emergency call on the DDS subscription first to allow for SUPL to be completed. 427 * 428 * @return true if Telecom should prefer this PhoneAccount, false if there is no preference 429 * needed. 430 */ isEmergencyPreferredAccount(int subId, int activeDataSubId)431 private boolean isEmergencyPreferredAccount(int subId, int activeDataSubId) { 432 Log.d(this, "isEmergencyPreferredAccount: subId=" + subId + ", activeData=" 433 + activeDataSubId); 434 final boolean gnssSuplRequiresDefaultData = mContext.getResources().getBoolean( 435 R.bool.config_gnss_supl_requires_default_data_for_emergency); 436 if (!gnssSuplRequiresDefaultData) { 437 Log.d(this, "isEmergencyPreferredAccount: Device does not require preference."); 438 // No preference is necessary. 439 return false; 440 } 441 442 SubscriptionController controller = SubscriptionController.getInstance(); 443 if (controller == null) { 444 Log.d(this, "isEmergencyPreferredAccount: SubscriptionController not available."); 445 return false; 446 } 447 // Only set an emergency preference on devices with multiple active subscriptions 448 // (include opportunistic subscriptions) in this check. 449 // API says never null, but this can return null in testing. 450 int[] activeSubIds = controller.getActiveSubIdList(false); 451 if (activeSubIds == null || activeSubIds.length <= 1) { 452 Log.d(this, "isEmergencyPreferredAccount: one or less active subscriptions."); 453 return false; 454 } 455 // Check to see if this PhoneAccount is associated with the default Data subscription. 456 if (!SubscriptionManager.isValidSubscriptionId(subId)) { 457 Log.d(this, "isEmergencyPreferredAccount: provided subId " + subId + "is not " 458 + "valid."); 459 return false; 460 } 461 int userDefaultData = controller.getDefaultDataSubId(); 462 boolean isActiveDataValid = SubscriptionManager.isValidSubscriptionId(activeDataSubId); 463 boolean isActiveDataOpportunistic = isActiveDataValid 464 && controller.isOpportunistic(activeDataSubId); 465 // compare the activeDataSubId to the subId specified only if it is valid and not an 466 // opportunistic subscription (only supports data). If not, use the current default 467 // defined by the user. 468 Log.d(this, "isEmergencyPreferredAccount: userDefaultData=" + userDefaultData 469 + ", isActiveDataOppurtunistic=" + isActiveDataOpportunistic); 470 return subId == ((isActiveDataValid && !isActiveDataOpportunistic) ? activeDataSubId : 471 userDefaultData); 472 } 473 474 /** 475 * Determines from carrier configuration whether pausing of IMS video calls is supported. 476 * 477 * @return {@code true} if pausing IMS video calls is supported. 478 */ isCarrierVideoPauseSupported()479 private boolean isCarrierVideoPauseSupported() { 480 // Check if IMS video pause is supported. 481 PersistableBundle b = 482 PhoneGlobals.getInstance().getCarrierConfigForSubId(mPhone.getSubId()); 483 return b != null && 484 b.getBoolean(CarrierConfigManager.KEY_SUPPORT_PAUSE_IMS_VIDEO_CALLS_BOOL); 485 } 486 487 /** 488 * Determines from carrier configuration whether RCS presence indication for video calls is 489 * supported. 490 * 491 * @return {@code true} if RCS presence indication for video calls is supported. 492 */ isCarrierVideoPresenceSupported()493 private boolean isCarrierVideoPresenceSupported() { 494 PersistableBundle b = 495 PhoneGlobals.getInstance().getCarrierConfigForSubId(mPhone.getSubId()); 496 return b != null && 497 b.getBoolean(CarrierConfigManager.KEY_USE_RCS_PRESENCE_BOOL); 498 } 499 500 /** 501 * Determines from carrier config whether instant lettering is supported. 502 * 503 * @return {@code true} if instant lettering is supported, {@code false} otherwise. 504 */ isCarrierInstantLetteringSupported()505 private boolean isCarrierInstantLetteringSupported() { 506 PersistableBundle b = 507 PhoneGlobals.getInstance().getCarrierConfigForSubId(mPhone.getSubId()); 508 return b != null && 509 b.getBoolean(CarrierConfigManager.KEY_CARRIER_INSTANT_LETTERING_AVAILABLE_BOOL); 510 } 511 512 /** 513 * Determines from carrier config whether merging calls is supported. 514 * 515 * @return {@code true} if merging calls is supported, {@code false} otherwise. 516 */ isCarrierMergeCallSupported()517 private boolean isCarrierMergeCallSupported() { 518 PersistableBundle b = 519 PhoneGlobals.getInstance().getCarrierConfigForSubId(mPhone.getSubId()); 520 return b != null && 521 b.getBoolean(CarrierConfigManager.KEY_SUPPORT_CONFERENCE_CALL_BOOL); 522 } 523 524 /** 525 * Determines from carrier config whether merging IMS calls is supported. 526 * 527 * @return {@code true} if merging IMS calls is supported, {@code false} otherwise. 528 */ isCarrierMergeImsCallSupported()529 private boolean isCarrierMergeImsCallSupported() { 530 PersistableBundle b = 531 PhoneGlobals.getInstance().getCarrierConfigForSubId(mPhone.getSubId()); 532 return b.getBoolean(CarrierConfigManager.KEY_SUPPORT_IMS_CONFERENCE_CALL_BOOL); 533 } 534 535 /** 536 * Determines from carrier config whether emergency video calls are supported. 537 * 538 * @return {@code true} if emergency video calls are allowed, {@code false} otherwise. 539 */ isCarrierEmergencyVideoCallsAllowed()540 private boolean isCarrierEmergencyVideoCallsAllowed() { 541 PersistableBundle b = 542 PhoneGlobals.getInstance().getCarrierConfigForSubId(mPhone.getSubId()); 543 return b != null && 544 b.getBoolean(CarrierConfigManager.KEY_ALLOW_EMERGENCY_VIDEO_CALLS_BOOL); 545 } 546 547 /** 548 * Determines from carrier config whether video conferencing is supported. 549 * 550 * @return {@code true} if video conferencing is supported, {@code false} otherwise. 551 */ isCarrierVideoConferencingSupported()552 private boolean isCarrierVideoConferencingSupported() { 553 PersistableBundle b = 554 PhoneGlobals.getInstance().getCarrierConfigForSubId(mPhone.getSubId()); 555 return b != null && 556 b.getBoolean(CarrierConfigManager.KEY_SUPPORT_VIDEO_CONFERENCE_CALL_BOOL); 557 } 558 559 /** 560 * Determines from carrier config whether merging of wifi calls is allowed when VoWIFI is 561 * turned off. 562 * 563 * @return {@code true} merging of wifi calls when VoWIFI is disabled should be prevented, 564 * {@code false} otherwise. 565 */ isCarrierMergeOfWifiCallsAllowedWhenVoWifiOff()566 private boolean isCarrierMergeOfWifiCallsAllowedWhenVoWifiOff() { 567 PersistableBundle b = 568 PhoneGlobals.getInstance().getCarrierConfigForSubId(mPhone.getSubId()); 569 return b != null && b.getBoolean( 570 CarrierConfigManager.KEY_ALLOW_MERGE_WIFI_CALLS_WHEN_VOWIFI_OFF_BOOL); 571 } 572 573 /** 574 * Determines from carrier config whether managing IMS conference calls is supported. 575 * 576 * @return {@code true} if managing IMS conference calls is supported, 577 * {@code false} otherwise. 578 */ isCarrierManageImsConferenceCallSupported()579 private boolean isCarrierManageImsConferenceCallSupported() { 580 PersistableBundle b = 581 PhoneGlobals.getInstance().getCarrierConfigForSubId(mPhone.getSubId()); 582 return b.getBoolean(CarrierConfigManager.KEY_SUPPORT_MANAGE_IMS_CONFERENCE_CALL_BOOL); 583 } 584 585 /** 586 * Determines from carrier config whether the carrier uses a sim call manager. 587 * 588 * @return {@code true} if the carrier uses a sim call manager, 589 * {@code false} otherwise. 590 */ isCarrierUsingSimCallManager()591 private boolean isCarrierUsingSimCallManager() { 592 PersistableBundle b = 593 PhoneGlobals.getInstance().getCarrierConfigForSubId(mPhone.getSubId()); 594 return !TextUtils.isEmpty( 595 b.getString(CarrierConfigManager.KEY_DEFAULT_SIM_CALL_MANAGER_STRING)); 596 } 597 598 /** 599 * Determines from carrier config whether showing percise call diconnect cause to user 600 * is supported. 601 * 602 * @return {@code true} if showing percise call diconnect cause to user is supported, 603 * {@code false} otherwise. 604 */ isCarrierShowPreciseFailedCause()605 private boolean isCarrierShowPreciseFailedCause() { 606 PersistableBundle b = 607 PhoneGlobals.getInstance().getCarrierConfigForSubId(mPhone.getSubId()); 608 return b.getBoolean(CarrierConfigManager.KEY_SHOW_PRECISE_FAILED_CAUSE_BOOL); 609 } 610 611 /** 612 * Determines from carrier config whether the carrier requires the use of a call recording 613 * tone. 614 * 615 * @return {@code true} if a call recording tone should be used, {@code false} otherwise. 616 */ isCarrierUseCallRecordingTone()617 private boolean isCarrierUseCallRecordingTone() { 618 PersistableBundle b = 619 PhoneGlobals.getInstance().getCarrierConfigForSubId(mPhone.getSubId()); 620 return b.getBoolean(CarrierConfigManager.KEY_PLAY_CALL_RECORDING_TONE_BOOL); 621 } 622 623 /** 624 * Where a device supports instant lettering and call subjects, retrieves the necessary 625 * PhoneAccount extras for those features. 626 * 627 * @return The {@link PhoneAccount} extras associated with the current subscription. 628 */ getPhoneAccountExtras()629 private Bundle getPhoneAccountExtras() { 630 PersistableBundle b = 631 PhoneGlobals.getInstance().getCarrierConfigForSubId(mPhone.getSubId()); 632 633 int instantLetteringMaxLength = b.getInt( 634 CarrierConfigManager.KEY_CARRIER_INSTANT_LETTERING_LENGTH_LIMIT_INT); 635 String instantLetteringEncoding = b.getString( 636 CarrierConfigManager.KEY_CARRIER_INSTANT_LETTERING_ENCODING_STRING); 637 Bundle phoneAccountExtras = new Bundle(); 638 phoneAccountExtras.putInt(PhoneAccount.EXTRA_CALL_SUBJECT_MAX_LENGTH, 639 instantLetteringMaxLength); 640 phoneAccountExtras.putString(PhoneAccount.EXTRA_CALL_SUBJECT_CHARACTER_ENCODING, 641 instantLetteringEncoding); 642 return phoneAccountExtras; 643 } 644 645 /** 646 * Receives callback from {@link PstnPhoneCapabilitiesNotifier} when the video capabilities 647 * have changed. 648 * 649 * @param isVideoCapable {@code true} if video is capable. 650 */ 651 @Override onVideoCapabilitiesChanged(boolean isVideoCapable)652 public void onVideoCapabilitiesChanged(boolean isVideoCapable) { 653 mIsVideoCapable = isVideoCapable; 654 synchronized (mAccountsLock) { 655 if (!mAccounts.contains(this)) { 656 // Account has already been torn down, don't try to register it again. 657 // This handles the case where teardown has already happened, and we got a video 658 // update that lost the race for the mAccountsLock. In such a scenario by the 659 // time we get here, the original phone account could have been torn down. 660 return; 661 } 662 mAccount = registerPstnPhoneAccount(mIsEmergency, mIsDummy); 663 } 664 } 665 updateRttCapability()666 public void updateRttCapability() { 667 boolean isRttEnabled = isRttCurrentlySupported(); 668 if (isRttEnabled != mIsRttCapable) { 669 Log.i(this, "updateRttCapability - changed, new value: " + isRttEnabled); 670 mAccount = registerPstnPhoneAccount(mIsEmergency, mIsDummy); 671 } 672 } 673 updateDefaultDataSubId(int activeDataSubId)674 public void updateDefaultDataSubId(int activeDataSubId) { 675 boolean isEmergencyPreferred = isEmergencyPreferredAccount(mPhone.getSubId(), 676 activeDataSubId); 677 if (isEmergencyPreferred != mIsEmergencyPreferred) { 678 Log.i(this, "updateDefaultDataSubId - changed, new value: " + isEmergencyPreferred); 679 mAccount = registerPstnPhoneAccount(mIsEmergency, mIsDummy); 680 } 681 } 682 683 /** 684 * Determines whether RTT is supported given the current state of the 685 * device. 686 */ isRttCurrentlySupported()687 private boolean isRttCurrentlySupported() { 688 boolean hasVoiceAvailability = isImsVoiceAvailable(); 689 690 boolean isRttSupported = PhoneGlobals.getInstance().phoneMgr 691 .isRttEnabled(mPhone.getSubId()); 692 693 boolean isRoaming = mTelephonyManager.isNetworkRoaming(mPhone.getSubId()); 694 695 return hasVoiceAvailability && isRttSupported && !isRoaming; 696 } 697 698 /** 699 * Indicates whether this account supports pausing video calls. 700 * @return {@code true} if the account supports pausing video calls, {@code false} 701 * otherwise. 702 */ isVideoPauseSupported()703 public boolean isVideoPauseSupported() { 704 return mIsVideoCapable && mIsVideoPauseSupported; 705 } 706 707 /** 708 * Indicates whether this account supports merging calls (i.e. conferencing). 709 * @return {@code true} if the account supports merging calls, {@code false} otherwise. 710 */ isMergeCallSupported()711 public boolean isMergeCallSupported() { 712 return mIsMergeCallSupported; 713 } 714 715 /** 716 * Indicates whether this account supports merging IMS calls (i.e. conferencing). 717 * @return {@code true} if the account supports merging IMS calls, {@code false} otherwise. 718 */ isMergeImsCallSupported()719 public boolean isMergeImsCallSupported() { 720 return mIsMergeImsCallSupported; 721 } 722 723 /** 724 * Indicates whether this account supports video conferencing. 725 * @return {@code true} if the account supports video conferencing, {@code false} otherwise. 726 */ isVideoConferencingSupported()727 public boolean isVideoConferencingSupported() { 728 return mIsVideoConferencingSupported; 729 } 730 731 /** 732 * Indicate whether this account allow merging of wifi calls when VoWIFI is off. 733 * @return {@code true} if allowed, {@code false} otherwise. 734 */ isMergeOfWifiCallsAllowedWhenVoWifiOff()735 public boolean isMergeOfWifiCallsAllowedWhenVoWifiOff() { 736 return mIsMergeOfWifiCallsAllowedWhenVoWifiOff; 737 } 738 739 /** 740 * Indicates whether this account supports managing IMS conference calls 741 * @return {@code true} if the account supports managing IMS conference calls, 742 * {@code false} otherwise. 743 */ isManageImsConferenceCallSupported()744 public boolean isManageImsConferenceCallSupported() { 745 return mIsManageImsConferenceCallSupported; 746 } 747 748 /** 749 * Indicates whether this account uses a sim call manger. 750 * @return {@code true} if the account uses a sim call manager, 751 * {@code false} otherwise. 752 */ isUsingSimCallManager()753 public boolean isUsingSimCallManager() { 754 return mIsUsingSimCallManager; 755 } 756 757 /** 758 * Indicates whether this account supports showing the precise call disconnect cause 759 * to user (i.e. conferencing). 760 * @return {@code true} if the account supports showing the precise call disconnect cause, 761 * {@code false} otherwise. 762 */ isShowPreciseFailedCause()763 public boolean isShowPreciseFailedCause() { 764 return mIsShowPreciseFailedCause; 765 } 766 isImsVoiceAvailable()767 private boolean isImsVoiceAvailable() { 768 if (mMmTelCapabilities != null) { 769 return mMmTelCapabilities.isCapable( 770 MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VOICE); 771 } 772 773 if (mMmTelManager == null) { 774 // The Subscription is invalid, so IMS is unavailable. 775 return false; 776 } 777 778 // In the rare case that mMmTelCapabilities hasn't been set, try fetching it 779 // directly and register callback. 780 registerMmTelCapabilityCallback(); 781 return mMmTelManager.isAvailable(ImsRegistrationImplBase.REGISTRATION_TECH_LTE, 782 MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VOICE) 783 || mMmTelManager.isAvailable(ImsRegistrationImplBase.REGISTRATION_TECH_IWLAN, 784 MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VOICE); 785 } 786 } 787 788 private OnSubscriptionsChangedListener mOnSubscriptionsChangedListener = 789 new OnSubscriptionsChangedListener() { 790 @Override 791 public void onSubscriptionsChanged() { 792 // Any time the SubscriptionInfo changes...rerun the setup 793 Log.i(this, "onSubscriptionsChanged - update accounts"); 794 tearDownAccounts(); 795 setupAccounts(); 796 } 797 }; 798 799 private final BroadcastReceiver mReceiver = new BroadcastReceiver() { 800 @Override 801 public void onReceive(Context context, Intent intent) { 802 if (Intent.ACTION_USER_SWITCHED.equals(intent.getAction())) { 803 Log.i(this, "User changed, re-registering phone accounts."); 804 805 int userHandleId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0); 806 UserHandle currentUserHandle = new UserHandle(userHandleId); 807 mIsPrimaryUser = UserManager.get(mContext).getPrimaryUser().getUserHandle() 808 .equals(currentUserHandle); 809 810 // Any time the user changes, re-register the accounts. 811 tearDownAccounts(); 812 setupAccounts(); 813 } else if (CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED.equals( 814 intent.getAction())) { 815 Log.i(this, "Carrier-config changed, checking for phone account updates."); 816 int subId = intent.getIntExtra(SubscriptionManager.EXTRA_SUBSCRIPTION_INDEX, 817 SubscriptionManager.INVALID_SUBSCRIPTION_ID); 818 handleCarrierConfigChange(subId); 819 } 820 } 821 }; 822 823 private final PhoneStateListener mPhoneStateListener = new PhoneStateListener() { 824 @Override 825 public void onServiceStateChanged(ServiceState serviceState) { 826 int newState = serviceState.getState(); 827 if (newState == ServiceState.STATE_IN_SERVICE && mServiceState != newState) { 828 tearDownAccounts(); 829 setupAccounts(); 830 } else { 831 synchronized (mAccountsLock) { 832 for (AccountEntry account : mAccounts) { 833 account.updateRttCapability(); 834 } 835 } 836 } 837 mServiceState = newState; 838 } 839 840 @Override 841 public void onActiveDataSubscriptionIdChanged(int subId) { 842 mActiveDataSubscriptionId = subId; 843 synchronized (mAccountsLock) { 844 for (AccountEntry account : mAccounts) { 845 account.updateDefaultDataSubId(mActiveDataSubscriptionId); 846 } 847 } 848 } 849 }; 850 851 private static TelecomAccountRegistry sInstance; 852 private final Context mContext; 853 private final TelecomManager mTelecomManager; 854 private final TelephonyManager mTelephonyManager; 855 private final SubscriptionManager mSubscriptionManager; 856 private List<AccountEntry> mAccounts = new LinkedList<AccountEntry>(); 857 private final Object mAccountsLock = new Object(); 858 private int mServiceState = ServiceState.STATE_POWER_OFF; 859 private int mActiveDataSubscriptionId = SubscriptionManager.INVALID_SUBSCRIPTION_ID; 860 private boolean mIsPrimaryUser = true; 861 862 // TODO: Remove back-pointer from app singleton to Service, since this is not a preferred 863 // pattern; redesign. This was added to fix a late release bug. 864 private TelephonyConnectionService mTelephonyConnectionService; 865 TelecomAccountRegistry(Context context)866 TelecomAccountRegistry(Context context) { 867 mContext = context; 868 mTelecomManager = TelecomManager.from(context); 869 mTelephonyManager = TelephonyManager.from(context); 870 mSubscriptionManager = SubscriptionManager.from(context); 871 } 872 873 /** 874 * Get the singleton instance. 875 */ getInstance(Context context)876 public static synchronized TelecomAccountRegistry getInstance(Context context) { 877 if (sInstance == null && context != null) { 878 sInstance = new TelecomAccountRegistry(context); 879 } 880 return sInstance; 881 } 882 setTelephonyConnectionService(TelephonyConnectionService telephonyConnectionService)883 void setTelephonyConnectionService(TelephonyConnectionService telephonyConnectionService) { 884 this.mTelephonyConnectionService = telephonyConnectionService; 885 } 886 getTelephonyConnectionService()887 TelephonyConnectionService getTelephonyConnectionService() { 888 return mTelephonyConnectionService; 889 } 890 891 /** 892 * Determines if the {@link AccountEntry} associated with a {@link PhoneAccountHandle} supports 893 * pausing video calls. 894 * 895 * @param handle The {@link PhoneAccountHandle}. 896 * @return {@code True} if video pausing is supported. 897 */ isVideoPauseSupported(PhoneAccountHandle handle)898 boolean isVideoPauseSupported(PhoneAccountHandle handle) { 899 synchronized (mAccountsLock) { 900 for (AccountEntry entry : mAccounts) { 901 if (entry.getPhoneAccountHandle().equals(handle)) { 902 return entry.isVideoPauseSupported(); 903 } 904 } 905 } 906 return false; 907 } 908 909 /** 910 * Determines if the {@link AccountEntry} associated with a {@link PhoneAccountHandle} supports 911 * merging calls. 912 * 913 * @param handle The {@link PhoneAccountHandle}. 914 * @return {@code True} if merging calls is supported. 915 */ isMergeCallSupported(PhoneAccountHandle handle)916 boolean isMergeCallSupported(PhoneAccountHandle handle) { 917 synchronized (mAccountsLock) { 918 for (AccountEntry entry : mAccounts) { 919 if (entry.getPhoneAccountHandle().equals(handle)) { 920 return entry.isMergeCallSupported(); 921 } 922 } 923 } 924 return false; 925 } 926 927 /** 928 * Determines if the {@link AccountEntry} associated with a {@link PhoneAccountHandle} supports 929 * video conferencing. 930 * 931 * @param handle The {@link PhoneAccountHandle}. 932 * @return {@code True} if video conferencing is supported. 933 */ isVideoConferencingSupported(PhoneAccountHandle handle)934 boolean isVideoConferencingSupported(PhoneAccountHandle handle) { 935 synchronized (mAccountsLock) { 936 for (AccountEntry entry : mAccounts) { 937 if (entry.getPhoneAccountHandle().equals(handle)) { 938 return entry.isVideoConferencingSupported(); 939 } 940 } 941 } 942 return false; 943 } 944 945 /** 946 * Determines if the {@link AccountEntry} associated with a {@link PhoneAccountHandle} allows 947 * merging of wifi calls when VoWIFI is disabled. 948 * 949 * @param handle The {@link PhoneAccountHandle}. 950 * @return {@code True} if merging of wifi calls is allowed when VoWIFI is disabled. 951 */ isMergeOfWifiCallsAllowedWhenVoWifiOff(final PhoneAccountHandle handle)952 boolean isMergeOfWifiCallsAllowedWhenVoWifiOff(final PhoneAccountHandle handle) { 953 synchronized (mAccountsLock) { 954 Optional<AccountEntry> result = mAccounts.stream().filter( 955 entry -> entry.getPhoneAccountHandle().equals(handle)).findFirst(); 956 957 if (result.isPresent()) { 958 return result.get().isMergeOfWifiCallsAllowedWhenVoWifiOff(); 959 } else { 960 return false; 961 } 962 } 963 } 964 965 /** 966 * Determines if the {@link AccountEntry} associated with a {@link PhoneAccountHandle} supports 967 * merging IMS calls. 968 * 969 * @param handle The {@link PhoneAccountHandle}. 970 * @return {@code True} if merging IMS calls is supported. 971 */ isMergeImsCallSupported(PhoneAccountHandle handle)972 boolean isMergeImsCallSupported(PhoneAccountHandle handle) { 973 synchronized (mAccountsLock) { 974 for (AccountEntry entry : mAccounts) { 975 if (entry.getPhoneAccountHandle().equals(handle)) { 976 return entry.isMergeImsCallSupported(); 977 } 978 } 979 } 980 return false; 981 } 982 983 /** 984 * Determines if the {@link AccountEntry} associated with a {@link PhoneAccountHandle} supports 985 * managing IMS conference calls. 986 * 987 * @param handle The {@link PhoneAccountHandle}. 988 * @return {@code True} if managing IMS conference calls is supported. 989 */ isManageImsConferenceCallSupported(PhoneAccountHandle handle)990 boolean isManageImsConferenceCallSupported(PhoneAccountHandle handle) { 991 synchronized (mAccountsLock) { 992 for (AccountEntry entry : mAccounts) { 993 if (entry.getPhoneAccountHandle().equals(handle)) { 994 return entry.isManageImsConferenceCallSupported(); 995 } 996 } 997 } 998 return false; 999 } 1000 1001 /** 1002 * showing precise call disconnect cause to the user. 1003 * 1004 * @param handle The {@link PhoneAccountHandle}. 1005 * @return {@code True} if showing precise call disconnect cause to the user is supported. 1006 */ isShowPreciseFailedCause(PhoneAccountHandle handle)1007 boolean isShowPreciseFailedCause(PhoneAccountHandle handle) { 1008 synchronized (mAccountsLock) { 1009 for (AccountEntry entry : mAccounts) { 1010 if (entry.getPhoneAccountHandle().equals(handle)) { 1011 return entry.isShowPreciseFailedCause(); 1012 } 1013 } 1014 } 1015 return false; 1016 } 1017 1018 /** 1019 * @return Reference to the {@code TelecomAccountRegistry}'s subscription manager. 1020 */ getSubscriptionManager()1021 SubscriptionManager getSubscriptionManager() { 1022 return mSubscriptionManager; 1023 } 1024 1025 /** 1026 * Returns the address (e.g. the phone number) associated with a subscription. 1027 * 1028 * @param handle The phone account handle to find the subscription address for. 1029 * @return The address. 1030 */ getAddress(PhoneAccountHandle handle)1031 public Uri getAddress(PhoneAccountHandle handle) { 1032 synchronized (mAccountsLock) { 1033 for (AccountEntry entry : mAccounts) { 1034 if (entry.getPhoneAccountHandle().equals(handle)) { 1035 return entry.mAccount.getAddress(); 1036 } 1037 } 1038 } 1039 return null; 1040 } 1041 1042 /** 1043 * Returns whethere a the subscription associated with a {@link PhoneAccountHandle} is using a 1044 * sim call manager. 1045 * 1046 * @param handle The phone account handle to find the subscription address for. 1047 * @return {@code true} if a sim call manager is in use, {@code false} otherwise. 1048 */ isUsingSimCallManager(PhoneAccountHandle handle)1049 public boolean isUsingSimCallManager(PhoneAccountHandle handle) { 1050 synchronized (mAccountsLock) { 1051 for (AccountEntry entry : mAccounts) { 1052 if (entry.getPhoneAccountHandle().equals(handle)) { 1053 return entry.isUsingSimCallManager(); 1054 } 1055 } 1056 } 1057 return false; 1058 } 1059 1060 /** 1061 * Sets up all the phone accounts for SIMs on first boot. 1062 */ setupOnBoot()1063 public void setupOnBoot() { 1064 // TODO: When this object "finishes" we should unregister by invoking 1065 // SubscriptionManager.getInstance(mContext).unregister(mOnSubscriptionsChangedListener); 1066 // This is not strictly necessary because it will be unregistered if the 1067 // notification fails but it is good form. 1068 1069 // Register for SubscriptionInfo list changes which is guaranteed 1070 // to invoke onSubscriptionsChanged the first time. 1071 SubscriptionManager.from(mContext).addOnSubscriptionsChangedListener( 1072 mOnSubscriptionsChangedListener); 1073 1074 // We also need to listen for changes to the service state (e.g. emergency -> in service) 1075 // because this could signal a removal or addition of a SIM in a single SIM phone. 1076 mTelephonyManager.listen(mPhoneStateListener, PhoneStateListener.LISTEN_SERVICE_STATE 1077 | PhoneStateListener.LISTEN_ACTIVE_DATA_SUBSCRIPTION_ID_CHANGE); 1078 1079 // Listen for user switches. When the user switches, we need to ensure that if the current 1080 // use is not the primary user we disable video calling. 1081 IntentFilter filter = new IntentFilter(); 1082 filter.addAction(Intent.ACTION_USER_SWITCHED); 1083 filter.addAction(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED); 1084 mContext.registerReceiver(mReceiver, filter); 1085 1086 // Listen to the RTT system setting so that we update it when the user flips it. 1087 ContentObserver rttUiSettingObserver = new ContentObserver( 1088 new Handler(Looper.getMainLooper())) { 1089 @Override 1090 public void onChange(boolean selfChange) { 1091 synchronized (mAccountsLock) { 1092 for (AccountEntry account : mAccounts) { 1093 account.updateRttCapability(); 1094 } 1095 } 1096 } 1097 }; 1098 1099 Uri rttSettingUri = Settings.Secure.getUriFor(Settings.Secure.RTT_CALLING_MODE); 1100 mContext.getContentResolver().registerContentObserver( 1101 rttSettingUri, false, rttUiSettingObserver); 1102 } 1103 1104 /** 1105 * Determines if the list of {@link AccountEntry}(s) contains an {@link AccountEntry} with a 1106 * specified {@link PhoneAccountHandle}. 1107 * 1108 * @param handle The {@link PhoneAccountHandle}. 1109 * @return {@code True} if an entry exists. 1110 */ hasAccountEntryForPhoneAccount(PhoneAccountHandle handle)1111 boolean hasAccountEntryForPhoneAccount(PhoneAccountHandle handle) { 1112 synchronized (mAccountsLock) { 1113 for (AccountEntry entry : mAccounts) { 1114 if (entry.getPhoneAccountHandle().equals(handle)) { 1115 return true; 1116 } 1117 } 1118 } 1119 return false; 1120 } 1121 1122 /** 1123 * Un-registers any {@link PhoneAccount}s which are no longer present in the list 1124 * {@code AccountEntry}(s). 1125 */ cleanupPhoneAccounts()1126 private void cleanupPhoneAccounts() { 1127 ComponentName telephonyComponentName = 1128 new ComponentName(mContext, TelephonyConnectionService.class); 1129 // This config indicates whether the emergency account was flagged as emergency calls only 1130 // in which case we need to consider all phone accounts, not just the call capable ones. 1131 final boolean emergencyCallsOnlyEmergencyAccount = mContext.getResources().getBoolean( 1132 R.bool.config_emergency_account_emergency_calls_only); 1133 List<PhoneAccountHandle> accountHandles = emergencyCallsOnlyEmergencyAccount 1134 ? mTelecomManager.getAllPhoneAccountHandles() 1135 : mTelecomManager.getCallCapablePhoneAccounts(true /* includeDisabled */); 1136 1137 for (PhoneAccountHandle handle : accountHandles) { 1138 if (telephonyComponentName.equals(handle.getComponentName()) && 1139 !hasAccountEntryForPhoneAccount(handle)) { 1140 Log.i(this, "Unregistering phone account %s.", handle); 1141 mTelecomManager.unregisterPhoneAccount(handle); 1142 } 1143 } 1144 } 1145 setupAccounts()1146 private void setupAccounts() { 1147 // Go through SIM-based phones and register ourselves -- registering an existing account 1148 // will cause the existing entry to be replaced. 1149 Phone[] phones = PhoneFactory.getPhones(); 1150 Log.i(this, "setupAccounts: Found %d phones. Attempting to register.", phones.length); 1151 1152 final boolean phoneAccountsEnabled = mContext.getResources().getBoolean( 1153 R.bool.config_pstn_phone_accounts_enabled); 1154 1155 synchronized (mAccountsLock) { 1156 try { 1157 if (phoneAccountsEnabled) { 1158 for (Phone phone : phones) { 1159 int subscriptionId = phone.getSubId(); 1160 Log.i(this, "setupAccounts: Phone with subscription id %d", subscriptionId); 1161 // setupAccounts can be called multiple times during service changes. 1162 // Don't add an account if the Icc has not been set yet. 1163 if (!SubscriptionManager.isValidSubscriptionId(subscriptionId) 1164 || phone.getFullIccSerialNumber() == null) { 1165 Log.d(this, "setupAccounts: skipping invalid subid %d", subscriptionId); 1166 continue; 1167 } 1168 // Don't add account if it's opportunistic subscription, which is considered 1169 // data only for now. 1170 SubscriptionInfo info = SubscriptionManager.from(mContext) 1171 .getActiveSubscriptionInfo(subscriptionId); 1172 if (info == null || info.isOpportunistic()) { 1173 Log.d(this, "setupAccounts: skipping unknown or opportunistic subid %d", 1174 subscriptionId); 1175 continue; 1176 } 1177 1178 mAccounts.add(new AccountEntry(phone, false /* emergency */, 1179 false /* isDummy */)); 1180 } 1181 } 1182 } finally { 1183 // If we did not list ANY accounts, we need to provide a "default" SIM account 1184 // for emergency numbers since no actual SIM is needed for dialing emergency 1185 // numbers but a phone account is. 1186 if (mAccounts.isEmpty()) { 1187 Log.i(this, "setupAccounts: adding default"); 1188 mAccounts.add( 1189 new AccountEntry(PhoneFactory.getDefaultPhone(), true /* emergency */, 1190 false /* isDummy */)); 1191 } 1192 } 1193 1194 // Add a fake account entry. 1195 if (DBG && phones.length > 0 && "TRUE".equals(System.getProperty("dummy_sim"))) { 1196 mAccounts.add(new AccountEntry(phones[0], false /* emergency */, 1197 true /* isDummy */)); 1198 } 1199 } 1200 1201 // Clean up any PhoneAccounts that are no longer relevant 1202 cleanupPhoneAccounts(); 1203 1204 // At some point, the phone account ID was switched from the subId to the iccId. 1205 // If there is a default account, check if this is the case, and upgrade the default account 1206 // from using the subId to iccId if so. 1207 PhoneAccountHandle defaultPhoneAccount = 1208 mTelecomManager.getUserSelectedOutgoingPhoneAccount(); 1209 ComponentName telephonyComponentName = 1210 new ComponentName(mContext, TelephonyConnectionService.class); 1211 1212 if (defaultPhoneAccount != null && 1213 telephonyComponentName.equals(defaultPhoneAccount.getComponentName()) && 1214 !hasAccountEntryForPhoneAccount(defaultPhoneAccount)) { 1215 1216 String phoneAccountId = defaultPhoneAccount.getId(); 1217 if (!TextUtils.isEmpty(phoneAccountId) && TextUtils.isDigitsOnly(phoneAccountId)) { 1218 PhoneAccountHandle upgradedPhoneAccount = 1219 PhoneUtils.makePstnPhoneAccountHandle( 1220 PhoneGlobals.getPhone(Integer.parseInt(phoneAccountId))); 1221 1222 if (hasAccountEntryForPhoneAccount(upgradedPhoneAccount)) { 1223 mTelecomManager.setUserSelectedOutgoingPhoneAccount(upgradedPhoneAccount); 1224 } 1225 } 1226 } 1227 } 1228 tearDownAccounts()1229 private void tearDownAccounts() { 1230 synchronized (mAccountsLock) { 1231 for (AccountEntry entry : mAccounts) { 1232 entry.teardown(); 1233 } 1234 mAccounts.clear(); 1235 } 1236 } 1237 1238 /** 1239 * Handles changes to the carrier configuration which may impact a phone account. There are 1240 * some extras defined in the {@link PhoneAccount} which are based on carrier config options. 1241 * Only checking for carrier config changes when the subscription is configured runs the risk of 1242 * missing carrier config changes which happen later. 1243 * @param subId The subid the carrier config changed for, if applicable. Will be 1244 * {@link SubscriptionManager#INVALID_SUBSCRIPTION_ID} if not specified. 1245 */ handleCarrierConfigChange(int subId)1246 private void handleCarrierConfigChange(int subId) { 1247 if (subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) { 1248 return; 1249 } 1250 synchronized (mAccountsLock) { 1251 for (AccountEntry entry : mAccounts) { 1252 if (entry.getSubId() == subId) { 1253 Log.d(this, "handleCarrierConfigChange: subId=%d, accountSubId=%d", subId, 1254 entry.getSubId()); 1255 entry.reRegisterPstnPhoneAccount(); 1256 } 1257 } 1258 } 1259 } 1260 } 1261