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