Merge "Change method to show mobile radio power to getRadioPower" into main
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index eef01fa..7e56e8b 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -619,17 +619,6 @@
</intent-filter>
</activity>
- <activity android:name=".settings.BandMode"
- android:label="@string/band_mode_title"
- android:exported="true"
- android:theme="@style/Theme.AppCompat.DayNight">
- <intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.VOICE_LAUNCH" />
- </intent-filter>
- </activity>
-
<provider
android:name="ServiceStateProvider"
android:authorities="service-state"
diff --git a/res/values-bs/strings.xml b/res/values-bs/strings.xml
index 6675ae7..992f1b2 100644
--- a/res/values-bs/strings.xml
+++ b/res/values-bs/strings.xml
@@ -596,7 +596,7 @@
<string name="failedToImportSingleContactMsg" msgid="228095510489830266">"Uvoz kontakta nije uspio"</string>
<string name="hac_mode_title" msgid="4127986689621125468">"Slušni aparat"</string>
<string name="hac_mode_summary" msgid="7774989500136009881">"Uključite kompatibilnost za slušni aparat"</string>
- <string name="rtt_mode_title" msgid="3075948111362818043">"Pozivanje sa slanjem SMS-ova u stvarnom vremenu (RTT)"</string>
+ <string name="rtt_mode_title" msgid="3075948111362818043">"Poziv sa SMS-ovima u stvarnom vremenu (RTT)"</string>
<string name="rtt_mode_summary" msgid="8631541375609989562">"Dozvolite razmjenu poruka tokom glasovnog poziva"</string>
<string name="rtt_mode_more_information" msgid="587500128658756318">"RTT pomaže pozivaocima koji su gluhi, imaju probleme sa sluhom ili govorom te onima kojima treba više od samog glasa.<br> <a href=<xliff:g id="URL">http://support.google.com/mobile?p=telephony_rtt</xliff:g>>Saznajte više</a>\n <br><br> - RTT pozivi se pohranjuju kao transkripti poruka\n <br> - RTT nije dostupan za video pozive"</string>
<string name="no_rtt_when_roaming" msgid="5268008247378355389">"Napomena: RTT nije dostupan u romingu"</string>
diff --git a/res/values-da/strings.xml b/res/values-da/strings.xml
index a9dd327..58f2670 100644
--- a/res/values-da/strings.xml
+++ b/res/values-da/strings.xml
@@ -596,9 +596,9 @@
<string name="failedToImportSingleContactMsg" msgid="228095510489830266">"Kontaktpersonen kunne ikke importeres"</string>
<string name="hac_mode_title" msgid="4127986689621125468">"Høreapparater"</string>
<string name="hac_mode_summary" msgid="7774989500136009881">"Slå høreapparatskompatibilitet til"</string>
- <string name="rtt_mode_title" msgid="3075948111362818043">"Opkald via sms i realtid"</string>
+ <string name="rtt_mode_title" msgid="3075948111362818043">"Opkald via beskeder i realtid"</string>
<string name="rtt_mode_summary" msgid="8631541375609989562">"Tillad afsendelse af sms-beskeder i et taleopkald"</string>
- <string name="rtt_mode_more_information" msgid="587500128658756318">"Sms i realtid hjælper personer, som er døve, hørehæmmede, talehandicappede, eller som har brug for mere end bare tale, med at foretage opkald.<br> <a href=<xliff:g id="URL">http://support.google.com/mobile?p=telephony_rtt</xliff:g>>Få flere oplysninger</a>\n <br><br> – Opkald via sms i realtid gemmes som en beskedtransskription\n <br> – Sms i realtid er ikke tilgængeligt til videoopkald"</string>
+ <string name="rtt_mode_more_information" msgid="587500128658756318">"Beskeder i realtid hjælper personer, som er døve, hørehæmmede, talehandicappede, eller som har brug for mere end bare tale, med at foretage opkald.<br> <a href=<xliff:g id="URL">http://support.google.com/mobile?p=telephony_rtt</xliff:g>>Få flere oplysninger</a>\n <br><br> – Opkald via beskeder i realtid gemmes som en beskedtransskription\n <br> – Beskeder i realtid er ikke tilgængeligt til videoopkald"</string>
<string name="no_rtt_when_roaming" msgid="5268008247378355389">"Bemærk! RTT er ikke tilgængeligt under roaming"</string>
<string-array name="tty_mode_entries">
<item msgid="3238070884803849303">"TTY fra"</item>
diff --git a/res/values-hi/strings.xml b/res/values-hi/strings.xml
index 5d03fe8..4f8e559 100644
--- a/res/values-hi/strings.xml
+++ b/res/values-hi/strings.xml
@@ -314,7 +314,7 @@
<string name="video_calling_settings_title" msgid="342829454913266078">"वाहक वीडियो कॉलिंग"</string>
<string name="gsm_umts_options" msgid="4968446771519376808">"GSM/UMTS विकल्प"</string>
<string name="cdma_options" msgid="3669592472226145665">"CDMA विकल्प"</string>
- <string name="throttle_data_usage" msgid="1944145350660420711">"डेटा उपयोग"</string>
+ <string name="throttle_data_usage" msgid="1944145350660420711">"डेटा खर्च"</string>
<string name="throttle_current_usage" msgid="7483859109708658613">"वर्तमान अवधि में उपयोग किया गया डेटा"</string>
<string name="throttle_time_frame" msgid="1813452485948918791">"डेटा उपयोग अवधि"</string>
<string name="throttle_rate" msgid="7641913901133634905">"डेटा दर नीति"</string>
diff --git a/res/values-ky/strings.xml b/res/values-ky/strings.xml
index 7bd3d32..3fca1ed 100644
--- a/res/values-ky/strings.xml
+++ b/res/values-ky/strings.xml
@@ -385,9 +385,9 @@
<string name="enable_disable_lafs" msgid="7448060358300805661">"Жергиликтүү аэропорттун учуу тартиби"</string>
<string name="lafs_enable" msgid="3125783406052655690">"Жергиликтүү аэропорттун учуу тартиби иштетилген"</string>
<string name="lafs_disable" msgid="7326815066813851447">"Жергиликтүү аэропорттун учуу тартиби өчүрүлгөн"</string>
- <string name="enable_disable_restaurants" msgid="3873247081569423019">"Ресторандар"</string>
- <string name="restaurants_enable" msgid="5810452674239139572">"Ресторандар иштетилген"</string>
- <string name="restaurants_disable" msgid="2733507854548413505">"Ресторандар өчүрүлгөн"</string>
+ <string name="enable_disable_restaurants" msgid="3873247081569423019">"Тамактануучу жайлар"</string>
+ <string name="restaurants_enable" msgid="5810452674239139572">"Тамактануучу жайлар иштетилген"</string>
+ <string name="restaurants_disable" msgid="2733507854548413505">"Тамактануучу жайлар өчүрүлгөн"</string>
<string name="enable_disable_lodgings" msgid="7849168585821435109">"Турак жайлар"</string>
<string name="lodgings_enable" msgid="2020598411398609514">"Турак жайлар иштетилген"</string>
<string name="lodgings_disable" msgid="5145649659459722661">"Турак жайлар өчүрүлгөн"</string>
diff --git a/res/values-lv/strings.xml b/res/values-lv/strings.xml
index f8bef4a..90165b8 100644
--- a/res/values-lv/strings.xml
+++ b/res/values-lv/strings.xml
@@ -908,7 +908,7 @@
<string name="radio_info_smsc_update_label" msgid="5141996256097115753">"Atjaunināt"</string>
<string name="radio_info_smsc_refresh_label" msgid="8409923721451604560">"Atsvaidzināt"</string>
<string name="radio_info_toggle_dns_check_label" msgid="1394078554927787350">"Pārslēgt DNS pārbaudi"</string>
- <string name="oem_radio_info_label" msgid="2914167475119997456">"OEM raksturīga informācija/iestatījumi"</string>
+ <string name="oem_radio_info_label" msgid="2914167475119997456">"OAR raksturīga informācija/iestatījumi"</string>
<string name="radio_info_endc_available" msgid="2983767110681230019">"EN-DC pieejamība (NSA):"</string>
<string name="radio_info_dcnr_restricted" msgid="7147511536420148173">"DCNR ierobežojums (NSA):"</string>
<string name="radio_info_nr_available" msgid="3383388088451237182">"NR pieejamība (NSA):"</string>
diff --git a/res/values/config.xml b/res/values/config.xml
index 939faa7..dcfa364 100644
--- a/res/values/config.xml
+++ b/res/values/config.xml
@@ -318,6 +318,13 @@
<string-array name="thermal_mitigation_allowlisted_packages" translatable="false">
</string-array>
+ <!-- Array of carriers that don't care about NGRAN's preference in the preferred emergency
+ network scan list after SIM is removed. -->
+ <integer-array name="config_carriers_ignore_ngran_preference_when_sim_removed">
+ <!-- 001-01 Test SIM -->
+ <item>1911</item>
+ </integer-array>
+
<!-- Array of countries that active SIM is needed for emergency calls. Values should be
ISO3166 country codes in lowercase. -->
<string-array name="config_countries_require_sim_for_emergency" translatable="false">
diff --git a/src/com/android/phone/CallNotifier.java b/src/com/android/phone/CallNotifier.java
index 73b61b6..daf3aa2 100644
--- a/src/com/android/phone/CallNotifier.java
+++ b/src/com/android/phone/CallNotifier.java
@@ -489,7 +489,7 @@
public void updatePhoneStateListeners(boolean isRefresh, int updateType, int subIdToUpdate) {
List<SubscriptionInfo> subInfos = SubscriptionManagerService.getInstance()
.getActiveSubscriptionInfoList(mApplication.getOpPackageName(),
- mApplication.getAttributionTag());
+ mApplication.getAttributionTag(), true/*isForAllProfile*/);
// Sort sub id list based on slot id, so that CFI/MWI notifications will be updated for
// slot 0 first then slot 1. This is needed to ensure that when CFI or MWI is enabled for
diff --git a/src/com/android/phone/PhoneGlobals.java b/src/com/android/phone/PhoneGlobals.java
index 483a706..0cb95c5 100644
--- a/src/com/android/phone/PhoneGlobals.java
+++ b/src/com/android/phone/PhoneGlobals.java
@@ -50,6 +50,7 @@
import android.telephony.TelephonyCallback;
import android.telephony.TelephonyLocalConnection;
import android.telephony.TelephonyManager;
+import android.text.TextUtils;
import android.util.ArraySet;
import android.util.LocalLog;
import android.util.Log;
@@ -1061,16 +1062,14 @@
&& reason == ROAMING_NOTIFICATION_REASON_CARRIER_CONFIG_CHANGED) {
mShownNotificationReasons.add(callingReason);
}
- boolean isShowRoamingNotificationEnabled = getCarrierConfigForSubId(mDefaultDataSubId)
- .getBoolean(CarrierConfigManager
- .KEY_SHOW_DATA_CONNECTED_ROAMING_NOTIFICATION_BOOL);
+ boolean shouldShowRoamingNotification = shouldShowRoamingNotification(roamingNumeric);
// No need to show it again if we never cancelled it explicitly.
if (getCurrentRoamingNotification() == ROAMING_NOTIFICATION_CONNECTED) {
return;
}
// Inform users that roaming charges may apply.
- if (!shownInThisNumeric && !shownForThisReason && isShowRoamingNotificationEnabled) {
+ if (!shownInThisNumeric && !shownForThisReason && shouldShowRoamingNotification) {
updateDataRoamingNotification(ROAMING_NOTIFICATION_CONNECTED);
} else {
// Don't show roaming notification if we've already shown for this MccMnc or
@@ -1078,7 +1077,7 @@
Log.d(LOG_TAG, "Skip roaming connected notification since already"
+ " shownInThisNumeric:" + shownInThisNumeric
+ " shownForThisReason:" + shownForThisReason
- + " isShowRoamingNotificationEnabled:" + isShowRoamingNotificationEnabled);
+ + " shouldShowRoamingNotification:" + shouldShowRoamingNotification);
// Dismiss notification if the other notification is shown.
if (getCurrentRoamingNotification() != ROAMING_NOTIFICATION_NO_NOTIFICATION) {
updateDataRoamingNotification(ROAMING_NOTIFICATION_NO_NOTIFICATION);
@@ -1173,10 +1172,10 @@
msg.arg1 = mDefaultDataSubId;
msg.sendToTarget();
} else if (dataAllowed && dataIsNowRoaming(mDefaultDataSubId)) {
- boolean isShowRoamingNotificationEnabled = getCarrierConfigForSubId(mDefaultDataSubId)
- .getBoolean(CarrierConfigManager
- .KEY_SHOW_DATA_CONNECTED_ROAMING_NOTIFICATION_BOOL);
- if (!isShowRoamingNotificationEnabled) return;
+ if (!shouldShowRoamingNotification(roamingOperatorNumeric)) {
+ Log.d(LOG_TAG, "Skip showing roaming connected notification.");
+ return;
+ }
// Don't show roaming notification if we've already shown for this MccMnc
if (roamingOperatorNumeric != null
&& !mPrevRoamingOperatorNumerics.add(roamingOperatorNumeric)) {
@@ -1213,6 +1212,46 @@
return getPhone(subId).getServiceState().getDataRoaming();
}
+ private boolean shouldShowRoamingNotification(String roamingNumeric) {
+ PersistableBundle config = getCarrierConfigForSubId(mDefaultDataSubId);
+ boolean showRoamingNotification = config.getBoolean(
+ CarrierConfigManager.KEY_SHOW_DATA_CONNECTED_ROAMING_NOTIFICATION_BOOL);
+
+ if (TextUtils.isEmpty(roamingNumeric) || !mFeatureFlags.hideRoamingIcon()) {
+ Log.d(LOG_TAG, "shouldShowRoamingNotification: roamingNumeric=" + roamingNumeric
+ + ", hideRoaming=" + mFeatureFlags.hideRoamingIcon());
+ return showRoamingNotification;
+ }
+
+ String[] includedMccMncs = config.getStringArray(CarrierConfigManager
+ .KEY_DATA_CONNECTED_ROAMING_NOTIFICATION_INCLUDED_MCC_MNCS_STRING_ARRAY);
+ if (includedMccMncs != null) {
+ for (String mccMnc : includedMccMncs) {
+ if (roamingNumeric.equals(mccMnc)) {
+ Log.d(LOG_TAG, "shouldShowRoamingNotification: show for MCC/MNC " + mccMnc);
+ return showRoamingNotification;
+ }
+ }
+ }
+
+ String[] excludedMccs = config.getStringArray(CarrierConfigManager
+ .KEY_DATA_CONNECTED_ROAMING_NOTIFICATION_EXCLUDED_MCCS_STRING_ARRAY);
+ String roamingMcc = roamingNumeric.length() < 3 ? "" : roamingNumeric.substring(0, 3);
+ if (excludedMccs != null && !TextUtils.isEmpty(roamingMcc)) {
+ for (String mcc : excludedMccs) {
+ if (roamingMcc.equals(mcc)) {
+ Log.d(LOG_TAG, "shouldShowRoamingNotification: ignore for MCC " + mcc);
+ return false;
+ }
+ }
+ }
+
+ if (showRoamingNotification) {
+ Log.d(LOG_TAG, "shouldShowRoamingNotification: show for numeric " + roamingNumeric);
+ }
+ return showRoamingNotification;
+ }
+
private void updateLimitedSimFunctionForDualSim() {
if (DBG) Log.d(LOG_TAG, "updateLimitedSimFunctionForDualSim");
// check conditions to display limited SIM function notification under dual SIM
diff --git a/src/com/android/phone/PhoneInterfaceManager.java b/src/com/android/phone/PhoneInterfaceManager.java
index 6a560f6..1937658 100644
--- a/src/com/android/phone/PhoneInterfaceManager.java
+++ b/src/com/android/phone/PhoneInterfaceManager.java
@@ -8051,7 +8051,7 @@
*/
private List<SubscriptionInfo> getActiveSubscriptionInfoListPrivileged() {
return getSubscriptionManagerService().getActiveSubscriptionInfoList(
- mApp.getOpPackageName(), mApp.getAttributionTag());
+ mApp.getOpPackageName(), mApp.getAttributionTag(), true/*isForAllProfile*/);
}
private ActivityStatsTechSpecificInfo[] mLastModemActivitySpecificInfo = null;
diff --git a/src/com/android/services/telephony/TelephonyConnectionService.java b/src/com/android/services/telephony/TelephonyConnectionService.java
index 7ee3a1e..48169a2 100644
--- a/src/com/android/services/telephony/TelephonyConnectionService.java
+++ b/src/com/android/services/telephony/TelephonyConnectionService.java
@@ -1389,7 +1389,7 @@
// one and causing UI Jank.
boolean noActiveSimCard = SubscriptionManagerService.getInstance()
.getActiveSubInfoCount(phone.getContext().getOpPackageName(),
- phone.getContext().getAttributionTag()) == 0;
+ phone.getContext().getAttributionTag(), true/*isForAllProfile*/) == 0;
// If there's no active sim card and the device is in emergency mode, use E account.
addExistingConnection(mPhoneUtilsProxy.makePstnPhoneAccountHandleWithPrefix(
phone, "", isEmergencyNumber && noActiveSimCard), repConnection);
diff --git a/src/com/android/services/telephony/domainselection/CarrierConfigHelper.java b/src/com/android/services/telephony/domainselection/CarrierConfigHelper.java
new file mode 100644
index 0000000..d39a6b7
--- /dev/null
+++ b/src/com/android/services/telephony/domainselection/CarrierConfigHelper.java
@@ -0,0 +1,207 @@
+/*
+ * Copyright (C) 2023 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.services.telephony.domainselection;
+
+import static android.telephony.AccessNetworkConstants.AccessNetworkType.NGRAN;
+import static android.telephony.CarrierConfigManager.ImsEmergency.KEY_EMERGENCY_OVER_IMS_SUPPORTED_3GPP_NETWORK_TYPES_INT_ARRAY;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.content.res.Resources;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+import android.os.PersistableBundle;
+import android.os.SystemProperties;
+import android.preference.PreferenceManager;
+import android.telephony.CarrierConfigManager;
+import android.telephony.SubscriptionManager;
+import android.telephony.TelephonyManager;
+import android.util.ArrayMap;
+import android.util.Log;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.phone.R;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.stream.Collectors;
+
+/** Helper class to cache carrier configurations. */
+public class CarrierConfigHelper extends Handler {
+ private static final String TAG = "CarrierConfigHelper";
+ private static final boolean DBG = (SystemProperties.getInt("ro.debuggable", 0) == 1);
+
+ @VisibleForTesting
+ public static final String KEY_VONR_EMERGENCY_SUPPORT = "vonr_emergency_support";
+
+ private final Context mContext;
+ private final CarrierConfigManager mConfigManager;
+ private final TelephonyManager mTelephonyManager;
+ private final ArrayMap<Integer, Boolean> mVoNrSupported = new ArrayMap<>();
+
+ private final CarrierConfigManager.CarrierConfigChangeListener mCarrierConfigChangeListener =
+ (slotIndex, subId, carrierId, specificCarrierId) -> onCarrierConfigurationChanged(
+ slotIndex, subId, carrierId);
+
+ // For test purpose only
+ private final SharedPreferences mSharedPreferences;
+
+ private List<Integer> mIgnoreNrWhenSimRemoved = null;
+
+ /**
+ * Creates an instance.
+ *
+ * @param context The Context this is associated with.
+ * @param looper The Looper to run the CarrierConfigHelper.
+ */
+ public CarrierConfigHelper(@NonNull Context context, @NonNull Looper looper) {
+ this(context, looper, null);
+ }
+
+ /**
+ * Creates an instance.
+ *
+ * @param context The Context this is associated with.
+ * @param looper The Looper to run the CarrierConfigHelper.
+ * @param sharedPreferences The SharedPreferences instance.
+ */
+ @VisibleForTesting
+ public CarrierConfigHelper(@NonNull Context context, @NonNull Looper looper,
+ @Nullable SharedPreferences sharedPreferences) {
+ super(looper);
+
+ mContext = context;
+ mTelephonyManager = context.getSystemService(TelephonyManager.class);
+ mConfigManager = context.getSystemService(CarrierConfigManager.class);
+ mConfigManager.registerCarrierConfigChangeListener(this::post,
+ mCarrierConfigChangeListener);
+ mSharedPreferences = sharedPreferences;
+
+ readFromSharedPreference();
+ readResourceConfiguration();
+ }
+
+ /**
+ * Returns whether VoNR emergency was supported with the last valid subscription.
+ *
+ * @param slotIndex The SIM slot index.
+ * @return true if VoNR emergency was supported with the last valid subscription.
+ * Otherwise, false.
+ */
+ public boolean isVoNrEmergencySupported(int slotIndex) {
+ return mVoNrSupported.get(Integer.valueOf(slotIndex));
+ }
+
+ @Override
+ public void handleMessage(Message msg) {
+ switch(msg.what) {
+ default:
+ super.handleMessage(msg);
+ break;
+ }
+ }
+
+ private void readFromSharedPreference() {
+ mVoNrSupported.clear();
+ int modemCount = mTelephonyManager.getActiveModemCount();
+ SharedPreferences sp = (mSharedPreferences != null) ? mSharedPreferences
+ : PreferenceManager.getDefaultSharedPreferences(mContext);
+ for (int i = 0; i < modemCount; i++) {
+ Boolean savedConfig = Boolean.valueOf(
+ sp.getBoolean(KEY_VONR_EMERGENCY_SUPPORT + i, false));
+ mVoNrSupported.put(Integer.valueOf(i), savedConfig);
+ Log.i(TAG, "readFromSharedPreference slot=" + i + ", " + savedConfig);
+ }
+ }
+
+ private void onCarrierConfigurationChanged(int slotIndex, int subId, int carrierId) {
+ Log.i(TAG, "onCarrierConfigurationChanged slotIndex=" + slotIndex
+ + ", subId=" + subId + ", carrierId=" + carrierId);
+
+ if (slotIndex < 0
+ || !SubscriptionManager.isValidSubscriptionId(subId)
+ || mTelephonyManager.getSimState(slotIndex) != TelephonyManager.SIM_STATE_READY) {
+ return;
+ }
+
+ PersistableBundle b = mConfigManager.getConfigForSubId(subId,
+ KEY_EMERGENCY_OVER_IMS_SUPPORTED_3GPP_NETWORK_TYPES_INT_ARRAY);
+ if (b.isEmpty()) {
+ Log.e(TAG, "onCarrierConfigurationChanged empty result");
+ return;
+ }
+
+ if (!CarrierConfigManager.isConfigForIdentifiedCarrier(b)) {
+ Log.i(TAG, "onCarrierConfigurationChanged not carrier specific configuration");
+ return;
+ }
+
+ int[] imsRatsConfig = b.getIntArray(
+ KEY_EMERGENCY_OVER_IMS_SUPPORTED_3GPP_NETWORK_TYPES_INT_ARRAY);
+ if (imsRatsConfig == null) imsRatsConfig = new int[0];
+ boolean carrierConfig = false;
+ for (int i = 0; i < imsRatsConfig.length; i++) {
+ if (imsRatsConfig[i] == NGRAN) {
+ carrierConfig = true;
+ break;
+ }
+ }
+ if (mIgnoreNrWhenSimRemoved.contains(carrierId)) carrierConfig = false;
+
+ Boolean savedConfig = mVoNrSupported.get(Integer.valueOf(slotIndex));
+ if (carrierConfig == savedConfig) {
+ return;
+ }
+
+ mVoNrSupported.put(Integer.valueOf(slotIndex), Boolean.valueOf(carrierConfig));
+
+ SharedPreferences sp = (mSharedPreferences != null) ? mSharedPreferences
+ : PreferenceManager.getDefaultSharedPreferences(mContext);
+ SharedPreferences.Editor editor = sp.edit();
+ editor.putBoolean(KEY_VONR_EMERGENCY_SUPPORT + slotIndex, carrierConfig);
+ editor.apply();
+
+ Log.i(TAG, "onCarrierConfigurationChanged preference updated slotIndex=" + slotIndex
+ + ", supported=" + carrierConfig);
+ }
+
+ private void readResourceConfiguration() {
+ try {
+ mIgnoreNrWhenSimRemoved = Arrays.stream(mContext.getResources().getIntArray(
+ R.array.config_carriers_ignore_ngran_preference_when_sim_removed))
+ .boxed().collect(Collectors.toList());
+ } catch (Resources.NotFoundException nfe) {
+ Log.e(TAG, "readResourceConfiguration exception=" + nfe);
+ } catch (NullPointerException npe) {
+ Log.e(TAG, "readResourceConfiguration exception=" + npe);
+ }
+ if (mIgnoreNrWhenSimRemoved == null) {
+ mIgnoreNrWhenSimRemoved = new ArrayList<Integer>();
+ }
+ Log.i(TAG, "readResourceConfiguration ignoreNrWhenSimRemoved=" + mIgnoreNrWhenSimRemoved);
+ }
+
+ /** Destroys the instance. */
+ public void destroy() {
+ if (DBG) Log.d(TAG, "destroy");
+ mConfigManager.unregisterCarrierConfigChangeListener(mCarrierConfigChangeListener);
+ }
+}
diff --git a/src/com/android/services/telephony/domainselection/CrossSimRedialingController.java b/src/com/android/services/telephony/domainselection/CrossSimRedialingController.java
index f1bb78c..44904f4 100644
--- a/src/com/android/services/telephony/domainselection/CrossSimRedialingController.java
+++ b/src/com/android/services/telephony/domainselection/CrossSimRedialingController.java
@@ -31,16 +31,19 @@
import android.os.SystemProperties;
import android.telephony.Annotation.PreciseDisconnectCauses;
import android.telephony.CarrierConfigManager;
+import android.telephony.PhoneNumberUtils;
+import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
+import android.telephony.emergency.EmergencyNumber;
import android.text.TextUtils;
import android.util.LocalLog;
import android.util.Log;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.telephony.Phone;
-import com.android.internal.telephony.PhoneFactory;
import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
/** Controls the cross stack redialing. */
public class CrossSimRedialingController extends Handler {
@@ -53,11 +56,11 @@
/**
* Returns whether the number is an emergency number in the given modem slot.
*
- * @param slotId The slot id to be checked.
+ * @param subId The sub id to be checked.
* @param number The number.
* @return {@code true} if the number is an emergency number in the given slot.
*/
- boolean isEmergencyNumber(int slotId, String number);
+ boolean isEmergencyNumber(int subId, String number);
}
@VisibleForTesting
@@ -73,17 +76,23 @@
private EmergencyNumberHelper mEmergencyNumberHelper = new EmergencyNumberHelper() {
@Override
- public boolean isEmergencyNumber(int slotId, String number) {
- // TODO(b/258112541) Add System api to check emergency number per subscription.
+ public boolean isEmergencyNumber(int subId, String number) {
+ number = PhoneNumberUtils.stripSeparators(number);
+ if (TextUtils.isEmpty(number)) return false;
+ Map<Integer, List<EmergencyNumber>> lists = null;
try {
- Phone phone = PhoneFactory.getPhone(slotId);
- if (phone != null
- && phone.getEmergencyNumberTracker() != null
- && phone.getEmergencyNumberTracker().isEmergencyNumber(number)) {
- return true;
- }
- } catch (IllegalStateException e) {
- loge("isEmergencyNumber e=" + e);
+ lists = mTelephonyManager.getEmergencyNumberList();
+ } catch (IllegalStateException ise) {
+ loge("isEmergencyNumber ise=" + ise);
+ } catch (RuntimeException rte) {
+ loge("isEmergencyNumber rte=" + rte);
+ }
+ if (lists == null) return false;
+
+ List<EmergencyNumber> list = lists.get(subId);
+ if (list == null || list.isEmpty()) return false;
+ for (EmergencyNumber eNumber : list) {
+ if (number.equals(eNumber.getNumber())) return true;
}
return false;
}
@@ -242,11 +251,12 @@
continue;
}
- if (mEmergencyNumberHelper.isEmergencyNumber(i, mNumber)) {
- logi("isThereOtherSlot index=" + i + ", found");
+ int subId = SubscriptionManager.getSubscriptionId(i);
+ if (mEmergencyNumberHelper.isEmergencyNumber(subId, mNumber)) {
+ logi("isThereOtherSlot index=" + i + "(" + subId + "), found");
return true;
} else {
- logi("isThereOtherSlot index=" + i + ", not emergency number");
+ logi("isThereOtherSlot index=" + i + "(" + subId + "), not emergency number");
}
}
@@ -278,6 +288,12 @@
+ ", startQuickTimerInService=" + mStartQuickCrossStackTimerWhenInService);
}
+ /** Test purpose only. */
+ @VisibleForTesting
+ public EmergencyNumberHelper getEmergencyNumberHelper() {
+ return mEmergencyNumberHelper;
+ }
+
/** Destroys the instance. */
public void destroy() {
if (DBG) logd("destroy");
diff --git a/src/com/android/services/telephony/domainselection/EmergencyCallDomainSelector.java b/src/com/android/services/telephony/domainselection/EmergencyCallDomainSelector.java
index b8956d5..3d6a4d1 100644
--- a/src/com/android/services/telephony/domainselection/EmergencyCallDomainSelector.java
+++ b/src/com/android/services/telephony/domainselection/EmergencyCallDomainSelector.java
@@ -210,12 +210,14 @@
private final PowerManager.WakeLock mPartialWakeLock;
private final CrossSimRedialingController mCrossSimRedialingController;
+ private final CarrierConfigHelper mCarrierConfigHelper;
/** Constructor. */
public EmergencyCallDomainSelector(Context context, int slotId, int subId,
@NonNull Looper looper, @NonNull ImsStateTracker imsStateTracker,
@NonNull DestroyListener destroyListener,
- @NonNull CrossSimRedialingController csrController) {
+ @NonNull CrossSimRedialingController csrController,
+ @NonNull CarrierConfigHelper carrierConfigHelper) {
super(context, slotId, subId, looper, imsStateTracker, destroyListener, TAG);
mImsStateTracker.addBarringInfoListener(this);
@@ -225,6 +227,7 @@
mPartialWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG);
mCrossSimRedialingController = csrController;
+ mCarrierConfigHelper = carrierConfigHelper;
acquireWakeLock();
}
@@ -496,12 +499,7 @@
b.getIntArray(KEY_EMERGENCY_OVER_IMS_SUPPORTED_3GPP_NETWORK_TYPES_INT_ARRAY);
mImsRoamRatsConfig = b.getIntArray(
KEY_EMERGENCY_OVER_IMS_ROAMING_SUPPORTED_3GPP_NETWORK_TYPES_INT_ARRAY);
- if (!isSimReady()) {
- // Default configuration includes only EUTRAN.
- // In case of no SIM or SIM locked state, add NGRAN.
- mImsRatsConfig = new int[] { EUTRAN, NGRAN };
- mImsRoamRatsConfig = new int[] { EUTRAN, NGRAN };
- }
+ maybeModifyImsRats();
mCsRatsConfig =
b.getIntArray(KEY_EMERGENCY_OVER_CS_SUPPORTED_ACCESS_NETWORK_TYPES_INT_ARRAY);
@@ -571,6 +569,16 @@
}
}
+ /** Adds NGRAN if SIM is absent or locked and the last valid subscription supported NGRAN. */
+ private void maybeModifyImsRats() {
+ if (mCarrierConfigHelper.isVoNrEmergencySupported(getSlotId())
+ && !isSimReady() && mImsRatsConfig.length < 2) {
+ // Default configuration includes only EUTRAN.
+ mImsRatsConfig = new int[] { EUTRAN, NGRAN };
+ mImsRoamRatsConfig = new int[] { EUTRAN, NGRAN };
+ }
+ }
+
/**
* Caches the resource configuration.
*/
@@ -849,6 +857,11 @@
}
}
+ // Adds NGRAN at the end of the list if SIM is absent or locked and NGRAN is not included.
+ if (!isSimReady() && !preferredNetworks.contains(NGRAN)) {
+ preferredNetworks.add(NGRAN);
+ }
+
return preferredNetworks;
}
diff --git a/src/com/android/services/telephony/domainselection/TelephonyDomainSelectionService.java b/src/com/android/services/telephony/domainselection/TelephonyDomainSelectionService.java
index 3a8fc86..de2d752 100644
--- a/src/com/android/services/telephony/domainselection/TelephonyDomainSelectionService.java
+++ b/src/com/android/services/telephony/domainselection/TelephonyDomainSelectionService.java
@@ -17,6 +17,7 @@
package com.android.services.telephony.domainselection;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.annotation.SuppressLint;
import android.content.Context;
import android.os.Handler;
@@ -71,7 +72,8 @@
@SelectorType int selectorType, boolean isEmergency, @NonNull Looper looper,
@NonNull ImsStateTracker imsStateTracker,
@NonNull DomainSelectorBase.DestroyListener listener,
- @NonNull CrossSimRedialingController crossSimRedialingController);
+ @NonNull CrossSimRedialingController crossSimRedialingController,
+ @NonNull CarrierConfigHelper carrierConfigHelper);
}
private static final class DefaultDomainSelectorFactory implements DomainSelectorFactory {
@@ -80,7 +82,8 @@
@SelectorType int selectorType, boolean isEmergency, @NonNull Looper looper,
@NonNull ImsStateTracker imsStateTracker,
@NonNull DomainSelectorBase.DestroyListener listener,
- @NonNull CrossSimRedialingController crossSimRedialingController) {
+ @NonNull CrossSimRedialingController crossSimRedialingController,
+ @NonNull CarrierConfigHelper carrierConfigHelper) {
DomainSelectorBase selector = null;
logi("create-DomainSelector: slotId=" + slotId + ", subId=" + subId
@@ -91,7 +94,8 @@
case SELECTOR_TYPE_CALLING:
if (isEmergency) {
selector = new EmergencyCallDomainSelector(context, slotId, subId, looper,
- imsStateTracker, listener, crossSimRedialingController);
+ imsStateTracker, listener, crossSimRedialingController,
+ carrierConfigHelper);
} else {
selector = new NormalCallDomainSelector(context, slotId, subId, looper,
imsStateTracker, listener);
@@ -195,15 +199,17 @@
private final DomainSelectorFactory mDomainSelectorFactory;
private Handler mServiceHandler;
private CrossSimRedialingController mCrossSimRedialingController;
+ private CarrierConfigHelper mCarrierConfigHelper;
public TelephonyDomainSelectionService(Context context) {
- this(context, ImsStateTracker::new, new DefaultDomainSelectorFactory());
+ this(context, ImsStateTracker::new, new DefaultDomainSelectorFactory(), null);
}
@VisibleForTesting
public TelephonyDomainSelectionService(Context context,
@NonNull ImsStateTrackerFactory imsStateTrackerFactory,
- @NonNull DomainSelectorFactory domainSelectorFactory) {
+ @NonNull DomainSelectorFactory domainSelectorFactory,
+ @Nullable CarrierConfigHelper carrierConfigHelper) {
mContext = context;
mImsStateTrackerFactory = imsStateTrackerFactory;
mDomainSelectorFactory = domainSelectorFactory;
@@ -225,6 +231,8 @@
}
mCrossSimRedialingController = new CrossSimRedialingController(context, getLooper());
+ mCarrierConfigHelper = (carrierConfigHelper != null)
+ ? carrierConfigHelper : new CarrierConfigHelper(context, getLooper());
logi("TelephonyDomainSelectionService created");
}
@@ -268,6 +276,11 @@
mCrossSimRedialingController = null;
}
+ if (mCarrierConfigHelper != null) {
+ mCarrierConfigHelper.destroy();
+ mCarrierConfigHelper = null;
+ }
+
if (mServiceHandler != null) {
mServiceHandler.getLooper().quit();
mServiceHandler = null;
@@ -290,7 +303,7 @@
ImsStateTracker ist = getImsStateTracker(slotId);
DomainSelectorBase selector = mDomainSelectorFactory.create(mContext, slotId, subId,
selectorType, isEmergency, getLooper(), ist, mDestroyListener,
- mCrossSimRedialingController);
+ mCrossSimRedialingController, mCarrierConfigHelper);
if (selector != null) {
// Ensures that ImsStateTracker is started before selecting the domain if not started
diff --git a/tests/src/com/android/services/telephony/domainselection/CarrierConfigHelperTest.java b/tests/src/com/android/services/telephony/domainselection/CarrierConfigHelperTest.java
new file mode 100644
index 0000000..5d4fe17
--- /dev/null
+++ b/tests/src/com/android/services/telephony/domainselection/CarrierConfigHelperTest.java
@@ -0,0 +1,277 @@
+/*
+ * Copyright (C) 2023 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.services.telephony.domainselection;
+
+import static android.telephony.AccessNetworkConstants.AccessNetworkType.EUTRAN;
+import static android.telephony.AccessNetworkConstants.AccessNetworkType.NGRAN;
+import static android.telephony.CarrierConfigManager.KEY_CARRIER_CONFIG_APPLIED_BOOL;
+import static android.telephony.CarrierConfigManager.ImsEmergency.KEY_EMERGENCY_OVER_IMS_SUPPORTED_3GPP_NETWORK_TYPES_INT_ARRAY;
+
+import static junit.framework.Assert.assertFalse;
+import static junit.framework.Assert.assertTrue;
+import static junit.framework.Assert.assertNotNull;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.content.res.Resources;
+import android.os.HandlerThread;
+import android.os.Looper;
+import android.os.PersistableBundle;
+import android.telephony.CarrierConfigManager;
+import android.telephony.SubscriptionManager;
+import android.telephony.TelephonyManager;
+import android.testing.TestableLooper;
+import android.util.Log;
+
+import com.android.TestContext;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.util.concurrent.Executor;
+
+/**
+ * Unit tests for CarrierConfigHelper
+ */
+public class CarrierConfigHelperTest {
+ private static final String TAG = "CarrierConfigHelperTest";
+
+ private static final int SLOT_0 = 0;
+ private static final int SLOT_1 = 1;
+ private static final int SUB_1 = 1;
+ private static final int TEST_SIM_CARRIER_ID = 1911;
+
+ @Mock private Context mContext;
+ @Mock private SharedPreferences mSharedPreferences;
+ @Mock private SharedPreferences.Editor mEditor;
+ @Mock private Resources mResources;
+
+ private HandlerThread mHandlerThread;
+ private TestableLooper mLooper;
+ private CarrierConfigHelper mCarrierConfigHelper;
+ private CarrierConfigManager mCarrierConfigManager;
+ private TelephonyManager mTelephonyManager;
+
+ @Before
+ public void setUp() throws Exception {
+ MockitoAnnotations.initMocks(this);
+ mContext = new TestContext() {
+ @Override
+ public String getSystemServiceName(Class<?> serviceClass) {
+ if (serviceClass == TelephonyManager.class) {
+ return Context.TELEPHONY_SERVICE;
+ } else if (serviceClass == CarrierConfigManager.class) {
+ return Context.CARRIER_CONFIG_SERVICE;
+ }
+ return super.getSystemServiceName(serviceClass);
+ }
+
+ @Override
+ public String getOpPackageName() {
+ return "";
+ }
+
+ @Override
+ public Resources getResources() {
+ return mResources;
+ }
+ };
+
+ if (Looper.myLooper() == null) {
+ Looper.prepare();
+ }
+
+ mHandlerThread = new HandlerThread("CarrierConfigHelperTest");
+ mHandlerThread.start();
+
+ try {
+ mLooper = new TestableLooper(mHandlerThread.getLooper());
+ } catch (Exception e) {
+ logd("Unable to create looper from handler.");
+ }
+
+ doReturn(mEditor).when(mSharedPreferences).edit();
+
+ mCarrierConfigManager = mContext.getSystemService(CarrierConfigManager.class);
+ mTelephonyManager = mContext.getSystemService(TelephonyManager.class);
+ doReturn(2).when(mTelephonyManager).getActiveModemCount();
+ doReturn(TelephonyManager.SIM_STATE_READY)
+ .when(mTelephonyManager).getSimState(anyInt());
+
+ doReturn(new int[] { TEST_SIM_CARRIER_ID }).when(mResources).getIntArray(anyInt());
+
+ mCarrierConfigHelper = new CarrierConfigHelper(mContext, mHandlerThread.getLooper(),
+ mSharedPreferences);
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ if (mCarrierConfigHelper != null) {
+ mCarrierConfigHelper.destroy();
+ mCarrierConfigHelper = null;
+ }
+
+ if (mLooper != null) {
+ mLooper.destroy();
+ mLooper = null;
+ }
+ }
+
+ @Test
+ public void testInit() throws Exception {
+ ArgumentCaptor<CarrierConfigManager.CarrierConfigChangeListener> callbackCaptor =
+ ArgumentCaptor.forClass(CarrierConfigManager.CarrierConfigChangeListener.class);
+ ArgumentCaptor<Executor> executorCaptor = ArgumentCaptor.forClass(Executor.class);
+
+ verify(mCarrierConfigManager).registerCarrierConfigChangeListener(executorCaptor.capture(),
+ callbackCaptor.capture());
+ assertNotNull(executorCaptor.getValue());
+ assertNotNull(callbackCaptor.getValue());
+ assertFalse(mCarrierConfigHelper.isVoNrEmergencySupported(SLOT_0));
+ }
+
+ @Test
+ public void testCarrierConfigNotApplied() throws Exception {
+ ArgumentCaptor<CarrierConfigManager.CarrierConfigChangeListener> callbackCaptor =
+ ArgumentCaptor.forClass(CarrierConfigManager.CarrierConfigChangeListener.class);
+
+ verify(mCarrierConfigManager).registerCarrierConfigChangeListener(any(),
+ callbackCaptor.capture());
+
+ CarrierConfigManager.CarrierConfigChangeListener callback = callbackCaptor.getValue();
+
+ assertNotNull(callback);
+
+ // NR is included but carrier config is not applied.
+ PersistableBundle b = getPersistableBundle(new int[] { EUTRAN, NGRAN }, false);
+ doReturn(b).when(mCarrierConfigManager).getConfigForSubId(anyInt(), anyString());
+ callback.onCarrierConfigChanged(SLOT_0, SUB_1, 0, 0);
+
+ assertFalse(mCarrierConfigHelper.isVoNrEmergencySupported(SLOT_0));
+ }
+
+ @Test
+ public void testCarrierConfigApplied() throws Exception {
+ ArgumentCaptor<CarrierConfigManager.CarrierConfigChangeListener> callbackCaptor =
+ ArgumentCaptor.forClass(CarrierConfigManager.CarrierConfigChangeListener.class);
+
+ verify(mCarrierConfigManager).registerCarrierConfigChangeListener(any(),
+ callbackCaptor.capture());
+
+ CarrierConfigManager.CarrierConfigChangeListener callback = callbackCaptor.getValue();
+
+ assertNotNull(callback);
+
+ // NR is included and carrier config is applied.
+ PersistableBundle b = getPersistableBundle(new int[] { EUTRAN, NGRAN }, true);
+ doReturn(b).when(mCarrierConfigManager).getConfigForSubId(anyInt(), anyString());
+ callback.onCarrierConfigChanged(SLOT_0, SUB_1, 0, 0);
+
+ assertTrue(mCarrierConfigHelper.isVoNrEmergencySupported(SLOT_0));
+ assertFalse(mCarrierConfigHelper.isVoNrEmergencySupported(SLOT_1));
+
+ verify(mEditor).putBoolean(eq(CarrierConfigHelper.KEY_VONR_EMERGENCY_SUPPORT + SLOT_0),
+ eq(true));
+
+ // NR is not included and carrier config is applied.
+ b = getPersistableBundle(new int[] { EUTRAN }, true);
+ doReturn(b).when(mCarrierConfigManager).getConfigForSubId(anyInt(), anyString());
+ callback.onCarrierConfigChanged(SLOT_0, SUB_1, 0, 0);
+
+ assertFalse(mCarrierConfigHelper.isVoNrEmergencySupported(SLOT_0));
+
+ verify(mEditor).putBoolean(eq(CarrierConfigHelper.KEY_VONR_EMERGENCY_SUPPORT + SLOT_0),
+ eq(false));
+ }
+
+ @Test
+ public void testCarrierConfigInvalidSubId() throws Exception {
+ ArgumentCaptor<CarrierConfigManager.CarrierConfigChangeListener> callbackCaptor =
+ ArgumentCaptor.forClass(CarrierConfigManager.CarrierConfigChangeListener.class);
+
+ verify(mCarrierConfigManager).registerCarrierConfigChangeListener(any(),
+ callbackCaptor.capture());
+
+ CarrierConfigManager.CarrierConfigChangeListener callback = callbackCaptor.getValue();
+
+ assertNotNull(callback);
+
+ // NR is included and carrier config is applied.
+ PersistableBundle b = getPersistableBundle(new int[] { EUTRAN, NGRAN }, true);
+ doReturn(b).when(mCarrierConfigManager).getConfigForSubId(anyInt(), anyString());
+
+ // Invalid subscription
+ callback.onCarrierConfigChanged(SLOT_0, SubscriptionManager.INVALID_SUBSCRIPTION_ID, 0, 0);
+
+ assertFalse(mCarrierConfigHelper.isVoNrEmergencySupported(SLOT_0));
+ }
+
+ @Test
+ public void testRestoreFromSharedPreferences() throws Exception {
+ doReturn(true).when(mSharedPreferences).getBoolean(anyString(), anyBoolean());
+ mCarrierConfigHelper = new CarrierConfigHelper(mContext, mHandlerThread.getLooper(),
+ mSharedPreferences);
+
+ assertTrue(mCarrierConfigHelper.isVoNrEmergencySupported(SLOT_0));
+ }
+
+ @Test
+ public void testCarrierIgnoreNrWhenSimRemoved() throws Exception {
+ ArgumentCaptor<CarrierConfigManager.CarrierConfigChangeListener> callbackCaptor =
+ ArgumentCaptor.forClass(CarrierConfigManager.CarrierConfigChangeListener.class);
+
+ verify(mCarrierConfigManager).registerCarrierConfigChangeListener(any(),
+ callbackCaptor.capture());
+
+ CarrierConfigManager.CarrierConfigChangeListener callback = callbackCaptor.getValue();
+
+ assertNotNull(callback);
+
+ // NR is included and carrier config for TEST SIM is applied.
+ PersistableBundle b = getPersistableBundle(new int[] { EUTRAN, NGRAN }, true);
+ doReturn(b).when(mCarrierConfigManager).getConfigForSubId(anyInt(), anyString());
+ callback.onCarrierConfigChanged(SLOT_0, SUB_1, TEST_SIM_CARRIER_ID, 0);
+
+ // NR is ignored.
+ assertFalse(mCarrierConfigHelper.isVoNrEmergencySupported(SLOT_0));
+ assertFalse(mCarrierConfigHelper.isVoNrEmergencySupported(SLOT_1));
+ }
+
+ private static PersistableBundle getPersistableBundle(int[] imsRats, boolean applied) {
+ PersistableBundle bundle = new PersistableBundle();
+ bundle.putIntArray(KEY_EMERGENCY_OVER_IMS_SUPPORTED_3GPP_NETWORK_TYPES_INT_ARRAY, imsRats);
+ bundle.putBoolean(KEY_CARRIER_CONFIG_APPLIED_BOOL, applied);
+ return bundle;
+ }
+
+ private static void logd(String str) {
+ Log.d(TAG, str);
+ }
+}
diff --git a/tests/src/com/android/services/telephony/domainselection/CrossSimRedialingControllerTest.java b/tests/src/com/android/services/telephony/domainselection/CrossSimRedialingControllerTest.java
index a32329d..2ed91b8 100644
--- a/tests/src/com/android/services/telephony/domainselection/CrossSimRedialingControllerTest.java
+++ b/tests/src/com/android/services/telephony/domainselection/CrossSimRedialingControllerTest.java
@@ -27,6 +27,7 @@
import static com.android.services.telephony.domainselection.CrossSimRedialingController.MSG_QUICK_CROSS_STACK_TIMEOUT;
import static junit.framework.Assert.assertFalse;
+import static junit.framework.Assert.assertNotNull;
import static junit.framework.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.anyInt;
@@ -42,6 +43,7 @@
import android.os.PersistableBundle;
import android.telephony.CarrierConfigManager;
import android.telephony.TelephonyManager;
+import android.telephony.emergency.EmergencyNumber;
import android.testing.TestableLooper;
import android.util.Log;
@@ -54,6 +56,11 @@
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
/**
* Unit tests for CrossSimRedialingController
*/
@@ -66,8 +73,6 @@
private static final String TELECOM_CALL_ID1 = "TC1";
private static final String TEST_EMERGENCY_NUMBER = "911";
- @Mock private CarrierConfigManager mCarrierConfigManager;
- @Mock private TelephonyManager mTelephonyManager;
@Mock private EmergencyCallDomainSelector mEcds;
@Mock private CrossSimRedialingController.EmergencyNumberHelper mEmergencyNumberHelper;
@@ -76,6 +81,8 @@
private HandlerThread mHandlerThread;
private TestableLooper mLooper;
private CrossSimRedialingController mCsrController;
+ private CarrierConfigManager mCarrierConfigManager;
+ private TelephonyManager mTelephonyManager;
@Before
public void setUp() throws Exception {
@@ -462,6 +469,42 @@
verify(mEcds, times(0)).notifyCrossStackTimerExpired();
}
+ @Test
+ public void testEmergencyNumberHelper() throws Exception {
+ mCsrController = new CrossSimRedialingController(mContext,
+ mHandlerThread.getLooper());
+
+ CrossSimRedialingController.EmergencyNumberHelper helper =
+ mCsrController.getEmergencyNumberHelper();
+
+ assertNotNull(helper);
+
+ EmergencyNumber num1 = new EmergencyNumber(TEST_EMERGENCY_NUMBER, "us", "",
+ EmergencyNumber.EMERGENCY_SERVICE_CATEGORY_POLICE, new ArrayList<String>(),
+ EmergencyNumber.EMERGENCY_NUMBER_SOURCE_DATABASE,
+ EmergencyNumber.EMERGENCY_CALL_ROUTING_UNKNOWN);
+
+ EmergencyNumber num2 = new EmergencyNumber("119", "jp", "",
+ EmergencyNumber.EMERGENCY_SERVICE_CATEGORY_POLICE, new ArrayList<String>(),
+ EmergencyNumber.EMERGENCY_NUMBER_SOURCE_DATABASE,
+ EmergencyNumber.EMERGENCY_CALL_ROUTING_UNKNOWN);
+
+ Map<Integer, List<EmergencyNumber>> lists = new HashMap<>();
+ List<EmergencyNumber> list = new ArrayList<>();
+ list.add(num1);
+ lists.put(1, list);
+
+ list = new ArrayList<>();
+ list.add(num2);
+ lists.put(2, list);
+
+ doReturn(lists).when(mTelephonyManager).getEmergencyNumberList();
+
+ assertTrue(helper.isEmergencyNumber(1, TEST_EMERGENCY_NUMBER));
+ assertFalse(helper.isEmergencyNumber(2, TEST_EMERGENCY_NUMBER));
+ assertFalse(helper.isEmergencyNumber(3, TEST_EMERGENCY_NUMBER));
+ }
+
private void createController() throws Exception {
mCsrController = new CrossSimRedialingController(mContext,
mHandlerThread.getLooper(), mEmergencyNumberHelper);
diff --git a/tests/src/com/android/services/telephony/domainselection/EmergencyCallDomainSelectorTest.java b/tests/src/com/android/services/telephony/domainselection/EmergencyCallDomainSelectorTest.java
index c8ac7e9..eab40f9 100644
--- a/tests/src/com/android/services/telephony/domainselection/EmergencyCallDomainSelectorTest.java
+++ b/tests/src/com/android/services/telephony/domainselection/EmergencyCallDomainSelectorTest.java
@@ -96,6 +96,7 @@
import android.telephony.EmergencyRegResult;
import android.telephony.NetworkRegistrationInfo;
import android.telephony.PreciseDisconnectCause;
+import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
import android.telephony.TransportSelectorCallback;
import android.telephony.WwanSelectorCallback;
@@ -140,6 +141,7 @@
@Mock private DomainSelectorBase.DestroyListener mDestroyListener;
@Mock private ProvisioningManager mProvisioningManager;
@Mock private CrossSimRedialingController mCsrdCtrl;
+ @Mock private CarrierConfigHelper mCarrierConfigHelper;
@Mock private Resources mResources;
private Context mContext;
@@ -2002,7 +2004,35 @@
}
@Test
- public void testSimLockScanPsPreferredIncludingNr() throws Exception {
+ public void testSimLockScanPsPreferredWithNr() throws Exception {
+ createSelector(SLOT_0_SUB_ID);
+ unsolBarringInfoChanged(false);
+
+ // The last valid subscription supported NR.
+ doReturn(true).when(mCarrierConfigHelper).isVoNrEmergencySupported(eq(SLOT_0));
+ when(mTelephonyManager.getSimState(anyInt())).thenReturn(
+ TelephonyManager.SIM_STATE_PIN_REQUIRED);
+
+ EmergencyRegResult 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(mWwanSelectorCallback, times(1)).onRequestEmergencyNetworkScan(
+ any(), anyInt(), any(), any());
+ assertEquals(4, mAccessNetwork.size());
+ assertEquals(EUTRAN, (int) mAccessNetwork.get(0));
+ assertEquals(NGRAN, (int) mAccessNetwork.get(1));
+ assertEquals(UTRAN, (int) mAccessNetwork.get(2));
+ assertEquals(GERAN, (int) mAccessNetwork.get(3));
+ }
+
+ @Test
+ public void testSimLockScanPsPreferredWithNrAtTheEnd() throws Exception {
createSelector(SLOT_0_SUB_ID);
unsolBarringInfoChanged(false);
@@ -2020,8 +2050,62 @@
verify(mWwanSelectorCallback, times(1)).onRequestEmergencyNetworkScan(
any(), anyInt(), any(), any());
+ assertEquals(4, mAccessNetwork.size());
+ assertEquals(EUTRAN, (int) mAccessNetwork.get(0));
+ assertEquals(UTRAN, (int) mAccessNetwork.get(1));
+ assertEquals(GERAN, (int) mAccessNetwork.get(2));
+ assertEquals(NGRAN, (int) mAccessNetwork.get(3));
+ }
+
+ @Test
+ public void testInvalidSubscriptionScanPsPreferredWithNrAtTheEnd() throws Exception {
+ createSelector(SubscriptionManager.INVALID_SUBSCRIPTION_ID);
+ unsolBarringInfoChanged(false);
+
+ EmergencyRegResult regResult = getEmergencyRegResult(
+ UNKNOWN, REGISTRATION_STATE_UNKNOWN, 0, false, false, 0, 0, "", "");
+ SelectionAttributes attr = getSelectionAttributes(SLOT_0,
+ SubscriptionManager.INVALID_SUBSCRIPTION_ID, regResult);
+ mDomainSelector.selectDomain(attr, mTransportSelectorCallback);
+ processAllMessages();
+
+ bindImsServiceUnregistered();
+ processAllMessages();
+
+ verify(mWwanSelectorCallback, times(1)).onRequestEmergencyNetworkScan(
+ any(), anyInt(), any(), any());
+ assertEquals(4, mAccessNetwork.size());
+ assertEquals(EUTRAN, (int) mAccessNetwork.get(0));
+ assertEquals(UTRAN, (int) mAccessNetwork.get(1));
+ assertEquals(GERAN, (int) mAccessNetwork.get(2));
+ assertEquals(NGRAN, (int) mAccessNetwork.get(3));
+ }
+
+ @Test
+ public void testInvalidSubscriptionScanPsPreferredWithNr() throws Exception {
+ createSelector(SubscriptionManager.INVALID_SUBSCRIPTION_ID);
+ unsolBarringInfoChanged(false);
+
+ // The last valid subscription supported NR.
+ doReturn(true).when(mCarrierConfigHelper).isVoNrEmergencySupported(eq(SLOT_0));
+
+ EmergencyRegResult regResult = getEmergencyRegResult(
+ UNKNOWN, REGISTRATION_STATE_UNKNOWN, 0, false, false, 0, 0, "", "");
+ SelectionAttributes attr = getSelectionAttributes(SLOT_0,
+ SubscriptionManager.INVALID_SUBSCRIPTION_ID, regResult);
+ mDomainSelector.selectDomain(attr, mTransportSelectorCallback);
+ processAllMessages();
+
+ bindImsServiceUnregistered();
+ processAllMessages();
+
+ verify(mWwanSelectorCallback, times(1)).onRequestEmergencyNetworkScan(
+ any(), anyInt(), any(), any());
+ assertEquals(4, mAccessNetwork.size());
assertEquals(EUTRAN, (int) mAccessNetwork.get(0));
assertEquals(NGRAN, (int) mAccessNetwork.get(1));
+ assertEquals(UTRAN, (int) mAccessNetwork.get(2));
+ assertEquals(GERAN, (int) mAccessNetwork.get(3));
}
private void setupForScanListTest(PersistableBundle bundle) throws Exception {
@@ -2097,7 +2181,7 @@
private void createSelector(int subId) throws Exception {
mDomainSelector = new EmergencyCallDomainSelector(
mContext, SLOT_0, subId, mHandlerThread.getLooper(),
- mImsStateTracker, mDestroyListener, mCsrdCtrl);
+ mImsStateTracker, mDestroyListener, mCsrdCtrl, mCarrierConfigHelper);
mDomainSelector.clearResourceConfiguration();
replaceInstance(DomainSelectorBase.class,
"mWwanSelectorCallback", mDomainSelector, mWwanSelectorCallback);
diff --git a/tests/src/com/android/services/telephony/domainselection/TelephonyDomainSelectionServiceTest.java b/tests/src/com/android/services/telephony/domainselection/TelephonyDomainSelectionServiceTest.java
index f340e94..647ef41 100644
--- a/tests/src/com/android/services/telephony/domainselection/TelephonyDomainSelectionServiceTest.java
+++ b/tests/src/com/android/services/telephony/domainselection/TelephonyDomainSelectionServiceTest.java
@@ -78,7 +78,8 @@
@SelectorType int selectorType, boolean isEmergency,
@NonNull Looper looper, @NonNull ImsStateTracker imsStateTracker,
@NonNull DomainSelectorBase.DestroyListener listener,
- @NonNull CrossSimRedialingController crossSimRedialingController) {
+ @NonNull CrossSimRedialingController crossSimRedialingController,
+ @NonNull CarrierConfigHelper carrierConfigHelper) {
switch (selectorType) {
case DomainSelectionService.SELECTOR_TYPE_CALLING: // fallthrough
case DomainSelectionService.SELECTOR_TYPE_SMS: // fallthrough
@@ -107,6 +108,7 @@
@Mock private TransportSelectorCallback mSelectorCallback1;
@Mock private TransportSelectorCallback mSelectorCallback2;
@Mock private ImsStateTracker mImsStateTracker;
+ @Mock private CarrierConfigHelper mCarrierConfigHelper;
private final ServiceState mServiceState = new ServiceState();
private final BarringInfo mBarringInfo = new BarringInfo();
@@ -128,7 +130,7 @@
mContext = new TestContext();
mDomainSelectionService = new TelephonyDomainSelectionService(mContext,
- mImsStateTrackerFactory, mDomainSelectorFactory);
+ mImsStateTrackerFactory, mDomainSelectorFactory, mCarrierConfigHelper);
mServiceHandler = new Handler(mDomainSelectionService.getLooper());
mTestableLooper = new TestableLooper(mDomainSelectionService.getLooper());