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