• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2022 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.domainselection;
18 
19 import static android.telephony.AccessNetworkConstants.AccessNetworkType.CDMA2000;
20 import static android.telephony.AccessNetworkConstants.AccessNetworkType.EUTRAN;
21 import static android.telephony.AccessNetworkConstants.AccessNetworkType.GERAN;
22 import static android.telephony.AccessNetworkConstants.AccessNetworkType.NGRAN;
23 import static android.telephony.AccessNetworkConstants.AccessNetworkType.UNKNOWN;
24 import static android.telephony.AccessNetworkConstants.AccessNetworkType.UTRAN;
25 import static android.telephony.AccessNetworkConstants.TRANSPORT_TYPE_INVALID;
26 import static android.telephony.AccessNetworkConstants.TRANSPORT_TYPE_WLAN;
27 import static android.telephony.AccessNetworkConstants.TRANSPORT_TYPE_WWAN;
28 import static android.telephony.BarringInfo.BARRING_SERVICE_TYPE_EMERGENCY;
29 import static android.telephony.CarrierConfigManager.KEY_CARRIER_VOLTE_TTY_SUPPORTED_BOOL;
30 import static android.telephony.CarrierConfigManager.ImsEmergency.DOMAIN_CS;
31 import static android.telephony.CarrierConfigManager.ImsEmergency.DOMAIN_PS_3GPP;
32 import static android.telephony.CarrierConfigManager.ImsEmergency.DOMAIN_PS_NON_3GPP;
33 import static android.telephony.CarrierConfigManager.ImsEmergency.KEY_EMERGENCY_CALL_SETUP_TIMER_ON_CURRENT_NETWORK_SEC_INT;
34 import static android.telephony.CarrierConfigManager.ImsEmergency.KEY_EMERGENCY_CDMA_PREFERRED_NUMBERS_STRING_ARRAY;
35 import static android.telephony.CarrierConfigManager.ImsEmergency.KEY_EMERGENCY_DOMAIN_PREFERENCE_INT_ARRAY;
36 import static android.telephony.CarrierConfigManager.ImsEmergency.KEY_EMERGENCY_DOMAIN_PREFERENCE_ROAMING_INT_ARRAY;
37 import static android.telephony.CarrierConfigManager.ImsEmergency.KEY_EMERGENCY_LTE_PREFERRED_AFTER_NR_FAILED_BOOL;
38 import static android.telephony.CarrierConfigManager.ImsEmergency.KEY_EMERGENCY_NETWORK_SCAN_TYPE_INT;
39 import static android.telephony.CarrierConfigManager.ImsEmergency.KEY_EMERGENCY_OVER_CS_ROAMING_SUPPORTED_ACCESS_NETWORK_TYPES_INT_ARRAY;
40 import static android.telephony.CarrierConfigManager.ImsEmergency.KEY_EMERGENCY_OVER_CS_SUPPORTED_ACCESS_NETWORK_TYPES_INT_ARRAY;
41 import static android.telephony.CarrierConfigManager.ImsEmergency.KEY_EMERGENCY_OVER_IMS_ROAMING_SUPPORTED_3GPP_NETWORK_TYPES_INT_ARRAY;
42 import static android.telephony.CarrierConfigManager.ImsEmergency.KEY_EMERGENCY_OVER_IMS_SUPPORTED_3GPP_NETWORK_TYPES_INT_ARRAY;
43 import static android.telephony.CarrierConfigManager.ImsEmergency.KEY_EMERGENCY_REQUIRES_IMS_REGISTRATION_BOOL;
44 import static android.telephony.CarrierConfigManager.ImsEmergency.KEY_EMERGENCY_REQUIRES_VOLTE_ENABLED_BOOL;
45 import static android.telephony.CarrierConfigManager.ImsEmergency.KEY_EMERGENCY_SCAN_TIMER_SEC_INT;
46 import static android.telephony.CarrierConfigManager.ImsEmergency.KEY_EMERGENCY_VOWIFI_REQUIRES_CONDITION_INT;
47 import static android.telephony.CarrierConfigManager.ImsEmergency.KEY_IMS_REASONINFO_CODE_TO_RETRY_EMERGENCY_INT_ARRAY;
48 import static android.telephony.CarrierConfigManager.ImsEmergency.KEY_MAXIMUM_CELLULAR_SEARCH_TIMER_SEC_INT;
49 import static android.telephony.CarrierConfigManager.ImsEmergency.KEY_MAXIMUM_NUMBER_OF_EMERGENCY_TRIES_OVER_VOWIFI_INT;
50 import static android.telephony.CarrierConfigManager.ImsEmergency.KEY_PREFER_IMS_EMERGENCY_WHEN_VOICE_CALLS_ON_CS_BOOL;
51 import static android.telephony.CarrierConfigManager.ImsEmergency.KEY_SCAN_LIMITED_SERVICE_AFTER_VOLTE_FAILURE_BOOL;
52 import static android.telephony.CarrierConfigManager.ImsEmergency.SCAN_TYPE_FULL_SERVICE_FOLLOWED_BY_LIMITED_SERVICE;
53 import static android.telephony.CarrierConfigManager.ImsEmergency.VOWIFI_REQUIRES_SETTING_ENABLED;
54 import static android.telephony.CarrierConfigManager.ImsEmergency.VOWIFI_REQUIRES_VALID_EID;
55 import static android.telephony.CarrierConfigManager.ImsWfc.KEY_EMERGENCY_CALL_OVER_EMERGENCY_PDN_BOOL;
56 import static android.telephony.NetworkRegistrationInfo.REGISTRATION_STATE_HOME;
57 import static android.telephony.NetworkRegistrationInfo.REGISTRATION_STATE_ROAMING;
58 import static android.telephony.NrVopsSupportInfo.NR_STATUS_EMC_5GCN_ONLY;
59 import static android.telephony.NrVopsSupportInfo.NR_STATUS_EMC_NR_EUTRA_5GCN;
60 import static android.telephony.PreciseDisconnectCause.EMERGENCY_PERM_FAILURE;
61 import static android.telephony.PreciseDisconnectCause.EMERGENCY_TEMP_FAILURE;
62 import static android.telephony.PreciseDisconnectCause.NO_VALID_SIM;
63 import static android.telephony.PreciseDisconnectCause.SERVICE_OPTION_NOT_AVAILABLE;
64 import static android.telephony.SubscriptionManager.PROFILE_CLASS_PROVISIONING;
65 import static android.telephony.TelephonyManager.DATA_CONNECTED;
66 import static android.telephony.TelephonyManager.DATA_DISCONNECTED;
67 import static android.telephony.TelephonyManager.DATA_DISCONNECTING;
68 import static android.telephony.TelephonyManager.DATA_UNKNOWN;
69 
70 import android.annotation.NonNull;
71 import android.content.Context;
72 import android.content.res.Resources;
73 import android.net.ConnectivityManager;
74 import android.net.Network;
75 import android.net.NetworkCapabilities;
76 import android.net.NetworkRequest;
77 import android.os.CancellationSignal;
78 import android.os.Looper;
79 import android.os.Message;
80 import android.os.PersistableBundle;
81 import android.os.PowerManager;
82 import android.os.SystemProperties;
83 import android.telecom.TelecomManager;
84 import android.telephony.AccessNetworkConstants.AccessNetworkType;
85 import android.telephony.AccessNetworkConstants.RadioAccessNetworkType;
86 import android.telephony.AccessNetworkConstants.TransportType;
87 import android.telephony.BarringInfo;
88 import android.telephony.CarrierConfigManager;
89 import android.telephony.DisconnectCause;
90 import android.telephony.DomainSelectionService;
91 import android.telephony.DomainSelectionService.SelectionAttributes;
92 import android.telephony.EmergencyRegistrationResult;
93 import android.telephony.NetworkRegistrationInfo;
94 import android.telephony.SubscriptionInfo;
95 import android.telephony.SubscriptionManager;
96 import android.telephony.TelephonyManager;
97 import android.telephony.TransportSelectorCallback;
98 import android.telephony.ims.ImsManager;
99 import android.telephony.ims.ImsMmTelManager;
100 import android.telephony.ims.ImsReasonInfo;
101 import android.telephony.ims.ProvisioningManager;
102 import android.text.TextUtils;
103 import android.util.LocalLog;
104 
105 import com.android.internal.annotations.VisibleForTesting;
106 import com.android.internal.telephony.flags.Flags;
107 import com.android.phone.R;
108 
109 import java.util.ArrayList;
110 import java.util.Arrays;
111 import java.util.List;
112 import java.util.function.IntFunction;
113 import java.util.stream.Collectors;
114 
115 /**
116  * Selects the domain for emergency calling.
117  */
118 public class EmergencyCallDomainSelector extends DomainSelectorBase
119         implements ImsStateTracker.BarringInfoListener, ImsStateTracker.ImsStateListener {
120     private static final String TAG = "DomainSelector-EmergencyCall";
121     private static final boolean DBG = (SystemProperties.getInt("ro.debuggable", 0) == 1);
122     private static final int LOG_SIZE = 50;
123 
124     /**
125      * Timeout before we requests network scan without waiting for the disconnection
126      * of ePDN.
127      */
128     private static final int DEFAULT_DATA_DISCONNECTION_TIMEOUT_MS = 2 * 1000; // 2 seconds
129 
130     /**
131      * Timeout of waiting for the IMS state change before selecting domain from initial state.
132      */
133     private static final int DEFAULT_WAIT_FOR_IMS_STATE_TIMEOUT_MS = 3 * 1000; // 3 seconds
134 
135     private static final int MSG_START_DOMAIN_SELECTION = 11;
136     @VisibleForTesting
137     public static final int MSG_NETWORK_SCAN_TIMEOUT = 12;
138     private static final int MSG_NETWORK_SCAN_RESULT = 13;
139     @VisibleForTesting
140     public static final int MSG_MAX_CELLULAR_TIMEOUT = 14;
141     @VisibleForTesting
142     public static final int MSG_WAIT_DISCONNECTION_TIMEOUT = 15;
143     @VisibleForTesting
144     public static final int MSG_WAIT_FOR_IMS_STATE_TIMEOUT = 16;
145     private static final int MSG_WIFI_AVAILABLE = 17;
146 
147     private static final int NOT_SUPPORTED = -1;
148 
149     private static List<Integer> sDefaultRetryReasonCodes = List.of(
150             ImsReasonInfo.CODE_LOCAL_CALL_CS_RETRY_REQUIRED,
151             ImsReasonInfo.CODE_LOCAL_INTERNAL_ERROR,
152             ImsReasonInfo.CODE_LOCAL_NOT_REGISTERED,
153             ImsReasonInfo.CODE_SIP_ALTERNATE_EMERGENCY_CALL);
154 
155     private static List<Integer> sDisconnectCauseForTerminatation = List.of(
156             SERVICE_OPTION_NOT_AVAILABLE);
157 
158     private static final LocalLog sLocalLog = new LocalLog(LOG_SIZE);
159 
160     private static List<String> sSimReadyAllowList;
161     private static List<String> sPreferSlotWithNormalServiceList;
162     private static List<String> sPreferCsAfterCsfbFailure;
163     private static List<String> sPreferGeranWhenSimAbsent;
164 
165     /**
166      * Network callback used to determine whether Wi-Fi is connected or not.
167      */
168     private ConnectivityManager.NetworkCallback mNetworkCallback =
169             new ConnectivityManager.NetworkCallback() {
170                 @Override
171                 public void onAvailable(Network network) {
172                     logi("onAvailable: " + network);
173                     if (network != null && !mWiFiNetworksAvailable.contains(network)) {
174                         mWiFiNetworksAvailable.add(network);
175                     }
176                     mWiFiAvailable = true;
177                     sendEmptyMessage(MSG_WIFI_AVAILABLE);
178                 }
179 
180                 @Override
181                 public void onLost(Network network) {
182                     logi("onLost: " + network);
183                     if (network != null) {
184                         mWiFiNetworksAvailable.remove(network);
185                     }
186                     if (!mWiFiNetworksAvailable.isEmpty()) {
187                         logi("onLost: available networks=" + mWiFiNetworksAvailable);
188                         return;
189                     }
190                     mWiFiAvailable = false;
191                 }
192 
193                 @Override
194                 public void onUnavailable() {
195                     logi("onUnavailable");
196                     mWiFiNetworksAvailable.clear();
197                     mWiFiAvailable = false;
198                 }
199             };
200 
201     private boolean mIsEmergencyBarred;
202     private boolean mImsRegistered;
203     private boolean mIsVoiceCapable;
204     private boolean mBarringInfoReceived;
205     private boolean mImsRegStateReceived;
206     private boolean mMmTelCapabilitiesReceived;
207     private int mVoWifiTrialCount = 0;
208 
209     private @RadioAccessNetworkType int mCsNetworkType = UNKNOWN;
210     private @RadioAccessNetworkType int mPsNetworkType = UNKNOWN;
211     private @RadioAccessNetworkType int mLastNetworkType = UNKNOWN;
212     private @TransportType int mLastTransportType = TRANSPORT_TYPE_INVALID;
213     private @DomainSelectionService.EmergencyScanType int mScanType;
214     private @RadioAccessNetworkType List<Integer> mLastPreferredNetworks;
215 
216     private CancellationSignal mCancelSignal;
217     private EmergencyRegistrationResult mLastRegResult;
218 
219     // Members for carrier configuration
220     private @RadioAccessNetworkType int[] mImsRatsConfig;
221     private @RadioAccessNetworkType int[] mCsRatsConfig;
222     private @RadioAccessNetworkType int[] mImsRoamRatsConfig;
223     private @RadioAccessNetworkType int[] mCsRoamRatsConfig;
224     private @CarrierConfigManager.ImsEmergency.EmergencyDomain int[] mDomainPreference;
225     private @CarrierConfigManager.ImsEmergency.EmergencyDomain int[] mDomainPreferenceRoam;
226     private List<String> mCdmaPreferredNumbers;
227     private boolean mPreferImsWhenCallsOnCs;
228     private int mVoWifiRequiresCondition;
229     private int mScanTimeout;
230     private int mMaxCellularTimeout;
231     private int mMaxNumOfVoWifiTries;
232     private boolean mVoWifiOverEmergencyPdn;
233     private @CarrierConfigManager.ImsEmergency.EmergencyScanType int mPreferredNetworkScanType;
234     private int mCallSetupTimerOnCurrentRat;
235     private boolean mRequiresImsRegistration;
236     private boolean mRequiresVoLteEnabled;
237     private boolean mLtePreferredAfterNrFailure;
238     private boolean mScanLimitedOnlyAfterVolteFailure;
239     private List<Integer> mRetryReasonCodes;
240     private boolean mNonTtyOrTtySupported;
241 
242     // Members for states
243     private boolean mIsMonitoringConnectivity;
244     private boolean mWiFiAvailable;
245     private boolean mWasCsfbAfterPsFailure;
246     private boolean mTryCsWhenPsFails;
247     private boolean mTryEsFallback;
248     private boolean mIsWaitingForDataDisconnection;
249     private boolean mSwitchRatPreferenceWithLocalNotRegistered;
250     private boolean mTerminateAfterCsFailure;
251     private int mModemCount;
252 
253     /** Indicates whether this instance is deactivated. */
254     private boolean mDestroyed = false;
255     /** Indicates whether emergency network scan is requested. */
256     private boolean mIsScanRequested = false;
257     /** Indicates whether selected domain has been notified. */
258     private boolean mDomainSelected = false;
259     /** Indicates whether the cross sim redialing timer has expired. */
260     private boolean mCrossStackTimerExpired = false;
261     /** Indicates whether max cellular timer expired. */
262     private boolean mMaxCellularTimerExpired = false;
263     /** Indicates whether network scan timer expired. */
264     private boolean mNetworkScanTimerExpired = false;
265 
266     /**
267      * Indicates whether {@link #selectDomain(SelectionAttributes, TransportSelectionCallback)}
268      * is called or not.
269      */
270     private boolean mDomainSelectionRequested = false;
271 
272     private final PowerManager.WakeLock mPartialWakeLock;
273     private final CrossSimRedialingController mCrossSimRedialingController;
274     private final DataConnectionStateHelper mEpdnHelper;
275     private final List<Network> mWiFiNetworksAvailable = new ArrayList<>();
276     private final ImsEmergencyRegistrationStateHelper mImsEmergencyRegistrationHelper;
277 
278     /** Constructor. */
EmergencyCallDomainSelector(Context context, int slotId, int subId, @NonNull Looper looper, @NonNull ImsStateTracker imsStateTracker, @NonNull DestroyListener destroyListener, @NonNull CrossSimRedialingController csrController, @NonNull DataConnectionStateHelper epdnHelper)279     public EmergencyCallDomainSelector(Context context, int slotId, int subId,
280             @NonNull Looper looper, @NonNull ImsStateTracker imsStateTracker,
281             @NonNull DestroyListener destroyListener,
282             @NonNull CrossSimRedialingController csrController,
283             @NonNull DataConnectionStateHelper epdnHelper) {
284         super(context, slotId, subId, looper, imsStateTracker, destroyListener, TAG);
285 
286         mImsStateTracker.addBarringInfoListener(this);
287         mImsStateTracker.addImsStateListener(this);
288 
289         PowerManager pm = context.getSystemService(PowerManager.class);
290         mPartialWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG);
291 
292         mCrossSimRedialingController = csrController;
293         mEpdnHelper = epdnHelper;
294         epdnHelper.setEmergencyCallDomainSelector(this);
295         mImsEmergencyRegistrationHelper = new ImsEmergencyRegistrationStateHelper(
296                 mContext, getSlotId(), getSubId(), getLooper());
297         acquireWakeLock();
298     }
299 
300     @Override
handleMessage(Message msg)301     public void handleMessage(Message msg) {
302         if (mDestroyed) return;
303 
304         switch(msg.what) {
305             case MSG_START_DOMAIN_SELECTION:
306                 startDomainSelection();
307                 break;
308 
309             case MSG_NETWORK_SCAN_TIMEOUT:
310                 handleNetworkScanTimeout();
311                 break;
312 
313             case MSG_NETWORK_SCAN_RESULT:
314                 handleScanResult((EmergencyRegistrationResult) msg.obj);
315                 break;
316 
317             case MSG_MAX_CELLULAR_TIMEOUT:
318                 handleMaxCellularTimeout();
319                 break;
320 
321             case MSG_WAIT_DISCONNECTION_TIMEOUT:
322                 requestScanDelayed();
323                 break;
324 
325             case MSG_WAIT_FOR_IMS_STATE_TIMEOUT:
326                 handleWaitForImsStateTimeout();
327                 break;
328 
329             case MSG_WIFI_AVAILABLE:
330                 handleWifiAvailable();
331                 break;
332 
333             default:
334                 super.handleMessage(msg);
335                 break;
336         }
337     }
338 
339     /**
340      * Handles the scan result.
341      *
342      * @param result The scan result.
343      */
handleScanResult(EmergencyRegistrationResult result)344     private void handleScanResult(EmergencyRegistrationResult result) {
345         logi("handleScanResult result=" + result);
346 
347         if (mLastTransportType == TRANSPORT_TYPE_WLAN) {
348             logi("handleScanResult timer expired, WLAN has been selected, ignore stale result");
349             return;
350         }
351 
352         // Detected the country and found that emergency calls are not allowed with this slot.
353         if (!allowEmergencyCalls(result)) {
354             terminateSelectionPermanentlyForSlot();
355             return;
356         }
357 
358         if (result.getAccessNetwork() == UNKNOWN) {
359             if (maybeRedialOnTheOtherSlotInNormalService(mLastRegResult)) {
360                 return;
361             }
362             if ((mPreferredNetworkScanType == SCAN_TYPE_FULL_SERVICE_FOLLOWED_BY_LIMITED_SERVICE)
363                       && (mScanType == DomainSelectionService.SCAN_TYPE_FULL_SERVICE)) {
364                 mScanType = DomainSelectionService.SCAN_TYPE_LIMITED_SERVICE;
365                 mWwanSelectorCallback.onRequestEmergencyNetworkScan(
366                         mLastPreferredNetworks, mScanType, false, mCancelSignal,
367                         (regResult) -> {
368                             logi("requestScan-onComplete");
369                             sendMessage(obtainMessage(MSG_NETWORK_SCAN_RESULT, regResult));
370                         });
371             } else if ((mPreferredNetworkScanType
372                     == CarrierConfigManager.ImsEmergency.SCAN_TYPE_FULL_SERVICE)
373                     && (mScanType == DomainSelectionService.SCAN_TYPE_FULL_SERVICE)) {
374                 mWwanSelectorCallback.onRequestEmergencyNetworkScan(
375                         mLastPreferredNetworks, mScanType, true, mCancelSignal,
376                         (regResult) -> {
377                             logi("requestScan-onComplete");
378                             sendMessage(obtainMessage(MSG_NETWORK_SCAN_RESULT, regResult));
379                         });
380             } else {
381                 // Continuous scan, do not start a new timer.
382                 requestScan(false);
383             }
384             return;
385         }
386 
387         checkAndSetTerminateAfterCsFailure(result);
388 
389         if (result.getRegState() != REGISTRATION_STATE_HOME
390                 && result.getRegState() != REGISTRATION_STATE_ROAMING) {
391             if (maybeRedialOnTheOtherSlotInNormalService(result)) {
392                 return;
393             }
394         }
395 
396         mLastRegResult = result;
397         removeMessages(MSG_NETWORK_SCAN_TIMEOUT);
398         onWwanNetworkTypeSelected(getAccessNetworkType(result));
399         mCancelSignal = null;
400         maybeModifyScanType(mLastNetworkType);
401     }
402 
403     /**
404      * Determines the scanned network type.
405      *
406      * @param result The result of network scan.
407      * @return The selected network type.
408      */
getAccessNetworkType(EmergencyRegistrationResult result)409     private @RadioAccessNetworkType int getAccessNetworkType(EmergencyRegistrationResult result) {
410         int accessNetworkType = result.getAccessNetwork();
411         if (accessNetworkType != EUTRAN) return accessNetworkType;
412 
413         int regState = result.getRegState();
414 
415         // Emergency is not supported with LTE, but CSFB is possible.
416         if ((regState == REGISTRATION_STATE_HOME || regState == REGISTRATION_STATE_ROAMING)
417                 && isCsDomainOnlyAvailable(result)) {
418             logi("getAccessNetworkType emergency not supported but CSFB is possible");
419             accessNetworkType = UTRAN;
420         }
421 
422         return accessNetworkType;
423     }
424 
isCsDomainOnlyAvailable(EmergencyRegistrationResult result)425     private boolean isCsDomainOnlyAvailable(EmergencyRegistrationResult result) {
426         int domain = result.getDomain();
427         if (domain == NetworkRegistrationInfo.DOMAIN_CS) return true;
428         if ((domain & NetworkRegistrationInfo.DOMAIN_CS) > 0) {
429             // b/341865236, check emcBearer only
430             return (!result.isEmcBearerSupported());
431         }
432         return false;
433     }
434 
435     @Override
reselectDomain(SelectionAttributes attr)436     public void reselectDomain(SelectionAttributes attr) {
437         logi("reselectDomain attr=" + attr);
438         mSelectionAttributes = attr;
439         post(() -> { reselectDomain(); });
440     }
441 
reselectDomain()442     private void reselectDomain() {
443         logi("reselectDomain tryCsWhenPsFails=" + mTryCsWhenPsFails);
444 
445         int cause = getDisconnectCause();
446         mCrossSimRedialingController.notifyCallFailure(cause);
447 
448         if ((cause == EMERGENCY_TEMP_FAILURE && mCrossSimRedialingController.isThereOtherSlot())
449                 || cause == EMERGENCY_PERM_FAILURE) {
450             logi("reselectDomain should redial on the other subscription");
451             terminateSelectionForCrossSimRedialing(cause == EMERGENCY_PERM_FAILURE);
452             return;
453         }
454 
455         if (mCrossStackTimerExpired) {
456             logi("reselectDomain cross stack timer expired");
457             terminateSelectionForCrossSimRedialing(false);
458             return;
459         }
460 
461         if (maybeTerminateSelection(cause)) {
462             logi("reselectDomain terminate selection");
463             return;
464         }
465 
466         mTerminateAfterCsFailure = false;
467 
468         if (mTryCsWhenPsFails) {
469             mTryCsWhenPsFails = false;
470             // Initial state was CSFB available and dial PS failed.
471             // Dial CS for CSFB instead of scanning with CS preferred network list.
472             logi("reselectDomain tryCs=" + accessNetworkTypeToString(mCsNetworkType));
473             if (mCsNetworkType != UNKNOWN) {
474                 mWasCsfbAfterPsFailure = true;
475                 onWwanNetworkTypeSelected(mCsNetworkType);
476                 return;
477             }
478         }
479 
480         if (mWasCsfbAfterPsFailure) {
481             mWasCsfbAfterPsFailure = false;
482             if (preferCsAfterCsfbFailure(cause)) {
483                 // b/299875872, combined attach but EXTENDED_SERVICE_REQUEST failed.
484                 // Try CS preferred scan instead of PS preferred scan.
485                 mLastNetworkType = EUTRAN;
486             }
487         }
488 
489         if (mMaxCellularTimerExpired) {
490             if (mLastTransportType == TRANSPORT_TYPE_WWAN
491                     && maybeDialOverWlan()) {
492                 // Cellular call failed and max cellular search timer expired, so redial on Wi-Fi.
493                 // If this VoWi-Fi fails, the timer shall be restarted on next reselectDomain().
494                 return;
495             } else if (mLastTransportType == TRANSPORT_TYPE_WLAN) {
496                 // Since VoWi-Fi failed, allow for requestScan to restart max cellular timer.
497                 mMaxCellularTimerExpired = false;
498             }
499         }
500 
501         if (mLastTransportType == TRANSPORT_TYPE_WWAN) {
502             if (mLastNetworkType == NGRAN && (!mTryEsFallback) && mLtePreferredAfterNrFailure) {
503                 int state = mEpdnHelper.getDataConnectionState(getSlotId());
504                 if (state != DATA_DISCONNECTED && state != DATA_UNKNOWN) {
505                     mIsWaitingForDataDisconnection = true;
506                     // If deactivation of ePDN has been started, then wait for the disconnection
507                     // with the timeout of 2 seconds and then request network scan.
508                     // If deactivation of ePDN hasn't been started yet, then wait for the start
509                     // of the deactivation with the timeout of 2 seconds.
510                     // The timer shall be restarted in notifyDataConnectionStateChange()
511                     // when starting the deactivation.
512                     sendEmptyMessageDelayed(MSG_WAIT_DISCONNECTION_TIMEOUT,
513                             DEFAULT_DATA_DISCONNECTION_TIMEOUT_MS);
514                     mDomainSelected = false;
515                     return;
516                 }
517             }
518         }
519 
520         if (mLastTransportType == TRANSPORT_TYPE_WLAN) {
521             // Dialing over Wi-Fi failed. Try scanning cellular networks.
522             onWwanSelected(this::reselectDomainInternal);
523             return;
524         }
525 
526         if (mLastNetworkType == EUTRAN && mLastRegResult != null
527                 && mSelectionAttributes.getPsDisconnectCause() != null
528                 && !mScanLimitedOnlyAfterVolteFailure
529                 && !mSwitchRatPreferenceWithLocalNotRegistered) {
530             int regState = mLastRegResult.getRegState();
531             int reasonCode = mSelectionAttributes.getPsDisconnectCause().getCode();
532             if (reasonCode == ImsReasonInfo.CODE_LOCAL_NOT_REGISTERED
533                     && regState != REGISTRATION_STATE_HOME
534                     && regState != REGISTRATION_STATE_ROAMING
535                     && isSimReady()) {
536                 // b/326292100, ePDN setup failed in limited state, request PS preferred scan.
537                 mLastNetworkType = UNKNOWN;
538                 mSwitchRatPreferenceWithLocalNotRegistered = true;
539             }
540         }
541 
542         requestScan(true);
543         mDomainSelected = false;
544     }
545 
preferCsAfterCsfbFailure(int cause)546     private boolean preferCsAfterCsfbFailure(int cause) {
547         if (cause != SERVICE_OPTION_NOT_AVAILABLE) return false;
548         if (sPreferCsAfterCsfbFailure == null || mLastRegResult == null
549                 || TextUtils.isEmpty(mLastRegResult.getCountryIso())) {
550             // Enabled by default if country is not identified.
551             return true;
552         }
553 
554         return sPreferCsAfterCsfbFailure.contains(mLastRegResult.getCountryIso());
555     }
556 
getDisconnectCause()557     private int getDisconnectCause() {
558         int cause = mSelectionAttributes.getCsDisconnectCause();
559 
560         ImsReasonInfo reasonInfo = mSelectionAttributes.getPsDisconnectCause();
561         if (reasonInfo != null) {
562             switch (reasonInfo.getCode()) {
563                 case ImsReasonInfo.CODE_EMERGENCY_TEMP_FAILURE:
564                     cause = EMERGENCY_TEMP_FAILURE;
565                     break;
566                 case ImsReasonInfo.CODE_EMERGENCY_PERM_FAILURE:
567                     cause = EMERGENCY_PERM_FAILURE;
568                     break;
569                 default:
570                     break;
571             }
572         }
573         return cause;
574     }
575 
reselectDomainInternal()576     private void reselectDomainInternal() {
577         post(() -> {
578             if (mDestroyed) return;
579             requestScan(true, false, true);
580             mDomainSelected = false;
581         });
582     }
583 
requestScanDelayed()584     private void requestScanDelayed() {
585         logi("requestScanDelayed waiting=" + mIsWaitingForDataDisconnection);
586         if (!mDestroyed && mIsWaitingForDataDisconnection) {
587             requestScan(true);
588             removeMessages(MSG_WAIT_DISCONNECTION_TIMEOUT);
589         }
590         mIsWaitingForDataDisconnection = false;
591     }
592 
593     @Override
finishSelection()594     public void finishSelection() {
595         logi("finishSelection");
596         destroy();
597     }
598 
599     @Override
onBarringInfoUpdated(BarringInfo barringInfo)600     public void onBarringInfoUpdated(BarringInfo barringInfo) {
601         if (mDestroyed) return;
602 
603         mBarringInfoReceived = true;
604         BarringInfo.BarringServiceInfo serviceInfo =
605                 barringInfo.getBarringServiceInfo(BARRING_SERVICE_TYPE_EMERGENCY);
606         mIsEmergencyBarred = serviceInfo.isBarred();
607         logi("onBarringInfoUpdated emergencyBarred=" + mIsEmergencyBarred
608                 + ", serviceInfo=" + serviceInfo);
609         selectDomain();
610     }
611 
612     @Override
selectDomain(SelectionAttributes attr, TransportSelectorCallback cb)613     public void selectDomain(SelectionAttributes attr, TransportSelectorCallback cb) {
614         logi("selectDomain attr=" + attr);
615         mTransportSelectorCallback = cb;
616         mSelectionAttributes = attr;
617         mLastRegResult = mSelectionAttributes.getEmergencyRegistrationResult();
618 
619         TelephonyManager tm = mContext.getSystemService(TelephonyManager.class);
620         mModemCount = tm.getActiveModemCount();
621 
622         sendEmptyMessage(MSG_START_DOMAIN_SELECTION);
623     }
624 
startDomainSelection()625     private void startDomainSelection() {
626         logi("startDomainSelection modemCount=" + mModemCount);
627         readResourceConfiguration();
628         updateCarrierConfiguration();
629         mDomainSelectionRequested = true;
630         startCrossStackTimer();
631         if (SubscriptionManager.isValidSubscriptionId(getSubId())) {
632             if (mCallSetupTimerOnCurrentRat > 0) {
633                 mImsEmergencyRegistrationHelper.start();
634             }
635             sendEmptyMessageDelayed(MSG_WAIT_FOR_IMS_STATE_TIMEOUT,
636                     DEFAULT_WAIT_FOR_IMS_STATE_TIMEOUT_MS);
637             selectDomain();
638         } else {
639             logi("startDomainSelection invalid subId");
640             onImsRegistrationStateChanged();
641             onImsMmTelCapabilitiesChanged();
642         }
643     }
644 
handleWaitForImsStateTimeout()645     private void handleWaitForImsStateTimeout() {
646         logi("handleWaitForImsStateTimeout");
647         onImsRegistrationStateChanged();
648         onImsMmTelCapabilitiesChanged();
649     }
650 
651     @Override
onImsMmTelFeatureAvailableChanged()652     public void onImsMmTelFeatureAvailableChanged() {
653         // DOMAIN_CS shall be selected when ImsService is not available.
654         // TODO(b/258289015) Recover the temporary failure in ImsService connection.
655     }
656 
657     @Override
onImsRegistrationStateChanged()658     public void onImsRegistrationStateChanged() {
659         mImsRegStateReceived = true;
660         mImsRegistered = mImsStateTracker.isImsRegistered();
661         logi("onImsRegistrationStateChanged " + mImsRegistered);
662         selectDomain();
663         handleImsStateChange();
664     }
665 
666     @Override
onImsMmTelCapabilitiesChanged()667     public void onImsMmTelCapabilitiesChanged() {
668         mMmTelCapabilitiesReceived = true;
669         mIsVoiceCapable = mImsStateTracker.isImsVoiceCapable();
670         logi("onImsMmTelCapabilitiesChanged " + mIsVoiceCapable);
671         selectDomain();
672         handleImsStateChange();
673     }
674 
handleImsStateChange()675     private void handleImsStateChange() {
676         if (!mVoWifiOverEmergencyPdn && !mDomainSelected
677                 && (mMaxCellularTimerExpired || mNetworkScanTimerExpired)) {
678             maybeDialOverWlan();
679         }
680     }
681 
isSimReady()682     private boolean isSimReady() {
683         if (!SubscriptionManager.isValidSubscriptionId(getSubId())) return false;
684         TelephonyManager tm = mContext.getSystemService(TelephonyManager.class);
685         return tm.getSimState(getSlotId()) == TelephonyManager.SIM_STATE_READY;
686     }
687 
688     /**
689      * Caches the configuration.
690      */
updateCarrierConfiguration()691     private void updateCarrierConfiguration() {
692         CarrierConfigManager configMgr = mContext.getSystemService(CarrierConfigManager.class);
693         PersistableBundle b = configMgr.getConfigForSubId(getSubId(),
694                 KEY_EMERGENCY_OVER_IMS_SUPPORTED_3GPP_NETWORK_TYPES_INT_ARRAY,
695                 KEY_EMERGENCY_OVER_IMS_ROAMING_SUPPORTED_3GPP_NETWORK_TYPES_INT_ARRAY,
696                 KEY_EMERGENCY_OVER_CS_SUPPORTED_ACCESS_NETWORK_TYPES_INT_ARRAY,
697                 KEY_EMERGENCY_OVER_CS_ROAMING_SUPPORTED_ACCESS_NETWORK_TYPES_INT_ARRAY,
698                 KEY_EMERGENCY_DOMAIN_PREFERENCE_INT_ARRAY,
699                 KEY_EMERGENCY_DOMAIN_PREFERENCE_ROAMING_INT_ARRAY,
700                 KEY_PREFER_IMS_EMERGENCY_WHEN_VOICE_CALLS_ON_CS_BOOL,
701                 KEY_EMERGENCY_VOWIFI_REQUIRES_CONDITION_INT,
702                 KEY_EMERGENCY_SCAN_TIMER_SEC_INT,
703                 KEY_MAXIMUM_CELLULAR_SEARCH_TIMER_SEC_INT,
704                 KEY_MAXIMUM_NUMBER_OF_EMERGENCY_TRIES_OVER_VOWIFI_INT,
705                 KEY_EMERGENCY_CALL_OVER_EMERGENCY_PDN_BOOL,
706                 KEY_EMERGENCY_NETWORK_SCAN_TYPE_INT,
707                 KEY_EMERGENCY_CALL_SETUP_TIMER_ON_CURRENT_NETWORK_SEC_INT,
708                 KEY_EMERGENCY_REQUIRES_IMS_REGISTRATION_BOOL,
709                 KEY_EMERGENCY_REQUIRES_VOLTE_ENABLED_BOOL,
710                 KEY_EMERGENCY_LTE_PREFERRED_AFTER_NR_FAILED_BOOL,
711                 KEY_SCAN_LIMITED_SERVICE_AFTER_VOLTE_FAILURE_BOOL,
712                 KEY_IMS_REASONINFO_CODE_TO_RETRY_EMERGENCY_INT_ARRAY,
713                 KEY_CARRIER_VOLTE_TTY_SUPPORTED_BOOL,
714                 KEY_EMERGENCY_CDMA_PREFERRED_NUMBERS_STRING_ARRAY);
715         if (b == null) {
716             b = CarrierConfigManager.getDefaultConfig();
717         }
718 
719         mImsRatsConfig =
720                 b.getIntArray(KEY_EMERGENCY_OVER_IMS_SUPPORTED_3GPP_NETWORK_TYPES_INT_ARRAY);
721         mImsRoamRatsConfig = b.getIntArray(
722                 KEY_EMERGENCY_OVER_IMS_ROAMING_SUPPORTED_3GPP_NETWORK_TYPES_INT_ARRAY);
723 
724         mCsRatsConfig =
725                 b.getIntArray(KEY_EMERGENCY_OVER_CS_SUPPORTED_ACCESS_NETWORK_TYPES_INT_ARRAY);
726         mCsRoamRatsConfig = b.getIntArray(
727                 KEY_EMERGENCY_OVER_CS_ROAMING_SUPPORTED_ACCESS_NETWORK_TYPES_INT_ARRAY);
728         mDomainPreference = b.getIntArray(KEY_EMERGENCY_DOMAIN_PREFERENCE_INT_ARRAY);
729         mDomainPreferenceRoam = b.getIntArray(KEY_EMERGENCY_DOMAIN_PREFERENCE_ROAMING_INT_ARRAY);
730         mPreferImsWhenCallsOnCs = b.getBoolean(
731                 KEY_PREFER_IMS_EMERGENCY_WHEN_VOICE_CALLS_ON_CS_BOOL);
732         mVoWifiRequiresCondition = b.getInt(KEY_EMERGENCY_VOWIFI_REQUIRES_CONDITION_INT);
733         mScanTimeout = b.getInt(KEY_EMERGENCY_SCAN_TIMER_SEC_INT) * 1000;
734         mMaxCellularTimeout = b.getInt(KEY_MAXIMUM_CELLULAR_SEARCH_TIMER_SEC_INT) * 1000;
735         mMaxNumOfVoWifiTries = b.getInt(KEY_MAXIMUM_NUMBER_OF_EMERGENCY_TRIES_OVER_VOWIFI_INT);
736         mVoWifiOverEmergencyPdn = b.getBoolean(KEY_EMERGENCY_CALL_OVER_EMERGENCY_PDN_BOOL);
737         mPreferredNetworkScanType = b.getInt(KEY_EMERGENCY_NETWORK_SCAN_TYPE_INT);
738         mCallSetupTimerOnCurrentRat = b.getInt(
739                 KEY_EMERGENCY_CALL_SETUP_TIMER_ON_CURRENT_NETWORK_SEC_INT) * 1000;
740         mRequiresImsRegistration = b.getBoolean(KEY_EMERGENCY_REQUIRES_IMS_REGISTRATION_BOOL);
741         mRequiresVoLteEnabled = b.getBoolean(KEY_EMERGENCY_REQUIRES_VOLTE_ENABLED_BOOL);
742         mLtePreferredAfterNrFailure = b.getBoolean(
743                 KEY_EMERGENCY_LTE_PREFERRED_AFTER_NR_FAILED_BOOL);
744         mScanLimitedOnlyAfterVolteFailure = b.getBoolean(
745                 KEY_SCAN_LIMITED_SERVICE_AFTER_VOLTE_FAILURE_BOOL);
746         String[] numbers = b.getStringArray(KEY_EMERGENCY_CDMA_PREFERRED_NUMBERS_STRING_ARRAY);
747         int[] imsReasonCodes =
748                 b.getIntArray(KEY_IMS_REASONINFO_CODE_TO_RETRY_EMERGENCY_INT_ARRAY);
749         boolean ttySupported = b.getBoolean(KEY_CARRIER_VOLTE_TTY_SUPPORTED_BOOL);
750         mNonTtyOrTtySupported = isNonTtyOrTtySupported(ttySupported);
751 
752         if (mImsRatsConfig == null) mImsRatsConfig = new int[0];
753         if (mCsRatsConfig == null) mCsRatsConfig = new int[0];
754         if (mImsRoamRatsConfig == null) mImsRoamRatsConfig = new int[0];
755         if (mCsRoamRatsConfig == null) mCsRoamRatsConfig = new int[0];
756         if (mDomainPreference == null) mDomainPreference = new int[0];
757         if (mDomainPreferenceRoam == null) mDomainPreferenceRoam = new int[0];
758         if (numbers == null) numbers = new String[0];
759         if (imsReasonCodes == null) imsReasonCodes = new int[0];
760 
761         mRetryReasonCodes = Arrays.stream(imsReasonCodes).boxed().collect(Collectors.toList());
762         mRetryReasonCodes.addAll(sDefaultRetryReasonCodes);
763 
764         logi("updateCarrierConfiguration "
765                 + "imsRats=" + arrayToString(mImsRatsConfig,
766                         EmergencyCallDomainSelector::accessNetworkTypeToString)
767                 + ", csRats=" + arrayToString(mCsRatsConfig,
768                         EmergencyCallDomainSelector::accessNetworkTypeToString)
769                 + ", imsRoamRats=" + arrayToString(mImsRoamRatsConfig,
770                         EmergencyCallDomainSelector::accessNetworkTypeToString)
771                 + ", csRoamRats=" + arrayToString(mCsRoamRatsConfig,
772                         EmergencyCallDomainSelector::accessNetworkTypeToString)
773                 + ", domainPref=" + arrayToString(mDomainPreference,
774                         EmergencyCallDomainSelector::domainPreferenceToString)
775                 + ", domainPrefRoam=" + arrayToString(mDomainPreferenceRoam,
776                         EmergencyCallDomainSelector::domainPreferenceToString)
777                 + ", preferImsOnCs=" + mPreferImsWhenCallsOnCs
778                 + ", voWifiRequiresCondition=" + mVoWifiRequiresCondition
779                 + ", scanTimeout=" + mScanTimeout
780                 + ", maxCellularTimeout=" + mMaxCellularTimeout
781                 + ", maxNumOfVoWifiTries=" + mMaxNumOfVoWifiTries
782                 + ", voWifiOverEmergencyPdn=" + mVoWifiOverEmergencyPdn
783                 + ", preferredScanType=" + carrierConfigNetworkScanTypeToString(
784                         mPreferredNetworkScanType)
785                 + ", callSetupTimer=" + mCallSetupTimerOnCurrentRat
786                 + ", requiresImsReg=" + mRequiresImsRegistration
787                 + ", requiresVoLteEnabled=" + mRequiresVoLteEnabled
788                 + ", ltePreferredAfterNr=" + mLtePreferredAfterNrFailure
789                 + ", scanLimitedOnly=" + mScanLimitedOnlyAfterVolteFailure
790                 + ", retryReasonCodes=" + mRetryReasonCodes
791                 + ", ttySupported=" + ttySupported
792                 + ", cdmaPreferredNumbers=" + arrayToString(numbers));
793 
794         mCdmaPreferredNumbers = Arrays.asList(numbers);
795 
796         if ((mPreferredNetworkScanType == CarrierConfigManager.ImsEmergency.SCAN_TYPE_FULL_SERVICE)
797                 || (mPreferredNetworkScanType
798                         == SCAN_TYPE_FULL_SERVICE_FOLLOWED_BY_LIMITED_SERVICE)) {
799             mScanType = DomainSelectionService.SCAN_TYPE_FULL_SERVICE;
800         } else {
801             mScanType = DomainSelectionService.SCAN_TYPE_NO_PREFERENCE;
802         }
803     }
804 
805     /**
806      * Caches the resource configuration.
807      */
readResourceConfiguration()808     private void readResourceConfiguration() {
809         if (sSimReadyAllowList == null) {
810             sSimReadyAllowList = readResourceConfiguration(
811                     R.array.config_countries_require_sim_for_emergency);
812         }
813         logi("readResourceConfiguration simReadyCountries=" + sSimReadyAllowList);
814 
815         if (sPreferSlotWithNormalServiceList == null) {
816             sPreferSlotWithNormalServiceList = readResourceConfiguration(
817                     R.array.config_countries_prefer_normal_service_capable_subscription);
818         }
819         logi("readResourceConfiguration preferNormalServiceCountries="
820                 + sPreferSlotWithNormalServiceList);
821 
822         if (sPreferCsAfterCsfbFailure == null) {
823             sPreferCsAfterCsfbFailure = readResourceConfiguration(
824                     R.array.config_countries_prefer_cs_preferred_scan_after_csfb_failure);
825         }
826         logi("readResourceConfiguration preferCsAfterCsfbFailure="
827                 + sPreferCsAfterCsfbFailure);
828 
829         if (sPreferGeranWhenSimAbsent == null) {
830             sPreferGeranWhenSimAbsent = readResourceConfiguration(
831                     R.array.config_countries_prefer_geran_when_sim_absent);
832         }
833         logi("readResourceConfiguration preferGeranWhenSimAbsent="
834                 + sPreferGeranWhenSimAbsent);
835     }
836 
readResourceConfiguration(int id)837     private List<String> readResourceConfiguration(int id) {
838         logi("readResourceConfiguration id=" + id);
839 
840         List<String> resource = null;
841         try {
842             resource = Arrays.asList(mContext.getResources().getStringArray(id));
843         } catch (Resources.NotFoundException nfe) {
844             loge("readResourceConfiguration exception=" + nfe);
845         } catch (NullPointerException npe) {
846             loge("readResourceConfiguration exception=" + npe);
847         } finally {
848             if (resource == null) {
849                 resource = new ArrayList<String>();
850             }
851         }
852         return resource;
853     }
854 
855     /** For test purpose only */
856     @VisibleForTesting
clearResourceConfiguration()857     public void clearResourceConfiguration() {
858         sSimReadyAllowList = null;
859         sPreferSlotWithNormalServiceList = null;
860         sPreferCsAfterCsfbFailure = null;
861         sPreferGeranWhenSimAbsent = null;
862     }
863 
selectDomain()864     private void selectDomain() {
865         // State updated right after creation.
866         if (!mDomainSelectionRequested) return;
867 
868         if (!mBarringInfoReceived || !mImsRegStateReceived || !mMmTelCapabilitiesReceived) {
869             logi("selectDomain not received"
870                     + " BarringInfo, IMS registration state, or MMTEL capabilities");
871             return;
872         }
873         removeMessages(MSG_WAIT_FOR_IMS_STATE_TIMEOUT);
874 
875         // The statements below should be executed only once to select domain from initial state.
876         // Next domain selection shall be triggered by reselectDomain().
877         // However, selectDomain() can be called by change of IMS service state and Barring status
878         // at any time. mIsScanRequested and mDomainSelected are not enough since there are cases
879         // when neither mIsScanRequested nor mDomainSelected is set though selectDomain() has been
880         // executed already.
881         // Reset mDomainSelectionRequested to avoid redundant execution of selectDomain().
882         mDomainSelectionRequested = false;
883 
884         if (!allowEmergencyCalls(mSelectionAttributes.getEmergencyRegistrationResult())) {
885             // Detected the country and found that emergency calls are not allowed with this slot.
886             terminateSelectionPermanentlyForSlot();
887             return;
888         }
889 
890         if (isWifiPreferred()
891                 || isInEmergencyCallbackModeOnWlan()) {
892             onWlanSelected();
893             return;
894         }
895 
896         onWwanSelected(this::selectDomainInternal);
897     }
898 
selectDomainInternal()899     private void selectDomainInternal() {
900         post(this::selectDomainFromInitialState);
901     }
902 
selectDomainFromInitialState()903     private void selectDomainFromInitialState() {
904         if (mDestroyed) return;
905 
906         if (isInEmergencyCallbackModeOnPsWwan()) {
907             logi("selectDomain PS cellular connected in ECBM");
908             mPsNetworkType = EUTRAN;
909             onWwanNetworkTypeSelected(mPsNetworkType);
910             return;
911         }
912 
913         boolean csInService = isCsInService();
914         boolean psInService = isPsInService();
915 
916         if (!csInService && !psInService) {
917             if (maybeRedialOnTheOtherSlotInNormalService(mLastRegResult)) {
918                 return;
919             }
920             mCsNetworkType = getSelectableCsNetworkType();
921             mPsNetworkType = getSelectablePsNetworkType(false);
922             logi("selectDomain limited service ps=" + accessNetworkTypeToString(mPsNetworkType)
923                     + ", cs=" + accessNetworkTypeToString(mCsNetworkType));
924             if (!isInRoaming()
925                     && (mPreferredNetworkScanType
926                             == CarrierConfigManager.ImsEmergency.SCAN_TYPE_FULL_SERVICE)) {
927                 requestScan(true);
928                 return;
929             }
930             if (mPsNetworkType != UNKNOWN) {
931                 onWwanNetworkTypeSelected(mPsNetworkType);
932             } else if (mCsNetworkType != UNKNOWN) {
933                 checkAndSetTerminateAfterCsFailure(mLastRegResult);
934                 onWwanNetworkTypeSelected(mCsNetworkType);
935             } else {
936                 requestScan(true);
937             }
938             maybeModifyScanType(mLastNetworkType);
939             return;
940         }
941 
942         // Domain selection per 3GPP TS 23.167 Table H.1.
943         // PS is preferred in case selection between CS and PS is implementation option.
944         mCsNetworkType = UNKNOWN;
945         mPsNetworkType = UNKNOWN;
946         if (csInService) mCsNetworkType = getSelectableCsNetworkType();
947         if (psInService) mPsNetworkType = getSelectablePsNetworkType(true);
948 
949         boolean csAvailable = mCsNetworkType != UNKNOWN;
950         boolean psAvailable = mPsNetworkType != UNKNOWN;
951 
952         logi("selectDomain CS={" + csInService + ", " + accessNetworkTypeToString(mCsNetworkType)
953                 + "}, PS={" + psInService + ", " + accessNetworkTypeToString(mPsNetworkType) + "}");
954         if (csAvailable && psAvailable) {
955             if (mSelectionAttributes.isExitedFromAirplaneMode()
956                     || mPreferImsWhenCallsOnCs || isImsRegisteredWithVoiceCapability()) {
957                 mTryCsWhenPsFails = true;
958                 onWwanNetworkTypeSelected(mPsNetworkType);
959             } else if (isDeactivatedSim()) {
960                 // Deactivated SIM but PS is in service and supports emergency calls.
961                 onWwanNetworkTypeSelected(mPsNetworkType);
962             } else {
963                 onWwanNetworkTypeSelected(mCsNetworkType);
964             }
965         } else if (psAvailable) {
966             mTryEsFallback = (mPsNetworkType == NGRAN) && isEsFallbackAvailable();
967             if (mSelectionAttributes.isExitedFromAirplaneMode()
968                     || !mRequiresImsRegistration || isImsRegisteredWithVoiceCapability()) {
969                 onWwanNetworkTypeSelected(mPsNetworkType);
970             } else if (isDeactivatedSim()) {
971                 // Deactivated SIM but PS is in service and supports emergency calls.
972                 onWwanNetworkTypeSelected(mPsNetworkType);
973             } else {
974                 // Carrier configuration requires IMS registration for emergency services over PS,
975                 // but not registered. Try CS emergency call.
976                 mTryEsFallback = false;
977                 requestScan(true, true);
978             }
979         } else if (csAvailable) {
980             onWwanNetworkTypeSelected(mCsNetworkType);
981         } else {
982             // PS is in service but not supports emergency calls.
983             if (!mSelectionAttributes.isExitedFromAirplaneMode()
984                     && mRequiresImsRegistration && !isImsRegisteredWithVoiceCapability()) {
985                 // Carrier configuration requires IMS registration for emergency services over PS,
986                 // but not registered. Try CS emergency call.
987                 requestScan(true, true);
988             } else {
989                 mTryEsFallback = isEsFallbackAvailable();
990                 requestScan(true);
991             }
992         }
993         maybeModifyScanType(mLastNetworkType);
994     }
995 
996     /**
997      * Requests network scan.
998      *
999      * @param startVoWifiTimer Indicates whether a VoWifi timer will be started.
1000      */
requestScan(boolean startVoWifiTimer)1001     private void requestScan(boolean startVoWifiTimer) {
1002         requestScan(startVoWifiTimer, false);
1003     }
1004 
1005     /**
1006      * Requests network scan.
1007      *
1008      * @param startVoWifiTimer Indicates whether a VoWifi timer will be started.
1009      * @param csPreferred Indicates whether CS preferred scan is requested.
1010      */
requestScan(boolean startVoWifiTimer, boolean csPreferred)1011     private void requestScan(boolean startVoWifiTimer, boolean csPreferred) {
1012         requestScan(startVoWifiTimer, csPreferred, false);
1013     }
1014 
1015     /**
1016      * Requests network scan.
1017      *
1018      * @param startVoWifiTimer Indicates whether a VoWifi timer will be started.
1019      * @param csPreferred Indicates whether CS preferred scan is requested.
1020      * @param wifiFailed Indicates dialing over Wi-Fi has failed.
1021      */
requestScan(boolean startVoWifiTimer, boolean csPreferred, boolean wifiFailed)1022     private void requestScan(boolean startVoWifiTimer, boolean csPreferred, boolean wifiFailed) {
1023         logi("requestScan timer=" + startVoWifiTimer + ", csPreferred=" + csPreferred
1024                 + ", wifiFailed=" + wifiFailed);
1025 
1026         mCancelSignal = new CancellationSignal();
1027         // In case dialing over Wi-Fi has failed, do not the change the domain preference.
1028         if (!wifiFailed || mLastPreferredNetworks == null) {
1029             mLastPreferredNetworks = getNextPreferredNetworks(csPreferred, mTryEsFallback);
1030         }
1031         mTryEsFallback = false;
1032 
1033         if (isInRoaming()
1034                 && (mPreferredNetworkScanType
1035                         == CarrierConfigManager.ImsEmergency.SCAN_TYPE_FULL_SERVICE)) {
1036             // FULL_SERVICE only preference is available only when not in roaming.
1037             mScanType = DomainSelectionService.SCAN_TYPE_NO_PREFERENCE;
1038         }
1039 
1040         mIsScanRequested = true;
1041         mWwanSelectorCallback.onRequestEmergencyNetworkScan(
1042                 mLastPreferredNetworks, mScanType, false, mCancelSignal,
1043                 (result) -> {
1044                     logi("requestScan-onComplete");
1045                     sendMessage(obtainMessage(MSG_NETWORK_SCAN_RESULT, result));
1046                 });
1047 
1048         if (startVoWifiTimer && isSimReady()) {
1049             if (isEmcOverWifiSupported()
1050                     && mScanTimeout > 0 && mVoWifiTrialCount < mMaxNumOfVoWifiTries) {
1051                 logi("requestScan start scan timer");
1052                 // remove any pending timers.
1053                 removeMessages(MSG_NETWORK_SCAN_TIMEOUT);
1054                 sendEmptyMessageDelayed(MSG_NETWORK_SCAN_TIMEOUT, mScanTimeout);
1055                 registerForConnectivityChanges();
1056             }
1057         }
1058         if (!mMaxCellularTimerExpired && !hasMessages(MSG_MAX_CELLULAR_TIMEOUT)) {
1059             startMaxCellularTimer();
1060         }
1061     }
1062 
1063     /**
1064      * Gets the list of preferred network type for the new scan request.
1065      *
1066      * @param csPreferred Indicates whether CS preferred scan is requested.
1067      * @param tryEsFallback Indicates whether scan requested for ES fallback.
1068      * @return The list of preferred network types.
1069      */
1070     @VisibleForTesting
getNextPreferredNetworks(boolean csPreferred, boolean tryEsFallback)1071     public @RadioAccessNetworkType List<Integer> getNextPreferredNetworks(boolean csPreferred,
1072             boolean tryEsFallback) {
1073         if (mRequiresVoLteEnabled && !isAdvancedCallingSettingEnabled()) {
1074             // Emergency call over IMS is not supported.
1075             logi("getNextPreferredNetworks VoLte setting is not enabled.");
1076             return generatePreferredNetworks(getCsNetworkTypeConfiguration());
1077         }
1078 
1079         List<Integer> preferredNetworks = new ArrayList<>();
1080 
1081         List<Integer> domains = getDomainPreference();
1082         int psPriority = domains.indexOf(DOMAIN_PS_3GPP);
1083         int csPriority = domains.indexOf(DOMAIN_CS);
1084         logi("getNextPreferredNetworks psPriority=" + psPriority + ", csPriority=" + csPriority
1085                 + ", csPreferred=" + csPreferred + ", esFallback=" + tryEsFallback
1086                 + ", lastNetworkType=" + accessNetworkTypeToString(mLastNetworkType));
1087 
1088         if (mLastRegResult != null
1089                 && sPreferGeranWhenSimAbsent.contains(mLastRegResult.getCountryIso())
1090                 && !isSimReady()) {
1091             logi("getNextPreferredNetworks preferGeran");
1092             preferredNetworks.add(GERAN);
1093             preferredNetworks.add(UTRAN);
1094             preferredNetworks.add(EUTRAN);
1095             preferredNetworks.add(NGRAN);
1096             return preferredNetworks;
1097         }
1098 
1099         if (!csPreferred && (mLastNetworkType == UNKNOWN || tryEsFallback)) {
1100             // Generate the list per the domain preference.
1101 
1102             if (psPriority == NOT_SUPPORTED && csPriority == NOT_SUPPORTED) {
1103                 // should not reach here. However, to avoid unexpected problems.
1104                 preferredNetworks = generatePreferredNetworks(getCsNetworkTypeConfiguration(),
1105                         getImsNetworkTypeConfiguration());
1106             } else if (psPriority == NOT_SUPPORTED && csPriority > NOT_SUPPORTED) {
1107                 // CS networks only.
1108                 preferredNetworks = generatePreferredNetworks(getCsNetworkTypeConfiguration());
1109             } else if (psPriority > NOT_SUPPORTED && csPriority == NOT_SUPPORTED) {
1110                 // PS networks only.
1111                 preferredNetworks = generatePreferredNetworks(getImsNetworkTypeConfiguration());
1112             } else if (psPriority < csPriority) {
1113                 // PS preferred.
1114                 preferredNetworks = generatePreferredNetworks(getImsNetworkTypeConfiguration(),
1115                         getCsNetworkTypeConfiguration());
1116             } else {
1117                 // CS preferred.
1118                 preferredNetworks = generatePreferredNetworks(getCsNetworkTypeConfiguration(),
1119                         getImsNetworkTypeConfiguration());
1120             }
1121 
1122             // Make NGRAN have the lowest priority
1123             if (tryEsFallback && preferredNetworks.contains(NGRAN)) {
1124                 preferredNetworks.remove(Integer.valueOf(NGRAN));
1125                 preferredNetworks.add(NGRAN);
1126             }
1127         } else if (csPreferred || mLastNetworkType == EUTRAN || mLastNetworkType == NGRAN) {
1128             if (!csPreferred && mLastNetworkType == NGRAN && mLtePreferredAfterNrFailure) {
1129                 // LTE is preferred after dialing over NR failed.
1130                 preferredNetworks = generatePreferredNetworks(getImsNetworkTypeConfiguration(),
1131                         getCsNetworkTypeConfiguration());
1132                 // Make NGRAN have the lowest priority
1133                 if (preferredNetworks.contains(NGRAN)) {
1134                     preferredNetworks.remove(Integer.valueOf(NGRAN));
1135                     preferredNetworks.add(NGRAN);
1136                 }
1137             } else  if (csPriority > NOT_SUPPORTED) {
1138                 // PS tried, generate the list with CS preferred.
1139                 preferredNetworks = generatePreferredNetworks(getCsNetworkTypeConfiguration(),
1140                         getImsNetworkTypeConfiguration());
1141             } else {
1142                 // CS not suppored.
1143                 preferredNetworks = generatePreferredNetworks(getImsNetworkTypeConfiguration());
1144             }
1145         } else {
1146             // CS tried, generate the list with PS preferred.
1147             if (psPriority > NOT_SUPPORTED) {
1148                 preferredNetworks = generatePreferredNetworks(getImsNetworkTypeConfiguration(),
1149                         getCsNetworkTypeConfiguration());
1150             } else {
1151                 // PS not suppored.
1152                 preferredNetworks = generatePreferredNetworks(getCsNetworkTypeConfiguration());
1153             }
1154         }
1155 
1156         // Adds NGRAN at the end of the list if SIM is absent or locked and NGRAN is not included.
1157         if (!isSimReady() && !preferredNetworks.contains(NGRAN)) {
1158             preferredNetworks.add(NGRAN);
1159         }
1160 
1161         if (!mNonTtyOrTtySupported) {
1162             logi("getNextPreferredNetworks adjust for TTY");
1163             preferredNetworks.remove(Integer.valueOf(NGRAN));
1164             preferredNetworks.remove(Integer.valueOf(EUTRAN));
1165             if (preferredNetworks.isEmpty()) {
1166                 preferredNetworks.add(Integer.valueOf(UTRAN));
1167                 preferredNetworks.add(Integer.valueOf(GERAN));
1168             }
1169         }
1170         return preferredNetworks;
1171     }
1172 
generatePreferredNetworks(List<Integer>....lists)1173     private @RadioAccessNetworkType List<Integer> generatePreferredNetworks(List<Integer>...lists) {
1174         List<Integer> preferredNetworks = new ArrayList<>();
1175         for (List<Integer> list : lists) {
1176             preferredNetworks.addAll(list);
1177         }
1178 
1179         return preferredNetworks;
1180     }
1181 
handleWifiAvailable()1182     private void handleWifiAvailable() {
1183         if (!mDomainSelected && (mMaxCellularTimerExpired || mNetworkScanTimerExpired)) {
1184             maybeDialOverWlan();
1185         }
1186     }
1187 
handleMaxCellularTimeout()1188     private void handleMaxCellularTimeout() {
1189         logi("handleMaxCellularTimeout");
1190         if (mVoWifiTrialCount >= mMaxNumOfVoWifiTries) {
1191             logi("handleMaxCellularTimeout already tried maximum");
1192             return;
1193         }
1194 
1195         mMaxCellularTimerExpired = true;
1196 
1197         if (mDomainSelected) {
1198             // Dialing is already requested.
1199             logi("handleMaxCellularTimeout wait for reselectDomain");
1200             return;
1201         }
1202 
1203         if (!maybeDialOverWlan()) {
1204             logd("handleMaxCellularTimeout VoWi-Fi is not available");
1205         }
1206     }
1207 
handleNetworkScanTimeout()1208     private void handleNetworkScanTimeout() {
1209         logi("handleNetworkScanTimeout");
1210         mNetworkScanTimerExpired = true;
1211         maybeDialOverWlan();
1212     }
1213 
maybeDialOverWlan()1214     private boolean maybeDialOverWlan() {
1215         boolean available = mWiFiAvailable;
1216         logi("maybeDialOverWlan overEmergencyPdn=" + mVoWifiOverEmergencyPdn
1217                 + ", wifiAvailable=" + available);
1218         if (mVoWifiOverEmergencyPdn) {
1219             // SOS APN
1220             if (!available && isImsRegisteredOverCrossSim()) {
1221                 available = true;
1222             }
1223             if (available) {
1224                 switch (mVoWifiRequiresCondition) {
1225                     case VOWIFI_REQUIRES_SETTING_ENABLED:
1226                         available = isWifiCallingSettingEnabled();
1227                         break;
1228                     case VOWIFI_REQUIRES_VALID_EID:
1229                         available = isWifiCallingActivated();
1230                         break;
1231                     default:
1232                         break;
1233                 }
1234             }
1235         } else {
1236             // IMS APN. When IMS is already registered over Wi-Fi.
1237             available = isImsRegisteredWithVoiceCapability() && isImsRegisteredOverWifi();
1238         }
1239 
1240         logi("maybeDialOverWlan VoWi-Fi available=" + available);
1241         if (available) {
1242             if (mCancelSignal != null) {
1243                 mCancelSignal.cancel();
1244                 mCancelSignal = null;
1245             }
1246             onWlanSelected();
1247         }
1248 
1249         return available;
1250     }
1251 
1252     /**
1253      * Determines whether CS is in service.
1254      *
1255      * @return {@code true} if CS is in service.
1256      */
isCsInService()1257     private boolean isCsInService() {
1258         EmergencyRegistrationResult regResult =
1259                 mSelectionAttributes.getEmergencyRegistrationResult();
1260         if (regResult == null) return false;
1261 
1262         int regState = regResult.getRegState();
1263         int domain = regResult.getDomain();
1264 
1265         if ((regState == REGISTRATION_STATE_HOME || regState == REGISTRATION_STATE_ROAMING)
1266                 && ((domain & NetworkRegistrationInfo.DOMAIN_CS) > 0)) {
1267             return true;
1268         }
1269 
1270         return false;
1271     }
1272 
1273     /**
1274      * Determines the network type of the circuit-switched(CS) network.
1275      *
1276      * @return The network type of the CS network.
1277      */
getSelectableCsNetworkType()1278     private @RadioAccessNetworkType int getSelectableCsNetworkType() {
1279         List<Integer> domains = getDomainPreference();
1280         if (domains.indexOf(DOMAIN_CS) == NOT_SUPPORTED) {
1281             return UNKNOWN;
1282         }
1283         EmergencyRegistrationResult regResult =
1284                 mSelectionAttributes.getEmergencyRegistrationResult();
1285         logi("getSelectableCsNetworkType regResult=" + regResult);
1286         if (regResult == null) return UNKNOWN;
1287 
1288         int accessNetwork = regResult.getAccessNetwork();
1289 
1290         List<Integer> ratList = getCsNetworkTypeConfiguration();
1291         if (ratList.contains(accessNetwork)) {
1292             return accessNetwork;
1293         }
1294 
1295         if ((regResult.getAccessNetwork() == EUTRAN)
1296                 && ((regResult.getDomain() & NetworkRegistrationInfo.DOMAIN_CS) > 0)) {
1297             if (ratList.contains(UTRAN)) return UTRAN;
1298         }
1299 
1300         return UNKNOWN;
1301     }
1302 
1303     /**
1304      * Determines whether PS is in service.
1305      *
1306      * @return {@code true} if PS is in service.
1307      */
isPsInService()1308     private boolean isPsInService() {
1309         EmergencyRegistrationResult regResult =
1310                 mSelectionAttributes.getEmergencyRegistrationResult();
1311         if (regResult == null) return false;
1312 
1313         int regState = regResult.getRegState();
1314         int domain = regResult.getDomain();
1315 
1316         if ((regState == REGISTRATION_STATE_HOME || regState == REGISTRATION_STATE_ROAMING)
1317                 && ((domain & NetworkRegistrationInfo.DOMAIN_PS) > 0)) {
1318             return true;
1319         }
1320 
1321         return false;
1322     }
1323 
1324     /**
1325      * Determines the network type supporting emergency services over packet-switched(PS) network.
1326      *
1327      * @param inService Indicates whether PS is IN_SERVICE state.
1328      * @return The network type if the network supports emergency services over PS network.
1329      */
getSelectablePsNetworkType(boolean inService)1330     private @RadioAccessNetworkType int getSelectablePsNetworkType(boolean inService) {
1331         List<Integer> domains = getDomainPreference();
1332         if ((domains.indexOf(DOMAIN_PS_3GPP) == NOT_SUPPORTED)
1333                 || !mNonTtyOrTtySupported) {
1334             return UNKNOWN;
1335         }
1336         EmergencyRegistrationResult regResult =
1337                 mSelectionAttributes.getEmergencyRegistrationResult();
1338         logi("getSelectablePsNetworkType regResult=" + regResult);
1339         if (regResult == null) return UNKNOWN;
1340         if (mRequiresVoLteEnabled && !isAdvancedCallingSettingEnabled()) {
1341             // Emergency call over IMS is not supported.
1342             logi("getSelectablePsNetworkType VoLte setting is not enabled.");
1343             return UNKNOWN;
1344         }
1345 
1346         int accessNetwork = regResult.getAccessNetwork();
1347         List<Integer> ratList = getImsNetworkTypeConfiguration();
1348         if (!inService && !ratList.contains(NGRAN) && !isSimReady()
1349                 && !TextUtils.isEmpty(regResult.getCountryIso())) {
1350             ratList.add(NGRAN);
1351             logi("getSelectablePsNetworkType ratList=" + ratList);
1352         }
1353         if (ratList.contains(accessNetwork)) {
1354             if (mIsEmergencyBarred) {
1355                 logi("getSelectablePsNetworkType barred");
1356                 return UNKNOWN;
1357             }
1358             if (accessNetwork == NGRAN) {
1359                 return ((regResult.getNwProvidedEmc() == NR_STATUS_EMC_5GCN_ONLY
1360                         || regResult.getNwProvidedEmc() == NR_STATUS_EMC_NR_EUTRA_5GCN)
1361                         && (regResult.isVopsSupported() || !inService))
1362                         ? NGRAN : UNKNOWN;
1363             } else if (accessNetwork == EUTRAN) {
1364                 return (regResult.isEmcBearerSupported()
1365                                 && (regResult.isVopsSupported() || !inService))
1366                         ? EUTRAN : UNKNOWN;
1367             }
1368         }
1369 
1370         return UNKNOWN;
1371     }
1372 
isEsFallbackAvailable()1373     private boolean isEsFallbackAvailable() {
1374         EmergencyRegistrationResult regResult =
1375                 mSelectionAttributes.getEmergencyRegistrationResult();
1376         if (regResult == null) return false;
1377 
1378         List<Integer> ratList = getImsNetworkTypeConfiguration();
1379         if (ratList.contains(EUTRAN)) {
1380             return (regResult.getNwProvidedEmf() > 0);
1381         }
1382         return false;
1383     }
1384 
1385     /**
1386      * Determines whether the SIM is a deactivated one.
1387      *
1388      * @return {@code true} if the SIM is a deactivated one.
1389      */
isDeactivatedSim()1390     private boolean isDeactivatedSim() {
1391         if (SubscriptionManager.isValidSubscriptionId(getSubId())) {
1392             TelephonyManager tm = mContext.getSystemService(TelephonyManager.class);
1393             tm = tm.createForSubscriptionId(getSubId());
1394             int state = tm.getDataActivationState();
1395             logi("isDeactivatedSim state=" + state);
1396             return (state == TelephonyManager.SIM_ACTIVATION_STATE_DEACTIVATED);
1397         }
1398         return false;
1399     }
1400 
1401     /**
1402      * Determines whether emergency call over Wi-Fi is allowed.
1403      *
1404      * @return {@code true} if emergency call over Wi-Fi allowed.
1405      */
isEmcOverWifiSupported()1406     private boolean isEmcOverWifiSupported() {
1407         if (isSimReady() && mNonTtyOrTtySupported) {
1408             List<Integer> domains = getDomainPreference();
1409             boolean ret = domains.contains(DOMAIN_PS_NON_3GPP);
1410             logi("isEmcOverWifiSupported " + ret);
1411             return ret;
1412         } else {
1413             logi("isEmcOverWifiSupported invalid subId or lock state");
1414         }
1415         return false;
1416     }
1417 
1418     /**
1419      * Determines whether Wi-Fi is preferred when IMS registered over Wi-Fi.
1420      *
1421      * @return {@code true} if Wi-Fi is preferred when IMS registered over Wi-Fi.
1422      */
isWifiPreferred()1423     private boolean isWifiPreferred() {
1424         if (SubscriptionManager.isValidSubscriptionId(getSubId())) {
1425             List<Integer> domains = getDomainPreference();
1426             int priority = domains.indexOf(DOMAIN_PS_NON_3GPP);
1427             logi("isWifiPreferred priority=" + priority);
1428 
1429             if ((priority == 0)
1430                     && isImsRegisteredWithVoiceCapability()
1431                     && isImsRegisteredOverWifi()) {
1432                 logi("isWifiPreferred try emergency call over Wi-Fi");
1433                 return true;
1434             }
1435         }
1436 
1437         return false;
1438     }
1439 
isAdvancedCallingSettingEnabled()1440     private boolean isAdvancedCallingSettingEnabled() {
1441         try {
1442             if (SubscriptionManager.isValidSubscriptionId(getSubId())) {
1443                 ImsManager imsMngr = mContext.getSystemService(ImsManager.class);
1444                 ImsMmTelManager mmTelManager = imsMngr.getImsMmTelManager(getSubId());
1445                 boolean result = mmTelManager.isAdvancedCallingSettingEnabled();
1446                 logi("isAdvancedCallingSettingEnabled " + result);
1447                 return result;
1448             }
1449         } catch (Exception e) {
1450             logi("isAdvancedCallingSettingEnabled e=" + e);
1451         }
1452         return true;
1453     }
1454 
isWifiCallingActivated()1455     private boolean isWifiCallingActivated() {
1456         try {
1457             ImsManager imsMngr = mContext.getSystemService(ImsManager.class);
1458             ProvisioningManager pm = imsMngr.getProvisioningManager(getSubId());
1459             String eid = pm.getProvisioningStringValue(
1460                     ProvisioningManager.KEY_VOICE_OVER_WIFI_ENTITLEMENT_ID);
1461             boolean activated = (!TextUtils.isEmpty(eid)) && (!TextUtils.equals("0", eid));
1462             logi("isWifiCallingActivated " + activated);
1463             return activated;
1464         } catch (Exception e) {
1465             logi("isWifiCallingActivated e=" + e);
1466         }
1467         return false;
1468     }
1469 
isWifiCallingSettingEnabled()1470     private boolean isWifiCallingSettingEnabled() {
1471         boolean result = false;
1472         try {
1473             if (SubscriptionManager.isValidSubscriptionId(getSubId())) {
1474                 ImsManager imsMngr = mContext.getSystemService(ImsManager.class);
1475                 ImsMmTelManager mmTelManager = imsMngr.getImsMmTelManager(getSubId());
1476                 if (isInRoaming()) {
1477                     result = mmTelManager.isVoWiFiRoamingSettingEnabled();
1478                 } else {
1479                     result = mmTelManager.isVoWiFiSettingEnabled();
1480                 }
1481                 logi("isWifiCallingSettingEnabled " + result);
1482                 return result;
1483             }
1484         } catch (Exception e) {
1485             logi("isWifiCallingSettingEnabled e=" + e);
1486         }
1487         return result;
1488     }
1489 
getImsNetworkTypeConfiguration()1490     private @NonNull List<Integer> getImsNetworkTypeConfiguration() {
1491         int[] rats = mImsRatsConfig;
1492         if (isInRoaming()) rats = mImsRoamRatsConfig;
1493 
1494         List<Integer> ratList = new ArrayList<Integer>();
1495         for (int i = 0; i < rats.length; i++) {
1496             ratList.add(rats[i]);
1497         }
1498 
1499         // Prefer LTE if UE is located in non-NR coverage.
1500         if (ratList.contains(NGRAN) && mLastRegResult != null
1501                 && mLastRegResult.getAccessNetwork() != UNKNOWN
1502                 && mLastRegResult.getAccessNetwork() != NGRAN
1503                 && !TextUtils.isEmpty(mLastRegResult.getCountryIso())) {
1504             ratList.remove(Integer.valueOf(NGRAN));
1505             ratList.add(NGRAN);
1506         }
1507 
1508         return ratList;
1509     }
1510 
getCsNetworkTypeConfiguration()1511     private @NonNull List<Integer> getCsNetworkTypeConfiguration() {
1512         int[] rats = mCsRatsConfig;
1513         if (isInRoaming()) rats = mCsRoamRatsConfig;
1514 
1515         List<Integer> ratList = new ArrayList<Integer>();
1516         for (int i = 0; i < rats.length; i++) {
1517             ratList.add(rats[i]);
1518         }
1519 
1520         if (!mCdmaPreferredNumbers.isEmpty()) {
1521             String number = mSelectionAttributes.getAddress().getSchemeSpecificPart();
1522             if (mCdmaPreferredNumbers.contains(number)) {
1523                 // The number will be dialed over CDMA.
1524                 ratList.clear();
1525                 ratList.add(new Integer(CDMA2000));
1526             } else {
1527                 // The number will be dialed over UTRAN or GERAN.
1528                 ratList.remove(new Integer(CDMA2000));
1529             }
1530         }
1531 
1532         return ratList;
1533     }
1534 
getDomainPreference()1535     private @NonNull List<Integer> getDomainPreference() {
1536         int[] domains = mDomainPreference;
1537         if (isInRoaming()) domains = mDomainPreferenceRoam;
1538 
1539         List<Integer> domainList = new ArrayList<Integer>();
1540         for (int i = 0; i < domains.length; i++) {
1541             domainList.add(domains[i]);
1542         }
1543         return domainList;
1544     }
1545 
isInRoaming()1546     private boolean isInRoaming() {
1547         if (!SubscriptionManager.isValidSubscriptionId(getSubId())) return false;
1548 
1549         TelephonyManager tm = mContext.getSystemService(TelephonyManager.class);
1550         tm = tm.createForSubscriptionId(getSubId());
1551         String netIso = tm.getNetworkCountryIso();
1552 
1553         EmergencyRegistrationResult regResult = mLastRegResult;
1554         if (regResult != null) {
1555             if (regResult.getRegState() == REGISTRATION_STATE_HOME) return false;
1556 
1557             String iso = regResult.getCountryIso();
1558             if (!TextUtils.isEmpty(iso)) netIso = iso;
1559         }
1560 
1561         String simIso = tm.getSimCountryIso();
1562         logi("isInRoaming simIso=" + simIso + ", netIso=" + netIso);
1563 
1564         if (TextUtils.isEmpty(simIso)) return false;
1565         if (TextUtils.isEmpty(netIso)) return false;
1566 
1567         return !(TextUtils.equals(simIso, netIso));
1568     }
1569 
1570     /**
1571      * Determines whether IMS is registered over Wi-Fi.
1572      *
1573      * @return {@code true} if IMS is registered over Wi-Fi.
1574      */
isImsRegisteredOverWifi()1575     private boolean isImsRegisteredOverWifi() {
1576         boolean ret = false;
1577         if (SubscriptionManager.isValidSubscriptionId(getSubId())) {
1578             ret = mImsStateTracker.isImsRegisteredOverWlan();
1579         }
1580 
1581         logi("isImsRegisteredOverWifi " + ret);
1582         return ret;
1583     }
1584 
1585     /**
1586      * Determines whether IMS is registered over the mobile data of another subscription.
1587      *
1588      * @return {@code true} if IMS is registered over the mobile data of another subscription.
1589      */
isImsRegisteredOverCrossSim()1590     private boolean isImsRegisteredOverCrossSim() {
1591         boolean ret = false;
1592         if (SubscriptionManager.isValidSubscriptionId(getSubId())) {
1593             ret = mImsStateTracker.isImsRegisteredOverCrossSim();
1594         }
1595 
1596         logi("isImsRegisteredOverCrossSim " + ret);
1597         return ret;
1598     }
1599 
1600     /**
1601      * Determines whether IMS is registered with voice capability.
1602      *
1603      * @return {@code true} if IMS is registered with voice capability.
1604      */
isImsRegisteredWithVoiceCapability()1605     private boolean isImsRegisteredWithVoiceCapability() {
1606         boolean ret = mImsRegistered && mIsVoiceCapable;
1607 
1608         logi("isImsRegisteredWithVoiceCapability " + ret);
1609         return ret;
1610     }
1611 
onWlanSelected()1612     private void onWlanSelected() {
1613         logi("onWlanSelected");
1614         if (mLastTransportType == TRANSPORT_TYPE_WLAN) {
1615             logi("onWlanSelected ignore duplicated callback");
1616             return;
1617         }
1618 
1619         mDomainSelected = true;
1620         mNetworkScanTimerExpired = false;
1621         mIsWaitingForDataDisconnection = false;
1622         removeMessages(MSG_WAIT_DISCONNECTION_TIMEOUT);
1623         mLastTransportType = TRANSPORT_TYPE_WLAN;
1624         mVoWifiTrialCount++;
1625         mTransportSelectorCallback.onWlanSelected(mVoWifiOverEmergencyPdn);
1626         mWwanSelectorCallback = null;
1627         removeMessages(MSG_NETWORK_SCAN_TIMEOUT);
1628         removeMessages(MSG_MAX_CELLULAR_TIMEOUT);
1629     }
1630 
onWwanSelected(Runnable runnable)1631     private void onWwanSelected(Runnable runnable) {
1632         logi("onWwanSelected");
1633         if (mLastTransportType == TRANSPORT_TYPE_WWAN) {
1634             logi("onWwanSelected ignore duplicated callback");
1635             return;
1636         }
1637 
1638         mLastTransportType = TRANSPORT_TYPE_WWAN;
1639         mTransportSelectorCallback.onWwanSelected((callback) -> {
1640             mWwanSelectorCallback = callback;
1641             runnable.run();
1642         });
1643     }
1644 
onWwanNetworkTypeSelected(@adioAccessNetworkType int accessNetworkType)1645     private void onWwanNetworkTypeSelected(@RadioAccessNetworkType int accessNetworkType) {
1646         logi("onWwanNetworkTypeSelected " + accessNetworkTypeToString(accessNetworkType));
1647         if (mWwanSelectorCallback == null) {
1648             logi("onWwanNetworkTypeSelected callback is null");
1649             return;
1650         }
1651 
1652         mDomainSelected = true;
1653         mNetworkScanTimerExpired = false;
1654         mLastNetworkType = accessNetworkType;
1655         int domain = NetworkRegistrationInfo.DOMAIN_CS;
1656         if (accessNetworkType == EUTRAN || accessNetworkType == NGRAN) {
1657             domain = NetworkRegistrationInfo.DOMAIN_PS;
1658         }
1659         mWwanSelectorCallback.onDomainSelected(domain,
1660                 (domain == NetworkRegistrationInfo.DOMAIN_PS));
1661     }
1662 
1663     /**
1664      * Registers for changes to network connectivity.
1665      */
registerForConnectivityChanges()1666     private void registerForConnectivityChanges() {
1667         if (mIsMonitoringConnectivity) {
1668             return;
1669         }
1670 
1671         mWiFiNetworksAvailable.clear();
1672         ConnectivityManager cm = mContext.getSystemService(ConnectivityManager.class);
1673         if (cm != null) {
1674             logi("registerForConnectivityChanges");
1675             NetworkRequest.Builder builder = new NetworkRequest.Builder();
1676             builder.addTransportType(NetworkCapabilities.TRANSPORT_WIFI);
1677             cm.registerNetworkCallback(builder.build(), mNetworkCallback);
1678             mIsMonitoringConnectivity = true;
1679         }
1680     }
1681 
1682     /**
1683      * Unregisters for connectivity changes.
1684      */
unregisterForConnectivityChanges()1685     private void unregisterForConnectivityChanges() {
1686         if (!mIsMonitoringConnectivity) {
1687             return;
1688         }
1689 
1690         mWiFiNetworksAvailable.clear();
1691         ConnectivityManager cm = mContext.getSystemService(ConnectivityManager.class);
1692         if (cm != null) {
1693             logi("unregisterForConnectivityChanges");
1694             cm.unregisterNetworkCallback(mNetworkCallback);
1695             mIsMonitoringConnectivity = false;
1696         }
1697     }
1698 
1699     /** Starts the max cellular timer. */
startMaxCellularTimer()1700     private void startMaxCellularTimer() {
1701         logd("startMaxCellularTimer tried=" + mVoWifiTrialCount
1702                 + ", max=" + mMaxNumOfVoWifiTries);
1703         if (isEmcOverWifiSupported()
1704                 && (mMaxCellularTimeout > 0)
1705                 && (mVoWifiTrialCount < mMaxNumOfVoWifiTries)) {
1706             logi("startMaxCellularTimer start timer");
1707             sendEmptyMessageDelayed(MSG_MAX_CELLULAR_TIMEOUT, mMaxCellularTimeout);
1708             registerForConnectivityChanges();
1709         }
1710     }
1711 
allowEmergencyCalls(EmergencyRegistrationResult regResult)1712     private boolean allowEmergencyCalls(EmergencyRegistrationResult regResult) {
1713         if (regResult == null) {
1714             loge("allowEmergencyCalls null regResult");
1715             return true;
1716         }
1717 
1718         String iso = regResult.getCountryIso();
1719         if (sSimReadyAllowList.contains(iso)) {
1720             if (isSimReady()) {
1721                 SubscriptionManager sm = mContext.getSystemService(SubscriptionManager.class);
1722                 SubscriptionInfo subInfo = sm.getActiveSubscriptionInfo(getSubId());
1723                 if (subInfo != null
1724                         && subInfo.getProfileClass() == PROFILE_CLASS_PROVISIONING) {
1725                     // b/334773484, bootstrap profile
1726                     logi("allowEmergencyCalls bootstrap profile, iso=" + iso);
1727                     return false;
1728                 }
1729             } else {
1730                 logi("allowEmergencyCalls SIM state not ready, iso=" + iso);
1731                 return false;
1732             }
1733         }
1734 
1735         return true;
1736     }
1737 
getCountryIso(String iso)1738     private String getCountryIso(String iso) {
1739         if (TextUtils.isEmpty(iso)) {
1740             TelephonyManager tm = mContext.getSystemService(TelephonyManager.class);
1741             iso = tm.getNetworkCountryIso(getSlotId());
1742             if (TextUtils.isEmpty(iso)) {
1743                 for (int i = 0; i < mModemCount; i++) {
1744                     iso = tm.getNetworkCountryIso(i);
1745                     if (!TextUtils.isEmpty(iso)) break;
1746                 }
1747             }
1748         }
1749         return iso;
1750     }
1751 
maybeRedialOnTheOtherSlotInNormalService( EmergencyRegistrationResult regResult)1752     private boolean maybeRedialOnTheOtherSlotInNormalService(
1753             EmergencyRegistrationResult regResult) {
1754         if (regResult == null) return false;
1755 
1756         String iso = getCountryIso(regResult.getCountryIso());
1757         if (sPreferSlotWithNormalServiceList.contains(iso)
1758                 && mCrossSimRedialingController.isThereOtherSlotInService()) {
1759             logi("maybeRedialOnTheOtherSlotInNormalService");
1760             terminateSelectionForCrossSimRedialing(false);
1761             return true;
1762         }
1763         return false;
1764     }
1765 
terminateSelectionPermanentlyForSlot()1766     private void terminateSelectionPermanentlyForSlot() {
1767         logi("terminateSelectionPermanentlyForSlot");
1768         mCrossSimRedialingController.notifyCallFailure(EMERGENCY_PERM_FAILURE);
1769         if (mCrossSimRedialingController.isThereOtherSlot()) {
1770             terminateSelection(DisconnectCause.EMERGENCY_PERM_FAILURE);
1771         } else {
1772             terminateSelection(DisconnectCause.ICC_ERROR);
1773         }
1774     }
1775 
terminateSelectionForCrossSimRedialing(boolean permanent)1776     private void terminateSelectionForCrossSimRedialing(boolean permanent) {
1777         logi("terminateSelectionForCrossSimRedialing perm=" + permanent);
1778         terminateSelection(permanent ? DisconnectCause.EMERGENCY_PERM_FAILURE
1779                 : DisconnectCause.EMERGENCY_TEMP_FAILURE);
1780     }
1781 
terminateSelection(int cause)1782     private void terminateSelection(int cause) {
1783         removeMessages(MSG_NETWORK_SCAN_TIMEOUT);
1784         removeMessages(MSG_MAX_CELLULAR_TIMEOUT);
1785         mTransportSelectorCallback.onSelectionTerminated(cause);
1786     }
1787 
maybeTerminateSelection(int cause)1788     private boolean maybeTerminateSelection(int cause) {
1789         switch (cause) {
1790             case NO_VALID_SIM:
1791                 // The disconnect cause saved in DomainSelectionConnection shall be used.
1792                 terminateSelection(DisconnectCause.NOT_VALID);
1793                 return true;
1794             default:
1795                 break;
1796         }
1797 
1798         ImsReasonInfo reasonInfo = mSelectionAttributes.getPsDisconnectCause();
1799         if (mRetryReasonCodes != null && reasonInfo != null) {
1800             if (!mRetryReasonCodes.contains(reasonInfo.getCode())) {
1801                 // The disconnect cause saved in DomainSelectionConnection shall be used.
1802                 terminateSelection(DisconnectCause.NOT_VALID);
1803                 return true;
1804             }
1805         } else if (reasonInfo == null
1806                 && sDisconnectCauseForTerminatation.contains(cause)
1807                 && mTerminateAfterCsFailure) {
1808             // b/341055741
1809             logi("maybeTerminateSelection terminate after CS failure");
1810             terminateSelection(DisconnectCause.NOT_VALID);
1811             return true;
1812         }
1813         return false;
1814     }
1815 
1816     /** Starts the cross stack timer. */
startCrossStackTimer()1817     public void startCrossStackTimer() {
1818         boolean inService = false;
1819         boolean inRoaming = false;
1820 
1821         if (mModemCount == 1) return;
1822 
1823         EmergencyRegistrationResult regResult =
1824                 mSelectionAttributes.getEmergencyRegistrationResult();
1825         if (regResult != null) {
1826             int regState = regResult.getRegState();
1827 
1828             if ((regResult.getDomain() > 0)
1829                     && (regState == REGISTRATION_STATE_HOME
1830                             || regState == REGISTRATION_STATE_ROAMING)) {
1831                 inService = true;
1832             }
1833             inRoaming = (regState == REGISTRATION_STATE_ROAMING) || isInRoaming();
1834         }
1835 
1836         String number = mSelectionAttributes.getAddress().getSchemeSpecificPart();
1837         mCrossSimRedialingController.startTimer(mContext, this, mSelectionAttributes.getCallId(),
1838                 number, inService, inRoaming, mModemCount);
1839     }
1840 
1841     /** Notifies that the cross stack redilaing timer has been expired. */
notifyCrossStackTimerExpired()1842     public void notifyCrossStackTimerExpired() {
1843         logi("notifyCrossStackTimerExpired");
1844 
1845         mCrossStackTimerExpired = true;
1846         boolean isHangupOngoingDialing = hangupOngoingDialing();
1847         if (mDomainSelected && !isHangupOngoingDialing) {
1848             // When reselecting domain, terminateSelection will be called.
1849             return;
1850         }
1851         mIsWaitingForDataDisconnection = false;
1852         removeMessages(MSG_WAIT_DISCONNECTION_TIMEOUT);
1853         terminateSelectionForCrossSimRedialing(isHangupOngoingDialing);
1854     }
1855 
1856     /**
1857      * If another slot has already permanently failed,
1858      * and IMS REG is not completed in the current slot, hang up the ongoing call.
1859      */
maybeHangupOngoingDialing()1860     public void maybeHangupOngoingDialing() {
1861         logi("maybeHangupOngoingDialing");
1862 
1863         if (mDomainSelected && hangupOngoingDialing()) {
1864             notifyCrossStackTimerExpired();
1865         }
1866     }
1867 
hangupOngoingDialing()1868     private boolean hangupOngoingDialing() {
1869         return Flags.hangupEmergencyCallForCrossSimRedialing()
1870                 && (mCallSetupTimerOnCurrentRat > 0)
1871                 && (!mImsEmergencyRegistrationHelper.isImsEmergencyRegistered());
1872     }
1873 
1874     /** Notifies the ePDN connection state changes. */
notifyDataConnectionStateChange(int slotId, int state)1875     public void notifyDataConnectionStateChange(int slotId, int state) {
1876         if (slotId == getSlotId() && mIsWaitingForDataDisconnection) {
1877             if (state == DATA_DISCONNECTED || state == DATA_UNKNOWN) {
1878                 requestScanDelayed();
1879             } else if (state == DATA_DISCONNECTING) {
1880                 logi("notifyDataConnectionStateChange deactivation starting, restart timer");
1881                 removeMessages(MSG_WAIT_DISCONNECTION_TIMEOUT);
1882                 sendEmptyMessageDelayed(MSG_WAIT_DISCONNECTION_TIMEOUT,
1883                         DEFAULT_DATA_DISCONNECTION_TIMEOUT_MS);
1884             }
1885         }
1886     }
1887 
maybeModifyScanType(int selectedNetworkType)1888     private void maybeModifyScanType(int selectedNetworkType) {
1889         if ((mPreferredNetworkScanType
1890                 != CarrierConfigManager.ImsEmergency.SCAN_TYPE_FULL_SERVICE)
1891                 && mScanLimitedOnlyAfterVolteFailure
1892                 && (selectedNetworkType == EUTRAN)) {
1893             mScanType = DomainSelectionService.SCAN_TYPE_LIMITED_SERVICE;
1894         }
1895     }
1896 
arrayToString(int[] intArray, IntFunction<String> func)1897     private static String arrayToString(int[] intArray, IntFunction<String> func) {
1898         int length = intArray.length;
1899         StringBuilder sb = new StringBuilder("{");
1900         if (length > 0) {
1901             int i = 0;
1902             sb.append(func.apply(intArray[i++]));
1903             while (i < length) {
1904                 sb.append(", ").append(func.apply(intArray[i++]));
1905             }
1906         }
1907         sb.append("}");
1908         return sb.toString();
1909     }
1910 
arrayToString(String[] stringArray)1911     private static String arrayToString(String[] stringArray) {
1912         StringBuilder sb;
1913         int length = stringArray.length;
1914         sb = new StringBuilder("{");
1915         if (length > 0) {
1916             int i = 0;
1917             sb.append(stringArray[i++]);
1918             while (i < length) {
1919                 sb.append(", ").append(stringArray[i++]);
1920             }
1921         }
1922         sb.append("}");
1923         return sb.toString();
1924     }
1925 
domainPreferenceToString( @arrierConfigManager.ImsEmergency.EmergencyDomain int domain)1926     private static String domainPreferenceToString(
1927             @CarrierConfigManager.ImsEmergency.EmergencyDomain int domain) {
1928         switch (domain) {
1929             case DOMAIN_CS: return "CS";
1930             case DOMAIN_PS_3GPP: return "PS_3GPP";
1931             case DOMAIN_PS_NON_3GPP: return "PS_NON_3GPP";
1932             default: return "UNKNOWN";
1933         }
1934     }
1935 
carrierConfigNetworkScanTypeToString( @arrierConfigManager.ImsEmergency.EmergencyScanType int scanType)1936     private static String carrierConfigNetworkScanTypeToString(
1937             @CarrierConfigManager.ImsEmergency.EmergencyScanType int scanType) {
1938         switch (scanType) {
1939             case CarrierConfigManager.ImsEmergency.SCAN_TYPE_NO_PREFERENCE: return "NO_PREF";
1940             case CarrierConfigManager.ImsEmergency.SCAN_TYPE_FULL_SERVICE: return "FULL";
1941             case SCAN_TYPE_FULL_SERVICE_FOLLOWED_BY_LIMITED_SERVICE: return "FULL_N_LIMITED";
1942             default: return "UNKNOWN";
1943         }
1944     }
1945 
accessNetworkTypeToString( @adioAccessNetworkType int accessNetworkType)1946     private static String accessNetworkTypeToString(
1947             @RadioAccessNetworkType int accessNetworkType) {
1948         switch (accessNetworkType) {
1949             case AccessNetworkType.UNKNOWN: return "UNKNOWN";
1950             case AccessNetworkType.GERAN: return "GERAN";
1951             case AccessNetworkType.UTRAN: return "UTRAN";
1952             case AccessNetworkType.EUTRAN: return "EUTRAN";
1953             case AccessNetworkType.CDMA2000: return "CDMA2000";
1954             case AccessNetworkType.IWLAN: return "IWLAN";
1955             case AccessNetworkType.NGRAN: return "NGRAN";
1956             default: return Integer.toString(accessNetworkType);
1957         }
1958     }
1959 
1960     /**
1961      * Destroys the instance.
1962      */
1963     @VisibleForTesting
destroy()1964     public void destroy() {
1965         if (DBG) logd("destroy");
1966 
1967         mEpdnHelper.setEmergencyCallDomainSelector(null);
1968         mImsEmergencyRegistrationHelper.destroy();
1969         mCrossSimRedialingController.stopTimer();
1970         releaseWakeLock();
1971 
1972         mDestroyed = true;
1973         mImsStateTracker.removeBarringInfoListener(this);
1974         mImsStateTracker.removeImsStateListener(this);
1975         unregisterForConnectivityChanges();
1976 
1977         super.destroy();
1978     }
1979 
acquireWakeLock()1980     private void acquireWakeLock() {
1981         if (mPartialWakeLock != null) {
1982             synchronized (mPartialWakeLock) {
1983                 logi("acquireWakeLock");
1984                 mPartialWakeLock.acquire();
1985             }
1986         }
1987     }
1988 
releaseWakeLock()1989     private void releaseWakeLock() {
1990         if (mPartialWakeLock != null) {
1991             synchronized (mPartialWakeLock) {
1992                 if (mPartialWakeLock.isHeld()) {
1993                     logi("releaseWakeLock");
1994                     mPartialWakeLock.release();
1995                 }
1996             }
1997         }
1998     }
1999 
isInEmergencyCallbackModeOnWlan()2000     private boolean isInEmergencyCallbackModeOnWlan() {
2001         return mEpdnHelper.isInEmergencyCallbackMode(getSlotId())
2002                 && mEpdnHelper.getTransportType(getSlotId()) == TRANSPORT_TYPE_WLAN
2003                 && mEpdnHelper.getDataConnectionState(getSlotId()) == DATA_CONNECTED;
2004     }
2005 
isInEmergencyCallbackModeOnPsWwan()2006     private boolean isInEmergencyCallbackModeOnPsWwan() {
2007         return mEpdnHelper.isInEmergencyCallbackMode(getSlotId())
2008                 && mEpdnHelper.getTransportType(getSlotId()) == TRANSPORT_TYPE_WWAN
2009                 && mEpdnHelper.getDataConnectionState(getSlotId()) == DATA_CONNECTED;
2010     }
2011 
2012     /**
2013      * Indicates whether the call is non-TTY or if TTY is supported.
2014      */
isNonTtyOrTtySupported(boolean ttySupported)2015     private boolean isNonTtyOrTtySupported(boolean ttySupported) {
2016         if (ttySupported) {
2017             return true;
2018         }
2019 
2020         TelecomManager tm = mContext.getSystemService(TelecomManager.class);
2021         if (tm == null) {
2022             logi("isNonTtyOrTtySupported telecom not available");
2023             return true;
2024         }
2025 
2026         boolean ret = (tm.getCurrentTtyMode() == TelecomManager.TTY_MODE_OFF);
2027         logi("isNonTtyOrTtySupported ret=" + ret);
2028 
2029         return ret;
2030     }
2031 
checkAndSetTerminateAfterCsFailure(EmergencyRegistrationResult result)2032     private void checkAndSetTerminateAfterCsFailure(EmergencyRegistrationResult result) {
2033         if (result == null) return;
2034         String mcc = result.getMcc();
2035         int accessNetwork = result.getAccessNetwork();
2036         if (!TextUtils.isEmpty(mcc) && mcc.startsWith("00") // test network
2037                 && (accessNetwork == UTRAN || accessNetwork == GERAN)) {
2038             // b/341055741
2039             mTerminateAfterCsFailure = true;
2040         }
2041     }
2042 
2043     @VisibleForTesting
isWiFiAvailable()2044     public boolean isWiFiAvailable() {
2045         return mWiFiAvailable;
2046     }
2047 
2048     @VisibleForTesting
getWiFiNetworksAvailable()2049     public List<Network> getWiFiNetworksAvailable() {
2050         return mWiFiNetworksAvailable;
2051     }
2052 
2053     @Override
logi(String msg)2054     protected void logi(String msg) {
2055         super.logi(msg);
2056         sLocalLog.log(msg);
2057     }
2058 
2059     @Override
loge(String msg)2060     protected void loge(String msg) {
2061         super.loge(msg);
2062         sLocalLog.log(msg);
2063     }
2064 }
2065