1 /* 2 * Copyright (C) 2021 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.ons; 18 19 import android.annotation.TestApi; 20 import android.content.Context; 21 import android.net.ConnectivityManager; 22 import android.net.Network; 23 import android.net.NetworkCapabilities; 24 import android.net.NetworkRequest; 25 import android.os.Handler; 26 import android.os.Looper; 27 import android.os.Message; 28 import android.os.ParcelUuid; 29 import android.os.PersistableBundle; 30 import android.telephony.CarrierConfigManager; 31 import android.telephony.SubscriptionInfo; 32 import android.telephony.SubscriptionManager; 33 import android.telephony.TelephonyManager; 34 import android.telephony.UiccCardInfo; 35 import android.telephony.euicc.EuiccManager; 36 import android.util.Log; 37 38 import com.android.internal.annotations.VisibleForTesting; 39 import com.android.internal.telephony.flags.Flags; 40 import com.android.ons.ONSProfileDownloader.DownloadRetryResultCode; 41 42 import java.util.ArrayList; 43 import java.util.List; 44 import java.util.Random; 45 46 /** 47 * @class ONSProfileActivator 48 * @brief ONSProfileActivator makes sure that the CBRS profile is downloaded, activated and grouped 49 * when an opportunistic data enabled pSIM is inserted. 50 */ 51 public class ONSProfileActivator implements ONSProfileConfigurator.ONSProfConfigListener, 52 ONSProfileDownloader.IONSProfileDownloaderListener { 53 54 private static final String TAG = ONSProfileActivator.class.getName(); 55 private final Context mContext; 56 private final SubscriptionManager mSubManager; 57 private final TelephonyManager mTelephonyManager; 58 private final CarrierConfigManager mCarrierConfigMgr; 59 private final EuiccManager mEuiccManager; 60 private final ONSProfileConfigurator mONSProfileConfig; 61 private final ONSProfileDownloader mONSProfileDownloader; 62 private final ConnectivityManager mConnectivityManager; 63 private final ONSStats mONSStats; 64 @VisibleForTesting protected boolean mIsInternetConnAvailable = false; 65 @VisibleForTesting protected boolean mRetryDownloadWhenNWConnected = false; 66 @VisibleForTesting protected int mDownloadRetryCount = 0; 67 68 @VisibleForTesting protected static final int REQUEST_CODE_DOWNLOAD_RETRY = 2; 69 ONSProfileActivator(Context context, ONSStats onsStats)70 public ONSProfileActivator(Context context, ONSStats onsStats) { 71 mContext = context; 72 SubscriptionManager sm = mContext.getSystemService(SubscriptionManager.class); 73 if (Flags.workProfileApiSplit()) { 74 sm = sm.createForAllUserProfiles(); 75 } 76 mSubManager = sm; 77 mTelephonyManager = mContext.getSystemService(TelephonyManager.class); 78 mCarrierConfigMgr = mContext.getSystemService(CarrierConfigManager.class); 79 mEuiccManager = mContext.getSystemService(EuiccManager.class); 80 mONSProfileConfig = new ONSProfileConfigurator(mContext, mSubManager, 81 mCarrierConfigMgr, mEuiccManager, this); 82 mONSProfileDownloader = new ONSProfileDownloader(mContext, mCarrierConfigMgr, 83 mEuiccManager, mSubManager, mONSProfileConfig, this); 84 85 //Monitor internet connection. 86 mConnectivityManager = context.getSystemService(ConnectivityManager.class); 87 mONSStats = onsStats; 88 NetworkRequest request = new NetworkRequest.Builder().addCapability( 89 NetworkCapabilities.NET_CAPABILITY_VALIDATED).build(); 90 mConnectivityManager.registerNetworkCallback(request, new NetworkCallback()); 91 } 92 93 /** 94 * This constructor is only for JUnit testing 95 */ 96 @TestApi ONSProfileActivator(Context mockContext, SubscriptionManager subscriptionManager, TelephonyManager telephonyManager, CarrierConfigManager carrierConfigMgr, EuiccManager euiccManager, ConnectivityManager connManager, ONSProfileConfigurator onsProfileConfigurator, ONSProfileDownloader onsProfileDownloader, ONSStats onsStats)97 ONSProfileActivator(Context mockContext, SubscriptionManager subscriptionManager, 98 TelephonyManager telephonyManager, CarrierConfigManager carrierConfigMgr, 99 EuiccManager euiccManager, ConnectivityManager connManager, 100 ONSProfileConfigurator onsProfileConfigurator, 101 ONSProfileDownloader onsProfileDownloader, ONSStats onsStats) { 102 mContext = mockContext; 103 mSubManager = subscriptionManager; 104 mTelephonyManager = telephonyManager; 105 mCarrierConfigMgr = carrierConfigMgr; 106 mEuiccManager = euiccManager; 107 mConnectivityManager = connManager; 108 mONSProfileConfig = onsProfileConfigurator; 109 mONSProfileDownloader = onsProfileDownloader; 110 mONSStats = onsStats; 111 } 112 getONSProfileConfigurator()113 ONSProfileConfigurator getONSProfileConfigurator() { 114 return mONSProfileConfig; 115 } 116 getONSProfileDownloader()117 ONSProfileDownloader getONSProfileDownloader() { 118 return mONSProfileDownloader; 119 } 120 121 private final Handler mHandler = new Handler(Looper.myLooper()) { 122 @Override 123 public void handleMessage(Message msg) { 124 switch (msg.what) { 125 case REQUEST_CODE_DOWNLOAD_RETRY: { 126 Result res = provisionCBRS(); 127 Log.d(TAG, res.toString()); 128 mONSStats.logEvent(new ONSStatsInfo().setProvisioningResult(res)); 129 } 130 break; 131 } 132 } 133 }; 134 135 /** 136 * Called when SIM state changes. Triggers CBRS Auto provisioning. 137 */ handleCarrierConfigChange()138 public Result handleCarrierConfigChange() { 139 Result res = provisionCBRS(); 140 Log.d(TAG, res.toString()); 141 mONSStats.logEvent(new ONSStatsInfo().setProvisioningResult(res)); 142 143 // Reset mDownloadRetryCount as carrier config change event is received. Either new SIM card 144 // is inserted or carrier config values are updated. 145 if (res == Result.DOWNLOAD_REQUESTED || res == Result.SUCCESS) { 146 mDownloadRetryCount = 0; 147 } 148 149 return res; 150 } 151 152 @Override onOppSubscriptionDeleted(int pSIMId)153 public void onOppSubscriptionDeleted(int pSIMId) { 154 Result res = provisionCBRS(); 155 Log.d(TAG, res.toString()); 156 mONSStats.logEvent(new ONSStatsInfo().setProvisioningResult(res)); 157 } 158 159 /** 160 * Checks if AutoProvisioning is enabled, MultiSIM and eSIM support, cbrs pSIM is inserted and 161 * makes sure device is in muti-SIM mode before triggering download of opportunistic eSIM. 162 * Once downloaded, groups with pSIM, sets opportunistic and activates. 163 */ provisionCBRS()164 private Result provisionCBRS() { 165 166 if (!isONSAutoProvisioningEnabled()) { 167 return Result.ERR_AUTO_PROVISIONING_DISABLED; 168 } 169 170 //Check if device supports eSIM 171 if (!isESIMSupported()) { 172 return Result.ERR_ESIM_NOT_SUPPORTED; 173 } 174 175 //Check if it's a multi SIM Phone. CBRS is not supported on Single SIM phone. 176 if (!isMultiSIMPhone()) { 177 return Result.ERR_MULTISIM_NOT_SUPPORTED; 178 } 179 180 //Check the number of active subscriptions. 181 List<SubscriptionInfo> activeSubInfos = mSubManager.getActiveSubscriptionInfoList(); 182 if (activeSubInfos == null || activeSubInfos.size() <= 0) { 183 return Result.ERR_NO_SIM_INSERTED; 184 } 185 int activeSubCount = activeSubInfos.size(); 186 Log.d(TAG, "Active subscription count:" + activeSubCount); 187 188 if (activeSubCount == 1) { 189 SubscriptionInfo pSubInfo = activeSubInfos.get(0); 190 if (pSubInfo.isOpportunistic()) { 191 //Only one SIM is active and its opportunistic SIM. 192 //Opportunistic eSIM shouldn't be used without pSIM. 193 return Result.ERR_SINGLE_ACTIVE_OPPORTUNISTIC_SIM; 194 } 195 196 //if pSIM is not a CBRS carrier 197 if (!isOppDataAutoProvisioningSupported( 198 pSubInfo.getSubscriptionId())) { 199 return Result.ERR_CARRIER_DOESNT_SUPPORT_CBRS; 200 } 201 202 if (isDeviceInSingleSIMMode()) { 203 if (!switchToMultiSIMMode()) { 204 return Result.ERR_CANNOT_SWITCH_TO_DUAL_SIM_MODE; 205 } 206 207 //Once device is Switched to Dual-SIM Mode, handleSimStateChange is triggered. 208 return Result.ERR_SWITCHING_TO_DUAL_SIM_MODE; 209 } 210 211 return downloadAndActivateOpportunisticSubscription(pSubInfo); 212 } else if (activeSubCount >= 2) { 213 //If all the SIMs are physical SIM then it's a sure case of DUAL Active Subscription. 214 boolean allPhysicalSIMs = true; 215 for (SubscriptionInfo subInfo : activeSubInfos) { 216 if (subInfo.isEmbedded()) { 217 allPhysicalSIMs = false; 218 break; 219 } 220 } 221 222 if (allPhysicalSIMs) { 223 return Result.ERR_DUAL_ACTIVE_SUBSCRIPTIONS; 224 } 225 226 //Check if one of the subscription is opportunistic but not marked. 227 //if one of the SIM is opportunistic and not grouped then group the subscription. 228 for (SubscriptionInfo subInfo : activeSubInfos) { 229 int pSubId = subInfo.getSubscriptionId(); 230 if (!subInfo.isEmbedded() && isOppDataAutoProvisioningSupported(pSubId)) { 231 232 Log.d(TAG, "CBRS pSIM found. SubId:" + pSubId); 233 234 //Check if other SIM is opportunistic based on carrier-id. 235 SubscriptionInfo oppSubInfo = mONSProfileConfig 236 .findOpportunisticSubscription(pSubId); 237 238 //If opportunistic eSIM is found and activated. 239 if (oppSubInfo != null) { 240 if (mSubManager.isActiveSubscriptionId(oppSubInfo.getSubscriptionId()) 241 && oppSubInfo.isOpportunistic()) { 242 //Already configured. No action required. 243 return Result.SUCCESS; 244 } 245 246 ParcelUuid pSIMGroupId = mONSProfileConfig.getPSIMGroupId(subInfo); 247 mONSProfileConfig.groupWithPSIMAndSetOpportunistic(oppSubInfo, pSIMGroupId); 248 return Result.SUCCESS; 249 } 250 } 251 } 252 253 return Result.ERR_DUAL_ACTIVE_SUBSCRIPTIONS; 254 } 255 256 return Result.ERR_UNKNOWN; 257 } 258 downloadAndActivateOpportunisticSubscription( SubscriptionInfo primaryCBRSSubInfo)259 private Result downloadAndActivateOpportunisticSubscription( 260 SubscriptionInfo primaryCBRSSubInfo) { 261 Log.d(TAG, "downloadAndActivateOpportunisticSubscription"); 262 263 //Check if pSIM is part of a group. If not then create a group. 264 ParcelUuid pSIMgroupId = mONSProfileConfig.getPSIMGroupId(primaryCBRSSubInfo); 265 266 //Check if opp eSIM is already downloaded but not grouped. 267 SubscriptionInfo oppSubInfo = mONSProfileConfig.findOpportunisticSubscription( 268 primaryCBRSSubInfo.getSubscriptionId()); 269 if (oppSubInfo != null) { 270 mONSProfileConfig.groupWithPSIMAndSetOpportunistic(oppSubInfo, pSIMgroupId); 271 return Result.SUCCESS; 272 } 273 274 if (!mIsInternetConnAvailable) { 275 Log.d(TAG, "No internet connection. Download will be attempted when " 276 + "connection is restored"); 277 mRetryDownloadWhenNWConnected = true; 278 return Result.ERR_WAITING_FOR_INTERNET_CONNECTION; 279 } 280 281 /* If download WiFi only flag is set and WiFi is not connected */ 282 if (getESIMDownloadViaWiFiOnlyFlag(primaryCBRSSubInfo.getSubscriptionId()) 283 && !isWiFiConnected()) { 284 Log.d(TAG, "Download via WiFi only flag is set but WiFi is not connected." 285 + "Download will be attempted when WiFi connection is restored"); 286 mRetryDownloadWhenNWConnected = true; 287 return Result.ERR_WAITING_FOR_WIFI_CONNECTION; 288 } 289 290 //Opportunistic subscription not found. Trigger Download. 291 ONSProfileDownloader.DownloadProfileResult res = mONSProfileDownloader.downloadProfile( 292 primaryCBRSSubInfo.getSubscriptionId()); 293 294 switch (res) { 295 case DUPLICATE_REQUEST: return Result.ERR_DUPLICATE_DOWNLOAD_REQUEST; 296 case INVALID_SMDP_ADDRESS: return Result.ERR_INVALID_CARRIER_CONFIG; 297 case SUCCESS: return Result.DOWNLOAD_REQUESTED; 298 } 299 300 return Result.ERR_UNKNOWN; 301 } 302 303 @Override onDownloadComplete(int primarySubId)304 public void onDownloadComplete(int primarySubId) { 305 mRetryDownloadWhenNWConnected = false; 306 SubscriptionInfo opportunisticESIM = mONSProfileConfig.findOpportunisticSubscription( 307 primarySubId); 308 if (opportunisticESIM == null) { 309 Log.e(TAG, "Downloaded Opportunistic eSIM not found. Unable to group with pSIM"); 310 mONSStats.logEvent(new ONSStatsInfo() 311 .setProvisioningResult(Result.ERR_DOWNLOADED_ESIM_NOT_FOUND) 312 .setPrimarySimSubId(primarySubId) 313 .setWifiConnected(isWiFiConnected())); 314 return; 315 } 316 317 SubscriptionInfo pSIMSubInfo = mSubManager.getActiveSubscriptionInfo(primarySubId); 318 if (pSIMSubInfo != null) { 319 // Group with same Primary SIM for which eSIM is downloaded. 320 mONSProfileConfig.groupWithPSIMAndSetOpportunistic( 321 opportunisticESIM, pSIMSubInfo.getGroupUuid()); 322 Log.d(TAG, "eSIM downloaded and configured successfully"); 323 mONSStats.logEvent(new ONSStatsInfo() 324 .setProvisioningResult(Result.SUCCESS) 325 .setRetryCount(mDownloadRetryCount) 326 .setWifiConnected(isWiFiConnected())); 327 } else { 328 Log.d(TAG, "ESIM downloaded but pSIM is not active or removed"); 329 mONSStats.logEvent(new ONSStatsInfo() 330 .setProvisioningResult(Result.ERR_PSIM_NOT_FOUND) 331 .setOppSimCarrierId(opportunisticESIM.getCarrierId()) 332 .setWifiConnected(isWiFiConnected())); 333 } 334 } 335 336 @Override onDownloadError(int pSIMSubId, DownloadRetryResultCode resultCode, int detailedErrorCode)337 public void onDownloadError(int pSIMSubId, DownloadRetryResultCode resultCode, 338 int detailedErrorCode) { 339 boolean logStats = true; 340 switch (resultCode) { 341 case ERR_MEMORY_FULL: { 342 //eUICC Memory full occurred while downloading opportunistic eSIM. 343 344 //First find and delete any opportunistic eSIMs from the operator same as the 345 // current primary SIM. 346 ArrayList<Integer> oppSubIds = mONSProfileConfig 347 .getOpportunisticSubIdsofPSIMOperator(pSIMSubId); 348 if (oppSubIds != null && oppSubIds.size() > 0) { 349 mONSProfileConfig.deleteSubscription(oppSubIds.get(0)); 350 } else { 351 //else, find the inactive opportunistic eSIMs (any operator) and delete one of 352 // them and retry download again. 353 mONSProfileConfig.deleteInactiveOpportunisticSubscriptions(pSIMSubId); 354 } 355 356 //Delete subscription -> onOppSubscriptionDeleted callback -> provisionCBRS -> 357 // triggers eSIM download again. 358 359 //Download retry will stop if there are no opportunistic eSIM profiles to delete. 360 } 361 break; 362 363 case ERR_INSTALL_ESIM_PROFILE_FAILED: { 364 //Since the installation of eSIM profile has failed there may be an issue with the 365 //format or profile data. We retry by first deleting existing eSIM profile from the 366 //operator same as the primary SIM and retry download opportunistic eSIM. 367 ArrayList<Integer> oppSubIds = mONSProfileConfig 368 .getOpportunisticSubIdsofPSIMOperator(pSIMSubId); 369 370 if (oppSubIds != null && oppSubIds.size() > 0) { 371 mONSProfileConfig.deleteSubscription(oppSubIds.get(0)); 372 } 373 374 //Download retry will stop if there are no opportunistic eSIM profiles to delete 375 // from the same operator. 376 } 377 break; 378 379 case ERR_RETRY_DOWNLOAD: { 380 if (startBackoffTimer(pSIMSubId)) { 381 // do not log the atom if download retry has not reached max limit. 382 logStats = false; 383 } 384 } 385 break; 386 default: { 387 // Stop download until SIM change or device reboot. 388 Log.e(TAG, "Download failed with cause=" + resultCode); 389 } 390 } 391 if (logStats) { 392 mONSStats.logEvent(new ONSStatsInfo() 393 .setDownloadResult(resultCode) 394 .setPrimarySimSubId(pSIMSubId) 395 .setRetryCount(mDownloadRetryCount) 396 .setDetailedErrCode(detailedErrorCode) 397 .setWifiConnected(isWiFiConnected())); 398 } 399 } 400 401 /** 402 * Called when eSIM download fails. Listener is called after a delay based on retry count with 403 * the error code: BACKOFF_TIMER_EXPIRED 404 * 405 * @param pSIMSubId Primary Subscription ID 406 * @return true if backoff timer starts; otherwise false. 407 */ 408 @VisibleForTesting startBackoffTimer(int pSIMSubId)409 protected boolean startBackoffTimer(int pSIMSubId) { 410 //retry logic 411 mDownloadRetryCount++; 412 Log.e(TAG, "Download retry count :" + mDownloadRetryCount); 413 414 //Stop download retry if number of retries exceeded max configured value. 415 if (mDownloadRetryCount > getDownloadRetryMaxAttemptsVal(pSIMSubId)) { 416 Log.e(TAG, "Max download retry attempted. Stopping retry"); 417 return false; 418 } 419 420 int backoffTimerVal = getDownloadRetryBackOffTimerVal(pSIMSubId); 421 int delay = calculateBackoffDelay(mDownloadRetryCount, backoffTimerVal); 422 423 Message retryMsg = new Message(); 424 retryMsg.what = REQUEST_CODE_DOWNLOAD_RETRY; 425 retryMsg.arg2 = pSIMSubId; 426 mHandler.sendMessageDelayed(retryMsg, delay); 427 428 Log.d(TAG, "Download failed. Retry after :" + delay + "MilliSecs"); 429 return true; 430 } 431 432 @VisibleForTesting calculateBackoffDelay(int retryCount, int backoffTimerVal)433 protected static int calculateBackoffDelay(int retryCount, int backoffTimerVal) { 434 /** 435 * Timer value is calculated using "Exponential Backoff retry" algorithm. 436 * When the first download failure occurs, retry download after 437 * BACKOFF_TIMER_VALUE [Carrier Configurable] seconds. 438 * 439 * If download fails again then, retry after either BACKOFF_TIMER_VALUE, 440 * 2xBACKOFF_TIMER_VALUE, or 3xBACKOFF_TIMER_VALUE seconds. 441 * 442 * In general after the cth failed attempt, retry after k * 443 * BACKOFF_TIMER_VALUE seconds, where k is a random integer between 1 and 444 * 2^c − 1. Max c value is KEY_ESIM_MAX_DOWNLOAD_RETRY_ATTEMPTS_INT 445 * [Carrier configurable] 446 */ 447 Random random = new Random(); 448 //Calculate 2^c − 1 449 int maxTime = (int) Math.pow(2, retryCount) - 1; 450 451 //Random value between (1 & 2^c − 1) and convert to millisecond 452 return ((random.nextInt(maxTime) + 1)) * backoffTimerVal * 1000; 453 } 454 455 /** 456 * Retrieves maximum retry attempts from carrier configuration. After maximum attempts, further 457 * attempts will not be made until next device reboot. 458 * 459 * @param subscriptionId subscription Id of the primary SIM. 460 * @return integer value for maximum allowed retry attempts. 461 */ getDownloadRetryMaxAttemptsVal(int subscriptionId)462 private int getDownloadRetryMaxAttemptsVal(int subscriptionId) { 463 PersistableBundle config = mCarrierConfigMgr.getConfigForSubId(subscriptionId); 464 return config.getInt(CarrierConfigManager.KEY_ESIM_MAX_DOWNLOAD_RETRY_ATTEMPTS_INT); 465 } 466 467 /** 468 * Retrieves backoff timer value (in seconds) from carrier configuration. Value is used to 469 * calculate delay before retrying profile download. 470 * 471 * @param subscriptionId subscription Id of the primary SIM. 472 * @return Backoff timer value in seconds. 473 */ getDownloadRetryBackOffTimerVal(int subscriptionId)474 private int getDownloadRetryBackOffTimerVal(int subscriptionId) { 475 PersistableBundle config = mCarrierConfigMgr.getConfigForSubId(subscriptionId); 476 return config.getInt(CarrierConfigManager.KEY_ESIM_DOWNLOAD_RETRY_BACKOFF_TIMER_SEC_INT); 477 } 478 479 480 /** 481 * Checks if device supports eSIM. 482 */ isESIMSupported()483 private boolean isESIMSupported() { 484 for (UiccCardInfo uiccCardInfo : mTelephonyManager.getUiccCardsInfo()) { 485 if (uiccCardInfo != null && !uiccCardInfo.isEuicc()) { 486 // Skip this card. 487 continue; 488 } 489 490 EuiccManager euiccManager = mEuiccManager.createForCardId(uiccCardInfo.getCardId()); 491 if (euiccManager.isEnabled()) { 492 return true; 493 } 494 } 495 496 return false; 497 } 498 499 /** 500 * Fetches ONS auto provisioning enable flag from device configuration. 501 * ONS auto provisioning feature executes only when the flag is set to true in device 502 * configuration. 503 */ isONSAutoProvisioningEnabled()504 private boolean isONSAutoProvisioningEnabled() { 505 return mContext.getResources().getBoolean(R.bool.enable_ons_auto_provisioning); 506 } 507 508 /** 509 * Check if device support multiple active SIMs 510 */ isMultiSIMPhone()511 private boolean isMultiSIMPhone() { 512 return (mTelephonyManager.getSupportedModemCount() >= 2); 513 } 514 515 /** 516 * Check if the given subscription is a CBRS supported carrier. 517 */ isOppDataAutoProvisioningSupported(int pSIMSubId)518 private boolean isOppDataAutoProvisioningSupported(int pSIMSubId) { 519 PersistableBundle config = mCarrierConfigMgr.getConfigForSubId(pSIMSubId); 520 return config.getBoolean(CarrierConfigManager 521 .KEY_CARRIER_SUPPORTS_OPP_DATA_AUTO_PROVISIONING_BOOL); 522 } 523 524 /** 525 * Checks if device is in single SIM mode. 526 */ isDeviceInSingleSIMMode()527 private boolean isDeviceInSingleSIMMode() { 528 return (mTelephonyManager.getActiveModemCount() <= 1); 529 } 530 531 /** 532 * Switches device to multi SIM mode. Checks if reboot is required before switching and 533 * configuration is triggered only if reboot not required. 534 */ switchToMultiSIMMode()535 private boolean switchToMultiSIMMode() { 536 if (!mTelephonyManager.doesSwitchMultiSimConfigTriggerReboot()) { 537 mTelephonyManager.switchMultiSimConfig(2); 538 return true; 539 } 540 541 return false; 542 } 543 isWiFiConnected()544 private boolean isWiFiConnected() { 545 Network activeNetwork = mConnectivityManager.getActiveNetwork(); 546 if ((activeNetwork != null) && mConnectivityManager.getNetworkCapabilities(activeNetwork) 547 .hasTransport(NetworkCapabilities.TRANSPORT_WIFI)) { 548 return true; 549 } 550 551 return false; 552 } 553 554 /** 555 * Retrieves WiFi only eSIM Download flag the given subscription from carrier configuration. 556 * 557 * @param subscriptionId subscription Id of the primary SIM. 558 * @return download flag. 559 */ getESIMDownloadViaWiFiOnlyFlag(int subscriptionId)560 private boolean getESIMDownloadViaWiFiOnlyFlag(int subscriptionId) { 561 PersistableBundle config = mCarrierConfigMgr.getConfigForSubId(subscriptionId); 562 return config.getBoolean( 563 CarrierConfigManager.KEY_OPPORTUNISTIC_ESIM_DOWNLOAD_VIA_WIFI_ONLY_BOOL); 564 } 565 566 private class NetworkCallback extends ConnectivityManager.NetworkCallback { 567 @Override onAvailable(Network network)568 public void onAvailable(Network network) { 569 super.onAvailable(network); 570 Log.d(TAG, "Internet connection available"); 571 mIsInternetConnAvailable = true; 572 if (mRetryDownloadWhenNWConnected) { 573 Result res = provisionCBRS(); 574 Log.d(TAG, res.toString()); 575 mONSStats.logEvent(new ONSStatsInfo().setProvisioningResult(res)); 576 } 577 } 578 579 @Override onLost(Network network)580 public void onLost(Network network) { 581 super.onLost(network); 582 Log.d(TAG, "Internet connection lost"); 583 mIsInternetConnAvailable = false; 584 } 585 } 586 587 /** 588 * Enum to map the results of the CBRS provisioning. The order of the defined enums must be kept 589 * intact and new entries should be appended at the end of the list. 590 */ 591 public enum Result { 592 SUCCESS, 593 DOWNLOAD_REQUESTED, 594 ERR_SWITCHING_TO_DUAL_SIM_MODE, 595 ERR_AUTO_PROVISIONING_DISABLED, 596 ERR_ESIM_NOT_SUPPORTED, 597 ERR_MULTISIM_NOT_SUPPORTED, 598 ERR_CARRIER_DOESNT_SUPPORT_CBRS, 599 ERR_DUAL_ACTIVE_SUBSCRIPTIONS, 600 ERR_NO_SIM_INSERTED, 601 ERR_SINGLE_ACTIVE_OPPORTUNISTIC_SIM, 602 ERR_CANNOT_SWITCH_TO_DUAL_SIM_MODE, 603 ERR_WAITING_FOR_INTERNET_CONNECTION, 604 ERR_WAITING_FOR_WIFI_CONNECTION, 605 ERR_DUPLICATE_DOWNLOAD_REQUEST, 606 ERR_INVALID_CARRIER_CONFIG, 607 ERR_DOWNLOADED_ESIM_NOT_FOUND, 608 ERR_PSIM_NOT_FOUND, 609 ERR_UNKNOWN; 610 } 611 } 612