Merge "Revert "Hide system apps until installed (2/2)"" into pi-dev
diff --git a/src/java/com/android/internal/telephony/CarrierKeyDownloadManager.java b/src/java/com/android/internal/telephony/CarrierKeyDownloadManager.java
index 5b53bcf..1513a33 100644
--- a/src/java/com/android/internal/telephony/CarrierKeyDownloadManager.java
+++ b/src/java/com/android/internal/telephony/CarrierKeyDownloadManager.java
@@ -522,6 +522,7 @@
DownloadManager.Request request = new DownloadManager.Request(Uri.parse(mURL));
request.setAllowedOverMetered(false);
request.setVisibleInDownloadsUi(false);
+ request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_HIDDEN);
Long carrierKeyDownloadRequestId = mDownloadManager.enqueue(request);
SharedPreferences.Editor editor = getDefaultSharedPreferences(mContext).edit();
diff --git a/src/java/com/android/internal/telephony/CarrierServiceStateTracker.java b/src/java/com/android/internal/telephony/CarrierServiceStateTracker.java
index f022e65..7f49f28 100644
--- a/src/java/com/android/internal/telephony/CarrierServiceStateTracker.java
+++ b/src/java/com/android/internal/telephony/CarrierServiceStateTracker.java
@@ -23,6 +23,7 @@
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
+import android.database.ContentObserver;
import android.os.Handler;
import android.os.Message;
import android.os.PersistableBundle;
@@ -30,6 +31,8 @@
import android.telephony.CarrierConfigManager;
import android.telephony.Rlog;
import android.telephony.ServiceState;
+import android.telephony.SubscriptionManager;
+import android.telephony.SubscriptionManager.OnSubscriptionsChangedListener;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.telephony.util.NotificationChannelController;
@@ -38,6 +41,7 @@
import java.util.Map;
+
/**
* This contains Carrier specific logic based on the states/events
* managed in ServiceStateTracker.
@@ -53,18 +57,70 @@
private static final int UNINITIALIZED_DELAY_VALUE = -1;
private Phone mPhone;
private ServiceStateTracker mSST;
-
+ private final Map<Integer, NotificationType> mNotificationTypeMap = new HashMap<>();
+ private int mPreviousSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
public static final int NOTIFICATION_PREF_NETWORK = 1000;
public static final int NOTIFICATION_EMERGENCY_NETWORK = 1001;
- private final Map<Integer, NotificationType> mNotificationTypeMap = new HashMap<>();
-
public CarrierServiceStateTracker(Phone phone, ServiceStateTracker sst) {
this.mPhone = phone;
this.mSST = sst;
phone.getContext().registerReceiver(mBroadcastReceiver, new IntentFilter(
CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED));
+ // Listen for subscriber changes
+ SubscriptionManager.from(mPhone.getContext()).addOnSubscriptionsChangedListener(
+ new OnSubscriptionsChangedListener(this.getLooper()) {
+ @Override
+ public void onSubscriptionsChanged() {
+ int subId = mPhone.getSubId();
+ if (mPreviousSubId != subId) {
+ mPreviousSubId = subId;
+ registerPrefNetworkModeObserver();
+ }
+ }
+ });
+
registerNotificationTypes();
+ registerPrefNetworkModeObserver();
+ }
+
+ private ContentObserver mPrefNetworkModeObserver = new ContentObserver(this) {
+ @Override
+ public void onChange(boolean selfChange) {
+ handlePrefNetworkModeChanged();
+ }
+ };
+
+ /**
+ * Return preferred network mode observer
+ */
+ @VisibleForTesting
+ public ContentObserver getContentObserver() {
+ return mPrefNetworkModeObserver;
+ }
+
+ private void registerPrefNetworkModeObserver() {
+ int subId = mPhone.getSubId();
+ unregisterPrefNetworkModeObserver();
+ if (SubscriptionManager.isValidSubscriptionId(subId)) {
+ mPhone.getContext().getContentResolver().registerContentObserver(
+ Settings.Global.getUriFor(Settings.Global.PREFERRED_NETWORK_MODE + subId),
+ true,
+ mPrefNetworkModeObserver);
+ }
+ }
+
+ private void unregisterPrefNetworkModeObserver() {
+ mPhone.getContext().getContentResolver().unregisterContentObserver(
+ mPrefNetworkModeObserver);
+ }
+
+ /**
+ * Returns mNotificationTypeMap
+ */
+ @VisibleForTesting
+ public Map<Integer, NotificationType> getNotificationTypeMap() {
+ return mNotificationTypeMap;
}
private void registerNotificationTypes() {
@@ -152,14 +208,25 @@
private void handleConfigChanges() {
for (Map.Entry<Integer, NotificationType> entry : mNotificationTypeMap.entrySet()) {
NotificationType notificationType = entry.getValue();
- if (evaluateSendingMessage(notificationType)) {
- Message notificationMsg = obtainMessage(notificationType.getTypeId(), null);
- Rlog.i(LOG_TAG, "starting timer for notifications." + notificationType.getTypeId());
- sendMessageDelayed(notificationMsg, getDelay(notificationType));
- } else {
- cancelNotification(notificationType.getTypeId());
- Rlog.i(LOG_TAG, "canceling notifications: " + notificationType.getTypeId());
- }
+ evaluateSendingMessageOrCancelNotification(notificationType);
+ }
+ }
+
+ private void handlePrefNetworkModeChanged() {
+ NotificationType notificationType = mNotificationTypeMap.get(NOTIFICATION_PREF_NETWORK);
+ if (notificationType != null) {
+ evaluateSendingMessageOrCancelNotification(notificationType);
+ }
+ }
+
+ private void evaluateSendingMessageOrCancelNotification(NotificationType notificationType) {
+ if (evaluateSendingMessage(notificationType)) {
+ Message notificationMsg = obtainMessage(notificationType.getTypeId(), null);
+ Rlog.i(LOG_TAG, "starting timer for notifications." + notificationType.getTypeId());
+ sendMessageDelayed(notificationMsg, getDelay(notificationType));
+ } else {
+ cancelNotification(notificationType.getTypeId());
+ Rlog.i(LOG_TAG, "canceling notifications: " + notificationType.getTypeId());
}
}
@@ -241,6 +308,13 @@
}
/**
+ * Dispose the CarrierServiceStateTracker.
+ */
+ public void dispose() {
+ unregisterPrefNetworkModeObserver();
+ }
+
+ /**
* Class that defines the different types of notifications.
*/
public interface NotificationType {
@@ -294,7 +368,7 @@
}
this.mDelay = bundle.getInt(
CarrierConfigManager.KEY_PREF_NETWORK_NOTIFICATION_DELAY_INT);
- Rlog.i(LOG_TAG, "reading time to delay notification emergency: " + mDelay);
+ Rlog.i(LOG_TAG, "reading time to delay notification pref network: " + mDelay);
}
public int getDelay() {
@@ -312,7 +386,7 @@
Rlog.i(LOG_TAG, "PrefNetworkNotification: sendMessage() w/values: "
+ "," + isPhoneStillRegistered() + "," + mDelay + "," + isGlobalMode()
+ "," + mSST.isRadioOn());
- if (mDelay == UNINITIALIZED_DELAY_VALUE || isPhoneStillRegistered() || isGlobalMode()
+ if (mDelay == UNINITIALIZED_DELAY_VALUE || isPhoneStillRegistered() || isGlobalMode()
|| isRadioOffOrAirplaneMode()) {
return false;
}
diff --git a/src/java/com/android/internal/telephony/GsmCdmaPhone.java b/src/java/com/android/internal/telephony/GsmCdmaPhone.java
index 3055e90..2c167bd 100644
--- a/src/java/com/android/internal/telephony/GsmCdmaPhone.java
+++ b/src/java/com/android/internal/telephony/GsmCdmaPhone.java
@@ -29,6 +29,7 @@
import static com.android.internal.telephony.CommandsInterface.SERVICE_CLASS_VOICE;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.app.ActivityManager;
import android.content.BroadcastReceiver;
import android.content.ContentValues;
@@ -1510,15 +1511,20 @@
}
@Override
+ @Nullable
public String getSubscriberId() {
- if (isPhoneTypeGsm()) {
- IccRecords r = mIccRecords.get();
- return (r != null) ? r.getIMSI() : null;
- } else if (isPhoneTypeCdma()) {
- return mSST.getImsi();
- } else { //isPhoneTypeCdmaLte()
- return (mSimRecords != null) ? mSimRecords.getIMSI() : "";
+ String subscriberId = null;
+ if (isPhoneTypeCdma()) {
+ subscriberId = mSST.getImsi();
+ } else {
+ // Both Gsm and CdmaLte get the IMSI from Usim.
+ IccRecords iccRecords = mUiccController.getIccRecords(
+ mPhoneId, UiccController.APP_FAM_3GPP);
+ if (iccRecords != null) {
+ subscriberId = iccRecords.getIMSI();
+ }
}
+ return subscriberId;
}
@Override
diff --git a/src/java/com/android/internal/telephony/ImsSmsDispatcher.java b/src/java/com/android/internal/telephony/ImsSmsDispatcher.java
index e7bd046..79ea8d2 100644
--- a/src/java/com/android/internal/telephony/ImsSmsDispatcher.java
+++ b/src/java/com/android/internal/telephony/ImsSmsDispatcher.java
@@ -280,6 +280,10 @@
+ " mMessageRef=" + tracker.mMessageRef
+ " SS=" + mPhone.getServiceState().getState());
+ // Flag that this Tracker is using the ImsService implementation of SMS over IMS for sending
+ // this message. Any fallbacks will happen over CS only.
+ tracker.mUsesImsServiceForIms = true;
+
HashMap<String, Object> map = tracker.getData();
byte[] pdu = (byte[]) map.get(MAP_KEY_PDU);
diff --git a/src/java/com/android/internal/telephony/LocaleTracker.java b/src/java/com/android/internal/telephony/LocaleTracker.java
index c2b576b..996e288 100644
--- a/src/java/com/android/internal/telephony/LocaleTracker.java
+++ b/src/java/com/android/internal/telephony/LocaleTracker.java
@@ -16,7 +16,7 @@
package com.android.internal.telephony;
-import static android.text.format.DateUtils.HOUR_IN_MILLIS;
+import static android.text.format.DateUtils.MINUTE_IN_MILLIS;
import static android.text.format.DateUtils.SECOND_IN_MILLIS;
import android.annotation.NonNull;
@@ -26,6 +26,7 @@
import android.content.Intent;
import android.content.IntentFilter;
import android.net.wifi.WifiManager;
+import android.os.AsyncResult;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
@@ -34,6 +35,7 @@
import android.telephony.CellInfoLte;
import android.telephony.CellInfoWcdma;
import android.telephony.Rlog;
+import android.telephony.ServiceState;
import android.telephony.TelephonyManager;
import android.text.TextUtils;
import android.util.LocalLog;
@@ -55,8 +57,14 @@
private static final boolean DBG = true;
private static final String TAG = LocaleTracker.class.getSimpleName();
- /** Event to trigger get cell info from the modem */
- private static final int EVENT_GET_CELL_INFO = 1;
+ /** Event for getting cell info from the modem */
+ private static final int EVENT_GET_CELL_INFO = 1;
+
+ /** Event for operator numeric update */
+ private static final int EVENT_UPDATE_OPERATOR_NUMERIC = 2;
+
+ /** Event for service state changed */
+ private static final int EVENT_SERVICE_STATE_CHANGED = 3;
// Todo: Read this from Settings.
/** The minimum delay to get cell info from the modem */
@@ -64,7 +72,11 @@
// Todo: Read this from Settings.
/** The maximum delay to get cell info from the modem */
- private static final long CELL_INFO_MAX_DELAY_MS = 1 * HOUR_IN_MILLIS;
+ private static final long CELL_INFO_MAX_DELAY_MS = 10 * MINUTE_IN_MILLIS;
+
+ // Todo: Read this from Settings.
+ /** The delay for periodically getting cell info from the modem */
+ private static final long CELL_INFO_PERIODIC_POLLING_DELAY_MS = 10 * MINUTE_IN_MILLIS;
private final Phone mPhone;
@@ -86,6 +98,9 @@
@Nullable
private String mCurrentCountryIso;
+ /** Current service state. Must be one of ServiceState.STATE_XXX. */
+ private int mLastServiceState = -1;
+
private final LocalLog mLocalLog = new LocalLog(50);
/** Broadcast receiver to get SIM card state changed event */
@@ -116,6 +131,13 @@
updateLocale();
}
break;
+ case EVENT_UPDATE_OPERATOR_NUMERIC:
+ updateOperatorNumericSync((String) msg.obj);
+ break;
+ case EVENT_SERVICE_STATE_CHANGED:
+ AsyncResult ar = (AsyncResult) msg.obj;
+ onServiceStateChanged((ServiceState) ar.result);
+ break;
default:
throw new IllegalStateException("Unexpected message arrives. msg = " + msg.what);
}
@@ -135,6 +157,8 @@
final IntentFilter filter = new IntentFilter();
filter.addAction(TelephonyManager.ACTION_SIM_CARD_STATE_CHANGED);
mPhone.getContext().registerReceiver(mBroadcastReceiver, filter);
+
+ mPhone.registerForServiceStateChanged(this, EVENT_SERVICE_STATE_CHANGED, null);
}
/**
@@ -202,19 +226,46 @@
}
/**
- * Update MCC/MNC from network service state.
+ * Called when service state changed.
+ *
+ * @param serviceState Service state
+ */
+ private void onServiceStateChanged(ServiceState serviceState) {
+ int state = serviceState.getState();
+ if (state != mLastServiceState) {
+ if (state != ServiceState.STATE_POWER_OFF && TextUtils.isEmpty(mOperatorNumeric)) {
+ // When the device is out of airplane mode or powered on, and network's MCC/MNC is
+ // not available, we get cell info from the modem.
+ String msg = "Service state " + ServiceState.rilServiceStateToString(state)
+ + ". Get cell info now.";
+ if (DBG) log(msg);
+ mLocalLog.log(msg);
+ getCellInfo();
+ } else if (state == ServiceState.STATE_POWER_OFF) {
+ // Clear the cell info when the device is in airplane mode.
+ if (mCellInfo != null) mCellInfo.clear();
+ stopCellInfoRetry();
+ }
+ updateLocale();
+ mLastServiceState = state;
+ }
+ }
+
+ /**
+ * Update MCC/MNC from network service state synchronously. Note if this is called from phone
+ * process's main thread and if the update operation requires getting cell info from the modem,
+ * the cached cell info will be used to determine the locale. If the cached cell info is not
+ * acceptable, use {@link #updateOperatorNumericAsync(String)} instead.
*
* @param operatorNumeric MCC/MNC of the operator
*/
- public synchronized void updateOperatorNumeric(String operatorNumeric) {
+ public synchronized void updateOperatorNumericSync(String operatorNumeric) {
// Check if the operator numeric changes.
- String msg = "updateOperatorNumeric. mcc/mnc=" + operatorNumeric;
- if (DBG) log(msg);
- mLocalLog.log(msg);
+ if (DBG) log("updateOperatorNumericSync. mcc/mnc=" + operatorNumeric);
if (!Objects.equals(mOperatorNumeric, operatorNumeric)) {
- if (DBG) {
- log("onUpdateOperatorNumeric: operator numeric changes to " + operatorNumeric);
- }
+ String msg = "Operator numeric changes to " + operatorNumeric;
+ if (DBG) log(msg);
+ mLocalLog.log(msg);
mOperatorNumeric = operatorNumeric;
// If the operator numeric becomes unavailable, we need to get the latest cell info so
@@ -224,12 +275,30 @@
log("Operator numeric unavailable. Get latest cell info from the modem.");
}
getCellInfo();
+ } else {
+ // If operator numeric is available, that means we camp on network. So we should
+ // clear the cell info and stop cell info retry.
+ if (mCellInfo != null) mCellInfo.clear();
+ stopCellInfoRetry();
}
updateLocale();
}
}
/**
+ * Update MCC/MNC from network service state asynchronously. The update operation will run
+ * in locale tracker's handler's thread, which can get cell info synchronously from service
+ * state tracker. Note that the country code will not be available immediately after calling
+ * this method.
+ *
+ * @param operatorNumeric MCC/MNC of the operator
+ */
+ public void updateOperatorNumericAsync(String operatorNumeric) {
+ if (DBG) log("updateOperatorNumericAsync. mcc/mnc=" + operatorNumeric);
+ sendMessage(obtainMessage(EVENT_UPDATE_OPERATOR_NUMERIC, operatorNumeric));
+ }
+
+ /**
* Get the delay time to get cell info from modem. The delay time grows exponentially to prevent
* battery draining.
*
@@ -248,25 +317,48 @@
}
/**
+ * Stop retrying getting cell info from the modem. It cancels any scheduled cell info retrieving
+ * request.
+ */
+ private void stopCellInfoRetry() {
+ mFailCellInfoCount = 0;
+ removeMessages(EVENT_GET_CELL_INFO);
+ }
+
+ /**
* Get cell info from the modem.
*/
private void getCellInfo() {
+ String msg;
+ if (!mPhone.getServiceStateTracker().getDesiredPowerState()) {
+ msg = "Radio is off. Stopped cell info retry. Cleared the previous cached cell info.";
+ if (mCellInfo != null) mCellInfo.clear();
+ if (DBG) log(msg);
+ mLocalLog.log(msg);
+ stopCellInfoRetry();
+ return;
+ }
+
// Get all cell info. Passing null to use default worksource, which indicates the original
// request is from telephony internally.
mCellInfo = mPhone.getAllCellInfo(null);
- String msg = "getCellInfo: cell info=" + mCellInfo;
+ msg = "getCellInfo: cell info=" + mCellInfo;
if (DBG) log(msg);
mLocalLog.log(msg);
if (CollectionUtils.isEmpty(mCellInfo)) {
// If we can't get a valid cell info. Try it again later.
long delay = getCellInfoDelayTime(++mFailCellInfoCount);
if (DBG) log("Can't get cell info. Try again in " + delay / 1000 + " secs.");
+ removeMessages(EVENT_GET_CELL_INFO);
sendMessageDelayed(obtainMessage(EVENT_GET_CELL_INFO), delay);
} else {
- mFailCellInfoCount = 0;
- // We successfully got cell info from the modem. Cancel the queued get cell info event
- // if there is any.
- removeMessages(EVENT_GET_CELL_INFO);
+ // We successfully got cell info from the modem. We should stop cell info retry.
+ stopCellInfoRetry();
+
+ // Now we need to get the cell info from the modem periodically even if we already got
+ // the cell info because the user can move.
+ sendMessageDelayed(obtainMessage(EVENT_GET_CELL_INFO),
+ CELL_INFO_PERIODIC_POLLING_DELAY_MS);
}
}
@@ -276,7 +368,7 @@
private void updateLocale() {
// If MCC is available from network service state, use it first.
String mcc = null;
- String countryIso = null;
+ String countryIso = "";
if (!TextUtils.isEmpty(mOperatorNumeric)) {
try {
mcc = mOperatorNumeric.substring(0, 3);
@@ -305,7 +397,9 @@
log(msg);
mLocalLog.log(msg);
if (!Objects.equals(countryIso, mCurrentCountryIso)) {
- log("updateLocale: Change the current country to " + countryIso);
+ msg = "updateLocale: Change the current country to " + countryIso;
+ log(msg);
+ mLocalLog.log(msg);
mCurrentCountryIso = countryIso;
TelephonyManager.setTelephonyProperty(mPhone.getPhoneId(),
diff --git a/src/java/com/android/internal/telephony/Phone.java b/src/java/com/android/internal/telephony/Phone.java
index 66405be..0f431ef 100644
--- a/src/java/com/android/internal/telephony/Phone.java
+++ b/src/java/com/android/internal/telephony/Phone.java
@@ -1420,8 +1420,6 @@
*/
public void registerForServiceStateChanged(
Handler h, int what, Object obj) {
- checkCorrectThread(h);
-
mServiceStateRegistrants.add(h, what, obj);
}
diff --git a/src/java/com/android/internal/telephony/RIL.java b/src/java/com/android/internal/telephony/RIL.java
index 374c639..9e74ee2 100644
--- a/src/java/com/android/internal/telephony/RIL.java
+++ b/src/java/com/android/internal/telephony/RIL.java
@@ -293,11 +293,6 @@
" mRadioProxyCookie = " + mRadioProxyCookie.get());
if ((long) msg.obj == mRadioProxyCookie.get()) {
resetProxyAndRequestList();
-
- // todo: rild should be back up since message was sent with a delay. this is
- // a hack.
- getRadioProxy(null);
- getOemHookProxy(null);
}
break;
}
@@ -350,6 +345,7 @@
clearRequestList(RADIO_NOT_AVAILABLE, false);
getRadioProxy(null);
+ getOemHookProxy(null);
}
/** Returns a {@link IRadio} instance or null if the service is not available. */
@@ -416,7 +412,7 @@
try {
mOemHookProxy = IOemHook.getService(
- HIDL_SERVICE_NAME[mPhoneId == null ? 0 : mPhoneId]);
+ HIDL_SERVICE_NAME[mPhoneId == null ? 0 : mPhoneId], true);
if (mOemHookProxy != null) {
// not calling linkToDeath() as ril service runs in the same process and death
// notification for that should be sufficient
@@ -435,12 +431,6 @@
CommandException.fromRilErrno(RADIO_NOT_AVAILABLE));
result.sendToTarget();
}
-
- // if service is not up, treat it like death notification to try to get service again
- mRilHandler.sendMessageDelayed(
- mRilHandler.obtainMessage(EVENT_RADIO_PROXY_DEAD,
- mRadioProxyCookie.incrementAndGet()),
- IRADIO_GET_SERVICE_DELAY_MILLIS);
}
return mOemHookProxy;
@@ -1199,18 +1189,27 @@
try {
if (radioProxy12 == null) {
// IRadio V1.0
+
+ // Getting data RAT here is just a workaround to support the older 1.0 vendor
+ // RIL. The new data service interface passes access network type instead of
+ // RAT for setup data request. It is impossible to convert access network
+ // type back to RAT here, so we directly get the data RAT from phone.
+ int dataRat = ServiceState.RIL_RADIO_TECHNOLOGY_UNKNOWN;
+ Phone phone = PhoneFactory.getPhone(mPhoneId);
+ if (phone != null) {
+ ServiceState ss = phone.getServiceState();
+ if (ss != null) {
+ dataRat = ss.getRilDataRadioTechnology();
+ }
+ }
if (RILJ_LOGD) {
riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)
- + ",radioTechnology=unknown,isRoaming=" + isRoaming
+ + ",dataRat=" + dataRat + ",isRoaming=" + isRoaming
+ ",allowRoaming=" + allowRoaming + "," + dataProfile);
}
- // The RAT field in setup data call request was never used before. Starting from
- // P, the new API passes in access network type instead of RAT. Since it's
- // not possible to convert access network type back to RAT, but we still need to
- // support the 1.0 API, we passed in unknown RAT to the modem. And modem must
- // setup the data call on its current camped network.
- radioProxy.setupDataCall(rr.mSerial, ServiceState.RIL_RADIO_TECHNOLOGY_UNKNOWN,
- dpi, dataProfile.isModemCognitive(), allowRoaming, isRoaming);
+
+ radioProxy.setupDataCall(rr.mSerial, dataRat, dpi,
+ dataProfile.isModemCognitive(), allowRoaming, isRoaming);
} else {
// IRadio V1.2
ArrayList<String> addresses = new ArrayList<>();
@@ -2011,6 +2010,10 @@
} catch (RemoteException | RuntimeException e) {
handleRadioProxyExceptionForRR(rr, "invokeOemRilRequestRaw", e);
}
+ } else {
+ // OEM Hook service is disabled for P and later devices.
+ // Deprecated OEM Hook APIs will perform dummy before being removed.
+ if (RILJ_LOGD) riljLog("Radio Oem Hook Service is disabled for P and later devices. ");
}
}
@@ -2036,6 +2039,10 @@
} catch (RemoteException | RuntimeException e) {
handleRadioProxyExceptionForRR(rr, "invokeOemRilRequestStrings", e);
}
+ } else {
+ // OEM Hook service is disabled for P and later devices.
+ // Deprecated OEM Hook APIs will perform dummy before being removed.
+ if (RILJ_LOGD) riljLog("Radio Oem Hook Service is disabled for P and later devices. ");
}
}
@@ -5025,6 +5032,8 @@
return "RIL_UNSOL_ICC_SLOT_STATUS";
case RIL_UNSOL_KEEPALIVE_STATUS:
return "RIL_UNSOL_KEEPALIVE_STATUS";
+ case RIL_UNSOL_PHYSICAL_CHANNEL_CONFIG:
+ return "RIL_UNSOL_PHYSICAL_CHANNEL_CONFIG";
default:
return "<unknown response>";
}
diff --git a/src/java/com/android/internal/telephony/RadioIndication.java b/src/java/com/android/internal/telephony/RadioIndication.java
index e80e5e7..f7a7943 100644
--- a/src/java/com/android/internal/telephony/RadioIndication.java
+++ b/src/java/com/android/internal/telephony/RadioIndication.java
@@ -36,6 +36,7 @@
import static com.android.internal.telephony.RILConstants.RIL_UNSOL_ON_SS;
import static com.android.internal.telephony.RILConstants.RIL_UNSOL_ON_USSD;
import static com.android.internal.telephony.RILConstants.RIL_UNSOL_PCO_DATA;
+import static com.android.internal.telephony.RILConstants.RIL_UNSOL_PHYSICAL_CHANNEL_CONFIG;
import static com.android.internal.telephony.RILConstants.RIL_UNSOL_RADIO_CAPABILITY;
import static com.android.internal.telephony.RILConstants.RIL_UNSOL_RESEND_INCALL_MUTE;
import static com.android.internal.telephony.RILConstants.RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED;
@@ -295,6 +296,8 @@
response.add(new PhysicalChannelConfig(status, config.cellBandwidthDownlink));
}
+ if (RIL.RILJ_LOGD) mRil.unsljLogRet(RIL_UNSOL_PHYSICAL_CHANNEL_CONFIG, response);
+
mRil.mPhysicalChannelConfigurationRegistrants.notifyRegistrants(
new AsyncResult(null, response, null));
}
diff --git a/src/java/com/android/internal/telephony/RatRatcheter.java b/src/java/com/android/internal/telephony/RatRatcheter.java
index b082972..2b4b5e9 100644
--- a/src/java/com/android/internal/telephony/RatRatcheter.java
+++ b/src/java/com/android/internal/telephony/RatRatcheter.java
@@ -101,7 +101,7 @@
/** Ratchets RATs and cell bandwidths if oldSS and newSS have the same RAT family. */
public void ratchet(ServiceState oldSS, ServiceState newSS, boolean locationChange) {
- if (isSameRatFamily(oldSS, newSS)) {
+ if (!locationChange && isSameRatFamily(oldSS, newSS)) {
updateBandwidths(oldSS.getCellBandwidths(), newSS);
}
// temporarily disable rat ratchet on location change.
@@ -123,9 +123,9 @@
int newDataRat = ratchetRat(oldSS.getRilDataRadioTechnology(),
newSS.getRilDataRadioTechnology());
newSS.setRilDataRadioTechnology(newDataRat);
- } else if (oldSS.getRilVoiceRadioTechnology() != newSS.getRilVoiceRadioTechnology()) {
+ } else if (oldSS.getRilDataRadioTechnology() != newSS.getRilDataRadioTechnology()) {
// resume rat ratchet on following rat change within the same location
- mVoiceRatchetEnabled = true;
+ mDataRatchetEnabled = true;
}
boolean newUsingCA = oldSS.isUsingCarrierAggregation()
@@ -136,6 +136,10 @@
private boolean isSameRatFamily(ServiceState ss1, ServiceState ss2) {
synchronized (mRatFamilyMap) {
+ // Either the two technologies are the same or their families must be non-null
+ // and the same.
+ if (ss1.getRilDataRadioTechnology() == ss2.getRilDataRadioTechnology()) return true;
+ if (mRatFamilyMap.get(ss1.getRilDataRadioTechnology()) == null) return false;
return mRatFamilyMap.get(ss1.getRilDataRadioTechnology())
== mRatFamilyMap.get(ss2.getRilDataRadioTechnology());
}
diff --git a/src/java/com/android/internal/telephony/SMSDispatcher.java b/src/java/com/android/internal/telephony/SMSDispatcher.java
index e26a0f5..1e5afc7 100644
--- a/src/java/com/android/internal/telephony/SMSDispatcher.java
+++ b/src/java/com/android/internal/telephony/SMSDispatcher.java
@@ -1454,7 +1454,13 @@
// fields need to be public for derived SmsDispatchers
private final HashMap<String, Object> mData;
public int mRetryCount;
- public int mImsRetry; // nonzero indicates initial message was sent over Ims
+ // IMS retry counter. Nonzero indicates initial message was sent over IMS channel in RIL and
+ // counts how many retries have been made on the IMS channel.
+ // Used in older implementations where the message is sent over IMS using the RIL.
+ public int mImsRetry;
+ // Tag indicating that this SMS is being handled by the ImsSmsDispatcher. This tracker
+ // should not try to use SMS over IMS over the RIL interface in this case when falling back.
+ public boolean mUsesImsServiceForIms;
public int mMessageRef;
public boolean mExpectMore;
public int mValidityPeriod;
@@ -1504,6 +1510,7 @@
mFormat = format;
mExpectMore = expectMore;
mImsRetry = 0;
+ mUsesImsServiceForIms = false;
mMessageRef = 0;
mUnsentPartCount = unsentPartCount;
mAnyPartFailed = anyPartFailed;
diff --git a/src/java/com/android/internal/telephony/ServiceStateTracker.java b/src/java/com/android/internal/telephony/ServiceStateTracker.java
index 4a6321a..db566ef 100644
--- a/src/java/com/android/internal/telephony/ServiceStateTracker.java
+++ b/src/java/com/android/internal/telephony/ServiceStateTracker.java
@@ -131,6 +131,7 @@
private static final long LAST_CELL_INFO_LIST_MAX_AGE_MS = 2000;
private long mLastCellInfoListTime;
private List<CellInfo> mLastCellInfoList = null;
+ private List<PhysicalChannelConfig> mLastPhysicalChannelConfigList = null;
private SignalStrength mSignalStrength;
@@ -582,6 +583,11 @@
}
// If we are previously in service, we need to notify that we are out of service now.
+ if (mSS != null && mSS.getVoiceRegState() == ServiceState.STATE_IN_SERVICE) {
+ mNetworkDetachedRegistrants.notifyRegistrants();
+ }
+
+ // If we are previously in service, we need to notify that we are out of service now.
if (mSS != null && mSS.getDataRegState() == ServiceState.STATE_IN_SERVICE) {
mDetachedRegistrants.notifyRegistrants();
}
@@ -671,6 +677,10 @@
mCi.unregisterForImsNetworkStateChanged(this);
mPhone.getCarrierActionAgent().unregisterForCarrierAction(this,
CARRIER_ACTION_SET_RADIO_ENABLED);
+ if (mCSST != null) {
+ mCSST.dispose();
+ mCSST = null;
+ }
}
public boolean getDesiredPowerState() {
@@ -1450,6 +1460,7 @@
+ list);
}
mPhone.notifyPhysicalChannelConfiguration(list);
+ mLastPhysicalChannelConfigList = list;
// only notify if bandwidths changed
if (RatRatcheter.updateBandwidths(getBandwidthsFromConfigs(list), mSS)) {
@@ -1789,7 +1800,7 @@
mNewSS.setCssIndicator(cssIndicator);
mNewSS.setRilVoiceRadioTechnology(newVoiceRat);
mNewSS.addNetworkRegistrationState(networkRegState);
- setChannelNumberFromCellIdentity(mNewSS, networkRegState.getCellIdentity());
+ setPhyCellInfoFromCellIdentity(mNewSS, networkRegState.getCellIdentity());
//Denial reason if registrationState = 3
int reasonForDenial = networkRegState.getReasonForDenial();
@@ -1865,7 +1876,14 @@
mNewSS.setDataRegState(serviceState);
mNewSS.setRilDataRadioTechnology(newDataRat);
mNewSS.addNetworkRegistrationState(networkRegState);
- setChannelNumberFromCellIdentity(mNewSS, networkRegState.getCellIdentity());
+
+ // When we receive OOS reset the PhyChanConfig list so that non-return-to-idle
+ // implementers of PhyChanConfig unsol will not carry forward a CA report
+ // (2 or more cells) to a new cell if they camp for emergency service only.
+ if (serviceState == ServiceState.STATE_OUT_OF_SERVICE) {
+ mLastPhysicalChannelConfigList = null;
+ }
+ setPhyCellInfoFromCellIdentity(mNewSS, networkRegState.getCellIdentity());
if (mPhone.isPhoneTypeGsm()) {
@@ -2004,7 +2022,22 @@
}
}
- private void setChannelNumberFromCellIdentity(ServiceState ss, CellIdentity cellIdentity) {
+ private static boolean isValidLteBandwidthKhz(int bandwidth) {
+ // Valid bandwidths, see 3gpp 36.101 sec. 5.6
+ switch (bandwidth) {
+ case 1400:
+ case 3000:
+ case 5000:
+ case 10000:
+ case 15000:
+ case 20000:
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ private void setPhyCellInfoFromCellIdentity(ServiceState ss, CellIdentity cellIdentity) {
if (cellIdentity == null) {
if (DBG) {
log("Could not set ServiceState channel number. CellIdentity null");
@@ -2016,6 +2049,49 @@
if (VDBG) {
log("Setting channel number: " + cellIdentity.getChannelNumber());
}
+
+ if (cellIdentity instanceof CellIdentityLte) {
+ CellIdentityLte cl = (CellIdentityLte) cellIdentity;
+ int[] bandwidths = null;
+ // Prioritize the PhysicalChannelConfig list because we might already be in carrier
+ // aggregation by the time poll state is performed.
+ if (!ArrayUtils.isEmpty(mLastPhysicalChannelConfigList)) {
+ bandwidths = getBandwidthsFromConfigs(mLastPhysicalChannelConfigList);
+ for (int bw : bandwidths) {
+ if (!isValidLteBandwidthKhz(bw)) {
+ loge("Invalid LTE Bandwidth in RegistrationState, " + bw);
+ bandwidths = null;
+ break;
+ }
+ }
+ }
+ // If we don't have a PhysicalChannelConfig[] list, then pull from CellIdentityLte.
+ // This is normal if we're in idle mode and the PhysicalChannelConfig[] has already
+ // been updated. This is also a fallback in case the PhysicalChannelConfig info
+ // is invalid (ie, broken).
+ // Also, for vendor implementations that do not report return-to-idle, we should
+ // prioritize the bandwidth report in the CellIdentity, because the physical channel
+ // config report may be stale in the case where a single carrier was used previously
+ // and we transition to camped-for-emergency (since we never have a physical
+ // channel active). In the normal case of single-carrier non-return-to-idle, the
+ // values *must* be the same, so it doesn't matter which is chosen.
+ if (bandwidths == null || bandwidths.length == 1) {
+ final int cbw = cl.getBandwidth();
+ if (isValidLteBandwidthKhz(cbw)) {
+ bandwidths = new int[] {cbw};
+ } else if (cbw == Integer.MAX_VALUE) {
+ // Bandwidth is unreported; c'est la vie. This is not an error because
+ // pre-1.2 HAL implementations do not support bandwidth reporting.
+ } else {
+ loge("Invalid LTE Bandwidth in RegistrationState, " + cbw);
+ }
+ }
+ if (bandwidths != null) {
+ ss.setCellBandwidths(bandwidths);
+ }
+ } else {
+ if (VDBG) log("Skipping bandwidth update for Non-LTE cell.");
+ }
}
/**
@@ -2684,7 +2760,7 @@
// until cell change or device is OOS
boolean isDataInService = mNewSS.getDataRegState() == ServiceState.STATE_IN_SERVICE;
- if (!hasLocationChanged && isDataInService) {
+ if (isDataInService) {
mRatRatcheter.ratchet(mSS, mNewSS, hasLocationChanged);
}
@@ -2868,8 +2944,9 @@
if (isInvalidOperatorNumeric(operatorNumeric)) {
if (DBG) log("operatorNumeric " + operatorNumeric + " is invalid");
// Passing empty string is important for the first update. The initial value of
- // operator numeric in locale tracker is null.
- mLocaleTracker.updateOperatorNumeric("");
+ // operator numeric in locale tracker is null. The async update will allow getting
+ // cell info from the modem instead of using the cached one.
+ mLocaleTracker.updateOperatorNumericAsync("");
mNitzState.handleNetworkUnavailable();
} else if (mSS.getRilDataRadioTechnology() != ServiceState.RIL_RADIO_TECHNOLOGY_IWLAN) {
// If the device is on IWLAN, modems manufacture a ServiceState with the MCC/MNC of
@@ -2881,7 +2958,7 @@
setOperatorIdd(operatorNumeric);
}
- mLocaleTracker.updateOperatorNumeric(operatorNumeric);
+ mLocaleTracker.updateOperatorNumericSync(operatorNumeric);
String countryIsoCode = mLocaleTracker.getCurrentCountry();
// Update Time Zone.
diff --git a/src/java/com/android/internal/telephony/SubscriptionController.java b/src/java/com/android/internal/telephony/SubscriptionController.java
index 500094b..fd12273 100644
--- a/src/java/com/android/internal/telephony/SubscriptionController.java
+++ b/src/java/com/android/internal/telephony/SubscriptionController.java
@@ -162,6 +162,7 @@
private static int mDefaultPhoneId = SubscriptionManager.DEFAULT_PHONE_INDEX;
private int[] colorArr;
+ private long mLastISubServiceRegTime;
public static SubscriptionController init(Phone phone) {
synchronized (SubscriptionController.class) {
@@ -207,7 +208,8 @@
mAppOps = (AppOpsManager)mContext.getSystemService(Context.APP_OPS_SERVICE);
if(ServiceManager.getService("isub") == null) {
- ServiceManager.addService("isub", this);
+ ServiceManager.addService("isub", this);
+ mLastISubServiceRegTime = System.currentTimeMillis();
}
if (DBG) logdl("[SubscriptionController] init by Context");
@@ -2135,6 +2137,7 @@
final long token = Binder.clearCallingIdentity();
try {
pw.println("SubscriptionController:");
+ pw.println(" mLastISubServiceRegTime=" + mLastISubServiceRegTime);
pw.println(" defaultSubId=" + getDefaultSubId());
pw.println(" defaultDataSubId=" + getDefaultDataSubId());
pw.println(" defaultVoiceSubId=" + getDefaultVoiceSubId());
diff --git a/src/java/com/android/internal/telephony/SubscriptionInfoUpdater.java b/src/java/com/android/internal/telephony/SubscriptionInfoUpdater.java
index e0f1fd4..afd49fa 100644
--- a/src/java/com/android/internal/telephony/SubscriptionInfoUpdater.java
+++ b/src/java/com/android/internal/telephony/SubscriptionInfoUpdater.java
@@ -600,6 +600,8 @@
+ Integer.toString(mInsertSimState[i]), i);
logd("SUB" + (i + 1) + " has invalid IccId");
} else /*if (sInsertSimState[i] != SIM_NOT_INSERT)*/ {
+ logd("updateSubscriptionInfoByIccId: adding subscription info record: iccid: "
+ + mIccId[i] + "slot: " + i);
mSubscriptionManager.addSubscriptionInfoRecord(mIccId[i], i);
}
if (isNewSim(mIccId[i], decIccId[i], oldIccId)) {
diff --git a/src/java/com/android/internal/telephony/TelephonyComponentFactory.java b/src/java/com/android/internal/telephony/TelephonyComponentFactory.java
index 462a1b1..8ad5720 100644
--- a/src/java/com/android/internal/telephony/TelephonyComponentFactory.java
+++ b/src/java/com/android/internal/telephony/TelephonyComponentFactory.java
@@ -104,8 +104,8 @@
* Create a new UiccProfile object.
*/
public UiccProfile makeUiccProfile(Context context, CommandsInterface ci, IccCardStatus ics,
- int phoneId, UiccCard uiccCard) {
- return new UiccProfile(context, ci, ics, phoneId, uiccCard);
+ int phoneId, UiccCard uiccCard, Object lock) {
+ return new UiccProfile(context, ci, ics, phoneId, uiccCard, lock);
}
public EriManager makeEriManager(Phone phone, Context context, int eriFileSource) {
diff --git a/src/java/com/android/internal/telephony/cdma/CdmaSMSDispatcher.java b/src/java/com/android/internal/telephony/cdma/CdmaSMSDispatcher.java
index b145b4b..bbaa3ca 100755
--- a/src/java/com/android/internal/telephony/cdma/CdmaSMSDispatcher.java
+++ b/src/java/com/android/internal/telephony/cdma/CdmaSMSDispatcher.java
@@ -16,12 +16,7 @@
package com.android.internal.telephony.cdma;
-import android.app.Activity;
-import android.app.PendingIntent;
-import android.app.PendingIntent.CanceledException;
-import android.content.Intent;
import android.os.Message;
-import android.provider.Telephony.Sms;
import android.telephony.Rlog;
import android.telephony.ServiceState;
import android.telephony.TelephonyManager;
@@ -124,6 +119,7 @@
+ " mRetryCount=" + tracker.mRetryCount
+ " mImsRetry=" + tracker.mImsRetry
+ " mMessageRef=" + tracker.mMessageRef
+ + " mUsesImsServiceForIms=" + tracker.mUsesImsServiceForIms
+ " SS=" + mPhone.getServiceState().getState());
int ss = mPhone.getServiceState().getState();
@@ -147,8 +143,11 @@
// sms over cdma is used:
// if sms over IMS is not supported AND
// this is not a retry case after sms over IMS failed
- // indicated by mImsRetry > 0
- if (0 == tracker.mImsRetry && !isIms() || imsSmsDisabled) {
+ // indicated by mImsRetry > 0 OR
+ // SMS over IMS is disabled because of the network type OR
+ // SMS over IMS is being handled by the ImsSmsDispatcher implementation and has indicated
+ // that the message should fall back to sending over CS.
+ if (0 == tracker.mImsRetry && !isIms() || imsSmsDisabled || tracker.mUsesImsServiceForIms) {
mCi.sendCdmaSms(pdu, reply);
} else {
mCi.sendImsCdmaSms(pdu, tracker.mImsRetry, tracker.mMessageRef, reply);
diff --git a/src/java/com/android/internal/telephony/dataconnection/ApnSetting.java b/src/java/com/android/internal/telephony/dataconnection/ApnSetting.java
index 9394ecb..6f1c8a6 100644
--- a/src/java/com/android/internal/telephony/dataconnection/ApnSetting.java
+++ b/src/java/com/android/internal/telephony/dataconnection/ApnSetting.java
@@ -19,6 +19,7 @@
import android.content.Context;
import android.hardware.radio.V1_0.ApnTypes;
import android.os.PersistableBundle;
+import android.provider.Telephony.Carriers;
import android.telephony.CarrierConfigManager;
import android.telephony.Rlog;
import android.telephony.ServiceState;
@@ -50,6 +51,7 @@
static final String V2_FORMAT_REGEX = "^\\[ApnSettingV2\\]\\s*";
static final String V3_FORMAT_REGEX = "^\\[ApnSettingV3\\]\\s*";
static final String V4_FORMAT_REGEX = "^\\[ApnSettingV4\\]\\s*";
+ static final String V5_FORMAT_REGEX = "^\\[ApnSettingV5\\]\\s*";
static final String TAG = "ApnSetting";
public final String carrier;
@@ -129,6 +131,16 @@
public final String mvnoMatchData;
/**
+ * The APN set id.
+ *
+ * APNs that are part of the same set should be preferred together, e.g. if the
+ * user selects a default APN with apnSetId=1, then we will prefer all APNs with apnSetId=1.
+ *
+ * If the apnSetId=Carriers.NO_SET_SET (=0) then the APN is not part of a set.
+ */
+ public final int apnSetId;
+
+ /**
* Indicates this APN setting is permanently failed and cannot be
* retried by the retry manager anymore.
* */
@@ -179,10 +191,26 @@
this.mtu = mtu;
this.mvnoType = mvnoType;
this.mvnoMatchData = mvnoMatchData;
+ this.apnSetId = Carriers.NO_SET_SET;
this.networkTypeBitmask = ServiceState.convertBearerBitmaskToNetworkTypeBitmask(
this.bearerBitmask);
}
+ // Constructor with default apn set id
+ public ApnSetting(int id, String numeric, String carrier, String apn,
+ String proxy, String port,
+ String mmsc, String mmsProxy, String mmsPort,
+ String user, String password, int authType, String[] types,
+ String protocol, String roamingProtocol, boolean carrierEnabled,
+ int networkTypeBitmask, int profileId, boolean modemCognitive, int maxConns,
+ int waitTime, int maxConnsTime, int mtu, String mvnoType,
+ String mvnoMatchData) {
+ this(id, numeric, carrier, apn, proxy, port, mmsc, mmsProxy, mmsPort, user, password,
+ authType, types, protocol, roamingProtocol, carrierEnabled, networkTypeBitmask,
+ profileId, modemCognitive, maxConns, waitTime, maxConnsTime, mtu, mvnoType,
+ mvnoMatchData, Carriers.NO_SET_SET);
+ }
+
public ApnSetting(int id, String numeric, String carrier, String apn,
String proxy, String port,
String mmsc, String mmsProxy, String mmsPort,
@@ -190,7 +218,7 @@
String protocol, String roamingProtocol, boolean carrierEnabled,
int networkTypeBitmask, int profileId, boolean modemCognitive, int maxConns,
int waitTime, int maxConnsTime, int mtu, String mvnoType,
- String mvnoMatchData) {
+ String mvnoMatchData, int apnSetId) {
this.id = id;
this.numeric = numeric;
this.carrier = carrier;
@@ -225,6 +253,7 @@
this.mtu = mtu;
this.mvnoType = mvnoType;
this.mvnoMatchData = mvnoMatchData;
+ this.apnSetId = apnSetId;
}
public ApnSetting(ApnSetting apn) {
@@ -232,7 +261,7 @@
apn.mmsPort, apn.user, apn.password, apn.authType, apn.types, apn.protocol,
apn.roamingProtocol, apn.carrierEnabled, apn.networkTypeBitmask, apn.profileId,
apn.modemCognitive, apn.maxConns, apn.waitTime, apn.maxConnsTime,
- apn.mtu, apn.mvnoType, apn.mvnoMatchData);
+ apn.mtu, apn.mvnoType, apn.mvnoMatchData, apn.apnSetId);
}
/**
@@ -267,6 +296,13 @@
* <profileId>, <modemCognitive>, <maxConns>, <waitTime>, <maxConnsTime>, <mtu>,
* <mvnoType>, <mvnoMatchData>, <networkTypeBitmask>
*
+ * v5 format:
+ * [ApnSettingV5] <carrier>, <apn>, <proxy>, <port>, <user>, <password>, <server>,
+ * <mmsc>, <mmsproxy>, <mmsport>, <mcc>, <mnc>, <authtype>,
+ * <type>[| <type>...], <protocol>, <roaming_protocol>, <carrierEnabled>, <bearerBitmask>,
+ * <profileId>, <modemCognitive>, <maxConns>, <waitTime>, <maxConnsTime>, <mtu>,
+ * <mvnoType>, <mvnoMatchData>, <networkTypeBitmask>, <apnSetId>
+ *
* Note that the strings generated by toString() do not contain the username
* and password and thus cannot be read by this method.
*/
@@ -275,7 +311,10 @@
int version;
// matches() operates on the whole string, so append .* to the regex.
- if (data.matches(V4_FORMAT_REGEX + ".*")) {
+ if (data.matches(V5_FORMAT_REGEX + ".*")) {
+ version = 5;
+ data = data.replaceFirst(V5_FORMAT_REGEX, "");
+ } else if (data.matches(V4_FORMAT_REGEX + ".*")) {
version = 4;
data = data.replaceFirst(V4_FORMAT_REGEX, "");
} else if (data.matches(V3_FORMAT_REGEX + ".*")) {
@@ -313,6 +352,7 @@
int mtu = PhoneConstants.UNSET_MTU;
String mvnoType = "";
String mvnoMatchData = "";
+ int apnSetId = Carriers.NO_SET_SET;
if (version == 1) {
typeArray = new String[a.length - 13];
System.arraycopy(a, 13, typeArray, 0, a.length - 13);
@@ -353,6 +393,9 @@
if (a.length > 26) {
networkTypeBitmask = ServiceState.getBitmaskFromString(a[26]);
}
+ if (a.length > 27) {
+ apnSetId = Integer.parseInt(a[27]);
+ }
}
// If both bearerBitmask and networkTypeBitmask were specified, bearerBitmask would be
@@ -364,7 +407,7 @@
return new ApnSetting(-1, a[10] + a[11], a[0], a[1], a[2], a[3], a[7], a[8], a[9], a[4],
a[5], authType, typeArray, protocol, roamingProtocol, carrierEnabled,
networkTypeBitmask, profileId, modemCognitive, maxConns, waitTime, maxConnsTime,
- mtu, mvnoType, mvnoMatchData);
+ mtu, mvnoType, mvnoMatchData, apnSetId);
}
/**
@@ -393,7 +436,7 @@
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
- sb.append("[ApnSettingV4] ")
+ sb.append("[ApnSettingV5] ")
.append(carrier)
.append(", ").append(id)
.append(", ").append(numeric)
@@ -425,6 +468,7 @@
sb.append(", ").append(mvnoMatchData);
sb.append(", ").append(permanentFailed);
sb.append(", ").append(networkTypeBitmask);
+ sb.append(", ").append(apnSetId);
return sb.toString();
}
@@ -651,7 +695,8 @@
&& mtu == other.mtu
&& mvnoType.equals(other.mvnoType)
&& mvnoMatchData.equals(other.mvnoMatchData)
- && networkTypeBitmask == other.networkTypeBitmask;
+ && networkTypeBitmask == other.networkTypeBitmask
+ && apnSetId == other.apnSetId;
}
/**
@@ -696,7 +741,8 @@
&& maxConnsTime == other.maxConnsTime
&& mtu == other.mtu
&& mvnoType.equals(other.mvnoType)
- && mvnoMatchData.equals(other.mvnoMatchData);
+ && mvnoMatchData.equals(other.mvnoMatchData)
+ && apnSetId == other.apnSetId;
}
/**
@@ -722,7 +768,8 @@
&& xorEquals(this.mmsc, other.mmsc)
&& xorEquals(this.mmsProxy, other.mmsProxy)
&& xorEquals(this.mmsPort, other.mmsPort))
- && this.networkTypeBitmask == other.networkTypeBitmask;
+ && this.networkTypeBitmask == other.networkTypeBitmask
+ && this.apnSetId == other.apnSetId;
}
// check whether the types of two APN same (even only one type of each APN is same)
diff --git a/src/java/com/android/internal/telephony/dataconnection/DataConnection.java b/src/java/com/android/internal/telephony/dataconnection/DataConnection.java
index a400f21..0696aa9 100644
--- a/src/java/com/android/internal/telephony/dataconnection/DataConnection.java
+++ b/src/java/com/android/internal/telephony/dataconnection/DataConnection.java
@@ -936,7 +936,6 @@
result.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR);
if (mApnSetting != null) {
- ApnSetting securedDunApn = mDct.fetchDunApn();
for (String type : mApnSetting.types) {
if (!mRestrictedNetworkOverride
&& (mConnectionParams != null && mConnectionParams.mUnmeteredUseOnly)
@@ -953,11 +952,7 @@
result.addCapability(NetworkCapabilities.NET_CAPABILITY_IMS);
result.addCapability(NetworkCapabilities.NET_CAPABILITY_CBS);
result.addCapability(NetworkCapabilities.NET_CAPABILITY_IA);
- // check if this is the DUN apn as well as returned by fetchDunApn().
- // If yes, add DUN capability too.
- if (mApnSetting.equals(securedDunApn)) {
- result.addCapability(NetworkCapabilities.NET_CAPABILITY_DUN);
- }
+ result.addCapability(NetworkCapabilities.NET_CAPABILITY_DUN);
break;
}
case PhoneConstants.APN_TYPE_DEFAULT: {
@@ -973,9 +968,7 @@
break;
}
case PhoneConstants.APN_TYPE_DUN: {
- if (securedDunApn == null || securedDunApn.equals(mApnSetting)) {
- result.addCapability(NetworkCapabilities.NET_CAPABILITY_DUN);
- }
+ result.addCapability(NetworkCapabilities.NET_CAPABILITY_DUN);
break;
}
case PhoneConstants.APN_TYPE_FOTA: {
@@ -1725,6 +1718,7 @@
misc.subscriberId = mPhone.getSubscriberId();
setNetworkRestriction();
+ if (DBG) log("mRestrictedNetworkOverride = " + mRestrictedNetworkOverride);
mNetworkAgent = new DcNetworkAgent(getHandler().getLooper(), mPhone.getContext(),
"DcNetworkAgent", mNetworkInfo, getNetworkCapabilities(), mLinkProperties,
50, misc);
@@ -2169,7 +2163,6 @@
String logStr = "Changed from " + mNetworkCapabilities + " to "
+ networkCapabilities + ", Data RAT="
+ mPhone.getServiceState().getRilDataRadioTechnology()
- + ", DUN APN=\"" + mDct.fetchDunApn() + "\""
+ ", mApnSetting=" + mApnSetting;
mNetCapsLocalLog.log(logStr);
log(logStr);
diff --git a/src/java/com/android/internal/telephony/dataconnection/DcTracker.java b/src/java/com/android/internal/telephony/dataconnection/DcTracker.java
index bdd334f..38d3852 100644
--- a/src/java/com/android/internal/telephony/dataconnection/DcTracker.java
+++ b/src/java/com/android/internal/telephony/dataconnection/DcTracker.java
@@ -16,6 +16,9 @@
package com.android.internal.telephony.dataconnection;
+import static android.Manifest.permission.READ_PHONE_STATE;
+
+import android.annotation.NonNull;
import android.app.AlarmManager;
import android.app.PendingIntent;
import android.app.ProgressDialog;
@@ -1706,27 +1709,27 @@
}
/**
- * Fetch dun apn
- * @return ApnSetting to be used for dun
+ * Fetch the DUN apns
+ * @return a list of DUN ApnSetting objects
*/
@VisibleForTesting
- public ApnSetting fetchDunApn() {
+ public @NonNull ArrayList<ApnSetting> fetchDunApns() {
if (SystemProperties.getBoolean("net.tethering.noprovisioning", false)) {
- log("fetchDunApn: net.tethering.noprovisioning=true ret: null");
- return null;
+ log("fetchDunApns: net.tethering.noprovisioning=true ret: empty list");
+ return new ArrayList<ApnSetting>(0);
}
int bearer = mPhone.getServiceState().getRilDataRadioTechnology();
IccRecords r = mIccRecords.get();
String operator = (r != null) ? r.getOperatorNumeric() : "";
ArrayList<ApnSetting> dunCandidates = new ArrayList<ApnSetting>();
- ApnSetting retDunSetting = null;
+ ArrayList<ApnSetting> retDunSettings = new ArrayList<ApnSetting>();
// Places to look for tether APN in order: TETHER_DUN_APN setting (to be deprecated soon),
// APN database, and config_tether_apndata resource (to be deprecated soon).
String apnData = Settings.Global.getString(mResolver, Settings.Global.TETHER_DUN_APN);
if (!TextUtils.isEmpty(apnData)) {
dunCandidates.addAll(ApnSetting.arrayFromString(apnData));
- if (VDBG) log("fetchDunApn: dunCandidates from Setting: " + dunCandidates);
+ if (VDBG) log("fetchDunApns: dunCandidates from Setting: " + dunCandidates);
}
// todo: remove this and config_tether_apndata after APNs are moved from overlay to apns xml
@@ -1741,7 +1744,7 @@
// apn may be null if apnString isn't valid or has error parsing
if (apn != null) dunCandidates.add(apn);
}
- if (VDBG) log("fetchDunApn: dunCandidates from resource: " + dunCandidates);
+ if (VDBG) log("fetchDunApns: dunCandidates from resource: " + dunCandidates);
}
}
@@ -1752,7 +1755,7 @@
dunCandidates.add(apn);
}
}
- if (VDBG) log("fetchDunApn: dunCandidates from database: " + dunCandidates);
+ if (VDBG) log("fetchDunApns: dunCandidates from database: " + dunCandidates);
}
}
@@ -1765,24 +1768,36 @@
if (dunSetting.hasMvnoParams()) {
if (r != null && ApnSetting.mvnoMatches(r, dunSetting.mvnoType,
dunSetting.mvnoMatchData)) {
- retDunSetting = dunSetting;
- break;
+ retDunSettings.add(dunSetting);
}
} else if (mMvnoMatched == false) {
- retDunSetting = dunSetting;
- break;
+ retDunSettings.add(dunSetting);
}
}
}
- if (VDBG) log("fetchDunApn: dunSetting=" + retDunSetting);
- return retDunSetting;
+ if (VDBG) log("fetchDunApns: dunSettings=" + retDunSettings);
+ return retDunSettings;
+ }
+
+ private int getPreferredApnSetId() {
+ Cursor c = mPhone.getContext().getContentResolver()
+ .query(Uri.withAppendedPath(Telephony.Carriers.CONTENT_URI,
+ "preferapnset/subId/" + mPhone.getSubId()),
+ new String[] {Telephony.Carriers.APN_SET_ID}, null, null, null);
+ if (c.getCount() < 1) {
+ loge("getPreferredApnSetId: no APNs found");
+ return Telephony.Carriers.NO_SET_SET;
+ } else {
+ c.moveToFirst();
+ return c.getInt(0 /* index of Telephony.Carriers.APN_SET_ID */);
+ }
}
public boolean hasMatchedTetherApnSetting() {
- ApnSetting matched = fetchDunApn();
- log("hasMatchedTetherApnSetting: APN=" + matched);
- return matched != null;
+ ArrayList<ApnSetting> matches = fetchDunApns();
+ log("hasMatchedTetherApnSetting: APNs=" + matches);
+ return matches.size() > 0;
}
/**
@@ -1793,7 +1808,8 @@
final int rilRat = mPhone.getServiceState().getRilDataRadioTechnology();
if (ServiceState.isCdma(rilRat)) return true;
- return (fetchDunApn() != null);
+ ArrayList<ApnSetting> apns = fetchDunApns();
+ return apns.size() > 0;
}
/**
@@ -1876,7 +1892,8 @@
cursor.getInt(cursor.getColumnIndexOrThrow(Telephony.Carriers.MAX_CONNS_TIME)),
cursor.getInt(cursor.getColumnIndexOrThrow(Telephony.Carriers.MTU)),
cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.MVNO_TYPE)),
- cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.MVNO_MATCH_DATA)));
+ cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.MVNO_MATCH_DATA)),
+ cursor.getInt(cursor.getColumnIndexOrThrow(Telephony.Carriers.APN_SET_ID)));
return apn;
}
@@ -2465,10 +2482,10 @@
private DcAsyncChannel checkForCompatibleConnectedApnContext(ApnContext apnContext) {
String apnType = apnContext.getApnType();
- ApnSetting dunSetting = null;
+ ArrayList<ApnSetting> dunSettings = null;
if (PhoneConstants.APN_TYPE_DUN.equals(apnType)) {
- dunSetting = fetchDunApn();
+ dunSettings = sortApnListByPreferred(fetchDunApns());
}
if (DBG) {
log("checkForCompatibleConnectedApnContext: apnContext=" + apnContext );
@@ -2481,23 +2498,26 @@
if (curDcac != null) {
ApnSetting apnSetting = curApnCtx.getApnSetting();
log("apnSetting: " + apnSetting);
- if (dunSetting != null) {
- if (dunSetting.equals(apnSetting)) {
- switch (curApnCtx.getState()) {
- case CONNECTED:
- if (DBG) {
- log("checkForCompatibleConnectedApnContext:"
- + " found dun conn=" + curDcac
- + " curApnCtx=" + curApnCtx);
- }
- return curDcac;
- case RETRYING:
- case CONNECTING:
- potentialDcac = curDcac;
- potentialApnCtx = curApnCtx;
- default:
- // Not connected, potential unchanged
- break;
+ if (dunSettings != null && dunSettings.size() > 0) {
+ for (ApnSetting dunSetting : dunSettings) {
+ if (dunSetting.equals(apnSetting)) {
+ switch (curApnCtx.getState()) {
+ case CONNECTED:
+ if (DBG) {
+ log("checkForCompatibleConnectedApnContext:"
+ + " found dun conn=" + curDcac
+ + " curApnCtx=" + curApnCtx);
+ }
+ return curDcac;
+ case RETRYING:
+ case CONNECTING:
+ potentialDcac = curDcac;
+ potentialApnCtx = curApnCtx;
+ break;
+ default:
+ // Not connected, potential unchanged
+ break;
+ }
}
}
} else if (apnSetting != null && apnSetting.canHandleType(apnType)) {
@@ -2513,6 +2533,7 @@
case CONNECTING:
potentialDcac = curDcac;
potentialApnCtx = curApnCtx;
+ break;
default:
// Not connected, potential unchanged
break;
@@ -3406,7 +3427,7 @@
dest.authType, resultTypes.toArray(new String[0]), protocol,
roamingProtocol, dest.carrierEnabled, networkTypeBitmask, dest.profileId,
(dest.modemCognitive || src.modemCognitive), dest.maxConns, dest.waitTime,
- dest.maxConnsTime, dest.mtu, dest.mvnoType, dest.mvnoMatchData);
+ dest.maxConnsTime, dest.mtu, dest.mvnoType, dest.mvnoMatchData, dest.apnSetId);
}
/** Return the DC AsyncChannel for the new data connection */
@@ -3450,11 +3471,13 @@
ArrayList<ApnSetting> apnList = new ArrayList<ApnSetting>();
if (requestedApnType.equals(PhoneConstants.APN_TYPE_DUN)) {
- ApnSetting dun = fetchDunApn();
- if (dun != null) {
- apnList.add(dun);
- if (DBG) log("buildWaitingApns: X added APN_TYPE_DUN apnList=" + apnList);
- return apnList;
+ ArrayList<ApnSetting> dunApns = fetchDunApns();
+ if (dunApns.size() > 0) {
+ for (ApnSetting dun : dunApns) {
+ apnList.add(dun);
+ if (DBG) log("buildWaitingApns: X added APN_TYPE_DUN apnList=" + apnList);
+ }
+ return sortApnListByPreferred(apnList);
}
}
@@ -3495,6 +3518,7 @@
if (ServiceState.bitmaskHasTech(mPreferredApn.networkTypeBitmask,
ServiceState.rilRadioTechnologyToNetworkType(radioTech))) {
apnList.add(mPreferredApn);
+ apnList = sortApnListByPreferred(apnList);
if (DBG) log("buildWaitingApns: X added preferred apnList=" + apnList);
return apnList;
} else {
@@ -3531,10 +3555,41 @@
} else {
loge("mAllApnSettings is null!");
}
+
+ apnList = sortApnListByPreferred(apnList);
if (DBG) log("buildWaitingApns: " + apnList.size() + " APNs in the list: " + apnList);
return apnList;
}
+ /**
+ * Sort a list of ApnSetting objects, with the preferred APNs at the front of the list
+ *
+ * e.g. if the preferred APN set = 2 and we have
+ * 1. APN with apn_set_id = 0 = Carriers.NO_SET_SET (no set is set)
+ * 2. APN with apn_set_id = 1 (not preferred set)
+ * 3. APN with apn_set_id = 2 (preferred set)
+ * Then the return order should be (3, 1, 2) or (3, 2, 1)
+ *
+ * e.g. if the preferred APN set = Carriers.NO_SET_SET (no preferred set) then the
+ * return order can be anything
+ */
+ @VisibleForTesting
+ public ArrayList<ApnSetting> sortApnListByPreferred(ArrayList<ApnSetting> list) {
+ if (list == null || list.size() <= 1) return list;
+ int preferredApnSetId = getPreferredApnSetId();
+ if (preferredApnSetId != Telephony.Carriers.NO_SET_SET) {
+ list.sort(new Comparator<ApnSetting>() {
+ @Override
+ public int compare(ApnSetting apn1, ApnSetting apn2) {
+ if (apn1.apnSetId == preferredApnSetId) return -1;
+ if (apn2.apnSetId == preferredApnSetId) return 1;
+ return 0;
+ }
+ });
+ }
+ return list;
+ }
+
private String apnListToString (ArrayList<ApnSetting> apns) {
StringBuilder result = new StringBuilder();
for (int i = 0, size = apns.size(); i < size; i++) {
@@ -4571,11 +4626,20 @@
if (VDBG_STALL) log("putRecoveryAction: " + action);
}
+ private void broadcastDataStallDetected(int recoveryAction) {
+ Intent intent = new Intent(TelephonyManager.ACTION_DATA_STALL_DETECTED);
+ SubscriptionManager.putPhoneIdAndSubIdExtra(intent, mPhone.getPhoneId());
+ intent.putExtra(TelephonyManager.EXTRA_RECOVERY_ACTION, recoveryAction);
+ mPhone.getContext().sendBroadcast(intent, READ_PHONE_STATE);
+ }
+
private void doRecovery() {
if (getOverallState() == DctConstants.State.CONNECTED) {
// Go through a series of recovery steps, each action transitions to the next action
final int recoveryAction = getRecoveryAction();
TelephonyMetrics.getInstance().writeDataStallEvent(mPhone.getPhoneId(), recoveryAction);
+ broadcastDataStallDetected(recoveryAction);
+
switch (recoveryAction) {
case RecoveryAction.GET_DATA_CALL_LIST:
EventLog.writeEvent(EventLogTags.DATA_STALL_RECOVERY_GET_DATA_CALL_LIST,
diff --git a/src/java/com/android/internal/telephony/euicc/EuiccCardController.java b/src/java/com/android/internal/telephony/euicc/EuiccCardController.java
index d3c59a3..5c5d244 100644
--- a/src/java/com/android/internal/telephony/euicc/EuiccCardController.java
+++ b/src/java/com/android/internal/telephony/euicc/EuiccCardController.java
@@ -220,6 +220,7 @@
@Override
public void onException(Throwable e) {
try {
+ loge("getAllProfiles callback onException: ", e);
callback.onComplete(getResultCode(e), null);
} catch (RemoteException exception) {
loge("getAllProfiles callback failure.", exception);
@@ -258,6 +259,7 @@
@Override
public void onException(Throwable e) {
try {
+ loge("getProfile callback onException: ", e);
callback.onComplete(getResultCode(e), null);
} catch (RemoteException exception) {
loge("getProfile callback failure.", exception);
@@ -296,6 +298,7 @@
@Override
public void onException(Throwable e) {
try {
+ loge("disableProfile callback onException: ", e);
callback.onComplete(getResultCode(e));
} catch (RemoteException exception) {
loge("disableProfile callback failure.", exception);
@@ -338,6 +341,7 @@
@Override
public void onException(Throwable e) {
try {
+ loge("switchToProfile callback onException: ", e);
callback.onComplete(getResultCode(e), profile);
} catch (RemoteException exception) {
loge("switchToProfile callback failure.", exception);
@@ -351,6 +355,7 @@
@Override
public void onException(Throwable e) {
try {
+ loge("getProfile in switchToProfile callback onException: ", e);
callback.onComplete(getResultCode(e), null);
} catch (RemoteException exception) {
loge("switchToProfile callback failure.", exception);
@@ -389,6 +394,7 @@
@Override
public void onException(Throwable e) {
try {
+ loge("setNickname callback onException: ", e);
callback.onComplete(getResultCode(e));
} catch (RemoteException exception) {
loge("setNickname callback failure.", exception);
@@ -417,19 +423,19 @@
AsyncResultCallback<Void> cardCb = new AsyncResultCallback<Void>() {
@Override
public void onResult(Void result) {
- SubscriptionController.getInstance().requestEmbeddedSubscriptionInfoListRefresh(
- () -> {
- try {
- callback.onComplete(EuiccCardManager.RESULT_OK);
- } catch (RemoteException exception) {
- loge("deleteProfile callback failure.", exception);
- }
- });
+ Log.i(TAG, "Request subscription info list refresh after delete.");
+ SubscriptionController.getInstance().requestEmbeddedSubscriptionInfoListRefresh();
+ try {
+ callback.onComplete(EuiccCardManager.RESULT_OK);
+ } catch (RemoteException exception) {
+ loge("deleteProfile callback failure.", exception);
+ }
};
@Override
public void onException(Throwable e) {
try {
+ loge("deleteProfile callback onException: ", e);
callback.onComplete(getResultCode(e));
} catch (RemoteException exception) {
loge("deleteProfile callback failure.", exception);
@@ -458,19 +464,19 @@
AsyncResultCallback<Void> cardCb = new AsyncResultCallback<Void>() {
@Override
public void onResult(Void result) {
- SubscriptionController.getInstance().requestEmbeddedSubscriptionInfoListRefresh(
- () -> {
- try {
- callback.onComplete(EuiccCardManager.RESULT_OK);
- } catch (RemoteException exception) {
- loge("resetMemory callback failure.", exception);
- }
- });
+ Log.i(TAG, "Request subscription info list refresh after reset memory.");
+ SubscriptionController.getInstance().requestEmbeddedSubscriptionInfoListRefresh();
+ try {
+ callback.onComplete(EuiccCardManager.RESULT_OK);
+ } catch (RemoteException exception) {
+ loge("resetMemory callback failure.", exception);
+ }
}
@Override
public void onException(Throwable e) {
try {
+ loge("resetMemory callback onException: ", e);
callback.onComplete(getResultCode(e));
} catch (RemoteException exception) {
loge("resetMemory callback failure.", exception);
@@ -509,6 +515,7 @@
@Override
public void onException(Throwable e) {
try {
+ loge("getDefaultSmdpAddress callback onException: ", e);
callback.onComplete(getResultCode(e), null);
} catch (RemoteException exception) {
loge("getDefaultSmdpAddress callback failure.", exception);
@@ -547,6 +554,7 @@
@Override
public void onException(Throwable e) {
try {
+ loge("getSmdsAddress callback onException: ", e);
callback.onComplete(getResultCode(e), null);
} catch (RemoteException exception) {
loge("getSmdsAddress callback failure.", exception);
@@ -585,6 +593,7 @@
@Override
public void onException(Throwable e) {
try {
+ loge("setDefaultSmdpAddress callback onException: ", e);
callback.onComplete(getResultCode(e));
} catch (RemoteException exception) {
loge("setDefaultSmdpAddress callback failure.", exception);
@@ -624,6 +633,7 @@
@Override
public void onException(Throwable e) {
try {
+ loge("getRulesAuthTable callback onException: ", e);
callback.onComplete(getResultCode(e), null);
} catch (RemoteException exception) {
loge("getRulesAuthTable callback failure.", exception);
@@ -662,6 +672,7 @@
@Override
public void onException(Throwable e) {
try {
+ loge("getEuiccChallenge callback onException: ", e);
callback.onComplete(getResultCode(e), null);
} catch (RemoteException exception) {
loge("getEuiccChallenge callback failure.", exception);
@@ -700,6 +711,7 @@
@Override
public void onException(Throwable e) {
try {
+ loge("getEuiccInfo1 callback onException: ", e);
callback.onComplete(getResultCode(e), null);
} catch (RemoteException exception) {
loge("getEuiccInfo1 callback failure.", exception);
@@ -738,6 +750,7 @@
@Override
public void onException(Throwable e) {
try {
+ loge("getEuiccInfo2 callback onException: ", e);
callback.onComplete(getResultCode(e), null);
} catch (RemoteException exception) {
loge("getEuiccInfo2 callback failure.", exception);
@@ -777,6 +790,7 @@
@Override
public void onException(Throwable e) {
try {
+ loge("authenticateServer callback onException: ", e);
callback.onComplete(getResultCode(e), null);
} catch (RemoteException exception) {
loge("authenticateServer callback failure.", exception);
@@ -817,6 +831,7 @@
@Override
public void onException(Throwable e) {
try {
+ loge("prepareDownload callback onException: ", e);
callback.onComplete(getResultCode(e), null);
} catch (RemoteException exception) {
loge("prepareDownload callback failure.", exception);
@@ -846,19 +861,19 @@
AsyncResultCallback<byte[]> cardCb = new AsyncResultCallback<byte[]>() {
@Override
public void onResult(byte[] result) {
- SubscriptionController.getInstance().requestEmbeddedSubscriptionInfoListRefresh(
- () -> {
- try {
- callback.onComplete(EuiccCardManager.RESULT_OK, result);
- } catch (RemoteException exception) {
- loge("loadBoundProfilePackage callback failure.", exception);
- }
- });
+ Log.i(TAG, "Request subscription info list refresh after install.");
+ SubscriptionController.getInstance().requestEmbeddedSubscriptionInfoListRefresh();
+ try {
+ callback.onComplete(EuiccCardManager.RESULT_OK, result);
+ } catch (RemoteException exception) {
+ loge("loadBoundProfilePackage callback failure.", exception);
+ }
}
@Override
public void onException(Throwable e) {
try {
+ loge("loadBoundProfilePackage callback onException: ", e);
callback.onComplete(getResultCode(e), null);
} catch (RemoteException exception) {
loge("loadBoundProfilePackage callback failure.", exception);
@@ -897,6 +912,7 @@
@Override
public void onException(Throwable e) {
try {
+ loge("cancelSession callback onException: ", e);
callback.onComplete(getResultCode(e), null);
} catch (RemoteException exception) {
loge("cancelSession callback failure.", exception);
@@ -936,6 +952,7 @@
@Override
public void onException(Throwable e) {
try {
+ loge("listNotifications callback onException: ", e);
callback.onComplete(getResultCode(e), null);
} catch (RemoteException exception) {
loge("listNotifications callback failure.", exception);
@@ -975,6 +992,7 @@
@Override
public void onException(Throwable e) {
try {
+ loge("retrieveNotificationList callback onException: ", e);
callback.onComplete(getResultCode(e), null);
} catch (RemoteException exception) {
loge("retrieveNotificationList callback failure.", exception);
@@ -1014,6 +1032,7 @@
@Override
public void onException(Throwable e) {
try {
+ loge("retrieveNotification callback onException: ", e);
callback.onComplete(getResultCode(e), null);
} catch (RemoteException exception) {
loge("retrieveNotification callback failure.", exception);
@@ -1053,6 +1072,7 @@
@Override
public void onException(Throwable e) {
try {
+ loge("removeNotificationFromList callback onException: ", e);
callback.onComplete(getResultCode(e));
} catch (RemoteException exception) {
loge("removeNotificationFromList callback failure.", exception);
diff --git a/src/java/com/android/internal/telephony/euicc/EuiccController.java b/src/java/com/android/internal/telephony/euicc/EuiccController.java
index 8c1b81e..ca36cf0 100644
--- a/src/java/com/android/internal/telephony/euicc/EuiccController.java
+++ b/src/java/com/android/internal/telephony/euicc/EuiccController.java
@@ -24,6 +24,7 @@
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
+import android.content.pm.ComponentInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.os.Binder;
@@ -984,6 +985,10 @@
@VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
public void sendOtaStatusChangedBroadcast() {
Intent intent = new Intent(EuiccManager.ACTION_OTA_STATUS_CHANGED);
+ ComponentInfo bestComponent = mConnector.findBestComponent(mContext.getPackageManager());
+ if (bestComponent != null) {
+ intent.setPackage(bestComponent.packageName);
+ }
mContext.sendBroadcast(intent, permission.WRITE_EMBEDDED_SUBSCRIPTIONS);
}
diff --git a/src/java/com/android/internal/telephony/gsm/GsmSMSDispatcher.java b/src/java/com/android/internal/telephony/gsm/GsmSMSDispatcher.java
index ef43430..99082ee 100644
--- a/src/java/com/android/internal/telephony/gsm/GsmSMSDispatcher.java
+++ b/src/java/com/android/internal/telephony/gsm/GsmSMSDispatcher.java
@@ -16,13 +16,8 @@
package com.android.internal.telephony.gsm;
-import android.app.Activity;
-import android.app.PendingIntent;
-import android.app.PendingIntent.CanceledException;
-import android.content.Intent;
import android.os.AsyncResult;
import android.os.Message;
-import android.provider.Telephony.Sms;
import android.provider.Telephony.Sms.Intents;
import android.telephony.Rlog;
import android.telephony.ServiceState;
@@ -188,6 +183,7 @@
+ " mRetryCount=" + tracker.mRetryCount
+ " mImsRetry=" + tracker.mImsRetry
+ " mMessageRef=" + tracker.mMessageRef
+ + " mUsesImsServiceForIms=" + tracker.mUsesImsServiceForIms
+ " SS=" + mPhone.getServiceState().getState());
int ss = mPhone.getServiceState().getState();
@@ -203,8 +199,11 @@
// sms over gsm is used:
// if sms over IMS is not supported AND
// this is not a retry case after sms over IMS failed
- // indicated by mImsRetry > 0
- if (0 == tracker.mImsRetry && !isIms()) {
+ // indicated by mImsRetry > 0 OR
+ // this tracker uses ImsSmsDispatcher to handle SMS over IMS. This dispatcher has received
+ // this message because the ImsSmsDispatcher has indicated that the message needs to
+ // fall back to sending over CS.
+ if (0 == tracker.mImsRetry && !isIms() || tracker.mUsesImsServiceForIms) {
if (tracker.mRetryCount == 0 && tracker.mExpectMore) {
mCi.sendSMSExpectMore(IccUtils.bytesToHexString(smsc),
IccUtils.bytesToHexString(pdu), reply);
diff --git a/src/java/com/android/internal/telephony/ims/MmTelFeatureCompatAdapter.java b/src/java/com/android/internal/telephony/ims/MmTelFeatureCompatAdapter.java
index 8eec9db..7b0619b 100644
--- a/src/java/com/android/internal/telephony/ims/MmTelFeatureCompatAdapter.java
+++ b/src/java/com/android/internal/telephony/ims/MmTelFeatureCompatAdapter.java
@@ -155,6 +155,10 @@
@Override
public void registrationDisconnected(ImsReasonInfo imsReasonInfo) throws RemoteException {
+ // At de-registration, notify the framework that no IMS capabilities are currently
+ // available.
+ Log.i(TAG, "registrationDisconnected: resetting MMTEL capabilities.");
+ notifyCapabilitiesStatusChanged(new MmTelCapabilities());
// Implemented in the Registration Adapter
}
diff --git a/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java b/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java
index d23aad7..4c858cc 100644
--- a/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java
+++ b/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java
@@ -2884,7 +2884,6 @@
@Override
public void onDeregistered(ImsReasonInfo imsReasonInfo) {
if (DBG) log("onImsDisconnected imsReasonInfo=" + imsReasonInfo);
- resetImsCapabilities();
mPhone.setServiceState(ServiceState.STATE_OUT_OF_SERVICE);
mPhone.setImsRegistered(false);
mPhone.processDisconnectReason(imsReasonInfo);
diff --git a/src/java/com/android/internal/telephony/imsphone/ImsPhoneConnection.java b/src/java/com/android/internal/telephony/imsphone/ImsPhoneConnection.java
index 04ae527..d63b9c2 100644
--- a/src/java/com/android/internal/telephony/imsphone/ImsPhoneConnection.java
+++ b/src/java/com/android/internal/telephony/imsphone/ImsPhoneConnection.java
@@ -996,11 +996,29 @@
}
public void onRttMessageReceived(String message) {
- getOrCreateRttTextHandler().sendToInCall(message);
+ synchronized (this) {
+ if (mRttTextHandler == null) {
+ Rlog.w(LOG_TAG, "onRttMessageReceived: RTT text handler not available."
+ + " Attempting to create one.");
+ if (mRttTextStream == null) {
+ Rlog.e(LOG_TAG, "onRttMessageReceived:"
+ + " Unable to process incoming message. No textstream available");
+ return;
+ }
+ createRttTextHandler();
+ }
+ }
+ mRttTextHandler.sendToInCall(message);
}
public void setCurrentRttTextStream(android.telecom.Connection.RttTextStream rttTextStream) {
- mRttTextStream = rttTextStream;
+ synchronized (this) {
+ mRttTextStream = rttTextStream;
+ if (mRttTextHandler == null && mIsRttEnabledForCall) {
+ Rlog.i(LOG_TAG, "setCurrentRttTextStream: Creating a text handler");
+ createRttTextHandler();
+ }
+ }
}
public boolean hasRttTextStream() {
@@ -1012,20 +1030,24 @@
}
public void startRttTextProcessing() {
- if (mRttTextStream == null) {
- Rlog.w(LOG_TAG, "startRttTextProcessing: no RTT text stream. Ignoring.");
- return;
+ synchronized (this) {
+ if (mRttTextStream == null) {
+ Rlog.w(LOG_TAG, "startRttTextProcessing: no RTT text stream. Ignoring.");
+ return;
+ }
+ if (mRttTextHandler != null) {
+ Rlog.w(LOG_TAG, "startRttTextProcessing: RTT text handler already exists");
+ return;
+ }
+ createRttTextHandler();
}
- getOrCreateRttTextHandler().initialize(mRttTextStream);
}
- private ImsRttTextHandler getOrCreateRttTextHandler() {
- if (mRttTextHandler != null) {
- return mRttTextHandler;
- }
+ // Make sure to synchronize on ImsPhoneConnection.this before calling.
+ private void createRttTextHandler() {
mRttTextHandler = new ImsRttTextHandler(Looper.getMainLooper(),
(message) -> getImsCall().sendRttMessage(message));
- return mRttTextHandler;
+ mRttTextHandler.initialize(mRttTextStream);
}
/**
diff --git a/src/java/com/android/internal/telephony/uicc/UiccCard.java b/src/java/com/android/internal/telephony/uicc/UiccCard.java
index a59e186..e55170a 100644
--- a/src/java/com/android/internal/telephony/uicc/UiccCard.java
+++ b/src/java/com/android/internal/telephony/uicc/UiccCard.java
@@ -46,7 +46,9 @@
public static final String EXTRA_ICC_CARD_ADDED =
"com.android.internal.telephony.uicc.ICC_CARD_ADDED";
- private final Object mLock = new Object();
+ // The lock object is created by UiccSlot that owns this UiccCard - this is to share the lock
+ // between UiccSlot, UiccCard and UiccProfile for now.
+ private final Object mLock;
private CardState mCardState;
private String mIccid;
protected String mCardId;
@@ -55,10 +57,11 @@
private CommandsInterface mCi;
private final int mPhoneId;
- public UiccCard(Context c, CommandsInterface ci, IccCardStatus ics, int phoneId) {
+ public UiccCard(Context c, CommandsInterface ci, IccCardStatus ics, int phoneId, Object lock) {
if (DBG) log("Creating");
mCardState = ics.mCardState;
mPhoneId = phoneId;
+ mLock = lock;
update(c, ci, ics);
}
@@ -83,7 +86,7 @@
if (mCardState != CardState.CARDSTATE_ABSENT) {
if (mUiccProfile == null) {
mUiccProfile = TelephonyComponentFactory.getInstance().makeUiccProfile(
- mContext, mCi, ics, mPhoneId, this);
+ mContext, mCi, ics, mPhoneId, this, mLock);
} else {
mUiccProfile.update(mContext, mCi, ics);
}
diff --git a/src/java/com/android/internal/telephony/uicc/UiccProfile.java b/src/java/com/android/internal/telephony/uicc/UiccProfile.java
index 201c6ff..e80ab1d 100644
--- a/src/java/com/android/internal/telephony/uicc/UiccProfile.java
+++ b/src/java/com/android/internal/telephony/uicc/UiccProfile.java
@@ -89,7 +89,9 @@
private static final String OPERATOR_BRAND_OVERRIDE_PREFIX = "operator_branding_";
- private final Object mLock = new Object();
+ // The lock object is created by UiccSlot that owns the UiccCard that owns this UiccProfile.
+ // This is to share the lock between UiccSlot, UiccCard and UiccProfile for now.
+ private final Object mLock;
private PinState mUniversalPinState;
private int mGsmUmtsSubscriptionAppIndex;
private int mCdmaSubscriptionAppIndex;
@@ -98,7 +100,7 @@
new UiccCardApplication[IccCardStatus.CARD_MAX_APPS];
private Context mContext;
private CommandsInterface mCi;
- private UiccCard mUiccCard; //parent
+ private final UiccCard mUiccCard; //parent
private CatService mCatService;
private UiccCarrierPrivilegeRules mCarrierPrivilegeRules;
private boolean mDisposed = false;
@@ -226,8 +228,9 @@
};
public UiccProfile(Context c, CommandsInterface ci, IccCardStatus ics, int phoneId,
- UiccCard uiccCard) {
+ UiccCard uiccCard, Object lock) {
if (DBG) log("Creating profile");
+ mLock = lock;
mUiccCard = uiccCard;
mPhoneId = phoneId;
// set current app type based on phone type - do this before calling update() as that
@@ -254,19 +257,20 @@
* Dispose the UiccProfile.
*/
public void dispose() {
- synchronized (mLock) {
- if (DBG) log("Disposing profile");
+ if (DBG) log("Disposing profile");
+ // mUiccCard is outside of mLock in order to prevent deadlocking. This is safe because
+ // EuiccCard#unregisterForEidReady handles its own lock
+ if (mUiccCard instanceof EuiccCard) {
+ ((EuiccCard) mUiccCard).unregisterForEidReady(mHandler);
+ }
+ synchronized (mLock) {
unregisterAllAppEvents();
unregisterCurrAppEvents();
InstallCarrierAppUtils.hideAllNotifications(mContext);
InstallCarrierAppUtils.unregisterPackageInstallReceiver(mContext);
- if (mUiccCard instanceof EuiccCard) {
- ((EuiccCard) mUiccCard).unregisterForEidReady(mHandler);
- }
-
mCi.unregisterForOffOrNotAvailable(mHandler);
mContext.unregisterReceiver(mReceiver);
@@ -859,15 +863,14 @@
@Override
public boolean hasIccCard() {
- synchronized (mLock) {
- if (mUiccCard != null && mUiccCard.getCardState()
- != IccCardStatus.CardState.CARDSTATE_ABSENT) {
- return true;
- }
- loge("hasIccCard: UiccProfile is not null but UiccCard is null or card state is "
- + "ABSENT");
- return false;
+ // mUiccCard is initialized in constructor, so won't be null
+ if (mUiccCard.getCardState()
+ != IccCardStatus.CardState.CARDSTATE_ABSENT) {
+ return true;
}
+ loge("hasIccCard: UiccProfile is not null but UiccCard is null or card state is "
+ + "ABSENT");
+ return false;
}
/**
@@ -1524,6 +1527,15 @@
}
/**
+ * Reloads carrier privileges as if a change were just detected. Useful to force a profile
+ * refresh without having to physically insert or remove a SIM card.
+ */
+ @VisibleForTesting
+ public void refresh() {
+ mHandler.sendMessage(mHandler.obtainMessage(EVENT_CARRIER_PRIVILEGES_LOADED));
+ }
+
+ /**
* Dump
*/
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
diff --git a/src/java/com/android/internal/telephony/uicc/UiccSlot.java b/src/java/com/android/internal/telephony/uicc/UiccSlot.java
index 5a6624b..25ef637 100644
--- a/src/java/com/android/internal/telephony/uicc/UiccSlot.java
+++ b/src/java/com/android/internal/telephony/uicc/UiccSlot.java
@@ -91,22 +91,8 @@
log("update: radioState=" + radioState + " mLastRadioState=" + mLastRadioState);
}
- if (oldState != CardState.CARDSTATE_ABSENT
- && mCardState == CardState.CARDSTATE_ABSENT) {
- // No notifications while radio is off or we just powering up
- if (radioState == RadioState.RADIO_ON && mLastRadioState == RadioState.RADIO_ON) {
- if (DBG) log("update: notify card removed");
- sendMessage(obtainMessage(EVENT_CARD_REMOVED, null));
- }
-
- UiccController.updateInternalIccState(
- IccCardConstants.INTENT_VALUE_ICC_ABSENT, null, mPhoneId);
-
- // no card present in the slot now; dispose card and make mUiccCard null
- if (mUiccCard != null) {
- mUiccCard.dispose();
- nullifyUiccCard(false /* sim state is not unknown */);
- }
+ if (absentStateUpdateNeeded(oldState)) {
+ updateCardStateAbsent();
// Because mUiccCard may be updated in both IccCardStatus and IccSlotStatus, we need to
// create a new UiccCard instance in two scenarios:
// 1. mCardState is changing from ABSENT to non ABSENT.
@@ -126,9 +112,9 @@
}
if (!mIsEuicc) {
- mUiccCard = new UiccCard(mContext, mCi, ics, mPhoneId);
+ mUiccCard = new UiccCard(mContext, mCi, ics, mPhoneId, mLock);
} else {
- mUiccCard = new EuiccCard(mContext, mCi, ics, phoneId);
+ mUiccCard = new EuiccCard(mContext, mCi, ics, phoneId, mLock);
}
} else {
if (mUiccCard != null) {
@@ -145,8 +131,14 @@
public void update(CommandsInterface ci, IccSlotStatus iss) {
if (DBG) log("slotStatus update: " + iss.toString());
synchronized (mLock) {
+ CardState oldState = mCardState;
mCi = ci;
+ parseAtr(iss.atr);
+ mCardState = iss.cardState;
+ mIccId = iss.iccid;
if (iss.slotState == IccSlotStatus.SlotState.SLOTSTATE_INACTIVE) {
+ // TODO: (b/79432584) evaluate whether should broadcast card state change
+ // even if it's inactive.
if (mActive) {
mActive = false;
mLastRadioState = RadioState.RADIO_UNAVAILABLE;
@@ -154,21 +146,44 @@
if (mUiccCard != null) mUiccCard.dispose();
nullifyUiccCard(true /* sim state is unknown */);
}
- parseAtr(iss.atr);
- mCardState = iss.cardState;
- mIccId = iss.iccid;
- } else if (!mActive && iss.slotState == IccSlotStatus.SlotState.SLOTSTATE_ACTIVE) {
+ } else {
mActive = true;
- parseAtr(iss.atr);
- // todo - ignoring these fields for now; relying on sim state changed to update
- // these
- // iss.cardState;
- // iss.iccid;
- // iss.logicalSlotIndex;
+ mPhoneId = iss.logicalSlotIndex;
+ if (absentStateUpdateNeeded(oldState)) {
+ updateCardStateAbsent();
+ }
+ // TODO: (b/79432584) Create UiccCard or EuiccCard object here.
+ // Right now It's OK not creating it because Card status update will do it.
+ // But we should really make them symmetric.
}
}
}
+ private boolean absentStateUpdateNeeded(CardState oldState) {
+ return (oldState != CardState.CARDSTATE_ABSENT || mUiccCard != null)
+ && mCardState == CardState.CARDSTATE_ABSENT;
+ }
+
+ private void updateCardStateAbsent() {
+ RadioState radioState =
+ (mCi == null) ? RadioState.RADIO_UNAVAILABLE : mCi.getRadioState();
+ // No notifications while radio is off or we just powering up
+ if (radioState == RadioState.RADIO_ON && mLastRadioState == RadioState.RADIO_ON) {
+ if (DBG) log("update: notify card removed");
+ sendMessage(obtainMessage(EVENT_CARD_REMOVED, null));
+ }
+
+ UiccController.updateInternalIccState(
+ IccCardConstants.INTENT_VALUE_ICC_ABSENT, null, mPhoneId);
+
+ // no card present in the slot now; dispose card and make mUiccCard null
+ if (mUiccCard != null) {
+ mUiccCard.dispose();
+ }
+ nullifyUiccCard(false /* sim state is not unknown */);
+ mLastRadioState = radioState;
+ }
+
// whenever we set mUiccCard to null, we lose the ability to differentiate between absent and
// unknown states. To mitigate this, we will us mStateIsUnknown to keep track. The sim is only
// unknown if we haven't heard from the radio or if the radio has become unavailable.
@@ -178,7 +193,7 @@
}
public boolean isStateUnknown() {
- return mStateIsUnknown;
+ return (mCardState == null || mCardState == CardState.CARDSTATE_ABSENT) && mStateIsUnknown;
}
private void checkIsEuiccSupported() {
diff --git a/src/java/com/android/internal/telephony/uicc/euicc/EuiccCard.java b/src/java/com/android/internal/telephony/uicc/euicc/EuiccCard.java
index 3ebfec2..b8b2818 100644
--- a/src/java/com/android/internal/telephony/uicc/euicc/EuiccCard.java
+++ b/src/java/com/android/internal/telephony/uicc/euicc/EuiccCard.java
@@ -116,8 +116,8 @@
private EuiccSpecVersion mSpecVersion;
private volatile String mEid;
- public EuiccCard(Context c, CommandsInterface ci, IccCardStatus ics, int phoneId) {
- super(c, ci, ics, phoneId);
+ public EuiccCard(Context c, CommandsInterface ci, IccCardStatus ics, int phoneId, Object lock) {
+ super(c, ci, ics, phoneId, lock);
// TODO: Set supportExtendedApdu based on ATR.
mApduSender = new ApduSender(ci, ISD_R_AID, false /* supportExtendedApdu */);
@@ -162,7 +162,12 @@
@Override
public void onException(Throwable e) {
- // Not notifying registrants if getting eid fails.
+ // Still notifying registrants even getting eid fails.
+ if (mEidReadyRegistrants != null) {
+ mEidReadyRegistrants.notifyRegistrants(new AsyncResult(null, null, null));
+ }
+ mEid = "";
+ mCardId = "";
Rlog.e(LOG_TAG, "Failed loading eid", e);
}
};
diff --git a/tests/telephonytests/src/com/android/internal/telephony/CarrierServiceStateTrackerTest.java b/tests/telephonytests/src/com/android/internal/telephony/CarrierServiceStateTrackerTest.java
index e81c9f4..529a798 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/CarrierServiceStateTrackerTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/CarrierServiceStateTrackerTest.java
@@ -16,7 +16,10 @@
package com.android.internal.telephony;
+import static com.android.internal.telephony.TelephonyTestUtils.waitForMs;
+
import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.atLeast;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.eq;
import static org.mockito.Mockito.isA;
@@ -27,18 +30,26 @@
import android.app.Notification;
import android.app.NotificationManager;
import android.content.Context;
+import android.content.Intent;
import android.content.pm.ApplicationInfo;
-import android.content.res.Resources;
+import android.database.ContentObserver;
+import android.net.Uri;
import android.os.HandlerThread;
import android.os.Message;
+import android.os.PersistableBundle;
+import android.provider.Settings;
+import android.telephony.CarrierConfigManager;
+import android.telephony.ServiceState;
+import android.test.mock.MockContentResolver;
import android.test.suitebuilder.annotation.SmallTest;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
-import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
+import java.util.Map;
+
/**
* Unit tests for {@link com.android.internal.telephony.CarrierServiceStateTracker}.
*/
@@ -46,25 +57,34 @@
public static final String LOG_TAG = "CSST";
public static final int TEST_TIMEOUT = 5000;
+ private CarrierServiceStateTracker mSpyCarrierSST;
private CarrierServiceStateTracker mCarrierSST;
private CarrierServiceStateTrackerTestHandler mCarrierServiceStateTrackerTestHandler;
- private CarrierServiceStateTracker.PrefNetworkNotification mPrefNetworkNotification;
- private CarrierServiceStateTracker.EmergencyNetworkNotification mEmergencyNetworkNotification;
+ private FakeContentResolver mFakeContentResolver;
- @Mock Context mContext;
- @Mock ServiceStateTracker mServiceStateTracker;
- @Mock NotificationManager mNotificationManager;
- @Mock Resources mResources;
+ NotificationManager mNotificationManager;
+ PersistableBundle mBundle;
+
+ private class FakeContentResolver extends MockContentResolver {
+ @Override
+ public void notifyChange(Uri uri, ContentObserver observer, boolean syncToNetwork) {
+ super.notifyChange(uri, observer, syncToNetwork);
+ logd("onChanged(uri=" + uri + ")" + observer);
+ if (observer != null) {
+ observer.dispatchChange(false, uri);
+ }
+ }
+ }
private class CarrierServiceStateTrackerTestHandler extends HandlerThread {
-
private CarrierServiceStateTrackerTestHandler(String name) {
super(name);
}
@Override
public void onLooperPrepared() {
- mCarrierSST = spy(new CarrierServiceStateTracker(mPhone, mServiceStateTracker));
+ mCarrierSST = new CarrierServiceStateTracker(mPhone, mSST);
+ mSpyCarrierSST = spy(mCarrierSST);
setReady(true);
}
}
@@ -74,15 +94,31 @@
MockitoAnnotations.initMocks(this);
logd(LOG_TAG + "Setup!");
super.setUp(getClass().getSimpleName());
+ mBundle = mContextFixture.getCarrierConfigBundle();
+ when(mPhone.getSubId()).thenReturn(1);
mCarrierServiceStateTrackerTestHandler =
new CarrierServiceStateTrackerTestHandler(getClass().getSimpleName());
mCarrierServiceStateTrackerTestHandler.start();
- when(mContext.getResources()).thenReturn(mResources);
- when(mContext.getPackageManager()).thenReturn(mPackageManager);
- when(mContext.getApplicationInfo()).thenReturn(new ApplicationInfo());
+ mFakeContentResolver = new CarrierServiceStateTrackerTest.FakeContentResolver();
+
+ when(mPhone.getContext().getContentResolver()).thenReturn(mFakeContentResolver);
+
+ doReturn(new ApplicationInfo()).when(mContext).getApplicationInfo();
+
+ mNotificationManager = (NotificationManager) mContext.getSystemService(
+ Context.NOTIFICATION_SERVICE);
+
+ setDefaultValues();
waitUntilReady();
}
+ private void setDefaultValues() {
+ mBundle.putInt(CarrierConfigManager.KEY_PREF_NETWORK_NOTIFICATION_DELAY_INT,
+ 0);
+ mBundle.putInt(CarrierConfigManager.KEY_EMERGENCY_NOTIFICATION_DELAY_INT,
+ 0);
+ }
+
@After
public void tearDown() throws Exception {
mCarrierServiceStateTrackerTestHandler.quit();
@@ -93,12 +129,12 @@
@SmallTest
public void testCancelBothNotifications() {
logd(LOG_TAG + ":testCancelBothNotifications()");
- Message notificationMsg = mCarrierSST.obtainMessage(
+ Message notificationMsg = mSpyCarrierSST.obtainMessage(
CarrierServiceStateTracker.CARRIER_EVENT_DATA_REGISTRATION, null);
- doReturn(false).when(mCarrierSST).evaluateSendingMessage(any());
- doReturn(mNotificationManager).when(mCarrierSST).getNotificationManager(any());
- mCarrierSST.handleMessage(notificationMsg);
- waitForHandlerAction(mCarrierSST, TEST_TIMEOUT);
+ doReturn(false).when(mSpyCarrierSST).evaluateSendingMessage(any());
+ doReturn(mNotificationManager).when(mSpyCarrierSST).getNotificationManager(any());
+ mSpyCarrierSST.handleMessage(notificationMsg);
+ waitForHandlerAction(mSpyCarrierSST, TEST_TIMEOUT);
verify(mNotificationManager).cancel(
CarrierServiceStateTracker.NOTIFICATION_EMERGENCY_NETWORK);
verify(mNotificationManager).cancel(
@@ -110,18 +146,58 @@
public void testSendBothNotifications() {
logd(LOG_TAG + ":testSendBothNotifications()");
Notification.Builder mNotificationBuilder = new Notification.Builder(mContext);
- Message notificationMsg = mCarrierSST.obtainMessage(
+ Message notificationMsg = mSpyCarrierSST.obtainMessage(
CarrierServiceStateTracker.CARRIER_EVENT_DATA_DEREGISTRATION, null);
- doReturn(true).when(mCarrierSST).evaluateSendingMessage(any());
- doReturn(false).when(mCarrierSST).isRadioOffOrAirplaneMode();
- doReturn(0).when(mCarrierSST).getDelay(any());
- doReturn(mNotificationBuilder).when(mCarrierSST).getNotificationBuilder(any());
- doReturn(mNotificationManager).when(mCarrierSST).getNotificationManager(any());
- mCarrierSST.handleMessage(notificationMsg);
- waitForHandlerAction(mCarrierSST, TEST_TIMEOUT);
+ doReturn(true).when(mSpyCarrierSST).evaluateSendingMessage(any());
+ doReturn(false).when(mSpyCarrierSST).isRadioOffOrAirplaneMode();
+ doReturn(0).when(mSpyCarrierSST).getDelay(any());
+ doReturn(mNotificationBuilder).when(mSpyCarrierSST).getNotificationBuilder(any());
+ doReturn(mNotificationManager).when(mSpyCarrierSST).getNotificationManager(any());
+ mSpyCarrierSST.handleMessage(notificationMsg);
+ waitForHandlerAction(mSpyCarrierSST, TEST_TIMEOUT);
verify(mNotificationManager).notify(
eq(CarrierServiceStateTracker.NOTIFICATION_PREF_NETWORK), isA(Notification.class));
verify(mNotificationManager).notify(
eq(CarrierServiceStateTracker.NOTIFICATION_EMERGENCY_NETWORK), any());
}
+
+ @Test
+ @SmallTest
+ public void testSendPrefNetworkNotification() {
+ logd(LOG_TAG + ":testSendPrefNetworkNotification()");
+ Intent intent = new Intent().setAction(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED);
+ mContext.sendBroadcast(intent);
+ waitForMs(300);
+
+ Map<Integer, CarrierServiceStateTracker.NotificationType> notificationTypeMap =
+ mCarrierSST.getNotificationTypeMap();
+ CarrierServiceStateTracker.NotificationType prefNetworkNotification =
+ notificationTypeMap.get(CarrierServiceStateTracker.NOTIFICATION_PREF_NETWORK);
+ CarrierServiceStateTracker.NotificationType spyPrefNetworkNotification = spy(
+ prefNetworkNotification);
+ notificationTypeMap.put(CarrierServiceStateTracker.NOTIFICATION_PREF_NETWORK,
+ spyPrefNetworkNotification);
+ Notification.Builder mNotificationBuilder = new Notification.Builder(mContext);
+ doReturn(ServiceState.STATE_OUT_OF_SERVICE).when(mSST.mSS).getVoiceRegState();
+ doReturn(ServiceState.STATE_OUT_OF_SERVICE).when(mSST.mSS).getDataRegState();
+ doReturn(true).when(mSST).isRadioOn();
+ doReturn(mNotificationBuilder).when(spyPrefNetworkNotification).getNotificationBuilder();
+
+ String prefNetworkMode = Settings.Global.PREFERRED_NETWORK_MODE + mPhone.getSubId();
+ Settings.Global.putInt(mFakeContentResolver, prefNetworkMode,
+ RILConstants.NETWORK_MODE_LTE_CDMA_EVDO);
+ mFakeContentResolver.notifyChange(
+ Settings.Global.getUriFor(prefNetworkMode), mSpyCarrierSST.getContentObserver());
+ waitForMs(500);
+ verify(mNotificationManager).notify(
+ eq(CarrierServiceStateTracker.NOTIFICATION_PREF_NETWORK), isA(Notification.class));
+
+ Settings.Global.putInt(mFakeContentResolver, prefNetworkMode,
+ RILConstants.NETWORK_MODE_LTE_CDMA_EVDO_GSM_WCDMA);
+ mFakeContentResolver.notifyChange(
+ Settings.Global.getUriFor(prefNetworkMode), mSpyCarrierSST.getContentObserver());
+ waitForMs(500);
+ verify(mNotificationManager, atLeast(1)).cancel(
+ CarrierServiceStateTracker.NOTIFICATION_PREF_NETWORK);
+ }
}
diff --git a/tests/telephonytests/src/com/android/internal/telephony/GsmCdmaPhoneTest.java b/tests/telephonytests/src/com/android/internal/telephony/GsmCdmaPhoneTest.java
index 1fc47e3..fa8bec3 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/GsmCdmaPhoneTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/GsmCdmaPhoneTest.java
@@ -32,6 +32,7 @@
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.eq;
import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
@@ -61,6 +62,7 @@
import com.android.internal.telephony.uicc.IccCardApplicationStatus;
import com.android.internal.telephony.uicc.IccException;
import com.android.internal.telephony.uicc.IccRecords;
+import com.android.internal.telephony.uicc.UiccController;
import com.android.internal.telephony.uicc.UiccProfile;
import com.android.internal.telephony.uicc.UiccSlot;
@@ -70,6 +72,7 @@
import org.junit.Test;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
+import org.mockito.Mockito;
import java.util.List;
@@ -179,6 +182,57 @@
@Test
@SmallTest
+ public void testGetSubscriberIdForGsmPhone() {
+ final String subscriberId = "123456789";
+ IccRecords iccRecords = Mockito.mock(IccRecords.class);
+ doReturn(subscriberId).when(iccRecords).getIMSI();
+ doReturn(iccRecords).when(mUiccController)
+ .getIccRecords(anyInt() /* phoneId */, eq(UiccController.APP_FAM_3GPP));
+
+ // Ensure the phone type is GSM
+ GsmCdmaPhone spyPhone = spy(mPhoneUT);
+ doReturn(false).when(spyPhone).isPhoneTypeCdma();
+ doReturn(false).when(spyPhone).isPhoneTypeCdmaLte();
+ doReturn(true).when(spyPhone).isPhoneTypeGsm();
+
+ assertEquals(subscriberId, spyPhone.getSubscriberId());
+ }
+
+ @Test
+ @SmallTest
+ public void testGetSubscriberIdForCdmaLtePhone() {
+ final String subscriberId = "abcdefghijk";
+ IccRecords iccRecords = Mockito.mock(IccRecords.class);
+ doReturn(subscriberId).when(iccRecords).getIMSI();
+ doReturn(iccRecords).when(mUiccController)
+ .getIccRecords(anyInt() /* phoneId */, eq(UiccController.APP_FAM_3GPP));
+
+ // Ensure the phone type is CdmaLte
+ GsmCdmaPhone spyPhone = spy(mPhoneUT);
+ doReturn(false).when(spyPhone).isPhoneTypeCdma();
+ doReturn(true).when(spyPhone).isPhoneTypeCdmaLte();
+ doReturn(false).when(spyPhone).isPhoneTypeGsm();
+
+ assertEquals(subscriberId, spyPhone.getSubscriberId());
+ }
+
+ @Test
+ @SmallTest
+ public void testGetSubscriberIdForCdmaPhone() {
+ final String subscriberId = "987654321";
+ doReturn(subscriberId).when(mSST).getImsi();
+
+ // Ensure the phone type is GSM
+ GsmCdmaPhone spyPhone = spy(mPhoneUT);
+ doReturn(true).when(spyPhone).isPhoneTypeCdma();
+ doReturn(false).when(spyPhone).isPhoneTypeCdmaLte();
+ doReturn(false).when(spyPhone).isPhoneTypeGsm();
+
+ assertEquals(subscriberId, spyPhone.getSubscriberId());
+ }
+
+ @Test
+ @SmallTest
public void testGetCellLocation() {
// GSM
CellLocation cellLocation = new GsmCellLocation();
diff --git a/tests/telephonytests/src/com/android/internal/telephony/LocaleTrackerTest.java b/tests/telephonytests/src/com/android/internal/telephony/LocaleTrackerTest.java
new file mode 100644
index 0000000..02f78ab
--- /dev/null
+++ b/tests/telephonytests/src/com/android/internal/telephony/LocaleTrackerTest.java
@@ -0,0 +1,184 @@
+/*
+ * Copyright 2018 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.internal.telephony;
+
+import static com.android.internal.telephony.TelephonyTestUtils.waitForMs;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Matchers.isNull;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
+import android.content.Context;
+import android.net.wifi.WifiManager;
+import android.os.AsyncResult;
+import android.os.HandlerThread;
+import android.telephony.CellIdentityGsm;
+import android.telephony.CellInfoGsm;
+import android.telephony.ServiceState;
+import android.test.suitebuilder.annotation.SmallTest;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.util.Arrays;
+
+public class LocaleTrackerTest extends TelephonyTest {
+
+ private static final String US_MCC = "310";
+ private static final String FAKE_MNC = "123";
+ private static final String US_COUNTRY_CODE = "us";
+ private static final String COUNTRY_CODE_UNAVAILABLE = "";
+
+ private LocaleTracker mLocaleTracker;
+ private LocaleTrackerTestHandler mLocaleTrackerTestHandler;
+
+ private CellInfoGsm mCellInfo;
+ private WifiManager mWifiManager;
+
+ private class LocaleTrackerTestHandler extends HandlerThread {
+
+ private LocaleTrackerTestHandler(String name) {
+ super(name);
+ }
+
+ @Override
+ public void onLooperPrepared() {
+ mLocaleTracker = new LocaleTracker(mPhone, this.getLooper());
+ setReady(true);
+ }
+ }
+
+ @Before
+ public void setUp() throws Exception {
+ logd("LocaleTrackerTest +Setup!");
+ super.setUp(getClass().getSimpleName());
+
+ // This is a workaround to bypass setting system properties, which causes access violation.
+ doReturn(-1).when(mPhone).getPhoneId();
+ mWifiManager = (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE);
+
+ mCellInfo = new CellInfoGsm();
+ mCellInfo.setCellIdentity(new CellIdentityGsm(Integer.parseInt(US_MCC),
+ Integer.parseInt(FAKE_MNC), 0, 0));
+ doReturn(Arrays.asList(mCellInfo)).when(mPhone).getAllCellInfo(isNull());
+ doReturn(true).when(mSST).getDesiredPowerState();
+
+ mLocaleTrackerTestHandler = new LocaleTrackerTestHandler(getClass().getSimpleName());
+ mLocaleTrackerTestHandler.start();
+ waitUntilReady();
+ logd("LocaleTrackerTest -Setup!");
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ mLocaleTracker.removeCallbacksAndMessages(null);
+ mLocaleTrackerTestHandler.quit();
+ super.tearDown();
+ }
+
+ @Test
+ @SmallTest
+ public void testUpdateOperatorNumericSync() throws Exception {
+ mLocaleTracker.updateOperatorNumericSync(US_MCC + FAKE_MNC);
+ assertEquals(US_COUNTRY_CODE, mLocaleTracker.getCurrentCountry());
+ verify(mWifiManager).setCountryCode(US_COUNTRY_CODE);
+ }
+
+ @Test
+ @SmallTest
+ public void testUpdateOperatorNumericAsync() throws Exception {
+ mLocaleTracker.updateOperatorNumericAsync(US_MCC + FAKE_MNC);
+ waitForMs(100);
+ assertEquals(US_COUNTRY_CODE, mLocaleTracker.getCurrentCountry());
+ verify(mWifiManager).setCountryCode(US_COUNTRY_CODE);
+ }
+
+ @Test
+ @SmallTest
+ public void testNoSim() throws Exception {
+ mLocaleTracker.updateOperatorNumericAsync("");
+ waitForHandlerAction(mLocaleTracker, 100);
+ assertEquals(US_COUNTRY_CODE, mLocaleTracker.getCurrentCountry());
+ verify(mWifiManager).setCountryCode(US_COUNTRY_CODE);
+ }
+
+ @Test
+ @SmallTest
+ public void testBootupInAirplaneModeOn() throws Exception {
+ doReturn(false).when(mSST).getDesiredPowerState();
+ mLocaleTracker.updateOperatorNumericAsync("");
+ waitForHandlerAction(mLocaleTracker, 100);
+ assertEquals(COUNTRY_CODE_UNAVAILABLE, mLocaleTracker.getCurrentCountry());
+ verify(mWifiManager).setCountryCode(COUNTRY_CODE_UNAVAILABLE);
+ }
+
+ @Test
+ @SmallTest
+ public void testTogglingAirplaneMode() throws Exception {
+ mLocaleTracker.updateOperatorNumericSync(US_MCC + FAKE_MNC);
+ assertEquals(US_COUNTRY_CODE, mLocaleTracker.getCurrentCountry());
+ verify(mWifiManager).setCountryCode(US_COUNTRY_CODE);
+
+ doReturn(false).when(mSST).getDesiredPowerState();
+ mLocaleTracker.updateOperatorNumericAsync("");
+ waitForHandlerAction(mLocaleTracker, 100);
+ assertEquals(COUNTRY_CODE_UNAVAILABLE, mLocaleTracker.getCurrentCountry());
+ verify(mWifiManager).setCountryCode(COUNTRY_CODE_UNAVAILABLE);
+
+ doReturn(true).when(mSST).getDesiredPowerState();
+ mLocaleTracker.updateOperatorNumericSync(US_MCC + FAKE_MNC);
+ assertEquals(US_COUNTRY_CODE, mLocaleTracker.getCurrentCountry());
+ verify(mWifiManager, times(2)).setCountryCode(US_COUNTRY_CODE);
+ }
+
+ @Test
+ @SmallTest
+ public void testCellInfoUnavailableRetry() throws Exception {
+ doReturn(null).when(mPhone).getAllCellInfo(isNull());
+ mLocaleTracker.updateOperatorNumericAsync("");
+ waitForHandlerAction(mLocaleTracker, 100);
+ assertEquals(COUNTRY_CODE_UNAVAILABLE, mLocaleTracker.getCurrentCountry());
+ verify(mWifiManager).setCountryCode(COUNTRY_CODE_UNAVAILABLE);
+
+ doReturn(Arrays.asList(mCellInfo)).when(mPhone).getAllCellInfo(isNull());
+ waitForHandlerActionDelayed(mLocaleTracker, 100, 2500);
+ assertEquals(US_COUNTRY_CODE, mLocaleTracker.getCurrentCountry());
+ verify(mWifiManager).setCountryCode(US_COUNTRY_CODE);
+ }
+
+ @Test
+ @SmallTest
+ public void testOutOfAirplaneMode() throws Exception {
+ doReturn(null).when(mPhone).getAllCellInfo(isNull());
+ mLocaleTracker.updateOperatorNumericAsync("");
+ waitForHandlerAction(mLocaleTracker, 100);
+ assertEquals(COUNTRY_CODE_UNAVAILABLE, mLocaleTracker.getCurrentCountry());
+ verify(mWifiManager).setCountryCode(COUNTRY_CODE_UNAVAILABLE);
+
+ doReturn(Arrays.asList(mCellInfo)).when(mPhone).getAllCellInfo(isNull());
+ ServiceState ss = new ServiceState();
+ ss.setState(ServiceState.STATE_IN_SERVICE);
+ AsyncResult ar = new AsyncResult(null, ss, null);
+ mLocaleTracker.sendMessage(mLocaleTracker.obtainMessage(3, ar));
+ waitForHandlerAction(mLocaleTracker, 100);
+ assertEquals(US_COUNTRY_CODE, mLocaleTracker.getCurrentCountry());
+ verify(mWifiManager).setCountryCode(US_COUNTRY_CODE);
+ }
+}
diff --git a/tests/telephonytests/src/com/android/internal/telephony/RILTest.java b/tests/telephonytests/src/com/android/internal/telephony/RILTest.java
index b45c62f..f2afc96 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/RILTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/RILTest.java
@@ -57,6 +57,7 @@
import static com.android.internal.telephony.RILConstants.RIL_REQUEST_SEND_DEVICE_STATE;
import static com.android.internal.telephony.RILConstants.RIL_REQUEST_SEND_SMS;
import static com.android.internal.telephony.RILConstants.RIL_REQUEST_SEND_SMS_EXPECT_MORE;
+import static com.android.internal.telephony.RILConstants.RIL_REQUEST_SETUP_DATA_CALL;
import static com.android.internal.telephony.RILConstants.RIL_REQUEST_SET_INITIAL_ATTACH_APN;
import static com.android.internal.telephony.RILConstants.RIL_REQUEST_SET_SIM_CARD_POWER;
import static com.android.internal.telephony.RILConstants.RIL_REQUEST_SET_SMSC_ADDRESS;
@@ -110,6 +111,7 @@
import android.os.PowerManager;
import android.os.WorkSource;
import android.support.test.filters.FlakyTest;
+import android.telephony.AccessNetworkConstants;
import android.telephony.CellIdentityCdma;
import android.telephony.CellIdentityGsm;
import android.telephony.CellIdentityLte;
@@ -204,6 +206,25 @@
private static final int TYPE_LTE = 3;
private static final int TYPE_WCDMA = 4;
+ private static final int PROFILE_ID = 0;
+ private static final String APN = "apn";
+ private static final String PROTOCOL = "IPV6";
+ private static final int AUTH_TYPE = 0;
+ private static final String USER_NAME = "username";
+ private static final String PASSWORD = "password";
+ private static final int TYPE = 0;
+ private static final int MAX_CONNS_TIME = 1;
+ private static final int MAX_CONNS = 3;
+ private static final int WAIT_TIME = 10;
+ private static final boolean APN_ENABLED = true;
+ private static final int SUPPORTED_APNT_YPES_BITMAP = 123456;
+ private static final String ROAMING_PROTOCOL = "IPV6";
+ private static final int BEARER_BITMAP = 123123;
+ private static final int MTU = 1234;
+ private static final String MVNO_TYPE = "";
+ private static final String MVNO_MATCH_DATA = "";
+ private static final boolean MODEM_COGNITIVE = true;
+
private class RILTestHandler extends HandlerThread {
RILTestHandler(String name) {
@@ -247,7 +268,8 @@
}
@Before
- public void setUp() {
+ public void setUp() throws Exception {
+ super.setUp(RILTest.class.getSimpleName());
MockitoAnnotations.initMocks(this);
mTestHandler = new RILTestHandler(getClass().getSimpleName());
mTestHandler.start();
@@ -257,6 +279,7 @@
@After
public void tearDown() throws Exception {
mTestHandler.quit();
+ super.tearDown();
}
@FlakyTest
@@ -1643,4 +1666,37 @@
assertEquals(getTdScdmaSignalStrength_1_0(-1), getTdScdmaSignalStrength_1_2(255));
}
+ @Test
+ public void testSetupDataCall() throws Exception {
+
+ DataProfile dp = new DataProfile(PROFILE_ID, APN, PROTOCOL, AUTH_TYPE, USER_NAME, PASSWORD,
+ TYPE, MAX_CONNS_TIME, MAX_CONNS, WAIT_TIME, APN_ENABLED, SUPPORTED_APNT_YPES_BITMAP,
+ ROAMING_PROTOCOL, BEARER_BITMAP, MTU, MVNO_TYPE, MVNO_MATCH_DATA, MODEM_COGNITIVE);
+ mRILUnderTest.setupDataCall(AccessNetworkConstants.AccessNetworkType.EUTRAN, dp, false,
+ false, 0, null, obtainMessage());
+ ArgumentCaptor<DataProfileInfo> dpiCaptor = ArgumentCaptor.forClass(DataProfileInfo.class);
+ verify(mRadioProxy).setupDataCall(
+ mSerialNumberCaptor.capture(), eq(AccessNetworkConstants.AccessNetworkType.EUTRAN),
+ dpiCaptor.capture(), eq(true), eq(false), eq(false));
+ verifyRILResponse(
+ mRILUnderTest, mSerialNumberCaptor.getValue(), RIL_REQUEST_SETUP_DATA_CALL);
+ DataProfileInfo dpi = dpiCaptor.getValue();
+ assertEquals(PROFILE_ID, dpi.profileId);
+ assertEquals(APN, dpi.apn);
+ assertEquals(PROTOCOL, dpi.protocol);
+ assertEquals(AUTH_TYPE, dpi.authType);
+ assertEquals(USER_NAME, dpi.user);
+ assertEquals(PASSWORD, dpi.password);
+ assertEquals(TYPE, dpi.type);
+ assertEquals(MAX_CONNS_TIME, dpi.maxConnsTime);
+ assertEquals(MAX_CONNS, dpi.maxConns);
+ assertEquals(WAIT_TIME, dpi.waitTime);
+ assertEquals(APN_ENABLED, dpi.enabled);
+ assertEquals(SUPPORTED_APNT_YPES_BITMAP, dpi.supportedApnTypesBitmap);
+ assertEquals(ROAMING_PROTOCOL, dpi.protocol);
+ assertEquals(BEARER_BITMAP, dpi.bearerBitmap);
+ assertEquals(MTU, dpi.mtu);
+ assertEquals(0, dpi.mvnoType);
+ assertEquals(MVNO_MATCH_DATA, dpi.mvnoMatchData);
+ }
}
diff --git a/tests/telephonytests/src/com/android/internal/telephony/ServiceStateTrackerTest.java b/tests/telephonytests/src/com/android/internal/telephony/ServiceStateTrackerTest.java
index 3108d2b..cb9f2ad 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/ServiceStateTrackerTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/ServiceStateTrackerTest.java
@@ -60,13 +60,16 @@
import android.telephony.AccessNetworkConstants.AccessNetworkType;
import android.telephony.CarrierConfigManager;
import android.telephony.CellIdentityGsm;
+import android.telephony.CellIdentityLte;
import android.telephony.CellInfo;
import android.telephony.CellInfoGsm;
import android.telephony.NetworkRegistrationState;
import android.telephony.NetworkService;
+import android.telephony.PhysicalChannelConfig;
import android.telephony.ServiceState;
import android.telephony.SignalStrength;
import android.telephony.SubscriptionManager;
+import android.telephony.TelephonyManager;
import android.telephony.gsm.GsmCellLocation;
import android.test.suitebuilder.annotation.MediumTest;
import android.test.suitebuilder.annotation.SmallTest;
@@ -88,6 +91,7 @@
import org.mockito.Mockito;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
@@ -1627,4 +1631,97 @@
waitForMs(200);
assertEquals(ServiceState.RIL_RADIO_TECHNOLOGY_GPRS, sst.mSS.getRilVoiceRadioTechnology());
}
+
+ private void sendPhyChanConfigChange(int[] bandwidths) {
+ ArrayList<PhysicalChannelConfig> pc = new ArrayList<>();
+ int ssType = PhysicalChannelConfig.CONNECTION_PRIMARY_SERVING;
+ for (int bw : bandwidths) {
+ pc.add(new PhysicalChannelConfig(ssType, bw));
+
+ // All cells after the first are secondary serving cells.
+ ssType = PhysicalChannelConfig.CONNECTION_SECONDARY_SERVING;
+ }
+ sst.sendMessage(sst.obtainMessage(ServiceStateTracker.EVENT_PHYSICAL_CHANNEL_CONFIG,
+ new AsyncResult(null, pc, null)));
+ waitForMs(100);
+ }
+
+ private void sendRegStateUpdateForLteCellId(CellIdentityLte cellId) {
+ NetworkRegistrationState dataResult = new NetworkRegistrationState(
+ 1, 2, 1, TelephonyManager.NETWORK_TYPE_LTE, 0, false, null, cellId, 1);
+ NetworkRegistrationState voiceResult = new NetworkRegistrationState(
+ 1, 1, 1, TelephonyManager.NETWORK_TYPE_LTE, 0, false, null, cellId,
+ false, 0, 0, 0);
+ sst.mPollingContext[0] = 2;
+ // update data reg state to be in service
+ sst.sendMessage(sst.obtainMessage(ServiceStateTracker.EVENT_POLL_STATE_GPRS,
+ new AsyncResult(sst.mPollingContext, dataResult, null)));
+ waitForMs(200);
+ sst.sendMessage(sst.obtainMessage(ServiceStateTracker.EVENT_POLL_STATE_REGISTRATION,
+ new AsyncResult(sst.mPollingContext, voiceResult, null)));
+ waitForMs(200);
+ }
+
+ @Test
+ public void testPhyChanBandwidthUpdatedOnDataRegState() throws Exception {
+ // Cell ID change should trigger hasLocationChanged.
+ CellIdentityLte cellIdentity5 =
+ new CellIdentityLte(1, 1, 5, 1, 5000, "001", "01", "test", "tst");
+
+ sendPhyChanConfigChange(new int[] {10000});
+ sendRegStateUpdateForLteCellId(cellIdentity5);
+ assertTrue(Arrays.equals(new int[] {5000}, sst.mSS.getCellBandwidths()));
+ }
+
+ @Test
+ public void testPhyChanBandwidthNotUpdatedWhenInvalidInCellIdentity() throws Exception {
+ // Cell ID change should trigger hasLocationChanged.
+ CellIdentityLte cellIdentityInv =
+ new CellIdentityLte(1, 1, 5, 1, 12345, "001", "01", "test", "tst");
+
+ sendPhyChanConfigChange(new int[] {10000});
+ sendRegStateUpdateForLteCellId(cellIdentityInv);
+ assertTrue(Arrays.equals(new int[] {10000}, sst.mSS.getCellBandwidths()));
+ }
+
+ @Test
+ public void testPhyChanBandwidthPrefersCarrierAggregationReport() throws Exception {
+ // Cell ID change should trigger hasLocationChanged.
+ CellIdentityLte cellIdentity10 =
+ new CellIdentityLte(1, 1, 5, 1, 10000, "001", "01", "test", "tst");
+
+ sendPhyChanConfigChange(new int[] {10000, 5000});
+ sendRegStateUpdateForLteCellId(cellIdentity10);
+ assertTrue(Arrays.equals(new int[] {10000, 5000}, sst.mSS.getCellBandwidths()));
+ }
+
+ @Test
+ public void testPhyChanBandwidthRatchetedOnPhyChanBandwidth() throws Exception {
+ // LTE Cell with bandwidth = 10000
+ CellIdentityLte cellIdentity10 =
+ new CellIdentityLte(1, 1, 1, 1, 10000, "1", "1", "test", "tst");
+
+ sendRegStateUpdateForLteCellId(cellIdentity10);
+ assertTrue(Arrays.equals(new int[] {10000}, sst.mSS.getCellBandwidths()));
+ sendPhyChanConfigChange(new int[] {10000, 5000});
+ assertTrue(Arrays.equals(new int[] {10000, 5000}, sst.mSS.getCellBandwidths()));
+ }
+
+ @Test
+ public void testPhyChanBandwidthResetsOnOos() throws Exception {
+ testPhyChanBandwidthRatchetedOnPhyChanBandwidth();
+ NetworkRegistrationState dataResult = new NetworkRegistrationState(
+ 1, 2, 0, TelephonyManager.NETWORK_TYPE_UNKNOWN, 0, false, null, null, 1);
+ NetworkRegistrationState voiceResult = new NetworkRegistrationState(
+ 1, 1, 0, TelephonyManager.NETWORK_TYPE_UNKNOWN, 0, false, null, null,
+ false, 0, 0, 0);
+ sst.mPollingContext[0] = 2;
+ sst.sendMessage(sst.obtainMessage(ServiceStateTracker.EVENT_POLL_STATE_GPRS,
+ new AsyncResult(sst.mPollingContext, dataResult, null)));
+ waitForMs(200);
+ sst.sendMessage(sst.obtainMessage(ServiceStateTracker.EVENT_POLL_STATE_REGISTRATION,
+ new AsyncResult(sst.mPollingContext, voiceResult, null)));
+ waitForMs(200);
+ assertTrue(Arrays.equals(new int[0], sst.mSS.getCellBandwidths()));
+ }
}
diff --git a/tests/telephonytests/src/com/android/internal/telephony/TelephonyTest.java b/tests/telephonytests/src/com/android/internal/telephony/TelephonyTest.java
index 56c6e91..89d8143 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/TelephonyTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/TelephonyTest.java
@@ -332,7 +332,8 @@
nullable(CommandsInterface.class));
doReturn(mUiccProfile).when(mTelephonyComponentFactory)
.makeUiccProfile(nullable(Context.class), nullable(CommandsInterface.class),
- nullable(IccCardStatus.class), anyInt(), nullable(UiccCard.class));
+ nullable(IccCardStatus.class), anyInt(), nullable(UiccCard.class),
+ nullable(Object.class));
doReturn(mCT).when(mTelephonyComponentFactory)
.makeGsmCdmaCallTracker(nullable(GsmCdmaPhone.class));
doReturn(mIccPhoneBookIntManager).when(mTelephonyComponentFactory)
diff --git a/tests/telephonytests/src/com/android/internal/telephony/dataconnection/ApnSettingTest.java b/tests/telephonytests/src/com/android/internal/telephony/dataconnection/ApnSettingTest.java
index 748ddf9..4c49e5b 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/dataconnection/ApnSettingTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/dataconnection/ApnSettingTest.java
@@ -138,6 +138,7 @@
assertEquals(a1.mvnoType, a2.mvnoType);
assertEquals(a1.mvnoMatchData, a2.mvnoMatchData);
assertEquals(a1.networkTypeBitmask, a2.networkTypeBitmask);
+ assertEquals(a1.apnSetId, a2.apnSetId);
}
@Test
@@ -230,6 +231,22 @@
"testspn");
assertApnSettingEqual(expectedApn, ApnSetting.fromString(testString));
+ // A v5 string with apnSetId=0
+ testString =
+ "[ApnSettingV5] Name,apn,,,,,,,,,123,45,,mms|*,IPV6,IP,true,0,,,,,,,spn,testspn,0,0";
+ expectedApn = new ApnSetting(
+ -1, "12345", "Name", "apn", "", "", "", "", "", "", "", 0, mmsTypes, "IPV6",
+ "IP", true, 0, 0, 0, false, 0, 0, 0, 0, "spn", "testspn");
+ assertApnSettingEqual(expectedApn, ApnSetting.fromString(testString));
+
+ // A v5 string with apnSetId=3
+ testString =
+ "[ApnSettingV5] Name,apn,,,,,,,,,123,45,,mms|*,IPV6,IP,true,0,,,,,,,spn,testspn,0,3";
+ expectedApn = new ApnSetting(
+ -1, "12345", "Name", "apn", "", "", "", "", "", "", "", 0, mmsTypes, "IPV6",
+ "IP", true, 0, 0, false, 0, 0, 0, 0, "spn", "testspn", 3);
+ assertApnSettingEqual(expectedApn, ApnSetting.fromString(testString));
+
// Return no apn if insufficient fields given.
testString = "[ApnSettingV3] Name,apn,,,,,,,,,123, 45,,mms|*";
assertEquals(null, ApnSetting.fromString(testString));
@@ -248,6 +265,8 @@
" ;[ApnSettingV3] Name1,apn1,,,,,,,,,123,46,,mms,IPV6,IP,true,12,,,,,,,gid,testGid";
testString +=
" ;[ApnSettingV3] Name1,apn2,,,,,,,,,123,46,,mms,IPV6,IP,true,12,,,,,,,,";
+ testString +=
+ " ;[ApnSettingV5] Name1,apn2,,,,,,,,,123,46,,mms,IPV6,IP,true,0,,,,,,,,,,3";
List<ApnSetting> expectedApns = new ArrayList<ApnSetting>();
expectedApns.add(new ApnSetting(
-1, "12345", "Name", "apn", "", "", "", "", "", "", "", 0, new String[]{"mms"}, "IPV6",
@@ -258,6 +277,9 @@
expectedApns.add(new ApnSetting(
-1, "12346", "Name1", "apn2", "", "", "", "", "", "", "", 0, new String[]{"mms"}, "IPV6",
"IP", true, 12, 0, 0, false, 0, 0, 0, 0, "", ""));
+ expectedApns.add(new ApnSetting(
+ -1, "12346", "Name1", "apn2", "", "", "", "", "", "", "", 0, new String[]{"mms"}, "IPV6",
+ "IP", true, 0, 0, false, 0, 0, 0, 0, "", "", 3));
assertApnSettingsEqual(expectedApns, ApnSetting.arrayFromString(testString));
}
@@ -265,13 +287,25 @@
@SmallTest
public void testToString() throws Exception {
String[] types = {"default", "*"};
+ // use default apn_set_id constructor
ApnSetting apn = new ApnSetting(
99, "12345", "Name", "apn", "proxy", "port",
"mmsc", "mmsproxy", "mmsport", "user", "password", 0,
types, "IPV6", "IP", true, 14, 0, 0, false, 0, 0, 0, 0, "", "");
- String expected = "[ApnSettingV4] Name, 99, 12345, apn, proxy, "
+ String expected = "[ApnSettingV5] Name, 99, 12345, apn, proxy, "
+ "mmsc, mmsproxy, mmsport, port, 0, default | *, "
- + "IPV6, IP, true, 14, 8192, 0, false, 0, 0, 0, 0, , , false, 4096";
+ + "IPV6, IP, true, 14, 8192, 0, false, 0, 0, 0, 0, , , false, 4096, 0";
+ assertEquals(expected, apn.toString());
+
+ int networkTypeBitmask = 1 << (14 - 1);
+ int bearerBitmask =
+ ServiceState.convertNetworkTypeBitmaskToBearerBitmask(networkTypeBitmask);
+ apn = new ApnSetting(99, "12345", "Name", "apn", "proxy", "port",
+ "mmsc", "mmsproxy", "mmsport", "user", "password", 0,
+ types, "IPV6", "IP", true, networkTypeBitmask, 0, false, 0, 0, 0, 0, "", "", 3);
+ expected = "[ApnSettingV5] Name, 99, 12345, apn, proxy, "
+ + "mmsc, mmsproxy, mmsport, port, 0, default | *, IPV6, IP, true, 0, "
+ + bearerBitmask + ", 0, false, 0, 0, 0, 0, , , false, 8192, 3";
assertEquals(expected, apn.toString());
}
@@ -863,4 +897,4 @@
assertTrue(apn1.equals(apn2, false));
assertFalse(apn1.equals(apn2, true));
}
-}
\ No newline at end of file
+}
diff --git a/tests/telephonytests/src/com/android/internal/telephony/dataconnection/DataConnectionTest.java b/tests/telephonytests/src/com/android/internal/telephony/dataconnection/DataConnectionTest.java
index d94a8b1..b2fea9b 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/dataconnection/DataConnectionTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/dataconnection/DataConnectionTest.java
@@ -129,6 +129,34 @@
"", // mvno_type
""); // mnvo_match_data
+ private ApnSetting mApn2 = new ApnSetting(
+ 2164, // id
+ "44010", // numeric
+ "sp-mode", // name
+ "spmode.ne.jp", // apn
+ "", // proxy
+ "", // port
+ "", // mmsc
+ "", // mmsproxy
+ "", // mmsport
+ "", // user
+ "", // password
+ -1, // authtype
+ new String[]{"default", "dun"}, // types
+ "IP", // protocol
+ "IP", // roaming_protocol
+ true, // carrier_enabled
+ 0, // bearer
+ 0, // bearer_bitmask
+ 0, // profile_id
+ false, // modem_cognitive
+ 0, // max_conns
+ 0, // wait_time
+ 0, // max_conns_time
+ 0, // mtu
+ "", // mvno_type
+ ""); // mnvo_match_data
+
private class DataConnectionTestHandler extends HandlerThread {
private DataConnectionTestHandler(String name) {
@@ -174,6 +202,7 @@
ServiceState.RIL_RADIO_TECHNOLOGY_UMTS);
doReturn(mApn1).when(mApnContext).getApnSetting();
doReturn(PhoneConstants.APN_TYPE_DEFAULT).when(mApnContext).getApnType();
+ doReturn(true).when(mDcTracker).isDataEnabled();
mDcFailBringUp.saveParameters(0, 0, -2);
doReturn(mDcFailBringUp).when(mDcTesterFailBringUpAll).getDcFailBringUp();
@@ -376,6 +405,36 @@
@Test
@SmallTest
+ public void testNetworkCapability() throws Exception {
+ mContextFixture.getCarrierConfigBundle().putStringArray(
+ CarrierConfigManager.KEY_CARRIER_METERED_APN_TYPES_STRINGS,
+ new String[] { "default" });
+ doReturn(mApn2).when(mApnContext).getApnSetting();
+ testConnectEvent();
+
+ assertTrue("capabilities: " + getNetworkCapabilities(), getNetworkCapabilities()
+ .hasCapability(NetworkCapabilities.NET_CAPABILITY_DUN));
+ assertTrue("capabilities: " + getNetworkCapabilities(), getNetworkCapabilities()
+ .hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET));
+ assertFalse("capabilities: " + getNetworkCapabilities(), getNetworkCapabilities()
+ .hasCapability(NetworkCapabilities.NET_CAPABILITY_MMS));
+
+ mDc.sendMessage(DataConnection.EVENT_DISCONNECT, mDcp);
+ waitForMs(100);
+ doReturn(mApn1).when(mApnContext).getApnSetting();
+ mDc.sendMessage(DataConnection.EVENT_CONNECT, mCp);
+ waitForMs(200);
+
+ assertFalse("capabilities: " + getNetworkCapabilities(), getNetworkCapabilities()
+ .hasCapability(NetworkCapabilities.NET_CAPABILITY_DUN));
+ assertTrue("capabilities: " + getNetworkCapabilities(), getNetworkCapabilities()
+ .hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET));
+ assertTrue("capabilities: " + getNetworkCapabilities(), getNetworkCapabilities()
+ .hasCapability(NetworkCapabilities.NET_CAPABILITY_SUPL));
+ }
+
+ @Test
+ @SmallTest
public void testMeteredCapability() throws Exception {
mContextFixture.getCarrierConfigBundle().
diff --git a/tests/telephonytests/src/com/android/internal/telephony/dataconnection/DcTrackerTest.java b/tests/telephonytests/src/com/android/internal/telephony/dataconnection/DcTrackerTest.java
index a2cb71c..89d670c 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/dataconnection/DcTrackerTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/dataconnection/DcTrackerTest.java
@@ -38,6 +38,7 @@
import android.app.AlarmManager;
import android.app.PendingIntent;
import android.content.ContentResolver;
+import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
@@ -89,6 +90,7 @@
import org.mockito.stubbing.Answer;
import java.lang.reflect.Method;
+import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.regex.Matcher;
@@ -122,6 +124,9 @@
1 << (TelephonyManager.NETWORK_TYPE_LTE - 1);
private static final int NETWORK_TYPE_EHRPD_BITMASK =
1 << (TelephonyManager.NETWORK_TYPE_EHRPD - 1);
+ private static final Uri PREFERAPN_URI = Uri.parse(
+ Telephony.Carriers.CONTENT_URI + "/preferapn");
+
@Mock
ISub mIsub;
@@ -181,6 +186,7 @@
}
private class ApnSettingContentProvider extends MockContentProvider {
+ private int mPreferredApnSet = 0;
@Override
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
@@ -225,7 +231,8 @@
Telephony.Carriers.MAX_CONNS_TIME, Telephony.Carriers.MTU,
Telephony.Carriers.MVNO_TYPE,
Telephony.Carriers.MVNO_MATCH_DATA,
- Telephony.Carriers.NETWORK_TYPE_BITMASK});
+ Telephony.Carriers.NETWORK_TYPE_BITMASK,
+ Telephony.Carriers.APN_SET_ID});
mc.addRow(new Object[]{
2163, // id
@@ -254,7 +261,8 @@
0, // mtu
"", // mvno_type
"", // mnvo_match_data
- NETWORK_TYPE_LTE_BITMASK // network_type_bitmask
+ NETWORK_TYPE_LTE_BITMASK, // network_type_bitmask
+ 0 // apn_set_id
});
mc.addRow(new Object[]{
@@ -284,7 +292,8 @@
0, // mtu
"", // mvno_type
"", // mnvo_match_data
- NETWORK_TYPE_LTE_BITMASK // network_type_bitmask
+ NETWORK_TYPE_LTE_BITMASK, // network_type_bitmask
+ 0 // apn_set_id
});
mc.addRow(new Object[]{
@@ -314,7 +323,8 @@
0, // mtu
"", // mvno_type
"", // mnvo_match_data
- 0 // network_type_bitmask
+ 0, // network_type_bitmask
+ 0 // apn_set_id
});
mc.addRow(new Object[]{
@@ -344,7 +354,8 @@
0, // mtu
"", // mvno_type
"", // mnvo_match_data
- NETWORK_TYPE_EHRPD_BITMASK // network_type_bitmask
+ NETWORK_TYPE_EHRPD_BITMASK, // network_type_bitmask
+ 0 // apn_set_id
});
mc.addRow(new Object[]{
@@ -374,14 +385,30 @@
0, // mtu
"", // mvno_type
"", // mnvo_match_data
- 0 // network_type_bitmask
+ 0, // network_type_bitmask
+ 0 // apn_set_id
});
+
return mc;
}
+ } else if (uri.isPathPrefixMatch(
+ Uri.withAppendedPath(Telephony.Carriers.CONTENT_URI, "preferapnset"))) {
+ MatrixCursor mc = new MatrixCursor(
+ new String[]{Telephony.Carriers.APN_SET_ID});
+ // apn_set_id is the only field used with this URL
+ mc.addRow(new Object[]{ mPreferredApnSet });
+ mc.addRow(new Object[]{ 0 });
+ return mc;
}
return null;
}
+
+ @Override
+ public int update(Uri url, ContentValues values, String where, String[] whereArgs) {
+ mPreferredApnSet = values.getAsInteger(Telephony.Carriers.APN_SET_ID);
+ return 1;
+ }
}
@Before
@@ -1293,7 +1320,7 @@
assertEquals(DctConstants.State.CONNECTED, mDct.getOverallState());
}
-// Test for fetchDunApn()
+ // Test for fetchDunApns()
@Test
@SmallTest
public void testFetchDunApn() {
@@ -1308,15 +1335,48 @@
Settings.Global.putString(mContext.getContentResolver(),
Settings.Global.TETHER_DUN_APN, dunApnString);
// should return APN from Setting
- ApnSetting dunApn = mDct.fetchDunApn();
+ ApnSetting dunApn = mDct.fetchDunApns().get(0);
assertTrue(dunApnExpected.equals(dunApn));
Settings.Global.putString(mContext.getContentResolver(),
Settings.Global.TETHER_DUN_APN, null);
// should return APN from db
- dunApn = mDct.fetchDunApn();
+ dunApn = mDct.fetchDunApns().get(0);
assertEquals(FAKE_APN5, dunApn.apn);
}
+
+ // Test for fetchDunApns() with apn set id
+ @Test
+ @SmallTest
+ public void testFetchDunApnWithPreferredApnSet() {
+ logd("Sending EVENT_RECORDS_LOADED");
+ mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_RECORDS_LOADED, null));
+ waitForMs(200);
+
+ // apnSetId=1
+ String dunApnString1 = "[ApnSettingV5]HOT mobile PC,pc.hotm,,,,,,,,,440,10,,DUN,,,true,"
+ + "0,,,,,,,,,,1";
+ // apnSetId=0
+ String dunApnString2 = "[ApnSettingV5]HOT mobile PC,pc.coldm,,,,,,,,,440,10,,DUN,,,true,"
+ + "0,,,,,,,,,,0";
+
+ ApnSetting dunApnExpected = ApnSetting.fromString(dunApnString1);
+
+ ContentResolver cr = mContext.getContentResolver();
+ Settings.Global.putString(cr, Settings.Global.TETHER_DUN_APN,
+ dunApnString1 + ";" + dunApnString2);
+
+ // set that we prefer apn set 1
+ ContentValues values = new ContentValues();
+ values.put(Telephony.Carriers.APN_SET_ID, 1);
+ cr.update(PREFERAPN_URI, values, null, null);
+
+ // return APN from Setting with apnSetId=1
+ ArrayList<ApnSetting> dunApns = mDct.sortApnListByPreferred(mDct.fetchDunApns());
+ assertEquals(2, dunApns.size());
+ assertTrue(dunApnExpected.equals(dunApns.get(0)));
+ }
+
// Test oos
@Test
@SmallTest
diff --git a/tests/telephonytests/src/com/android/internal/telephony/ims/ImsManagerTest.java b/tests/telephonytests/src/com/android/internal/telephony/ims/ImsManagerTest.java
index d4c54b9..2bf0094 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/ims/ImsManagerTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/ims/ImsManagerTest.java
@@ -53,8 +53,12 @@
private static final boolean WFC_IMS_ENABLE_DEFAULT_VAL = false;
private static final boolean WFC_IMS_ROAMING_ENABLE_DEFAULT_VAL = true;
private static final boolean VT_IMS_ENABLE_DEFAULT_VAL = true;
- private static final int WFC_IMS_MODE_DEFAULT_VAL = 2;
- private static final int WFC_IMS_ROAMING_MODE_DEFAULT_VAL = 3;
+ private static final boolean WFC_IMS_EDITABLE_VAL = true;
+ private static final boolean WFC_IMS_NOT_EDITABLE_VAL = false;
+ private static final int WFC_IMS_MODE_DEFAULT_VAL =
+ ImsConfig.WfcModeFeatureValueConstants.CELLULAR_PREFERRED;
+ private static final int WFC_IMS_ROAMING_MODE_DEFAULT_VAL =
+ ImsConfig.WfcModeFeatureValueConstants.WIFI_PREFERRED;
PersistableBundle mBundle;
@Mock IBinder mBinder;
@@ -62,7 +66,6 @@
Hashtable<Integer, Integer> mProvisionedIntVals = new Hashtable<>();
Hashtable<Integer, String> mProvisionedStringVals = new Hashtable<>();
ImsConfigImplBase.ImsConfigStub mImsConfigStub;
- ImsConfig mImsConfig;
@Mock MmTelFeatureConnection mMmTelFeatureConnection;
private final int[] mSubId = {0};
@@ -94,6 +97,8 @@
private void setDefaultValues() {
mBundle.putBoolean(CarrierConfigManager.KEY_EDITABLE_ENHANCED_4G_LTE_BOOL,
ENHANCED_4G_MODE_EDITABLE);
+ mBundle.putBoolean(CarrierConfigManager.KEY_EDITABLE_WFC_MODE_BOOL,
+ WFC_IMS_EDITABLE_VAL);
mBundle.putBoolean(CarrierConfigManager.KEY_CARRIER_DEFAULT_WFC_IMS_ENABLED_BOOL,
WFC_IMS_ENABLE_DEFAULT_VAL);
mBundle.putBoolean(CarrierConfigManager.KEY_CARRIER_DEFAULT_WFC_IMS_ROAMING_ENABLED_BOOL,
@@ -239,14 +244,22 @@
}
+ /**
+ * Tests that when a WFC mode is set for home/roaming, that setting is sent to the ImsService
+ * correctly.
+ *
+ * Preconditions:
+ * - CarrierConfigManager.KEY_EDITABLE_WFC_MODE_BOOL = true
+ */
@Test @SmallTest
public void testSetWfcSetting_true_shouldSetWfcModeWrtRoamingState() throws Exception {
- doReturn(String.valueOf(ImsConfig.WfcModeFeatureValueConstants.CELLULAR_PREFERRED))
+ // First, Set WFC home/roaming mode that is not the Carrier Config default.
+ doReturn(String.valueOf(ImsConfig.WfcModeFeatureValueConstants.WIFI_PREFERRED))
.when(mSubscriptionController).getSubscriptionProperty(
anyInt(),
eq(SubscriptionManager.WFC_IMS_MODE),
anyString());
- doReturn(String.valueOf(ImsConfig.WfcModeFeatureValueConstants.WIFI_PREFERRED))
+ doReturn(String.valueOf(ImsConfig.WfcModeFeatureValueConstants.CELLULAR_PREFERRED))
.when(mSubscriptionController).getSubscriptionProperty(
anyInt(),
eq(SubscriptionManager.WFC_IMS_ROAMING_MODE),
@@ -257,22 +270,100 @@
doReturn(true).when(mTelephonyManager).isNetworkRoaming(eq(mSubId[0]));
// Turn on WFC
imsManager.setWfcSetting(true);
- // Roaming mode (WIFI_PREFERRED) should be set. With 1000 ms timeout.
+ // Roaming mode (CELLULAR_PREFERRED) should be set. With 1000 ms timeout.
verify(mImsConfigImplBaseMock, timeout(1000)).setConfig(
eq(ImsConfig.ConfigConstants.VOICE_OVER_WIFI_MODE),
- eq(ImsConfig.WfcModeFeatureValueConstants.WIFI_PREFERRED));
+ eq(ImsConfig.WfcModeFeatureValueConstants.CELLULAR_PREFERRED));
// Not roaming
doReturn(false).when(mTelephonyManager).isNetworkRoaming(eq(mSubId[0]));
// Turn on WFC
imsManager.setWfcSetting(true);
- // Home mode (CELLULAR_PREFERRED) should be set. With 1000 ms timeout.
+ // Home mode (WIFI_PREFERRED) should be set. With 1000 ms timeout.
verify(mImsConfigImplBaseMock, timeout(1000)).setConfig(
eq(ImsConfig.ConfigConstants.VOICE_OVER_WIFI_MODE),
- eq(ImsConfig.WfcModeFeatureValueConstants.CELLULAR_PREFERRED));
+ eq(ImsConfig.WfcModeFeatureValueConstants.WIFI_PREFERRED));
}
- private ImsManager initializeProvisionedValues() {
+ /**
+ * Tests that the settings for WFC mode are ignored if the Carrier sets the settings to not
+ * editable.
+ *
+ * Preconditions:
+ * - CarrierConfigManager.KEY_EDITABLE_WFC_MODE_BOOL = false
+ */
+ @Test @SmallTest
+ public void testSetWfcSetting_wfcNotEditable() throws Exception {
+ mBundle.putBoolean(CarrierConfigManager.KEY_EDITABLE_WFC_MODE_BOOL,
+ WFC_IMS_NOT_EDITABLE_VAL);
+ // Set some values that are different than the defaults for WFC mode.
+ doReturn(String.valueOf(ImsConfig.WfcModeFeatureValueConstants.WIFI_ONLY))
+ .when(mSubscriptionController).getSubscriptionProperty(
+ anyInt(),
+ eq(SubscriptionManager.WFC_IMS_MODE),
+ anyString());
+ doReturn(String.valueOf(ImsConfig.WfcModeFeatureValueConstants.WIFI_ONLY))
+ .when(mSubscriptionController).getSubscriptionProperty(
+ anyInt(),
+ eq(SubscriptionManager.WFC_IMS_ROAMING_MODE),
+ anyString());
+ ImsManager imsManager = initializeProvisionedValues();
+
+ // Roaming
+ doReturn(true).when(mTelephonyManager).isNetworkRoaming(eq(mSubId[0]));
+ // Turn on WFC
+ imsManager.setWfcSetting(true);
+ // User defined setting for Roaming mode (WIFI_ONLY) should be set independent of whether or
+ // not WFC mode is editable. With 1000 ms timeout.
+ verify(mImsConfigImplBaseMock, timeout(1000)).setConfig(
+ eq(ImsConfig.ConfigConstants.VOICE_OVER_WIFI_MODE),
+ eq(ImsConfig.WfcModeFeatureValueConstants.WIFI_ONLY));
+
+ // Not roaming
+ doReturn(false).when(mTelephonyManager).isNetworkRoaming(eq(mSubId[0]));
+ // Turn on WFC
+ imsManager.setWfcSetting(true);
+ // Default Home mode (CELLULAR_PREFERRED) should be set. With 1000 ms timeout.
+ verify(mImsConfigImplBaseMock, timeout(1000)).setConfig(
+ eq(ImsConfig.ConfigConstants.VOICE_OVER_WIFI_MODE),
+ eq(WFC_IMS_MODE_DEFAULT_VAL));
+ }
+
+ /**
+ * Tests that the CarrierConfig defaults will be used if no setting is set in the Subscription
+ * Manager.
+ *
+ * Preconditions:
+ * - CarrierConfigManager.KEY_EDITABLE_WFC_MODE_BOOL = true
+ * - CarrierConfigManager.KEY_CARRIER_DEFAULT_WFC_IMS_MODE_INT = Carrier preferred
+ * - CarrierConfigManager.KEY_CARRIER_DEFAULT_WFC_IMS_ROAMING_MODE_INT = WiFi preferred
+ */
+ @Test @SmallTest
+ public void testSetWfcSetting_noUserSettingSet() throws Exception {
+ ImsManager imsManager = initializeProvisionedValues();
+
+ // Roaming
+ doReturn(true).when(mTelephonyManager).isNetworkRoaming(eq(mSubId[0]));
+ // Turn on WFC
+ imsManager.setWfcSetting(true);
+
+ // Default Roaming mode (WIFI_PREFERRED) for carrier should be set. With 1000 ms timeout.
+ verify(mImsConfigImplBaseMock, timeout(1000)).setConfig(
+ eq(ImsConfig.ConfigConstants.VOICE_OVER_WIFI_MODE),
+ eq(WFC_IMS_ROAMING_MODE_DEFAULT_VAL));
+
+ // Not roaming
+ doReturn(false).when(mTelephonyManager).isNetworkRoaming(eq(mSubId[0]));
+ // Turn on WFC
+ imsManager.setWfcSetting(true);
+
+ // Default Home mode (CELLULAR_PREFERRED) for carrier should be set. With 1000 ms timeout.
+ verify(mImsConfigImplBaseMock, timeout(1000)).setConfig(
+ eq(ImsConfig.ConfigConstants.VOICE_OVER_WIFI_MODE),
+ eq(WFC_IMS_MODE_DEFAULT_VAL));
+ }
+
+ private ImsManager initializeProvisionedValues() throws Exception {
when(mImsConfigImplBaseMock.getConfigInt(anyInt()))
.thenAnswer(invocation -> {
return getProvisionedInt((Integer) (invocation.getArguments()[0]));
@@ -288,15 +379,11 @@
// Configure ImsConfigStub
mImsConfigStub = new ImsConfigImplBase.ImsConfigStub(mImsConfigImplBaseMock);
- doReturn(mImsConfigStub).when(mImsConfigImplBaseMock).getIImsConfig();
-
- // Configure ImsConfig
- mImsConfig = new ImsConfig(mImsConfigStub, mContext);
+ doReturn(mImsConfigStub).when(mMmTelFeatureConnection).getConfigInterface();
// Configure ImsManager
ImsManager imsManager = ImsManager.getInstance(mContext, mPhoneId);
try {
- replaceInstance(ImsManager.class, "mConfig", imsManager, mImsConfig);
replaceInstance(ImsManager.class, "mMmTelFeatureConnection", imsManager,
mMmTelFeatureConnection);
} catch (Exception ex) {
diff --git a/tests/telephonytests/src/com/android/internal/telephony/uicc/UiccCardTest.java b/tests/telephonytests/src/com/android/internal/telephony/uicc/UiccCardTest.java
index dc21b70..27b8531 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/uicc/UiccCardTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/uicc/UiccCardTest.java
@@ -63,7 +63,8 @@
@Override
public void onLooperPrepared() {
mUicccard = new UiccCard(mContextFixture.getTestDouble(),
- mSimulatedCommands, mIccCardStatus, 0 /* phoneId */);
+ mSimulatedCommands, mIccCardStatus, 0 /* phoneId */,
+ new Object());
/* create a custom handler for the Handler Thread */
mHandler = new Handler(mTestHandlerThread.getLooper()) {
@Override
diff --git a/tests/telephonytests/src/com/android/internal/telephony/uicc/UiccProfileTest.java b/tests/telephonytests/src/com/android/internal/telephony/uicc/UiccProfileTest.java
index 8b87e9f..0ae5531 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/uicc/UiccProfileTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/uicc/UiccProfileTest.java
@@ -84,7 +84,7 @@
public void onLooperPrepared() {
mUiccProfile = new UiccProfile(mContextFixture.getTestDouble(),
mSimulatedCommands, mIccCardStatus, 0 /* phoneId */,
- mUiccCard);
+ mUiccCard, new Object());
/* create a custom handler for the Handler Thread */
mHandler = new Handler(mTestHandlerThread.getLooper()) {
@Override
diff --git a/tests/telephonytests/src/com/android/internal/telephony/uicc/UiccSlotTest.java b/tests/telephonytests/src/com/android/internal/telephony/uicc/UiccSlotTest.java
index c046980..457f021 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/uicc/UiccSlotTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/uicc/UiccSlotTest.java
@@ -102,8 +102,9 @@
@Test
@SmallTest
- public void testUpdateSlotStatus() {
+ public void testUpdateInactiveSlotStatus() {
IccSlotStatus iss = new IccSlotStatus();
+ iss.logicalSlotIndex = 0;
iss.slotState = IccSlotStatus.SlotState.SLOTSTATE_INACTIVE;
iss.cardState = IccCardStatus.CardState.CARDSTATE_PRESENT;
iss.iccid = "fake-iccid";
@@ -122,8 +123,35 @@
assertNull(mUiccSlot.getUiccCard());
assertEquals(IccCardStatus.CardState.CARDSTATE_PRESENT, mUiccSlot.getCardState());
assertEquals(iss.iccid, mUiccSlot.getIccId());
+ }
+ @Test
+ @SmallTest
+ public void testUpdateActiveSlotStatus() {
+ // initial state
+ assertTrue(mUiccSlot.isActive());
+ assertNull(mUiccSlot.getUiccCard());
+ assertEquals(IccCardStatus.CardState.CARDSTATE_ABSENT, mUiccSlot.getCardState());
+ assertNull(mUiccSlot.getIccId());
+
+ mSimulatedCommands.setRadioPower(true, null);
+ int phoneId = 0;
+ IccSlotStatus iss = new IccSlotStatus();
+ iss.logicalSlotIndex = phoneId;
iss.slotState = IccSlotStatus.SlotState.SLOTSTATE_ACTIVE;
+ iss.cardState = IccCardStatus.CardState.CARDSTATE_ABSENT;
+ iss.iccid = "fake-iccid";
+
+ // update slot to inactive
+ mUiccSlot.update(mSimulatedCommands, iss);
+
+ // assert on updated values
+ assertTrue(mUiccSlot.isActive());
+ assertNull(mUiccSlot.getUiccCard());
+ assertEquals(IccCardStatus.CardState.CARDSTATE_ABSENT, mUiccSlot.getCardState());
+ assertEquals(iss.iccid, mUiccSlot.getIccId());
+ verify(mSubInfoRecordUpdater).updateInternalIccState(
+ IccCardConstants.INTENT_VALUE_ICC_ABSENT, null, phoneId);
// update slot to active
mUiccSlot.update(mSimulatedCommands, iss);
@@ -136,6 +164,7 @@
@SmallTest
public void testUpdateSlotStatusEuiccIsSupported() {
IccSlotStatus iss = new IccSlotStatus();
+ iss.logicalSlotIndex = 0;
iss.slotState = IccSlotStatus.SlotState.SLOTSTATE_INACTIVE;
iss.cardState = IccCardStatus.CardState.CARDSTATE_PRESENT;
iss.iccid = "fake-iccid";
@@ -170,6 +199,7 @@
@SmallTest
public void testUpdateSlotStatusEuiccIsNotSupported() {
IccSlotStatus iss = new IccSlotStatus();
+ iss.logicalSlotIndex = 0;
iss.slotState = IccSlotStatus.SlotState.SLOTSTATE_INACTIVE;
iss.cardState = IccCardStatus.CardState.CARDSTATE_PRESENT;
iss.iccid = "fake-iccid";
@@ -221,7 +251,8 @@
mIccCardStatus.mCardState = IccCardStatus.CardState.CARDSTATE_PRESENT;
mUiccSlot.update(mSimulatedCommands, mIccCardStatus, phoneId);
verify(mTelephonyComponentFactory).makeUiccProfile(
- anyObject(), eq(mSimulatedCommands), eq(mIccCardStatus), anyInt(), anyObject());
+ anyObject(), eq(mSimulatedCommands), eq(mIccCardStatus), anyInt(), anyObject(),
+ anyObject());
assertEquals(IccCardStatus.CardState.CARDSTATE_PRESENT, mUiccSlot.getCardState());
assertNotNull(mUiccSlot.getUiccCard());
diff --git a/tests/telephonytests/src/com/android/internal/telephony/uicc/UiccStateChangedLauncherTest.java b/tests/telephonytests/src/com/android/internal/telephony/uicc/UiccStateChangedLauncherTest.java
index a90e947..f933596 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/uicc/UiccStateChangedLauncherTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/uicc/UiccStateChangedLauncherTest.java
@@ -101,7 +101,7 @@
// The first broadcast should be sent after initialization.
UiccCard card = new UiccCard(mContext, mSimulatedCommands,
- makeCardStatus(CardState.CARDSTATE_PRESENT), 0 /* phoneId */);
+ makeCardStatus(CardState.CARDSTATE_PRESENT), 0 /* phoneId */, new Object());
when(UiccController.getInstance().getUiccCardForPhone(0)).thenReturn(card);
uiccLauncher.handleMessage(msg);
diff --git a/tests/telephonytests/src/com/android/internal/telephony/uicc/euicc/EuiccCardTest.java b/tests/telephonytests/src/com/android/internal/telephony/uicc/euicc/EuiccCardTest.java
index 801ef86..a3d7245 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/uicc/euicc/EuiccCardTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/uicc/euicc/EuiccCardTest.java
@@ -103,7 +103,7 @@
public void onLooperPrepared() {
mEuiccCard =
new EuiccCard(mContextFixture.getTestDouble(), mMockCi, mMockIccCardStatus,
- 0 /* phoneId */) {
+ 0 /* phoneId */, new Object()) {
@Override
protected byte[] getDeviceId() {
return IccUtils.bcdToBytes("987654321012345");
@@ -173,7 +173,7 @@
final CountDownLatch latch = new CountDownLatch(1);
mHandler.post(() -> {
mEuiccCard = new EuiccCard(mContextFixture.getTestDouble(), mMockCi,
- mMockIccCardStatus, 0 /* phoneId */);
+ mMockIccCardStatus, 0 /* phoneId */, new Object());
latch.countDown();
});
assertTrue(latch.await(WAIT_TIMEOUT_MLLIS, TimeUnit.MILLISECONDS));