diff options
author | Android Build Coastguard Worker <android-build-coastguard-worker@google.com> | 2023-07-07 01:26:36 +0000 |
---|---|---|
committer | Android Build Coastguard Worker <android-build-coastguard-worker@google.com> | 2023-07-07 01:26:36 +0000 |
commit | 4b0cd89280695b4aa5b527534e374d098a352ff3 (patch) | |
tree | 6ab377c21a9227c077fe7707c570cc95a6f93968 | |
parent | 60f33a6fe4abdd20675c96340016197c52d8f631 (diff) | |
parent | 8eaedf7cc2d20d4f81a967c6a4af12aec1bfff7e (diff) | |
download | AlternativeNetworkAccess-android14-mainline-networking-release.tar.gz |
Snap for 10447354 from 8eaedf7cc2d20d4f81a967c6a4af12aec1bfff7e to mainline-networking-releaseaml_net_341610030aml_net_341510050aml_net_341510000aml_net_341411030aml_net_341311010aml_net_341310020aml_net_341014000aml_net_340913000android14-mainline-networking-release
Change-Id: Id2c084bd08c60935483bbfbc05c12efe1a365ae0
20 files changed, 1707 insertions, 306 deletions
@@ -27,10 +27,20 @@ android_app { "telephony-common", "app-compat-annotations", ], - srcs: ["src/**/*.java"], + srcs: [ + "src/**/*.java", + ":statslog-ons-java-gen", + ], aaptflags: ["--auto-add-overlay"], certificate: "platform", optimize: { proguard_flags_files: ["proguard.flags"], }, } + +genrule { + name: "statslog-ons-java-gen", + tools: ["stats-log-api-gen"], + cmd: "$(location stats-log-api-gen) --java $(out) --module ons --javaPackage com.android.ons --javaClass OnsStatsLog", + out: ["com/android/ons/OnsStatsLog.java"], +} diff --git a/AndroidManifest.xml b/AndroidManifest.xml index 0141961..fb2346f 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -21,8 +21,8 @@ android:process="com.android.phone" android:sharedUserId="android.uid.phone"> - <protected-broadcast android:name="com.android.ons.action.DOWNLOAD" /> - <protected-broadcast android:name="com.android.ons.action.CONFIG" /> + <protected-broadcast android:name="com.android.ons.action.ESIM_DOWNLOAD" /> + <protected-broadcast android:name="com.android.ons.action.ESIM_CONFIG" /> <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" /> <uses-permission android:name="android.permission.READ_PHONE_STATE"/> @@ -1,6 +1 @@ -# Default code reviewers picked from top 3 or more developers. -# Please update this list if you find better candidates. -sasindran@google.com -rgreenwalt@google.com -amruthr@google.com -jacknudelman@google.com
\ No newline at end of file +file:platform/frameworks/opt/telephony:/OWNERS diff --git a/PREUPLOAD.cfg b/PREUPLOAD.cfg index de2615a..de4cf97 100644 --- a/PREUPLOAD.cfg +++ b/PREUPLOAD.cfg @@ -20,14 +20,4 @@ bpfmt = -d [Hook Scripts] checkstyle_hook = ${REPO_ROOT}/prebuilts/checkstyle/checkstyle.py --sha ${PREUPLOAD_COMMIT} -strings_lint_hook = ${REPO_ROOT}/frameworks/base/tools/stringslint/stringslint_sha.sh ${PREUPLOAD_COMMIT} - -hidden_api_txt_checksorted_hook = ${REPO_ROOT}/tools/platform-compat/hiddenapi/checksorted_sha.sh ${PREUPLOAD_COMMIT} ${REPO_ROOT} - -hidden_api_txt_exclude_hook = ${REPO_ROOT}/frameworks/base/tools/hiddenapi/exclude.sh ${PREUPLOAD_COMMIT} ${REPO_ROOT} - ktlint_hook = ${REPO_ROOT}/prebuilts/ktlint/ktlint.py -f ${PREUPLOAD_FILES} - -owners_hook = ${REPO_ROOT}/frameworks/base/tools/aosp/aosp_sha.sh ${PREUPLOAD_COMMIT} "OWNERS$" - -shell_hook = ${REPO_ROOT}/frameworks/base/tools/aosp/aosp_sha.sh ${PREUPLOAD_COMMIT} "^packages/Shell/"
\ No newline at end of file diff --git a/src/com/android/ons/ONSNetworkScanCtlr.java b/src/com/android/ons/ONSNetworkScanCtlr.java index 97ef770..e14148f 100644 --- a/src/com/android/ons/ONSNetworkScanCtlr.java +++ b/src/com/android/ons/ONSNetworkScanCtlr.java @@ -40,10 +40,10 @@ import com.android.telephony.Rlog; import java.util.ArrayList; import java.util.Arrays; -import java.util.stream.Collectors; import java.util.List; import java.util.Set; import java.util.concurrent.TimeUnit; +import java.util.stream.Collectors; /** * Network Scan controller class which will scan for the specific bands as requested and @@ -266,11 +266,16 @@ public class ONSNetworkScanCtlr { } /* get mcc mnc from cell info if the cell is for LTE */ - private String getMccMnc(CellInfo cellInfo) { + @VisibleForTesting + protected String getMccMnc(CellInfo cellInfo) { if (cellInfo instanceof CellInfoLte) { return ((CellInfoLte) cellInfo).getCellIdentity().getMccString() + ((CellInfoLte) cellInfo).getCellIdentity().getMncString(); } + else if (cellInfo instanceof CellInfoNr) { + return ((CellInfoNr) cellInfo).getCellIdentity().getMccString() + + ((CellInfoNr) cellInfo).getCellIdentity().getMncString(); + } return null; } diff --git a/src/com/android/ons/ONSProfileActivator.java b/src/com/android/ons/ONSProfileActivator.java index 5325b8f..05228b8 100644 --- a/src/com/android/ons/ONSProfileActivator.java +++ b/src/com/android/ons/ONSProfileActivator.java @@ -35,6 +35,7 @@ import android.telephony.euicc.EuiccManager; import android.util.Log; import com.android.internal.annotations.VisibleForTesting; +import com.android.ons.ONSProfileDownloader.DownloadRetryResultCode; import java.util.ArrayList; import java.util.List; @@ -48,8 +49,6 @@ import java.util.Random; public class ONSProfileActivator implements ONSProfileConfigurator.ONSProfConfigListener, ONSProfileDownloader.IONSProfileDownloaderListener { - public static final String ACTION_CARRIER_CONFIG_CHANGED = - "android.telephony.action.CARRIER_CONFIG_CHANGED"; private static final String TAG = ONSProfileActivator.class.getName(); private final Context mContext; private final SubscriptionManager mSubManager; @@ -59,13 +58,14 @@ public class ONSProfileActivator implements ONSProfileConfigurator.ONSProfConfig private final ONSProfileConfigurator mONSProfileConfig; private final ONSProfileDownloader mONSProfileDownloader; private final ConnectivityManager mConnectivityManager; + private final ONSStats mONSStats; @VisibleForTesting protected boolean mIsInternetConnAvailable = false; @VisibleForTesting protected boolean mRetryDownloadWhenNWConnected = false; - private int mDownloadRetryCount = 0; + @VisibleForTesting protected int mDownloadRetryCount = 0; @VisibleForTesting protected static final int REQUEST_CODE_DOWNLOAD_RETRY = 2; - public ONSProfileActivator(Context context) { + public ONSProfileActivator(Context context, ONSStats onsStats) { mContext = context; mSubManager = mContext.getSystemService(SubscriptionManager.class); mTelephonyManager = mContext.getSystemService(TelephonyManager.class); @@ -78,7 +78,7 @@ public class ONSProfileActivator implements ONSProfileConfigurator.ONSProfConfig //Monitor internet connection. mConnectivityManager = context.getSystemService(ConnectivityManager.class); - + mONSStats = onsStats; NetworkRequest request = new NetworkRequest.Builder().addCapability( NetworkCapabilities.NET_CAPABILITY_VALIDATED).build(); mConnectivityManager.registerNetworkCallback(request, new NetworkCallback()); @@ -92,7 +92,7 @@ public class ONSProfileActivator implements ONSProfileConfigurator.ONSProfConfig TelephonyManager telephonyManager, CarrierConfigManager carrierConfigMgr, EuiccManager euiccManager, ConnectivityManager connManager, ONSProfileConfigurator onsProfileConfigurator, - ONSProfileDownloader onsProfileDownloader) { + ONSProfileDownloader onsProfileDownloader, ONSStats onsStats) { mContext = mockContext; mSubManager = subscriptionManager; mTelephonyManager = telephonyManager; @@ -101,6 +101,7 @@ public class ONSProfileActivator implements ONSProfileConfigurator.ONSProfConfig mConnectivityManager = connManager; mONSProfileConfig = onsProfileConfigurator; mONSProfileDownloader = onsProfileDownloader; + mONSStats = onsStats; } ONSProfileConfigurator getONSProfileConfigurator() { @@ -116,7 +117,9 @@ public class ONSProfileActivator implements ONSProfileConfigurator.ONSProfConfig public void handleMessage(Message msg) { switch (msg.what) { case REQUEST_CODE_DOWNLOAD_RETRY: { - provisionCBRS(); + Result res = provisionCBRS(); + Log.d(TAG, res.toString()); + mONSStats.logEvent(new ONSStatsInfo().setProvisioningResult(res)); } break; } @@ -127,19 +130,24 @@ public class ONSProfileActivator implements ONSProfileConfigurator.ONSProfConfig * Called when SIM state changes. Triggers CBRS Auto provisioning. */ public Result handleCarrierConfigChange() { - /*final int simState = mTelephonyManager.getSimState(); - if (simState != TelephonyManager.SIM_STATE_READY) { - return Result.ERR_SIM_NOT_READY; - }*/ - Result res = provisionCBRS(); Log.d(TAG, res.toString()); + mONSStats.logEvent(new ONSStatsInfo().setProvisioningResult(res)); + + // Reset mDownloadRetryCount as carrier config change event is received. Either new SIM card + // is inserted or carrier config values are updated. + if (res == Result.DOWNLOAD_REQUESTED || res == Result.SUCCESS) { + mDownloadRetryCount = 0; + } + return res; } @Override public void onOppSubscriptionDeleted(int pSIMId) { - provisionCBRS(); + Result res = provisionCBRS(); + Log.d(TAG, res.toString()); + mONSStats.logEvent(new ONSStatsInfo().setProvisioningResult(res)); } /** @@ -165,12 +173,13 @@ public class ONSProfileActivator implements ONSProfileConfigurator.ONSProfConfig //Check the number of active subscriptions. List<SubscriptionInfo> activeSubInfos = mSubManager.getActiveSubscriptionInfoList(); + if (activeSubInfos == null || activeSubInfos.size() <= 0) { + return Result.ERR_NO_SIM_INSERTED; + } int activeSubCount = activeSubInfos.size(); Log.d(TAG, "Active subscription count:" + activeSubCount); - if (activeSubCount <= 0) { - return Result.ERR_NO_SIM_INSERTED; - } else if (activeSubCount == 1) { + if (activeSubCount == 1) { SubscriptionInfo pSubInfo = activeSubInfos.get(0); if (pSubInfo.isOpportunistic()) { //Only one SIM is active and its opportunistic SIM. @@ -273,8 +282,16 @@ public class ONSProfileActivator implements ONSProfileConfigurator.ONSProfConfig } //Opportunistic subscription not found. Trigger Download. - mONSProfileDownloader.downloadProfile(primaryCBRSSubInfo.getSubscriptionId()); - return Result.SUCCESS; + ONSProfileDownloader.DownloadProfileResult res = mONSProfileDownloader.downloadProfile( + primaryCBRSSubInfo.getSubscriptionId()); + + switch (res) { + case DUPLICATE_REQUEST: return Result.ERR_DUPLICATE_DOWNLOAD_REQUEST; + case INVALID_SMDP_ADDRESS: return Result.ERR_INVALID_CARRIER_CONFIG; + case SUCCESS: return Result.DOWNLOAD_REQUESTED; + } + + return Result.ERR_UNKNOWN; } @Override @@ -284,23 +301,37 @@ public class ONSProfileActivator implements ONSProfileConfigurator.ONSProfConfig primarySubId); if (opportunisticESIM == null) { Log.e(TAG, "Downloaded Opportunistic eSIM not found. Unable to group with pSIM"); + mONSStats.logEvent(new ONSStatsInfo() + .setProvisioningResult(Result.ERR_DOWNLOADED_ESIM_NOT_FOUND) + .setPrimarySimSubId(primarySubId) + .setWifiConnected(isWiFiConnected())); return; } SubscriptionInfo pSIMSubInfo = mSubManager.getActiveSubscriptionInfo(primarySubId); if (pSIMSubInfo != null) { + // Group with same Primary SIM for which eSIM is downloaded. mONSProfileConfig.groupWithPSIMAndSetOpportunistic( opportunisticESIM, pSIMSubInfo.getGroupUuid()); Log.d(TAG, "eSIM downloaded and configured successfully"); + mONSStats.logEvent(new ONSStatsInfo() + .setProvisioningResult(Result.SUCCESS) + .setRetryCount(mDownloadRetryCount) + .setWifiConnected(isWiFiConnected())); } else { Log.d(TAG, "ESIM downloaded but pSIM is not active or removed"); + mONSStats.logEvent(new ONSStatsInfo() + .setProvisioningResult(Result.ERR_PSIM_NOT_FOUND) + .setOppSimCarrierId(opportunisticESIM.getCarrierId()) + .setWifiConnected(isWiFiConnected())); } } @Override - public void onDownloadError(ONSProfileDownloader.DownloadRetryOperationCode operationCode, - int pSIMSubId) { - switch (operationCode) { + public void onDownloadError(int pSIMSubId, DownloadRetryResultCode resultCode, + int detailedErrorCode) { + boolean logStats = true; + switch (resultCode) { case ERR_MEMORY_FULL: { //eUICC Memory full occurred while downloading opportunistic eSIM. @@ -340,34 +371,48 @@ public class ONSProfileActivator implements ONSProfileConfigurator.ONSProfConfig break; case ERR_RETRY_DOWNLOAD: { - startBackoffTimer(pSIMSubId, mDownloadRetryCount); + if (startBackoffTimer(pSIMSubId)) { + // do not log the atom if download retry has not reached max limit. + logStats = false; + } } break; - - case ERR_UNRESOLVABLE: { - //Stop download until SIM change or device reboot. + default: { + // Stop download until SIM change or device reboot. + Log.e(TAG, "Download failed with cause=" + resultCode); } } + if (logStats) { + mONSStats.logEvent(new ONSStatsInfo() + .setDownloadResult(resultCode) + .setPrimarySimSubId(pSIMSubId) + .setRetryCount(mDownloadRetryCount) + .setDetailedErrCode(detailedErrorCode) + .setWifiConnected(isWiFiConnected())); + } } /** * 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 + * + * @param pSIMSubId Primary Subscription ID + * @return true if backoff timer starts; otherwise false. */ @VisibleForTesting - protected void startBackoffTimer(int pSIMSubId, int retryCount) { + protected boolean startBackoffTimer(int pSIMSubId) { //retry logic - retryCount++; - Log.e(TAG, "Download retry count :" + retryCount); - if (retryCount >= getDownloadRetryMaxAttemptsVal(pSIMSubId)) { + mDownloadRetryCount++; + Log.e(TAG, "Download retry count :" + mDownloadRetryCount); + + //Stop download retry if number of retries exceeded max configured value. + if (mDownloadRetryCount > getDownloadRetryMaxAttemptsVal(pSIMSubId)) { Log.e(TAG, "Max download retry attempted. Stopping retry"); - return; + return false; } int backoffTimerVal = getDownloadRetryBackOffTimerVal(pSIMSubId); - int delay = calculateBackoffDelay(retryCount, backoffTimerVal); + int delay = calculateBackoffDelay(mDownloadRetryCount, backoffTimerVal); Message retryMsg = new Message(); retryMsg.what = REQUEST_CODE_DOWNLOAD_RETRY; @@ -375,6 +420,7 @@ public class ONSProfileActivator implements ONSProfileConfigurator.ONSProfConfig mHandler.sendMessageDelayed(retryMsg, delay); Log.d(TAG, "Download failed. Retry after :" + delay + "MilliSecs"); + return true; } @VisibleForTesting @@ -405,7 +451,7 @@ public class ONSProfileActivator implements ONSProfileConfigurator.ONSProfConfig * attempts will not be made until next device reboot. * * @param subscriptionId subscription Id of the primary SIM. - * @return + * @return integer value for maximum allowed retry attempts. */ private int getDownloadRetryMaxAttemptsVal(int subscriptionId) { PersistableBundle config = mCarrierConfigMgr.getConfigForSubId(subscriptionId); @@ -506,7 +552,9 @@ public class ONSProfileActivator implements ONSProfileConfigurator.ONSProfConfig Log.d(TAG, "Internet connection available"); mIsInternetConnAvailable = true; if (mRetryDownloadWhenNWConnected) { - provisionCBRS(); + Result res = provisionCBRS(); + Log.d(TAG, res.toString()); + mONSStats.logEvent(new ONSStatsInfo().setProvisioningResult(res)); } } @@ -518,20 +566,28 @@ public class ONSProfileActivator implements ONSProfileConfigurator.ONSProfConfig } } + /** + * Enum to map the results of the CBRS provisioning. The order of the defined enums must be kept + * intact and new entries should be appended at the end of the list. + */ public enum Result { SUCCESS, + DOWNLOAD_REQUESTED, ERR_SWITCHING_TO_DUAL_SIM_MODE, ERR_AUTO_PROVISIONING_DISABLED, ERR_ESIM_NOT_SUPPORTED, ERR_MULTISIM_NOT_SUPPORTED, ERR_CARRIER_DOESNT_SUPPORT_CBRS, - ERR_DUAL_ACTIVE_SUBSCRIPTIONS,//Both the slots have primary SIMs + ERR_DUAL_ACTIVE_SUBSCRIPTIONS, ERR_NO_SIM_INSERTED, ERR_SINGLE_ACTIVE_OPPORTUNISTIC_SIM, ERR_CANNOT_SWITCH_TO_DUAL_SIM_MODE, - ERR_SIM_NOT_READY, ERR_WAITING_FOR_INTERNET_CONNECTION, ERR_WAITING_FOR_WIFI_CONNECTION, + ERR_DUPLICATE_DOWNLOAD_REQUEST, + ERR_INVALID_CARRIER_CONFIG, + ERR_DOWNLOADED_ESIM_NOT_FOUND, + ERR_PSIM_NOT_FOUND, ERR_UNKNOWN; } } diff --git a/src/com/android/ons/ONSProfileConfigurator.java b/src/com/android/ons/ONSProfileConfigurator.java index 6026a95..84bcdad 100644 --- a/src/com/android/ons/ONSProfileConfigurator.java +++ b/src/com/android/ons/ONSProfileConfigurator.java @@ -127,10 +127,15 @@ public class ONSProfileConfigurator { @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()); - mSubscriptionManager.addSubscriptionsIntoGroup(subList, groupUuid); + if (groupUuid != null && groupUuid.equals(opportunisticESIM.getGroupUuid())) { + Log.d(TAG, "opportunistc eSIM and CBRS pSIM already grouped"); + } else { + Log.d(TAG, "Grouping opportunistc eSIM and CBRS pSIM"); + ArrayList<Integer> subList = new ArrayList<>(); + subList.add(opportunisticESIM.getSubscriptionId()); + mSubscriptionManager.addSubscriptionsIntoGroup(subList, groupUuid); + } + if (!opportunisticESIM.isOpportunistic()) { Log.d(TAG, "set Opportunistic to TRUE"); mSubscriptionManager.setOpportunistic(true, @@ -151,7 +156,7 @@ public class ONSProfileConfigurator { PendingIntent callbackIntent = PendingIntent.getBroadcast(mContext, REQUEST_CODE_ACTIVATE_SUB, intent, PendingIntent.FLAG_IMMUTABLE); Log.d(TAG, "Activate oppSub request sent to SubManager"); - mSubscriptionManager.switchToSubscription(subId, callbackIntent); + mEuiccManager.switchToSubscription(subId, callbackIntent); } /** @@ -253,6 +258,10 @@ public class ONSProfileConfigurator { //Get the list of active subscriptions List<SubscriptionInfo> availSubInfoList = mSubscriptionManager .getAvailableSubscriptionInfoList(); + if (availSubInfoList == null) { + Log.e(TAG, "getAvailableSubscriptionInfoList returned null"); + return null; + } Log.d(TAG, "Available subscriptions: " + availSubInfoList.size()); //Get the list of opportunistic carrier-ids list from carrier config. @@ -264,8 +273,12 @@ public class ONSProfileConfigurator { return null; } - ParcelUuid pSIMSubGroupId = mSubscriptionManager.getActiveSubscriptionInfo(pSIMId) - .getGroupUuid(); + SubscriptionInfo subscriptionInfo = mSubscriptionManager.getActiveSubscriptionInfo(pSIMId); + if (subscriptionInfo == null) { + Log.e(TAG, "getActiveSubscriptionInfo returned null for: " + pSIMId); + return null; + } + ParcelUuid pSIMSubGroupId = subscriptionInfo.getGroupUuid(); for (SubscriptionInfo subInfo : availSubInfoList) { if (subInfo.getSubscriptionId() != pSIMId) { for (int carrId : oppCarrierIdArr) { diff --git a/src/com/android/ons/ONSProfileDownloader.java b/src/com/android/ons/ONSProfileDownloader.java index f83aab9..11c6237 100644 --- a/src/com/android/ons/ONSProfileDownloader.java +++ b/src/com/android/ons/ONSProfileDownloader.java @@ -37,7 +37,7 @@ public class ONSProfileDownloader { interface IONSProfileDownloaderListener { void onDownloadComplete(int primarySubId); - void onDownloadError(DownloadRetryOperationCode operationCode, int pSIMSubId); + void onDownloadError(int pSIMSubId, DownloadRetryResultCode resultCode, int detailErrCode); } private static final String TAG = ONSProfileDownloader.class.getName(); @@ -54,14 +54,16 @@ public class ONSProfileDownloader { private final ONSProfileConfigurator mONSProfileConfig; private IONSProfileDownloaderListener mListener; - @VisibleForTesting - protected enum DownloadRetryOperationCode{ + // Subscription Id of the CBRS PSIM for which opportunistic eSIM is being downloaded. Used to + // ignore duplicate download requests when download is in progress. + private int mDownloadingPSimSubId; + + protected enum DownloadRetryResultCode { DOWNLOAD_SUCCESSFUL, ERR_UNRESOLVABLE, ERR_MEMORY_FULL, ERR_INSTALL_ESIM_PROFILE_FAILED, - ERR_RETRY_DOWNLOAD, - BACKOFF_TIMER_EXPIRED + ERR_RETRY_DOWNLOAD }; public ONSProfileDownloader(Context context, CarrierConfigManager carrierConfigManager, @@ -85,8 +87,16 @@ public class ONSProfileDownloader { @Override public void handleMessage(Message msg) { switch (msg.what) { - case REQUEST_CODE_DOWNLOAD_SUB: { //arg1 -> ResultCode + // Received Response for download request. REQUEST_CODE_DOWNLOAD_SUB was sent to LPA + // as part of request intent. + case REQUEST_CODE_DOWNLOAD_SUB: { Log.d(TAG, "REQUEST_CODE_DOWNLOAD_SUB callback received"); + + //Clear downloading subscription flag. Indicates no download in progress. + synchronized (this) { + mDownloadingPSimSubId = -1; + } + int pSIMSubId = ((Intent) msg.obj).getIntExtra(PARAM_PRIMARY_SUBID, 0); int detailedErrCode = ((Intent) msg.obj).getIntExtra( EuiccManager.EXTRA_EMBEDDED_SUBSCRIPTION_DETAILED_CODE, 0); @@ -99,23 +109,23 @@ public class ONSProfileDownloader { Log.d(TAG, "Operation Code : " + operationCode); Log.d(TAG, "Error Code : " + errorCode); - DownloadRetryOperationCode opCode = mapDownloaderErrorCode(msg.arg1, + DownloadRetryResultCode resultCode = mapDownloaderErrorCode(msg.arg1, detailedErrCode, operationCode, errorCode); - Log.d(TAG, "DownloadRetryOperationCode: " + opCode); + Log.d(TAG, "DownloadRetryResultCode: " + resultCode); - switch (opCode) { + switch (resultCode) { case DOWNLOAD_SUCCESSFUL: mListener.onDownloadComplete(pSIMSubId); break; case ERR_UNRESOLVABLE: - mListener.onDownloadError(opCode, pSIMSubId); + mListener.onDownloadError(pSIMSubId, resultCode, detailedErrCode); Log.e(TAG, "Unresolvable download error: " + getUnresolvableErrorDescription(errorCode)); break; default: - mListener.onDownloadError(opCode, pSIMSubId); + mListener.onDownloadError(pSIMSubId, resultCode, detailedErrCode); break; } } @@ -124,7 +134,7 @@ public class ONSProfileDownloader { } @VisibleForTesting - protected DownloadRetryOperationCode mapDownloaderErrorCode(int resultCode, + protected DownloadRetryResultCode mapDownloaderErrorCode(int resultCode, int detailedErrCode, int operationCode, int errorCode) { @@ -138,17 +148,17 @@ 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.ERR_MEMORY_FULL; + return DownloadRetryResultCode.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.ERR_RETRY_DOWNLOAD; + return DownloadRetryResultCode.ERR_RETRY_DOWNLOAD; } //All other errors are unresolvable or retry after SIM State Change - return DownloadRetryOperationCode.ERR_UNRESOLVABLE; + return DownloadRetryResultCode.ERR_UNRESOLVABLE; } @@ -156,29 +166,29 @@ public class ONSProfileDownloader { //Success Cases case EuiccManager.EMBEDDED_SUBSCRIPTION_RESULT_OK: { - return DownloadRetryOperationCode.DOWNLOAD_SUCCESSFUL; + return DownloadRetryResultCode.DOWNLOAD_SUCCESSFUL; } //Low eUICC memory cases case EuiccManager.ERROR_EUICC_INSUFFICIENT_MEMORY: { Log.d(TAG, "Download ERR: EUICC_INSUFFICIENT_MEMORY"); - return DownloadRetryOperationCode.ERR_MEMORY_FULL; + return DownloadRetryResultCode.ERR_MEMORY_FULL; } //Temporary download error cases case EuiccManager.ERROR_TIME_OUT: case EuiccManager.ERROR_CONNECTION_ERROR: case EuiccManager.ERROR_OPERATION_BUSY: { - return DownloadRetryOperationCode.ERR_RETRY_DOWNLOAD; + return DownloadRetryResultCode.ERR_RETRY_DOWNLOAD; } //Profile installation failure cases case EuiccManager.ERROR_INSTALL_PROFILE: { - return DownloadRetryOperationCode.ERR_INSTALL_ESIM_PROFILE_FAILED; + return DownloadRetryResultCode.ERR_INSTALL_ESIM_PROFILE_FAILED; } default: { - return DownloadRetryOperationCode.ERR_UNRESOLVABLE; + return DownloadRetryResultCode.ERR_UNRESOLVABLE; } } } @@ -214,14 +224,28 @@ public class ONSProfileDownloader { return "Unknown"; } - @VisibleForTesting - protected void downloadProfile(int primarySubId) { + protected enum DownloadProfileResult { + SUCCESS, + DUPLICATE_REQUEST, + INVALID_SMDP_ADDRESS + } + + protected DownloadProfileResult downloadProfile(int primarySubId) { Log.d(TAG, "downloadProfile"); //Get SMDP address from carrier configuration. String smdpAddress = getSMDPServerAddress(primarySubId); if (smdpAddress == null || smdpAddress.length() <= 0) { - return; + return DownloadProfileResult.INVALID_SMDP_ADDRESS; + } + + synchronized (this) { + if (mDownloadingPSimSubId == primarySubId) { + Log.d(TAG, "Download already in progress."); + return DownloadProfileResult.DUPLICATE_REQUEST; + } + + mDownloadingPSimSubId = primarySubId; } //Generate Activation code 1${SM-DP+ FQDN}$ @@ -236,6 +260,8 @@ public class ONSProfileDownloader { Log.d(TAG, "Download Request sent to EUICC Manager"); mEuiccManager.downloadSubscription(DownloadableSubscription.forActivationCode( activationCode), true, callbackIntent); + + return DownloadProfileResult.SUCCESS; } /** diff --git a/src/com/android/ons/ONSProfileSelector.java b/src/com/android/ons/ONSProfileSelector.java index ab9168d..95287fc 100644 --- a/src/com/android/ons/ONSProfileSelector.java +++ b/src/com/android/ons/ONSProfileSelector.java @@ -31,10 +31,10 @@ import android.os.RemoteException; import android.telephony.AvailableNetworkInfo; import android.telephony.CellInfo; import android.telephony.CellInfoLte; +import android.telephony.CellInfoNr; import android.telephony.SignalStrength; import android.telephony.SubscriptionInfo; import android.telephony.SubscriptionManager; -import android.telephony.TelephonyFrameworkInitializer; import android.telephony.TelephonyManager; import android.telephony.UiccCardInfo; import android.telephony.UiccPortInfo; @@ -43,7 +43,6 @@ import android.text.TextUtils; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.telephony.ISetOpportunisticDataCallback; -import com.android.internal.telephony.ISub; import com.android.internal.telephony.IUpdateAvailableNetworksCallback; import com.android.telephony.Rlog; @@ -195,7 +194,7 @@ public class ONSProfileSelector { } } else { logDebug("switch to sub:" + subId); - switchToSubscription(subId); + switchToSubscription(subId, getAvailableESIMPortIndex()); } } }; @@ -267,20 +266,28 @@ public class ONSProfileSelector { } } - private String getMcc(CellInfo cellInfo) { + @VisibleForTesting + protected String getMcc(CellInfo cellInfo) { String mcc = ""; if (cellInfo instanceof CellInfoLte) { mcc = ((CellInfoLte) cellInfo).getCellIdentity().getMccString(); } + else if (cellInfo instanceof CellInfoNr) { + mcc = ((CellInfoNr) cellInfo).getCellIdentity().getMccString(); + } return mcc; } - private String getMnc(CellInfo cellInfo) { + @VisibleForTesting + protected String getMnc(CellInfo cellInfo) { String mnc = ""; if (cellInfo instanceof CellInfoLte) { mnc = ((CellInfoLte) cellInfo).getCellIdentity().getMncString(); } + else if (cellInfo instanceof CellInfoNr) { + mnc = ((CellInfoNr) cellInfo).getCellIdentity().getMncString(); + } return mnc; } @@ -350,7 +357,7 @@ public class ONSProfileSelector { private HashMap<Integer, IUpdateAvailableNetworksCallback> callbackStubs = new HashMap<>(); - private void switchToSubscription(int subId) { + private void switchToSubscription(int subId, int availableSIMPortIndex) { Intent callbackIntent = new Intent(ACTION_SUB_SWITCH); callbackIntent.setClass(mContext, OpportunisticNetworkService.class); updateToken(); @@ -359,21 +366,22 @@ public class ONSProfileSelector { mSubId = subId; PendingIntent replyIntent = PendingIntent.getService(mContext, 1, callbackIntent, PendingIntent.FLAG_ONE_SHOT | PendingIntent.FLAG_IMMUTABLE); - int eSIMPortIndex = getAvailableESIMPortIndex(); - if (eSIMPortIndex == TelephonyManager.INVALID_PORT_INDEX) { + if (availableSIMPortIndex == TelephonyManager.INVALID_PORT_INDEX) { sendUpdateNetworksCallbackHelper(mNetworkScanCallback, TelephonyManager.UPDATE_AVAILABLE_NETWORKS_SIM_PORT_NOT_AVAILABLE); return; } - mEuiccManager.switchToSubscription(subId, eSIMPortIndex, replyIntent); + mEuiccManager.switchToSubscription(subId, availableSIMPortIndex, replyIntent); } - private int getAvailableESIMPortIndex() { - //Check if an opportunistic subscription is already active. If yes then, use the same port. + @VisibleForTesting + protected int getAvailableESIMPortIndex() { //Check if an opportunistic subscription is already active. If yes then, use the same port. List<SubscriptionInfo> subscriptionInfos = mSubscriptionManager - .getActiveSubscriptionInfoList(); + .getCompleteActiveSubscriptionInfoList(); if (subscriptionInfos != null) { + logDebug("[getAvailableESIMPortIndex] subscriptionInfos size:" + + subscriptionInfos.size()); for (SubscriptionInfo subscriptionInfo : subscriptionInfos) { if (subscriptionInfo.isEmbedded() && subscriptionInfo.isOpportunistic()) { return subscriptionInfo.getPortIndex(); @@ -383,12 +391,14 @@ public class ONSProfileSelector { //Look for available port. for (UiccCardInfo uiccCardInfo : mTelephonyManager.getUiccCardsInfo()) { + logDebug("[getAvailableESIMPortIndex] CardInfo: " + uiccCardInfo.toString()); if (!uiccCardInfo.isEuicc()) { continue; } EuiccManager euiccManager = mEuiccManager.createForCardId(uiccCardInfo.getCardId()); for (UiccPortInfo uiccPortInfo : uiccCardInfo.getPorts()) { + logDebug("[getAvailableESIMPortIndex] PortInfo: " + uiccPortInfo.toString()); //Port is available if no profiles enabled on it. if (euiccManager.isSimPortAvailable(uiccPortInfo.getPortIndex())) { return uiccPortInfo.getPortIndex(); @@ -396,6 +406,7 @@ public class ONSProfileSelector { } } + logDebug("[getAvailableESIMPortIndex] No Port is available."); return TelephonyManager.INVALID_PORT_INDEX; } @@ -481,31 +492,6 @@ public class ONSProfileSelector { return new HashSet<>(availableNetworks1).equals(new HashSet<>(availableNetworks2)); } - private boolean isPrimaryActiveOnOpportunisticSlot( - ArrayList<AvailableNetworkInfo> availableNetworks) { - /* Check if any of the available network is an embedded profile. if none are embedded, - * return false - * Todo <b/130535071> */ - if (!isOpportunisticSubEmbedded(availableNetworks)) { - return false; - } - - List<SubscriptionInfo> subscriptionInfos = - mSubscriptionManager.getActiveSubscriptionInfoList(false); - if (subscriptionInfos == null) { - return false; - } - - /* if there is a primary subscription active on the eSIM, return true */ - for (SubscriptionInfo subscriptionInfo : subscriptionInfos) { - if (!subscriptionInfo.isOpportunistic() && subscriptionInfo.isEmbedded()) { - return true; - } - } - - return false; - - } private void sendUpdateNetworksCallbackHelper(IUpdateAvailableNetworksCallback callback, int result) { if (callback == null) { @@ -537,11 +523,12 @@ public class ONSProfileSelector { return; } - /* if primary subscription is active on opportunistic slot, do not switch out the same. */ - if (isPrimaryActiveOnOpportunisticSlot(availableNetworks)) { - logDebug("primary subscription active on opportunistic sub"); + /* Check if ports are available on the embedded slot */ + int availSIMPortIndex = getAvailableESIMPortIndex(); + if (availSIMPortIndex == TelephonyManager.INVALID_PORT_INDEX) { + logDebug("SIM port not available."); sendUpdateNetworksCallbackHelper(callbackStub, - TelephonyManager.UPDATE_AVAILABLE_NETWORKS_INVALID_ARGUMENTS); + TelephonyManager.UPDATE_AVAILABLE_NETWORKS_SIM_PORT_NOT_AVAILABLE); return; } @@ -574,7 +561,8 @@ public class ONSProfileSelector { /* if subscription is not active, activate the sub */ if (!mSubscriptionManager.isActiveSubId(filteredAvailableNetworks.get(0).getSubId())) { mNetworkScanCallback = callbackStub; - switchToSubscription(filteredAvailableNetworks.get(0).getSubId()); + switchToSubscription(filteredAvailableNetworks.get(0).getSubId(), + availSIMPortIndex); } else { if (enableModem(filteredAvailableNetworks.get(0).getSubId(), true)) { sendUpdateNetworksCallbackHelper(callbackStub, @@ -844,27 +832,12 @@ public class ONSProfileSelector { ISetOpportunisticDataCallback callbackStub) { if ((subId == SubscriptionManager.DEFAULT_SUBSCRIPTION_ID) || (isOpprotunisticSub(subId) && mSubscriptionManager.isActiveSubId(subId))) { - ISub iSub = ISub.Stub.asInterface( - TelephonyFrameworkInitializer - .getTelephonyServiceManager() - .getSubscriptionServiceRegisterer() - .get()); - if (iSub == null) { - log("Could not get Subscription Service handle"); - if (Compatibility.isChangeEnabled( - OpportunisticNetworkService.CALLBACK_ON_MORE_ERROR_CODE_CHANGE)) { - sendSetOpptCallbackHelper(callbackStub, - TelephonyManager.SET_OPPORTUNISTIC_SUB_REMOTE_SERVICE_EXCEPTION); - } else { - sendSetOpptCallbackHelper(callbackStub, - TelephonyManager.SET_OPPORTUNISTIC_SUB_VALIDATION_FAILED); - } - return; - } try { - iSub.setPreferredDataSubscriptionId(subId, needValidation, callbackStub); - } catch (RemoteException ex) { - log("Could not connect to Subscription Service"); + mSubscriptionManager.setPreferredDataSubscriptionId(subId, needValidation, + mHandler::post, result -> sendSetOpptCallbackHelper(callbackStub, result)); + } catch (Exception ex) { + log("setPreferredDataSubscriptionId failed. subId=" + subId + ", needValidation=" + + needValidation + ", ex=" + ex); if (Compatibility.isChangeEnabled( OpportunisticNetworkService.CALLBACK_ON_MORE_ERROR_CODE_CHANGE)) { sendSetOpptCallbackHelper(callbackStub, diff --git a/src/com/android/ons/ONSStats.java b/src/com/android/ons/ONSStats.java new file mode 100644 index 0000000..d961344 --- /dev/null +++ b/src/com/android/ons/ONSStats.java @@ -0,0 +1,200 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.ons; + +import android.content.Context; +import android.content.SharedPreferences; +import android.telephony.SubscriptionInfo; +import android.telephony.SubscriptionManager; + +import com.android.ons.ONSProfileActivator.Result; +import com.android.ons.ONSProfileDownloader.DownloadRetryResultCode; + +import java.util.List; + +public class ONSStats { + private static final String ONS_ATOM_LOG_FILE = "ons_atom_log_info"; + private static final String KEY_PROVISIONING_RESULT = "_provisioning_result"; + private static final String KEY_DOWNLOAD_RESULT = "_download_result"; + private static final String KEY_RETRY_COUNT = "_retry_count"; + private static final String KEY_DETAILED_ERROR_CODE = "_detailed_error_code"; + private static final String KEY_OPP_CARRIER_ID = "_opportunistic_carrier_id"; + private static final String KEY_PRIMARY_CARRIER_ID = "_primary_sim_carrier_id"; + private final Context mContext; + private final SubscriptionManager mSubscriptionManager; + + /** Constructor to create instance for ONSStats. */ + public ONSStats(Context context, SubscriptionManager subscriptionManager) { + mContext = context; + mSubscriptionManager = subscriptionManager; + } + + /** + * It logs the ONS atom with the info passed as ONSStatsInfo. If the information is already + * logged, it will be skipped. + * + * @param info information to be logged. + * @return returns true if information is logged, otherwise false. + */ + public boolean logEvent(ONSStatsInfo info) { + // check if the info needs to be ignored. + if (ignoreEvent(info)) { + return false; + } + int statsCode = OnsStatsLog.ONS_OPPORTUNISTIC_ESIM_PROVISIONING_COMPLETE__ERROR_CODE__RESULT_UNKNOWN; + if (info.isProvisioningResultUpdated()) { + switch (info.getProvisioningResult()) { + case SUCCESS: + statsCode = OnsStatsLog.ONS_OPPORTUNISTIC_ESIM_PROVISIONING_COMPLETE__ERROR_CODE__RESULT_SUCCESS; + break; + case ERR_CANNOT_SWITCH_TO_DUAL_SIM_MODE: + statsCode = OnsStatsLog.ONS_OPPORTUNISTIC_ESIM_PROVISIONING_COMPLETE__ERROR_CODE__RESULT_SWITCH_TO_MULTISIM_FAILED; + break; + case ERR_CARRIER_DOESNT_SUPPORT_CBRS: + case ERR_AUTO_PROVISIONING_DISABLED: + statsCode = OnsStatsLog.ONS_OPPORTUNISTIC_ESIM_PROVISIONING_COMPLETE__ERROR_CODE__RESULT_AUTO_PROVISIONING_DISABLED; + break; + case ERR_ESIM_NOT_SUPPORTED: + case ERR_MULTISIM_NOT_SUPPORTED: + statsCode = OnsStatsLog.ONS_OPPORTUNISTIC_ESIM_PROVISIONING_COMPLETE__ERROR_CODE__RESULT_DEVICE_NOT_CAPABLE; + break; + case ERR_SINGLE_ACTIVE_OPPORTUNISTIC_SIM: + case ERR_DUAL_ACTIVE_SUBSCRIPTIONS: + case ERR_PSIM_NOT_FOUND: + case ERR_DOWNLOADED_ESIM_NOT_FOUND: + statsCode = OnsStatsLog.ONS_OPPORTUNISTIC_ESIM_PROVISIONING_COMPLETE__ERROR_CODE__RESULT_ESIM_PROVISIONING_FAILED; + break; + case ERR_WAITING_FOR_INTERNET_CONNECTION: + case ERR_WAITING_FOR_WIFI_CONNECTION: + statsCode = OnsStatsLog.ONS_OPPORTUNISTIC_ESIM_PROVISIONING_COMPLETE__ERROR_CODE__RESULT_INTERNET_NOT_AVAILABLE; + break; + case ERR_INVALID_CARRIER_CONFIG: + statsCode = OnsStatsLog.ONS_OPPORTUNISTIC_ESIM_PROVISIONING_COMPLETE__ERROR_CODE__RESULT_UNRESOLVABLE_ERROR; + break; + default: + break; + } + } else { + switch (info.getDownloadResult()) { + case ERR_UNRESOLVABLE: + statsCode = OnsStatsLog.ONS_OPPORTUNISTIC_ESIM_PROVISIONING_COMPLETE__ERROR_CODE__RESULT_UNRESOLVABLE_ERROR; + break; + case ERR_MEMORY_FULL: + statsCode = OnsStatsLog.ONS_OPPORTUNISTIC_ESIM_PROVISIONING_COMPLETE__ERROR_CODE__RESULT_MEMORY_FULL; + break; + case ERR_INSTALL_ESIM_PROFILE_FAILED: + statsCode = OnsStatsLog.ONS_OPPORTUNISTIC_ESIM_PROVISIONING_COMPLETE__ERROR_CODE__RESULT_INSTALL_ESIM_PROFILE_FAILED; + break; + case ERR_RETRY_DOWNLOAD: + statsCode = OnsStatsLog.ONS_OPPORTUNISTIC_ESIM_PROVISIONING_COMPLETE__ERROR_CODE__RESULT_CONNECTION_ERROR; + break; + default: + break; + } + } + OnsStatsLog.write( + OnsStatsLog.ONS_OPPORTUNISTIC_ESIM_PROVISIONING_COMPLETE, + getSimCarrierId(info.getPrimarySimSubId()), + info.getOppSimCarrierId(), + info.isWifiConnected(), + statsCode, + info.getRetryCount(), + info.getDetailedErrCode()); + updateSharedPreferences(info); + return true; + } + + private void updateSharedPreferences(ONSStatsInfo info) { + SharedPreferences sharedPref = + mContext.getSharedPreferences(ONS_ATOM_LOG_FILE, Context.MODE_PRIVATE); + SharedPreferences.Editor editor = sharedPref.edit(); + if (info.isProvisioningResultUpdated()) { + editor.putInt(KEY_PROVISIONING_RESULT, info.getProvisioningResult().ordinal()); + editor.remove(KEY_DOWNLOAD_RESULT); + } else { + editor.putInt(KEY_DOWNLOAD_RESULT, info.getDownloadResult().ordinal()); + editor.remove(KEY_PROVISIONING_RESULT); + } + editor.putInt(KEY_PRIMARY_CARRIER_ID, getSimCarrierId(info.getPrimarySimSubId())) + .putInt(KEY_RETRY_COUNT, info.getRetryCount()) + .putInt(KEY_OPP_CARRIER_ID, info.getOppSimCarrierId()) + .putInt(KEY_DETAILED_ERROR_CODE, info.getDetailedErrCode()) + .apply(); + } + + private boolean ignoreEvent(ONSStatsInfo info) { + Result result = info.getProvisioningResult(); + if (info.isProvisioningResultUpdated()) { + info.setDetailedErrCode(result.ordinal()); + // Codes are ignored since they are intermediate state of CBRS provisioning check. + if ((result == Result.DOWNLOAD_REQUESTED) + || result == Result.ERR_NO_SIM_INSERTED + || result == Result.ERR_DUPLICATE_DOWNLOAD_REQUEST + || result == Result.ERR_SWITCHING_TO_DUAL_SIM_MODE) { + return true; + } + + // add subscription id for carrier if it doesn't support CBRS. + if (result == Result.ERR_CARRIER_DOESNT_SUPPORT_CBRS) { + List<SubscriptionInfo> subInfos = + mSubscriptionManager.getActiveSubscriptionInfoList(); + info.setPrimarySimSubId( + (subInfos != null && !subInfos.isEmpty()) + ? subInfos.get(0).getSubscriptionId() + : -1); + } + } + + SharedPreferences sharedPref = + mContext.getSharedPreferences(ONS_ATOM_LOG_FILE, Context.MODE_PRIVATE); + + boolean errorCodeUpdated = + (info.isProvisioningResultUpdated() + ? sharedPref.getInt(KEY_PROVISIONING_RESULT, -1) != result.ordinal() + : sharedPref.getInt(KEY_DOWNLOAD_RESULT, -1) + != info.getDownloadResult().ordinal()); + boolean carrierIdUpdated = + sharedPref.getInt(KEY_PRIMARY_CARRIER_ID, -1) + != getSimCarrierId(info.getPrimarySimSubId()); + boolean retryCountUpdated = sharedPref.getInt(KEY_RETRY_COUNT, -1) != info.getRetryCount(); + boolean oppCarrierIdChanged = + sharedPref.getInt(KEY_OPP_CARRIER_ID, -1) != info.getOppSimCarrierId(); + boolean detailedErrorChanged = + sharedPref.getInt(KEY_DETAILED_ERROR_CODE, -1) != info.getDetailedErrCode(); + if (!(errorCodeUpdated + || carrierIdUpdated + || retryCountUpdated + || oppCarrierIdChanged + || detailedErrorChanged)) { + // Result codes are meant to log on every occurrence. These should not be ignored. + if (result == Result.SUCCESS + || result == Result.ERR_DOWNLOADED_ESIM_NOT_FOUND + || info.getDownloadResult() + == DownloadRetryResultCode.ERR_INSTALL_ESIM_PROFILE_FAILED) { + return false; + } + return true; + } + return false; + } + + private int getSimCarrierId(int subId) { + if (subId == -1) return -1; + SubscriptionInfo subInfo = mSubscriptionManager.getActiveSubscriptionInfo(subId); + return (subInfo != null) ? subInfo.getCarrierId() : -1; + } +} diff --git a/src/com/android/ons/ONSStatsInfo.java b/src/com/android/ons/ONSStatsInfo.java new file mode 100644 index 0000000..080ed4a --- /dev/null +++ b/src/com/android/ons/ONSStatsInfo.java @@ -0,0 +1,125 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.ons; + +import com.android.ons.ONSProfileActivator.Result; +import com.android.ons.ONSProfileDownloader.DownloadRetryResultCode; + +public final class ONSStatsInfo { + public static final int INVALID_VALUE = -1; + private Result mProvisioningResult = null; + private DownloadRetryResultCode mDownloadResult = null; + private int mPrimarySimSubId = INVALID_VALUE; + private int mOppSimCarrierId = INVALID_VALUE; + private int mRetryCount = INVALID_VALUE; + private int mDetailedErrCode = INVALID_VALUE; + private boolean mIsWifiConnected = false; + private boolean mIsProvisioningResultUpdated = false; + + public Result getProvisioningResult() { + return mProvisioningResult; + } + + public DownloadRetryResultCode getDownloadResult() { + return mDownloadResult; + } + + public int getPrimarySimSubId() { + return mPrimarySimSubId; + } + + public int getOppSimCarrierId() { + return mOppSimCarrierId; + } + + public int getRetryCount() { + return mRetryCount; + } + + public int getDetailedErrCode() { + return mDetailedErrCode; + } + + public boolean isWifiConnected() { + return mIsWifiConnected; + } + + public boolean isProvisioningResultUpdated() { + return mIsProvisioningResultUpdated; + } + + public ONSStatsInfo setProvisioningResult(Result result) { + mProvisioningResult = result; + mDownloadResult = null; + mIsProvisioningResultUpdated = true; + return this; + } + + public ONSStatsInfo setDownloadResult(DownloadRetryResultCode retryResultCode) { + mProvisioningResult = null; + mDownloadResult = retryResultCode; + mIsProvisioningResultUpdated = false; + return this; + } + + public ONSStatsInfo setPrimarySimSubId(int primarySimSubId) { + mPrimarySimSubId = primarySimSubId; + return this; + } + + public ONSStatsInfo setOppSimCarrierId(int oppSimCarrierId) { + mOppSimCarrierId = oppSimCarrierId; + return this; + } + + public ONSStatsInfo setRetryCount(int retryCount) { + mRetryCount = retryCount; + return this; + } + + public ONSStatsInfo setDetailedErrCode(int detailedErrCode) { + mDetailedErrCode = detailedErrCode; + return this; + } + + public ONSStatsInfo setWifiConnected(boolean wifiConnected) { + mIsWifiConnected = wifiConnected; + return this; + } + + @Override + public String toString() { + return "ONSStatsInfo{" + + "mProvisioningResult=" + + mProvisioningResult + + ", mDownloadResult=" + + mDownloadResult + + ", mPrimarySimSubId=" + + mPrimarySimSubId + + ", mOppSimCarrierId=" + + mOppSimCarrierId + + ", mRetryCount=" + + mRetryCount + + ", mDetailedErrCode=" + + mDetailedErrCode + + ", mIsWifiConnected=" + + mIsWifiConnected + + ", mIsProvisioningResultUpdated=" + + mIsProvisioningResultUpdated + + '}'; + } +} diff --git a/src/com/android/ons/OpportunisticNetworkService.java b/src/com/android/ons/OpportunisticNetworkService.java index 13e7034..d41051c 100644 --- a/src/com/android/ons/OpportunisticNetworkService.java +++ b/src/com/android/ons/OpportunisticNetworkService.java @@ -35,6 +35,7 @@ import android.os.Message; import android.os.RemoteException; import android.os.TelephonyServiceManager.ServiceRegisterer; import android.telephony.AvailableNetworkInfo; +import android.telephony.CarrierConfigManager; import android.telephony.SubscriptionInfo; import android.telephony.SubscriptionManager; import android.telephony.TelephonyFrameworkInitializer; @@ -62,6 +63,7 @@ public class OpportunisticNetworkService extends Service { private TelephonyManager mTelephonyManager; @VisibleForTesting protected SubscriptionManager mSubscriptionManager; private ONSProfileActivator mONSProfileActivator; + private ONSStats mONSStats; private Handler mHandler = null; private final Object mLock = new Object(); @@ -311,10 +313,19 @@ public class OpportunisticNetworkService extends Service { @Override public int getPreferredDataSubscriptionId(String callingPackage, String callingFeatureId) { - TelephonyPermissions - .checkCallingOrSelfReadPhoneState(mContext, - mSubscriptionManager.getDefaultSubscriptionId(), - callingPackage, callingFeatureId, "getPreferredDataSubscriptionId"); + if (!TelephonyPermissions.checkReadPhoneStateOnAnyActiveSub( + mContext, + Binder.getCallingPid(), + Binder.getCallingUid(), + callingPackage, + callingFeatureId, + "getPreferredDataSubscriptionId")) { + throw new SecurityException( + "getPreferredDataSubscriptionId requires READ_PHONE_STATE," + + " READ_PRIVILEGED_PHONE_STATE, or carrier privileges on" + + " any active subscription."); + } + final long identity = Binder.clearCallingIdentity(); try { return mProfileSelector.getPreferredDataSubscriptionId(); @@ -421,7 +432,7 @@ public class OpportunisticNetworkService extends Service { } break; - case ONSProfileActivator.ACTION_CARRIER_CONFIG_CHANGED: + case CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED: mONSProfileActivator.handleCarrierConfigChange(); break; } @@ -455,10 +466,11 @@ public class OpportunisticNetworkService extends Service { mSubscriptionManager = (SubscriptionManager) mContext.getSystemService( Context.TELEPHONY_SUBSCRIPTION_SERVICE); mONSConfigInputHashMap = new HashMap<String, ONSConfigInput>(); + mONSStats = new ONSStats(mContext, mSubscriptionManager); mContext.registerReceiver(mBroadcastReceiver, new IntentFilter(TelephonyIntents.ACTION_SIM_STATE_CHANGED)); enableOpportunisticNetwork(getPersistentEnableState()); - mONSProfileActivator = new ONSProfileActivator(mContext); + mONSProfileActivator = new ONSProfileActivator(mContext, mONSStats); } private void handleCarrierAppAvailableNetworks( diff --git a/tests/src/com/android/ons/ONSNetworkScanCtlrTest.java b/tests/src/com/android/ons/ONSNetworkScanCtlrTest.java index e4470c5..0053adc 100644 --- a/tests/src/com/android/ons/ONSNetworkScanCtlrTest.java +++ b/tests/src/com/android/ons/ONSNetworkScanCtlrTest.java @@ -20,31 +20,25 @@ import static org.junit.Assert.assertFalse; import static org.mockito.Mockito.*; import android.os.Looper; -import android.os.PersistableBundle; import android.telephony.AccessNetworkConstants; import android.telephony.AvailableNetworkInfo; -import android.telephony.CarrierConfigManager; import android.telephony.CellIdentityLte; +import android.telephony.CellIdentityNr; import android.telephony.CellInfo; import android.telephony.CellInfoLte; +import android.telephony.CellInfoNr; import android.telephony.NetworkScan; import android.telephony.NetworkScanRequest; import android.telephony.RadioAccessSpecifier; import android.telephony.SubscriptionInfo; -import android.telephony.TelephonyManager; -import android.util.Log; - -import androidx.test.InstrumentationRegistry; import org.junit.After; import org.junit.Before; import org.junit.Test; -import org.mockito.Mock; -import org.mockito.MockitoAnnotations; -import java.sql.Array; -import java.util.Arrays; import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; import java.util.List; public class ONSNetworkScanCtlrTest extends ONSBaseTest { @@ -341,4 +335,16 @@ public class ONSNetworkScanCtlrTest extends ONSBaseTest { waitUntilReady(); mReady = false; } + + @Test + public void testGetMncMccFromCellInfoNr() { + mONSNetworkScanCtlr = new ONSNetworkScanCtlr(mContext, mMockTelephonyManager, null); + + CellIdentityNr cellIdentityNr = new CellIdentityNr(0, 0, 0, new int[]{0}, "111", "222", 0, + "", "", Collections.emptyList()); + + CellInfoNr cellinfoNr = new CellInfoNr(0, true, 0, cellIdentityNr, null); + + assertEquals(mONSNetworkScanCtlr.getMccMnc(cellinfoNr), "111222"); + } } diff --git a/tests/src/com/android/ons/ONSProfileActivatorTest.java b/tests/src/com/android/ons/ONSProfileActivatorTest.java index c678d24..478f23a 100644 --- a/tests/src/com/android/ons/ONSProfileActivatorTest.java +++ b/tests/src/com/android/ons/ONSProfileActivatorTest.java @@ -18,6 +18,8 @@ package com.android.ons; import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; import android.content.Context; import android.content.res.Resources; @@ -25,6 +27,7 @@ import android.net.ConnectivityManager; import android.net.NetworkCapabilities; import android.net.NetworkRequest; import android.os.Looper; +import android.os.ParcelUuid; import android.os.PersistableBundle; import android.telephony.CarrierConfigManager; import android.telephony.SubscriptionInfo; @@ -41,9 +44,12 @@ import org.mockito.MockitoAnnotations; import java.util.ArrayList; import java.util.List; +import java.util.UUID; public class ONSProfileActivatorTest extends ONSBaseTest { private static final String TAG = ONSProfileActivatorTest.class.getName(); + private static final int TEST_SUBID_0 = 0; + private static final int TEST_SUBID_1 = 1; @Mock Context mMockContext; @@ -66,18 +72,20 @@ public class ONSProfileActivatorTest extends ONSBaseTest { @Mock SubscriptionInfo mMockSubInfo; @Mock - SubscriptionInfo mMockSubInfo2; + SubscriptionInfo mMockSubInfo1; @Mock List<SubscriptionInfo> mMocksubsInPSIMGroup; @Mock Resources mMockResources; + @Mock + ONSStats mMockONSStats; @Before public void setUp() throws Exception { super.setUp("ONSTest"); MockitoAnnotations.initMocks(this); Looper.prepare(); - doReturn(TelephonyManager.SIM_STATE_READY).when(mMockTeleManager).getSimState(); + doReturn(mMockResources).when(mMockContext).getResources(); doReturn(mMockConnectivityManager).when(mMockContext).getSystemService( @@ -86,6 +94,36 @@ public class ONSProfileActivatorTest extends ONSBaseTest { NetworkCapabilities.NET_CAPABILITY_VALIDATED).build(); doNothing().when(mMockConnectivityManager).registerNetworkCallback(request, new ConnectivityManager.NetworkCallback()); + + PersistableBundle persistableBundle = new PersistableBundle(); + persistableBundle.putBoolean(CarrierConfigManager + .KEY_CARRIER_SUPPORTS_OPP_DATA_AUTO_PROVISIONING_BOOL, true); + doReturn(persistableBundle).when(mMockCarrierConfigManager).getConfigForSubId(TEST_SUBID_1); + } + + // Worker thread is used for testing asynchronous APIs and Message Handlers. + // ASync APIs are called and Handler messages are processed by Worker thread. Test results are + // verified by Main Thread. + static class WorkerThread extends Thread { + Looper mWorkerLooper; + private final Runnable mRunnable; + + WorkerThread(Runnable runnable) { + mRunnable = runnable; + } + + @Override + public void run() { + super.run(); + Looper.prepare(); + mWorkerLooper = Looper.myLooper(); + mRunnable.run(); + mWorkerLooper.loop(); + } + + public void exit() { + mWorkerLooper.quitSafely(); + } } /*@Test @@ -102,12 +140,13 @@ public class ONSProfileActivatorTest extends ONSBaseTest { @Test public void testONSAutoProvisioningDisabled() { - doReturn(TelephonyManager.SIM_STATE_READY).when(mMockTeleManager).getSimState(); + doReturn(false).when(mMockResources).getBoolean(R.bool.enable_ons_auto_provisioning); ONSProfileActivator onsProfileActivator = new ONSProfileActivator(mMockContext, mMockSubManager, mMockTeleManager, mMockCarrierConfigManager, mMockEuiccManager, - mMockConnectivityManager, mMockONSProfileConfigurator, mMockONSProfileDownloader); + mMockConnectivityManager, mMockONSProfileConfigurator, mMockONSProfileDownloader, + mMockONSStats); assertEquals(ONSProfileActivator.Result.ERR_AUTO_PROVISIONING_DISABLED, onsProfileActivator.handleCarrierConfigChange()); @@ -115,13 +154,14 @@ public class ONSProfileActivatorTest extends ONSBaseTest { @Test public void testESIMNotSupported() { - 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 onsProfileActivator = new ONSProfileActivator(mMockContext, mMockSubManager, mMockTeleManager, mMockCarrierConfigManager, mMockEuiccManager, - mMockConnectivityManager, mMockONSProfileConfigurator, mMockONSProfileDownloader); + mMockConnectivityManager, mMockONSProfileConfigurator, mMockONSProfileDownloader, + mMockONSStats); assertEquals(ONSProfileActivator.Result.ERR_ESIM_NOT_SUPPORTED, onsProfileActivator.handleCarrierConfigChange()); @@ -130,7 +170,7 @@ public class ONSProfileActivatorTest extends ONSBaseTest { @Test //@DisplayName("Single SIM Device with eSIM support") public void testMultiSIMNotSupported() { - 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(); @@ -138,7 +178,8 @@ public class ONSProfileActivatorTest extends ONSBaseTest { ONSProfileActivator onsProfileActivator = new ONSProfileActivator(mMockContext, mMockSubManager, mMockTeleManager, mMockCarrierConfigManager, mMockEuiccManager, - mMockConnectivityManager, mMockONSProfileConfigurator, mMockONSProfileDownloader); + mMockConnectivityManager, mMockONSProfileConfigurator, mMockONSProfileDownloader, + mMockONSStats); assertEquals(ONSProfileActivator.Result.ERR_MULTISIM_NOT_SUPPORTED, onsProfileActivator.handleCarrierConfigChange()); @@ -146,7 +187,7 @@ public class ONSProfileActivatorTest extends ONSBaseTest { @Test public void testDeviceSwitchToDualSIMModeFailed() { - 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(); @@ -154,18 +195,14 @@ public class ONSProfileActivatorTest extends ONSBaseTest { doReturn(true).when(mMockTeleManager).doesSwitchMultiSimConfigTriggerReboot(); doReturn(mMockactiveSubInfos).when(mMockSubManager).getActiveSubscriptionInfoList(); doReturn(1).when(mMockactiveSubInfos).size(); - doReturn(mMockSubInfo).when(mMockactiveSubInfos).get(0); + doReturn(mMockSubInfo).when(mMockactiveSubInfos).get(TEST_SUBID_0); doReturn(1).when(mMockSubInfo).getSubscriptionId(); doReturn(false).when(mMockSubInfo).isOpportunistic(); - 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); + mMockConnectivityManager, mMockONSProfileConfigurator, mMockONSProfileDownloader, + mMockONSStats); assertEquals(ONSProfileActivator.Result.ERR_CANNOT_SWITCH_TO_DUAL_SIM_MODE, onsProfileActivator.handleCarrierConfigChange()); @@ -173,26 +210,23 @@ public class ONSProfileActivatorTest extends ONSBaseTest { @Test public void testDeviceSwitchToDualSIMModeSuccess() { - 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(mMockSubInfo).when(mMockactiveSubInfos).get(TEST_SUBID_0); doReturn(1).when(mMockSubInfo).getSubscriptionId(); doReturn(false).when(mMockSubInfo).isOpportunistic(); - 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); + mMockConnectivityManager, mMockONSProfileConfigurator, mMockONSProfileDownloader, + mMockONSStats); assertEquals(ONSProfileActivator.Result.ERR_SWITCHING_TO_DUAL_SIM_MODE, onsProfileActivator.handleCarrierConfigChange()); @@ -200,7 +234,7 @@ public class ONSProfileActivatorTest extends ONSBaseTest { //@DisplayName("Dual SIM device with no SIM inserted") public void testNoActiveSubscriptions() { - 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(); @@ -210,7 +244,25 @@ public class ONSProfileActivatorTest extends ONSBaseTest { ONSProfileActivator onsProfileActivator = new ONSProfileActivator(mMockContext, mMockSubManager, mMockTeleManager, mMockCarrierConfigManager, mMockEuiccManager, - mMockConnectivityManager, mMockONSProfileConfigurator, mMockONSProfileDownloader); + mMockConnectivityManager, mMockONSProfileConfigurator, mMockONSProfileDownloader, + mMockONSStats); + + assertEquals(ONSProfileActivator.Result.ERR_NO_SIM_INSERTED, + onsProfileActivator.handleCarrierConfigChange()); + } + + public void testNullActiveSubscriptionList() { + + 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(null).when(mMockSubManager).getActiveSubscriptionInfoList(); + + ONSProfileActivator onsProfileActivator = new ONSProfileActivator(mMockContext, + mMockSubManager, mMockTeleManager, mMockCarrierConfigManager, mMockEuiccManager, + mMockConnectivityManager, mMockONSProfileConfigurator, mMockONSProfileDownloader, + mMockONSStats); assertEquals(ONSProfileActivator.Result.ERR_NO_SIM_INSERTED, onsProfileActivator.handleCarrierConfigChange()); @@ -219,7 +271,7 @@ public class ONSProfileActivatorTest extends ONSBaseTest { @Test //@DisplayName("Dual SIM device and non CBRS carrier pSIM inserted") public void testNonCBRSCarrierPSIMInserted() { - 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(); @@ -228,17 +280,18 @@ public class ONSProfileActivatorTest extends ONSBaseTest { PersistableBundle persistableBundle = new PersistableBundle(); persistableBundle.putBoolean(CarrierConfigManager .KEY_CARRIER_SUPPORTS_OPP_DATA_AUTO_PROVISIONING_BOOL, false); - doReturn(persistableBundle).when(mMockCarrierConfigManager).getConfigForSubId(1); + doReturn(persistableBundle).when(mMockCarrierConfigManager).getConfigForSubId(TEST_SUBID_0); doReturn(mMockactiveSubInfos).when(mMockSubManager).getActiveSubscriptionInfoList(); doReturn(1).when(mMockactiveSubInfos).size(); - doReturn(mMockSubInfo).when(mMockactiveSubInfos).get(0); - doReturn(1).when(mMockSubInfo).getSubscriptionId(); + doReturn(mMockSubInfo).when(mMockactiveSubInfos).get(TEST_SUBID_0); + doReturn(TEST_SUBID_0).when(mMockSubInfo).getSubscriptionId(); doReturn(false).when(mMockSubInfo).isOpportunistic(); ONSProfileActivator onsProfileActivator = new ONSProfileActivator(mMockContext, mMockSubManager, mMockTeleManager, mMockCarrierConfigManager, mMockEuiccManager, - mMockConnectivityManager, mMockONSProfileConfigurator, mMockONSProfileDownloader); + mMockConnectivityManager, mMockONSProfileConfigurator, mMockONSProfileDownloader, + mMockONSStats); assertEquals(ONSProfileActivator.Result.ERR_CARRIER_DOESNT_SUPPORT_CBRS, onsProfileActivator.handleCarrierConfigChange()); @@ -247,7 +300,7 @@ public class ONSProfileActivatorTest extends ONSBaseTest { @Test //@DisplayName("Dual SIM device with Two PSIM active subscriptions") public void testTwoActivePSIMSubscriptions() { - 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(); @@ -255,69 +308,101 @@ public class ONSProfileActivatorTest extends ONSBaseTest { ArrayList<SubscriptionInfo> mActiveSubInfos = new ArrayList<>(); mActiveSubInfos.add(mMockSubInfo); - mActiveSubInfos.add(mMockSubInfo2); + mActiveSubInfos.add(mMockSubInfo1); doReturn(mActiveSubInfos).when(mMockSubManager).getActiveSubscriptionInfoList(); doReturn(false).when(mMockSubInfo).isEmbedded(); - doReturn(false).when(mMockSubInfo2).isEmbedded(); + doReturn(false).when(mMockSubInfo1).isEmbedded(); ONSProfileActivator onsProfileActivator = new ONSProfileActivator(mMockContext, mMockSubManager, mMockTeleManager, mMockCarrierConfigManager, mMockEuiccManager, - mMockConnectivityManager, mMockONSProfileConfigurator, mMockONSProfileDownloader); + mMockConnectivityManager, mMockONSProfileConfigurator, mMockONSProfileDownloader, + mMockONSStats); assertEquals(ONSProfileActivator.Result.ERR_DUAL_ACTIVE_SUBSCRIPTIONS, onsProfileActivator.handleCarrierConfigChange()); } - /*@Test - //Cannot mock/spy class android.os.PersistableBundle - public void testOneActivePSIMAndOneNonOpportunisticESIM() { - doReturn(true).when(mMockONSUtil).isESIMSupported(); - doReturn(true).when(mMockONSUtil).isMultiSIMPhone(); + @Test + public void testOneCBRSPSIMAndOneNonCBRSESIM() { + 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(mMockSubInfo1); - mActiveSubInfos.add(mMockSubInfo2); doReturn(mActiveSubInfos).when(mMockSubManager).getActiveSubscriptionInfoList(); - doReturn(false).when(mMockSubInfo1).isEmbedded(); - doReturn(true).when(mMockSubInfo2).isEmbedded(); - //0 - using carrier-id=0 to make sure it doesn't map to any opportunistic carrier-id - doReturn(0).when(mMockSubInfo2).getCarrierId(); + doReturn(false).when(mMockSubInfo).isEmbedded(); + doReturn(true).when(mMockSubInfo1).isEmbedded(); + doReturn(TEST_SUBID_0).when(mMockSubInfo).getSubscriptionId(); + doReturn(TEST_SUBID_1).when(mMockSubInfo1).getSubscriptionId(); + + PersistableBundle persistableBundle = new PersistableBundle(); + persistableBundle.putBoolean(CarrierConfigManager + .KEY_CARRIER_SUPPORTS_OPP_DATA_AUTO_PROVISIONING_BOOL, false); + doReturn(persistableBundle).when(mMockCarrierConfigManager).getConfigForSubId(TEST_SUBID_0); ONSProfileActivator onsProfileActivator = new ONSProfileActivator(mMockContext, - mMockONSProfileConfigurator, mMockONSProfileDownloader); + mMockSubManager, mMockTeleManager, mMockCarrierConfigManager, mMockEuiccManager, + mMockConnectivityManager, mMockONSProfileConfigurator, mMockONSProfileDownloader, + mMockONSStats); assertEquals(ONSProfileActivator.Result.ERR_DUAL_ACTIVE_SUBSCRIPTIONS, - onsProfileActivator.handleSimStateChange()); - }*/ + onsProfileActivator.handleCarrierConfigChange()); + } + + @Test + public void testOneCBRSPSIMAndOneOpportunisticESIM() { + 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(); - /*@Test - //Cannot mock/spy class android.os.PersistableBundle - public void testOneActivePSIMAndOneOpportunisticESIM() { - doReturn(true).when(mMockONSUtil).isESIMSupported(); - doReturn(true).when(mMockONSUtil).isMultiSIMPhone(); ArrayList<SubscriptionInfo> mActiveSubInfos = new ArrayList<>(); - mActiveSubInfos.add(mMockSubInfo1); - mActiveSubInfos.add(mMockSubInfo2); + mActiveSubInfos.add(mMockSubInfo); //Primary CBRS SIM + mActiveSubInfos.add(mMockSubInfo1); //Opportunistic eSIM doReturn(mActiveSubInfos).when(mMockSubManager).getActiveSubscriptionInfoList(); - doReturn(false).when(mMockSubInfo1).isEmbedded(); - doReturn(true).when(mMockSubInfo2).isEmbedded(); - doReturn(1).when(mMockSubInfo2).getSubscriptionId(); - doReturn(mMockCarrierConfig).when(mMockCarrierConfigManager).getConfigForSubId(1); - doReturn(new int[]{1}).when(mMockCarrierConfig).get( - CarrierConfigManager.KEY_OPPORTUNISTIC_CARRIER_IDS_INT_ARRAY); - //1 - using carrier-id=1 to match with opportunistic carrier-id - doReturn(1).when(mMockSubInfo2).getCarrierId(); + doReturn(mActiveSubInfos).when(mMockSubManager).getAvailableSubscriptionInfoList(); + + doReturn(mMockSubInfo).when(mMockSubManager).getActiveSubscriptionInfo(TEST_SUBID_0); + doReturn(TEST_SUBID_0).when(mMockSubInfo).getSubscriptionId(); + doReturn(true).when(mMockSubManager).isActiveSubscriptionId(TEST_SUBID_0); + doReturn(false).when(mMockSubInfo).isOpportunistic(); + doReturn(false).when(mMockSubInfo).isEmbedded(); + ParcelUuid pSIMSubGroupId = new ParcelUuid(new UUID(0, 1)); + doReturn(pSIMSubGroupId).when(mMockSubInfo).getGroupUuid(); + PersistableBundle persistableBundle = new PersistableBundle(); + persistableBundle.putBoolean(CarrierConfigManager + .KEY_CARRIER_SUPPORTS_OPP_DATA_AUTO_PROVISIONING_BOOL, true); + persistableBundle.putIntArray(CarrierConfigManager + .KEY_OPPORTUNISTIC_CARRIER_IDS_INT_ARRAY, new int[]{1, 2}); + doReturn(persistableBundle).when(mMockCarrierConfigManager).getConfigForSubId(TEST_SUBID_0); + + doReturn(mMockSubInfo1).when(mMockSubManager).getActiveSubscriptionInfo(TEST_SUBID_1); + doReturn(TEST_SUBID_1).when(mMockSubInfo1).getSubscriptionId(); + doReturn(true).when(mMockSubManager).isActiveSubscriptionId(TEST_SUBID_1); + doReturn(true).when(mMockSubInfo1).isOpportunistic(); + doReturn(true).when(mMockSubInfo1).isEmbedded(); + doReturn(pSIMSubGroupId).when(mMockSubInfo1).getGroupUuid(); + doReturn(1).when(mMockSubInfo1).getCarrierId(); + + doReturn(mMockSubInfo1).when(mMockONSProfileConfigurator) + .findOpportunisticSubscription(TEST_SUBID_0); ONSProfileActivator onsProfileActivator = new ONSProfileActivator(mMockContext, - mMockONSProfileConfigurator, mMockONSProfileDownloader); + mMockSubManager, mMockTeleManager, mMockCarrierConfigManager, mMockEuiccManager, + mMockConnectivityManager, mMockONSProfileConfigurator, mMockONSProfileDownloader, + mMockONSStats); assertEquals(ONSProfileActivator.Result.SUCCESS, - onsProfileActivator.handleSimStateChange()); - }*/ + onsProfileActivator.handleCarrierConfigChange()); + } @Test //@DisplayName("Dual SIM device with only opportunistic eSIM active") public void testOnlyOpportunisticESIMActive() { - 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(); @@ -329,7 +414,8 @@ public class ONSProfileActivatorTest extends ONSBaseTest { ONSProfileActivator onsProfileActivator = new ONSProfileActivator(mMockContext, mMockSubManager, mMockTeleManager, mMockCarrierConfigManager, mMockEuiccManager, - mMockConnectivityManager, mMockONSProfileConfigurator, mMockONSProfileDownloader); + mMockConnectivityManager, mMockONSProfileConfigurator, mMockONSProfileDownloader, + mMockONSStats); assertEquals(ONSProfileActivator.Result.ERR_SINGLE_ACTIVE_OPPORTUNISTIC_SIM, onsProfileActivator.handleCarrierConfigChange()); @@ -338,30 +424,28 @@ public class ONSProfileActivatorTest extends ONSBaseTest { @Test //@DisplayName("Dual SIM device, only CBRS carrier pSIM inserted and pSIM not Grouped") public void testCBRSpSIMAndNotGrouped() { - 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(TEST_SUBID_1).when(mMockSubInfo).getSubscriptionId(); doReturn(null).when(mMockSubInfo).getGroupUuid(); + doReturn(ONSProfileDownloader.DownloadProfileResult.SUCCESS).when(mMockONSProfileDownloader) + .downloadProfile(TEST_SUBID_1); ONSProfileActivator onsProfileActivator = new ONSProfileActivator(mMockContext, mMockSubManager, mMockTeleManager, mMockCarrierConfigManager, mMockEuiccManager, - mMockConnectivityManager, mMockONSProfileConfigurator, mMockONSProfileDownloader); + mMockConnectivityManager, mMockONSProfileConfigurator, mMockONSProfileDownloader, + mMockONSStats); onsProfileActivator.mIsInternetConnAvailable = true; - assertEquals(ONSProfileActivator.Result.SUCCESS, + assertEquals(ONSProfileActivator.Result.DOWNLOAD_REQUESTED, onsProfileActivator.handleCarrierConfigChange()); } @@ -400,8 +484,7 @@ public class ONSProfileActivatorTest extends ONSBaseTest { } }; - ONSProfileDownloaderTest.WorkerThread workerThread = new ONSProfileDownloaderTest - .WorkerThread(runnable); + WorkerThread workerThread = new WorkerThread(runnable); workerThread.start(); synchronized (lock) { @@ -441,7 +524,7 @@ public class ONSProfileActivatorTest extends ONSBaseTest { ONSProfileActivator onsProfileActivator = new ONSProfileActivator(mMockContext, mMockSubManager, mMockEuiCCManager, mMockTeleManager, - mMockONSProfileConfigurator, mMockONSProfileDownloader); + mMockONSProfileConfigurator, mMockONSProfileDownloader, mMockONSStats); assertEquals(ONSProfileActivator.Result.SUCCESS, onsProfileActivator.handleSimStateChange()); @@ -516,7 +599,7 @@ public class ONSProfileActivatorTest extends ONSBaseTest { //TODO: mock ParcelUuid - pSIM group ONSProfileActivator onsProfileActivator = new ONSProfileActivator(mMockContext, - mMockONSProfileConfigurator, mMockONSProfileDownloader); + mMockONSProfileConfigurator, mMockONSProfileDownloader, mMockONSStats); assertEquals(ONSProfileActivator.Result.ERR_INVALID_PSIM_SUBID, onsProfileActivator.retryDownloadAfterReboot()); @@ -537,8 +620,88 @@ public class ONSProfileActivatorTest extends ONSBaseTest { verify(mMockEUICCManager, never()).downloadSubscription(null, true, null); }*/ + @Test + public void testESIMDownloadFailureAndRetry() { + 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(ONSProfileDownloader.DownloadProfileResult.SUCCESS).when(mMockONSProfileDownloader) + .downloadProfile(TEST_SUBID_0); + + doReturn(mMockactiveSubInfos).when(mMockSubManager).getActiveSubscriptionInfoList(); + doReturn(1).when(mMockactiveSubInfos).size(); + doReturn(mMockSubInfo).when(mMockactiveSubInfos).get(0); + doReturn(false).when(mMockSubInfo).isOpportunistic(); + doReturn(TEST_SUBID_0).when(mMockSubInfo).getSubscriptionId(); + doReturn(null).when(mMockSubInfo).getGroupUuid(); + + final int maxRetryCount = 5; + final int retryBackoffTime = 1; //1 second + + PersistableBundle persistableBundle = new PersistableBundle(); + persistableBundle.putBoolean(CarrierConfigManager + .KEY_CARRIER_SUPPORTS_OPP_DATA_AUTO_PROVISIONING_BOOL, true); + persistableBundle.putInt(CarrierConfigManager + .KEY_ESIM_MAX_DOWNLOAD_RETRY_ATTEMPTS_INT, maxRetryCount); + persistableBundle.putInt(CarrierConfigManager + .KEY_ESIM_DOWNLOAD_RETRY_BACKOFF_TIMER_SEC_INT, retryBackoffTime); + doReturn(persistableBundle).when(mMockCarrierConfigManager).getConfigForSubId(TEST_SUBID_0); + + final Object lock = new Object(); + class TestRunnable implements Runnable { + public ONSProfileActivator mOnsProfileActivator; + + @Override + public void run() { + mOnsProfileActivator = new ONSProfileActivator(mMockContext, + mMockSubManager, mMockTeleManager, mMockCarrierConfigManager, + mMockEuiccManager, mMockConnectivityManager, mMockONSProfileConfigurator, + mMockONSProfileDownloader, mMockONSStats); + + synchronized (lock) { + lock.notify(); + } + } + } + + TestRunnable runnable = new TestRunnable(); + WorkerThread workerThread = new WorkerThread(runnable); + workerThread.start(); + + synchronized (lock) { + try { + lock.wait(); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + + ONSProfileActivator onsProfileActivator = runnable.mOnsProfileActivator; + onsProfileActivator.mIsInternetConnAvailable = true; + + for (int idx = 0; idx <= maxRetryCount; idx++) { + onsProfileActivator.onDownloadError( + TEST_SUBID_0, + ONSProfileDownloader.DownloadRetryResultCode.ERR_RETRY_DOWNLOAD, 0); + + //Wait for Handler to process download message. Backoff delay + 500 milli secs. + try { + Thread.sleep(onsProfileActivator.calculateBackoffDelay( + onsProfileActivator.mDownloadRetryCount, retryBackoffTime) + 1000); + } catch (Exception e) { + e.printStackTrace(); + } + } + + workerThread.exit(); + + verify(mMockONSProfileDownloader, times(maxRetryCount)).downloadProfile(TEST_SUBID_0); + } + @After public void tearDown() throws Exception { super.tearDown(); } -}
\ No newline at end of file +} + diff --git a/tests/src/com/android/ons/ONSProfileConfiguratorTest.java b/tests/src/com/android/ons/ONSProfileConfiguratorTest.java index 394a3ae..7c88658 100644 --- a/tests/src/com/android/ons/ONSProfileConfiguratorTest.java +++ b/tests/src/com/android/ons/ONSProfileConfiguratorTest.java @@ -97,6 +97,22 @@ public class ONSProfileConfiguratorTest extends ONSBaseTest { } @Test + public void testAlreadyGroupedSubscriptions() { + doReturn(TEST_SUB_ID).when(mMockSubscriptionInfo1).getSubscriptionId(); + doReturn(true).when(mMockSubscriptionInfo1).isOpportunistic(); + + ONSProfileConfigurator mOnsProfileConfigurator = new ONSProfileConfigurator(mContext, + mMockSubManager, mMockCarrierConfigManager, mMockEuiccMngr, mMockConfigListener); + + ParcelUuid uuid = new ParcelUuid(new UUID(1, 2)); + doReturn(uuid).when(mMockSubscriptionInfo1).getGroupUuid(); + + mOnsProfileConfigurator.groupWithPSIMAndSetOpportunistic(mMockSubscriptionInfo1, uuid); + + verifyNoMoreInteractions(mMockSubManager); + } + + @Test public void testActivateSubscription() { ONSProfileConfigurator mOnsProfileConfigurator = new ONSProfileConfigurator(mContext, mMockSubManager, mMockCarrierConfigManager, mMockEuiccMngr, mMockConfigListener); @@ -115,7 +131,7 @@ public class ONSProfileConfiguratorTest extends ONSBaseTest { PendingIntent.FLAG_IMMUTABLE); mOnsProfileConfigurator.activateSubscription(TEST_SUB_ID); - verify(mMockSubManager).switchToSubscription(TEST_SUB_ID, callbackIntent); + verify(mMockEuiccMngr).switchToSubscription(TEST_SUB_ID, callbackIntent); } @Test diff --git a/tests/src/com/android/ons/ONSProfileDownloaderTest.java b/tests/src/com/android/ons/ONSProfileDownloaderTest.java index f37ef1e..e82df6a 100644 --- a/tests/src/com/android/ons/ONSProfileDownloaderTest.java +++ b/tests/src/com/android/ons/ONSProfileDownloaderTest.java @@ -16,9 +16,12 @@ package com.android.ons; +import static org.mockito.Mockito.any; import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.eq; import static org.mockito.Mockito.never; +import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyZeroInteractions; @@ -33,6 +36,8 @@ import android.telephony.euicc.EuiccManager; import android.util.Log; import android.util.Pair; +import com.android.ons.ONSProfileDownloader.DownloadProfileResult; + import org.junit.After; import org.junit.Before; import org.junit.Test; @@ -42,7 +47,7 @@ import org.mockito.MockitoAnnotations; public class ONSProfileDownloaderTest extends ONSBaseTest { private static final String TAG = ONSProfileDownloaderTest.class.getName(); private static final int TEST_SUB_ID = 1; - private static final String TEST_SMDP_ADDRESS = "LPA:1$TEST-ESIM.COM$"; + private static final String TEST_SMDP_ADDRESS = "TEST-ESIM.COM"; @Mock Context mMockContext; @@ -117,8 +122,9 @@ public class ONSProfileDownloaderTest extends ONSBaseTest { @Override public void onDownloadError( - ONSProfileDownloader.DownloadRetryOperationCode operationCode, - int pSIMSubId) { + int pSIMSubId, + ONSProfileDownloader.DownloadRetryResultCode operationCode, + int detailedErrorCode) { } }; @@ -233,8 +239,7 @@ public class ONSProfileDownloaderTest extends ONSBaseTest { } verify(mMockDownloadListener).onDownloadError( - ONSProfileDownloader.DownloadRetryOperationCode.ERR_MEMORY_FULL, - TEST_SUB_ID); + TEST_SUB_ID, ONSProfileDownloader.DownloadRetryResultCode.ERR_MEMORY_FULL, 0); workerThread.exit(); } @@ -246,8 +251,7 @@ public class ONSProfileDownloaderTest extends ONSBaseTest { 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); + TEST_SUB_ID, ONSProfileDownloader.DownloadRetryResultCode.ERR_RETRY_DOWNLOAD, 0); Runnable runnable = new Runnable() { @Override @@ -288,8 +292,7 @@ public class ONSProfileDownloaderTest extends ONSBaseTest { .getEncodedActivationCode(); verify(mMockDownloadListener).onDownloadError( - ONSProfileDownloader.DownloadRetryOperationCode.ERR_RETRY_DOWNLOAD, - TEST_SUB_ID); + TEST_SUB_ID, ONSProfileDownloader.DownloadRetryResultCode.ERR_RETRY_DOWNLOAD, 0); workerThread.exit(); } @@ -302,8 +305,7 @@ public class ONSProfileDownloaderTest extends ONSBaseTest { 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); + TEST_SUB_ID, ONSProfileDownloader.DownloadRetryResultCode.ERR_RETRY_DOWNLOAD, 0); Runnable runnable = new Runnable() { @Override @@ -344,8 +346,7 @@ public class ONSProfileDownloaderTest extends ONSBaseTest { .getEncodedActivationCode(); verify(mMockDownloadListener).onDownloadError( - ONSProfileDownloader.DownloadRetryOperationCode.ERR_RETRY_DOWNLOAD, - TEST_SUB_ID); + TEST_SUB_ID, ONSProfileDownloader.DownloadRetryResultCode.ERR_RETRY_DOWNLOAD, 0); workerThread.exit(); } @@ -358,8 +359,7 @@ public class ONSProfileDownloaderTest extends ONSBaseTest { 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); + TEST_SUB_ID, ONSProfileDownloader.DownloadRetryResultCode.ERR_RETRY_DOWNLOAD, 0); Runnable runnable = new Runnable() { @Override @@ -400,8 +400,7 @@ public class ONSProfileDownloaderTest extends ONSBaseTest { .getEncodedActivationCode(); verify(mMockDownloadListener).onDownloadError( - ONSProfileDownloader.DownloadRetryOperationCode.ERR_RETRY_DOWNLOAD, - TEST_SUB_ID); + TEST_SUB_ID, ONSProfileDownloader.DownloadRetryResultCode.ERR_RETRY_DOWNLOAD, 0); workerThread.exit(); } @@ -414,8 +413,7 @@ public class ONSProfileDownloaderTest extends ONSBaseTest { 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); + TEST_SUB_ID, ONSProfileDownloader.DownloadRetryResultCode.ERR_RETRY_DOWNLOAD, 0); Runnable runnable = new Runnable() { @Override @@ -450,8 +448,7 @@ public class ONSProfileDownloaderTest extends ONSBaseTest { } verify(mMockDownloadListener).onDownloadError( - ONSProfileDownloader.DownloadRetryOperationCode.ERR_UNRESOLVABLE, - TEST_SUB_ID); + TEST_SUB_ID, ONSProfileDownloader.DownloadRetryResultCode.ERR_UNRESOLVABLE, 0); workerThread.exit(); } @@ -469,51 +466,51 @@ public class ONSProfileDownloaderTest extends ONSBaseTest { ONSProfileDownloader.DownloadHandler downloadHandler = onsProfileDownloader.new DownloadHandler(); - ONSProfileDownloader.DownloadRetryOperationCode res = + ONSProfileDownloader.DownloadRetryResultCode res = downloadHandler.mapDownloaderErrorCode( EuiccManager.EMBEDDED_SUBSCRIPTION_RESULT_OK, 0, 0, 0); assertEquals( - ONSProfileDownloader.DownloadRetryOperationCode.DOWNLOAD_SUCCESSFUL, res); + ONSProfileDownloader.DownloadRetryResultCode.DOWNLOAD_SUCCESSFUL, res); res = downloadHandler.mapDownloaderErrorCode( EuiccManager.EMBEDDED_SUBSCRIPTION_RESULT_RESOLVABLE_ERROR, 0, EuiccManager.OPERATION_EUICC_GSMA, EuiccManager.ERROR_EUICC_INSUFFICIENT_MEMORY); - assertEquals(ONSProfileDownloader.DownloadRetryOperationCode + assertEquals(ONSProfileDownloader.DownloadRetryResultCode .ERR_MEMORY_FULL, res); res = downloadHandler.mapDownloaderErrorCode( EuiccManager.EMBEDDED_SUBSCRIPTION_RESULT_RESOLVABLE_ERROR, 0, EuiccManager.OPERATION_SIM_SLOT, EuiccManager.ERROR_TIME_OUT); - assertEquals(ONSProfileDownloader.DownloadRetryOperationCode + assertEquals(ONSProfileDownloader.DownloadRetryResultCode .ERR_RETRY_DOWNLOAD, res); res = downloadHandler.mapDownloaderErrorCode( EuiccManager.EMBEDDED_SUBSCRIPTION_RESULT_RESOLVABLE_ERROR, 0, EuiccManager.OPERATION_SMDX, EuiccManager.ERROR_CONNECTION_ERROR); - assertEquals(ONSProfileDownloader.DownloadRetryOperationCode + assertEquals(ONSProfileDownloader.DownloadRetryResultCode .ERR_RETRY_DOWNLOAD, res); res = downloadHandler.mapDownloaderErrorCode( EuiccManager.EMBEDDED_SUBSCRIPTION_RESULT_RESOLVABLE_ERROR, 0, EuiccManager.OPERATION_SMDX, EuiccManager.ERROR_INVALID_RESPONSE); - assertEquals(ONSProfileDownloader.DownloadRetryOperationCode + assertEquals(ONSProfileDownloader.DownloadRetryResultCode .ERR_UNRESOLVABLE, res); res = downloadHandler.mapDownloaderErrorCode( EuiccManager.EMBEDDED_SUBSCRIPTION_RESULT_ERROR, 0, EuiccManager.OPERATION_SMDX, EuiccManager.ERROR_INVALID_RESPONSE); - assertEquals(ONSProfileDownloader.DownloadRetryOperationCode + assertEquals(ONSProfileDownloader.DownloadRetryResultCode .ERR_UNRESOLVABLE, res); res = downloadHandler.mapDownloaderErrorCode( EuiccManager.EMBEDDED_SUBSCRIPTION_RESULT_ERROR, 0xA810048, EuiccManager.OPERATION_SMDX_SUBJECT_REASON_CODE, 0); - assertEquals(ONSProfileDownloader.DownloadRetryOperationCode + assertEquals(ONSProfileDownloader.DownloadRetryResultCode .ERR_MEMORY_FULL, res); synchronized (lock) { @@ -595,6 +592,99 @@ public class ONSProfileDownloaderTest extends ONSBaseTest { workerThread.exit(); } + @Test + public void testMultipleDownloadRequests() { + doReturn(TEST_SUB_ID).when(mMockSubInfo).getSubscriptionId(); + PersistableBundle config = new PersistableBundle(); + config.putString(CarrierConfigManager.KEY_SMDP_SERVER_ADDRESS_STRING, TEST_SMDP_ADDRESS); + doReturn(config).when(mMockCarrierConfigManager).getConfigForSubId(TEST_SUB_ID); + + ONSProfileDownloader onsProfileDownloader = new ONSProfileDownloader(mContext, + mMockCarrierConfigManager, mMockEUICCManager, mMockONSProfileConfig, + mMockDownloadListener); + + //When multiple download requests are received, download should be triggered only once. + onsProfileDownloader.downloadProfile(mMockSubInfo.getSubscriptionId()); + onsProfileDownloader.downloadProfile(mMockSubInfo.getSubscriptionId()); + onsProfileDownloader.downloadProfile(mMockSubInfo.getSubscriptionId()); + onsProfileDownloader.downloadProfile(mMockSubInfo.getSubscriptionId()); + verify(mMockEUICCManager, times(1)).downloadSubscription(any(), eq(true), any()); + + //Simulate response for download request from LPA. + Intent intent = new Intent(mContext, ONSProfileResultReceiver.class); + 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); + intent.putExtra(EuiccManager.EXTRA_EMBEDDED_SUBSCRIPTION_OPERATION_CODE, + EuiccManager.OPERATION_DOWNLOAD); + + onsProfileDownloader.onCallbackIntentReceived(intent, + EuiccManager.EMBEDDED_SUBSCRIPTION_RESULT_OK); + + //Trigger new download after a sec + try { + Thread.sleep(1000); + } catch (Exception e) { + e.printStackTrace(); + } + + //After download response is received, new download requests should be processed. + onsProfileDownloader.downloadProfile(mMockSubInfo.getSubscriptionId()); + onsProfileDownloader.downloadProfile(mMockSubInfo.getSubscriptionId()); + onsProfileDownloader.downloadProfile(mMockSubInfo.getSubscriptionId()); + onsProfileDownloader.downloadProfile(mMockSubInfo.getSubscriptionId()); + verify(mMockEUICCManager, times(1)).downloadSubscription(any(), eq(true), any()); + } + + @Test + public void testDownloadRequestFailures() { + doReturn(TEST_SUB_ID).when(mMockSubInfo).getSubscriptionId(); + PersistableBundle invalidConfig = new PersistableBundle(); + invalidConfig.putString(CarrierConfigManager.KEY_SMDP_SERVER_ADDRESS_STRING, ""); + + PersistableBundle validConfig = new PersistableBundle(); + validConfig.putString( + CarrierConfigManager.KEY_SMDP_SERVER_ADDRESS_STRING, TEST_SMDP_ADDRESS); + + // Only the first download request, will receive invalid SMDP server address. + doReturn(invalidConfig, validConfig) + .when(mMockCarrierConfigManager) + .getConfigForSubId(TEST_SUB_ID); + + ONSProfileDownloader onsProfileDownloader = + new ONSProfileDownloader( + mContext, + mMockCarrierConfigManager, + mMockEUICCManager, + mMockONSProfileConfig, + mMockDownloadListener); + + // First download request to be failed with INVALID_SMDP_ADDRESS error because of empty SMDP + // server address in configuration. + DownloadProfileResult retryResultCode = + onsProfileDownloader.downloadProfile(mMockSubInfo.getSubscriptionId()); + assertEquals(DownloadProfileResult.INVALID_SMDP_ADDRESS, retryResultCode); + + verify(mMockEUICCManager, never()).downloadSubscription(any(), eq(true), any()); + + // Second Download request should be success and processed to EuiccManager. + retryResultCode = onsProfileDownloader.downloadProfile(mMockSubInfo.getSubscriptionId()); + assertEquals(DownloadProfileResult.SUCCESS, retryResultCode); + verify(mMockEUICCManager).downloadSubscription(any(), eq(true), any()); + + // Since download request is in progress, no further request to be sent to EuiccManager. + // They should return with DUPLICATE_REQUEST error. + retryResultCode = onsProfileDownloader.downloadProfile(mMockSubInfo.getSubscriptionId()); + assertEquals(DownloadProfileResult.DUPLICATE_REQUEST, retryResultCode); + + retryResultCode = onsProfileDownloader.downloadProfile(mMockSubInfo.getSubscriptionId()); + assertEquals(DownloadProfileResult.DUPLICATE_REQUEST, retryResultCode); + + verify(mMockEUICCManager).downloadSubscription(any(), eq(true), any()); + } + @After public void tearDown() throws Exception { super.tearDown(); diff --git a/tests/src/com/android/ons/ONSProfileSelectorTest.java b/tests/src/com/android/ons/ONSProfileSelectorTest.java index e86726a..68925f7 100644 --- a/tests/src/com/android/ons/ONSProfileSelectorTest.java +++ b/tests/src/com/android/ons/ONSProfileSelectorTest.java @@ -25,11 +25,16 @@ import android.os.Looper; import android.os.ServiceManager; import android.telephony.AvailableNetworkInfo; import android.telephony.CellIdentityLte; +import android.telephony.CellIdentityNr; import android.telephony.CellInfo; import android.telephony.CellInfoLte; +import android.telephony.CellInfoNr; import android.telephony.SubscriptionInfo; import android.telephony.SubscriptionManager; import android.telephony.TelephonyManager; +import android.telephony.UiccCardInfo; +import android.telephony.UiccPortInfo; +import android.telephony.euicc.EuiccManager; import android.util.Log; import com.android.internal.telephony.ISub; @@ -43,6 +48,7 @@ import org.mockito.MockitoAnnotations; import java.lang.reflect.Field; import java.util.ArrayList; +import java.util.Collections; import java.util.List; import java.util.Map; @@ -54,6 +60,8 @@ public class ONSProfileSelectorTest extends ONSBaseTest { private int mDataSubId; private int mResult; @Mock + EuiccManager mMockEuiccManager; + @Mock ONSNetworkScanCtlr mONSNetworkScanCtlr; @Mock TelephonyManager mSubscriptionBoundTelephonyManager; @@ -160,6 +168,18 @@ public class ONSProfileSelectorTest extends ONSBaseTest { ArrayList<AvailableNetworkInfo> availableNetworkInfos = new ArrayList<AvailableNetworkInfo>(); availableNetworkInfos.add(availableNetworkInfo); + UiccPortInfo uiccPortInfo = new UiccPortInfo("", 1, 1, false); + ArrayList<UiccPortInfo> uiccPortInfoList = new ArrayList<>(); + uiccPortInfoList.add(uiccPortInfo); + + UiccCardInfo uiccCardInfo = new UiccCardInfo(true, 1, "", 0, false, true, uiccPortInfoList); + ArrayList<UiccCardInfo> uiccCardInfoList = new ArrayList<>(); + uiccCardInfoList.add(uiccCardInfo); + + doReturn(uiccCardInfoList).when(mMockTelephonyManager).getUiccCardsInfo(); + doReturn(mMockEuiccManager).when(mMockEuiccManager).createForCardId(1); + doReturn(true).when(mMockEuiccManager).isSimPortAvailable(1); + IUpdateAvailableNetworksCallback mCallback = new IUpdateAvailableNetworksCallback.Stub() { @Override public void onComplete(int result) { @@ -180,6 +200,8 @@ public class ONSProfileSelectorTest extends ONSBaseTest { .getOpportunisticSubscriptions(); mONSProfileSelector = new MyONSProfileSelector(mContext, mONSProfileSelectionCallback); + mONSProfileSelector.mTelephonyManager = mMockTelephonyManager; + mONSProfileSelector.mEuiccManager = mMockEuiccManager; mONSProfileSelector.updateOppSubs(); mONSProfileSelector.startProfileSelection(availableNetworkInfos, mCallback); mLooper = Looper.myLooper(); @@ -203,13 +225,17 @@ public class ONSProfileSelectorTest extends ONSBaseTest { @Test public void testStartProfileSelectionSuccess() { int subId = 5; - List<SubscriptionInfo> subscriptionInfoList = new ArrayList<SubscriptionInfo>(); - SubscriptionInfo subscriptionInfo = new SubscriptionInfo(subId, "", 1, "TMO", "TMO", 1, 1, - "123", 1, null, "310", "210", "", false, null, "1"); - SubscriptionInfo subscriptionInfo2 = new SubscriptionInfo(5, "", 1, "TMO", "TMO", 1, 1, - "123", 1, null, "310", "211", "", false, null, "1"); - subscriptionInfoList.add(subscriptionInfo); - doReturn(subscriptionInfo).when(mSubscriptionManager).getActiveSubscriptionInfo(subId); + List<SubscriptionInfo> activeSubscriptionInfoList = new ArrayList<SubscriptionInfo>(); + List<SubscriptionInfo> oppSubscriptionInfoList = new ArrayList<SubscriptionInfo>(); + SubscriptionInfo subscriptionInfo1 = new SubscriptionInfo(subId, "", 1, "TMO", "TMO", 1, 1, + "123", 1, null, "310", "210", "", true, null, "1", 1, true, null, false, 1, 1, 1, + null, null, false, 0); + SubscriptionInfo subscriptionInfo2 = new SubscriptionInfo(6, "", 1, "TMO", "TMO", 1, 1, + "123", 1, null, "310", "211", "", true, null, "1", 1, false, null, false, 1, 1, 1, + null, null, false, 0); + oppSubscriptionInfoList.add(subscriptionInfo1); + activeSubscriptionInfoList.add(subscriptionInfo1); + activeSubscriptionInfoList.add(subscriptionInfo2); List<CellInfo> results2 = new ArrayList<CellInfo>(); CellIdentityLte cellIdentityLte = new CellIdentityLte(310, 210, 1, 1, 1); @@ -236,8 +262,14 @@ public class ONSProfileSelectorTest extends ONSBaseTest { @Override public void run() { Looper.prepare(); - doReturn(subscriptionInfoList).when(mSubscriptionManager) + doReturn(subscriptionInfo1).when(mSubscriptionManager) + .getActiveSubscriptionInfo(subId); + doReturn(oppSubscriptionInfoList).when(mSubscriptionManager) .getOpportunisticSubscriptions(); + doReturn(activeSubscriptionInfoList).when(mSubscriptionManager) + .getActiveSubscriptionInfoList(); + doReturn(activeSubscriptionInfoList).when(mSubscriptionManager) + .getCompleteActiveSubscriptionInfoList(); doReturn(true).when(mSubscriptionManager).isActiveSubId(subId); doReturn(true).when(mSubscriptionBoundTelephonyManager).enableModemForSlot( anyInt(), anyBoolean()); @@ -280,13 +312,18 @@ public class ONSProfileSelectorTest extends ONSBaseTest { List<SubscriptionInfo> subscriptionInfoList = new ArrayList<SubscriptionInfo>(); SubscriptionInfo subscriptionInfo = new SubscriptionInfo(5, "", 1, "TMO", "TMO", 1, 1, - "123", 1, null, "310", "210", "", false, null, "1"); + "123", 1, null, "310", "210", "", true, null, "1", 1, true, null, false, 1, 1, 1, + null, null, false, 0); subscriptionInfoList.add(subscriptionInfo); SubscriptionInfo subscriptionInfo_2 = new SubscriptionInfo(8, "", 1, "Vzw", "Vzw", 1, 1, - "123", 1, null, "311", "480", "", false, null, "1"); + "456", 1, null, "311", "480", "", true, null, "1", 1, true, null, false, 1, 1, 1, + null, null, false, 1); subscriptionInfoList.add(subscriptionInfo_2); doReturn(subscriptionInfo).when(mSubscriptionManager).getActiveSubscriptionInfo(5); doReturn(subscriptionInfo_2).when(mSubscriptionManager).getActiveSubscriptionInfo(8); + doReturn(subscriptionInfoList).when(mSubscriptionManager) + .getCompleteActiveSubscriptionInfoList(); + doReturn(subscriptionInfoList).when(mSubscriptionManager).getOpportunisticSubscriptions(); List<CellInfo> results2 = new ArrayList<CellInfo>(); CellIdentityLte cellIdentityLte = new CellIdentityLte(310, 210, 1, 1, 1); @@ -323,8 +360,6 @@ public class ONSProfileSelectorTest extends ONSBaseTest { @Override public void run() { Looper.prepare(); - doReturn(subscriptionInfoList).when(mSubscriptionManager) - .getOpportunisticSubscriptions(); doReturn(true).when(mSubscriptionManager).isActiveSubId(anyInt()); doReturn(true).when(mSubscriptionBoundTelephonyManager).enableModemForSlot( anyInt(), anyBoolean()); @@ -354,13 +389,16 @@ public class ONSProfileSelectorTest extends ONSBaseTest { public void testStartProfileSelectionWithActivePrimarySimOnESim() { List<SubscriptionInfo> opportunisticSubscriptionInfoList = new ArrayList<SubscriptionInfo>(); List<SubscriptionInfo> activeSubscriptionInfoList = new ArrayList<SubscriptionInfo>(); - SubscriptionInfo subscriptionInfo = new SubscriptionInfo(5, "", 1, "TMO", "TMO", 1, 1, - "123", 1, null, "310", "210", "", true, null, "1", true, null, 1839, 1); + SubscriptionInfo subscriptionInfo1 = new SubscriptionInfo(5, "", 1, "TMO", "TMO", 1, 1, + "123", 1, null, "310", "210", "", true, null, "1", 1, true, null, false, 1839, 1, + 1, null, null, false, 1); SubscriptionInfo subscriptionInfo2 = new SubscriptionInfo(6, "", 1, "TMO", "TMO", 1, 1, - "123", 1, null, "310", "211", "", true, null, "1", false, null, 1839, 1); - opportunisticSubscriptionInfoList.add(subscriptionInfo); + "456", 1, null, "310", "211", "", true, null, "1", 1, false, null, false, 1839, 1, + 1, null, null, false, 2); + + activeSubscriptionInfoList.add(subscriptionInfo1); activeSubscriptionInfoList.add(subscriptionInfo2); - doReturn(subscriptionInfo).when(mSubscriptionManager).getActiveSubscriptionInfo(5); + doReturn(subscriptionInfo1).when(mSubscriptionManager).getActiveSubscriptionInfo(5); doReturn(subscriptionInfo2).when(mSubscriptionManager).getActiveSubscriptionInfo(6); ArrayList<String> mccMncs = new ArrayList<>(); @@ -370,6 +408,19 @@ public class ONSProfileSelectorTest extends ONSBaseTest { ArrayList<AvailableNetworkInfo> availableNetworkInfos = new ArrayList<AvailableNetworkInfo>(); availableNetworkInfos.add(availableNetworkInfo); + ArrayList<UiccPortInfo> uiccPortInfoList = new ArrayList<>(); + uiccPortInfoList.add(new UiccPortInfo("1", 0, 0, false)); + uiccPortInfoList.add(new UiccPortInfo("2", 1, 1, true)); + + UiccCardInfo uiccCardInfo = new UiccCardInfo( + true, 1, "1", 0, false, true, uiccPortInfoList); + ArrayList<UiccCardInfo> uiccCardInfoList = new ArrayList<>(); + uiccCardInfoList.add(uiccCardInfo); + + doReturn(uiccCardInfoList).when(mMockTelephonyManager).getUiccCardsInfo(); + doReturn(mMockEuiccManager).when(mMockEuiccManager).createForCardId(1); + doReturn(true).when(mMockEuiccManager).isSimPortAvailable(1); + IUpdateAvailableNetworksCallback mCallback = new IUpdateAvailableNetworksCallback.Stub() { @Override public void onComplete(int result) { @@ -388,12 +439,18 @@ public class ONSProfileSelectorTest extends ONSBaseTest { doReturn(false).when(mSubscriptionManager).isActiveSubId(anyInt()); doReturn(activeSubscriptionInfoList).when(mSubscriptionManager) .getActiveSubscriptionInfoList(anyBoolean()); + doReturn(activeSubscriptionInfoList).when(mSubscriptionManager) + .getActiveSubscriptionInfoList(); + doReturn(true).when(mSubscriptionBoundTelephonyManager).enableModemForSlot( + anyInt(), anyBoolean()); mONSProfileSelector = new MyONSProfileSelector(mContext, new MyONSProfileSelector.ONSProfileSelectionCallback() { public void onProfileSelectionDone() { setReady(true); } }); + mONSProfileSelector.mTelephonyManager = mMockTelephonyManager; + mONSProfileSelector.mEuiccManager = mMockEuiccManager; mONSProfileSelector.updateOppSubs(); mONSProfileSelector.startProfileSelection(availableNetworkInfos, mCallback); mLooper = Looper.myLooper(); @@ -415,7 +472,8 @@ public class ONSProfileSelectorTest extends ONSBaseTest { callbackIntent.putExtra("sequenceId", 1); callbackIntent.putExtra("subId", 5); waitUntilReady(); - assertEquals(TelephonyManager.UPDATE_AVAILABLE_NETWORKS_INVALID_ARGUMENTS, mResult); + assertEquals(TelephonyManager.UPDATE_AVAILABLE_NETWORKS_NO_OPPORTUNISTIC_SUB_AVAILABLE, + mResult); } public static void waitForMs(long ms) { @@ -559,15 +617,24 @@ public class ONSProfileSelectorTest extends ONSBaseTest { @Test public void testStartProfileSelectionSuccessWithSameArgumentsAgain() { - List<SubscriptionInfo> subscriptionInfoList = new ArrayList<SubscriptionInfo>(); - SubscriptionInfo subscriptionInfo = new SubscriptionInfo(5, "", 1, "TMO", "TMO", 1, 1, - "123", 1, null, "310", "210", "", false, null, "1"); + List<SubscriptionInfo> activeSubscriptionInfoList = new ArrayList<SubscriptionInfo>(); + List<SubscriptionInfo> oppSubscriptionInfoList = new ArrayList<SubscriptionInfo>(); + SubscriptionInfo subscriptionInfo1 = new SubscriptionInfo(5, "", 1, "TMO", "TMO", 1, 1, + "123", 1, null, "310", "210", "", true, null, "1", 1, true, null, false, 1, 1, 1, + null, null, false, 0); SubscriptionInfo subscriptionInfo2 = new SubscriptionInfo(6, "", 1, "TMO", "TMO", 1, 1, - "123", 1, null, "310", "211", "", false, null, "1"); - subscriptionInfoList.add(subscriptionInfo); - doReturn(subscriptionInfo).when(mSubscriptionManager).getActiveSubscriptionInfo(5); + "123", 1, null, "310", "211", "", true, null, "1", 1, false, null, false, 1, 1, 1, + null, null, false, 0); + + oppSubscriptionInfoList.add(subscriptionInfo1); + doReturn(subscriptionInfo1).when(mSubscriptionManager).getActiveSubscriptionInfo(5); doReturn(subscriptionInfo2).when(mSubscriptionManager).getActiveSubscriptionInfo(6); + activeSubscriptionInfoList.add(subscriptionInfo1); + activeSubscriptionInfoList.add(subscriptionInfo2); + doReturn(activeSubscriptionInfoList).when(mSubscriptionManager) + .getCompleteActiveSubscriptionInfoList(); + List<CellInfo> results2 = new ArrayList<CellInfo>(); CellIdentityLte cellIdentityLte = new CellIdentityLte(310, 210, 1, 1, 1); CellInfoLte cellInfoLte = new CellInfoLte(); @@ -599,7 +666,7 @@ public class ONSProfileSelectorTest extends ONSBaseTest { @Override public void run() { Looper.prepare(); - doReturn(subscriptionInfoList).when(mSubscriptionManager) + doReturn(oppSubscriptionInfoList).when(mSubscriptionManager) .getOpportunisticSubscriptions(); doReturn(true).when(mSubscriptionManager).isActiveSubId(anyInt()); doReturn(true).when(mSubscriptionBoundTelephonyManager).enableModemForSlot( @@ -636,7 +703,7 @@ public class ONSProfileSelectorTest extends ONSBaseTest { @Override public void run() { Looper.prepare(); - doReturn(subscriptionInfoList).when(mSubscriptionManager) + doReturn(oppSubscriptionInfoList).when(mSubscriptionManager) .getOpportunisticSubscriptions(); doReturn(true).when(mSubscriptionManager).isActiveSubId(anyInt()); doReturn(true).when(mSubscriptionBoundTelephonyManager).enableModemForSlot( @@ -759,6 +826,233 @@ public class ONSProfileSelectorTest extends ONSBaseTest { }).start(); waitUntilReady(); waitForMs(500); - assertEquals(mONSProfileSelector.getCurrentPreferredData(), 5); + assertEquals(5, mONSProfileSelector.getCurrentPreferredData()); + } + + @Test + public void testAvailablePortWhenTwoPrimarySIMsAreActive() { + /** + * 2 - Primary active subscriptions and + * 1 - Inactive opportunistic subscription + */ + + List<SubscriptionInfo> activeSubscriptionInfoList = new ArrayList<SubscriptionInfo>(); + List<SubscriptionInfo> opportunisticInfoList = new ArrayList<SubscriptionInfo>(); + + SubscriptionInfo oppSubInfo = new SubscriptionInfo(4, "", -1, "TMO", "TMO", 1, 1, + "001", 1, null, "110", "210", "", true, null, "1", 1, true, null, false, 2839, 1, + 1, null, null, false, TelephonyManager.INVALID_PORT_INDEX); + + SubscriptionInfo primarySubInfo1 = new SubscriptionInfo(5, "", 0, "TMO", "TMO", 1, 1, + "123", 1, null, "310", "210", "", true, null, "1", 1, false, null, false, 1839, 1, + 1, null, null, false, 0); + SubscriptionInfo primarySubInfo2 = new SubscriptionInfo(6, "", 0, "TMO", "TMO", 1, 1, + "456", 1, null, "310", "211", "", true, null, "1", 1, false, null, false, 1839, 1, + 1, null, null, false, 1); + + activeSubscriptionInfoList.add(primarySubInfo1); + activeSubscriptionInfoList.add(primarySubInfo2); + opportunisticInfoList.add(oppSubInfo); + + doReturn(opportunisticInfoList).when(mSubscriptionManager).getOpportunisticSubscriptions(); + doReturn(activeSubscriptionInfoList).when(mSubscriptionManager) + .getCompleteActiveSubscriptionInfoList(); + + UiccPortInfo uiccPortInfo1 = new UiccPortInfo("", 0, 0, true); + UiccPortInfo uiccPortInfo2 = new UiccPortInfo("", 1, 0, true); + ArrayList<UiccPortInfo> uiccPortInfoList = new ArrayList<>(); + uiccPortInfoList.add(uiccPortInfo1); + uiccPortInfoList.add(uiccPortInfo2); + + UiccCardInfo uiccCardInfo = new UiccCardInfo(true, 1, "", 0, false, true, uiccPortInfoList); + ArrayList<UiccCardInfo> uiccCardInfoList = new ArrayList<>(); + uiccCardInfoList.add(uiccCardInfo); + + doReturn(uiccCardInfoList).when(mMockTelephonyManager).getUiccCardsInfo(); + doReturn(mMockEuiccManager).when(mMockEuiccManager).createForCardId(1); + doReturn(false).when(mMockEuiccManager).isSimPortAvailable(0); + doReturn(false).when(mMockEuiccManager).isSimPortAvailable(1); + + mONSProfileSelector = new MyONSProfileSelector(mContext, null); + mONSProfileSelector.mTelephonyManager = mMockTelephonyManager; + mONSProfileSelector.mEuiccManager = mMockEuiccManager; + + int portIdx = mONSProfileSelector.getAvailableESIMPortIndex(); + assertEquals(TelephonyManager.INVALID_PORT_INDEX, portIdx); + } + + @Test + public void testAvailablePortWhenOpportunisticEsimIsActive() { + /** + * 1 - Primary active subscriptions and + * 1 - Active opportunistic subscription + */ + + List<SubscriptionInfo> activeSubscriptionInfoList = new ArrayList<SubscriptionInfo>(); + List<SubscriptionInfo> opportunisticInfoList = new ArrayList<SubscriptionInfo>(); + + SubscriptionInfo oppSubInfo = new SubscriptionInfo(5, "", 1, "TMO", "TMO", 1, 1, + "123", 1, null, "310", "210", "", true, null, "1", 1, true, null, false, 1839, 1, + 1, null, null, false, 0); + + SubscriptionInfo primarySubInfo = new SubscriptionInfo(6, "", 1, "TMO", "TMO", 1, 1, + "456", 1, null, "310", "211", "", true, null, "1", 1, false, null, false, 1839, 1, + 1, null, null, false, 1); + + opportunisticInfoList.add(oppSubInfo); + activeSubscriptionInfoList.add(oppSubInfo); + activeSubscriptionInfoList.add(primarySubInfo); + + doReturn(opportunisticInfoList).when(mSubscriptionManager) + .getOpportunisticSubscriptions(); + doReturn(activeSubscriptionInfoList).when(mSubscriptionManager) + .getCompleteActiveSubscriptionInfoList(); + + mONSProfileSelector = new MyONSProfileSelector(mContext, null); + int portIdx = mONSProfileSelector.getAvailableESIMPortIndex(); + assertEquals(0, portIdx); + } + + @Test + public void testAvailablePortWhenTwoOpportunisticEsimsAreActive() { + /** + * 2 - Active opportunistic subscriptions. + */ + + List<SubscriptionInfo> activeSubscriptionInfoList = new ArrayList<SubscriptionInfo>(); + List<SubscriptionInfo> opportunisticInfoList = new ArrayList<SubscriptionInfo>(); + + SubscriptionInfo opportunisticSubInfo1 = new SubscriptionInfo(5, "", 1, "TMO", "TMO", 1, 1, + "123", 1, null, "310", "210", "", true, null, "1", 1, true, null, false, 1839, 1, + 1, null, null, false, 0); + + SubscriptionInfo opportunisticSubInfo2 = new SubscriptionInfo(6, "", 1, "TMO", "TMO", 1, 1, + "456", 1, null, "310", "211", "", true, null, "1", 1, true, null, false, 1839, 1, + 1, null, null, false, 1); + + opportunisticInfoList.add(opportunisticSubInfo1); + opportunisticInfoList.add(opportunisticSubInfo2); + activeSubscriptionInfoList.add(opportunisticSubInfo1); + activeSubscriptionInfoList.add(opportunisticSubInfo2); + + doReturn(opportunisticInfoList).when(mSubscriptionManager) + .getOpportunisticSubscriptions(); + doReturn(activeSubscriptionInfoList).when(mSubscriptionManager) + .getCompleteActiveSubscriptionInfoList(); + + mONSProfileSelector = new MyONSProfileSelector(mContext, null); + int portIdx = mONSProfileSelector.getAvailableESIMPortIndex(); + + /* one of the opportunistic eSIM port should be selected */ + assertTrue(portIdx == 0 || portIdx == 1); + } + + @Test + public void testAvailablePortWhenOpportunisticEsimIsActiveAndInactiveSubscriptions() { + /** + * 1 - Primary active subscription and + * 1 - Active opportunistic subscription and + * 2 - Inactive opportunistic subscriptions + */ + + List<SubscriptionInfo> activeSubscriptionInfoList = new ArrayList<SubscriptionInfo>(); + List<SubscriptionInfo> opportunisticInfoList = new ArrayList<SubscriptionInfo>(); + + SubscriptionInfo opportunisticSubInfo1 = new SubscriptionInfo(5, "", 1, "TMO", "TMO", 1, 1, + "123", 1, null, "310", "210", "", true, null, "1", 1, true, null, false, 1839, 1, + 1, null, null, false, 1); + SubscriptionInfo primarySubInfo = new SubscriptionInfo(6, "", 1, "TMO", "TMO", 1, 1, + "456", 1, null, "310", "211", "", true, null, "1", 1, false, null, false, 1839, 1, + 1, null, null, false, 0); + + SubscriptionInfo opportunisticSubInfo2 = new SubscriptionInfo(7, "", 1, "TMO", "TMO", 1, 1, + "789", 1, null, "310", "210", "", true, null, "1", 1, true, null, false, 1839, 1, + 1, null, null, false, TelephonyManager.INVALID_PORT_INDEX); + + SubscriptionInfo oppSubInfo3 = new SubscriptionInfo(8, "", 1, "TMO", "TMO", 1, 1, + "012", 1, null, "310", "210", "", true, null, "1", 1, true, null, false, 1839, 1, + 1, null, null, false, TelephonyManager.INVALID_PORT_INDEX); + + opportunisticInfoList.add(opportunisticSubInfo1); + opportunisticInfoList.add(opportunisticSubInfo2); + opportunisticInfoList.add(oppSubInfo3); + activeSubscriptionInfoList.add(opportunisticSubInfo1); + activeSubscriptionInfoList.add(primarySubInfo); + + doReturn(opportunisticInfoList).when(mSubscriptionManager) + .getOpportunisticSubscriptions(); + doReturn(activeSubscriptionInfoList).when(mSubscriptionManager) + .getCompleteActiveSubscriptionInfoList(); + + mONSProfileSelector = new MyONSProfileSelector(mContext, null); + int portIdx = mONSProfileSelector.getAvailableESIMPortIndex(); + assertEquals(1, portIdx); + } + + @Test + public void testAvailablePortWhenOnlyInactiveSubscriptions() { + /** + * 1 - Primary inactive subscription and + * 2 - Inactive opportunistic subscriptions + */ + + List<SubscriptionInfo> activeSubscriptionInfoList = new ArrayList<SubscriptionInfo>(); + List<SubscriptionInfo> opportunisticInfoList = new ArrayList<SubscriptionInfo>(); + + SubscriptionInfo oppSubInfo1 = new SubscriptionInfo(5, "", 1, "TMO", "TMO", 1, 1, + "123", 1, null, "310", "210", "", true, null, "1", 1, true, null, false, 1839, 1, + 1, null, null, false, TelephonyManager.INVALID_PORT_INDEX); + + // Not used in activeSubscriptionInfoList or opportunisticInfoList + /*SubscriptionInfo primarySubInfo = new SubscriptionInfo(6, "", 1, "TMO", "TMO", 1, 1, + "456", 1, null, "310", "211", "", true, null, "1", 1, false, null, false, 1839, 1, + 1, null, null, false, 2);*/ + + SubscriptionInfo oppSubInfo2 = new SubscriptionInfo(7, "", 1, "TMO", "TMO", 1, 1, + "789", 1, null, "310", "210", "", true, null, "1", 1, true, null, false, 1839, 1, + 1, null, null, false, TelephonyManager.INVALID_PORT_INDEX); + + opportunisticInfoList.add(oppSubInfo1); + opportunisticInfoList.add(oppSubInfo2); + + doReturn(opportunisticInfoList).when(mSubscriptionManager) + .getOpportunisticSubscriptions(); + doReturn(activeSubscriptionInfoList).when(mSubscriptionManager) + .getCompleteActiveSubscriptionInfoList(); + + UiccPortInfo uiccPortInfo1 = new UiccPortInfo("", 0, 0, false); + UiccPortInfo uiccPortInfo2 = new UiccPortInfo("", 1, 0, false); + ArrayList<UiccPortInfo> uiccPortInfoList = new ArrayList<>(); + uiccPortInfoList.add(uiccPortInfo1); + uiccPortInfoList.add(uiccPortInfo2); + + UiccCardInfo uiccCardInfo = new UiccCardInfo(true, 1, "", 0, false, true, uiccPortInfoList); + ArrayList<UiccCardInfo> uiccCardInfoList = new ArrayList<>(); + uiccCardInfoList.add(uiccCardInfo); + + doReturn(uiccCardInfoList).when(mMockTelephonyManager).getUiccCardsInfo(); + doReturn(mMockEuiccManager).when(mMockEuiccManager).createForCardId(1); + doReturn(true).when(mMockEuiccManager).isSimPortAvailable(0); + doReturn(true).when(mMockEuiccManager).isSimPortAvailable(1); + + mONSProfileSelector = new MyONSProfileSelector(mContext, null); + mONSProfileSelector.mTelephonyManager = mMockTelephonyManager; + mONSProfileSelector.mEuiccManager = mMockEuiccManager; + + int portIdx = mONSProfileSelector.getAvailableESIMPortIndex(); + assertTrue(portIdx == 0 || portIdx == 1); + } + + @Test + public void testGetMncMccFromCellInfoNr() { + mONSProfileSelector = new MyONSProfileSelector(mContext, null); + + CellIdentityNr cellIdentityNr = new CellIdentityNr(0, 0, 0, new int[]{0}, "111", "222", 0, + "", "", Collections.emptyList()); + + CellInfoNr cellinfoNr = new CellInfoNr(0, true, 0, cellIdentityNr, null); + + assertEquals(mONSProfileSelector.getMcc(cellinfoNr), "111"); + assertEquals(mONSProfileSelector.getMnc(cellinfoNr), "222"); } } diff --git a/tests/src/com/android/ons/ONSStatsInfoTest.java b/tests/src/com/android/ons/ONSStatsInfoTest.java new file mode 100644 index 0000000..3cd0456 --- /dev/null +++ b/tests/src/com/android/ons/ONSStatsInfoTest.java @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.ons; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; + +import com.android.ons.ONSProfileActivator.Result; +import com.android.ons.ONSProfileDownloader.DownloadRetryResultCode; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +@RunWith(JUnit4.class) +public class ONSStatsInfoTest { + + @Test + public void testProvisioningResult() { + ONSStatsInfo info; + info = new ONSStatsInfo().setProvisioningResult(Result.ERR_AUTO_PROVISIONING_DISABLED); + assertEquals(Result.ERR_AUTO_PROVISIONING_DISABLED, info.getProvisioningResult()); + assertNull(info.getDownloadResult()); + assertTrue(info.isProvisioningResultUpdated()); + } + + @Test + public void testDownloadResult() { + ONSStatsInfo info; + info = new ONSStatsInfo().setDownloadResult(DownloadRetryResultCode.ERR_MEMORY_FULL); + assertEquals(DownloadRetryResultCode.ERR_MEMORY_FULL, info.getDownloadResult()); + assertNull(info.getProvisioningResult()); + assertFalse(info.isProvisioningResultUpdated()); + } + + @Test + public void testPrimarySimSubId() { + ONSStatsInfo info; + info = new ONSStatsInfo().setPrimarySimSubId(1); + assertEquals(1, info.getPrimarySimSubId()); + } + + @Test + public void testOppSimCarrierId() { + ONSStatsInfo info; + info = new ONSStatsInfo().setOppSimCarrierId(1221); + assertEquals(1221, info.getOppSimCarrierId()); + } + + @Test + public void testRetryCount() { + ONSStatsInfo info; + info = new ONSStatsInfo().setRetryCount(3); + assertEquals(3, info.getRetryCount()); + } + + @Test + public void testDetailedErrCode() { + ONSStatsInfo info; + info = new ONSStatsInfo().setDetailedErrCode(1000); + assertEquals(1000, info.getDetailedErrCode()); + } + + @Test + public void testIsWifiConnected() { + ONSStatsInfo info; + info = new ONSStatsInfo().setWifiConnected(true); + assertTrue(info.isWifiConnected()); + } + + @Test + public void testIsProvisioningResultUpdated() { + ONSStatsInfo info; + info = new ONSStatsInfo().setProvisioningResult(Result.ERR_ESIM_NOT_SUPPORTED); + assertTrue(info.isProvisioningResultUpdated()); + + info.setDownloadResult(DownloadRetryResultCode.ERR_MEMORY_FULL); + assertFalse(info.isProvisioningResultUpdated()); + } +} diff --git a/tests/src/com/android/ons/ONSStatsTest.java b/tests/src/com/android/ons/ONSStatsTest.java new file mode 100644 index 0000000..12c49af --- /dev/null +++ b/tests/src/com/android/ons/ONSStatsTest.java @@ -0,0 +1,317 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.ons; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.doReturn; + +import android.content.Context; +import android.content.SharedPreferences; +import android.telephony.SubscriptionInfo; +import android.telephony.SubscriptionManager; + +import com.android.ons.ONSProfileActivator.Result; +import com.android.ons.ONSProfileDownloader.DownloadRetryResultCode; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.mockito.Spy; + +import java.util.HashMap; +import java.util.Map; +import java.util.Set; + +@RunWith(JUnit4.class) +public class ONSStatsTest { + + private static final String ONS_ATOM_LOG_FILE = "ons_atom_log_info"; + private static final String KEY_DETAILED_ERROR_CODE = "_detailed_error_code"; + + @Spy private Context mContext; + @Mock private SubscriptionManager mSubscriptionManager; + private SharedPreferences mSharedPreferences; + @Mock private SubscriptionInfo mSubInfoId1; + @Mock private SubscriptionInfo mSubInfoId2; + private ONSStats mONSStats; + + private class FakeSharedPreferences implements SharedPreferences { + HashMap<String, Object> mMap = new HashMap<>(); + + @Override + public Map<String, ?> getAll() { + return mMap; + } + + @Override + public String getString(String key, String defValue) { + return (String) mMap.getOrDefault(key, defValue); + } + + @Override + public Set<String> getStringSet(String key, Set<String> defValues) { + if (mMap.containsKey(key)) { + return (Set<String>) mMap.get(key); + } + return defValues; + } + + @Override + public int getInt(String key, int defValue) { + return (int) mMap.getOrDefault(key, defValue); + } + + @Override + public long getLong(String key, long defValue) { + return 0; // not used + } + + @Override + public float getFloat(String key, float defValue) { + return (float) mMap.getOrDefault(key, defValue); + } + + @Override + public boolean getBoolean(String key, boolean defValue) { + return (boolean) mMap.getOrDefault(key, defValue); + } + + @Override + public boolean contains(String key) { + return mMap.containsKey(key); + } + + @Override + public Editor edit() { + TestEditor editor = new TestEditor(); + editor.map = mMap; + return editor; + } + + @Override + public void registerOnSharedPreferenceChangeListener( + OnSharedPreferenceChangeListener listener) {} + + @Override + public void unregisterOnSharedPreferenceChangeListener( + OnSharedPreferenceChangeListener listener) {} + + private class TestEditor implements SharedPreferences.Editor { + HashMap<String, Object> map = new HashMap<>(); + + @Override + public SharedPreferences.Editor putString(String key, String value) { + map.put(key, value); + return this; + } + + @Override + public SharedPreferences.Editor putStringSet(String key, Set<String> values) { + map.put(key, values); + return this; + } + + @Override + public SharedPreferences.Editor putInt(String key, int value) { + map.put(key, value); + return this; + } + + @Override + public SharedPreferences.Editor putLong(String key, long value) { + map.put(key, value); + return this; + } + + @Override + public SharedPreferences.Editor putFloat(String key, float value) { + map.put(key, value); + return this; + } + + @Override + public SharedPreferences.Editor putBoolean(String key, boolean value) { + map.put(key, value); + return this; + } + + @Override + public SharedPreferences.Editor remove(String key) { + map.remove(key); + return this; + } + + @Override + public SharedPreferences.Editor clear() { + map.clear(); + return this; + } + + @Override + public boolean commit() { + mMap = map; + return true; + } + + @Override + public void apply() { + mMap = map; + } + } + ; + } + ; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + mSharedPreferences = new FakeSharedPreferences(); + doReturn(mSharedPreferences) + .when(mContext) + .getSharedPreferences(eq(ONS_ATOM_LOG_FILE), eq(Context.MODE_PRIVATE)); + doReturn(123).when(mSubInfoId1).getCarrierId(); + doReturn(456).when(mSubInfoId2).getCarrierId(); + doReturn(mSubInfoId1).when(mSubscriptionManager).getActiveSubscriptionInfo(1); + doReturn(mSubInfoId2).when(mSubscriptionManager).getActiveSubscriptionInfo(2); + mONSStats = new ONSStats(mContext, mSubscriptionManager); + } + + @After + public void tearDown() { + mSharedPreferences.edit().clear().apply(); + } + + @Test + public void testLogEvent() { + ONSStatsInfo info = + new ONSStatsInfo() + .setPrimarySimSubId(1) + .setProvisioningResult(Result.ERR_CANNOT_SWITCH_TO_DUAL_SIM_MODE); + assertTrue(mONSStats.logEvent(info)); + } + + @Test + public void testIgnoredLogEvents() { + // ignored error codes should not log. + ONSStatsInfo info = new ONSStatsInfo().setProvisioningResult(Result.DOWNLOAD_REQUESTED); + assertFalse(mONSStats.logEvent(info)); + + info = new ONSStatsInfo().setProvisioningResult(Result.ERR_NO_SIM_INSERTED); + assertFalse(mONSStats.logEvent(info)); + + info = new ONSStatsInfo().setProvisioningResult(Result.ERR_DUPLICATE_DOWNLOAD_REQUEST); + assertFalse(mONSStats.logEvent(info)); + + info = new ONSStatsInfo().setProvisioningResult(Result.ERR_SWITCHING_TO_DUAL_SIM_MODE); + assertFalse(mONSStats.logEvent(info)); + } + + @Test + public void testRepeatedLogEvents() { + ONSStatsInfo info; + info = + new ONSStatsInfo() + .setDownloadResult(DownloadRetryResultCode.ERR_MEMORY_FULL) + .setDetailedErrCode(10011); + assertTrue(mONSStats.logEvent(info)); + + // same result should not log consecutively + assertFalse(mONSStats.logEvent(info)); + assertFalse(mONSStats.logEvent(info)); + } + + @Test + public void testRepeatedAllowedLogEvents() { + ONSStatsInfo info; + info = new ONSStatsInfo().setProvisioningResult(Result.ERR_DOWNLOADED_ESIM_NOT_FOUND); + assertTrue(mONSStats.logEvent(info)); + + // ERR_DOWNLOADED_ESIM_NOT_FOUND is allowed to log consecutively + assertTrue(mONSStats.logEvent(info)); + assertTrue(mONSStats.logEvent(info)); + + info = + new ONSStatsInfo() + .setDownloadResult(DownloadRetryResultCode.ERR_INSTALL_ESIM_PROFILE_FAILED); + assertTrue(mONSStats.logEvent(info)); + + // ERR_INSTALL_ESIM_PROFILE_FAILED is allowed to log consecutively + assertTrue(mONSStats.logEvent(info)); + assertTrue(mONSStats.logEvent(info)); + } + + @Test + public void testRepeatedSuccessLogEvents() { + ONSStatsInfo info; + info = new ONSStatsInfo().setProvisioningResult(Result.SUCCESS).setRetryCount(2); + + // should log every time if eSIM is newly downloaded. + assertTrue(mONSStats.logEvent(info)); + assertTrue(mONSStats.logEvent(info)); + + info = new ONSStatsInfo().setProvisioningResult(Result.SUCCESS); + // should log even if eSIM is already downloaded and event triggered just to group it. + assertTrue(mONSStats.logEvent(info)); + assertTrue(mONSStats.logEvent(info)); + } + + @Test + public void testRepeatedErrorWithInfoChangeLogEvents() { + ONSStatsInfo info = + new ONSStatsInfo() + .setPrimarySimSubId(1) + .setProvisioningResult(Result.ERR_AUTO_PROVISIONING_DISABLED); + assertTrue(mONSStats.logEvent(info)); + + // Same error should log if the info is changed. + info.setPrimarySimSubId(2); + assertTrue(mONSStats.logEvent(info)); + + // no change in info + assertFalse(mONSStats.logEvent(info)); + } + + @Test + public void testDetailedErrorCodeLogEvents() { + ONSStatsInfo info; + info = new ONSStatsInfo().setProvisioningResult(Result.ERR_WAITING_FOR_INTERNET_CONNECTION); + assertTrue(mONSStats.logEvent(info)); + + // For provisioning errors; Result enum ordinal is set as detailed error code. + assertEquals( + Result.ERR_WAITING_FOR_INTERNET_CONNECTION.ordinal(), + mSharedPreferences.getInt(KEY_DETAILED_ERROR_CODE, -1)); + assertEquals( + Result.ERR_WAITING_FOR_INTERNET_CONNECTION.ordinal(), info.getDetailedErrCode()); + + // For Download errors; detailed error code is updated from EuiccManager. + info = + new ONSStatsInfo() + .setDownloadResult(DownloadRetryResultCode.ERR_MEMORY_FULL) + .setDetailedErrCode(10223); + assertTrue(mONSStats.logEvent(info)); + assertEquals(10223, mSharedPreferences.getInt(KEY_DETAILED_ERROR_CODE, -1)); + assertEquals(10223, info.getDetailedErrCode()); + } +} diff --git a/tests/src/com/android/ons/OpportunisticNetworkServiceTest.java b/tests/src/com/android/ons/OpportunisticNetworkServiceTest.java index 0a75371..5b2d67c 100644 --- a/tests/src/com/android/ons/OpportunisticNetworkServiceTest.java +++ b/tests/src/com/android/ons/OpportunisticNetworkServiceTest.java @@ -76,13 +76,26 @@ public class OpportunisticNetworkServiceTest extends ONSBaseTest { mOpportunisticNetworkService = new OpportunisticNetworkService(); mOpportunisticNetworkService.initialize(mContext); mOpportunisticNetworkService.mSubscriptionManager = mSubscriptionManager; - iOpportunisticNetworkService = (IOns) mOpportunisticNetworkService.onBind(null); + for (int retry = 2; retry > 0; retry--) { + + iOpportunisticNetworkService = (IOns) mOpportunisticNetworkService.onBind(null); + + if (iOpportunisticNetworkService != null) { + break; + } + + try { + Thread.sleep(100); + } catch (Exception e) { + Log.e(TAG, e.toString()); + } + } mLooper = Looper.myLooper(); setReady(true); Looper.loop(); } }).start(); - waitUntilReady(200); + waitUntilReady(300); } @After @@ -208,6 +221,7 @@ public class OpportunisticNetworkServiceTest extends ONSBaseTest { }; try { + assertNotNull(iOpportunisticNetworkService); iOpportunisticNetworkService.setPreferredDataSubscriptionId(5, false, callbackStub, pkgForDebug); } catch (RemoteException ex) { |