• 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.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