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