Merge "Fixed the set/getAllowedNetworkTypes debug messages"
diff --git a/assets/CarrierRestrictionOperatorDetails.json b/assets/CarrierRestrictionOperatorDetails.json
new file mode 100644
index 0000000..166cc39
--- /dev/null
+++ b/assets/CarrierRestrictionOperatorDetails.json
@@ -0,0 +1,4 @@
+{
+ "_comment": "Operator should register with its application package name, carrierId and all the corresponding SHAIDs",
+ "_comment": "Example format :: << \"packageName\" : {\"carrierId\":<int>, \"callerSHA1Id\":[<SHAID1>, <SHAID2>]} >>"
+}
\ No newline at end of file
diff --git a/src/com/android/phone/PhoneInterfaceManager.java b/src/com/android/phone/PhoneInterfaceManager.java
index 4d467ab..61f38d8 100644
--- a/src/com/android/phone/PhoneInterfaceManager.java
+++ b/src/com/android/phone/PhoneInterfaceManager.java
@@ -31,6 +31,7 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.RequiresPermission;
+import android.app.ActivityManager;
import android.app.AppOpsManager;
import android.app.PendingIntent;
import android.app.PropertyInvalidatedCache;
@@ -436,6 +437,8 @@
private static final int SET_NETWORK_SELECTION_MODE_AUTOMATIC_TIMEOUT_MS = 2000; // 2 seconds
+ private static final int MODEM_ACTIVITY_TIME_OFFSET_CORRECTION_MS = 50;
+
/**
* With support for MEP(multiple enabled profile) in Android T, a SIM card can have more than
* one ICCID active at the same time.
@@ -489,13 +492,11 @@
private static final class PurchasePremiumCapabilityArgument {
public @TelephonyManager.PremiumCapability int capability;
- public @NonNull String appName;
public @NonNull IIntegerConsumer callback;
PurchasePremiumCapabilityArgument(@TelephonyManager.PremiumCapability int capability,
- @NonNull String appName, @NonNull IIntegerConsumer callback) {
+ @NonNull IIntegerConsumer callback) {
this.capability = capability;
- this.appName = appName;
this.callback = callback;
}
}
@@ -1467,6 +1468,8 @@
ModemActivityInfo info = (ModemActivityInfo) ar.result;
if (isModemActivityInfoValid(info)) {
mergeModemActivityInfo(info);
+ } else {
+ loge("queryModemActivityInfo: invalid response");
}
// This is needed to decouple ret from mLastModemActivityInfo
// We don't want to return mLastModemActivityInfo which is updated
@@ -2177,7 +2180,7 @@
PurchasePremiumCapabilityArgument arg =
(PurchasePremiumCapabilityArgument) request.argument;
SlicePurchaseController.getInstance(request.phone).purchasePremiumCapability(
- arg.capability, arg.appName, onCompleted);
+ arg.capability, onCompleted);
break;
}
@@ -2422,8 +2425,7 @@
mRadioInterfaceCapabilities = RadioInterfaceCapabilityController.getInstance();
mNotifyUserActivity = new AtomicBoolean(false);
PropertyInvalidatedCache.invalidateCache(TelephonyManager.CACHE_KEY_PHONE_ACCOUNT_TO_SUBID);
- mTelephony2gUpdater = new Telephony2gUpdater(
- Executors.newSingleThreadExecutor(), mApp);
+ mTelephony2gUpdater = new Telephony2gUpdater(mApp);
mTelephony2gUpdater.init();
publish();
}
@@ -8028,7 +8030,7 @@
}
}
- // Checks that ModemActivityInfo is valid. Sleep time, Idle time, Rx time and Tx time should be
+ // Checks that ModemActivityInfo is valid. Sleep time and Idle time should be
// less than total activity duration.
private boolean isModemActivityInfoValid(ModemActivityInfo info) {
if (info == null) {
@@ -8036,13 +8038,13 @@
}
int activityDurationMs =
(int) (info.getTimestampMillis() - mLastModemActivityInfo.getTimestampMillis());
+ activityDurationMs += MODEM_ACTIVITY_TIME_OFFSET_CORRECTION_MS;
+
int totalTxTimeMs = Arrays.stream(info.getTransmitTimeMillis()).sum();
return (info.isValid()
&& (info.getSleepTimeMillis() <= activityDurationMs)
- && (info.getIdleTimeMillis() <= activityDurationMs)
- && (info.getReceiveTimeMillis() <= activityDurationMs)
- && (totalTxTimeMs <= activityDurationMs));
+ && (info.getIdleTimeMillis() <= activityDurationMs));
}
private void updateLastModemActivityInfo(ModemActivityInfo info, int rat, int freq) {
@@ -11452,6 +11454,12 @@
+ " failed due to missing permissions.");
throw new SecurityException("purchasePremiumCapability requires permission "
+ "READ_BASIC_PHONE_STATE.");
+ } else if (!TelephonyPermissions.checkInternetPermissionNoThrow(
+ mApp, "purchasePremiumCapability")) {
+ log("purchasePremiumCapability "
+ + TelephonyManager.convertPremiumCapabilityToString(capability)
+ + " failed due to missing permissions.");
+ throw new SecurityException("purchasePremiumCapability requires permission INTERNET.");
}
Phone phone = getPhone(subId);
@@ -11470,15 +11478,50 @@
}
return;
}
- String appName;
+
+ String callingProcess;
try {
- appName = mApp.getPackageManager().getApplicationLabel(mApp.getPackageManager()
- .getApplicationInfo(getCurrentPackageName(), 0)).toString();
+ callingProcess = mApp.getPackageManager().getApplicationInfo(
+ getCurrentPackageName(), 0).processName;
} catch (PackageManager.NameNotFoundException e) {
- appName = "An application";
+ callingProcess = getCurrentPackageName();
}
+
+ boolean isVisible = false;
+ ActivityManager am = mApp.getSystemService(ActivityManager.class);
+ if (am != null) {
+ List<ActivityManager.RunningAppProcessInfo> processes = am.getRunningAppProcesses();
+ if (processes != null) {
+ for (ActivityManager.RunningAppProcessInfo process : processes) {
+ log("purchasePremiumCapability: process " + process.processName
+ + "has importance " + process.importance);
+ if (process.processName.equals(callingProcess) && process.importance
+ <= ActivityManager.RunningAppProcessInfo.IMPORTANCE_VISIBLE) {
+ isVisible = true;
+ break;
+ }
+ }
+ }
+ }
+
+ if (!isVisible) {
+ try {
+ int result = TelephonyManager.PURCHASE_PREMIUM_CAPABILITY_RESULT_NOT_FOREGROUND;
+ callback.accept(result);
+ loge("purchasePremiumCapability: " + callingProcess + " is not in the foreground.");
+ } catch (RemoteException e) {
+ String logStr = "Purchase premium capability "
+ + TelephonyManager.convertPremiumCapabilityToString(capability)
+ + " failed due to RemoteException handling background application: " + e;
+ if (DBG) log(logStr);
+ AnomalyReporter.reportAnomaly(
+ UUID.fromString(PURCHASE_PREMIUM_CAPABILITY_ERROR_UUID), logStr);
+ }
+ return;
+ }
+
sendRequestAsync(CMD_PURCHASE_PREMIUM_CAPABILITY,
- new PurchasePremiumCapabilityArgument(capability, appName, callback), phone, null);
+ new PurchasePremiumCapabilityArgument(capability, callback), phone, null);
}
/**
diff --git a/src/com/android/phone/Telephony2gUpdater.java b/src/com/android/phone/Telephony2gUpdater.java
index 0919385..baaa684 100644
--- a/src/com/android/phone/Telephony2gUpdater.java
+++ b/src/com/android/phone/Telephony2gUpdater.java
@@ -30,8 +30,13 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.telephony.RILConstants;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashSet;
import java.util.List;
+import java.util.Set;
import java.util.concurrent.Executor;
+import java.util.concurrent.Executors;
/**
* A {@link BroadcastReceiver} that ensures that user restrictions are correctly applied to
@@ -39,27 +44,50 @@
* This includes handling broadcasts from user restriction state changes, as well as ensuring that
* SIM-specific settings are correctly applied when new subscriptions become active.
*
+ * <p>
* Callers are expected to call {@code init()} and keep an instance of this class alive.
+ * </p>
*/
public class Telephony2gUpdater extends BroadcastReceiver {
- private static final String TAG = "TelephonyUserManagerReceiver";
+ private static final String TAG = "Telephony2gUpdater";
// We can't interact with the HAL on the main thread of the phone process (where
// receivers are run by default), so we execute our logic from a separate thread.
+ // The correctness of this implementation relies heavily on this executor ensuring
+ // tasks are serially executed i.e. ExecutorService.newSingleThreadExecutor()
private final Executor mExecutor;
private final Context mContext;
private final long mBaseAllowedNetworks;
- public Telephony2gUpdater(Executor executor, Context context) {
- this(executor, context,
+ private UserManager mUserManager;
+ private TelephonyManager mTelephonyManager;
+ private SubscriptionManager mSubscriptionManager;
+
+ // The current subscription ids
+ // Ensure this value is never accessed concurrently
+ private Set<Integer> mCurrentSubscriptions;
+ // We keep track of the last value to avoid updating when unrelated user restrictions change
+ // Ensure this value is never accessed concurrently
+ private boolean mDisallowCellular2gRestriction;
+
+ public Telephony2gUpdater(Context context) {
+ this(Executors.newSingleThreadExecutor(), context,
RadioAccessFamily.getRafFromNetworkType(RILConstants.PREFERRED_NETWORK_MODE));
}
- public Telephony2gUpdater(Executor executor, Context context,
- long baseAllowedNetworks) {
+ @VisibleForTesting
+ public Telephony2gUpdater(Executor executor, Context context, long baseAllowedNetworks) {
mExecutor = executor;
mContext = context;
mBaseAllowedNetworks = baseAllowedNetworks;
+
+ mUserManager = mContext.getSystemService(UserManager.class);
+ mTelephonyManager = mContext.getSystemService(TelephonyManager.class);
+ mSubscriptionManager = mContext.getSystemService(SubscriptionManager.class);
+
+ // All user restrictions are false by default
+ mDisallowCellular2gRestriction = false;
+ mCurrentSubscriptions = new HashSet<>();
}
/**
@@ -80,41 +108,42 @@
Log.i(TAG, "Received callback for action " + intent.getAction());
final PendingResult result = goAsync();
mExecutor.execute(() -> {
- Log.i(TAG, "Running handler for action " + intent.getAction());
- handleUserRestrictionsChanged(context);
- result.finish();
+ boolean disallow2g = mUserManager.hasUserRestriction(UserManager.DISALLOW_CELLULAR_2G);
+ if (mDisallowCellular2gRestriction == disallow2g) {
+ Log.i(TAG, "No update to DISALLOW_CELLULAR_2G restriction.");
+ return;
+ }
+
+ mDisallowCellular2gRestriction = disallow2g;
+
+ Log.i(TAG, "Running handler for all subscriptions based on DISALLOW_CELLULAR_2G change."
+ + " Restriction value: " + mDisallowCellular2gRestriction);
+ handleUserRestrictionsChanged(mCurrentSubscriptions);
+ if (result != null) {
+ result.finish();
+ }
});
}
/**
- * Update all active subscriptions with allowed network types depending on the current state
- * of the {@link UserManager.DISALLOW_2G}.
+ * Update subscriptions with allowed network types depending on the current state
+ * of the {@link UserManager#DISALLOW_CELLULAR_2G}.
+ *
+ * @param subIds A list of subIds to update.
*/
- @VisibleForTesting
- public void handleUserRestrictionsChanged(Context context) {
- UserManager um = context.getSystemService(UserManager.class);
- TelephonyManager tm = context.getSystemService(TelephonyManager.class);
- SubscriptionManager sm = context.getSystemService(SubscriptionManager.class);
+ private void handleUserRestrictionsChanged(Collection<Integer> subIds) {
final long twoGBitmask = TelephonyManager.NETWORK_CLASS_BITMASK_2G;
- boolean shouldDisable2g = um.hasUserRestriction(UserManager.DISALLOW_CELLULAR_2G);
-
- // This is expected when subscription info cannot be determined. We'll get another
- // callback in the future from our SubscriptionListener once we have valid subscriptions.
- List<SubscriptionInfo> subscriptionInfoList = sm.getAvailableSubscriptionInfoList();
- if (subscriptionInfoList == null) {
- return;
- }
-
long allowedNetworkTypes = mBaseAllowedNetworks;
// 2G device admin controls are global
- for (SubscriptionInfo info : subscriptionInfoList) {
- TelephonyManager telephonyManager = tm.createForSubscriptionId(
- info.getSubscriptionId());
- if (shouldDisable2g) {
+ for (Integer subId : subIds) {
+ TelephonyManager telephonyManager = mTelephonyManager.createForSubscriptionId(subId);
+ if (mDisallowCellular2gRestriction) {
+ Log.i(TAG, "Disabling 2g based on user restriction for subId: " + subId);
allowedNetworkTypes &= ~twoGBitmask;
} else {
+ Log.i(TAG, "Enabling 2g based on user restriction for subId: " + subId);
allowedNetworkTypes |= twoGBitmask;
}
telephonyManager.setAllowedNetworkTypesForReason(
@@ -126,8 +155,30 @@
private class SubscriptionListener extends SubscriptionManager.OnSubscriptionsChangedListener {
@Override
public void onSubscriptionsChanged() {
- Log.i(TAG, "Running handler for subscription change.");
- handleUserRestrictionsChanged(mContext);
+ // Note that this entire callback gets invoked in the single threaded executor
+ List<SubscriptionInfo> allSubscriptions =
+ mSubscriptionManager.getCompleteActiveSubscriptionInfoList();
+
+ HashSet<Integer> updatedSubIds = new HashSet<>(allSubscriptions.size());
+ List<Integer> newSubIds = new ArrayList<>();
+
+ for (SubscriptionInfo info : allSubscriptions) {
+ updatedSubIds.add(info.getSubscriptionId());
+ if (!mCurrentSubscriptions.contains(info.getSubscriptionId())) {
+ newSubIds.add(info.getSubscriptionId());
+ }
+ }
+
+ mCurrentSubscriptions = updatedSubIds;
+
+ if (newSubIds.isEmpty()) {
+ Log.d(TAG, "No new subIds. Skipping update.");
+ return;
+ }
+
+ Log.i(TAG, "New subscriptions found. Running handler to update 2g restrictions with "
+ + "subIds " + newSubIds.toString());
+ handleUserRestrictionsChanged(newSubIds);
}
}
diff --git a/src/com/android/phone/slice/SlicePurchaseController.java b/src/com/android/phone/slice/SlicePurchaseController.java
index 3864119..e36325e 100644
--- a/src/com/android/phone/slice/SlicePurchaseController.java
+++ b/src/com/android/phone/slice/SlicePurchaseController.java
@@ -40,6 +40,7 @@
import android.os.Message;
import android.os.PersistableBundle;
import android.provider.DeviceConfig;
+import android.sysprop.TelephonyProperties;
import android.telephony.AnomalyReporter;
import android.telephony.CarrierConfigManager;
import android.telephony.SubscriptionManager;
@@ -204,11 +205,9 @@
public static final String EXTRA_FAILURE_REASON =
"com.android.phone.slice.extra.FAILURE_REASON";
/**
- * Extra for the application name requesting to purchase the premium capability
- * from the slice purchase application.
+ * Extra for the user's carrier.
*/
- public static final String EXTRA_REQUESTING_APP_NAME =
- "com.android.phone.slice.extra.REQUESTING_APP_NAME";
+ public static final String EXTRA_CARRIER = "com.android.phone.slice.extra.CARRIER";
/**
* Extra for the canceled PendingIntent that the slice purchase application can send as a
* response if the performance boost notification or WebView was canceled by the user.
@@ -497,11 +496,10 @@
break;
}
case EVENT_START_SLICE_PURCHASE_APP: {
- int capability = msg.arg1;
- String appName = (String) msg.obj;
- logd("EVENT_START_SLICE_PURCHASE_APP: " + appName + " requests capability "
+ int capability = (int) msg.obj;
+ logd("EVENT_START_SLICE_PURCHASE_APP: "
+ TelephonyManager.convertPremiumCapabilityToString(capability));
- onStartSlicePurchaseApplication(capability, appName);
+ onStartSlicePurchaseApplication(capability);
break;
}
case EVENT_PURCHASE_TIMEOUT: {
@@ -565,13 +563,11 @@
* Purchase the given premium capability from the carrier.
*
* @param capability The premium capability to purchase.
- * @param appName The name of the application requesting premium capabilities.
* @param onComplete The callback message to send when the purchase request is complete.
*/
public synchronized void purchasePremiumCapability(
- @TelephonyManager.PremiumCapability int capability, @NonNull String appName,
- @NonNull Message onComplete) {
- logd("purchasePremiumCapability: " + appName + " requests capability "
+ @TelephonyManager.PremiumCapability int capability, @NonNull Message onComplete) {
+ logd("purchasePremiumCapability: "
+ TelephonyManager.convertPremiumCapabilityToString(capability));
// Check whether the premium capability can be purchased.
if (!arePremiumCapabilitiesSupportedByDevice()) {
@@ -627,8 +623,7 @@
// All state checks passed. Mark purchase pending and start the slice purchase application.
// Process through the handler since this method is synchronized.
mPendingPurchaseCapabilities.put(capability, onComplete);
- sendMessage(obtainMessage(EVENT_START_SLICE_PURCHASE_APP, capability, 0 /* unused */,
- appName));
+ sendMessage(obtainMessage(EVENT_START_SLICE_PURCHASE_APP, capability));
}
private void sendPurchaseResult(@TelephonyManager.PremiumCapability int capability,
@@ -687,8 +682,8 @@
}
}
- private void onStartSlicePurchaseApplication(@TelephonyManager.PremiumCapability int capability,
- @NonNull String appName) {
+ private void onStartSlicePurchaseApplication(
+ @TelephonyManager.PremiumCapability int capability) {
PremiumNetworkEntitlementResponse premiumNetworkEntitlementResponse =
mPremiumNetworkEntitlementApi.checkEntitlementStatus(capability);
@@ -721,7 +716,8 @@
}
String purchaseUrl = getPurchaseUrl(premiumNetworkEntitlementResponse);
- if (TextUtils.isEmpty(purchaseUrl)) {
+ String carrier = getSimOperator();
+ if (TextUtils.isEmpty(purchaseUrl) || TextUtils.isEmpty(carrier)) {
handlePurchaseResult(capability,
PURCHASE_PREMIUM_CAPABILITY_RESULT_CARRIER_DISABLED, false);
return;
@@ -753,7 +749,7 @@
intent.putExtra(EXTRA_SUB_ID, mPhone.getSubId());
intent.putExtra(EXTRA_PREMIUM_CAPABILITY, capability);
intent.putExtra(EXTRA_PURCHASE_URL, purchaseUrl);
- intent.putExtra(EXTRA_REQUESTING_APP_NAME, appName);
+ intent.putExtra(EXTRA_CARRIER, carrier);
intent.putExtra(EXTRA_INTENT_CANCELED, createPendingIntent(
ACTION_SLICE_PURCHASE_APP_RESPONSE_CANCELED, capability, false));
intent.putExtra(EXTRA_INTENT_CARRIER_ERROR, createPendingIntent(
@@ -805,6 +801,20 @@
}
/**
+ * Get the SIM operator. This is the carrier name from the SIM rather than from the network,
+ * which will be the same regardless of whether the user is roaming or not.
+ *
+ * @return The operator name from the SIM.
+ */
+ @VisibleForTesting
+ @Nullable public String getSimOperator() {
+ if (mPhone.getPhoneId() < TelephonyProperties.icc_operator_alpha().size()) {
+ return TelephonyProperties.icc_operator_alpha().get(mPhone.getPhoneId());
+ }
+ return null;
+ }
+
+ /**
* Create the PendingIntent to allow the slice purchase application to send back responses.
*
* @param action The action that will be sent for this PendingIntent
@@ -819,6 +829,7 @@
Intent intent = new Intent(action);
intent.putExtra(EXTRA_PHONE_ID, mPhone.getPhoneId());
intent.putExtra(EXTRA_PREMIUM_CAPABILITY, capability);
+ intent.setPackage(mPhone.getContext().getPackageName());
return PendingIntent.getBroadcast(mPhone.getContext(), capability, intent,
PendingIntent.FLAG_CANCEL_CURRENT
| (mutable ? PendingIntent.FLAG_MUTABLE : PendingIntent.FLAG_IMMUTABLE));
@@ -1028,6 +1039,11 @@
}
private boolean isNetworkAvailable() {
+ if (mPhone.getServiceState().getDataRoaming()) {
+ logd("Network unavailable because it is roaming.");
+ return false;
+ }
+
// TODO (b/251558673): Create a listener for data network type changed to dismiss
// notification and activity when the network is no longer available.
switch (mPhone.getServiceState().getDataNetworkType()) {
diff --git a/src/com/android/services/telephony/TelephonyConnectionService.java b/src/com/android/services/telephony/TelephonyConnectionService.java
index 0b71feb..7d7d949 100644
--- a/src/com/android/services/telephony/TelephonyConnectionService.java
+++ b/src/com/android/services/telephony/TelephonyConnectionService.java
@@ -590,36 +590,41 @@
new DomainSelectionConnection.DomainSelectionConnectionCallback() {
@Override
public void onSelectionTerminated(@DisconnectCauses int cause) {
- Log.v(this, "Call domain selection terminated.");
- if (mDomainSelectionConnection != null) {
- mDomainSelectionConnection = null;
- }
-
- if (mNormalCallConnection != null) {
- // TODO: To support ShowPreciseFailedCause,
- // TelephonyConnection.getShowPreciseFailedCause API should be added.
-
- // If cause is NOT_VALID then, it's a redial cancellation and use cause
- // code from original connection.
- com.android.internal.telephony.Connection connection =
- mNormalCallConnection.getOriginalConnection();
- if (connection != null) {
- if (cause == android.telephony.DisconnectCause.NOT_VALID) {
- cause = connection.getDisconnectCause();
+ mDomainSelectionMainExecutor.execute(new Runnable() {
+ int mCause = cause;
+ @Override
+ public void run() {
+ Log.v(this, "Call domain selection terminated.");
+ if (mDomainSelectionConnection != null) {
+ mDomainSelectionConnection = null;
}
- String reason = connection.getVendorDisconnectCause();
+ if (mNormalCallConnection != null) {
+ // TODO: To support ShowPreciseFailedCause, TelephonyConnection
+ // .getShowPreciseFailedCause API should be added.
- mNormalCallConnection.setTelephonyConnectionDisconnected(
- mDisconnectCauseFactory.toTelecomDisconnectCause(
- cause, reason));
- Log.d(this, "Call connection closed. Cause: " + cause
- + " Reason: " + reason);
+ // If cause is NOT_VALID then, it's a redial cancellation and
+ // use cause code from original connection.
+ com.android.internal.telephony.Connection connection =
+ mNormalCallConnection.getOriginalConnection();
+ if (connection != null) {
+ if (mCause == android.telephony.DisconnectCause.NOT_VALID) {
+ mCause = connection.getDisconnectCause();
+ }
+
+ String reason = connection.getVendorDisconnectCause();
+ int phoneId = mNormalCallConnection.getPhone().getPhoneId();
+ mNormalCallConnection.setTelephonyConnectionDisconnected(
+ mDisconnectCauseFactory.toTelecomDisconnectCause(
+ mCause, reason, phoneId));
+ Log.d(this, "Call connection closed. Cause: " + mCause
+ + " Reason: " + reason);
+ }
+ mNormalCallConnection.close();
+ mNormalCallConnection = null;
+ }
}
- mNormalCallConnection.close();
- mNormalCallConnection = null;
- }
-
+ });
}
};
diff --git a/src/com/android/services/telephony/domainselection/EmergencyCallDomainSelector.java b/src/com/android/services/telephony/domainselection/EmergencyCallDomainSelector.java
index 9aaf6da..ae4659d 100644
--- a/src/com/android/services/telephony/domainselection/EmergencyCallDomainSelector.java
+++ b/src/com/android/services/telephony/domainselection/EmergencyCallDomainSelector.java
@@ -125,7 +125,7 @@
private int mScanTimeout;
private int mMaxNumOfVoWifiTries;
private @CarrierConfigManager.ImsEmergency.EmergencyScanType int mPreferredNetworkScanType;
- private int mCallSetupTimerOnCurrentRatSec;
+ private int mCallSetupTimerOnCurrentRat;
private boolean mRequiresImsRegistration;
private boolean mRequiresVoLteEnabled;
private boolean mLtePreferredAfterNrFailure;
@@ -221,8 +221,14 @@
@Override
public void reselectDomain(SelectionAttributes attr) {
- logi("reselectDomain tryCsWhenPsFails=" + mTryCsWhenPsFails + ", attr=" + attr);
+ logi("reselectDomain attr=" + attr);
mSelectionAttributes = attr;
+ post(() -> { reselectDomain(); });
+ }
+
+ private void reselectDomain() {
+ logi("reselectDomain tryCsWhenPsFails=" + mTryCsWhenPsFails);
+
if (mTryCsWhenPsFails) {
mTryCsWhenPsFails = false;
mCsNetworkType = getSelectableCsNetworkType();
@@ -241,10 +247,7 @@
if (mLastTransportType == TRANSPORT_TYPE_WLAN) {
// Dialing over Wi-Fi failed. Try scanning cellular networks.
- onWwanSelected(() -> {
- requestScan(true, false, true);
- mDomainSelected = false;
- });
+ onWwanSelected(this::reselectDomainInternal);
return;
}
@@ -252,6 +255,13 @@
mDomainSelected = false;
}
+ private void reselectDomainInternal() {
+ post(() -> {
+ requestScan(true, false, true);
+ mDomainSelected = false;
+ });
+ }
+
@Override
public void finishSelection() {
logi("finishSelection");
@@ -343,11 +353,11 @@
mDomainPreferenceRoam = b.getIntArray(KEY_EMERGENCY_DOMAIN_PREFERENCE_ROAMING_INT_ARRAY);
mPreferImsWhenCallsOnCs = b.getBoolean(
KEY_PREFER_IMS_EMERGENCY_WHEN_VOICE_CALLS_ON_CS_BOOL);
- mScanTimeout = b.getInt(KEY_EMERGENCY_SCAN_TIMER_SEC_INT);
+ mScanTimeout = b.getInt(KEY_EMERGENCY_SCAN_TIMER_SEC_INT) * 1000;
mMaxNumOfVoWifiTries = b.getInt(KEY_MAXIMUM_NUMBER_OF_EMERGENCY_TRIES_OVER_VOWIFI_INT);
mPreferredNetworkScanType = b.getInt(KEY_EMERGENCY_NETWORK_SCAN_TYPE_INT);
- mCallSetupTimerOnCurrentRatSec = b.getInt(
- KEY_EMERGENCY_CALL_SETUP_TIMER_ON_CURRENT_NETWORK_SEC_INT);
+ mCallSetupTimerOnCurrentRat = b.getInt(
+ KEY_EMERGENCY_CALL_SETUP_TIMER_ON_CURRENT_NETWORK_SEC_INT) * 1000;
mRequiresImsRegistration = b.getBoolean(KEY_EMERGENCY_REQUIRES_IMS_REGISTRATION_BOOL);
mRequiresVoLteEnabled = b.getBoolean(KEY_EMERGENCY_REQUIRES_VOLTE_ENABLED_BOOL);
mLtePreferredAfterNrFailure = b.getBoolean(
@@ -380,7 +390,7 @@
+ ", maxNumOfVoWifiTries=" + mMaxNumOfVoWifiTries
+ ", preferredScanType=" + carrierConfigNetworkScanTypeToString(
mPreferredNetworkScanType)
- + ", callSetupTimer=" + mCallSetupTimerOnCurrentRatSec
+ + ", callSetupTimer=" + mCallSetupTimerOnCurrentRat
+ ", requiresImsReg=" + mRequiresImsRegistration
+ ", requiresVoLteEnabled=" + mRequiresVoLteEnabled
+ ", ltePreferredAfterNr=" + mLtePreferredAfterNrFailure
@@ -422,6 +432,10 @@
}
private void selectDomainInternal() {
+ post(this::selectDomainFromInitialState);
+ }
+
+ private void selectDomainFromInitialState() {
if (getImsNetworkTypeConfiguration().isEmpty()
|| (mRequiresVoLteEnabled && !isAdvancedCallingSettingEnabled())) {
// Emergency call over IMS is not supported.
@@ -896,6 +910,12 @@
private void onWlanSelected() {
logi("onWlanSelected");
+ if (mLastTransportType == TRANSPORT_TYPE_WLAN) {
+ logi("onWlanSelected ignore duplicated callback");
+ return;
+ }
+
+ mDomainSelected = true;
mLastTransportType = TRANSPORT_TYPE_WLAN;
mVoWifiTrialCount++;
mTransportSelectorCallback.onWlanSelected();
@@ -904,10 +924,8 @@
private void onWwanSelected(Runnable runnable) {
logi("onWwanSelected");
- if (mLastTransportType == TRANSPORT_TYPE_WWAN
- && mWwanSelectorCallback != null) {
- logi("onWwanSelected already notified");
- runnable.run();
+ if (mLastTransportType == TRANSPORT_TYPE_WWAN) {
+ logi("onWwanSelected ignore duplicated callback");
return;
}
diff --git a/testapps/TestSliceApp/app/src/main/java/com/google/android/sample/testsliceapp/PrioritizeLatency.java b/testapps/TestSliceApp/app/src/main/java/com/google/android/sample/testsliceapp/PrioritizeLatency.java
index 0f120f4..a74e7f0 100644
--- a/testapps/TestSliceApp/app/src/main/java/com/google/android/sample/testsliceapp/PrioritizeLatency.java
+++ b/testapps/TestSliceApp/app/src/main/java/com/google/android/sample/testsliceapp/PrioritizeLatency.java
@@ -23,7 +23,7 @@
import static android.telephony.TelephonyManager.PURCHASE_PREMIUM_CAPABILITY_RESULT_FEATURE_NOT_SUPPORTED;
import static android.telephony.TelephonyManager.PURCHASE_PREMIUM_CAPABILITY_RESULT_NETWORK_NOT_AVAILABLE;
import static android.telephony.TelephonyManager.PURCHASE_PREMIUM_CAPABILITY_RESULT_NOT_DEFAULT_DATA_SUBSCRIPTION;
-import static android.telephony.TelephonyManager.PURCHASE_PREMIUM_CAPABILITY_RESULT_OVERRIDDEN;
+import static android.telephony.TelephonyManager.PURCHASE_PREMIUM_CAPABILITY_RESULT_NOT_FOREGROUND;
import static android.telephony.TelephonyManager.PURCHASE_PREMIUM_CAPABILITY_RESULT_PENDING_NETWORK_SETUP;
import static android.telephony.TelephonyManager.PURCHASE_PREMIUM_CAPABILITY_RESULT_SUCCESS;
import static android.telephony.TelephonyManager.PURCHASE_PREMIUM_CAPABILITY_RESULT_THROTTLED;
@@ -271,8 +271,8 @@
return "Already purchased";
case PURCHASE_PREMIUM_CAPABILITY_RESULT_ALREADY_IN_PROGRESS:
return "Already in progress";
- case PURCHASE_PREMIUM_CAPABILITY_RESULT_OVERRIDDEN:
- return "Overridden";
+ case PURCHASE_PREMIUM_CAPABILITY_RESULT_NOT_FOREGROUND:
+ return "Not foreground";
case PURCHASE_PREMIUM_CAPABILITY_RESULT_USER_CANCELED:
return "User canceled";
case PURCHASE_PREMIUM_CAPABILITY_RESULT_CARRIER_DISABLED:
diff --git a/tests/src/com/android/phone/Telephony2gUpdaterTest.java b/tests/src/com/android/phone/Telephony2gUpdaterTest.java
index 3443767..3684f30 100644
--- a/tests/src/com/android/phone/Telephony2gUpdaterTest.java
+++ b/tests/src/com/android/phone/Telephony2gUpdaterTest.java
@@ -16,13 +16,17 @@
package com.android.phone;
+import static org.junit.Assert.fail;
+import static org.mockito.Mockito.any;
import static org.mockito.Mockito.anyInt;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
+import android.content.Intent;
import android.os.UserManager;
import android.telephony.SubscriptionInfo;
import android.telephony.SubscriptionManager;
@@ -35,22 +39,33 @@
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.stubbing.Answer;
import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
+import java.util.List;
+import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
+import java.util.concurrent.TimeUnit;
@RunWith(AndroidJUnit4.class)
public class Telephony2gUpdaterTest extends TelephonyTestBase {
+ private static final long DRAIN_TIMEOUT = 10;
private Telephony2gUpdater mTelephony2gUpdater;
+ private SubscriptionManager.OnSubscriptionsChangedListener mChangedListener;
private Executor mExecutor;
+ private CountDownLatch mLatch;
private UserManager mMockUserManager;
private TelephonyManager mMockTelephonyManager;
private SubscriptionManager mMockSubscriptionManager;
+ // Set up to be returned from mMockSubscriptionManager.getCompleteActiveSubscriptionInfoList()
+ // Updates will be reflected in subsequent calls to the mock method.
+ private List<SubscriptionInfo> mCurrentSubscriptions;
+
// 2G Bitmask is 0b10000000_01001011
private static final long BASE_NETWORK = 0b11111111_11111111;
private static final long EXPECTED_DISABLED = 0b01111111_10110100;
@@ -65,89 +80,247 @@
mMockUserManager = mContext.getSystemService(UserManager.class);
mMockSubscriptionManager = mContext.getSystemService(SubscriptionManager.class);
+ mCurrentSubscriptions = new ArrayList<>();
+ setupMutableSubscriptionInfoMock();
+
mExecutor = Executors.newSingleThreadExecutor();
- mTelephony2gUpdater = new Telephony2gUpdater(mExecutor,
- getTestContext(), BASE_NETWORK);
+ mTelephony2gUpdater = new Telephony2gUpdater(mExecutor, getTestContext(), BASE_NETWORK);
+ mTelephony2gUpdater.init();
+ ArgumentCaptor<SubscriptionManager.OnSubscriptionsChangedListener> argument =
+ ArgumentCaptor.forClass(SubscriptionManager.OnSubscriptionsChangedListener.class);
+ verify(mMockSubscriptionManager).addOnSubscriptionsChangedListener(any(Executor.class),
+ argument.capture());
+ mChangedListener = argument.getValue();
}
@Test
- public void handleUserRestrictionsChanged_noSubscriptions_noAllowedNetworksChanged() {
- when(mMockSubscriptionManager.getAvailableSubscriptionInfoList()).thenReturn(
- new ArrayList<>());
- mTelephony2gUpdater.handleUserRestrictionsChanged(getTestContext());
+ public void onSubscriptionsChanged_noSubscriptions_noAllowedNetworksChanged() {
+ triggerOnSubscriptionChangedAndWait();
verify(mMockTelephonyManager, never()).setAllowedNetworkTypesForReason(anyInt(), anyInt());
}
@Test
- public void handleUserRestrictionsChanged_nullSubscriptions_noAllowedNetworksChanged() {
- when(mMockSubscriptionManager.getAvailableSubscriptionInfoList()).thenReturn(null);
- mTelephony2gUpdater.handleUserRestrictionsChanged(getTestContext());
- verify(mMockTelephonyManager, never()).setAllowedNetworkTypesForReason(anyInt(), anyInt());
- }
+ public void onSubscriptionsChanged_oneSubscription_allowedNetworksUpdated() {
+ TelephonyManager tmSubscription1 = addSubscriptionAndGetMock(1001);
+ triggerOnSubscriptionChangedAndWait();
- @Test
- public void handleUserRestrictionsChanged_oneSubscription_allowedNetworksUpdated() {
- TelephonyManager tmSubscription1 = mock(TelephonyManager.class);
- when(mMockSubscriptionManager.getAvailableSubscriptionInfoList()).thenReturn(
- Collections.singletonList(getSubInfo(1)));
- when(mMockTelephonyManager.createForSubscriptionId(1)).thenReturn(tmSubscription1);
- when(mMockUserManager.hasUserRestriction(UserManager.DISALLOW_CELLULAR_2G)).thenReturn(
- true);
-
- mTelephony2gUpdater.handleUserRestrictionsChanged(getTestContext());
-
- System.out.println(TelephonyManager.convertNetworkTypeBitmaskToString(11L));
verify(tmSubscription1, times(1)).setAllowedNetworkTypesForReason(
- TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_USER_RESTRICTIONS, EXPECTED_DISABLED);
+ TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_USER_RESTRICTIONS, EXPECTED_ENABLED);
}
@Test
- public void handleUserRestrictionsChanged_manySubscriptionsDisallow2g_allowedNetworkUpdated() {
-
- // Two subscriptions are available
- when(mMockSubscriptionManager.getAvailableSubscriptionInfoList()).thenReturn(
- Arrays.asList(getSubInfo(1), getSubInfo(2)));
- TelephonyManager tmSubscription1 = mock(TelephonyManager.class);
- TelephonyManager tmSubscription2 = mock(TelephonyManager.class);
- when(mMockTelephonyManager.createForSubscriptionId(1)).thenReturn(tmSubscription1);
- when(mMockTelephonyManager.createForSubscriptionId(2)).thenReturn(tmSubscription2);
+ public void onSubscriptionsChanged_manySubscriptionsDisallow2g_allowedNetworkUpdated() {
// 2g is disallowed
when(mMockUserManager.hasUserRestriction(UserManager.DISALLOW_CELLULAR_2G)).thenReturn(
true);
+ triggerBroadcastReceiverAndWait();
- mTelephony2gUpdater.handleUserRestrictionsChanged(getTestContext());
+ TelephonyManager tmSubscription1 = addSubscriptionAndGetMock(1001);
+ TelephonyManager tmSubscription2 = addSubscriptionAndGetMock(1002);
+
+ triggerOnSubscriptionChangedAndWait();
verify(tmSubscription1, times(1)).setAllowedNetworkTypesForReason(
TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_USER_RESTRICTIONS, EXPECTED_DISABLED);
+ verify(tmSubscription2, times(1)).setAllowedNetworkTypesForReason(
+ TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_USER_RESTRICTIONS, EXPECTED_DISABLED);
+ }
+
+ @Test
+ public void onSubscriptionsChanged_noNewSubscriptions_noAllowedNetworksChanged() {
+ when(mMockUserManager.hasUserRestriction(UserManager.DISALLOW_CELLULAR_2G)).thenReturn(
+ true);
+ triggerBroadcastReceiverAndWait();
+
+ TelephonyManager tmSubscription1 = addSubscriptionAndGetMock(1001);
+
+ triggerOnSubscriptionChangedAndWait();
+ triggerOnSubscriptionChangedAndWait();
+
+ // subscriptions were updated twice, but we have no new subIds so we only expect one update
verify(tmSubscription1, times(1)).setAllowedNetworkTypesForReason(
TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_USER_RESTRICTIONS, EXPECTED_DISABLED);
}
@Test
- public void handleUserRestrictionsChanged_manySubscriptionsAllow2g_allowedNetworkUpdated() {
+ public void onSubscriptionsChanged_removeSubscription_noAdditionalNetworkChanges() {
+ // We start with 2 subIds
+ TelephonyManager tmSubscription1 = addSubscriptionAndGetMock(1001);
+ TelephonyManager tmSubscription2 = addSubscriptionAndGetMock(1002);
- // Two subscriptions are available
- when(mMockSubscriptionManager.getAvailableSubscriptionInfoList()).thenReturn(
- Arrays.asList(getSubInfo(1), getSubInfo(2)));
- TelephonyManager tmSubscription1 = mock(TelephonyManager.class);
- TelephonyManager tmSubscription2 = mock(TelephonyManager.class);
- when(mMockTelephonyManager.createForSubscriptionId(1)).thenReturn(tmSubscription1);
- when(mMockTelephonyManager.createForSubscriptionId(2)).thenReturn(tmSubscription2);
+ triggerOnSubscriptionChangedAndWait();
- // 2g is allowed
+ // 2g is still enabled since the default is to not set the user restriction
+ verify(tmSubscription1, times(1)).setAllowedNetworkTypesForReason(
+ TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_USER_RESTRICTIONS, EXPECTED_ENABLED);
+ verify(tmSubscription2, times(1)).setAllowedNetworkTypesForReason(
+ TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_USER_RESTRICTIONS, EXPECTED_ENABLED);
+
+
+ mCurrentSubscriptions.remove(1);
+ triggerOnSubscriptionChangedAndWait();
+
+ // Subscriptions have changed, but we've only removed a subscription so there should be no
+ // extra updates to allowed network types
+ verify(tmSubscription1, times(1)).setAllowedNetworkTypesForReason(
+ TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_USER_RESTRICTIONS, EXPECTED_ENABLED);
+ verify(tmSubscription2, times(1)).setAllowedNetworkTypesForReason(
+ TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_USER_RESTRICTIONS, EXPECTED_ENABLED);
+ }
+
+ @Test
+ public void onSubscriptionsChanged_removeSubscriptionAndReAdd() {
+ when(mMockUserManager.hasUserRestriction(UserManager.DISALLOW_CELLULAR_2G)).thenReturn(
+ true);
+ triggerBroadcastReceiverAndWait();
+
+ TelephonyManager tmSubscription1 = addSubscriptionAndGetMock(1001);
+ triggerOnSubscriptionChangedAndWait();
+ mCurrentSubscriptions.remove(0);
+ triggerOnSubscriptionChangedAndWait();
+ mCurrentSubscriptions.add(getSubInfo(1001));
+ triggerOnSubscriptionChangedAndWait();
+
+ // subscriptions were updated thrice, but one of those updates removed a subscription
+ // such that the sub list was empty, so we only expect an update on the first and last
+ // updates.
+ verify(tmSubscription1, times(2)).setAllowedNetworkTypesForReason(
+ TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_USER_RESTRICTIONS, EXPECTED_DISABLED);
+ }
+
+ @Test
+ public void onSubscriptionsChanged_addSubscription_updateAllowedNetworks() {
+ // We start with 2 subIds and update subscriptions
+ TelephonyManager tmSubscription1 = addSubscriptionAndGetMock(1001);
+ TelephonyManager tmSubscription2 = addSubscriptionAndGetMock(1002);
+ triggerOnSubscriptionChangedAndWait();
+
+ // Then add a subId and update subscriptions again
+ TelephonyManager tmSubscription3 = addSubscriptionAndGetMock(1003);
+ triggerOnSubscriptionChangedAndWait();
+
+ // we only need to update the new subscription
+ verify(tmSubscription1, times(1)).setAllowedNetworkTypesForReason(
+ TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_USER_RESTRICTIONS, EXPECTED_ENABLED);
+ verify(tmSubscription2, times(1)).setAllowedNetworkTypesForReason(
+ TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_USER_RESTRICTIONS, EXPECTED_ENABLED);
+ verify(tmSubscription3, times(1)).setAllowedNetworkTypesForReason(
+ TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_USER_RESTRICTIONS, EXPECTED_ENABLED);
+ }
+
+ @Test
+ public void onUserRestrictionUnchanged_noChangeToRestriction_noAllowedNetworksUpdated() {
+ TelephonyManager tmSubscription = addSubscriptionAndGetMock(1001);
+ triggerOnSubscriptionChangedAndWait();
+ // precondition: we've updated allowed networks to the default (2g enabled)
+ verify(tmSubscription, times(1)).setAllowedNetworkTypesForReason(
+ TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_USER_RESTRICTIONS, EXPECTED_ENABLED);
+ verify(tmSubscription, never()).setAllowedNetworkTypesForReason(
+ TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_USER_RESTRICTIONS, EXPECTED_DISABLED);
+
+ when(mMockUserManager.hasUserRestriction(UserManager.DISALLOW_CELLULAR_2G)).thenReturn(
+ true);
+ triggerBroadcastReceiverAndWait();
+ triggerBroadcastReceiverAndWait();
+
+ // expect we only updated once even though we got two broadcasts for user restriction
+ // updates
+ verify(tmSubscription, times(1)).setAllowedNetworkTypesForReason(
+ TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_USER_RESTRICTIONS, EXPECTED_DISABLED);
+ // extra check to ensure we haven't also somehow updated back to enabled along the way
+ verify(tmSubscription, times(1)).setAllowedNetworkTypesForReason(
+ TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_USER_RESTRICTIONS, EXPECTED_ENABLED);
+ }
+
+ @Test
+ public void onUserRestrictionChanged_restrictionChanged_allowedNetworksUpdated() {
+ // precondition: we've updated allowed networks to the default (2g enabled)
+ TelephonyManager tmSubscription = addSubscriptionAndGetMock(1001);
+ triggerOnSubscriptionChangedAndWait();
+ verify(tmSubscription, times(1)).setAllowedNetworkTypesForReason(
+ TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_USER_RESTRICTIONS, EXPECTED_ENABLED);
+ verify(tmSubscription, never()).setAllowedNetworkTypesForReason(
+ TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_USER_RESTRICTIONS, EXPECTED_DISABLED);
+
+ // update the user restriction to disallow 2g
+ reset(tmSubscription);
+ when(mMockUserManager.hasUserRestriction(UserManager.DISALLOW_CELLULAR_2G)).thenReturn(
+ true);
+ triggerBroadcastReceiverAndWait();
+ verify(tmSubscription, never()).setAllowedNetworkTypesForReason(
+ TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_USER_RESTRICTIONS, EXPECTED_ENABLED);
+ verify(tmSubscription, times(1)).setAllowedNetworkTypesForReason(
+ TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_USER_RESTRICTIONS, EXPECTED_DISABLED);
+
+
+ // update the user restriction to allow 2g again
+ reset(tmSubscription);
when(mMockUserManager.hasUserRestriction(UserManager.DISALLOW_CELLULAR_2G)).thenReturn(
false);
-
- mTelephony2gUpdater.handleUserRestrictionsChanged(getTestContext());
-
- verify(tmSubscription1, times(1)).setAllowedNetworkTypesForReason(
+ triggerBroadcastReceiverAndWait();
+ verify(tmSubscription, times(1)).setAllowedNetworkTypesForReason(
TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_USER_RESTRICTIONS, EXPECTED_ENABLED);
- verify(tmSubscription1, times(1)).setAllowedNetworkTypesForReason(
- TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_USER_RESTRICTIONS, EXPECTED_ENABLED);
+ verify(tmSubscription, never()).setAllowedNetworkTypesForReason(
+ TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_USER_RESTRICTIONS, EXPECTED_DISABLED);
+
}
private SubscriptionInfo getSubInfo(int id) {
return new SubscriptionInfo(id, "890126042XXXXXXXXXXX", 0, "T-mobile", "T-mobile", 0, 255,
"12345", 0, null, "310", "260", "156", false, null, null);
}
+
+ private void triggerOnSubscriptionChangedAndWait() {
+ mExecutor.execute(() -> mChangedListener.onSubscriptionsChanged());
+ drainSingleThreadedExecutor();
+ }
+
+ private void triggerBroadcastReceiverAndWait() {
+ mTelephony2gUpdater.onReceive(mContext, new Intent());
+ drainSingleThreadedExecutor();
+ }
+
+ /**
+ * Wait for all tasks on executor up to the point of invocation to drain, then return.
+ *
+ * This helper takes advantage of the fact that we're using an immutable single threaded
+ * executor that guarantees tasks are executed in the order they are enqueued. It enqueues a
+ * task that decrements a latch and then waits on that task to finish. By definition, once the
+ * test task finishes, all previously enqueued tasks will have also completed.
+ */
+ private void drainSingleThreadedExecutor() {
+ resetExecutorLatch();
+ mExecutor.execute(() -> mLatch.countDown());
+ try {
+ mLatch.await(DRAIN_TIMEOUT, TimeUnit.SECONDS);
+ } catch (InterruptedException e) {
+ fail(e.getMessage());
+ }
+ }
+
+ private void resetExecutorLatch() {
+ mLatch = new CountDownLatch(1);
+ }
+
+ /**
+ * Helper that allows you to update subInfo and have that change reflected on subsequent calls
+ * to {@link SubscriptionManager#getCompleteActiveSubscriptionInfoList()}
+ */
+ private void setupMutableSubscriptionInfoMock() {
+ var answer = new Answer<List<SubscriptionInfo>>() {
+ @Override
+ public List<SubscriptionInfo> answer(InvocationOnMock invocation) throws Throwable {
+ return mCurrentSubscriptions;
+ }
+ };
+ when(mMockSubscriptionManager.getCompleteActiveSubscriptionInfoList()).thenAnswer(answer);
+ }
+
+ private TelephonyManager addSubscriptionAndGetMock(int subId) {
+ mCurrentSubscriptions.add(getSubInfo(subId));
+ TelephonyManager tmSubscription = mock(TelephonyManager.class);
+ when(mMockTelephonyManager.createForSubscriptionId(subId)).thenReturn(tmSubscription);
+ return tmSubscription;
+ }
+
}
diff --git a/tests/src/com/android/phone/slice/SlicePurchaseControllerTest.java b/tests/src/com/android/phone/slice/SlicePurchaseControllerTest.java
index e2ebac0..921babb 100644
--- a/tests/src/com/android/phone/slice/SlicePurchaseControllerTest.java
+++ b/tests/src/com/android/phone/slice/SlicePurchaseControllerTest.java
@@ -70,7 +70,7 @@
@RunWith(AndroidJUnit4.class)
public class SlicePurchaseControllerTest extends TelephonyTestBase {
- private static final String TAG = "SlicePurchaseControllerTest";
+ private static final String CARRIER = "Some Carrier";
private static final String DAILY_NOTIFICATION_COUNT_KEY = "daily_notification_count0";
private static final String MONTHLY_NOTIFICATION_COUNT_KEY = "monthly_notification_count0";
private static final int YEAR = 2000;
@@ -148,6 +148,7 @@
mSlicePurchaseController = spy(slicePurchaseController);
doReturn(null).when(mSlicePurchaseController).createPendingIntent(
anyString(), anyInt(), anyBoolean());
+ doReturn(CARRIER).when(mSlicePurchaseController).getSimOperator();
replaceInstance(SlicePurchaseController.class, "sInstances", mSlicePurchaseController,
Map.of(PHONE_ID, mSlicePurchaseController));
replaceInstance(SlicePurchaseController.class, "mPremiumNetworkEntitlementApi",
@@ -272,8 +273,7 @@
@Test
public void testPurchasePremiumCapabilityResultFeatureNotSupported() {
mSlicePurchaseController.purchasePremiumCapability(
- TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY, TAG,
- mHandler.obtainMessage());
+ TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY, mHandler.obtainMessage());
mTestableLooper.processAllMessages();
assertEquals(TelephonyManager.PURCHASE_PREMIUM_CAPABILITY_RESULT_FEATURE_NOT_SUPPORTED,
mResult);
@@ -283,8 +283,7 @@
.getCachedAllowedNetworkTypesBitmask();
mSlicePurchaseController.purchasePremiumCapability(
- TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY, TAG,
- mHandler.obtainMessage());
+ TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY, mHandler.obtainMessage());
mTestableLooper.processAllMessages();
assertNotEquals(TelephonyManager.PURCHASE_PREMIUM_CAPABILITY_RESULT_FEATURE_NOT_SUPPORTED,
mResult);
@@ -296,8 +295,7 @@
.getCachedAllowedNetworkTypesBitmask();
mSlicePurchaseController.purchasePremiumCapability(
- TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY, TAG,
- mHandler.obtainMessage());
+ TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY, mHandler.obtainMessage());
mTestableLooper.processAllMessages();
assertEquals(TelephonyManager.PURCHASE_PREMIUM_CAPABILITY_RESULT_CARRIER_DISABLED, mResult);
@@ -308,8 +306,7 @@
SlicePurchaseController.SLICE_PURCHASE_TEST_FILE);
mSlicePurchaseController.purchasePremiumCapability(
- TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY, TAG,
- mHandler.obtainMessage());
+ TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY, mHandler.obtainMessage());
mTestableLooper.processAllMessages();
assertNotEquals(TelephonyManager.PURCHASE_PREMIUM_CAPABILITY_RESULT_CARRIER_DISABLED,
mResult);
@@ -325,8 +322,7 @@
SlicePurchaseController.SLICE_PURCHASE_TEST_FILE);
mSlicePurchaseController.purchasePremiumCapability(
- TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY, TAG,
- mHandler.obtainMessage());
+ TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY, mHandler.obtainMessage());
mTestableLooper.processAllMessages();
assertEquals(
TelephonyManager.PURCHASE_PREMIUM_CAPABILITY_RESULT_NOT_DEFAULT_DATA_SUBSCRIPTION,
@@ -336,8 +332,7 @@
doReturn(SubscriptionManager.getDefaultDataSubscriptionId()).when(mPhone).getSubId();
mSlicePurchaseController.purchasePremiumCapability(
- TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY, TAG,
- mHandler.obtainMessage());
+ TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY, mHandler.obtainMessage());
mTestableLooper.processAllMessages();
assertNotEquals(
TelephonyManager.PURCHASE_PREMIUM_CAPABILITY_RESULT_NOT_DEFAULT_DATA_SUBSCRIPTION,
@@ -355,8 +350,7 @@
doReturn(SubscriptionManager.getDefaultDataSubscriptionId()).when(mPhone).getSubId();
mSlicePurchaseController.purchasePremiumCapability(
- TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY, TAG,
- mHandler.obtainMessage());
+ TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY, mHandler.obtainMessage());
mTestableLooper.processAllMessages();
assertEquals(TelephonyManager.PURCHASE_PREMIUM_CAPABILITY_RESULT_NETWORK_NOT_AVAILABLE,
mResult);
@@ -365,8 +359,7 @@
doReturn(TelephonyManager.NETWORK_TYPE_NR).when(mServiceState).getDataNetworkType();
mSlicePurchaseController.purchasePremiumCapability(
- TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY, TAG,
- mHandler.obtainMessage());
+ TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY, mHandler.obtainMessage());
mTestableLooper.processAllMessages();
assertNotEquals(TelephonyManager.PURCHASE_PREMIUM_CAPABILITY_RESULT_NETWORK_NOT_AVAILABLE,
mResult);
@@ -385,8 +378,7 @@
doReturn(null).when(mPremiumNetworkEntitlementApi).checkEntitlementStatus(anyInt());
mSlicePurchaseController.purchasePremiumCapability(
- TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY, TAG,
- mHandler.obtainMessage());
+ TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY, mHandler.obtainMessage());
mTestableLooper.processAllMessages();
assertEquals(TelephonyManager.PURCHASE_PREMIUM_CAPABILITY_RESULT_ENTITLEMENT_CHECK_FAILED,
mResult);
@@ -398,8 +390,7 @@
.checkEntitlementStatus(anyInt());
mSlicePurchaseController.purchasePremiumCapability(
- TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY, TAG,
- mHandler.obtainMessage());
+ TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY, mHandler.obtainMessage());
mTestableLooper.processAllMessages();
assertEquals(TelephonyManager.PURCHASE_PREMIUM_CAPABILITY_RESULT_ALREADY_PURCHASED,
mResult);
@@ -409,8 +400,7 @@
PremiumNetworkEntitlementResponse.PREMIUM_NETWORK_PROVISION_STATUS_IN_PROGRESS;
mSlicePurchaseController.purchasePremiumCapability(
- TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY, TAG,
- mHandler.obtainMessage());
+ TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY, mHandler.obtainMessage());
mTestableLooper.processAllMessages();
assertEquals(TelephonyManager.PURCHASE_PREMIUM_CAPABILITY_RESULT_ALREADY_IN_PROGRESS,
mResult);
@@ -425,16 +415,14 @@
PURCHASE_CONDITION_TIMEOUT);
mSlicePurchaseController.purchasePremiumCapability(
- TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY, TAG,
- mHandler.obtainMessage());
+ TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY, mHandler.obtainMessage());
mTestableLooper.processAllMessages();
assertEquals(TelephonyManager.PURCHASE_PREMIUM_CAPABILITY_RESULT_ENTITLEMENT_CHECK_FAILED,
mResult);
// retry to verify throttled
mSlicePurchaseController.purchasePremiumCapability(
- TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY, TAG,
- mHandler.obtainMessage());
+ TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY, mHandler.obtainMessage());
mTestableLooper.processAllMessages();
assertEquals(TelephonyManager.PURCHASE_PREMIUM_CAPABILITY_RESULT_THROTTLED, mResult);
@@ -450,16 +438,14 @@
sendValidPurchaseRequest();
mSlicePurchaseController.purchasePremiumCapability(
- TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY, TAG,
- mHandler.obtainMessage());
+ TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY, mHandler.obtainMessage());
mTestableLooper.processAllMessages();
assertEquals(TelephonyManager.PURCHASE_PREMIUM_CAPABILITY_RESULT_ALREADY_IN_PROGRESS,
mResult);
// retry to verify same result
mSlicePurchaseController.purchasePremiumCapability(
- TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY, TAG,
- mHandler.obtainMessage());
+ TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY, mHandler.obtainMessage());
mTestableLooper.processAllMessages();
assertEquals(TelephonyManager.PURCHASE_PREMIUM_CAPABILITY_RESULT_ALREADY_IN_PROGRESS,
mResult);
@@ -487,8 +473,7 @@
testPurchasePremiumCapabilityResultSuccess();
mSlicePurchaseController.purchasePremiumCapability(
- TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY, TAG,
- mHandler.obtainMessage());
+ TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY, mHandler.obtainMessage());
mTestableLooper.processAllMessages();
assertEquals(TelephonyManager.PURCHASE_PREMIUM_CAPABILITY_RESULT_PENDING_NETWORK_SETUP,
mResult);
@@ -507,16 +492,14 @@
sendNetworkSlicingConfig(TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY, true);
mSlicePurchaseController.purchasePremiumCapability(
- TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY, TAG,
- mHandler.obtainMessage());
+ TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY, mHandler.obtainMessage());
mTestableLooper.processAllMessages();
assertEquals(TelephonyManager.PURCHASE_PREMIUM_CAPABILITY_RESULT_ALREADY_PURCHASED,
mResult);
// retry to verify same result
mSlicePurchaseController.purchasePremiumCapability(
- TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY, TAG,
- mHandler.obtainMessage());
+ TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY, mHandler.obtainMessage());
mTestableLooper.processAllMessages();
assertEquals(TelephonyManager.PURCHASE_PREMIUM_CAPABILITY_RESULT_ALREADY_PURCHASED,
mResult);
@@ -537,8 +520,7 @@
// retry to verify throttled
mSlicePurchaseController.purchasePremiumCapability(
- TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY, TAG,
- mHandler.obtainMessage());
+ TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY, mHandler.obtainMessage());
mTestableLooper.processAllMessages();
assertEquals(TelephonyManager.PURCHASE_PREMIUM_CAPABILITY_RESULT_THROTTLED, mResult);
@@ -565,8 +547,7 @@
// retry to verify throttled
mSlicePurchaseController.purchasePremiumCapability(
- TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY, TAG,
- mHandler.obtainMessage());
+ TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY, mHandler.obtainMessage());
mTestableLooper.processAllMessages();
assertEquals(TelephonyManager.PURCHASE_PREMIUM_CAPABILITY_RESULT_THROTTLED, mResult);
@@ -596,8 +577,7 @@
// retry to verify throttled
mSlicePurchaseController.purchasePremiumCapability(
- TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY, TAG,
- mHandler.obtainMessage());
+ TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY, mHandler.obtainMessage());
mTestableLooper.processAllMessages();
assertEquals(TelephonyManager.PURCHASE_PREMIUM_CAPABILITY_RESULT_THROTTLED, mResult);
@@ -660,8 +640,7 @@
// retry to verify throttled
mSlicePurchaseController.purchasePremiumCapability(
- TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY, TAG,
- mHandler.obtainMessage());
+ TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY, mHandler.obtainMessage());
mTestableLooper.processAllMessages();
assertEquals(TelephonyManager.PURCHASE_PREMIUM_CAPABILITY_RESULT_THROTTLED, mResult);
@@ -678,8 +657,7 @@
// retry to verify throttled
mSlicePurchaseController.purchasePremiumCapability(
- TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY, TAG,
- mHandler.obtainMessage());
+ TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY, mHandler.obtainMessage());
mTestableLooper.processAllMessages();
assertEquals(TelephonyManager.PURCHASE_PREMIUM_CAPABILITY_RESULT_THROTTLED, mResult);
}
@@ -741,8 +719,7 @@
// send purchase request
mSlicePurchaseController.purchasePremiumCapability(
- TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY, TAG,
- mHandler.obtainMessage());
+ TelephonyManager.PREMIUM_CAPABILITY_PRIORITIZE_LATENCY, mHandler.obtainMessage());
mTestableLooper.processAllMessages();
// verify that the purchase request was sent successfully
diff --git a/tests/src/com/android/services/telephony/domainselection/EmergencyCallDomainSelectorTest.java b/tests/src/com/android/services/telephony/domainselection/EmergencyCallDomainSelectorTest.java
index e1de0ab..3f6ce98 100644
--- a/tests/src/com/android/services/telephony/domainselection/EmergencyCallDomainSelectorTest.java
+++ b/tests/src/com/android/services/telephony/domainselection/EmergencyCallDomainSelectorTest.java
@@ -903,6 +903,39 @@
verify(mTransportSelectorCallback, times(1)).onWlanSelected();
}
+ @Test
+ public void testIgnoreDuplicatedCallbacks() throws Exception {
+ createSelector(SLOT_0_SUB_ID);
+ unsolBarringInfoChanged(true);
+
+ EmergencyRegResult regResult = getEmergencyRegResult(EUTRAN, REGISTRATION_STATE_HOME,
+ NetworkRegistrationInfo.DOMAIN_PS,
+ true, true, 0, 0, "", "");
+ SelectionAttributes attr = getSelectionAttributes(SLOT_0, SLOT_0_SUB_ID, regResult);
+ mDomainSelector.selectDomain(attr, mTransportSelectorCallback);
+ processAllMessages();
+
+ bindImsService(true);
+
+ verify(mTransportSelectorCallback, times(1)).onWwanSelected(any());
+
+ // duplicated event
+ unsolBarringInfoChanged(true);
+
+ // ignore duplicated callback, no change in interaction
+ verify(mTransportSelectorCallback, times(1)).onWwanSelected(any());
+
+ mDomainSelector.handleMessage(mDomainSelector.obtainMessage(MSG_NETWORK_SCAN_TIMEOUT));
+
+ verify(mTransportSelectorCallback, times(1)).onWlanSelected();
+
+ // duplicated event
+ mDomainSelector.handleMessage(mDomainSelector.obtainMessage(MSG_NETWORK_SCAN_TIMEOUT));
+
+ // ignore duplicated callback, no change in interaction
+ verify(mTransportSelectorCallback, times(1)).onWlanSelected();
+ }
+
private void createSelector(int subId) throws Exception {
mDomainSelector = new EmergencyCallDomainSelector(
mContext, SLOT_0, subId, mHandlerThread.getLooper(),
@@ -913,10 +946,12 @@
}
private void verifyCsDialed() {
+ processAllMessages();
verify(mWwanSelectorCallback, times(1)).onDomainSelected(eq(DOMAIN_CS));
}
private void verifyPsDialed() {
+ processAllMessages();
verify(mWwanSelectorCallback, times(1)).onDomainSelected(eq(DOMAIN_PS));
}
@@ -929,6 +964,7 @@
}
private void verifyScanPreferred(int scanType, int expectedPreferredAccessNetwork) {
+ processAllMessages();
verify(mWwanSelectorCallback, times(1)).onRequestEmergencyNetworkScan(
any(), eq(scanType), any(), any());
assertEquals(expectedPreferredAccessNetwork, (int) mAccessNetwork.get(0));