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 mIsTestAccount;
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 isTest)134         AccountEntry(Phone phone, boolean isEmergency, boolean isTest) {
135             mPhone = phone;
136             mIsEmergency = isEmergency;
137             mIsTestAccount = isTest;
138             mIsAdhocConfCapable = mPhone.isImsRegistered();
139             mAccount = registerPstnPhoneAccount(isEmergency, isTest);
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 (mIsTestAccount || isEmergency) {
147                 // For test 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, mIsTestAccount);
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 isTestAccount)261         private PhoneAccount registerPstnPhoneAccount(boolean isEmergency, boolean isTestAccount) {
262             PhoneAccount account = buildPstnPhoneAccount(mIsEmergency, mIsTestAccount);
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 isTestAccount)271         private PhoneAccount buildPstnPhoneAccount(boolean isEmergency, boolean isTestAccount) {
272             String testPrefix = isTestAccount ? "Test " : "";
273 
274             // Build the Phone account handle.
275             PhoneAccountHandle phoneAccountHandle =
276                     PhoneUtils.makePstnPhoneAccountHandleWithPrefix(
277                             mPhone, testPrefix, 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 = testPrefix + subDisplayName;
338                 description = testPrefix + 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, mIsTestAccount);
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, mIsTestAccount);
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, mIsTestAccount);
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, mIsTestAccount);
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, mIsTestAccount);
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                 int userHandleId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0);
1018                 UserHandle currentUserHandle = UserHandle.of(userHandleId);
1019                 mIsPrimaryUser = currentUserHandle.isSystem();
1020 
1021                 // Any time the user changes, re-register the accounts.
1022                 tearDownAccounts();
1023                 setupAccounts();
1024             } else if (CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED.equals(
1025                     intent.getAction())) {
1026                 Log.i(this, "Carrier-config changed, checking for phone account updates.");
1027                 int subId = intent.getIntExtra(SubscriptionManager.EXTRA_SUBSCRIPTION_INDEX,
1028                         SubscriptionManager.INVALID_SUBSCRIPTION_ID);
1029                 handleCarrierConfigChange(subId);
1030             }
1031         }
1032     };
1033 
1034     private BroadcastReceiver mLocaleChangeReceiver = new BroadcastReceiver() {
1035         @Override
1036         public void onReceive(Context context, Intent intent) {
1037             Log.i(this, "Locale change; re-registering phone accounts.");
1038             tearDownAccounts();
1039             setupAccounts();
1040         }
1041     };
1042 
1043     private final PhoneStateListener mPhoneStateListener = new PhoneStateListener() {
1044         @Override
1045         public void onServiceStateChanged(ServiceState serviceState) {
1046             int newState = serviceState.getState();
1047             if (newState == ServiceState.STATE_IN_SERVICE && mServiceState != newState) {
1048                 tearDownAccounts();
1049                 setupAccounts();
1050             } else {
1051                 synchronized (mAccountsLock) {
1052                     for (AccountEntry account : mAccounts) {
1053                         account.updateRttCapability();
1054                     }
1055                 }
1056             }
1057             mServiceState = newState;
1058         }
1059 
1060         @Override
1061         public void onActiveDataSubscriptionIdChanged(int subId) {
1062             mActiveDataSubscriptionId = subId;
1063             synchronized (mAccountsLock) {
1064                 for (AccountEntry account : mAccounts) {
1065                     account.updateDefaultDataSubId(mActiveDataSubscriptionId);
1066                 }
1067             }
1068         }
1069     };
1070 
1071     private static TelecomAccountRegistry sInstance;
1072     private final Context mContext;
1073     private final TelecomManager mTelecomManager;
1074     private final android.telephony.ims.ImsManager mImsManager;
1075     private final TelephonyManager mTelephonyManager;
1076     private final SubscriptionManager mSubscriptionManager;
1077     private List<AccountEntry> mAccounts = new LinkedList<AccountEntry>();
1078     private final Object mAccountsLock = new Object();
1079     private int mSubscriptionListenerState = LISTENER_STATE_UNREGISTERED;
1080     private int mServiceState = ServiceState.STATE_POWER_OFF;
1081     private int mActiveDataSubscriptionId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
1082     private boolean mIsPrimaryUser = true;
1083     private ExponentialBackoff mRegisterSubscriptionListenerBackoff;
1084     private final HandlerThread mHandlerThread = new HandlerThread("TelecomAccountRegistry");
1085 
1086     // TODO: Remove back-pointer from app singleton to Service, since this is not a preferred
1087     // pattern; redesign. This was added to fix a late release bug.
1088     private TelephonyConnectionService mTelephonyConnectionService;
1089 
1090     // Used to register subscription changed listener when initial attempts fail.
1091     private Runnable mRegisterOnSubscriptionsChangedListenerRunnable = new Runnable() {
1092         @Override
1093         public void run() {
1094             if (mSubscriptionListenerState != LISTENER_STATE_REGISTERED) {
1095                 Log.i(this, "TelecomAccountRegistry: performing delayed register.");
1096                 SubscriptionManager.from(mContext).addOnSubscriptionsChangedListener(
1097                         mOnSubscriptionsChangedListener);
1098             }
1099         }
1100     };
1101 
TelecomAccountRegistry(Context context)1102     TelecomAccountRegistry(Context context) {
1103         mContext = context;
1104         mTelecomManager = context.getSystemService(TelecomManager.class);
1105         mImsManager = context.getSystemService(android.telephony.ims.ImsManager.class);
1106         mTelephonyManager = TelephonyManager.from(context);
1107         mSubscriptionManager = SubscriptionManager.from(context);
1108         mHandlerThread.start();
1109         mRegisterSubscriptionListenerBackoff = new ExponentialBackoff(
1110                 REGISTER_START_DELAY_MS,
1111                 REGISTER_MAXIMUM_DELAY_MS,
1112                 2, /* multiplier */
1113                 mHandlerThread.getLooper(),
1114                 mRegisterOnSubscriptionsChangedListenerRunnable);
1115     }
1116 
1117     /**
1118      * Get the singleton instance.
1119      */
getInstance(Context context)1120     public static synchronized TelecomAccountRegistry getInstance(Context context) {
1121         if (sInstance == null && context != null) {
1122             sInstance = new TelecomAccountRegistry(context);
1123         }
1124         return sInstance;
1125     }
1126 
setTelephonyConnectionService(TelephonyConnectionService telephonyConnectionService)1127     void setTelephonyConnectionService(TelephonyConnectionService telephonyConnectionService) {
1128         this.mTelephonyConnectionService = telephonyConnectionService;
1129     }
1130 
getTelephonyConnectionService()1131     TelephonyConnectionService getTelephonyConnectionService() {
1132         return mTelephonyConnectionService;
1133     }
1134 
1135     /**
1136      * Determines if the {@link AccountEntry} associated with a {@link PhoneAccountHandle} supports
1137      * pausing video calls.
1138      *
1139      * @param handle The {@link PhoneAccountHandle}.
1140      * @return {@code True} if video pausing is supported.
1141      */
isVideoPauseSupported(PhoneAccountHandle handle)1142     boolean isVideoPauseSupported(PhoneAccountHandle handle) {
1143         synchronized (mAccountsLock) {
1144             for (AccountEntry entry : mAccounts) {
1145                 if (entry.getPhoneAccountHandle().equals(handle)) {
1146                     return entry.isVideoPauseSupported();
1147                 }
1148             }
1149         }
1150         return false;
1151     }
1152 
1153     /**
1154      * Determines if the {@link AccountEntry} associated with a {@link PhoneAccountHandle} supports
1155      * merging calls.
1156      *
1157      * @param handle The {@link PhoneAccountHandle}.
1158      * @return {@code True} if merging calls is supported.
1159      */
isMergeCallSupported(PhoneAccountHandle handle)1160     boolean isMergeCallSupported(PhoneAccountHandle handle) {
1161         synchronized (mAccountsLock) {
1162             for (AccountEntry entry : mAccounts) {
1163                 if (entry.getPhoneAccountHandle().equals(handle)) {
1164                     return entry.isMergeCallSupported();
1165                 }
1166             }
1167         }
1168         return false;
1169     }
1170 
1171     /**
1172      * Determines if the {@link AccountEntry} associated with a {@link PhoneAccountHandle} supports
1173      * video conferencing.
1174      *
1175      * @param handle The {@link PhoneAccountHandle}.
1176      * @return {@code True} if video conferencing is supported.
1177      */
isVideoConferencingSupported(PhoneAccountHandle handle)1178     boolean isVideoConferencingSupported(PhoneAccountHandle handle) {
1179         synchronized (mAccountsLock) {
1180             for (AccountEntry entry : mAccounts) {
1181                 if (entry.getPhoneAccountHandle().equals(handle)) {
1182                     return entry.isVideoConferencingSupported();
1183                 }
1184             }
1185         }
1186         return false;
1187     }
1188 
1189     /**
1190      * Determines if the {@link AccountEntry} associated with a {@link PhoneAccountHandle} allows
1191      * merging of wifi calls when VoWIFI is disabled.
1192      *
1193      * @param handle The {@link PhoneAccountHandle}.
1194      * @return {@code True} if merging of wifi calls is allowed when VoWIFI is disabled.
1195      */
isMergeOfWifiCallsAllowedWhenVoWifiOff(final PhoneAccountHandle handle)1196     boolean isMergeOfWifiCallsAllowedWhenVoWifiOff(final PhoneAccountHandle handle) {
1197         synchronized (mAccountsLock) {
1198             Optional<AccountEntry> result = mAccounts.stream().filter(
1199                     entry -> entry.getPhoneAccountHandle().equals(handle)).findFirst();
1200 
1201             if (result.isPresent()) {
1202                 return result.get().isMergeOfWifiCallsAllowedWhenVoWifiOff();
1203             } else {
1204                 return false;
1205             }
1206         }
1207     }
1208 
1209     /**
1210      * Determines if the {@link AccountEntry} associated with a {@link PhoneAccountHandle} supports
1211      * merging IMS calls.
1212      *
1213      * @param handle The {@link PhoneAccountHandle}.
1214      * @return {@code True} if merging IMS calls is supported.
1215      */
isMergeImsCallSupported(PhoneAccountHandle handle)1216     boolean isMergeImsCallSupported(PhoneAccountHandle handle) {
1217         synchronized (mAccountsLock) {
1218             for (AccountEntry entry : mAccounts) {
1219                 if (entry.getPhoneAccountHandle().equals(handle)) {
1220                     return entry.isMergeImsCallSupported();
1221                 }
1222             }
1223         }
1224         return false;
1225     }
1226 
1227     /**
1228      * Determines if the {@link AccountEntry} associated with a {@link PhoneAccountHandle} supports
1229      * managing IMS conference calls.
1230      *
1231      * @param handle The {@link PhoneAccountHandle}.
1232      * @return {@code True} if managing IMS conference calls is supported.
1233      */
isManageImsConferenceCallSupported(PhoneAccountHandle handle)1234     boolean isManageImsConferenceCallSupported(PhoneAccountHandle handle) {
1235         synchronized (mAccountsLock) {
1236             for (AccountEntry entry : mAccounts) {
1237                 if (entry.getPhoneAccountHandle().equals(handle)) {
1238                     return entry.isManageImsConferenceCallSupported();
1239                 }
1240             }
1241         }
1242         return false;
1243     }
1244 
1245     /**
1246      * showing precise call disconnect cause to the user.
1247      *
1248      * @param handle The {@link PhoneAccountHandle}.
1249      * @return {@code True} if showing precise call disconnect cause to the user is supported.
1250      */
isShowPreciseFailedCause(PhoneAccountHandle handle)1251     boolean isShowPreciseFailedCause(PhoneAccountHandle handle) {
1252         synchronized (mAccountsLock) {
1253             for (AccountEntry entry : mAccounts) {
1254                 if (entry.getPhoneAccountHandle().equals(handle)) {
1255                     return entry.isShowPreciseFailedCause();
1256                 }
1257             }
1258         }
1259         return false;
1260     }
1261 
1262     /**
1263      * @return Reference to the {@code TelecomAccountRegistry}'s subscription manager.
1264      */
getSubscriptionManager()1265     SubscriptionManager getSubscriptionManager() {
1266         return mSubscriptionManager;
1267     }
1268 
1269     /**
1270      * Returns the address (e.g. the phone number) associated with a subscription.
1271      *
1272      * @param handle The phone account handle to find the subscription address for.
1273      * @return The address.
1274      */
getAddress(PhoneAccountHandle handle)1275     public Uri getAddress(PhoneAccountHandle handle) {
1276         synchronized (mAccountsLock) {
1277             for (AccountEntry entry : mAccounts) {
1278                 if (entry.getPhoneAccountHandle().equals(handle)) {
1279                     return entry.mAccount.getAddress();
1280                 }
1281             }
1282         }
1283         return null;
1284     }
1285 
refreshAdhocConference(boolean isEnableAdhocConf)1286     public void refreshAdhocConference(boolean isEnableAdhocConf) {
1287         synchronized (mAccountsLock) {
1288             Log.v(this, "refreshAdhocConference isEnable = " + isEnableAdhocConf);
1289             for (AccountEntry entry : mAccounts) {
1290                 boolean hasAdhocConfCapability = entry.mAccount.hasCapabilities(
1291                         PhoneAccount.CAPABILITY_ADHOC_CONFERENCE_CALLING);
1292                 if (!isEnableAdhocConf && hasAdhocConfCapability) {
1293                     entry.updateAdhocConfCapability(isEnableAdhocConf);
1294                 } else if (isEnableAdhocConf && !hasAdhocConfCapability) {
1295                     entry.updateAdhocConfCapability(entry.mPhone.isImsRegistered());
1296                 }
1297             }
1298         }
1299     }
1300 
1301     /**
1302      * Returns whethere a the subscription associated with a {@link PhoneAccountHandle} is using a
1303      * sim call manager.
1304      *
1305      * @param handle The phone account handle to find the subscription address for.
1306      * @return {@code true} if a sim call manager is in use, {@code false} otherwise.
1307      */
isUsingSimCallManager(PhoneAccountHandle handle)1308     public boolean isUsingSimCallManager(PhoneAccountHandle handle) {
1309         synchronized (mAccountsLock) {
1310             for (AccountEntry entry : mAccounts) {
1311                 if (entry.getPhoneAccountHandle().equals(handle)) {
1312                     return entry.isUsingSimCallManager();
1313                 }
1314             }
1315         }
1316         return false;
1317     }
1318 
1319     /**
1320      * Sets up all the phone accounts for SIMs on first boot.
1321      */
setupOnBoot()1322     public void setupOnBoot() {
1323         // TODO: When this object "finishes" we should unregister by invoking
1324         // SubscriptionManager.getInstance(mContext).unregister(mOnSubscriptionsChangedListener);
1325         // This is not strictly necessary because it will be unregistered if the
1326         // notification fails but it is good form.
1327 
1328         // Register for SubscriptionInfo list changes which is guaranteed
1329         // to invoke onSubscriptionsChanged the first time.
1330         Log.i(this, "TelecomAccountRegistry: setupOnBoot - register subscription listener");
1331         SubscriptionManager.from(mContext).addOnSubscriptionsChangedListener(
1332                 mOnSubscriptionsChangedListener);
1333 
1334         // We also need to listen for changes to the service state (e.g. emergency -> in service)
1335         // because this could signal a removal or addition of a SIM in a single SIM phone.
1336         mTelephonyManager.listen(mPhoneStateListener, PhoneStateListener.LISTEN_SERVICE_STATE
1337                 | PhoneStateListener.LISTEN_ACTIVE_DATA_SUBSCRIPTION_ID_CHANGE);
1338 
1339         // Listen for user switches.  When the user switches, we need to ensure that if the current
1340         // use is not the primary user we disable video calling.
1341         IntentFilter filter = new IntentFilter();
1342         filter.addAction(Intent.ACTION_USER_SWITCHED);
1343         filter.addAction(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED);
1344         mContext.registerReceiver(mReceiver, filter);
1345 
1346         //We also need to listen for locale changes
1347         //(e.g. system language changed -> SIM card name changed)
1348         IntentFilter localeChangeFilter = new IntentFilter(Intent.ACTION_LOCALE_CHANGED);
1349         localeChangeFilter.addAction(TelephonyManager.ACTION_NETWORK_COUNTRY_CHANGED);
1350         mContext.registerReceiver(mLocaleChangeReceiver, localeChangeFilter);
1351 
1352         registerContentObservers();
1353     }
1354 
registerContentObservers()1355     private void registerContentObservers() {
1356         // Listen to the RTT system setting so that we update it when the user flips it.
1357         ContentObserver rttUiSettingObserver = new ContentObserver(
1358                 new Handler(Looper.getMainLooper())) {
1359             @Override
1360             public void onChange(boolean selfChange) {
1361                 synchronized (mAccountsLock) {
1362                     for (AccountEntry account : mAccounts) {
1363                         account.updateRttCapability();
1364                     }
1365                 }
1366             }
1367         };
1368 
1369         Uri rttSettingUri = Settings.Secure.getUriFor(Settings.Secure.RTT_CALLING_MODE);
1370         mContext.getContentResolver().registerContentObserver(
1371                 rttSettingUri, false, rttUiSettingObserver);
1372 
1373         // Listen to the changes to the user's Contacts Discovery Setting.
1374         ContentObserver contactDiscoveryObserver = new ContentObserver(
1375                 new Handler(Looper.getMainLooper())) {
1376             @Override
1377             public void onChange(boolean selfChange) {
1378                 synchronized (mAccountsLock) {
1379                     for (AccountEntry account : mAccounts) {
1380                         account.updateVideoPresenceCapability();
1381                     }
1382                 }
1383             }
1384         };
1385         Uri contactDiscUri = Uri.withAppendedPath(Telephony.SimInfo.CONTENT_URI,
1386                 Telephony.SimInfo.COLUMN_IMS_RCS_UCE_ENABLED);
1387         mContext.getContentResolver().registerContentObserver(
1388                 contactDiscUri, true /*notifyForDescendants*/, contactDiscoveryObserver);
1389     }
1390 
1391     /**
1392      * Determines if the list of {@link AccountEntry}(s) contains an {@link AccountEntry} with a
1393      * specified {@link PhoneAccountHandle}.
1394      *
1395      * @param handle The {@link PhoneAccountHandle}.
1396      * @return {@code True} if an entry exists.
1397      */
hasAccountEntryForPhoneAccount(PhoneAccountHandle handle)1398     boolean hasAccountEntryForPhoneAccount(PhoneAccountHandle handle) {
1399         synchronized (mAccountsLock) {
1400             for (AccountEntry entry : mAccounts) {
1401                 if (entry.getPhoneAccountHandle().equals(handle)) {
1402                     return true;
1403                 }
1404             }
1405         }
1406         return false;
1407     }
1408 
1409     /**
1410      * Un-registers any {@link PhoneAccount}s which are no longer present in the list
1411      * {@code AccountEntry}(s).
1412      */
cleanupPhoneAccounts()1413     private void cleanupPhoneAccounts() {
1414         ComponentName telephonyComponentName =
1415                 new ComponentName(mContext, TelephonyConnectionService.class);
1416         // This config indicates whether the emergency account was flagged as emergency calls only
1417         // in which case we need to consider all phone accounts, not just the call capable ones.
1418         final boolean emergencyCallsOnlyEmergencyAccount = mContext.getResources().getBoolean(
1419                 R.bool.config_emergency_account_emergency_calls_only);
1420         List<PhoneAccountHandle> accountHandles = emergencyCallsOnlyEmergencyAccount
1421                 ? mTelecomManager.getAllPhoneAccountHandles()
1422                 : mTelecomManager.getCallCapablePhoneAccounts();
1423 
1424         for (PhoneAccountHandle handle : accountHandles) {
1425             if (telephonyComponentName.equals(handle.getComponentName()) &&
1426                     !hasAccountEntryForPhoneAccount(handle)) {
1427                 Log.i(this, "Unregistering phone account %s.", handle);
1428                 mTelecomManager.unregisterPhoneAccount(handle);
1429             }
1430         }
1431     }
1432 
setupAccounts()1433     private void setupAccounts() {
1434         // Go through SIM-based phones and register ourselves -- registering an existing account
1435         // will cause the existing entry to be replaced.
1436         Phone[] phones = PhoneFactory.getPhones();
1437         Log.i(this, "setupAccounts: Found %d phones.  Attempting to register.", phones.length);
1438 
1439         final boolean phoneAccountsEnabled = mContext.getResources().getBoolean(
1440                 R.bool.config_pstn_phone_accounts_enabled);
1441 
1442         synchronized (mAccountsLock) {
1443             try {
1444                 if (phoneAccountsEnabled) {
1445                     for (Phone phone : phones) {
1446                         int subscriptionId = phone.getSubId();
1447                         Log.i(this, "setupAccounts: Phone with subscription id %d", subscriptionId);
1448                         // setupAccounts can be called multiple times during service changes.
1449                         // Don't add an account if the Icc has not been set yet.
1450                         if (!SubscriptionManager.isValidSubscriptionId(subscriptionId)
1451                                 || phone.getFullIccSerialNumber() == null) {
1452                             Log.d(this, "setupAccounts: skipping invalid subid %d", subscriptionId);
1453                             continue;
1454                         }
1455                         // Don't add account if it's opportunistic subscription, which is considered
1456                         // data only for now.
1457                         SubscriptionInfo info = SubscriptionManager.from(mContext)
1458                                 .getActiveSubscriptionInfo(subscriptionId);
1459                         if (info == null || info.isOpportunistic()) {
1460                             Log.d(this, "setupAccounts: skipping unknown or opportunistic subid %d",
1461                                     subscriptionId);
1462                             continue;
1463                         }
1464 
1465                         mAccounts.add(new AccountEntry(phone, false /* emergency */,
1466                                 false /* isTest */));
1467                     }
1468                 }
1469             } finally {
1470                 // If we did not list ANY accounts, we need to provide a "default" SIM account
1471                 // for emergency numbers since no actual SIM is needed for dialing emergency
1472                 // numbers but a phone account is.
1473                 if (mAccounts.isEmpty()) {
1474                     Log.i(this, "setupAccounts: adding default");
1475                     mAccounts.add(
1476                             new AccountEntry(PhoneFactory.getDefaultPhone(), true /* emergency */,
1477                                     false /* isTest */));
1478                 }
1479             }
1480 
1481             // Add a fake account entry.
1482             if (DBG && phones.length > 0 && "TRUE".equals(System.getProperty("test_sim"))) {
1483                 mAccounts.add(new AccountEntry(phones[0], false /* emergency */,
1484                         true /* isTest */));
1485             }
1486         }
1487 
1488         // Clean up any PhoneAccounts that are no longer relevant
1489         cleanupPhoneAccounts();
1490     }
1491 
tearDownAccounts()1492     private void tearDownAccounts() {
1493         synchronized (mAccountsLock) {
1494             for (AccountEntry entry : mAccounts) {
1495                 entry.teardown();
1496             }
1497             mAccounts.clear();
1498         }
1499     }
1500 
1501     /**
1502      * Handles changes to the carrier configuration which may impact a phone account.  There are
1503      * some extras defined in the {@link PhoneAccount} which are based on carrier config options.
1504      * Only checking for carrier config changes when the subscription is configured runs the risk of
1505      * missing carrier config changes which happen later.
1506      * @param subId The subid the carrier config changed for, if applicable.  Will be
1507      *              {@link SubscriptionManager#INVALID_SUBSCRIPTION_ID} if not specified.
1508      */
handleCarrierConfigChange(int subId)1509     private void handleCarrierConfigChange(int subId) {
1510         if (subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
1511             return;
1512         }
1513         synchronized (mAccountsLock) {
1514             for (AccountEntry entry : mAccounts) {
1515                 if (entry.getSubId() == subId) {
1516                     Log.d(this, "handleCarrierConfigChange: subId=%d, accountSubId=%d", subId,
1517                             entry.getSubId());
1518                     entry.reRegisterPstnPhoneAccount();
1519                 }
1520             }
1521         }
1522     }
1523 }
1524