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