summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorandroid-build-team Robot <android-build-team-robot@google.com>2021-06-10 01:09:54 +0000
committerandroid-build-team Robot <android-build-team-robot@google.com>2021-06-10 01:09:54 +0000
commita321c3b61e7b5ca9ae5a9ae1c701585841633b1e (patch)
treea7a05b4073b9f4cf1495803ddd8c2f3f05b8c425
parentc00e143d14dfbb3ef446b4591fcec473099ee3ad (diff)
parenta014eea499ce47dd6e5f3ee19cc68fab3ea3a5ca (diff)
downloadImsServiceEntitlement-a321c3b61e7b5ca9ae5a9ae1c701585841633b1e.tar.gz
Snap for 7442307 from a014eea499ce47dd6e5f3ee19cc68fab3ea3a5ca to sc-d2-release
Change-Id: I902c130dc8eb68587cbf9ffda599be0a7ee29832
-rw-r--r--AndroidManifest.xml8
-rw-r--r--src/com/android/imsserviceentitlement/EntitlementUtils.java30
-rw-r--r--src/com/android/imsserviceentitlement/ImsEntitlementPollingService.java10
-rw-r--r--src/com/android/imsserviceentitlement/ImsEntitlementReceiver.java173
-rw-r--r--src/com/android/imsserviceentitlement/WfcActivationController.java2
-rw-r--r--src/com/android/imsserviceentitlement/entitlement/EntitlementConfiguration.java20
-rw-r--r--src/com/android/imsserviceentitlement/entitlement/EntitlementConfigurationsDataStore.java13
-rw-r--r--src/com/android/imsserviceentitlement/utils/Executors.java44
-rw-r--r--tests/unittests/src/com/android/imsserviceentitlement/EntitlementUtilsTest.java3
-rw-r--r--tests/unittests/src/com/android/imsserviceentitlement/ImsEntitlementPollingServiceTest.java21
-rw-r--r--tests/unittests/src/com/android/imsserviceentitlement/ImsEntitlementReceiverTest.java236
-rw-r--r--tests/unittests/src/com/android/imsserviceentitlement/WfcActivationControllerTest.java3
12 files changed, 522 insertions, 41 deletions
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index fa64f24..2311c9b 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -64,6 +64,14 @@
android:permission="android.permission.BIND_JOB_SERVICE">
</service>
<!-- END: FCM related components -->
+
+ <receiver
+ android:name=".ImsEntitlementReceiver"
+ android:exported="true">
+ <intent-filter>
+ <action android:name="android.telephony.action.CARRIER_CONFIG_CHANGED" />
+ </intent-filter>
+ </receiver>
</application>
</manifest>
diff --git a/src/com/android/imsserviceentitlement/EntitlementUtils.java b/src/com/android/imsserviceentitlement/EntitlementUtils.java
index 62943c7..83dab5a 100644
--- a/src/com/android/imsserviceentitlement/EntitlementUtils.java
+++ b/src/com/android/imsserviceentitlement/EntitlementUtils.java
@@ -16,8 +16,12 @@
package com.android.imsserviceentitlement;
+import static com.android.imsserviceentitlement.utils.Executors.getAsyncExecutor;
+import static com.android.imsserviceentitlement.utils.Executors.getDirectExecutor;
+
import android.util.Log;
+import androidx.annotation.MainThread;
import androidx.annotation.Nullable;
import androidx.annotation.WorkerThread;
@@ -27,39 +31,25 @@ import com.android.imsserviceentitlement.entitlement.EntitlementResult;
import com.google.common.util.concurrent.FutureCallback;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
-import com.google.common.util.concurrent.ListeningExecutorService;
-import com.google.common.util.concurrent.MoreExecutors;
-
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
-/** Handle entitlement check */
-public class EntitlementUtils {
+/** Handles entitlement check from main thread. */
+public final class EntitlementUtils {
public static final String LOG_TAG = "IMSSE-EntitlementUtils";
- private static final ExecutorService EXECUTOR_SERVICE = Executors.newCachedThreadPool();
- private static final ExecutorService DIRECT_EXECUTOR_SERVICE =
- MoreExecutors.newDirectExecutorService();
private static ListenableFuture<EntitlementResult> sCheckEntitlementFuture;
- /**
- * Whether to execute entitlementCheck in caller's thread, set to true via reflection for test.
- */
- private static boolean sUseDirectExecutorForTest = false;
-
private EntitlementUtils() {}
/**
* Performs the entitlement status check, and passes the result via {@link
* EntitlementResultCallback}.
*/
+ @MainThread
public static void entitlementCheck(
ImsEntitlementApi activationApi, EntitlementResultCallback callback) {
- ListeningExecutorService service =
- MoreExecutors.listeningDecorator(
- sUseDirectExecutorForTest ? DIRECT_EXECUTOR_SERVICE : EXECUTOR_SERVICE);
- sCheckEntitlementFuture = service.submit(() -> getEntitlementStatus(activationApi));
+ sCheckEntitlementFuture =
+ Futures.submit(() -> getEntitlementStatus(activationApi), getAsyncExecutor());
Futures.addCallback(
sCheckEntitlementFuture,
new FutureCallback<EntitlementResult>() {
@@ -75,7 +65,7 @@ public class EntitlementUtils {
sCheckEntitlementFuture = null;
}
},
- DIRECT_EXECUTOR_SERVICE);
+ getDirectExecutor());
}
/** Cancels the running task of entitlement status check if exist. */
diff --git a/src/com/android/imsserviceentitlement/ImsEntitlementPollingService.java b/src/com/android/imsserviceentitlement/ImsEntitlementPollingService.java
index d5c834b..f35503b 100644
--- a/src/com/android/imsserviceentitlement/ImsEntitlementPollingService.java
+++ b/src/com/android/imsserviceentitlement/ImsEntitlementPollingService.java
@@ -48,9 +48,9 @@ import com.android.imsserviceentitlement.utils.ImsUtils;
import com.android.imsserviceentitlement.utils.TelephonyUtils;
/**
- * The {@link JobService} for querying entitlement status in the background.
- * The jobId is unique for different subId + job combination, so can run the same job for different
- * subIds w/o cancelling each others. See {@link JobManager}.
+ * The {@link JobService} for querying entitlement status in the background. The jobId is unique for
+ * different subId + job combination, so can run the same job for different subIds w/o cancelling
+ * each others. See {@link JobManager}.
*/
public class ImsEntitlementPollingService extends JobService {
private static final String TAG = "IMSSE-ImsEntitlementPollingService";
@@ -250,8 +250,8 @@ public class ImsEntitlementPollingService extends JobService {
}
/**
- * Returns {@code true} when {@code EntitlementResult} says WFC is not activated;
- * Otherwise {@code false} if {@code EntitlementResult} is not of any known pattern.
+ * Returns {@code true} when {@code EntitlementResult} says WFC is not activated; Otherwise
+ * {@code false} if {@code EntitlementResult} is not of any known pattern.
*/
private boolean shouldTurnOffWfc(@Nullable EntitlementResult result) {
if (result == null) {
diff --git a/src/com/android/imsserviceentitlement/ImsEntitlementReceiver.java b/src/com/android/imsserviceentitlement/ImsEntitlementReceiver.java
new file mode 100644
index 0000000..dc78b0a
--- /dev/null
+++ b/src/com/android/imsserviceentitlement/ImsEntitlementReceiver.java
@@ -0,0 +1,173 @@
+/*
+ * Copyright (C) 2021 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.imsserviceentitlement;
+
+import static com.android.imsserviceentitlement.entitlement.EntitlementConfiguration.ClientBehavior.NEEDS_TO_RESET;
+import static com.android.imsserviceentitlement.entitlement.EntitlementConfiguration.ClientBehavior.VALID_DURING_VALIDITY;
+import static com.android.imsserviceentitlement.entitlement.EntitlementConfiguration.ClientBehavior.VALID_WITHOUT_DURATION;
+import static com.android.imsserviceentitlement.utils.Executors.getAsyncExecutor;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.SharedPreferences;
+import android.os.UserManager;
+import android.provider.Settings;
+import android.telephony.CarrierConfigManager;
+import android.telephony.SubscriptionManager;
+import android.util.Log;
+
+import androidx.annotation.VisibleForTesting;
+import androidx.annotation.WorkerThread;
+
+import com.android.imsserviceentitlement.entitlement.EntitlementConfiguration;
+import com.android.imsserviceentitlement.entitlement.EntitlementConfiguration.ClientBehavior;
+import com.android.imsserviceentitlement.job.JobManager;
+import com.android.imsserviceentitlement.utils.TelephonyUtils;
+
+/** Watches events and manages service entitlement polling. */
+public class ImsEntitlementReceiver extends BroadcastReceiver {
+ private static final String TAG = "IMSSE-ImsEntitlementReceiver";
+
+ /**
+ * Shared preference name for activation information, the key used in this file should append
+ * slot id if the value depended on carrier.
+ */
+ private static final String PREFERENCE_ACTIVATION_INFO = "PREFERENCE_ACTIVATION_INFO";
+ /**
+ * Shared preference key for last known subscription id of a SIM slot; default value {@link
+ * SubscriptionManager#INVALID_SUBSCRIPTION_ID}.
+ */
+ private static final String KEY_LAST_SUB_ID = "last_sub_id_";
+ /** Shared preference key for last boot count. */
+ private static final String KEY_LAST_BOOT_COUNT = "last_boot_count_";
+
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ int currentSubId =
+ intent.getIntExtra(
+ SubscriptionManager.EXTRA_SUBSCRIPTION_INDEX,
+ SubscriptionManager.INVALID_SUBSCRIPTION_ID);
+ int slotId =
+ intent.getIntExtra(
+ SubscriptionManager.EXTRA_SLOT_INDEX,
+ SubscriptionManager.INVALID_SIM_SLOT_INDEX);
+ Dependencies dependencies = createDependency(context, currentSubId);
+ if (!dependencies.userManager.isSystemUser()
+ || !TelephonyUtils.isImsProvisioningRequired(context, currentSubId)) {
+ return;
+ }
+
+ String action = intent.getAction();
+ if (CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED.equals(action)) {
+ final PendingResult result = goAsync();
+ getAsyncExecutor().execute(
+ () -> handleCarrierConfigChanged(
+ context, currentSubId, slotId, dependencies.jobManager, result));
+ }
+ }
+
+ /**
+ * Handles the event of SIM change and device boot up while receiving {@link
+ * CarrierConfigManager#ACTION_CARRIER_CONFIG_CHANGED}.
+ */
+ @WorkerThread
+ private void handleCarrierConfigChanged(
+ Context context, int currentSubId, int slotId, JobManager jobManager,
+ PendingResult result) {
+ if (!SubscriptionManager.isValidSubscriptionId(currentSubId)) {
+ return;
+ }
+ boolean shouldQuery = false;
+
+ // Handle device boot up.
+ if (isBootUp(context, slotId)) {
+ ClientBehavior clientBehavior =
+ new EntitlementConfiguration(context, currentSubId).entitlementValidation();
+ Log.d(TAG, "Device boot up, clientBehavior=" + clientBehavior);
+ if (clientBehavior == VALID_DURING_VALIDITY
+ || clientBehavior == VALID_WITHOUT_DURATION
+ || clientBehavior == NEEDS_TO_RESET) {
+ shouldQuery = true;
+ }
+ }
+
+ // Handle SIM changed.
+ int lastSubId = getAndSetSubId(context, currentSubId, slotId);
+ if (currentSubId != lastSubId) {
+ Log.d(TAG,
+ "SubId for slot " + slotId + " changed: " + lastSubId + " -> " + currentSubId);
+ if (SubscriptionManager.isValidSubscriptionId(lastSubId)) {
+ new EntitlementConfiguration(context, lastSubId).reset();
+ }
+ shouldQuery = true;
+ }
+
+ if (shouldQuery) {
+ jobManager.queryEntitlementStatusOnceNetworkReady();
+ }
+
+ if (result != null) {
+ result.finish();
+ }
+ }
+
+ /**
+ * Returns {@code true} if current boot count greater than previous one. Saves the latest boot
+ * count into shared preference.
+ */
+ @VisibleForTesting
+ boolean isBootUp(Context context, int slotId) {
+ SharedPreferences preferences =
+ context.getSharedPreferences(PREFERENCE_ACTIVATION_INFO, Context.MODE_PRIVATE);
+ int lastBootCount = preferences.getInt(KEY_LAST_BOOT_COUNT + slotId, 0);
+ int currentBootCount =
+ Settings.Global.getInt(
+ context.getContentResolver(), Settings.Global.BOOT_COUNT, /* def= */ -1);
+ preferences.edit().putInt(KEY_LAST_BOOT_COUNT + slotId, currentBootCount).apply();
+
+ return currentBootCount != lastBootCount;
+ }
+
+ private int getAndSetSubId(Context context, int currentSubId, int slotId) {
+ SharedPreferences preferences =
+ context.getSharedPreferences(PREFERENCE_ACTIVATION_INFO, Context.MODE_PRIVATE);
+ int lastSubId = preferences.getInt(
+ KEY_LAST_SUB_ID + slotId, SubscriptionManager.INVALID_SUBSCRIPTION_ID);
+ preferences.edit().putInt(KEY_LAST_SUB_ID + slotId, currentSubId).apply();
+ return lastSubId;
+ }
+
+ /** Returns initialized dependencies */
+ @VisibleForTesting
+ Dependencies createDependency(Context context, int subId) {
+ // Wrap return value
+ Dependencies ret = new Dependencies();
+ ret.telephonyUtils = new TelephonyUtils(context, subId);
+ ret.userManager = context.getSystemService(UserManager.class);
+ ret.jobManager =
+ JobManager.getInstance(context, ImsEntitlementPollingService.COMPONENT_NAME, subId);
+ return ret;
+ }
+
+ /** A collection of dependency objects */
+ protected static class Dependencies {
+ public TelephonyUtils telephonyUtils;
+ public UserManager userManager;
+ public JobManager jobManager;
+ }
+}
diff --git a/src/com/android/imsserviceentitlement/WfcActivationController.java b/src/com/android/imsserviceentitlement/WfcActivationController.java
index bb25278..ed63bf9 100644
--- a/src/com/android/imsserviceentitlement/WfcActivationController.java
+++ b/src/com/android/imsserviceentitlement/WfcActivationController.java
@@ -60,8 +60,6 @@ public class WfcActivationController {
private static final int ENTITLEMENT_STATUS_UPDATE_RETRY_MAX = 6;
private static final long ENTITLEMENT_STATUS_UPDATE_RETRY_INTERVAL_MS =
Duration.ofSeconds(5).toMillis();
- private static final long ENTITLEMENT_STATUS_UPDATE_RETRY_INTERVAL_MS_ATT =
- Duration.ofMinutes(30).toMillis();
// Dependencies
private final WfcActivationUi mActivationUi;
diff --git a/src/com/android/imsserviceentitlement/entitlement/EntitlementConfiguration.java b/src/com/android/imsserviceentitlement/entitlement/EntitlementConfiguration.java
index 8b51988..7617cc6 100644
--- a/src/com/android/imsserviceentitlement/entitlement/EntitlementConfiguration.java
+++ b/src/com/android/imsserviceentitlement/entitlement/EntitlementConfiguration.java
@@ -35,23 +35,23 @@ public class EntitlementConfiguration {
/** Default value of VoLTE/VoWifi/SMSoverIP entitlemenet status. */
private static final int INCOMPATIBLE_STATE = 2;
- private final EntitlementConfigurationsDataStore mConfigutationsDataStore;
+ private final EntitlementConfigurationsDataStore mConfigurationsDataStore;
private XmlDoc mXmlDoc = new XmlDoc(null);
public EntitlementConfiguration(Context context, int subId) {
- mConfigutationsDataStore = new EntitlementConfigurationsDataStore(context, subId);
- mConfigutationsDataStore.get().ifPresent(rawXml -> mXmlDoc = new XmlDoc(rawXml));
+ mConfigurationsDataStore = EntitlementConfigurationsDataStore.getInstance(context, subId);
+ mConfigurationsDataStore.get().ifPresent(rawXml -> mXmlDoc = new XmlDoc(rawXml));
}
/** Update VERS characteristics with given version and validity. */
public void update(String rawXml) {
- mConfigutationsDataStore.set(rawXml);
+ mConfigurationsDataStore.set(rawXml);
mXmlDoc = new XmlDoc(rawXml);
}
/**
- * Returns VoLTE entitlement status from the {@link EntitlementCharacteristicDataStore}. If no
+ * Returns VoLTE entitlement status from the {@link EntitlementConfigurationsDataStore}. If no
* data exist then return the default value {@link #INCOMPATIBLE_STATE}.
*/
public int getVolteStatus() {
@@ -64,7 +64,7 @@ public class EntitlementConfiguration {
}
/**
- * Returns VoWiFi entitlement status from the {@link EntitlementCharacteristicDataStore}. If no
+ * Returns VoWiFi entitlement status from the {@link EntitlementConfigurationsDataStore}. If no
* data exist then return the default value {@link #INCOMPATIBLE_STATE}.
*/
public int getVoWifiStatus() {
@@ -77,7 +77,7 @@ public class EntitlementConfiguration {
}
/**
- * Returns SMSoIP entitlement status from the {@link EntitlementCharacteristicDataStore}. If no
+ * Returns SMSoIP entitlement status from the {@link EntitlementConfigurationsDataStore}. If no
* data exist then return the default value {@link #INCOMPATIBLE_STATE}.
*/
public int getSmsOverIpStatus() {
@@ -90,7 +90,7 @@ public class EntitlementConfiguration {
}
/**
- * Returns token stored in the {@link EntitlementCharacteristicDataStore} if it is in validity
+ * Returns token stored in the {@link EntitlementConfigurationsDataStore} if it is in validity
* period. Returns {@link Optional#empty()} if the token was expired or the value of token
* validity not positive.
*/
@@ -101,7 +101,7 @@ public class EntitlementConfiguration {
}
private boolean isTokenInValidityPeriod() {
- long queryTimeMillis = mConfigutationsDataStore.getQueryTimeMillis();
+ long queryTimeMillis = mConfigurationsDataStore.getQueryTimeMillis();
long tokenValidityMillis = TimeUnit.SECONDS.toMillis(getTokenValidity());
if (queryTimeMillis <= 0) {
@@ -115,7 +115,7 @@ public class EntitlementConfiguration {
return true;
}
- return System.currentTimeMillis() - queryTimeMillis < tokenValidityMillis;
+ return (System.currentTimeMillis() - queryTimeMillis) < tokenValidityMillis;
}
/**
diff --git a/src/com/android/imsserviceentitlement/entitlement/EntitlementConfigurationsDataStore.java b/src/com/android/imsserviceentitlement/entitlement/EntitlementConfigurationsDataStore.java
index 29ea637..6947e2b 100644
--- a/src/com/android/imsserviceentitlement/entitlement/EntitlementConfigurationsDataStore.java
+++ b/src/com/android/imsserviceentitlement/entitlement/EntitlementConfigurationsDataStore.java
@@ -18,6 +18,7 @@ package com.android.imsserviceentitlement.entitlement;
import android.content.Context;
import android.content.SharedPreferences;
+import android.util.SparseArray;
import java.util.Optional;
@@ -29,7 +30,17 @@ class EntitlementConfigurationsDataStore {
private final SharedPreferences mPreferences;
- EntitlementConfigurationsDataStore(Context context, int subId) {
+ private static final SparseArray<EntitlementConfigurationsDataStore> sInstances =
+ new SparseArray<>();
+
+ public static EntitlementConfigurationsDataStore getInstance(Context context, int subId) {
+ if (sInstances.get(subId) == null) {
+ sInstances.put(subId, new EntitlementConfigurationsDataStore(context, subId));
+ }
+ return sInstances.get(subId);
+ }
+
+ private EntitlementConfigurationsDataStore(Context context, int subId) {
this.mPreferences = context.getSharedPreferences(
PREFERENCE_ENTITLEMENT_CHARACTERISTICS + "_" + subId,
Context.MODE_PRIVATE);
diff --git a/src/com/android/imsserviceentitlement/utils/Executors.java b/src/com/android/imsserviceentitlement/utils/Executors.java
new file mode 100644
index 0000000..3f8e68f
--- /dev/null
+++ b/src/com/android/imsserviceentitlement/utils/Executors.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2021 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.imsserviceentitlement.utils;
+
+import static android.os.AsyncTask.THREAD_POOL_EXECUTOR;
+
+import java.util.concurrent.Executor;
+
+/** Provides executors for running the tasks asynchronized. */
+public final class Executors {
+ /**
+ * Whether to execute entitlementCheck in caller's thread, set to true via reflection for test.
+ */
+ private static boolean sUseDirectExecutorForTest = false;
+
+ private static final Executor ASYNC_EXECUTOR = THREAD_POOL_EXECUTOR;
+ private static final Executor DIRECT_EXECUTOR = Runnable::run;
+
+ private Executors() {}
+
+ /** Returns {@link Executor} executing tasks asynchronously. */
+ public static Executor getAsyncExecutor() {
+ return sUseDirectExecutorForTest ? DIRECT_EXECUTOR : ASYNC_EXECUTOR;
+ }
+
+ /** Returns {@link Executor} executing tasks from the caller's thread. */
+ public static Executor getDirectExecutor() {
+ return DIRECT_EXECUTOR;
+ }
+}
diff --git a/tests/unittests/src/com/android/imsserviceentitlement/EntitlementUtilsTest.java b/tests/unittests/src/com/android/imsserviceentitlement/EntitlementUtilsTest.java
index 928273d..474e755 100644
--- a/tests/unittests/src/com/android/imsserviceentitlement/EntitlementUtilsTest.java
+++ b/tests/unittests/src/com/android/imsserviceentitlement/EntitlementUtilsTest.java
@@ -24,6 +24,7 @@ import androidx.test.runner.AndroidJUnit4;
import com.android.imsserviceentitlement.WfcActivationController.EntitlementResultCallback;
import com.android.imsserviceentitlement.entitlement.EntitlementResult;
+import com.android.imsserviceentitlement.utils.Executors;
import org.junit.Before;
import org.junit.Rule;
@@ -44,7 +45,7 @@ public class EntitlementUtilsTest {
@Before
public void setup() throws Exception {
- Field field = EntitlementUtils.class.getDeclaredField("sUseDirectExecutorForTest");
+ Field field = Executors.class.getDeclaredField("sUseDirectExecutorForTest");
field.setAccessible(true);
field.set(null, true);
}
diff --git a/tests/unittests/src/com/android/imsserviceentitlement/ImsEntitlementPollingServiceTest.java b/tests/unittests/src/com/android/imsserviceentitlement/ImsEntitlementPollingServiceTest.java
index 6dc333c..2737c62 100644
--- a/tests/unittests/src/com/android/imsserviceentitlement/ImsEntitlementPollingServiceTest.java
+++ b/tests/unittests/src/com/android/imsserviceentitlement/ImsEntitlementPollingServiceTest.java
@@ -16,11 +16,14 @@
package com.android.imsserviceentitlement;
+import static com.google.common.truth.Truth.assertThat;
+
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.app.job.JobParameters;
+import android.app.job.JobScheduler;
import android.content.Context;
import android.os.PersistableBundle;
import android.telephony.CarrierConfigManager;
@@ -67,17 +70,19 @@ public class ImsEntitlementPollingServiceTest {
@Mock private CarrierConfigManager mCarrierConfigManager;
private ImsEntitlementPollingService mService;
+ private JobScheduler mScheduler;
private static final int SUB_ID = 1;
private static final int SLOT_ID = 0;
@Before
- public void setup() throws Exception {
+ public void setUp() throws Exception {
mService = new ImsEntitlementPollingService();
mService.attachBaseContext(mContext);
mService.onCreate();
mService.onBind(null);
mService.injectImsEntitlementApi(mImsEntitlementApi);
+ mScheduler = mContext.getSystemService(JobScheduler.class);
setActivedSubscription();
setupImsUtils();
setJobParameters();
@@ -154,6 +159,16 @@ public class ImsEntitlementPollingServiceTest {
verify(mImsUtils).setSmsoipProvisioned(true);
}
+ @Test
+ public void enqueueJob_hasJob() {
+ ImsEntitlementPollingService.enqueueJob(mContext, SUB_ID, 0);
+
+ assertThat(
+ mScheduler.getPendingJob(
+ jobIdWithSubId(JobManager.QUERY_ENTITLEMENT_STATUS_JOB_ID, SUB_ID)))
+ .isNotNull();
+ }
+
private void setActivedSubscription() {
when(mSubscriptionInfo.getSimSlotIndex()).thenReturn(SLOT_ID);
when(mSubscriptionManager.getActiveSubscriptionInfo(SUB_ID)).thenReturn(mSubscriptionInfo);
@@ -209,6 +224,10 @@ public class ImsEntitlementPollingServiceTest {
.build();
}
+ private int jobIdWithSubId(int jobId, int subId) {
+ return 1000 * subId + jobId;
+ }
+
private static final Ts43VowifiStatus sDisableVoWiFi =
Ts43VowifiStatus.builder()
.setEntitlementStatus(EntitlementStatus.DISABLED)
diff --git a/tests/unittests/src/com/android/imsserviceentitlement/ImsEntitlementReceiverTest.java b/tests/unittests/src/com/android/imsserviceentitlement/ImsEntitlementReceiverTest.java
new file mode 100644
index 0000000..dbea9a1
--- /dev/null
+++ b/tests/unittests/src/com/android/imsserviceentitlement/ImsEntitlementReceiverTest.java
@@ -0,0 +1,236 @@
+/*
+ * Copyright (C) 2021 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.imsserviceentitlement;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.SharedPreferences;
+import android.os.PersistableBundle;
+import android.os.UserManager;
+import android.telephony.CarrierConfigManager;
+import android.telephony.SubscriptionManager;
+
+import androidx.test.core.app.ApplicationProvider;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.imsserviceentitlement.entitlement.EntitlementConfiguration;
+import com.android.imsserviceentitlement.job.JobManager;
+import com.android.imsserviceentitlement.utils.Executors;
+import com.android.imsserviceentitlement.utils.TelephonyUtils;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.Spy;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
+
+import java.lang.reflect.Field;
+
+@RunWith(AndroidJUnit4.class)
+public class ImsEntitlementReceiverTest {
+ private static final int SUB_ID = 1;
+ private static final int LAST_SUB_ID = 2;
+ private static final String RAW_XML =
+ "<wap-provisioningdoc version=\"1.1\">\n"
+ + " <characteristic type=\"APPLICATION\">\n"
+ + " <parm name=\"AppID\" value=\"ap2004\"/>\n"
+ + " <parm name=\"EntitlementStatus\" value=\"1\"/>\n"
+ + " </characteristic>\n"
+ + "</wap-provisioningdoc>\n";
+
+ private static final String RAW_XML_VERSION_0_VALIDITY_0 =
+ "<wap-provisioningdoc version=\"1.1\">\n"
+ + " <characteristic type=\"VERS\">\n"
+ + " <parm name=\"version\" value=\"0\"/>\n"
+ + " <parm name=\"validity\" value=\"0\"/>\n"
+ + " </characteristic>\n"
+ + "</wap-provisioningdoc>\n";
+
+ private static final String RAW_XML_INVALID_VERS =
+ "<wap-provisioningdoc version=\"1.1\">\n"
+ + " <characteristic type=\"VERS\">\n"
+ + " <parm name=\"version\" value=\"-1\"/>\n"
+ + " <parm name=\"validity\" value=\"-1\"/>\n"
+ + " </characteristic>\n"
+ + "</wap-provisioningdoc>\n";
+ private static final ComponentName POLLING_SERVICE_COMPONENT_NAME =
+ ComponentName.unflattenFromString(
+ "com.android.imsserviceentitlement/.ImsEntitlementPollingService");
+
+ @Rule public final MockitoRule rule = MockitoJUnit.rule();
+
+ @Mock private TelephonyUtils mMockTelephonyUtils;
+ @Mock private UserManager mMockUserManager;
+ @Mock private CarrierConfigManager mCarrierConfigManager;
+ @Mock private JobManager mMockJobManager;
+
+ @Spy private final Context mContext = ApplicationProvider.getApplicationContext();
+
+ private ImsEntitlementReceiver mReceiver;
+ private boolean mIsBootUp;
+
+ @Before
+ public void setUp() throws Exception {
+ mReceiver = new ImsEntitlementReceiver() {
+ @Override
+ protected Dependencies createDependency(Context context, int subId) {
+ Dependencies dependencies = new Dependencies();
+ dependencies.userManager = mMockUserManager;
+ dependencies.telephonyUtils = mMockTelephonyUtils;
+ dependencies.jobManager = mMockJobManager;
+ return dependencies;
+ }
+
+ @Override
+ protected boolean isBootUp(Context context, int slotId) {
+ return mIsBootUp;
+ }
+ };
+ mIsBootUp = false;
+
+ new EntitlementConfiguration(mContext, LAST_SUB_ID).update(RAW_XML);
+ new EntitlementConfiguration(mContext, SUB_ID).reset();
+
+ when(mMockUserManager.isSystemUser()).thenReturn(true);
+
+ setLastSubId(LAST_SUB_ID, 0);
+ setupCarrierConfig();
+ useDirectExecutor();
+ }
+
+ @Test
+ public void onReceive_simChanged_dataReset() {
+ mReceiver.onReceive(mContext, getCarrierConfigChangedIntent(SUB_ID, /* slotId= */ 0));
+
+ assertThat(
+ new EntitlementConfiguration(mContext, LAST_SUB_ID).getVoWifiStatus()).isEqualTo(2);
+ verify(mMockJobManager, times(1)).queryEntitlementStatusOnceNetworkReady();
+ }
+
+ @Test
+ public void onReceive_theSameSim_dataNotReset() {
+ mReceiver.onReceive(
+ mContext, getCarrierConfigChangedIntent(LAST_SUB_ID, /* slotId= */ 0));
+
+ assertThat(
+ new EntitlementConfiguration(mContext, LAST_SUB_ID).getVoWifiStatus()).isEqualTo(1);
+ verify(mMockJobManager, never()).queryEntitlementStatusOnceNetworkReady();
+ }
+
+ @Test
+ public void onReceive_differentSlot_dataNotReset() {
+ setLastSubId(LAST_SUB_ID, 1);
+
+ mReceiver.onReceive(
+ mContext, getCarrierConfigChangedIntent(LAST_SUB_ID, /* slotId= */ 1));
+
+ assertThat(
+ new EntitlementConfiguration(mContext, LAST_SUB_ID).getVoWifiStatus()).isEqualTo(1);
+ verify(mMockJobManager, never()).queryEntitlementStatusOnceNetworkReady();
+ }
+
+ @Test
+ public void onReceive_simChangedAndDifferentSlotId_dataReset() {
+ setLastSubId(LAST_SUB_ID, 1);
+
+ mReceiver.onReceive(mContext, getCarrierConfigChangedIntent(SUB_ID, /* slotId= */ 1));
+
+ assertThat(
+ new EntitlementConfiguration(mContext, LAST_SUB_ID).getVoWifiStatus()).isEqualTo(2);
+ verify(mMockJobManager).queryEntitlementStatusOnceNetworkReady();
+ }
+
+ @Test
+ public void onReceive_isSystemUser_jobScheduled() {
+ when(mMockUserManager.isSystemUser()).thenReturn(true);
+
+ mReceiver.onReceive(
+ mContext, getCarrierConfigChangedIntent(SUB_ID, /* slotId= */ 0));
+
+ verify(mMockJobManager).queryEntitlementStatusOnceNetworkReady();
+ }
+
+ @Test
+ public void onReceive_notSystemUser_noJobScheduled() {
+ when(mMockUserManager.isSystemUser()).thenReturn(false);
+
+ mReceiver.onReceive(
+ mContext, getCarrierConfigChangedIntent(SUB_ID, /* slotId= */ 0));
+
+ verify(mMockJobManager, never()).queryEntitlementStatusOnceNetworkReady();
+ }
+
+ @Test
+ public void onReceive_deviceBootUp_jobScheduled() {
+ new EntitlementConfiguration(mContext, LAST_SUB_ID).update(RAW_XML_VERSION_0_VALIDITY_0);
+ mIsBootUp = true;
+
+ mReceiver.onReceive(mContext, getCarrierConfigChangedIntent(LAST_SUB_ID, /* slotId= */ 0));
+
+ verify(mMockJobManager).queryEntitlementStatusOnceNetworkReady();
+ }
+
+ @Test
+ public void onReceive_bootCompleteInvalidVers_noJobScheduled() {
+ new EntitlementConfiguration(mContext, LAST_SUB_ID).update(RAW_XML_INVALID_VERS);
+ mIsBootUp = true;
+
+ mReceiver.onReceive(mContext, getCarrierConfigChangedIntent(LAST_SUB_ID, /* slotId= */ 0));
+
+ verify(mMockJobManager, never()).queryEntitlementStatusOnceNetworkReady();
+ }
+
+ private Intent getCarrierConfigChangedIntent(int subId, int slotId) {
+ Intent intent = new Intent(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED);
+ intent.putExtra(SubscriptionManager.EXTRA_SUBSCRIPTION_INDEX, subId);
+ intent.putExtra(SubscriptionManager.EXTRA_SLOT_INDEX, slotId);
+ return intent;
+ }
+
+ private void setupCarrierConfig() {
+ PersistableBundle carrierConfig = new PersistableBundle();
+ carrierConfig.putBoolean(
+ CarrierConfigManager.ImsServiceEntitlement.KEY_IMS_PROVISIONING_BOOL, true);
+ when(mContext.getSystemService(CarrierConfigManager.class))
+ .thenReturn(mCarrierConfigManager);
+ when(mCarrierConfigManager.getConfigForSubId(SUB_ID)).thenReturn(carrierConfig);
+ when(mCarrierConfigManager.getConfigForSubId(LAST_SUB_ID)).thenReturn(carrierConfig);
+ }
+
+ private void setLastSubId(int subId, int slotId) {
+ SharedPreferences preferences =
+ mContext.getSharedPreferences("PREFERENCE_ACTIVATION_INFO", Context.MODE_PRIVATE);
+ preferences.edit().putInt("last_sub_id_" + slotId, subId).apply();
+ }
+
+ private void useDirectExecutor() throws Exception {
+ Field field = Executors.class.getDeclaredField("sUseDirectExecutorForTest");
+ field.setAccessible(true);
+ field.set(null, true);
+ }
+}
diff --git a/tests/unittests/src/com/android/imsserviceentitlement/WfcActivationControllerTest.java b/tests/unittests/src/com/android/imsserviceentitlement/WfcActivationControllerTest.java
index bd78b14..72b9341 100644
--- a/tests/unittests/src/com/android/imsserviceentitlement/WfcActivationControllerTest.java
+++ b/tests/unittests/src/com/android/imsserviceentitlement/WfcActivationControllerTest.java
@@ -39,6 +39,7 @@ import com.android.imsserviceentitlement.ts43.Ts43VowifiStatus.AddrStatus;
import com.android.imsserviceentitlement.ts43.Ts43VowifiStatus.EntitlementStatus;
import com.android.imsserviceentitlement.ts43.Ts43VowifiStatus.ProvStatus;
import com.android.imsserviceentitlement.ts43.Ts43VowifiStatus.TcStatus;
+import com.android.imsserviceentitlement.utils.Executors;
import org.junit.Before;
import org.junit.Rule;
@@ -79,7 +80,7 @@ public class WfcActivationControllerTest {
when(mTelephonyManager.createForSubscriptionId(SUB_ID)).thenReturn(mTelephonyManager);
setNetworkConnected(true);
- Field field = EntitlementUtils.class.getDeclaredField("sUseDirectExecutorForTest");
+ Field field = Executors.class.getDeclaredField("sUseDirectExecutorForTest");
field.setAccessible(true);
field.set(null, true);
}