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