Merge "Check the preferred scan type in limited service state" into main
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 074de4a..5c8504a 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -169,6 +169,9 @@
<!-- Needed to register for UWB state changes for satellite communication -->
<uses-permission android:name="android.permission.UWB_PRIVILEGED"/>
+ <!-- Needed to initiate configuration update -->
+ <uses-permission android:name="android.permission.UPDATE_CONFIG"/>
+
<!-- Needed to bind the domain selection service. -->
<uses-permission android:name="android.permission.BIND_DOMAIN_SELECTION_SERVICE" />
@@ -577,6 +580,16 @@
</intent-filter>
</receiver>
+ <!-- Update configuration data file -->
+ <receiver android:name="com.android.internal.telephony.configupdate.TelephonyConfigUpdateInstallReceiver"
+ android:exported="true"
+ android:permission="android.permission.UPDATE_CONFIG">
+ <intent-filter>
+ <action android:name="android.os.action.UPDATE_CONFIG" />
+ <data android:scheme="content" android:host="*" android:mimeType="*/*" />
+ </intent-filter>
+ </receiver>
+
<receiver
android:name="com.android.internal.telephony.uicc.ShowInstallAppNotificationReceiver"
android:exported="false"/>
diff --git a/assets/CarrierRestrictionOperatorDetails.json b/assets/CarrierRestrictionOperatorDetails.json
index f3da100..8602d4e 100644
--- a/assets/CarrierRestrictionOperatorDetails.json
+++ b/assets/CarrierRestrictionOperatorDetails.json
@@ -1,5 +1,6 @@
{
"_comment": "Operator should register with its application package name, carrierId and all the corresponding SHAIDs",
"_comment": "Example format :: << \"packageName\" : {\"carrierId\":<int>, \"callerSHA1Id\":[<SHAID1>, <SHAID2>]} >>",
- "com.vzw.hss.myverizon":{"carrierId":1839,"callerSHA1Id":["C58EE7871896786F8BF70EBDB137DE10074043E9","AE23A03436DF07B0CD70FE881CDA2EC1D21215D7B7B0CC68E67B67F5DF89526A"]}
+ "com.vzw.hss.myverizon":{"carrierId":1839,"callerSHA1Id":["C58EE7871896786F8BF70EBDB137DE10074043E9","AE23A03436DF07B0CD70FE881CDA2EC1D21215D7B7B0CC68E67B67F5DF89526A"]},
+ "com.google.android.apps.tycho":{"carrierId":1989,"callerSHA1Id":["B9CFCE1C47A6AC713442718F15EF55B00B3A6D1A6D48CB46249FA8EB51465350","4C36AF4A5BDAD97C1F3D8B283416D244496C2AC5EAFE8226079EF6F676FD1859"]}
}
\ No newline at end of file
diff --git a/res/values-iw/strings.xml b/res/values-iw/strings.xml
index a51c72d..78e4cfc 100644
--- a/res/values-iw/strings.xml
+++ b/res/values-iw/strings.xml
@@ -321,9 +321,9 @@
<string name="throttle_help" msgid="2624535757028809735">"למידע נוסף"</string>
<string name="throttle_status_subtext" msgid="1110276415078236687">"<xliff:g id="USED_0">%1$s</xliff:g> (<xliff:g id="USED_1">%2$d</xliff:g>%%) מתוך התקופה המרבית של <xliff:g id="USED_2">%3$s</xliff:g>\nהתקופה הבאה מתחילה בעוד <xliff:g id="USED_3">%4$d</xliff:g> ימים (<xliff:g id="USED_4">%5$s</xliff:g>)"</string>
<string name="throttle_data_usage_subtext" msgid="3185429653996709840">"<xliff:g id="USED_0">%1$s</xliff:g> (<xliff:g id="USED_1">%2$d</xliff:g>??) מתוך התקופה המרבית של<xliff:g id="USED_2">%3$s</xliff:g>"</string>
- <string name="throttle_data_rate_reduced_subtext" msgid="8369839346277847725">"<xliff:g id="USED_0">%1$s</xliff:g> חריגה מהמקסימום\nקצב הנתונים ירד ל-<xliff:g id="USED_1">%2$d</xliff:g> Kb לשנייה"</string>
+ <string name="throttle_data_rate_reduced_subtext" msgid="8369839346277847725">"<xliff:g id="USED_0">%1$s</xliff:g> חריגה מהמקסימום\nקצב הנתונים ירד ל-<xliff:g id="USED_1">%2$d</xliff:g>Kb לשנייה"</string>
<string name="throttle_time_frame_subtext" msgid="6462089615392402127">"<xliff:g id="USED_0">%1$d</xliff:g>?? מהמחזור חלפו\nהתקופה הבאה מתחילה בעוד <xliff:g id="USED_1">%2$d</xliff:g> ימים (<xliff:g id="USED_2">%3$s</xliff:g>)"</string>
- <string name="throttle_rate_subtext" msgid="7221971817325779535">"קצב הנתונים יורד ל-<xliff:g id="USED">%1$d</xliff:g> Kb לשנייה במקרה של חריגה ממגבלת השימוש בנתונים"</string>
+ <string name="throttle_rate_subtext" msgid="7221971817325779535">"קצב הנתונים יורד ל-<xliff:g id="USED">%1$d</xliff:g>Kb לשנייה במקרה של חריגה ממגבלת השימוש בנתונים"</string>
<string name="throttle_help_subtext" msgid="2817114897095534807">"למידע נוסף על מדיניות השימוש בנתונים ברשת הסלולרית של הספק שלך"</string>
<string name="cell_broadcast_sms" msgid="4053449797289031063">"SMS בשידור סלולרי"</string>
<string name="enable_disable_cell_bc_sms" msgid="4759958924031721350">"SMS בשידור סלולרי"</string>
diff --git a/res/values-mr/strings.xml b/res/values-mr/strings.xml
index 76dee50..1201657 100644
--- a/res/values-mr/strings.xml
+++ b/res/values-mr/strings.xml
@@ -296,7 +296,7 @@
<string name="limited_sim_function_with_phone_num_notification_message" msgid="5928988883403677610">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g> चे कॉल आणि डेटा सेवा <xliff:g id="PHONE_NUMBER">%2$s</xliff:g> वापरताना ब्लॉक केले जाऊ शकतात."</string>
<string name="limited_sim_function_notification_message" msgid="5338638075496721160">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g> चे कॉल आणि डेटा सेवा दुसरे सिम वापरताना ब्लॉक केले जाऊ शकतात."</string>
<string name="sip_accounts_removed_notification_title" msgid="3528076957535736095">"आढळलेली आणि काढून टाकलेली कालबाह्य झालेली SIP खाती"</string>
- <string name="sip_accounts_removed_notification_message" msgid="1916856744869791592">"Android प्लॅटफॉर्मवर आता SIP कॉलिंगला सपोर्ट नाही.\nतुमची अस्तित्वात असलेली SIP खाती <xliff:g id="REMOVED_SIP_ACCOUNTS">%s</xliff:g> काढून टाकली आहेत.\nकृपया तुमच्या कॉलिंगसंबंधित डीफॉल्ट खात्याचे सेटिंग कंफर्म करा."</string>
+ <string name="sip_accounts_removed_notification_message" msgid="1916856744869791592">"Android प्लॅटफॉर्मवर आता SIP कॉलिंगला सपोर्ट नाही.\nतुमची अस्तित्वात असलेली SIP खाती <xliff:g id="REMOVED_SIP_ACCOUNTS">%s</xliff:g> काढून टाकली आहेत.\nकृपया तुमच्या कॉलिंगसंबंधित डीफॉल्ट खात्याचे सेटिंग कन्फर्म करा."</string>
<string name="sip_accounts_removed_notification_action" msgid="3772778402370555562">"सेटिंग्जवर जा"</string>
<string name="data_usage_title" msgid="8438592133893837464">"अॅप डेटा वापर"</string>
<string name="data_usage_template" msgid="6287906680674061783">"<xliff:g id="ID_2">%2$s</xliff:g> दरम्यान <xliff:g id="ID_1">%1$s</xliff:g> मोबाइल डेटा वापरला गेला"</string>
@@ -876,7 +876,7 @@
<string name="radio_info_dds" msgid="1122593144425697126">"डीफॉल्ट डेटा सिम SubId:"</string>
<string name="radio_info_dl_kbps" msgid="2382922659525318726">"DL बँडविड्थ (kbps):"</string>
<string name="radio_info_ul_kbps" msgid="2102225400904799036">"UL बँडविड्थ (kbps):"</string>
- <string name="radio_info_phy_chan_config" msgid="608045501232211303">"प्रत्यक्ष चॅनलची कॉंफिगरेशन:"</string>
+ <string name="radio_info_phy_chan_config" msgid="608045501232211303">"प्रत्यक्ष चॅनलची कॉन्फिगरेशन:"</string>
<string name="radio_info_cell_info_refresh_rate" msgid="670511448975997340">"सेल माहिती रिफ्रेश रेट:"</string>
<string name="radio_info_cellinfo_label" msgid="8199062974670377659">"सर्व सेल परिमाण माहिती:"</string>
<string name="radio_info_gprs_service_label" msgid="6819204246355412952">"डेटा सर्व्हिस:"</string>
diff --git a/src/com/android/phone/CarrierConfigLoader.java b/src/com/android/phone/CarrierConfigLoader.java
index ef71016..9b71919 100644
--- a/src/com/android/phone/CarrierConfigLoader.java
+++ b/src/com/android/phone/CarrierConfigLoader.java
@@ -52,6 +52,7 @@
import android.service.carrier.CarrierIdentifier;
import android.service.carrier.CarrierService;
import android.service.carrier.ICarrierService;
+import android.telephony.AnomalyReporter;
import android.telephony.CarrierConfigManager;
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyFrameworkInitializer;
@@ -94,6 +95,7 @@
import java.util.Locale;
import java.util.Objects;
import java.util.Set;
+import java.util.UUID;
import java.util.stream.Collectors;
import java.util.stream.Stream;
@@ -218,6 +220,10 @@
CarrierConfigManager.KEY_CARRIER_CONFIG_APPLIED_BOOL
};
+ // UUID to report anomaly when config changed reported with subId that map to invalid phone
+ private static final String UUID_NOTIFY_CONFIG_CHANGED_WITH_INVALID_PHONE =
+ "d81cef11-c2f1-4d76-955d-7f50e8590c48";
+
// Handler to process various events.
//
// For each phoneId, the event sequence should be:
@@ -1483,9 +1489,14 @@
int phoneId = SubscriptionManager.getPhoneId(subscriptionId);
if (!SubscriptionManager.isValidPhoneId(phoneId)) {
- logd("Ignore invalid phoneId: " + phoneId + " for subId: " + subscriptionId);
- throw new IllegalArgumentException(
- "Invalid phoneId " + phoneId + " for subId " + subscriptionId);
+ final String msg =
+ "Ignore invalid phoneId: " + phoneId + " for subId: " + subscriptionId;
+ if (mFeatureFlags.addAnomalyWhenNotifyConfigChangedWithInvalidPhone()) {
+ AnomalyReporter.reportAnomaly(
+ UUID.fromString(UUID_NOTIFY_CONFIG_CHANGED_WITH_INVALID_PHONE), msg);
+ }
+ logd(msg);
+ throw new IllegalArgumentException(msg);
}
enforceTelephonyFeatureWithException(getCurrentPackageName(),
diff --git a/src/com/android/phone/PhoneInterfaceManager.java b/src/com/android/phone/PhoneInterfaceManager.java
index 839d8cb..e18818c 100644
--- a/src/com/android/phone/PhoneInterfaceManager.java
+++ b/src/com/android/phone/PhoneInterfaceManager.java
@@ -8504,7 +8504,8 @@
setNetworkSelectionModeAutomatic(subId);
Phone phone = getPhone(subId);
cleanUpAllowedNetworkTypes(phone, subId);
- setDataRoamingEnabled(subId, getDefaultDataRoamingEnabled(subId));
+ setDataRoamingEnabled(subId, phone == null ? false
+ : phone.getDataSettingsManager().isDefaultDataRoamingEnabled());
getPhone(subId).resetCarrierKeysForImsiEncryption();
}
// There has been issues when Sms raw table somehow stores orphan
@@ -10107,20 +10108,6 @@
}
/**
- * Returns true if the data roaming is enabled by default, i.e the system property
- * of {@link #DEFAULT_DATA_ROAMING_PROPERTY_NAME} is true or the config of
- * {@link CarrierConfigManager#KEY_CARRIER_DEFAULT_DATA_ROAMING_ENABLED_BOOL} is true.
- */
- private boolean getDefaultDataRoamingEnabled(int subId) {
- final CarrierConfigManager configMgr = (CarrierConfigManager)
- mApp.getSystemService(Context.CARRIER_CONFIG_SERVICE);
- boolean isDataRoamingEnabled = TelephonyProperties.data_roaming().orElse(false);
- isDataRoamingEnabled |= configMgr.getConfigForSubId(subId).getBoolean(
- CarrierConfigManager.KEY_CARRIER_DEFAULT_DATA_ROAMING_ENABLED_BOOL);
- return isDataRoamingEnabled;
- }
-
- /**
* Returns the default network type for the given {@code subId}, if the default network type is
* not set, return {@link Phone#PREFERRED_NT_MODE}.
*/
diff --git a/src/com/android/phone/satellite/accesscontrol/SatelliteAccessController.java b/src/com/android/phone/satellite/accesscontrol/SatelliteAccessController.java
index 76032f8..36280e9 100644
--- a/src/com/android/phone/satellite/accesscontrol/SatelliteAccessController.java
+++ b/src/com/android/phone/satellite/accesscontrol/SatelliteAccessController.java
@@ -51,6 +51,7 @@
import com.android.internal.telephony.PhoneFactory;
import com.android.internal.telephony.TelephonyCountryDetector;
import com.android.internal.telephony.flags.FeatureFlags;
+import com.android.internal.telephony.satellite.SatelliteConfig;
import com.android.internal.telephony.satellite.SatelliteController;
import com.android.phone.PhoneGlobals;
@@ -106,6 +107,7 @@
private static final int CMD_IS_SATELLITE_COMMUNICATION_ALLOWED = 1;
protected static final int EVENT_WAIT_FOR_CURRENT_LOCATION_TIMEOUT = 2;
protected static final int EVENT_KEEP_ON_DEVICE_ACCESS_CONTROLLER_RESOURCES_TIMEOUT = 3;
+ protected static final int EVENT_CONFIG_DATA_UPDATED = 4;
private static SatelliteAccessController sInstance;
@@ -176,6 +178,8 @@
mCountryDetector = TelephonyCountryDetector.getInstance(context);
mSatelliteController = SatelliteController.getInstance();
loadOverlayConfigs(context);
+ mSatelliteController.registerForConfigUpdateChanged(this, EVENT_CONFIG_DATA_UPDATED,
+ context);
if (s2CellFile != null) {
mSatelliteS2CellFile = s2CellFile;
}
@@ -215,6 +219,9 @@
case EVENT_KEEP_ON_DEVICE_ACCESS_CONTROLLER_RESOURCES_TIMEOUT:
cleanupOnDeviceAccessControllerResources();
break;
+ case EVENT_CONFIG_DATA_UPDATED:
+ updateSatelliteConfigData((Context) msg.obj);
+ break;
default:
logw("SatelliteAccessControllerHandler: unexpected message code: " + msg.what);
break;
@@ -338,6 +345,59 @@
return SystemClock.elapsedRealtimeNanos();
}
+ /**
+ * Update country codes, S2CellFile and satellite region allowed by ConfigUpdater
+ * or CarrierConfig
+ */
+ @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
+ public void updateSatelliteConfigData(Context context) {
+ logd("updateSatelliteConfigData");
+
+ SatelliteConfig satelliteConfig = mSatelliteController.getSatelliteConfig();
+ if (satelliteConfig != null && satelliteConfig.getSatelliteS2CellFile(context) != null) {
+ logd("Check mSatelliteS2CellFile from ConfigUpdater");
+ Path pathSatelliteS2CellFile = satelliteConfig.getSatelliteS2CellFile(context);
+ mSatelliteS2CellFile = pathSatelliteS2CellFile.toFile();
+ if (mSatelliteS2CellFile != null && !mSatelliteS2CellFile.exists()) {
+ loge("The satellite S2 cell file " + mSatelliteS2CellFile.getName()
+ + " does not exist");
+ mSatelliteS2CellFile = null;
+ }
+ }
+
+ if (mSatelliteS2CellFile == null) {
+ logd("Check mSatelliteS2CellFile from CarrierConfig");
+ String satelliteS2CellFileName = getSatelliteS2CellFileFromOverlayConfig(context);
+ mSatelliteS2CellFile = TextUtils.isEmpty(satelliteS2CellFileName)
+ ? null : new File(satelliteS2CellFileName);
+ if (mSatelliteS2CellFile != null && !mSatelliteS2CellFile.exists()) {
+ loge("The satellite S2 cell file " + mSatelliteS2CellFile.getName()
+ + " does not exist");
+ mSatelliteS2CellFile = null;
+ }
+ }
+
+ if (mSatelliteS2CellFile == null) {
+ logd("Since mSatelliteS2CellFile is null, don't need to refer other configurations");
+ return;
+ }
+
+ if (satelliteConfig != null
+ && !satelliteConfig.getDeviceSatelliteCountryCodes().isEmpty()) {
+ logd("update mSatelliteCountryCodes by ConfigUpdater");
+ mSatelliteCountryCodes = satelliteConfig.getDeviceSatelliteCountryCodes();
+ } else {
+ mSatelliteCountryCodes = getSatelliteCountryCodesFromOverlayConfig(context);
+ }
+
+ if (satelliteConfig != null && satelliteConfig.isSatelliteDataForAllowedRegion() != null) {
+ logd("update mIsSatelliteAllowAccessControl by ConfigUpdater");
+ mIsSatelliteAllowAccessControl = satelliteConfig.isSatelliteDataForAllowedRegion();
+ } else {
+ mIsSatelliteAllowAccessControl = getSatelliteAccessAllowFromOverlayConfig(context);
+ }
+ }
+
private void loadOverlayConfigs(@NonNull Context context) {
mSatelliteCountryCodes = getSatelliteCountryCodesFromOverlayConfig(context);
mIsSatelliteAllowAccessControl = getSatelliteAccessAllowFromOverlayConfig(context);
diff --git a/src/com/android/services/telephony/DisconnectCauseUtil.java b/src/com/android/services/telephony/DisconnectCauseUtil.java
index 91ecb93..c00adef 100644
--- a/src/com/android/services/telephony/DisconnectCauseUtil.java
+++ b/src/com/android/services/telephony/DisconnectCauseUtil.java
@@ -119,16 +119,20 @@
FlagsAdapter featureFlags) {
Context context = PhoneGlobals.getInstance();
- return new DisconnectCause(
- toTelecomDisconnectCauseCode(telephonyDisconnectCause, carrierConfig),
- toTelecomDisconnectCauseLabel(context, telephonyDisconnectCause,
- telephonyPreciseDisconnectCause, carrierConfig, featureFlags),
- toTelecomDisconnectCauseDescription(context, telephonyDisconnectCause, phoneId),
- toTelecomDisconnectReason(context, telephonyDisconnectCause, reason, phoneId),
- toTelecomDisconnectCauseTone(telephonyDisconnectCause, carrierConfig, featureFlags),
- telephonyDisconnectCause,
- telephonyPreciseDisconnectCause,
- imsReasonInfo);
+ return new DisconnectCause.Builder()
+ .setCode(toTelecomDisconnectCauseCode(telephonyDisconnectCause, carrierConfig))
+ .setLabel(toTelecomDisconnectCauseLabel(context, telephonyDisconnectCause,
+ telephonyPreciseDisconnectCause, carrierConfig, featureFlags))
+ .setDescription(toTelecomDisconnectCauseDescription(
+ context, telephonyDisconnectCause, phoneId))
+ .setReason(toTelecomDisconnectReason(
+ context, telephonyDisconnectCause, reason, phoneId))
+ .setTone(toTelecomDisconnectCauseTone(
+ telephonyDisconnectCause, carrierConfig, featureFlags))
+ .setTelephonyDisconnectCause(telephonyDisconnectCause)
+ .setTelephonyPreciseDisconnectCause(telephonyPreciseDisconnectCause)
+ .setImsReasonInfo(imsReasonInfo)
+ .build();
}
/**
diff --git a/src/com/android/services/telephony/TelephonyConnectionService.java b/src/com/android/services/telephony/TelephonyConnectionService.java
index a510e51..67b32df 100644
--- a/src/com/android/services/telephony/TelephonyConnectionService.java
+++ b/src/com/android/services/telephony/TelephonyConnectionService.java
@@ -141,6 +141,9 @@
// existing call.
private static final int DEFAULT_DSDA_OUTGOING_CALL_HOLD_TIMEOUT_MS = 2000;
+ // Timeout to wait for the termination of incoming call before continue with the emergency call.
+ private static final int DEFAULT_REJECT_INCOMING_CALL_TIMEOUT_MS = 10 * 1000; // 10 seconds.
+
// If configured, reject attempts to dial numbers matching this pattern.
private static final Pattern CDMA_ACTIVATION_CODE_REGEX_PATTERN =
Pattern.compile("\\*228[0-9]{0,2}");
@@ -706,6 +709,20 @@
}
}
+ private static class OnDisconnectListener extends
+ com.android.internal.telephony.Connection.ListenerBase {
+ private final CompletableFuture<Boolean> mFuture;
+
+ OnDisconnectListener(CompletableFuture<Boolean> future) {
+ mFuture = future;
+ }
+
+ @Override
+ public void onDisconnect(int cause) {
+ mFuture.complete(true);
+ }
+ };
+
private final DomainSelectionConnection.DomainSelectionConnectionCallback
mEmergencyDomainSelectionConnectionCallback =
new DomainSelectionConnection.DomainSelectionConnectionCallback() {
@@ -1252,27 +1269,9 @@
final Connection resultConnection = getTelephonyConnection(request, numberToDial,
true, handle, phone);
- CompletableFuture<Void> maybeHoldFuture = CompletableFuture.completedFuture(null);
- if (mTelephonyManagerProxy.isConcurrentCallsPossible()
- && shouldHoldForEmergencyCall(phone)) {
- // If the PhoneAccountHandle was adjusted on building the TelephonyConnection,
- // the relevant PhoneAccountHandle will be updated in resultConnection.
- PhoneAccountHandle phoneAccountHandle =
- resultConnection.getPhoneAccountHandle() == null
- ? request.getAccountHandle() : resultConnection.getPhoneAccountHandle();
- Conferenceable c = maybeHoldCallsOnOtherSubs(phoneAccountHandle);
- if (c != null) {
- maybeHoldFuture = delayDialForOtherSubHold(phone, c, (success) -> {
- Log.i(this, "onCreateOutgoingConn emergency-"
- + " delayDialForOtherSubHold success = " + success);
- if (!success) {
- // Terminates the existing call to make way for the emergency call.
- hangup(c, android.telephony.DisconnectCause
- .OUTGOING_EMERGENCY_CALL_PLACED);
- }
- });
- }
- }
+ CompletableFuture<Void> maybeHoldFuture =
+ checkAndHoldCallsOnOtherSubsForEmergencyCall(request,
+ resultConnection, phone);
Consumer<Boolean> ddsSwitchConsumer = (result) -> {
Log.i(this, "onCreateOutgoingConn emergency-"
+ " delayDialForDdsSwitch result = " + result);
@@ -1284,6 +1283,32 @@
}
}
+ private CompletableFuture<Void> checkAndHoldCallsOnOtherSubsForEmergencyCall(
+ ConnectionRequest request, Connection resultConnection, Phone phone) {
+ CompletableFuture<Void> maybeHoldFuture = CompletableFuture.completedFuture(null);
+ if (mTelephonyManagerProxy.isConcurrentCallsPossible()
+ && shouldHoldForEmergencyCall(phone)) {
+ // If the PhoneAccountHandle was adjusted on building the TelephonyConnection,
+ // the relevant PhoneAccountHandle will be updated in resultConnection.
+ PhoneAccountHandle phoneAccountHandle =
+ resultConnection.getPhoneAccountHandle() == null
+ ? request.getAccountHandle() : resultConnection.getPhoneAccountHandle();
+ Conferenceable c = maybeHoldCallsOnOtherSubs(phoneAccountHandle);
+ if (c != null) {
+ maybeHoldFuture = delayDialForOtherSubHold(phone, c, (success) -> {
+ Log.i(this, "checkAndHoldCallsOnOtherSubsForEmergencyCall"
+ + " delayDialForOtherSubHold success = " + success);
+ if (!success) {
+ // Terminates the existing call to make way for the emergency call.
+ hangup(c, android.telephony.DisconnectCause
+ .OUTGOING_EMERGENCY_CALL_PLACED);
+ }
+ });
+ }
+ }
+ return maybeHoldFuture;
+ }
+
private Connection placeOutgoingConnection(ConnectionRequest request,
Connection resultConnection, Phone phone) {
// If there was a failure, the resulting connection will not be a TelephonyConnection,
@@ -2303,11 +2328,15 @@
// On GSM phones, null connection means that we dialed an MMI code
int telephonyDisconnectCause = handleMmiCode(
phone, android.telephony.DisconnectCause.OUTGOING_FAILURE);
- mNormalCallConnection.setTelephonyConnectionDisconnected(mDisconnectCauseFactory
- .toTelecomDisconnectCause(telephonyDisconnectCause,
- "Connection is null", phone.getPhoneId()));
+ if (mNormalCallConnection.getState() != Connection.STATE_DISCONNECTED) {
+ mNormalCallConnection.setTelephonyConnectionDisconnected(
+ mDisconnectCauseFactory.toTelecomDisconnectCause(
+ telephonyDisconnectCause,
+ "Connection is null",
+ phone.getPhoneId()));
+ mNormalCallConnection.close();
+ }
clearNormalCallDomainSelectionConnection();
- mNormalCallConnection.close();
return;
}
@@ -2354,6 +2383,7 @@
boolean isMmiCode = (dialPart.startsWith("*") || dialPart.startsWith("#"))
&& dialPart.endsWith("#");
boolean isSuppServiceCode = ImsPhoneMmiCode.isSuppServiceCodes(dialPart, phone);
+ boolean isPotentialUssdCode = isMmiCode && !isSuppServiceCode;
// If the number is both an MMI code and a supplementary service code,
// it shall be treated as UT. In this case, domain selection is not performed.
@@ -2362,6 +2392,10 @@
return false;
}
+ /* For USSD codes, connection is closed and MMIDialogActivity is started.
+ To avoid connection close and return false. isPotentialUssdCode is handled after
+ all condition checks. */
+
// Check and select same domain as ongoing call on the same subscription (if exists)
int activeCallDomain = getActiveCallDomain(phone.getSubId());
if (activeCallDomain != NetworkRegistrationInfo.DOMAIN_UNKNOWN
@@ -2397,6 +2431,15 @@
mNormalCallConnection = connection;
future.thenAcceptAsync((domain) -> handleOutgoingCallConnectionByCallDomainSelection(
domain, phone, number, videoState), mDomainSelectionMainExecutor);
+
+ if (isPotentialUssdCode) {
+ Log.v(LOG_TAG, "PotentialUssdCode. Closing connection with DisconnectCause.DIALED_MMI");
+ connection.setTelephonyConnectionDisconnected(
+ mDisconnectCauseFactory.toTelecomDisconnectCause(
+ android.telephony.DisconnectCause.DIALED_MMI,
+ "Dialing USSD", phone.getPhoneId()));
+ connection.close();
+ }
return true;
}
@@ -2413,6 +2456,32 @@
Log.i(this, "placeEmergencyConnection");
mIsEmergencyCallPending = true;
+ mEmergencyConnection = (TelephonyConnection) resultConnection;
+ }
+
+ CompletableFuture<Void> maybeHoldFuture =
+ checkAndHoldCallsOnOtherSubsForEmergencyCall(request, resultConnection, phone);
+ maybeHoldFuture.thenRun(() -> placeEmergencyConnectionInternal(resultConnection,
+ phone, request, numberToDial, isTestEmergencyNumber, needToTurnOnRadio));
+
+ // Non TelephonyConnection type instance means dialing failure.
+ return resultConnection;
+ }
+
+ @SuppressWarnings("FutureReturnValueIgnored")
+ private void placeEmergencyConnectionInternal(final Connection resultConnection,
+ final Phone phone, final ConnectionRequest request,
+ final String numberToDial, final boolean isTestEmergencyNumber,
+ final boolean needToTurnOnRadio) {
+
+ if (mEmergencyConnection == null) {
+ Log.i(this, "placeEmergencyConnectionInternal dialing canceled");
+ return;
+ }
+
+ if (resultConnection instanceof TelephonyConnection) {
+ Log.i(this, "placeEmergencyConnectionInternal");
+
((TelephonyConnection) resultConnection).addTelephonyConnectionListener(
mEmergencyConnectionListener);
@@ -2420,7 +2489,6 @@
mEmergencyStateTracker = EmergencyStateTracker.getInstance();
}
- mEmergencyConnection = (TelephonyConnection) resultConnection;
CompletableFuture<Integer> future = mEmergencyStateTracker.startEmergencyCall(
phone, resultConnection, isTestEmergencyNumber);
future.thenAccept((result) -> {
@@ -2446,8 +2514,6 @@
}
});
}
- // Non TelephonyConnection type instance means dialing failure.
- return resultConnection;
}
@SuppressWarnings("FutureReturnValueIgnored")
@@ -2509,8 +2575,13 @@
}
Bundle extras = request.getExtras();
extras.putInt(PhoneConstants.EXTRA_DIAL_DOMAIN, result);
- placeOutgoingConnection(request, resultConnection, phone);
- mIsEmergencyCallPending = false;
+ CompletableFuture<Void> rejectFuture = checkAndRejectIncomingCall(phone, (ret) -> {
+ if (!ret) {
+ Log.i(this, "createEmergencyConnection reject incoming call failed");
+ }
+ });
+ rejectFuture.thenRun(() -> placeEmergencyConnectionOnSelectedDomain(request,
+ resultConnection, phone));
}, mDomainSelectionMainExecutor);
}
@@ -2525,10 +2596,26 @@
Log.i(this, "dialCsEmergencyCall dialing canceled");
return;
}
- placeOutgoingConnection(request, resultConnection, phone);
+ CompletableFuture<Void> future = checkAndRejectIncomingCall(phone, (ret) -> {
+ if (!ret) {
+ Log.i(this, "dialCsEmergencyCall reject incoming call failed");
+ }
+ });
+ future.thenRun(() -> placeEmergencyConnectionOnSelectedDomain(request,
+ resultConnection, phone));
});
}
+ private void placeEmergencyConnectionOnSelectedDomain(ConnectionRequest request,
+ TelephonyConnection resultConnection, Phone phone) {
+ if (mEmergencyConnection == null) {
+ Log.i(this, "placeEmergencyConnectionOnSelectedDomain dialing canceled");
+ return;
+ }
+ placeOutgoingConnection(request, resultConnection, phone);
+ mIsEmergencyCallPending = false;
+ }
+
private void releaseEmergencyCallDomainSelection(boolean cancel, boolean isActive) {
if (mEmergencyCallDomainSelectionConnection != null) {
if (cancel) mEmergencyCallDomainSelectionConnection.cancelSelection();
@@ -2778,11 +2865,29 @@
return false;
}
- private void onEmergencyRedialOnDomain(TelephonyConnection connection,
+ private void onEmergencyRedialOnDomain(final TelephonyConnection connection,
final Phone phone, @NetworkRegistrationInfo.Domain int domain) {
Log.i(this, "onEmergencyRedialOnDomain phoneId=" + phone.getPhoneId()
+ ", domain=" + DomainSelectionService.getDomainName(domain));
+ final Bundle extras = new Bundle();
+ extras.putInt(PhoneConstants.EXTRA_DIAL_DOMAIN, domain);
+
+ CompletableFuture<Void> future = checkAndRejectIncomingCall(phone, (ret) -> {
+ if (!ret) {
+ Log.i(this, "onEmergencyRedialOnDomain reject incoming call failed");
+ }
+ });
+ future.thenRun(() -> onEmergencyRedialOnDomainInternal(connection, phone, extras));
+ }
+
+ private void onEmergencyRedialOnDomainInternal(TelephonyConnection connection,
+ Phone phone, Bundle extras) {
+ if (mEmergencyConnection == null) {
+ Log.i(this, "onEmergencyRedialOnDomainInternal dialing canceled");
+ return;
+ }
+
String number = connection.getAddress().getSchemeSpecificPart();
// Indicates undetectable emergency number with DialArgs
@@ -2791,12 +2896,9 @@
if (connection.getEmergencyServiceCategory() != null) {
isEmergency = true;
eccCategory = connection.getEmergencyServiceCategory();
- Log.i(this, "onEmergencyRedialOnDomain eccCategory=" + eccCategory);
+ Log.i(this, "onEmergencyRedialOnDomainInternal eccCategory=" + eccCategory);
}
- Bundle extras = new Bundle();
- extras.putInt(PhoneConstants.EXTRA_DIAL_DOMAIN, domain);
-
com.android.internal.telephony.Connection originalConnection =
connection.getOriginalConnection();
try {
@@ -2811,14 +2913,20 @@
connection::registerForCallEvents);
}
} catch (CallStateException e) {
- Log.e(this, e, "onEmergencyRedialOnDomain, exception: " + e);
+ Log.e(this, e, "onEmergencyRedialOnDomainInternal, exception: " + e);
+ onLocalHangup(connection);
+ connection.unregisterForCallEvents();
+ handleCallStateException(e, connection, phone);
+ return;
}
if (originalConnection == null) {
- Log.d(this, "onEmergencyRedialOnDomain, phone.dial returned null");
- connection.setDisconnected(
+ Log.d(this, "onEmergencyRedialOnDomainInternal, phone.dial returned null");
+ onLocalHangup(connection);
+ connection.setTelephonyConnectionDisconnected(
mDisconnectCauseFactory.toTelecomDisconnectCause(
android.telephony.DisconnectCause.ERROR_UNSPECIFIED,
"unknown error"));
+ connection.close();
} else {
connection.setOriginalConnection(originalConnection);
}
@@ -3366,6 +3474,52 @@
}
/**
+ * If needed, block until an incoming call is disconnected for outgoing emergency call,
+ * or timeout expires.
+ * @param phone The Phone to reject the incoming call
+ * @param completeConsumer The consumer to call once rejecting incoming call has been
+ * completed. {@code true} result if the operation commpletes successfully, or
+ * {@code false} if the operation timed out/failed.
+ */
+ private CompletableFuture<Void> checkAndRejectIncomingCall(Phone phone,
+ Consumer<Boolean> completeConsumer) {
+ if (phone == null) {
+ // Unexpected inputs
+ Log.i(this, "checkAndRejectIncomingCall phone is null");
+ completeConsumer.accept(false);
+ return CompletableFuture.completedFuture(null);
+ }
+
+ Call ringingCall = phone.getRingingCall();
+ if (ringingCall == null || !ringingCall.isRinging()) {
+ completeConsumer.accept(true);
+ return CompletableFuture.completedFuture(null);
+ }
+ Log.i(this, "checkAndRejectIncomingCall found a ringing call");
+
+ try {
+ ringingCall.hangup();
+ CompletableFuture<Boolean> future = new CompletableFuture<>();
+ com.android.internal.telephony.Connection cn = ringingCall.getLatestConnection();
+ cn.addListener(new OnDisconnectListener(future));
+ // A timeout that will complete the future to not block the outgoing call indefinitely.
+ CompletableFuture<Boolean> timeout = new CompletableFuture<>();
+ phone.getContext().getMainThreadHandler().postDelayed(
+ () -> timeout.complete(false), DEFAULT_REJECT_INCOMING_CALL_TIMEOUT_MS);
+ // Ensure that the Consumer is completed on the main thread.
+ return future.acceptEitherAsync(timeout, completeConsumer,
+ phone.getContext().getMainExecutor()).exceptionally((ex) -> {
+ Log.w(this, "checkAndRejectIncomingCall - exceptionally= " + ex);
+ return null;
+ });
+ } catch (Exception e) {
+ Log.w(this, "checkAndRejectIncomingCall - exception= " + e.getMessage());
+ completeConsumer.accept(false);
+ return CompletableFuture.completedFuture(null);
+ }
+ }
+
+ /**
* Get the Phone to use for an emergency call of the given emergency number address:
* a) If there are multiple Phones with the Subscriptions that support the emergency number
* address, and one of them is the default voice Phone, consider the default voice phone
diff --git a/src/com/android/services/telephony/domainselection/EmergencyCallDomainSelector.java b/src/com/android/services/telephony/domainselection/EmergencyCallDomainSelector.java
index ac68599..53b3659 100644
--- a/src/com/android/services/telephony/domainselection/EmergencyCallDomainSelector.java
+++ b/src/com/android/services/telephony/domainselection/EmergencyCallDomainSelector.java
@@ -85,6 +85,7 @@
import android.telephony.TransportSelectorCallback;
import android.telephony.ims.ImsManager;
import android.telephony.ims.ImsMmTelManager;
+import android.telephony.ims.ImsReasonInfo;
import android.telephony.ims.ProvisioningManager;
import android.text.TextUtils;
import android.util.LocalLog;
@@ -335,11 +336,11 @@
private void reselectDomain() {
logi("reselectDomain tryCsWhenPsFails=" + mTryCsWhenPsFails);
- int cause = mSelectionAttributes.getCsDisconnectCause();
+ int cause = getDisconnectCause();
mCrossSimRedialingController.notifyCallFailure(cause);
- if (cause == EMERGENCY_PERM_FAILURE
- || cause == EMERGENCY_TEMP_FAILURE) {
+ if ((cause == EMERGENCY_PERM_FAILURE || cause == EMERGENCY_TEMP_FAILURE)
+ && mCrossSimRedialingController.isThereOtherSlot()) {
logi("reselectDomain should redial on the other subscription");
terminateSelectionForCrossSimRedialing(cause == EMERGENCY_PERM_FAILURE);
return;
@@ -394,6 +395,25 @@
mDomainSelected = false;
}
+ private int getDisconnectCause() {
+ int cause = mSelectionAttributes.getCsDisconnectCause();
+
+ ImsReasonInfo reasonInfo = mSelectionAttributes.getPsDisconnectCause();
+ if (reasonInfo != null) {
+ switch (reasonInfo.getCode()) {
+ case ImsReasonInfo.CODE_EMERGENCY_TEMP_FAILURE:
+ cause = EMERGENCY_TEMP_FAILURE;
+ break;
+ case ImsReasonInfo.CODE_EMERGENCY_PERM_FAILURE:
+ cause = EMERGENCY_PERM_FAILURE;
+ break;
+ default:
+ break;
+ }
+ }
+ return cause;
+ }
+
private void reselectDomainInternal() {
post(() -> {
if (mDestroyed) return;
@@ -657,6 +677,13 @@
private void selectDomainFromInitialState() {
if (mDestroyed) return;
+ if (isInEmergencyCallbackModeOnPsWwan()) {
+ logi("selectDomain PS cellular connected in ECBM");
+ mPsNetworkType = EUTRAN;
+ onWwanNetworkTypeSelected(mPsNetworkType);
+ return;
+ }
+
boolean csInService = isCsInService();
boolean psInService = isPsInService();
@@ -1610,6 +1637,12 @@
&& mEcbmHelper.getDataConnectionState(getSlotId()) == DATA_CONNECTED;
}
+ private boolean isInEmergencyCallbackModeOnPsWwan() {
+ return mEcbmHelper.isInEmergencyCallbackMode(getSlotId())
+ && mEcbmHelper.getTransportType(getSlotId()) == TRANSPORT_TYPE_WWAN
+ && mEcbmHelper.getDataConnectionState(getSlotId()) == DATA_CONNECTED;
+ }
+
@Override
protected void logi(String msg) {
super.logi(msg);
diff --git a/src/com/android/services/telephony/domainselection/EmergencyCallbackModeHelper.java b/src/com/android/services/telephony/domainselection/EmergencyCallbackModeHelper.java
index e42dfe7..cdf2225 100644
--- a/src/com/android/services/telephony/domainselection/EmergencyCallbackModeHelper.java
+++ b/src/com/android/services/telephony/domainselection/EmergencyCallbackModeHelper.java
@@ -68,7 +68,7 @@
@NonNull PreciseDataConnectionState dataConnectionState) {
ApnSetting apnSetting = dataConnectionState.getApnSetting();
if ((apnSetting == null)
- || ((apnSetting.getApnTypeBitmask() | ApnSetting.TYPE_EMERGENCY) == 0)) {
+ || ((apnSetting.getApnTypeBitmask() & ApnSetting.TYPE_EMERGENCY) == 0)) {
return;
}
mTransportType = dataConnectionState.getTransportType();
diff --git a/testapps/GbaTestApp/res/values-mr/strings.xml b/testapps/GbaTestApp/res/values-mr/strings.xml
index 75aaf5f..f8e8992 100644
--- a/testapps/GbaTestApp/res/values-mr/strings.xml
+++ b/testapps/GbaTestApp/res/values-mr/strings.xml
@@ -3,9 +3,9 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_name" msgid="2922839697457005451">"GbaTestApp"</string>
<string name="label_settings" msgid="8030871890526865502">"सेटिंग्ज"</string>
- <string name="label_carrier" msgid="1470455313066422804">"वाहक कॉंफिगरेशन"</string>
- <string name="label_service" msgid="2668963955237345578">"सेवा कॉंफिगरेशन"</string>
- <string name="label_test" msgid="8425079572898571918">"चाचणी कॉंफिगरेशन"</string>
+ <string name="label_carrier" msgid="1470455313066422804">"वाहकाचे कॉन्फिगरेशन"</string>
+ <string name="label_service" msgid="2668963955237345578">"सेवेचे कॉन्फिगरेशन"</string>
+ <string name="label_test" msgid="8425079572898571918">"चाचणीचे कॉन्फिगरेशन"</string>
<string name="button_name_running" msgid="4557363091224858010">"रन करत आहे"</string>
<string name="button_name_exit" msgid="8025683733431538975">"बाहेर पडा"</string>
<string name="label_test_result" msgid="892984695972956196">"चाचणी परिणाम"</string>
diff --git a/tests/src/com/android/phone/satellite/accesscontrol/SatelliteAccessControllerTest.java b/tests/src/com/android/phone/satellite/accesscontrol/SatelliteAccessControllerTest.java
index c44b347..e6f70aa 100644
--- a/tests/src/com/android/phone/satellite/accesscontrol/SatelliteAccessControllerTest.java
+++ b/tests/src/com/android/phone/satellite/accesscontrol/SatelliteAccessControllerTest.java
@@ -23,6 +23,7 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.mockito.ArgumentMatchers.any;
@@ -31,7 +32,11 @@
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.clearInvocations;
import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -57,6 +62,8 @@
import com.android.internal.telephony.PhoneFactory;
import com.android.internal.telephony.TelephonyCountryDetector;
import com.android.internal.telephony.flags.FeatureFlags;
+import com.android.internal.telephony.satellite.SatelliteConfig;
+import com.android.internal.telephony.satellite.SatelliteConfigParser;
import com.android.internal.telephony.satellite.SatelliteController;
import org.junit.After;
@@ -70,6 +77,8 @@
import java.io.File;
import java.lang.reflect.Field;
+import java.nio.file.Path;
+import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
@@ -531,6 +540,42 @@
assertTrue(mQueriedSatelliteAllowed);
}
+ @Test
+ public void testUpdateSatelliteConfigData() {
+ // Verify the case when the configParser is not exist.
+ SatelliteConfigParser spyConfigParserNull =
+ spy(new SatelliteConfigParser((byte[]) null));
+ doReturn(spyConfigParserNull).when(mMockSatelliteController).getSatelliteConfigParser();
+ mSatelliteAccessControllerUT.updateSatelliteConfigData(mMockContext);
+
+ assertNull(spyConfigParserNull.getConfig());
+
+ // Verify the case when the configParser is exist but empty.
+ SatelliteConfigParser spyConfigParserEmpty =
+ spy(new SatelliteConfigParser("test".getBytes()));
+ doReturn(spyConfigParserEmpty).when(mMockSatelliteController).getSatelliteConfigParser();
+ mSatelliteAccessControllerUT.updateSatelliteConfigData(mMockContext);
+
+ assertNull(spyConfigParserEmpty.getConfig());
+
+ // Verify the case when the configParser is exist and valid data
+ SatelliteConfig mockSatelliteConfig = mock(SatelliteConfig.class);
+ final String filePath = "/data/user_de/0/com.android.phone/app_satellite/s2_cell_file";
+ Path targetSatS2FilePath = Paths.get(filePath);
+ doReturn(false).when(mockSatelliteConfig).isFileExist(any());
+ doReturn(targetSatS2FilePath).when(mockSatelliteConfig)
+ .copySatS2FileToPhoneDirectory(any(), any());
+ doReturn(Arrays.asList("US")).when(mockSatelliteConfig).getDeviceSatelliteCountryCodes();
+ doReturn(false).when(mockSatelliteConfig).isSatelliteDataForAllowedRegion();
+ doReturn(targetSatS2FilePath).when(mockSatelliteConfig).getSatelliteS2CellFile(any());
+ doReturn(mockSatelliteConfig).when(mMockSatelliteController).getSatelliteConfig();
+
+ mSatelliteAccessControllerUT.updateSatelliteConfigData(mMockContext);
+ verify(mockSatelliteConfig, times(0)).getDeviceSatelliteCountryCodes();
+ verify(mockSatelliteConfig, times(0)).isSatelliteDataForAllowedRegion();
+ verify(mockSatelliteConfig, times(2)).getSatelliteS2CellFile(any());
+ }
+
private void clearAllInvocations() {
clearInvocations(mMockSatelliteController);
clearInvocations(mMockSatelliteOnDeviceAccessController);
diff --git a/tests/src/com/android/phone/security/SafetySourceReceiverTest.java b/tests/src/com/android/phone/security/SafetySourceReceiverTest.java
index de1f101..305e698 100644
--- a/tests/src/com/android/phone/security/SafetySourceReceiverTest.java
+++ b/tests/src/com/android/phone/security/SafetySourceReceiverTest.java
@@ -60,12 +60,16 @@
MockitoAnnotations.initMocks(this);
SafetySourceReceiver receiver = new SafetySourceReceiver();
mSafetySourceReceiver = spy(receiver);
+
+ when(mContext.getPackageManager().hasSystemFeature(
+ PackageManager.FEATURE_TELEPHONY)).thenReturn(true);
}
@Test
public void testOnReceive() {
mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_IDENTIFIER_DISCLOSURE_TRANSPARENCY_UNSOL_EVENTS,
- Flags.FLAG_ENABLE_MODEM_CIPHER_TRANSPARENCY_UNSOL_EVENTS);
+ Flags.FLAG_ENABLE_MODEM_CIPHER_TRANSPARENCY_UNSOL_EVENTS,
+ Flags.FLAG_ENFORCE_TELEPHONY_FEATURE_MAPPING_FOR_PUBLIC_APIS);
Phone mockPhone = mock(Phone.class);
when(mSafetySourceReceiver.getDefaultPhone()).thenReturn(mockPhone);
@@ -80,7 +84,8 @@
public void testOnReceive_featureFlagsOff() {
mSetFlagsRule.disableFlags(
Flags.FLAG_ENABLE_IDENTIFIER_DISCLOSURE_TRANSPARENCY_UNSOL_EVENTS,
- Flags.FLAG_ENABLE_MODEM_CIPHER_TRANSPARENCY_UNSOL_EVENTS);
+ Flags.FLAG_ENABLE_MODEM_CIPHER_TRANSPARENCY_UNSOL_EVENTS,
+ Flags.FLAG_ENFORCE_TELEPHONY_FEATURE_MAPPING_FOR_PUBLIC_APIS);
Intent intent = new Intent(ACTION_REFRESH_SAFETY_SOURCES);
intent.putExtra(EXTRA_REFRESH_SAFETY_SOURCES_BROADCAST_ID, "aBroadcastId");
@@ -96,9 +101,6 @@
Flags.FLAG_ENFORCE_TELEPHONY_FEATURE_MAPPING_FOR_PUBLIC_APIS);
when(mSafetySourceReceiver.getDefaultPhone()).thenReturn(null);
- when(mContext.getPackageManager().hasSystemFeature(
- PackageManager.FEATURE_TELEPHONY)).thenReturn(true);
-
Intent intent = new Intent(ACTION_REFRESH_SAFETY_SOURCES);
intent.putExtra(EXTRA_REFRESH_SAFETY_SOURCES_BROADCAST_ID, "aBroadcastId");
@@ -125,5 +127,4 @@
verify(mockPhone, never()).refreshSafetySources(any());
}
-
}
diff --git a/tests/src/com/android/services/telephony/TelephonyConnectionServiceTest.java b/tests/src/com/android/services/telephony/TelephonyConnectionServiceTest.java
index f0e900a..e791d3c 100644
--- a/tests/src/com/android/services/telephony/TelephonyConnectionServiceTest.java
+++ b/tests/src/com/android/services/telephony/TelephonyConnectionServiceTest.java
@@ -325,6 +325,10 @@
@After
public void tearDown() throws Exception {
+ if (mTestConnectionService != null
+ && mTestConnectionService.getEmergencyConnection() != null) {
+ mTestConnectionService.onLocalHangup(mTestConnectionService.getEmergencyConnection());
+ }
mTestConnectionService = null;
super.tearDown();
}
@@ -1990,6 +1994,27 @@
}
/**
+ * For DSDA devices with AP domain selection service enabled, placing an outgoing call
+ * on a 2nd sub will hold the existing ACTIVE connection on the first sub.
+ */
+ @Test
+ @SmallTest
+ public void testHoldOnOtherSubForVirtualDsdaDeviceWithDomainSelectionEnabled() {
+ when(mTelephonyManagerProxy.isConcurrentCallsPossible()).thenReturn(true);
+ doReturn(true).when(mDomainSelectionResolver).isDomainSelectionSupported();
+
+ ArrayList<android.telecom.Connection> tcs = new ArrayList<>();
+ SimpleTelephonyConnection tc1 = createTestConnection(SUB1_HANDLE, 0, false);
+ tc1.setTelephonyConnectionActive();
+ tcs.add(tc1);
+
+ Conferenceable c = TelephonyConnectionService.maybeHoldCallsOnOtherSubs(
+ tcs, new ArrayList<>(), SUB2_HANDLE, mTelephonyManagerProxy);
+ assertTrue(c.equals(tc1));
+ assertTrue(tc1.wasHeld);
+ }
+
+ /**
* For DSDA devices, if the existing connection was already held, placing an outgoing call on a
* 2nd sub will not attempt to hold the existing connection on the first sub.
*/
@@ -2267,8 +2292,7 @@
ArgumentCaptor<DialArgs> argsCaptor = ArgumentCaptor.forClass(DialArgs.class);
- Connection nc = Mockito.mock(Connection.class);
- doReturn(nc).when(mPhone0).dial(anyString(), any(), any());
+ doReturn(mInternalConnection).when(mPhone0).dial(anyString(), any(), any());
verify(mPhone0).dial(anyString(), argsCaptor.capture(), any());
DialArgs dialArgs = argsCaptor.getValue();
@@ -2296,8 +2320,131 @@
ArgumentCaptor<DialArgs> argsCaptor = ArgumentCaptor.forClass(DialArgs.class);
- Connection nc = Mockito.mock(Connection.class);
- doReturn(nc).when(mPhone0).dial(anyString(), any(), any());
+ doReturn(mInternalConnection).when(mPhone0).dial(anyString(), any(), any());
+
+ verify(mPhone0).dial(anyString(), argsCaptor.capture(), any());
+ DialArgs dialArgs = argsCaptor.getValue();
+ assertNotNull("DialArgs param is null", dialArgs);
+ assertNotNull("intentExtras is null", dialArgs.intentExtras);
+ assertTrue(dialArgs.intentExtras.containsKey(PhoneConstants.EXTRA_DIAL_DOMAIN));
+ assertEquals(selectedDomain,
+ dialArgs.intentExtras.getInt(PhoneConstants.EXTRA_DIAL_DOMAIN, -1));
+ }
+
+ @Test
+ public void testDomainSelectionRedialFailedWithException() throws Exception {
+ setupForCallTest();
+
+ int preciseDisconnectCause = com.android.internal.telephony.CallFailCause.ERROR_UNSPECIFIED;
+ int disconnectCause = android.telephony.DisconnectCause.ERROR_UNSPECIFIED;
+ int selectedDomain = DOMAIN_CS;
+
+ TestTelephonyConnection c = setupForReDialForDomainSelection(
+ mPhone0, selectedDomain, preciseDisconnectCause, disconnectCause, true);
+
+ CallStateException cse = new CallStateException(CallStateException.ERROR_CALLING_DISABLED,
+ "Calling disabled via ro.telephony.disable-call property");
+ doThrow(cse).when(mPhone0).dial(anyString(), any(), any());
+
+ assertTrue(mTestConnectionService.maybeReselectDomain(c, null, true,
+ android.telephony.DisconnectCause.NOT_VALID));
+ verify(mEmergencyCallDomainSelectionConnection).reselectDomain(any());
+ verify(mEmergencyCallDomainSelectionConnection).cancelSelection();
+ verify(mEmergencyStateTracker).endCall(any());
+ }
+
+ @Test
+ public void testDomainSelectionRejectIncoming() throws Exception {
+ setupForCallTest();
+
+ int selectedDomain = DOMAIN_CS;
+
+ setupForDialForDomainSelection(mPhone0, selectedDomain, true);
+
+ doReturn(mInternalConnection2).when(mCall).getLatestConnection();
+ doReturn(true).when(mCall).isRinging();
+ doReturn(mCall).when(mPhone0).getRingingCall();
+
+ mTestConnectionService.onCreateOutgoingConnection(PHONE_ACCOUNT_HANDLE_1,
+ createConnectionRequest(PHONE_ACCOUNT_HANDLE_1,
+ TEST_EMERGENCY_NUMBER, TELECOM_CALL_ID1));
+
+ ArgumentCaptor<android.telecom.Connection> connectionCaptor =
+ ArgumentCaptor.forClass(android.telecom.Connection.class);
+
+ verify(mDomainSelectionResolver)
+ .getDomainSelectionConnection(eq(mPhone0), eq(SELECTOR_TYPE_CALLING), eq(true));
+ verify(mEmergencyStateTracker)
+ .startEmergencyCall(eq(mPhone0), connectionCaptor.capture(), eq(false));
+ verify(mEmergencyCallDomainSelectionConnection).createEmergencyConnection(any(), any());
+
+ android.telecom.Connection tc = connectionCaptor.getValue();
+
+ assertNotNull(tc);
+ assertEquals(TELECOM_CALL_ID1, tc.getTelecomCallId());
+ assertEquals(mTestConnectionService.getEmergencyConnection(), tc);
+
+ ArgumentCaptor<Connection.Listener> listenerCaptor =
+ ArgumentCaptor.forClass(Connection.Listener.class);
+
+ verify(mInternalConnection2).addListener(listenerCaptor.capture());
+ verify(mCall).hangup();
+ verify(mPhone0, never()).dial(anyString(), any(), any());
+
+ Connection.Listener listener = listenerCaptor.getValue();
+
+ assertNotNull(listener);
+
+ listener.onDisconnect(0);
+
+ verify(mSatelliteSOSMessageRecommender).onEmergencyCallStarted(any());
+
+ ArgumentCaptor<DialArgs> argsCaptor = ArgumentCaptor.forClass(DialArgs.class);
+
+ verify(mPhone0).dial(anyString(), argsCaptor.capture(), any());
+
+ DialArgs dialArgs = argsCaptor.getValue();
+
+ assertNotNull("DialArgs param is null", dialArgs);
+ assertNotNull("intentExtras is null", dialArgs.intentExtras);
+ assertTrue(dialArgs.intentExtras.containsKey(PhoneConstants.EXTRA_DIAL_DOMAIN));
+ assertEquals(selectedDomain,
+ dialArgs.intentExtras.getInt(PhoneConstants.EXTRA_DIAL_DOMAIN, -1));
+ }
+
+ @Test
+ public void testDomainSelectionRedialRejectIncoming() throws Exception {
+ setupForCallTest();
+
+ int preciseDisconnectCause = com.android.internal.telephony.CallFailCause.ERROR_UNSPECIFIED;
+ int disconnectCause = android.telephony.DisconnectCause.ERROR_UNSPECIFIED;
+ int selectedDomain = DOMAIN_CS;
+
+ TestTelephonyConnection c = setupForReDialForDomainSelection(
+ mPhone0, selectedDomain, preciseDisconnectCause, disconnectCause, true);
+
+ doReturn(mInternalConnection2).when(mCall).getLatestConnection();
+ doReturn(true).when(mCall).isRinging();
+ doReturn(mCall).when(mPhone0).getRingingCall();
+
+ assertTrue(mTestConnectionService.maybeReselectDomain(c, null, true,
+ android.telephony.DisconnectCause.NOT_VALID));
+ verify(mEmergencyCallDomainSelectionConnection).reselectDomain(any());
+
+ ArgumentCaptor<Connection.Listener> listenerCaptor =
+ ArgumentCaptor.forClass(Connection.Listener.class);
+
+ verify(mInternalConnection2).addListener(listenerCaptor.capture());
+ verify(mCall).hangup();
+ verify(mPhone0, never()).dial(anyString(), any(), any());
+
+ Connection.Listener listener = listenerCaptor.getValue();
+
+ assertNotNull(listener);
+
+ listener.onDisconnect(0);
+
+ ArgumentCaptor<DialArgs> argsCaptor = ArgumentCaptor.forClass(DialArgs.class);
verify(mPhone0).dial(anyString(), argsCaptor.capture(), any());
DialArgs dialArgs = argsCaptor.getValue();
@@ -2621,6 +2768,7 @@
setupForDialForDomainSelection(mPhone0, selectedDomain, true);
doReturn(mPhone0).when(mImsPhone).getDefaultPhone();
+ doReturn(mInternalConnection).when(mPhone0).dial(anyString(), any(), any());
TestTelephonyConnection c = setupForReDialForDomainSelection(
mImsPhone, selectedDomain, preciseDisconnectCause, disconnectCause, false);
@@ -2671,6 +2819,7 @@
setupForDialForDomainSelection(mPhone0, selectedDomain, true);
doReturn(mPhone0).when(mImsPhone).getDefaultPhone();
+ doReturn(mInternalConnection).when(mPhone0).dial(anyString(), any(), any());
TestTelephonyConnection c = setupForReDialForDomainSelection(
mImsPhone, selectedDomain, preciseDisconnectCause, disconnectCause, false);
diff --git a/tests/src/com/android/services/telephony/domainselection/EmergencyCallDomainSelectorTest.java b/tests/src/com/android/services/telephony/domainselection/EmergencyCallDomainSelectorTest.java
index f7b249a..50085e7 100644
--- a/tests/src/com/android/services/telephony/domainselection/EmergencyCallDomainSelectorTest.java
+++ b/tests/src/com/android/services/telephony/domainselection/EmergencyCallDomainSelectorTest.java
@@ -280,6 +280,8 @@
any(), anyInt(), anyBoolean(), any(), any());
when(mResources.getStringArray(anyInt())).thenReturn(null);
+
+ doReturn(false).when(mCsrdCtrl).isThereOtherSlot();
}
@After
@@ -2219,6 +2221,7 @@
public void testCrossStackTimerTempFailure() throws Exception {
createSelector(SLOT_0_SUB_ID);
unsolBarringInfoChanged(false);
+ doReturn(true).when(mCsrdCtrl).isThereOtherSlot();
EmergencyRegistrationResult regResult = getEmergencyRegResult(UTRAN,
REGISTRATION_STATE_HOME,
@@ -2243,12 +2246,48 @@
processAllMessages();
verify(mCsrdCtrl).notifyCallFailure(eq(PreciseDisconnectCause.EMERGENCY_TEMP_FAILURE));
+ verify(mTransportSelectorCallback)
+ .onSelectionTerminated(eq(DisconnectCause.EMERGENCY_TEMP_FAILURE));
+ }
+
+ @Test
+ public void testCrossStackTimerTempFailureNoValidSubscription() throws Exception {
+ createSelector(SLOT_0_SUB_ID);
+ unsolBarringInfoChanged(false);
+ doReturn(false).when(mCsrdCtrl).isThereOtherSlot();
+
+ EmergencyRegistrationResult regResult = getEmergencyRegResult(UTRAN,
+ REGISTRATION_STATE_HOME,
+ NetworkRegistrationInfo.DOMAIN_CS,
+ true, true, 0, 0, "", "");
+ SelectionAttributes attr = getSelectionAttributes(SLOT_0, SLOT_0_SUB_ID, regResult);
+ mDomainSelector.selectDomain(attr, mTransportSelectorCallback);
+ processAllMessages();
+
+ bindImsServiceUnregistered();
+
+ verifyCsDialed();
+
+ attr = new SelectionAttributes.Builder(SLOT_0, SLOT_0_SUB_ID, SELECTOR_TYPE_CALLING)
+ .setAddress(TEST_URI)
+ .setEmergency(true)
+ .setEmergencyRegistrationResult(regResult)
+ .setCsDisconnectCause(PreciseDisconnectCause.EMERGENCY_TEMP_FAILURE)
+ .build();
+
+ mDomainSelector.reselectDomain(attr);
+ processAllMessages();
+
+ verify(mCsrdCtrl).notifyCallFailure(eq(PreciseDisconnectCause.EMERGENCY_TEMP_FAILURE));
+ verify(mTransportSelectorCallback, never())
+ .onSelectionTerminated(eq(DisconnectCause.EMERGENCY_TEMP_FAILURE));
}
@Test
public void testCrossStackTimerPermFailure() throws Exception {
createSelector(SLOT_0_SUB_ID);
unsolBarringInfoChanged(false);
+ doReturn(true).when(mCsrdCtrl).isThereOtherSlot();
EmergencyRegistrationResult regResult = getEmergencyRegResult(UTRAN,
REGISTRATION_STATE_HOME,
@@ -2273,6 +2312,41 @@
processAllMessages();
verify(mCsrdCtrl).notifyCallFailure(eq(PreciseDisconnectCause.EMERGENCY_PERM_FAILURE));
+ verify(mTransportSelectorCallback)
+ .onSelectionTerminated(eq(DisconnectCause.EMERGENCY_PERM_FAILURE));
+ }
+
+ @Test
+ public void testCrossStackTimerPermFailureNoValidSubscription() throws Exception {
+ createSelector(SLOT_0_SUB_ID);
+ unsolBarringInfoChanged(false);
+ doReturn(false).when(mCsrdCtrl).isThereOtherSlot();
+
+ EmergencyRegistrationResult regResult = getEmergencyRegResult(UTRAN,
+ REGISTRATION_STATE_HOME,
+ NetworkRegistrationInfo.DOMAIN_CS,
+ true, true, 0, 0, "", "");
+ SelectionAttributes attr = getSelectionAttributes(SLOT_0, SLOT_0_SUB_ID, regResult);
+ mDomainSelector.selectDomain(attr, mTransportSelectorCallback);
+ processAllMessages();
+
+ bindImsServiceUnregistered();
+
+ verifyCsDialed();
+
+ attr = new SelectionAttributes.Builder(SLOT_0, SLOT_0_SUB_ID, SELECTOR_TYPE_CALLING)
+ .setAddress(TEST_URI)
+ .setEmergency(true)
+ .setEmergencyRegistrationResult(regResult)
+ .setCsDisconnectCause(PreciseDisconnectCause.EMERGENCY_PERM_FAILURE)
+ .build();
+
+ mDomainSelector.reselectDomain(attr);
+ processAllMessages();
+
+ verify(mCsrdCtrl).notifyCallFailure(eq(PreciseDisconnectCause.EMERGENCY_PERM_FAILURE));
+ verify(mTransportSelectorCallback, never())
+ .onSelectionTerminated(eq(DisconnectCause.EMERGENCY_PERM_FAILURE));
}
@Test
@@ -2898,6 +2972,16 @@
doReturn(TRANSPORT_TYPE_WWAN).when(mEcbmHelper).getTransportType(anyInt());
doReturn(DATA_CONNECTED).when(mEcbmHelper).getDataConnectionState(anyInt());
+ doAnswer(new Answer<Void>() {
+ @Override
+ public Void answer(InvocationOnMock invocation) throws Throwable {
+ Consumer<WwanSelectorCallback> consumer =
+ (Consumer<WwanSelectorCallback>) invocation.getArguments()[0];
+ consumer.accept(mWwanSelectorCallback);
+ return null;
+ }
+ }).when(mTransportSelectorCallback).onWwanSelected(any());
+
EmergencyRegistrationResult regResult = getEmergencyRegResult(UNKNOWN,
REGISTRATION_STATE_UNKNOWN,
0, false, false, 0, 0, "", "");
@@ -2910,6 +2994,7 @@
verify(mTransportSelectorCallback, never()).onWlanSelected(anyBoolean());
verify(mTransportSelectorCallback).onWwanSelected(any());
+ verify(mWwanSelectorCallback).onDomainSelected(eq(DOMAIN_PS), eq(true));
}
@Test
@@ -2980,6 +3065,42 @@
verify(mTransportSelectorCallback).onWwanSelected(any());
}
+ @Test
+ public void testNotInEcbmOnWwanConnected() throws Exception {
+ createSelector(SLOT_0_SUB_ID);
+ unsolBarringInfoChanged(false);
+
+ doReturn(false).when(mEcbmHelper).isInEmergencyCallbackMode(anyInt());
+ doReturn(TRANSPORT_TYPE_WLAN).when(mEcbmHelper).getTransportType(anyInt());
+ doReturn(DATA_CONNECTED).when(mEcbmHelper).getDataConnectionState(anyInt());
+
+ doAnswer(new Answer<Void>() {
+ @Override
+ public Void answer(InvocationOnMock invocation) throws Throwable {
+ Consumer<WwanSelectorCallback> consumer =
+ (Consumer<WwanSelectorCallback>) invocation.getArguments()[0];
+ consumer.accept(mWwanSelectorCallback);
+ return null;
+ }
+ }).when(mTransportSelectorCallback).onWwanSelected(any());
+
+ EmergencyRegistrationResult regResult = getEmergencyRegResult(UNKNOWN,
+ REGISTRATION_STATE_UNKNOWN,
+ 0, false, false, 0, 0, "", "");
+ SelectionAttributes attr = getSelectionAttributes(SLOT_0, SLOT_0_SUB_ID, regResult);
+ mDomainSelector.selectDomain(attr, mTransportSelectorCallback);
+ processAllMessages();
+
+ bindImsServiceUnregistered();
+ processAllMessages();
+
+ verify(mTransportSelectorCallback, never()).onWlanSelected(anyBoolean());
+ verify(mTransportSelectorCallback).onWwanSelected(any());
+ verify(mWwanSelectorCallback, never()).onDomainSelected(anyInt(), anyBoolean());
+ verify(mWwanSelectorCallback).onRequestEmergencyNetworkScan(
+ any(), anyInt(), anyBoolean(), any(), any());
+ }
+
private void setupForScanListTest(PersistableBundle bundle) throws Exception {
setupForScanListTest(bundle, false);
}