• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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