Merge "Introduced forceResetCarrierKeysForImsiEncryption TestAPI to delete Imsi Certificate." into main
diff --git a/res/values-ne/strings.xml b/res/values-ne/strings.xml
index baa5aa7..0f06fe7 100644
--- a/res/values-ne/strings.xml
+++ b/res/values-ne/strings.xml
@@ -130,7 +130,7 @@
<string name="enable_cdma_cw" msgid="811047045863422232">"अन गर्नुहोस्"</string>
<string name="disable_cdma_cw" msgid="7119290446496301734">"रद्द गर्नुहोस्"</string>
<string name="cdma_call_waiting_in_ims_on" msgid="6390979414188659218">"IMS अन्तर्गत CDMA कल प्रतीक्षाको सुविधा सक्रिय छ"</string>
- <string name="cdma_call_waiting_in_ims_off" msgid="1099246114368636334">"IMS अन्तर्गत CDMA कल प्रतीक्षाको सुविधा निष्क्रिय छ"</string>
+ <string name="cdma_call_waiting_in_ims_off" msgid="1099246114368636334">"IMS अन्तर्गत CDMA कल प्रतीक्षाको सुविधा अफ छ"</string>
<string name="updating_title" msgid="6130548922615719689">"कल सेटिङहरू"</string>
<string name="call_settings_admin_user_only" msgid="7238947387649986286">"कल सेटिङहरू केवल प्रशासकीय प्रयोगकर्ताद्वारा परिवर्तन गर्न सकिन्छ।"</string>
<string name="phone_account_settings_user_restriction" msgid="9142685151087208396">"एड्मिन वा कार्य प्रोफाइलका प्रयोगकर्ता मात्र फोनमा लिंक गरिएको खाताका सेटिङ बदल्न सक्नुहुन्छ।"</string>
@@ -771,7 +771,7 @@
<string name="clh_callFailed_interworking_unspecified_txt" msgid="7969686413930847182">"कल पूरा गर्न सकिएन। त्रुटिको कोड: १२७।"</string>
<string name="labelCallBarring" msgid="4180377113052853173">"कल ब्यारिङ"</string>
<string name="sum_call_barring_enabled" msgid="5184331188926370824">"सक्रिय छ"</string>
- <string name="sum_call_barring_disabled" msgid="5699448000600153096">"निष्क्रिय छ"</string>
+ <string name="sum_call_barring_disabled" msgid="5699448000600153096">"अफ छ"</string>
<string name="call_barring_baoc" msgid="7400892586336429326">"सबै बहिर्गमन"</string>
<string name="call_barring_baoc_enabled" msgid="3131509193386668182">"सबै बहिर्गमन कलहरूमाथिको रोक असक्षम पार्ने हो?"</string>
<string name="call_barring_baoc_disabled" msgid="8534224684091141509">"सबै बहिर्गमन कलहरूमाथि रोक लगाउने हो?"</string>
@@ -863,7 +863,7 @@
<string name="radioInfo_service_in" msgid="45753418231446400">"सेवामा"</string>
<string name="radioInfo_service_out" msgid="287972405416142312">"सेवा उपलब्ध छैन"</string>
<string name="radioInfo_service_emergency" msgid="4763879891415016848">"आपत्कालीन कल मात्र"</string>
- <string name="radioInfo_service_off" msgid="3456583511226783064">"रेडियो निष्क्रिय छ"</string>
+ <string name="radioInfo_service_off" msgid="3456583511226783064">"रेडियो अफ छ"</string>
<string name="radioInfo_roaming_in" msgid="3156335577793145965">"रोमिङ"</string>
<string name="radioInfo_roaming_not" msgid="1904547918725478110">"रोमिङमा छैन"</string>
<string name="radioInfo_phone_idle" msgid="2191653783170757819">"निष्क्रिय"</string>
diff --git a/res/values-pt/strings.xml b/res/values-pt/strings.xml
index 966aa15..ecd6673 100644
--- a/res/values-pt/strings.xml
+++ b/res/values-pt/strings.xml
@@ -44,8 +44,8 @@
<string name="pause_prompt_yes" msgid="8184132073048369575">"Sim"</string>
<string name="pause_prompt_no" msgid="2145264674774138579">"Não"</string>
<string name="wild_prompt_str" msgid="5858910969703305375">"Substituir caractere curinga por"</string>
- <string name="no_vm_number" msgid="6623853880546176930">"Número correio de voz ausente"</string>
- <string name="no_vm_number_msg" msgid="5165161462411372504">"Não há um número correio de voz armazenado no chip."</string>
+ <string name="no_vm_number" msgid="6623853880546176930">"Não há um número do correio de voz"</string>
+ <string name="no_vm_number_msg" msgid="5165161462411372504">"Não há um número do correio de voz armazenado no chip."</string>
<string name="add_vm_number_str" msgid="7368168964435881637">"Adicionar número"</string>
<string name="voice_number_setting_primary_user_only" msgid="3394706575741912843">"As configurações do correio de voz só podem ser modificadas pelo usuário principal."</string>
<string name="puk_unlocked" msgid="4627340655215746511">"O seu chip foi desbloqueado. O seu telefone está desbloqueando…"</string>
@@ -157,7 +157,7 @@
<item msgid="6813323051965618926">"Ocultar número"</item>
<item msgid="9150034130629852635">"Mostrar número"</item>
</string-array>
- <string name="vm_changed" msgid="4739599044379692505">"Número correio de voz alterado."</string>
+ <string name="vm_changed" msgid="4739599044379692505">"Número do correio de voz alterado."</string>
<string name="vm_change_failed" msgid="7877733929455763566">"Não foi possível alterar o número do correio de voz.\nEntre em contato com sua operadora se o problema persistir."</string>
<string name="fw_change_failed" msgid="9179241823460192148">"Não foi possível alterar o número de encaminhamento.\nEntre em contato com sua operadora se o problema persistir."</string>
<string name="fw_get_in_vm_failed" msgid="2432678237218183844">"Não foi possível recuperar e salvar as configurações de número atual de encaminhamento.\nMudar para o novo provedor?"</string>
@@ -521,7 +521,7 @@
<string name="pin2_unblocked" msgid="4481107908727789303">"PIN2 não mais bloqueado"</string>
<string name="pin2_error_exception" msgid="8116103864600823641">"Erro de rede ou do chip"</string>
<string name="doneButton" msgid="7371209609238460207">"Concluído"</string>
- <string name="voicemail_settings_number_label" msgid="1265118640154688162">"Número correio de voz"</string>
+ <string name="voicemail_settings_number_label" msgid="1265118640154688162">"Número do correio de voz"</string>
<string name="card_title_dialing" msgid="8742182654254431781">"Chamando..."</string>
<string name="card_title_redialing" msgid="18130232613559964">"Rediscando"</string>
<string name="card_title_conf_call" msgid="901197309274457427">"Teleconferência"</string>
@@ -533,7 +533,7 @@
<string name="notification_voicemail_title" msgid="3932876181831601351">"Novo correio de voz"</string>
<string name="notification_voicemail_title_count" msgid="2806950319222327082">"Novo correio de voz (<xliff:g id="COUNT">%d</xliff:g>)"</string>
<string name="notification_voicemail_text_format" msgid="5720947141702312537">"Discar <xliff:g id="VOICEMAIL_NUMBER">%s</xliff:g>"</string>
- <string name="notification_voicemail_no_vm_number" msgid="3423686009815186750">"Número correio de voz desconhecido"</string>
+ <string name="notification_voicemail_no_vm_number" msgid="3423686009815186750">"Número do correio de voz desconhecido"</string>
<string name="notification_network_selection_title" msgid="255595526707809121">"Sem serviço"</string>
<string name="notification_network_selection_text" msgid="553288408722427659">"A rede selecionada (<xliff:g id="OPERATOR_NAME">%s</xliff:g>) não está disponível"</string>
<string name="incall_error_power_off" product="watch" msgid="7191184639454113633">"Ative a rede móvel e desative o modo avião ou o modo de economia de bateria para ligar."</string>
diff --git a/res/values/config.xml b/res/values/config.xml
index 847c4c5..03da05b 100644
--- a/res/values/config.xml
+++ b/res/values/config.xml
@@ -394,4 +394,10 @@
<!-- Whether to turn off OEM-enabled satellite during emergency call -->
<bool name="config_turn_off_oem_enabled_satellite_during_emergency_call">false</bool>
+
+ <!-- The timeout duration in milliseconds used to determine how long does it wait for modem to
+ get in-service state when dialing emergency routing emergency calls in airplane mode before
+ starting the call. If the value is 0, it doesn't wait and starts the call right after
+ turning radio power on. -->
+ <integer name="config_in_service_wait_timer_when_dialing_emergency_routing_ecc_in_apm">3000</integer>
</resources>
diff --git a/src/com/android/phone/PhoneGlobals.java b/src/com/android/phone/PhoneGlobals.java
index dcddf2b..bab260c 100644
--- a/src/com/android/phone/PhoneGlobals.java
+++ b/src/com/android/phone/PhoneGlobals.java
@@ -571,8 +571,10 @@
// Initialize EmergencyStateTracker if domain selection is supported
boolean isSuplDdsSwitchRequiredForEmergencyCall = getResources()
.getBoolean(R.bool.config_gnss_supl_requires_default_data_for_emergency);
+ int inServiceWaitTimeWhenDialEccInApm = getResources().getInteger(R.integer
+ .config_in_service_wait_timer_when_dialing_emergency_routing_ecc_in_apm);
EmergencyStateTracker.make(this, isSuplDdsSwitchRequiredForEmergencyCall,
- mFeatureFlags);
+ inServiceWaitTimeWhenDialEccInApm, mFeatureFlags);
DynamicRoutingController.getInstance().initialize(this);
}
diff --git a/src/com/android/phone/PhoneInterfaceManager.java b/src/com/android/phone/PhoneInterfaceManager.java
index bb88426..b0f88b2 100644
--- a/src/com/android/phone/PhoneInterfaceManager.java
+++ b/src/com/android/phone/PhoneInterfaceManager.java
@@ -13228,14 +13228,17 @@
return;
}
if (isAllowed) {
- if (mFeatureFlags.carrierRoamingNbIotNtn()
- && !mSatelliteAccessController.getSatelliteDisallowedReasons()
- .isEmpty()) {
- result.accept(SATELLITE_RESULT_ACCESS_BARRED);
- } else {
- mSatelliteController.requestSatelliteEnabled(
+ ResultReceiver resultReceiver = new ResultReceiver(mMainThreadHandler) {
+ @Override
+ protected void onReceiveResult(int resultCode, Bundle resultData) {
+ Log.d(LOG_TAG, "updateSystemSelectionChannels resultCode="
+ + resultCode);
+ mSatelliteController.requestSatelliteEnabled(
enableSatellite, enableDemoMode, isEmergency, callback);
- }
+ }
+ };
+ mSatelliteAccessController.updateSystemSelectionChannels(
+ resultReceiver);
} else {
result.accept(SATELLITE_RESULT_ACCESS_BARRED);
}
@@ -14865,4 +14868,25 @@
Binder.restoreCallingIdentity(identity);
}
}
+
+ /**
+ * Returns carrier id maps to the passing {@link CarrierIdentifier}.
+ *
+ * @param carrierIdentifier {@link CarrierIdentifier}.
+ *
+ * @return carrier id from passing {@link CarrierIdentifier} or UNKNOWN_CARRIER_ID
+ * if the carrier cannot be identified
+ */
+ public int getCarrierIdFromIdentifier(@NonNull CarrierIdentifier carrierIdentifier) {
+ enforceReadPrivilegedPermission("getCarrierIdFromIdentifier");
+ enforceTelephonyFeatureWithException(getCurrentPackageName(),
+ PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION, "getCarrierIdFromIdentifier");
+
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ return CarrierResolver.getCarrierIdFromIdentifier(mApp, carrierIdentifier);
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
}
diff --git a/src/com/android/phone/satellite/accesscontrol/SatelliteAccessConfigurationParser.java b/src/com/android/phone/satellite/accesscontrol/SatelliteAccessConfigurationParser.java
new file mode 100644
index 0000000..0658279
--- /dev/null
+++ b/src/com/android/phone/satellite/accesscontrol/SatelliteAccessConfigurationParser.java
@@ -0,0 +1,392 @@
+/*
+ * Copyright (C) 2024 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.phone.satellite.accesscontrol;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.net.ParseException;
+import android.os.Build;
+import android.telephony.satellite.EarfcnRange;
+import android.telephony.satellite.SatelliteAccessConfiguration;
+import android.telephony.satellite.SatelliteInfo;
+import android.telephony.satellite.SatellitePosition;
+import android.util.Log;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+import org.json.JSONArray;
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import java.io.ByteArrayOutputStream;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.UUID;
+
+public class SatelliteAccessConfigurationParser {
+ private static final String TAG = "SatelliteAccessConfigurationParser";
+
+ public static final String SATELLITE_ACCESS_CONTROL_CONFIGS = "access_control_configs";
+ public static final String SATELLITE_CONFIG_ID = "config_id";
+ public static final String SATELLITE_INFOS = "satellite_infos";
+ public static final String SATELLITE_ID = "satellite_id";
+ public static final String SATELLITE_POSITION = "satellite_position";
+ public static final String SATELLITE_LONGITUDE = "longitude";
+ public static final String SATELLITE_ALTITUDE = "altitude";
+ public static final String SATELLITE_EARFCN_RANGES = "earfcn_ranges";
+ public static final String SATELLITE_START_EARFCN = "start_earfcn";
+ public static final String SATELLITE_END_EARFCN = "end_earfcn";
+ public static final String SATELLITE_BANDS = "bands";
+ public static final String SATELLITE_TAG_ID_LIST = "tag_ids";
+
+
+ /**
+ * Parses a JSON file containing satellite access configurations.
+ *
+ * @param fileName The name of the JSON file to parse.
+ * @return A map of satellite access configurations, keyed by config ID.
+ * @throws RuntimeException if the JSON file cannot be parsed or if a required field is missing.
+ */
+ @Nullable
+ public static Map<Integer, SatelliteAccessConfiguration> parse(@NonNull String fileName) {
+ logd("SatelliteAccessConfigurationParser: parse: " + fileName);
+ Map<Integer, SatelliteAccessConfiguration> satelliteAccessConfigurationMap;
+
+ try {
+ String jsonString = readJsonStringFromFile(fileName);
+ JSONObject satelliteAccessConfigJsonObject = new JSONObject(jsonString);
+ JSONArray configurationArrayJson = satelliteAccessConfigJsonObject.optJSONArray(
+ SATELLITE_ACCESS_CONTROL_CONFIGS);
+
+ if (configurationArrayJson == null) {
+ loge("parse : failed to parse satellite access configurations json");
+ return null;
+ }
+
+ satelliteAccessConfigurationMap =
+ parseSatelliteAccessConfigurations(configurationArrayJson);
+
+ } catch (JSONException | ParseException e) {
+ loge("Failed to parse satellite access configurations: " + e.getMessage());
+ throw new RuntimeException(e);
+ }
+
+ logd("satelliteAccessConfigurationMap= " + satelliteAccessConfigurationMap);
+ return satelliteAccessConfigurationMap;
+ }
+
+ private static void logd(String log) {
+ if (!Build.TYPE.equals("user")) {
+ Log.d(TAG, log);
+ }
+ }
+
+ private static void loge(String log) {
+ Log.e(TAG, log);
+ }
+
+ @NonNull
+ protected static List<Integer> parseSatelliteTagIdList(@NonNull JSONObject satelliteInfoJson) {
+ List<Integer> tagIdList = new ArrayList<>();
+ try {
+ JSONArray tagIdArray = satelliteInfoJson.optJSONArray(SATELLITE_TAG_ID_LIST);
+ tagIdList = parseIntegerList(tagIdArray);
+ } catch (JSONException e) {
+ loge("parseSatelliteInfo: parsing is error");
+ return tagIdList;
+ }
+
+ logd("parseSatelliteBandList: " + tagIdList);
+ return tagIdList;
+ }
+
+ @Nullable
+ private static Map<Integer, SatelliteAccessConfiguration> parseSatelliteAccessConfigurations(
+ JSONArray satelliteAccessConfigurationJsonArray) throws JSONException {
+ Map<Integer, SatelliteAccessConfiguration> satelliteConfigMap = new HashMap<>();
+ if (satelliteAccessConfigurationJsonArray == null) {
+ loge("parseSatelliteAccessConfigurations: jsonArray is null, return null");
+ return null;
+ }
+
+ for (int i = 0; i < satelliteAccessConfigurationJsonArray.length(); i++) {
+ JSONObject satelliteAccessConfigurationJson =
+ satelliteAccessConfigurationJsonArray.getJSONObject(i);
+
+ int configId = satelliteAccessConfigurationJson.optInt(SATELLITE_CONFIG_ID, -1);
+ if (!isRegionalConfigIdValid(configId)) {
+ loge("parseAccessControlConfigs: invalid config_id, return null");
+ return null;
+ }
+
+ JSONArray satelliteInfoJsonArray = satelliteAccessConfigurationJson
+ .getJSONArray(SATELLITE_INFOS);
+ List<SatelliteInfo> satelliteInfoList = parseSatelliteInfoList(satelliteInfoJsonArray);
+ if (satelliteInfoList.isEmpty()) {
+ logd("parseAccessControlConfigs: satelliteInfoList is empty");
+ }
+
+ List<Integer> tagIdList = parseSatelliteTagIdList(satelliteAccessConfigurationJson);
+ if (satelliteInfoList.isEmpty() && tagIdList.isEmpty()) {
+ loge("parseAccessControlConfigs: satelliteInfoList is empty and tagId is null");
+ return null;
+ }
+
+ satelliteConfigMap.put(configId,
+ new SatelliteAccessConfiguration(satelliteInfoList, tagIdList));
+ }
+
+ logd("parseSatelliteAccessConfigurations: " + satelliteConfigMap);
+ return satelliteConfigMap;
+ }
+
+ /**
+ * Checks if a regional configuration ID is valid.
+ * A valid regional configuration ID is a non-null integer that is greater than or equal to
+ * zero.
+ *
+ * @param configId The regional configuration ID to check.
+ * @return {@code true} if the ID is valid, {@code false} otherwise.
+ */
+ public static boolean isRegionalConfigIdValid(@Nullable Integer configId) {
+ return (configId != null && configId >= 0);
+ }
+
+ @Nullable
+ protected static UUID parseSatelliteId(@NonNull JSONObject satelliteInfoJson) {
+ String uuidString = satelliteInfoJson.optString(SATELLITE_ID, null);
+ UUID satelliteId;
+ if (uuidString != null) {
+ try {
+ satelliteId = UUID.fromString(uuidString);
+ } catch (IllegalArgumentException e) {
+ loge("getSatelliteId: invalid UUID format: " + uuidString + " | " + e.getMessage());
+ return null;
+ }
+ } else {
+ loge("getSatelliteId: satellite uuid is missing");
+ return null;
+ }
+
+ logd("getSatelliteId: satellite uuid is " + satelliteId);
+ return satelliteId;
+ }
+
+ @Nullable
+ protected static SatellitePosition parseSatellitePosition(
+ @NonNull JSONObject satelliteInfoJson) {
+ JSONObject jsonObject = satelliteInfoJson.optJSONObject(SATELLITE_POSITION);
+ if (jsonObject == null) {
+ loge("parseSatellitePosition: jsonObject is null");
+ return null;
+ }
+ SatellitePosition satellitePosition;
+ try {
+ double longitude = jsonObject.getDouble(SATELLITE_LONGITUDE);
+ double altitude = jsonObject.getDouble(SATELLITE_ALTITUDE);
+ if (isValidLongitude(longitude) && isValidAltitude(altitude)) {
+ satellitePosition = new SatellitePosition(longitude, altitude);
+ } else {
+ loge("parseSatellitePosition: invalid value: " + longitude + " | " + altitude);
+ return null;
+ }
+ } catch (JSONException e) {
+ loge("parseSatellitePosition: json parsing error " + e.getMessage());
+ return null;
+ }
+
+ logd("parseSatellitePosition: " + satellitePosition);
+ return satellitePosition;
+ }
+
+ @NonNull
+ protected static List<EarfcnRange> parseSatelliteEarfcnRangeList(
+ @NonNull JSONObject satelliteInfoJson) {
+ JSONArray earfcnRangesArray = satelliteInfoJson.optJSONArray(SATELLITE_EARFCN_RANGES);
+ List<EarfcnRange> earfcnRangeList = new ArrayList<>();
+ if (earfcnRangesArray == null) {
+ loge("parseSatelliteEarfcnRangeList: earfcn_ranges is missing");
+ return earfcnRangeList;
+ }
+
+ try {
+ for (int j = 0; j < earfcnRangesArray.length(); j++) {
+ JSONObject earfcnRangeJson = earfcnRangesArray.getJSONObject(j);
+ EarfcnRange earfcnRange = parseEarfcnRange(earfcnRangeJson);
+ if (earfcnRange == null) {
+ loge("parseSatelliteEarfcnRangeList: earfcnRange is null, return empty list");
+ earfcnRangeList.clear();
+ return earfcnRangeList;
+ }
+ earfcnRangeList.add(earfcnRange);
+ }
+ } catch (JSONException e) {
+ loge("parseSatelliteEarfcnRangeList: earfcnRange json parsing error");
+ earfcnRangeList.clear();
+ return earfcnRangeList;
+ }
+ logd("parseSatelliteEarfcnRangeList: " + earfcnRangeList);
+ return earfcnRangeList;
+ }
+
+ @NonNull
+ protected static List<Integer> parseSatelliteBandList(@NonNull JSONObject satelliteInfoJson) {
+ List<Integer> bandList = new ArrayList<>();
+ try {
+ JSONArray bandArray = satelliteInfoJson.getJSONArray(SATELLITE_BANDS);
+ bandList = parseIntegerList(bandArray);
+ } catch (JSONException e) {
+ loge("parseSatelliteInfo: bands parsing is error");
+ return bandList;
+ }
+
+ logd("parseSatelliteBandList: " + bandList);
+ return bandList;
+ }
+
+ @NonNull
+ protected static List<SatelliteInfo> parseSatelliteInfoList(JSONArray satelliteInfojsonArray)
+ throws JSONException {
+ List<SatelliteInfo> satelliteInfoList = new ArrayList<>();
+ for (int i = 0; i < satelliteInfojsonArray.length(); i++) {
+ JSONObject SatelliteInfoJson = satelliteInfojsonArray.getJSONObject(i);
+ if (SatelliteInfoJson == null) {
+ satelliteInfoList.clear();
+ break;
+ }
+ UUID id = parseSatelliteId(SatelliteInfoJson);
+ SatellitePosition position = parseSatellitePosition(SatelliteInfoJson);
+ List<EarfcnRange> earfcnRangeList = parseSatelliteEarfcnRangeList(SatelliteInfoJson);
+ List<Integer> bandList = parseSatelliteBandList(SatelliteInfoJson);
+
+ if (id == null || (bandList.isEmpty() && earfcnRangeList.isEmpty())) {
+ loge("parseSatelliteInfo: id is " + id
+ + " or both band list and earfcn range list are empty");
+ satelliteInfoList.clear();
+ return satelliteInfoList;
+ }
+
+ SatelliteInfo info = new SatelliteInfo(id, position, bandList, earfcnRangeList);
+ satelliteInfoList.add(info);
+ }
+ logd("parseSatelliteInfoList: " + satelliteInfoList);
+ return satelliteInfoList;
+ }
+
+ /**
+ * Load json file from the filePath
+ *
+ * @param jsonFilePath The file path of json file
+ * @return json string type json contents
+ */
+ @Nullable
+ @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
+ public static String readJsonStringFromFile(@NonNull String jsonFilePath) {
+ logd("jsonFilePath is " + jsonFilePath);
+ String json = null;
+ try (InputStream inputStream = new FileInputStream(jsonFilePath);
+ ByteArrayOutputStream byteArrayStream = new ByteArrayOutputStream()) {
+ byte[] buffer = new byte[1024];
+ int length;
+ while ((length = inputStream.read(buffer)) != -1) {
+ byteArrayStream.write(buffer, 0, length);
+ }
+ json = byteArrayStream.toString(StandardCharsets.UTF_8);
+ } catch (FileNotFoundException e) {
+ loge("Error file " + jsonFilePath + " is not founded: " + e.getMessage());
+ } catch (IOException | NullPointerException e) {
+ loge("Error reading file " + jsonFilePath + ": " + e);
+ } finally {
+ logd("jsonString is " + json);
+ }
+ return json;
+ }
+
+ private static boolean isValidEarfcn(int earfcn) {
+ if (earfcn >= 0 && earfcn <= 65535) {
+ return true;
+ }
+ loge("isValidEarfcn: earfcn value is out of valid range: " + earfcn);
+ return false;
+ }
+
+ private static boolean isValidEarfcnRange(int start, int end) {
+ if (start <= end) {
+ return true;
+ }
+ loge("isValidEarfcnRange: earfcn range start " + start + " is bigger than end " + end);
+ return false;
+ }
+
+ @Nullable
+ private static EarfcnRange parseEarfcnRange(@Nullable JSONObject jsonObject) {
+ logd("parseEarfcnRange");
+ if (jsonObject == null) {
+ loge("parseEarfcnRange: jsonObject is null");
+ return null;
+ }
+ try {
+ int start = jsonObject.getInt(SATELLITE_START_EARFCN);
+ int end = jsonObject.getInt(SATELLITE_END_EARFCN);
+
+ if (isValidEarfcn(start) && isValidEarfcn(end) && isValidEarfcnRange(start, end)) {
+ return new EarfcnRange(start, end);
+ }
+
+ loge("parseEarfcnRange: earfcn value is not valid, return null");
+ return null;
+ } catch (JSONException e) {
+ loge("parseEarfcnRange: json parsing error: " + e.getMessage());
+ return null;
+ }
+ }
+
+ @NonNull
+ private static List<Integer> parseIntegerList(@Nullable JSONArray jsonArray)
+ throws JSONException {
+ List<Integer> intList = new ArrayList<>();
+ if (jsonArray == null) {
+ loge("parseIntegerList: jsonArray is null, return IntArray with empty");
+ return intList;
+ }
+ for (int i = 0; i < jsonArray.length(); i++) {
+ try {
+ intList.add(jsonArray.getInt(i));
+ } catch (JSONException e) {
+ loge("parseIntegerList: jsonArray parsing error: " + e.getMessage());
+ intList.clear();
+ }
+ }
+ logd("parseIntegerList: " + intList);
+ return intList;
+ }
+
+ private static boolean isValidLongitude(double longitude) {
+ return (longitude >= -180.0 && longitude <= 180.0);
+ }
+
+ private static boolean isValidAltitude(double altitude) {
+ return (altitude >= 0);
+ }
+}
diff --git a/src/com/android/phone/satellite/accesscontrol/SatelliteAccessController.java b/src/com/android/phone/satellite/accesscontrol/SatelliteAccessController.java
index c1cc74e..a47691e 100644
--- a/src/com/android/phone/satellite/accesscontrol/SatelliteAccessController.java
+++ b/src/com/android/phone/satellite/accesscontrol/SatelliteAccessController.java
@@ -20,15 +20,16 @@
import static android.telephony.satellite.SatelliteManager.KEY_SATELLITE_COMMUNICATION_ALLOWED;
import static android.telephony.satellite.SatelliteManager.KEY_SATELLITE_PROVISIONED;
import static android.telephony.satellite.SatelliteManager.KEY_SATELLITE_SUPPORTED;
-import static android.telephony.satellite.SatelliteManager.SATELLITE_DISALLOWED_REASON_NOT_SUPPORTED;
-import static android.telephony.satellite.SatelliteManager.SATELLITE_DISALLOWED_REASON_NOT_PROVISIONED;
-import static android.telephony.satellite.SatelliteManager.SATELLITE_DISALLOWED_REASON_NOT_IN_ALLOWED_REGION;
-import static android.telephony.satellite.SatelliteManager.SATELLITE_DISALLOWED_REASON_UNSUPPORTED_DEFAULT_MSG_APP;
import static android.telephony.satellite.SatelliteManager.SATELLITE_DISALLOWED_REASON_LOCATION_DISABLED;
+import static android.telephony.satellite.SatelliteManager.SATELLITE_DISALLOWED_REASON_NOT_IN_ALLOWED_REGION;
+import static android.telephony.satellite.SatelliteManager.SATELLITE_DISALLOWED_REASON_NOT_PROVISIONED;
+import static android.telephony.satellite.SatelliteManager.SATELLITE_DISALLOWED_REASON_NOT_SUPPORTED;
+import static android.telephony.satellite.SatelliteManager.SATELLITE_DISALLOWED_REASON_UNSUPPORTED_DEFAULT_MSG_APP;
import static android.telephony.satellite.SatelliteManager.SATELLITE_RESULT_INVALID_TELEPHONY_STATE;
import static android.telephony.satellite.SatelliteManager.SATELLITE_RESULT_LOCATION_DISABLED;
import static android.telephony.satellite.SatelliteManager.SATELLITE_RESULT_LOCATION_NOT_AVAILABLE;
import static android.telephony.satellite.SatelliteManager.SATELLITE_RESULT_NOT_SUPPORTED;
+import static android.telephony.satellite.SatelliteManager.SATELLITE_RESULT_NO_RESOURCES;
import static android.telephony.satellite.SatelliteManager.SATELLITE_RESULT_REQUEST_NOT_SUPPORTED;
import static android.telephony.satellite.SatelliteManager.SATELLITE_RESULT_SUCCESS;
@@ -59,6 +60,7 @@
import android.os.Bundle;
import android.os.CancellationSignal;
import android.os.Handler;
+import android.os.HandlerExecutor;
import android.os.HandlerThread;
import android.os.IBinder;
import android.os.Looper;
@@ -71,10 +73,12 @@
import android.provider.DeviceConfig;
import android.telecom.TelecomManager;
import android.telephony.AnomalyReporter;
+import android.telephony.CarrierConfigManager;
import android.telephony.DropBoxManagerLoggerBackend;
import android.telephony.NetworkRegistrationInfo;
import android.telephony.PersistentLogger;
import android.telephony.Rlog;
+import android.telephony.SubscriptionInfo;
import android.telephony.SubscriptionManager;
import android.telephony.satellite.ISatelliteCommunicationAllowedStateCallback;
import android.telephony.satellite.ISatelliteDisallowedReasonsCallback;
@@ -83,7 +87,9 @@
import android.telephony.satellite.SatelliteAccessConfiguration;
import android.telephony.satellite.SatelliteManager;
import android.telephony.satellite.SatelliteSubscriberProvisionStatus;
+import android.telephony.satellite.SystemSelectionSpecifier;
import android.text.TextUtils;
+import android.util.IntArray;
import android.util.Pair;
import com.android.internal.R;
@@ -100,6 +106,7 @@
import com.android.internal.telephony.satellite.metrics.AccessControllerMetricsStats;
import com.android.internal.telephony.satellite.metrics.ConfigUpdaterMetricsStats;
import com.android.internal.telephony.satellite.metrics.ControllerMetricsStats;
+import com.android.internal.telephony.subscription.SubscriptionManagerService;
import com.android.internal.telephony.util.TelephonyUtils;
import com.android.phone.PhoneGlobals;
@@ -120,6 +127,7 @@
import java.util.Locale;
import java.util.Map;
import java.util.Objects;
+import java.util.Optional;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
@@ -162,6 +170,8 @@
protected static final int EVENT_CONFIG_DATA_UPDATED = 4;
protected static final int EVENT_COUNTRY_CODE_CHANGED = 5;
protected static final int EVENT_LOCATION_SETTINGS_ENABLED = 6;
+ protected static final int CMD_UPDATE_SYSTEM_SELECTION_CHANNELS = 7;
+ protected static final int EVENT_LOCATION_SETTINGS_DISABLED = 8;
public static final int DEFAULT_REGIONAL_SATELLITE_CONFIG_ID = 0;
public static final int UNKNOWN_REGIONAL_SATELLITE_CONFIG_ID = -1;
@@ -177,7 +187,7 @@
private static final int SATELLITE_DISALLOWED_REASON_NONE = -1;
private static final List<Integer> DISALLOWED_REASONS_TO_BE_RESET =
Arrays.asList(SATELLITE_DISALLOWED_REASON_NOT_IN_ALLOWED_REGION,
- SATELLITE_DISALLOWED_REASON_LOCATION_DISABLED);
+ SATELLITE_DISALLOWED_REASON_LOCATION_DISABLED);
private static final HashMap<Integer, Pair<Integer, Integer>>
SATELLITE_SOS_UNAVAILABLE_REASONS = new HashMap<>(Map.of(
@@ -222,6 +232,8 @@
/** Feature flags to control behavior and errors. */
@NonNull
private final FeatureFlags mFeatureFlags;
+ @NonNull
+ private final Context mContext;
@GuardedBy("mLock")
@Nullable
protected SatelliteOnDeviceAccessController mSatelliteOnDeviceAccessController;
@@ -246,11 +258,16 @@
@NonNull
private final ISatelliteProvisionStateCallback mInternalSatelliteProvisionStateCallback;
@NonNull
+ private final ResultReceiver mInternalUpdateSystemSelectionChannelsResultReceiver;
+ @NonNull
protected final Object mLock = new Object();
@GuardedBy("mLock")
@NonNull
private final Set<ResultReceiver> mSatelliteAllowResultReceivers = new HashSet<>();
@NonNull
+ private final Set<ResultReceiver>
+ mUpdateSystemSelectionChannelsResultReceivers = new HashSet<>();
+ @NonNull
private List<String> mSatelliteCountryCodes;
private boolean mIsSatelliteAllowAccessControl;
@Nullable
@@ -264,6 +281,7 @@
@Nullable
private File mOverriddenSatelliteS2CellFile;
private long mOverriddenLocationFreshDurationNanos;
+
@GuardedBy("mLock")
@NonNull
private final Map<SatelliteOnDeviceAccessController.LocationToken, Integer>
@@ -287,11 +305,23 @@
@GuardedBy("mLock")
@Nullable
protected Integer mNewRegionalConfigId = null;
+ @NonNull
+ private final CarrierConfigManager mCarrierConfigManager;
+ @NonNull
+ private final CarrierConfigManager.CarrierConfigChangeListener mCarrierConfigChangeListener;
+ /**
+ * Key: Sub Id, Value: (key: Regional satellite config Id, value: SatelliteRegionalConfig
+ * contains satellite config IDs and set of earfcns in the corresponding regions).
+ */
+ @GuardedBy("mRegionalSatelliteEarfcnsLock")
+ private Map<Integer, Map<Integer, SatelliteRegionalConfig>>
+ mSatelliteRegionalConfigPerSubMap = new HashMap();
+ @NonNull private final Object mRegionalSatelliteEarfcnsLock = new Object();
/** Key: Config ID; Value: SatelliteAccessConfiguration */
- @NonNull
- private HashMap<Integer, SatelliteAccessConfiguration> mSatelliteAccessConfigMap =
- new HashMap<>();
+ @GuardedBy("mLock")
+ @Nullable
+ private Map<Integer, SatelliteAccessConfiguration> mSatelliteAccessConfigMap;
/** These are used for CTS test */
private Path mCtsSatS2FilePath = null;
@@ -375,6 +405,9 @@
if (mLocationManager.isLocationEnabled()) {
plogd("Location settings is just enabled");
sendRequestAsync(EVENT_LOCATION_SETTINGS_ENABLED, null);
+ } else {
+ plogd("Location settings is just enabled");
+ sendRequestAsync(EVENT_LOCATION_SETTINGS_DISABLED, null);
}
}
}
@@ -405,6 +438,7 @@
@Nullable SatelliteOnDeviceAccessController satelliteOnDeviceAccessController,
@Nullable File s2CellFile) {
super(looper);
+ mContext = context;
if (isSatellitePersistentLoggingEnabled(context, featureFlags)) {
mPersistentLogger = new PersistentLogger(
DropBoxManagerLoggerBackend.getInstance(context));
@@ -453,6 +487,8 @@
mNotifySatelliteAvailabilityEnabled =
context.getResources().getBoolean(
R.bool.config_satellite_should_notify_availability);
+ initializeSatelliteSystemNotification(context);
+ registerDefaultSmsAppChangedBroadcastReceiver(context);
mInternalSatelliteSupportedStateCallback = new ISatelliteSupportedStateCallback.Stub() {
@Override
@@ -527,15 +563,33 @@
+ satelliteSubscriberProvisionStatus);
}
};
+ initializeSatelliteSystemNotification(context);
result = mSatelliteController.registerForSatelliteProvisionStateChanged(
mInternalSatelliteProvisionStateCallback);
plogd("registerForSatelliteProvisionStateChanged result: " + result);
+ mInternalUpdateSystemSelectionChannelsResultReceiver = new ResultReceiver(this) {
+ @Override
+ protected void onReceiveResult(int resultCode, Bundle resultData) {
+ plogd("UpdateSystemSelectionChannels.onReceiveResult: resultCode=" + resultCode
+ + ", resultData=" + resultData);
+ sendUpdateSystemSelectionChannelsResult(resultCode, resultData);
+ }
+ };
+
// Init the SatelliteOnDeviceAccessController so that the S2 level can be cached
initSatelliteOnDeviceAccessController();
- initializeSatelliteSystemNotification(context);
registerLocationModeChangedBroadcastReceiver(context);
- registerDefaultSmsAppChangedBroadcastReceiver(context);
+
+ mCarrierConfigManager = context.getSystemService(CarrierConfigManager.class);
+ mCarrierConfigChangeListener =
+ (slotIndex, subId, carrierId, specificCarrierId) -> handleCarrierConfigChanged(
+ context, slotIndex, subId, carrierId, specificCarrierId);
+
+ if (mCarrierConfigManager != null) {
+ mCarrierConfigManager.registerCarrierConfigChangeListener(
+ new HandlerExecutor(new Handler(looper)), mCarrierConfigChangeListener);
+ }
}
private void updateCurrentSatelliteAllowedState(boolean isAllowed) {
@@ -591,10 +645,14 @@
updateSatelliteConfigData((Context) ar.userObj);
break;
case EVENT_LOCATION_SETTINGS_ENABLED:
+ case EVENT_LOCATION_SETTINGS_DISABLED:
// Fall through
case EVENT_COUNTRY_CODE_CHANGED:
handleSatelliteAllowedRegionPossiblyChanged(msg.what);
break;
+ case CMD_UPDATE_SYSTEM_SELECTION_CHANNELS:
+ handleCmdUpdateSystemSelectionChannels((ResultReceiver) msg.obj);
+ break;
default:
plogw("SatelliteAccessControllerHandler: unexpected message code: " + msg.what);
break;
@@ -665,28 +723,29 @@
SatelliteAccessConfiguration satelliteAccessConfig = null;
synchronized (mLock) {
- if (isSatelliteCommunicationAllowed && isRegionalConfigIdValid(
- mRegionalConfigId)) {
+ if (isSatelliteCommunicationAllowed && SatelliteAccessConfigurationParser
+ .isRegionalConfigIdValid(mRegionalConfigId)) {
plogd("requestSatelliteAccessConfigurationForCurrentLocation : "
+ "mRegionalConfigId is " + mRegionalConfigId);
- satelliteAccessConfig =
- mSatelliteAccessConfigMap.get(mRegionalConfigId);
+ satelliteAccessConfig = Optional.ofNullable(mSatelliteAccessConfigMap)
+ .map(map -> map.get(mRegionalConfigId))
+ .orElse(null);
}
}
plogd("requestSatelliteAccessConfigurationForCurrentLocation : "
+ "satelliteAccessConfig is " + satelliteAccessConfig);
- Bundle bundle = new Bundle();
- bundle.putParcelable(KEY_SATELLITE_ACCESS_CONFIGURATION, satelliteAccessConfig);
- result.send(resultCode, bundle);
+ if (satelliteAccessConfig == null) {
+ result.send(SATELLITE_RESULT_NO_RESOURCES, null);
+ } else {
+ Bundle bundle = new Bundle();
+ bundle.putParcelable(KEY_SATELLITE_ACCESS_CONFIGURATION, satelliteAccessConfig);
+ result.send(resultCode, bundle);
+ }
}
};
requestIsCommunicationAllowedForCurrentLocation(internalResultReceiver, false);
}
- private boolean isRegionalConfigIdValid(@Nullable Integer configId) {
- return (configId != null && configId >= 0);
- }
-
/**
* This API should be used by only CTS tests to override the overlay configs of satellite
* access controller.
@@ -734,6 +793,28 @@
return true;
}
+ /**
+ * Report updated system selection to modem and report the update result.
+ */
+ public void updateSystemSelectionChannels(@NonNull ResultReceiver result) {
+ plogd("updateSystemSelectionChannels");
+ if (!mFeatureFlags.carrierRoamingNbIotNtn()) {
+ plogd("updateSystemSelectionChannels: "
+ + "carrierRoamingNbIotNtn flag is disabled");
+ result.send(SATELLITE_RESULT_REQUEST_NOT_SUPPORTED, null);
+ return;
+ }
+ synchronized (mLock) {
+ if (mRegionalConfigId == null) {
+ plogd("updateSystemSelectionChannels: Invalid Regional config ID."
+ + " System Selection channels can not be passed down to modem");
+ result.send(SatelliteManager.SATELLITE_RESULT_ACCESS_BARRED, null);
+ return;
+ }
+ }
+ sendRequestAsync(CMD_UPDATE_SYSTEM_SELECTION_CHANNELS, result);
+ }
+
protected File getTestSatelliteS2File(String fileName) {
plogd("getTestSatelliteS2File: fileName=" + fileName);
if (TextUtils.equals(fileName, GOOGLE_US_SAN_SAT_S2_FILE_NAME)) {
@@ -1028,6 +1109,7 @@
ploge("The satellite S2 cell file " + satelliteS2CellFileName + " does not exist");
mSatelliteS2CellFile = null;
}
+
mLocationFreshDurationNanos = getSatelliteLocationFreshDurationFromOverlayConfig(context);
mAccessControllerMetricsStats.setConfigDataSource(
SatelliteConstants.CONFIG_DATA_SOURCE_DEVICE_CONFIG);
@@ -1038,6 +1120,28 @@
mLocationQueryThrottleIntervalNanos = getLocationQueryThrottleIntervalNanos(context);
}
+ protected void loadSatelliteAccessConfigurationFromDeviceConfig() {
+ String satelliteConfigurationFileName =
+ getSatelliteConfigurationFileNameFromOverlayConfig(mContext);
+ loadSatelliteAccessConfigurationFromFile(satelliteConfigurationFileName);
+ }
+
+ protected void loadSatelliteAccessConfigurationFromFile(String fileName) {
+ logd("loadSatelliteAccessConfigurationFromFile: " + fileName);
+ if (!TextUtils.isEmpty(fileName)) {
+ try {
+ synchronized (mLock) {
+ mSatelliteAccessConfigMap =
+ SatelliteAccessConfigurationParser.parse(fileName);
+ }
+ } catch (Exception e) {
+ loge("loadSatelliteAccessConfigurationFromFile: failed load json file: " + e);
+ }
+ } else {
+ loge("loadSatelliteAccessConfigurationFromFile: fileName is empty");
+ }
+ }
+
private void loadConfigUpdaterConfigs() {
if (mSharedPreferences == null) {
ploge("loadConfigUpdaterConfigs : mSharedPreferences is null");
@@ -1159,9 +1263,9 @@
}
private void registerDefaultSmsAppChangedBroadcastReceiver(Context context) {
- if (!mFeatureFlags.oemEnabledSatelliteFlag()) {
+ if (!mFeatureFlags.carrierRoamingNbIotNtn()) {
plogd("registerDefaultSmsAppChangedBroadcastReceiver: Flag "
- + "oemEnabledSatellite is disabled");
+ + "carrierRoamingNbIotNtn is disabled");
return;
}
IntentFilter intentFilter = new IntentFilter();
@@ -1273,7 +1377,7 @@
}
private void sendSatelliteAllowResultToReceivers(int resultCode, Bundle resultData,
- boolean allowed) {
+ boolean allowed) {
plogd("sendSatelliteAllowResultToReceivers : resultCode is " + resultCode);
if (resultCode == SATELLITE_RESULT_SUCCESS) {
updateCurrentSatelliteAllowedState(allowed);
@@ -1331,12 +1435,17 @@
logd("mSatelliteDisallowedReasons:"
+ String.join(", ", mSatelliteDisallowedReasons.toString()));
notifySatelliteDisallowedReasonsChanged();
- if (mNotifySatelliteAvailabilityEnabled) {
+ if (mFeatureFlags.carrierRoamingNbIotNtn() && mNotifySatelliteAvailabilityEnabled) {
showSatelliteSystemNotification();
}
}
private void showSatelliteSystemNotification() {
+ if (mNotificationManager == null) {
+ logd("showSatelliteSystemNotification: NotificationManager is null");
+ return;
+ }
+
if (mSatelliteDisallowedReasons.isEmpty()) {
if (!hasAlreadyNotified(KEY_AVAILABLE_NOTIFICATION_SHOWN, 0)) {
mNotificationManager.notifyAsUser(
@@ -1449,15 +1558,18 @@
);
notificationChannel.setSound(null, null);
mNotificationManager = context.getSystemService(NotificationManager.class);
+ if(mNotificationManager == null) {
+ ploge("initializeSatelliteSystemNotification: notificationManager is null");
+ return;
+ }
mNotificationManager.createNotificationChannel(notificationChannel);
createAvailableNotifications(context);
createUnavailableNotifications(context);
}
- private Notification createNotification(@NonNull Context context,
- String title,
- String content) {
+ private Notification createNotification(@NonNull Context context, String title,
+ String content) {
Notification.Builder notificationBuilder = new Notification.Builder(context)
.setContentTitle(title)
.setContentText(content)
@@ -1521,42 +1633,52 @@
public void onReceive(Context context, Intent intent) {
if (intent.getAction()
.equals(Intent.ACTION_PACKAGE_CHANGED)) {
- boolean isDefaultMsgAppSupported = false;
- ComponentName componentName =
- SmsApplication.getDefaultSmsApplicationAsUser(
- context, true, context.getUser());
- logd("Current default SMS app:" + componentName);
- if (componentName != null) {
- String packageName = componentName.getPackageName();
- List<String> supportedMsgApps =
- mSatelliteController.getSatelliteSupportedMsgApps(
- mSatelliteController.getSelectedSatelliteSubId());
- if (supportedMsgApps.contains(packageName)) {
- isDefaultMsgAppSupported = true;
- }
- } else {
- logd("No default SMS app");
- }
-
- if (isDefaultMsgAppSupported) {
- if (mSatelliteDisallowedReasons.contains(Integer.valueOf(
- SATELLITE_DISALLOWED_REASON_UNSUPPORTED_DEFAULT_MSG_APP))) {
- mSatelliteDisallowedReasons.remove(Integer.valueOf(
- SATELLITE_DISALLOWED_REASON_UNSUPPORTED_DEFAULT_MSG_APP));
- handleEventDisallowedReasonsChanged();
- }
- } else {
- if (!mSatelliteDisallowedReasons.contains(Integer.valueOf(
- SATELLITE_DISALLOWED_REASON_UNSUPPORTED_DEFAULT_MSG_APP))) {
- mSatelliteDisallowedReasons.add(Integer.valueOf(
- SATELLITE_DISALLOWED_REASON_UNSUPPORTED_DEFAULT_MSG_APP));
- handleEventDisallowedReasonsChanged();
- }
- }
+ evaluatePossibleChangeInDefaultSmsApp(context);
}
}
};
+ private void evaluatePossibleChangeInDefaultSmsApp(@NonNull Context context) {
+ if (!mFeatureFlags.carrierRoamingNbIotNtn()) {
+ plogd("evaluatePossibleChangeInDefaultSmsApp: Flag "
+ + "carrierRoamingNbIotNtn is disabled");
+ return;
+ }
+
+ boolean isDefaultMsgAppSupported = false;
+ ComponentName componentName = SmsApplication.getDefaultSmsApplicationAsUser(
+ context, true, context.getUser());
+ plogd("Current default SMS app:" + componentName);
+ if (componentName != null) {
+ String packageName = componentName.getPackageName();
+ List<String> supportedMsgApps =
+ mSatelliteController.getSatelliteSupportedMsgApps(
+ mSatelliteController.getSelectedSatelliteSubId());
+ plogd("supportedMsgApps:" + String.join(", ", supportedMsgApps));
+ if (supportedMsgApps.contains(packageName)) {
+ isDefaultMsgAppSupported = true;
+ }
+ } else {
+ plogd("No default SMS app");
+ }
+
+ if (isDefaultMsgAppSupported) {
+ if (mSatelliteDisallowedReasons.contains(Integer.valueOf(
+ SATELLITE_DISALLOWED_REASON_UNSUPPORTED_DEFAULT_MSG_APP))) {
+ mSatelliteDisallowedReasons.remove(Integer.valueOf(
+ SATELLITE_DISALLOWED_REASON_UNSUPPORTED_DEFAULT_MSG_APP));
+ handleEventDisallowedReasonsChanged();
+ }
+ } else {
+ if (!mSatelliteDisallowedReasons.contains(Integer.valueOf(
+ SATELLITE_DISALLOWED_REASON_UNSUPPORTED_DEFAULT_MSG_APP))) {
+ mSatelliteDisallowedReasons.add(Integer.valueOf(
+ SATELLITE_DISALLOWED_REASON_UNSUPPORTED_DEFAULT_MSG_APP));
+ handleEventDisallowedReasonsChanged();
+ }
+ }
+ }
+
private void handleSatelliteAllowedRegionPossiblyChanged(int handleEvent) {
if (!mFeatureFlags.oemEnabledSatelliteFlag()) {
ploge("handleSatelliteAllowedRegionPossiblyChanged: "
@@ -1873,7 +1995,9 @@
if (!Objects.equals(mRegionalConfigId, mNewRegionalConfigId)) {
mRegionalConfigId = mNewRegionalConfigId;
notifyRegionalSatelliteConfigurationChanged(
- mSatelliteAccessConfigMap.get(mRegionalConfigId));
+ Optional.ofNullable(mSatelliteAccessConfigMap)
+ .map(map -> map.get(mRegionalConfigId))
+ .orElse(null));
}
}
}
@@ -2024,7 +2148,8 @@
* {@link SatelliteOnDeviceAccessController} instance and the
* device is using a user build.
*/
- private boolean initSatelliteOnDeviceAccessController() throws IllegalStateException {
+ private boolean initSatelliteOnDeviceAccessController()
+ throws IllegalStateException {
synchronized (mLock) {
if (getSatelliteS2CellFile() == null) return false;
@@ -2041,6 +2166,7 @@
restartKeepOnDeviceAccessControllerResourcesTimer();
mS2Level = mSatelliteOnDeviceAccessController.getS2Level();
plogd("mS2Level=" + mS2Level);
+ loadSatelliteAccessConfigurationFromDeviceConfig();
} catch (Exception ex) {
ploge("Got exception in creating an instance of SatelliteOnDeviceAccessController,"
+ " ex=" + ex + ", sat s2 file="
@@ -2048,6 +2174,7 @@
reportAnomaly(UUID_CREATE_ON_DEVICE_ACCESS_CONTROLLER_EXCEPTION,
"Exception in creating on-device satellite access controller");
mSatelliteOnDeviceAccessController = null;
+ mSatelliteAccessConfigMap = null;
if (!mIsOverlayConfigOverridden) {
mSatelliteS2CellFile = null;
}
@@ -2068,11 +2195,84 @@
ploge("cleanupOnDeviceAccessControllerResources: ex=" + ex);
}
mSatelliteOnDeviceAccessController = null;
+ mSatelliteAccessConfigMap = null;
stopKeepOnDeviceAccessControllerResourcesTimer();
}
}
}
+ private void handleCmdUpdateSystemSelectionChannels(
+ @NonNull ResultReceiver resultReceiver) {
+ synchronized (mLock) {
+ mUpdateSystemSelectionChannelsResultReceivers.add(resultReceiver);
+ if (mUpdateSystemSelectionChannelsResultReceivers.size() > 1) {
+ plogd("updateSystemSelectionChannels is already being processed");
+ return;
+ }
+ int subId = mSatelliteController.getSelectedSatelliteSubId();
+ plogd("handleCmdUpdateSystemSelectionChannels: SatellitePhone subId: " + subId);
+ if (subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
+ sendUpdateSystemSelectionChannelsResult(
+ SATELLITE_RESULT_INVALID_TELEPHONY_STATE, null);
+ return;
+ }
+
+ String mccmnc = "";
+ final SubscriptionInfo subInfo = SubscriptionManagerService.getInstance()
+ .getSubscriptionInfo(subId);
+ if (subInfo != null) {
+ mccmnc = subInfo.getMccString() + subInfo.getMncString();
+ }
+
+ synchronized (mRegionalSatelliteEarfcnsLock) {
+ /* Key: Regional satellite config ID, Value: SatelliteRegionalConfig
+ * contains satellite config IDs and set of earfcns in the corresponding regions.
+ */
+ Map<Integer, SatelliteRegionalConfig> satelliteRegionalConfigMap =
+ mSatelliteRegionalConfigPerSubMap.get(subId);
+ if (satelliteRegionalConfigMap == null || satelliteRegionalConfigMap.isEmpty()) {
+ plogd("handleCmdUpdateSystemSelectionChannels: config IDs and Earfcns are not"
+ + " found for subId: "
+ + subId);
+ sendUpdateSystemSelectionChannelsResult(
+ SATELLITE_RESULT_INVALID_TELEPHONY_STATE, null);
+ return;
+ }
+
+ SatelliteRegionalConfig satelliteRegionalConfig = satelliteRegionalConfigMap.get(
+ mRegionalConfigId);
+ if (satelliteRegionalConfig == null) {
+ plogd("handleCmdUpdateSystemSelectionChannels: "
+ + "Earfcns for satellite config Id: " + mRegionalConfigId
+ + " not found");
+ sendUpdateSystemSelectionChannelsResult(
+ SATELLITE_RESULT_INVALID_TELEPHONY_STATE, null);
+ return;
+ }
+ IntArray bands = new IntArray();
+ IntArray earfcns = new IntArray();
+ for (Integer value : satelliteRegionalConfig.getEarfcns()) {
+ earfcns.add(value);
+ }
+
+ mSatelliteController.updateSystemSelectionChannels(
+ new SystemSelectionSpecifier(mccmnc, bands, earfcns),
+ mInternalUpdateSystemSelectionChannelsResultReceiver);
+ }
+ }
+ }
+
+ private void sendUpdateSystemSelectionChannelsResult(int resultCode, Bundle resultData) {
+ plogd("sendUpdateSystemSelectionChannelsResult: resultCode=" + resultCode);
+
+ synchronized (mLock) {
+ for (ResultReceiver resultReceiver : mUpdateSystemSelectionChannelsResultReceivers) {
+ resultReceiver.send(resultCode, resultData);
+ }
+ mUpdateSystemSelectionChannelsResultReceivers.clear();
+ }
+ }
+
private static boolean getSatelliteAccessAllowFromOverlayConfig(@NonNull Context context) {
Boolean accessAllowed = null;
try {
@@ -2094,6 +2294,28 @@
return accessAllowed;
}
+
+ @Nullable
+ protected String getSatelliteConfigurationFileNameFromOverlayConfig(
+ @NonNull Context context) {
+ String satelliteAccessControlInfoFile = null;
+
+ if (!mFeatureFlags.carrierRoamingNbIotNtn()) {
+ logd("mFeatureFlags: carrierRoamingNbIotNtn is disabled");
+ return satelliteAccessControlInfoFile;
+ }
+
+ try {
+ satelliteAccessControlInfoFile = context.getResources().getString(
+ com.android.internal.R.string.satellite_access_config_file);
+ } catch (Resources.NotFoundException ex) {
+ loge("getSatelliteConfigurationFileNameFromOverlayConfig: got ex=" + ex);
+ }
+
+ logd("satelliteAccessControlInfoFile =" + satelliteAccessControlInfoFile);
+ return satelliteAccessControlInfoFile;
+ }
+
@Nullable
private static String getSatelliteS2CellFileFromOverlayConfig(@NonNull Context context) {
String s2CellFile = null;
@@ -2323,7 +2545,9 @@
}
synchronized (mLock) {
SatelliteAccessConfiguration satelliteAccessConfig =
- mSatelliteAccessConfigMap.get(mRegionalConfigId);
+ Optional.ofNullable(mSatelliteAccessConfigMap)
+ .map(map -> map.get(mRegionalConfigId))
+ .orElse(null);
callback.onSatelliteAccessConfigurationChanged(satelliteAccessConfig);
logd("registerForCommunicationAllowedStateChanged: satelliteAccessConfig: "
+ satelliteAccessConfig + " of mRegionalConfigId: "
@@ -2362,15 +2586,17 @@
* Returns integer array of disallowed reasons of satellite.
*
* @return Integer array of disallowed reasons of satellite.
- *
*/
- @NonNull public List<Integer> getSatelliteDisallowedReasons() {
+ @NonNull
+ public List<Integer> getSatelliteDisallowedReasons() {
if (!mFeatureFlags.carrierRoamingNbIotNtn()) {
plogd("getSatelliteDisallowedReasons: carrierRoamingNbIotNtn is disabled");
return new ArrayList<>();
}
synchronized (mSatelliteDisallowedReasonsLock) {
+ logd("mSatelliteDisallowedReasons:"
+ + String.join(", ", mSatelliteDisallowedReasons.toString()));
return mSatelliteDisallowedReasons;
}
}
@@ -2379,7 +2605,6 @@
* Registers for disallowed reasons change event from satellite service.
*
* @param callback The callback to handle disallowed reasons changed event.
- *
*/
public void registerForSatelliteDisallowedReasonsChanged(
@NonNull ISatelliteDisallowedReasonsCallback callback) {
@@ -2413,7 +2638,7 @@
*
* @param callback The callback that was passed to
* {@link #registerForSatelliteDisallowedReasonsChanged(
- * ISatelliteDisallowedReasonsCallback)}.
+ *ISatelliteDisallowedReasonsCallback)}.
*/
public void unregisterForSatelliteDisallowedReasonsChanged(
@NonNull ISatelliteDisallowedReasonsCallback callback) {
@@ -2571,7 +2796,7 @@
Rlog.w(TAG, log);
}
- private static void loge(@NonNull String log) {
+ protected static void loge(@NonNull String log) {
Rlog.e(TAG, log);
}
@@ -2618,6 +2843,72 @@
resetRequired);
}
+ private static final class SatelliteRegionalConfig {
+ /** Regional satellite config IDs */
+ private final int mConfigId;
+
+ /** Set of earfcns in the corresponding regions */
+ private final Set<Integer> mEarfcns;
+
+ SatelliteRegionalConfig(int configId, Set<Integer> earfcns) {
+ this.mConfigId = configId;
+ this.mEarfcns = earfcns;
+ }
+
+ public Set<Integer> getEarfcns() {
+ return mEarfcns;
+ }
+ }
+
+ private void updateSatelliteRegionalConfig(int subId) {
+ plogd("updateSatelliteRegionalConfig: subId: " + subId);
+ if (subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
+ return;
+ }
+
+ mSatelliteController.updateRegionalSatelliteEarfcns(subId);
+ //key: regional satellite config Id,
+ //value: set of earfcns in the corresponding regions
+ Map<String, Set<Integer>> earfcnsMap = mSatelliteController
+ .getRegionalSatelliteEarfcns(subId);
+ if (earfcnsMap.isEmpty()) {
+ plogd("updateSatelliteRegionalConfig: Earfcns are not found for subId: "
+ + subId);
+ return;
+ }
+
+ synchronized (mRegionalSatelliteEarfcnsLock) {
+ SatelliteRegionalConfig satelliteRegionalConfig;
+ /* Key: Regional satellite config ID, Value: SatelliteRegionalConfig
+ * contains satellite config IDs and set of earfcns in the corresponding regions.
+ */
+ Map<Integer, SatelliteRegionalConfig> satelliteRegionalConfigMap = new HashMap<>();
+ for (String configId: earfcnsMap.keySet()) {
+ Set<Integer> earfcnsSet = new HashSet<>();
+ for (int earfcn : earfcnsMap.get(configId)) {
+ earfcnsSet.add(earfcn);
+ }
+ satelliteRegionalConfig = new SatelliteRegionalConfig(Integer.valueOf(configId),
+ earfcnsSet);
+ satelliteRegionalConfigMap.put(Integer.valueOf(configId), satelliteRegionalConfig);
+ }
+
+ mSatelliteRegionalConfigPerSubMap.put(subId, satelliteRegionalConfigMap);
+ }
+ }
+
+ private void handleCarrierConfigChanged(@NonNull Context context, int slotIndex,
+ int subId, int carrierId, int specificCarrierId) {
+ if (!mFeatureFlags.carrierRoamingNbIotNtn()) {
+ plogd("handleCarrierConfigChanged: carrierRoamingNbIotNtn flag is disabled");
+ return;
+ }
+ plogd("handleCarrierConfigChanged: slotIndex=" + slotIndex + ", subId=" + subId
+ + ", carrierId=" + carrierId + ", specificCarrierId=" + specificCarrierId);
+ updateSatelliteRegionalConfig(subId);
+ evaluatePossibleChangeInDefaultSmsApp(context);
+ }
+
private void plogv(@NonNull String log) {
Rlog.v(TAG, log);
if (mPersistentLogger != null) {
diff --git a/tests/src/com/android/phone/satellite/accesscontrol/SatelliteAccessConfigurationParserTest.java b/tests/src/com/android/phone/satellite/accesscontrol/SatelliteAccessConfigurationParserTest.java
new file mode 100644
index 0000000..d577a63
--- /dev/null
+++ b/tests/src/com/android/phone/satellite/accesscontrol/SatelliteAccessConfigurationParserTest.java
@@ -0,0 +1,314 @@
+/*
+ * Copyright (C) 2024 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.phone.satellite.accesscontrol;
+
+import static com.android.phone.satellite.accesscontrol.SatelliteAccessConfigurationParser.SATELLITE_ACCESS_CONTROL_CONFIGS;
+import static com.android.phone.satellite.accesscontrol.SatelliteAccessConfigurationParser.SATELLITE_CONFIG_ID;
+import static com.android.phone.satellite.accesscontrol.SatelliteAccessConfigurationParser.SATELLITE_INFOS;
+import static com.android.phone.satellite.accesscontrol.SatelliteAccessConfigurationParser.isRegionalConfigIdValid;
+import static com.android.phone.satellite.accesscontrol.SatelliteAccessConfigurationParser.parseSatelliteBandList;
+import static com.android.phone.satellite.accesscontrol.SatelliteAccessConfigurationParser.parseSatelliteEarfcnRangeList;
+import static com.android.phone.satellite.accesscontrol.SatelliteAccessConfigurationParser.parseSatelliteId;
+import static com.android.phone.satellite.accesscontrol.SatelliteAccessConfigurationParser.parseSatelliteInfoList;
+import static com.android.phone.satellite.accesscontrol.SatelliteAccessConfigurationParser.parseSatellitePosition;
+import static com.android.phone.satellite.accesscontrol.SatelliteAccessConfigurationParser.parseSatelliteTagIdList;
+import static com.android.phone.satellite.accesscontrol.SatelliteAccessConfigurationParser.readJsonStringFromFile;
+
+import static junit.framework.Assert.assertFalse;
+import static junit.framework.Assert.assertNotNull;
+import static junit.framework.Assert.assertTrue;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+
+import android.content.Context;
+import android.telephony.satellite.EarfcnRange;
+import android.telephony.satellite.SatelliteAccessConfiguration;
+import android.telephony.satellite.SatelliteInfo;
+import android.telephony.satellite.SatellitePosition;
+import android.util.Log;
+
+import androidx.annotation.NonNull;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.platform.app.InstrumentationRegistry;
+
+import org.json.JSONArray;
+import org.json.JSONObject;
+import org.junit.After;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.MockitoAnnotations;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.UUID;
+
+/** Unit test for {@link SatelliteAccessConfigurationParser} */
+@RunWith(AndroidJUnit4.class)
+public class SatelliteAccessConfigurationParserTest {
+ private static final String TAG = "SatelliteAccessConfigurationParserTest";
+
+ private static final String TEST_FILE_NAME = "test.json";
+ private static final String TEST_INVALID_FILE_NAME = "nonexistent_file.json";
+
+ private static final String TEST_SATELLITE_UUID1 = "5d0cc4f8-9223-4196-ad7a-803002db7af7";
+ private static final String TEST_SATELLITE_UUID2 = "0d30312e-a73f-444d-b99b-a893dfb42ee9";
+ private static final String TEST_SATELLITE_UUID3 = "01a0b0ca-11bc-4777-87ae-f39afbbec1e9";
+
+ private static final String VALID_JSON_STRING =
+ """
+ {
+ "access_control_configs": [
+ {
+ "config_id": 123,
+ "satellite_infos": [
+ {
+ "satellite_id": "5d0cc4f8-9223-4196-ad7a-803002db7af7",
+ "satellite_position": {
+ "longitude": 45.5,
+ "altitude": 35786000
+ },
+ "bands": [
+ 1234,
+ 5678
+ ],
+ "earfcn_ranges": [
+ {
+ "start_earfcn": 1500,
+ "end_earfcn": 1800
+ }
+ ]
+ },
+ {
+ "satellite_id": "0d30312e-a73f-444d-b99b-a893dfb42ee9",
+ "satellite_position": {
+ "longitude": -120.3,
+ "altitude": 35786000
+ },
+ "bands": [
+ 3456,
+ 7890
+ ],
+ "earfcn_ranges": [
+ {
+ "start_earfcn": 2000,
+ "end_earfcn": 2300
+ }
+ ]
+ }
+ ],
+ "tag_ids": [
+ 7,
+ 10
+ ]
+ },
+ {
+ "config_id": 890,
+ "satellite_infos": [
+ {
+ "satellite_id": "01a0b0ca-11bc-4777-87ae-f39afbbec1e9",
+ "satellite_position": {
+ "longitude": -120,
+ "altitude": 1234567
+ },
+ "bands": [
+ 13579,
+ 24680
+ ],
+ "earfcn_ranges": [
+ {
+ "start_earfcn": 6420,
+ "end_earfcn": 15255
+ }
+ ]
+ }
+ ],
+ "tag_ids": [
+ 6420,
+ 15255
+ ]
+ }
+ ]
+ }
+ """;
+
+
+ // Mandatory : config_id ( >= 0)
+ // SatelliteInfoList : NonNull
+ // UUID (0-9, a-f and hyphen : '_' and 'z' are invalid)
+ // longitude (-180 ~ 180)
+ // altitude ( >= 0)
+ private static final String INVALID_JSON_STRING =
+ """
+ {
+ "access_control_configs": [
+ {
+ "config_id": -100,
+ "satellite_infos": [
+ {
+ "satellite_id": "01z0b0ca-11bc-4777_87ae-f39afbbec1e9",
+ "satellite_position": {
+ "longitude": -181,
+ "altitude": -1
+ },
+ "earfcn_ranges": [
+ {
+ "start_earfcn": -1,
+ "end_earfcn": 65536
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ }
+ """;
+
+ @Before
+ public void setUp() throws Exception {
+ Log.d(TAG, "setUp");
+ MockitoAnnotations.initMocks(this);
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ Log.d(TAG, "tearDown");
+ }
+
+ @AfterClass
+ public static void afterClass() throws Exception {
+ }
+
+ @BeforeClass
+ public static void beforeClass() throws Exception {
+ }
+
+ private static File createTestJsonFile(@NonNull String content) throws Exception {
+ Log.d(TAG, "createTestJsonFile");
+ Context context = InstrumentationRegistry.getInstrumentation().getTargetContext();
+ File testFile = new File(context.getCacheDir(), TEST_FILE_NAME);
+ try (FileOutputStream fos = new FileOutputStream(testFile)) {
+ fos.write(content.getBytes(StandardCharsets.UTF_8));
+ }
+ return testFile;
+ }
+
+ @Test
+ public void testLoadJsonFile() throws Exception {
+ Log.d(TAG, "testLoadJsonFile");
+ assertNull(readJsonStringFromFile(TEST_INVALID_FILE_NAME));
+ assertNull(readJsonStringFromFile(null));
+
+ File file = createTestJsonFile(VALID_JSON_STRING);
+ assertEquals(VALID_JSON_STRING, readJsonStringFromFile(file.getPath()));
+
+ assertTrue(file.delete());
+ }
+
+
+ private SatelliteInfo getSatelliteInfo(UUID id, SatellitePosition position,
+ List<Integer> bandList, List<EarfcnRange> rangeList) {
+ return new SatelliteInfo(id, position, bandList, rangeList);
+ }
+
+ private Map<Integer, SatelliteAccessConfiguration> getExpectedMap() {
+ List<SatelliteInfo> satelliteInfoList1 = new ArrayList<>();
+ satelliteInfoList1.add(
+ getSatelliteInfo(UUID.fromString(TEST_SATELLITE_UUID1),
+ new SatellitePosition(45.5, 35786000),
+ List.of(1234, 5678),
+ new ArrayList<>(List.of(new EarfcnRange(1500, 1800)))
+ ));
+ satelliteInfoList1.add(
+ getSatelliteInfo(UUID.fromString(TEST_SATELLITE_UUID2),
+ new SatellitePosition(-120.3, 35786000),
+ List.of(3456, 7890),
+ new ArrayList<>(List.of(new EarfcnRange(2000, 2300)))
+ ));
+
+ List<Integer> tagIdList1 = List.of(7, 10);
+ SatelliteAccessConfiguration satelliteAccessConfiguration1 =
+ new SatelliteAccessConfiguration(satelliteInfoList1, tagIdList1);
+
+ HashMap<Integer, SatelliteAccessConfiguration> expectedResult = new HashMap<>();
+ expectedResult.put(123, satelliteAccessConfiguration1);
+
+ List<SatelliteInfo> satelliteInfoList2 = new ArrayList<>();
+ List<Integer> tagIdList2 = List.of(6420, 15255);
+ satelliteInfoList2.add(
+ getSatelliteInfo(UUID.fromString(TEST_SATELLITE_UUID3),
+ new SatellitePosition(-120, 1234567),
+ List.of(13579, 24680),
+ new ArrayList<>(List.of(new EarfcnRange(6420, 15255)))
+ ));
+ SatelliteAccessConfiguration satelliteAccessConfiguration2 =
+ new SatelliteAccessConfiguration(satelliteInfoList2, tagIdList2);
+ expectedResult.put(890, satelliteAccessConfiguration2);
+ return expectedResult;
+ }
+
+
+ @Test
+ public void testParsingValidSatelliteAccessConfiguration() throws Exception {
+ Log.d(TAG, "testParsingValidSatelliteAccessConfiguration");
+ File file = createTestJsonFile(VALID_JSON_STRING);
+ assertEquals(getExpectedMap(),
+ SatelliteAccessConfigurationParser.parse(file.getCanonicalPath()));
+ }
+
+ @Test
+ public void testParsingInvalidSatelliteAccessConfiguration() throws Exception {
+ Log.d(TAG, "testParsingInvalidSatelliteAccessConfiguration");
+ File file = createTestJsonFile(INVALID_JSON_STRING);
+ String jsonString = readJsonStringFromFile(file.getCanonicalPath());
+ JSONObject satelliteAccessConfigJsonObject = new JSONObject(jsonString);
+ JSONArray configurationArrayJson = satelliteAccessConfigJsonObject.optJSONArray(
+ SATELLITE_ACCESS_CONTROL_CONFIGS);
+
+ for (int i = 0; i < configurationArrayJson.length(); i++) {
+ JSONObject configJson = configurationArrayJson.getJSONObject(i);
+
+ int configId = configJson.optInt(SATELLITE_CONFIG_ID, -1);
+ assertFalse(isRegionalConfigIdValid(configId));
+
+ JSONArray satelliteInfoArray = configJson.getJSONArray(SATELLITE_INFOS);
+ List<SatelliteInfo> satelliteInfoList = parseSatelliteInfoList(satelliteInfoArray);
+ assertNotNull(satelliteInfoList);
+ assertTrue(satelliteInfoList.isEmpty());
+
+ for (int j = 0; j < satelliteInfoArray.length(); j++) {
+ JSONObject infoJson = satelliteInfoArray.getJSONObject(i);
+ assertNull(parseSatelliteId(infoJson));
+ assertNull(parseSatellitePosition(infoJson));
+ assertTrue(parseSatelliteEarfcnRangeList(infoJson).isEmpty());
+ assertNotNull(parseSatelliteBandList(infoJson));
+ assertEquals(0, parseSatelliteBandList(infoJson).size());
+ }
+
+ List<Integer> tagIdList = parseSatelliteTagIdList(configJson);
+ assertNotNull(tagIdList);
+ }
+ }
+}
diff --git a/tests/src/com/android/phone/satellite/accesscontrol/SatelliteAccessControllerTest.java b/tests/src/com/android/phone/satellite/accesscontrol/SatelliteAccessControllerTest.java
index b388954..c8013d6 100644
--- a/tests/src/com/android/phone/satellite/accesscontrol/SatelliteAccessControllerTest.java
+++ b/tests/src/com/android/phone/satellite/accesscontrol/SatelliteAccessControllerTest.java
@@ -27,6 +27,7 @@
import static android.telephony.satellite.SatelliteManager.SATELLITE_RESULT_LOCATION_NOT_AVAILABLE;
import static android.telephony.satellite.SatelliteManager.SATELLITE_RESULT_MODEM_ERROR;
import static android.telephony.satellite.SatelliteManager.SATELLITE_RESULT_NOT_SUPPORTED;
+import static android.telephony.satellite.SatelliteManager.SATELLITE_RESULT_NO_RESOURCES;
import static android.telephony.satellite.SatelliteManager.SATELLITE_RESULT_REQUEST_NOT_SUPPORTED;
import static android.telephony.satellite.SatelliteManager.SATELLITE_RESULT_SUCCESS;
@@ -619,10 +620,9 @@
verify(mockResultReceiver, times(1)).send(resultCodeCaptor.capture(),
bundleCaptor.capture());
- assertEquals(SATELLITE_RESULT_SUCCESS, (int) resultCodeCaptor.getValue());
- assertTrue(bundleCaptor.getValue().containsKey(KEY_SATELLITE_ACCESS_CONFIGURATION));
- assertNull(bundleCaptor.getValue().getParcelable(KEY_SATELLITE_ACCESS_CONFIGURATION,
- SatelliteAccessConfiguration.class));
+ assertEquals(SATELLITE_RESULT_NO_RESOURCES, (int) resultCodeCaptor.getValue());
+ assertNull(bundleCaptor.getValue());
+
verify(mockSatelliteAllowedStateCallback, times(1))
.onSatelliteAccessConfigurationChanged(
satelliteAccessConfigurationCaptor.capture());
@@ -1410,6 +1410,33 @@
}
@Test
+ public void testLoadSatelliteAccessConfigurationFromDeviceConfig() {
+ when(mMockFeatureFlags.oemEnabledSatelliteFlag()).thenReturn(false);
+ assertNull(mSatelliteAccessControllerUT
+ .getSatelliteConfigurationFileNameFromOverlayConfig(mMockContext));
+
+ when(mMockFeatureFlags.oemEnabledSatelliteFlag()).thenReturn(true);
+ when(mMockContext.getResources()).thenReturn(mMockResources);
+ when(mMockResources
+ .getString(eq(com.android.internal.R.string.satellite_access_config_file)))
+ .thenReturn("test_satellite_file.json");
+ assertEquals("test_satellite_file.json", mSatelliteAccessControllerUT
+ .getSatelliteConfigurationFileNameFromOverlayConfig(mMockContext));
+
+ when(mMockResources
+ .getString(eq(com.android.internal.R.string.satellite_access_config_file)))
+ .thenReturn(null);
+ assertNull(mSatelliteAccessControllerUT
+ .getSatelliteConfigurationFileNameFromOverlayConfig(mMockContext));
+ try {
+ mSatelliteAccessControllerUT.loadSatelliteAccessConfigurationFromDeviceConfig();
+ } catch (Exception e) {
+ fail("Unexpected exception thrown: " + e.getMessage());
+ }
+ }
+
+
+ @Test
public void testUpdateSatelliteConfigData() throws Exception {
verify(mMockSatelliteController).registerForConfigUpdateChanged(
mConfigUpdateHandlerCaptor.capture(), mConfigUpdateIntCaptor.capture(),