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