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