diff options
author | Avinash Malipatil <avinashmp@google.com> | 2022-03-16 05:41:00 +0000 |
---|---|---|
committer | Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com> | 2022-03-16 05:41:00 +0000 |
commit | c1da635fc0e403211baadfd6f620f790bea79ec2 (patch) | |
tree | b390b691692a2850e2c8ffa3b27e5259e48ce3ef | |
parent | ca27d9ea3f04e65058385bb46a9ec3cf7bdfb55a (diff) | |
parent | ac6e9baf2333a3ab5bba45aa8b76d995a95dc055 (diff) | |
download | AlternativeNetworkAccess-c1da635fc0e403211baadfd6f620f790bea79ec2.tar.gz |
Use worker thread to create message handlers and perform background tasks. am: c6e04fbfe1 am: d4f3f94e41 am: ac6e9baf23
Original change: https://android-review.googlesource.com/c/platform/packages/services/AlternativeNetworkAccess/+/1991674
Change-Id: I08bedbaf0d786d5433e9e1763764460b2fb7146f
-rw-r--r-- | AndroidManifest.xml | 8 | ||||
-rw-r--r-- | src/com/android/ons/ONSProfileActivator.java | 372 | ||||
-rw-r--r-- | src/com/android/ons/ONSProfileConfigurator.java | 355 | ||||
-rw-r--r-- | src/com/android/ons/ONSProfileDownloader.java | 205 | ||||
-rw-r--r-- | src/com/android/ons/ONSProfileResultReceiver.java | 46 | ||||
-rw-r--r-- | src/com/android/ons/OpportunisticNetworkService.java | 114 | ||||
-rw-r--r-- | tests/src/com/android/ons/ONSProfileActivatorTest.java | 324 | ||||
-rw-r--r-- | tests/src/com/android/ons/ONSProfileConfiguratorTest.java | 208 | ||||
-rw-r--r-- | tests/src/com/android/ons/ONSProfileDownloaderTest.java | 284 |
9 files changed, 1096 insertions, 820 deletions
diff --git a/AndroidManifest.xml b/AndroidManifest.xml index 770de9e..24f7968 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -21,7 +21,8 @@ android:process="com.android.phone" android:sharedUserId="android.uid.phone"> - <protected-broadcast android:name="com.android.ons.ONSProfileResultReceiver.CALLBACK" /> + <protected-broadcast android:name="com.android.ons.action.DOWNLOAD" /> + <protected-broadcast android:name="com.android.ons.action.CONFIG" /> <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" /> <application @@ -49,7 +50,10 @@ <action android:name="android.telephony.action.MULTI_SIM_CONFIG_CHANGED"/> </intent-filter> <intent-filter> - <action android:name="com.android.ons.ONSProfileResultReceiver.CALLBACK"/> + <action android:name="com.android.ons.action.ESIM_DOWNLOAD"/> + </intent-filter> + <intent-filter> + <action android:name="com.android.ons.action.ESIM_CONFIG"/> </intent-filter> </receiver> </application> diff --git a/src/com/android/ons/ONSProfileActivator.java b/src/com/android/ons/ONSProfileActivator.java index 6dd6c33..0dc57b4 100644 --- a/src/com/android/ons/ONSProfileActivator.java +++ b/src/com/android/ons/ONSProfileActivator.java @@ -18,49 +18,114 @@ package com.android.ons; import android.annotation.TestApi; import android.content.Context; +import android.net.ConnectivityManager; +import android.net.Network; +import android.net.NetworkCapabilities; +import android.net.NetworkRequest; +import android.os.Handler; +import android.os.Looper; +import android.os.Message; import android.os.ParcelUuid; +import android.os.PersistableBundle; +import android.telephony.CarrierConfigManager; import android.telephony.SubscriptionInfo; import android.telephony.SubscriptionManager; import android.telephony.TelephonyManager; +import android.telephony.euicc.EuiccManager; import android.util.Log; +import com.android.internal.annotations.VisibleForTesting; + +import java.util.ArrayList; import java.util.List; +import java.util.Random; /** * @class ONSProfileActivator * @brief ONSProfileActivator makes sure that the CBRS profile is downloaded, activated and grouped * when an opportunistic data enabled pSIM is inserted. */ -public class ONSProfileActivator implements ONSProfileConfigurator.ONSProfConfigListener { +public class ONSProfileActivator implements ONSProfileConfigurator.ONSProfConfigListener, + ONSProfileDownloader.IONSProfileDownloaderListener { + private static final String TAG = ONSProfileActivator.class.getName(); private final Context mContext; + private final SubscriptionManager mSubManager; + private final TelephonyManager mTelephonyManager; + private final CarrierConfigManager mCarrierConfigMgr; + private final EuiccManager mEuiccManager; private final ONSProfileConfigurator mONSProfileConfig; private final ONSProfileDownloader mONSProfileDownloader; + private final ConnectivityManager mConnectivityManager; + @VisibleForTesting protected boolean mIsInternetConnAvailable = false; + @VisibleForTesting protected boolean mRetryDownloadWhenNWConnected = false; + private int mDownloadRetryCount = 0; + + @VisibleForTesting protected static final int REQUEST_CODE_DOWNLOAD_RETRY = 2; public ONSProfileActivator(Context context) { mContext = context; - - mONSProfileConfig = new ONSProfileConfigurator(mContext, this); - mONSProfileDownloader = new ONSProfileDownloader(mContext, mONSProfileConfig, - primarySubId -> onDownloadComplete(primarySubId)); + mSubManager = mContext.getSystemService(SubscriptionManager.class); + mTelephonyManager = mContext.getSystemService(TelephonyManager.class); + mCarrierConfigMgr = mContext.getSystemService(CarrierConfigManager.class); + mEuiccManager = mContext.getSystemService(EuiccManager.class); + mONSProfileConfig = new ONSProfileConfigurator(mContext, mSubManager, + mCarrierConfigMgr, mEuiccManager, this); + mONSProfileDownloader = new ONSProfileDownloader(mContext, mCarrierConfigMgr, + mEuiccManager, mONSProfileConfig, this); + + //Monitor internet connection. + mConnectivityManager = context.getSystemService(ConnectivityManager.class); + + NetworkRequest request = new NetworkRequest.Builder().addCapability( + NetworkCapabilities.NET_CAPABILITY_VALIDATED).build(); + mConnectivityManager.registerNetworkCallback(request, new NetworkCallback()); } /** * This constructor is only for JUnit testing */ @TestApi - ONSProfileActivator(Context mockContext, ONSProfileConfigurator mockONSProfileConfigurator, - ONSProfileDownloader mockONSProfileDownloader) { + ONSProfileActivator(Context mockContext, SubscriptionManager subscriptionManager, + TelephonyManager telephonyManager, CarrierConfigManager carrierConfigMgr, + EuiccManager euiccManager, ConnectivityManager connManager, + ONSProfileConfigurator onsProfileConfigurator, + ONSProfileDownloader onsProfileDownloader) { mContext = mockContext; - mONSProfileConfig = mockONSProfileConfigurator; - mONSProfileDownloader = mockONSProfileDownloader; + mSubManager = subscriptionManager; + mTelephonyManager = telephonyManager; + mCarrierConfigMgr = carrierConfigMgr; + mEuiccManager = euiccManager; + mConnectivityManager = connManager; + mONSProfileConfig = onsProfileConfigurator; + mONSProfileDownloader = onsProfileDownloader; } + ONSProfileConfigurator getONSProfileConfigurator() { + return mONSProfileConfig; + } + + ONSProfileDownloader getONSProfileDownloader() { + return mONSProfileDownloader; + } + + private final Handler mHandler = new Handler(Looper.myLooper()) { + @Override + public void handleMessage(Message msg) { + switch (msg.what) { + case REQUEST_CODE_DOWNLOAD_RETRY: { + provisionCBRS(); + } + break; + } + } + }; + /** * Called when SIM state changes. Triggers CBRS Auto provisioning. */ public Result handleSimStateChange() { - final int simState = mONSProfileConfig.getTelephonyManager().getSimState(); + final int simState = mTelephonyManager.getSimState(); if (simState != TelephonyManager.SIM_STATE_READY) { return Result.ERR_SIM_NOT_READY; } @@ -71,16 +136,6 @@ public class ONSProfileActivator implements ONSProfileConfigurator.ONSProfConfig } @Override - public void onConnectionChanged(boolean bConnected) { - if (bConnected && mONSProfileConfig != null - && mONSProfileConfig.getRetryDownloadWhenConnectedFlag()) { - Log.d(TAG, "Internet connection restored. Retrying CBRS auto provisioning"); - Result res = provisionCBRS(); - Log.d(TAG, res.toString()); - } - } - - @Override public void onOppSubscriptionDeleted(int pSIMId) { provisionCBRS(); } @@ -92,23 +147,22 @@ public class ONSProfileActivator implements ONSProfileConfigurator.ONSProfConfig */ private Result provisionCBRS() { - if (!mONSProfileConfig.isONSAutoProvisioningEnabled()) { + if (!isONSAutoProvisioningEnabled()) { return Result.ERR_AUTO_PROVISIONING_DISABLED; } //Check if device supports eSIM - if (!mONSProfileConfig.isESIMSupported()) { + if (!isESIMSupported()) { return Result.ERR_ESIM_NOT_SUPPORTED; } //Check if it's a multi SIM Phone. CBRS is not supported on Single SIM phone. - if (!mONSProfileConfig.isMultiSIMPhone()) { + if (!isMultiSIMPhone()) { return Result.ERR_MULTISIM_NOT_SUPPORTED; } //Check the number of active subscriptions. - SubscriptionManager subManager = mONSProfileConfig.getSubscriptionManager(); - List<SubscriptionInfo> activeSubInfos = subManager.getActiveSubscriptionInfoList(); + List<SubscriptionInfo> activeSubInfos = mSubManager.getActiveSubscriptionInfoList(); int activeSubCount = activeSubInfos.size(); Log.d(TAG, "Active subscription count:" + activeSubCount); @@ -123,18 +177,18 @@ public class ONSProfileActivator implements ONSProfileConfigurator.ONSProfConfig } //if pSIM is not a CBRS carrier - if (!mONSProfileConfig.isOppDataAutoProvisioningSupported( + if (!isOppDataAutoProvisioningSupported( pSubInfo.getSubscriptionId())) { return Result.ERR_CARRIER_DOESNT_SUPPORT_CBRS; } - if (mONSProfileConfig.isDeviceInSingleSIMMode()) { - if (!mONSProfileConfig.switchToMultiSIMMode()) { + if (isDeviceInSingleSIMMode()) { + if (!switchToMultiSIMMode()) { return Result.ERR_CANNOT_SWITCH_TO_DUAL_SIM_MODE; } //Once device is Switched to Dual-SIM Mode, handleSimStateChange is triggered. - return Result.ERR_SWITCHED_TO_DUAL_SIM_MODE; + return Result.ERR_SWITCHING_TO_DUAL_SIM_MODE; } return downloadAndActivateOpportunisticSubscription(pSubInfo); @@ -156,8 +210,7 @@ public class ONSProfileActivator implements ONSProfileConfigurator.ONSProfConfig //if one of the SIM is opportunistic and not grouped then group the subscription. for (SubscriptionInfo subInfo : activeSubInfos) { int pSubId = subInfo.getSubscriptionId(); - if (!subInfo.isEmbedded() && mONSProfileConfig - .isOppDataAutoProvisioningSupported(pSubId)) { + if (!subInfo.isEmbedded() && isOppDataAutoProvisioningSupported(pSubId)) { Log.d(TAG, "CBRS pSIM found. SubId:" + pSubId); @@ -167,7 +220,7 @@ public class ONSProfileActivator implements ONSProfileConfigurator.ONSProfConfig //If opportunistic eSIM is found and activated. if (oppSubInfo != null) { - if (subManager.isActiveSubscriptionId(oppSubInfo.getSubscriptionId()) + if (mSubManager.isActiveSubscriptionId(oppSubInfo.getSubscriptionId()) && oppSubInfo.isOpportunistic()) { //Already configured. No action required. return Result.SUCCESS; @@ -201,22 +254,38 @@ public class ONSProfileActivator implements ONSProfileConfigurator.ONSProfConfig return Result.SUCCESS; } + if (!mIsInternetConnAvailable) { + Log.d(TAG, "No internet connection. Download will be attempted when " + + "connection is restored"); + mRetryDownloadWhenNWConnected = true; + return Result.ERR_WAITING_FOR_INTERNET_CONNECTION; + } + + /* If download WiFi only flag is set and WiFi is not connected */ + if (getESIMDownloadViaWiFiOnlyFlag(primaryCBRSSubInfo.getSubscriptionId()) + && !isWiFiConnected()) { + Log.d(TAG, "Download via WiFi only flag is set but WiFi is not connected." + + "Download will be attempted when WiFi connection is restored"); + mRetryDownloadWhenNWConnected = true; + return Result.ERR_WAITING_FOR_WIFI_CONNECTION; + } + //Opportunistic subscription not found. Trigger Download. - mONSProfileDownloader.downloadOpportunisticESIM(primaryCBRSSubInfo); + mONSProfileDownloader.downloadProfile(primaryCBRSSubInfo.getSubscriptionId()); return Result.SUCCESS; } - private void onDownloadComplete(int primarySubId) { - mONSProfileConfig.setRetryDownloadWhenConnectedFlag(false); - SubscriptionInfo opportunisticESIM = mONSProfileConfig - .findOpportunisticSubscription(primarySubId); + @Override + public void onDownloadComplete(int primarySubId) { + mRetryDownloadWhenNWConnected = false; + SubscriptionInfo opportunisticESIM = mONSProfileConfig.findOpportunisticSubscription( + primarySubId); if (opportunisticESIM == null) { Log.e(TAG, "Downloaded Opportunistic eSIM not found. Unable to group with pSIM"); return; } - SubscriptionManager subManager = mONSProfileConfig.getSubscriptionManager(); - SubscriptionInfo pSIMSubInfo = subManager.getActiveSubscriptionInfo(primarySubId); + SubscriptionInfo pSIMSubInfo = mSubManager.getActiveSubscriptionInfo(primarySubId); if (pSIMSubInfo != null) { mONSProfileConfig.groupWithPSIMAndSetOpportunistic( opportunisticESIM, pSIMSubInfo.getGroupUuid()); @@ -226,8 +295,230 @@ public class ONSProfileActivator implements ONSProfileConfigurator.ONSProfConfig } } + @Override + public void onDownloadError(ONSProfileDownloader.DownloadRetryOperationCode operationCode, + int pSIMSubId) { + switch (operationCode) { + case ERR_MEMORY_FULL: { + //eUICC Memory full occurred while downloading opportunistic eSIM. + + //First find and delete any opportunistic eSIMs from the operator same as the + // current primary SIM. + ArrayList<Integer> oppSubIds = mONSProfileConfig + .getOpportunisticSubIdsofPSIMOperator(pSIMSubId); + if (oppSubIds != null && oppSubIds.size() > 0) { + mONSProfileConfig.deleteSubscription(oppSubIds.get(0)); + } else { + //else, find the inactive opportunistic eSIMs (any operator) and delete one of + // them and retry download again. + mONSProfileConfig.deleteInactiveOpportunisticSubscriptions(pSIMSubId); + } + + //Delete subscription -> onOppSubscriptionDeleted callback -> provisionCBRS -> + // triggers eSIM download again. + + //Download retry will stop if there are no opportunistic eSIM profiles to delete. + } + break; + + case ERR_INSTALL_ESIM_PROFILE_FAILED: { + //Since the installation of eSIM profile has failed there may be an issue with the + //format or profile data. We retry by first deleting existing eSIM profile from the + //operator same as the primary SIM and retry download opportunistic eSIM. + ArrayList<Integer> oppSubIds = mONSProfileConfig + .getOpportunisticSubIdsofPSIMOperator(pSIMSubId); + + if (oppSubIds != null && oppSubIds.size() > 0) { + mONSProfileConfig.deleteSubscription(oppSubIds.get(0)); + } + + //Download retry will stop if there are no opportunistic eSIM profiles to delete + // from the same operator. + } + break; + + case ERR_RETRY_DOWNLOAD: { + startBackoffTimer(pSIMSubId, mDownloadRetryCount); + } + break; + + case ERR_UNRESOLVABLE: { + //Stop download until SIM change or device reboot. + } + } + } + + /** + * Called when eSIM download fails. Listener is called after a delay based on retry count with + * the error code: BACKOFF_TIMER_EXPIRED + * @param pSIMSubId + * @param retryCount + */ + @VisibleForTesting + protected void startBackoffTimer(int pSIMSubId, int retryCount) { + //retry logic + retryCount++; + Log.e(TAG, "Download retry count :" + retryCount); + if (retryCount >= getDownloadRetryMaxAttemptsVal(pSIMSubId)) { + Log.e(TAG, "Max download retry attempted. Stopping retry"); + return; + } + + int backoffTimerVal = getDownloadRetryBackOffTimerVal(pSIMSubId); + int delay = calculateBackoffDelay(retryCount, backoffTimerVal); + + Message retryMsg = new Message(); + retryMsg.what = REQUEST_CODE_DOWNLOAD_RETRY; + retryMsg.arg2 = pSIMSubId; + mHandler.sendMessageDelayed(retryMsg, delay); + + Log.d(TAG, "Download failed. Retry after :" + delay + "MilliSecs"); + } + + @VisibleForTesting + protected static int calculateBackoffDelay(int retryCount, int backoffTimerVal) { + /** + * Timer value is calculated using "Exponential Backoff retry" algorithm. + * When the first download failure occurs, retry download after + * BACKOFF_TIMER_VALUE [Carrier Configurable] seconds. + * + * If download fails again then, retry after either BACKOFF_TIMER_VALUE, + * 2xBACKOFF_TIMER_VALUE, or 3xBACKOFF_TIMER_VALUE seconds. + * + * In general after the cth failed attempt, retry after k * + * BACKOFF_TIMER_VALUE seconds, where k is a random integer between 1 and + * 2^c − 1. Max c value is KEY_ESIM_MAX_DOWNLOAD_RETRY_ATTEMPTS_INT + * [Carrier configurable] + */ + Random random = new Random(); + //Calculate 2^c − 1 + int maxTime = (int) Math.pow(2, retryCount) - 1; + + //Random value between (1 & 2^c − 1) and convert to millisecond + return ((random.nextInt(maxTime) + 1)) * backoffTimerVal * 1000; + } + + /** + * Retrieves maximum retry attempts from carrier configuration. After maximum attempts, further + * attempts will not be made until next device reboot. + * + * @param subscriptionId subscription Id of the primary SIM. + * @return + */ + private int getDownloadRetryMaxAttemptsVal(int subscriptionId) { + PersistableBundle config = mCarrierConfigMgr.getConfigForSubId(subscriptionId); + return config.getInt(CarrierConfigManager.KEY_ESIM_MAX_DOWNLOAD_RETRY_ATTEMPTS_INT); + } + + /** + * Retrieves backoff timer value (in seconds) from carrier configuration. Value is used to + * calculate delay before retrying profile download. + * + * @param subscriptionId subscription Id of the primary SIM. + * @return Backoff timer value in seconds. + */ + private int getDownloadRetryBackOffTimerVal(int subscriptionId) { + PersistableBundle config = mCarrierConfigMgr.getConfigForSubId(subscriptionId); + return config.getInt(CarrierConfigManager.KEY_ESIM_DOWNLOAD_RETRY_BACKOFF_TIMER_SEC_INT); + } + + + /** + * Checks if device supports eSIM. + */ + private boolean isESIMSupported() { + return (mEuiccManager != null && mEuiccManager.isEnabled()); + } + + /** + * Fetches ONS auto provisioning enable flag from device configuration. + * ONS auto provisioning feature executes only when the flag is set to true in device + * configuration. + */ + private boolean isONSAutoProvisioningEnabled() { + return mContext.getResources().getBoolean(R.bool.enable_ons_auto_provisioning); + } + + /** + * Check if device support multiple active SIMs + */ + private boolean isMultiSIMPhone() { + return (mTelephonyManager.getSupportedModemCount() >= 2); + } + + /** + * Check if the given subscription is a CBRS supported carrier. + */ + private boolean isOppDataAutoProvisioningSupported(int pSIMSubId) { + PersistableBundle config = mCarrierConfigMgr.getConfigForSubId(pSIMSubId); + return config.getBoolean(CarrierConfigManager + .KEY_CARRIER_SUPPORTS_OPP_DATA_AUTO_PROVISIONING_BOOL); + } + + /** + * Checks if device is in single SIM mode. + */ + private boolean isDeviceInSingleSIMMode() { + return (mTelephonyManager.getActiveModemCount() <= 1); + } + + /** + * Switches device to multi SIM mode. Checks if reboot is required before switching and + * configuration is triggered only if reboot not required. + */ + private boolean switchToMultiSIMMode() { + if (!mTelephonyManager.doesSwitchMultiSimConfigTriggerReboot()) { + mTelephonyManager.switchMultiSimConfig(2); + return true; + } + + return false; + } + + private boolean isWiFiConnected() { + Network activeNetwork = mConnectivityManager.getActiveNetwork(); + if ((activeNetwork != null) && mConnectivityManager.getNetworkCapabilities(activeNetwork) + .hasTransport(NetworkCapabilities.TRANSPORT_WIFI)) { + return true; + } + + return false; + } + + /** + * Retrieves WiFi only eSIM Download flag the given subscription from carrier configuration. + * + * @param subscriptionId subscription Id of the primary SIM. + * @return download flag. + */ + private boolean getESIMDownloadViaWiFiOnlyFlag(int subscriptionId) { + PersistableBundle config = mCarrierConfigMgr.getConfigForSubId(subscriptionId); + return config.getBoolean( + CarrierConfigManager.KEY_OPPORTUNISTIC_ESIM_DOWNLOAD_VIA_WIFI_ONLY_BOOL); + } + + private class NetworkCallback extends ConnectivityManager.NetworkCallback { + @Override + public void onAvailable(Network network) { + super.onAvailable(network); + Log.d(TAG, "Internet connection available"); + mIsInternetConnAvailable = true; + if (mRetryDownloadWhenNWConnected) { + provisionCBRS(); + } + } + + @Override + public void onLost(Network network) { + super.onLost(network); + Log.d(TAG, "Internet connection lost"); + mIsInternetConnAvailable = false; + } + } + public enum Result { SUCCESS, + ERR_SWITCHING_TO_DUAL_SIM_MODE, ERR_AUTO_PROVISIONING_DISABLED, ERR_ESIM_NOT_SUPPORTED, ERR_MULTISIM_NOT_SUPPORTED, @@ -236,8 +527,9 @@ public class ONSProfileActivator implements ONSProfileConfigurator.ONSProfConfig ERR_NO_SIM_INSERTED, ERR_SINGLE_ACTIVE_OPPORTUNISTIC_SIM, ERR_CANNOT_SWITCH_TO_DUAL_SIM_MODE, - ERR_SWITCHED_TO_DUAL_SIM_MODE, ERR_SIM_NOT_READY, + ERR_WAITING_FOR_INTERNET_CONNECTION, + ERR_WAITING_FOR_WIFI_CONNECTION, ERR_UNKNOWN; } } diff --git a/src/com/android/ons/ONSProfileConfigurator.java b/src/com/android/ons/ONSProfileConfigurator.java index 11c4a45..6026a95 100644 --- a/src/com/android/ons/ONSProfileConfigurator.java +++ b/src/com/android/ons/ONSProfileConfigurator.java @@ -16,25 +16,22 @@ package com.android.ons; -import android.annotation.TestApi; import android.app.PendingIntent; import android.content.Context; import android.content.Intent; -import android.net.ConnectivityManager; -import android.net.Network; -import android.net.NetworkCapabilities; -import android.net.NetworkRequest; import android.os.Handler; +import android.os.Looper; import android.os.Message; import android.os.ParcelUuid; import android.os.PersistableBundle; import android.telephony.CarrierConfigManager; import android.telephony.SubscriptionInfo; import android.telephony.SubscriptionManager; -import android.telephony.TelephonyManager; import android.telephony.euicc.EuiccManager; import android.util.Log; +import com.android.internal.annotations.VisibleForTesting; + import java.util.ArrayList; import java.util.List; @@ -46,75 +43,56 @@ import java.util.List; public class ONSProfileConfigurator { private static final String TAG = ONSProfileConfigurator.class.getName(); - private static final String PARAM_SUB_ID = "SUB_ID"; - private static final String PARAM_REQUEST_TYPE = "REQUEST_TYPE"; - private static final int REQUEST_CODE_ACTIVATE_SUB = 1; - private static final int REQUEST_CODE_DELETE_SUB = 2; - private static final String PREF_NAME = "ONSProvisioning"; - private static final String PREF_RETRY_DOWNLOAD_WHEN_CONNECTED = "RetryDownloadAfterReconnect"; + @VisibleForTesting protected static final String PARAM_SUB_ID = "SUB_ID"; + @VisibleForTesting protected static final String PARAM_REQUEST_TYPE = "REQUEST_TYPE"; + @VisibleForTesting protected static final int REQUEST_CODE_ACTIVATE_SUB = 1; + @VisibleForTesting protected static final int REQUEST_CODE_DELETE_SUB = 2; + @VisibleForTesting + protected static final String ACTION_ONS_ESIM_CONFIG = "com.android.ons.action.ESIM_CONFIG"; private final Context mContext; - private SubscriptionManager mSubManager; - private EuiccManager mEuiccManager; - private TelephonyManager mTelephonyManager; - private CarrierConfigManager mCarrierConfigMgr = null; - private static Handler sDeleteSubscriptionCallbackHandler = null; + private final SubscriptionManager mSubscriptionManager; + private final CarrierConfigManager mCarrierConfigManager; + private final EuiccManager mEuiccManager; private ONSProfConfigListener mONSProfConfigListener = null; - private boolean mRetryDownloadWhenNWConnected = false; - private boolean mIsInternetConnAvailable = false; + private final Handler mHandler; - public ONSProfileConfigurator(Context context, ONSProfConfigListener listener) { + public ONSProfileConfigurator(Context context, SubscriptionManager subscriptionManager, + CarrierConfigManager carrierConfigManager, + EuiccManager euiccManager, ONSProfConfigListener listener) { mContext = context; + mSubscriptionManager = subscriptionManager; + mCarrierConfigManager = carrierConfigManager; + mEuiccManager = euiccManager; mONSProfConfigListener = listener; - mSubManager = mContext.getSystemService(SubscriptionManager.class); - mEuiccManager = mContext.getSystemService(EuiccManager.class); - mTelephonyManager = mContext.getSystemService(TelephonyManager.class); - mCarrierConfigMgr = mContext.getSystemService(CarrierConfigManager.class); - - //Don't monitor internet connection or create handler if Auto-Provisioning is disabled. - if (isONSAutoProvisioningEnabled()) { - //Monitor internet connection. - final ConnectivityManager connMgr = (ConnectivityManager) context - .getSystemService(Context.CONNECTIVITY_SERVICE); - NetworkRequest request = new NetworkRequest.Builder() - .addCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED) - .build(); - connMgr.registerNetworkCallback(request, new NetworkCallback()); - - //Delete Subscription response handler. - if (sDeleteSubscriptionCallbackHandler == null) { - sDeleteSubscriptionCallbackHandler = new Handler(mContext.getMainLooper()) { - @Override - public void handleMessage(Message msg) { - if (msg.what == REQUEST_CODE_DELETE_SUB) { - if (mONSProfConfigListener != null) { - mONSProfConfigListener.onOppSubscriptionDeleted(msg.arg1); - } - } - } - }; + mHandler = new Handler(Looper.myLooper()) { + @Override + public void handleMessage(Message msg) { + super.handleMessage(msg); + callbackMsgHandler(msg); } - } - } - - @TestApi - ONSProfileConfigurator(Context mockContext, SubscriptionManager mockSubManager, - EuiccManager mockEuiccMangr, TelephonyManager mockTelephonyMangr) { - mContext = mockContext; - mSubManager = mockSubManager; - mEuiccManager = mockEuiccMangr; - mTelephonyManager = mockTelephonyMangr; + }; } /** * Callback to receive result for subscription activate request and process the same. * - * @param context * @param intent * @param resultCode */ - public static void onCallbackIntentReceived(Intent intent, int resultCode) { + public void onCallbackIntentReceived(Intent intent, int resultCode) { + Message msg = new Message(); + msg.obj = intent; + msg.arg1 = resultCode; + mHandler.sendMessage(msg); + } + + @VisibleForTesting + protected void callbackMsgHandler(Message msg) { + Intent intent = (Intent) msg.obj; + int resultCode = msg.arg1; + int reqCode = intent.getIntExtra(PARAM_REQUEST_TYPE, 0); switch (reqCode) { case REQUEST_CODE_ACTIVATE_SUB: { @@ -125,83 +103,20 @@ public class ONSProfileConfigurator { EuiccManager.EXTRA_EMBEDDED_SUBSCRIPTION_DETAILED_CODE, 0)); } break; - case REQUEST_CODE_DELETE_SUB: { if (resultCode != EuiccManager.EMBEDDED_SUBSCRIPTION_RESULT_OK) { Log.e(TAG, "Error removing euicc opportunistic profile." + "Detailed error code = " + intent.getIntExtra( EuiccManager.EXTRA_EMBEDDED_SUBSCRIPTION_DETAILED_CODE, 0)); - } else { - Message msg = new Message(); - msg.what = REQUEST_CODE_DELETE_SUB; - msg.arg1 = intent.getIntExtra(PARAM_SUB_ID, 0); - sDeleteSubscriptionCallbackHandler.sendMessage(msg); - Log.d(TAG, "Opportunistic subscription deleted successfully. Id:" + msg.arg1); + } else if (mONSProfConfigListener != null) { + int subId = intent.getIntExtra(PARAM_SUB_ID, 0); + mONSProfConfigListener.onOppSubscriptionDeleted(subId); + Log.d(TAG, "Opportunistic subscription deleted successfully. Id:" + subId); } } break; } - } - - /** - * Returns instance of Subscription Manager system service. - */ - public SubscriptionManager getSubscriptionManager() { - return mSubManager; - } - - /** - * Returns instance of EUICC Manager system service. - */ - public EuiccManager getEuiccManager() { - return mEuiccManager; - } - - /** - * Returns instance of Telephony Manager system service. - */ - public TelephonyManager getTelephonyManager() { - return mTelephonyManager; - } - - /** - * Returns instance of carrier configuration Manager system service. - */ - public CarrierConfigManager getCarrierConfigManager() { - return mCarrierConfigMgr; - } - - /** - * Checks if device supports eSIM. - */ - public boolean isESIMSupported() { - return (mEuiccManager != null && mEuiccManager.isEnabled()); - } - - /** - * Check if device support multiple active SIMs - */ - public boolean isMultiSIMPhone() { - return (mTelephonyManager.getSupportedModemCount() >= 2); - } - - /** - * Fetches ONS auto provisioning enable flag from device configuration. - * ONS auto provisioning feature executes only when the flag is set to true in device - * configuration. - */ - public boolean isONSAutoProvisioningEnabled() { - return mContext.getResources().getBoolean(R.bool.enable_ons_auto_provisioning); - } - - /** - * Check if the given subscription is a CBRS supported carrier. - */ - public boolean isOppDataAutoProvisioningSupported(int pSIMSubId) { - PersistableBundle config = getCarrierConfigManager().getConfigForSubId(pSIMSubId); - return config.getBoolean( - CarrierConfigManager.KEY_CARRIER_SUPPORTS_OPP_DATA_AUTO_PROVISIONING_BOOL); - } + }; /** * Adds downloaded subscription to the group, activates and enables opportunistic data. @@ -209,15 +124,17 @@ public class ONSProfileConfigurator { * @param opportunisticESIM * @param groupUuid */ - public void groupWithPSIMAndSetOpportunistic( + @VisibleForTesting + protected void groupWithPSIMAndSetOpportunistic( SubscriptionInfo opportunisticESIM, ParcelUuid groupUuid) { Log.d(TAG, "Grouping opportunistc eSIM and CBRS pSIM"); ArrayList<Integer> subList = new ArrayList<>(); subList.add(opportunisticESIM.getSubscriptionId()); - mSubManager.addSubscriptionsIntoGroup(subList, groupUuid); + mSubscriptionManager.addSubscriptionsIntoGroup(subList, groupUuid); if (!opportunisticESIM.isOpportunistic()) { Log.d(TAG, "set Opportunistic to TRUE"); - mSubManager.setOpportunistic(true, opportunisticESIM.getSubscriptionId()); + mSubscriptionManager.setOpportunistic(true, + opportunisticESIM.getSubscriptionId()); } //activateSubscription(opportunisticESIM);// -> activate after download flag is passed as //true in download request so no need of explicit activation. @@ -228,38 +145,30 @@ public class ONSProfileConfigurator { */ public void activateSubscription(int subId) { Intent intent = new Intent(mContext, ONSProfileResultReceiver.class); - intent.setAction(ONSProfileResultReceiver.ACTION_ONS_RESULT_CALLBACK); - intent.putExtra(Intent.EXTRA_COMPONENT_NAME, ONSProfileConfigurator.class.getName()); + intent.setAction(ACTION_ONS_ESIM_CONFIG); intent.putExtra(PARAM_REQUEST_TYPE, REQUEST_CODE_ACTIVATE_SUB); intent.putExtra(PARAM_SUB_ID, subId); PendingIntent callbackIntent = PendingIntent.getBroadcast(mContext, REQUEST_CODE_ACTIVATE_SUB, intent, PendingIntent.FLAG_IMMUTABLE); Log.d(TAG, "Activate oppSub request sent to SubManager"); - mSubManager.switchToSubscription(subId, callbackIntent); + mSubscriptionManager.switchToSubscription(subId, callbackIntent); } /** * Deletes inactive opportunistic subscriptions irrespective of the CBRS operator. * Called when sufficient memory is not available before downloading new profile. */ - public boolean deleteOpportunisticSubscriptions(int pSIMId) { + public boolean deleteInactiveOpportunisticSubscriptions(int pSIMId) { Log.d(TAG, "deleteInactiveOpportunisticSubscriptions"); - //First delete old opportunistic eSIM from same operator. - //If there are no such eSIM to delete then delete other - //opportunistic eSIMs. - if (deleteOldOpportunisticESimsOfPSIMOperator(pSIMId)) { - return true; - } - - List<SubscriptionInfo> subList = mSubManager.getOpportunisticSubscriptions(); + List<SubscriptionInfo> subList = mSubscriptionManager.getOpportunisticSubscriptions(); if (subList == null || subList.size() <= 0) { return false; } for (SubscriptionInfo subInfo : subList) { int subId = subInfo.getSubscriptionId(); - if (!mSubManager.isActiveSubscriptionId(subId)) { + if (!mSubscriptionManager.isActiveSubscriptionId(subId)) { deleteSubscription(subId); return true; } @@ -269,49 +178,53 @@ public class ONSProfileConfigurator { } /** - * Deletes previously downloaded opportunistic eSIM associated with pSIM CBRS operator. + * Returns previously downloaded opportunistic eSIM associated with pSIM CBRS operator. * Helpful to cleanup before downloading new opportunistic eSIM from the same CBRS operator. * - * @return true - If an eSIM is delete request is sent. - * false - If no suitable eSIM is found for delete. + * @return true - If an eSIM is found. + * false - If no eSIM is found. */ - boolean deleteOldOpportunisticESimsOfPSIMOperator(int pSIMSubId) { - Log.d(TAG, "deleteOldOpportunisticESimsOfPSIMOperator"); + ArrayList<Integer> getOpportunisticSubIdsofPSIMOperator(int pSIMSubId) { + Log.d(TAG, "getOpportunisticSubIdsofPSIMOperator"); + ArrayList<Integer> opportunisticSubIds = new ArrayList<Integer>(); //1.Get the list of all opportunistic carrier-ids of newly inserted pSIM from carrier config - PersistableBundle config = getCarrierConfigManager().getConfigForSubId(pSIMSubId); + PersistableBundle config = mCarrierConfigManager.getConfigForSubId(pSIMSubId); int[] oppCarrierIdArr = config.getIntArray( CarrierConfigManager.KEY_OPPORTUNISTIC_CARRIER_IDS_INT_ARRAY); if (oppCarrierIdArr == null || oppCarrierIdArr.length <= 0) { - return false; + return null; } //2. Get list of all subscriptions - List<SubscriptionInfo> oppSubList = mSubManager.getAvailableSubscriptionInfoList(); + List<SubscriptionInfo> oppSubList = mSubscriptionManager.getAvailableSubscriptionInfoList(); for (SubscriptionInfo subInfo : oppSubList) { for (int oppCarrierId : oppCarrierIdArr) { //Carrier-id of opportunistic eSIM matches with one of thecarrier-ids in carrier // config of pSIM - if (subInfo.isEmbedded() && oppCarrierId == subInfo.getCarrierId()) { + if (subInfo.isEmbedded() && oppCarrierId == subInfo + .getCarrierId()) { //3.if carrier-id of eSIM matches with one of the pSIM opportunistic carrier-ids //and eSIM's pSIM carrier-id matches with new pSIM then delete the subscription - deleteSubscription(subInfo.getSubscriptionId()); - return true; + opportunisticSubIds.add(subInfo.getSubscriptionId()); } } } - return false; + return opportunisticSubIds; } - private void deleteSubscription(int subId) { + /** + * Sends delete request to the eUICC manager to delete a given subscription. + * @param subId + */ + public void deleteSubscription(int subId) { Log.d(TAG, "deleting subscription. SubId: " + subId); Intent intent = new Intent(mContext, ONSProfileResultReceiver.class); - intent.setAction(ONSProfileResultReceiver.ACTION_ONS_RESULT_CALLBACK); - intent.putExtra(Intent.EXTRA_COMPONENT_NAME, ONSProfileConfigurator.class.getName()); + intent.setAction(ACTION_ONS_ESIM_CONFIG); intent.putExtra(PARAM_REQUEST_TYPE, REQUEST_CODE_DELETE_SUB); intent.putExtra(PARAM_SUB_ID, subId); PendingIntent callbackIntent = PendingIntent.getBroadcast(mContext, - REQUEST_CODE_DELETE_SUB, intent, PendingIntent.FLAG_IMMUTABLE); + REQUEST_CODE_DELETE_SUB, intent, PendingIntent.FLAG_MUTABLE); mEuiccManager.deleteSubscription(subId, callbackIntent); } @@ -327,7 +240,7 @@ public class ONSProfileConfigurator { Log.d(TAG, "Creating Group for Primary SIM"); List<Integer> pSubList = new ArrayList<>(); pSubList.add(primaryCBRSSubInfo.getSubscriptionId()); - return mSubManager.createSubscriptionGroup(pSubList); + return mSubscriptionManager.createSubscriptionGroup(pSubList); } /** @@ -338,11 +251,12 @@ public class ONSProfileConfigurator { Log.d(TAG, "findOpportunisticSubscription. PSIM Id : " + pSIMId); //Get the list of active subscriptions - List<SubscriptionInfo> availSubInfoList = mSubManager.getAvailableSubscriptionInfoList(); + List<SubscriptionInfo> availSubInfoList = mSubscriptionManager + .getAvailableSubscriptionInfoList(); Log.d(TAG, "Available subscriptions: " + availSubInfoList.size()); //Get the list of opportunistic carrier-ids list from carrier config. - PersistableBundle config = mCarrierConfigMgr.getConfigForSubId(pSIMId); + PersistableBundle config = mCarrierConfigManager.getConfigForSubId(pSIMId); int[] oppCarrierIdArr = config.getIntArray( CarrierConfigManager.KEY_OPPORTUNISTIC_CARRIER_IDS_INT_ARRAY); if (oppCarrierIdArr == null || oppCarrierIdArr.length <= 0) { @@ -350,7 +264,8 @@ public class ONSProfileConfigurator { return null; } - ParcelUuid pSIMSubGroupId = mSubManager.getActiveSubscriptionInfo(pSIMId).getGroupUuid(); + ParcelUuid pSIMSubGroupId = mSubscriptionManager.getActiveSubscriptionInfo(pSIMId) + .getGroupUuid(); for (SubscriptionInfo subInfo : availSubInfoList) { if (subInfo.getSubscriptionId() != pSIMId) { for (int carrId : oppCarrierIdArr) { @@ -359,8 +274,10 @@ public class ONSProfileConfigurator { // carrier config is newly downloaded opportunistic eSIM. ParcelUuid oppSubGroupId = subInfo.getGroupUuid(); - if (oppSubGroupId == null || oppSubGroupId.equals(pSIMSubGroupId)) { - Log.d(TAG, "Opp subscription found:" + subInfo.getSubscriptionId()); + if (oppSubGroupId == null /*Immediately after opp eSIM is downloaded case*/ + || oppSubGroupId.equals(pSIMSubGroupId) /*Already downloaded and + grouped case.*/) { + Log.d(TAG, "Opp subscription:" + subInfo.getSubscriptionId()); return subInfo; } } @@ -372,115 +289,9 @@ public class ONSProfileConfigurator { } /** - * Retrieves SMDP+ server address of the given subscription from carrier configuration. - * - * @param subscriptionId subscription Id of the primary SIM. - * @return FQDN of SMDP+ server. - */ - public String getSMDPServerAddress(int subscriptionId) { - PersistableBundle config = mCarrierConfigMgr.getConfigForSubId(subscriptionId); - return config.getString(CarrierConfigManager.KEY_SMDP_SERVER_ADDRESS_STRING); - } - - /** - * Retrieves backoff timer value (in seconds) from carrier configuration. Value is used to - * calculate delay before retrying profile download. - * - * @param subscriptionId subscription Id of the primary SIM. - * @return Backoff timer value in seconds. - */ - public int getDownloadRetryBackOffTimerVal(int subscriptionId) { - PersistableBundle config = getCarrierConfigManager().getConfigForSubId(subscriptionId); - return config.getInt(CarrierConfigManager.KEY_ESIM_DOWNLOAD_RETRY_BACKOFF_TIMER_SEC_INT); - } - - /** - * Retrieves maximum retry attempts from carrier configuration. After maximum attempts, further - * attempts will not be made until next device reboot. - * - * @param subscriptionId subscription Id of the primary SIM. - * @return - */ - public int getDownloadRetryMaxAttemptsVal(int subscriptionId) { - PersistableBundle config = getCarrierConfigManager().getConfigForSubId(subscriptionId); - return config.getInt(CarrierConfigManager.KEY_ESIM_MAX_DOWNLOAD_RETRY_ATTEMPTS_INT); - } - - /** - * Checks if device is in single SIM mode. - */ - public boolean isDeviceInSingleSIMMode() { - return (mTelephonyManager.getActiveModemCount() <= 1); - } - - /** - * Switches device to multi SIM mode. Checks if reboot is required before switching and - * configuration is triggered only if reboot not required. - */ - public boolean switchToMultiSIMMode() { - if (!mTelephonyManager.doesSwitchMultiSimConfigTriggerReboot()) { - mTelephonyManager.switchMultiSimConfig(2); - return true; - } - - return false; - } - - /** - * Saves flag to retry download when internet connection is restored. - * - * @param enable - true - retry download when connected. - * false - No retry required. - */ - public void setRetryDownloadWhenConnectedFlag(boolean enable) { - mRetryDownloadWhenNWConnected = enable; - } - - /** - * Retrieves flag to retry download when internet connection is restored. - */ - public boolean getRetryDownloadWhenConnectedFlag() { - return mRetryDownloadWhenNWConnected; - } - - public boolean isInternetConnectionAvailable() { - return mIsInternetConnAvailable; - } - - private class NetworkCallback extends ConnectivityManager.NetworkCallback { - @Override - public void onAvailable(Network network) { - super.onAvailable(network); - Log.d(TAG, "Internet connection available"); - mIsInternetConnAvailable = true; - if (mONSProfConfigListener != null) { - mONSProfConfigListener.onConnectionChanged(true); - } - } - - @Override - public void onLost(Network network) { - super.onLost(network); - Log.d(TAG, "Internet connection lost"); - mIsInternetConnAvailable = false; - if (mONSProfConfigListener != null) { - mONSProfConfigListener.onConnectionChanged(false); - } - } - } - - /** - * Listener interface to notify delete subscription operation and internet connection status - * change. + * Listener interface to notify delete subscription operation. */ public interface ONSProfConfigListener { - - /** - * Change in connection is used to decide whether to send download request or differ. - * When connection is available, previously pending download is resumed. - */ - void onConnectionChanged(boolean bConnected); - /** * Called when the delete subscription request is processed successfully. */ diff --git a/src/com/android/ons/ONSProfileDownloader.java b/src/com/android/ons/ONSProfileDownloader.java index 9a8aa6c..5b273d5 100644 --- a/src/com/android/ons/ONSProfileDownloader.java +++ b/src/com/android/ons/ONSProfileDownloader.java @@ -20,8 +20,10 @@ import android.app.PendingIntent; import android.content.Context; import android.content.Intent; import android.os.Handler; +import android.os.Looper; import android.os.Message; -import android.telephony.SubscriptionInfo; +import android.os.PersistableBundle; +import android.telephony.CarrierConfigManager; import android.telephony.euicc.DownloadableSubscription; import android.telephony.euicc.EuiccManager; import android.util.Log; @@ -29,50 +31,55 @@ import android.util.Pair; import com.android.internal.annotations.VisibleForTesting; -import java.util.Random; import java.util.Stack; public class ONSProfileDownloader { interface IONSProfileDownloaderListener { void onDownloadComplete(int primarySubId); + void onDownloadError(DownloadRetryOperationCode operationCode, int pSIMSubId); } private static final String TAG = ONSProfileDownloader.class.getName(); + public static final String ACTION_ONS_ESIM_DOWNLOAD = "com.android.ons.action.ESIM_DOWNLOAD"; @VisibleForTesting protected static final String PARAM_PRIMARY_SUBID = "PrimarySubscriptionID"; @VisibleForTesting protected static final String PARAM_REQUEST_TYPE = "REQUEST"; @VisibleForTesting protected static final int REQUEST_CODE_DOWNLOAD_SUB = 1; - @VisibleForTesting protected static final int REQUEST_CODE_DOWNLOAD_RETRY = 2; - private static IONSProfileDownloaderListener sListener; - private static Handler sHandler; + private final Handler mHandler; private final Context mContext; + private final CarrierConfigManager mCarrierConfigManager; + private final EuiccManager mEuiccManager; private final ONSProfileConfigurator mONSProfileConfig; + private IONSProfileDownloaderListener mListener; @VisibleForTesting protected enum DownloadRetryOperationCode{ DOWNLOAD_SUCCESSFUL, - STOP_RETRY_UNTIL_SIM_STATE_CHANGE, - DELETE_INACTIVE_OPP_ESIM_IF_EXISTS, - DELETE_EXISTING_PROFILE_AND_RETRY, - RETRY_AFTER_BACKOFF_TIME, + ERR_UNRESOLVABLE, + ERR_MEMORY_FULL, + ERR_INSTALL_ESIM_PROFILE_FAILED, + ERR_RETRY_DOWNLOAD, + BACKOFF_TIMER_EXPIRED }; - public ONSProfileDownloader(Context context, ONSProfileConfigurator onsProfileConfigurator, + public ONSProfileDownloader(Context context, CarrierConfigManager carrierConfigManager, + EuiccManager euiccManager, + ONSProfileConfigurator onsProfileConfigurator, IONSProfileDownloaderListener listener) { mContext = context; - sListener = listener; + mListener = listener; + mEuiccManager = euiccManager; mONSProfileConfig = onsProfileConfigurator; - sHandler = new DownloadHandler(); + mCarrierConfigManager = carrierConfigManager; + + mHandler = new DownloadHandler(); } class DownloadHandler extends Handler { - private int mDownloadRetryCount = 0; - private final Random mRandom; - DownloadHandler() { - mRandom = new Random(); + super(Looper.myLooper()); } @Override @@ -92,56 +99,35 @@ public class ONSProfileDownloader { Log.d(TAG, "Operation Code : " + operationCode); Log.d(TAG, "Error Code : " + errorCode); - DownloadRetryOperationCode opCode = getOperationCode(msg.arg1, detailedErrCode, - operationCode, errorCode); + DownloadRetryOperationCode opCode = mapDownloaderErrorCode(msg.arg1, + detailedErrCode, operationCode, errorCode); Log.d(TAG, "DownloadRetryOperationCode: " + opCode); switch (opCode) { case DOWNLOAD_SUCCESSFUL: - ONSProfileDownloader.sListener.onDownloadComplete(pSIMSubId); - break; - - case STOP_RETRY_UNTIL_SIM_STATE_CHANGE: - mONSProfileConfig.setRetryDownloadWhenConnectedFlag(false); - Log.e(TAG, "Download ERR: unresolvable error occurred. Detailed" - + "Error Code:" + detailedErrCode); + mListener.onDownloadComplete(pSIMSubId); break; - case DELETE_INACTIVE_OPP_ESIM_IF_EXISTS: - if (!mONSProfileConfig.deleteOpportunisticSubscriptions(pSIMSubId)) { - Log.e(TAG, "Unable to free eUICC memory. Stop retry."); - } else { - retryDownloadAfterBackoffTime(pSIMSubId); - } + case ERR_UNRESOLVABLE: + mListener.onDownloadError(opCode, pSIMSubId); + Log.e(TAG, "Unresolvable download error: " + + getUnresolvableErrorDescription(errorCode)); break; - case DELETE_EXISTING_PROFILE_AND_RETRY: - if (!mONSProfileConfig - .deleteOldOpportunisticESimsOfPSIMOperator(pSIMSubId)) { - Log.e(TAG, "Unable to delete existing profile. Stop retry."); - } else { - retryDownloadAfterBackoffTime(pSIMSubId); - } - break; - - case RETRY_AFTER_BACKOFF_TIME: - retryDownloadAfterBackoffTime(pSIMSubId); + default: + mListener.onDownloadError(opCode, pSIMSubId); break; } } break; - - case REQUEST_CODE_DOWNLOAD_RETRY: { - Log.d(TAG, "Retrying download"); - downloadProfile(msg.arg2); //arg1 -> primary SubId - } - break; } } @VisibleForTesting - protected DownloadRetryOperationCode getOperationCode(int resultCode, int detailedErrCode, - int operationCode, int errorCode) { + protected DownloadRetryOperationCode mapDownloaderErrorCode(int resultCode, + int detailedErrCode, + int operationCode, + int errorCode) { if (operationCode == EuiccManager.OPERATION_DOWNLOAD) { @@ -153,23 +139,23 @@ public class ONSProfileDownloader { //Low eUICC memory cases if (errorCode == EuiccManager.ERROR_EUICC_INSUFFICIENT_MEMORY) { Log.d(TAG, "Download ERR: EUICC_INSUFFICIENT_MEMORY"); - return DownloadRetryOperationCode.DELETE_INACTIVE_OPP_ESIM_IF_EXISTS; + return DownloadRetryOperationCode.ERR_MEMORY_FULL; } //Temporary download error cases if (errorCode == EuiccManager.ERROR_TIME_OUT || errorCode == EuiccManager.ERROR_CONNECTION_ERROR || errorCode == EuiccManager.ERROR_OPERATION_BUSY) { - return DownloadRetryOperationCode.RETRY_AFTER_BACKOFF_TIME; + return DownloadRetryOperationCode.ERR_RETRY_DOWNLOAD; } //Profile installation failure cases if (errorCode == EuiccManager.ERROR_INSTALL_PROFILE) { - return DownloadRetryOperationCode.DELETE_EXISTING_PROFILE_AND_RETRY; + return DownloadRetryOperationCode.ERR_INSTALL_ESIM_PROFILE_FAILED; } //UnResolvable error cases - return DownloadRetryOperationCode.STOP_RETRY_UNTIL_SIM_STATE_CHANGE; + return DownloadRetryOperationCode.ERR_UNRESOLVABLE; } else if (operationCode == EuiccManager.OPERATION_SMDX_SUBJECT_REASON_CODE) { //SMDP Error codes handling @@ -178,115 +164,90 @@ public class ONSProfileDownloader { //8.1 - eUICC, 4.8 - Insufficient Memory // eUICC does not have sufficient space for this Profile. if (errCode.equals(Pair.create("8.1.0", "4.8"))) { - return DownloadRetryOperationCode.DELETE_INACTIVE_OPP_ESIM_IF_EXISTS; + return DownloadRetryOperationCode.ERR_MEMORY_FULL; } //8.8.5 - Download order, 4.10 - Time to Live Expired //The Download order has expired if (errCode.equals(Pair.create("8.8.5", "4.10"))) { - return DownloadRetryOperationCode.RETRY_AFTER_BACKOFF_TIME; + return DownloadRetryOperationCode.ERR_RETRY_DOWNLOAD; } //All other errors are unresolvable or retry after SIM State Change - return DownloadRetryOperationCode.STOP_RETRY_UNTIL_SIM_STATE_CHANGE; + return DownloadRetryOperationCode.ERR_UNRESOLVABLE; } else { //Ignore if Operation code is not DOWNLOAD or SMDX_SUBJECT_REASON_CODE. //Callback is registered only for download requests. - return DownloadRetryOperationCode.STOP_RETRY_UNTIL_SIM_STATE_CHANGE; + return DownloadRetryOperationCode.ERR_UNRESOLVABLE; } } + } - private void retryDownloadAfterBackoffTime(int pSIMSubId) { - //retry logic - mDownloadRetryCount++; - Log.e(TAG, "Download retry count :" + mDownloadRetryCount); - if (mDownloadRetryCount >= mONSProfileConfig - .getDownloadRetryMaxAttemptsVal(pSIMSubId)) { - Log.e(TAG, "Max download retry attempted. Stopping retry"); - return; - } + private String getUnresolvableErrorDescription(int errorCode) { + switch (errorCode) { + case EuiccManager.ERROR_INVALID_ACTIVATION_CODE: + return "ERROR_INVALID_ACTIVATION_CODE"; - int backoffTimerVal = mONSProfileConfig.getDownloadRetryBackOffTimerVal(pSIMSubId); - int delay = calculateBackoffDelay(mDownloadRetryCount, backoffTimerVal); + case EuiccManager.ERROR_UNSUPPORTED_VERSION: + return "ERROR_UNSUPPORTED_VERSION"; - Message retryMsg = new Message(); - retryMsg.what = REQUEST_CODE_DOWNLOAD_RETRY; - retryMsg.arg2 = pSIMSubId; - sendMessageDelayed(retryMsg, delay); + case EuiccManager.ERROR_INSTALL_PROFILE: + return "ERROR_INSTALL_PROFILE"; - Log.d(TAG, "Download failed. Retry after :" + delay + "MilliSecs"); - } + case EuiccManager.ERROR_SIM_MISSING: + return "ERROR_SIM_MISSING"; - @VisibleForTesting - protected int calculateBackoffDelay(int retryCount, int backoffTimerVal) { - /** - * Timer value is calculated using "Exponential Backoff retry" algorithm. - * When the first download failure occurs, retry download after - * BACKOFF_TIMER_VALUE [Carrier Configurable] seconds. - * - * If download fails again then, retry after either BACKOFF_TIMER_VALUE, - * 2xBACKOFF_TIMER_VALUE, or 3xBACKOFF_TIMER_VALUE seconds. - * - * In general after the cth failed attempt, retry after k * - * BACKOFF_TIMER_VALUE seconds, where k is a random integer between 1 and - * 2^c − 1. Max c value is KEY_ESIM_MAX_DOWNLOAD_RETRY_ATTEMPTS_INT - * [Carrier configurable] - */ - //Calculate 2^c − 1 - int maxTime = (int) Math.pow(2, retryCount) - 1; - - //Random value between (1 & 2^c − 1) and convert to millisecond - return ((mRandom.nextInt(maxTime) + 1)) * backoffTimerVal * 1000; + case EuiccManager.ERROR_ADDRESS_MISSING: + return "ERROR_ADDRESS_MISSING"; + + case EuiccManager.ERROR_CERTIFICATE_ERROR: + return "ERROR_CERTIFICATE_ERROR"; + + case EuiccManager.ERROR_NO_PROFILES_AVAILABLE: + return "ERROR_NO_PROFILES_AVAILABLE"; + + case EuiccManager.ERROR_CARRIER_LOCKED: + return "ERROR_CARRIER_LOCKED"; } - } - /** - * Finds the eSIM profile of the given CBRS carrier. Returns null if eSIM profile is not found. - * - * @param primaryCBRSSubInfo SubscriptionInfo of a CBRS Carrier of which corresponding eSIM info - * is required. - * @return - */ - public void downloadOpportunisticESIM(SubscriptionInfo primaryCBRSSubInfo) { - //Delete old eSIM (if exists) from the same operator as current pSIM. - /*mONSProfileConfig.deleteOldOpportunisticESimsOfPSIMOperator( - primaryCBRSSubInfo.getSubscriptionId());*/ - downloadProfile(primaryCBRSSubInfo.getSubscriptionId()); - return; + return "Unknown"; } @VisibleForTesting protected void downloadProfile(int primarySubId) { Log.d(TAG, "downloadProfile"); - if (!mONSProfileConfig.isInternetConnectionAvailable()) { - Log.d(TAG, "No internet connection. Download will be attempted when " - + "connection is restored"); - mONSProfileConfig.setRetryDownloadWhenConnectedFlag(true); - return; - } //Get SMDP address from carrier configuration - String smdpAddr = mONSProfileConfig.getSMDPServerAddress(primarySubId); + String smdpAddr = getSMDPServerAddress(primarySubId); if (smdpAddr == null || smdpAddr.length() <= 0) { return; } Intent intent = new Intent(mContext, ONSProfileResultReceiver.class); - intent.setAction(ONSProfileResultReceiver.ACTION_ONS_RESULT_CALLBACK); - intent.putExtra(Intent.EXTRA_COMPONENT_NAME, ONSProfileDownloader.class.getName()); + intent.setAction(ACTION_ONS_ESIM_DOWNLOAD); intent.putExtra(PARAM_REQUEST_TYPE, REQUEST_CODE_DOWNLOAD_SUB); intent.putExtra(PARAM_PRIMARY_SUBID, primarySubId); PendingIntent callbackIntent = PendingIntent.getBroadcast(mContext, REQUEST_CODE_DOWNLOAD_SUB, intent, PendingIntent.FLAG_MUTABLE); Log.d(TAG, "Download Request sent to EUICC Manager"); - mONSProfileConfig.getEuiccManager().downloadSubscription( - DownloadableSubscription.forActivationCode(smdpAddr), + mEuiccManager.downloadSubscription(DownloadableSubscription.forActivationCode(smdpAddr), true, callbackIntent); } /** + * Retrieves SMDP+ server address of the given subscription from carrier configuration. + * + * @param subscriptionId subscription Id of the primary SIM. + * @return FQDN of SMDP+ server. + */ + private String getSMDPServerAddress(int subscriptionId) { + PersistableBundle config = mCarrierConfigManager.getConfigForSubId(subscriptionId); + return config.getString(CarrierConfigManager.KEY_SMDP_SERVER_ADDRESS_STRING); + } + + /** * Given encoded error code described in * {@link android.telephony.euicc.EuiccManager#OPERATION_SMDX_SUBJECT_REASON_CODE} decode it * into SubjectCode[5.2.6.1] and ReasonCode[5.2.6.2] from GSMA (SGP.22 v2.2) @@ -327,11 +288,11 @@ public class ONSProfileDownloader { * @param intent * @param resultCode */ - public static void onCallbackIntentReceived(Intent intent, int resultCode) { + public void onCallbackIntentReceived(Intent intent, int resultCode) { Message msg = new Message(); msg.what = REQUEST_CODE_DOWNLOAD_SUB; msg.arg1 = resultCode; msg.obj = intent; - sHandler.sendMessage(msg); + mHandler.sendMessage(msg); } } diff --git a/src/com/android/ons/ONSProfileResultReceiver.java b/src/com/android/ons/ONSProfileResultReceiver.java index bc94aae..c893751 100644 --- a/src/com/android/ons/ONSProfileResultReceiver.java +++ b/src/com/android/ons/ONSProfileResultReceiver.java @@ -34,49 +34,21 @@ import android.util.Log; public class ONSProfileResultReceiver extends BroadcastReceiver { private static final String TAG = ONSProfileResultReceiver.class.getName(); - - public static final String ACTION_ONS_RESULT_CALLBACK = - "com.android.ons.ONSProfileResultReceiver.CALLBACK"; + public static final String EXTRA_RESULT_CODE = "ResultCode"; @Override public void onReceive(Context context, Intent intent) { - int resultCode = getResultCode(); - callbackIntentHandler(intent, resultCode); - } - - protected void callbackIntentHandler(Intent intent, int resultCode) { String action = intent.getAction(); - String compName = intent.getStringExtra(Intent.EXTRA_COMPONENT_NAME); - - if (action.equals(ACTION_ONS_RESULT_CALLBACK)) { - if (compName.equals(ONSProfileConfigurator.class.getName())) { - WorkerThread workerThread = new WorkerThread(goAsync(), - () -> ONSProfileConfigurator.onCallbackIntentReceived(intent, resultCode)); - workerThread.start(); - } else if (compName.equals(ONSProfileDownloader.class.getName())) { - WorkerThread workerThread = new WorkerThread(goAsync(), - () -> ONSProfileDownloader.onCallbackIntentReceived(intent, resultCode)); - workerThread.start(); - } - } else if (action.equals(TelephonyManager.ACTION_MULTI_SIM_CONFIG_CHANGED)) { + if (action.equals(TelephonyManager.ACTION_MULTI_SIM_CONFIG_CHANGED)) { int simCount = intent.getIntExtra(TelephonyManager.EXTRA_ACTIVE_SIM_SUPPORTED_COUNT, 0); Log.d(TAG, "Mutli-SIM configed for " + simCount + "SIMs"); - } - } - - private class WorkerThread extends Thread { - private final PendingResult mAsyncResult; - private final Runnable mRunnable; - WorkerThread(PendingResult asyncResult, Runnable runnable) { - mAsyncResult = asyncResult; - mRunnable = runnable; - } - - @Override - public void run() { - super.run(); - mRunnable.run(); - mAsyncResult.finish(); + } else { + Intent serviceIntent = new Intent(context, OpportunisticNetworkService.class); + serviceIntent.setAction(intent.getAction()); + serviceIntent.putExtra(EXTRA_RESULT_CODE, getResultCode()); + serviceIntent.putExtra(Intent.EXTRA_INTENT, intent); + context.startService(serviceIntent); + Log.d(TAG, "Service Started:" + serviceIntent.toString()); } } } diff --git a/src/com/android/ons/OpportunisticNetworkService.java b/src/com/android/ons/OpportunisticNetworkService.java index f634104..b869090 100644 --- a/src/com/android/ons/OpportunisticNetworkService.java +++ b/src/com/android/ons/OpportunisticNetworkService.java @@ -30,6 +30,7 @@ import android.os.Binder; import android.os.Build; import android.os.Handler; import android.os.IBinder; +import android.os.Looper; import android.os.Message; import android.os.RemoteException; import android.os.TelephonyServiceManager.ServiceRegisterer; @@ -61,6 +62,7 @@ public class OpportunisticNetworkService extends Service { private TelephonyManager mTelephonyManager; @VisibleForTesting protected SubscriptionManager mSubscriptionManager; private ONSProfileActivator mONSProfileActivator; + private Handler mHandler = null; private final Object mLock = new Object(); @VisibleForTesting protected boolean mIsEnabled; @@ -106,21 +108,48 @@ public class OpportunisticNetworkService extends Service { } }; - private Handler mHandler = new Handler() { - @Override - public void handleMessage(Message msg) { - switch (msg.what) { - case MSG_SIM_STATE_CHANGE: - synchronized (mLock) { - handleSimStateChange(); - } - break; - default: - log("invalid message"); - break; + private void createMsgHandler() { + mHandler = new Handler(Looper.myLooper()) { + @Override + public void handleMessage(Message msg) { + switch (msg.what) { + case MSG_SIM_STATE_CHANGE: + synchronized (mLock) { + handleSimStateChange(); + } + break; + default: + log("invalid message"); + break; + } + } + }; + } + + private void startWorkerThreadAndInit() { + Thread thread = new Thread() { + @Override + public void run() { + super.run(); + Looper.prepare(); + Looper looper = Looper.myLooper(); + initialize(getBaseContext()); + synchronized (this) { + this.notifyAll(); + } + looper.loop(); + } + }; + + thread.start(); + synchronized (thread) { + try { + thread.wait(); + } catch (Exception e) { + log(e.getLocalizedMessage()); } } - }; + } private static boolean enforceModifyPhoneStatePermission(Context context) { if (context.checkCallingOrSelfPermission(android.Manifest.permission.MODIFY_PHONE_STATE) @@ -337,7 +366,7 @@ public class OpportunisticNetworkService extends Service { @Override public void onCreate() { - initialize(getBaseContext()); + startWorkerThreadAndInit(); /* register the service */ ServiceRegisterer opportunisticNetworkServiceRegisterer = TelephonyFrameworkInitializer @@ -350,23 +379,51 @@ public class OpportunisticNetworkService extends Service { @Override public int onStartCommand(Intent intent, int flags, int startId) { - if (intent == null) { - return START_STICKY; - } + mHandler.post(new Runnable() { - String action = intent.getAction(); - if (action == null) { - return START_STICKY; - } + private Intent mIntent = null; + Runnable setIntent(Intent intent) { + mIntent = intent; + return this; + } - switch (action) { - case ONSProfileSelector.ACTION_SUB_SWITCH: { - if (mProfileSelector != null) { - mProfileSelector.onSubSwitchComplete(intent); + @Override + public void run() { + if (mIntent == null) { + return; + } + + String action = mIntent.getAction(); + if (action == null) { + return; + } + + switch (action) { + case ONSProfileSelector.ACTION_SUB_SWITCH: { + if (mProfileSelector != null) { + mProfileSelector.onSubSwitchComplete(mIntent); + } + } + break; + + case ONSProfileDownloader.ACTION_ONS_ESIM_DOWNLOAD: { + mONSProfileActivator.getONSProfileDownloader().onCallbackIntentReceived( + mIntent.getParcelableExtra(Intent.EXTRA_INTENT), + mIntent.getIntExtra(ONSProfileResultReceiver.EXTRA_RESULT_CODE, 0) + ); + } + break; + + case ONSProfileConfigurator.ACTION_ONS_ESIM_CONFIG: { + mONSProfileActivator.getONSProfileConfigurator().onCallbackIntentReceived( + mIntent.getParcelableExtra(Intent.EXTRA_INTENT), + mIntent.getIntExtra(ONSProfileResultReceiver.EXTRA_RESULT_CODE, 0) + ); + } + break; } - break; } - } + }.setIntent(intent)); return START_STICKY; } @@ -375,7 +432,7 @@ public class OpportunisticNetworkService extends Service { public void onDestroy() { super.onDestroy(); log("Destroyed Successfully..."); - + mHandler.getLooper().quitSafely(); } /** @@ -387,6 +444,7 @@ public class OpportunisticNetworkService extends Service { @VisibleForTesting protected void initialize(Context context) { mContext = context; + createMsgHandler(); mTelephonyManager = TelephonyManager.from(mContext); mProfileSelector = new ONSProfileSelector(mContext, mProfileSelectionCallback); mSharedPref = mContext.createDeviceProtectedStorageContext().getSharedPreferences( diff --git a/tests/src/com/android/ons/ONSProfileActivatorTest.java b/tests/src/com/android/ons/ONSProfileActivatorTest.java index 8189017..dae5f8d 100644 --- a/tests/src/com/android/ons/ONSProfileActivatorTest.java +++ b/tests/src/com/android/ons/ONSProfileActivatorTest.java @@ -16,14 +16,22 @@ package com.android.ons; +import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.doReturn; import android.content.Context; +import android.content.res.Resources; +import android.net.ConnectivityManager; +import android.net.NetworkCapabilities; +import android.net.NetworkRequest; +import android.os.Looper; +import android.os.PersistableBundle; import android.telephony.CarrierConfigManager; import android.telephony.SubscriptionInfo; import android.telephony.SubscriptionManager; import android.telephony.TelephonyManager; import android.telephony.euicc.EuiccManager; +import android.util.Log; import org.junit.After; import org.junit.Before; @@ -42,10 +50,12 @@ public class ONSProfileActivatorTest extends ONSBaseTest { @Mock SubscriptionManager mMockSubManager; @Mock - EuiccManager mMockEuiCCManager; + EuiccManager mMockEuiccManager; @Mock TelephonyManager mMockTeleManager; @Mock + ConnectivityManager mMockConnectivityManager; + @Mock CarrierConfigManager mMockCarrierConfigManager; @Mock ONSProfileConfigurator mMockONSProfileConfigurator; @@ -59,156 +69,190 @@ public class ONSProfileActivatorTest extends ONSBaseTest { SubscriptionInfo mMockSubInfo2; @Mock List<SubscriptionInfo> mMocksubsInPSIMGroup; + @Mock + Resources mMockResources; @Before public void setUp() throws Exception { super.setUp("ONSTest"); MockitoAnnotations.initMocks(this); - - doReturn(mMockSubManager).when(mMockONSProfileConfigurator).getSubscriptionManager(); - doReturn(mMockEuiCCManager).when(mMockONSProfileConfigurator).getEuiccManager(); - doReturn(mMockTeleManager).when(mMockONSProfileConfigurator).getTelephonyManager(); + Looper.prepare(); doReturn(TelephonyManager.SIM_STATE_READY).when(mMockTeleManager).getSimState(); - doReturn(mMockCarrierConfigManager).when(mMockONSProfileConfigurator) - .getCarrierConfigManager(); + doReturn(mMockResources).when(mMockContext).getResources(); + + doReturn(mMockConnectivityManager).when(mMockContext).getSystemService( + Context.CONNECTIVITY_SERVICE); + NetworkRequest request = new NetworkRequest.Builder().addCapability( + NetworkCapabilities.NET_CAPABILITY_VALIDATED).build(); + doNothing().when(mMockConnectivityManager).registerNetworkCallback(request, + new ConnectivityManager.NetworkCallback()); } @Test public void testSIMNotReady() { doReturn(TelephonyManager.SIM_STATE_NOT_READY).when(mMockTeleManager).getSimState(); - final ONSProfileActivator mONSProfileActivator = new ONSProfileActivator(mMockContext, - mMockONSProfileConfigurator, mMockONSProfileDownloader); + ONSProfileActivator onsProfileActivator = new ONSProfileActivator(mMockContext, + mMockSubManager, mMockTeleManager, mMockCarrierConfigManager, mMockEuiccManager, + mMockConnectivityManager, mMockONSProfileConfigurator, mMockONSProfileDownloader); assertEquals(ONSProfileActivator.Result.ERR_SIM_NOT_READY, - mONSProfileActivator.handleSimStateChange()); + onsProfileActivator.handleSimStateChange()); } @Test public void testONSAutoProvisioningDisabled() { - doReturn(false).when(mMockONSProfileConfigurator).isONSAutoProvisioningEnabled(); + doReturn(TelephonyManager.SIM_STATE_READY).when(mMockTeleManager).getSimState(); + doReturn(false).when(mMockResources).getBoolean(R.bool.enable_ons_auto_provisioning); - ONSProfileActivator mONSProfileActivator = new ONSProfileActivator(mMockContext, - mMockONSProfileConfigurator, mMockONSProfileDownloader); + ONSProfileActivator onsProfileActivator = new ONSProfileActivator(mMockContext, + mMockSubManager, mMockTeleManager, mMockCarrierConfigManager, mMockEuiccManager, + mMockConnectivityManager, mMockONSProfileConfigurator, mMockONSProfileDownloader); assertEquals(ONSProfileActivator.Result.ERR_AUTO_PROVISIONING_DISABLED, - mONSProfileActivator.handleSimStateChange()); + onsProfileActivator.handleSimStateChange()); } @Test - //@DisplayName("Device doesn't support eSIM") public void testESIMNotSupported() { - doReturn(true).when(mMockONSProfileConfigurator).isONSAutoProvisioningEnabled(); - doReturn(true).when(mMockONSProfileConfigurator).isONSAutoProvisioningEnabled(); - doReturn(false).when(mMockONSProfileConfigurator).isESIMSupported(); + doReturn(TelephonyManager.SIM_STATE_READY).when(mMockTeleManager).getSimState(); + doReturn(true).when(mMockResources).getBoolean(R.bool.enable_ons_auto_provisioning); + doReturn(false).when(mMockEuiccManager).isEnabled(); - ONSProfileActivator mONSProfileActivator = new ONSProfileActivator(mMockContext, - mMockONSProfileConfigurator, mMockONSProfileDownloader); + ONSProfileActivator onsProfileActivator = new ONSProfileActivator(mMockContext, + mMockSubManager, mMockTeleManager, mMockCarrierConfigManager, mMockEuiccManager, + mMockConnectivityManager, mMockONSProfileConfigurator, mMockONSProfileDownloader); assertEquals(ONSProfileActivator.Result.ERR_ESIM_NOT_SUPPORTED, - mONSProfileActivator.handleSimStateChange()); + onsProfileActivator.handleSimStateChange()); } @Test //@DisplayName("Single SIM Device with eSIM support") public void testMultiSIMNotSupported() { - doReturn(true).when(mMockONSProfileConfigurator).isONSAutoProvisioningEnabled(); - doReturn(true).when(mMockONSProfileConfigurator).isESIMSupported(); - doReturn(false).when(mMockONSProfileConfigurator).isMultiSIMPhone(); + doReturn(TelephonyManager.SIM_STATE_READY).when(mMockTeleManager).getSimState(); + doReturn(true).when(mMockResources).getBoolean(R.bool.enable_ons_auto_provisioning); + doReturn(true).when(mMockEuiccManager).isEnabled(); + doReturn(1).when(mMockTeleManager).getSupportedModemCount(); + doReturn(2).when(mMockTeleManager).getActiveModemCount(); - ONSProfileActivator mONSProfileActivator = new ONSProfileActivator(mMockContext, - mMockONSProfileConfigurator, mMockONSProfileDownloader); + ONSProfileActivator onsProfileActivator = new ONSProfileActivator(mMockContext, + mMockSubManager, mMockTeleManager, mMockCarrierConfigManager, mMockEuiccManager, + mMockConnectivityManager, mMockONSProfileConfigurator, mMockONSProfileDownloader); assertEquals(ONSProfileActivator.Result.ERR_MULTISIM_NOT_SUPPORTED, - mONSProfileActivator.handleSimStateChange()); + onsProfileActivator.handleSimStateChange()); } @Test public void testDeviceSwitchToDualSIMModeFailed() { - doReturn(true).when(mMockONSProfileConfigurator).isONSAutoProvisioningEnabled(); - doReturn(true).when(mMockONSProfileConfigurator).isESIMSupported(); - doReturn(true).when(mMockONSProfileConfigurator).isMultiSIMPhone(); + doReturn(TelephonyManager.SIM_STATE_READY).when(mMockTeleManager).getSimState(); + doReturn(true).when(mMockResources).getBoolean(R.bool.enable_ons_auto_provisioning); + doReturn(true).when(mMockEuiccManager).isEnabled(); + doReturn(2).when(mMockTeleManager).getSupportedModemCount(); + doReturn(1).when(mMockTeleManager).getActiveModemCount(); + doReturn(true).when(mMockTeleManager).doesSwitchMultiSimConfigTriggerReboot(); doReturn(mMockactiveSubInfos).when(mMockSubManager).getActiveSubscriptionInfoList(); doReturn(1).when(mMockactiveSubInfos).size(); doReturn(mMockSubInfo).when(mMockactiveSubInfos).get(0); doReturn(1).when(mMockSubInfo).getSubscriptionId(); doReturn(false).when(mMockSubInfo).isOpportunistic(); - doReturn(true).when(mMockONSProfileConfigurator) - .isOppDataAutoProvisioningSupported(1); - doReturn(true).when(mMockONSProfileConfigurator).isDeviceInSingleSIMMode(); - doReturn(false).when(mMockONSProfileConfigurator).switchToMultiSIMMode(); - ONSProfileActivator mONSProfileActivator = new ONSProfileActivator(mMockContext, - mMockONSProfileConfigurator, mMockONSProfileDownloader); + PersistableBundle persistableBundle = new PersistableBundle(); + persistableBundle.putBoolean(CarrierConfigManager + .KEY_CARRIER_SUPPORTS_OPP_DATA_AUTO_PROVISIONING_BOOL, true); + doReturn(persistableBundle).when(mMockCarrierConfigManager).getConfigForSubId(1); + + ONSProfileActivator onsProfileActivator = new ONSProfileActivator(mMockContext, + mMockSubManager, mMockTeleManager, mMockCarrierConfigManager, mMockEuiccManager, + mMockConnectivityManager, mMockONSProfileConfigurator, mMockONSProfileDownloader); assertEquals(ONSProfileActivator.Result.ERR_CANNOT_SWITCH_TO_DUAL_SIM_MODE, - mONSProfileActivator.handleSimStateChange()); + onsProfileActivator.handleSimStateChange()); } @Test public void testDeviceSwitchToDualSIMModeSuccess() { - doReturn(true).when(mMockONSProfileConfigurator).isONSAutoProvisioningEnabled(); - doReturn(true).when(mMockONSProfileConfigurator).isESIMSupported(); - doReturn(true).when(mMockONSProfileConfigurator).isMultiSIMPhone(); + doReturn(TelephonyManager.SIM_STATE_READY).when(mMockTeleManager).getSimState(); + doReturn(true).when(mMockResources).getBoolean(R.bool.enable_ons_auto_provisioning); + doReturn(true).when(mMockEuiccManager).isEnabled(); + doReturn(2).when(mMockTeleManager).getSupportedModemCount(); + doReturn(1).when(mMockTeleManager).getActiveModemCount(); doReturn(mMockactiveSubInfos).when(mMockSubManager).getActiveSubscriptionInfoList(); doReturn(1).when(mMockactiveSubInfos).size(); doReturn(mMockSubInfo).when(mMockactiveSubInfos).get(0); doReturn(1).when(mMockSubInfo).getSubscriptionId(); doReturn(false).when(mMockSubInfo).isOpportunistic(); - doReturn(true).when(mMockONSProfileConfigurator) - .isOppDataAutoProvisioningSupported(1); - doReturn(true).when(mMockONSProfileConfigurator).isDeviceInSingleSIMMode(); - doReturn(true).when(mMockONSProfileConfigurator).switchToMultiSIMMode(); - ONSProfileActivator mONSProfileActivator = new ONSProfileActivator(mMockContext, - mMockONSProfileConfigurator, mMockONSProfileDownloader); + PersistableBundle persistableBundle = new PersistableBundle(); + persistableBundle.putBoolean(CarrierConfigManager + .KEY_CARRIER_SUPPORTS_OPP_DATA_AUTO_PROVISIONING_BOOL, true); + doReturn(persistableBundle).when(mMockCarrierConfigManager).getConfigForSubId(1); + doReturn(false).when(mMockTeleManager).doesSwitchMultiSimConfigTriggerReboot(); + + ONSProfileActivator onsProfileActivator = new ONSProfileActivator(mMockContext, + mMockSubManager, mMockTeleManager, mMockCarrierConfigManager, mMockEuiccManager, + mMockConnectivityManager, mMockONSProfileConfigurator, mMockONSProfileDownloader); - assertEquals(ONSProfileActivator.Result.ERR_SWITCHED_TO_DUAL_SIM_MODE, - mONSProfileActivator.handleSimStateChange()); + assertEquals(ONSProfileActivator.Result.ERR_SWITCHING_TO_DUAL_SIM_MODE, + onsProfileActivator.handleSimStateChange()); } //@DisplayName("Dual SIM device with no SIM inserted") public void testNoActiveSubscriptions() { - doReturn(true).when(mMockONSProfileConfigurator).isONSAutoProvisioningEnabled(); - doReturn(true).when(mMockONSProfileConfigurator).isESIMSupported(); - doReturn(true).when(mMockONSProfileConfigurator).isMultiSIMPhone(); + doReturn(TelephonyManager.SIM_STATE_READY).when(mMockTeleManager).getSimState(); + doReturn(true).when(mMockResources).getBoolean(R.bool.enable_ons_auto_provisioning); + doReturn(true).when(mMockEuiccManager).isEnabled(); + doReturn(2).when(mMockTeleManager).getSupportedModemCount(); + doReturn(2).when(mMockTeleManager).getActiveModemCount(); doReturn(mMockactiveSubInfos).when(mMockSubManager).getActiveSubscriptionInfoList(); doReturn(0).when(mMockactiveSubInfos).size(); - ONSProfileActivator mONSProfileActivator = new ONSProfileActivator(mMockContext, - mMockONSProfileConfigurator, mMockONSProfileDownloader); + ONSProfileActivator onsProfileActivator = new ONSProfileActivator(mMockContext, + mMockSubManager, mMockTeleManager, mMockCarrierConfigManager, mMockEuiccManager, + mMockConnectivityManager, mMockONSProfileConfigurator, mMockONSProfileDownloader); assertEquals(ONSProfileActivator.Result.ERR_NO_SIM_INSERTED, - mONSProfileActivator.handleSimStateChange()); + onsProfileActivator.handleSimStateChange()); } @Test //@DisplayName("Dual SIM device and non CBRS carrier pSIM inserted") public void testNonCBRSCarrierPSIMInserted() { - doReturn(true).when(mMockONSProfileConfigurator).isONSAutoProvisioningEnabled(); - doReturn(true).when(mMockONSProfileConfigurator).isESIMSupported(); - doReturn(true).when(mMockONSProfileConfigurator).isMultiSIMPhone(); - doReturn(false).when(mMockONSProfileConfigurator).isOppDataAutoProvisioningSupported(1); + doReturn(TelephonyManager.SIM_STATE_READY).when(mMockTeleManager).getSimState(); + doReturn(true).when(mMockResources).getBoolean(R.bool.enable_ons_auto_provisioning); + doReturn(true).when(mMockEuiccManager).isEnabled(); + doReturn(2).when(mMockTeleManager).getSupportedModemCount(); + doReturn(2).when(mMockTeleManager).getActiveModemCount(); + + PersistableBundle persistableBundle = new PersistableBundle(); + persistableBundle.putBoolean(CarrierConfigManager + .KEY_CARRIER_SUPPORTS_OPP_DATA_AUTO_PROVISIONING_BOOL, false); + doReturn(persistableBundle).when(mMockCarrierConfigManager).getConfigForSubId(1); + doReturn(mMockactiveSubInfos).when(mMockSubManager).getActiveSubscriptionInfoList(); doReturn(1).when(mMockactiveSubInfos).size(); doReturn(mMockSubInfo).when(mMockactiveSubInfos).get(0); doReturn(1).when(mMockSubInfo).getSubscriptionId(); doReturn(false).when(mMockSubInfo).isOpportunistic(); - doReturn(false).when(mMockONSProfileConfigurator).isOppDataAutoProvisioningSupported(1); - ONSProfileActivator mONSProfileActivator = new ONSProfileActivator(mMockContext, - mMockONSProfileConfigurator, mMockONSProfileDownloader); + ONSProfileActivator onsProfileActivator = new ONSProfileActivator(mMockContext, + mMockSubManager, mMockTeleManager, mMockCarrierConfigManager, mMockEuiccManager, + mMockConnectivityManager, mMockONSProfileConfigurator, mMockONSProfileDownloader); assertEquals(ONSProfileActivator.Result.ERR_CARRIER_DOESNT_SUPPORT_CBRS, - mONSProfileActivator.handleSimStateChange()); + onsProfileActivator.handleSimStateChange()); } @Test //@DisplayName("Dual SIM device with Two PSIM active subscriptions") public void testTwoActivePSIMSubscriptions() { - doReturn(true).when(mMockONSProfileConfigurator).isONSAutoProvisioningEnabled(); - doReturn(true).when(mMockONSProfileConfigurator).isESIMSupported(); - doReturn(true).when(mMockONSProfileConfigurator).isMultiSIMPhone(); + doReturn(TelephonyManager.SIM_STATE_READY).when(mMockTeleManager).getSimState(); + doReturn(true).when(mMockResources).getBoolean(R.bool.enable_ons_auto_provisioning); + doReturn(true).when(mMockEuiccManager).isEnabled(); + doReturn(2).when(mMockTeleManager).getSupportedModemCount(); + doReturn(2).when(mMockTeleManager).getActiveModemCount(); + ArrayList<SubscriptionInfo> mActiveSubInfos = new ArrayList<>(); mActiveSubInfos.add(mMockSubInfo); mActiveSubInfos.add(mMockSubInfo2); @@ -216,18 +260,19 @@ public class ONSProfileActivatorTest extends ONSBaseTest { doReturn(false).when(mMockSubInfo).isEmbedded(); doReturn(false).when(mMockSubInfo2).isEmbedded(); - ONSProfileActivator mONSProfileActivator = new ONSProfileActivator(mMockContext, - mMockONSProfileConfigurator, mMockONSProfileDownloader); + ONSProfileActivator onsProfileActivator = new ONSProfileActivator(mMockContext, + mMockSubManager, mMockTeleManager, mMockCarrierConfigManager, mMockEuiccManager, + mMockConnectivityManager, mMockONSProfileConfigurator, mMockONSProfileDownloader); assertEquals(ONSProfileActivator.Result.ERR_DUAL_ACTIVE_SUBSCRIPTIONS, - mONSProfileActivator.handleSimStateChange()); + onsProfileActivator.handleSimStateChange()); } /*@Test //Cannot mock/spy class android.os.PersistableBundle public void testOneActivePSIMAndOneNonOpportunisticESIM() { - doReturn(true).when(mMockONSProfileConfigurator).isESIMSupported(); - doReturn(true).when(mMockONSProfileConfigurator).isMultiSIMPhone(); + doReturn(true).when(mMockONSUtil).isESIMSupported(); + doReturn(true).when(mMockONSUtil).isMultiSIMPhone(); ArrayList<SubscriptionInfo> mActiveSubInfos = new ArrayList<>(); mActiveSubInfos.add(mMockSubInfo1); mActiveSubInfos.add(mMockSubInfo2); @@ -237,18 +282,18 @@ public class ONSProfileActivatorTest extends ONSBaseTest { //0 - using carrier-id=0 to make sure it doesn't map to any opportunistic carrier-id doReturn(0).when(mMockSubInfo2).getCarrierId(); - ONSProfileActivator mONSProfileActivator = new ONSProfileActivator(mMockContext, + ONSProfileActivator onsProfileActivator = new ONSProfileActivator(mMockContext, mMockONSProfileConfigurator, mMockONSProfileDownloader); assertEquals(ONSProfileActivator.Result.ERR_DUAL_ACTIVE_SUBSCRIPTIONS, - mONSProfileActivator.handleSimStateChange()); + onsProfileActivator.handleSimStateChange()); }*/ /*@Test //Cannot mock/spy class android.os.PersistableBundle public void testOneActivePSIMAndOneOpportunisticESIM() { - doReturn(true).when(mMockONSProfileConfigurator).isESIMSupported(); - doReturn(true).when(mMockONSProfileConfigurator).isMultiSIMPhone(); + doReturn(true).when(mMockONSUtil).isESIMSupported(); + doReturn(true).when(mMockONSUtil).isMultiSIMPhone(); ArrayList<SubscriptionInfo> mActiveSubInfos = new ArrayList<>(); mActiveSubInfos.add(mMockSubInfo1); mActiveSubInfos.add(mMockSubInfo2); @@ -262,51 +307,112 @@ public class ONSProfileActivatorTest extends ONSBaseTest { //1 - using carrier-id=1 to match with opportunistic carrier-id doReturn(1).when(mMockSubInfo2).getCarrierId(); - ONSProfileActivator mONSProfileActivator = new ONSProfileActivator(mMockContext, + ONSProfileActivator onsProfileActivator = new ONSProfileActivator(mMockContext, mMockONSProfileConfigurator, mMockONSProfileDownloader); assertEquals(ONSProfileActivator.Result.SUCCESS, - mONSProfileActivator.handleSimStateChange()); + onsProfileActivator.handleSimStateChange()); }*/ @Test //@DisplayName("Dual SIM device with only opportunistic eSIM active") public void testOnlyOpportunisticESIMActive() { - doReturn(true).when(mMockONSProfileConfigurator).isONSAutoProvisioningEnabled(); - doReturn(true).when(mMockONSProfileConfigurator).isESIMSupported(); - doReturn(true).when(mMockONSProfileConfigurator).isMultiSIMPhone(); + doReturn(TelephonyManager.SIM_STATE_READY).when(mMockTeleManager).getSimState(); + doReturn(true).when(mMockResources).getBoolean(R.bool.enable_ons_auto_provisioning); + doReturn(true).when(mMockEuiccManager).isEnabled(); + doReturn(2).when(mMockTeleManager).getSupportedModemCount(); + doReturn(2).when(mMockTeleManager).getActiveModemCount(); doReturn(mMockactiveSubInfos).when(mMockSubManager).getActiveSubscriptionInfoList(); doReturn(1).when(mMockactiveSubInfos).size(); doReturn(mMockSubInfo).when(mMockactiveSubInfos).get(0); doReturn(true).when(mMockSubInfo).isOpportunistic(); - ONSProfileActivator mONSProfileActivator = new ONSProfileActivator(mMockContext, - mMockONSProfileConfigurator, mMockONSProfileDownloader); + ONSProfileActivator onsProfileActivator = new ONSProfileActivator(mMockContext, + mMockSubManager, mMockTeleManager, mMockCarrierConfigManager, mMockEuiccManager, + mMockConnectivityManager, mMockONSProfileConfigurator, mMockONSProfileDownloader); assertEquals(ONSProfileActivator.Result.ERR_SINGLE_ACTIVE_OPPORTUNISTIC_SIM, - mONSProfileActivator.handleSimStateChange()); + onsProfileActivator.handleSimStateChange()); } @Test //@DisplayName("Dual SIM device, only CBRS carrier pSIM inserted and pSIM not Grouped") public void testCBRSpSIMAndNotGrouped() { - doReturn(true).when(mMockONSProfileConfigurator).isONSAutoProvisioningEnabled(); - doReturn(true).when(mMockONSProfileConfigurator).isESIMSupported(); - doReturn(true).when(mMockONSProfileConfigurator).isMultiSIMPhone(); - doReturn(true).when(mMockONSProfileConfigurator).isOppDataAutoProvisioningSupported(1); + doReturn(TelephonyManager.SIM_STATE_READY).when(mMockTeleManager).getSimState(); + doReturn(true).when(mMockResources).getBoolean(R.bool.enable_ons_auto_provisioning); + doReturn(true).when(mMockEuiccManager).isEnabled(); + doReturn(2).when(mMockTeleManager).getSupportedModemCount(); + doReturn(2).when(mMockTeleManager).getActiveModemCount(); + + PersistableBundle persistableBundle = new PersistableBundle(); + persistableBundle.putBoolean(CarrierConfigManager + .KEY_CARRIER_SUPPORTS_OPP_DATA_AUTO_PROVISIONING_BOOL, true); + doReturn(persistableBundle).when(mMockCarrierConfigManager).getConfigForSubId(1); + doReturn(mMockactiveSubInfos).when(mMockSubManager).getActiveSubscriptionInfoList(); doReturn(1).when(mMockactiveSubInfos).size(); doReturn(mMockSubInfo).when(mMockactiveSubInfos).get(0); doReturn(false).when(mMockSubInfo).isOpportunistic(); doReturn(1).when(mMockSubInfo).getSubscriptionId(); - doReturn(true).when(mMockONSProfileConfigurator).isOppDataAutoProvisioningSupported(1); doReturn(null).when(mMockSubInfo).getGroupUuid(); - ONSProfileActivator mONSProfileActivator = new ONSProfileActivator(mMockContext, - mMockONSProfileConfigurator, mMockONSProfileDownloader); + ONSProfileActivator onsProfileActivator = new ONSProfileActivator(mMockContext, + mMockSubManager, mMockTeleManager, mMockCarrierConfigManager, mMockEuiccManager, + mMockConnectivityManager, mMockONSProfileConfigurator, mMockONSProfileDownloader); + onsProfileActivator.mIsInternetConnAvailable = true; assertEquals(ONSProfileActivator.Result.SUCCESS, - mONSProfileActivator.handleSimStateChange()); + onsProfileActivator.handleSimStateChange()); + } + + @Test + public void testCalculateBackoffDelay() { + final Object lock = new Object(); + + Runnable runnable = new Runnable() { + @Override + public void run() { + int delay = ONSProfileActivator.calculateBackoffDelay(1, 1) / 1000; + assertEquals(true, (delay >= 1 && delay <= 2)); + + Log.i(TAG, "calculateBackoffDelay(2, 1)"); + delay = ONSProfileActivator.calculateBackoffDelay(2, 1) / 1000; + assertEquals(true, (delay >= 1 && delay < 4)); + + delay = ONSProfileActivator.calculateBackoffDelay(3, 1) / 1000; + assertEquals(true, (delay >= 1 && delay < 8)); + + delay = ONSProfileActivator.calculateBackoffDelay(4, 1) / 1000; + assertEquals(true, (delay >= 1 && delay < 16)); + + delay = ONSProfileActivator.calculateBackoffDelay(1, 2) / 1000; + assertEquals(true, (delay >= 1 && delay <= 4)); + + delay = ONSProfileActivator.calculateBackoffDelay(1, 3) / 1000; + assertEquals(true, (delay >= 1 && delay <= 6)); + + delay = ONSProfileActivator.calculateBackoffDelay(2, 2) / 1000; + assertEquals(true, (delay >= 2 && delay < 8)); + + synchronized (lock) { + lock.notifyAll(); + } + } + }; + + ONSProfileDownloaderTest.WorkerThread workerThread = new ONSProfileDownloaderTest + .WorkerThread(runnable); + workerThread.start(); + + synchronized (lock) { + try { + lock.wait(); + } catch (Exception e) { + Log.e(TAG, e.getLocalizedMessage()); + } + } + + workerThread.exit(); } /* Unable to mock final class ParcelUuid. These testcases should be enabled once the solution @@ -318,7 +424,7 @@ public class ONSProfileActivatorTest extends ONSBaseTest { doReturn(true).when(mMockONSProfileConfigurator) .isESIMSupported(); - doReturn(true).when(mMockONSProfileConfigurator).isMultiSIMPhone(); + doReturn(true).when(mMockONSUtil).isMultiSIMPhone(); doReturn(true).when(mMockONSProfileConfigurator).isOppDataAutoProvisioningSupported( mMockPrimaryCBRSSubInfo); doReturn(mMockactiveSubInfos).when(mMockSubManager).getActiveSubscriptionInfoList(); @@ -332,13 +438,13 @@ public class ONSProfileActivatorTest extends ONSBaseTest { mMockParcelUuid); doReturn(1).when(mMocksubsInPSIMGroup).size(); - ONSProfileActivator mONSProfileActivator = + ONSProfileActivator onsProfileActivator = new ONSProfileActivator(mMockContext, mMockSubManager, mMockEuiCCManager, mMockTeleManager, mMockONSProfileConfigurator, mMockONSProfileDownloader); assertEquals(ONSProfileActivator.Result.SUCCESS, - mONSProfileActivator.handleSimStateChange()); + onsProfileActivator.handleSimStateChange()); } @Test @@ -349,7 +455,7 @@ public class ONSProfileActivatorTest extends ONSBaseTest { doReturn(true).when(mMockONSProfileConfigurator) .isESIMSupported(); - doReturn(true).when(mMockONSProfileConfigurator).isMultiSIMPhone(); + doReturn(true).when(mMockONSUtil).isMultiSIMPhone(); doReturn(true).when(mMockONSProfileConfigurator).isOppDataAutoProvisioningSupported( mMockPrimaryCBRSSubInfo); doReturn(mMockactiveSubInfos).when(mMockSubManager).getActiveSubscriptionInfoList(); @@ -363,12 +469,12 @@ public class ONSProfileActivatorTest extends ONSBaseTest { mMockParcelUuid); doReturn(2).when(mMocksubsInPSIMGroup).size(); - ONSProfileActivator mONSProfileActivator = + ONSProfileActivator onsProfileActivator = new ONSProfileActivator(mMockContext, mMockSubManager, mMockEuiCCManager, mMockTeleManager, mMockONSProfileConfigurator, mMockONSProfileDownloader); assertEquals(ONSProfileActivator.Result.SUCCESS, - mONSProfileActivator.handleSimStateChange()); + onsProfileActivator.handleSimStateChange()); } @Test @@ -379,7 +485,7 @@ public class ONSProfileActivatorTest extends ONSBaseTest { doReturn(true).when(mMockONSProfileConfigurator) .isESIMSupported(); - doReturn(true).when(mMockONSProfileConfigurator).isMultiSIMPhone(); + doReturn(true).when(mMockONSUtil).isMultiSIMPhone(); doReturn(true).when(mMockONSProfileConfigurator).isOppDataAutoProvisioningSupported( mMockPrimaryCBRSSubInfo); doReturn(mMockactiveSubInfos).when(mMockSubManager).getActiveSubscriptionInfoList(); @@ -393,30 +499,44 @@ public class ONSProfileActivatorTest extends ONSBaseTest { mMockParcelUuid); doReturn(3).when(mMocksubsInPSIMGroup).size(); - ONSProfileActivator mONSProfileActivator = + ONSProfileActivator onsProfileActivator = new ONSProfileActivator(mMockContext, mMockSubManager, mMockEuiCCManager, mMockTeleManager, mMockONSProfileConfigurator, mMockONSProfileDownloader); assertEquals(ONSProfileActivator.Result.SUCCESS, - mONSProfileActivator.handleSimStateChange()); + onsProfileActivator.handleSimStateChange()); } @Test public void testRetryDownloadAfterRebootWithOppESIMAlreadyDownloaded() { doReturn(true).when(mMockONSProfileConfigurator).getRetryDownloadAfterReboot(); doReturn(1).when(mMockONSProfileConfigurator).getRetryDownloadPSIMSubId(); - doReturn(mMockSubManager).when(mMockONSProfileConfigurator).getSubscriptionManager(); + doReturn(mMockSubManager).when(mMockONSUtil).getSubscriptionManager(); doReturn(mMocksubsInPSIMGroup).when(mMockSubManager).getActiveSubscriptionInfo(); //TODO: mock ParcelUuid - pSIM group - ONSProfileActivator mONSProfileActivator = new ONSProfileActivator(mMockContext, + ONSProfileActivator onsProfileActivator = new ONSProfileActivator(mMockContext, mMockONSProfileConfigurator, mMockONSProfileDownloader); assertEquals(ONSProfileActivator.Result.ERR_INVALID_PSIM_SUBID, - mONSProfileActivator.retryDownloadAfterReboot()); + onsProfileActivator.retryDownloadAfterReboot()); } */ + /*@Test + public void testNoInternetDownloadRequest() { + doReturn(TEST_SUB_ID).when(mMockSubInfo).getSubscriptionId(); + + ONSProfileDownloader onsProfileDownloader = new ONSProfileDownloader(mMockContext, + mMockCarrierConfigManager, mMockEUICCManager, mMockONSProfileConfig, null); + + onsProfileDownloader.mIsInternetConnAvailable = false; + onsProfileDownloader.downloadOpportunisticESIM(mMockSubInfo); + + assertEquals(onsProfileDownloader.mRetryDownloadWhenNWConnected, true); + verify(mMockEUICCManager, never()).downloadSubscription(null, true, null); + }*/ + @After public void tearDown() throws Exception { super.tearDown(); diff --git a/tests/src/com/android/ons/ONSProfileConfiguratorTest.java b/tests/src/com/android/ons/ONSProfileConfiguratorTest.java index 981d91b..394a3ae 100644 --- a/tests/src/com/android/ons/ONSProfileConfiguratorTest.java +++ b/tests/src/com/android/ons/ONSProfileConfiguratorTest.java @@ -17,8 +17,18 @@ package com.android.ons; import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyNoMoreInteractions; +import android.app.PendingIntent; import android.content.Context; +import android.content.Intent; +import android.os.Looper; +import android.os.Message; +import android.os.ParcelUuid; +import android.os.PersistableBundle; +import android.telephony.CarrierConfigManager; +import android.telephony.SubscriptionInfo; import android.telephony.SubscriptionManager; import android.telephony.TelephonyManager; import android.telephony.euicc.EuiccManager; @@ -29,84 +39,174 @@ import org.junit.Test; import org.mockito.Mock; import org.mockito.MockitoAnnotations; +import java.util.ArrayList; +import java.util.UUID; + public class ONSProfileConfiguratorTest extends ONSBaseTest { private static final String TAG = ONSProfileConfiguratorTest.class.getName(); - @Mock - private Context mMockContext; - @Mock - SubscriptionManager mMockSubManager; - @Mock - EuiccManager mMockEuiccManager; - @Mock - TelephonyManager mMockTelephonyManager; - @Mock - private ONSProfileActivator mMockONSProfileActivator; + private static final int TEST_SUB_ID = 1; + @Mock SubscriptionManager mMockSubManager; + @Mock SubscriptionInfo mMockSubscriptionInfo1; + @Mock SubscriptionInfo mMockSubscriptionInfo2; + @Mock EuiccManager mMockEuiccMngr; + @Mock TelephonyManager mMockTelephonyManager; + @Mock CarrierConfigManager mMockCarrierConfigManager; + @Mock private Context mMockContext; + @Mock private ONSProfileActivator mMockONSProfileActivator; + @Mock private ONSProfileConfigurator.ONSProfConfigListener mMockConfigListener; @Before public void setUp() throws Exception { super.setUp("ONSTest"); MockitoAnnotations.initMocks(this); + Looper.prepare(); } @Test - public void testESIMNotSupported() { - doReturn(false).when(mMockEuiccManager).isEnabled(); - ONSProfileConfigurator mOnsProfileConfigurator = new ONSProfileConfigurator(mMockContext, - mMockSubManager, mMockEuiccManager, mMockTelephonyManager); - assertEquals(false, mOnsProfileConfigurator.isESIMSupported()); + public void testDeleteSubscription() { + ONSProfileConfigurator mOnsProfileConfigurator = new ONSProfileConfigurator(mContext, + mMockSubManager, mMockCarrierConfigManager, mMockEuiccMngr, mMockConfigListener); + + Intent intent = new Intent(); + intent.putExtra( + ONSProfileConfigurator.PARAM_REQUEST_TYPE, + ONSProfileConfigurator.REQUEST_CODE_DELETE_SUB); + intent.putExtra(ONSProfileConfigurator.PARAM_SUB_ID, TEST_SUB_ID); + Message msg = new Message(); + msg.obj = intent; + msg.arg1 = EuiccManager.EMBEDDED_SUBSCRIPTION_RESULT_OK; + mOnsProfileConfigurator.callbackMsgHandler(msg); + + verify(mMockConfigListener).onOppSubscriptionDeleted(TEST_SUB_ID); } @Test - public void testESIMSupported() { - doReturn(true).when(mMockEuiccManager).isEnabled(); + public void testGroupSubscriptionAndSetOpportunistic() { + doReturn(TEST_SUB_ID).when(mMockSubscriptionInfo1).getSubscriptionId(); + + ONSProfileConfigurator mOnsProfileConfigurator = new ONSProfileConfigurator(mContext, + mMockSubManager, mMockCarrierConfigManager, mMockEuiccMngr, mMockConfigListener); - ONSProfileConfigurator mOnsProfileConfigurator = new ONSProfileConfigurator(mMockContext, - mMockSubManager, mMockEuiccManager, mMockTelephonyManager); - assertEquals(true, mOnsProfileConfigurator.isESIMSupported()); + ParcelUuid parcelUuid = new ParcelUuid(new UUID(1, 2)); + mOnsProfileConfigurator.groupWithPSIMAndSetOpportunistic( + mMockSubscriptionInfo1, parcelUuid); + + ArrayList<Integer> subList = new ArrayList<>(); + subList.add(TEST_SUB_ID); + verify(mMockSubManager).addSubscriptionsIntoGroup(subList, parcelUuid); } @Test - public void testMultiSIMNotSupported() { - doReturn(1).when(mMockTelephonyManager).getActiveModemCount(); - - ONSProfileConfigurator mOnsProfileConfigurator = new ONSProfileConfigurator(mMockContext, - mMockSubManager, mMockEuiccManager, mMockTelephonyManager); - assertEquals(false, mOnsProfileConfigurator.isMultiSIMPhone()); + public void testActivateSubscription() { + ONSProfileConfigurator mOnsProfileConfigurator = new ONSProfileConfigurator(mContext, + mMockSubManager, mMockCarrierConfigManager, mMockEuiccMngr, mMockConfigListener); + + Intent intent = new Intent(mContext, ONSProfileResultReceiver.class); + intent.setAction(ONSProfileConfigurator.ACTION_ONS_ESIM_CONFIG); + intent.putExtra( + ONSProfileConfigurator.PARAM_REQUEST_TYPE, + ONSProfileConfigurator.REQUEST_CODE_ACTIVATE_SUB); + intent.putExtra(ONSProfileConfigurator.PARAM_SUB_ID, TEST_SUB_ID); + PendingIntent callbackIntent = + PendingIntent.getBroadcast( + mContext, + ONSProfileConfigurator.REQUEST_CODE_ACTIVATE_SUB, + intent, + PendingIntent.FLAG_IMMUTABLE); + + mOnsProfileConfigurator.activateSubscription(TEST_SUB_ID); + verify(mMockSubManager).switchToSubscription(TEST_SUB_ID, callbackIntent); } @Test - public void testMultiSIMSupported() { - doReturn(2).when(mMockTelephonyManager).getSupportedModemCount(); + public void testdeleteInactiveOpportunisticSubscriptionsWithNoneSavedOppSubs() { + ONSProfileConfigurator mOnsProfileConfigurator = new ONSProfileConfigurator(mContext, + mMockSubManager, mMockCarrierConfigManager, mMockEuiccMngr, mMockConfigListener); + + PersistableBundle persistableBundle = new PersistableBundle(); + persistableBundle.putIntArray( + CarrierConfigManager.KEY_OPPORTUNISTIC_CARRIER_IDS_INT_ARRAY, null); + doReturn(persistableBundle).when(mMockCarrierConfigManager).getConfigForSubId(TEST_SUB_ID); + + boolean res = mOnsProfileConfigurator.deleteInactiveOpportunisticSubscriptions(TEST_SUB_ID); + // verify(mOnsProfileConfigurator).deleteOldOpportunisticESimsOfPSIMOperator(TEST_SUB_ID); + assertEquals(res, false); + } - ONSProfileConfigurator mOnsProfileConfigurator = new ONSProfileConfigurator(mMockContext, - mMockSubManager, mMockEuiccManager, mMockTelephonyManager); - assertEquals(true, mOnsProfileConfigurator.isMultiSIMPhone()); + @Test + public void testdeleteInactiveOpportunisticSubscriptionsWithSavedOppSubs() { + ONSProfileConfigurator mOnsProfileConfigurator = new ONSProfileConfigurator(mContext, + mMockSubManager, mMockCarrierConfigManager, mMockEuiccMngr, mMockConfigListener); + + doReturn(1).when(mMockSubscriptionInfo1).getSubscriptionId(); + doReturn(true).when(mMockSubManager).isActiveSubscriptionId(1); + + doReturn(2).when(mMockSubscriptionInfo2).getSubscriptionId(); + doReturn(false).when(mMockSubManager).isActiveSubscriptionId(2); + + ArrayList<SubscriptionInfo> oppSubList = new ArrayList<>(); + oppSubList.add(mMockSubscriptionInfo1); + oppSubList.add(mMockSubscriptionInfo2); + doReturn(oppSubList).when(mMockSubManager).getOpportunisticSubscriptions(); + + Intent intent = new Intent(mContext, ONSProfileResultReceiver.class); + intent.setAction(ONSProfileConfigurator.ACTION_ONS_ESIM_CONFIG); + intent.putExtra( + ONSProfileConfigurator.PARAM_REQUEST_TYPE, + ONSProfileConfigurator.REQUEST_CODE_DELETE_SUB); + intent.putExtra(ONSProfileConfigurator.PARAM_SUB_ID, 2); + PendingIntent callbackIntent2 = + PendingIntent.getBroadcast( + mContext, + ONSProfileConfigurator.REQUEST_CODE_DELETE_SUB, + intent, + PendingIntent.FLAG_MUTABLE); + + boolean res = mOnsProfileConfigurator.deleteInactiveOpportunisticSubscriptions(2); + verify(mMockEuiccMngr).deleteSubscription(2, callbackIntent2); + verifyNoMoreInteractions(mMockEuiccMngr); + //verify(mMockEuiccManager).deleteSubscription(2, callbackIntent2); + // verify(mOnsProfileConfigurator).deleteOldOpportunisticESimsOfPSIMOperator(TEST_SUB_ID); + assertEquals(res, true); } - /* This test case needs application context instead of mock Context. Need to investigate how to - get application in Junit test class. @Test - public void testRetryDownloadAfterRebootFlagSaving() { - ONSProfileConfigurator mOnsProfileConfigurator = new ONSProfileConfigurator( - Context.getApplicationContext(), mMockSubManager, mMockEuiccManager, - mMockTelephonyManager); - - mOnsProfileConfigurator.setRetryDownloadAfterReboot(true, 1); - assertEquals(true, mOnsProfileConfigurator.getRetryDownloadAfterReboot()); - assertEquals(1, mOnsProfileConfigurator.getRetryDownloadpSIMSubId()); - - mOnsProfileConfigurator.setRetryDownloadAfterReboot(false, 1); - assertEquals(false, mOnsProfileConfigurator.getRetryDownloadAfterReboot()); - assertEquals(1, mOnsProfileConfigurator.getRetryDownloadpSIMSubId()); - - mOnsProfileConfigurator.setRetryDownloadAfterReboot(true, 2); - assertEquals(true, mOnsProfileConfigurator.getRetryDownloadAfterReboot()); - assertEquals(1, mOnsProfileConfigurator.getRetryDownloadpSIMSubId()); - - mOnsProfileConfigurator.setRetryDownloadAfterReboot(false, 2); - assertEquals(false, mOnsProfileConfigurator.getRetryDownloadAfterReboot()); - assertEquals(1, mOnsProfileConfigurator.getRetryDownloadpSIMSubId()); - }*/ + public void testFindOpportunisticSubscription() { + ONSProfileConfigurator mOnsProfileConfigurator = new ONSProfileConfigurator(mContext, + mMockSubManager, mMockCarrierConfigManager, mMockEuiccMngr, mMockConfigListener); + + int[] oppCarrierList = {2}; + PersistableBundle persistableBundle = new PersistableBundle(); + persistableBundle.putIntArray( + CarrierConfigManager.KEY_OPPORTUNISTIC_CARRIER_IDS_INT_ARRAY, oppCarrierList); + doReturn(persistableBundle).when(mMockCarrierConfigManager).getConfigForSubId(TEST_SUB_ID); + + ArrayList<SubscriptionInfo> oppSubList = new ArrayList<>(); + oppSubList.add(mMockSubscriptionInfo1); + oppSubList.add(mMockSubscriptionInfo2); + doReturn(oppSubList).when(mMockSubManager).getAvailableSubscriptionInfoList(); + + ParcelUuid groupUUID = new ParcelUuid(new UUID(0, 100)); + doReturn(groupUUID).when(mMockSubscriptionInfo1).getGroupUuid(); + doReturn(true).when(mMockSubscriptionInfo1).isEmbedded(); + doReturn(1).when(mMockSubscriptionInfo1).getCarrierId(); + doReturn(mMockSubscriptionInfo1).when(mMockSubManager) + .getActiveSubscriptionInfo(TEST_SUB_ID); + doReturn(TEST_SUB_ID).when(mMockSubscriptionInfo1).getSubscriptionId(); + + doReturn(null).when(mMockSubscriptionInfo2).getGroupUuid(); + doReturn(true).when(mMockSubscriptionInfo2).isEmbedded(); + doReturn(2).when(mMockSubscriptionInfo2).getCarrierId(); + doReturn(mMockSubscriptionInfo2).when(mMockSubManager).getActiveSubscriptionInfo(2); + doReturn(2).when(mMockSubscriptionInfo2).getSubscriptionId(); + + SubscriptionInfo oppSubscription = mOnsProfileConfigurator + .findOpportunisticSubscription(TEST_SUB_ID); + assertEquals(oppSubscription, mMockSubscriptionInfo2); + + doReturn(groupUUID).when(mMockSubscriptionInfo2).getGroupUuid(); + assertEquals(oppSubscription, mMockSubscriptionInfo2); + } @After public void tearDown() throws Exception { diff --git a/tests/src/com/android/ons/ONSProfileDownloaderTest.java b/tests/src/com/android/ons/ONSProfileDownloaderTest.java index 1334e95..f89d9bb 100644 --- a/tests/src/com/android/ons/ONSProfileDownloaderTest.java +++ b/tests/src/com/android/ons/ONSProfileDownloaderTest.java @@ -16,18 +16,17 @@ package com.android.ons; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.argThat; -import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyZeroInteractions; -import android.app.PendingIntent; import android.content.Context; import android.content.Intent; import android.os.Looper; +import android.os.PersistableBundle; +import android.telephony.CarrierConfigManager; import android.telephony.SubscriptionInfo; import android.telephony.euicc.DownloadableSubscription; import android.telephony.euicc.EuiccManager; @@ -48,11 +47,13 @@ public class ONSProfileDownloaderTest extends ONSBaseTest { @Mock Context mMockContext; @Mock + EuiccManager mMockEUICCManager; + @Mock SubscriptionInfo mMockSubInfo; @Mock - private ONSProfileConfigurator mMockONSProfileConfig; + CarrierConfigManager mMockCarrierConfigManager; @Mock - EuiccManager mMockEUICCManager; + private ONSProfileConfigurator mMockONSProfileConfig; @Mock ONSProfileDownloader.IONSProfileDownloaderListener mMockDownloadListener; @@ -60,7 +61,7 @@ public class ONSProfileDownloaderTest extends ONSBaseTest { public void setUp() throws Exception { super.setUp("ONSTest"); MockitoAnnotations.initMocks(this); - doReturn(mMockEUICCManager).when(mMockONSProfileConfig).getEuiccManager(); + Looper.prepare(); } static class WorkerThread extends Thread { @@ -86,29 +87,16 @@ public class ONSProfileDownloaderTest extends ONSBaseTest { } @Test - public void testNoInternetDownloadRequest() { - doReturn(false).when(mMockONSProfileConfig).isInternetConnectionAvailable(); + public void testNullSMDPAddress() { doReturn(TEST_SUB_ID).when(mMockSubInfo).getSubscriptionId(); + PersistableBundle config = new PersistableBundle(); + config.putString(CarrierConfigManager.KEY_SMDP_SERVER_ADDRESS_STRING, null); + doReturn(config).when(mMockCarrierConfigManager).getConfigForSubId(TEST_SUB_ID); - Looper.prepare(); ONSProfileDownloader onsProfileDownloader = new ONSProfileDownloader(mMockContext, - mMockONSProfileConfig, null); - onsProfileDownloader.downloadOpportunisticESIM(mMockSubInfo); + mMockCarrierConfigManager, mMockEUICCManager, mMockONSProfileConfig, null); - verify(mMockONSProfileConfig).setRetryDownloadWhenConnectedFlag(true); - verify(mMockEUICCManager, never()).downloadSubscription(null, true, null); - } - - @Test - public void testNullSMDPAddress() { - doReturn(true).when(mMockONSProfileConfig).isInternetConnectionAvailable(); - doReturn(null).when(mMockONSProfileConfig).getSMDPServerAddress(TEST_SUB_ID); - doReturn(TEST_SUB_ID).when(mMockSubInfo).getSubscriptionId(); - - Looper.prepare(); - ONSProfileDownloader onsProfileDownloader = - new ONSProfileDownloader(mMockContext, mMockONSProfileConfig, null); - onsProfileDownloader.downloadOpportunisticESIM(mMockSubInfo); + onsProfileDownloader.downloadProfile(mMockSubInfo.getSubscriptionId()); verify(mMockEUICCManager, never()).downloadSubscription(null, true, null); } @@ -126,16 +114,24 @@ public class ONSProfileDownloaderTest extends ONSBaseTest { lock.notify(); } } + + @Override + public void onDownloadError( + ONSProfileDownloader.DownloadRetryOperationCode operationCode, + int pSIMSubId) { + + } }; Runnable runnable = new Runnable() { @Override public void run() { - ONSProfileDownloader onsProfileDownloader = - new ONSProfileDownloader(mMockContext, mMockONSProfileConfig, mListener); + ONSProfileDownloader onsProfileDownloader = new ONSProfileDownloader(mMockContext, + mMockCarrierConfigManager, mMockEUICCManager, mMockONSProfileConfig, + mListener); Intent intent = new Intent(mContext, ONSProfileResultReceiver.class); - intent.setAction(ONSProfileResultReceiver.ACTION_ONS_RESULT_CALLBACK); + intent.setAction(ONSProfileDownloader.ACTION_ONS_ESIM_DOWNLOAD); intent.putExtra(Intent.EXTRA_COMPONENT_NAME, ONSProfileDownloader.class.getName()); intent.putExtra(ONSProfileDownloader.PARAM_PRIMARY_SUBID, TEST_SUB_ID); intent.putExtra(ONSProfileDownloader.PARAM_REQUEST_TYPE, @@ -143,7 +139,7 @@ public class ONSProfileDownloaderTest extends ONSBaseTest { intent.putExtra(EuiccManager.EXTRA_EMBEDDED_SUBSCRIPTION_OPERATION_CODE, EuiccManager.OPERATION_DOWNLOAD); - ONSProfileDownloader.onCallbackIntentReceived(intent, + onsProfileDownloader.onCallbackIntentReceived(intent, EuiccManager.EMBEDDED_SUBSCRIPTION_RESULT_OK); } }; @@ -164,26 +160,27 @@ public class ONSProfileDownloaderTest extends ONSBaseTest { @Test public void testDownloadFailureUnresolvableError() { - doReturn(2).when(mMockONSProfileConfig).getDownloadRetryMaxAttemptsVal(TEST_SUB_ID); - doReturn(1).when(mMockONSProfileConfig).getDownloadRetryBackOffTimerVal(TEST_SUB_ID); - doReturn(mMockEUICCManager).when(mMockONSProfileConfig).getEuiccManager(); - doReturn(true).when(mMockONSProfileConfig).isInternetConnectionAvailable(); - doReturn(TEST_SMDP_ADDRESS).when(mMockONSProfileConfig).getSMDPServerAddress(TEST_SUB_ID); + PersistableBundle config = new PersistableBundle(); + config.putInt(CarrierConfigManager.KEY_ESIM_DOWNLOAD_RETRY_BACKOFF_TIMER_SEC_INT, 1); + config.putInt(CarrierConfigManager.KEY_ESIM_MAX_DOWNLOAD_RETRY_ATTEMPTS_INT, 2); + config.putString(CarrierConfigManager.KEY_SMDP_SERVER_ADDRESS_STRING, TEST_SMDP_ADDRESS); + doReturn(config).when(mMockCarrierConfigManager).getConfigForSubId(TEST_SUB_ID); Runnable runnable = new Runnable() { @Override public void run() { - ONSProfileDownloader onsProfileDownloader = new ONSProfileDownloader(mContext, - mMockONSProfileConfig, mMockDownloadListener); + ONSProfileDownloader onsProfileDownloader = new ONSProfileDownloader(mMockContext, + mMockCarrierConfigManager, mMockEUICCManager, mMockONSProfileConfig, + mMockDownloadListener); Intent intent = new Intent(mContext, ONSProfileResultReceiver.class); - intent.setAction(ONSProfileResultReceiver.ACTION_ONS_RESULT_CALLBACK); + intent.setAction(ONSProfileDownloader.ACTION_ONS_ESIM_DOWNLOAD); intent.putExtra(Intent.EXTRA_COMPONENT_NAME, ONSProfileDownloader.class.getName()); intent.putExtra(ONSProfileDownloader.PARAM_PRIMARY_SUBID, TEST_SUB_ID); intent.putExtra(ONSProfileDownloader.PARAM_REQUEST_TYPE, ONSProfileDownloader.REQUEST_CODE_DOWNLOAD_SUB); - ONSProfileDownloader.onCallbackIntentReceived(intent, + onsProfileDownloader.onCallbackIntentReceived(intent, EuiccManager.EMBEDDED_SUBSCRIPTION_RESULT_ERROR); } }; @@ -207,12 +204,12 @@ public class ONSProfileDownloaderTest extends ONSBaseTest { Runnable runnable = new Runnable() { @Override public void run() { - ONSProfileDownloader onsProfileDownloader = - new ONSProfileDownloader(mMockContext, mMockONSProfileConfig, - mMockDownloadListener); + ONSProfileDownloader onsProfileDownloader = new ONSProfileDownloader(mMockContext, + mMockCarrierConfigManager, mMockEUICCManager, mMockONSProfileConfig, + mMockDownloadListener); Intent intent = new Intent(mContext, ONSProfileResultReceiver.class); - intent.setAction(ONSProfileResultReceiver.ACTION_ONS_RESULT_CALLBACK); + intent.setAction(ONSProfileDownloader.ACTION_ONS_ESIM_DOWNLOAD); intent.putExtra(Intent.EXTRA_COMPONENT_NAME, ONSProfileDownloader.class.getName()); intent.putExtra(ONSProfileDownloader.PARAM_PRIMARY_SUBID, TEST_SUB_ID); intent.putExtra(ONSProfileDownloader.PARAM_REQUEST_TYPE, @@ -222,7 +219,7 @@ public class ONSProfileDownloaderTest extends ONSBaseTest { intent.putExtra(EuiccManager.EXTRA_EMBEDDED_SUBSCRIPTION_ERROR_CODE, EuiccManager.ERROR_EUICC_INSUFFICIENT_MEMORY); - ONSProfileDownloader.onCallbackIntentReceived(intent, + onsProfileDownloader.onCallbackIntentReceived(intent, EuiccManager.EMBEDDED_SUBSCRIPTION_RESULT_RESOLVABLE_ERROR); } }; @@ -236,27 +233,32 @@ public class ONSProfileDownloaderTest extends ONSBaseTest { Log.e(TAG, e.getMessage()); } - verify(mMockONSProfileConfig).deleteOpportunisticSubscriptions(TEST_SUB_ID); + verify(mMockDownloadListener).onDownloadError( + ONSProfileDownloader.DownloadRetryOperationCode.ERR_MEMORY_FULL, + TEST_SUB_ID); workerThread.exit(); } @Test public void testDownloadFailureConnectionError() { - - doReturn(2).when(mMockONSProfileConfig).getDownloadRetryMaxAttemptsVal(TEST_SUB_ID); - doReturn(1).when(mMockONSProfileConfig).getDownloadRetryBackOffTimerVal(TEST_SUB_ID); - doReturn(mMockEUICCManager).when(mMockONSProfileConfig).getEuiccManager(); - doReturn(true).when(mMockONSProfileConfig).isInternetConnectionAvailable(); - doReturn(TEST_SMDP_ADDRESS).when(mMockONSProfileConfig).getSMDPServerAddress(TEST_SUB_ID); + PersistableBundle config = new PersistableBundle(); + config.putInt(CarrierConfigManager.KEY_ESIM_DOWNLOAD_RETRY_BACKOFF_TIMER_SEC_INT, 1); + config.putInt(CarrierConfigManager.KEY_ESIM_MAX_DOWNLOAD_RETRY_ATTEMPTS_INT, 2); + config.putString(CarrierConfigManager.KEY_SMDP_SERVER_ADDRESS_STRING, TEST_SMDP_ADDRESS); + doReturn(config).when(mMockCarrierConfigManager).getConfigForSubId(TEST_SUB_ID); + doNothing().when(mMockDownloadListener).onDownloadError( + ONSProfileDownloader.DownloadRetryOperationCode.ERR_RETRY_DOWNLOAD, + TEST_SUB_ID); Runnable runnable = new Runnable() { @Override public void run() { ONSProfileDownloader onsProfileDownloader = new ONSProfileDownloader(mContext, - mMockONSProfileConfig, mMockDownloadListener); + mMockCarrierConfigManager, mMockEUICCManager, mMockONSProfileConfig, + mMockDownloadListener); Intent intent = new Intent(mContext, ONSProfileResultReceiver.class); - intent.setAction(ONSProfileResultReceiver.ACTION_ONS_RESULT_CALLBACK); + intent.setAction(ONSProfileDownloader.ACTION_ONS_ESIM_DOWNLOAD); intent.putExtra(Intent.EXTRA_COMPONENT_NAME, ONSProfileDownloader.class.getName()); intent.putExtra(ONSProfileDownloader.PARAM_PRIMARY_SUBID, TEST_SUB_ID); intent.putExtra(ONSProfileDownloader.PARAM_REQUEST_TYPE, @@ -266,7 +268,7 @@ public class ONSProfileDownloaderTest extends ONSBaseTest { intent.putExtra(EuiccManager.EXTRA_EMBEDDED_SUBSCRIPTION_OPERATION_CODE, EuiccManager.OPERATION_DOWNLOAD); - ONSProfileDownloader.onCallbackIntentReceived(intent, + onsProfileDownloader.onCallbackIntentReceived(intent, EuiccManager.EMBEDDED_SUBSCRIPTION_RESULT_RESOLVABLE_ERROR); } }; @@ -286,31 +288,33 @@ public class ONSProfileDownloaderTest extends ONSBaseTest { String testActCode = DownloadableSubscription.forActivationCode(TEST_SMDP_ADDRESS) .getEncodedActivationCode(); - verify(mMockEUICCManager).downloadSubscription( - argThat((DownloadableSubscription ds) -> - ds.getEncodedActivationCode().equals(testActCode)), - eq(true), any(PendingIntent.class)); + verify(mMockDownloadListener).onDownloadError( + ONSProfileDownloader.DownloadRetryOperationCode.ERR_RETRY_DOWNLOAD, + TEST_SUB_ID); workerThread.exit(); } @Test public void testDownloadFailureTimeout() { - - doReturn(2).when(mMockONSProfileConfig).getDownloadRetryMaxAttemptsVal(TEST_SUB_ID); - doReturn(1).when(mMockONSProfileConfig).getDownloadRetryBackOffTimerVal(TEST_SUB_ID); - doReturn(mMockEUICCManager).when(mMockONSProfileConfig).getEuiccManager(); - doReturn(true).when(mMockONSProfileConfig).isInternetConnectionAvailable(); - doReturn(TEST_SMDP_ADDRESS).when(mMockONSProfileConfig).getSMDPServerAddress(TEST_SUB_ID); + PersistableBundle config = new PersistableBundle(); + config.putInt(CarrierConfigManager.KEY_ESIM_DOWNLOAD_RETRY_BACKOFF_TIMER_SEC_INT, 1); + config.putInt(CarrierConfigManager.KEY_ESIM_MAX_DOWNLOAD_RETRY_ATTEMPTS_INT, 2); + config.putString(CarrierConfigManager.KEY_SMDP_SERVER_ADDRESS_STRING, TEST_SMDP_ADDRESS); + doReturn(config).when(mMockCarrierConfigManager).getConfigForSubId(TEST_SUB_ID); + doNothing().when(mMockDownloadListener).onDownloadError( + ONSProfileDownloader.DownloadRetryOperationCode.ERR_RETRY_DOWNLOAD, + TEST_SUB_ID); Runnable runnable = new Runnable() { @Override public void run() { ONSProfileDownloader onsProfileDownloader = new ONSProfileDownloader(mContext, - mMockONSProfileConfig, mMockDownloadListener); + mMockCarrierConfigManager, mMockEUICCManager, mMockONSProfileConfig, + mMockDownloadListener); Intent intent = new Intent(mContext, ONSProfileResultReceiver.class); - intent.setAction(ONSProfileResultReceiver.ACTION_ONS_RESULT_CALLBACK); + intent.setAction(ONSProfileDownloader.ACTION_ONS_ESIM_DOWNLOAD); intent.putExtra(Intent.EXTRA_COMPONENT_NAME, ONSProfileDownloader.class.getName()); intent.putExtra(ONSProfileDownloader.PARAM_PRIMARY_SUBID, TEST_SUB_ID); intent.putExtra(ONSProfileDownloader.PARAM_REQUEST_TYPE, @@ -320,7 +324,7 @@ public class ONSProfileDownloaderTest extends ONSBaseTest { intent.putExtra(EuiccManager.EXTRA_EMBEDDED_SUBSCRIPTION_ERROR_CODE, EuiccManager.ERROR_TIME_OUT); - ONSProfileDownloader.onCallbackIntentReceived(intent, + onsProfileDownloader.onCallbackIntentReceived(intent, EuiccManager.EMBEDDED_SUBSCRIPTION_RESULT_RESOLVABLE_ERROR); } }; @@ -340,31 +344,33 @@ public class ONSProfileDownloaderTest extends ONSBaseTest { String testActCode = DownloadableSubscription.forActivationCode(TEST_SMDP_ADDRESS) .getEncodedActivationCode(); - verify(mMockEUICCManager).downloadSubscription( - argThat((DownloadableSubscription ds) -> - ds.getEncodedActivationCode().equals(testActCode)), - eq(true), any(PendingIntent.class)); + verify(mMockDownloadListener).onDownloadError( + ONSProfileDownloader.DownloadRetryOperationCode.ERR_RETRY_DOWNLOAD, + TEST_SUB_ID); workerThread.exit(); } @Test public void testDownloadFailureOperationBusy() { - - doReturn(2).when(mMockONSProfileConfig).getDownloadRetryMaxAttemptsVal(TEST_SUB_ID); - doReturn(1).when(mMockONSProfileConfig).getDownloadRetryBackOffTimerVal(TEST_SUB_ID); - doReturn(mMockEUICCManager).when(mMockONSProfileConfig).getEuiccManager(); - doReturn(true).when(mMockONSProfileConfig).isInternetConnectionAvailable(); - doReturn(TEST_SMDP_ADDRESS).when(mMockONSProfileConfig).getSMDPServerAddress(TEST_SUB_ID); + PersistableBundle config = new PersistableBundle(); + config.putInt(CarrierConfigManager.KEY_ESIM_DOWNLOAD_RETRY_BACKOFF_TIMER_SEC_INT, 1); + config.putInt(CarrierConfigManager.KEY_ESIM_MAX_DOWNLOAD_RETRY_ATTEMPTS_INT, 2); + config.putString(CarrierConfigManager.KEY_SMDP_SERVER_ADDRESS_STRING, TEST_SMDP_ADDRESS); + doReturn(config).when(mMockCarrierConfigManager).getConfigForSubId(TEST_SUB_ID); + doNothing().when(mMockDownloadListener).onDownloadError( + ONSProfileDownloader.DownloadRetryOperationCode.ERR_RETRY_DOWNLOAD, + TEST_SUB_ID); Runnable runnable = new Runnable() { @Override public void run() { ONSProfileDownloader onsProfileDownloader = new ONSProfileDownloader(mContext, - mMockONSProfileConfig, mMockDownloadListener); + mMockCarrierConfigManager, mMockEUICCManager, mMockONSProfileConfig, + mMockDownloadListener); Intent intent = new Intent(mContext, ONSProfileResultReceiver.class); - intent.setAction(ONSProfileResultReceiver.ACTION_ONS_RESULT_CALLBACK); + intent.setAction(ONSProfileDownloader.ACTION_ONS_ESIM_DOWNLOAD); intent.putExtra(Intent.EXTRA_COMPONENT_NAME, ONSProfileDownloader.class.getName()); intent.putExtra(ONSProfileDownloader.PARAM_PRIMARY_SUBID, TEST_SUB_ID); intent.putExtra(ONSProfileDownloader.PARAM_REQUEST_TYPE, @@ -374,7 +380,7 @@ public class ONSProfileDownloaderTest extends ONSBaseTest { intent.putExtra(EuiccManager.EXTRA_EMBEDDED_SUBSCRIPTION_ERROR_CODE, EuiccManager.ERROR_OPERATION_BUSY); - ONSProfileDownloader.onCallbackIntentReceived(intent, + onsProfileDownloader.onCallbackIntentReceived(intent, EuiccManager.EMBEDDED_SUBSCRIPTION_RESULT_RESOLVABLE_ERROR); } }; @@ -394,31 +400,33 @@ public class ONSProfileDownloaderTest extends ONSBaseTest { String testActCode = DownloadableSubscription.forActivationCode(TEST_SMDP_ADDRESS) .getEncodedActivationCode(); - verify(mMockEUICCManager).downloadSubscription( - argThat((DownloadableSubscription ds) -> - ds.getEncodedActivationCode().equals(testActCode)), - eq(true), any(PendingIntent.class)); + verify(mMockDownloadListener).onDownloadError( + ONSProfileDownloader.DownloadRetryOperationCode.ERR_RETRY_DOWNLOAD, + TEST_SUB_ID); workerThread.exit(); } @Test public void testDownloadFailureInvalidResponse() { - - doReturn(2).when(mMockONSProfileConfig).getDownloadRetryMaxAttemptsVal(TEST_SUB_ID); - doReturn(1).when(mMockONSProfileConfig).getDownloadRetryBackOffTimerVal(TEST_SUB_ID); - doReturn(mMockEUICCManager).when(mMockONSProfileConfig).getEuiccManager(); - doReturn(true).when(mMockONSProfileConfig).isInternetConnectionAvailable(); - doReturn(TEST_SMDP_ADDRESS).when(mMockONSProfileConfig).getSMDPServerAddress(TEST_SUB_ID); + PersistableBundle config = new PersistableBundle(); + config.putInt(CarrierConfigManager.KEY_ESIM_DOWNLOAD_RETRY_BACKOFF_TIMER_SEC_INT, 1); + config.putInt(CarrierConfigManager.KEY_ESIM_MAX_DOWNLOAD_RETRY_ATTEMPTS_INT, 2); + config.putString(CarrierConfigManager.KEY_SMDP_SERVER_ADDRESS_STRING, TEST_SMDP_ADDRESS); + doReturn(config).when(mMockCarrierConfigManager).getConfigForSubId(TEST_SUB_ID); + doNothing().when(mMockDownloadListener).onDownloadError( + ONSProfileDownloader.DownloadRetryOperationCode.ERR_RETRY_DOWNLOAD, + TEST_SUB_ID); Runnable runnable = new Runnable() { @Override public void run() { ONSProfileDownloader onsProfileDownloader = new ONSProfileDownloader(mContext, - mMockONSProfileConfig, mMockDownloadListener); + mMockCarrierConfigManager, mMockEUICCManager, mMockONSProfileConfig, + mMockDownloadListener); Intent intent = new Intent(mContext, ONSProfileResultReceiver.class); - intent.setAction(ONSProfileResultReceiver.ACTION_ONS_RESULT_CALLBACK); + intent.setAction(ONSProfileDownloader.ACTION_ONS_ESIM_DOWNLOAD); intent.putExtra(Intent.EXTRA_COMPONENT_NAME, ONSProfileDownloader.class.getName()); intent.putExtra(ONSProfileDownloader.PARAM_PRIMARY_SUBID, TEST_SUB_ID); intent.putExtra(ONSProfileDownloader.PARAM_REQUEST_TYPE, @@ -428,7 +436,7 @@ public class ONSProfileDownloaderTest extends ONSBaseTest { intent.putExtra(EuiccManager.EXTRA_EMBEDDED_SUBSCRIPTION_ERROR_CODE, EuiccManager.ERROR_INVALID_RESPONSE); - ONSProfileDownloader.onCallbackIntentReceived(intent, + onsProfileDownloader.onCallbackIntentReceived(intent, EuiccManager.EMBEDDED_SUBSCRIPTION_RESULT_ERROR); } }; @@ -442,61 +450,9 @@ public class ONSProfileDownloaderTest extends ONSBaseTest { e.printStackTrace(); } - verifyZeroInteractions(mMockEUICCManager); - workerThread.exit(); - } - - @Test - public void testCalculateBackoffDelay() { - final Object lock = new Object(); - - Runnable runnable = new Runnable() { - @Override - public void run() { - ONSProfileDownloader onsProfileDownloader = new ONSProfileDownloader(mContext, - mMockONSProfileConfig, mMockDownloadListener); - ONSProfileDownloader.DownloadHandler downloadHandler = - onsProfileDownloader.new DownloadHandler(); - - int delay = downloadHandler.calculateBackoffDelay(1, 1) / 1000; - assertEquals(true, (delay >= 1 && delay <= 2)); - - Log.i(TAG, "calculateBackoffDelay(2, 1)"); - delay = downloadHandler.calculateBackoffDelay(2, 1) / 1000; - assertEquals(true, (delay >= 1 && delay < 4)); - - delay = downloadHandler.calculateBackoffDelay(3, 1) / 1000; - assertEquals(true, (delay >= 1 && delay < 8)); - - delay = downloadHandler.calculateBackoffDelay(4, 1) / 1000; - assertEquals(true, (delay >= 1 && delay < 16)); - - delay = downloadHandler.calculateBackoffDelay(1, 2) / 1000; - assertEquals(true, (delay >= 1 && delay <= 4)); - - delay = downloadHandler.calculateBackoffDelay(1, 3) / 1000; - assertEquals(true, (delay >= 1 && delay <= 6)); - - delay = downloadHandler.calculateBackoffDelay(2, 2) / 1000; - assertEquals(true, (delay >= 2 && delay < 8)); - - synchronized (lock) { - lock.notifyAll(); - } - } - }; - - WorkerThread workerThread = new WorkerThread(runnable); - workerThread.start(); - - synchronized (lock) { - try { - lock.wait(); - } catch (Exception e) { - Log.e(TAG, e.getLocalizedMessage()); - } - } - + verify(mMockDownloadListener).onDownloadError( + ONSProfileDownloader.DownloadRetryOperationCode.ERR_UNRESOLVABLE, + TEST_SUB_ID); workerThread.exit(); } @@ -507,58 +463,60 @@ public class ONSProfileDownloaderTest extends ONSBaseTest { Runnable runnable = new Runnable() { @Override public void run() { - ONSProfileDownloader onsProfileDownloader = new ONSProfileDownloader(mContext, - mMockONSProfileConfig, mMockDownloadListener); + ONSProfileDownloader onsProfileDownloader = new ONSProfileDownloader(mMockContext, + mMockCarrierConfigManager, mMockEUICCManager, mMockONSProfileConfig, + mMockDownloadListener); + ONSProfileDownloader.DownloadHandler downloadHandler = onsProfileDownloader.new DownloadHandler(); ONSProfileDownloader.DownloadRetryOperationCode res = - downloadHandler.getOperationCode( + downloadHandler.mapDownloaderErrorCode( EuiccManager.EMBEDDED_SUBSCRIPTION_RESULT_OK, 0, EuiccManager.OPERATION_DOWNLOAD, 0); assertEquals( ONSProfileDownloader.DownloadRetryOperationCode.DOWNLOAD_SUCCESSFUL, res); - res = downloadHandler.getOperationCode( + res = downloadHandler.mapDownloaderErrorCode( EuiccManager.EMBEDDED_SUBSCRIPTION_RESULT_RESOLVABLE_ERROR, 0, EuiccManager.OPERATION_DOWNLOAD, EuiccManager.ERROR_EUICC_INSUFFICIENT_MEMORY); assertEquals(ONSProfileDownloader.DownloadRetryOperationCode - .DELETE_INACTIVE_OPP_ESIM_IF_EXISTS, res); + .ERR_MEMORY_FULL, res); - res = downloadHandler.getOperationCode( + res = downloadHandler.mapDownloaderErrorCode( EuiccManager.EMBEDDED_SUBSCRIPTION_RESULT_RESOLVABLE_ERROR, 0, EuiccManager.OPERATION_DOWNLOAD, EuiccManager.ERROR_TIME_OUT); assertEquals(ONSProfileDownloader.DownloadRetryOperationCode - .RETRY_AFTER_BACKOFF_TIME, res); + .ERR_RETRY_DOWNLOAD, res); - res = downloadHandler.getOperationCode( + res = downloadHandler.mapDownloaderErrorCode( EuiccManager.EMBEDDED_SUBSCRIPTION_RESULT_RESOLVABLE_ERROR, 0, EuiccManager.OPERATION_DOWNLOAD, EuiccManager.ERROR_CONNECTION_ERROR); assertEquals(ONSProfileDownloader.DownloadRetryOperationCode - .RETRY_AFTER_BACKOFF_TIME, res); + .ERR_RETRY_DOWNLOAD, res); - res = downloadHandler.getOperationCode( + res = downloadHandler.mapDownloaderErrorCode( EuiccManager.EMBEDDED_SUBSCRIPTION_RESULT_RESOLVABLE_ERROR, 0, EuiccManager.OPERATION_DOWNLOAD, EuiccManager.ERROR_INVALID_RESPONSE); assertEquals(ONSProfileDownloader.DownloadRetryOperationCode - .STOP_RETRY_UNTIL_SIM_STATE_CHANGE, res); + .ERR_UNRESOLVABLE, res); - res = downloadHandler.getOperationCode( + res = downloadHandler.mapDownloaderErrorCode( EuiccManager.EMBEDDED_SUBSCRIPTION_RESULT_ERROR, 0, EuiccManager.OPERATION_DOWNLOAD, EuiccManager.ERROR_INVALID_RESPONSE); assertEquals(ONSProfileDownloader.DownloadRetryOperationCode - .STOP_RETRY_UNTIL_SIM_STATE_CHANGE, res); + .ERR_UNRESOLVABLE, res); - res = downloadHandler.getOperationCode( + res = downloadHandler.mapDownloaderErrorCode( EuiccManager.EMBEDDED_SUBSCRIPTION_RESULT_ERROR, 0xA810048, EuiccManager.OPERATION_SMDX_SUBJECT_REASON_CODE, 0); assertEquals(ONSProfileDownloader.DownloadRetryOperationCode - .DELETE_INACTIVE_OPP_ESIM_IF_EXISTS, res); + .ERR_MEMORY_FULL, res); synchronized (lock) { lock.notifyAll(); |