[ImsServiceEntitlement] execute handleInitialEntitlementStatus and handleReevaluationEntitlementStatus on the main thread
Error:
RuntimeException Can't create handler inside thread Thread[AsyncTask #1,5,main] that has not called Looper.prepare()
Solution:
1. Execute the callback (handleInitialEntitlementStatus or handleReevaluationEntitlementStatus) in onSuccess() on the main thread, even though onSuccess() runs on the async thread
2. Use a handler to post delayed events instead of using CountDownTimer
bug: 399230129
bug: 398184731
Change-Id: I2aa58c22a6c770a0d96cccb637b2f244c8dd8629
diff --git a/src/com/android/imsserviceentitlement/WfcActivationController.java b/src/com/android/imsserviceentitlement/WfcActivationController.java
index 4b65e46..ccf6015 100644
--- a/src/com/android/imsserviceentitlement/WfcActivationController.java
+++ b/src/com/android/imsserviceentitlement/WfcActivationController.java
@@ -31,7 +31,8 @@
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
-import android.os.CountDownTimer;
+import android.os.Handler;
+import android.os.Looper;
import android.text.TextUtils;
import android.util.Log;
@@ -70,6 +71,7 @@
private final Intent mStartIntent;
private final MetricsLogger mMetricsLogger;
private final Context mContext;
+ private final Handler mMainThreadHandler;
// States
private int mEvaluateTimes = 0;
@@ -88,6 +90,7 @@
this.mTelephonyUtils = new TelephonyUtils(context, getSubId());
this.mImsUtils = ImsUtils.getInstance(context, getSubId());
this.mMetricsLogger = new MetricsLogger(mTelephonyUtils);
+ this.mMainThreadHandler = new Handler(Looper.getMainLooper());
}
@VisibleForTesting
@@ -97,7 +100,8 @@
ImsEntitlementApi imsEntitlementApi,
Intent intent,
ImsUtils imsUtils,
- MetricsLogger metricsLogger) {
+ MetricsLogger metricsLogger,
+ Handler handler) {
this.mContext = context;
this.mStartIntent = intent;
this.mActivationUi = wfcActivationUi;
@@ -105,6 +109,7 @@
this.mTelephonyUtils = new TelephonyUtils(context, getSubId());
this.mImsUtils = imsUtils;
this.mMetricsLogger = metricsLogger;
+ this.mMainThreadHandler = handler;
}
/** Indicates the controller to start WFC activation or emergency address update flow. */
@@ -127,7 +132,9 @@
return;
}
EntitlementUtils.entitlementCheck(
- mImsEntitlementApi, result -> handleInitialEntitlementStatus(result));
+ mImsEntitlementApi,
+ result -> mMainThreadHandler.post(
+ () -> handleInitialEntitlementStatus(result)));
}
/**
@@ -144,7 +151,9 @@
@MainThread
public void reevaluateEntitlementStatus() {
EntitlementUtils.entitlementCheck(
- mImsEntitlementApi, result -> handleReevaluationEntitlementStatus(result));
+ mImsEntitlementApi,
+ result -> mMainThreadHandler.post(
+ () -> handleReevaluationEntitlementStatus(result)));
}
/** The interface for handling the entitlement check result. */
@@ -314,9 +323,9 @@
// Check again after 5s, max retry 6 times
if (mEvaluateTimes < ENTITLEMENT_STATUS_UPDATE_RETRY_MAX) {
mEvaluateTimes += 1;
- postDelay(
- getEntitlementStatusUpdateRetryIntervalMs(),
- this::reevaluateEntitlementStatus);
+ mMainThreadHandler.postDelayed(
+ this::reevaluateEntitlementStatus,
+ getEntitlementStatusUpdateRetryIntervalMs());
} else {
mEvaluateTimes = 0;
showGeneralErrorUi();
@@ -359,22 +368,6 @@
}
}
- /** Runs {@code action} on caller's thread after {@code delayMillis} ms. */
- private static void postDelay(long delayMillis, Runnable action) {
- new CountDownTimer(delayMillis, delayMillis + 100) {
- // Use a countDownInterval bigger than millisInFuture so onTick never fires.
- @Override
- public void onTick(long millisUntilFinished) {
- // Do nothing
- }
-
- @Override
- public void onFinish() {
- action.run();
- }
- }.start();
- }
-
private void finishStatsLog(int result) {
mAppResult = result;
}
diff --git a/tests/unittests/src/com/android/imsserviceentitlement/WfcActivationControllerTest.java b/tests/unittests/src/com/android/imsserviceentitlement/WfcActivationControllerTest.java
index b69127c..8599f5c 100644
--- a/tests/unittests/src/com/android/imsserviceentitlement/WfcActivationControllerTest.java
+++ b/tests/unittests/src/com/android/imsserviceentitlement/WfcActivationControllerTest.java
@@ -36,11 +36,16 @@
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.os.PersistableBundle;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.Message;
+import android.os.TestLooperManager;
import android.telephony.CarrierConfigManager;
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
import androidx.test.core.app.ApplicationProvider;
+import androidx.test.platform.app.InstrumentationRegistry;
import androidx.test.runner.AndroidJUnit4;
import com.android.imsserviceentitlement.entitlement.EntitlementResult;
@@ -53,6 +58,7 @@
import com.android.imsserviceentitlement.utils.ImsUtils;
import com.android.imsserviceentitlement.utils.MetricsLogger;
+import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
@@ -86,11 +92,21 @@
private WfcActivationController mWfcActivationController;
private Context mContext;
private PersistableBundle mCarrierConfig;
+ private TestLooperManager mTestLooperManager;
+ private Handler mUiHandler;
+ private HandlerThread mUiHandlerThread;
@Before
public void setUp() throws Exception {
mContext = spy(ApplicationProvider.getApplicationContext());
+ mUiHandlerThread = new HandlerThread("MockUiThread");
+ mUiHandlerThread.start();
+ mUiHandler = new Handler(mUiHandlerThread.getLooper());
+ mTestLooperManager =
+ InstrumentationRegistry.getInstrumentation()
+ .acquireLooperManager(mUiHandlerThread.getLooper());
+
when(mContext.getSystemService(CarrierConfigManager.class))
.thenReturn(mMockCarrierConfigManager);
when(mContext.getSystemService(TelephonyManager.class)).thenReturn(mMockTelephonyManager);
@@ -104,6 +120,12 @@
field.set(null, true);
}
+ @After
+ public void tearDown() {
+ mTestLooperManager.release();
+ mUiHandlerThread.quit();
+ }
+
@Test
public void startFlow_launchAppForActivation_setPurposeActivation() {
InOrder mOrderVerifier = inOrder(mMockActivationUi);
@@ -149,18 +171,7 @@
@Test
public void finish_launchAppForActivateWithIsSkipWfcActivationTrue_notWriteMetrics() {
setIsSkipWfcActivation(true);
- Intent startIntent = new Intent(Intent.ACTION_MAIN);
- startIntent.putExtra(SubscriptionManager.EXTRA_SUBSCRIPTION_INDEX, SUB_ID);
- startIntent.putExtra(
- ActivityConstants.EXTRA_LAUNCH_CARRIER_APP, ActivityConstants.LAUNCH_APP_ACTIVATE);
- mWfcActivationController =
- new WfcActivationController(
- mContext,
- mMockActivationUi,
- mMockActivationApi,
- startIntent,
- mMockImsUtils,
- mMockMetricsLogger);
+ buildActivity(ActivityConstants.LAUNCH_APP_ACTIVATE);
mWfcActivationController.finish();
@@ -170,18 +181,7 @@
@Test
public void finish_launchAppForUpdateWithIsSkipWfcActivationTrue_writeMetrics() {
setIsSkipWfcActivation(true);
- Intent startIntent = new Intent(Intent.ACTION_MAIN);
- startIntent.putExtra(SubscriptionManager.EXTRA_SUBSCRIPTION_INDEX, SUB_ID);
- startIntent.putExtra(
- ActivityConstants.EXTRA_LAUNCH_CARRIER_APP, ActivityConstants.LAUNCH_APP_UPDATE);
- mWfcActivationController =
- new WfcActivationController(
- mContext,
- mMockActivationUi,
- mMockActivationApi,
- startIntent,
- mMockImsUtils,
- mMockMetricsLogger);
+ buildActivity(ActivityConstants.LAUNCH_APP_UPDATE);
mWfcActivationController.finish();
@@ -190,18 +190,7 @@
@Test
public void finish_launchAppForUpdateAndIsSkipWfcActivationFalse_writeMetrics() {
- Intent startIntent = new Intent(Intent.ACTION_MAIN);
- startIntent.putExtra(SubscriptionManager.EXTRA_SUBSCRIPTION_INDEX, SUB_ID);
- startIntent.putExtra(
- ActivityConstants.EXTRA_LAUNCH_CARRIER_APP, ActivityConstants.LAUNCH_APP_UPDATE);
- mWfcActivationController =
- new WfcActivationController(
- mContext,
- mMockActivationUi,
- mMockActivationApi,
- startIntent,
- mMockImsUtils,
- mMockMetricsLogger);
+ buildActivity(ActivityConstants.LAUNCH_APP_UPDATE);
mWfcActivationController.finish();
@@ -215,6 +204,7 @@
buildActivity(ActivityConstants.LAUNCH_APP_ACTIVATE);
mWfcActivationController.finishFlow();
+ mTestLooperManager.execute(mTestLooperManager.next());
mOrderVerifier
.verify(mMockActivationUi)
@@ -250,20 +240,10 @@
.build())
.build());
setNetworkConnected(false);
- Intent intent = new Intent(Intent.ACTION_MAIN);
- intent.putExtra(SubscriptionManager.EXTRA_SUBSCRIPTION_INDEX, SUB_ID);
- intent.putExtra(ActivityConstants.EXTRA_LAUNCH_CARRIER_APP,
- ActivityConstants.LAUNCH_APP_UPDATE);
- mWfcActivationController =
- new WfcActivationController(
- mContext,
- mMockActivationUi,
- mMockActivationApi,
- null,
- mMockImsUtils,
- mMockMetricsLogger);
+ buildActivity(ActivityConstants.LAUNCH_APP_UPDATE);
mWfcActivationController.finishFlow();
+ mTestLooperManager.execute(mTestLooperManager.next());
verify(mMockActivationUi).setResultAndFinish(eq(Activity.RESULT_OK));
}
@@ -272,20 +252,10 @@
public void finish_startFlowForActivate_writeLoggerPurposeActivation() {
when(mMockTelephonyManager.getSimCarrierId()).thenReturn(CARRIER_ID);
when(mMockTelephonyManager.getSimSpecificCarrierId()).thenReturn(CARRIER_ID);
- Intent intent = new Intent(Intent.ACTION_MAIN);
- intent.putExtra(SubscriptionManager.EXTRA_SUBSCRIPTION_INDEX, SUB_ID);
- intent.putExtra(ActivityConstants.EXTRA_LAUNCH_CARRIER_APP,
- ActivityConstants.LAUNCH_APP_ACTIVATE);
- mWfcActivationController =
- new WfcActivationController(
- mContext,
- mMockActivationUi,
- mMockActivationApi,
- intent,
- mMockImsUtils,
- mMockMetricsLogger);
+ buildActivity(ActivityConstants.LAUNCH_APP_ACTIVATE);
mWfcActivationController.startFlow();
+ mTestLooperManager.execute(mTestLooperManager.next());
mWfcActivationController.finish();
verify(mMockMetricsLogger).start(eq(IMS_SERVICE_ENTITLEMENT_UPDATED__PURPOSE__ACTIVATION));
@@ -298,10 +268,6 @@
public void finish_entitlementResultWfcEntitled_writeLoggerAppResultSuccessful() {
when(mMockTelephonyManager.getSimCarrierId()).thenReturn(CARRIER_ID);
when(mMockTelephonyManager.getSimSpecificCarrierId()).thenReturn(CARRIER_ID);
- Intent intent = new Intent(Intent.ACTION_MAIN);
- intent.putExtra(SubscriptionManager.EXTRA_SUBSCRIPTION_INDEX, SUB_ID);
- intent.putExtra(ActivityConstants.EXTRA_LAUNCH_CARRIER_APP,
- ActivityConstants.LAUNCH_APP_ACTIVATE);
when(mMockActivationApi.checkEntitlementStatus())
.thenReturn(
EntitlementResult.builder(false)
@@ -313,16 +279,10 @@
.setAddrStatus(AddrStatus.AVAILABLE)
.build())
.build());
- mWfcActivationController =
- new WfcActivationController(
- mContext,
- mMockActivationUi,
- mMockActivationApi,
- intent,
- mMockImsUtils,
- mMockMetricsLogger);
+ buildActivity(ActivityConstants.LAUNCH_APP_ACTIVATE);
mWfcActivationController.startFlow();
+ mTestLooperManager.execute(mTestLooperManager.next());
mWfcActivationController.finish();
verify(mMockMetricsLogger).start(eq(IMS_SERVICE_ENTITLEMENT_UPDATED__PURPOSE__ACTIVATION));
@@ -347,6 +307,7 @@
buildActivity(ActivityConstants.LAUNCH_APP_ACTIVATE);
mWfcActivationController.evaluateEntitlementStatus();
+ mTestLooperManager.execute(mTestLooperManager.next());
verify(mMockActivationUi).setResultAndFinish(Activity.RESULT_OK);
}
@@ -368,6 +329,7 @@
buildActivity(ActivityConstants.LAUNCH_APP_ACTIVATE);
mWfcActivationController.evaluateEntitlementStatus();
+ mTestLooperManager.execute(mTestLooperManager.next());
verify(mMockActivationUi).showWebview(EMERGENCY_ADDRESS_WEB_URL,
EMERGENCY_ADDRESS_WEB_DATA);
@@ -389,6 +351,7 @@
buildActivity(ActivityConstants.LAUNCH_APP_ACTIVATE);
mWfcActivationController.evaluateEntitlementStatus();
+ mTestLooperManager.execute(mTestLooperManager.next());
verify(mMockActivationUi).showWebview(EMERGENCY_ADDRESS_WEB_URL, null);
}
@@ -406,6 +369,7 @@
buildActivity(ActivityConstants.LAUNCH_APP_ACTIVATE);
mWfcActivationController.evaluateEntitlementStatus();
+ mTestLooperManager.execute(mTestLooperManager.next());
verifyErrorUi(R.string.activate_title, R.string.failure_contact_carrier);
}
@@ -425,6 +389,7 @@
buildActivity(ActivityConstants.LAUNCH_APP_ACTIVATE);
mWfcActivationController.evaluateEntitlementStatus();
+ mTestLooperManager.execute(mTestLooperManager.next());
verifyErrorUi(R.string.activate_title, R.string.wfc_activation_error);
}
@@ -445,6 +410,7 @@
buildActivity(ActivityConstants.LAUNCH_APP_ACTIVATE);
mWfcActivationController.reevaluateEntitlementStatus();
+ mTestLooperManager.execute(mTestLooperManager.next());
verify(mMockActivationUi).setResultAndFinish(Activity.RESULT_OK);
}
@@ -464,6 +430,7 @@
buildActivity(ActivityConstants.LAUNCH_APP_ACTIVATE);
mWfcActivationController.reevaluateEntitlementStatus();
+ mTestLooperManager.execute(mTestLooperManager.next());
verifyErrorUi(R.string.activate_title, R.string.wfc_activation_error);
}
@@ -484,6 +451,7 @@
buildActivity(ActivityConstants.LAUNCH_APP_UPDATE);
mWfcActivationController.reevaluateEntitlementStatus();
+ mTestLooperManager.execute(mTestLooperManager.next());
verify(mMockActivationUi).setResultAndFinish(eq(Activity.RESULT_OK));
}
@@ -500,20 +468,10 @@
.build())
.build();
when(mMockActivationApi.checkEntitlementStatus()).thenReturn(entitlementResult);
- Intent intent = new Intent(Intent.ACTION_MAIN);
- intent.putExtra(SubscriptionManager.EXTRA_SUBSCRIPTION_INDEX, SUB_ID);
- intent.putExtra(ActivityConstants.EXTRA_LAUNCH_CARRIER_APP,
- ActivityConstants.LAUNCH_APP_UPDATE);
- mWfcActivationController =
- new WfcActivationController(
- mContext,
- mMockActivationUi,
- mMockActivationApi,
- intent,
- mMockImsUtils,
- mMockMetricsLogger);
+ buildActivity(ActivityConstants.LAUNCH_APP_UPDATE);
mWfcActivationController.reevaluateEntitlementStatus();
+ mTestLooperManager.execute(mTestLooperManager.next());
verify(mMockImsUtils).turnOffWfc(any());
}
@@ -533,6 +491,7 @@
buildActivity(ActivityConstants.LAUNCH_APP_UPDATE);
mWfcActivationController.reevaluateEntitlementStatus();
+ mTestLooperManager.execute(mTestLooperManager.next());
verifyErrorUi(R.string.e911_title, R.string.address_update_error);
}
@@ -555,6 +514,7 @@
buildActivity(ActivityConstants.LAUNCH_APP_UPDATE);
mWfcActivationController.evaluateEntitlementStatus();
+ mTestLooperManager.execute(mTestLooperManager.next());
verify(mMockActivationUi).showWebview(EMERGENCY_ADDRESS_WEB_URL,
EMERGENCY_ADDRESS_WEB_DATA);
@@ -577,6 +537,7 @@
buildActivity(ActivityConstants.LAUNCH_APP_SHOW_TC);
mWfcActivationController.evaluateEntitlementStatus();
+ mTestLooperManager.execute(mTestLooperManager.next());
verify(mMockActivationUi).showWebview(EMERGENCY_ADDRESS_WEB_URL, null);
}
@@ -594,6 +555,7 @@
buildActivity(ActivityConstants.LAUNCH_APP_UPDATE);
mWfcActivationController.evaluateEntitlementStatus();
+ mTestLooperManager.execute(mTestLooperManager.next());
verifyErrorUi(R.string.e911_title, R.string.failure_contact_carrier);
}
@@ -611,6 +573,7 @@
buildActivity(ActivityConstants.LAUNCH_APP_UPDATE);
mWfcActivationController.evaluateEntitlementStatus();
+ mTestLooperManager.execute(mTestLooperManager.next());
verifyErrorUi(R.string.e911_title, R.string.address_update_error);
}
@@ -620,8 +583,14 @@
intent.putExtra(SubscriptionManager.EXTRA_SUBSCRIPTION_INDEX, SUB_ID);
intent.putExtra(ActivityConstants.EXTRA_LAUNCH_CARRIER_APP, extraLaunchCarrierApp);
mWfcActivationController =
- new WfcActivationController(mContext, mMockActivationUi, mMockActivationApi,
- intent);
+ new WfcActivationController(
+ mContext,
+ mMockActivationUi,
+ mMockActivationApi,
+ intent,
+ mMockImsUtils,
+ mMockMetricsLogger,
+ mUiHandler);
}
private void setNetworkConnected(boolean isConnected) {