• 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         int activeSubCount = activeSubInfos.size();
177         Log.d(TAG, "Active subscription count:" + activeSubCount);
178 
179         if (activeSubCount <= 0) {
180             return Result.ERR_NO_SIM_INSERTED;
181         } else if (activeSubCount == 1) {
182             SubscriptionInfo pSubInfo = activeSubInfos.get(0);
183             if (pSubInfo.isOpportunistic()) {
184                 //Only one SIM is active and its opportunistic SIM.
185                 //Opportunistic eSIM shouldn't be used without pSIM.
186                 return Result.ERR_SINGLE_ACTIVE_OPPORTUNISTIC_SIM;
187             }
188 
189             //if pSIM is not a CBRS carrier
190             if (!isOppDataAutoProvisioningSupported(
191                     pSubInfo.getSubscriptionId())) {
192                 return Result.ERR_CARRIER_DOESNT_SUPPORT_CBRS;
193             }
194 
195             if (isDeviceInSingleSIMMode()) {
196                 if (!switchToMultiSIMMode()) {
197                     return Result.ERR_CANNOT_SWITCH_TO_DUAL_SIM_MODE;
198                 }
199 
200                 //Once device is Switched to Dual-SIM Mode, handleSimStateChange is triggered.
201                 return Result.ERR_SWITCHING_TO_DUAL_SIM_MODE;
202             }
203 
204             return downloadAndActivateOpportunisticSubscription(pSubInfo);
205         } else if (activeSubCount >= 2) {
206             //If all the SIMs are physical SIM then it's a sure case of DUAL Active Subscription.
207             boolean allPhysicalSIMs = true;
208             for (SubscriptionInfo subInfo : activeSubInfos) {
209                 if (subInfo.isEmbedded()) {
210                     allPhysicalSIMs = false;
211                     break;
212                 }
213             }
214 
215             if (allPhysicalSIMs) {
216                 return Result.ERR_DUAL_ACTIVE_SUBSCRIPTIONS;
217             }
218 
219             //Check if one of the subscription is opportunistic but not marked.
220             //if one of the SIM is opportunistic and not grouped then group the subscription.
221             for (SubscriptionInfo subInfo : activeSubInfos) {
222                 int pSubId = subInfo.getSubscriptionId();
223                 if (!subInfo.isEmbedded() && isOppDataAutoProvisioningSupported(pSubId)) {
224 
225                     Log.d(TAG, "CBRS pSIM found. SubId:" + pSubId);
226 
227                     //Check if other SIM is opportunistic based on carrier-id.
228                     SubscriptionInfo oppSubInfo = mONSProfileConfig
229                             .findOpportunisticSubscription(pSubId);
230 
231                     //If opportunistic eSIM is found and activated.
232                     if (oppSubInfo != null) {
233                         if (mSubManager.isActiveSubscriptionId(oppSubInfo.getSubscriptionId())
234                                 && oppSubInfo.isOpportunistic()) {
235                             //Already configured. No action required.
236                             return Result.SUCCESS;
237                         }
238 
239                         ParcelUuid pSIMGroupId = mONSProfileConfig.getPSIMGroupId(subInfo);
240                         mONSProfileConfig.groupWithPSIMAndSetOpportunistic(oppSubInfo, pSIMGroupId);
241                         return Result.SUCCESS;
242                     }
243                 }
244             }
245 
246             return Result.ERR_DUAL_ACTIVE_SUBSCRIPTIONS;
247         }
248 
249         return Result.ERR_UNKNOWN;
250     }
251 
downloadAndActivateOpportunisticSubscription( SubscriptionInfo primaryCBRSSubInfo)252     private Result downloadAndActivateOpportunisticSubscription(
253             SubscriptionInfo primaryCBRSSubInfo) {
254         Log.d(TAG, "downloadAndActivateOpportunisticSubscription");
255 
256         //Check if pSIM is part of a group. If not then create a group.
257         ParcelUuid pSIMgroupId = mONSProfileConfig.getPSIMGroupId(primaryCBRSSubInfo);
258 
259         //Check if opp eSIM is already downloaded but not grouped.
260         SubscriptionInfo oppSubInfo = mONSProfileConfig.findOpportunisticSubscription(
261                 primaryCBRSSubInfo.getSubscriptionId());
262         if (oppSubInfo != null) {
263             mONSProfileConfig.groupWithPSIMAndSetOpportunistic(oppSubInfo, pSIMgroupId);
264             return Result.SUCCESS;
265         }
266 
267         if (!mIsInternetConnAvailable) {
268             Log.d(TAG, "No internet connection. Download will be attempted when "
269                     + "connection is restored");
270             mRetryDownloadWhenNWConnected = true;
271             return Result.ERR_WAITING_FOR_INTERNET_CONNECTION;
272         }
273 
274         /* If download WiFi only flag is set and WiFi is not connected */
275         if (getESIMDownloadViaWiFiOnlyFlag(primaryCBRSSubInfo.getSubscriptionId())
276                 && !isWiFiConnected()) {
277             Log.d(TAG, "Download via WiFi only flag is set but WiFi is not connected."
278                     + "Download will be attempted when WiFi connection is restored");
279             mRetryDownloadWhenNWConnected = true;
280             return Result.ERR_WAITING_FOR_WIFI_CONNECTION;
281         }
282 
283         //Opportunistic subscription not found. Trigger Download.
284         ONSProfileDownloader.DownloadProfileResult res = mONSProfileDownloader.downloadProfile(
285                 primaryCBRSSubInfo.getSubscriptionId());
286 
287         switch (res) {
288             case DUPLICATE_REQUEST: return Result.ERR_DUPLICATE_DOWNLOAD_REQUEST;
289             case INVALID_SMDP_ADDRESS: return Result.ERR_INVALID_CARRIER_CONFIG;
290             case SUCCESS: return Result.DOWNLOAD_REQUESTED;
291         }
292 
293         return Result.ERR_UNKNOWN;
294     }
295 
296     @Override
onDownloadComplete(int primarySubId)297     public void onDownloadComplete(int primarySubId) {
298         mRetryDownloadWhenNWConnected = false;
299         SubscriptionInfo opportunisticESIM = mONSProfileConfig.findOpportunisticSubscription(
300                 primarySubId);
301         if (opportunisticESIM == null) {
302             Log.e(TAG, "Downloaded Opportunistic eSIM not found. Unable to group with pSIM");
303             mONSStats.logEvent(new ONSStatsInfo()
304                     .setProvisioningResult(Result.ERR_DOWNLOADED_ESIM_NOT_FOUND)
305                     .setPrimarySimSubId(primarySubId)
306                     .setWifiConnected(isWiFiConnected()));
307             return;
308         }
309 
310         SubscriptionInfo pSIMSubInfo = mSubManager.getActiveSubscriptionInfo(primarySubId);
311         if (pSIMSubInfo != null) {
312             // Group with same Primary SIM for which eSIM is downloaded.
313             mONSProfileConfig.groupWithPSIMAndSetOpportunistic(
314                     opportunisticESIM, pSIMSubInfo.getGroupUuid());
315             Log.d(TAG, "eSIM downloaded and configured successfully");
316             mONSStats.logEvent(new ONSStatsInfo()
317                     .setProvisioningResult(Result.SUCCESS)
318                     .setRetryCount(mDownloadRetryCount)
319                     .setWifiConnected(isWiFiConnected()));
320         } else {
321             Log.d(TAG, "ESIM downloaded but pSIM is not active or removed");
322             mONSStats.logEvent(new ONSStatsInfo()
323                     .setProvisioningResult(Result.ERR_PSIM_NOT_FOUND)
324                     .setOppSimCarrierId(opportunisticESIM.getCarrierId())
325                     .setWifiConnected(isWiFiConnected()));
326         }
327     }
328 
329     @Override
onDownloadError(int pSIMSubId, DownloadRetryResultCode resultCode, int detailedErrorCode)330     public void onDownloadError(int pSIMSubId, DownloadRetryResultCode resultCode,
331             int detailedErrorCode) {
332         boolean logStats = true;
333         switch (resultCode) {
334             case ERR_MEMORY_FULL: {
335                 //eUICC Memory full occurred while downloading opportunistic eSIM.
336 
337                 //First find and delete any opportunistic eSIMs from the operator same as the
338                 // current primary SIM.
339                 ArrayList<Integer> oppSubIds = mONSProfileConfig
340                         .getOpportunisticSubIdsofPSIMOperator(pSIMSubId);
341                 if (oppSubIds != null && oppSubIds.size() > 0) {
342                     mONSProfileConfig.deleteSubscription(oppSubIds.get(0));
343                 } else {
344                     //else, find the inactive opportunistic eSIMs (any operator) and delete one of
345                     // them and retry download again.
346                     mONSProfileConfig.deleteInactiveOpportunisticSubscriptions(pSIMSubId);
347                 }
348 
349                 //Delete subscription -> onOppSubscriptionDeleted callback ->  provisionCBRS ->
350                 // triggers eSIM download again.
351 
352                 //Download retry will stop if there are no opportunistic eSIM profiles to delete.
353             }
354             break;
355 
356             case ERR_INSTALL_ESIM_PROFILE_FAILED: {
357                 //Since the installation of eSIM profile has failed there may be an issue with the
358                 //format or profile data. We retry by first deleting existing eSIM profile from the
359                 //operator same as the primary SIM and retry download opportunistic eSIM.
360                 ArrayList<Integer> oppSubIds = mONSProfileConfig
361                         .getOpportunisticSubIdsofPSIMOperator(pSIMSubId);
362 
363                 if (oppSubIds != null && oppSubIds.size() > 0) {
364                     mONSProfileConfig.deleteSubscription(oppSubIds.get(0));
365                 }
366 
367                 //Download retry will stop if there are no opportunistic eSIM profiles to delete
368                 // from the same operator.
369             }
370             break;
371 
372             case ERR_RETRY_DOWNLOAD: {
373                 if (startBackoffTimer(pSIMSubId)) {
374                     // do not log the atom if download retry has not reached max limit.
375                     logStats = false;
376                 }
377             }
378             break;
379             default: {
380                 // Stop download until SIM change or device reboot.
381                 Log.e(TAG, "Download failed with cause=" + resultCode);
382             }
383         }
384         if (logStats) {
385             mONSStats.logEvent(new ONSStatsInfo()
386                     .setDownloadResult(resultCode)
387                     .setPrimarySimSubId(pSIMSubId)
388                     .setRetryCount(mDownloadRetryCount)
389                     .setDetailedErrCode(detailedErrorCode)
390                     .setWifiConnected(isWiFiConnected()));
391         }
392     }
393 
394     /**
395      * Called when eSIM download fails. Listener is called after a delay based on retry count with
396      * the error code: BACKOFF_TIMER_EXPIRED
397      *
398      * @param pSIMSubId Primary Subscription ID
399      * @return true if backoff timer starts; otherwise false.
400      */
401     @VisibleForTesting
startBackoffTimer(int pSIMSubId)402     protected boolean startBackoffTimer(int pSIMSubId) {
403         //retry logic
404         mDownloadRetryCount++;
405         Log.e(TAG, "Download retry count :" + mDownloadRetryCount);
406 
407         //Stop download retry if number of retries exceeded max configured value.
408         if (mDownloadRetryCount > getDownloadRetryMaxAttemptsVal(pSIMSubId)) {
409             Log.e(TAG, "Max download retry attempted. Stopping retry");
410             return false;
411         }
412 
413         int backoffTimerVal = getDownloadRetryBackOffTimerVal(pSIMSubId);
414         int delay = calculateBackoffDelay(mDownloadRetryCount, backoffTimerVal);
415 
416         Message retryMsg = new Message();
417         retryMsg.what = REQUEST_CODE_DOWNLOAD_RETRY;
418         retryMsg.arg2 = pSIMSubId;
419         mHandler.sendMessageDelayed(retryMsg, delay);
420 
421         Log.d(TAG, "Download failed. Retry after :" + delay + "MilliSecs");
422         return true;
423     }
424 
425     @VisibleForTesting
calculateBackoffDelay(int retryCount, int backoffTimerVal)426     protected static int calculateBackoffDelay(int retryCount, int backoffTimerVal) {
427         /**
428          * Timer value is calculated using "Exponential Backoff retry" algorithm.
429          * When the first download failure occurs, retry download after
430          * BACKOFF_TIMER_VALUE [Carrier Configurable] seconds.
431          *
432          * If download fails again then, retry after either BACKOFF_TIMER_VALUE,
433          * 2xBACKOFF_TIMER_VALUE, or 3xBACKOFF_TIMER_VALUE seconds.
434          *
435          * In general after the cth failed attempt, retry after k *
436          * BACKOFF_TIMER_VALUE seconds, where k is a random integer between 1 and
437          * 2^c − 1. Max c value is KEY_ESIM_MAX_DOWNLOAD_RETRY_ATTEMPTS_INT
438          * [Carrier configurable]
439          */
440         Random random = new Random();
441         //Calculate 2^c − 1
442         int maxTime = (int) Math.pow(2, retryCount) - 1;
443 
444         //Random value between (1 & 2^c − 1) and convert to millisecond
445         return ((random.nextInt(maxTime) + 1)) * backoffTimerVal * 1000;
446     }
447 
448     /**
449      * Retrieves maximum retry attempts from carrier configuration. After maximum attempts, further
450      * attempts will not be made until next device reboot.
451      *
452      * @param subscriptionId subscription Id of the primary SIM.
453      * @return integer value for maximum allowed retry attempts.
454      */
getDownloadRetryMaxAttemptsVal(int subscriptionId)455     private int getDownloadRetryMaxAttemptsVal(int subscriptionId) {
456         PersistableBundle config = mCarrierConfigMgr.getConfigForSubId(subscriptionId);
457         return config.getInt(CarrierConfigManager.KEY_ESIM_MAX_DOWNLOAD_RETRY_ATTEMPTS_INT);
458     }
459 
460     /**
461      * Retrieves backoff timer value (in seconds) from carrier configuration. Value is used to
462      * calculate delay before retrying profile download.
463      *
464      * @param subscriptionId subscription Id of the primary SIM.
465      * @return Backoff timer value in seconds.
466      */
getDownloadRetryBackOffTimerVal(int subscriptionId)467     private int getDownloadRetryBackOffTimerVal(int subscriptionId) {
468         PersistableBundle config = mCarrierConfigMgr.getConfigForSubId(subscriptionId);
469         return config.getInt(CarrierConfigManager.KEY_ESIM_DOWNLOAD_RETRY_BACKOFF_TIMER_SEC_INT);
470     }
471 
472 
473     /**
474      * Checks if device supports eSIM.
475      */
isESIMSupported()476     private boolean isESIMSupported() {
477         return (mEuiccManager != null && mEuiccManager.isEnabled());
478     }
479 
480     /**
481      * Fetches ONS auto provisioning enable flag from device configuration.
482      * ONS auto provisioning feature executes only when the flag is set to true in device
483      * configuration.
484      */
isONSAutoProvisioningEnabled()485     private boolean isONSAutoProvisioningEnabled() {
486         return mContext.getResources().getBoolean(R.bool.enable_ons_auto_provisioning);
487     }
488 
489     /**
490      * Check if device support multiple active SIMs
491      */
isMultiSIMPhone()492     private boolean isMultiSIMPhone() {
493         return (mTelephonyManager.getSupportedModemCount() >= 2);
494     }
495 
496     /**
497      * Check if the given subscription is a CBRS supported carrier.
498      */
isOppDataAutoProvisioningSupported(int pSIMSubId)499     private boolean isOppDataAutoProvisioningSupported(int pSIMSubId) {
500         PersistableBundle config = mCarrierConfigMgr.getConfigForSubId(pSIMSubId);
501         return config.getBoolean(CarrierConfigManager
502                 .KEY_CARRIER_SUPPORTS_OPP_DATA_AUTO_PROVISIONING_BOOL);
503     }
504 
505     /**
506      * Checks if device is in single SIM mode.
507      */
isDeviceInSingleSIMMode()508     private boolean isDeviceInSingleSIMMode() {
509         return (mTelephonyManager.getActiveModemCount() <= 1);
510     }
511 
512     /**
513      * Switches device to multi SIM mode. Checks if reboot is required before switching and
514      * configuration is triggered only if reboot not required.
515      */
switchToMultiSIMMode()516     private boolean switchToMultiSIMMode() {
517         if (!mTelephonyManager.doesSwitchMultiSimConfigTriggerReboot()) {
518             mTelephonyManager.switchMultiSimConfig(2);
519             return true;
520         }
521 
522         return false;
523     }
524 
isWiFiConnected()525     private boolean isWiFiConnected() {
526         Network activeNetwork = mConnectivityManager.getActiveNetwork();
527         if ((activeNetwork != null) && mConnectivityManager.getNetworkCapabilities(activeNetwork)
528                 .hasTransport(NetworkCapabilities.TRANSPORT_WIFI)) {
529             return true;
530         }
531 
532         return false;
533     }
534 
535     /**
536      * Retrieves WiFi only eSIM Download flag the given subscription from carrier configuration.
537      *
538      * @param subscriptionId subscription Id of the primary SIM.
539      * @return download flag.
540      */
getESIMDownloadViaWiFiOnlyFlag(int subscriptionId)541     private boolean getESIMDownloadViaWiFiOnlyFlag(int subscriptionId) {
542         PersistableBundle config = mCarrierConfigMgr.getConfigForSubId(subscriptionId);
543         return config.getBoolean(
544                 CarrierConfigManager.KEY_OPPORTUNISTIC_ESIM_DOWNLOAD_VIA_WIFI_ONLY_BOOL);
545     }
546 
547     private class NetworkCallback extends ConnectivityManager.NetworkCallback {
548         @Override
onAvailable(Network network)549         public void onAvailable(Network network) {
550             super.onAvailable(network);
551             Log.d(TAG, "Internet connection available");
552             mIsInternetConnAvailable = true;
553             if (mRetryDownloadWhenNWConnected) {
554                 Result res = provisionCBRS();
555                 Log.d(TAG, res.toString());
556                 mONSStats.logEvent(new ONSStatsInfo().setProvisioningResult(res));
557             }
558         }
559 
560         @Override
onLost(Network network)561         public void onLost(Network network) {
562             super.onLost(network);
563             Log.d(TAG, "Internet connection lost");
564             mIsInternetConnAvailable = false;
565         }
566     }
567 
568     /**
569      * Enum to map the results of the CBRS provisioning. The order of the defined enums must be kept
570      * intact and new entries should be appended at the end of the list.
571      */
572     public enum Result {
573         SUCCESS,
574         DOWNLOAD_REQUESTED,
575         ERR_SWITCHING_TO_DUAL_SIM_MODE,
576         ERR_AUTO_PROVISIONING_DISABLED,
577         ERR_ESIM_NOT_SUPPORTED,
578         ERR_MULTISIM_NOT_SUPPORTED,
579         ERR_CARRIER_DOESNT_SUPPORT_CBRS,
580         ERR_DUAL_ACTIVE_SUBSCRIPTIONS,
581         ERR_NO_SIM_INSERTED,
582         ERR_SINGLE_ACTIVE_OPPORTUNISTIC_SIM,
583         ERR_CANNOT_SWITCH_TO_DUAL_SIM_MODE,
584         ERR_WAITING_FOR_INTERNET_CONNECTION,
585         ERR_WAITING_FOR_WIFI_CONNECTION,
586         ERR_DUPLICATE_DOWNLOAD_REQUEST,
587         ERR_INVALID_CARRIER_CONFIG,
588         ERR_DOWNLOADED_ESIM_NOT_FOUND,
589         ERR_PSIM_NOT_FOUND,
590         ERR_UNKNOWN;
591     }
592 }
593