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