[automerger skipped] Merge "Added new testNotifyCellLocationForSubscriberByUserSwitched" am: 93cc1d5336 am: 062a26cd3e am: 340e9f6ddd -s ours
am skip reason: skip tag Change-Id I111eb3569b6f30d0ca5bb50a9e04770a1f04fdd7 with SHA-1 6121a24c3e is already in history
Original change: https://android-review.googlesource.com/c/platform/frameworks/opt/telephony/+/1552066
Change-Id: I6409fa728b699e385e34e428ea1b1d6070ff525b
diff --git a/jarjar-rules-shared.txt b/jarjar-rules-shared.txt
index 5635b18..4f3f617 100644
--- a/jarjar-rules-shared.txt
+++ b/jarjar-rules-shared.txt
@@ -4,6 +4,7 @@
rule android.os.Registrant* com.android.internal.telephony.Registrant@1
rule android.hidl.** android.internal.hidl.@1
rule android.sysprop.** android.internal.telephony.sysprop.@1
+rule android.util.IndentingPrintWriter* com.android.internal.telephony.AndroidUtilIndentingPrintWriter@1
rule android.util.LocalLog* com.android.internal.telephony.LocalLog@1
rule android.util.TimeUtils* com.android.internal.telephony.TimeUtils@1
rule com.android.internal.os.SomeArgs* com.android.internal.telephony.SomeArgs@1
diff --git a/src/java/com/android/internal/telephony/BtSmsInterfaceManager.java b/src/java/com/android/internal/telephony/BtSmsInterfaceManager.java
index 7271bf3..40e9a1c 100644
--- a/src/java/com/android/internal/telephony/BtSmsInterfaceManager.java
+++ b/src/java/com/android/internal/telephony/BtSmsInterfaceManager.java
@@ -18,7 +18,9 @@
package com.android.internal.telephony;
import android.app.PendingIntent;
+import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothMapClient;
import android.bluetooth.BluetoothProfile;
import android.content.Context;
import android.net.Uri;
@@ -40,10 +42,6 @@
*/
public void sendText(Context context, String destAddr, String text, PendingIntent sentIntent,
PendingIntent deliveryIntent, SubscriptionInfo info) {
- /*
- This is to remove the usage of hidden constant MAP_CLIENT and hidden API
- BluetoothMapClient.sendMessage(). This code is currently not functional anyway; it will be
- re-enabled in a later release.
BluetoothAdapter btAdapter = BluetoothAdapter.getDefaultAdapter();
if (btAdapter == null) {
// No bluetooth service on this platform?
@@ -56,10 +54,11 @@
sendErrorInPendingIntent(sentIntent, SmsManager.RESULT_INVALID_BLUETOOTH_ADDRESS);
return;
}
- btAdapter.getProfileProxy(context.getApplicationContext(),
+ if (btAdapter.getProfileProxy(context.getApplicationContext(),
new MapMessageSender(destAddr, text, device, sentIntent, deliveryIntent),
- BluetoothProfile.MAP_CLIENT);
- */
+ BluetoothProfile.MAP_CLIENT)) {
+ return;
+ }
throw new RuntimeException("Can't send message through BluetoothMapClient");
}
@@ -100,7 +99,6 @@
@Override
public void onServiceConnected(int profile, BluetoothProfile proxy) {
Log.d(LOG_TAG, "Service connected");
- /*
if (profile != BluetoothProfile.MAP_CLIENT) {
return;
}
@@ -112,8 +110,6 @@
}
BluetoothAdapter.getDefaultAdapter()
.closeProfileProxy(BluetoothProfile.MAP_CLIENT, mapProfile);
- */
- throw new RuntimeException("Can't send message through BluetoothMapClient");
}
@Override
diff --git a/src/java/com/android/internal/telephony/CarrierInfoManager.java b/src/java/com/android/internal/telephony/CarrierInfoManager.java
index c73214a..00f8c39 100644
--- a/src/java/com/android/internal/telephony/CarrierInfoManager.java
+++ b/src/java/com/android/internal/telephony/CarrierInfoManager.java
@@ -254,7 +254,13 @@
return;
}
mLastAccessResetCarrierKey = now;
- deleteCarrierInfoForImsiEncryption(context);
+ int[] subIds = context.getSystemService(SubscriptionManager.class)
+ .getSubscriptionIds(mPhoneId);
+ if (subIds == null || subIds.length < 1) {
+ Log.e(LOG_TAG, "Could not reset carrier keys, subscription for mPhoneId=" + mPhoneId);
+ return;
+ }
+ deleteCarrierInfoForImsiEncryption(context, subIds[0]);
Intent resetIntent = new Intent(TelephonyIntents.ACTION_CARRIER_CERTIFICATE_DOWNLOAD);
SubscriptionManager.putPhoneIdAndSubIdExtra(resetIntent, mPhoneId);
context.sendBroadcastAsUser(resetIntent, UserHandle.ALL);
@@ -264,12 +270,12 @@
* Deletes all the keys for a given Carrier from the device keystore.
* @param context Context
*/
- public static void deleteCarrierInfoForImsiEncryption(Context context) {
- Log.i(LOG_TAG, "deleting carrier key from db");
+ public static void deleteCarrierInfoForImsiEncryption(Context context, int subId) {
+ Log.i(LOG_TAG, "deleting carrier key from db for subId=" + subId);
String mcc = "";
String mnc = "";
- final TelephonyManager telephonyManager =
- (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
+ final TelephonyManager telephonyManager = context.getSystemService(TelephonyManager.class)
+ .createForSubscriptionId(subId);
String simOperator = telephonyManager.getSimOperator();
if (!TextUtils.isEmpty(simOperator)) {
mcc = simOperator.substring(0, 3);
diff --git a/src/java/com/android/internal/telephony/CarrierServiceStateTracker.java b/src/java/com/android/internal/telephony/CarrierServiceStateTracker.java
index c7e34a0..64dc7ec 100644
--- a/src/java/com/android/internal/telephony/CarrierServiceStateTracker.java
+++ b/src/java/com/android/internal/telephony/CarrierServiceStateTracker.java
@@ -32,9 +32,9 @@
import android.telephony.CarrierConfigManager;
import android.telephony.RadioAccessFamily;
import android.telephony.ServiceState;
-import android.telephony.TelephonyCallback;
import android.telephony.SubscriptionManager;
import android.telephony.SubscriptionManager.OnSubscriptionsChangedListener;
+import android.telephony.TelephonyCallback;
import android.telephony.TelephonyManager;
import android.telephony.TelephonyManager.NetworkTypeBitMask;
diff --git a/src/java/com/android/internal/telephony/CarrierServicesSmsFilter.java b/src/java/com/android/internal/telephony/CarrierServicesSmsFilter.java
index 8d6985d..8379824 100644
--- a/src/java/com/android/internal/telephony/CarrierServicesSmsFilter.java
+++ b/src/java/com/android/internal/telephony/CarrierServicesSmsFilter.java
@@ -43,7 +43,13 @@
/**
* Filters incoming SMS with carrier services.
- * <p> A new instance must be created for filtering each message.
+ *
+ * <p>A new instance must be created for filtering each message.
+ *
+ * <p>Note that if a carrier services app is unavailable at the time a message is received because
+ * credential-encrypted storage is unavailable and it is not direct-boot aware, and the message ends
+ * up being handled by a filter further down the chain, that message will not be redelivered to the
+ * carrier app once the user unlocks the storage.
*/
public class CarrierServicesSmsFilter {
protected static final boolean DBG = true;
@@ -238,9 +244,10 @@
void filterSms(CarrierSmsFilterCallback smsFilterCallback) {
mSmsFilterCallback = smsFilterCallback;
if (!mCarrierMessagingServiceWrapper.bindToCarrierMessagingService(
- mContext, mPackageName, ()-> onServiceReady())) {
+ mContext, mPackageName, runnable -> runnable.run(), ()-> onServiceReady())) {
loge("CarrierSmsFilter::filterSms: bindService() for failed for " + mPackageName);
- smsFilterCallback.onFilterComplete(CarrierMessagingService.RECEIVE_OPTIONS_DEFAULT);
+ smsFilterCallback.onReceiveSmsComplete(
+ CarrierMessagingService.RECEIVE_OPTIONS_DEFAULT);
} else {
logv("CarrierSmsFilter::filterSms: bindService() for succeeded for "
+ mPackageName);
@@ -254,12 +261,12 @@
private void onServiceReady() {
try {
log("onServiceReady: calling filterSms on " + mPackageName);
- mCarrierMessagingServiceWrapper.filterSms(
+ mCarrierMessagingServiceWrapper.receiveSms(
new MessagePdu(Arrays.asList(mPdus)), mSmsFormat, mDestPort,
- mPhone.getSubId(), mSmsFilterCallback);
+ mPhone.getSubId(), runnable -> runnable.run(), mSmsFilterCallback);
} catch (RuntimeException e) {
loge("Exception filtering the SMS with " + mPackageName + ": " + e);
- mSmsFilterCallback.onFilterComplete(
+ mSmsFilterCallback.onReceiveSmsComplete(
CarrierMessagingService.RECEIVE_OPTIONS_DEFAULT);
}
}
@@ -287,14 +294,14 @@
* This method should be called only once.
*/
@Override
- public void onFilterComplete(int result) {
+ public void onReceiveSmsComplete(int result) {
log("CarrierSmsFilterCallback::onFilterComplete: Called from " + mPackageName
+ " with result: " + result);
// in the case that timeout has already passed and triggered, but the initial callback
// is run afterwards, we should not follow through
if (!mIsOnFilterCompleteCalled) {
mIsOnFilterCompleteCalled = true;
- mCarrierMessagingServiceWrapper.disposeConnection(mContext);
+ mCarrierMessagingServiceWrapper.disconnect();
mFilterAggregator.onFilterComplete(result);
}
}
@@ -394,7 +401,7 @@
private void handleFilterCallbacksTimeout() {
for (CarrierSmsFilterCallback callback : mFilterAggregator.mCallbacks) {
log("handleFilterCallbacksTimeout: calling onFilterComplete");
- callback.onFilterComplete(CarrierMessagingService.RECEIVE_OPTIONS_DEFAULT);
+ callback.onReceiveSmsComplete(CarrierMessagingService.RECEIVE_OPTIONS_DEFAULT);
}
}
}
diff --git a/src/java/com/android/internal/telephony/CellularNetworkValidator.java b/src/java/com/android/internal/telephony/CellularNetworkValidator.java
index cee9cea..7124703 100644
--- a/src/java/com/android/internal/telephony/CellularNetworkValidator.java
+++ b/src/java/com/android/internal/telephony/CellularNetworkValidator.java
@@ -235,7 +235,7 @@
*/
public boolean isValidationFeatureSupported() {
return PhoneConfigurationManager.getInstance().getCurrentPhoneCapability()
- .validationBeforeSwitchSupported;
+ .isNetworkValidationBeforeSwitchSupported();
}
@VisibleForTesting
diff --git a/src/java/com/android/internal/telephony/CommandsInterface.java b/src/java/com/android/internal/telephony/CommandsInterface.java
index 7572d11..6ae0b1f 100644
--- a/src/java/com/android/internal/telephony/CommandsInterface.java
+++ b/src/java/com/android/internal/telephony/CommandsInterface.java
@@ -34,7 +34,7 @@
import android.telephony.TelephonyManager;
import android.telephony.data.DataCallResponse;
import android.telephony.data.DataProfile;
-import android.telephony.data.SliceInfo;
+import android.telephony.data.NetworkSliceInfo;
import android.telephony.data.TrafficDescriptor;
import android.telephony.emergency.EmergencyNumber;
@@ -1874,8 +1874,8 @@
*/
void setupDataCall(int accessNetworkType, DataProfile dataProfile, boolean isRoaming,
boolean allowRoaming, int reason, LinkProperties linkProperties, int pduSessionId,
- SliceInfo sliceInfo, TrafficDescriptor trafficDescriptor, boolean matchAllRuleAllowed,
- Message result);
+ NetworkSliceInfo sliceInfo, TrafficDescriptor trafficDescriptor,
+ boolean matchAllRuleAllowed, Message result);
/**
* Deactivate packet data connection
@@ -2637,7 +2637,6 @@
*/
default void cancelHandover(Message result, int callId) {};
-
/**
* Control the data throttling at modem.
*
@@ -2650,4 +2649,12 @@
*/
default void setDataThrottling(Message result, WorkSource workSource,
int dataThrottlingAction, long completionWindowMillis) {};
+
+ /**
+ * Request to get the current slicing configuration including URSP rules and
+ * NSSAIs (configured, allowed and rejected).
+ *
+ * @param result Message that will be sent back to handler.
+ */
+ default void getSlicingConfig(Message result) {};
}
diff --git a/src/java/com/android/internal/telephony/DeviceStateMonitor.java b/src/java/com/android/internal/telephony/DeviceStateMonitor.java
index 0997186..1752d90 100644
--- a/src/java/com/android/internal/telephony/DeviceStateMonitor.java
+++ b/src/java/com/android/internal/telephony/DeviceStateMonitor.java
@@ -16,6 +16,7 @@
package com.android.internal.telephony;
+import static android.app.UiModeManager.PROJECTION_TYPE_AUTOMOTIVE;
import static android.hardware.radio.V1_0.DeviceStateType.CHARGING_STATE;
import static android.hardware.radio.V1_0.DeviceStateType.LOW_DATA_EXPECTED;
import static android.hardware.radio.V1_0.DeviceStateType.POWER_SAVE_MODE;
@@ -25,7 +26,6 @@
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
-import android.content.res.Configuration;
import android.hardware.display.DisplayManager;
import android.hardware.radio.V1_5.IndicationFilter;
import android.net.ConnectivityManager;
@@ -71,7 +71,7 @@
protected static final String TAG = DeviceStateMonitor.class.getSimpleName();
static final int EVENT_RIL_CONNECTED = 0;
- static final int EVENT_CAR_MODE_CHANGED = 1;
+ static final int EVENT_AUTOMOTIVE_PROJECTION_STATE_CHANGED = 1;
@VisibleForTesting
static final int EVENT_SCREEN_STATE_CHANGED = 2;
static final int EVENT_POWER_SAVE_MODE_CHANGED = 3;
@@ -173,11 +173,11 @@
private boolean mIsWifiConnected;
/**
- * Car mode is on. True means the device is currently connected to Android Auto. This should be
- * handled by mIsScreenOn, but the Android Auto display is private and not accessible by
- * DeviceStateMonitor from DisplayMonitor.
+ * Automotive projection is active. True means the device is currently connected to Android
+ * Auto. This should be handled by mIsScreenOn, but the Android Auto display is private and not
+ * accessible by DeviceStateMonitor from DisplayMonitor.
*/
- private boolean mIsCarModeOn;
+ private boolean mIsAutomotiveProjectionActive;
/**
* True indicates we should always enable the signal strength reporting from radio.
@@ -248,14 +248,6 @@
msg = obtainMessage(EVENT_TETHERING_STATE_CHANGED);
msg.arg1 = isTetheringOn ? 1 : 0;
break;
- case UiModeManager.ACTION_ENTER_CAR_MODE_PRIORITIZED:
- msg = obtainMessage(EVENT_CAR_MODE_CHANGED);
- msg.arg1 = 1; // car mode on
- break;
- case UiModeManager.ACTION_EXIT_CAR_MODE_PRIORITIZED:
- msg = obtainMessage(EVENT_CAR_MODE_CHANGED);
- msg.arg1 = 0; // car mode off
- break;
default:
log("Unexpected broadcast intent: " + intent, false);
return;
@@ -279,7 +271,7 @@
mIsPowerSaveOn = isPowerSaveModeOn();
mIsCharging = isDeviceCharging();
mIsScreenOn = isScreenOn();
- mIsCarModeOn = isCarModeOn();
+ mIsAutomotiveProjectionActive = isAutomotiveProjectionActive();
// Assuming tethering is always off after boot up.
mIsTetheringOn = false;
mIsLowDataExpected = false;
@@ -289,7 +281,7 @@
+ ", mIsCharging=" + mIsCharging
+ ", mIsPowerSaveOn=" + mIsPowerSaveOn
+ ", mIsLowDataExpected=" + mIsLowDataExpected
- + ", mIsCarModeOn=" + mIsCarModeOn
+ + ", mIsAutomotiveProjectionActive=" + mIsAutomotiveProjectionActive
+ ", mIsWifiConnected=" + mIsWifiConnected
+ ", mIsAlwaysSignalStrengthReportingEnabled="
+ mIsAlwaysSignalStrengthReportingEnabled, false);
@@ -299,8 +291,6 @@
filter.addAction(BatteryManager.ACTION_CHARGING);
filter.addAction(BatteryManager.ACTION_DISCHARGING);
filter.addAction(TetheringManager.ACTION_TETHER_STATE_CHANGED);
- filter.addAction(UiModeManager.ACTION_ENTER_CAR_MODE_PRIORITIZED);
- filter.addAction(UiModeManager.ACTION_EXIT_CAR_MODE_PRIORITIZED);
mPhone.getContext().registerReceiver(mBroadcastReceiver, filter, null, mPhone);
mPhone.mCi.registerForRilConnected(this, EVENT_RIL_CONNECTED, null);
@@ -309,6 +299,16 @@
ConnectivityManager cm = (ConnectivityManager) phone.getContext().getSystemService(
Context.CONNECTIVITY_SERVICE);
cm.registerNetworkCallback(mWifiNetworkRequest, mNetworkCallback);
+
+ UiModeManager umm = (UiModeManager) phone.getContext().getSystemService(
+ Context.UI_MODE_SERVICE);
+ umm.addOnProjectionStateChangeListener(PROJECTION_TYPE_AUTOMOTIVE,
+ phone.getContext().getMainExecutor(),
+ (t, pkgs) -> {
+ Message msg = obtainMessage(EVENT_AUTOMOTIVE_PROJECTION_STATE_CHANGED);
+ msg.arg1 = Math.min(pkgs.size(), 1);
+ sendMessage(msg);
+ });
}
/**
@@ -403,8 +403,8 @@
// 1. The device is charging.
// 2. When the screen is on.
// 3. When the tethering is on.
- // 4. When car mode (Android Auto) is on.
- return mIsCharging || mIsScreenOn || mIsTetheringOn || mIsCarModeOn;
+ // 4. When automotive projection (Android Auto) is on.
+ return mIsCharging || mIsScreenOn || mIsTetheringOn || mIsAutomotiveProjectionActive;
}
/**
@@ -460,7 +460,7 @@
case EVENT_CHARGING_STATE_CHANGED:
case EVENT_TETHERING_STATE_CHANGED:
case EVENT_UPDATE_ALWAYS_REPORT_SIGNAL_STRENGTH:
- case EVENT_CAR_MODE_CHANGED:
+ case EVENT_AUTOMOTIVE_PROJECTION_STATE_CHANGED:
onUpdateDeviceState(msg.what, msg.arg1 != 0);
break;
case EVENT_WIFI_CONNECTION_CHANGED:
@@ -507,9 +507,9 @@
if (mIsAlwaysSignalStrengthReportingEnabled == state) return;
mIsAlwaysSignalStrengthReportingEnabled = state;
break;
- case EVENT_CAR_MODE_CHANGED:
- if (mIsCarModeOn == state) return;
- mIsCarModeOn = state;
+ case EVENT_AUTOMOTIVE_PROJECTION_STATE_CHANGED:
+ if (mIsAutomotiveProjectionActive == state) return;
+ mIsAutomotiveProjectionActive = state;
break;
default:
return;
@@ -740,15 +740,16 @@
}
/**
- * @return True if car mode (Android Auto) is on.
+ * @return True if automotive projection (Android Auto) is active.
*/
- private boolean isCarModeOn() {
+ private boolean isAutomotiveProjectionActive() {
final UiModeManager umm = (UiModeManager) mPhone.getContext().getSystemService(
Context.UI_MODE_SERVICE);
if (umm == null) return false;
- boolean retval = umm.getCurrentModeType() == Configuration.UI_MODE_TYPE_CAR;
- log("isCarModeOn=" + retval, true);
- return retval;
+ boolean isAutomotiveProjectionActive = (umm.getActiveProjectionTypes()
+ & PROJECTION_TYPE_AUTOMOTIVE) != 0;
+ log("isAutomotiveProjectionActive=" + isAutomotiveProjectionActive, true);
+ return isAutomotiveProjectionActive;
}
/**
@@ -799,7 +800,7 @@
ipw.println("mIsCharging=" + mIsCharging);
ipw.println("mIsPowerSaveOn=" + mIsPowerSaveOn);
ipw.println("mIsLowDataExpected=" + mIsLowDataExpected);
- ipw.println("mIsCarModeOn=" + mIsCarModeOn);
+ ipw.println("mIsAutomotiveProjectionActive=" + mIsAutomotiveProjectionActive);
ipw.println("mUnsolicitedResponseFilter=" + mUnsolicitedResponseFilter);
ipw.println("mIsWifiConnected=" + mIsWifiConnected);
ipw.println("mIsAlwaysSignalStrengthReportingEnabled="
diff --git a/src/java/com/android/internal/telephony/GsmCdmaConnection.java b/src/java/com/android/internal/telephony/GsmCdmaConnection.java
index cdf1f42..e9ecb79 100644
--- a/src/java/com/android/internal/telephony/GsmCdmaConnection.java
+++ b/src/java/com/android/internal/telephony/GsmCdmaConnection.java
@@ -559,6 +559,9 @@
case CallFailCause.USER_ALERTING_NO_ANSWER:
return DisconnectCause.TIMED_OUT;
+ case CallFailCause.RADIO_OFF:
+ return DisconnectCause.POWER_OFF;
+
case CallFailCause.ACCESS_CLASS_BLOCKED:
case CallFailCause.ERROR_UNSPECIFIED:
case CallFailCause.NORMAL_CLEARING:
diff --git a/src/java/com/android/internal/telephony/GsmCdmaPhone.java b/src/java/com/android/internal/telephony/GsmCdmaPhone.java
index bd2f3a8..494ca06 100644
--- a/src/java/com/android/internal/telephony/GsmCdmaPhone.java
+++ b/src/java/com/android/internal/telephony/GsmCdmaPhone.java
@@ -89,6 +89,7 @@
import com.android.internal.telephony.cdma.CdmaSubscriptionSourceManager;
import com.android.internal.telephony.dataconnection.DataEnabledSettings;
import com.android.internal.telephony.dataconnection.DcTracker;
+import com.android.internal.telephony.dataconnection.LinkBandwidthEstimator;
import com.android.internal.telephony.dataconnection.TransportManager;
import com.android.internal.telephony.emergency.EmergencyNumberTracker;
import com.android.internal.telephony.gsm.GsmMmiCode;
@@ -198,7 +199,7 @@
private SIMRecords mSimRecords;
// For non-persisted manual network selection
- private String mManualNetworkSelectionPlmn = "";
+ private String mManualNetworkSelectionPlmn;
//Common
// Instance Variables
@@ -239,6 +240,17 @@
}
}
+ /**
+ * Used to create ImsManager instances, which may be injected during testing.
+ */
+ @VisibleForTesting
+ public interface ImsManagerFactory {
+ /**
+ * Create a new instance of ImsManager for the specified phoneId.
+ */
+ ImsManager create(Context context, int phoneId);
+ }
+
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
private IccSmsInterfaceManager mIccSmsInterfaceManager;
@@ -251,6 +263,8 @@
private final SettingsObserver mSettingsObserver;
+ private final ImsManagerFactory mImsManagerFactory;
+
// Constructors
public GsmCdmaPhone(Context context, CommandsInterface ci, PhoneNotifier notifier, int phoneId,
@@ -261,12 +275,23 @@
public GsmCdmaPhone(Context context, CommandsInterface ci, PhoneNotifier notifier,
boolean unitTestMode, int phoneId, int precisePhoneType,
TelephonyComponentFactory telephonyComponentFactory) {
+ this(context, ci, notifier,
+ unitTestMode, phoneId, precisePhoneType,
+ telephonyComponentFactory,
+ ImsManager::getInstance);
+ }
+
+ public GsmCdmaPhone(Context context, CommandsInterface ci, PhoneNotifier notifier,
+ boolean unitTestMode, int phoneId, int precisePhoneType,
+ TelephonyComponentFactory telephonyComponentFactory,
+ ImsManagerFactory imsManagerFactory) {
super(precisePhoneType == PhoneConstants.PHONE_TYPE_GSM ? "GSM" : "CDMA",
notifier, context, ci, unitTestMode, phoneId, telephonyComponentFactory);
// phone type needs to be set before other initialization as other objects rely on it
mPrecisePhoneType = precisePhoneType;
mVoiceCallSessionStats = new VoiceCallSessionStats(mPhoneId, this);
+ mImsManagerFactory = imsManagerFactory;
initOnce(ci);
initRatSpecific(precisePhoneType);
// CarrierSignalAgent uses CarrierActionAgent in construction so it needs to be created
@@ -281,7 +306,7 @@
.makeServiceStateTracker(this, this.mCi);
mEmergencyNumberTracker = mTelephonyComponentFactory
.inject(EmergencyNumberTracker.class.getName()).makeEmergencyNumberTracker(
- this, this.mCi);
+ this, this.mCi);
mDataEnabledSettings = mTelephonyComponentFactory
.inject(DataEnabledSettings.class.getName()).makeDataEnabledSettings(this);
mDeviceStateMonitor = mTelephonyComponentFactory.inject(DeviceStateMonitor.class.getName())
@@ -322,6 +347,10 @@
SubscriptionController.getInstance().registerForUiccAppsEnabled(this,
EVENT_UICC_APPS_ENABLEMENT_SETTING_CHANGED, null, false);
+ mLinkBandwidthEstimator = mTelephonyComponentFactory
+ .inject(LinkBandwidthEstimator.class.getName())
+ .makeLinkBandwidthEstimator(this);
+
loadTtyMode();
CallManager.getInstance().registerPhone(this);
@@ -1651,6 +1680,7 @@
boolean isSelectedPhoneForEmergencyCall, boolean forceApply, int reason) {
mSST.setRadioPowerForReason(power, forEmergencyCall, isSelectedPhoneForEmergencyCall,
forceApply, reason);
+
}
private void storeVoiceMailNumber(String number) {
@@ -1859,7 +1889,7 @@
@Override
public void deleteCarrierInfoForImsiEncryption() {
- CarrierInfoManager.deleteCarrierInfoForImsiEncryption(mContext);
+ CarrierInfoManager.deleteCarrierInfoForImsiEncryption(mContext, getSubId());
}
@Override
@@ -2018,7 +2048,7 @@
mManualNetworkSelectionPlmn = nsm.operatorNumeric;
} else {
//on Phone0 in emergency mode (no SIM), or in some races then clear the cache
- mManualNetworkSelectionPlmn = "";
+ mManualNetworkSelectionPlmn = null;
Rlog.e(LOG_TAG, "Cannot update network selection due to invalid subId "
+ subId);
}
@@ -4552,6 +4582,27 @@
return Collections.emptyList();
}
+ /**
+ * @return Currently bound data service package names.
+ */
+ public @NonNull List<String> getDataServicePackages() {
+ List<String> packages = new ArrayList<>();
+ int[] transports = new int[]{AccessNetworkConstants.TRANSPORT_TYPE_WWAN,
+ AccessNetworkConstants.TRANSPORT_TYPE_WLAN};
+
+ for (int transport : transports) {
+ DcTracker dct = getDcTracker(transport);
+ if (dct != null) {
+ String pkg = dct.getDataServiceManager().getDataServicePackageName();
+ if (!TextUtils.isEmpty(pkg)) {
+ packages.add(pkg);
+ }
+ }
+ }
+
+ return packages;
+ }
+
private void updateBroadcastEmergencyCallStateChangesAfterCarrierConfigChanged(
PersistableBundle config) {
if (config == null) {
@@ -4616,4 +4667,18 @@
loge("Invalid cdma_roaming_mode settings: " + config_cdma_roaming_mode);
}
}
+
+ /**
+ * Determines if IMS is enabled for call.
+ *
+ * @return {@code true} if IMS calling is enabled.
+ */
+ public boolean isImsUseEnabled() {
+ ImsManager imsManager = mImsManagerFactory.create(mContext, mPhoneId);
+ boolean imsUseEnabled = ((imsManager.isVolteEnabledByPlatform()
+ && imsManager.isEnhanced4gLteModeSettingEnabledByUser())
+ || (imsManager.isWfcEnabledByPlatform() && imsManager.isWfcEnabledByUser())
+ && imsManager.isNonTtyOrTtyOnVolteEnabled());
+ return imsUseEnabled;
+ }
}
diff --git a/src/java/com/android/internal/telephony/IccSmsInterfaceManager.java b/src/java/com/android/internal/telephony/IccSmsInterfaceManager.java
index a1a9578..bb21281 100644
--- a/src/java/com/android/internal/telephony/IccSmsInterfaceManager.java
+++ b/src/java/com/android/internal/telephony/IccSmsInterfaceManager.java
@@ -21,6 +21,7 @@
import static android.telephony.SmsManager.STATUS_ON_ICC_UNREAD;
import android.Manifest;
+import android.annotation.RequiresPermission;
import android.app.AppOpsManager;
import android.app.PendingIntent;
import android.compat.annotation.UnsupportedAppUsage;
@@ -537,7 +538,7 @@
+ " text='" + text + "' sentIntent=" + sentIntent + " deliveryIntent="
+ deliveryIntent + " priority=" + priority + " expectMore=" + expectMore
+ " validityPeriod=" + validityPeriod + " isForVVM=" + isForVvm
- + " id= " + messageId);
+ + " " + SmsController.formatCrossStackMessageId(messageId));
}
notifyIfOutgoingEmergencySms(destAddr);
destAddr = filterDestAddress(destAddr);
@@ -743,7 +744,7 @@
for (String part : parts) {
log("sendMultipartTextWithOptions: destAddr=" + destAddr + ", srAddr=" + scAddr
+ ", part[" + (i++) + "]=" + part
- + " id: " + messageId);
+ + " " + SmsController.formatCrossStackMessageId(messageId));
}
}
notifyIfOutgoingEmergencySms(destAddr);
@@ -1049,8 +1050,9 @@
/**
* Reset all cell broadcast ranges. Previously enabled ranges will become invalid after this.
*/
+ @RequiresPermission(android.Manifest.permission.MODIFY_CELL_BROADCASTS)
public void resetAllCellBroadcastRanges() {
- mContext.enforceCallingPermission(android.Manifest.permission.RECEIVE_EMERGENCY_BROADCAST,
+ mContext.enforceCallingPermission(android.Manifest.permission.MODIFY_CELL_BROADCASTS,
"resetAllCellBroadcastRanges");
mCdmaBroadcastRangeManager.clearRanges();
mCellBroadcastRangeManager.clearRanges();
diff --git a/src/java/com/android/internal/telephony/InboundSmsHandler.java b/src/java/com/android/internal/telephony/InboundSmsHandler.java
index 8f98a5f..f4aba4f 100644
--- a/src/java/com/android/internal/telephony/InboundSmsHandler.java
+++ b/src/java/com/android/internal/telephony/InboundSmsHandler.java
@@ -16,6 +16,9 @@
package com.android.internal.telephony;
+import static android.os.PowerWhitelistManager.REASON_EVENT_MMS;
+import static android.os.PowerWhitelistManager.REASON_EVENT_SMS;
+import static android.os.PowerWhitelistManager.TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_ALLOWED;
import static android.provider.Telephony.Sms.Intents.RESULT_SMS_DATABASE_ERROR;
import static android.provider.Telephony.Sms.Intents.RESULT_SMS_DISPATCH_FAILURE;
import static android.provider.Telephony.Sms.Intents.RESULT_SMS_INVALID_URI;
@@ -206,8 +209,10 @@
// The notitfication tag used when showing a notification. The combination of notification tag
// and notification id should be unique within the phone app.
- private static final String NOTIFICATION_TAG = "InboundSmsHandler";
- private static final int NOTIFICATION_ID_NEW_MESSAGE = 1;
+ @VisibleForTesting
+ public static final String NOTIFICATION_TAG = "InboundSmsHandler";
+ @VisibleForTesting
+ public static final int NOTIFICATION_ID_NEW_MESSAGE = 1;
/** URI for raw table of SMS provider. */
protected static final Uri sRawUri = Uri.withAppendedPath(Telephony.Sms.CONTENT_URI, "raw");
@@ -676,7 +681,7 @@
* This method is called when a new SMS PDU is injected into application framework.
* @param ar is the AsyncResult that has the SMS PDU to be injected.
*/
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
private void handleInjectSms(AsyncResult ar, boolean isOverIms) {
int result;
SmsDispatchersController.SmsInjectionCallback callback = null;
@@ -806,7 +811,7 @@
* @param smsSource the source of the SMS message
* @return {@link Intents#RESULT_SMS_HANDLED} if the message was accepted, or an error status
*/
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
protected int dispatchNormalMessage(SmsMessageBase sms, @SmsSource int smsSource) {
SmsHeader smsHeader = sms.getUserDataHeader();
InboundSmsTracker tracker;
@@ -987,8 +992,8 @@
log("processMessagePart: all " + messageCount + " segments "
+ " received. refNumber: " + refNumber, tracker.getMessageId());
} catch (SQLException e) {
- loge("processMessagePart: Can't access multipart SMS database, id: "
- + tracker.getMessageId(), e);
+ loge("processMessagePart: Can't access multipart SMS database, "
+ + SmsController.formatCrossStackMessageId(tracker.getMessageId()), e);
return false;
} finally {
if (cursor != null) {
@@ -1043,7 +1048,8 @@
tracker,
(isWapPush ? new byte[][] {output.toByteArray()} : pdus),
destPort,
- resultReceiver);
+ resultReceiver,
+ block);
}
if (isWapPush) {
@@ -1116,7 +1122,7 @@
* @return true if an ordered broadcast was sent to the carrier app; false otherwise.
*/
private boolean processMessagePartWithUserLocked(InboundSmsTracker tracker,
- byte[][] pdus, int destPort, SmsBroadcastReceiver resultReceiver) {
+ byte[][] pdus, int destPort, SmsBroadcastReceiver resultReceiver, boolean block) {
if (destPort == SmsHeader.PORT_WAP_PUSH && mWapPush.isWapPushForMms(pdus[0], this)) {
showNewMessageNotification();
return false;
@@ -1125,14 +1131,15 @@
// This is a regular SMS - hand it to the carrier or system app for filtering.
boolean filterInvoked = filterSms(
pdus, destPort, tracker, resultReceiver, false /* userUnlocked */,
- false /* block */);
+ block);
if (filterInvoked) {
// filter invoked, wait for it to return the result.
return true;
- } else {
- // filter not invoked, show the notification and do nothing further.
+ } else if (!block) {
+ // filter not invoked and message not blocked, show the notification and do nothing
+ // further. Even if the message is blocked, we keep it in the database so it can be
+ // reprocessed by filters once credential-encrypted storage is available.
showNewMessageNotification();
- return false;
}
}
return false;
@@ -1385,9 +1392,12 @@
bundle = bopts.toBundle();
}
long duration = mPowerWhitelistManager.whitelistAppTemporarilyForEvent(
- pkgName, PowerWhitelistManager.EVENT_SMS, reason);
+ pkgName, PowerWhitelistManager.EVENT_SMS, REASON_EVENT_SMS, reason);
if (bopts == null) bopts = BroadcastOptions.makeBasic();
- bopts.setTemporaryAppWhitelistDuration(duration);
+ bopts.setTemporaryAppAllowlist(duration,
+ TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_ALLOWED,
+ REASON_EVENT_SMS,
+ "");
bundle = bopts.toBundle();
return bundle;
@@ -1560,8 +1570,8 @@
return Intents.RESULT_SMS_DUPLICATED; // reject message
}
} catch (SQLException e) {
- loge("addTrackerToRawTable: Can't access SMS database, id: "
- + tracker.getMessageId(), e);
+ loge("addTrackerToRawTable: Can't access SMS database, "
+ + SmsController.formatCrossStackMessageId(tracker.getMessageId()), e);
return RESULT_SMS_DATABASE_ERROR; // reject message
}
} else {
@@ -1592,8 +1602,8 @@
}
return Intents.RESULT_SMS_HANDLED;
} catch (Exception e) {
- loge("addTrackerToRawTable: error parsing URI for new row: " + newUri + " id: "
- + tracker.getMessageId(), e);
+ loge("addTrackerToRawTable: error parsing URI for new row: " + newUri
+ + " " + SmsController.formatCrossStackMessageId(tracker.getMessageId()), e);
return RESULT_SMS_INVALID_URI;
}
}
@@ -1651,9 +1661,13 @@
long duration = mPowerWhitelistManager.whitelistAppTemporarilyForEvent(
mContext.getPackageName(),
PowerWhitelistManager.EVENT_MMS,
+ REASON_EVENT_MMS,
"mms-broadcast");
BroadcastOptions bopts = BroadcastOptions.makeBasic();
- bopts.setTemporaryAppWhitelistDuration(duration);
+ bopts.setTemporaryAppAllowlist(duration,
+ TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_ALLOWED,
+ REASON_EVENT_MMS,
+ "");
Bundle options = bopts.toBundle();
String mimeType = intent.getType();
@@ -1726,7 +1740,7 @@
@Override
public void onFilterComplete(int result) {
- log("onFilterComplete: result is " + result, mMessageId);
+ log("onFilterComplete: result is " + result, mTracker.getMessageId());
boolean carrierRequestedDrop =
(result & CarrierMessagingService.RECEIVE_OPTIONS_DROP) != 0;
@@ -1745,12 +1759,18 @@
}
// Now that all filters have been invoked, drop the message if it is blocked.
- // TODO(b/156910035): Remove mUserUnlocked once we stop showing the new message
- // notification for blocked numbers.
- if (mUserUnlocked && mBlock) {
- log("onFilterComplete: dropping message as the sender is blocked",
- mTracker.getMessageId());
- dropFilteredSms(mTracker, mSmsBroadcastReceiver, mBlock);
+ if (mBlock) {
+ // Only delete the message if the user is unlocked. Otherwise, we should reprocess
+ // the message after unlock so the filter has a chance to run while credential-
+ // encrypted storage is available.
+ if (mUserUnlocked) {
+ log("onFilterComplete: dropping message as the sender is blocked",
+ mTracker.getMessageId());
+ dropFilteredSms(mTracker, mSmsBroadcastReceiver, mBlock);
+ } else {
+ // Just complete handling of the message without dropping it.
+ sendMessage(EVENT_BROADCAST_COMPLETE);
+ }
return;
}
@@ -1802,7 +1822,7 @@
*/
protected void logWithLocalLog(String logMsg, long id) {
log(logMsg, id);
- mLocalLog.log(logMsg + ", id: " + id);
+ mLocalLog.log(logMsg + ", " + SmsController.formatCrossStackMessageId(id));
}
/**
@@ -1821,7 +1841,7 @@
*/
protected void logeWithLocalLog(String logMsg, long id) {
loge(logMsg, id);
- mLocalLog.log(logMsg + ", id: " + id);
+ mLocalLog.log(logMsg + ", " + SmsController.formatCrossStackMessageId(id));
}
/**
@@ -1840,7 +1860,7 @@
* @param id unique message id
*/
protected void log(String s, long id) {
- log(s + ", id: " + id);
+ log(s + ", " + SmsController.formatCrossStackMessageId(id));
}
/**
@@ -1859,7 +1879,7 @@
* @param id unique message id
*/
protected void loge(String s, long id) {
- loge(s + ", id: " + id);
+ loge(s + ", " + SmsController.formatCrossStackMessageId(id));
}
/**
diff --git a/src/java/com/android/internal/telephony/InboundSmsTracker.java b/src/java/com/android/internal/telephony/InboundSmsTracker.java
index 9ddee8d..9b67612 100644
--- a/src/java/com/android/internal/telephony/InboundSmsTracker.java
+++ b/src/java/com/android/internal/telephony/InboundSmsTracker.java
@@ -326,9 +326,9 @@
builder.append(") deleteArgs=(").append(Arrays.toString(mDeleteWhereArgs));
builder.append(')');
}
- builder.append(" id=");
- builder.append(mMessageId);
- builder.append('}');
+ builder.append(" ");
+ builder.append(SmsController.formatCrossStackMessageId(mMessageId));
+ builder.append("}");
return builder.toString();
}
diff --git a/src/java/com/android/internal/telephony/LocaleTracker.java b/src/java/com/android/internal/telephony/LocaleTracker.java
index 89778e6..1f7ad17 100755
--- a/src/java/com/android/internal/telephony/LocaleTracker.java
+++ b/src/java/com/android/internal/telephony/LocaleTracker.java
@@ -86,10 +86,12 @@
* <p> This broadcast is not effective on user build.
*
* <p>Example: To override the current country <code>
+ * adb root
* adb shell am broadcast -a com.android.internal.telephony.action.COUNTRY_OVERRIDE
* --es country us </code>
*
* <p> To remove the override <code>
+ * adb root
* adb shell am broadcast -a com.android.internal.telephony.action.COUNTRY_OVERRIDE
* --ez reset true</code>
*/
diff --git a/src/java/com/android/internal/telephony/MultiSimSettingController.java b/src/java/com/android/internal/telephony/MultiSimSettingController.java
index dc32ba5..2f5e8b0 100644
--- a/src/java/com/android/internal/telephony/MultiSimSettingController.java
+++ b/src/java/com/android/internal/telephony/MultiSimSettingController.java
@@ -699,8 +699,9 @@
if (mPrimarySubList.size() == 1 && change == PRIMARY_SUB_REMOVED
&& (!dataSelected || !smsSelected || !voiceSelected)) {
dialogType = EXTRA_DEFAULT_SUBSCRIPTION_SELECT_TYPE_ALL;
- } else if (mPrimarySubList.size() > 1 && isUserVisibleChange(change)) {
- // If change is SWAPPED_IN_GROUP or MARKED_OPPT orINITIALIZED, don't ask user again.
+ } else if (mPrimarySubList.size() > 1 && (isUserVisibleChange(change)
+ || (change == PRIMARY_SUB_INITIALIZED && !dataSelected))) {
+ // If change is SWAPPED_IN_GROUP or MARKED_OPPT, don't ask user again.
dialogType = EXTRA_DEFAULT_SUBSCRIPTION_SELECT_TYPE_DATA;
}
diff --git a/src/java/com/android/internal/telephony/NetworkScanRequestTracker.java b/src/java/com/android/internal/telephony/NetworkScanRequestTracker.java
index ed0fc3e..92f552a 100644
--- a/src/java/com/android/internal/telephony/NetworkScanRequestTracker.java
+++ b/src/java/com/android/internal/telephony/NetworkScanRequestTracker.java
@@ -445,7 +445,10 @@
.setCallingPackage(nsri.mCallingPackage)
.setCallingPid(nsri.mPid)
.setCallingUid(nsri.mUid)
+ .setCallingFeatureId(nsri.mPhone.getContext().getAttributionTag())
.setMinSdkVersionForFine(Build.VERSION_CODES.Q)
+ .setMinSdkVersionForCoarse(Build.VERSION_CODES.Q)
+ .setMinSdkVersionForEnforcement(Build.VERSION_CODES.Q)
.setMethod("NetworkScanTracker#onResult")
.build();
if (ar.exception == null && ar.result != null) {
diff --git a/src/java/com/android/internal/telephony/NetworkTypeController.java b/src/java/com/android/internal/telephony/NetworkTypeController.java
index 2bb7e66..210f485 100644
--- a/src/java/com/android/internal/telephony/NetworkTypeController.java
+++ b/src/java/com/android/internal/telephony/NetworkTypeController.java
@@ -275,7 +275,7 @@
if (kv[1].equals(ICON_5G)) {
icon = TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_NSA;
} else if (kv[1].equals(ICON_5G_PLUS)) {
- icon = TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_NSA_MMWAVE;
+ icon = TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_ADVANCED;
} else {
if (DBG) loge("Invalid 5G icon = " + kv[1]);
}
@@ -367,7 +367,7 @@
// NR display is not accurate when physical channel config notifications are off
if (mIsPhysicalChannelConfigOn && (nrNsa || nrSa)) {
// Process NR display network type
- displayNetworkType = getNrDisplayType();
+ displayNetworkType = getNrDisplayType(nrSa);
if (displayNetworkType == TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NONE) {
// Use LTE values if 5G values aren't defined
displayNetworkType = getLteDisplayType();
@@ -379,7 +379,7 @@
return displayNetworkType;
}
- private @Annotation.OverrideNetworkType int getNrDisplayType() {
+ private @Annotation.OverrideNetworkType int getNrDisplayType(boolean isNrSa) {
// Don't show 5G icon if preferred network type does not include 5G
if ((mPhone.getCachedAllowedNetworkTypesBitmask()
& TelephonyManager.NETWORK_TYPE_BITMASK_NR) == 0) {
@@ -387,21 +387,24 @@
}
// Icon display keys in order of priority
List<String> keys = new ArrayList<>();
- // TODO: Update for NR SA
- switch (mPhone.getServiceState().getNrState()) {
- case NetworkRegistrationInfo.NR_STATE_CONNECTED:
- if (isNrMmwave()) {
- keys.add(STATE_CONNECTED_MMWAVE);
- }
- keys.add(STATE_CONNECTED);
- break;
- case NetworkRegistrationInfo.NR_STATE_NOT_RESTRICTED:
- keys.add(isPhysicalLinkActive() ? STATE_NOT_RESTRICTED_RRC_CON
- : STATE_NOT_RESTRICTED_RRC_IDLE);
- break;
- case NetworkRegistrationInfo.NR_STATE_RESTRICTED:
- keys.add(STATE_RESTRICTED);
- break;
+ if (isNrSa && isNrMmwave()) {
+ keys.add(STATE_CONNECTED_MMWAVE);
+ } else {
+ switch (mPhone.getServiceState().getNrState()) {
+ case NetworkRegistrationInfo.NR_STATE_CONNECTED:
+ if (isNrMmwave()) {
+ keys.add(STATE_CONNECTED_MMWAVE);
+ }
+ keys.add(STATE_CONNECTED);
+ break;
+ case NetworkRegistrationInfo.NR_STATE_NOT_RESTRICTED:
+ keys.add(isPhysicalLinkActive() ? STATE_NOT_RESTRICTED_RRC_CON
+ : STATE_NOT_RESTRICTED_RRC_IDLE);
+ break;
+ case NetworkRegistrationInfo.NR_STATE_RESTRICTED:
+ keys.add(STATE_RESTRICTED);
+ break;
+ }
}
for (String key : keys) {
diff --git a/src/java/com/android/internal/telephony/Phone.java b/src/java/com/android/internal/telephony/Phone.java
index 39846b9..9d7444d 100644
--- a/src/java/com/android/internal/telephony/Phone.java
+++ b/src/java/com/android/internal/telephony/Phone.java
@@ -78,6 +78,7 @@
import com.android.internal.telephony.dataconnection.DataConnectionReasons;
import com.android.internal.telephony.dataconnection.DataEnabledSettings;
import com.android.internal.telephony.dataconnection.DcTracker;
+import com.android.internal.telephony.dataconnection.LinkBandwidthEstimator;
import com.android.internal.telephony.dataconnection.TransportManager;
import com.android.internal.telephony.emergency.EmergencyNumberTracker;
import com.android.internal.telephony.imsphone.ImsPhoneCall;
@@ -457,6 +458,8 @@
protected VoiceCallSessionStats mVoiceCallSessionStats;
protected SmsStats mSmsStats;
+ protected LinkBandwidthEstimator mLinkBandwidthEstimator;
+
public IccRecords getIccRecords() {
return mIccRecords.get();
}
@@ -2026,7 +2029,7 @@
* Retrieves manually selected network info.
*/
public String getManualNetworkSelectionPlmn() {
- return "";
+ return null;
}
@@ -2695,6 +2698,18 @@
mCi.nvResetConfig(2 /* erase NV */, response);
}
+ /**
+ * Erase data saved in the SharedPreference. Used for network reset
+ *
+ */
+ public boolean eraseDataInSharedPreferences() {
+ SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(getContext());
+ SharedPreferences.Editor editor = sp.edit();
+ Rlog.d(LOG_TAG, "Erase all data saved in SharedPreferences");
+ editor.clear();
+ return editor.commit();
+ }
+
public void setSystemSelectionChannels(List<RadioAccessSpecifier> specifiers,
Message response) {
mCi.setSystemSelectionChannels(specifiers, response);
@@ -4366,20 +4381,6 @@
}
/**
- * Determines if IMS is enabled for call.
- *
- * @return {@code true} if IMS calling is enabled.
- */
- public boolean isImsUseEnabled() {
- ImsManager imsManager = ImsManager.getInstance(mContext, mPhoneId);
- boolean imsUseEnabled = ((imsManager.isVolteEnabledByPlatform()
- && imsManager.isEnhanced4gLteModeSettingEnabledByUser())
- || (imsManager.isWfcEnabledByPlatform() && imsManager.isWfcEnabledByUser())
- && imsManager.isNonTtyOrTtyOnVolteEnabled());
- return imsUseEnabled;
- }
-
- /**
* Determines if the connection to IMS services are available yet.
* @return {@code true} if the connection to IMS services are available.
*/
@@ -4759,6 +4760,29 @@
return Collections.emptyList();
}
+ /**
+ *
+ * @return
+ */
+ public @NonNull List<String> getDataServicePackages() {
+ return Collections.emptyList();
+ }
+
+ /**
+ * Return link bandwidth estimator
+ */
+ public LinkBandwidthEstimator getLinkBandwidthEstimator() {
+ return mLinkBandwidthEstimator;
+ }
+
+ /**
+ * Request to get the current slicing configuration including URSP rules and
+ * NSSAIs (configured, allowed and rejected).
+ */
+ public void getSlicingConfig(Message response) {
+ mCi.getSlicingConfig(response);
+ }
+
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
pw.println("Phone: subId=" + getSubId());
pw.println(" mPhoneId=" + mPhoneId);
@@ -4935,6 +4959,12 @@
pw.println("++++++++++++++++++++++++++++++++");
}
+ if (getLinkBandwidthEstimator() != null) {
+ pw.println("LinkBandwidthEstimator:");
+ getLinkBandwidthEstimator().dump(fd, pw, args);
+ pw.println("++++++++++++++++++++++++++++++++");
+ }
+
pw.println("Phone Local Log: ");
if (mLocalLog != null) {
try {
diff --git a/src/java/com/android/internal/telephony/PhoneConfigurationManager.java b/src/java/com/android/internal/telephony/PhoneConfigurationManager.java
index 907d3e6..d92f96d 100644
--- a/src/java/com/android/internal/telephony/PhoneConfigurationManager.java
+++ b/src/java/com/android/internal/telephony/PhoneConfigurationManager.java
@@ -312,7 +312,7 @@
}
public int getNumberOfModemsWithSimultaneousDataConnections() {
- return mStaticCapability.maxActiveData;
+ return mStaticCapability.getMaxActiveDataSubscriptions();
}
private void notifyCapabilityChanged() {
@@ -327,7 +327,7 @@
*/
public void switchMultiSimConfig(int numOfSims) {
log("switchMultiSimConfig: with numOfSims = " + numOfSims);
- if (getStaticPhoneCapability().logicalModemList.size() < numOfSims) {
+ if (getStaticPhoneCapability().getLogicalModemList().size() < numOfSims) {
log("switchMultiSimConfig: Phone is not capable of enabling "
+ numOfSims + " sims, exiting!");
return;
diff --git a/src/java/com/android/internal/telephony/PhoneFactory.java b/src/java/com/android/internal/telephony/PhoneFactory.java
index a480af8..d51fa91 100644
--- a/src/java/com/android/internal/telephony/PhoneFactory.java
+++ b/src/java/com/android/internal/telephony/PhoneFactory.java
@@ -177,7 +177,6 @@
cdmaSubscription, i);
}
-
if (numPhones > 0) {
final RadioConfig radioConfig = RadioConfig.make(context,
sCommandsInterfaces[0].getHalVersion());
@@ -190,6 +189,7 @@
radioConfig, null);
}
+
// Instantiate UiccController so that all other classes can just
// call getInstance()
sUiccController = UiccController.make(context);
diff --git a/src/java/com/android/internal/telephony/PhoneNotifier.java b/src/java/com/android/internal/telephony/PhoneNotifier.java
index 4378529..701a157 100644
--- a/src/java/com/android/internal/telephony/PhoneNotifier.java
+++ b/src/java/com/android/internal/telephony/PhoneNotifier.java
@@ -124,7 +124,6 @@
void notifyPhysicalChannelConfig(Phone sender, List<PhysicalChannelConfig> configs);
/** Notify DataEnabled has changed. */
-
void notifyDataEnabled(Phone sender, boolean enabled, @DataEnabledReason int reason);
/** Notify Allowed Network Type has changed. */
diff --git a/src/java/com/android/internal/telephony/PhoneSubInfoController.java b/src/java/com/android/internal/telephony/PhoneSubInfoController.java
index 8211f2d..2727a19 100644
--- a/src/java/com/android/internal/telephony/PhoneSubInfoController.java
+++ b/src/java/com/android/internal/telephony/PhoneSubInfoController.java
@@ -264,6 +264,17 @@
return PhoneFactory.getPhone(phoneId);
}
+ private boolean enforceIccSimChallengeResponsePermission(Context context, int subId,
+ String callingPackage, String callingFeatureId, String message) {
+ if (TelephonyPermissions.checkCallingOrSelfUseIccAuthWithDeviceIdentifier(context,
+ callingPackage, callingFeatureId, message)) {
+ return true;
+ }
+ if (VDBG) log("No USE_ICC_AUTH_WITH_DEVICE_IDENTIFIER permission.");
+ enforcePrivilegedPermissionOrCarrierPrivilege(subId, message);
+ return true;
+ }
+
/**
* Make sure caller has either read privileged phone permission or carrier privilege.
*
@@ -370,8 +381,9 @@
});
}
- public String getIccSimChallengeResponse(int subId, int appType, int authType, String data)
- throws RemoteException {
+ @Override
+ public String getIccSimChallengeResponse(int subId, int appType, int authType, String data,
+ String callingPackage, String callingFeatureId) throws RemoteException {
CallPhoneMethodHelper<String> toExecute = (phone)-> {
UiccCard uiccCard = phone.getUiccCard();
if (uiccCard == null) {
@@ -396,12 +408,9 @@
return uiccApp.getIccRecords().getIccSimChallengeResponse(authType, data);
};
- return callPhoneMethodWithPermissionCheck(subId, null, null, "getIccSimChallengeResponse",
- toExecute,
- (aContext, aSubId, aCallingPackage, aCallingFeatureId, aMessage) -> {
- enforcePrivilegedPermissionOrCarrierPrivilege(aSubId, aMessage);
- return true;
- });
+ return callPhoneMethodWithPermissionCheck(subId, callingPackage, callingFeatureId,
+ "getIccSimChallengeResponse", toExecute,
+ this::enforceIccSimChallengeResponsePermission);
}
public String getGroupIdLevel1ForSubscriber(int subId, String callingPackage,
diff --git a/src/java/com/android/internal/telephony/PhoneSwitcher.java b/src/java/com/android/internal/telephony/PhoneSwitcher.java
index 46bf008..73859ef 100644
--- a/src/java/com/android/internal/telephony/PhoneSwitcher.java
+++ b/src/java/com/android/internal/telephony/PhoneSwitcher.java
@@ -24,6 +24,8 @@
import static android.telephony.TelephonyManager.SET_OPPORTUNISTIC_SUB_INACTIVE_SUBSCRIPTION;
import static android.telephony.TelephonyManager.SET_OPPORTUNISTIC_SUB_SUCCESS;
import static android.telephony.TelephonyManager.SET_OPPORTUNISTIC_SUB_VALIDATION_FAILED;
+import static android.telephony.ims.stub.ImsRegistrationImplBase.REGISTRATION_TECH_CROSS_SIM;
+import static android.telephony.ims.stub.ImsRegistrationImplBase.REGISTRATION_TECH_IWLAN;
import static java.util.Arrays.copyOf;
@@ -56,8 +58,10 @@
import android.telephony.TelephonyManager;
import android.telephony.TelephonyRegistryManager;
import android.telephony.data.ApnSetting;
+import android.telephony.ims.stub.ImsRegistrationImplBase;
import android.util.LocalLog;
+import com.android.ims.ImsManager;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.telephony.SubscriptionController.WatchedInt;
import com.android.internal.telephony.dataconnection.ApnConfigTypeRepository;
@@ -309,6 +313,19 @@
private final DefaultNetworkCallback mDefaultNetworkCallback = new DefaultNetworkCallback();
/**
+ * Interface to get ImsRegistrationTech. It's a wrapper of ImsManager#getRegistrationTech,
+ * to make it mock-able in unittests.
+ */
+ public interface ImsRegTechProvider {
+ /** Get IMS registration tech. */
+ @ImsRegistrationImplBase.ImsRegistrationTech int get(Context context, int phoneId);
+ }
+
+ @VisibleForTesting
+ public ImsRegTechProvider mImsRegTechProvider =
+ (context, phoneId) -> ImsManager.getInstance(context, phoneId).getRegistrationTech();
+
+ /**
* Method to get singleton instance.
*/
public static PhoneSwitcher getInstance() {
@@ -327,6 +344,27 @@
return sPhoneSwitcher;
}
+ /**
+ * Whether this phone IMS registration is on its original network. This result impacts
+ * whether we want to do DDS switch to the phone having voice call.
+ * If it's registered on IWLAN or cross SIM in multi-SIM case, return false. Otherwise,
+ * return true.
+ */
+ private boolean isImsOnOriginalNetwork(Phone phone) {
+ if (phone == null) return false;
+ int phoneId = phone.getPhoneId();
+ if (!SubscriptionManager.isValidPhoneId(phoneId)) return false;
+
+ int imsRegTech = mImsRegTechProvider.get(mContext, phoneId);
+ // If IMS is registered on IWLAN or cross SIM, return false.
+ boolean isOnOriginalNetwork = (imsRegTech != REGISTRATION_TECH_IWLAN)
+ && (imsRegTech != REGISTRATION_TECH_CROSS_SIM);
+ if (!isOnOriginalNetwork) {
+ log("IMS call on IWLAN or cross SIM. Call will be ignored for DDS switch");
+ }
+ return isOnOriginalNetwork;
+ }
+
private boolean isPhoneInVoiceCallChanged() {
int oldPhoneIdInVoiceCall = mPhoneIdInVoiceCall;
// If there's no active call, the value will become INVALID_PHONE_INDEX
@@ -334,7 +372,8 @@
// subscription.
mPhoneIdInVoiceCall = SubscriptionManager.INVALID_PHONE_INDEX;
for (Phone phone : PhoneFactory.getPhones()) {
- if (isPhoneInVoiceCall(phone) || isPhoneInVoiceCall(phone.getImsPhone())) {
+ if (isPhoneInVoiceCall(phone) || (isPhoneInVoiceCall(phone.getImsPhone())
+ && isImsOnOriginalNetwork(phone))) {
mPhoneIdInVoiceCall = phone.getPhoneId();
break;
}
diff --git a/src/java/com/android/internal/telephony/RIL.java b/src/java/com/android/internal/telephony/RIL.java
index 638ff39..53f876c 100644
--- a/src/java/com/android/internal/telephony/RIL.java
+++ b/src/java/com/android/internal/telephony/RIL.java
@@ -109,9 +109,9 @@
import android.telephony.data.DataCallResponse.HandoverFailureMode;
import android.telephony.data.DataProfile;
import android.telephony.data.DataService;
+import android.telephony.data.NetworkSliceInfo;
import android.telephony.data.Qos;
import android.telephony.data.QosBearerSession;
-import android.telephony.data.SliceInfo;
import android.telephony.data.TrafficDescriptor;
import android.telephony.emergency.EmergencyNumber;
import android.text.TextUtils;
@@ -430,7 +430,7 @@
switch(rr.mRequest) {
case RIL_REQUEST_GET_ACTIVITY_INFO:
timeoutResponse = new ModemActivityInfo(
- 0, 0, 0, new int [ModemActivityInfo.TX_POWER_LEVELS], 0);
+ 0, 0, 0, new int [ModemActivityInfo.getNumTxPowerLevels()], 0);
break;
};
return timeoutResponse;
@@ -1804,7 +1804,8 @@
}
long messageId = ((SMSDispatcher.SmsTracker) result.obj).mMessageId;
if (RILJ_LOGV) {
- Rlog.d(RILJ_LOG_TAG, "getOutgoingSmsMessageId messageId: " + messageId);
+ Rlog.d(RILJ_LOG_TAG, "getOutgoingSmsMessageId "
+ + SmsController.formatCrossStackMessageId(messageId));
}
return messageId;
}
@@ -1930,7 +1931,7 @@
return dpi;
}
- private static OptionalSliceInfo convertToHalSliceInfo(@Nullable SliceInfo sliceInfo) {
+ private static OptionalSliceInfo convertToHalSliceInfo(@Nullable NetworkSliceInfo sliceInfo) {
OptionalSliceInfo optionalSliceInfo = new OptionalSliceInfo();
if (sliceInfo == null) {
return optionalSliceInfo;
@@ -1956,8 +1957,8 @@
new android.hardware.radio.V1_6.TrafficDescriptor();
OptionalDnn optionalDnn = new OptionalDnn();
- if (trafficDescriptor.getDnn() != null) {
- optionalDnn.value(trafficDescriptor.getDnn());
+ if (trafficDescriptor.getDataNetworkName() != null) {
+ optionalDnn.value(trafficDescriptor.getDataNetworkName());
}
td.dnn = optionalDnn;
@@ -2051,8 +2052,8 @@
@Override
public void setupDataCall(int accessNetworkType, DataProfile dataProfile, boolean isRoaming,
boolean allowRoaming, int reason, LinkProperties linkProperties, int pduSessionId,
- SliceInfo sliceInfo, TrafficDescriptor trafficDescriptor, boolean matchAllRuleAllowed,
- Message result) {
+ NetworkSliceInfo sliceInfo, TrafficDescriptor trafficDescriptor,
+ boolean matchAllRuleAllowed, Message result) {
IRadio radioProxy = getRadioProxy(result);
if (radioProxy != null) {
@@ -5572,8 +5573,7 @@
} catch (RemoteException | RuntimeException e) {
handleRadioProxyExceptionForRR(rr, "setCarrierInfoForImsiEncryption", e);
}
- }
- else if (mRadioVersion.greaterOrEqual(RADIO_HAL_VERSION_1_1)) {
+ } else if (mRadioVersion.greaterOrEqual(RADIO_HAL_VERSION_1_1)) {
android.hardware.radio.V1_1.IRadio radioProxy11 =
(android.hardware.radio.V1_1.IRadio ) radioProxy;
@@ -5977,6 +5977,32 @@
}
}
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void getSlicingConfig(Message result) {
+ android.hardware.radio.V1_6.IRadio radioProxy16 = getRadioV16(result);
+
+ if (radioProxy16 != null) {
+ RILRequest rr = obtainRequest(RIL_REQUEST_GET_SLICING_CONFIG, result,
+ mRILDefaultWorkSource);
+
+ if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));
+
+ try {
+ radioProxy16.getSlicingConfig(rr.mSerial);
+ } catch (RemoteException | RuntimeException e) {
+ handleRadioProxyExceptionForRR(rr, "getSlicingConfig", e);
+ }
+ } else {
+ if (RILJ_LOGD) Rlog.d(RILJ_LOG_TAG, "getSlicingConfig: REQUEST_NOT_SUPPORTED");
+ AsyncResult.forMessage(result, null,
+ CommandException.fromRilErrno(REQUEST_NOT_SUPPORTED));
+ result.sendToTarget();
+ }
+ }
+
//***** Private Methods
/** Helper that gets V1.6 of the radio interface OR sends back REQUEST_NOT_SUPPORTED */
@Nullable private android.hardware.radio.V1_6.IRadio getRadioV16(Message msg) {
@@ -6954,6 +6980,8 @@
return "RIL_REQUEST_SET_ALLOWED_NETWORK_TYPE_BITMAP";
case RIL_REQUEST_GET_ALLOWED_NETWORK_TYPES_BITMAP:
return "RIL_REQUEST_GET_ALLOWED_NETWORK_TYPE_BITMAP";
+ case RIL_REQUEST_GET_SLICING_CONFIG:
+ return "RIL_REQUEST_GET_SLICING_CONFIG";
default: return "<unknown request>";
}
}
@@ -7490,7 +7518,7 @@
List<LinkAddress> laList = new ArrayList<>();
List<QosBearerSession> qosSessions = new ArrayList<>();
- SliceInfo sliceInfo = null;
+ NetworkSliceInfo sliceInfo = null;
List<TrafficDescriptor> trafficDescriptors = new ArrayList<>();
if (dcResult instanceof android.hardware.radio.V1_0.SetupDataCallResult) {
@@ -7657,17 +7685,17 @@
.build();
}
- private static SliceInfo convertToSliceInfo(OptionalSliceInfo optionalSliceInfo) {
+ private static NetworkSliceInfo convertToSliceInfo(OptionalSliceInfo optionalSliceInfo) {
if (optionalSliceInfo.getDiscriminator() == OptionalSliceInfo.hidl_discriminator.noinit) {
return null;
}
android.hardware.radio.V1_6.SliceInfo si = optionalSliceInfo.value();
- SliceInfo.Builder builder =
- new SliceInfo.Builder()
+ NetworkSliceInfo.Builder builder =
+ new NetworkSliceInfo.Builder()
.setSliceServiceType(si.sst)
.setMappedHplmnSliceServiceType(si.mappedHplmnSst);
- if (si.sliceDifferentiator != SliceInfo.SLICE_DIFFERENTIATOR_NO_SLICE) {
+ if (si.sliceDifferentiator != NetworkSliceInfo.SLICE_DIFFERENTIATOR_NO_SLICE) {
builder
.setSliceDifferentiator(si.sliceDifferentiator)
.setMappedHplmnSliceDifferentiator(si.mappedHplmnSD);
@@ -7681,7 +7709,14 @@
? null : td.dnn.value();
String osAppId = td.osAppId.getDiscriminator() == OptionalOsAppId.hidl_discriminator.noinit
? null : new String(arrayListToPrimitiveArray(td.osAppId.value().osAppId));
- return new TrafficDescriptor(dnn, osAppId);
+ TrafficDescriptor.Builder builder = new TrafficDescriptor.Builder();
+ if (dnn != null) {
+ builder.setDataNetworkName(dnn);
+ }
+ if (osAppId != null) {
+ builder.setOsAppId(osAppId);
+ }
+ return builder.build();
}
/**
diff --git a/src/java/com/android/internal/telephony/RadioConfig.java b/src/java/com/android/internal/telephony/RadioConfig.java
index 7a1e089..32b24fe 100644
--- a/src/java/com/android/internal/telephony/RadioConfig.java
+++ b/src/java/com/android/internal/telephony/RadioConfig.java
@@ -16,6 +16,9 @@
package com.android.internal.telephony;
+import static android.telephony.PhoneCapability.DEVICE_NR_CAPABILITY_NSA;
+import static android.telephony.PhoneCapability.DEVICE_NR_CAPABILITY_SA;
+
import static com.android.internal.telephony.RILConstants.RADIO_NOT_AVAILABLE;
import static com.android.internal.telephony.RILConstants.REQUEST_NOT_SUPPORTED;
import static com.android.internal.telephony.RILConstants.RIL_REQUEST_GET_HAL_DEVICE_CAPABILITIES;
@@ -45,6 +48,7 @@
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.List;
import java.util.NoSuchElementException;
import java.util.concurrent.atomic.AtomicLong;
@@ -77,6 +81,7 @@
private final SparseArray<RILRequest> mRequestList = new SparseArray<RILRequest>();
/* default work source which will blame phone process */
private final WorkSource mDefaultWorkSource;
+ private final int[] mDeviceNrCapabilities;
private static RadioConfig sRadioConfig;
private static final Object sLock = new Object();
@@ -108,6 +113,24 @@
mDefaultWorkSource = new WorkSource(context.getApplicationInfo().uid,
context.getPackageName());
+
+ boolean is5gStandalone = context.getResources().getBoolean(
+ com.android.internal.R.bool.config_telephony5gStandalone);
+ boolean is5gNonStandalone = context.getResources().getBoolean(
+ com.android.internal.R.bool.config_telephony5gNonStandalone);
+
+ if (!is5gStandalone && !is5gNonStandalone) {
+ mDeviceNrCapabilities = new int[0];
+ } else {
+ List<Integer> list = new ArrayList<>();
+ if (is5gNonStandalone) {
+ list.add(DEVICE_NR_CAPABILITY_NSA);
+ }
+ if (is5gStandalone) {
+ list.add(DEVICE_NR_CAPABILITY_SA);
+ }
+ mDeviceNrCapabilities = list.stream().mapToInt(Integer::valueOf).toArray();
+ }
}
/**
@@ -563,6 +586,13 @@
}
}
+ /**
+ * Returns the device's nr capability.
+ */
+ public int[] getDeviceNrCapabilities() {
+ return mDeviceNrCapabilities;
+ }
+
static ArrayList<IccSlotStatus> convertHalSlotStatus(
ArrayList<android.hardware.radio.config.V1_0.SimSlotStatus> halSlotStatusList) {
ArrayList<IccSlotStatus> response = new ArrayList<IccSlotStatus>(halSlotStatusList.size());
diff --git a/src/java/com/android/internal/telephony/RadioConfigResponse.java b/src/java/com/android/internal/telephony/RadioConfigResponse.java
index 95c304d..88e5e80 100644
--- a/src/java/com/android/internal/telephony/RadioConfigResponse.java
+++ b/src/java/com/android/internal/telephony/RadioConfigResponse.java
@@ -20,6 +20,7 @@
import static android.telephony.TelephonyManager
.CAPABILITY_NR_DUAL_CONNECTIVITY_CONFIGURATION_AVAILABLE;
import static android.telephony.TelephonyManager.CAPABILITY_SECONDARY_LINK_BANDWIDTH_VISIBLE;
+import static android.telephony.TelephonyManager.CAPABILITY_SLICING_CONFIG_SUPPORTED;
import static android.telephony.TelephonyManager.CAPABILITY_THERMAL_MITIGATION_DATA_THROTTLING;
import static android.telephony.TelephonyManager.RadioInterfaceCapability;
@@ -133,7 +134,6 @@
// TODO b/121394331: clean up V1_1.PhoneCapability fields.
int maxActiveVoiceCalls = 0;
int maxActiveData = phoneCapability.maxActiveData;
- int max5G = 0;
boolean validationBeforeSwitchSupported = phoneCapability.isInternetLingeringSupported;
List<ModemInfo> logicalModemList = new ArrayList();
@@ -142,8 +142,8 @@
logicalModemList.add(new ModemInfo(modemInfo.modemId));
}
- return new PhoneCapability(maxActiveVoiceCalls, maxActiveData, max5G, logicalModemList,
- validationBeforeSwitchSupported);
+ return new PhoneCapability(maxActiveVoiceCalls, maxActiveData, logicalModemList,
+ validationBeforeSwitchSupported, mRadioConfig.getDeviceNrCapabilities());
}
/**
* Response function for IRadioConfig.getPhoneCapability().
@@ -310,6 +310,8 @@
Rlog.d(TAG, "CAPABILITY_NR_DUAL_CONNECTIVITY_CONFIGURATION_AVAILABLE");
caps.add(CAPABILITY_THERMAL_MITIGATION_DATA_THROTTLING);
Rlog.d(TAG, "CAPABILITY_THERMAL_MITIGATION_DATA_THROTTLING");
+ caps.add(CAPABILITY_SLICING_CONFIG_SUPPORTED);
+ Rlog.d(TAG, "CAPABILITY_SLICING_CONFIG_SUPPORTED");
}
}
return caps;
diff --git a/src/java/com/android/internal/telephony/RadioResponse.java b/src/java/com/android/internal/telephony/RadioResponse.java
index 7dd9dfb..313ef0b 100644
--- a/src/java/com/android/internal/telephony/RadioResponse.java
+++ b/src/java/com/android/internal/telephony/RadioResponse.java
@@ -56,6 +56,7 @@
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
import android.telephony.data.DataCallResponse;
+import android.telephony.data.SlicingConfig;
import android.text.TextUtils;
import com.android.internal.telephony.dataconnection.KeepaliveStatus;
@@ -2803,16 +2804,16 @@
if (responseInfo.error == RadioError.NONE) {
final int sleepModeTimeMs = activityInfo.sleepModeTimeMs;
final int idleModeTimeMs = activityInfo.idleModeTimeMs;
- int [] txModeTimeMs = new int[ModemActivityInfo.TX_POWER_LEVELS];
- for (int i = 0; i < ModemActivityInfo.TX_POWER_LEVELS; i++) {
+ int [] txModeTimeMs = new int[ModemActivityInfo.getNumTxPowerLevels()];
+ for (int i = 0; i < ModemActivityInfo.getNumTxPowerLevels(); i++) {
txModeTimeMs[i] = activityInfo.txmModetimeMs[i];
}
final int rxModeTimeMs = activityInfo.rxModeTimeMs;
ret = new ModemActivityInfo(SystemClock.elapsedRealtime(), sleepModeTimeMs,
idleModeTimeMs, txModeTimeMs, rxModeTimeMs);
} else {
- ret = new ModemActivityInfo(0, 0, 0, new int [ModemActivityInfo.TX_POWER_LEVELS],
- 0);
+ ret = new ModemActivityInfo(0, 0, 0,
+ new int[ModemActivityInfo.getNumTxPowerLevels()], 0);
responseInfo.error = RadioError.NONE;
}
sendMessageResponse(rr.mResult, ret);
@@ -3102,10 +3103,11 @@
RILRequest rr = mRil.processResponse_1_6(info);
if (rr != null) {
+ SlicingConfig ret = new SlicingConfig(slicingConfig);
if (info.error == RadioError.NONE) {
- sendMessageResponse(rr.mResult, slicingConfig);
+ sendMessageResponse(rr.mResult, ret);
}
- mRil.processResponseDone_1_6(rr, info, slicingConfig);
+ mRil.processResponseDone_1_6(rr, info, ret);
}
}
}
diff --git a/src/java/com/android/internal/telephony/SMSDispatcher.java b/src/java/com/android/internal/telephony/SMSDispatcher.java
index 6774d46..d47dda1 100644
--- a/src/java/com/android/internal/telephony/SMSDispatcher.java
+++ b/src/java/com/android/internal/telephony/SMSDispatcher.java
@@ -359,7 +359,8 @@
SmsSenderCallback senderCallback) {
mSenderCallback = senderCallback;
if (!mCarrierMessagingServiceWrapper.bindToCarrierMessagingService(
- mContext, carrierPackageName, ()->onServiceReady())) {
+ mContext, carrierPackageName, runnable -> runnable.run(),
+ ()->onServiceReady())) {
Rlog.e(TAG, "bindService() for carrier messaging service failed");
mSenderCallback.onSendSmsComplete(
CarrierMessagingService.SEND_STATUS_RETRY_ON_CARRIER_NETWORK,
@@ -394,6 +395,7 @@
(mTracker.mDeliveryIntent != null)
? CarrierMessagingService.SEND_FLAG_REQUEST_DELIVERY_STATUS
: 0,
+ runnable -> runnable.run(),
mSenderCallback);
} catch (RuntimeException e) {
Rlog.e(TAG, "Exception sending the SMS: " + e);
@@ -433,10 +435,11 @@
(mTracker.mDeliveryIntent != null)
? CarrierMessagingService.SEND_FLAG_REQUEST_DELIVERY_STATUS
: 0,
+ runnable -> runnable.run(),
mSenderCallback);
} catch (RuntimeException e) {
Rlog.e(TAG, "Exception sending the SMS: " + e
- + " id: " + mTracker.mMessageId);
+ + " " + SmsController.formatCrossStackMessageId(mTracker.mMessageId));
mSenderCallback.onSendSmsComplete(
CarrierMessagingService.SEND_STATUS_RETRY_ON_CARRIER_NETWORK,
0 /* messageRef */);
@@ -468,7 +471,7 @@
checkCallerIsPhoneOrCarrierApp();
final long identity = Binder.clearCallingIdentity();
try {
- mSmsSender.mCarrierMessagingServiceWrapper.disposeConnection(mContext);
+ mSmsSender.mCarrierMessagingServiceWrapper.disconnect();
processSendSmsResponse(mSmsSender.mTracker, result, messageRef);
} finally {
Binder.restoreCallingIdentity(identity);
@@ -481,8 +484,8 @@
}
@Override
- public void onFilterComplete(int result) {
- Rlog.e(TAG, "Unexpected onFilterComplete call with result: " + result);
+ public void onReceiveSmsComplete(int result) {
+ Rlog.e(TAG, "Unexpected onReceiveSmsComplete call with result: " + result);
}
@Override
@@ -509,7 +512,8 @@
switch (result) {
case CarrierMessagingService.SEND_STATUS_OK:
Rlog.d(TAG, "processSendSmsResponse: Sending SMS by CarrierMessagingService "
- + "succeeded. id: " + tracker.mMessageId);
+ + "succeeded. "
+ + SmsController.formatCrossStackMessageId(tracker.mMessageId));
sendMessage(obtainMessage(EVENT_SEND_SMS_COMPLETE,
new AsyncResult(tracker,
smsResponse,
@@ -517,19 +521,21 @@
break;
case CarrierMessagingService.SEND_STATUS_ERROR:
Rlog.d(TAG, "processSendSmsResponse: Sending SMS by CarrierMessagingService failed."
- + " id: " + tracker.mMessageId);
+ + " " + SmsController.formatCrossStackMessageId(tracker.mMessageId));
sendMessage(obtainMessage(EVENT_SEND_SMS_COMPLETE,
new AsyncResult(tracker, smsResponse,
new CommandException(CommandException.Error.GENERIC_FAILURE))));
break;
case CarrierMessagingService.SEND_STATUS_RETRY_ON_CARRIER_NETWORK:
Rlog.d(TAG, "processSendSmsResponse: Sending SMS by CarrierMessagingService failed."
- + " Retry on carrier network. id: " + tracker.mMessageId);
+ + " Retry on carrier network. "
+ + SmsController.formatCrossStackMessageId(tracker.mMessageId));
sendSubmitPdu(tracker);
break;
default:
Rlog.d(TAG, "processSendSmsResponse: Unknown result " + result + " Retry on carrier"
- + " network. id: " + tracker.mMessageId);
+ + " network. "
+ + SmsController.formatCrossStackMessageId(tracker.mMessageId));
sendSubmitPdu(tracker);
}
}
@@ -555,7 +561,8 @@
MultipartSmsSenderCallback senderCallback) {
mSenderCallback = senderCallback;
if (!mCarrierMessagingServiceWrapper.bindToCarrierMessagingService(
- mContext, carrierPackageName, ()->onServiceReady())) {
+ mContext, carrierPackageName, runnable -> runnable.run(),
+ ()->onServiceReady())) {
Rlog.e(TAG, "bindService() for carrier messaging service failed");
mSenderCallback.onSendMultipartSmsComplete(
CarrierMessagingService.SEND_STATUS_RETRY_ON_CARRIER_NETWORK,
@@ -582,6 +589,7 @@
statusReportRequested
? CarrierMessagingService.SEND_FLAG_REQUEST_DELIVERY_STATUS
: 0,
+ runnable -> runnable.run(),
mSenderCallback);
} catch (RuntimeException e) {
Rlog.e(TAG, "Exception sending the SMS: " + e);
@@ -613,7 +621,7 @@
*/
@Override
public void onSendMultipartSmsComplete(int result, int[] messageRefs) {
- mSmsSender.mCarrierMessagingServiceWrapper.disposeConnection(mContext);
+ mSmsSender.mCarrierMessagingServiceWrapper.disconnect();
if (mSmsSender.mTrackers == null) {
Rlog.e(TAG, "Unexpected onSendMultipartSmsComplete call with null trackers.");
@@ -630,8 +638,8 @@
}
@Override
- public void onFilterComplete(int result) {
- Rlog.e(TAG, "Unexpected onFilterComplete call with result: " + result);
+ public void onReceiveSmsComplete(int result) {
+ Rlog.e(TAG, "Unexpected onReceiveSmsComplete call with result: " + result);
}
@Override
@@ -655,7 +663,8 @@
switch (result) {
case CarrierMessagingService.SEND_STATUS_OK:
Rlog.d(TAG, "processSendMultipartSmsResponse: Sending SMS by "
- + "CarrierMessagingService succeeded. id: " + trackers[0].mMessageId);
+ + "CarrierMessagingService succeeded. "
+ + SmsController.formatCrossStackMessageId(trackers[0].mMessageId));
// Sending a multi-part SMS by CarrierMessagingService successfully completed.
// Send EVENT_SEND_SMS_COMPLETE for all the parts one by one.
for (int i = 0; i < trackers.length; i++) {
@@ -675,7 +684,8 @@
break;
case CarrierMessagingService.SEND_STATUS_ERROR:
Rlog.d(TAG, "processSendMultipartSmsResponse: Sending SMS by "
- + "CarrierMessagingService failed. id: " + trackers[0].mMessageId);
+ + "CarrierMessagingService failed. "
+ + SmsController.formatCrossStackMessageId(trackers[0].mMessageId));
// Sending a multi-part SMS by CarrierMessagingService failed.
// Send EVENT_SEND_SMS_COMPLETE with GENERIC_FAILURE for all the parts one by one.
for (int i = 0; i < trackers.length; i++) {
@@ -696,15 +706,16 @@
break;
case CarrierMessagingService.SEND_STATUS_RETRY_ON_CARRIER_NETWORK:
Rlog.d(TAG, "processSendMultipartSmsResponse: Sending SMS by "
- + "CarrierMessagingService failed. Retry on carrier network. id: "
- + trackers[0].mMessageId);
+ + "CarrierMessagingService failed. Retry on carrier network. "
+ + SmsController.formatCrossStackMessageId(trackers[0].mMessageId));
// All the parts for a multi-part SMS are handled together for retry. It helps to
// check user confirmation once also if needed.
sendSubmitPdu(trackers);
break;
default:
Rlog.d(TAG, "processSendMultipartSmsResponse: Unknown result " + result
- + ". Retry on carrier network. id: " + trackers[0].mMessageId);
+ + ". Retry on carrier network. "
+ + SmsController.formatCrossStackMessageId(trackers[0].mMessageId));
sendSubmitPdu(trackers);
}
}
@@ -754,7 +765,7 @@
if (ar.exception == null) {
if (DBG) {
Rlog.d(TAG, "SMS send complete. Broadcasting intent: " + sentIntent
- + " id: " + tracker.mMessageId);
+ + " " + SmsController.formatCrossStackMessageId(tracker.mMessageId));
}
if (tracker.mDeliveryIntent != null) {
@@ -773,7 +784,8 @@
tracker.isFromDefaultSmsApplication(mContext));
} else {
if (DBG) {
- Rlog.d(TAG, "SMS send failed id: " + tracker.mMessageId);
+ Rlog.d(TAG, "SMS send failed "
+ + SmsController.formatCrossStackMessageId(tracker.mMessageId));
}
int ss = mPhone.getServiceState().getState();
@@ -792,7 +804,7 @@
+ " mImsRetry=" + tracker.mImsRetry
+ " mMessageRef=" + tracker.mMessageRef
+ " SS= " + mPhone.getServiceState().getState()
- + " id=" + tracker.mMessageId);
+ + " " + SmsController.formatCrossStackMessageId(tracker.mMessageId));
}
// if sms over IMS is not supported on data and voice is not available...
@@ -1721,7 +1733,7 @@
PackageManager pm = mContext.getPackageManager();
try {
ApplicationInfo appInfo = pm.getApplicationInfoAsUser(appPackage, 0,
- UserHandle.getUserHandleForUid(userId));
+ UserHandle.of(userId));
return appInfo.loadSafeLabel(pm);
} catch (PackageManager.NameNotFoundException e) {
Rlog.e(TAG, "PackageManager Name Not Found for package " + appPackage);
@@ -1846,7 +1858,7 @@
mSmsDispatchersController.sendRetrySms(tracker);
} else {
Rlog.e(TAG, mSmsDispatchersController + " is null. Retry failed"
- + " id: " + tracker.mMessageId);
+ + " " + SmsController.formatCrossStackMessageId(tracker.mMessageId));
}
}
@@ -2142,7 +2154,7 @@
mSentIntent.send(context, error, fillIn);
} catch (CanceledException ex) {
Rlog.e(TAG, "Failed to send result"
- + " id: " + mMessageId);
+ + " " + SmsController.formatCrossStackMessageId(mMessageId));
}
}
reportAnomaly(error, errorCode);
diff --git a/src/java/com/android/internal/telephony/ServiceStateTracker.java b/src/java/com/android/internal/telephony/ServiceStateTracker.java
index ccc8539..5807b54 100755
--- a/src/java/com/android/internal/telephony/ServiceStateTracker.java
+++ b/src/java/com/android/internal/telephony/ServiceStateTracker.java
@@ -87,6 +87,7 @@
import android.telephony.SubscriptionManager.OnSubscriptionsChangedListener;
import android.telephony.TelephonyManager;
import android.telephony.VoiceSpecificRegistrationInfo;
+import android.telephony.ims.stub.ImsRegistrationImplBase;
import android.text.TextUtils;
import android.util.EventLog;
import android.util.LocalLog;
@@ -94,6 +95,7 @@
import android.util.SparseArray;
import android.util.SparseBooleanArray;
+import com.android.internal.R;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.telephony.cdma.CdmaSubscriptionSourceManager;
import com.android.internal.telephony.cdma.EriInfo;
@@ -239,6 +241,7 @@
private RegistrantList mNrStateChangedRegistrants = new RegistrantList();
private RegistrantList mNrFrequencyChangedRegistrants = new RegistrantList();
private RegistrantList mCssIndicatorChangedRegistrants = new RegistrantList();
+ private final RegistrantList mAirplaneModeChangedRegistrants = new RegistrantList();
/* Radio power off pending flag and tag counter */
private boolean mPendingRadioPowerOffAfterDataOff = false;
@@ -428,7 +431,6 @@
Context context = mPhone.getContext();
mPhone.notifyPhoneStateChanged();
- mPhone.notifyCallForwardingIndicator();
if (!SubscriptionManager.isValidSubscriptionId(mPrevSubId)) {
// just went from invalid to valid subId, so notify with current service
@@ -2007,6 +2009,7 @@
public void onAirplaneModeChanged(boolean isAirplaneModeOn) {
mLastNitzData = null;
mNitzState.handleAirplaneModeChanged(isAirplaneModeOn);
+ mAirplaneModeChangedRegistrants.notifyResult(isAirplaneModeOn);
}
protected Phone getPhone() {
@@ -2867,6 +2870,36 @@
wfcFlightSpnFormat = wfcSpnFormats[flightModeIdx];
}
+ String crossSimSpnFormat = null;
+ if (mPhone.getImsPhone() != null
+ && (mPhone.getImsPhone() != null)
+ && (mPhone.getImsPhone().getImsRegistrationTech()
+ == ImsRegistrationImplBase.REGISTRATION_TECH_CROSS_SIM)) {
+ // In Cros SIM Calling mode show SPN or PLMN + Cross SIM Calling
+ //
+ // 1) Show SPN + Cross SIM Calling If SIM has SPN and SPN display condition
+ // is satisfied or SPN override is enabled for this carrier
+ //
+ // 2) Show PLMN + Cross SIM Calling if there is no valid SPN in case 1
+ PersistableBundle bundle = getCarrierConfig();
+ int crossSimSpnFormatIdx =
+ bundle.getInt(CarrierConfigManager.KEY_CROSS_SIM_SPN_FORMAT_INT);
+ boolean useRootLocale =
+ bundle.getBoolean(CarrierConfigManager.KEY_WFC_SPN_USE_ROOT_LOCALE);
+
+ String[] crossSimSpnFormats = SubscriptionManager.getResourcesForSubId(
+ mPhone.getContext(),
+ mPhone.getSubId(), useRootLocale)
+ .getStringArray(R.array.crossSimSpnFormats);
+
+ if (crossSimSpnFormatIdx < 0 || crossSimSpnFormatIdx >= crossSimSpnFormats.length) {
+ loge("updateSpnDisplay: KEY_CROSS_SIM_SPN_FORMAT_INT out of bounds: "
+ + crossSimSpnFormatIdx);
+ crossSimSpnFormatIdx = 0;
+ }
+ crossSimSpnFormat = crossSimSpnFormats[crossSimSpnFormatIdx];
+ }
+
if (mPhone.isPhoneTypeGsm()) {
// The values of plmn/showPlmn change in different scenarios.
// 1) No service but emergency call allowed -> expected
@@ -2934,9 +2967,27 @@
&& ((rule & CARRIER_NAME_DISPLAY_BITMASK_SHOW_SPN)
== CARRIER_NAME_DISPLAY_BITMASK_SHOW_SPN);
if (DBG) log("updateSpnDisplay: rawSpn = " + spn);
-
- if (!TextUtils.isEmpty(spn) && !TextUtils.isEmpty(wfcVoiceSpnFormat) &&
- !TextUtils.isEmpty(wfcDataSpnFormat)) {
+ if (!TextUtils.isEmpty(crossSimSpnFormat)) {
+ if (!TextUtils.isEmpty(spn)) {
+ // Show SPN + Cross-SIM Calling If SIM has SPN and SPN display condition
+ // is satisfied or SPN override is enabled for this carrier.
+ String originalSpn = spn.trim();
+ spn = String.format(crossSimSpnFormat, originalSpn);
+ dataSpn = spn;
+ showSpn = true;
+ showPlmn = false;
+ } else if (!TextUtils.isEmpty(plmn)) {
+ // Show PLMN + Cross-SIM Calling if there is no valid SPN in the above case
+ String originalPlmn = plmn.trim();
+ PersistableBundle config = getCarrierConfig();
+ if (mIccRecords != null && config.getBoolean(
+ CarrierConfigManager.KEY_WFC_CARRIER_NAME_OVERRIDE_BY_PNN_BOOL)) {
+ originalPlmn = mIccRecords.getPnnHomeName();
+ }
+ plmn = String.format(crossSimSpnFormat, originalPlmn);
+ }
+ } else if (!TextUtils.isEmpty(spn) && !TextUtils.isEmpty(wfcVoiceSpnFormat)
+ && !TextUtils.isEmpty(wfcDataSpnFormat)) {
// Show SPN + Wi-Fi Calling If SIM has SPN and SPN display condition
// is satisfied or SPN override is enabled for this carrier.
@@ -4745,6 +4796,27 @@
}
/**
+ * Registration for Airplane Mode changing. The state of Airplane Mode will be returned
+ * {@link AsyncResult#result} as a {@link Boolean} Object.
+ * The {@link AsyncResult} will be in the notification {@link Message#obj}.
+ * @param h handler to notify
+ * @param what what code of message when delivered
+ * @param obj placed in {@link AsyncResult#userObj}
+ */
+ public void registerForAirplaneModeChanged(Handler h, int what, Object obj) {
+ mAirplaneModeChangedRegistrants.add(h, what, obj);
+ }
+
+ /**
+ * Unregister for Airplane Mode changed event.
+ *
+ * @param h The handler
+ */
+ public void unregisterForAirplaneModeChanged(Handler h) {
+ mAirplaneModeChangedRegistrants.remove(h);
+ }
+
+ /**
* Registration point for transition into network attached.
* @param h handler to notify
* @param what what code of message when delivered
@@ -5000,6 +5072,7 @@
updateReportingCriteria(config);
updateOperatorNamePattern(config);
mCdnr.updateEfFromCarrierConfig(config);
+ mPhone.notifyCallForwardingIndicator();
// Sometimes the network registration information comes before carrier config is ready.
// For some cases like roaming/non-roaming overriding, we need carrier config. So it's
diff --git a/src/java/com/android/internal/telephony/SmsController.java b/src/java/com/android/internal/telephony/SmsController.java
index 3c9fe0a..e7feaf4 100644
--- a/src/java/com/android/internal/telephony/SmsController.java
+++ b/src/java/com/android/internal/telephony/SmsController.java
@@ -841,4 +841,11 @@
return false;
}
}
+
+ /**
+ * Internal API to consistently format the debug log output of the cross-stack message id.
+ */
+ public static String formatCrossStackMessageId(long id) {
+ return "{x-message-id:" + id + "}";
+ }
}
diff --git a/src/java/com/android/internal/telephony/SmsDispatchersController.java b/src/java/com/android/internal/telephony/SmsDispatchersController.java
index ddaf571..2e38376 100644
--- a/src/java/com/android/internal/telephony/SmsDispatchersController.java
+++ b/src/java/com/android/internal/telephony/SmsDispatchersController.java
@@ -16,8 +16,6 @@
package com.android.internal.telephony;
-import static com.android.internal.telephony.IccSmsInterfaceManager.SMS_MESSAGE_PERIOD_NOT_SPECIFIED;
-import static com.android.internal.telephony.IccSmsInterfaceManager.SMS_MESSAGE_PRIORITY_NOT_SPECIFIED;
import static com.android.internal.telephony.SmsResponse.NO_ERROR_CODE;
import static com.android.internal.telephony.cdma.sms.BearerData.ERROR_NONE;
import static com.android.internal.telephony.cdma.sms.BearerData.ERROR_TEMPORARY;
@@ -788,9 +786,8 @@
long messageId) {
if (mImsSmsDispatcher.isAvailable() || mImsSmsDispatcher.isEmergencySmsSupport(destAddr)) {
mImsSmsDispatcher.sendText(destAddr, scAddr, text, sentIntent, deliveryIntent,
- messageUri, callingPkg, persistMessage, SMS_MESSAGE_PRIORITY_NOT_SPECIFIED,
- false /*expectMore*/, SMS_MESSAGE_PERIOD_NOT_SPECIFIED, isForVvm,
- messageId);
+ messageUri, callingPkg, persistMessage, priority, false /*expectMore*/,
+ validityPeriod, isForVvm, messageId);
} else {
if (isCdmaMo()) {
mCdmaDispatcher.sendText(destAddr, scAddr, text, sentIntent, deliveryIntent,
@@ -915,10 +912,8 @@
long messageId) {
if (mImsSmsDispatcher.isAvailable()) {
mImsSmsDispatcher.sendMultipartText(destAddr, scAddr, parts, sentIntents,
- deliveryIntents, messageUri, callingPkg, persistMessage,
- SMS_MESSAGE_PRIORITY_NOT_SPECIFIED,
- false /*expectMore*/, SMS_MESSAGE_PERIOD_NOT_SPECIFIED,
- messageId);
+ deliveryIntents, messageUri, callingPkg, persistMessage, priority,
+ false /*expectMore*/, validityPeriod, messageId);
} else {
if (isCdmaMo()) {
mCdmaDispatcher.sendMultipartText(destAddr, scAddr, parts, sentIntents,
diff --git a/src/java/com/android/internal/telephony/SmsResponse.java b/src/java/com/android/internal/telephony/SmsResponse.java
index 2c8afca..851d04b 100644
--- a/src/java/com/android/internal/telephony/SmsResponse.java
+++ b/src/java/com/android/internal/telephony/SmsResponse.java
@@ -59,8 +59,7 @@
String ret = "{ mMessageRef = " + mMessageRef
+ ", mErrorCode = " + mErrorCode
+ ", mAckPdu = " + mAckPdu
- + ", mMessageId = " + mMessageId
- + "}";
+ + ", " + SmsController.formatCrossStackMessageId(mMessageId) + "}";
return ret;
}
}
diff --git a/src/java/com/android/internal/telephony/SmsUsageMonitor.java b/src/java/com/android/internal/telephony/SmsUsageMonitor.java
index 7f07d4c..c1d4c3e 100644
--- a/src/java/com/android/internal/telephony/SmsUsageMonitor.java
+++ b/src/java/com/android/internal/telephony/SmsUsageMonitor.java
@@ -16,6 +16,7 @@
package com.android.internal.telephony;
+import android.app.role.RoleManager;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.ContentResolver;
import android.content.Context;
@@ -52,6 +53,7 @@
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
+import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.regex.Pattern;
@@ -126,6 +128,8 @@
/** Last modified time for pattern file */
private long mPatternFileLastModified = 0;
+ private RoleManager mRoleManager;
+
/** Directory for per-app SMS permission XML file. */
private static final String SMS_POLICY_FILE_DIRECTORY = "/data/misc/sms";
@@ -249,6 +253,7 @@
public SmsUsageMonitor(Context context) {
mContext = context;
ContentResolver resolver = context.getContentResolver();
+ mRoleManager = (RoleManager) mContext.getSystemService(Context.ROLE_SERVICE);
mMaxAllowed = Settings.Global.getInt(resolver,
Settings.Global.SMS_OUTGOING_CHECK_MAX_COUNT,
@@ -346,7 +351,7 @@
/**
* Check to see if an application is allowed to send new SMS messages, and confirm with
* user if the send limit was reached or if a non-system app is potentially sending to a
- * premium SMS short code or number.
+ * premium SMS short code or number. If the app is the default SMS app, there's no send limit.
*
* @param appName the package name of the app requesting to send an SMS
* @param smsWaiting the number of new messages desired to send
@@ -364,7 +369,12 @@
mSmsStamp.put(appName, sentList);
}
- return isUnderLimit(sentList, smsWaiting);
+ List<String> defaultApp = mRoleManager.getRoleHolders(RoleManager.ROLE_SMS);
+ if (defaultApp.contains(appName)) {
+ return true;
+ } else {
+ return isUnderLimit(sentList, smsWaiting);
+ }
}
}
diff --git a/src/java/com/android/internal/telephony/SubscriptionController.java b/src/java/com/android/internal/telephony/SubscriptionController.java
index 7f4cfff..1044169 100644
--- a/src/java/com/android/internal/telephony/SubscriptionController.java
+++ b/src/java/com/android/internal/telephony/SubscriptionController.java
@@ -31,6 +31,7 @@
import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
+import android.database.ContentObserver;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
@@ -63,6 +64,7 @@
import android.util.LocalLog;
import android.util.Log;
+import com.android.ims.ImsManager;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.telephony.IccCardConstants.State;
import com.android.internal.telephony.dataconnection.DataEnabledOverride;
@@ -359,6 +361,29 @@
invalidateActiveDataSubIdCaches();
invalidateSlotIndexCaches();
+ mContext.getContentResolver().registerContentObserver(
+ SubscriptionManager.SIM_INFO_SUW_RESTORE_CONTENT_URI, false,
+ new ContentObserver(new Handler()) {
+ @Override
+ public void onChange(boolean selfChange, Uri uri) {
+ if (uri.equals(SubscriptionManager.SIM_INFO_SUW_RESTORE_CONTENT_URI)) {
+ refreshCachedActiveSubscriptionInfoList();
+ notifySubscriptionInfoChanged();
+
+ SubscriptionManager subManager = SubscriptionManager.from(mContext);
+ for (SubscriptionInfo subInfo : getActiveSubscriptionInfoList(
+ mContext.getOpPackageName(), mContext.getAttributionTag())) {
+ if (SubscriptionController.getInstance()
+ .isActiveSubId(subInfo.getSubscriptionId())) {
+ ImsManager imsManager = ImsManager.getInstance(mContext,
+ subInfo.getSimSlotIndex());
+ imsManager.updateImsServiceConfig();
+ }
+ }
+ }
+ }
+ });
+
if (DBG) logdl("[SubscriptionController] init by Context");
}
@@ -748,6 +773,7 @@
return subInfo;
}
}
+
// check cache for opportunistic subscriptions too, before querying db
for (SubscriptionInfo subInfo : mCacheOpportunisticSubInfoList) {
if (subInfo.getSubscriptionId() == subId) {
@@ -2074,6 +2100,82 @@
}
}
+ /**
+ * Set device to device status sharing preference
+ * @param sharing the sharing preference to set
+ * @param subId
+ * @return the number of records updated
+ */
+ @Override
+ public int setDeviceToDeviceStatusSharing(int sharing, int subId) {
+ if (DBG) logd("[setDeviceToDeviceStatusSharing]- sharing:" + sharing + " subId:" + subId);
+
+ enforceModifyPhoneState("setDeviceToDeviceStatusSharing");
+
+ // Now that all security checks passes, perform the operation as ourselves.
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ validateSubId(subId);
+ if (sharing < 0) {
+ if (DBG) logd("[setDeviceToDeviceStatusSharing]- fail");
+ return -1;
+ }
+ ContentValues value = new ContentValues(1);
+ value.put(SubscriptionManager.D2D_STATUS_SHARING, sharing);
+ if (DBG) logd("[setDeviceToDeviceStatusSharing]- sharing:" + sharing + " set");
+
+ int result = updateDatabase(value, subId, true);
+
+ // Refresh the Cache of Active Subscription Info List
+ refreshCachedActiveSubscriptionInfoList();
+
+ notifySubscriptionInfoChanged();
+
+ return result;
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
+
+ /**
+ * Set contacts that allow device to device status sharing.
+ * @param contacts contacts to set
+ * @param subscriptionId
+ * @return the number of records updated
+ */
+ @Override
+ public int setDeviceToDeviceStatusSharingContacts(String contacts, int subscriptionId) {
+ if (DBG) {
+ logd("[setDeviceToDeviceStatusSharingContacts]- contacts:" + contacts
+ + " subId:" + subscriptionId);
+ }
+
+ enforceModifyPhoneState("setDeviceToDeviceStatusSharingContacts");
+
+ // Now that all security checks passes, perform the operation as ourselves.
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ validateSubId(subscriptionId);
+ ContentValues value = new ContentValues(1);
+ value.put(SubscriptionManager.D2D_STATUS_SHARING_SELECTED_CONTACTS, contacts);
+ if (DBG) {
+ logd("[setDeviceToDeviceStatusSharingContacts]- contacts:" + contacts
+ + " set");
+ }
+
+ int result = updateDatabase(value, subscriptionId, true);
+
+ // Refresh the Cache of Active Subscription Info List
+ refreshCachedActiveSubscriptionInfoList();
+
+ notifySubscriptionInfoChanged();
+
+ return result;
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
+
public void syncGroupedSetting(int refSubId) {
logd("syncGroupedSetting");
try (Cursor cursor = mContext.getContentResolver().query(
@@ -3012,6 +3114,7 @@
case SubscriptionManager.WFC_IMS_ROAMING_ENABLED:
case SubscriptionManager.IMS_RCS_UCE_ENABLED:
case SubscriptionManager.CROSS_SIM_CALLING_ENABLED:
+ case SubscriptionManager.VOIMS_OPT_IN_STATUS:
value.put(propKey, Integer.parseInt(propValue));
break;
case SubscriptionManager.ALLOWED_NETWORK_TYPES:
@@ -3089,6 +3192,9 @@
case SubscriptionManager.GROUP_UUID:
case SubscriptionManager.DATA_ENABLED_OVERRIDE_RULES:
case SubscriptionManager.ALLOWED_NETWORK_TYPES:
+ case SubscriptionManager.VOIMS_OPT_IN_STATUS:
+ case SubscriptionManager.D2D_STATUS_SHARING:
+ case SubscriptionManager.D2D_STATUS_SHARING_SELECTED_CONTACTS:
resultValue = cursor.getString(0);
break;
default:
diff --git a/src/java/com/android/internal/telephony/SubscriptionInfoUpdater.java b/src/java/com/android/internal/telephony/SubscriptionInfoUpdater.java
index a76f0f6..9132e5e 100644
--- a/src/java/com/android/internal/telephony/SubscriptionInfoUpdater.java
+++ b/src/java/com/android/internal/telephony/SubscriptionInfoUpdater.java
@@ -457,8 +457,10 @@
// At this phase, the subscription list is accessible. Treating NOT_READY
// as equivalent to ABSENT, once the rest of the system can handle it.
sIccId[phoneId] = ICCID_STRING_FOR_NO_SIM;
- updateSubscriptionInfoByIccId(phoneId, false /* updateEmbeddedSubs */);
+ } else {
+ sIccId[phoneId] = null;
}
+ updateSubscriptionInfoByIccId(phoneId, false /* updateEmbeddedSubs */);
broadcastSimStateChanged(phoneId, IccCardConstants.INTENT_VALUE_ICC_NOT_READY,
null);
@@ -579,15 +581,26 @@
* 2. ACTION_SIM_STATE_CHANGED/ACTION_SIM_CARD_STATE_CHANGED
* /ACTION_SIM_APPLICATION_STATE_CHANGED
* 3. ACTION_SUBSCRIPTION_CARRIER_IDENTITY_CHANGED
- * 4. ACTION_CARRIER_CONFIG_CHANGED
+ * 4. restore sim-specific settings
+ * 5. ACTION_CARRIER_CONFIG_CHANGED
*/
broadcastSimStateChanged(phoneId, IccCardConstants.INTENT_VALUE_ICC_LOADED, null);
broadcastSimCardStateChanged(phoneId, TelephonyManager.SIM_STATE_PRESENT);
broadcastSimApplicationStateChanged(phoneId, TelephonyManager.SIM_STATE_LOADED);
updateSubscriptionCarrierId(phoneId, IccCardConstants.INTENT_VALUE_ICC_LOADED);
+ /* Sim-specific settings restore depends on knowing both the mccmnc and the carrierId of the
+ sim which is why it must be done after #updateSubscriptionCarrierId(). It is done before
+ carrier config update to avoid any race conditions with user settings that depend on
+ carrier config*/
+ restoreSimSpecificSettingsForPhone(phoneId);
updateCarrierServices(phoneId, IccCardConstants.INTENT_VALUE_ICC_LOADED);
}
+ private void restoreSimSpecificSettingsForPhone(int phoneId) {
+ SubscriptionManager subManager = SubscriptionManager.from(sContext);
+ subManager.restoreSimSpecificSettingsForIccIdFromBackup(sIccId[phoneId]);
+ }
+
private void updateCarrierServices(int phoneId, String simState) {
CarrierConfigManager configManager =
(CarrierConfigManager) sContext.getSystemService(Context.CARRIER_CONFIG_SERVICE);
@@ -707,7 +720,7 @@
mSubscriptionController.clearSubInfoRecord(phoneId);
// If SIM is not absent, insert new record or update existing record.
- if (!ICCID_STRING_FOR_NO_SIM.equals(sIccId[phoneId])) {
+ if (!ICCID_STRING_FOR_NO_SIM.equals(sIccId[phoneId]) && sIccId[phoneId] != null) {
logd("updateSubscriptionInfoByIccId: adding subscription info record: iccid: "
+ sIccId[phoneId] + ", phoneId:" + phoneId);
mSubscriptionManager.addSubscriptionInfoRecord(sIccId[phoneId], phoneId);
@@ -1117,12 +1130,10 @@
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
protected void broadcastSimStateChanged(int phoneId, String state, String reason) {
+ // Note: This intent is way deprecated and is only being kept around because there's no
+ // graceful way to deprecate a sticky broadcast that has a lot of listeners.
+ // DO NOT add any new extras to this broadcast -- it is not protected by any permissions.
Intent i = new Intent(TelephonyIntents.ACTION_SIM_STATE_CHANGED);
- // TODO - we'd like this intent to have a single snapshot of all sim state,
- // but until then this should not use REPLACE_PENDING or we may lose
- // information
- // i.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING
- // | Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
i.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
i.putExtra(PhoneConstants.PHONE_NAME_KEY, "Phone");
i.putExtra(IccCardConstants.INTENT_KEY_ICC_STATE, state);
diff --git a/src/java/com/android/internal/telephony/TelephonyComponentFactory.java b/src/java/com/android/internal/telephony/TelephonyComponentFactory.java
index 39a36af..4632a60 100644
--- a/src/java/com/android/internal/telephony/TelephonyComponentFactory.java
+++ b/src/java/com/android/internal/telephony/TelephonyComponentFactory.java
@@ -35,6 +35,7 @@
import com.android.internal.telephony.cdma.EriManager;
import com.android.internal.telephony.dataconnection.DataEnabledSettings;
import com.android.internal.telephony.dataconnection.DcTracker;
+import com.android.internal.telephony.dataconnection.LinkBandwidthEstimator;
import com.android.internal.telephony.dataconnection.TransportManager;
import com.android.internal.telephony.emergency.EmergencyNumberTracker;
import com.android.internal.telephony.imsphone.ImsExternalCallTracker;
@@ -69,6 +70,7 @@
private static final String TAG = TelephonyComponentFactory.class.getSimpleName();
private static TelephonyComponentFactory sInstance;
+ private final TelephonyFacade mTelephonyFacade = new TelephonyFacade();
private InjectedComponents mInjectedComponents;
@@ -447,4 +449,11 @@
SubscriptionController sc) {
return new SubscriptionInfoUpdater(looper, context, sc);
}
+
+ /**
+ * Create a new LinkBandwidthEstimator.
+ */
+ public LinkBandwidthEstimator makeLinkBandwidthEstimator(Phone phone) {
+ return new LinkBandwidthEstimator(phone, mTelephonyFacade);
+ }
}
diff --git a/src/java/com/android/internal/telephony/TelephonyFacade.java b/src/java/com/android/internal/telephony/TelephonyFacade.java
new file mode 100644
index 0000000..31a2242
--- /dev/null
+++ b/src/java/com/android/internal/telephony/TelephonyFacade.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.telephony;
+
+import android.net.TrafficStats;
+import android.os.SystemClock;
+
+/**
+ * This class is a wrapper of various static methods to simplify unit tests with static methods
+ */
+public class TelephonyFacade {
+ /**
+ * Returns milliseconds since boot, including time spent in sleep.
+ *
+ * @return Current time since boot in milliseconds.
+ */
+ public long getElapsedSinceBootMillis() {
+ return SystemClock.elapsedRealtime();
+ }
+
+ /**
+ * Wrapper for {@link TrafficStats#getMobileTxBytes}.
+ */
+ public long getMobileTxBytes() {
+ return TrafficStats.getMobileTxBytes();
+ }
+
+ /**
+ * Wrapper for {@link TrafficStats#getMobileRxBytes}.
+ */
+ public long getMobileRxBytes() {
+ return TrafficStats.getMobileRxBytes();
+ }
+}
diff --git a/src/java/com/android/internal/telephony/WapPushOverSms.java b/src/java/com/android/internal/telephony/WapPushOverSms.java
index 11e4709..d502aad 100755
--- a/src/java/com/android/internal/telephony/WapPushOverSms.java
+++ b/src/java/com/android/internal/telephony/WapPushOverSms.java
@@ -16,6 +16,9 @@
package com.android.internal.telephony;
+import static android.os.PowerWhitelistManager.REASON_EVENT_MMS;
+import static android.os.PowerWhitelistManager.TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_ALLOWED;
+
import static com.google.android.mms.pdu.PduHeaders.MESSAGE_TYPE_NOTIFICATION_IND;
import android.annotation.NonNull;
@@ -369,7 +372,8 @@
} else {
synchronized (this) {
mPowerWhitelistManager.whitelistAppTemporarilyForEvent(
- mWapPushManagerPackage, PowerWhitelistManager.EVENT_MMS, "mms-mgr");
+ mWapPushManagerPackage, PowerWhitelistManager.EVENT_MMS,
+ REASON_EVENT_MMS, "mms-mgr");
}
Intent intent = new Intent();
@@ -429,9 +433,13 @@
if (DBG) Rlog.v(TAG, "Delivering MMS to: " + componentName.getPackageName() +
" " + componentName.getClassName());
long duration = mPowerWhitelistManager.whitelistAppTemporarilyForEvent(
- componentName.getPackageName(), PowerWhitelistManager.EVENT_MMS, "mms-app");
+ componentName.getPackageName(), PowerWhitelistManager.EVENT_MMS,
+ REASON_EVENT_MMS, "mms-app");
BroadcastOptions bopts = BroadcastOptions.makeBasic();
- bopts.setTemporaryAppWhitelistDuration(duration);
+ bopts.setTemporaryAppAllowlist(duration,
+ TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_ALLOWED,
+ REASON_EVENT_MMS,
+ "");
options = bopts.toBundle();
}
diff --git a/src/java/com/android/internal/telephony/cdma/CdmaSMSDispatcher.java b/src/java/com/android/internal/telephony/cdma/CdmaSMSDispatcher.java
index feec32a..1742db7 100644
--- a/src/java/com/android/internal/telephony/cdma/CdmaSMSDispatcher.java
+++ b/src/java/com/android/internal/telephony/cdma/CdmaSMSDispatcher.java
@@ -30,6 +30,7 @@
import com.android.internal.telephony.PhoneConstants;
import com.android.internal.telephony.SMSDispatcher;
import com.android.internal.telephony.SmsConstants;
+import com.android.internal.telephony.SmsController;
import com.android.internal.telephony.SmsDispatchersController;
import com.android.internal.telephony.SmsHeader;
import com.android.internal.telephony.SmsMessageBase;
@@ -109,7 +110,7 @@
+ " mMessageRef=" + tracker.mMessageRef
+ " mUsesImsServiceForIms=" + tracker.mUsesImsServiceForIms
+ " SS=" + ss
- + " id=" + tracker.mMessageId);
+ + " " + SmsController.formatCrossStackMessageId(tracker.mMessageId));
// if sms over IMS is not supported on data and voice is not available...
if (!isIms() && ss != ServiceState.STATE_IN_SERVICE) {
diff --git a/src/java/com/android/internal/telephony/cdnr/CarrierDisplayNameResolver.java b/src/java/com/android/internal/telephony/cdnr/CarrierDisplayNameResolver.java
index 3cdfffa..b7e009b 100644
--- a/src/java/com/android/internal/telephony/cdnr/CarrierDisplayNameResolver.java
+++ b/src/java/com/android/internal/telephony/cdnr/CarrierDisplayNameResolver.java
@@ -34,10 +34,13 @@
import android.os.PersistableBundle;
import android.telephony.CarrierConfigManager;
import android.telephony.ServiceState;
+import android.telephony.SubscriptionManager;
+import android.telephony.ims.stub.ImsRegistrationImplBase;
import android.text.TextUtils;
import android.util.LocalLog;
import android.util.SparseArray;
+import com.android.internal.R;
import com.android.internal.telephony.GsmCdmaPhone;
import com.android.internal.telephony.Phone;
import com.android.internal.telephony.cdnr.EfData.EFSource;
@@ -377,6 +380,48 @@
return result;
}
+ private CarrierDisplayNameData getCarrierDisplayNameFromCrossSimCallingOverride(
+ CarrierDisplayNameData rawCarrierDisplayNameData) {
+ PersistableBundle config = getCarrierConfig();
+ int crossSimSpnFormatIdx =
+ config.getInt(CarrierConfigManager.KEY_CROSS_SIM_SPN_FORMAT_INT);
+ boolean useRootLocale =
+ config.getBoolean(CarrierConfigManager.KEY_WFC_SPN_USE_ROOT_LOCALE);
+
+ String[] crossSimSpnFormats = SubscriptionManager.getResourcesForSubId(
+ mPhone.getContext(),
+ mPhone.getSubId(), useRootLocale)
+ .getStringArray(R.array.crossSimSpnFormats);
+
+ if (crossSimSpnFormatIdx < 0 || crossSimSpnFormatIdx >= crossSimSpnFormats.length) {
+ Rlog.e(TAG, "updateSpnDisplay: KEY_CROSS_SIM_SPN_FORMAT_INT out of bounds: "
+ + crossSimSpnFormatIdx);
+ crossSimSpnFormatIdx = 0;
+ }
+ String crossSimSpnFormat = crossSimSpnFormats[crossSimSpnFormatIdx];
+ // Override the spn, data spn, plmn by Cross-SIM Calling
+ List<PlmnNetworkName> efPnn = getEfPnn();
+ String plmn = efPnn.isEmpty() ? "" : getPlmnNetworkName(efPnn.get(0));
+ CarrierDisplayNameData result = rawCarrierDisplayNameData;
+ String rawSpn = rawCarrierDisplayNameData.getSpn();
+ String rawPlmn = TextUtils.isEmpty(plmn) ? rawCarrierDisplayNameData.getPlmn() : plmn;
+ String crossSimSpn = String.format(crossSimSpnFormat, rawSpn);
+ String crossSimPlmn = String.format(crossSimSpnFormat, plmn);
+ if (!TextUtils.isEmpty(rawSpn) && !TextUtils.isEmpty(crossSimSpn)) {
+ result = new CarrierDisplayNameData.Builder()
+ .setSpn(crossSimSpn)
+ .setDataSpn(crossSimSpn)
+ .setShowSpn(true)
+ .build();
+ } else if (!TextUtils.isEmpty(rawPlmn) && !TextUtils.isEmpty(crossSimPlmn)) {
+ result = new CarrierDisplayNameData.Builder()
+ .setPlmn(crossSimPlmn)
+ .setShowPlmn(true)
+ .build();
+ }
+ return result;
+ }
+
/**
* Override the given carrier display name data {@code data} by out of service rule.
* @param data the carrier display name data need to be overridden.
@@ -423,7 +468,13 @@
private void resolveCarrierDisplayName() {
CarrierDisplayNameData data = getCarrierDisplayNameFromEf();
if (DBG) Rlog.d(TAG, "CarrierName from EF: " + data);
- if (getCombinedRegState(getServiceState()) == ServiceState.STATE_IN_SERVICE) {
+ if ((mPhone.getImsPhone() != null) && (mPhone.getImsPhone().getImsRegistrationTech()
+ == ImsRegistrationImplBase.REGISTRATION_TECH_CROSS_SIM)) {
+ data = getCarrierDisplayNameFromCrossSimCallingOverride(data);
+ if (DBG) {
+ Rlog.d(TAG, "CarrierName override by Cross-SIM Calling " + data);
+ }
+ } else if (getCombinedRegState(getServiceState()) == ServiceState.STATE_IN_SERVICE) {
if (mPhone.isWifiCallingEnabled()) {
data = getCarrierDisplayNameFromWifiCallingOverride(data);
if (DBG) {
diff --git a/src/java/com/android/internal/telephony/d2d/Communicator.java b/src/java/com/android/internal/telephony/d2d/Communicator.java
index 8c3c630..c370811 100644
--- a/src/java/com/android/internal/telephony/d2d/Communicator.java
+++ b/src/java/com/android/internal/telephony/d2d/Communicator.java
@@ -24,7 +24,9 @@
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
+import java.util.Optional;
import java.util.Set;
+import java.util.stream.Collectors;
/**
* Responsible for facilitating device-to-device communication between both ends of a call.
@@ -106,6 +108,9 @@
public Communicator(@NonNull List<TransportProtocol> transportProtocols,
@NonNull Callback callback) {
+ Log.i(this, "Initializing communicator with transports: %s",
+ transportProtocols.stream().map(p -> p.getClass().getSimpleName()).collect(
+ Collectors.joining(",")));
mTransportProtocols.addAll(transportProtocols);
mTransportProtocols.forEach(p -> p.setCallback(this));
mCallback = callback;
@@ -121,10 +126,11 @@
/**
* Handles state changes for a call.
- * @param c The call in question.
+ * @param id The call in question.
* @param state The new state.
*/
- public void onStateChanged(Connection c, @Connection.ConnectionState int state) {
+ public void onStateChanged(String id, @Connection.ConnectionState int state) {
+ Log.i(this, "onStateChanged: id=%s, newState=%d", id, state);
if (state == Connection.STATE_ACTIVE) {
// Protocol negotiation can start as we are active
if (mActiveTransport == null && !mIsNegotiationAttempted) {
@@ -291,4 +297,33 @@
}
return "";
}
+
+ /**
+ * Test method used to force a transport type to be the active transport.
+ * @param transport The transport to activate.
+ */
+ public void setTransportActive(@NonNull String transport) {
+ Optional<TransportProtocol> tp = mTransportProtocols.stream()
+ .filter(t -> t.getClass().getSimpleName().equals(transport))
+ .findFirst();
+ if (!tp.isPresent()) {
+ Log.w(this, "setTransportActive: %s is not a valid transport.");
+ return;
+ }
+
+ mTransportProtocols.stream()
+ .filter(p -> p != tp.get())
+ .forEach(t -> t.forceNotNegotiated());
+ tp.get().forceNegotiated();
+ mActiveTransport = tp.get();
+ mIsNegotiated = true;
+ Log.i(this, "setTransportActive: %s has been forced active.", transport);
+ }
+
+ /**
+ * @return the list of {@link TransportProtocol} which are configured at the current time.
+ */
+ public @NonNull List<TransportProtocol> getTransportProtocols() {
+ return mTransportProtocols;
+ }
}
diff --git a/src/java/com/android/internal/telephony/d2d/DtmfTransport.java b/src/java/com/android/internal/telephony/d2d/DtmfTransport.java
index 5ec9e50..de26037 100644
--- a/src/java/com/android/internal/telephony/d2d/DtmfTransport.java
+++ b/src/java/com/android/internal/telephony/d2d/DtmfTransport.java
@@ -611,4 +611,14 @@
}
}
}
+
+ @Override
+ public void forceNegotiated() {
+
+ }
+
+ @Override
+ public void forceNotNegotiated() {
+
+ }
}
diff --git a/src/java/com/android/internal/telephony/d2d/MessageTypeAndValueHelper.java b/src/java/com/android/internal/telephony/d2d/MessageTypeAndValueHelper.java
new file mode 100644
index 0000000..2d36051
--- /dev/null
+++ b/src/java/com/android/internal/telephony/d2d/MessageTypeAndValueHelper.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.telephony.d2d;
+
+import android.telecom.Connection;
+import android.telecom.DiagnosticCall;
+import android.telephony.TelephonyManager;
+
+import com.android.internal.telephony.BiMap;
+
+/**
+ * Helper class to map between the message types and values used in {@link Communicator} and those
+ * defined in the public API in {@link DiagnosticCall}.
+ */
+public class MessageTypeAndValueHelper {
+ // Maps between the local message and value types defined here and those defined in the
+ // DiagnosticCall class as part of the actual API.
+
+ /**
+ * Convert between the local message type (e.g.
+ * {@link Communicator#MESSAGE_CALL_RADIO_ACCESS_TYPE})
+ * and
+ * the ones referred to in {@link DiagnosticCall}.
+ */
+ public static final BiMap<Integer, Integer> MSG_TYPE_TO_DC_MSG_TYPE = new BiMap<>();
+
+ /**
+ * Convert between the local RAT type (e.g. {@link Communicator#RADIO_ACCESS_TYPE_IWLAN}) and
+ * the ones
+ * referred to by {@link DiagnosticCall#MESSAGE_CALL_NETWORK_TYPE}.
+ */
+ public static final BiMap<Integer, Integer> RAT_TYPE_TO_DC_NETWORK_TYPE = new BiMap<>();
+
+ /**
+ * Convert between the local codec (e.g. {@link Communicator#AUDIO_CODEC_AMR_WB}) and the ones
+ * referred to by {@link DiagnosticCall#MESSAGE_CALL_AUDIO_CODEC}.
+ */
+ public static final BiMap<Integer, Integer> CODEC_TO_DC_CODEC = new BiMap<>();
+
+ /**
+ * Convert between the local battery state (e.g. {@link Communicator#BATTERY_STATE_GOOD}) and
+ * the ones referred to by {@link DiagnosticCall#MESSAGE_DEVICE_BATTERY_STATE}.
+ */
+ public static final BiMap<Integer, Integer> BATTERY_STATE_TO_DC_BATTERY_STATE = new BiMap();
+
+ /**
+ * Convert between the local battery state (e.g. {@link Communicator#COVERAGE_GOOD}) and the
+ * ones referred to by {@link DiagnosticCall#MESSAGE_DEVICE_NETWORK_COVERAGE}.
+ */
+ public static final BiMap<Integer, Integer> COVERAGE_TO_DC_COVERAGE = new BiMap();
+
+ static {
+ MSG_TYPE_TO_DC_MSG_TYPE.put(Communicator.MESSAGE_CALL_RADIO_ACCESS_TYPE,
+ DiagnosticCall.MESSAGE_CALL_NETWORK_TYPE);
+ MSG_TYPE_TO_DC_MSG_TYPE.put(Communicator.MESSAGE_CALL_AUDIO_CODEC,
+ DiagnosticCall.MESSAGE_CALL_AUDIO_CODEC);
+ MSG_TYPE_TO_DC_MSG_TYPE.put(Communicator.MESSAGE_DEVICE_BATTERY_STATE,
+ DiagnosticCall.MESSAGE_DEVICE_BATTERY_STATE);
+ MSG_TYPE_TO_DC_MSG_TYPE.put(Communicator.MESSAGE_DEVICE_NETWORK_COVERAGE,
+ DiagnosticCall.MESSAGE_DEVICE_NETWORK_COVERAGE);
+
+ RAT_TYPE_TO_DC_NETWORK_TYPE.put(Communicator.RADIO_ACCESS_TYPE_LTE,
+ TelephonyManager.NETWORK_TYPE_LTE);
+ RAT_TYPE_TO_DC_NETWORK_TYPE.put(Communicator.RADIO_ACCESS_TYPE_IWLAN,
+ TelephonyManager.NETWORK_TYPE_IWLAN);
+ RAT_TYPE_TO_DC_NETWORK_TYPE.put(Communicator.RADIO_ACCESS_TYPE_NR,
+ TelephonyManager.NETWORK_TYPE_NR);
+
+ CODEC_TO_DC_CODEC.put(Communicator.AUDIO_CODEC_EVS, Connection.AUDIO_CODEC_EVS_WB);
+ CODEC_TO_DC_CODEC.put(Communicator.AUDIO_CODEC_AMR_WB, Connection.AUDIO_CODEC_AMR_WB);
+ CODEC_TO_DC_CODEC.put(Communicator.AUDIO_CODEC_AMR_NB, Connection.AUDIO_CODEC_AMR);
+
+ BATTERY_STATE_TO_DC_BATTERY_STATE.put(Communicator.BATTERY_STATE_LOW,
+ DiagnosticCall.BATTERY_STATE_LOW);
+ BATTERY_STATE_TO_DC_BATTERY_STATE.put(Communicator.BATTERY_STATE_GOOD,
+ DiagnosticCall.BATTERY_STATE_GOOD);
+ BATTERY_STATE_TO_DC_BATTERY_STATE.put(Communicator.BATTERY_STATE_CHARGING,
+ DiagnosticCall.BATTERY_STATE_CHARGING);
+
+ COVERAGE_TO_DC_COVERAGE.put(Communicator.COVERAGE_POOR, DiagnosticCall.COVERAGE_POOR);
+ COVERAGE_TO_DC_COVERAGE.put(Communicator.COVERAGE_GOOD, DiagnosticCall.COVERAGE_GOOD);
+ }
+}
diff --git a/src/java/com/android/internal/telephony/d2d/RtpTransport.java b/src/java/com/android/internal/telephony/d2d/RtpTransport.java
index eb86aba..595a94c 100644
--- a/src/java/com/android/internal/telephony/d2d/RtpTransport.java
+++ b/src/java/com/android/internal/telephony/d2d/RtpTransport.java
@@ -20,6 +20,7 @@
import android.net.Uri;
import android.os.Handler;
import android.telecom.Log;
+import android.telephony.ims.ImsCallProfile;
import android.telephony.ims.RtpHeaderExtension;
import android.telephony.ims.RtpHeaderExtensionType;
import android.util.ArraySet;
@@ -283,6 +284,15 @@
private final Handler mHandler;
/**
+ * {@code true} if the carrier supports negotiating the RTP header extensions using SDP.
+ * If {@code true}, we can expected the
+ * {@link ImsCallProfile#getAcceptedRtpHeaderExtensionTypes()} to contain the SDP negotiated RTP
+ * header extensions. If {@code false} we will assume the protocol is negotiated only after
+ * receiving an RTP header extension of the expected type.
+ */
+ private final boolean mIsSdpNegotiationSupported;
+
+ /**
* Protocol status.
*/
private int mProtocolStatus = PROTOCOL_STATUS_NEGOTIATION_REQUIRED;
@@ -297,11 +307,14 @@
* @param rtpAdapter Adapter for abstract send/receive of RTP header extension data.
* @param timeoutsAdapter Timeouts adapter for dealing with time based configurations.
* @param handler Handler for posting future events.
+ * @param isSdpNegotiationSupported Indicates whether SDP negotiation
*/
- public RtpTransport(RtpAdapter rtpAdapter, Timeouts.Adapter timeoutsAdapter, Handler handler) {
+ public RtpTransport(RtpAdapter rtpAdapter, Timeouts.Adapter timeoutsAdapter, Handler handler,
+ boolean isSdpNegotiationSupported) {
mRtpAdapter = rtpAdapter;
mTimeoutsAdapter = timeoutsAdapter;
mHandler = handler;
+ mIsSdpNegotiationSupported = isSdpNegotiationSupported;
}
/**
@@ -329,23 +342,36 @@
mRtpAdapter.getAcceptedRtpHeaderExtensions();
mSupportedRtpHeaderExtensionTypes.addAll(acceptedExtensions);
- boolean areExtensionsAvailable = acceptedExtensions.stream().anyMatch(
- e -> e.getUri().equals(DEVICE_STATE_RTP_HEADER_EXTENSION))
- && acceptedExtensions.stream().anyMatch(
+ Log.i(this, "startNegotiation: supportedExtensions=%s", mSupportedRtpHeaderExtensionTypes
+ .stream()
+ .map(e -> e.toString())
+ .collect(Collectors.joining(",")));
+
+ if (mIsSdpNegotiationSupported) {
+ boolean areExtensionsAvailable = acceptedExtensions.stream().anyMatch(
+ e -> e.getUri().equals(DEVICE_STATE_RTP_HEADER_EXTENSION))
+ && acceptedExtensions.stream().anyMatch(
e -> e.getUri().equals(CALL_STATE_RTP_HEADER_EXTENSION));
- if (areExtensionsAvailable) {
- // Headers were negotiated during SDP, so we can assume negotiation is complete and
- // signal to the communicator that we can use this transport.
- mProtocolStatus = PROTOCOL_STATUS_NEGOTIATION_COMPLETE;
- Log.i(this, "startNegotiation: header extensions available, negotiation success");
- notifyProtocolReady();
+ if (areExtensionsAvailable) {
+ // Headers were negotiated during SDP, so we can assume negotiation is complete and
+ // signal to the communicator that we can use this transport.
+ mProtocolStatus = PROTOCOL_STATUS_NEGOTIATION_COMPLETE;
+ Log.i(this, "startNegotiation: header extensions available, negotiation success");
+ notifyProtocolReady();
+ } else {
+ // Headers failed to be negotiated during SDP. Assume protocol is not available.
+ // TODO: Implement fallback logic where we still try an SDP probe/response.
+ mProtocolStatus = PROTOCOL_STATUS_NEGOTIATION_FAILED;
+ Log.i(this,
+ "startNegotiation: header extensions not available; negotiation failed");
+ notifyProtocolUnavailable();
+ }
} else {
- // Headers failed to be negotiated during SDP. Assume protocol is not available.
- // TODO: Implement fallback logic where we still try an SDP probe/response.
- mProtocolStatus = PROTOCOL_STATUS_NEGOTIATION_FAILED;
- Log.i(this, "startNegotiation: header extensions not available; negotiation failed");
- notifyProtocolUnavailable();
+ Log.i(this, "startNegotiation: SDP negotiation not supported; negotiation complete");
+ // TODO: This is temporary; we will need to implement a probe/response in this scenario
+ // if SDP is not supported. For now we will just assume the protocol is ready.
+ notifyProtocolReady();
}
}
@@ -358,10 +384,33 @@
public void sendMessages(Set<Communicator.Message> messages) {
Set<RtpHeaderExtension> toSend = messages.stream().map(m -> generateRtpHeaderExtension(m))
.collect(Collectors.toSet());
+ Log.i(this, "sendMessages: sending=%s", messages);
mRtpAdapter.sendRtpHeaderExtensions(toSend);
}
/**
+ * Forces the protocol status to negotiated; for test purposes.
+ */
+ @Override
+ public void forceNegotiated() {
+ // If there is no supported RTP header extensions we need to fake it.
+ if (mSupportedRtpHeaderExtensionTypes == null
+ || mSupportedRtpHeaderExtensionTypes.isEmpty()) {
+ mSupportedRtpHeaderExtensionTypes.add(DEVICE_STATE_RTP_HEADER_EXTENSION_TYPE);
+ mSupportedRtpHeaderExtensionTypes.add(CALL_STATE_RTP_HEADER_EXTENSION_TYPE);
+ }
+ mProtocolStatus = PROTOCOL_STATUS_NEGOTIATION_COMPLETE;
+ }
+
+ /**
+ * Forces the protocol status to un-negotiated; for test purposes.
+ */
+ @Override
+ public void forceNotNegotiated() {
+ mProtocolStatus = PROTOCOL_STATUS_NEGOTIATION_REQUIRED;
+ }
+
+ /**
* Called by the platform when RTP header extensions are received and need to be translated to
* concrete messages.
* Results in a callback via
diff --git a/src/java/com/android/internal/telephony/d2d/Timeouts.java b/src/java/com/android/internal/telephony/d2d/Timeouts.java
index 28ef0ec..e01c920 100644
--- a/src/java/com/android/internal/telephony/d2d/Timeouts.java
+++ b/src/java/com/android/internal/telephony/d2d/Timeouts.java
@@ -107,7 +107,7 @@
* @return
*/
public static long getDtmfNegotiationTimeoutMillis(ContentResolver cr) {
- return get(cr, "dtmf_negotiation_timeout_millis", 1000L);
+ return get(cr, "dtmf_negotiation_timeout_millis", 3000L);
}
/**
diff --git a/src/java/com/android/internal/telephony/d2d/TransportProtocol.java b/src/java/com/android/internal/telephony/d2d/TransportProtocol.java
index 4943788..91bf7d3 100644
--- a/src/java/com/android/internal/telephony/d2d/TransportProtocol.java
+++ b/src/java/com/android/internal/telephony/d2d/TransportProtocol.java
@@ -70,4 +70,14 @@
* @param messages the messages to send via the transport.
*/
void sendMessages(Set<Communicator.Message> messages);
+
+ /**
+ * Forces this transport to be in a negotiated state.
+ */
+ void forceNegotiated();
+
+ /**
+ * Forces this transport to be in a non-negotiated state.
+ */
+ void forceNotNegotiated();
}
diff --git a/src/java/com/android/internal/telephony/dataconnection/CellularDataService.java b/src/java/com/android/internal/telephony/dataconnection/CellularDataService.java
index 9b1db18..b38e2be 100644
--- a/src/java/com/android/internal/telephony/dataconnection/CellularDataService.java
+++ b/src/java/com/android/internal/telephony/dataconnection/CellularDataService.java
@@ -29,7 +29,7 @@
import android.telephony.data.DataProfile;
import android.telephony.data.DataService;
import android.telephony.data.DataServiceCallback;
-import android.telephony.data.SliceInfo;
+import android.telephony.data.NetworkSliceInfo;
import android.telephony.data.TrafficDescriptor;
import com.android.internal.telephony.CommandException;
@@ -160,7 +160,7 @@
@Override
public void setupDataCall(int accessNetworkType, DataProfile dataProfile,
boolean isRoaming, boolean allowRoaming, int reason, LinkProperties linkProperties,
- int pduSessionId, SliceInfo sliceInfo, TrafficDescriptor trafficDescriptor,
+ int pduSessionId, NetworkSliceInfo sliceInfo, TrafficDescriptor trafficDescriptor,
boolean matchAllRuleAllowed, DataServiceCallback callback) {
if (DBG) log("setupDataCall " + getSlotIndex());
diff --git a/src/java/com/android/internal/telephony/dataconnection/DataConnection.java b/src/java/com/android/internal/telephony/dataconnection/DataConnection.java
index aaf71bd..c2ae9ce 100644
--- a/src/java/com/android/internal/telephony/dataconnection/DataConnection.java
+++ b/src/java/com/android/internal/telephony/dataconnection/DataConnection.java
@@ -69,9 +69,9 @@
import android.telephony.data.DataProfile;
import android.telephony.data.DataService;
import android.telephony.data.DataServiceCallback;
+import android.telephony.data.NetworkSliceInfo;
import android.telephony.data.Qos;
import android.telephony.data.QosBearerSession;
-import android.telephony.data.SliceInfo;
import android.telephony.data.TrafficDescriptor;
import android.text.TextUtils;
import android.util.LocalLog;
@@ -99,6 +99,7 @@
import com.android.internal.util.Protocol;
import com.android.internal.util.State;
import com.android.internal.util.StateMachine;
+import com.android.net.module.util.NetworkCapabilitiesUtils;
import com.android.telephony.Rlog;
import java.io.FileDescriptor;
@@ -310,7 +311,7 @@
private int mUplinkBandwidth = 14;
private Qos mDefaultQos = null;
private List<QosBearerSession> mQosBearerSessions = new ArrayList<>();
- private SliceInfo mSliceInfo;
+ private NetworkSliceInfo mSliceInfo;
private List<TrafficDescriptor> mTrafficDescriptors = new ArrayList<>();
/** The corresponding network agent for this data connection. */
@@ -376,7 +377,8 @@
static final int EVENT_START_HANDOVER_ON_TARGET = BASE + 36;
static final int EVENT_ALLOCATE_PDU_SESSION_ID = BASE + 37;
static final int EVENT_RELEASE_PDU_SESSION_ID = BASE + 38;
- private static final int CMD_TO_STRING_COUNT = EVENT_RELEASE_PDU_SESSION_ID - BASE + 1;
+ static final int EVENT_LINK_BANDWIDTH_ESTIMATOR_UPDATE = BASE + 39;
+ private static final int CMD_TO_STRING_COUNT = EVENT_LINK_BANDWIDTH_ESTIMATOR_UPDATE - BASE + 1;
private static String[] sCmdToString = new String[CMD_TO_STRING_COUNT];
static {
@@ -426,6 +428,8 @@
sCmdToString[EVENT_START_HANDOVER_ON_TARGET - BASE] = "EVENT_START_HANDOVER_ON_TARGET";
sCmdToString[EVENT_ALLOCATE_PDU_SESSION_ID - BASE] = "EVENT_ALLOCATE_PDU_SESSION_ID";
sCmdToString[EVENT_RELEASE_PDU_SESSION_ID - BASE] = "EVENT_RELEASE_PDU_SESSION_ID";
+ sCmdToString[EVENT_LINK_BANDWIDTH_ESTIMATOR_UPDATE - BASE] =
+ "EVENT_LINK_BANDWIDTH_ESTIMATOR_UPDATE";
}
// Convert cmd to string or null if unknown
static String cmdToString(int cmd) {
@@ -483,6 +487,11 @@
// Data can only be (temporarily) suspended while data is in active state
if (getCurrentState() != mActiveState) return false;
+ // never set suspend for emergency apn
+ if (mApnSetting != null && mApnSetting.isEmergencyApn()) {
+ return false;
+ }
+
// if we are not in-service change to SUSPENDED
final ServiceStateTracker sst = mPhone.getServiceStateTracker();
if (sst.getCurrentDataConnectionState() != ServiceState.STATE_IN_SERVICE) {
@@ -617,7 +626,7 @@
return mPduSessionId;
}
- public SliceInfo getSliceInfo() {
+ public NetworkSliceInfo getSliceInfo() {
return mSliceInfo;
}
@@ -881,8 +890,8 @@
String dnn = null;
String osAppId = null;
if (cp.mApnContext.getApnTypeBitmask() == ApnSetting.TYPE_ENTERPRISE) {
- // TODO(b/181916712): update osAppId to use NetworkCapability API once it's available
- osAppId = ApnSetting.getApnTypesStringFromBitmask(mApnSetting.getApnTypeBitmask());
+ osAppId = NetworkCapabilities.getCapabilityCarrierName(
+ NetworkCapabilities.NET_CAPABILITY_ENTERPRISE);
} else {
dnn = mApnSetting.getApnName();
}
@@ -948,6 +957,7 @@
return DataFailCause.NONE;
}
+ // setup data call for REQUEST_TYPE_NORMAL
allocatePduSessionId(psi -> {
this.setPduSessionId(psi);
mDataServiceManager.setupDataCall(
@@ -974,7 +984,7 @@
msg.obj = allocateCallback;
mPhone.mCi.allocatePduSessionId(msg);
} else {
- allocateCallback.accept(EVENT_ALLOCATE_PDU_SESSION_ID);
+ allocateCallback.accept(PDU_SESSION_ID_NOT_SET);
}
}
@@ -1369,8 +1379,6 @@
} else {
if (DBG) log("onSetupConnectionCompleted received successful DataCallResponse");
mCid = response.getId();
- updateQosParameters(response);
- updateSliceInfo(response);
if (response.getPduSessionId() != getPduSessionId()) {
if (getDoAllocatePduSessionId()) {
@@ -1573,28 +1581,65 @@
uplinkUpdated = true;
}
}
+
if (!downlinkUpdated || !uplinkUpdated) {
- String ratName = ServiceState.rilRadioTechnologyToString(mRilRat);
- if (mRilRat == ServiceState.RIL_RADIO_TECHNOLOGY_LTE && isNRConnected()) {
- ratName = mPhone.getServiceState().getNrFrequencyRange()
- == ServiceState.FREQUENCY_RANGE_MMWAVE
- ? DctConstants.RAT_NAME_NR_NSA_MMWAVE : DctConstants.RAT_NAME_NR_NSA;
- }
- Pair<Integer, Integer> values = mDct.getLinkBandwidthsFromCarrierConfig(ratName);
- if (values != null) {
- if (!downlinkUpdated) {
- mDownlinkBandwidth = values.first;
- }
- if (!uplinkUpdated) {
- mUplinkBandwidth = values.second;
- }
- }
+ fallBackToCarrierConfigValues(downlinkUpdated, uplinkUpdated);
+ }
+
+ if (mNetworkAgent != null) {
+ mNetworkAgent.sendNetworkCapabilities(getNetworkCapabilities(), DataConnection.this);
+ }
+ }
+
+ private void updateLinkBandwidthsFromBandwidthEstimator(int uplinkBandwidthKbps,
+ int downlinkBandwidthKbps) {
+ if (DBG) {
+ log("updateLinkBandwidthsFromBandwidthEstimator, UL= "
+ + uplinkBandwidthKbps + " DL= " + downlinkBandwidthKbps);
+ }
+ boolean downlinkUpdated = false;
+ boolean uplinkUpdated = false;
+ if (downlinkBandwidthKbps > 0) {
+ mDownlinkBandwidth = downlinkBandwidthKbps;
+ downlinkUpdated = true;
+ }
+ if (uplinkBandwidthKbps > 0) {
+ mUplinkBandwidth = uplinkBandwidthKbps;
+ uplinkUpdated = true;
+ }
+
+ if (!downlinkUpdated || !uplinkUpdated) {
+ fallBackToCarrierConfigValues(downlinkUpdated, uplinkUpdated);
}
if (mNetworkAgent != null) {
mNetworkAgent.sendNetworkCapabilities(getNetworkCapabilities(), DataConnection.this);
}
}
+ private void fallBackToCarrierConfigValues(boolean downlinkUpdated, boolean uplinkUpdated) {
+ String ratName = ServiceState.rilRadioTechnologyToString(mRilRat);
+ if (mRilRat == ServiceState.RIL_RADIO_TECHNOLOGY_LTE && isNRConnected()) {
+ ratName = mPhone.getServiceState().getNrFrequencyRange()
+ == ServiceState.FREQUENCY_RANGE_MMWAVE
+ ? DctConstants.RAT_NAME_NR_NSA_MMWAVE : DctConstants.RAT_NAME_NR_NSA;
+ }
+ Pair<Integer, Integer> values = mDct.getLinkBandwidthsFromCarrierConfig(ratName);
+ if (values != null) {
+ if (!downlinkUpdated) {
+ mDownlinkBandwidth = values.first;
+ }
+ if (!uplinkUpdated) {
+ mUplinkBandwidth = values.second;
+ }
+ }
+ }
+
+ /** Update Tx and Rx link bandwidth estimation values */
+ public void updateLinkBandwidthEstimation(int uplinkBandwidthKbps, int downlinkBandwidthKbps) {
+ sendMessage(DataConnection.EVENT_LINK_BANDWIDTH_ESTIMATOR_UPDATE,
+ new Pair<Integer, Integer>(uplinkBandwidthKbps, downlinkBandwidthKbps));
+ }
+
private boolean isBandwidthSourceKey(String source) {
return source.equals(mPhone.getContext().getResources().getString(
com.android.internal.R.string.config_bandwidthEstimateSource));
@@ -1722,11 +1767,11 @@
* @return True if this data connection supports enterprise use.
*/
private boolean isEnterpriseUse() {
- // TODO(b/181916712): update osAppId to use NetworkCapability API once it's available
boolean enterpriseTrafficDescriptor = mTrafficDescriptors
.stream()
.anyMatch(td -> td.getOsAppId() != null && td.getOsAppId().equals(
- ApnSetting.TYPE_ENTERPRISE_STRING));
+ NetworkCapabilities.getCapabilityCarrierName(
+ NetworkCapabilities.NET_CAPABILITY_ENTERPRISE)));
boolean enterpriseApnContext = mApnContexts.keySet()
.stream()
.anyMatch(ac -> ac.getApnTypeBitmask() == ApnSetting.TYPE_ENTERPRISE);
@@ -1832,8 +1877,7 @@
builder.removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED);
}
- // TODO: Need to remove the use of hidden API deduceRestrictedCapability
- if (builder.build().deduceRestrictedCapability()) {
+ if (NetworkCapabilitiesUtils.inferRestrictedCapability(builder.build())) {
builder.removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED);
}
@@ -3138,6 +3182,15 @@
retVal = HANDLED;
break;
}
+ case EVENT_LINK_BANDWIDTH_ESTIMATOR_UPDATE: {
+ Pair<Integer, Integer> pair = (Pair<Integer, Integer>) msg.obj;
+ if (isBandwidthSourceKey(
+ DctConstants.BANDWIDTH_SOURCE_BANDWIDTH_ESTIMATOR_KEY)) {
+ updateLinkBandwidthsFromBandwidthEstimator(pair.first, pair.second);
+ }
+ retVal = HANDLED;
+ break;
+ }
case EVENT_REEVALUATE_RESTRICTED_STATE: {
// If the network was restricted, and now it does not need to be restricted
// anymore, we should add the NET_CAPABILITY_NOT_RESTRICTED capability.
diff --git a/src/java/com/android/internal/telephony/dataconnection/DataServiceManager.java b/src/java/com/android/internal/telephony/dataconnection/DataServiceManager.java
index 5e37338..91a6d96 100644
--- a/src/java/com/android/internal/telephony/dataconnection/DataServiceManager.java
+++ b/src/java/com/android/internal/telephony/dataconnection/DataServiceManager.java
@@ -39,7 +39,7 @@
import android.os.RegistrantList;
import android.os.RemoteException;
import android.os.UserHandle;
-import android.permission.PermissionManager;
+import android.permission.LegacyPermissionManager;
import android.telephony.AccessNetworkConstants;
import android.telephony.AccessNetworkConstants.TransportType;
import android.telephony.AnomalyReporter;
@@ -51,7 +51,7 @@
import android.telephony.data.DataServiceCallback;
import android.telephony.data.IDataService;
import android.telephony.data.IDataServiceCallback;
-import android.telephony.data.SliceInfo;
+import android.telephony.data.NetworkSliceInfo;
import android.telephony.data.TrafficDescriptor;
import android.text.TextUtils;
@@ -91,7 +91,7 @@
private final CarrierConfigManager mCarrierConfigManager;
private final AppOpsManager mAppOps;
- private final PermissionManager mPermissionManager;
+ private final LegacyPermissionManager mPermissionManager;
private final int mTransportType;
@@ -228,6 +228,8 @@
mIDataService.createDataServiceProvider(mPhone.getPhoneId());
mIDataService.registerForDataCallListChanged(mPhone.getPhoneId(),
new CellularDataServiceCallback("dataCallListChanged"));
+ mIDataService.registerForUnthrottleApn(mPhone.getPhoneId(),
+ new CellularDataServiceCallback("unthrottleApn"));
} catch (RemoteException e) {
mDeathRecipient.binderDied();
loge("Remote exception. " + e);
@@ -355,8 +357,8 @@
// NOTE: Do NOT use AppGlobals to retrieve the permission manager; AppGlobals
// caches the service instance, but we need to explicitly request a new service
// so it can be mocked out for tests
- mPermissionManager =
- (PermissionManager) phone.getContext().getSystemService(Context.PERMISSION_SERVICE);
+ mPermissionManager = (LegacyPermissionManager) phone.getContext().getSystemService(
+ Context.LEGACY_PERMISSION_SERVICE);
mAppOps = (AppOpsManager) phone.getContext().getSystemService(Context.APP_OPS_SERVICE);
IntentFilter intentFilter = new IntentFilter();
@@ -500,7 +502,7 @@
*
* @return package name of the data service package for the the current transportType.
*/
- private String getDataServicePackageName() {
+ public String getDataServicePackageName() {
return getDataServicePackageName(mTransportType);
}
@@ -632,7 +634,7 @@
*/
public void setupDataCall(int accessNetworkType, DataProfile dataProfile, boolean isRoaming,
boolean allowRoaming, int reason, LinkProperties linkProperties, int pduSessionId,
- @Nullable SliceInfo sliceInfo, @Nullable TrafficDescriptor trafficDescriptor,
+ @Nullable NetworkSliceInfo sliceInfo, @Nullable TrafficDescriptor trafficDescriptor,
boolean matchAllRuleAllowed, Message onCompleteMessage) {
if (DBG) log("setupDataCall");
if (!mBound) {
diff --git a/src/java/com/android/internal/telephony/dataconnection/DataThrottler.java b/src/java/com/android/internal/telephony/dataconnection/DataThrottler.java
index ebfe49d..532be97 100644
--- a/src/java/com/android/internal/telephony/dataconnection/DataThrottler.java
+++ b/src/java/com/android/internal/telephony/dataconnection/DataThrottler.java
@@ -127,6 +127,21 @@
return RetryManager.NO_SUGGESTED_RETRY_DELAY;
}
+ /**
+ * Resets retry times for all APNs to {@link RetryManager.NO_SUGGESTED_RETRY_DELAY}.
+ */
+ public void reset() {
+ final List<Integer> apnTypes = new ArrayList<>();
+ for (ThrottleStatus throttleStatus : mThrottleStatus.values()) {
+ apnTypes.add(throttleStatus.getApnType());
+ }
+
+ for (int apnType : apnTypes) {
+ setRetryTime(apnType, RetryManager.NO_SUGGESTED_RETRY_DELAY,
+ DcTracker.REQUEST_TYPE_NORMAL);
+ }
+ }
+
private ThrottleStatus createStatus(@Annotation.ApnType int apnType, long retryElapsedTime,
@DcTracker.RequestNetworkType int newRequestType) {
ThrottleStatus.Builder builder = new ThrottleStatus.Builder();
diff --git a/src/java/com/android/internal/telephony/dataconnection/DcTracker.java b/src/java/com/android/internal/telephony/dataconnection/DcTracker.java
index e40158e..16fdbb2 100644
--- a/src/java/com/android/internal/telephony/dataconnection/DcTracker.java
+++ b/src/java/com/android/internal/telephony/dataconnection/DcTracker.java
@@ -261,6 +261,9 @@
private static final String INTENT_DATA_STALL_ALARM_EXTRA_TRANSPORT_TYPE =
"data_stall_alarm_extra_transport_type";
+ // Unique id for no data notification on setup data permanently failed.
+ private static final int NO_DATA_NOTIFICATION = 1001;
+
/** The higher index has higher priority. */
private static final DctConstants.State[] DATA_CONNECTION_STATE_PRIORITIES = {
DctConstants.State.IDLE,
@@ -819,6 +822,8 @@
DctConstants.EVENT_PS_RESTRICT_DISABLED, null);
mPhone.getServiceStateTracker().registerForDataRegStateOrRatChanged(mTransportType, this,
DctConstants.EVENT_DATA_RAT_CHANGED, null);
+ mPhone.getServiceStateTracker().registerForAirplaneModeChanged(this,
+ DctConstants.EVENT_AIRPLANE_MODE_CHANGED, null);
}
public void unregisterServiceStateTrackerEvents() {
@@ -829,6 +834,7 @@
mPhone.getServiceStateTracker().unregisterForPsRestrictedEnabled(this);
mPhone.getServiceStateTracker().unregisterForPsRestrictedDisabled(this);
mPhone.getServiceStateTracker().unregisterForDataRegStateOrRatChanged(mTransportType, this);
+ mPhone.getServiceStateTracker().unregisterForAirplaneModeChanged(this);
}
private void registerForAllEvents() {
@@ -853,6 +859,7 @@
registerServiceStateTrackerEvents();
mDataServiceManager.registerForServiceBindingChanged(this,
DctConstants.EVENT_DATA_SERVICE_BINDING_CHANGED, null);
+ mDataServiceManager.registerForApnUnthrottled(this, DctConstants.EVENT_APN_UNTHROTTLED);
}
public void dispose() {
@@ -910,6 +917,7 @@
mDataServiceManager.unregisterForServiceBindingChanged(this);
mDataEnabledSettings.unregisterForDataEnabledChanged(this);
mDataEnabledSettings.unregisterForDataEnabledOverrideChanged(this);
+ mDataServiceManager.unregisterForApnUnthrottled(this);
}
/**
@@ -1935,6 +1943,9 @@
}
private int getPreferredApnSetId() {
+ // preferapnset uri returns all APNs for the current carrier which have an apn_set_id
+ // equal to the preferred APN (if no preferred APN, or if the preferred APN has no set id,
+ // the query will return null)
Cursor c = mPhone.getContext().getContentResolver()
.query(Uri.withAppendedPath(Telephony.Carriers.CONTENT_URI,
"preferapnset/subId/" + mPhone.getSubId()),
@@ -2302,9 +2313,13 @@
protected void startReconnect(long delay, ApnContext apnContext,
@RequestNetworkType int requestType) {
+ apnContext.setState(DctConstants.State.RETRYING);
Message msg = obtainMessage(DctConstants.EVENT_DATA_RECONNECT,
mPhone.getSubId(), requestType, apnContext);
cancelReconnect(apnContext);
+
+ // Wait a bit before trying the next APN, so that
+ // we're not tying up the RIL command channel
sendMessageDelayed(msg, delay);
if (DBG) {
@@ -2426,8 +2441,7 @@
}
}
- private void onApnUnthrottled(Message msg) {
- String apn = (String) msg.obj;
+ private void onApnUnthrottled(String apn) {
if (apn != null) {
ApnContext ac = mApnContexts.get(apn);
if (ac != null) {
@@ -2505,6 +2519,19 @@
}
}
+ private void sendRequestNetworkCompleteMessages(@ApnType int apnType,
+ @RequestNetworkType int requestType, boolean success,
+ boolean fallbackOnFailedHandover) {
+ List<Message> messageList = mRequestNetworkCompletionMsgs.get(apnType);
+ if (messageList != null) {
+ for (Message msg : messageList) {
+ sendRequestNetworkCompleteMsg(msg, success, mTransportType, requestType,
+ fallbackOnFailedHandover);
+ }
+ messageList.clear();
+ }
+ }
+
private void sendRequestNetworkCompleteMsg(Message message, boolean success,
@TransportType int transport,
@RequestNetworkType int requestType,
@@ -2905,6 +2932,16 @@
startNetStatPoll();
startDataStallAlarm(DATA_STALL_NOT_SUSPECTED);
+
+ PersistableBundle b = getCarrierConfig();
+ if (apnContext.getApnTypeBitmask() == ApnSetting.TYPE_DEFAULT
+ && b.getBoolean(CarrierConfigManager
+ .KEY_DISPLAY_NO_DATA_NOTIFICATION_ON_PERMANENT_FAILURE_BOOL)) {
+ NotificationManager notificationManager = (NotificationManager)
+ mPhone.getContext().getSystemService(Context.NOTIFICATION_SERVICE);
+ notificationManager.cancel(Integer.toString(mPhone.getSubId()),
+ NO_DATA_NOTIFICATION);
+ }
}
/**
@@ -2923,15 +2960,8 @@
+ DataCallResponse.failureModeToString(handoverFailureMode));
} else if (handoverFailureMode
!= DataCallResponse.HANDOVER_FAILURE_MODE_NO_FALLBACK_RETRY_HANDOVER) {
- int apnType = ApnSetting.getApnTypesBitmaskFromString(apnContext.getApnType());
- List<Message> messageList = mRequestNetworkCompletionMsgs.get(apnType);
- if (messageList != null) {
- for (Message msg : messageList) {
- sendRequestNetworkCompleteMsg(msg, success, mTransportType, requestType,
- fallbackOnFailedHandover);
- }
- messageList.clear();
- }
+ sendRequestNetworkCompleteMessages(apnContext.getApnTypeBitmask(), requestType, success,
+ fallbackOnFailedHandover);
}
if (success) {
@@ -3082,6 +3112,34 @@
log("cause=" + DataFailCause.toString(cause)
+ ", mark apn as permanent failed. apn = " + apn);
apnContext.markApnPermanentFailed(apn);
+
+ PersistableBundle b = getCarrierConfig();
+ if (apnContext.getApnTypeBitmask() == ApnSetting.TYPE_DEFAULT
+ && b.getBoolean(CarrierConfigManager
+ .KEY_DISPLAY_NO_DATA_NOTIFICATION_ON_PERMANENT_FAILURE_BOOL)) {
+ NotificationManager notificationManager = (NotificationManager)
+ mPhone.getContext().getSystemService(Context.NOTIFICATION_SERVICE);
+
+ CharSequence title = mPhone.getContext().getText(
+ com.android.internal.R.string.RestrictedOnDataTitle);
+ CharSequence details = mPhone.getContext().getText(
+ com.android.internal.R.string.RestrictedStateContent);
+
+ Notification notification = new Notification.Builder(mPhone.getContext(),
+ NotificationChannelController.CHANNEL_ID_MOBILE_DATA_STATUS)
+ .setWhen(System.currentTimeMillis())
+ .setAutoCancel(true)
+ .setSmallIcon(com.android.internal.R.drawable.stat_sys_warning)
+ .setTicker(title)
+ .setColor(mPhone.getContext().getResources().getColor(
+ com.android.internal.R.color.system_notification_accent_color))
+ .setContentTitle(title)
+ .setStyle(new Notification.BigTextStyle().bigText(details))
+ .setContentText(details)
+ .build();
+ notificationManager.notify(Integer.toString(mPhone.getSubId()),
+ NO_DATA_NOTIFICATION, notification);
+ }
}
int newRequestType = calculateNewRetryRequestType(handoverFailureMode, requestType,
@@ -3108,10 +3166,6 @@
+ ". Request type=" + requestTypeToString(requestType) + ", Retry in "
+ delay + "ms.");
}
- apnContext.setState(DctConstants.State.RETRYING);
- // Wait a bit before trying the next APN, so that
- // we're not tying up the RIL command channel
-
startReconnect(delay, apnContext, requestType);
} else {
// If we are not going to retry any APN, set this APN context to failed state.
@@ -3120,6 +3174,9 @@
apnContext.setDataConnection(null);
log("onDataSetupCompleteError: Stop retrying APNs. delay=" + delay
+ ", requestType=" + requestTypeToString(requestType));
+ //send request network complete messages as needed
+ sendRequestNetworkCompleteMessages(apnContext.getApnTypeBitmask(),
+ requestType, false, fallbackOnFailedHandover);
}
}
@@ -3687,9 +3744,16 @@
break;
case DctConstants.EVENT_TRY_SETUP_DATA:
- trySetupData((ApnContext) msg.obj, msg.arg1);
+ apnContext = (ApnContext) msg.obj;
+ requestType = msg.arg1;
+ if (!trySetupData(apnContext, requestType)) {
+ // Note that this might be a retry handover request that we need to notify
+ // handover completion. Note if it fails, we will not retry anymore (because
+ // it's due to pre-condition not met) and will not fallback.
+ sendRequestNetworkCompleteMessages(apnContext.getApnTypeBitmask(), requestType,
+ false, false);
+ }
break;
-
case DctConstants.EVENT_CLEAN_UP_CONNECTION:
if (DBG) log("EVENT_CLEAN_UP_CONNECTION");
cleanUpConnectionInternal(true, RELEASE_TYPE_DETACH, (ApnContext) msg.obj);
@@ -3985,7 +4049,16 @@
onSimStateUpdated(simState);
break;
case DctConstants.EVENT_APN_UNTHROTTLED:
- onApnUnthrottled(msg);
+ ar = (AsyncResult) msg.obj;
+ String apn = (String) ar.result;
+ onApnUnthrottled(apn);
+ break;
+ case DctConstants.EVENT_AIRPLANE_MODE_CHANGED:
+ ar = (AsyncResult) msg.obj;
+ if (!(Boolean) ar.result) {
+ log("Airplane Mode switched off, resetting data throttler");
+ mDataThrottler.reset();
+ }
break;
default:
Rlog.e("DcTracker", "Unhandled event=" + msg);
@@ -4262,7 +4335,7 @@
if (isNetworkTypeUnmetered(NETWORK_TYPE_NR)) {
if (mNrNsaMmwaveUnmetered) {
- if (override == TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_NSA_MMWAVE) {
+ if (override == TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_ADVANCED) {
if (DBG) log("NR unmetered for mmwave only");
return true;
}
@@ -4274,7 +4347,7 @@
}
return false;
}
- if (override == TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_NSA_MMWAVE
+ if (override == TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_ADVANCED
|| override == TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_NSA
|| rat == NETWORK_TYPE_NR) {
if (DBG) log("NR unmetered for all frequencies");
@@ -4285,7 +4358,7 @@
if (mNrNsaAllUnmetered) {
if (mNrNsaMmwaveUnmetered) {
- if (override == TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_NSA_MMWAVE) {
+ if (override == TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_ADVANCED) {
if (DBG) log("NR NSA unmetered for mmwave only via carrier configs");
return true;
}
@@ -4297,7 +4370,7 @@
}
return false;
}
- if (override == TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_NSA_MMWAVE
+ if (override == TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_ADVANCED
|| override == TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_NSA) {
if (DBG) log("NR NSA unmetered for all frequencies via carrier configs");
return true;
@@ -4361,7 +4434,7 @@
boolean isNrNsa = (networkType == TelephonyManager.NETWORK_TYPE_LTE
|| networkType == TelephonyManager.NETWORK_TYPE_LTE_CA)
&& (overrideNetworkType == TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_NSA
- || overrideNetworkType == TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_NSA_MMWAVE);
+ || overrideNetworkType == TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_ADVANCED);
boolean is5GHysteresisActive = mPhone.getDisplayInfoController().is5GHysteresisActive();
// True if device is on NR SA or NR NSA, or neither but 5G hysteresis is active
@@ -4853,6 +4926,14 @@
private long mTimeLastRecoveryStartMs;
// Whether current network good or not
private boolean mIsValidNetwork;
+ // Whether data stall happened or not.
+ private boolean mWasDataStall;
+ // Whether the result of last action(RADIO_RESTART) reported.
+ private boolean mLastActionReported;
+ // The real time for data stall start.
+ private long mDataStallStartMs;
+ // Last data stall action.
+ private @RecoveryAction int mLastAction;
public DataStallRecoveryHandler() {
reset();
@@ -4863,6 +4944,36 @@
putRecoveryAction(RECOVERY_ACTION_GET_DATA_CALL_LIST);
}
+ private void setNetworkValidationState(boolean isValid) {
+ // Validation status is true and was not data stall.
+ if (isValid && !mWasDataStall) {
+ return;
+ }
+
+ if (!mWasDataStall) {
+ mWasDataStall = true;
+ mDataStallStartMs = SystemClock.elapsedRealtime();
+ if (DBG) log("data stall: start time = " + mDataStallStartMs);
+ return;
+ }
+
+ if (!mLastActionReported) {
+ int timeDuration = (int) (SystemClock.elapsedRealtime() - mDataStallStartMs);
+ if (DBG) {
+ log("data stall: lastaction = " + mLastAction + ", isRecovered = "
+ + isValid + ", mTimeDuration = " + timeDuration);
+ }
+ DataStallRecoveryStats.onDataStallEvent(mLastAction, mPhone, isValid,
+ timeDuration);
+ mLastActionReported = true;
+ }
+
+ if (isValid) {
+ mLastActionReported = false;
+ mWasDataStall = false;
+ }
+ }
+
public boolean isAggressiveRecovery() {
@RecoveryAction int action = getRecoveryAction();
@@ -4939,7 +5050,8 @@
mPhone.getPhoneId(), signalStrength);
TelephonyMetrics.getInstance().writeDataStallEvent(
mPhone.getPhoneId(), recoveryAction);
- DataStallRecoveryStats.onDataStallEvent(recoveryAction, mPhone);
+ mLastAction = recoveryAction;
+ mLastActionReported = false;
broadcastDataStallDetected(recoveryAction);
switch (recoveryAction) {
@@ -4983,6 +5095,7 @@
}
public void processNetworkStatusChanged(boolean isValid) {
+ setNetworkValidationState(isValid);
if (isValid) {
mIsValidNetwork = true;
reset();
@@ -5232,10 +5345,14 @@
if (networkTypeBitmask == 0) {
profileType = DataProfile.TYPE_COMMON;
- } else if (ServiceState.bearerBitmapHasCdma(networkTypeBitmask)) {
+ } else if ((networkTypeBitmask & TelephonyManager.NETWORK_STANDARDS_FAMILY_BITMASK_3GPP2)
+ == networkTypeBitmask) {
profileType = DataProfile.TYPE_3GPP2;
- } else {
+ } else if ((networkTypeBitmask & TelephonyManager.NETWORK_STANDARDS_FAMILY_BITMASK_3GPP)
+ == networkTypeBitmask) {
profileType = DataProfile.TYPE_3GPP;
+ } else {
+ profileType = DataProfile.TYPE_COMMON;
}
return new DataProfile.Builder()
@@ -5269,6 +5386,9 @@
cleanUpAllConnectionsInternal(false, Phone.REASON_IWLAN_DATA_SERVICE_DIED);
}
}
+ } else {
+ //reset throttling after binding to data service
+ mDataThrottler.reset();
}
mDataServiceBound = bound;
}
diff --git a/src/java/com/android/internal/telephony/dataconnection/LinkBandwidthEstimator.java b/src/java/com/android/internal/telephony/dataconnection/LinkBandwidthEstimator.java
new file mode 100644
index 0000000..100b1b9
--- /dev/null
+++ b/src/java/com/android/internal/telephony/dataconnection/LinkBandwidthEstimator.java
@@ -0,0 +1,1102 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.telephony.dataconnection;
+
+import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.hardware.display.DisplayManager;
+import android.net.ConnectivityManager;
+import android.net.Network;
+import android.net.NetworkCapabilities;
+import android.os.AsyncResult;
+import android.os.Handler;
+import android.os.HandlerExecutor;
+import android.os.Message;
+import android.os.OutcomeReceiver;
+import android.preference.PreferenceManager;
+import android.telephony.AccessNetworkConstants;
+import android.telephony.CellIdentity;
+import android.telephony.CellIdentityGsm;
+import android.telephony.CellIdentityLte;
+import android.telephony.CellIdentityNr;
+import android.telephony.CellIdentityTdscdma;
+import android.telephony.CellIdentityWcdma;
+import android.telephony.ModemActivityInfo;
+import android.telephony.NetworkRegistrationInfo;
+import android.telephony.ServiceState;
+import android.telephony.SignalStrength;
+import android.telephony.TelephonyCallback;
+import android.telephony.TelephonyManager;
+import android.util.ArrayMap;
+import android.util.LocalLog;
+import android.util.Pair;
+import android.view.Display;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.telephony.DctConstants;
+import com.android.internal.telephony.Phone;
+import com.android.internal.telephony.PhoneConstants;
+import com.android.internal.telephony.TelephonyFacade;
+import com.android.internal.util.IndentingPrintWriter;
+import com.android.telephony.Rlog;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.util.Map;
+import java.util.Objects;
+
+/**
+ * Link Bandwidth Estimator based on the byte counts in TrafficStats and the time reported in modem
+ * activity.
+ */
+public class LinkBandwidthEstimator extends Handler {
+ private static final String TAG = LinkBandwidthEstimator.class.getSimpleName();
+ private static final boolean DBG = false;
+ @VisibleForTesting
+ static final int MSG_SCREEN_STATE_CHANGED = 1;
+ @VisibleForTesting
+ static final int MSG_TRAFFIC_STATS_POLL = 2;
+ @VisibleForTesting
+ static final int MSG_MODEM_ACTIVITY_RETURNED = 3;
+ @VisibleForTesting
+ static final int MSG_DEFAULT_NETWORK_CHANGED = 4;
+ @VisibleForTesting
+ static final int MSG_SIGNAL_STRENGTH_CHANGED = 5;
+ @VisibleForTesting
+ static final int MSG_NR_FREQUENCY_CHANGED = 6;
+ @VisibleForTesting
+ static final int MSG_NR_STATE_CHANGED = 7;
+
+ // TODO: move the following parameters to xml file
+ private static final int TRAFFIC_STATS_POLL_INTERVAL_MS = 1_000;
+ private static final int MODEM_POLL_MIN_INTERVAL_MS = 5_000;
+ private static final int TRAFFIC_MODEM_POLL_BYTE_RATIO = 8;
+ private static final int TRAFFIC_POLL_BYTE_THRESHOLD_MAX = 20_000;
+ private static final int BYTE_DELTA_ACC_THRESHOLD_MAX_KB = 5_000;
+ private static final int MODEM_POLL_TIME_DELTA_MAX_MS = 15_000;
+ private static final int FILTER_UPDATE_MAX_INTERVAL_MS = 5_100;
+ // BW samples with Tx or Rx time below the following value is ignored.
+ private static final int TX_RX_TIME_MIN_MS = 200;
+ // The large time constant used in BW filter
+ private static final int TIME_CONSTANT_LARGE_SEC = 6;
+ // The small time constant used in BW filter
+ private static final int TIME_CONSTANT_SMALL_SEC = 6;
+ // If RSSI changes by more than the below value, update BW filter with small time constant
+ private static final int RSSI_DELTA_THRESHOLD_DB = 6;
+ // The up-scaling factor of filter coefficient.
+ private static final int FILTER_SCALE = 128;
+ // Force weight to 0 if the elapsed time is above LARGE_TIME_DECAY_RATIO * time constant
+ private static final int LARGE_TIME_DECAY_RATIO = 4;
+ // Modem Tx time may contain Rx time as defined in HAL. To work around the issue, if Tx time
+ // over Rx time ratio is above the following value, use Tx time + Rx time as Rx time.
+ private static final int TX_OVER_RX_TIME_RATIO_THRESHOLD_NUM = 3;
+ private static final int TX_OVER_RX_TIME_RATIO_THRESHOLD_DEN = 2;
+ // Default Link bandwidth value if the RAT entry is not found in static BW table.
+ private static final int DEFAULT_LINK_BAND_WIDTH_KBPS = 14;
+ // If Tx or Rx link bandwidth change is above the following value, send the BW update
+ private static final int BW_UPDATE_THRESHOLD_PERCENT = 15;
+
+ // To be used in link bandwidth estimation, each TrafficStats poll sample needs to be above
+ // a predefine threshold.
+ // For RAT with static BW above HIGH_BANDWIDTH_THRESHOLD_KBPS, it uses the following table.
+ // For others RATs, the thresholds are derived from the static BW values.
+ // The following table is defined per signal level, int [NUM_SIGNAL_LEVEL].
+ private static final int HIGH_BANDWIDTH_THRESHOLD_KBPS = 5000;
+ //Array dimension : int [NUM_LINK_DIRECTION][NUM_SIGNAL_LEVEL]
+ private static final int[][] BYTE_DELTA_THRESHOLD_KB =
+ {{200, 300, 400, 600, 1000}, {400, 600, 800, 1000, 1000}};
+ // Used to derive byte count threshold from avg BW
+ private static final int AVG_BW_TO_LOW_BW_RATIO = 4;
+ private static final int BYTE_DELTA_THRESHOLD_MIN_KB = 10;
+ private static final int MAX_ERROR_PERCENT = 100 * 100;
+ private static final String[] AVG_BW_PER_RAT = {
+ "GPRS:24,24", "EDGE:70,18", "UMTS:115,115", "CDMA:14,14",
+ "CDMA - 1xRTT:30,30", "CDMA - EvDo rev. 0:750,48", "CDMA - EvDo rev. A:950,550",
+ "HSDPA:4300,620", "HSUPA:4300,1800", "HSPA:4300,1800", "CDMA - EvDo rev. B:1500,550",
+ "CDMA - eHRPD:750,48", "HSPA+:13000,3400", "TD_SCDMA:115,115",
+ "LTE:30000,15000", "NR_NSA:47000,18000",
+ "NR_NSA_MMWAVE:145000,60000", "NR:145000,60000"};
+ private static final Map<String, Pair<Integer, Integer>> AVG_BW_PER_RAT_MAP = new ArrayMap<>();
+
+ // To be used in the long term avg, each count needs to be above the following value
+ static final int BW_STATS_COUNT_THRESHOLD = 5;
+ static final int NUM_SIGNAL_LEVEL = 5;
+ static final int LINK_TX = 0;
+ static final int LINK_RX = 1;
+ private static final int NUM_LINK_DIRECTION = 2;
+
+ private final Phone mPhone;
+ private final TelephonyFacade mTelephonyFacade;
+ private final TelephonyManager mTelephonyManager;
+ private final ConnectivityManager mConnectivityManager;
+ private final LocalLog mLocalLog = new LocalLog(512);
+ private boolean mScreenOn = false;
+ private boolean mIsOnDefaultRoute = false;
+ private long mLastModemPollTimeMs;
+ private boolean mLastTrafficValid = true;
+ private long mLastMobileTxBytes;
+ private long mLastMobileRxBytes;
+ private long mTxBytesDeltaAcc;
+ private long mRxBytesDeltaAcc;
+
+ private ModemActivityInfo mLastModemActivityInfo = null;
+ private final TelephonyCallback mTelephonyCallback = new TelephonyCallbackImpl();
+ private int mSignalStrengthDbm;
+ private int mSignalLevel;
+ private int mDataRat = TelephonyManager.NETWORK_TYPE_UNKNOWN;
+ private int mTac;
+ private String mPlmn = "";
+ private NetworkCapabilities mNetworkCapabilities;
+ private NetworkBandwidth mPlaceholderNetwork;
+
+ private long mFilterUpdateTimeMs;
+
+ private int mBandwidthUpdateSignalDbm = -1;
+ private int mBandwidthUpdateSignalLevel = -1;
+ private int mBandwidthUpdateDataRat = TelephonyManager.NETWORK_TYPE_UNKNOWN;
+ private String mBandwidthUpdatePlmn = "";
+ private BandwidthState mTxState = new BandwidthState(LINK_TX);
+ private BandwidthState mRxState = new BandwidthState(LINK_RX);
+
+ private static void initAvgBwPerRatTable() {
+ for (String config : AVG_BW_PER_RAT) {
+ int rxKbps = 14;
+ int txKbps = 14;
+ String[] kv = config.split(":");
+ if (kv.length == 2) {
+ String[] split = kv[1].split(",");
+ if (split.length == 2) {
+ try {
+ rxKbps = Integer.parseInt(split[0]);
+ txKbps = Integer.parseInt(split[1]);
+ } catch (NumberFormatException ignored) {
+ }
+ }
+ AVG_BW_PER_RAT_MAP.put(kv[0], new Pair<>(rxKbps, txKbps));
+ }
+ }
+ }
+
+ private final DisplayManager.DisplayListener mDisplayListener =
+ new DisplayManager.DisplayListener() {
+ @Override
+ public void onDisplayAdded(int displayId) {
+ }
+
+ @Override
+ public void onDisplayRemoved(int displayId) {
+ }
+
+ @Override
+ public void onDisplayChanged(int displayId) {
+ obtainMessage(MSG_SCREEN_STATE_CHANGED, isScreenOn()).sendToTarget();
+ }
+ };
+
+ private final OutcomeReceiver<ModemActivityInfo, TelephonyManager.ModemActivityInfoException>
+ mOutcomeReceiver =
+ new OutcomeReceiver<ModemActivityInfo, TelephonyManager.ModemActivityInfoException>() {
+ @Override
+ public void onResult(ModemActivityInfo result) {
+ obtainMessage(MSG_MODEM_ACTIVITY_RETURNED, result).sendToTarget();
+ }
+
+ @Override
+ public void onError(TelephonyManager.ModemActivityInfoException e) {
+ Rlog.e(TAG, "error reading modem stats:" + e);
+ obtainMessage(MSG_MODEM_ACTIVITY_RETURNED, null).sendToTarget();
+ }
+ };
+
+ private final ConnectivityManager.NetworkCallback mDefaultNetworkCallback =
+ new ConnectivityManager.NetworkCallback() {
+ @Override
+ public void onCapabilitiesChanged(@NonNull Network network,
+ @NonNull NetworkCapabilities networkCapabilities) {
+ obtainMessage(MSG_DEFAULT_NETWORK_CHANGED, networkCapabilities).sendToTarget();
+ }
+
+ public void onLost(@NonNull Network network) {
+ obtainMessage(MSG_DEFAULT_NETWORK_CHANGED, null).sendToTarget();
+ }
+ };
+
+ public LinkBandwidthEstimator(Phone phone, TelephonyFacade telephonyFacade) {
+ mPhone = phone;
+ mTelephonyFacade = telephonyFacade;
+ mTelephonyManager = phone.getContext()
+ .getSystemService(TelephonyManager.class)
+ .createForSubscriptionId(phone.getSubId());
+ mConnectivityManager = phone.getContext().getSystemService(ConnectivityManager.class);
+ DisplayManager dm = (DisplayManager) phone.getContext().getSystemService(
+ Context.DISPLAY_SERVICE);
+ dm.registerDisplayListener(mDisplayListener, null);
+ handleScreenStateChanged(isScreenOn());
+ mConnectivityManager.registerDefaultNetworkCallback(mDefaultNetworkCallback, this);
+ mTelephonyManager.registerTelephonyCallback(new HandlerExecutor(this),
+ mTelephonyCallback);
+ mPlaceholderNetwork = new NetworkBandwidth("");
+ initAvgBwPerRatTable();
+ registerDataServiceState();
+ }
+
+ @Override
+ public void handleMessage(Message msg) {
+ AsyncResult ar;
+ switch (msg.what) {
+ case MSG_SCREEN_STATE_CHANGED:
+ handleScreenStateChanged((boolean) msg.obj);
+ break;
+ case MSG_TRAFFIC_STATS_POLL:
+ handleTrafficStatsPoll();
+ break;
+ case MSG_MODEM_ACTIVITY_RETURNED:
+ handleModemActivityReturned((ModemActivityInfo) msg.obj);
+ break;
+ case MSG_DEFAULT_NETWORK_CHANGED:
+ handleDefaultNetworkChanged((NetworkCapabilities) msg.obj);
+ break;
+ case MSG_SIGNAL_STRENGTH_CHANGED:
+ handleSignalStrengthChanged((SignalStrength) msg.obj);
+ break;
+ case MSG_NR_FREQUENCY_CHANGED:
+ // fall through
+ case MSG_NR_STATE_CHANGED:
+ updateStaticBwValueResetFilter();
+ break;
+ default:
+ Rlog.e(TAG, "invalid message " + msg.what);
+ break;
+ }
+ }
+
+ /**
+ * @return True if one the device's screen (e.g. main screen, wifi display, HDMI display etc...)
+ * is on.
+ */
+ private boolean isScreenOn() {
+ // Note that we don't listen to Intent.SCREEN_ON and Intent.SCREEN_OFF because they are no
+ // longer adequate for monitoring the screen state since they are not sent in cases where
+ // the screen is turned off transiently such as due to the proximity sensor.
+ final DisplayManager dm = (DisplayManager) mPhone.getContext().getSystemService(
+ Context.DISPLAY_SERVICE);
+ Display[] displays = dm.getDisplays();
+
+ if (displays != null) {
+ for (Display display : displays) {
+ // Anything other than STATE_ON is treated as screen off, such as STATE_DOZE,
+ // STATE_DOZE_SUSPEND, etc...
+ if (display.getState() == Display.STATE_ON) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ return false;
+ }
+
+ private void handleScreenStateChanged(boolean screenOn) {
+ if (mScreenOn == screenOn) {
+ return;
+ }
+ mScreenOn = screenOn;
+ handleTrafficStatsPollConditionChanged();
+ }
+
+ private void handleDefaultNetworkChanged(NetworkCapabilities networkCapabilities) {
+ mNetworkCapabilities = networkCapabilities;
+ boolean isOnDefaultRoute;
+ if (networkCapabilities == null) {
+ isOnDefaultRoute = false;
+ } else {
+ isOnDefaultRoute = networkCapabilities.hasTransport(TRANSPORT_CELLULAR);
+ }
+ if (mIsOnDefaultRoute == isOnDefaultRoute) {
+ return;
+ }
+ mIsOnDefaultRoute = isOnDefaultRoute;
+ handleTrafficStatsPollConditionChanged();
+ }
+
+ private void handleTrafficStatsPollConditionChanged() {
+ removeMessages(MSG_TRAFFIC_STATS_POLL);
+ if (mScreenOn && mIsOnDefaultRoute) {
+ updateDataRatCellIdentity();
+ handleTrafficStatsPoll();
+ }
+ }
+
+ private void handleTrafficStatsPoll() {
+ long mobileTxBytes = mTelephonyFacade.getMobileTxBytes();
+ long mobileRxBytes = mTelephonyFacade.getMobileRxBytes();
+ long txBytesDelta = mobileTxBytes - mLastMobileTxBytes;
+ long rxBytesDelta = mobileRxBytes - mLastMobileRxBytes;
+
+ // Schedule the next traffic stats poll
+ sendEmptyMessageDelayed(MSG_TRAFFIC_STATS_POLL, TRAFFIC_STATS_POLL_INTERVAL_MS);
+
+ mLastMobileTxBytes = mobileTxBytes;
+ mLastMobileRxBytes = mobileRxBytes;
+ // Sometimes TrafficStats byte counts return invalid values
+ // Ignore two polls if it happens
+ boolean trafficValid = txBytesDelta >= 0 && rxBytesDelta >= 0;
+ if (!mLastTrafficValid || !trafficValid) {
+ mLastTrafficValid = trafficValid;
+ Rlog.e(TAG, " run into invalid traffic count");
+ return;
+ }
+
+ mTxBytesDeltaAcc += txBytesDelta;
+ mRxBytesDeltaAcc += rxBytesDelta;
+
+ boolean doModemPoll = true;
+ // Check if it meets the requirement to request modem activity
+ long txByteDeltaThr = Math.min(mTxState.mByteDeltaAccThr / TRAFFIC_MODEM_POLL_BYTE_RATIO,
+ TRAFFIC_POLL_BYTE_THRESHOLD_MAX);
+ long rxByteDeltaThr = Math.min(mRxState.mByteDeltaAccThr / TRAFFIC_MODEM_POLL_BYTE_RATIO,
+ TRAFFIC_POLL_BYTE_THRESHOLD_MAX);
+ if (txBytesDelta < txByteDeltaThr && rxBytesDelta < rxByteDeltaThr
+ && mTxBytesDeltaAcc < mTxState.mByteDeltaAccThr
+ && mRxBytesDeltaAcc < mRxState.mByteDeltaAccThr) {
+ doModemPoll = false;
+ }
+
+ long currTimeMs = mTelephonyFacade.getElapsedSinceBootMillis();
+ long timeSinceLastModemPollMs = currTimeMs - mLastModemPollTimeMs;
+ if (timeSinceLastModemPollMs < MODEM_POLL_MIN_INTERVAL_MS) {
+ doModemPoll = false;
+ }
+
+ if (doModemPoll) {
+ StringBuilder sb = new StringBuilder();
+ logd(sb.append("txByteDelta ").append(txBytesDelta)
+ .append(" rxByteDelta ").append(rxBytesDelta)
+ .append(" txByteDeltaAcc ").append(mTxBytesDeltaAcc)
+ .append(" rxByteDeltaAcc ").append(mRxBytesDeltaAcc)
+ .append(" trigger modem activity request").toString());
+ updateDataRatCellIdentity();
+ // Filter update will happen after the request
+ makeRequestModemActivity();
+ return;
+ }
+
+ long timeSinceLastFilterUpdateMs = currTimeMs - mFilterUpdateTimeMs;
+ // Update filter
+ if (timeSinceLastFilterUpdateMs >= FILTER_UPDATE_MAX_INTERVAL_MS) {
+ updateDataRatCellIdentity();
+ updateTxRxBandwidthFilterSendToDataConnection();
+ }
+ }
+
+ private void makeRequestModemActivity() {
+ mLastModemPollTimeMs = mTelephonyFacade.getElapsedSinceBootMillis();
+ // TODO: add CountDown in case that onResult/OnError() never happen
+ mTelephonyManager.requestModemActivityInfo(Runnable::run, mOutcomeReceiver);
+ }
+
+ private void handleModemActivityReturned(ModemActivityInfo result) {
+ updateBandwidthTxRxSamples(result);
+ updateTxRxBandwidthFilterSendToDataConnection();
+ mLastModemActivityInfo = result;
+ // Update for next poll
+ resetByteDeltaAcc();
+ invalidateTxRxSamples();
+ }
+
+ private void resetByteDeltaAcc() {
+ mTxBytesDeltaAcc = 0;
+ mRxBytesDeltaAcc = 0;
+ }
+
+ private void invalidateTxRxSamples() {
+ mTxState.mBwSampleValid = false;
+ mRxState.mBwSampleValid = false;
+ }
+
+ private void updateBandwidthTxRxSamples(ModemActivityInfo modemActivityInfo) {
+ if (mLastModemActivityInfo == null || modemActivityInfo == null
+ || mNetworkCapabilities == null) {
+ return;
+ }
+
+ long lastTimeMs = mLastModemActivityInfo.getTimestampMillis();
+ long currTimeMs = modemActivityInfo.getTimestampMillis();
+ long timeDeltaMs = currTimeMs - lastTimeMs;
+
+ if (timeDeltaMs > MODEM_POLL_TIME_DELTA_MAX_MS || timeDeltaMs <= 0) {
+ return;
+ }
+ ModemActivityInfo deltaInfo = mLastModemActivityInfo.getDelta(modemActivityInfo);
+ long txTimeDeltaMs = getModemTxTimeMs(deltaInfo);
+ long rxTimeDeltaMs = deltaInfo.getReceiveTimeMillis();
+
+ // Check if txTimeDeltaMs / rxTimeDeltaMs > TX_OVER_RX_TIME_RATIO_THRESHOLD
+ boolean isTxTimeOverRxTimeRatioLarge = (txTimeDeltaMs * TX_OVER_RX_TIME_RATIO_THRESHOLD_DEN
+ > rxTimeDeltaMs * TX_OVER_RX_TIME_RATIO_THRESHOLD_NUM);
+ long rxTimeBwEstMs = isTxTimeOverRxTimeRatioLarge
+ ? (txTimeDeltaMs + rxTimeDeltaMs) : rxTimeDeltaMs;
+
+ mTxState.updateBandwidthSample(mTxBytesDeltaAcc, txTimeDeltaMs);
+ mRxState.updateBandwidthSample(mRxBytesDeltaAcc, rxTimeBwEstMs);
+
+ int reportedTxTputKbps = mNetworkCapabilities.getLinkUpstreamBandwidthKbps();
+ int reportedRxTputKbps = mNetworkCapabilities.getLinkDownstreamBandwidthKbps();
+
+ StringBuilder sb = new StringBuilder();
+ logd(sb.append("UpdateBwSample")
+ .append(" dBm ").append(mSignalStrengthDbm)
+ .append(" level ").append(mSignalLevel)
+ .append(" rat ").append(getDataRatName(mDataRat))
+ .append(" plmn ").append(mPlmn)
+ .append(" tac ").append(mTac)
+ .append(" reportedTxKbps ").append(reportedTxTputKbps)
+ .append(" reportedRxKbps ").append(reportedRxTputKbps)
+ .append(" txMs ").append(txTimeDeltaMs)
+ .append(" rxMs ").append(rxTimeDeltaMs)
+ .append(" txKB ").append(mTxBytesDeltaAcc / 1024)
+ .append(" rxKB ").append(mRxBytesDeltaAcc / 1024)
+ .append(" txKBThr ").append(mTxState.mByteDeltaAccThr / 1024)
+ .append(" rxKBThr ").append(mRxState.mByteDeltaAccThr / 1024)
+ .toString());
+ }
+
+ private long getModemTxTimeMs(ModemActivityInfo modemActivity) {
+ long txTimeMs = 0;
+ for (int lvl = 0; lvl < ModemActivityInfo.getNumTxPowerLevels(); lvl++) {
+ txTimeMs += modemActivity.getTransmitDurationMillisAtPowerLevel(lvl);
+ }
+ return txTimeMs;
+ }
+
+ private void updateTxRxBandwidthFilterSendToDataConnection() {
+ mFilterUpdateTimeMs = mTelephonyFacade.getElapsedSinceBootMillis();
+ mTxState.updateBandwidthFilter();
+ mRxState.updateBandwidthFilter();
+
+ if (mTxState.hasLargeBwChange()
+ || mRxState.hasLargeBwChange()
+ || mBandwidthUpdateDataRat != mDataRat
+ || mBandwidthUpdateSignalLevel != mSignalLevel
+ || !mBandwidthUpdatePlmn.equals(mPlmn)) {
+ mTxState.mLastReportedBwKbps = mTxState.mAvgUsedKbps < 0 ? -1 : mTxState.mFilterKbps;
+ mRxState.mLastReportedBwKbps = mRxState.mAvgUsedKbps < 0 ? -1 : mRxState.mFilterKbps;
+ sendLinkBandwidthToDataConnection(
+ mTxState.mLastReportedBwKbps,
+ mRxState.mLastReportedBwKbps);
+ }
+ mBandwidthUpdateSignalDbm = mSignalStrengthDbm;
+ mBandwidthUpdateSignalLevel = mSignalLevel;
+ mBandwidthUpdateDataRat = mDataRat;
+ mBandwidthUpdatePlmn = mPlmn;
+
+ mTxState.calculateError();
+ mRxState.calculateError();
+ }
+
+ private class BandwidthState {
+ private final int mLink;
+ int mFilterKbps;
+ int mByteDeltaAccThr = BYTE_DELTA_THRESHOLD_KB[0][0];
+ int mAvgUsedKbps;
+ int mBwSampleKbps;
+ boolean mBwSampleValid;
+ long mBwSampleValidTimeMs;
+ int mStaticBwKbps;
+ int mLastReportedBwKbps;
+ private final Map<String, EstimationError> mErrorMap = new ArrayMap<>();
+
+ private class EstimationError {
+ final String mRatName;
+ final long[] mBwEstIntNse = new long[NUM_SIGNAL_LEVEL];
+ final long[] mBwEstExtNse = new long[NUM_SIGNAL_LEVEL];
+ final long[] mStaticBwNse = new long[NUM_SIGNAL_LEVEL];
+ final int[] mCount = new int[NUM_SIGNAL_LEVEL];
+
+ EstimationError(String ratName) {
+ mRatName = ratName;
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ return sb.append(mRatName)
+ .append("\n Internal\n").append(printAvgError(mBwEstIntNse, mCount))
+ .append("\n External\n").append(printAvgError(mBwEstExtNse, mCount))
+ .append("\n StaticBw\n").append(printAvgError(mStaticBwNse, mCount))
+ .toString();
+ }
+
+ private String printAvgError(long[] stats, int[] count) {
+ StringBuilder sb = new StringBuilder();
+ for (int k = 0; k < NUM_SIGNAL_LEVEL; k++) {
+ int avgStat = (count[k] >= BW_STATS_COUNT_THRESHOLD && stats[k] >= 0)
+ ? (int) Math.sqrt(stats[k] / count[k]) : 0;
+ sb.append(" " + avgStat);
+ }
+ return sb.toString();
+ }
+ }
+
+ BandwidthState(int link) {
+ mLink = link;
+ }
+
+ private EstimationError lookupEstimationError(String dataRatName) {
+ EstimationError ans = mErrorMap.get(dataRatName);
+ if (ans == null) {
+ ans = new EstimationError(dataRatName);
+ mErrorMap.put(dataRatName, ans);
+ }
+ return ans;
+ }
+
+ private void updateBandwidthSample(long bytesDelta, long timeDeltaMs) {
+ if (bytesDelta < mByteDeltaAccThr) {
+ return;
+ }
+ if (timeDeltaMs < TX_RX_TIME_MIN_MS) {
+ return;
+ }
+ int linkBandwidthKbps = (int) (bytesDelta * 8 * 1000 / timeDeltaMs / 1024);
+ mBwSampleValid = true;
+ mBwSampleKbps = linkBandwidthKbps;
+
+ String dataRatName = getDataRatName(mDataRat);
+ NetworkBandwidth network = lookupNetwork(mPlmn, dataRatName);
+ // Update per RAT stats of all TAC
+ network.update(linkBandwidthKbps, mLink, mSignalLevel);
+
+ // Update per TAC stats
+ network = lookupNetwork(mPlmn, mTac, dataRatName);
+ network.update(linkBandwidthKbps, mLink, mSignalLevel);
+ }
+
+ private void updateBandwidthFilter() {
+ int avgKbps = getAvgLinkBandwidthKbps();
+ // Feed the filter with the long term avg if there is no valid BW sample so that filter
+ // will gradually converge the long term avg.
+ int filterInKbps = mBwSampleValid ? mBwSampleKbps : avgKbps;
+
+ long currTimeMs = mTelephonyFacade.getElapsedSinceBootMillis();
+ int timeDeltaSec = (int) (currTimeMs - mBwSampleValidTimeMs) / 1000;
+
+ // If the operation condition changes significantly since the last update
+ // or the sample has higher BW, use a faster filter. Otherwise, use a slow filter
+ int timeConstantSec;
+ if (Math.abs(mBandwidthUpdateSignalDbm - mSignalStrengthDbm) > RSSI_DELTA_THRESHOLD_DB
+ || !mBandwidthUpdatePlmn.equals(mPlmn)
+ || mBandwidthUpdateDataRat != mDataRat
+ || (mBwSampleValid && mBwSampleKbps > avgKbps)) {
+ timeConstantSec = TIME_CONSTANT_SMALL_SEC;
+ } else {
+ timeConstantSec = TIME_CONSTANT_LARGE_SEC;
+ }
+ // Update timestamp for next iteration
+ if (mBwSampleValid) {
+ mBwSampleValidTimeMs = currTimeMs;
+ }
+
+ if (filterInKbps == mFilterKbps) {
+ logv(mLink + " skip filter because the same input / current = " + filterInKbps);
+ return;
+ }
+
+ int alpha = timeDeltaSec > LARGE_TIME_DECAY_RATIO * timeConstantSec ? 0
+ : (int) (FILTER_SCALE * Math.exp(-1.0 * timeDeltaSec / timeConstantSec));
+ mFilterKbps = alpha == 0 ? filterInKbps : ((mFilterKbps * alpha
+ + filterInKbps * FILTER_SCALE - filterInKbps * alpha) / FILTER_SCALE);
+ StringBuilder sb = new StringBuilder();
+ logv(sb.append(mLink)
+ .append(" lastSampleWeight=").append(alpha)
+ .append("/").append(FILTER_SCALE)
+ .append(" filterInKbps=").append(filterInKbps)
+ .append(" avgKbps=").append(avgKbps)
+ .append(" filterOutKbps=").append(mFilterKbps)
+ .toString());
+ }
+
+ private int getAvgUsedLinkBandwidthKbps() {
+ // Check if current TAC/RAT/level has enough stats
+ String dataRatName = getDataRatName(mDataRat);
+ NetworkBandwidth network = lookupNetwork(mPlmn, mTac, dataRatName);
+ int count = network.getCount(mLink, mSignalLevel);
+ if (count >= BW_STATS_COUNT_THRESHOLD) {
+ return (int) (network.getValue(mLink, mSignalLevel) / count);
+ }
+
+ // Check if current RAT/level has enough stats
+ network = lookupNetwork(mPlmn, dataRatName);
+ count = network.getCount(mLink, mSignalLevel);
+ if (count >= BW_STATS_COUNT_THRESHOLD) {
+ return (int) (network.getValue(mLink, mSignalLevel) / count);
+ }
+ return -1;
+ }
+
+ private int getCurrentCount() {
+ String dataRatName = getDataRatName(mDataRat);
+ NetworkBandwidth network = lookupNetwork(mPlmn, dataRatName);
+ return network.getCount(mLink, mSignalLevel);
+ }
+
+ /** get a long term avg value (PLMN/RAT/TAC/level dependent) or static value */
+ private int getAvgLinkBandwidthKbps() {
+ mAvgUsedKbps = getAvgUsedLinkBandwidthKbps();
+ if (mAvgUsedKbps > 0) {
+ return mAvgUsedKbps;
+ }
+ // Fall back to static value
+ return mStaticBwKbps;
+ }
+
+ private void resetBandwidthFilter() {
+ mFilterKbps = getAvgLinkBandwidthKbps();
+ }
+
+ private void updateByteCountThr() {
+ // For high BW RAT cases, use predefined value + threshold derived from avg usage BW
+ if (mStaticBwKbps > HIGH_BANDWIDTH_THRESHOLD_KBPS) {
+ int lowBytes = calculateByteCountThreshold(getAvgUsedLinkBandwidthKbps(),
+ MODEM_POLL_MIN_INTERVAL_MS);
+ // Start with a predefined value
+ mByteDeltaAccThr = BYTE_DELTA_THRESHOLD_KB[mLink][mSignalLevel] * 1024;
+ if (lowBytes > 0) {
+ // Raise the threshold if the avg usage BW is high
+ mByteDeltaAccThr = Math.max(lowBytes, mByteDeltaAccThr);
+ mByteDeltaAccThr = Math.min(mByteDeltaAccThr,
+ BYTE_DELTA_ACC_THRESHOLD_MAX_KB * 1024);
+ }
+ return;
+ }
+ // For low BW RAT cases, derive the threshold from avg BW values
+ mByteDeltaAccThr = calculateByteCountThreshold(mStaticBwKbps,
+ MODEM_POLL_MIN_INTERVAL_MS);
+
+ mByteDeltaAccThr = Math.max(mByteDeltaAccThr, BYTE_DELTA_THRESHOLD_MIN_KB * 1024);
+ // Low BW RAT threshold value should be no more than high BW one.
+ mByteDeltaAccThr = Math.min(mByteDeltaAccThr, BYTE_DELTA_THRESHOLD_KB[mLink][0] * 1024);
+ }
+
+ // Calculate a byte count threshold for the given avg BW and observation window size
+ private int calculateByteCountThreshold(int avgBwKbps, int durationMs) {
+ return avgBwKbps / 8 * durationMs / AVG_BW_TO_LOW_BW_RATIO;
+ }
+
+ public boolean hasLargeBwChange() {
+ int deltaKbps = Math.abs(mLastReportedBwKbps - mFilterKbps);
+ return mAvgUsedKbps > 0
+ && deltaKbps * 100 > BW_UPDATE_THRESHOLD_PERCENT * mLastReportedBwKbps;
+ }
+
+ public void calculateError() {
+ if (!mBwSampleValid || getCurrentCount() <= BW_STATS_COUNT_THRESHOLD + 1) {
+ return;
+ }
+ int bwEstExtErrPercent = calculateErrorPercent(mLastReportedBwKbps, mBwSampleKbps);
+ int bwEstAvgErrPercent = calculateErrorPercent(mAvgUsedKbps, mBwSampleKbps);
+ int bwEstIntErrPercent = calculateErrorPercent(mFilterKbps, mBwSampleKbps);
+ int coldStartErrPercent = calculateErrorPercent(mStaticBwKbps, mBwSampleKbps);
+ EstimationError err = lookupEstimationError(getDataRatName(mDataRat));
+ err.mBwEstIntNse[mSignalLevel] += bwEstIntErrPercent * bwEstIntErrPercent;
+ err.mBwEstExtNse[mSignalLevel] += bwEstExtErrPercent * bwEstExtErrPercent;
+ err.mStaticBwNse[mSignalLevel] += coldStartErrPercent * coldStartErrPercent;
+ err.mCount[mSignalLevel]++;
+ StringBuilder sb = new StringBuilder();
+ logd(sb.append(mLink)
+ .append(" sampKbps ").append(mBwSampleKbps)
+ .append(" filtKbps ").append(mFilterKbps)
+ .append(" reportKbps ").append(mLastReportedBwKbps)
+ .append(" avgUsedKbps ").append(mAvgUsedKbps)
+ .append(" csKbps ").append(mStaticBwKbps)
+ .append(" intErrPercent ").append(bwEstIntErrPercent)
+ .append(" avgErrPercent ").append(bwEstAvgErrPercent)
+ .append(" extErrPercent ").append(bwEstExtErrPercent)
+ .append(" csErrPercent ").append(coldStartErrPercent)
+ .toString());
+ }
+
+ private int calculateErrorPercent(int inKbps, int bwSampleKbps) {
+ int errorKbps = inKbps - bwSampleKbps;
+ int errorPercent = bwSampleKbps > 0 ? (errorKbps * 100 / bwSampleKbps) : 0;
+ return Math.max(-MAX_ERROR_PERCENT, Math.min(errorPercent, MAX_ERROR_PERCENT));
+ }
+ }
+
+ /**
+ * Update the byte count threshold.
+ * It should be called whenever the RAT or signal level is changed.
+ * For the RAT with high BW (4G and beyond), use BYTE_DELTA_THRESHOLD_KB table.
+ * For other RATs, derive the threshold based on the static BW values.
+ */
+ private void updateByteCountThr() {
+ mTxState.updateByteCountThr();
+ mRxState.updateByteCountThr();
+ }
+
+ // Reset BW filter to a long term avg value (PLMN/RAT/TAC dependent) or static BW value.
+ // It should be called whenever PLMN/RAT or static BW value is changed;
+ private void resetBandwidthFilter() {
+ StringBuilder sb = new StringBuilder();
+ mTxState.resetBandwidthFilter();
+ mRxState.resetBandwidthFilter();
+ }
+
+ private void sendLinkBandwidthToDataConnection(int linkBandwidthTxKps, int linkBandwidthRxKps) {
+ DcTracker dt = mPhone.getDcTracker(AccessNetworkConstants.TRANSPORT_TYPE_WWAN);
+ if (dt == null) {
+ return;
+ }
+ DataConnection dc = dt.getDataConnectionByApnType(PhoneConstants.APN_TYPE_DEFAULT);
+ if (dc == null) {
+ return;
+ }
+ logv("send to DC tx " + linkBandwidthTxKps + " rx " + linkBandwidthRxKps);
+ dc.updateLinkBandwidthEstimation(linkBandwidthTxKps, linkBandwidthRxKps);
+ }
+
+ private void handleSignalStrengthChanged(SignalStrength signalStrength) {
+ if (signalStrength == null) {
+ return;
+ }
+
+ updateDataRatCellIdentity();
+
+ mSignalStrengthDbm = signalStrength.getDbm();
+ mSignalLevel = signalStrength.getLevel();
+ if (Math.abs(mBandwidthUpdateSignalDbm - mSignalStrengthDbm) > RSSI_DELTA_THRESHOLD_DB) {
+ updateByteCountThr();
+ updateTxRxBandwidthFilterSendToDataConnection();
+ }
+ }
+
+ private void registerDataServiceState() {
+ mPhone.getServiceStateTracker().registerForNrStateChanged(this,
+ MSG_NR_STATE_CHANGED, null);
+ mPhone.getServiceStateTracker().registerForNrFrequencyChanged(this,
+ MSG_NR_FREQUENCY_CHANGED, null);
+ }
+
+ private String getDataRatName(int rat) {
+ if (rat == TelephonyManager.NETWORK_TYPE_LTE && isNRConnected()) {
+ return mPhone.getServiceState().getNrFrequencyRange()
+ == ServiceState.FREQUENCY_RANGE_MMWAVE
+ ? DctConstants.RAT_NAME_NR_NSA_MMWAVE : DctConstants.RAT_NAME_NR_NSA;
+ }
+ return TelephonyManager.getNetworkTypeName(rat);
+ }
+
+ // Update avg BW values.
+ // It should be called whenever the RAT could be changed.
+ // return true if avg value is changed;
+ private boolean updateStaticBwValue(int dataRat) {
+ Pair<Integer, Integer> values = getStaticAvgBw(dataRat);
+ if (values == null) {
+ mTxState.mStaticBwKbps = DEFAULT_LINK_BAND_WIDTH_KBPS;
+ mRxState.mStaticBwKbps = DEFAULT_LINK_BAND_WIDTH_KBPS;
+ return true;
+ }
+ if (mTxState.mStaticBwKbps != values.second
+ || mRxState.mStaticBwKbps != values.first) {
+ mTxState.mStaticBwKbps = values.second;
+ mRxState.mStaticBwKbps = values.first;
+ return true;
+ }
+ return false;
+ }
+
+ /** get per-RAT static bandwidth value */
+ public Pair<Integer, Integer> getStaticAvgBw(int dataRat) {
+ String dataRatName = getDataRatName(dataRat);
+ Pair<Integer, Integer> values = AVG_BW_PER_RAT_MAP.get(dataRatName);
+ if (values == null) {
+ Rlog.e(TAG, dataRatName + " is not found in Avg BW table");
+ }
+ return values;
+ }
+
+ private void updateStaticBwValueResetFilter() {
+ if (updateStaticBwValue(mDataRat)) {
+ updateByteCountThr();
+ resetBandwidthFilter();
+ updateTxRxBandwidthFilterSendToDataConnection();
+ }
+ }
+
+ /** Check if the device is connected to NR 5G Non-Standalone network. */
+ private boolean isNRConnected() {
+ return mPhone.getServiceState().getNrState()
+ == NetworkRegistrationInfo.NR_STATE_CONNECTED;
+ }
+
+ private void updateDataRatCellIdentity() {
+ boolean updatedPlmn = false;
+ CellIdentity cellIdentity = mPhone.getCurrentCellIdentity();
+ mTac = getTac(cellIdentity);
+ String plmn;
+ if (cellIdentity.getPlmn() != null) {
+ plmn = cellIdentity.getPlmn();
+ } else {
+ if (cellIdentity.getOperatorAlphaShort() != null) {
+ plmn = cellIdentity.getOperatorAlphaShort().toString();
+ } else {
+ plmn = "";
+ }
+ }
+ if (mPlmn == null || !plmn.equals(mPlmn)) {
+ updatedPlmn = true;
+ mPlmn = plmn;
+ }
+
+ boolean updatedRat = false;
+ NetworkRegistrationInfo nri = mPhone.getServiceState().getNetworkRegistrationInfo(
+ NetworkRegistrationInfo.DOMAIN_PS, AccessNetworkConstants.TRANSPORT_TYPE_WWAN);
+ if (nri != null) {
+ int dataRat = nri.getAccessNetworkTechnology();
+ if (dataRat != mDataRat) {
+ updatedRat = true;
+ mDataRat = dataRat;
+ updateStaticBwValue(mDataRat);
+ updateByteCountThr();
+ }
+ }
+
+ if (updatedPlmn || updatedRat) {
+ resetBandwidthFilter();
+ updateTxRxBandwidthFilterSendToDataConnection();
+ }
+ }
+
+ private int getTac(@NonNull CellIdentity cellIdentity) {
+ if (cellIdentity instanceof CellIdentityLte) {
+ return ((CellIdentityLte) cellIdentity).getTac();
+ }
+ if (cellIdentity instanceof CellIdentityNr) {
+ return ((CellIdentityNr) cellIdentity).getTac();
+ }
+ if (cellIdentity instanceof CellIdentityWcdma) {
+ return ((CellIdentityWcdma) cellIdentity).getLac();
+ }
+ if (cellIdentity instanceof CellIdentityTdscdma) {
+ return ((CellIdentityTdscdma) cellIdentity).getLac();
+ }
+ if (cellIdentity instanceof CellIdentityGsm) {
+ return ((CellIdentityGsm) cellIdentity).getLac();
+ }
+ return 0;
+ }
+
+ private class TelephonyCallbackImpl extends TelephonyCallback implements
+ TelephonyCallback.SignalStrengthsListener {
+ @Override
+ public void onSignalStrengthsChanged(SignalStrength signalStrength) {
+ obtainMessage(MSG_SIGNAL_STRENGTH_CHANGED, signalStrength).sendToTarget();
+ }
+ }
+
+ void logv(String msg) {
+ if (DBG) Rlog.v(TAG, msg);
+ }
+
+ void logd(String msg) {
+ if (DBG) Rlog.d(TAG, msg);
+ mLocalLog.log(msg);
+ }
+
+ @VisibleForTesting
+ static final int UNKNOWN_TAC = -1;
+ // Map with NetworkKey as the key and NetworkBandwidth as the value.
+ // NetworkKey is specified by the PLMN, data RAT and TAC of network.
+ // NetworkBandwidth represents the bandwidth related stats of each network.
+ private final Map<NetworkKey, NetworkBandwidth> mNetworkMap = new ArrayMap<>();
+ private static class NetworkKey {
+ private final String mPlmn;
+ private final String mDataRat;
+ private final int mTac;
+ NetworkKey(String plmn, int tac, String dataRat) {
+ mPlmn = plmn;
+ mTac = tac;
+ mDataRat = dataRat;
+ }
+ @Override
+ public boolean equals(@Nullable Object o) {
+ if (o == null || !(o instanceof NetworkKey) || hashCode() != o.hashCode()) {
+ return false;
+ }
+
+ if (this == o) {
+ return true;
+ }
+
+ NetworkKey that = (NetworkKey) o;
+ return mPlmn.equals(that.mPlmn)
+ && mTac == that.mTac
+ && mDataRat.equals(that.mDataRat);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mPlmn, mDataRat, mTac);
+ }
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ sb.append("Plmn").append(mPlmn)
+ .append("Rat").append(mDataRat)
+ .append("Tac").append(mTac)
+ .toString();
+ return sb.toString();
+ }
+ }
+
+ @NonNull
+ private NetworkBandwidth lookupNetwork(String plmn, String dataRat) {
+ return lookupNetwork(plmn, UNKNOWN_TAC, dataRat);
+ }
+
+ /** Look up NetworkBandwidth and create a new one if it doesn't exist */
+ @VisibleForTesting
+ @NonNull
+ public NetworkBandwidth lookupNetwork(String plmn, int tac, String dataRat) {
+ if (plmn == null || dataRat.equals(
+ TelephonyManager.getNetworkTypeName(TelephonyManager.NETWORK_TYPE_UNKNOWN))) {
+ return mPlaceholderNetwork;
+ }
+ NetworkKey key = new NetworkKey(plmn, tac, dataRat);
+ NetworkBandwidth ans = mNetworkMap.get(key);
+ if (ans == null) {
+ ans = new NetworkBandwidth(key.toString());
+ mNetworkMap.put(key, ans);
+ }
+ return ans;
+ }
+
+ /** A class holding link bandwidth related stats */
+ @VisibleForTesting
+ public class NetworkBandwidth {
+ private final String mKey;
+ NetworkBandwidth(String key) {
+ mKey = key;
+ }
+
+ /** Update link bandwidth stats */
+ public void update(long value, int link, int level) {
+ SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(
+ mPhone.getContext());
+ String valueKey = getValueKey(link, level);
+ String countKey = getCountKey(link, level);
+ SharedPreferences.Editor editor = sp.edit();
+ long currValue = sp.getLong(valueKey, 0);
+ int currCount = sp.getInt(countKey, 0);
+ editor.putLong(valueKey, currValue + value);
+ editor.putInt(countKey, currCount + 1);
+ editor.apply();
+ }
+
+ private String getValueKey(int link, int level) {
+ return getDataKey(link, level) + "Data";
+ }
+
+ private String getCountKey(int link, int level) {
+ return getDataKey(link, level) + "Count";
+ }
+
+ private String getDataKey(int link, int level) {
+ StringBuilder sb = new StringBuilder();
+ return sb.append(mKey)
+ .append("Link").append(link)
+ .append("Level").append(level)
+ .toString();
+ }
+
+ /** Get the accumulated bandwidth value */
+ public long getValue(int link, int level) {
+ SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(
+ mPhone.getContext());
+ String valueKey = getValueKey(link, level);
+ return sp.getLong(valueKey, 0);
+ }
+
+ /** Get the accumulated bandwidth count */
+ public int getCount(int link, int level) {
+ SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(
+ mPhone.getContext());
+ String countKey = getCountKey(link, level);
+ return sp.getInt(countKey, 0);
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ sb.append(mKey);
+ sb.append("\n");
+ for (int link = 0; link < NUM_LINK_DIRECTION; link++) {
+ sb.append((link == 0 ? "tx" : "rx"));
+ sb.append("\n avgKbps");
+ for (int level = 0; level < NUM_SIGNAL_LEVEL; level++) {
+ int count = getCount(link, level);
+ int avgKbps = count == 0 ? 0 : (int) (getValue(link, level) / count);
+ sb.append(" ").append(avgKbps);
+ }
+ sb.append("\n count");
+ for (int level = 0; level < NUM_SIGNAL_LEVEL; level++) {
+ int count = getCount(link, level);
+ sb.append(" ").append(count);
+ }
+ sb.append("\n");
+ }
+ return sb.toString();
+ }
+ }
+
+ /**
+ * Dump the internal state and local logs
+ */
+ public void dump(FileDescriptor fd, PrintWriter printWriter, String[] args) {
+ IndentingPrintWriter pw = new IndentingPrintWriter(printWriter, " ");
+ pw.increaseIndent();
+ pw.println("current PLMN " + mPlmn + " TAC " + mTac + " RAT " + getDataRatName(mDataRat));
+ pw.println("all networks visited since device boot");
+ for (NetworkBandwidth network : mNetworkMap.values()) {
+ pw.println(network.toString());
+ }
+
+ pw.println("Tx NRMSE");
+ for (BandwidthState.EstimationError err : mTxState.mErrorMap.values()) {
+ pw.println(err.toString());
+ }
+
+ pw.println("Rx NRMSE");
+ for (BandwidthState.EstimationError err : mRxState.mErrorMap.values()) {
+ pw.println(err.toString());
+ }
+
+ try {
+ mLocalLog.dump(fd, pw, args);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ pw.decreaseIndent();
+ pw.println();
+ pw.flush();
+ }
+
+}
diff --git a/src/java/com/android/internal/telephony/euicc/EuiccController.java b/src/java/com/android/internal/telephony/euicc/EuiccController.java
index 2d43271..2d81299 100644
--- a/src/java/com/android/internal/telephony/euicc/EuiccController.java
+++ b/src/java/com/android/internal/telephony/euicc/EuiccController.java
@@ -1293,7 +1293,10 @@
confirmationCodeRetried);
intent.putExtra(EXTRA_OPERATION, op);
PendingIntent resolutionIntent = PendingIntent.getActivity(
- mContext, 0 /* requestCode */, intent, PendingIntent.FLAG_ONE_SHOT);
+ mContext,
+ 0 /* requestCode */,
+ intent,
+ PendingIntent.FLAG_ONE_SHOT | PendingIntent.FLAG_MUTABLE);
extrasIntent.putExtra(
EuiccManager.EXTRA_EMBEDDED_SUBSCRIPTION_RESOLUTION_INTENT, resolutionIntent);
}
diff --git a/src/java/com/android/internal/telephony/gsm/GsmSMSDispatcher.java b/src/java/com/android/internal/telephony/gsm/GsmSMSDispatcher.java
index b113b5a..b3a8038 100644
--- a/src/java/com/android/internal/telephony/gsm/GsmSMSDispatcher.java
+++ b/src/java/com/android/internal/telephony/gsm/GsmSMSDispatcher.java
@@ -29,6 +29,7 @@
import com.android.internal.telephony.Phone;
import com.android.internal.telephony.SMSDispatcher;
import com.android.internal.telephony.SmsConstants;
+import com.android.internal.telephony.SmsController;
import com.android.internal.telephony.SmsDispatchersController;
import com.android.internal.telephony.SmsHeader;
import com.android.internal.telephony.SmsMessageBase;
@@ -156,7 +157,7 @@
+ " mMessageRef=" + tracker.mMessageRef
+ " mUsesImsServiceForIms=" + tracker.mUsesImsServiceForIms
+ " SS=" + ss
- + " id=" + tracker.mMessageId);
+ + " " + SmsController.formatCrossStackMessageId(tracker.mMessageId));
// if sms over IMS is not supported on data and voice is not available...
if (!isIms() && ss != ServiceState.STATE_IN_SERVICE) {
diff --git a/src/java/com/android/internal/telephony/ims/ImsResolver.java b/src/java/com/android/internal/telephony/ims/ImsResolver.java
index 5e30a7a..b717582 100644
--- a/src/java/com/android/internal/telephony/ims/ImsResolver.java
+++ b/src/java/com/android/internal/telephony/ims/ImsResolver.java
@@ -1522,7 +1522,7 @@
for (ResolveInfo entry : packageManager.queryIntentServicesAsUser(
serviceIntent,
PackageManager.GET_META_DATA,
- UserHandle.getUserHandleForUid(UserHandle.myUserId()))) {
+ UserHandle.of(UserHandle.myUserId()))) {
ServiceInfo serviceInfo = entry.serviceInfo;
if (serviceInfo != null) {
diff --git a/src/java/com/android/internal/telephony/ims/ImsServiceController.java b/src/java/com/android/internal/telephony/ims/ImsServiceController.java
index 82122db..c47d5b0 100644
--- a/src/java/com/android/internal/telephony/ims/ImsServiceController.java
+++ b/src/java/com/android/internal/telephony/ims/ImsServiceController.java
@@ -28,7 +28,7 @@
import android.os.IInterface;
import android.os.RemoteException;
import android.os.UserHandle;
-import android.permission.PermissionManager;
+import android.permission.LegacyPermissionManager;
import android.telephony.AnomalyReporter;
import android.telephony.ims.ImsService;
import android.telephony.ims.aidl.IImsConfig;
@@ -226,7 +226,7 @@
private static final boolean ENFORCE_SINGLE_SERVICE_FOR_SIP_TRANSPORT = false;
private final ComponentName mComponentName;
private final HandlerThread mHandlerThread = new HandlerThread("ImsServiceControllerHandler");
- private final PermissionManager mPermissionManager;
+ private final LegacyPermissionManager mPermissionManager;
private ImsFeatureBinderRepository mRepo;
private ImsServiceControllerCallbacks mCallbacks;
private ExponentialBackoff mBackoff;
@@ -324,8 +324,8 @@
2, /* multiplier */
mHandlerThread.getLooper(),
mRestartImsServiceRunnable);
- mPermissionManager =
- (PermissionManager) mContext.getSystemService(Context.PERMISSION_SERVICE);
+ mPermissionManager = (LegacyPermissionManager) mContext.getSystemService(
+ Context.LEGACY_PERMISSION_SERVICE);
mRepo = repo;
mPackageManager = mContext.getPackageManager();
diff --git a/src/java/com/android/internal/telephony/ims/MmTelFeatureCompatAdapter.java b/src/java/com/android/internal/telephony/ims/MmTelFeatureCompatAdapter.java
index 7b0619b..b343763 100644
--- a/src/java/com/android/internal/telephony/ims/MmTelFeatureCompatAdapter.java
+++ b/src/java/com/android/internal/telephony/ims/MmTelFeatureCompatAdapter.java
@@ -65,6 +65,8 @@
TelephonyManager.NETWORK_TYPE_LTE);
REG_TECH_TO_NET_TYPE.put(ImsRegistrationImplBase.REGISTRATION_TECH_IWLAN,
TelephonyManager.NETWORK_TYPE_IWLAN);
+ REG_TECH_TO_NET_TYPE.put(ImsRegistrationImplBase.REGISTRATION_TECH_CROSS_SIM,
+ TelephonyManager.NETWORK_TYPE_IWLAN);
}
// Feature Type for compatibility with old "feature" updates
@@ -516,7 +518,8 @@
Intent intent = new Intent(ImsManager.ACTION_IMS_INCOMING_CALL);
intent.setPackage(TelephonyManager.PHONE_PROCESS_NAME);
return PendingIntent.getBroadcast(mContext, 0, intent,
- PendingIntent.FLAG_UPDATE_CURRENT);
+ // Mutable because information associated with the call is passed back here.
+ PendingIntent.FLAG_MUTABLE | PendingIntent.FLAG_UPDATE_CURRENT);
}
private int convertCapability(int capability, int radioTech) {
diff --git a/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java b/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java
index bd68f66..d7aad9f 100755
--- a/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java
+++ b/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java
@@ -43,6 +43,7 @@
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
+import android.os.ParcelUuid;
import android.os.PersistableBundle;
import android.os.Registrant;
import android.os.RegistrantList;
@@ -61,6 +62,7 @@
import android.telephony.ServiceState;
import android.telephony.SubscriptionInfo;
import android.telephony.SubscriptionManager;
+import android.telephony.TelephonyLocalConnection;
import android.telephony.TelephonyManager;
import android.telephony.emergency.EmergencyNumber;
import android.telephony.ims.ImsCallProfile;
@@ -533,6 +535,8 @@
private boolean mAlwaysPlayRemoteHoldTone = false;
private boolean mAutoRetryFailedWifiEmergencyCall = false;
private boolean mSupportCepOnPeer = true;
+ private boolean mSupportD2DUsingRtp = false;
+ private boolean mSupportSdpForRtpHeaderExtensions = false;
// Tracks the state of our background/foreground calls while a call hold/swap operation is
// in progress. Values listed above.
private HoldSwapState mHoldSwitchingState = HoldSwapState.INACTIVE;
@@ -1026,16 +1030,7 @@
null);
}
- // Where device to device communication is available, ensure that the
- // supported RTP header extension types defined in {@link RtpTransport} are
- // set as the offered RTP header extensions for this device.
- if (mConfig != null && mConfig.isD2DCommunicationSupported) {
- ArraySet<RtpHeaderExtensionType> types = new ArraySet<>();
- types.add(RtpTransport.CALL_STATE_RTP_HEADER_EXTENSION_TYPE);
- types.add(RtpTransport.DEVICE_STATE_RTP_HEADER_EXTENSION_TYPE);
- logi("connectionReady: set offered RTP header extension types");
- mImsManager.setOfferedRtpHeaderExtensionTypes(types);
- }
+ maybeConfigureRtpHeaderExtensions();
if (mCarrierConfigLoaded) {
mImsManager.updateImsServiceConfig();
@@ -1044,6 +1039,32 @@
sendImsServiceStateIntent(ImsManager.ACTION_IMS_SERVICE_UP);
}
+ /**
+ * Configures RTP header extension types used during SDP negotiation.
+ */
+ private void maybeConfigureRtpHeaderExtensions() {
+ // Where device to device communication is available, ensure that the
+ // supported RTP header extension types defined in {@link RtpTransport} are
+ // set as the offered RTP header extensions for this device.
+ if (mConfig != null && mConfig.isD2DCommunicationSupported && mSupportD2DUsingRtp) {
+ ArraySet<RtpHeaderExtensionType> types = new ArraySet<>();
+ if (mSupportSdpForRtpHeaderExtensions) {
+ types.add(RtpTransport.CALL_STATE_RTP_HEADER_EXTENSION_TYPE);
+ types.add(RtpTransport.DEVICE_STATE_RTP_HEADER_EXTENSION_TYPE);
+ logi("maybeConfigureRtpHeaderExtensions: set offered RTP header extension types");
+
+ } else {
+ logi("maybeConfigureRtpHeaderExtensions: SDP negotiation not supported; not "
+ + "setting offered RTP header extension types");
+ }
+ try {
+ mImsManager.setOfferedRtpHeaderExtensionTypes(types);
+ } catch (ImsException e) {
+ loge("maybeConfigureRtpHeaderExtensions: failed to set extensions; " + e);
+ }
+ }
+ }
+
private void stopListeningForCalls() {
log("stopListeningForCalls");
mOperationLocalLog.log("stopListeningForCalls - Disconnecting from ImsService");
@@ -1437,6 +1458,8 @@
if (mImsManager != null) {
mImsManager.updateImsServiceConfig();
}
+ // Check for changes due to carrier config.
+ maybeConfigureRtpHeaderExtensions();
}
/**
@@ -1480,6 +1503,11 @@
CarrierConfigManager.KEY_AUTO_RETRY_FAILED_WIFI_EMERGENCY_CALL);
mSupportCepOnPeer = carrierConfig.getBoolean(
CarrierConfigManager.KEY_SUPPORT_IMS_CONFERENCE_EVENT_PACKAGE_ON_PEER_BOOL);
+ mSupportD2DUsingRtp = carrierConfig.getBoolean(
+ CarrierConfigManager.KEY_SUPPORTS_DEVICE_TO_DEVICE_COMMUNICATION_USING_RTP_BOOL);
+ mSupportSdpForRtpHeaderExtensions = carrierConfig.getBoolean(
+ CarrierConfigManager
+ .KEY_SUPPORTS_SDP_NEGOTIATION_OF_D2D_RTP_HEADER_EXTENSIONS_BOOL);
if (mPhone.getContext().getResources().getBoolean(
com.android.internal.R.bool.config_allow_ussd_over_ims)) {
@@ -1565,6 +1593,9 @@
ImsCallProfile profile = mImsManager.createCallProfile(serviceType, callType);
if (conn.isAdhocConference()) {
profile.setCallExtraBoolean(ImsCallProfile.EXTRA_CONFERENCE, true);
+ // Also set value for EXTRA_CONFERENCE_DEPRECATED in case receivers are using old
+ // values.
+ profile.setCallExtraBoolean(ImsCallProfile.EXTRA_CONFERENCE_DEPRECATED, true);
}
profile.setCallExtraInt(ImsCallProfile.EXTRA_OIR, clirMode);
profile.setCallExtraInt(ImsCallProfile.EXTRA_RETRY_CALL_FAIL_REASON,
@@ -1600,7 +1631,10 @@
if (intentExtras.containsKey(
android.telecom.TelecomManager.EXTRA_OUTGOING_PICTURE)) {
- // TODO(hallliu) Set ImsCallProfile.EXTRA_PICTURE_URL with cached URL string
+ String url = TelephonyLocalConnection.getCallComposerServerUrlForHandle(
+ mPhone.getSubId(), ((ParcelUuid) intentExtras.getParcelable(
+ TelecomManager.EXTRA_OUTGOING_PICTURE)).getUuid());
+ profile.setCallExtra(ImsCallProfile.EXTRA_PICTURE_URL, url);
}
if (conn.hasRttTextStream()) {
@@ -2691,6 +2725,7 @@
return DisconnectCause.TIMED_OUT;
case ImsReasonInfo.CODE_LOCAL_POWER_OFF:
+ case ImsReasonInfo.CODE_RADIO_OFF:
return DisconnectCause.POWER_OFF;
case ImsReasonInfo.CODE_LOCAL_LOW_BATTERY:
@@ -3081,6 +3116,7 @@
if (conn != null) {
conn.setPreciseDisconnectCause(getPreciseDisconnectCauseFromReasonInfo(reasonInfo));
+ conn.setImsReasonInfo(reasonInfo);
}
if (reasonInfo.getCode() == ImsReasonInfo.CODE_SIP_ALTERNATE_EMERGENCY_CALL
@@ -3761,6 +3797,15 @@
}
cqm.saveCallQuality(callQuality);
mCallQualityMetrics.put(callId, cqm);
+
+ ImsPhoneConnection conn = findConnection(imsCall);
+ if (conn != null) {
+ Bundle report = new Bundle();
+ report.putParcelable(android.telecom.Connection.EXTRA_CALL_QUALITY_REPORT,
+ callQuality);
+ conn.onConnectionEvent(android.telecom.Connection.EVENT_CALL_QUALITY_REPORT,
+ report);
+ }
}
/**
@@ -4394,6 +4439,11 @@
pw.println(" mSupportCepOnPeer=" + mSupportCepOnPeer);
if (mConfig != null) {
pw.println(" isDeviceToDeviceCommsSupported= " + mConfig.isD2DCommunicationSupported);
+ if (mConfig.isD2DCommunicationSupported) {
+ pw.println(" mSupportD2DUsingRtp= " + mSupportD2DUsingRtp);
+ pw.println(" mSupportSdpForRtpHeaderExtensions= "
+ + mSupportSdpForRtpHeaderExtensions);
+ }
}
pw.println(" Event Log:");
pw.increaseIndent();
@@ -4457,7 +4507,10 @@
public boolean isVowifiEnabled() {
return isImsCapabilityInCacheAvailable(MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VOICE,
- ImsRegistrationImplBase.REGISTRATION_TECH_IWLAN);
+ ImsRegistrationImplBase.REGISTRATION_TECH_IWLAN)
+ || isImsCapabilityInCacheAvailable(
+ MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VOICE,
+ ImsRegistrationImplBase.REGISTRATION_TECH_CROSS_SIM);
}
public boolean isVideoCallEnabled() {
diff --git a/src/java/com/android/internal/telephony/imsphone/ImsPhoneCommandInterface.java b/src/java/com/android/internal/telephony/imsphone/ImsPhoneCommandInterface.java
index f2f8738..1371c92 100644
--- a/src/java/com/android/internal/telephony/imsphone/ImsPhoneCommandInterface.java
+++ b/src/java/com/android/internal/telephony/imsphone/ImsPhoneCommandInterface.java
@@ -26,7 +26,7 @@
import android.telephony.SignalThresholdInfo;
import android.telephony.TelephonyManager;
import android.telephony.data.DataProfile;
-import android.telephony.data.SliceInfo;
+import android.telephony.data.NetworkSliceInfo;
import android.telephony.data.TrafficDescriptor;
import android.telephony.emergency.EmergencyNumber;
@@ -286,8 +286,8 @@
@Override
public void setupDataCall(int accessNetworkType, DataProfile dataProfile, boolean isRoaming,
boolean allowRoaming, int reason, LinkProperties linkProperties, int pduSessionId,
- SliceInfo sliceInfo, TrafficDescriptor trafficDescriptor, boolean matchAllRuleAllowed,
- Message result) {
+ NetworkSliceInfo sliceInfo, TrafficDescriptor trafficDescriptor,
+ boolean matchAllRuleAllowed, Message result) {
}
@Override
diff --git a/src/java/com/android/internal/telephony/imsphone/ImsPhoneConnection.java b/src/java/com/android/internal/telephony/imsphone/ImsPhoneConnection.java
index e9f17ab..8403fc9 100755
--- a/src/java/com/android/internal/telephony/imsphone/ImsPhoneConnection.java
+++ b/src/java/com/android/internal/telephony/imsphone/ImsPhoneConnection.java
@@ -17,6 +17,7 @@
package com.android.internal.telephony.imsphone;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.Context;
import android.net.Uri;
@@ -39,6 +40,7 @@
import android.telephony.TelephonyManager;
import android.telephony.ims.AudioCodecAttributes;
import android.telephony.ims.ImsCallProfile;
+import android.telephony.ims.ImsReasonInfo;
import android.telephony.ims.ImsStreamMediaProfile;
import android.telephony.ims.RtpHeaderExtension;
import android.telephony.ims.RtpHeaderExtensionType;
@@ -141,6 +143,12 @@
*/
private boolean mIsLocalVideoCapable = true;
+ /**
+ * When the call is in a disconnected, state, will be set to the {@link ImsReasonInfo}
+ * associated with the disconnection, if known.
+ */
+ private ImsReasonInfo mImsReasonInfo;
+
//***** Event Constants
private static final int EVENT_DTMF_DONE = 1;
private static final int EVENT_PAUSE_DONE = 2;
@@ -1420,6 +1428,14 @@
}
/**
+ * Indicates whether current phone connection is cross sim calling or not
+ * @return boolean: true if cross sim calling, false otherwise
+ */
+ public boolean isCrossSimCall() {
+ return mImsCall != null && mImsCall.isCrossSimCall();
+ }
+
+ /**
* Handles notifications from the {@link ImsVideoCallProviderWrapper} of session modification
* responses received.
*
@@ -1568,6 +1584,23 @@
}
/**
+ * For a connection being disconnected, sets the {@link ImsReasonInfo} which describes the
+ * reason for the disconnection.
+ * @param imsReasonInfo The IMS reason info.
+ */
+ public void setImsReasonInfo(@Nullable ImsReasonInfo imsReasonInfo) {
+ mImsReasonInfo = imsReasonInfo;
+ }
+
+ /**
+ * @return the {@link ImsReasonInfo} describing why this connection disconnected, or
+ * {@code null} otherwise.
+ */
+ public @Nullable ImsReasonInfo getImsReasonInfo() {
+ return mImsReasonInfo;
+ }
+
+ /**
* Converts an {@link ImsCallProfile} verification status to a
* {@link android.telecom.Connection} verification status.
* @param verificationStatus The {@link ImsCallProfile} verification status.
diff --git a/src/java/com/android/internal/telephony/imsphone/ImsPhoneMmiCode.java b/src/java/com/android/internal/telephony/imsphone/ImsPhoneMmiCode.java
index e0f2ff1..2a437f7 100644
--- a/src/java/com/android/internal/telephony/imsphone/ImsPhoneMmiCode.java
+++ b/src/java/com/android/internal/telephony/imsphone/ImsPhoneMmiCode.java
@@ -1382,7 +1382,8 @@
} else if (ar.exception instanceof ImsException) {
sb.append(getImsErrorMessage(ar));
}
- } else if (ar.result != null && (int) ar.result == CommandsInterface.SS_STATUS_UNKNOWN) {
+ } else if (ar.result != null && ar.result instanceof Integer
+ && (int) ar.result == CommandsInterface.SS_STATUS_UNKNOWN) {
mState = State.FAILED;
sb = null;
} else if (isActivate()) {
diff --git a/src/java/com/android/internal/telephony/metrics/DataStallRecoveryStats.java b/src/java/com/android/internal/telephony/metrics/DataStallRecoveryStats.java
index 9074a7b..410afcf 100644
--- a/src/java/com/android/internal/telephony/metrics/DataStallRecoveryStats.java
+++ b/src/java/com/android/internal/telephony/metrics/DataStallRecoveryStats.java
@@ -36,7 +36,7 @@
* @param phone
*/
public static void onDataStallEvent(@DcTracker.RecoveryAction int recoveryAction,
- Phone phone) {
+ Phone phone, boolean isRecovered, int durationMillis) {
if (phone.getPhoneType() == PhoneConstants.PHONE_TYPE_IMS) {
phone = phone.getDefaultPhone();
}
@@ -50,7 +50,8 @@
boolean isMultiSim = SimSlotState.getCurrentState().numActiveSims > 1;
TelephonyStatsLog.write(TelephonyStatsLog.DATA_STALL_RECOVERY_REPORTED, carrierId, rat,
- signalStrength, recoveryAction, isOpportunistic, isMultiSim, band);
+ signalStrength, recoveryAction, isOpportunistic, isMultiSim, band, isRecovered,
+ durationMillis);
}
/** Returns the RAT used for data (including IWLAN). */
diff --git a/src/java/com/android/internal/telephony/metrics/MetricsCollector.java b/src/java/com/android/internal/telephony/metrics/MetricsCollector.java
index ce01b7e..6cbfefa 100644
--- a/src/java/com/android/internal/telephony/metrics/MetricsCollector.java
+++ b/src/java/com/android/internal/telephony/metrics/MetricsCollector.java
@@ -41,6 +41,7 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.telephony.Phone;
import com.android.internal.telephony.PhoneFactory;
+import com.android.internal.telephony.TelephonyStatsLog;
import com.android.internal.telephony.imsphone.ImsPhone;
import com.android.internal.telephony.nano.PersistAtomsProto.CellularDataServiceSwitch;
import com.android.internal.telephony.nano.PersistAtomsProto.CellularServiceState;
@@ -186,14 +187,12 @@
return StatsManager.PULL_SKIP;
}
- StatsEvent e =
- StatsEvent.newBuilder()
- .setAtomId(SIM_SLOT_STATE)
- .writeInt(state.numActiveSlots)
- .writeInt(state.numActiveSims)
- .writeInt(state.numActiveEsims)
- .build();
- data.add(e);
+ data.add(
+ TelephonyStatsLog.buildStatsEvent(
+ SIM_SLOT_STATE,
+ state.numActiveSlots,
+ state.numActiveSims,
+ state.numActiveEsims));
return StatsManager.PULL_SUCCESS;
}
@@ -209,12 +208,7 @@
rafSupported |= phone.getRadioAccessFamily();
}
- StatsEvent e =
- StatsEvent.newBuilder()
- .setAtomId(SUPPORTED_RADIO_ACCESS_FAMILY)
- .writeLong(rafSupported)
- .build();
- data.add(e);
+ data.add(TelephonyStatsLog.buildStatsEvent(SUPPORTED_RADIO_ACCESS_FAMILY, rafSupported));
return StatsManager.PULL_SUCCESS;
}
@@ -226,11 +220,7 @@
// All phones should have the same version of the carrier ID table, so only query the
// first one.
int version = phones[0].getCarrierIdListVersion();
- data.add(
- StatsEvent.newBuilder()
- .setAtomId(CARRIER_ID_TABLE_VERSION)
- .writeInt(version)
- .build());
+ data.add(TelephonyStatsLog.buildStatsEvent(CARRIER_ID_TABLE_VERSION, version));
return StatsManager.PULL_SUCCESS;
}
}
@@ -379,208 +369,171 @@
}
private static StatsEvent buildStatsEvent(CellularDataServiceSwitch serviceSwitch) {
- return StatsEvent.newBuilder()
- .setAtomId(CELLULAR_DATA_SERVICE_SWITCH)
- .writeInt(serviceSwitch.ratFrom)
- .writeInt(serviceSwitch.ratTo)
- .writeInt(serviceSwitch.simSlotIndex)
- .writeBoolean(serviceSwitch.isMultiSim)
- .writeInt(serviceSwitch.carrierId)
- .writeInt(serviceSwitch.switchCount)
- .build();
+ return TelephonyStatsLog.buildStatsEvent(
+ CELLULAR_DATA_SERVICE_SWITCH,
+ serviceSwitch.ratFrom,
+ serviceSwitch.ratTo,
+ serviceSwitch.simSlotIndex,
+ serviceSwitch.isMultiSim,
+ serviceSwitch.carrierId,
+ serviceSwitch.switchCount);
}
private static StatsEvent buildStatsEvent(CellularServiceState state) {
- return StatsEvent.newBuilder()
- .setAtomId(CELLULAR_SERVICE_STATE)
- .writeInt(state.voiceRat)
- .writeInt(state.dataRat)
- .writeInt(state.voiceRoamingType)
- .writeInt(state.dataRoamingType)
- .writeBoolean(state.isEndc)
- .writeInt(state.simSlotIndex)
- .writeBoolean(state.isMultiSim)
- .writeInt(state.carrierId)
- .writeInt(
- (int)
- (round(state.totalTimeMillis, DURATION_BUCKET_MILLIS)
- / SECOND_IN_MILLIS))
- .build();
+ return TelephonyStatsLog.buildStatsEvent(
+ CELLULAR_SERVICE_STATE,
+ state.voiceRat,
+ state.dataRat,
+ state.voiceRoamingType,
+ state.dataRoamingType,
+ state.isEndc,
+ state.simSlotIndex,
+ state.isMultiSim,
+ state.carrierId,
+ (int) (round(state.totalTimeMillis, DURATION_BUCKET_MILLIS) / SECOND_IN_MILLIS));
}
private static StatsEvent buildStatsEvent(VoiceCallRatUsage usage) {
- return StatsEvent.newBuilder()
- .setAtomId(VOICE_CALL_RAT_USAGE)
- .writeInt(usage.carrierId)
- .writeInt(usage.rat)
- .writeLong(
- round(usage.totalDurationMillis, DURATION_BUCKET_MILLIS) / SECOND_IN_MILLIS)
- .writeLong(usage.callCount)
- .build();
+ return TelephonyStatsLog.buildStatsEvent(
+ VOICE_CALL_RAT_USAGE,
+ usage.carrierId,
+ usage.rat,
+ round(usage.totalDurationMillis, DURATION_BUCKET_MILLIS) / SECOND_IN_MILLIS,
+ usage.callCount);
}
private static StatsEvent buildStatsEvent(VoiceCallSession session) {
- return StatsEvent.newBuilder()
- .setAtomId(VOICE_CALL_SESSION)
- .writeInt(session.bearerAtStart)
- .writeInt(session.bearerAtEnd)
- .writeInt(session.direction)
- .writeInt(session.setupDuration)
- .writeBoolean(session.setupFailed)
- .writeInt(session.disconnectReasonCode)
- .writeInt(session.disconnectExtraCode)
- .writeString(session.disconnectExtraMessage)
- .writeInt(session.ratAtStart)
- .writeInt(session.ratAtEnd)
- .writeLong(session.ratSwitchCount)
- .writeLong(session.codecBitmask)
- .writeInt(session.concurrentCallCountAtStart)
- .writeInt(session.concurrentCallCountAtEnd)
- .writeInt(session.simSlotIndex)
- .writeBoolean(session.isMultiSim)
- .writeBoolean(session.isEsim)
- .writeInt(session.carrierId)
- .writeBoolean(session.srvccCompleted)
- .writeLong(session.srvccFailureCount)
- .writeLong(session.srvccCancellationCount)
- .writeBoolean(session.rttEnabled)
- .writeBoolean(session.isEmergency)
- .writeBoolean(session.isRoaming)
+ return TelephonyStatsLog.buildStatsEvent(
+ VOICE_CALL_SESSION,
+ session.bearerAtStart,
+ session.bearerAtEnd,
+ session.direction,
+ session.setupDuration,
+ session.setupFailed,
+ session.disconnectReasonCode,
+ session.disconnectExtraCode,
+ session.disconnectExtraMessage,
+ session.ratAtStart,
+ session.ratAtEnd,
+ session.ratSwitchCount,
+ session.codecBitmask,
+ session.concurrentCallCountAtStart,
+ session.concurrentCallCountAtEnd,
+ session.simSlotIndex,
+ session.isMultiSim,
+ session.isEsim,
+ session.carrierId,
+ session.srvccCompleted,
+ session.srvccFailureCount,
+ session.srvccCancellationCount,
+ session.rttEnabled,
+ session.isEmergency,
+ session.isRoaming,
// workaround: dimension required for keeping multiple pulled atoms
- .writeInt(sRandom.nextInt())
+ sRandom.nextInt(),
// New fields introduced in Android S
- .writeInt(session.signalStrengthAtEnd)
- .writeInt(session.bandAtEnd)
- .writeInt(session.setupDurationMillis)
- .writeInt(session.mainCodecQuality)
- .writeBoolean(session.videoEnabled)
- .writeInt(session.ratAtConnected)
- .writeBoolean(session.isMultiparty)
- .build();
+ session.signalStrengthAtEnd,
+ session.bandAtEnd,
+ session.setupDurationMillis,
+ session.mainCodecQuality,
+ session.videoEnabled,
+ session.ratAtConnected,
+ session.isMultiparty);
}
private static StatsEvent buildStatsEvent(IncomingSms sms) {
- return StatsEvent.newBuilder()
- .setAtomId(INCOMING_SMS)
- .writeInt(sms.smsFormat)
- .writeInt(sms.smsTech)
- .writeInt(sms.rat)
- .writeInt(sms.smsType)
- .writeInt(sms.totalParts)
- .writeInt(sms.receivedParts)
- .writeBoolean(sms.blocked)
- .writeInt(sms.error)
- .writeBoolean(sms.isRoaming)
- .writeInt(sms.simSlotIndex)
- .writeBoolean(sms.isMultiSim)
- .writeBoolean(sms.isEsim)
- .writeInt(sms.carrierId)
- .writeLong(sms.messageId)
- .build();
+ return TelephonyStatsLog.buildStatsEvent(
+ INCOMING_SMS,
+ sms.smsFormat,
+ sms.smsTech,
+ sms.rat,
+ sms.smsType,
+ sms.totalParts,
+ sms.receivedParts,
+ sms.blocked,
+ sms.error,
+ sms.isRoaming,
+ sms.simSlotIndex,
+ sms.isMultiSim,
+ sms.isEsim,
+ sms.carrierId,
+ sms.messageId);
}
private static StatsEvent buildStatsEvent(OutgoingSms sms) {
- return StatsEvent.newBuilder()
- .setAtomId(OUTGOING_SMS)
- .writeInt(sms.smsFormat)
- .writeInt(sms.smsTech)
- .writeInt(sms.rat)
- .writeInt(sms.sendResult)
- .writeInt(sms.errorCode)
- .writeBoolean(sms.isRoaming)
- .writeBoolean(sms.isFromDefaultApp)
- .writeInt(sms.simSlotIndex)
- .writeBoolean(sms.isMultiSim)
- .writeBoolean(sms.isEsim)
- .writeInt(sms.carrierId)
- .writeLong(sms.messageId)
- .writeInt(sms.retryId)
- .build();
+ return TelephonyStatsLog.buildStatsEvent(
+ OUTGOING_SMS,
+ sms.smsFormat,
+ sms.smsTech,
+ sms.rat,
+ sms.sendResult,
+ sms.errorCode,
+ sms.isRoaming,
+ sms.isFromDefaultApp,
+ sms.simSlotIndex,
+ sms.isMultiSim,
+ sms.isEsim,
+ sms.carrierId,
+ sms.messageId,
+ sms.retryId);
}
private static StatsEvent buildStatsEvent(DataCallSession dataCallSession) {
- return StatsEvent.newBuilder()
- .setAtomId(DATA_CALL_SESSION)
- .writeInt(dataCallSession.dimension)
- .writeBoolean(dataCallSession.isMultiSim)
- .writeBoolean(dataCallSession.isEsim)
- .writeInt(0) // profile is deprecated, so we default to 0
- .writeInt(dataCallSession.apnTypeBitmask)
- .writeInt(dataCallSession.carrierId)
- .writeBoolean(dataCallSession.isRoaming)
- .writeInt(dataCallSession.ratAtEnd)
- .writeBoolean(dataCallSession.oosAtEnd)
- .writeLong(dataCallSession.ratSwitchCount)
- .writeBoolean(dataCallSession.isOpportunistic)
- .writeInt(dataCallSession.ipType)
- .writeBoolean(dataCallSession.setupFailed)
- .writeInt(dataCallSession.failureCause)
- .writeInt(dataCallSession.suggestedRetryMillis)
- .writeInt(dataCallSession.deactivateReason)
- .writeLong(round(
- dataCallSession.durationMinutes, DURATION_BUCKET_MILLIS / MINUTE_IN_MILLIS))
- .writeBoolean(dataCallSession.ongoing)
- .writeInt(dataCallSession.bandAtEnd)
- .build();
+ return TelephonyStatsLog.buildStatsEvent(
+ DATA_CALL_SESSION,
+ dataCallSession.dimension,
+ dataCallSession.isMultiSim,
+ dataCallSession.isEsim,
+ 0, // profile is deprecated, so we default to 0
+ dataCallSession.apnTypeBitmask,
+ dataCallSession.carrierId,
+ dataCallSession.isRoaming,
+ dataCallSession.ratAtEnd,
+ dataCallSession.oosAtEnd,
+ dataCallSession.ratSwitchCount,
+ dataCallSession.isOpportunistic,
+ dataCallSession.ipType,
+ dataCallSession.setupFailed,
+ dataCallSession.failureCause,
+ dataCallSession.suggestedRetryMillis,
+ dataCallSession.deactivateReason,
+ round(dataCallSession.durationMinutes, DURATION_BUCKET_MILLIS / MINUTE_IN_MILLIS),
+ dataCallSession.ongoing,
+ dataCallSession.bandAtEnd);
}
private static StatsEvent buildStatsEvent(ImsRegistrationStats stats) {
- return StatsEvent.newBuilder()
- .setAtomId(IMS_REGISTRATION_STATS)
- .writeInt(stats.carrierId)
- .writeInt(stats.simSlotIndex)
- .writeInt(stats.rat)
- .writeInt(
- (int)
- (round(stats.registeredMillis, DURATION_BUCKET_MILLIS)
- / SECOND_IN_MILLIS))
- .writeInt(
- (int)
- (round(stats.voiceCapableMillis, DURATION_BUCKET_MILLIS)
- / SECOND_IN_MILLIS))
- .writeInt(
- (int)
- (round(stats.voiceAvailableMillis, DURATION_BUCKET_MILLIS)
- / SECOND_IN_MILLIS))
- .writeInt(
- (int)
- (round(stats.smsCapableMillis, DURATION_BUCKET_MILLIS)
- / SECOND_IN_MILLIS))
- .writeInt(
- (int)
- (round(stats.smsAvailableMillis, DURATION_BUCKET_MILLIS)
- / SECOND_IN_MILLIS))
- .writeInt(
- (int)
- (round(stats.videoCapableMillis, DURATION_BUCKET_MILLIS)
- / SECOND_IN_MILLIS))
- .writeInt(
- (int)
- (round(stats.videoAvailableMillis, DURATION_BUCKET_MILLIS)
- / SECOND_IN_MILLIS))
- .writeInt(
- (int)
- (round(stats.utCapableMillis, DURATION_BUCKET_MILLIS)
- / SECOND_IN_MILLIS))
- .writeInt(
- (int)
- (round(stats.utAvailableMillis, DURATION_BUCKET_MILLIS)
- / SECOND_IN_MILLIS))
- .build();
+ return TelephonyStatsLog.buildStatsEvent(
+ IMS_REGISTRATION_STATS,
+ stats.carrierId,
+ stats.simSlotIndex,
+ stats.rat,
+ (int) (round(stats.registeredMillis, DURATION_BUCKET_MILLIS) / SECOND_IN_MILLIS),
+ (int) (round(stats.voiceCapableMillis, DURATION_BUCKET_MILLIS) / SECOND_IN_MILLIS),
+ (int)
+ (round(stats.voiceAvailableMillis, DURATION_BUCKET_MILLIS)
+ / SECOND_IN_MILLIS),
+ (int) (round(stats.smsCapableMillis, DURATION_BUCKET_MILLIS) / SECOND_IN_MILLIS),
+ (int) (round(stats.smsAvailableMillis, DURATION_BUCKET_MILLIS) / SECOND_IN_MILLIS),
+ (int) (round(stats.videoCapableMillis, DURATION_BUCKET_MILLIS) / SECOND_IN_MILLIS),
+ (int)
+ (round(stats.videoAvailableMillis, DURATION_BUCKET_MILLIS)
+ / SECOND_IN_MILLIS),
+ (int) (round(stats.utCapableMillis, DURATION_BUCKET_MILLIS) / SECOND_IN_MILLIS),
+ (int) (round(stats.utAvailableMillis, DURATION_BUCKET_MILLIS) / SECOND_IN_MILLIS));
}
private static StatsEvent buildStatsEvent(ImsRegistrationTermination termination) {
- return StatsEvent.newBuilder()
- .setAtomId(IMS_REGISTRATION_TERMINATION)
- .writeInt(termination.carrierId)
- .writeBoolean(termination.isMultiSim)
- .writeInt(termination.ratAtEnd)
- .writeBoolean(termination.setupFailed)
- .writeInt(termination.reasonCode)
- .writeInt(termination.extraCode)
- .writeString(termination.extraMessage)
- .writeInt(termination.count)
- .build();
+ return TelephonyStatsLog.buildStatsEvent(
+ IMS_REGISTRATION_TERMINATION,
+ termination.carrierId,
+ termination.isMultiSim,
+ termination.ratAtEnd,
+ termination.setupFailed,
+ termination.reasonCode,
+ termination.extraCode,
+ termination.extraMessage,
+ termination.count);
}
/** Returns all phones in {@link PhoneFactory}, or an empty array if phones not made yet. */
diff --git a/src/java/com/android/internal/telephony/metrics/ModemPowerMetrics.java b/src/java/com/android/internal/telephony/metrics/ModemPowerMetrics.java
index 67816c9..ad27acb 100644
--- a/src/java/com/android/internal/telephony/metrics/ModemPowerMetrics.java
+++ b/src/java/com/android/internal/telephony/metrics/ModemPowerMetrics.java
@@ -71,7 +71,7 @@
m.rxTimeMs = stats.getRxTimeMillis();
List<Long> txTimeMillis = new ArrayList<>();
- for (int i = 0; i < ModemActivityInfo.TX_POWER_LEVELS; i++) {
+ for (int i = 0; i < ModemActivityInfo.getNumTxPowerLevels(); i++) {
long t = stats.getTxTimeMillis(i);
if (t >= 0) {
txTimeMillis.add(t);
diff --git a/src/java/com/android/internal/telephony/metrics/TelephonyMetrics.java b/src/java/com/android/internal/telephony/metrics/TelephonyMetrics.java
index 9487a13..d1e7ad2 100644
--- a/src/java/com/android/internal/telephony/metrics/TelephonyMetrics.java
+++ b/src/java/com/android/internal/telephony/metrics/TelephonyMetrics.java
@@ -78,6 +78,7 @@
import com.android.internal.telephony.PhoneConstants;
import com.android.internal.telephony.RIL;
import com.android.internal.telephony.RILConstants;
+import com.android.internal.telephony.SmsController;
import com.android.internal.telephony.SmsResponse;
import com.android.internal.telephony.UUSInfo;
import com.android.internal.telephony.emergency.EmergencyNumberTracker;
@@ -1872,7 +1873,7 @@
SmsSession.Event.Type.SMS_SEND_RESULT)
.setImsServiceErrno(resultCode)
.setErrorCode(errorReason)
- .setMessageId((messageId))
+ .setMessageId(messageId)
);
smsSession.decreaseExpectedResponse();
@@ -2441,7 +2442,7 @@
+ " parts, source = " + smsSource
+ " blocked = " + blocked
+ " type = " + type
- + " messageId = " + messageId);
+ + " " + SmsController.formatCrossStackMessageId(messageId));
int smsFormat = convertSmsFormat(format);
int smsError =
diff --git a/src/java/com/android/internal/telephony/sip/SipCommandInterface.java b/src/java/com/android/internal/telephony/sip/SipCommandInterface.java
index 342ddb8..f3c1839 100644
--- a/src/java/com/android/internal/telephony/sip/SipCommandInterface.java
+++ b/src/java/com/android/internal/telephony/sip/SipCommandInterface.java
@@ -26,7 +26,7 @@
import android.telephony.SignalThresholdInfo;
import android.telephony.TelephonyManager;
import android.telephony.data.DataProfile;
-import android.telephony.data.SliceInfo;
+import android.telephony.data.NetworkSliceInfo;
import android.telephony.data.TrafficDescriptor;
import android.telephony.emergency.EmergencyNumber;
@@ -287,8 +287,8 @@
@Override
public void setupDataCall(int accessNetworkType, DataProfile dataProfile, boolean isRoaming,
boolean allowRoaming, int reason, LinkProperties linkProperties, int pduSessionId,
- SliceInfo sliceInfo, TrafficDescriptor trafficDescriptor, boolean matchAllRuleAllowed,
- Message result) {
+ NetworkSliceInfo sliceInfo, TrafficDescriptor trafficDescriptor,
+ boolean matchAllRuleAllowed, Message result) {
}
@Override
diff --git a/tests/telephonytests/src/android/telephony/ims/ImsFeatureTest.java b/tests/telephonytests/src/android/telephony/ims/ImsFeatureTest.java
index 319d200..80167d6 100644
--- a/tests/telephonytests/src/android/telephony/ims/ImsFeatureTest.java
+++ b/tests/telephonytests/src/android/telephony/ims/ImsFeatureTest.java
@@ -248,6 +248,8 @@
// add some capabilities
request.addCapabilitiesToEnableForTech(MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VOICE,
ImsRegistrationImplBase.REGISTRATION_TECH_IWLAN);
+ request.addCapabilitiesToEnableForTech(MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VOICE,
+ ImsRegistrationImplBase.REGISTRATION_TECH_CROSS_SIM);
request.addCapabilitiesToEnableForTech(
MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VIDEO
| MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VOICE,
diff --git a/tests/telephonytests/src/com/android/internal/telephony/CellularNetworkValidatorTest.java b/tests/telephonytests/src/com/android/internal/telephony/CellularNetworkValidatorTest.java
index 0601384..2c1e18b 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/CellularNetworkValidatorTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/CellularNetworkValidatorTest.java
@@ -57,9 +57,9 @@
public class CellularNetworkValidatorTest extends TelephonyTest {
private CellularNetworkValidator mValidatorUT;
private static final PhoneCapability CAPABILITY_WITH_VALIDATION_SUPPORTED =
- new PhoneCapability(1, 1, 0, null, true);
+ new PhoneCapability(1, 1, null, true, new int[0]);
private static final PhoneCapability CAPABILITY_WITHOUT_VALIDATION_SUPPORTED =
- new PhoneCapability(1, 1, 0, null, false);
+ new PhoneCapability(1, 1, null, false, new int[0]);
private final CellIdentityLte mCellIdentityLte1 = new CellIdentityLte(123, 456, 0, 0, 111);
private final CellIdentityLte mCellIdentityLte2 = new CellIdentityLte(321, 654, 0, 0, 222);
@Mock
diff --git a/tests/telephonytests/src/com/android/internal/telephony/ContextFixture.java b/tests/telephonytests/src/com/android/internal/telephony/ContextFixture.java
index b34807d..b96056a 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/ContextFixture.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/ContextFixture.java
@@ -33,6 +33,7 @@
import android.app.DownloadManager;
import android.app.KeyguardManager;
import android.app.NotificationManager;
+import android.app.UiModeManager;
import android.app.usage.UsageStatsManager;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
@@ -82,6 +83,7 @@
import android.test.mock.MockContentProvider;
import android.test.mock.MockContentResolver;
import android.test.mock.MockContext;
+import android.util.DisplayMetrics;
import android.util.Log;
import com.google.common.collect.ArrayListMultimap;
@@ -271,6 +273,7 @@
case Context.DISPLAY_SERVICE:
case Context.POWER_SERVICE:
case Context.PERMISSION_SERVICE:
+ case Context.LEGACY_PERMISSION_SERVICE:
// These are final classes so cannot be mocked,
// return real services.
return TestApplication.getAppContext().getSystemService(name);
@@ -299,18 +302,20 @@
return Context.POWER_WHITELIST_MANAGER;
} else if (serviceClass == SystemConfigManager.class) {
return Context.SYSTEM_CONFIG_SERVICE;
- } else if (serviceClass == CarrierConfigManager.class){
- return Context.CARRIER_CONFIG_SERVICE;
} else if (serviceClass == ActivityManager.class) {
return Context.ACTIVITY_SERVICE;
+ } else if (serviceClass == LocationManager.class) {
+ return Context.LOCATION_SERVICE;
+ } else if (serviceClass == CarrierConfigManager.class) {
+ return Context.CARRIER_CONFIG_SERVICE;
} else if (serviceClass == TelephonyManager.class) {
return Context.TELEPHONY_SERVICE;
+ } else if (serviceClass == UiModeManager.class) {
+ return Context.UI_MODE_SERVICE;
} else if (serviceClass == KeyguardManager.class) {
return Context.KEYGUARD_SERVICE;
} else if (serviceClass == VcnManager.class) {
return Context.VCN_MANAGEMENT_SERVICE;
- } else if (serviceClass == LocationManager.class) {
- return Context.LOCATION_SERVICE;
}
return super.getSystemServiceName(serviceClass);
}
@@ -629,7 +634,6 @@
// The application context is the most important object this class provides to the system
// under test.
private final Context mContext = spy(new FakeContext());
-
// We then create a spy on the application context allowing standard Mockito-style
// when(...) logic to be used to add specific little responses where needed.
@@ -657,13 +661,14 @@
mock(TelephonyRegistryManager.class);
private final SystemConfigManager mSystemConfigManager = mock(SystemConfigManager.class);
private final PowerWhitelistManager mPowerWhitelistManager = mock(PowerWhitelistManager.class);
+ private final LocationManager mLocationManager = mock(LocationManager.class);
private final KeyguardManager mKeyguardManager = mock(KeyguardManager.class);
private final VcnManager mVcnManager = mock(VcnManager.class);
- private final LocationManager mLocationManager = mock(LocationManager.class);
private final ContentProvider mContentProvider = spy(new FakeContentProvider());
private final Configuration mConfiguration = new Configuration();
+ private final DisplayMetrics mDisplayMetrics = new DisplayMetrics();
private final SharedPreferences mSharedPreferences = PreferenceManager
.getDefaultSharedPreferences(TestApplication.getAppContext());
private final MockContentResolver mContentResolver = new MockContentResolver();
@@ -718,6 +723,8 @@
mConfiguration.locale = Locale.US;
doReturn(mConfiguration).when(mResources).getConfiguration();
+ mDisplayMetrics.density = 2.25f;
+ doReturn(mDisplayMetrics).when(mResources).getDisplayMetrics();
mContentResolver.addProvider(Settings.AUTHORITY, mContentProvider);
// Settings caches the provider after first get/set call, this is needed to make sure
// Settings is using mContentProvider as the cached provider across all tests.
diff --git a/tests/telephonytests/src/com/android/internal/telephony/DeviceStateMonitorTest.java b/tests/telephonytests/src/com/android/internal/telephony/DeviceStateMonitorTest.java
index 5a0a6b7..44f3aa5 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/DeviceStateMonitorTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/DeviceStateMonitorTest.java
@@ -25,6 +25,7 @@
import static org.mockito.Matchers.anyInt;
import static org.mockito.Matchers.eq;
import static org.mockito.Matchers.nullable;
+import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.verify;
@@ -32,6 +33,8 @@
import static java.util.Arrays.asList;
import android.annotation.IntDef;
+import android.app.UiModeManager;
+import android.content.Context;
import android.content.Intent;
import android.hardware.radio.V1_5.IndicationFilter;
import android.net.ConnectivityManager;
@@ -47,6 +50,7 @@
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -128,6 +132,8 @@
STATE_TYPE_CHARGING, STATE_TYPE_SCREEN, STATE_TYPE_TETHERING}
);
+ @Mock
+ UiModeManager mUiModeManager;
private DeviceStateMonitor mDSM;
// Given a stateType, return the event type that can change the state
private int state2Event(@StateType int stateType) {
@@ -155,6 +161,9 @@
@Before
public void setUp() throws Exception {
super.setUp(getClass().getSimpleName());
+ mContextFixture.setSystemService(Context.UI_MODE_SERVICE, mUiModeManager);
+ // We don't even need a mock executor, we just need to not throw.
+ doReturn(null).when(mContextFixture.getTestDouble()).getMainExecutor();
mDSM = new DeviceStateMonitor(mPhone);
// Initialize with ALL states off
diff --git a/tests/telephonytests/src/com/android/internal/telephony/FakeTelephonyProvider.java b/tests/telephonytests/src/com/android/internal/telephony/FakeTelephonyProvider.java
index 5ec14e6..f2624af 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/FakeTelephonyProvider.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/FakeTelephonyProvider.java
@@ -115,7 +115,9 @@
+ Telephony.SimInfo.COLUMN_ALLOWED_NETWORK_TYPES + " BIGINT DEFAULT -1,"
+ Telephony.SimInfo.COLUMN_IMS_RCS_UCE_ENABLED + " INTEGER DEFAULT 0, "
+ Telephony.SimInfo.COLUMN_RCS_CONFIG + " BLOB,"
- + Telephony.SimInfo.COLUMN_ALLOWED_NETWORK_TYPES_FOR_REASONS + " TEXT"
+ + Telephony.SimInfo.COLUMN_ALLOWED_NETWORK_TYPES_FOR_REASONS + " TEXT,"
+ + Telephony.SimInfo.COLUMN_D2D_STATUS_SHARING + " INTEGER DEFAULT 0,"
+ + Telephony.SimInfo.COLUMN_D2D_STATUS_SHARING_SELECTED_CONTACTS + "TEXT"
+ ");";
}
diff --git a/tests/telephonytests/src/com/android/internal/telephony/GsmCdmaPhoneTest.java b/tests/telephonytests/src/com/android/internal/telephony/GsmCdmaPhoneTest.java
index fd0c825..1d03c46 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/GsmCdmaPhoneTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/GsmCdmaPhoneTest.java
@@ -133,9 +133,10 @@
super.setUp(getClass().getSimpleName());
doReturn(false).when(mSST).isDeviceShuttingDown();
+ doReturn(true).when(mImsManager).isVolteEnabledByPlatform();
mPhoneUT = new GsmCdmaPhone(mContext, mSimulatedCommands, mNotifier, true, 0,
- PhoneConstants.PHONE_TYPE_GSM, mTelephonyComponentFactory);
+ PhoneConstants.PHONE_TYPE_GSM, mTelephonyComponentFactory, (c, p) -> mImsManager);
mPhoneUT.setVoiceCallSessionStats(mVoiceCallSessionStats);
ArgumentCaptor<Integer> integerArgumentCaptor = ArgumentCaptor.forClass(Integer.class);
verify(mUiccController).registerForIccChanged(eq(mPhoneUT), integerArgumentCaptor.capture(),
@@ -998,7 +999,7 @@
};
Phone phone = new GsmCdmaPhone(mContext, sc, mNotifier, true, 0,
- PhoneConstants.PHONE_TYPE_GSM, mTelephonyComponentFactory);
+ PhoneConstants.PHONE_TYPE_GSM, mTelephonyComponentFactory, (c, p) -> mImsManager);
phone.setVoiceCallSessionStats(mVoiceCallSessionStats);
ArgumentCaptor<Integer> integerArgumentCaptor = ArgumentCaptor.forClass(Integer.class);
verify(mUiccController).registerForIccChanged(eq(phone), integerArgumentCaptor.capture(),
diff --git a/tests/telephonytests/src/com/android/internal/telephony/MultiSimSettingControllerTest.java b/tests/telephonytests/src/com/android/internal/telephony/MultiSimSettingControllerTest.java
index c93de7d..0c7fe8e 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/MultiSimSettingControllerTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/MultiSimSettingControllerTest.java
@@ -35,6 +35,7 @@
import static org.mockito.Mockito.clearInvocations;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import android.content.Intent;
@@ -367,6 +368,41 @@
@Test
@SmallTest
+ public void testSimpleDsdsFirstBoot() {
+ // at first boot default is not set
+ doReturn(-1).when(mSubControllerMock).getDefaultDataSubId();
+
+ doReturn(true).when(mPhoneMock1).isUserDataEnabled();
+ doReturn(true).when(mPhoneMock2).isUserDataEnabled();
+ // After initialization, sub 2 should have mobile data off.
+ mMultiSimSettingControllerUT.notifyAllSubscriptionLoaded();
+ mMultiSimSettingControllerUT.notifyCarrierConfigChanged(0, 1);
+ mMultiSimSettingControllerUT.notifyCarrierConfigChanged(1, 2);
+ processAllMessages();
+ verify(mDataEnabledSettingsMock1).setDataEnabled(
+ TelephonyManager.DATA_ENABLED_REASON_USER, false);
+ verify(mDataEnabledSettingsMock2).setDataEnabled(
+ TelephonyManager.DATA_ENABLED_REASON_USER, false);
+
+ // as a result of the above calls, update new values to be returned
+ doReturn(false).when(mPhoneMock1).isUserDataEnabled();
+ doReturn(false).when(mPhoneMock2).isUserDataEnabled();
+
+ Intent intent = captureBroadcastIntent();
+ assertEquals(ACTION_PRIMARY_SUBSCRIPTION_LIST_CHANGED, intent.getAction());
+ assertEquals(EXTRA_DEFAULT_SUBSCRIPTION_SELECT_TYPE_DATA,
+ intent.getIntExtra(EXTRA_DEFAULT_SUBSCRIPTION_SELECT_TYPE, -1));
+
+ // Setting default data should not trigger any more setDataEnabled().
+ doReturn(2).when(mSubControllerMock).getDefaultDataSubId();
+ mMultiSimSettingControllerUT.notifyDefaultDataSubChanged();
+ processAllMessages();
+ verify(mDataEnabledSettingsMock1, times(1)).setDataEnabled(anyInt(), anyBoolean());
+ verify(mDataEnabledSettingsMock2, times(1)).setDataEnabled(anyInt(), anyBoolean());
+ }
+
+ @Test
+ @SmallTest
public void testDsdsGrouping() {
doReturn(2).when(mSubControllerMock).getDefaultDataSubId();
doReturn(false).when(mPhoneMock1).isUserDataEnabled();
diff --git a/tests/telephonytests/src/com/android/internal/telephony/NetworkTypeControllerTest.java b/tests/telephonytests/src/com/android/internal/telephony/NetworkTypeControllerTest.java
index d8a0585..96a89c2 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/NetworkTypeControllerTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/NetworkTypeControllerTest.java
@@ -140,7 +140,54 @@
// NR NSA, millimeter wave frequency
doReturn(ServiceState.FREQUENCY_RANGE_MMWAVE).when(mServiceState).getNrFrequencyRange();
updateOverrideNetworkType();
- assertEquals(TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_NSA_MMWAVE,
+ assertEquals(TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_ADVANCED,
+ mNetworkTypeController.getOverrideNetworkType());
+ }
+
+ @Test
+ public void testUpdateOverrideNetworkTypeNrSa() throws Exception {
+ // not NR
+ doReturn(TelephonyManager.NETWORK_TYPE_LTE).when(mServiceState).getDataNetworkType();
+ doReturn(NetworkRegistrationInfo.NR_STATE_NONE).when(mServiceState).getNrState();
+ updateOverrideNetworkType();
+ assertEquals(TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NONE,
+ mNetworkTypeController.getOverrideNetworkType());
+
+ // NR SA connected
+ mNetworkRegistrationInfo = new NetworkRegistrationInfo.Builder()
+ .setAccessNetworkTechnology(TelephonyManager.NETWORK_TYPE_NR)
+ .setRegistrationState(NetworkRegistrationInfo.REGISTRATION_STATE_HOME)
+ .build();
+ doReturn(mNetworkRegistrationInfo).when(mServiceState).getNetworkRegistrationInfo(
+ anyInt(), anyInt());
+
+ updateOverrideNetworkType();
+
+ assertEquals(TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NONE,
+ mNetworkTypeController.getOverrideNetworkType());
+ }
+
+ @Test
+ public void testUpdateOverrideNetworkTypeNrSaMmwave() throws Exception {
+ // not NR
+ doReturn(TelephonyManager.NETWORK_TYPE_LTE).when(mServiceState).getDataNetworkType();
+ doReturn(NetworkRegistrationInfo.NR_STATE_NONE).when(mServiceState).getNrState();
+ updateOverrideNetworkType();
+ assertEquals(TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NONE,
+ mNetworkTypeController.getOverrideNetworkType());
+
+ // NR SA connected and millimeter wave frequency
+ mNetworkRegistrationInfo = new NetworkRegistrationInfo.Builder()
+ .setAccessNetworkTechnology(TelephonyManager.NETWORK_TYPE_NR)
+ .setRegistrationState(NetworkRegistrationInfo.REGISTRATION_STATE_HOME)
+ .build();
+ doReturn(mNetworkRegistrationInfo).when(mServiceState).getNetworkRegistrationInfo(
+ anyInt(), anyInt());
+ doReturn(ServiceState.FREQUENCY_RANGE_MMWAVE).when(mServiceState).getNrFrequencyRange();
+
+ updateOverrideNetworkType();
+
+ assertEquals(TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_ADVANCED,
mNetworkTypeController.getOverrideNetworkType());
}
@@ -456,7 +503,7 @@
broadcastCarrierConfigs();
assertEquals("connected_mmwave", getCurrentState().getName());
- assertEquals(TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_NSA_MMWAVE,
+ assertEquals(TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_ADVANCED,
mNetworkTypeController.getOverrideNetworkType());
// should trigger 10 second timer
@@ -465,7 +512,7 @@
processAllMessages();
assertEquals("connected", getCurrentState().getName());
- assertEquals(TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_NSA_MMWAVE,
+ assertEquals(TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_ADVANCED,
mNetworkTypeController.getOverrideNetworkType());
assertTrue(mNetworkTypeController.is5GHysteresisActive());
@@ -489,7 +536,7 @@
broadcastCarrierConfigs();
assertEquals("connected_mmwave", getCurrentState().getName());
- assertEquals(TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_NSA_MMWAVE,
+ assertEquals(TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_ADVANCED,
mNetworkTypeController.getOverrideNetworkType());
// trigger 10 second timer after disconnecting from NR
@@ -498,7 +545,7 @@
processAllMessages();
assertEquals("connected", getCurrentState().getName());
- assertEquals(TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_NSA_MMWAVE,
+ assertEquals(TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_ADVANCED,
mNetworkTypeController.getOverrideNetworkType());
assertTrue(mNetworkTypeController.is5GHysteresisActive());
@@ -512,7 +559,7 @@
// timer should not have gone off
assertEquals("connected_mmwave", getCurrentState().getName());
- assertEquals(TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_NSA_MMWAVE,
+ assertEquals(TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_ADVANCED,
mNetworkTypeController.getOverrideNetworkType());
assertFalse(mNetworkTypeController.is5GHysteresisActive());
}
@@ -622,7 +669,7 @@
broadcastCarrierConfigs();
assertEquals("connected_mmwave", getCurrentState().getName());
- assertEquals(TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_NSA_MMWAVE,
+ assertEquals(TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_ADVANCED,
mNetworkTypeController.getOverrideNetworkType());
// should trigger 10 second primary timer
@@ -631,7 +678,7 @@
processAllMessages();
assertEquals("connected", getCurrentState().getName());
- assertEquals(TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_NSA_MMWAVE,
+ assertEquals(TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_ADVANCED,
mNetworkTypeController.getOverrideNetworkType());
assertTrue(mNetworkTypeController.is5GHysteresisActive());
@@ -641,7 +688,7 @@
// should trigger 30 second secondary timer
assertEquals("connected", getCurrentState().getName());
- assertEquals(TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_NSA_MMWAVE,
+ assertEquals(TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_ADVANCED,
mNetworkTypeController.getOverrideNetworkType());
assertTrue(mNetworkTypeController.is5GHysteresisActive());
@@ -667,7 +714,7 @@
broadcastCarrierConfigs();
assertEquals("connected_mmwave", getCurrentState().getName());
- assertEquals(TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_NSA_MMWAVE,
+ assertEquals(TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_ADVANCED,
mNetworkTypeController.getOverrideNetworkType());
// should trigger 10 second primary timer
@@ -676,7 +723,7 @@
processAllMessages();
assertEquals("connected", getCurrentState().getName());
- assertEquals(TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_NSA_MMWAVE,
+ assertEquals(TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_ADVANCED,
mNetworkTypeController.getOverrideNetworkType());
assertTrue(mNetworkTypeController.is5GHysteresisActive());
@@ -686,7 +733,7 @@
// should trigger 30 second secondary timer
assertEquals("connected", getCurrentState().getName());
- assertEquals(TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_NSA_MMWAVE,
+ assertEquals(TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_ADVANCED,
mNetworkTypeController.getOverrideNetworkType());
assertTrue(mNetworkTypeController.is5GHysteresisActive());
@@ -700,7 +747,7 @@
// timer should not have gone off
assertEquals("connected_mmwave", getCurrentState().getName());
- assertEquals(TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_NSA_MMWAVE,
+ assertEquals(TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_ADVANCED,
mNetworkTypeController.getOverrideNetworkType());
assertFalse(mNetworkTypeController.is5GHysteresisActive());
}
@@ -717,7 +764,7 @@
broadcastCarrierConfigs();
assertEquals("connected_mmwave", getCurrentState().getName());
- assertEquals(TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_NSA_MMWAVE,
+ assertEquals(TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_ADVANCED,
mNetworkTypeController.getOverrideNetworkType());
// should trigger 10 second primary timer
@@ -726,7 +773,7 @@
processAllMessages();
assertEquals("connected", getCurrentState().getName());
- assertEquals(TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_NSA_MMWAVE,
+ assertEquals(TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_ADVANCED,
mNetworkTypeController.getOverrideNetworkType());
assertTrue(mNetworkTypeController.is5GHysteresisActive());
diff --git a/tests/telephonytests/src/com/android/internal/telephony/PhoneCapabilityTest.java b/tests/telephonytests/src/com/android/internal/telephony/PhoneCapabilityTest.java
index a504dc1..2410625 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/PhoneCapabilityTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/PhoneCapabilityTest.java
@@ -16,6 +16,7 @@
package com.android.internal.telephony;
+import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotEquals;
@@ -35,23 +36,25 @@
public void basicTests() throws Exception {
int maxActiveVoiceCalls = 1;
int maxActiveData = 2;
- int max5G = 3;
ModemInfo modemInfo = new ModemInfo(1, 2, true, false);
List<ModemInfo> logicalModemList = new ArrayList<>();
logicalModemList.add(modemInfo);
+ int[] deviceNrCapabilities = new int[]{PhoneCapability.DEVICE_NR_CAPABILITY_SA};
- PhoneCapability capability = new PhoneCapability(maxActiveVoiceCalls, maxActiveData, max5G,
- logicalModemList, false);
+ PhoneCapability capability = new PhoneCapability(maxActiveVoiceCalls, maxActiveData,
+ logicalModemList, false, deviceNrCapabilities);
- assertEquals(maxActiveVoiceCalls, capability.maxActiveVoiceCalls);
- assertEquals(maxActiveData, capability.maxActiveData);
- assertEquals(max5G, capability.max5G);
- assertEquals(1, capability.logicalModemList.size());
- assertEquals(modemInfo, capability.logicalModemList.get(0));
- PhoneCapability toCompare = new PhoneCapability(
- maxActiveVoiceCalls + 1, maxActiveData - 1, max5G, logicalModemList, false);
- assertEquals(capability, new PhoneCapability(
- maxActiveVoiceCalls, maxActiveData, max5G, logicalModemList, false));
+ assertEquals(maxActiveVoiceCalls, capability.getMaxActiveVoiceSubscriptions());
+ assertEquals(maxActiveData, capability.getMaxActiveDataSubscriptions());
+ assertEquals(1, capability.getLogicalModemList().size());
+ assertEquals(modemInfo, capability.getLogicalModemList().get(0));
+ assertArrayEquals(deviceNrCapabilities, capability.getDeviceNrCapabilities());
+
+ PhoneCapability toCompare = new PhoneCapability(maxActiveVoiceCalls + 1, maxActiveData - 1,
+ logicalModemList, false, deviceNrCapabilities);
+ assertEquals(capability,
+ new PhoneCapability(maxActiveVoiceCalls, maxActiveData, logicalModemList,
+ false, deviceNrCapabilities));
assertNotEquals(capability, toCompare);
}
@@ -60,24 +63,24 @@
public void parcelReadWrite() throws Exception {
int maxActiveVoiceCalls = 1;
int maxActiveData = 2;
- int max5G = 3;
ModemInfo modemInfo = new ModemInfo(1, 2, true, false);
List<ModemInfo> logicalModemList = new ArrayList<>();
logicalModemList.add(modemInfo);
+ int[] deviceNrCapabilities = new int[]{};
- PhoneCapability capability = new PhoneCapability(maxActiveVoiceCalls, maxActiveData, max5G,
- logicalModemList, false);
+ PhoneCapability capability = new PhoneCapability(maxActiveVoiceCalls, maxActiveData,
+ logicalModemList, false, deviceNrCapabilities);
Parcel parcel = Parcel.obtain();
capability.writeToParcel(parcel, 0);
parcel.setDataPosition(0);
PhoneCapability toCompare = PhoneCapability.CREATOR.createFromParcel(parcel);
- assertEquals(maxActiveVoiceCalls, toCompare.maxActiveVoiceCalls);
- assertEquals(maxActiveData, toCompare.maxActiveData);
- assertEquals(max5G, toCompare.max5G);
- assertEquals(1, toCompare.logicalModemList.size());
- assertEquals(modemInfo, toCompare.logicalModemList.get(0));
+ assertEquals(maxActiveVoiceCalls, toCompare.getMaxActiveVoiceSubscriptions());
+ assertEquals(maxActiveData, toCompare.getMaxActiveDataSubscriptions());
+ assertEquals(1, toCompare.getLogicalModemList().size());
+ assertEquals(modemInfo, toCompare.getLogicalModemList().get(0));
+ assertArrayEquals(deviceNrCapabilities, toCompare.getDeviceNrCapabilities());
assertEquals(capability, toCompare);
}
}
diff --git a/tests/telephonytests/src/com/android/internal/telephony/PhoneSwitcherTest.java b/tests/telephonytests/src/com/android/internal/telephony/PhoneSwitcherTest.java
index e13baca..3485f49 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/PhoneSwitcherTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/PhoneSwitcherTest.java
@@ -20,6 +20,8 @@
import static android.telephony.TelephonyManager.SET_OPPORTUNISTIC_SUB_INACTIVE_SUBSCRIPTION;
import static android.telephony.TelephonyManager.SET_OPPORTUNISTIC_SUB_SUCCESS;
import static android.telephony.TelephonyManager.SET_OPPORTUNISTIC_SUB_VALIDATION_FAILED;
+import static android.telephony.ims.stub.ImsRegistrationImplBase.REGISTRATION_TECH_IWLAN;
+import static android.telephony.ims.stub.ImsRegistrationImplBase.REGISTRATION_TECH_LTE;
import static com.android.internal.telephony.PhoneSwitcher.ECBM_DEFAULT_DATA_SWITCH_BASE_TIME_MS;
import static com.android.internal.telephony.PhoneSwitcher.EVENT_DATA_ENABLED_CHANGED;
@@ -56,6 +58,7 @@
import android.os.Messenger;
import android.telephony.PhoneCapability;
import android.telephony.SubscriptionManager;
+import android.telephony.data.ApnSetting;
import android.test.suitebuilder.annotation.SmallTest;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
@@ -84,6 +87,8 @@
@Mock
private Phone mPhone2; // mPhone as phone 1 is already defined in TelephonyTest.
@Mock
+ private Phone mImsPhone;
+ @Mock
private DataEnabledSettings mDataEnabledSettings2;
@Mock
private Handler mActivePhoneSwitchHandler;
@@ -99,6 +104,8 @@
private ISetOpportunisticDataCallback mSetOpptDataCallback2;
@Mock
CompletableFuture<Boolean> mFuturePhone;
+ @Mock
+ PhoneSwitcher.ImsRegTechProvider mMockImsRegTechProvider;
private PhoneSwitcher mPhoneSwitcher;
private SubscriptionManager.OnSubscriptionsChangedListener mSubChangedListener;
@@ -116,7 +123,7 @@
public void setUp() throws Exception {
super.setUp(getClass().getSimpleName());
- PhoneCapability phoneCapability = new PhoneCapability(1, 1, 0, null, false);
+ PhoneCapability phoneCapability = new PhoneCapability(1, 1, null, false, new int[0]);
doReturn(phoneCapability).when(mPhoneConfigurationManager).getCurrentPhoneCapability();
doReturn(Call.State.ACTIVE).when(mActiveCall).getState();
@@ -529,6 +536,66 @@
assertEquals(0, mPhoneSwitcher.getPreferredDataPhoneId());
}
+ private void mockImsRegTech(int phoneId, int regTech) {
+ doReturn(regTech).when(mMockImsRegTechProvider).get(any(), eq(phoneId));
+ mPhoneSwitcher.mImsRegTechProvider = mMockImsRegTechProvider;
+ }
+
+ @Test
+ @SmallTest
+ public void testNonDefaultDataPhoneInCall_ImsCallOnLte_shouldSwitchDds() throws Exception {
+ initialize();
+ setAllPhonesInactive();
+
+ // Phone 0 has sub 1, phone 1 has sub 2.
+ // Sub 1 is default data sub.
+ // Both are active subscriptions are active sub, as they are in both active slots.
+ setSlotIndexToSubId(0, 1);
+ setSlotIndexToSubId(1, 2);
+ setDefaultDataSubId(1);
+ processAllMessages();
+
+ // Phone 0 should be the default data phoneId.
+ assertEquals(0, mPhoneSwitcher.getPreferredDataPhoneId());
+
+ // Phone2 has active IMS call on LTE. And data of DEFAULT apn is enabled. This should
+ // trigger data switch.
+ doReturn(mImsPhone).when(mPhone2).getImsPhone();
+ doReturn(true).when(mDataEnabledSettings2).isDataEnabled(ApnSetting.TYPE_DEFAULT);
+ mockImsRegTech(1, REGISTRATION_TECH_LTE);
+ notifyPhoneAsInCall(mImsPhone);
+
+ // Phone 1 should become the default data phone.
+ assertEquals(1, mPhoneSwitcher.getPreferredDataPhoneId());
+ }
+
+ @Test
+ @SmallTest
+ public void testNonDefaultDataPhoneInCall_ImsCallOnWlan_shouldNotSwitchDds() throws Exception {
+ initialize();
+ setAllPhonesInactive();
+
+ // Phone 0 has sub 1, phone 1 has sub 2.
+ // Sub 1 is default data sub.
+ // Both are active subscriptions are active sub, as they are in both active slots.
+ setSlotIndexToSubId(0, 1);
+ setSlotIndexToSubId(1, 2);
+ setDefaultDataSubId(1);
+ processAllMessages();
+
+ // Phone 0 should be the default data phoneId.
+ assertEquals(0, mPhoneSwitcher.getPreferredDataPhoneId());
+
+ // Phone2 has active call, but data is turned off. So no data switching should happen.
+ doReturn(mImsPhone).when(mPhone2).getImsPhone();
+ doReturn(true).when(mDataEnabledSettings2).isDataEnabled(ApnSetting.TYPE_DEFAULT);
+ mockImsRegTech(1, REGISTRATION_TECH_IWLAN);
+ notifyPhoneAsInCall(mImsPhone);
+
+ // Phone 0 should remain the default data phone.
+ assertEquals(0, mPhoneSwitcher.getPreferredDataPhoneId());
+ }
+
@Test
@SmallTest
public void testNonDefaultDataPhoneInCall() throws Exception {
@@ -1005,6 +1072,9 @@
doReturn(mInactiveCall).when(mPhone2).getForegroundCall();
doReturn(mInactiveCall).when(mPhone2).getBackgroundCall();
doReturn(mInactiveCall).when(mPhone2).getRingingCall();
+ doReturn(mInactiveCall).when(mImsPhone).getForegroundCall();
+ doReturn(mInactiveCall).when(mImsPhone).getBackgroundCall();
+ doReturn(mInactiveCall).when(mImsPhone).getRingingCall();
}
private void notifyPhoneAsInCall(Phone phone) {
diff --git a/tests/telephonytests/src/com/android/internal/telephony/RILTest.java b/tests/telephonytests/src/com/android/internal/telephony/RILTest.java
index f4c20f5..7c81bda 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/RILTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/RILTest.java
@@ -43,6 +43,7 @@
import static com.android.internal.telephony.RILConstants.RIL_REQUEST_GET_IMSI;
import static com.android.internal.telephony.RILConstants.RIL_REQUEST_GET_RADIO_CAPABILITY;
import static com.android.internal.telephony.RILConstants.RIL_REQUEST_GET_SIM_STATUS;
+import static com.android.internal.telephony.RILConstants.RIL_REQUEST_GET_SLICING_CONFIG;
import static com.android.internal.telephony.RILConstants.RIL_REQUEST_GET_SMSC_ADDRESS;
import static com.android.internal.telephony.RILConstants.RIL_REQUEST_GET_UICC_APPLICATIONS_ENABLEMENT;
import static com.android.internal.telephony.RILConstants.RIL_REQUEST_HANGUP;
@@ -2361,6 +2362,7 @@
response = new DataCallResponse.Builder()
.setCause(0)
+ .setRetryDurationMillis(-1L)
.setId(0)
.setLinkStatus(2)
.setProtocolType(ApnSetting.PROTOCOL_IPV4V6)
@@ -2820,4 +2822,18 @@
mRILUnderTest.setCompatVersion(testRequest, RIL.RADIO_HAL_VERSION_1_5);
assertEquals(RIL.RADIO_HAL_VERSION_1_3, mRILUnderTest.getCompatVersion(testRequest));
}
+
+ @FlakyTest
+ @Test
+ public void testGetSlicingConfig() throws Exception {
+ // Use Radio HAL v1.6
+ try {
+ replaceInstance(RIL.class, "mRadioVersion", mRILUnderTest, mRadioVersionV16);
+ } catch (Exception e) {
+ }
+ mRILUnderTest.getSlicingConfig(obtainMessage());
+ verify(mRadioProxy).getSlicingConfig(mSerialNumberCaptor.capture());
+ verifyRILResponse_1_6(
+ mRILUnderTest, mSerialNumberCaptor.getValue(), RIL_REQUEST_GET_SLICING_CONFIG);
+ }
}
diff --git a/tests/telephonytests/src/com/android/internal/telephony/RadioConfigResponseTest.java b/tests/telephonytests/src/com/android/internal/telephony/RadioConfigResponseTest.java
index f069262..a346ece 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/RadioConfigResponseTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/RadioConfigResponseTest.java
@@ -54,6 +54,8 @@
TelephonyManager.CAPABILITY_NR_DUAL_CONNECTIVITY_CONFIGURATION_AVAILABLE));
assertFalse(
caps.contains(TelephonyManager.CAPABILITY_THERMAL_MITIGATION_DATA_THROTTLING));
+ assertFalse(
+ caps.contains(TelephonyManager.CAPABILITY_SLICING_CONFIG_SUPPORTED));
}
@Test
@@ -68,6 +70,8 @@
TelephonyManager.CAPABILITY_NR_DUAL_CONNECTIVITY_CONFIGURATION_AVAILABLE));
assertFalse(
caps.contains(TelephonyManager.CAPABILITY_THERMAL_MITIGATION_DATA_THROTTLING));
+ assertFalse(
+ caps.contains(TelephonyManager.CAPABILITY_SLICING_CONFIG_SUPPORTED));
}
@Test
@@ -82,5 +86,7 @@
TelephonyManager.CAPABILITY_NR_DUAL_CONNECTIVITY_CONFIGURATION_AVAILABLE));
assertTrue(
caps.contains(TelephonyManager.CAPABILITY_THERMAL_MITIGATION_DATA_THROTTLING));
+ assertTrue(
+ caps.contains(TelephonyManager.CAPABILITY_SLICING_CONFIG_SUPPORTED));
}
}
diff --git a/tests/telephonytests/src/com/android/internal/telephony/ServiceStateTrackerTest.java b/tests/telephonytests/src/com/android/internal/telephony/ServiceStateTrackerTest.java
index 2a23387..0bef358 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/ServiceStateTrackerTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/ServiceStateTrackerTest.java
@@ -91,6 +91,7 @@
import android.telephony.TelephonyManager;
import android.telephony.cdma.CdmaCellLocation;
import android.telephony.gsm.GsmCellLocation;
+import android.telephony.ims.stub.ImsRegistrationImplBase;
import android.test.suitebuilder.annotation.MediumTest;
import android.test.suitebuilder.annotation.SmallTest;
import android.text.TextUtils;
@@ -164,6 +165,7 @@
private static final String CARRIER_NAME_DISPLAY_NO_SERVICE = "No service";
private static final String CARRIER_NAME_DISPLAY_EMERGENCY_CALL = "emergency call";
private static final String WIFI_CALLING_VOICE_FORMAT = "%s wifi calling";
+ private static final String CROSS_SIM_CALLING_VOICE_FORMAT = "%s Cross-SIM Calling";
private static final String WIFI_CALLING_DATA_FORMAT = "%s wifi data";
private static final String WIFI_CALLING_FLIGHT_MODE_FORMAT = "%s flight mode";
@@ -2595,6 +2597,40 @@
}
@Test
+ public void testUpdateSpnDisplay_spnNotEmptyAndCrossSimCallingEnabled_showSpnOnly() {
+ // GSM phone
+
+ doReturn(true).when(mPhone).isPhoneTypeGsm();
+
+ // In Service
+ ServiceState ss = new ServiceState();
+ ss.setVoiceRegState(ServiceState.STATE_IN_SERVICE);
+ ss.setDataRegState(ServiceState.STATE_IN_SERVICE);
+ sst.mSS = ss;
+
+ // cross-sim-calling is enable
+ doReturn(mImsPhone).when(mPhone).getImsPhone();
+ doReturn(ImsRegistrationImplBase.REGISTRATION_TECH_CROSS_SIM).when(mImsPhone)
+ .getImsRegistrationTech();
+ String[] formats = {CROSS_SIM_CALLING_VOICE_FORMAT, "%s"};
+ Resources r = mContext.getResources();
+ doReturn(formats).when(r).getStringArray(anyInt());
+
+ // update the spn
+ sst.updateSpnDisplay();
+
+ // Only spn should be shown
+ String spn = mBundle.getString(CarrierConfigManager.KEY_CARRIER_NAME_STRING);
+ Bundle b = getExtrasFromLastSpnUpdateIntent();
+ assertThat(b.getString(TelephonyManager.EXTRA_SPN))
+ .isEqualTo(String.format(CROSS_SIM_CALLING_VOICE_FORMAT, spn));
+ assertThat(b.getBoolean(TelephonyManager.EXTRA_SHOW_SPN)).isTrue();
+ assertThat(b.getString(TelephonyManager.EXTRA_DATA_SPN))
+ .isEqualTo(String.format(CROSS_SIM_CALLING_VOICE_FORMAT, spn));
+ assertThat(b.getBoolean(TelephonyManager.EXTRA_SHOW_PLMN)).isFalse();
+ }
+
+ @Test
public void testUpdateSpnDisplay_spnNotEmptyAndWifiCallingEnabled_showSpnOnly() {
// GSM phone
doReturn(true).when(mPhone).isPhoneTypeGsm();
diff --git a/tests/telephonytests/src/com/android/internal/telephony/SimulatedCommands.java b/tests/telephonytests/src/com/android/internal/telephony/SimulatedCommands.java
index a64de8c..40fa229 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/SimulatedCommands.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/SimulatedCommands.java
@@ -49,7 +49,7 @@
import android.telephony.TelephonyManager;
import android.telephony.data.DataCallResponse;
import android.telephony.data.DataProfile;
-import android.telephony.data.SliceInfo;
+import android.telephony.data.NetworkSliceInfo;
import android.telephony.data.TrafficDescriptor;
import android.telephony.emergency.EmergencyNumber;
@@ -1188,8 +1188,8 @@
@Override
public void setupDataCall(int accessNetworkType, DataProfile dataProfile, boolean isRoaming,
boolean allowRoaming, int reason, LinkProperties linkProperties, int pduSessionId,
- SliceInfo sliceInfo, TrafficDescriptor trafficDescriptor, boolean matchAllRuleAllowed,
- Message result) {
+ NetworkSliceInfo sliceInfo, TrafficDescriptor trafficDescriptor,
+ boolean matchAllRuleAllowed, Message result) {
SimulatedCommandsVerifier.getInstance().setupDataCall(accessNetworkType, dataProfile,
isRoaming, allowRoaming, reason, linkProperties, pduSessionId, sliceInfo,
@@ -2436,6 +2436,12 @@
resultSuccess(message, null);
}
+ @Override
+ public void getSlicingConfig(Message result) {
+ SimulatedCommandsVerifier.getInstance().getSlicingConfig(result);
+ resultSuccess(result, null);
+ }
+
@VisibleForTesting
public void setDataRegStateResult(Object regStateResult) {
mDataRegStateResult = regStateResult;
@@ -2445,4 +2451,5 @@
public void setVoiceRegStateResult(Object regStateResult) {
mVoiceRegStateResult = regStateResult;
}
+
}
diff --git a/tests/telephonytests/src/com/android/internal/telephony/SimulatedCommandsVerifier.java b/tests/telephonytests/src/com/android/internal/telephony/SimulatedCommandsVerifier.java
index 5d40fe6..c4d54ff 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/SimulatedCommandsVerifier.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/SimulatedCommandsVerifier.java
@@ -26,7 +26,7 @@
import android.telephony.SignalThresholdInfo;
import android.telephony.TelephonyManager;
import android.telephony.data.DataProfile;
-import android.telephony.data.SliceInfo;
+import android.telephony.data.NetworkSliceInfo;
import android.telephony.data.TrafficDescriptor;
import android.telephony.emergency.EmergencyNumber;
@@ -1204,8 +1204,8 @@
@Override
public void setupDataCall(int accessNetworkType, DataProfile dataProfile, boolean isRoaming,
boolean allowRoaming, int reason, LinkProperties linkProperties, int pduSessionId,
- SliceInfo sliceInfo, TrafficDescriptor trafficDescriptor, boolean matchAllRuleAllowed,
- Message result) {
+ NetworkSliceInfo sliceInfo, TrafficDescriptor trafficDescriptor,
+ boolean matchAllRuleAllowed, Message result) {
}
@Override
@@ -1492,4 +1492,8 @@
@Override
public void releasePduSessionId(Message result, int pduSessionId) {
}
+
+ @Override
+ public void getSlicingConfig(Message result) {
+ }
}
diff --git a/tests/telephonytests/src/com/android/internal/telephony/SubscriptionControllerTest.java b/tests/telephonytests/src/com/android/internal/telephony/SubscriptionControllerTest.java
index 6566d3d..2daeaea 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/SubscriptionControllerTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/SubscriptionControllerTest.java
@@ -47,6 +47,7 @@
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
+import android.os.Looper;
import android.os.ParcelUuid;
import android.os.PersistableBundle;
import android.os.UserHandle;
@@ -112,6 +113,10 @@
public void setUp() throws Exception {
super.setUp("SubscriptionControllerTest");
+ if (Looper.myLooper() == null) {
+ Looper.prepare();
+ }
+
doReturn(SINGLE_SIM).when(mTelephonyManager).getSimCount();
doReturn(SINGLE_SIM).when(mTelephonyManager).getPhoneCount();
mMockContentResolver = (MockContentResolver) mContext.getContentResolver();
@@ -144,8 +149,10 @@
/*clear sub info in mSubscriptionControllerUT since they will otherwise be persistent
* between each test case. */
- mSubscriptionControllerUT.clearSubInfo();
- mSubscriptionControllerUT.resetStaticMembers();
+ if (mSubscriptionControllerUT != null) {
+ mSubscriptionControllerUT.clearSubInfo();
+ mSubscriptionControllerUT.resetStaticMembers();
+ }
/* clear settings for default voice/data/sms sub ID */
Settings.Global.putInt(mContext.getContentResolver(),
diff --git a/tests/telephonytests/src/com/android/internal/telephony/SubscriptionInfoUpdaterTest.java b/tests/telephonytests/src/com/android/internal/telephony/SubscriptionInfoUpdaterTest.java
index f9199f7..5b8be32 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/SubscriptionInfoUpdaterTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/SubscriptionInfoUpdaterTest.java
@@ -88,6 +88,7 @@
private static final String FAKE_ICCID_1 = "89012604200000000000";
private static final String FAKE_MCC_MNC_1 = "123456";
private static final String FAKE_MCC_MNC_2 = "456789";
+ private static final int FAKE_PHONE_ID_1 = 0;
private SubscriptionInfoUpdater mUpdater;
private IccRecords mIccRecord;
@@ -239,17 +240,17 @@
@SmallTest
public void testSimNotReady() throws Exception {
mUpdater.updateInternalIccState(
- IccCardConstants.INTENT_VALUE_ICC_NOT_READY, null, FAKE_SUB_ID_1);
+ IccCardConstants.INTENT_VALUE_ICC_NOT_READY, null, FAKE_PHONE_ID_1);
processAllMessages();
assertFalse(mUpdater.isSubInfoInitialized());
verify(mSubscriptionContent, never()).put(anyString(), any());
CarrierConfigManager mConfigManager = (CarrierConfigManager)
mContext.getSystemService(Context.CARRIER_CONFIG_SERVICE);
- verify(mConfigManager, never()).updateConfigForPhoneId(eq(FAKE_SUB_ID_1),
+ verify(mConfigManager, never()).updateConfigForPhoneId(eq(FAKE_PHONE_ID_1),
eq(IccCardConstants.INTENT_VALUE_ICC_NOT_READY));
- verify(mSubscriptionController, never()).clearSubInfo();
- verify(mSubscriptionController, never()).notifySubscriptionInfoChanged();
+ verify(mSubscriptionController).clearSubInfoRecord(FAKE_PHONE_ID_1);
+ verify(mSubscriptionController).notifySubscriptionInfoChanged();
}
@Test
@@ -259,19 +260,19 @@
doReturn(true).when(mIccCard).isEmptyProfile();
mUpdater.updateInternalIccState(
- IccCardConstants.INTENT_VALUE_ICC_NOT_READY, null, FAKE_SUB_ID_1);
+ IccCardConstants.INTENT_VALUE_ICC_NOT_READY, null, FAKE_PHONE_ID_1);
processAllMessages();
assertTrue(mUpdater.isSubInfoInitialized());
// Sub info should be cleared and change should be notified.
- verify(mSubscriptionController).clearSubInfoRecord(eq(FAKE_SUB_ID_1));
+ verify(mSubscriptionController).clearSubInfoRecord(eq(FAKE_PHONE_ID_1));
verify(mSubscriptionController).notifySubscriptionInfoChanged();
// No new sub should be added.
verify(mSubscriptionManager, never()).addSubscriptionInfoRecord(any(), anyInt());
verify(mSubscriptionContent, never()).put(anyString(), any());
CarrierConfigManager mConfigManager = (CarrierConfigManager)
mContext.getSystemService(Context.CARRIER_CONFIG_SERVICE);
- verify(mConfigManager).updateConfigForPhoneId(eq(FAKE_SUB_ID_1),
+ verify(mConfigManager).updateConfigForPhoneId(eq(FAKE_PHONE_ID_1),
eq(IccCardConstants.INTENT_VALUE_ICC_NOT_READY));
}
@@ -286,24 +287,24 @@
doReturn(false).when(mSubInfo).areUiccApplicationsEnabled();
mUpdater.updateInternalIccState(
- IccCardConstants.INTENT_VALUE_ICC_NOT_READY, null, FAKE_SUB_ID_1);
+ IccCardConstants.INTENT_VALUE_ICC_NOT_READY, null, FAKE_PHONE_ID_1);
processAllMessages();
assertTrue(mUpdater.isSubInfoInitialized());
// Sub info should be cleared and change should be notified.
- verify(mSubscriptionController).clearSubInfoRecord(eq(FAKE_SUB_ID_1));
+ verify(mSubscriptionController).clearSubInfoRecord(eq(FAKE_PHONE_ID_1));
verify(mSubscriptionController).notifySubscriptionInfoChanged();
// No new sub should be added.
verify(mSubscriptionManager, never()).addSubscriptionInfoRecord(any(), anyInt());
verify(mSubscriptionContent, never()).put(anyString(), any());
CarrierConfigManager mConfigManager = (CarrierConfigManager)
mContext.getSystemService(Context.CARRIER_CONFIG_SERVICE);
- verify(mConfigManager).updateConfigForPhoneId(eq(FAKE_SUB_ID_1),
+ verify(mConfigManager).updateConfigForPhoneId(eq(FAKE_PHONE_ID_1),
eq(IccCardConstants.INTENT_VALUE_ICC_NOT_READY));
// When becomes ABSENT, UICC_APPLICATIONS_ENABLED should be reset to true.
mUpdater.updateInternalIccState(
- IccCardConstants.INTENT_VALUE_ICC_ABSENT, null, FAKE_SUB_ID_1);
+ IccCardConstants.INTENT_VALUE_ICC_ABSENT, null, FAKE_PHONE_ID_1);
processAllMessages();
ArgumentCaptor<ContentValues> valueCapture = ArgumentCaptor.forClass(ContentValues.class);
verify(mContentProvider).update(eq(SubscriptionManager.CONTENT_URI), valueCapture.capture(),
diff --git a/tests/telephonytests/src/com/android/internal/telephony/TelephonyPermissionsTest.java b/tests/telephonytests/src/com/android/internal/telephony/TelephonyPermissionsTest.java
index dbaa29a..6ca706e 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/TelephonyPermissionsTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/TelephonyPermissionsTest.java
@@ -36,7 +36,7 @@
import android.os.Bundle;
import android.os.IBinder;
import android.os.ServiceManager;
-import android.permission.PermissionManager;
+import android.permission.LegacyPermissionManager;
import android.provider.DeviceConfig;
import android.provider.Settings;
import android.telephony.SubscriptionManager;
@@ -46,7 +46,7 @@
import android.test.suitebuilder.annotation.SmallTest;
import com.android.internal.util.test.FakeSettingsProvider;
-import com.android.server.pm.permission.PermissionManagerService;
+import com.android.server.pm.permission.LegacyPermissionManagerService;
import org.junit.Before;
import org.junit.Test;
@@ -88,7 +88,7 @@
@Mock
private TelephonyManager mTelephonyManagerMockForSub2;
@Mock
- private PermissionManagerService mMockPermissionManagerService;
+ private LegacyPermissionManagerService mMockLegacyPermissionManagerService;
private MockContentResolver mMockContentResolver;
private FakeSettingsConfigProvider mFakeSettingsConfigProvider;
@@ -107,10 +107,10 @@
when(mMockSubscriptionManager.getCompleteActiveSubscriptionIdList()).thenReturn(
new int[]{SUB_ID});
- PermissionManager permissionManager = new PermissionManager(mMockContext, null,
- mMockPermissionManagerService);
- when(mMockContext.getSystemService(Context.PERMISSION_SERVICE)).thenReturn(
- permissionManager);
+ LegacyPermissionManager legacyPermissionManager = new LegacyPermissionManager(
+ mMockLegacyPermissionManagerService);
+ when(mMockContext.getSystemService(Context.LEGACY_PERMISSION_SERVICE)).thenReturn(
+ legacyPermissionManager);
// By default, assume we have no permissions or app-ops bits.
doThrow(new SecurityException()).when(mMockContext)
@@ -325,8 +325,8 @@
// performed by a SystemAPI in PermissionManager; this test verifies when this API returns
// the calling package meets the requirements for device identifier access the telephony
// check also returns true.
- when(mMockPermissionManagerService.checkDeviceIdentifierAccess(PACKAGE, MSG, FEATURE, PID,
- UID)).thenReturn(PackageManager.PERMISSION_GRANTED);
+ when(mMockLegacyPermissionManagerService.checkDeviceIdentifierAccess(PACKAGE, MSG, FEATURE,
+ PID, UID)).thenReturn(PackageManager.PERMISSION_GRANTED);
assertTrue(
TelephonyPermissions.checkCallingOrSelfReadDeviceIdentifiers(mMockContext,
SUB_ID, PACKAGE, FEATURE, MSG));
@@ -616,7 +616,7 @@
android.Manifest.permission.READ_DEVICE_CONFIG)).thenReturn(
PackageManager.PERMISSION_GRANTED);
- when(mMockPermissionManagerService.checkDeviceIdentifierAccess(any(), any(), any(),
+ when(mMockLegacyPermissionManagerService.checkDeviceIdentifierAccess(any(), any(), any(),
anyInt(), anyInt())).thenReturn(PackageManager.PERMISSION_DENIED);
// TelephonyPermissions queries DeviceConfig to determine if the identifier access
diff --git a/tests/telephonytests/src/com/android/internal/telephony/TelephonyRegistryTest.java b/tests/telephonytests/src/com/android/internal/telephony/TelephonyRegistryTest.java
index 44dc4c7..1362b33 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/TelephonyRegistryTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/TelephonyRegistryTest.java
@@ -29,7 +29,7 @@
import static org.junit.Assert.fail;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
-import static org.mockito.Mockito.anyString;
+import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
@@ -65,7 +65,6 @@
import org.junit.After;
import org.junit.Before;
-import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
@@ -92,6 +91,7 @@
private int mSrvccState = -1;
private int mRadioPowerState = RADIO_POWER_UNAVAILABLE;
private List<PhysicalChannelConfig> mPhysicalChannelConfigs;
+ private TelephonyRegistry.ConfigurationProvider mMockConfigurationProvider;
private CellLocation mCellLocation;
// All events contribute to TelephonyRegistry#isPhoneStatePermissionRequired
@@ -198,18 +198,18 @@
@Override
public void onLinkCapacityEstimateChanged(
List<LinkCapacityEstimate> linkCapacityEstimateList) {
- mLinkCapacityEstimateList = linkCapacityEstimateList;
- }
-
- @Override
- public void onPhysicalChannelConfigChanged(@NonNull List<PhysicalChannelConfig> configs) {
- mPhysicalChannelConfigs = configs;
+ mLinkCapacityEstimateList = linkCapacityEstimateList;
}
@Override
public void onCellLocationChanged(CellLocation location) {
mCellLocation = location;
}
+
+ @Override
+ public void onPhysicalChannelConfigChanged(@NonNull List<PhysicalChannelConfig> configs) {
+ mPhysicalChannelConfigs = configs;
+ }
}
private void addTelephonyRegistryService() {
@@ -227,12 +227,13 @@
@Before
public void setUp() throws Exception {
super.setUp("TelephonyRegistryTest");
- TelephonyRegistry.ConfigurationProvider mockConfigurationProvider =
- mock(TelephonyRegistry.ConfigurationProvider.class);
- when(mockConfigurationProvider.getRegistrationLimit()).thenReturn(-1);
- when(mockConfigurationProvider.isRegistrationLimitEnabledInPlatformCompat(anyInt()))
+ mMockConfigurationProvider = mock(TelephonyRegistry.ConfigurationProvider.class);
+ when(mMockConfigurationProvider.getRegistrationLimit()).thenReturn(-1);
+ when(mMockConfigurationProvider.isRegistrationLimitEnabledInPlatformCompat(anyInt()))
.thenReturn(false);
- mTelephonyRegistry = new TelephonyRegistry(mContext, mockConfigurationProvider);
+ when(mMockConfigurationProvider.isCallStateReadPhoneStateEnforcedInPlatformCompat(
+ anyString(), any())).thenReturn(false);
+ mTelephonyRegistry = new TelephonyRegistry(mContext, mMockConfigurationProvider);
addTelephonyRegistryService();
mTelephonyCallback = new TelephonyCallbackWrapper();
mTelephonyCallback.init(mSimpleExecutor);
@@ -252,7 +253,7 @@
doReturn(mMockSubInfo).when(mSubscriptionManager).getActiveSubscriptionInfo(anyInt());
doReturn(0/*slotIndex*/).when(mMockSubInfo).getSimSlotIndex();
// mTelephonyRegistry.listen with notifyNow = true should trigger callback immediately.
- PhoneCapability phoneCapability = new PhoneCapability(1, 2, 3, null, false);
+ PhoneCapability phoneCapability = new PhoneCapability(1, 2, null, false, new int[0]);
int[] events = {TelephonyCallback.EVENT_PHONE_CAPABILITY_CHANGED};
mTelephonyRegistry.notifyPhoneCapabilityChanged(phoneCapability);
mTelephonyRegistry.listenWithEventList(0, mContext.getOpPackageName(),
@@ -261,7 +262,7 @@
assertEquals(phoneCapability, mPhoneCapability);
// notifyPhoneCapabilityChanged with a new capability. Callback should be triggered.
- phoneCapability = new PhoneCapability(3, 2, 2, null, false);
+ phoneCapability = new PhoneCapability(3, 2, null, false, new int[0]);
mTelephonyRegistry.notifyPhoneCapabilityChanged(phoneCapability);
processAllMessages();
assertEquals(phoneCapability, mPhoneCapability);
@@ -487,19 +488,41 @@
assertSecurityExceptionThrown(
READ_PHONE_STATE_EVENTS.stream().mapToInt(i -> i).toArray());
- // Grant permssion
+ // Grant permission
mContextFixture.addCallingOrSelfPermission(android.Manifest.permission.READ_PHONE_STATE);
assertSecurityExceptionNotThrown(
READ_PHONE_STATE_EVENTS.stream().mapToInt(i -> i).toArray());
}
/**
+ * Test enforcement of READ_PHONE_STATE for call state related events.
+ */
+ @Test
+ public void testCallStateChangedPermission() {
+ int[] events = new int[] {TelephonyCallback.EVENT_CALL_STATE_CHANGED,
+ TelephonyCallback.EVENT_LEGACY_CALL_STATE_CHANGED};
+ // Disable change ID for READ_PHONE_STATE enforcement
+ when(mMockConfigurationProvider.isCallStateReadPhoneStateEnforcedInPlatformCompat(
+ anyString(), any())).thenReturn(false);
+ // Start without READ_PHONE_STATE permission
+ mContextFixture.addCallingOrSelfPermission("");
+ assertSecurityExceptionNotThrown(events);
+ // Grant permission
+ mContextFixture.addCallingOrSelfPermission(android.Manifest.permission.READ_PHONE_STATE);
+ assertSecurityExceptionNotThrown(events);
+ //Enable READ_PHONE_STATE enforcement
+ when(mMockConfigurationProvider.isCallStateReadPhoneStateEnforcedInPlatformCompat(
+ anyString(), any())).thenReturn(true);
+ assertSecurityExceptionNotThrown(events);
+ // revoke READ_PHONE_STATE permission
+ mContextFixture.removeCallingOrSelfPermission(android.Manifest.permission.READ_PHONE_STATE);
+ assertSecurityExceptionThrown(events);
+
+ }
+
+ /**
* Test listen to events that require READ_PRECISE_PHONE_STATE permission.
*/
- // FIXME(b/159082270) - Simply not granting location permission doesn't fix the test because
- // Location is soft-denied to apps that aren't in the foreground, and soft-denial currently
- // short-circuits the test.
- @Ignore("Skip due to b/159082270")
@Test
public void testReadPrecisePhoneStatePermission() {
// Clear all permission grants for test.
@@ -514,7 +537,7 @@
assertSecurityExceptionThrown(
READ_PRECISE_PHONE_STATE_EVENTS.stream().mapToInt(i -> i).toArray());
- // Grant permssion
+ // Grant permission
mContextFixture.addCallingOrSelfPermission(
android.Manifest.permission.READ_PRECISE_PHONE_STATE);
assertSecurityExceptionNotThrown(
@@ -555,7 +578,7 @@
assertSecurityExceptionThrown(
READ_PRIVILEGED_PHONE_STATE_EVENTS.stream().mapToInt(i -> i).toArray());
- // Grant permssion
+ // Grant permission
mContextFixture.addCallingOrSelfPermission(
android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE);
assertSecurityExceptionNotThrown(
@@ -572,7 +595,7 @@
assertSecurityExceptionThrown(
READ_ACTIVE_EMERGENCY_SESSION_EVENTS.stream().mapToInt(i -> i).toArray());
- // Grant permssion
+ // Grant permission
mContextFixture.addCallingOrSelfPermission(
android.Manifest.permission.READ_ACTIVE_EMERGENCY_SESSION);
assertSecurityExceptionNotThrown(
diff --git a/tests/telephonytests/src/com/android/internal/telephony/TelephonyTest.java b/tests/telephonytests/src/com/android/internal/telephony/TelephonyTest.java
index ab076d8..b1f0e2e 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/TelephonyTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/TelephonyTest.java
@@ -58,7 +58,7 @@
import android.os.RegistrantList;
import android.os.ServiceManager;
import android.os.UserManager;
-import android.permission.PermissionManager;
+import android.permission.LegacyPermissionManager;
import android.provider.BlockedNumberContract;
import android.provider.DeviceConfig;
import android.provider.Settings;
@@ -88,6 +88,7 @@
import com.android.internal.telephony.dataconnection.DataEnabledSettings;
import com.android.internal.telephony.dataconnection.DataThrottler;
import com.android.internal.telephony.dataconnection.DcTracker;
+import com.android.internal.telephony.dataconnection.LinkBandwidthEstimator;
import com.android.internal.telephony.dataconnection.TransportManager;
import com.android.internal.telephony.emergency.EmergencyNumberTracker;
import com.android.internal.telephony.imsphone.ImsExternalCallTracker;
@@ -112,6 +113,7 @@
import com.android.internal.telephony.uicc.UiccProfile;
import com.android.internal.telephony.uicc.UiccSlot;
import com.android.server.pm.PackageManagerService;
+import com.android.server.pm.permission.LegacyPermissionManagerService;
import com.android.server.pm.permission.PermissionManagerService;
import org.mockito.Mock;
@@ -208,6 +210,8 @@
@Mock
protected PackageManagerService mMockPackageManager;
@Mock
+ protected LegacyPermissionManagerService mMockLegacyPermissionManager;
+ @Mock
protected PermissionManagerService mMockPermissionManager;
protected NetworkRegistrationInfo mNetworkRegistrationInfo =
@@ -320,6 +324,8 @@
@Mock
protected ImsStats mImsStats;
@Mock
+ protected LinkBandwidthEstimator mLinkBandwidthEstimator;
+ @Mock
protected PinStorage mPinStorage;
@Mock
protected LocationManager mLocationManager;
@@ -534,6 +540,8 @@
.makeDataEnabledSettings(nullable(Phone.class));
doReturn(mEriManager).when(mTelephonyComponentFactory)
.makeEriManager(nullable(Phone.class), anyInt());
+ doReturn(mLinkBandwidthEstimator).when(mTelephonyComponentFactory)
+ .makeLinkBandwidthEstimator(nullable(Phone.class));
//mPhone
doReturn(mContext).when(mPhone).getContext();
@@ -564,6 +572,7 @@
doReturn(mSmsStats).when(mPhone).getSmsStats();
doReturn(mImsStats).when(mImsPhone).getImsStats();
mIccSmsInterfaceManager.mDispatchersController = mSmsDispatchersController;
+ doReturn(mLinkBandwidthEstimator).when(mPhone).getLinkBandwidthEstimator();
//mUiccController
doReturn(mUiccCardApplication3gpp).when(mUiccController).getUiccCardApplication(anyInt(),
@@ -640,6 +649,7 @@
mSST.mRestrictedState = mRestrictedState;
mServiceManagerMockedServices.put("connectivity_metrics_logger", mConnMetLoggerBinder);
mServiceManagerMockedServices.put("package", mMockPackageManager);
+ mServiceManagerMockedServices.put("legacy_permission", mMockLegacyPermissionManager);
mServiceManagerMockedServices.put("permissionmgr", mMockPermissionManager);
logd("mMockPermissionManager replaced");
doReturn(new int[]{AccessNetworkConstants.TRANSPORT_TYPE_WWAN,
@@ -850,12 +860,21 @@
// TelephonyPermissions uses a SystemAPI to check if the calling package meets any of the
// generic requirements for device identifier access (currently READ_PRIVILEGED_PHONE_STATE,
- // appop, and device / profile owner checks. This sets up the PermissionManager to return
+ // appop, and device / profile owner checks). This sets up the PermissionManager to return
// that access requirements are met.
setIdentifierAccess(true);
- PermissionManager permissionManager = new PermissionManager(mContext, null,
- mMockPermissionManager);
- doReturn(permissionManager).when(mContext).getSystemService(eq(Context.PERMISSION_SERVICE));
+ LegacyPermissionManager legacyPermissionManager =
+ new LegacyPermissionManager(mMockLegacyPermissionManager);
+ doReturn(legacyPermissionManager).when(mContext)
+ .getSystemService(Context.LEGACY_PERMISSION_SERVICE);
+ // Also make sure all appop checks fails, to not interfere tests. Tests should explicitly
+ // mock AppOpManager to return allowed/default mode. Note by default a mock returns 0 which
+ // is MODE_ALLOWED, hence this setup is necessary.
+ doReturn(AppOpsManager.MODE_IGNORED).when(mAppOpsManager).noteOpNoThrow(
+ /* op= */ anyString(), /* uid= */ anyInt(),
+ /* packageName= */ nullable(String.class),
+ /* attributionTag= */ nullable(String.class),
+ /* message= */ nullable(String.class));
// TelephonyPermissions queries DeviceConfig to determine if the identifier access
// restrictions should be enabled; this results in a NPE when DeviceConfig uses
@@ -882,9 +901,8 @@
protected void setIdentifierAccess(boolean hasAccess) {
doReturn(hasAccess ? PackageManager.PERMISSION_GRANTED
- : PackageManager.PERMISSION_DENIED).when(
- mMockPermissionManager).checkDeviceIdentifierAccess(any(), any(), any(), anyInt(),
- anyInt());
+ : PackageManager.PERMISSION_DENIED).when(mMockLegacyPermissionManager)
+ .checkDeviceIdentifierAccess(any(), any(), any(), anyInt(), anyInt());
}
protected void setCarrierPrivileges(boolean hasCarrierPrivileges) {
diff --git a/tests/telephonytests/src/com/android/internal/telephony/d2d/CommunicatorTest.java b/tests/telephonytests/src/com/android/internal/telephony/d2d/CommunicatorTest.java
index 2ebb1bc..40abd53 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/d2d/CommunicatorTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/d2d/CommunicatorTest.java
@@ -57,7 +57,6 @@
MockitoAnnotations.initMocks(this);
TransportProtocol protocol1 = getMockTransportProtocol();
TransportProtocol protocol2 = getMockTransportProtocol();
-
mTransportProtocols.add(protocol1);
mTransportProtocols.add(protocol2);
}
diff --git a/tests/telephonytests/src/com/android/internal/telephony/d2d/RtpTransportConversionTest.java b/tests/telephonytests/src/com/android/internal/telephony/d2d/RtpTransportConversionTest.java
index 72fda53..0c251a0 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/d2d/RtpTransportConversionTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/d2d/RtpTransportConversionTest.java
@@ -26,7 +26,6 @@
import android.os.Handler;
import android.telephony.ims.RtpHeaderExtension;
-import android.telephony.ims.RtpHeaderExtensionType;
import android.test.suitebuilder.annotation.SmallTest;
import android.util.ArraySet;
@@ -84,7 +83,7 @@
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
- mRtpTransport = new RtpTransport(mRtpAdapter, mTimeoutsAdapter, mHandler);
+ mRtpTransport = new RtpTransport(mRtpAdapter, mTimeoutsAdapter, mHandler, true /* sdp */);
mRtpTransport.setCallback(mCallback);
when(mRtpAdapter.getAcceptedRtpHeaderExtensions()).thenReturn(
diff --git a/tests/telephonytests/src/com/android/internal/telephony/d2d/RtpTransportTest.java b/tests/telephonytests/src/com/android/internal/telephony/d2d/RtpTransportTest.java
index 4208212..c241cf2 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/d2d/RtpTransportTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/d2d/RtpTransportTest.java
@@ -67,7 +67,7 @@
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
- mRtpTransport = new RtpTransport(mRtpAdapter, mTimeoutsAdapter, mHandler);
+ mRtpTransport = new RtpTransport(mRtpAdapter, mTimeoutsAdapter, mHandler, true /* sdp */);
mRtpTransport.setCallback(mCallback);
}
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 1940ad0..a6cdcae 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/dataconnection/DataConnectionTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/dataconnection/DataConnectionTest.java
@@ -419,11 +419,11 @@
assertEquals("spmode.ne.jp", dpCaptor.getValue().getApn());
if (tdCaptor.getValue() != null) {
if (mApnContext.getApnTypeBitmask() == ApnSetting.TYPE_ENTERPRISE) {
- assertEquals(null, tdCaptor.getValue().getDnn());
+ assertEquals(null, tdCaptor.getValue().getDataNetworkName());
assertTrue(tdCaptor.getValue().getOsAppId()
.contains(ApnSetting.TYPE_ENTERPRISE_STRING));
} else {
- assertEquals("spmode.ne.jp", tdCaptor.getValue().getDnn());
+ assertEquals("spmode.ne.jp", tdCaptor.getValue().getDataNetworkName());
assertEquals(null, tdCaptor.getValue().getOsAppId());
}
}
@@ -789,12 +789,14 @@
assertTrue(getNetworkCapabilities().hasCapability(NET_CAPABILITY_NOT_CONGESTED));
mDc.onMeterednessChanged(true);
+ waitForMs(100);
assertFalse(getNetworkCapabilities().hasCapability(NET_CAPABILITY_NOT_METERED));
assertTrue(getNetworkCapabilities().hasCapability(NET_CAPABILITY_TEMPORARILY_NOT_METERED));
assertTrue(getNetworkCapabilities().hasCapability(NET_CAPABILITY_NOT_CONGESTED));
mDc.onMeterednessChanged(false);
+ waitForMs(100);
assertFalse(getNetworkCapabilities().hasCapability(NET_CAPABILITY_NOT_METERED));
assertFalse(getNetworkCapabilities().hasCapability(NET_CAPABILITY_TEMPORARILY_NOT_METERED));
@@ -813,12 +815,14 @@
assertTrue(getNetworkCapabilities().hasCapability(NET_CAPABILITY_NOT_CONGESTED));
mDc.onCongestednessChanged(true);
+ waitForMs(100);
assertFalse(getNetworkCapabilities().hasCapability(NET_CAPABILITY_NOT_METERED));
assertFalse(getNetworkCapabilities().hasCapability(NET_CAPABILITY_TEMPORARILY_NOT_METERED));
assertFalse(getNetworkCapabilities().hasCapability(NET_CAPABILITY_NOT_CONGESTED));
mDc.onCongestednessChanged(false);
+ waitForMs(100);
assertFalse(getNetworkCapabilities().hasCapability(NET_CAPABILITY_NOT_METERED));
assertFalse(getNetworkCapabilities().hasCapability(NET_CAPABILITY_TEMPORARILY_NOT_METERED));
diff --git a/tests/telephonytests/src/com/android/internal/telephony/dataconnection/DataProfileTest.java b/tests/telephonytests/src/com/android/internal/telephony/dataconnection/DataProfileTest.java
index 55f621a..b641ecd 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/dataconnection/DataProfileTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/dataconnection/DataProfileTest.java
@@ -107,6 +107,33 @@
-1, // mvno_type
""); // mnvo_match_data
+ private ApnSetting mApn4 = ApnSetting.makeApnSetting(
+ 2163, // id
+ "44010", // numeric
+ "sp-mode", // name
+ "fake_apn", // apn
+ null, // proxy
+ -1, // port
+ null, // mmsc
+ null, // mmsproxy
+ -1, // mmsport
+ "user", // user
+ "passwd", // password
+ -1, // authtype
+ ApnSetting.TYPE_DEFAULT | ApnSetting.TYPE_SUPL, // types
+ ApnSetting.PROTOCOL_IP, // protocol
+ ApnSetting.PROTOCOL_IP, // roaming_protocol
+ true, // carrier_enabled
+ 10360, // networktype_bitmask
+ 1234, // profile_id
+ false, // modem_cognitive
+ 111, // max_conns
+ 456, // wait_time
+ 789, // max_conns_time
+ 0, // mtu
+ -1, // mvno_type
+ ""); // mnvo_match_data
+
@SmallTest
public void testCreateFromApnSetting() throws Exception {
DataProfile dp = DcTracker.createDataProfile(mApn1, mApn1.getProfileId(), false);
@@ -132,11 +159,13 @@
assertEquals(RILConstants.SETUP_DATA_AUTH_PAP_CHAP, dp.getAuthType());
assertEquals(mApn3.getUser(), dp.getUserName());
assertEquals(mApn3.getPassword(), dp.getPassword());
- assertEquals(2, dp.getType()); // TYPE_3GPP2
+ assertEquals(0, dp.getType()); // TYPE_COMMON
assertEquals(mApn3.getWaitTime(), dp.getWaitTime());
assertEquals(mApn3.isEnabled(), dp.isEnabled());
int expectedBearerBitmap = mApn3.getNetworkTypeBitmask();
assertEquals(expectedBearerBitmap, dp.getBearerBitmask());
+ dp = DcTracker.createDataProfile(mApn4, mApn4.getProfileId(), false);
+ assertEquals(2, dp.getType()); // TYPE_3GPP2
}
@SmallTest
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 23e7b04..a1b91e5 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/dataconnection/DcTrackerTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/dataconnection/DcTrackerTest.java
@@ -1199,7 +1199,7 @@
eq(AccessNetworkType.EUTRAN), any(DataProfile.class), eq(false), eq(false),
eq(DataService.REQUEST_REASON_NORMAL), any(), anyInt(), any(), tdCaptor.capture(),
anyBoolean(), any(Message.class));
- assertEquals("FAKE APN 1", tdCaptor.getValue().getDnn());
+ assertEquals("FAKE APN 1", tdCaptor.getValue().getDataNetworkName());
assertEquals(null, tdCaptor.getValue().getOsAppId());
mNetworkRegistrationInfo = new NetworkRegistrationInfo.Builder()
@@ -1218,8 +1218,8 @@
eq(AccessNetworkType.NGRAN), any(DataProfile.class), eq(false), eq(false),
eq(DataService.REQUEST_REASON_NORMAL), any(), anyInt(), any(), tdCaptor.capture(),
anyBoolean(), any(Message.class));
- assertEquals(null, tdCaptor.getValue().getDnn());
- assertTrue(tdCaptor.getValue().getOsAppId().contains(ApnSetting.TYPE_ENTERPRISE_STRING));
+ assertEquals(null, tdCaptor.getValue().getDataNetworkName());
+ assertTrue(tdCaptor.getValue().getOsAppId().equals("ENTERPRISE"));
}
@Test
@@ -2186,7 +2186,7 @@
// NetCapability should switch to unmetered with fr=MMWAVE
doReturn(new TelephonyDisplayInfo(TelephonyManager.NETWORK_TYPE_LTE,
- TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_NSA_MMWAVE))
+ TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_ADVANCED))
.when(mDisplayInfoController).getTelephonyDisplayInfo();
mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_TELEPHONY_DISPLAY_INFO_CHANGED));
waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler());
@@ -2223,7 +2223,7 @@
// NetCapability should switch to unmetered when fr=MMWAVE and MMWAVE unmetered
doReturn(new TelephonyDisplayInfo(TelephonyManager.NETWORK_TYPE_LTE,
- TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_NSA_MMWAVE))
+ TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_ADVANCED))
.when(mDisplayInfoController).getTelephonyDisplayInfo();
mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_TELEPHONY_DISPLAY_INFO_CHANGED));
waitForLastHandlerAction(mDcTrackerTestHandler.getThreadHandler());
diff --git a/tests/telephonytests/src/com/android/internal/telephony/dataconnection/LinkBandwidthEstimatorTest.java b/tests/telephonytests/src/com/android/internal/telephony/dataconnection/LinkBandwidthEstimatorTest.java
new file mode 100644
index 0000000..e48f183
--- /dev/null
+++ b/tests/telephonytests/src/com/android/internal/telephony/dataconnection/LinkBandwidthEstimatorTest.java
@@ -0,0 +1,547 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.telephony.dataconnection;
+
+import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
+
+import static com.android.internal.telephony.dataconnection.LinkBandwidthEstimator.BW_STATS_COUNT_THRESHOLD;
+import static com.android.internal.telephony.dataconnection.LinkBandwidthEstimator.LINK_RX;
+import static com.android.internal.telephony.dataconnection.LinkBandwidthEstimator.LINK_TX;
+import static com.android.internal.telephony.dataconnection.LinkBandwidthEstimator.MSG_DEFAULT_NETWORK_CHANGED;
+import static com.android.internal.telephony.dataconnection.LinkBandwidthEstimator.MSG_MODEM_ACTIVITY_RETURNED;
+import static com.android.internal.telephony.dataconnection.LinkBandwidthEstimator.MSG_NR_FREQUENCY_CHANGED;
+import static com.android.internal.telephony.dataconnection.LinkBandwidthEstimator.MSG_SCREEN_STATE_CHANGED;
+import static com.android.internal.telephony.dataconnection.LinkBandwidthEstimator.MSG_SIGNAL_STRENGTH_CHANGED;
+import static com.android.internal.telephony.dataconnection.LinkBandwidthEstimator.UNKNOWN_TAC;
+
+import static org.junit.Assert.*;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.Mockito.eq;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.net.NetworkCapabilities;
+import android.telephony.CellIdentityLte;
+import android.telephony.ModemActivityInfo;
+import android.telephony.NetworkRegistrationInfo;
+import android.telephony.ServiceState;
+import android.telephony.TelephonyManager;
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
+import android.util.Pair;
+
+import com.android.internal.telephony.TelephonyFacade;
+import com.android.internal.telephony.TelephonyTest;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+
+@RunWith(AndroidTestingRunner.class)
+@TestableLooper.RunWithLooper
+public class LinkBandwidthEstimatorTest extends TelephonyTest {
+ private LinkBandwidthEstimator mLBE;
+ private static final int [] TX_TIME_1_MS = new int[]{0, 0, 0, 0, 0};
+ private static final int [] TX_TIME_2_MS = new int[]{100, 0, 0, 0, 100};
+ private static final int RX_TIME_1_MS = 100;
+ private static final int RX_TIME_2_MS = 200;
+ private static final ModemActivityInfo MAI_INIT =
+ new ModemActivityInfo(0, 0, 0, TX_TIME_1_MS, RX_TIME_1_MS);
+ private static final ModemActivityInfo MAI_TX_RX_TIME_HIGH =
+ new ModemActivityInfo(100L, 0, 0, TX_TIME_2_MS, RX_TIME_2_MS);
+ private static final ModemActivityInfo MAI_RX_TIME_HIGH =
+ new ModemActivityInfo(100L, 0, 0, TX_TIME_1_MS, RX_TIME_2_MS);
+ private NetworkCapabilities mNetworkCapabilities;
+ private CellIdentityLte mCellIdentity;
+ private long mElapsedTimeMs = 0;
+ private long mTxBytes = 0;
+ private long mRxBytes = 0;
+ @Mock
+ TelephonyFacade mTelephonyFacade;
+ @Mock
+ DataConnection mDataConnection;
+ private NetworkRegistrationInfo mNri;
+
+ @Before
+ public void setUp() throws Exception {
+ super.setUp(getClass().getSimpleName());
+ mNetworkCapabilities = new NetworkCapabilities.Builder()
+ .addTransportType(TRANSPORT_CELLULAR)
+ .build();
+
+ mCellIdentity = new CellIdentityLte(310, 260, 1234, 123456, 366);
+ mNri = new NetworkRegistrationInfo.Builder()
+ .setAccessNetworkTechnology(TelephonyManager.NETWORK_TYPE_LTE)
+ .build();
+ when(mServiceState.getNetworkRegistrationInfo(anyInt(), anyInt())).thenReturn(mNri);
+ when(mTelephonyFacade.getElapsedSinceBootMillis()).thenReturn(0L);
+ when(mTelephonyFacade.getMobileTxBytes()).thenReturn(0L);
+ when(mTelephonyFacade.getMobileTxBytes()).thenReturn(0L);
+ when(mPhone.getCurrentCellIdentity()).thenReturn(mCellIdentity);
+ when(mDcTracker.getDataConnectionByApnType(anyString())).thenReturn(mDataConnection);
+ when(mSignalStrength.getDbm()).thenReturn(-100);
+ when(mSignalStrength.getLevel()).thenReturn(1);
+ mLBE = new LinkBandwidthEstimator(mPhone, mTelephonyFacade);
+ mLBE.obtainMessage(MSG_DEFAULT_NETWORK_CHANGED, mNetworkCapabilities).sendToTarget();
+ processAllMessages();
+ }
+
+ private void addElapsedTime(long timeMs) {
+ mElapsedTimeMs += timeMs;
+ when(mTelephonyFacade.getElapsedSinceBootMillis()).thenReturn(mElapsedTimeMs);
+ }
+
+ private void addTxBytes(long txBytes) {
+ mTxBytes += txBytes;
+ when(mTelephonyFacade.getMobileTxBytes()).thenReturn(mTxBytes);
+ }
+
+ private void addRxBytes(long rxBytes) {
+ mRxBytes += rxBytes;
+ when(mTelephonyFacade.getMobileRxBytes()).thenReturn(mRxBytes);
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ super.tearDown();
+ }
+
+ @Test
+ public void testScreenOnTxTrafficHighOneModemPoll() throws Exception {
+ addElapsedTime(4_100);
+ moveTimeForward(4_100);
+ mLBE.obtainMessage(MSG_SCREEN_STATE_CHANGED, true).sendToTarget();
+ addTxBytes(500_000L);
+ addRxBytes(10_000L);
+ addElapsedTime(2_100);
+ moveTimeForward(2_100);
+ processAllMessages();
+
+ verify(mTelephonyManager, times(1)).requestModemActivityInfo(any(), any());
+ }
+
+ @Test
+ public void testScreenOnTxRxTrafficHighTwoModemPoll() throws Exception {
+ addElapsedTime(4_100);
+ moveTimeForward(4_100);
+ mLBE.obtainMessage(MSG_SCREEN_STATE_CHANGED, true).sendToTarget();
+ processAllMessages();
+
+ addTxBytes(10_000L);
+ addRxBytes(20_000L);
+ addElapsedTime(2_100);
+ moveTimeForward(2_100);
+ processAllMessages();
+ verify(mTelephonyManager, times(1)).requestModemActivityInfo(any(), any());
+
+ mLBE.obtainMessage(MSG_MODEM_ACTIVITY_RETURNED, MAI_INIT).sendToTarget();
+ processAllMessages();
+
+ addTxBytes(100_000L);
+ addRxBytes(200_000L);
+ addElapsedTime(5_100);
+ moveTimeForward(5_100);
+ processAllMessages();
+
+ mLBE.obtainMessage(MSG_MODEM_ACTIVITY_RETURNED, MAI_TX_RX_TIME_HIGH).sendToTarget();
+ processAllMessages();
+
+ verify(mTelephonyManager, times(2)).requestModemActivityInfo(any(), any());
+ verify(mDataConnection, times(1)).updateLinkBandwidthEstimation(eq(-1), eq(-1));
+ }
+
+ @Test
+ public void testScreenOnRxTrafficHighTwoModemPollRxTimeHigh() throws Exception {
+ addElapsedTime(4_100);
+ moveTimeForward(4_100);
+ mLBE.obtainMessage(MSG_SCREEN_STATE_CHANGED, true).sendToTarget();
+ processAllMessages();
+
+ addTxBytes(10_000L);
+ addRxBytes(20_000L);
+ addElapsedTime(2_100);
+ moveTimeForward(2_100);
+ processAllMessages();
+ verify(mTelephonyManager, times(1)).requestModemActivityInfo(any(), any());
+
+ mLBE.obtainMessage(MSG_MODEM_ACTIVITY_RETURNED, MAI_INIT).sendToTarget();
+ processAllMessages();
+
+ addTxBytes(100_000L);
+ addRxBytes(200_000L);
+ addElapsedTime(5_100);
+ moveTimeForward(5_100);
+ processAllMessages();
+
+ mLBE.obtainMessage(MSG_MODEM_ACTIVITY_RETURNED, MAI_RX_TIME_HIGH).sendToTarget();
+ processAllMessages();
+
+ verify(mTelephonyManager, times(2)).requestModemActivityInfo(any(), any());
+ verify(mDataConnection, times(1)).updateLinkBandwidthEstimation(eq(-1), eq(-1));
+ }
+
+ @Test
+ public void testScreenOnTxRxTrafficLow() throws Exception {
+ addElapsedTime(4_100);
+ moveTimeForward(4_100);
+ mLBE.obtainMessage(MSG_SCREEN_STATE_CHANGED, true).sendToTarget();
+ addTxBytes(10_000L);
+ addRxBytes(10_000L);
+ addElapsedTime(2_100);
+ moveTimeForward(2_100);
+ processAllMessages();
+ verify(mTelephonyManager, never()).requestModemActivityInfo(any(), any());
+ }
+
+ @Test
+ public void testScreenOnTrafficLowSampleHighAcc() throws Exception {
+ addElapsedTime(4_100);
+ moveTimeForward(4_100);
+ mLBE.obtainMessage(MSG_SCREEN_STATE_CHANGED, true).sendToTarget();
+ for (int i = 0; i < 30; i++) {
+ addTxBytes(10_000L);
+ addRxBytes(19_000L);
+ addElapsedTime(1_100);
+ moveTimeForward(1_100);
+ processAllMessages();
+ }
+ verify(mTelephonyManager, times(2)).requestModemActivityInfo(any(), any());
+ }
+
+ @Test
+ public void testScreenOnDefaultNetworkToggleNoExtraTrafficPoll() throws Exception {
+ mLBE.obtainMessage(MSG_SCREEN_STATE_CHANGED, true).sendToTarget();
+ processAllMessages();
+ mLBE.obtainMessage(MSG_DEFAULT_NETWORK_CHANGED, null).sendToTarget();
+ addElapsedTime(500);
+ moveTimeForward(500);
+ processAllMessages();
+ mLBE.obtainMessage(MSG_DEFAULT_NETWORK_CHANGED, mNetworkCapabilities).sendToTarget();
+ for (int i = 0; i < 3; i++) {
+ addElapsedTime(1_100);
+ moveTimeForward(1_100);
+ processAllMessages();
+ }
+
+ verify(mTelephonyFacade, times(4)).getMobileTxBytes();
+ }
+
+ @Test
+ public void testRatChangeTriggerBandwidthUpdate() throws Exception {
+ mLBE.obtainMessage(MSG_SCREEN_STATE_CHANGED, true).sendToTarget();
+ addTxBytes(10_000L);
+ addRxBytes(19_000L);
+ addElapsedTime(2000);
+ moveTimeForward(2000);
+ processAllMessages();
+
+ addTxBytes(10_000L);
+ addRxBytes(19_000L);
+ mNri = new NetworkRegistrationInfo.Builder()
+ .setAccessNetworkTechnology(TelephonyManager.NETWORK_TYPE_NR)
+ .build();
+ when(mServiceState.getNetworkRegistrationInfo(anyInt(), anyInt())).thenReturn(mNri);
+ addElapsedTime(6000);
+ moveTimeForward(6000);
+ processAllMessages();
+
+ verify(mTelephonyManager, times(0)).requestModemActivityInfo(any(), any());
+ verify(mDataConnection, times(2)).updateLinkBandwidthEstimation(eq(-1), eq(-1));
+ }
+
+ @Test
+ public void testSignalLevelChangeTriggerBandwidthUpdate() throws Exception {
+ mLBE.obtainMessage(MSG_SCREEN_STATE_CHANGED, true).sendToTarget();
+ processAllMessages();
+
+ for (int i = 0; i < BW_STATS_COUNT_THRESHOLD + 2; i++) {
+ addTxBytes(10_000L);
+ addRxBytes(500_000L);
+ addElapsedTime(5_100);
+ moveTimeForward(5_100);
+ processAllMessages();
+ mLBE.obtainMessage(MSG_MODEM_ACTIVITY_RETURNED, new ModemActivityInfo(
+ i * 5_100L, 0, 0, TX_TIME_2_MS, i * RX_TIME_2_MS)).sendToTarget();
+ processAllMessages();
+ }
+
+ verify(mDataConnection, times(1)).updateLinkBandwidthEstimation(eq(-1), eq(-1));
+ verify(mDataConnection, times(1)).updateLinkBandwidthEstimation(eq(-1), eq(19_597));
+
+ addTxBytes(20_000L);
+ addRxBytes(50_000L);
+ when(mSignalStrength.getDbm()).thenReturn(-110);
+ mLBE.obtainMessage(MSG_SIGNAL_STRENGTH_CHANGED, mSignalStrength).sendToTarget();
+ addElapsedTime(6000);
+ moveTimeForward(6000);
+ processAllMessages();
+
+ verify(mDataConnection, times(2)).updateLinkBandwidthEstimation(eq(-1), eq(-1));
+ }
+
+ @Test
+ public void testAvgBwForAllPossibleRat() throws Exception {
+ Pair<Integer, Integer> values = mLBE.getStaticAvgBw(TelephonyManager.NETWORK_TYPE_GPRS);
+ assertEquals(24, (int) values.second);
+ values = mLBE.getStaticAvgBw(TelephonyManager.NETWORK_TYPE_EDGE);
+ assertEquals(18, (int) values.second);
+ values = mLBE.getStaticAvgBw(TelephonyManager.NETWORK_TYPE_UMTS);
+ assertEquals(115, (int) values.second);
+ values = mLBE.getStaticAvgBw(TelephonyManager.NETWORK_TYPE_CDMA);
+ assertEquals(14, (int) values.second);
+ values = mLBE.getStaticAvgBw(TelephonyManager.NETWORK_TYPE_1xRTT);
+ assertEquals(30, (int) values.second);
+ values = mLBE.getStaticAvgBw(TelephonyManager.NETWORK_TYPE_EVDO_0);
+ assertEquals(48, (int) values.second);
+ values = mLBE.getStaticAvgBw(TelephonyManager.NETWORK_TYPE_EVDO_A);
+ assertEquals(550, (int) values.second);
+ values = mLBE.getStaticAvgBw(TelephonyManager.NETWORK_TYPE_HSDPA);
+ assertEquals(620, (int) values.second);
+ values = mLBE.getStaticAvgBw(TelephonyManager.NETWORK_TYPE_HSUPA);
+ assertEquals(1800, (int) values.second);
+ values = mLBE.getStaticAvgBw(TelephonyManager.NETWORK_TYPE_HSPA);
+ assertEquals(1800, (int) values.second);
+ values = mLBE.getStaticAvgBw(TelephonyManager.NETWORK_TYPE_EVDO_B);
+ assertEquals(550, (int) values.second);
+ values = mLBE.getStaticAvgBw(TelephonyManager.NETWORK_TYPE_EHRPD);
+ assertEquals(750, (int) values.first);
+ values = mLBE.getStaticAvgBw(TelephonyManager.NETWORK_TYPE_HSPAP);
+ assertEquals(3400, (int) values.second);
+ values = mLBE.getStaticAvgBw(TelephonyManager.NETWORK_TYPE_TD_SCDMA);
+ assertEquals(115, (int) values.first);
+ values = mLBE.getStaticAvgBw(TelephonyManager.NETWORK_TYPE_LTE);
+ assertEquals(15000, (int) values.second);
+ when(mServiceState.getNrState()).thenReturn(NetworkRegistrationInfo.NR_STATE_CONNECTED);
+ when(mServiceState.getNrFrequencyRange()).thenReturn(ServiceState.FREQUENCY_RANGE_MMWAVE);
+ values = mLBE.getStaticAvgBw(TelephonyManager.NETWORK_TYPE_LTE);
+ assertEquals(145000, (int) values.first);
+ when(mServiceState.getNrFrequencyRange()).thenReturn(ServiceState.FREQUENCY_RANGE_UNKNOWN);
+ values = mLBE.getStaticAvgBw(TelephonyManager.NETWORK_TYPE_LTE);
+ assertEquals(47000, (int) values.first);
+ values = mLBE.getStaticAvgBw(TelephonyManager.NETWORK_TYPE_NR);
+ assertEquals(145_000, (int) values.first);
+ }
+
+ @Test
+ public void testSwitchToNrMmwaveTriggerBandwidthUpdate() throws Exception {
+ mLBE.obtainMessage(MSG_SCREEN_STATE_CHANGED, true).sendToTarget();
+ addTxBytes(10_000L);
+ addRxBytes(19_000L);
+ addElapsedTime(2000);
+ moveTimeForward(2000);
+ processAllMessages();
+
+ addTxBytes(10_000L);
+ addRxBytes(19_000L);
+ when(mServiceState.getNrState()).thenReturn(NetworkRegistrationInfo.NR_STATE_CONNECTED);
+ when(mServiceState.getNrFrequencyRange()).thenReturn(ServiceState.FREQUENCY_RANGE_MMWAVE);
+ when(mSignalStrength.getLevel()).thenReturn(2);
+ mLBE.obtainMessage(MSG_NR_FREQUENCY_CHANGED).sendToTarget();
+ addElapsedTime(6000);
+ moveTimeForward(6000);
+ processAllMessages();
+
+ verify(mDataConnection, times(1)).updateLinkBandwidthEstimation(eq(-1), eq(-1));
+ }
+
+ @Test
+ public void testEnoughModemPollTriggerBwUpdate() throws Exception {
+ mLBE.obtainMessage(MSG_SCREEN_STATE_CHANGED, true).sendToTarget();
+ processAllMessages();
+
+ for (int i = 0; i < BW_STATS_COUNT_THRESHOLD + 2; i++) {
+ addTxBytes(10_000L);
+ addRxBytes(500_000L);
+ addElapsedTime(5_100);
+ moveTimeForward(5_100);
+ processAllMessages();
+ mLBE.obtainMessage(MSG_MODEM_ACTIVITY_RETURNED, new ModemActivityInfo(
+ i * 5_100L, 0, 0, TX_TIME_2_MS, i * RX_TIME_2_MS)).sendToTarget();
+ processAllMessages();
+ }
+
+ verify(mTelephonyManager, times(BW_STATS_COUNT_THRESHOLD + 2))
+ .requestModemActivityInfo(any(), any());
+ verify(mDataConnection, times(1)).updateLinkBandwidthEstimation(eq(-1), eq(-1));
+ verify(mDataConnection, times(1)).updateLinkBandwidthEstimation(eq(-1), eq(19_597));
+ }
+
+ @Test
+ public void testUseCurrentTacStatsWithEnoughData() throws Exception {
+ mLBE.obtainMessage(MSG_SCREEN_STATE_CHANGED, true).sendToTarget();
+ processAllMessages();
+
+ for (int i = 0; i < BW_STATS_COUNT_THRESHOLD; i++) {
+ addTxBytes(10_000L);
+ addRxBytes(500_000L);
+ addElapsedTime(5_100);
+ moveTimeForward(5_100);
+ processAllMessages();
+ mLBE.obtainMessage(MSG_MODEM_ACTIVITY_RETURNED, new ModemActivityInfo(
+ i * 5_100L, 0, 0, TX_TIME_2_MS, i * RX_TIME_2_MS)).sendToTarget();
+ processAllMessages();
+ }
+
+ mCellIdentity = new CellIdentityLte(310, 260, 1235, 123457, 367);
+ when(mPhone.getCurrentCellIdentity()).thenReturn(mCellIdentity);
+ for (int i = BW_STATS_COUNT_THRESHOLD; i < 3 * BW_STATS_COUNT_THRESHOLD; i++) {
+ addTxBytes(10_000L);
+ addRxBytes(500_000L);
+ addElapsedTime(5_100);
+ moveTimeForward(5_100);
+ processAllMessages();
+ mLBE.obtainMessage(MSG_MODEM_ACTIVITY_RETURNED, new ModemActivityInfo(
+ i * 5_100L, 0, 0, TX_TIME_2_MS, i * RX_TIME_2_MS)).sendToTarget();
+ processAllMessages();
+ }
+
+ verify(mDataConnection, times(1)).updateLinkBandwidthEstimation(eq(-1), eq(-1));
+ verify(mDataConnection, times(1)).updateLinkBandwidthEstimation(eq(-1), eq(19_597));
+ }
+
+ @Test
+ public void testUseAllTacStatsIfNoEnoughDataWithCurrentTac() throws Exception {
+ mLBE.obtainMessage(MSG_SCREEN_STATE_CHANGED, true).sendToTarget();
+ processAllMessages();
+ mLBE.obtainMessage(MSG_SIGNAL_STRENGTH_CHANGED, mSignalStrength).sendToTarget();
+ processAllMessages();
+
+ for (int i = 0; i < BW_STATS_COUNT_THRESHOLD; i++) {
+ addTxBytes(10_000L);
+ addRxBytes(900_000L);
+ addElapsedTime(5_100);
+ moveTimeForward(5_100);
+ processAllMessages();
+ mLBE.obtainMessage(MSG_MODEM_ACTIVITY_RETURNED, new ModemActivityInfo(
+ i * 5_100L, 0, 0, TX_TIME_2_MS, i * RX_TIME_2_MS)).sendToTarget();
+ processAllMessages();
+ }
+
+ mCellIdentity = new CellIdentityLte(310, 260, 1234, 123456, 367);
+ when(mPhone.getCurrentCellIdentity()).thenReturn(mCellIdentity);
+ for (int i = BW_STATS_COUNT_THRESHOLD; i < BW_STATS_COUNT_THRESHOLD * 3 / 2; i++) {
+ addTxBytes(10_000L);
+ addRxBytes(1_000_000L);
+ addElapsedTime(5_100);
+ moveTimeForward(5_100);
+ processAllMessages();
+ mLBE.obtainMessage(MSG_MODEM_ACTIVITY_RETURNED, new ModemActivityInfo(
+ i * 5_100L, 0, 0, TX_TIME_2_MS, i * RX_TIME_2_MS)).sendToTarget();
+ processAllMessages();
+ }
+
+ LinkBandwidthEstimator.NetworkBandwidth network = mLBE.lookupNetwork("310260", 366, "LTE");
+ assertEquals(BW_STATS_COUNT_THRESHOLD - 1, network.getCount(LINK_RX, 1));
+ assertEquals(900_000L * 8 * 1000 / 200 / 1024 * (BW_STATS_COUNT_THRESHOLD - 1),
+ network.getValue(LINK_RX, 1));
+ network = mLBE.lookupNetwork("310260", 367, "LTE");
+ assertEquals(2, network.getCount(LINK_RX, 1));
+ assertEquals(1_000_000L * 8 * 1000 / 200 / 1024 * 2,
+ network.getValue(LINK_RX, 1));
+ network = mLBE.lookupNetwork("310260", UNKNOWN_TAC, "LTE");
+ assertEquals(BW_STATS_COUNT_THRESHOLD * 3 / 2 - 1, network.getCount(LINK_RX, 1));
+ assertEquals(218_748, network.getValue(LINK_RX, 1));
+ verify(mDataConnection, times(2)).updateLinkBandwidthEstimation(eq(-1), eq(-1));
+ }
+
+ @Test
+ public void testSwitchCarrierFallbackToColdStartValue() throws Exception {
+ mLBE.obtainMessage(MSG_SCREEN_STATE_CHANGED, true).sendToTarget();
+ processAllMessages();
+
+ for (int i = 0; i < BW_STATS_COUNT_THRESHOLD + 5; i++) {
+ addTxBytes(10_000L);
+ addRxBytes(500_000L);
+ addElapsedTime(5_100);
+ moveTimeForward(5_100);
+ processAllMessages();
+ mLBE.obtainMessage(MSG_MODEM_ACTIVITY_RETURNED, new ModemActivityInfo(
+ i * 5_100L, 0, 0, TX_TIME_2_MS, i * RX_TIME_2_MS)).sendToTarget();
+ processAllMessages();
+ }
+
+ verify(mDataConnection, times(1)).updateLinkBandwidthEstimation(eq(-1), eq(-1));
+ verify(mDataConnection, times(1)).updateLinkBandwidthEstimation(eq(-1), eq(19_597));
+
+ mCellIdentity = new CellIdentityLte(320, 265, 1234, 123456, 366);
+ when(mPhone.getCurrentCellIdentity()).thenReturn(mCellIdentity);
+
+ addTxBytes(10_000L);
+ addRxBytes(10_000L);
+ addElapsedTime(5_100);
+ moveTimeForward(5_100);
+ processAllMessages();
+
+ verify(mDataConnection, times(2)).updateLinkBandwidthEstimation(eq(-1), eq(-1));
+ }
+
+ @Test
+ public void testIgnoreLowTxRxTime() throws Exception {
+ mLBE.obtainMessage(MSG_SCREEN_STATE_CHANGED, true).sendToTarget();
+ processAllMessages();
+
+ for (int i = 0; i < BW_STATS_COUNT_THRESHOLD + 5; i++) {
+ addTxBytes(10_000L);
+ addRxBytes(500_000L);
+ addElapsedTime(5_100);
+ moveTimeForward(5_100);
+ processAllMessages();
+ mLBE.obtainMessage(MSG_MODEM_ACTIVITY_RETURNED, new ModemActivityInfo(
+ i * 5_100L, 0, 0, TX_TIME_2_MS, i * 80)).sendToTarget();
+ processAllMessages();
+ }
+
+ verify(mDataConnection, times(1)).updateLinkBandwidthEstimation(eq(-1), eq(-1));
+ verify(mDataConnection, times(1)).updateLinkBandwidthEstimation(anyInt(), anyInt());
+ }
+
+ @Test
+ public void testUseHighTxRxByteEdge() throws Exception {
+ mLBE.obtainMessage(MSG_SCREEN_STATE_CHANGED, true).sendToTarget();
+ processAllMessages();
+ mNri = new NetworkRegistrationInfo.Builder()
+ .setAccessNetworkTechnology(TelephonyManager.NETWORK_TYPE_EDGE)
+ .build();
+ when(mServiceState.getNetworkRegistrationInfo(anyInt(), anyInt())).thenReturn(mNri);
+ mLBE.obtainMessage(MSG_SIGNAL_STRENGTH_CHANGED, mSignalStrength).sendToTarget();
+ processAllMessages();
+ for (int i = 0; i < BW_STATS_COUNT_THRESHOLD + 5; i++) {
+ addTxBytes(12_000L);
+ addRxBytes(12_000L);
+ addElapsedTime(5_100);
+ moveTimeForward(5_100);
+ processAllMessages();
+ mLBE.obtainMessage(MSG_MODEM_ACTIVITY_RETURNED, new ModemActivityInfo(
+ i * 5_100L, 0, 0, TX_TIME_2_MS, i * RX_TIME_2_MS * 5)).sendToTarget();
+ processAllMessages();
+ }
+
+ LinkBandwidthEstimator.NetworkBandwidth network = mLBE.lookupNetwork("310260", 366, "EDGE");
+
+ assertEquals(0, network.getCount(LINK_TX, 1));
+ assertEquals(BW_STATS_COUNT_THRESHOLD + 4, network.getCount(LINK_RX, 1));
+ assertEquals(12_000L * 8 / 1024 * (BW_STATS_COUNT_THRESHOLD + 4),
+ network.getValue(LINK_RX, 1));
+ verify(mDataConnection, times(1)).updateLinkBandwidthEstimation(eq(-1), eq(92));
+ }
+}
diff --git a/tests/telephonytests/src/com/android/internal/telephony/euicc/EuiccControllerTest.java b/tests/telephonytests/src/com/android/internal/telephony/euicc/EuiccControllerTest.java
index 7c33f34..43de6f6 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/euicc/EuiccControllerTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/euicc/EuiccControllerTest.java
@@ -1290,7 +1290,8 @@
private void callGetDownloadableSubscriptionMetadata(DownloadableSubscription subscription,
boolean complete, GetDownloadableSubscriptionMetadataResult result) {
prepareGetDownloadableSubscriptionMetadataCall(complete, result);
- PendingIntent resultCallback = PendingIntent.getBroadcast(mContext, 0, new Intent(), 0);
+ PendingIntent resultCallback = PendingIntent.getBroadcast(mContext, 0, new Intent(),
+ PendingIntent.FLAG_IMMUTABLE);
mController.getDownloadableSubscriptionMetadata(0, subscription, PACKAGE_NAME,
resultCallback);
}
@@ -1311,14 +1312,16 @@
}
}).when(mMockConnector).getDefaultDownloadableSubscriptionList(anyInt(), anyBoolean(),
any());
- PendingIntent resultCallback = PendingIntent.getBroadcast(mContext, 0, new Intent(), 0);
+ PendingIntent resultCallback = PendingIntent.getBroadcast(mContext, 0, new Intent(),
+ PendingIntent.FLAG_IMMUTABLE);
mController.getDefaultDownloadableSubscriptionList(CARD_ID, PACKAGE_NAME, resultCallback);
}
private void callDownloadSubscription(DownloadableSubscription subscription,
boolean switchAfterDownload, final boolean complete, final int result,
final int resolvableError, String callingPackage) {
- PendingIntent resultCallback = PendingIntent.getBroadcast(mContext, 0, new Intent(), 0);
+ PendingIntent resultCallback = PendingIntent.getBroadcast(mContext, 0, new Intent(),
+ PendingIntent.FLAG_IMMUTABLE);
doAnswer(new Answer<Void>() {
@Override
public Void answer(InvocationOnMock invocation) throws Exception {
@@ -1345,7 +1348,8 @@
private void callDeleteSubscription(int subscriptionId, String iccid, final boolean complete,
final int result, String callingPackage) {
- PendingIntent resultCallback = PendingIntent.getBroadcast(mContext, 0, new Intent(), 0);
+ PendingIntent resultCallback = PendingIntent.getBroadcast(mContext, 0, new Intent(),
+ PendingIntent.FLAG_IMMUTABLE);
doAnswer(new Answer<Void>() {
@Override
public Void answer(InvocationOnMock invocation) throws Exception {
@@ -1364,7 +1368,8 @@
private void callSwitchToSubscription(int subscriptionId, String iccid, final boolean complete,
final int result, String callingPackage) {
- PendingIntent resultCallback = PendingIntent.getBroadcast(mContext, 0, new Intent(), 0);
+ PendingIntent resultCallback = PendingIntent.getBroadcast(mContext, 0, new Intent(),
+ PendingIntent.FLAG_IMMUTABLE);
doAnswer(new Answer<Void>() {
@Override
public Void answer(InvocationOnMock invocation) throws Exception {
@@ -1383,7 +1388,8 @@
private void callUpdateSubscriptionNickname(int subscriptionId, String iccid, String nickname,
final boolean complete, final int result, String callingPackage) {
- PendingIntent resultCallback = PendingIntent.getBroadcast(mContext, 0, new Intent(), 0);
+ PendingIntent resultCallback = PendingIntent.getBroadcast(mContext, 0, new Intent(),
+ PendingIntent.FLAG_IMMUTABLE);
doAnswer(new Answer<Void>() {
@Override
public Void answer(InvocationOnMock invocation) throws Exception {
@@ -1403,7 +1409,8 @@
}
private void callEraseSubscriptions(final boolean complete, final int result) {
- PendingIntent resultCallback = PendingIntent.getBroadcast(mContext, 0, new Intent(), 0);
+ PendingIntent resultCallback = PendingIntent.getBroadcast(mContext, 0, new Intent(),
+ PendingIntent.FLAG_IMMUTABLE);
doAnswer(new Answer<Void>() {
@Override
public Void answer(InvocationOnMock invocation) throws Exception {
@@ -1421,7 +1428,8 @@
}
private void callEraseSubscriptionsWithOptions(final boolean complete, final int result) {
- PendingIntent resultCallback = PendingIntent.getBroadcast(mContext, 0, new Intent(), 0);
+ PendingIntent resultCallback = PendingIntent.getBroadcast(mContext, 0, new Intent(),
+ PendingIntent.FLAG_IMMUTABLE);
doAnswer(new Answer<Void>() {
@Override
public Void answer(InvocationOnMock invocation) throws Exception {
@@ -1440,7 +1448,8 @@
}
private void callRetainSubscriptionsForFactoryReset(final boolean complete, final int result) {
- PendingIntent resultCallback = PendingIntent.getBroadcast(mContext, 0, new Intent(), 0);
+ PendingIntent resultCallback = PendingIntent.getBroadcast(mContext, 0, new Intent(),
+ PendingIntent.FLAG_IMMUTABLE);
doAnswer(new Answer<Void>() {
@Override
public Void answer(InvocationOnMock invocation) throws Exception {
diff --git a/tests/telephonytests/src/com/android/internal/telephony/gsm/GsmInboundSmsHandlerTest.java b/tests/telephonytests/src/com/android/internal/telephony/gsm/GsmInboundSmsHandlerTest.java
index d201bcf..4796a97 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/gsm/GsmInboundSmsHandlerTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/gsm/GsmInboundSmsHandlerTest.java
@@ -37,6 +37,8 @@
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
+import android.app.Notification;
+import android.app.NotificationManager;
import android.content.BroadcastReceiver;
import android.content.ContentValues;
import android.content.Context;
@@ -381,6 +383,61 @@
@Test
@MediumTest
+ public void testNewSmsWithUserLocked_notificationShown() {
+ // user locked
+ UserManager userManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
+ doReturn(false).when(userManager).isUserUnlocked();
+
+ transitionFromStartupToIdle();
+
+ sendNewSms();
+
+ verify(mContext, never()).sendBroadcast(any(Intent.class));
+ assertEquals("IdleState", getCurrentState().getName());
+
+ // Filter should be invoked.
+ verifySmsFiltersInvoked(times(1));
+
+ // New message notification should be shown.
+ NotificationManager notificationManager =
+ (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE);
+ verify(notificationManager).notify(
+ eq(InboundSmsHandler.NOTIFICATION_TAG),
+ eq(InboundSmsHandler.NOTIFICATION_ID_NEW_MESSAGE),
+ any(Notification.class));
+ }
+
+ @Test
+ @MediumTest
+ public void testNewSmsFromBlockedNumberWithUserLocked_noNotificationShown() {
+ String blockedNumber = "1234567890";
+ mFakeBlockedNumberContentProvider.mBlockedNumbers.add(blockedNumber);
+
+ // user locked
+ UserManager userManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
+ doReturn(false).when(userManager).isUserUnlocked();
+
+ transitionFromStartupToIdle();
+
+ sendNewSms();
+
+ verify(mContext, never()).sendBroadcast(any(Intent.class));
+ assertEquals("IdleState", getCurrentState().getName());
+
+ // Filter should be invoked.
+ verifySmsFiltersInvoked(times(1));
+
+ // No new message notification should be shown.
+ NotificationManager notificationManager =
+ (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE);
+ verify(notificationManager, never()).notify(
+ eq(InboundSmsHandler.NOTIFICATION_TAG),
+ eq(InboundSmsHandler.NOTIFICATION_ID_NEW_MESSAGE),
+ any(Notification.class));
+ }
+
+ @Test
+ @MediumTest
public void testNewSms_filterInvoked_noBroadcastsSent() {
// Configure the first filter to drop the SMS.
when(mSmsFilter.filterSms(any(byte[][].class), anyInt(),
diff --git a/tests/telephonytests/src/com/android/internal/telephony/gsm/GsmSmsDispatcherTest.java b/tests/telephonytests/src/com/android/internal/telephony/gsm/GsmSmsDispatcherTest.java
index 405e237..c69c875 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/gsm/GsmSmsDispatcherTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/gsm/GsmSmsDispatcherTest.java
@@ -281,7 +281,7 @@
ArrayList<PendingIntent> sentIntents = new ArrayList<>();
PendingIntent sentIntent = PendingIntent.getBroadcast(realContext, 0,
- new Intent(TEST_INTENT), 0);
+ new Intent(TEST_INTENT), PendingIntent.FLAG_IMMUTABLE);
sentIntents.add(sentIntent);
sentIntents.add(sentIntent);
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 2b7e0cf..aacfd4a 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsPhoneCallTrackerTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsPhoneCallTrackerTest.java
@@ -1281,13 +1281,23 @@
}
/**
- * Ensures when D2D communication is supported that we register the expected D2D RTP header
- * extension types.
+ * Ensures when both RTP and SDP is supported that we register the expected header extension
+ * types.
* @throws Exception
*/
@Test
@SmallTest
public void testConfigureRtpHeaderExtensionTypes() throws Exception {
+
+ mContextFixture.getCarrierConfigBundle().putBoolean(
+ CarrierConfigManager.KEY_SUPPORTS_DEVICE_TO_DEVICE_COMMUNICATION_USING_RTP_BOOL,
+ true);
+ mContextFixture.getCarrierConfigBundle().putBoolean(
+ CarrierConfigManager.KEY_SUPPORTS_SDP_NEGOTIATION_OF_D2D_RTP_HEADER_EXTENSIONS_BOOL,
+ true);
+ // Hacky but ImsPhoneCallTracker caches carrier config, so necessary.
+ mCTUT.updateCarrierConfigCache(mContextFixture.getCarrierConfigBundle());
+
ImsPhoneCallTracker.Config config = new ImsPhoneCallTracker.Config();
config.isD2DCommunicationSupported = true;
mCTUT.setConfig(config);
@@ -1303,6 +1313,35 @@
}
/**
+ * Ensures when SDP is not supported (by RTP is) we don't register any extensions.
+ * @throws Exception
+ */
+ @Test
+ @SmallTest
+ public void testRtpButNoSdp() throws Exception {
+
+ mContextFixture.getCarrierConfigBundle().putBoolean(
+ CarrierConfigManager.KEY_SUPPORTS_DEVICE_TO_DEVICE_COMMUNICATION_USING_RTP_BOOL,
+ true);
+ mContextFixture.getCarrierConfigBundle().putBoolean(
+ CarrierConfigManager.KEY_SUPPORTS_SDP_NEGOTIATION_OF_D2D_RTP_HEADER_EXTENSIONS_BOOL,
+ false);
+ // Hacky but ImsPhoneCallTracker caches carrier config, so necessary.
+ mCTUT.updateCarrierConfigCache(mContextFixture.getCarrierConfigBundle());
+
+ ImsPhoneCallTracker.Config config = new ImsPhoneCallTracker.Config();
+ config.isD2DCommunicationSupported = true;
+ mCTUT.setConfig(config);
+ mConnectorListener.connectionReady(mImsManager);
+
+ // Expect to get offered header extensions since d2d is supported.
+ verify(mImsManager).setOfferedRtpHeaderExtensionTypes(
+ mRtpHeaderExtensionTypeCaptor.capture());
+ Set<RtpHeaderExtensionType> types = mRtpHeaderExtensionTypeCaptor.getValue();
+ assertEquals(0, types.size());
+ }
+
+ /**
* Ensures when D2D communication is not supported that we don't register the D2D RTP header
* extension types.
* @throws Exception