Merge "Make CellBroadcast APIs public"
diff --git a/src/java/com/android/internal/telephony/IccSmsInterfaceManager.java b/src/java/com/android/internal/telephony/IccSmsInterfaceManager.java
index 3558d4e..0e9598d 100644
--- a/src/java/com/android/internal/telephony/IccSmsInterfaceManager.java
+++ b/src/java/com/android/internal/telephony/IccSmsInterfaceManager.java
@@ -178,17 +178,17 @@
int count = messages.size();
for (int i = 0; i < count; i++) {
- byte[] ba = messages.get(i);
- if (ba[0] == STATUS_ON_ICC_UNREAD) {
- int n = ba.length;
- byte[] nba = new byte[n - 1];
- System.arraycopy(ba, 1, nba, 0, n - 1);
- byte[] record = makeSmsRecordData(STATUS_ON_ICC_READ, nba);
- fh.updateEFLinearFixed(IccConstants.EF_SMS, i + 1, record, null, null);
- if (Rlog.isLoggable("SMS", Log.DEBUG)) {
- log("SMS " + (i + 1) + " marked as read");
- }
- }
+ byte[] ba = messages.get(i);
+ if ((ba[0] & 0x07) == STATUS_ON_ICC_UNREAD) {
+ int n = ba.length;
+ byte[] nba = new byte[n - 1];
+ System.arraycopy(ba, 1, nba, 0, n - 1);
+ byte[] record = makeSmsRecordData(STATUS_ON_ICC_READ, nba);
+ fh.updateEFLinearFixed(IccConstants.EF_SMS, i + 1, record, null, null);
+ if (Rlog.isLoggable("SMS", Log.DEBUG)) {
+ log("SMS " + (i + 1) + " marked as read");
+ }
+ }
}
}
@@ -785,7 +785,7 @@
}
// Status bits for this record. See TS 51.011 10.5.3
- data[0] = (byte)(status & 7);
+ data[0] = (byte) (status & 0x07);
System.arraycopy(pdu, 0, data, 1, pdu.length);
diff --git a/src/java/com/android/internal/telephony/MccTable.java b/src/java/com/android/internal/telephony/MccTable.java
index 2e70c45..9d00831 100644
--- a/src/java/com/android/internal/telephony/MccTable.java
+++ b/src/java/com/android/internal/telephony/MccTable.java
@@ -30,6 +30,7 @@
import com.android.internal.app.LocaleStore;
import com.android.internal.app.LocaleStore.LocaleInfo;
+import libcore.timezone.CountryTimeZones;
import libcore.timezone.TimeZoneFinder;
import java.util.ArrayList;
@@ -96,7 +97,9 @@
return null;
}
final String lowerCaseCountryCode = entry.mIso;
- return TimeZoneFinder.getInstance().lookupDefaultTimeZoneIdByCountry(lowerCaseCountryCode);
+ CountryTimeZones countryTimeZones =
+ TimeZoneFinder.getInstance().lookupCountryTimeZones(lowerCaseCountryCode);
+ return countryTimeZones == null ? null : countryTimeZones.getDefaultTimeZoneId();
}
/**
diff --git a/src/java/com/android/internal/telephony/PhoneFactory.java b/src/java/com/android/internal/telephony/PhoneFactory.java
index b290104..886c83f 100644
--- a/src/java/com/android/internal/telephony/PhoneFactory.java
+++ b/src/java/com/android/internal/telephony/PhoneFactory.java
@@ -538,6 +538,16 @@
pw.println("++++++++++++++++++++++++++++++++");
}
+ pw.println("ImsResolver:");
+ pw.increaseIndent();
+ try {
+ if (sImsResolver != null) sImsResolver.dump(fd, pw, args);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ pw.decreaseIndent();
+ pw.println("++++++++++++++++++++++++++++++++");
+
pw.println("SubscriptionMonitor:");
pw.increaseIndent();
try {
diff --git a/src/java/com/android/internal/telephony/PhoneSwitcher.java b/src/java/com/android/internal/telephony/PhoneSwitcher.java
index e350ba1..bf8fd7a 100644
--- a/src/java/com/android/internal/telephony/PhoneSwitcher.java
+++ b/src/java/com/android/internal/telephony/PhoneSwitcher.java
@@ -1047,6 +1047,11 @@
}
private void transitionToEmergencyPhone() {
+ if (mNumPhones <= 0) {
+ log("No phones: unable to reset preferred phone for emergency");
+ return;
+ }
+
if (mPreferredDataPhoneId != DEFAULT_EMERGENCY_PHONE_ID) {
log("No active subscriptions: resetting preferred phone to 0 for emergency");
mPreferredDataPhoneId = DEFAULT_EMERGENCY_PHONE_ID;
diff --git a/src/java/com/android/internal/telephony/SubscriptionController.java b/src/java/com/android/internal/telephony/SubscriptionController.java
index 1ab70b6..31e5f4d 100644
--- a/src/java/com/android/internal/telephony/SubscriptionController.java
+++ b/src/java/com/android/internal/telephony/SubscriptionController.java
@@ -1589,8 +1589,16 @@
}
}
String nameToSet;
- if (displayName == null) {
- nameToSet = mContext.getString(SubscriptionManager.DEFAULT_NAME_RES);
+ if (TextUtils.isEmpty(displayName) || displayName.trim().length() == 0) {
+ nameToSet = mTelephonyManager.getSimOperatorName(subId);
+ if (TextUtils.isEmpty(nameToSet)) {
+ if (nameSource == SubscriptionManager.NAME_SOURCE_USER_INPUT
+ && SubscriptionManager.isValidSlotIndex(getSlotIndex(subId))) {
+ nameToSet = "CARD " + (getSlotIndex(subId) + 1);
+ } else {
+ nameToSet = mContext.getString(SubscriptionManager.DEFAULT_NAME_RES);
+ }
+ }
} else {
nameToSet = displayName;
}
diff --git a/src/java/com/android/internal/telephony/SubscriptionInfoUpdater.java b/src/java/com/android/internal/telephony/SubscriptionInfoUpdater.java
index 84bae1c..2a6a39b 100644
--- a/src/java/com/android/internal/telephony/SubscriptionInfoUpdater.java
+++ b/src/java/com/android/internal/telephony/SubscriptionInfoUpdater.java
@@ -68,8 +68,6 @@
import java.io.FileDescriptor;
import java.io.PrintWriter;
-import java.security.MessageDigest;
-import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.List;
@@ -975,58 +973,55 @@
return;
}
- if (!isCarrierServicePackage(phoneId, configPackageName)) {
- loge("Cannot manage subId=" + currentSubId + ", carrierPackage=" + configPackageName);
- return;
- }
-
ContentValues cv = new ContentValues();
- boolean isOpportunistic = config.getBoolean(
- CarrierConfigManager.KEY_IS_OPPORTUNISTIC_SUBSCRIPTION_BOOL, false);
- if (currentSubInfo.isOpportunistic() != isOpportunistic) {
- if (DBG) logd("Set SubId=" + currentSubId + " isOpportunistic=" + isOpportunistic);
- cv.put(SubscriptionManager.IS_OPPORTUNISTIC, isOpportunistic ? "1" : "0");
- }
+ ParcelUuid groupUuid = null;
+ // carrier certificates are not subscription-specific, so we want to load them even if
+ // this current package is not a CarrierServicePackage
String[] certs = config.getStringArray(
CarrierConfigManager.KEY_CARRIER_CERTIFICATE_STRING_ARRAY);
if (certs != null) {
UiccAccessRule[] carrierConfigAccessRules = new UiccAccessRule[certs.length];
- try {
- for (int i = 0; i < certs.length; i++) {
- carrierConfigAccessRules[i] = new UiccAccessRule(
- MessageDigest.getInstance("SHA-256").digest(certs[i].getBytes()), null, 0);
- }
- } catch (NoSuchAlgorithmException e) {
- throw new RuntimeException("for setCarrierConfigAccessRules, SHA-256 must exist",
- e);
+ for (int i = 0; i < certs.length; i++) {
+ carrierConfigAccessRules[i] = new UiccAccessRule(IccUtils.hexStringToBytes(
+ certs[i]), null, 0);
}
cv.put(SubscriptionManager.ACCESS_RULES_FROM_CARRIER_CONFIGS,
UiccAccessRule.encodeRules(carrierConfigAccessRules));
}
- String groupUuidString =
+ if (!isCarrierServicePackage(phoneId, configPackageName)) {
+ loge("Cannot manage subId=" + currentSubId + ", carrierPackage=" + configPackageName);
+ } else {
+ boolean isOpportunistic = config.getBoolean(
+ CarrierConfigManager.KEY_IS_OPPORTUNISTIC_SUBSCRIPTION_BOOL, false);
+ if (currentSubInfo.isOpportunistic() != isOpportunistic) {
+ if (DBG) logd("Set SubId=" + currentSubId + " isOpportunistic=" + isOpportunistic);
+ cv.put(SubscriptionManager.IS_OPPORTUNISTIC, isOpportunistic ? "1" : "0");
+ }
+
+ String groupUuidString =
config.getString(CarrierConfigManager.KEY_SUBSCRIPTION_GROUP_UUID_STRING, "");
- ParcelUuid groupUuid = null;
- if (!TextUtils.isEmpty(groupUuidString)) {
- try {
- // Update via a UUID Structure to ensure consistent formatting
- groupUuid = ParcelUuid.fromString(groupUuidString);
- if (groupUuid.equals(REMOVE_GROUP_UUID)
+ if (!TextUtils.isEmpty(groupUuidString)) {
+ try {
+ // Update via a UUID Structure to ensure consistent formatting
+ groupUuid = ParcelUuid.fromString(groupUuidString);
+ if (groupUuid.equals(REMOVE_GROUP_UUID)
&& currentSubInfo.getGroupUuid() != null) {
- cv.put(SubscriptionManager.GROUP_UUID, (String) null);
- if (DBG) logd("Group Removed for" + currentSubId);
- } else if (SubscriptionController.getInstance().canPackageManageGroup(groupUuid,
+ cv.put(SubscriptionManager.GROUP_UUID, (String) null);
+ if (DBG) logd("Group Removed for" + currentSubId);
+ } else if (SubscriptionController.getInstance().canPackageManageGroup(groupUuid,
configPackageName)) {
- cv.put(SubscriptionManager.GROUP_UUID, groupUuid.toString());
- cv.put(SubscriptionManager.GROUP_OWNER, configPackageName);
- if (DBG) logd("Group Added for" + currentSubId);
- } else {
- loge("configPackageName " + configPackageName + " doesn't own grouUuid "
+ cv.put(SubscriptionManager.GROUP_UUID, groupUuid.toString());
+ cv.put(SubscriptionManager.GROUP_OWNER, configPackageName);
+ if (DBG) logd("Group Added for" + currentSubId);
+ } else {
+ loge("configPackageName " + configPackageName + " doesn't own grouUuid "
+ groupUuid);
+ }
+ } catch (IllegalArgumentException e) {
+ loge("Invalid Group UUID=" + groupUuidString);
}
- } catch (IllegalArgumentException e) {
- loge("Invalid Group UUID=" + groupUuidString);
}
}
if (cv.size() > 0 && mContext.getContentResolver().update(SubscriptionManager
diff --git a/src/java/com/android/internal/telephony/cdma/CdmaInboundSmsHandler.java b/src/java/com/android/internal/telephony/cdma/CdmaInboundSmsHandler.java
index ec14efa..5eadd86 100644
--- a/src/java/com/android/internal/telephony/cdma/CdmaInboundSmsHandler.java
+++ b/src/java/com/android/internal/telephony/cdma/CdmaInboundSmsHandler.java
@@ -152,6 +152,12 @@
mServiceCategoryProgramHandler.dispatchSmsMessage(sms);
return Intents.RESULT_SMS_HANDLED;
+ case SmsEnvelope.TELESERVICE_FDEA_WAP:
+ if (!sms.preprocessCdmaFdeaWap()) {
+ return Intents.RESULT_SMS_HANDLED;
+ }
+ teleService = SmsEnvelope.TELESERVICE_WAP;
+ // fall through
case SmsEnvelope.TELESERVICE_WAP:
// handled below, after storage check
break;
diff --git a/src/java/com/android/internal/telephony/dataconnection/DcController.java b/src/java/com/android/internal/telephony/dataconnection/DcController.java
index ed2bc82..5901985 100644
--- a/src/java/com/android/internal/telephony/dataconnection/DcController.java
+++ b/src/java/com/android/internal/telephony/dataconnection/DcController.java
@@ -18,10 +18,8 @@
import android.content.Context;
import android.hardware.radio.V1_4.DataConnActiveStatus;
-import android.net.INetworkPolicyListener;
import android.net.LinkAddress;
import android.net.LinkProperties.CompareResult;
-import android.net.NetworkPolicyManager;
import android.net.NetworkUtils;
import android.os.AsyncResult;
import android.os.Build;
@@ -69,7 +67,6 @@
private DccDefaultState mDccDefaultState = new DccDefaultState();
final TelephonyManager mTelephonyManager;
- final NetworkPolicyManager mNetworkPolicyManager;
private PhoneStateListener mPhoneStateListener;
@@ -107,8 +104,6 @@
mTelephonyManager = (TelephonyManager) phone.getContext()
.getSystemService(Context.TELEPHONY_SERVICE);
- mNetworkPolicyManager = (NetworkPolicyManager) phone.getContext()
- .getSystemService(Context.NETWORK_POLICY_SERVICE);
mDcTesterDeactivateAll = (Build.IS_DEBUGGABLE)
? new DcTesterDeactivateAll(mPhone, DcController.this, getHandler())
@@ -173,21 +168,6 @@
return mExecutingCarrierChange;
}
- private final INetworkPolicyListener mListener = new NetworkPolicyManager.Listener() {
- @Override
- public void onSubscriptionOverride(int subId, int overrideMask, int overrideValue) {
- if (mPhone == null || mPhone.getSubId() != subId) return;
-
- final HashMap<Integer, DataConnection> dcListActiveByCid;
- synchronized (mDcListAll) {
- dcListActiveByCid = new HashMap<>(mDcListActiveByCid);
- }
- for (DataConnection dc : dcListActiveByCid.values()) {
- dc.onSubscriptionOverride(overrideMask, overrideValue);
- }
- }
- };
-
private class DccDefaultState extends State {
@Override
public void enter() {
@@ -199,10 +179,6 @@
mDataServiceManager.registerForDataCallListChanged(getHandler(),
DataConnection.EVENT_DATA_STATE_CHANGED);
-
- if (mNetworkPolicyManager != null) {
- mNetworkPolicyManager.registerListener(mListener);
- }
}
@Override
@@ -216,9 +192,6 @@
if (mDcTesterDeactivateAll != null) {
mDcTesterDeactivateAll.dispose();
}
- if (mNetworkPolicyManager != null) {
- mNetworkPolicyManager.unregisterListener(mListener);
- }
}
@Override
diff --git a/src/java/com/android/internal/telephony/dataconnection/DcTracker.java b/src/java/com/android/internal/telephony/dataconnection/DcTracker.java
index a88b90b..ab3183c 100644
--- a/src/java/com/android/internal/telephony/dataconnection/DcTracker.java
+++ b/src/java/com/android/internal/telephony/dataconnection/DcTracker.java
@@ -17,6 +17,8 @@
package com.android.internal.telephony.dataconnection;
import static android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE;
+import static android.net.NetworkPolicyManager.OVERRIDE_UNMETERED;
+import static android.telephony.NetworkRegistrationInfo.NR_STATE_CONNECTED;
import static android.telephony.TelephonyManager.NETWORK_TYPE_LTE;
import static android.telephony.TelephonyManager.NETWORK_TYPE_NR;
@@ -41,10 +43,12 @@
import android.database.ContentObserver;
import android.database.Cursor;
import android.net.ConnectivityManager;
+import android.net.INetworkPolicyListener;
import android.net.LinkProperties;
import android.net.NetworkAgent;
import android.net.NetworkCapabilities;
import android.net.NetworkConfig;
+import android.net.NetworkPolicyManager;
import android.net.NetworkRequest;
import android.net.ProxyInfo;
import android.net.TrafficStats;
@@ -78,6 +82,7 @@
import android.telephony.SubscriptionManager;
import android.telephony.SubscriptionManager.OnSubscriptionsChangedListener;
import android.telephony.TelephonyManager;
+import android.telephony.TelephonyManager.NetworkType;
import android.telephony.cdma.CdmaCellLocation;
import android.telephony.data.ApnSetting;
import android.telephony.data.ApnSetting.ApnType;
@@ -331,6 +336,20 @@
private final LocalLog mDataRoamingLeakageLog = new LocalLog(50);
private final LocalLog mApnSettingsInitializationLog = new LocalLog(50);
+ /* Default for 5G connection reevaluation alarm durations */
+ private long mHysteresisTimeMs = 0;
+ private long mWatchdogTimeMs = 1000 * 60 * 60;
+
+ /* Used to check whether 5G timers are currently active and waiting to go off */
+ private boolean mHysteresis = false;
+ private boolean mWatchdog = false;
+
+ /* Used to check whether phone was recently connected to 5G. */
+ private boolean m5GWasConnected = false;
+
+ /* Used to keep track of unmetered overrides per network type */
+ private long mUnmeteredOverrideBitMask = 0;
+
private final BroadcastReceiver mIntentReceiver = new BroadcastReceiver () {
@Override
public void onReceive(Context context, Intent intent) {
@@ -361,6 +380,17 @@
if (mIccRecords.get() != null && mIccRecords.get().getRecordsLoaded()) {
setDefaultDataRoamingEnabled();
}
+ CarrierConfigManager configManager = (CarrierConfigManager) mPhone.getContext()
+ .getSystemService(Context.CARRIER_CONFIG_SERVICE);
+ if (configManager != null) {
+ PersistableBundle b = configManager.getConfigForSubId(mPhone.getSubId());
+ if (b != null) {
+ mHysteresisTimeMs = b.getLong(
+ CarrierConfigManager.KEY_5G_ICON_DISPLAY_GRACE_PERIOD_SEC_INT);
+ mWatchdogTimeMs = b.getLong(
+ CarrierConfigManager.KEY_5G_WATCHDOG_TIME_MS_LONG);
+ }
+ }
} else {
if (DBG) log("onReceive: Unknown action=" + action);
}
@@ -414,6 +444,23 @@
}
};
+ private NetworkPolicyManager mNetworkPolicyManager;
+ private final INetworkPolicyListener mNetworkPolicyListener =
+ new NetworkPolicyManager.Listener() {
+ @Override
+ public void onSubscriptionOverride(int subId, int overrideMask, int overrideValue,
+ long networkTypeMask) {
+ if (mPhone == null || mPhone.getSubId() != subId) return;
+
+ if (overrideMask == OVERRIDE_UNMETERED) {
+ mUnmeteredOverrideBitMask = overrideValue == 0 ? 0 : networkTypeMask;
+ reevaluateUnmeteredConnections();
+ } else {
+ overrideDataConnections(overrideMask, overrideValue);
+ }
+ }
+ };
+
private final SettingsObserver mSettingsObserver;
private void registerSettingsObserver() {
@@ -727,6 +774,9 @@
mSubscriptionManager = SubscriptionManager.from(mPhone.getContext());
mSubscriptionManager.addOnSubscriptionsChangedListener(mOnSubscriptionsChangedListener);
+ mNetworkPolicyManager = NetworkPolicyManager.from(mPhone.getContext());
+ mNetworkPolicyManager.registerListener(mNetworkPolicyListener);
+
HandlerThread dcHandlerThread = new HandlerThread("DcHandlerThread");
dcHandlerThread.start();
Handler dcHandler = new Handler(dcHandlerThread.getLooper());
@@ -788,6 +838,7 @@
DctConstants.EVENT_PS_RESTRICT_DISABLED, null);
mPhone.getServiceStateTracker().registerForDataRegStateOrRatChanged(mTransportType, this,
DctConstants.EVENT_DATA_RAT_CHANGED, null);
+ mPhone.registerForServiceStateChanged(this, DctConstants.EVENT_5G_NETWORK_CHANGED, null);
}
public void unregisterServiceStateTrackerEvents() {
@@ -799,6 +850,7 @@
mPhone.getServiceStateTracker().unregisterForPsRestrictedDisabled(this);
mPhone.getServiceStateTracker().unregisterForDataRegStateOrRatChanged(mTransportType,
this);
+ mPhone.unregisterForServiceStateChanged(this);
}
private void registerForAllEvents() {
@@ -844,6 +896,7 @@
mSubscriptionManager
.removeOnSubscriptionsChangedListener(mOnSubscriptionsChangedListener);
+ mNetworkPolicyManager.unregisterListener(mNetworkPolicyListener);
mDcc.dispose();
mDcTesterFailBringUpAll.dispose();
@@ -896,6 +949,12 @@
}
}
+ private void overrideDataConnections(int overrideMask, int overrideValue) {
+ for (DataConnection dataConnection : mDataConnections.values()) {
+ dataConnection.onSubscriptionOverride(overrideMask, overrideValue);
+ }
+ }
+
public long getSubId() {
return mPhone.getSubId();
}
@@ -3808,6 +3867,17 @@
case DctConstants.EVENT_DATA_ENABLED_OVERRIDE_RULES_CHANGED:
onDataEnabledOverrideRulesChanged();
break;
+ case DctConstants.EVENT_5G_NETWORK_CHANGED:
+ reevaluateUnmeteredConnections();
+ break;
+ case DctConstants.EVENT_5G_TIMER_HYSTERESIS:
+ reevaluateUnmeteredConnections();
+ mHysteresis = false;
+ break;
+ case DctConstants.EVENT_5G_TIMER_WATCHDOG:
+ mWatchdog = false;
+ reevaluateUnmeteredConnections();
+ break;
default:
Rlog.e("DcTracker", "Unhandled event=" + msg);
break;
@@ -3966,6 +4036,53 @@
}
}
+ private void reevaluateUnmeteredConnections() {
+ if (isNetworkTypeUnmetered(NETWORK_TYPE_NR)) {
+ if (mPhone.getServiceState().getNrState() == NR_STATE_CONNECTED) {
+ if (!m5GWasConnected) { //4G -> 5G
+ stopHysteresisAlarm();
+ overrideDataConnections(OVERRIDE_UNMETERED, OVERRIDE_UNMETERED);
+ }
+ if (!mWatchdog) {
+ startWatchdogAlarm();
+ }
+ m5GWasConnected = true;
+ } else {
+ if (m5GWasConnected) { //5G -> 4G
+ if (!mHysteresis && !startHysteresisAlarm()) {
+ // hysteresis is not active but carrier does not support hysteresis
+ stopWatchdogAlarm();
+ overrideMeterednessForNetworkType(
+ mTelephonyManager.getNetworkType(mPhone.getSubId()));
+ }
+ m5GWasConnected = false;
+ } else { //4G -> 4G
+ if (!hasMessages(DctConstants.EVENT_5G_TIMER_HYSTERESIS)) {
+ stopWatchdogAlarm();
+ overrideMeterednessForNetworkType(
+ mTelephonyManager.getNetworkType(mPhone.getSubId()));
+ }
+ // do nothing if waiting for hysteresis alarm to go off
+ }
+ }
+ } else {
+ stopWatchdogAlarm();
+ stopHysteresisAlarm();
+ overrideMeterednessForNetworkType(mTelephonyManager.getNetworkType(mPhone.getSubId()));
+ m5GWasConnected = false;
+ }
+ }
+
+ private void overrideMeterednessForNetworkType(@NetworkType int networkType) {
+ int overrideValue = isNetworkTypeUnmetered(networkType) ? OVERRIDE_UNMETERED : 0;
+ overrideDataConnections(OVERRIDE_UNMETERED, overrideValue);
+ }
+
+ private boolean isNetworkTypeUnmetered(@NetworkType int networkType) {
+ long networkTypeMask = TelephonyManager.getBitMaskForNetworkType(networkType);
+ return (mUnmeteredOverrideBitMask & networkTypeMask) == networkTypeMask;
+ }
+
private void log(String s) {
Rlog.d(mLogTag, s);
}
@@ -4779,6 +4896,37 @@
}
}
+ /**
+ * 5G connection reevaluation alarms
+ */
+ private boolean startHysteresisAlarm() {
+ if (mHysteresisTimeMs > 0) {
+ // only create hysteresis alarm if CarrierConfig allows it
+ sendMessageDelayed(obtainMessage(DctConstants.EVENT_5G_TIMER_HYSTERESIS),
+ mHysteresisTimeMs);
+ mHysteresis = true;
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ private void stopHysteresisAlarm() {
+ removeMessages(DctConstants.EVENT_5G_TIMER_HYSTERESIS);
+ mHysteresis = false;
+ }
+
+ private void startWatchdogAlarm() {
+ sendMessageDelayed(obtainMessage(DctConstants.EVENT_5G_TIMER_WATCHDOG),
+ mWatchdogTimeMs);
+ mWatchdog = true;
+ }
+
+ private void stopWatchdogAlarm() {
+ removeMessages(DctConstants.EVENT_5G_TIMER_WATCHDOG);
+ mWatchdog = false;
+ }
+
private static DataProfile createDataProfile(ApnSetting apn, boolean isPreferred) {
return createDataProfile(apn, apn.getProfileId(), isPreferred);
}
diff --git a/src/java/com/android/internal/telephony/dataconnection/TelephonyNetworkFactory.java b/src/java/com/android/internal/telephony/dataconnection/TelephonyNetworkFactory.java
index d60efaf..382c1d6 100644
--- a/src/java/com/android/internal/telephony/dataconnection/TelephonyNetworkFactory.java
+++ b/src/java/com/android/internal/telephony/dataconnection/TelephonyNetworkFactory.java
@@ -357,6 +357,7 @@
+ "connection. Just move the request to transport "
+ AccessNetworkConstants.transportTypeToString(targetTransport)
+ ", dc=" + dc);
+ entry.setValue(targetTransport);
releaseNetworkInternal(networkRequest, DcTracker.RELEASE_TYPE_NORMAL,
currentTransport);
requestNetworkInternal(networkRequest, DcTracker.REQUEST_TYPE_NORMAL,
diff --git a/src/java/com/android/internal/telephony/dataconnection/TransportManager.java b/src/java/com/android/internal/telephony/dataconnection/TransportManager.java
index 43275ec..ff72919 100644
--- a/src/java/com/android/internal/telephony/dataconnection/TransportManager.java
+++ b/src/java/com/android/internal/telephony/dataconnection/TransportManager.java
@@ -208,7 +208,9 @@
public final @ApnType int apnType;
public final int targetTransport;
public final HandoverCallback callback;
- HandoverParams(int apnType, int targetTransport, HandoverCallback callback) {
+
+ @VisibleForTesting
+ public HandoverParams(int apnType, int targetTransport, HandoverCallback callback) {
this.apnType = apnType;
this.targetTransport = targetTransport;
this.callback = callback;
diff --git a/src/java/com/android/internal/telephony/ims/ImsResolver.java b/src/java/com/android/internal/telephony/ims/ImsResolver.java
index 78e416f..7558071 100644
--- a/src/java/com/android/internal/telephony/ims/ImsResolver.java
+++ b/src/java/com/android/internal/telephony/ims/ImsResolver.java
@@ -41,15 +41,20 @@
import android.telephony.ims.aidl.IImsRcsFeature;
import android.telephony.ims.aidl.IImsRegistration;
import android.telephony.ims.feature.ImsFeature;
+import android.telephony.ims.feature.MmTelFeature;
import android.telephony.ims.stub.ImsFeatureConfiguration;
import android.text.TextUtils;
+import android.util.LocalLog;
import android.util.Log;
import android.util.SparseArray;
import com.android.ims.internal.IImsServiceFeatureCallback;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.os.SomeArgs;
+import com.android.internal.util.IndentingPrintWriter;
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
@@ -169,18 +174,12 @@
@Override
public String toString() {
- StringBuilder res = new StringBuilder();
- res.append("[ImsServiceInfo] name=");
- res.append(name);
- res.append(", supportedFeatures=[ ");
- for (ImsFeatureConfiguration.FeatureSlotPair feature : mSupportedFeatures) {
- res.append("(");
- res.append(feature.slotId);
- res.append(",");
- res.append(ImsFeature.FEATURE_LOG_MAP.get(feature.featureType));
- res.append(") ");
- }
- return res.toString();
+ return "[ImsServiceInfo] name="
+ + name
+ + ", featureFromMetadata="
+ + featureFromMetadata
+ + ","
+ + printFeatures(mSupportedFeatures);
}
}
@@ -387,6 +386,8 @@
private final boolean mIsDynamicBinding;
// Package name of the default device service.
private String mDeviceService;
+ // Persistent Logging
+ private final LocalLog mEventLog = new LocalLog(50);
// Synchronize all messages on a handler to ensure that the cache includes the most recent
// version of the installed ImsServices.
@@ -403,6 +404,7 @@
break;
}
case HANDLER_BOOT_COMPLETE: {
+ mEventLog.log("handling BOOT_COMPLETE");
// Re-evaluate bound services for all slots after requerying packagemanager
maybeAddedImsService(null);
break;
@@ -437,6 +439,7 @@
overrideService(slotId, packageName);
} else {
Log.i(TAG, "overriding device ImsService - packageName=" + packageName);
+ mEventLog.log("overriding device ImsService with " + packageName);
if (TextUtils.equals(mDeviceService, packageName)) {
// No change in device service.
break;
@@ -479,12 +482,14 @@
@Override
public void onError(ComponentName name) {
Log.w(TAG, "onError: " + name + "returned with an error result");
+ mEventLog.log("onError - dynamic query error for " + name);
scheduleQueryForFeatures(name, DELAY_DYNAMIC_QUERY_MS);
}
@Override
public void onPermanentError(ComponentName name) {
Log.w(TAG, "onPermanentError: component=" + name);
+ mEventLog.log("onPermanentError - error for " + name);
mHandler.obtainMessage(HANDLER_REMOVE_PACKAGE,
name.getPackageName()).sendToTarget();
}
@@ -571,6 +576,7 @@
* Needs to be called after the constructor to kick off the process of binding to ImsServices.
*/
public void initialize() {
+ mEventLog.log("Initializing");
Log.i(TAG, "Initializing cache.");
mFeatureQueryManager = mDynamicQueryManagerFactory.create(mContext, mDynamicQueryListener);
@@ -591,6 +597,7 @@
String newPackageName = config.getString(
CarrierConfigManager.KEY_CONFIG_IMS_PACKAGE_OVERRIDE_STRING, null);
if (!TextUtils.isEmpty(newPackageName)) {
+ mEventLog.log("Initializing: found carrier package.");
updateBoundCarrierServices(i, newPackageName);
Log.i(TAG, "Initializing, found package " + newPackageName + " on slot "
+ i);
@@ -767,6 +774,8 @@
services = new SparseArray<>();
mBoundImsServicesByFeature.add(slotId, services);
}
+ mEventLog.log("putImsController - [" + slotId + ", "
+ + ImsFeature.FEATURE_LOG_MAP.get(feature) + "] -> " + controller);
Log.i(TAG, "ImsServiceController added on slot: " + slotId + " with feature: "
+ ImsFeature.FEATURE_LOG_MAP.get(feature) + " using package: "
+ controller.getComponentName());
@@ -788,6 +797,8 @@
}
ImsServiceController c = services.get(feature, null);
if (c != null) {
+ mEventLog.log("removeImsController - [" + slotId + ", "
+ + ImsFeature.FEATURE_LOG_MAP.get(feature) + "] -> " + c);
Log.i(TAG, "ImsServiceController removed on slot: " + slotId + " with feature: "
+ ImsFeature.FEATURE_LOG_MAP.get(feature) + " using package: "
+ c.getComponentName());
@@ -813,18 +824,23 @@
// out the cache for the existing features or update yet. Instead start a query
// for features dynamically.
if (info.featureFromMetadata) {
- // update features in the cache
+ mEventLog.log("maybeAddedImsService - updating features for " + info.name
+ + ": " + printFeatures(match.getSupportedFeatures()) + " -> "
+ + printFeatures(info.getSupportedFeatures()));
Log.i(TAG, "Updating features in cached ImsService: " + info.name);
Log.d(TAG, "Updating features - Old features: " + match + " new features: "
+ info);
+ // update features in the cache
match.replaceFeatures(info.getSupportedFeatures());
updateImsServiceFeatures(info);
} else {
+ mEventLog.log("maybeAddedImsService - scheduling query for " + info);
// start a query to get ImsService features
scheduleQueryForFeatures(info);
}
} else {
Log.i(TAG, "Adding newly added ImsService to cache: " + info.name);
+ mEventLog.log("maybeAddedImsService - adding new ImsService: " + info);
mInstalledServicesCache.put(info.name, info);
if (info.featureFromMetadata) {
newlyAddedInfos.add(info);
@@ -858,6 +874,7 @@
ImsServiceInfo match = getInfoByPackageName(mInstalledServicesCache, packageName);
if (match != null) {
mInstalledServicesCache.remove(match.name);
+ mEventLog.log("maybeRemovedImsService - removing ImsService: " + match);
Log.i(TAG, "Removing ImsService: " + match.name);
unbindImsService(match);
updateImsServiceFeatures(getImsServiceInfoFromCache(mDeviceService));
@@ -980,6 +997,8 @@
Log.i(TAG, "Binding ImsService: " + controller.getComponentName()
+ " with features: " + features);
controller.bind(features);
+ mEventLog.log("bindImsServiceWithFeatures - create new controller: "
+ + controller);
}
mActiveControllers.put(info.name, controller);
}
@@ -995,6 +1014,7 @@
// Calls imsServiceFeatureRemoved on all features in the controller
try {
Log.i(TAG, "Unbinding ImsService: " + controller.getComponentName());
+ mEventLog.log("unbindImsService - unbinding and removing " + controller);
controller.unbind();
} catch (RemoteException e) {
Log.e(TAG, "unbindImsService: Remote Exception: " + e.getMessage());
@@ -1074,6 +1094,8 @@
}
Log.i(TAG, "imsServiceFeaturesChanged: config=" + config.getServiceFeatures()
+ ", ComponentName=" + controller.getComponentName());
+ mEventLog.log("imsServiceFeaturesChanged - for " + controller + ", new config "
+ + config.getServiceFeatures());
handleFeaturesChanged(controller.getComponentName(), config.getServiceFeatures());
}
@@ -1083,6 +1105,7 @@
return;
}
Log.w(TAG, "imsServiceBindPermanentError: component=" + name);
+ mEventLog.log("imsServiceBindPermanentError - for " + name);
mHandler.obtainMessage(HANDLER_REMOVE_PACKAGE, name.getPackageName()).sendToTarget();
}
@@ -1103,6 +1126,8 @@
// Possibly rebind to another ImsService for testing.
// Called from the handler ONLY
private void overrideService(int slotId, String newPackageName) {
+ mEventLog.log("overriding carrier ImsService to " + newPackageName
+ + " on slot " + slotId);
if (slotId <= SubscriptionManager.INVALID_SIM_SLOT_INDEX) {
// not specified, replace package on all slots.
for (int i = 0; i < mNumSlots; i++) {
@@ -1143,6 +1168,8 @@
mCarrierServices[slotId] = newPackageName;
if (!TextUtils.equals(newPackageName, oldPackageName)) {
Log.i(TAG, "Carrier Config updated, binding new ImsService");
+ mEventLog.log("updateBoundCarrierServices - carrier package changed: "
+ + oldPackageName + " -> " + newPackageName + " on slot " + slotId);
// Unbind old ImsService, not needed anymore
// ImsService is retrieved from the cache. If the cache hasn't been populated yet,
// the calls to unbind/bind will fail (intended during initial start up).
@@ -1152,12 +1179,16 @@
// if there is no carrier ImsService, newInfo is null. This we still want to update
// bindings for device ImsService to pick up the missing features.
if (newInfo == null || newInfo.featureFromMetadata) {
+ mEventLog.log("updateBoundCarrierServices - recalculating bindings "
+ + (newInfo != null ? newInfo : "for device"));
bindImsService(newInfo);
// Recalculate the device ImsService features to reflect changes.
updateImsServiceFeatures(getImsServiceInfoFromCache(mDeviceService));
} else {
// ImsServiceInfo that has not had features queried yet. Start async
// bind and query features.
+ mEventLog.log("updateBoundCarrierServices - scheduling feature query for "
+ + newInfo);
scheduleQueryForFeatures(newInfo);
}
}
@@ -1212,10 +1243,13 @@
// Starts a dynamic query. Called from handler ONLY.
private void startDynamicQuery(ImsServiceInfo service) {
+ mEventLog.log("startDynamicQuery - starting query for " + service);
boolean queryStarted = mFeatureQueryManager.startQuery(service.name,
service.controllerFactory.getServiceInterface());
if (!queryStarted) {
Log.w(TAG, "startDynamicQuery: service could not connect. Retrying after delay.");
+ mEventLog.log("startDynamicQuery - query failed. Retrying in "
+ + DELAY_DYNAMIC_QUERY_MS + " mS");
scheduleQueryForFeatures(service, DELAY_DYNAMIC_QUERY_MS);
} else {
Log.d(TAG, "startDynamicQuery: Service queried, waiting for response.");
@@ -1231,6 +1265,8 @@
+ name);
return;
}
+ mEventLog.log("dynamicQueryComplete for package " + name + ", features: "
+ + printFeatures(service.getSupportedFeatures()) + " -> " + printFeatures(features));
// Add features to service
service.replaceFeatures(features);
if (isActiveCarrierService(service)) {
@@ -1245,7 +1281,7 @@
}
}
- private String printFeatures(Set<ImsFeatureConfiguration.FeatureSlotPair> features) {
+ private static String printFeatures(Set<ImsFeatureConfiguration.FeatureSlotPair> features) {
StringBuilder featureString = new StringBuilder();
featureString.append(" features: [");
if (features != null) {
@@ -1254,7 +1290,7 @@
featureString.append(feature.slotId);
featureString.append(",");
featureString.append(ImsFeature.FEATURE_LOG_MAP.get(feature.featureType));
- featureString.append("} ");
+ featureString.append("}");
}
featureString.append("]");
}
@@ -1372,4 +1408,55 @@
}
return infos;
}
+
+ // Dump is called on the main thread, since ImsResolver Handler is also handled on main thread,
+ // we shouldn't need to worry about concurrent access of private params.
+ public void dump(FileDescriptor fd, PrintWriter printWriter, String[] args) {
+ IndentingPrintWriter pw = new IndentingPrintWriter(printWriter, " ");
+ pw.println("ImsResolver:");
+ pw.increaseIndent();
+ pw.println("mIsDynamicBinding = " + mIsDynamicBinding);
+ pw.println("mDeviceService = " + mDeviceService);
+ pw.println("mCarrierServices: ");
+ pw.increaseIndent();
+ for (String s : mCarrierServices) {
+ pw.println(s);
+ }
+ pw.decreaseIndent();
+ pw.println("Bound Features:");
+ pw.increaseIndent();
+ for (int i = 0; i < mNumSlots; i++) {
+ for (int j = 0; j < MmTelFeature.FEATURE_MAX; j++) {
+ pw.print("slot=");
+ pw.print(i);
+ pw.print(", feature=");
+ pw.print(MmTelFeature.FEATURE_LOG_MAP.getOrDefault(j, "?"));
+ pw.println(": ");
+ pw.increaseIndent();
+ ImsServiceController c = getImsServiceController(i, j);
+ pw.println(c == null ? "none" : c);
+ pw.decreaseIndent();
+ }
+ }
+ pw.decreaseIndent();
+ pw.println("Cached ImsServices:");
+ pw.increaseIndent();
+ for (ImsServiceInfo i : mInstalledServicesCache.values()) {
+ pw.println(i);
+ }
+ pw.decreaseIndent();
+ pw.println("Active controllers:");
+ pw.increaseIndent();
+ for (ImsServiceController c : mActiveControllers.values()) {
+ pw.println(c);
+ pw.increaseIndent();
+ c.dump(pw);
+ pw.decreaseIndent();
+ }
+ pw.decreaseIndent();
+ pw.println("Event Log:");
+ pw.increaseIndent();
+ mEventLog.dump(pw);
+ pw.decreaseIndent();
+ }
}
diff --git a/src/java/com/android/internal/telephony/ims/ImsServiceController.java b/src/java/com/android/internal/telephony/ims/ImsServiceController.java
index f9658bd..dbd434f 100644
--- a/src/java/com/android/internal/telephony/ims/ImsServiceController.java
+++ b/src/java/com/android/internal/telephony/ims/ImsServiceController.java
@@ -36,6 +36,7 @@
import android.telephony.ims.aidl.IImsServiceController;
import android.telephony.ims.feature.ImsFeature;
import android.telephony.ims.stub.ImsFeatureConfiguration;
+import android.util.LocalLog;
import android.util.Log;
import com.android.ims.internal.IImsFeatureStatusCallback;
@@ -43,6 +44,7 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.telephony.ExponentialBackoff;
+import java.io.PrintWriter;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
@@ -73,6 +75,7 @@
mIsBound = true;
mIsBinding = false;
try {
+ mLocalLog.log("onServiceConnected");
Log.d(LOG_TAG, "ImsService(" + name + "): onServiceConnected with binder: "
+ service);
setServiceController(service);
@@ -87,6 +90,8 @@
// Remote exception means that the binder already died.
cleanupConnection();
startDelayedRebindToService();
+ mLocalLog.log("onConnected exception=" + e.getMessage() + ", retry in "
+ + mBackoff.getCurrentDelay() + " mS");
Log.e(LOG_TAG, "ImsService(" + name + ") RemoteException:"
+ e.getMessage());
}
@@ -99,6 +104,7 @@
mIsBinding = false;
}
cleanupConnection();
+ mLocalLog.log("onServiceDisconnected");
Log.w(LOG_TAG, "ImsService(" + name + "): onServiceDisconnected. Waiting...");
// Service disconnected, but we are still technically bound. Waiting for reconnect.
}
@@ -114,11 +120,13 @@
mContext.unbindService(mImsServiceConnection);
Log.w(LOG_TAG, "ImsService(" + name + "): onBindingDied. Starting rebind...");
startDelayedRebindToService();
+ mLocalLog.log("onBindingDied, retrying in " + mBackoff.getCurrentDelay() + " mS");
}
@Override
public void onNullBinding(ComponentName name) {
Log.w(LOG_TAG, "ImsService(" + name + "): onNullBinding. Removing.");
+ mLocalLog.log("onNullBinding");
synchronized (mLock) {
mIsBinding = false;
mIsBound = false;
@@ -137,16 +145,6 @@
}
}
- private ImsService.Listener mFeatureChangedListener = new ImsService.Listener() {
- @Override
- public void onUpdateSupportedImsFeatures(ImsFeatureConfiguration c) {
- if (mCallbacks == null) {
- return;
- }
- mCallbacks.imsServiceFeaturesChanged(c, ImsServiceController.this);
- }
- };
-
/**
* Defines callbacks that are used by the ImsServiceController to notify when an ImsService
* has created or removed a new feature as well as the associated ImsServiceController.
@@ -213,10 +211,22 @@
private Set<IImsServiceFeatureCallback> mImsStatusCallbacks = ConcurrentHashMap.newKeySet();
// Only added or removed, never accessed on purpose.
private Set<ImsFeatureStatusCallback> mFeatureStatusCallbacks = new HashSet<>();
+ private final LocalLog mLocalLog = new LocalLog(10);
protected final Object mLock = new Object();
protected final Context mContext;
+ private ImsService.Listener mFeatureChangedListener = new ImsService.Listener() {
+ @Override
+ public void onUpdateSupportedImsFeatures(ImsFeatureConfiguration c) {
+ if (mCallbacks == null) {
+ return;
+ }
+ mLocalLog.log("onUpdateSupportedImsFeatures to " + c.getServiceFeatures());
+ mCallbacks.imsServiceFeaturesChanged(c, ImsServiceController.this);
+ }
+ };
+
private class ImsFeatureContainer {
public int slotId;
public int featureType;
@@ -361,17 +371,22 @@
mImsServiceConnection = new ImsServiceConnection();
int serviceFlags = Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE
| Context.BIND_IMPORTANT;
+ mLocalLog.log("binding " + imsFeatureSet);
Log.i(LOG_TAG, "Binding ImsService:" + mComponentName);
try {
boolean bindSucceeded = startBindToService(imsServiceIntent,
mImsServiceConnection, serviceFlags);
if (!bindSucceeded) {
+ mLocalLog.log(" binding failed, retrying in "
+ + mBackoff.getCurrentDelay() + " mS");
mIsBinding = false;
mBackoff.notifyFailed();
}
return bindSucceeded;
} catch (Exception e) {
mBackoff.notifyFailed();
+ mLocalLog.log(" binding exception=" + e.getMessage() + ", retrying in "
+ + mBackoff.getCurrentDelay() + " mS");
Log.e(LOG_TAG, "Error binding (" + mComponentName + ") with exception: "
+ e.getMessage() + ", rebinding in " + mBackoff.getCurrentDelay()
+ " ms");
@@ -406,6 +421,7 @@
changeImsServiceFeatures(new HashSet<>());
removeImsServiceFeatureCallbacks();
Log.i(LOG_TAG, "Unbinding ImsService: " + mComponentName);
+ mLocalLog.log("unbinding");
mContext.unbindService(mImsServiceConnection);
mIsBound = false;
mIsBinding = false;
@@ -424,6 +440,7 @@
if (mImsFeatures.equals(newImsFeatures)) {
return;
}
+ mLocalLog.log("Features changed (" + mImsFeatures + "->" + newImsFeatures + ")");
Log.i(LOG_TAG, "Features changed (" + mImsFeatures + "->" + newImsFeatures + ") for "
+ "ImsService: " + mComponentName);
HashSet<ImsFeatureConfiguration.FeatureSlotPair> oldImsFeatures =
@@ -615,6 +632,7 @@
// Grant runtime permissions to ImsService. PermissionManager ensures that the ImsService is
// system/signed before granting permissions.
private void grantPermissionsToService() {
+ mLocalLog.log("grant permissions to " + getComponentName());
Log.i(LOG_TAG, "Granting Runtime permissions to:" + getComponentName());
String[] pkgToGrant = {mComponentName.getPackageName()};
try {
@@ -796,4 +814,18 @@
setServiceController(null);
}
}
+
+ @Override
+ public String toString() {
+ synchronized (mLock) {
+ return "[ImsServiceController: componentName=" + getComponentName() + ", features="
+ + mImsFeatures + ", isBinding=" + mIsBinding + ", isBound=" + mIsBound
+ + ", serviceController=" + getImsServiceController() + ", rebindDelay="
+ + getRebindDelay() + "]";
+ }
+ }
+
+ public void dump(PrintWriter printWriter) {
+ mLocalLog.dump(printWriter);
+ }
}
diff --git a/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java b/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java
index 6509be8..9eacadf 100644
--- a/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java
+++ b/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java
@@ -1216,6 +1216,7 @@
logi("Ignoring hold request while already holding or swapping");
return;
}
+ HoldSwapState oldHoldState = mHoldSwitchingState;
ImsCall callToHold = mForegroundCall.getImsCall();
mHoldSwitchingState = HoldSwapState.HOLDING_TO_DIAL_OUTGOING;
@@ -1228,6 +1229,8 @@
ImsCommand.IMS_CMD_HOLD);
} catch (ImsException e) {
mForegroundCall.switchWith(mBackgroundCall);
+ mHoldSwitchingState = oldHoldState;
+ logHoldSwapState("holdActiveCallForPendingMo - fail");
throw new CallStateException(e.getMessage());
}
}
@@ -1242,6 +1245,7 @@
logi("Ignoring hold request while already holding or swapping");
return;
}
+ HoldSwapState oldHoldState = mHoldSwitchingState;
ImsCall callToHold = mForegroundCall.getImsCall();
if (mBackgroundCall.getState().isAlive()) {
mCallExpectedToResume = mBackgroundCall.getImsCall();
@@ -1257,6 +1261,8 @@
ImsCommand.IMS_CMD_HOLD);
} catch (ImsException e) {
mForegroundCall.switchWith(mBackgroundCall);
+ mHoldSwitchingState = oldHoldState;
+ logHoldSwapState("holdActiveCall - fail");
throw new CallStateException(e.getMessage());
}
}
@@ -1270,6 +1276,7 @@
&& mRingingCall.getState() == ImsPhoneCall.State.WAITING;
if (switchingWithWaitingCall) {
ImsCall callToHold = mForegroundCall.getImsCall();
+ HoldSwapState oldHoldState = mHoldSwitchingState;
mHoldSwitchingState = HoldSwapState.HOLDING_TO_ANSWER_INCOMING;
mForegroundCall.switchWith(mBackgroundCall);
logHoldSwapState("holdActiveCallForWaitingCall");
@@ -1279,6 +1286,8 @@
ImsCommand.IMS_CMD_HOLD);
} catch (ImsException e) {
mForegroundCall.switchWith(mBackgroundCall);
+ mHoldSwitchingState = oldHoldState;
+ logHoldSwapState("holdActiveCallForWaitingCall - fail");
throw new CallStateException(e.getMessage());
}
}
@@ -1288,24 +1297,28 @@
* Unhold the currently held call.
*/
void unholdHeldCall() throws CallStateException {
- try {
- ImsCall imsCall = mBackgroundCall.getImsCall();
- if (mHoldSwitchingState == HoldSwapState.PENDING_SINGLE_CALL_UNHOLD
- || mHoldSwitchingState == HoldSwapState.SWAPPING_ACTIVE_AND_HELD) {
- logi("Ignoring unhold request while already unholding or swapping");
- return;
- }
- if (imsCall != null) {
- mCallExpectedToResume = imsCall;
- mHoldSwitchingState = HoldSwapState.PENDING_SINGLE_CALL_UNHOLD;
- mForegroundCall.switchWith(mBackgroundCall);
- logHoldSwapState("unholdCurrentCall");
+ ImsCall imsCall = mBackgroundCall.getImsCall();
+ if (mHoldSwitchingState == HoldSwapState.PENDING_SINGLE_CALL_UNHOLD
+ || mHoldSwitchingState == HoldSwapState.SWAPPING_ACTIVE_AND_HELD) {
+ logi("Ignoring unhold request while already unholding or swapping");
+ return;
+ }
+ if (imsCall != null) {
+ mCallExpectedToResume = imsCall;
+ HoldSwapState oldHoldState = mHoldSwitchingState;
+ mHoldSwitchingState = HoldSwapState.PENDING_SINGLE_CALL_UNHOLD;
+ mForegroundCall.switchWith(mBackgroundCall);
+ logHoldSwapState("unholdCurrentCall");
+ try {
imsCall.resume();
mMetrics.writeOnImsCommand(mPhone.getPhoneId(), imsCall.getSession(),
ImsCommand.IMS_CMD_RESUME);
+ } catch (ImsException e) {
+ mForegroundCall.switchWith(mBackgroundCall);
+ mHoldSwitchingState = oldHoldState;
+ logHoldSwapState("unholdCurrentCall - fail");
+ throw new CallStateException(e.getMessage());
}
- } catch (ImsException e) {
- throw new CallStateException(e.getMessage());
}
}
diff --git a/src/java/com/google/android/mms/ContentType.java b/src/java/com/google/android/mms/ContentType.java
index 24b22e8..12e4b7e 100644
--- a/src/java/com/google/android/mms/ContentType.java
+++ b/src/java/com/google/android/mms/ContentType.java
@@ -63,6 +63,7 @@
public static final String AUDIO_3GPP = "audio/3gpp";
public static final String AUDIO_X_WAV = "audio/x-wav";
public static final String AUDIO_OGG = "application/ogg";
+ public static final String AUDIO_OGG2 = "audio/ogg";
public static final String VIDEO_UNSPECIFIED = "video/*";
public static final String VIDEO_3GPP = "video/3gpp";
@@ -115,6 +116,7 @@
sSupportedContentTypes.add(AUDIO_X_WAV);
sSupportedContentTypes.add(AUDIO_3GPP);
sSupportedContentTypes.add(AUDIO_OGG);
+ sSupportedContentTypes.add(AUDIO_OGG2);
sSupportedContentTypes.add(VIDEO_3GPP);
sSupportedContentTypes.add(VIDEO_3G2);
@@ -156,6 +158,7 @@
sSupportedAudioTypes.add(AUDIO_X_WAV);
sSupportedAudioTypes.add(AUDIO_3GPP);
sSupportedAudioTypes.add(AUDIO_OGG);
+ sSupportedAudioTypes.add(AUDIO_OGG2);
// add supported video types
sSupportedVideoTypes.add(VIDEO_3GPP);
diff --git a/tests/telephonytests/src/com/android/internal/telephony/SubscriptionInfoUpdaterTest.java b/tests/telephonytests/src/com/android/internal/telephony/SubscriptionInfoUpdaterTest.java
index 0fb1253..806a8de 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/SubscriptionInfoUpdaterTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/SubscriptionInfoUpdaterTest.java
@@ -57,6 +57,7 @@
import com.android.internal.telephony.euicc.EuiccController;
import com.android.internal.telephony.uicc.IccFileHandler;
import com.android.internal.telephony.uicc.IccRecords;
+import com.android.internal.telephony.uicc.IccUtils;
import com.android.internal.telephony.uicc.UiccSlot;
import org.junit.After;
@@ -67,8 +68,6 @@
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
-import java.security.MessageDigest;
-import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
@@ -768,17 +767,13 @@
@SmallTest
public void testUpdateFromCarrierConfigCarrierCertificates() {
String[] certs = new String[2];
- certs[0] = "testCertificate";
- certs[1] = "testCertificate2";
+ certs[0] = "d1f1";
+ certs[1] = "b5d6";
UiccAccessRule[] carrierConfigAccessRules = new UiccAccessRule[certs.length];
- try {
- for (int i = 0; i < certs.length; i++) {
- carrierConfigAccessRules[i] = new UiccAccessRule(
- MessageDigest.getInstance("SHA-256").digest(certs[i].getBytes()), null, 0);
- }
- } catch (NoSuchAlgorithmException e) {
- throw new RuntimeException("for setCarrierConfigAccessRules, SHA-256 must exist", e);
+ for (int i = 0; i < certs.length; i++) {
+ carrierConfigAccessRules[i] = new UiccAccessRule(
+ IccUtils.hexStringToBytes(certs[i]), null, 0);
}
final int phoneId = mPhone.getPhoneId();
diff --git a/tests/telephonytests/src/com/android/internal/telephony/cdma/sms/CdmaSmsTest.java b/tests/telephonytests/src/com/android/internal/telephony/cdma/sms/CdmaSmsTest.java
index a315bde..069b08c 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/cdma/sms/CdmaSmsTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/cdma/sms/CdmaSmsTest.java
@@ -22,9 +22,11 @@
import com.android.internal.telephony.GsmAlphabet.TextEncodingDetails;
import com.android.internal.telephony.SmsHeader;
+import com.android.internal.telephony.SmsMessageBase;
import com.android.internal.telephony.cdma.SmsMessage;
import com.android.internal.util.HexDump;
+import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Arrays;
@@ -1033,4 +1035,34 @@
}
}
}
+
+ @SmallTest
+ public void testPreprocessFdeaWdpUserData() throws Exception {
+ // Refer to https://patents.google.com/patent/CN103906005A/en
+ String wdpUserData =
+ "0003156D60018103F80008011F805C26B031230B8383634B1B0BA34B7B717BB3732173BB0B81736B" +
+ "6B996B6B2B9B9B0B3B2805A43D7C246414C212522A3A522BD31AD3931210046C841B43A3A381D179" +
+ "798981719199A1718999B97189897A12522A3A522BD31AD393121004402C081815175C486C018999" +
+ "9989B181C9B99991C80454047011AF78";
+
+ SmsMessage cdmaSmsMessage = new SmsMessage();
+
+ Field field = SmsMessageBase.class.getDeclaredField("mUserData");
+ field.setAccessible(true);
+ field.set(cdmaSmsMessage, HexDump.hexStringToByteArray(wdpUserData));
+
+ BearerData bearerData = new BearerData();
+ bearerData.userData = new UserData();
+
+ field = SmsMessage.class.getDeclaredField("mBearerData");
+ field.setAccessible(true);
+ field.set(cdmaSmsMessage, bearerData);
+ bearerData = (BearerData) field.get(cdmaSmsMessage);
+
+ assertTrue(cdmaSmsMessage.preprocessCdmaFdeaWap());
+ assertEquals(BearerData.MESSAGE_TYPE_DELIVER, bearerData.messageType);
+ assertEquals(0x56D6, bearerData.messageId);
+ assertEquals(0x7F, bearerData.userData.numFields);
+ assertNotNull(bearerData.userData.payload);
+ }
}
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 2e181f0..ec071ff 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/dataconnection/DcTrackerTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/dataconnection/DcTrackerTest.java
@@ -51,6 +51,7 @@
import android.net.LinkProperties;
import android.net.NetworkAgent;
import android.net.NetworkCapabilities;
+import android.net.NetworkPolicyManager;
import android.net.NetworkRequest;
import android.net.Uri;
import android.os.AsyncResult;
@@ -148,6 +149,8 @@
PermissionManagerService mMockPermissionManager;
@Mock
Handler mHandler;
+ @Mock
+ NetworkPolicyManager mNetworkPolicyManager;
private DcTracker mDct;
private DcTrackerTestHandler mDcTrackerTestHandler;
@@ -506,7 +509,8 @@
}
).when(mSubscriptionManager).addOnSubscriptionsChangedListener(any());
doReturn(mSubscriptionInfo).when(mSubscriptionManager).getActiveSubscriptionInfo(anyInt());
-
+ doReturn(mNetworkPolicyManager).when(mContext)
+ .getSystemService(Context.NETWORK_POLICY_SERVICE);
doReturn(1).when(mIsub).getDefaultDataSubId();
doReturn(mIsub).when(mBinder).queryLocalInterface(anyString());
mServiceManagerMockedServices.put("isub", mBinder);
diff --git a/tests/telephonytests/src/com/android/internal/telephony/dataconnection/TelephonyNetworkFactoryTest.java b/tests/telephonytests/src/com/android/internal/telephony/dataconnection/TelephonyNetworkFactoryTest.java
index b624679..1b67149 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/dataconnection/TelephonyNetworkFactoryTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/dataconnection/TelephonyNetworkFactoryTest.java
@@ -23,6 +23,8 @@
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
import android.content.Context;
import android.net.ConnectivityManager;
@@ -30,11 +32,15 @@
import android.net.NetworkCapabilities;
import android.net.NetworkRequest;
import android.net.StringNetworkSpecifier;
+import android.os.AsyncResult;
import android.os.Binder;
+import android.os.Handler;
import android.os.HandlerThread;
import android.os.Looper;
import android.os.Messenger;
+import android.telephony.AccessNetworkConstants;
import android.telephony.Rlog;
+import android.telephony.data.ApnSetting;
import android.test.suitebuilder.annotation.SmallTest;
import androidx.test.filters.FlakyTest;
@@ -43,6 +49,8 @@
import com.android.internal.telephony.RadioConfig;
import com.android.internal.telephony.SubscriptionController;
import com.android.internal.telephony.TelephonyTest;
+import com.android.internal.telephony.dataconnection.TransportManager.HandoverParams;
+import com.android.internal.telephony.dataconnection.TransportManager.HandoverParams.HandoverCallback;
import com.android.internal.telephony.mocks.ConnectivityServiceMock;
import com.android.internal.telephony.mocks.PhoneSwitcherMock;
import com.android.internal.telephony.mocks.SubscriptionControllerMock;
@@ -54,6 +62,7 @@
import org.junit.Test;
import org.mockito.Mock;
+import java.lang.reflect.Field;
import java.util.ArrayList;
public class TelephonyNetworkFactoryTest extends TelephonyTest {
@@ -303,4 +312,45 @@
waitForMs(250);
assertEquals(3, mNetworkRequestList.size());
}
+
+ /**
+ * Test handover when there is no live data connection
+ */
+ @Test
+ @SmallTest
+ public void testHandoverNoLiveData() throws Exception {
+ createMockedTelephonyComponents(1);
+ mPhoneSwitcherMock.setPreferredDataPhoneId(0);
+ mSubscriptionControllerMock.setDefaultDataSubId(0);
+ mSubscriptionControllerMock.setSlotSubId(0, 0);
+ mSubscriptionMonitorMock.notifySubscriptionChanged(0);
+
+ mPhoneSwitcherMock.setPhoneActive(0, true);
+ mConnectivityServiceMock.addDefaultRequest();
+
+ makeSubSpecificMmsRequest(0);
+
+ waitForMs(100);
+
+ Field f = TelephonyNetworkFactory.class.getDeclaredField("mInternalHandler");
+ f.setAccessible(true);
+ Handler h = (Handler) f.get(mTelephonyNetworkFactoryUT);
+
+ HandoverCallback handoverCallback = mock(HandoverCallback.class);
+
+ HandoverParams hp = new HandoverParams(ApnSetting.TYPE_MMS,
+ AccessNetworkConstants.TRANSPORT_TYPE_WLAN, handoverCallback);
+ AsyncResult ar = new AsyncResult(null, hp, null);
+ h.sendMessage(h.obtainMessage(5, ar));
+ waitForMs(100);
+
+ doReturn(AccessNetworkConstants.TRANSPORT_TYPE_WLAN).when(mTransportManager)
+ .getCurrentTransport(anyInt());
+
+ hp = new HandoverParams(ApnSetting.TYPE_MMS, AccessNetworkConstants.TRANSPORT_TYPE_WWAN,
+ handoverCallback);
+ ar = new AsyncResult(null, hp, null);
+ h.sendMessage(h.obtainMessage(5, ar));
+ waitForMs(100);
+ }
}
diff --git a/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsPhoneCallTrackerTest.java b/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsPhoneCallTrackerTest.java
index 32afa2f..a72bc82 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsPhoneCallTrackerTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsPhoneCallTrackerTest.java
@@ -391,6 +391,31 @@
@Test
@SmallTest
+ public void testImsHoldException() throws Exception {
+ testImsMTCallAccept();
+ doThrow(new ImsException()).when(mImsCall).hold();
+ try {
+ mCTUT.holdActiveCall();
+ Assert.fail("No exception thrown");
+ } catch (Exception e) {
+ // expected
+ verify(mImsCall).hold();
+ }
+
+ // After the first hold exception, try holding (successfully) again to make sure that it
+ // goes through
+ doNothing().when(mImsCall).hold();
+ try {
+ mCTUT.holdActiveCall();
+ verify(mImsCall, times(2)).hold();
+ } catch (Exception ex) {
+ ex.printStackTrace();
+ Assert.fail("unexpected exception thrown" + ex.getMessage());
+ }
+ }
+
+ @Test
+ @SmallTest
public void testImsMTCallReject() {
testImsMTCall();
assertTrue(mCTUT.mRingingCall.isRinging());