summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--proto/src/telephony_config_update.proto46
-rw-r--r--src/java/com/android/internal/telephony/configupdate/ConfigParser.java100
-rw-r--r--src/java/com/android/internal/telephony/configupdate/ConfigProviderAdaptor.java54
-rw-r--r--src/java/com/android/internal/telephony/configupdate/TelephonyConfigUpdateInstallReceiver.java200
-rw-r--r--src/java/com/android/internal/telephony/satellite/SatelliteConfig.java233
-rw-r--r--src/java/com/android/internal/telephony/satellite/SatelliteConfigParser.java94
-rw-r--r--src/java/com/android/internal/telephony/satellite/SatelliteController.java122
-rw-r--r--tests/telephonytests/src/com/android/internal/telephony/configupdate/TelephonyConfigUpdateInstallReceiverTest.java175
-rw-r--r--tests/telephonytests/src/com/android/internal/telephony/satellite/SatelliteConfigParserTest.java227
-rw-r--r--tests/telephonytests/src/com/android/internal/telephony/satellite/SatelliteControllerTest.java227
10 files changed, 1408 insertions, 70 deletions
diff --git a/proto/src/telephony_config_update.proto b/proto/src/telephony_config_update.proto
new file mode 100644
index 0000000000..c193f3527a
--- /dev/null
+++ b/proto/src/telephony_config_update.proto
@@ -0,0 +1,46 @@
+
+// Copyright 2024 Google LLC
+//
+// 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.
+
+syntax = "proto2";
+package com.android.internal.telephony.satellite;
+
+option java_package = "com.android.internal.telephony.satellite";
+option java_outer_classname = "SatelliteConfigData";
+
+message TelephonyConfigProto {
+ optional SatelliteConfigProto satellite = 1;
+}
+
+message SatelliteConfigProto {
+ optional int32 version = 1;
+ repeated CarrierSupportedSatelliteServicesProto carrier_supported_satellite_services = 2;
+ optional SatelliteRegionProto device_satellite_region = 3;
+}
+
+message CarrierSupportedSatelliteServicesProto {
+ optional int32 carrier_id = 1;
+ repeated SatelliteProviderCapabilityProto supported_satellite_provider_capabilities = 2;
+}
+
+message SatelliteProviderCapabilityProto{
+ optional string carrier_plmn = 1;
+ repeated int32 allowed_services = 2;
+}
+
+message SatelliteRegionProto {
+ optional bytes s2_cell_file = 1;
+ repeated string country_codes = 2;
+ optional bool is_allowed = 3;
+} \ No newline at end of file
diff --git a/src/java/com/android/internal/telephony/configupdate/ConfigParser.java b/src/java/com/android/internal/telephony/configupdate/ConfigParser.java
new file mode 100644
index 0000000000..5c3ac866df
--- /dev/null
+++ b/src/java/com/android/internal/telephony/configupdate/ConfigParser.java
@@ -0,0 +1,100 @@
+/*
+ * 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.internal.telephony.configupdate;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+public abstract class ConfigParser<T> {
+
+ public static final int VERSION_UNKNOWN = -1;
+
+ protected int mVersion = VERSION_UNKNOWN;
+
+ protected T mConfig;
+
+ /**
+ * Constructs a parser from the raw data
+ *
+ * @param data the config data
+ */
+ public ConfigParser(@Nullable byte[] data) {
+ parseData(data);
+ }
+
+ /**
+ * Constructs a parser from the input stream
+ *
+ * @param input the input stream of the config
+ * @return the instance of the ConfigParser
+ */
+ public ConfigParser(@NonNull InputStream input) throws IOException {
+ parseData(input.readAllBytes());
+ }
+
+ /**
+ * Constructs a parser from the input stream
+ *
+ * @param file the input file of the config
+ * @return the instance of the ConfigParser
+ */
+ public ConfigParser(@NonNull File file) throws IOException {
+ try (FileInputStream fis = new FileInputStream(file)) {
+ parseData(fis.readAllBytes());
+ }
+ }
+
+ /**
+ * Get the version of the config
+ *
+ * @return the version of the config if it is defined, or VERSION_UNKNOWN
+ */
+ public int getVersion() {
+ return mVersion;
+ }
+
+ /**
+ * Get the config
+ *
+ * @return the config
+ */
+ public @Nullable T getConfig() {
+ return mConfig;
+ }
+
+ /**
+ * Get the sub config raw data by id
+ *
+ * @param id the identifier of the sub config
+ * @return the raw data of the sub config
+ */
+ public @Nullable byte[] getData(String id) {
+ return null;
+ }
+
+ /**
+ * Parse the config data
+ *
+ * @param data the config data
+ */
+ protected abstract void parseData(@Nullable byte[] data);
+}
diff --git a/src/java/com/android/internal/telephony/configupdate/ConfigProviderAdaptor.java b/src/java/com/android/internal/telephony/configupdate/ConfigProviderAdaptor.java
new file mode 100644
index 0000000000..1344534daf
--- /dev/null
+++ b/src/java/com/android/internal/telephony/configupdate/ConfigProviderAdaptor.java
@@ -0,0 +1,54 @@
+/*
+ * 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.internal.telephony.configupdate;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+
+import java.util.concurrent.Executor;
+
+public interface ConfigProviderAdaptor {
+
+ String DOMAIN_SATELLITE = "satellite";
+
+ /**
+ * Get the config from the provider
+ */
+ @Nullable ConfigParser getConfigParser(String domain);
+
+ class Callback {
+ /**
+ * The callback when the config is changed
+ * @param config the config is changed
+ */
+ public void onChanged(@Nullable ConfigParser config) {}
+ }
+
+ /**
+ * Register the callback to monitor the config change
+ * @param executor The executor to execute the callback.
+ * @param callback the callback to monitor the config change
+ */
+ void registerCallback(@NonNull Executor executor, @NonNull Callback callback);
+
+ /**
+ * Unregister the callback
+ * @param callback the callback to be unregistered
+ */
+ void unregisterCallback(@NonNull Callback callback);
+}
diff --git a/src/java/com/android/internal/telephony/configupdate/TelephonyConfigUpdateInstallReceiver.java b/src/java/com/android/internal/telephony/configupdate/TelephonyConfigUpdateInstallReceiver.java
new file mode 100644
index 0000000000..0db7844c8d
--- /dev/null
+++ b/src/java/com/android/internal/telephony/configupdate/TelephonyConfigUpdateInstallReceiver.java
@@ -0,0 +1,200 @@
+/*
+ * 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.internal.telephony.configupdate;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.Context;
+import android.content.Intent;
+import android.util.Log;
+import android.util.Slog;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.telephony.satellite.SatelliteConfigParser;
+import com.android.server.updates.ConfigUpdateInstallReceiver;
+
+import libcore.io.IoUtils;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.Iterator;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.Executor;
+
+public class TelephonyConfigUpdateInstallReceiver extends ConfigUpdateInstallReceiver implements
+ ConfigProviderAdaptor {
+
+ private static final String TAG = "TelephonyConfigUpdateInstallReceiver";
+ @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
+ protected static final String UPDATE_DIR = "/data/misc/telephonyconfig";
+ @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
+ protected static final String UPDATE_CONTENT_PATH = "telephony_config.pb";
+ protected static final String UPDATE_METADATA_PATH = "metadata/";
+ public static final String VERSION = "version";
+
+ private ConcurrentHashMap<Executor, Callback> mCallbackHashMap = new ConcurrentHashMap<>();
+ @NonNull
+ private final Object mConfigParserLock = new Object();
+ @GuardedBy("mConfigParserLock")
+ private ConfigParser mConfigParser;
+
+
+ public static TelephonyConfigUpdateInstallReceiver sReceiverAdaptorInstance =
+ new TelephonyConfigUpdateInstallReceiver();
+
+ /**
+ * @return The singleton instance of TelephonyConfigUpdateInstallReceiver
+ */
+ @NonNull
+ public static TelephonyConfigUpdateInstallReceiver getInstance() {
+ return sReceiverAdaptorInstance;
+ }
+
+ public TelephonyConfigUpdateInstallReceiver() {
+ super(UPDATE_DIR, UPDATE_CONTENT_PATH, UPDATE_METADATA_PATH, VERSION);
+ }
+
+ /**
+ * @return byte array type of config data protobuffer file
+ */
+ @Nullable
+ @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
+ public byte[] getCurrentContent() {
+ try {
+ return IoUtils.readFileAsByteArray(updateContent.getCanonicalPath());
+ } catch (IOException e) {
+ Slog.i(TAG, "Failed to read current content, assuming first update!");
+ return null;
+ }
+ }
+
+ @Override
+ @VisibleForTesting(visibility = VisibleForTesting.Visibility.PROTECTED)
+ public void postInstall(Context context, Intent intent) {
+ Log.d(TAG, "Telephony config is updated in file partition");
+ ConfigParser updatedConfigParser = getNewConfigParser(DOMAIN_SATELLITE,
+ getCurrentContent());
+
+ if (updatedConfigParser == null) {
+ Log.d(TAG, "updatedConfigParser is null");
+ return;
+ }
+
+ boolean isParserChanged = false;
+
+ synchronized (getInstance().mConfigParserLock) {
+ if (getInstance().mConfigParser == null) {
+ getInstance().mConfigParser = updatedConfigParser;
+ isParserChanged = true;
+ } else {
+ int updatedVersion = updatedConfigParser.mVersion;
+ int previousVersion = getInstance().mConfigParser.mVersion;
+ Log.d(TAG, "previous version is " + previousVersion + " | updated version is "
+ + updatedVersion);
+ if (updatedVersion > previousVersion) {
+ getInstance().mConfigParser = updatedConfigParser;
+ isParserChanged = true;
+ }
+ }
+ }
+
+ if (isParserChanged) {
+ if (getInstance().mCallbackHashMap.keySet().isEmpty()) {
+ Log.d(TAG, "mCallbackHashMap.keySet().isEmpty");
+ return;
+ }
+ Iterator<Executor> iterator =
+ getInstance().mCallbackHashMap.keySet().iterator();
+ while (iterator.hasNext()) {
+ Executor executor = iterator.next();
+ getInstance().mCallbackHashMap.get(executor).onChanged(
+ updatedConfigParser);
+ }
+ }
+ }
+
+ @Nullable
+ @Override
+ public ConfigParser getConfigParser(String domain) {
+ Log.d(TAG, "getConfigParser");
+ synchronized (getInstance().mConfigParserLock) {
+ if (getInstance().mConfigParser == null) {
+ Log.d(TAG, "CreateNewConfigParser with domain " + domain);
+ getInstance().mConfigParser = getNewConfigParser(domain, getCurrentContent());
+ }
+ return getInstance().mConfigParser;
+ }
+ }
+
+ @Override
+ public void registerCallback(@NonNull Executor executor, @NonNull Callback callback) {
+ mCallbackHashMap.put(executor, callback);
+ }
+
+ @Override
+ public void unregisterCallback(@NonNull Callback callback) {
+ Iterator<Executor> iterator = mCallbackHashMap.keySet().iterator();
+ while (iterator.hasNext()) {
+ Executor executor = iterator.next();
+ if (mCallbackHashMap.get(executor) == callback) {
+ mCallbackHashMap.remove(executor);
+ break;
+ }
+ }
+ }
+
+ @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
+ public File getUpdateDir() {
+ return getInstance().updateDir;
+ }
+
+ @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
+ public File getUpdateContent() {
+ return getInstance().updateContent;
+ }
+
+ @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
+ public ConcurrentHashMap<Executor, Callback> getCallbackMap() {
+ return getInstance().mCallbackHashMap;
+ }
+
+ @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
+ public void setCallbackMap(ConcurrentHashMap<Executor, Callback> map) {
+ getInstance().mCallbackHashMap = map;
+ }
+
+ /**
+ * @param data byte array type of config data
+ * @return when data is null, return null otherwise return ConfigParser
+ */
+ @Nullable
+ @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
+ public ConfigParser getNewConfigParser(String domain, @Nullable byte[] data) {
+ if (data == null) {
+ Log.d(TAG, "content data is null");
+ return null;
+ }
+ switch (domain) {
+ case DOMAIN_SATELLITE:
+ return new SatelliteConfigParser(data);
+ default:
+ Log.e(TAG, "DOMAIN should be specified");
+ return null;
+ }
+ }
+}
diff --git a/src/java/com/android/internal/telephony/satellite/SatelliteConfig.java b/src/java/com/android/internal/telephony/satellite/SatelliteConfig.java
new file mode 100644
index 0000000000..8d7e723184
--- /dev/null
+++ b/src/java/com/android/internal/telephony/satellite/SatelliteConfig.java
@@ -0,0 +1,233 @@
+/*
+ * 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.internal.telephony.satellite;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.Context;
+import android.util.Log;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.telephony.satellite.nano.SatelliteConfigData;
+
+import java.io.ByteArrayInputStream;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.StandardCopyOption;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * SatelliteConfig is utility class for satellite.
+ * It is obtained through the getConfig() at the SatelliteConfigParser.
+ */
+public class SatelliteConfig {
+
+ private static final String TAG = "SatelliteConfig";
+ private static final String SATELLITE_DIR_NAME = "satellite";
+ private static final String S2_CELL_FILE_NAME = "s2_cell_file";
+ private int mVersion;
+ private Map<Integer, Map<String, Set<Integer>>> mSupportedServicesPerCarrier;
+ private List<String> mSatelliteRegionCountryCodes;
+ private Boolean mIsSatelliteRegionAllowed;
+ private Path mSatS2FilePath;
+ private SatelliteConfigData.SatelliteConfigProto mConfigData;
+
+ public SatelliteConfig(SatelliteConfigData.SatelliteConfigProto configData) {
+ mConfigData = configData;
+ mVersion = mConfigData.version;
+ mSupportedServicesPerCarrier = getCarrierSupportedSatelliteServices();
+ mSatelliteRegionCountryCodes = List.of(
+ mConfigData.deviceSatelliteRegion.countryCodes);
+ mIsSatelliteRegionAllowed = mConfigData.deviceSatelliteRegion.isAllowed;
+ mSatS2FilePath = null;
+
+ Log.d(TAG, "mVersion:" + mVersion + " | "
+ + "mSupportedServicesPerCarrier:" + mSupportedServicesPerCarrier + " | "
+ + "mSatelliteRegionCountryCodes:" + mSatelliteRegionCountryCodes + " | "
+ + "mIsSatelliteRegionAllowed:" + mIsSatelliteRegionAllowed + " | "
+ + "s2CellFile size:" + mConfigData.deviceSatelliteRegion.s2CellFile.length);
+ }
+
+ /**
+ * @return a Map data with carrier_id, plmns and allowed_services.
+ */
+ private Map<Integer, Map<String, Set<Integer>>> getCarrierSupportedSatelliteServices() {
+ SatelliteConfigData.CarrierSupportedSatelliteServicesProto[] satelliteServices =
+ mConfigData.carrierSupportedSatelliteServices;
+ Map<Integer, Map<String, Set<Integer>>> carrierToServicesMap = new HashMap<>();
+ for (SatelliteConfigData.CarrierSupportedSatelliteServicesProto carrierProto :
+ satelliteServices) {
+ SatelliteConfigData.SatelliteProviderCapabilityProto[] satelliteCapabilities =
+ carrierProto.supportedSatelliteProviderCapabilities;
+ Map<String, Set<Integer>> satelliteCapabilityMap = new HashMap<>();
+ for (SatelliteConfigData.SatelliteProviderCapabilityProto capabilityProto :
+ satelliteCapabilities) {
+ String carrierPlmn = capabilityProto.carrierPlmn;
+ Set<Integer> allowedServices = new HashSet<>();
+ for (int service : capabilityProto.allowedServices) {
+ allowedServices.add(service);
+ }
+ satelliteCapabilityMap.put(carrierPlmn, allowedServices);
+ }
+ carrierToServicesMap.put(carrierProto.carrierId, satelliteCapabilityMap);
+ }
+ return carrierToServicesMap;
+ }
+
+ /**
+ * Get satellite plmns for carrier
+ *
+ * @param carrierId the carrier identifier.
+ * @return Plmns corresponding to carrier identifier.
+ */
+ @NonNull
+ public List<String> getAllSatellitePlmnsForCarrier(int carrierId) {
+ if (mSupportedServicesPerCarrier != null) {
+ Map<String, Set<Integer>> satelliteCapabilitiesMap = mSupportedServicesPerCarrier.get(
+ carrierId);
+ if (satelliteCapabilitiesMap != null) {
+ return new ArrayList<>(satelliteCapabilitiesMap.keySet());
+ }
+ }
+ Log.d(TAG, "getAllSatellitePlmnsForCarrier : mConfigData is null or no config data");
+ return new ArrayList<>();
+ }
+
+ /**
+ * Get supported satellite services of all providers for a carrier.
+ * The format of the return value - Key: PLMN, Value: Set of supported satellite services.
+ *
+ * @param carrierId the carrier identifier.
+ * @return all supported satellite services for a carrier
+ */
+ @NonNull
+ public Map<String, Set<Integer>> getSupportedSatelliteServices(int carrierId) {
+ if (mSupportedServicesPerCarrier != null) {
+ Map<String, Set<Integer>> satelliteCapaMap =
+ mSupportedServicesPerCarrier.get(carrierId);
+ if (satelliteCapaMap != null) {
+ return satelliteCapaMap;
+ } else {
+ Log.d(TAG, "No supported services found for carrier=" + carrierId);
+ }
+ } else {
+ Log.d(TAG, "mSupportedServicesPerCarrier is null");
+ }
+ return new HashMap<>();
+ }
+
+ /**
+ * @return satellite region country codes
+ */
+ @NonNull
+ public List<String> getDeviceSatelliteCountryCodes() {
+ if (mSatelliteRegionCountryCodes != null) {
+ return mSatelliteRegionCountryCodes;
+ }
+ Log.d(TAG, "getDeviceSatelliteCountryCodes : mConfigData is null or no config data");
+ return new ArrayList<>();
+ }
+
+ /**
+ * @return satellite access allow value, if there is no config data then it returns null.
+ */
+ @Nullable
+ public Boolean isSatelliteDataForAllowedRegion() {
+ if (mIsSatelliteRegionAllowed == null) {
+ Log.d(TAG, "getIsSatelliteRegionAllowed : mConfigData is null or no config data");
+ }
+ return mIsSatelliteRegionAllowed;
+ }
+
+
+ /**
+ * @param context the Context
+ * @return satellite s2_cell_file path
+ */
+ @Nullable
+ public Path getSatelliteS2CellFile(@Nullable Context context) {
+ if (context == null) {
+ Log.d(TAG, "getSatelliteS2CellFile : context is null");
+ return null;
+ }
+
+ if (isFileExist(mSatS2FilePath)) {
+ Log.d(TAG, "File mSatS2FilePath is already exist");
+ return mSatS2FilePath;
+ }
+
+ if (mConfigData != null && mConfigData.deviceSatelliteRegion != null) {
+ mSatS2FilePath = copySatS2FileToPhoneDirectory(context,
+ mConfigData.deviceSatelliteRegion.s2CellFile);
+ return mSatS2FilePath;
+ }
+ Log.d(TAG, "getSatelliteS2CellFile :"
+ + "mConfigData is null or mConfigData.deviceSatelliteRegion is null");
+ return null;
+ }
+
+ /**
+ * @param context the Context
+ * @param byteArrayFile byte array type of protobuffer config data
+ * @return the satellite_cell_file path
+ */
+ @Nullable
+ @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
+ public Path copySatS2FileToPhoneDirectory(@Nullable Context context,
+ @Nullable byte[] byteArrayFile) {
+
+ if (context == null || byteArrayFile == null) {
+ Log.d(TAG, "copySatS2FileToPhoneDirectory : context or byteArrayFile are null");
+ return null;
+ }
+
+ File satS2FileDir = context.getDir(SATELLITE_DIR_NAME, Context.MODE_PRIVATE);
+ if (!satS2FileDir.exists()) {
+ satS2FileDir.mkdirs();
+ }
+
+ Path targetSatS2FilePath = satS2FileDir.toPath().resolve(S2_CELL_FILE_NAME);
+ try {
+ InputStream inputStream = new ByteArrayInputStream(byteArrayFile);
+ if (inputStream == null) {
+ Log.d(TAG, "copySatS2FileToPhoneDirectory: Resource=" + S2_CELL_FILE_NAME
+ + " not found");
+ } else {
+ Files.copy(inputStream, targetSatS2FilePath, StandardCopyOption.REPLACE_EXISTING);
+ }
+ } catch (IOException ex) {
+ Log.e(TAG, "copySatS2FileToPhoneDirectory: ex=" + ex);
+ }
+ return targetSatS2FilePath;
+ }
+
+ /**
+ * @return {@code true} if the SatS2File is already existed and {@code false} otherwise.
+ */
+ @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
+ public boolean isFileExist(Path filePath) {
+ return Files.exists(filePath);
+ }
+}
diff --git a/src/java/com/android/internal/telephony/satellite/SatelliteConfigParser.java b/src/java/com/android/internal/telephony/satellite/SatelliteConfigParser.java
new file mode 100644
index 0000000000..4ff1880ba5
--- /dev/null
+++ b/src/java/com/android/internal/telephony/satellite/SatelliteConfigParser.java
@@ -0,0 +1,94 @@
+/*
+ * 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.internal.telephony.satellite;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.util.Log;
+
+import com.android.internal.telephony.configupdate.ConfigParser;
+import com.android.internal.telephony.satellite.nano.SatelliteConfigData;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+
+
+/**
+ * SatelliteConfigParser parses the config data and create SatelliteConfig.
+ * The config data is located at "/data/misc/telephonyconfig/telephony_config.pb".
+ * It is obtained through the getConfigParser() at the TelephonyConfigUpdateInstallReceiver.
+ */
+public class SatelliteConfigParser extends ConfigParser<SatelliteConfig> {
+ private static final String TAG = "SatelliteConfigParser";
+
+ /**
+ * Create an instance of SatelliteConfigParser with byte array data.
+ *
+ * @param data the config data formatted as byte array.
+ */
+ public SatelliteConfigParser(@Nullable byte[] data) {
+ super(data);
+ }
+
+ /**
+ * Create an instance of SatelliteConfigParser with InputStream data.
+ *
+ * @param input the config data formatted as InputStream.
+ */
+ public SatelliteConfigParser(@NonNull InputStream input)
+ throws IOException {
+ super(input);
+ }
+
+ /**
+ * Create an instance of SatelliteConfigParser with File data.
+ *
+ * @param file the config data formatted as File.
+ */
+ public SatelliteConfigParser(@NonNull File file) throws IOException {
+ super(file);
+ }
+
+ @Override
+ protected void parseData(@Nullable byte[] data) {
+ boolean parseError = false;
+ try {
+ if (data == null) {
+ Log.d(TAG, "config data is null");
+ return;
+ }
+ SatelliteConfigData.TelephonyConfigProto telephonyConfigData =
+ SatelliteConfigData.TelephonyConfigProto.parseFrom(data);
+ if (telephonyConfigData == null || telephonyConfigData.satellite == null) {
+ Log.e(TAG, "telephonyConfigData or telephonyConfigData.satellite is null");
+ return;
+ }
+ mVersion = telephonyConfigData.satellite.version;
+ mConfig = new SatelliteConfig(telephonyConfigData.satellite);
+ Log.d(TAG, "SatelliteConfig is created");
+ } catch (Exception e) {
+ parseError = true;
+ Log.e(TAG, "Parse Error : " + e.getMessage());
+ } finally {
+ if (parseError) {
+ mVersion = VERSION_UNKNOWN;
+ mConfig = null;
+ }
+ }
+ }
+}
diff --git a/src/java/com/android/internal/telephony/satellite/SatelliteController.java b/src/java/com/android/internal/telephony/satellite/SatelliteController.java
index 0d3973d127..55db6d21b5 100644
--- a/src/java/com/android/internal/telephony/satellite/SatelliteController.java
+++ b/src/java/com/android/internal/telephony/satellite/SatelliteController.java
@@ -34,6 +34,8 @@ import static android.telephony.satellite.SatelliteManager.SATELLITE_RESULT_MODE
import static android.telephony.satellite.SatelliteManager.SATELLITE_RESULT_REQUEST_NOT_SUPPORTED;
import static android.telephony.satellite.SatelliteManager.SATELLITE_RESULT_SUCCESS;
+import static com.android.internal.telephony.configupdate.ConfigProviderAdaptor.DOMAIN_SATELLITE;
+
import android.annotation.ArrayRes;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -66,6 +68,8 @@ import android.os.ICancellationSignal;
import android.os.Looper;
import android.os.Message;
import android.os.PersistableBundle;
+import android.os.Registrant;
+import android.os.RegistrantList;
import android.os.RemoteException;
import android.os.ResultReceiver;
import android.os.ServiceSpecificException;
@@ -101,6 +105,9 @@ import com.android.internal.telephony.DeviceStateMonitor;
import com.android.internal.telephony.IIntegerConsumer;
import com.android.internal.telephony.Phone;
import com.android.internal.telephony.PhoneFactory;
+import com.android.internal.telephony.configupdate.ConfigParser;
+import com.android.internal.telephony.configupdate.ConfigProviderAdaptor;
+import com.android.internal.telephony.configupdate.TelephonyConfigUpdateInstallReceiver;
import com.android.internal.telephony.flags.FeatureFlags;
import com.android.internal.telephony.satellite.metrics.ControllerMetricsStats;
import com.android.internal.telephony.satellite.metrics.ProvisionMetricsStats;
@@ -118,6 +125,7 @@ import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicLong;
import java.util.function.Consumer;
@@ -187,6 +195,7 @@ public class SatelliteController extends Handler {
private static final int EVENT_SERVICE_STATE_CHANGED = 37;
private static final int EVENT_SATELLITE_CAPABILITIES_CHANGED = 38;
private static final int EVENT_WAIT_FOR_SATELLITE_ENABLING_RESPONSE_TIMED_OUT = 39;
+ private static final int EVENT_SATELLITE_CONFIG_DATA_UPDATED = 40;
@NonNull private static SatelliteController sInstance;
@NonNull private final Context mContext;
@@ -298,6 +307,7 @@ public class SatelliteController extends Handler {
@NonNull private final CarrierConfigManager mCarrierConfigManager;
@NonNull private final CarrierConfigManager.CarrierConfigChangeListener
mCarrierConfigChangeListener;
+ @NonNull private final ConfigProviderAdaptor.Callback mConfigDataUpdatedCallback;
@NonNull private final Object mCarrierConfigArrayLock = new Object();
@GuardedBy("mCarrierConfigArrayLock")
@NonNull private final SparseArray<PersistableBundle> mCarrierConfigArray = new SparseArray<>();
@@ -365,6 +375,8 @@ public class SatelliteController extends Handler {
private static final String NOTIFICATION_CHANNEL = "satelliteChannel";
private static final String NOTIFICATION_CHANNEL_ID = "satellite";
+ private final RegistrantList mSatelliteConfigUpdateChangedRegistrants = new RegistrantList();
+
/**
* @return The singleton instance of SatelliteController.
*/
@@ -454,12 +466,64 @@ public class SatelliteController extends Handler {
handleCarrierConfigChanged(slotIndex, subId, carrierId, specificCarrierId);
mCarrierConfigManager.registerCarrierConfigChangeListener(
new HandlerExecutor(new Handler(looper)), mCarrierConfigChangeListener);
+
+ mConfigDataUpdatedCallback = new ConfigProviderAdaptor.Callback() {
+ @Override
+ public void onChanged(@Nullable ConfigParser config) {
+ SatelliteControllerHandlerRequest request =
+ new SatelliteControllerHandlerRequest(true,
+ SatelliteServiceUtils.getPhone());
+ sendRequestAsync(EVENT_SATELLITE_CONFIG_DATA_UPDATED, request, null);
+ }
+ };
+ TelephonyConfigUpdateInstallReceiver.getInstance()
+ .registerCallback(Executors.newSingleThreadExecutor(), mConfigDataUpdatedCallback);
+
mDSM.registerForSignalStrengthReportDecision(this, CMD_UPDATE_NTN_SIGNAL_STRENGTH_REPORTING,
null);
loadSatelliteSharedPreferences();
mWaitTimeForSatelliteEnablingResponse = getWaitForSatelliteEnablingResponseTimeoutMillis();
}
+ /**
+ * Register a callback to get a updated satellite config data.
+ * @param h Handler to notify
+ * @param what msg.what when the message is delivered
+ * @param obj AsyncResult.userObj when the message is delivered
+ */
+ public void registerForConfigUpdateChanged(Handler h, int what, Object obj) {
+ Registrant r = new Registrant(h, what, obj);
+ mSatelliteConfigUpdateChangedRegistrants.add(r);
+ }
+
+ /**
+ * Unregister a callback to get a updated satellite config data.
+ * @param h Handler to notify
+ */
+ public void unregisterForConfigUpdateChanged(Handler h) {
+ mSatelliteConfigUpdateChangedRegistrants.remove(h);
+ }
+
+ /**
+ * Get satelliteConfig from SatelliteConfigParser
+ */
+ public SatelliteConfig getSatelliteConfig() {
+ if (getSatelliteConfigParser() == null) {
+ Log.d(TAG, "getSatelliteConfigParser() is not ready");
+ return null;
+ }
+ return (SatelliteConfig) getSatelliteConfigParser().getConfig();
+ }
+
+ /**
+ * Get SatelliteConfigParser from TelephonyConfigUpdateInstallReceiver
+ */
+ @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
+ public SatelliteConfigParser getSatelliteConfigParser() {
+ return (SatelliteConfigParser) TelephonyConfigUpdateInstallReceiver
+ .getInstance().getConfigParser(DOMAIN_SATELLITE);
+ }
+
@VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
protected void initializeSatelliteModeRadios() {
if (mContentResolver != null) {
@@ -1287,6 +1351,12 @@ public class SatelliteController extends Handler {
break;
}
+ case EVENT_SATELLITE_CONFIG_DATA_UPDATED: {
+ handleEventConfigDataUpdated();
+ mSatelliteConfigUpdateChangedRegistrants.notifyRegistrants();
+ break;
+ }
+
default:
Log.w(TAG, "SatelliteControllerHandler: unexpected message code: " +
msg.what);
@@ -1294,6 +1364,19 @@ public class SatelliteController extends Handler {
}
}
+ private void handleEventConfigDataUpdated() {
+ updateSupportedSatelliteServicesForActiveSubscriptions();
+ int[] activeSubIds = mSubscriptionManagerService.getActiveSubIdList(true);
+ if (activeSubIds != null) {
+ for (int subId : activeSubIds) {
+ processNewCarrierConfigData(subId);
+ }
+ } else {
+ loge("updateSupportedSatelliteServicesForActiveSubscriptions: "
+ + "activeSubIds is null");
+ }
+ }
+
private void notifyRequester(SatelliteControllerHandlerRequest request) {
synchronized (request) {
request.notifyAll();
@@ -3193,9 +3276,22 @@ public class SatelliteController extends Handler {
return;
}
+ SatelliteConfig satelliteConfig = getSatelliteConfig();
+ if (satelliteConfig != null) {
+ TelephonyManager tm = mContext.getSystemService(TelephonyManager.class);
+ int carrierId = tm.createForSubscriptionId(subId).getSimCarrierId();
+ List<String> plmnList = satelliteConfig.getAllSatellitePlmnsForCarrier(carrierId);
+ if (!plmnList.isEmpty()) {
+ logd("mMergedPlmnListPerCarrier is updated by ConfigUpdater : " + plmnList);
+ mMergedPlmnListPerCarrier.put(subId, plmnList);
+ return;
+ }
+ }
+
if (mSatelliteServicesSupportedByCarriers.containsKey(subId)) {
carrierPlmnList =
mSatelliteServicesSupportedByCarriers.get(subId).keySet().stream().toList();
+ logd("mMergedPlmnListPerCarrier is updated by carrier config");
} else {
carrierPlmnList = new ArrayList<>();
}
@@ -3205,10 +3301,31 @@ public class SatelliteController extends Handler {
}
private void updateSupportedSatelliteServices(int subId) {
+ logd("updateSupportedSatelliteServices with subId " + subId);
synchronized (mSupportedSatelliteServicesLock) {
+ SatelliteConfig satelliteConfig = getSatelliteConfig();
+
+ TelephonyManager tm = mContext.getSystemService(TelephonyManager.class);
+ int carrierId = tm.createForSubscriptionId(subId).getSimCarrierId();
+
+ if (satelliteConfig != null) {
+ Map<String, Set<Integer>> supportedServicesPerPlmn =
+ satelliteConfig.getSupportedSatelliteServices(carrierId);
+ if (!supportedServicesPerPlmn.isEmpty()) {
+ mSatelliteServicesSupportedByCarriers.put(subId, supportedServicesPerPlmn);
+ logd("updateSupportedSatelliteServices using ConfigUpdater, "
+ + "supportedServicesPerPlmn = " + supportedServicesPerPlmn);
+ updatePlmnListPerCarrier(subId);
+ return;
+ } else {
+ logd("supportedServicesPerPlmn is empty");
+ }
+ }
+
mSatelliteServicesSupportedByCarriers.put(
subId, readSupportedSatelliteServicesFromCarrierConfig(subId));
updatePlmnListPerCarrier(subId);
+ logd("updateSupportedSatelliteServices using carrier config");
}
}
@@ -3262,8 +3379,11 @@ public class SatelliteController extends Handler {
updateCarrierConfig(subId);
updateEntitlementPlmnListPerCarrier(subId);
updateSupportedSatelliteServicesForActiveSubscriptions();
- configureSatellitePlmnForCarrier(subId);
+ processNewCarrierConfigData(subId);
+ }
+ private void processNewCarrierConfigData(int subId) {
+ configureSatellitePlmnForCarrier(subId);
synchronized (mIsSatelliteEnabledLock) {
mSatelliteAttachRestrictionForCarrierArray.clear();
mIsSatelliteAttachEnabledForCarrierArrayPerSub.clear();
diff --git a/tests/telephonytests/src/com/android/internal/telephony/configupdate/TelephonyConfigUpdateInstallReceiverTest.java b/tests/telephonytests/src/com/android/internal/telephony/configupdate/TelephonyConfigUpdateInstallReceiverTest.java
new file mode 100644
index 0000000000..629327d243
--- /dev/null
+++ b/tests/telephonytests/src/com/android/internal/telephony/configupdate/TelephonyConfigUpdateInstallReceiverTest.java
@@ -0,0 +1,175 @@
+/*
+ * 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.internal.telephony.configupdate;
+
+import static com.android.internal.telephony.configupdate.TelephonyConfigUpdateInstallReceiver.UPDATE_CONTENT_PATH;
+import static com.android.internal.telephony.configupdate.TelephonyConfigUpdateInstallReceiver.UPDATE_DIR;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertSame;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.atLeast;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+
+import android.content.Intent;
+
+import androidx.annotation.Nullable;
+
+import com.android.internal.telephony.TelephonyTest;
+import com.android.internal.telephony.satellite.SatelliteConfigParser;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.io.File;
+import java.util.Base64;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.Executor;
+import java.util.concurrent.Executors;
+
+public class TelephonyConfigUpdateInstallReceiverTest extends TelephonyTest {
+
+ public static final String DOMAIN_SATELLITE = "satellite";
+ @Mock
+ private Executor mExecutor;
+ @Mock
+ private ConfigProviderAdaptor.Callback mCallback;
+
+ @Before
+ public void setUp() throws Exception {
+ super.setUp(getClass().getSimpleName());
+ MockitoAnnotations.initMocks(this);
+ logd(TAG + " Setup!");
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ logd(TAG + " tearDown");
+ super.tearDown();
+ }
+
+ @Test
+ public void testTelephonyConfigUpdateInstallReceiver() {
+ TelephonyConfigUpdateInstallReceiver testReceiver =
+ new TelephonyConfigUpdateInstallReceiver();
+ assertEquals(UPDATE_DIR, testReceiver.getUpdateDir().toString());
+ assertEquals(new File(new File(UPDATE_DIR), UPDATE_CONTENT_PATH).toString(),
+ testReceiver.getUpdateContent().toString());
+ }
+
+ @Test
+ public void testGetInstance() {
+ TelephonyConfigUpdateInstallReceiver testReceiver1 =
+ TelephonyConfigUpdateInstallReceiver.getInstance();
+ TelephonyConfigUpdateInstallReceiver testReceiver2 =
+ TelephonyConfigUpdateInstallReceiver.getInstance();
+ assertSame(testReceiver1, testReceiver2);
+ }
+
+ @Test
+ public void testPostInstall() throws Exception {
+ // create spyTelephonyConfigUpdateInstallReceiver
+ TelephonyConfigUpdateInstallReceiver spyTelephonyConfigUpdateInstallReceiver =
+ spy(new TelephonyConfigUpdateInstallReceiver());
+
+ // mock BeforeParser
+ String mBase64StrForPBByteArray =
+ "CjYIBBIeCAESDgoGMzEwMTYwEAEQAhADEgoKBjMxMDIyMBADGhIKCjAxMjM0NTY3ODkSAlVTGAE=";
+ byte[] mBytesProtoBuffer = Base64.getDecoder().decode(mBase64StrForPBByteArray);
+ doReturn(mBytesProtoBuffer).when(
+ spyTelephonyConfigUpdateInstallReceiver).getCurrentContent();
+ SatelliteConfigParser mMockSatelliteConfigParserBefore =
+ spy(new SatelliteConfigParser(mBytesProtoBuffer));
+ doReturn(mMockSatelliteConfigParserBefore).when(
+ spyTelephonyConfigUpdateInstallReceiver).getConfigParser(DOMAIN_SATELLITE);
+
+ // mock UpdatedParser
+ SatelliteConfigParser spySatelliteConfigParserAfter =
+ spy(new SatelliteConfigParser(mBytesProtoBuffer));
+ doReturn(5).when(spySatelliteConfigParserAfter).getVersion();
+ doReturn(spySatelliteConfigParserAfter).when(spyTelephonyConfigUpdateInstallReceiver)
+ .getNewConfigParser(any(), any());
+
+ replaceInstance(TelephonyConfigUpdateInstallReceiver.class, "sReceiverAdaptorInstance",
+ null, spyTelephonyConfigUpdateInstallReceiver);
+
+ assertSame(spyTelephonyConfigUpdateInstallReceiver,
+ TelephonyConfigUpdateInstallReceiver.getInstance());
+
+ ConcurrentHashMap<Executor, ConfigProviderAdaptor.Callback> spyCallbackHashMap = spy(
+ new ConcurrentHashMap<>());
+ spyCallbackHashMap.put(mExecutor, mCallback);
+ spyTelephonyConfigUpdateInstallReceiver.setCallbackMap(spyCallbackHashMap);
+ spyTelephonyConfigUpdateInstallReceiver.postInstall(mContext, new Intent());
+
+ verify(spyCallbackHashMap, atLeast(1)).keySet();
+ }
+
+
+ @Test
+ public void testGetConfig() throws Exception {
+ TelephonyConfigUpdateInstallReceiver spyTelephonyConfigUpdateInstallReceiver =
+ spy(new TelephonyConfigUpdateInstallReceiver());
+
+ doReturn(null).when(
+ spyTelephonyConfigUpdateInstallReceiver).getCurrentContent();
+
+ replaceInstance(TelephonyConfigUpdateInstallReceiver.class, "sReceiverAdaptorInstance",
+ null, spyTelephonyConfigUpdateInstallReceiver);
+ assertNull(TelephonyConfigUpdateInstallReceiver.getInstance().getConfigParser(
+ DOMAIN_SATELLITE));
+
+ String mBase64StrForPBByteArray =
+ "CjYIBBIeCAESDgoGMzEwMTYwEAEQAhADEgoKBjMxMDIyMBADGhIKCjAxMjM0NTY3ODkSAlVTGAE=";
+ byte[] mBytesProtoBuffer = Base64.getDecoder().decode(mBase64StrForPBByteArray);
+ doReturn(mBytesProtoBuffer).when(
+ spyTelephonyConfigUpdateInstallReceiver).getCurrentContent();
+
+ replaceInstance(TelephonyConfigUpdateInstallReceiver.class, "sReceiverAdaptorInstance",
+ null, spyTelephonyConfigUpdateInstallReceiver);
+
+ assertNotNull(TelephonyConfigUpdateInstallReceiver.getInstance().getConfigParser(
+ DOMAIN_SATELLITE));
+ }
+
+ @Test
+ public void testRegisterUnRegisterCallback() {
+ TelephonyConfigUpdateInstallReceiver testReceiver =
+ TelephonyConfigUpdateInstallReceiver.getInstance();
+
+ ConfigProviderAdaptor.Callback testCallback = new ConfigProviderAdaptor.Callback() {
+ @Override
+ public void onChanged(@Nullable ConfigParser config) {
+ super.onChanged(config);
+ }
+ };
+ Executor executor = Executors.newSingleThreadExecutor();
+
+ testReceiver.registerCallback(executor, testCallback);
+ assertSame(testCallback, testReceiver.getCallbackMap().get(executor));
+
+ testReceiver.unregisterCallback(testCallback);
+ assertEquals(0, testReceiver.getCallbackMap().size());
+ }
+}
diff --git a/tests/telephonytests/src/com/android/internal/telephony/satellite/SatelliteConfigParserTest.java b/tests/telephonytests/src/com/android/internal/telephony/satellite/SatelliteConfigParserTest.java
new file mode 100644
index 0000000000..e4f0255a92
--- /dev/null
+++ b/tests/telephonytests/src/com/android/internal/telephony/satellite/SatelliteConfigParserTest.java
@@ -0,0 +1,227 @@
+/*
+ * 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.internal.telephony.satellite;
+
+import static junit.framework.Assert.assertNotNull;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.spy;
+
+import android.testing.AndroidTestingRunner;
+
+import com.android.internal.telephony.TelephonyTest;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mockito;
+import org.mockito.MockitoAnnotations;
+
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.Base64;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+@RunWith(AndroidTestingRunner.class)
+
+public class SatelliteConfigParserTest extends TelephonyTest {
+
+ /**
+ * satelliteConfigBuilder.setVersion(4);
+ *
+ * carrierSupportedSatelliteServiceBuilder.setCarrierId(1);
+ *
+ * satelliteProviderCapabilityBuilder.setCarrierPlmn("310160");
+ * satelliteProviderCapabilityBuilder.addAllowedServices(1);
+ * satelliteProviderCapabilityBuilder.addAllowedServices(2);
+ * satelliteProviderCapabilityBuilder.addAllowedServices(3);
+ *
+ * satelliteProviderCapabilityBuilder.setCarrierPlmn("310220");
+ * satelliteProviderCapabilityBuilder.addAllowedServices(3);
+ *
+ * String test = "0123456789";
+ * bigString.append(test.repeat(1));
+ * satelliteRegionBuilder.setS2CellFile(ByteString.copyFrom(bigString.toString().getBytes()));
+ * satelliteRegionBuilder.addCountryCodes("US");
+ * satelliteRegionBuilder.setIsAllowed(true);
+ */
+ private String mBase64StrForPBByteArray =
+ "CjYIBBIeCAESDgoGMzEwMTYwEAEQAhADEgoKBjMxMDIyMBADGhIKCjAxMjM0NTY3ODkSAlVTGAE=";
+ private byte[] mBytesProtoBuffer = Base64.getDecoder().decode(mBase64StrForPBByteArray);
+
+
+ @Before
+ public void setUp() throws Exception {
+ super.setUp(getClass().getSimpleName());
+ MockitoAnnotations.initMocks(this);
+ logd(TAG + " Setup!");
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ logd(TAG + " tearDown");
+ super.tearDown();
+ }
+
+ @Test
+ public void testGetAllSatellitePlmnsForCarrier() {
+ List<String> compareList_cid1 = new ArrayList<>();
+ compareList_cid1.add("310160");
+ compareList_cid1.add("310220");
+ List<String> compareList_cid_placeholder = new ArrayList<>();
+ compareList_cid_placeholder.add("310260");
+ compareList_cid_placeholder.add("45060");
+
+
+ SatelliteConfigParser satelliteConfigParserNull = new SatelliteConfigParser((byte[]) null);
+ assertNotNull(satelliteConfigParserNull);
+ assertNull(satelliteConfigParserNull.getConfig());
+
+ SatelliteConfigParser satelliteConfigParserPlaceHolder =
+ new SatelliteConfigParser((byte[]) null);
+ assertNotNull(satelliteConfigParserPlaceHolder);
+ assertNull(satelliteConfigParserPlaceHolder.getConfig());
+
+ SatelliteConfigParser satelliteConfigParser = new SatelliteConfigParser(mBytesProtoBuffer);
+
+ List<String> parsedList1 = satelliteConfigParser.getConfig()
+ .getAllSatellitePlmnsForCarrier(1);
+ Collections.sort(compareList_cid1);
+ Collections.sort(compareList_cid_placeholder);
+ Collections.sort(parsedList1);
+
+ assertEquals(compareList_cid1, parsedList1);
+ assertNotEquals(compareList_cid_placeholder, parsedList1);
+
+ List<String> parsedList2 = satelliteConfigParser.getConfig()
+ .getAllSatellitePlmnsForCarrier(0);
+ assertEquals(0, parsedList2.size());
+ }
+
+ @Test
+ public void testGetSupportedSatelliteServices() {
+ Map<String, Set<Integer>> compareMapCarrierId1 = new HashMap<>();
+ Set<Integer> compareSet310160 = new HashSet<>();
+ compareSet310160.add(1);
+ compareSet310160.add(2);
+ compareSet310160.add(3);
+ compareMapCarrierId1.put("310160", compareSet310160);
+
+ Set<Integer> compareSet310220 = new HashSet<>();
+ compareSet310220.add(3);
+ compareMapCarrierId1.put("310220", compareSet310220);
+
+ SatelliteConfigParser satelliteConfigParserNull = new SatelliteConfigParser((byte[]) null);
+ assertNotNull(satelliteConfigParserNull);
+ assertNull(satelliteConfigParserNull.getConfig());
+
+ SatelliteConfigParser satelliteConfigParserPlaceholder =
+ new SatelliteConfigParser("test".getBytes());
+ assertNotNull(satelliteConfigParserPlaceholder);
+ assertNull(satelliteConfigParserPlaceholder.getConfig());
+
+ SatelliteConfigParser satelliteConfigParser = new SatelliteConfigParser(mBytesProtoBuffer);
+ Map<String, Set<Integer>> parsedMap1 = satelliteConfigParser.getConfig()
+ .getSupportedSatelliteServices(0);
+ Map<String, Set<Integer>> parsedMap2 = satelliteConfigParser.getConfig()
+ .getSupportedSatelliteServices(1);
+ assertEquals(0, parsedMap1.size());
+ assertEquals(2, parsedMap2.size());
+ assertEquals(compareMapCarrierId1, parsedMap2);
+ }
+
+ @Test
+ public void testGetDeviceSatelliteCountryCodes() {
+ List<String> compareList_countryCodes = new ArrayList<>();
+ compareList_countryCodes.add("US");
+ Collections.sort(compareList_countryCodes);
+
+ List<String> compareList_countryCodes_placeholder = new ArrayList<>();
+ compareList_countryCodes_placeholder.add("US");
+ compareList_countryCodes_placeholder.add("IN");
+ Collections.sort(compareList_countryCodes_placeholder);
+
+ SatelliteConfigParser satelliteConfigParserNull = new SatelliteConfigParser((byte[]) null);
+ assertNotNull(satelliteConfigParserNull);
+ assertNull(satelliteConfigParserNull.getConfig());
+
+ SatelliteConfigParser satelliteConfigParser = new SatelliteConfigParser(mBytesProtoBuffer);
+ List<String> tempList = satelliteConfigParser.getConfig().getDeviceSatelliteCountryCodes();
+ List<String> parsedList = new ArrayList<>(tempList);
+ Collections.sort(parsedList);
+
+ assertEquals(compareList_countryCodes, parsedList);
+ assertNotEquals(compareList_countryCodes_placeholder, parsedList);
+ }
+
+ @Test
+ public void testGetSatelliteS2CellFile() {
+ final String filePath = "/data/user_de/0/com.android.phone/app_satellite/s2_cell_file";
+ Path targetSatS2FilePath = Paths.get(filePath);
+
+ SatelliteConfigParser mockedSatelliteConfigParserNull = spy(
+ new SatelliteConfigParser((byte[]) null));
+ assertNotNull(mockedSatelliteConfigParserNull);
+ assertNull(mockedSatelliteConfigParserNull.getConfig());
+
+ SatelliteConfigParser mockedSatelliteConfigParserPlaceholder = spy(
+ new SatelliteConfigParser("test".getBytes()));
+ assertNotNull(mockedSatelliteConfigParserPlaceholder);
+ assertNull(mockedSatelliteConfigParserPlaceholder.getConfig());
+
+ SatelliteConfigParser mockedSatelliteConfigParser =
+ spy(new SatelliteConfigParser(mBytesProtoBuffer));
+ SatelliteConfig mockedSatelliteConfig = Mockito.mock(SatelliteConfig.class);
+ doReturn(targetSatS2FilePath).when(mockedSatelliteConfig).getSatelliteS2CellFile(any());
+ doReturn(mockedSatelliteConfig).when(mockedSatelliteConfigParser).getConfig();
+// assertNotNull(mockedSatelliteConfigParser.getConfig());
+// doReturn(false).when(mockedSatelliteConfigParser).getConfig().isFileExist(any());
+// doReturn(targetSatS2FilePath).when(mockedSatelliteConfigParser).getConfig()
+// .copySatS2FileToPhoneDirectory(any(), any());
+ assertEquals(targetSatS2FilePath,
+ mockedSatelliteConfigParser.getConfig().getSatelliteS2CellFile(mContext));
+ }
+
+ @Test
+ public void testGetSatelliteAccessAllow() {
+ SatelliteConfigParser satelliteConfigParserNull = new SatelliteConfigParser((byte[]) null);
+ assertNotNull(satelliteConfigParserNull);
+ assertNull(satelliteConfigParserNull.getConfig());
+
+ SatelliteConfigParser satelliteConfigParserPlaceholder =
+ new SatelliteConfigParser("test".getBytes());
+ assertNotNull(satelliteConfigParserPlaceholder);
+ assertNull(satelliteConfigParserPlaceholder.getConfig());
+
+ SatelliteConfigParser satelliteConfigParser = new SatelliteConfigParser(mBytesProtoBuffer);
+ assertNotNull(satelliteConfigParser);
+ assertNotNull(satelliteConfigParser.getConfig());
+ assertTrue(satelliteConfigParser.getConfig().isSatelliteDataForAllowedRegion());
+ }
+}
diff --git a/tests/telephonytests/src/com/android/internal/telephony/satellite/SatelliteControllerTest.java b/tests/telephonytests/src/com/android/internal/telephony/satellite/SatelliteControllerTest.java
index 431b4cc182..f1a8de93e0 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/satellite/SatelliteControllerTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/satellite/SatelliteControllerTest.java
@@ -124,6 +124,8 @@ import com.android.internal.telephony.IVoidConsumer;
import com.android.internal.telephony.Phone;
import com.android.internal.telephony.PhoneFactory;
import com.android.internal.telephony.TelephonyTest;
+import com.android.internal.telephony.configupdate.ConfigProviderAdaptor;
+import com.android.internal.telephony.configupdate.TelephonyConfigUpdateInstallReceiver;
import com.android.internal.telephony.flags.FeatureFlags;
import com.android.internal.telephony.satellite.metrics.ControllerMetricsStats;
import com.android.internal.telephony.satellite.metrics.ProvisionMetricsStats;
@@ -189,6 +191,10 @@ public class SatelliteControllerTest extends TelephonyTest {
@Mock private ISatelliteTransmissionUpdateCallback mStartTransmissionUpdateCallback;
@Mock private ISatelliteTransmissionUpdateCallback mStopTransmissionUpdateCallback;
@Mock private FeatureFlags mFeatureFlags;
+ @Mock private TelephonyConfigUpdateInstallReceiver mMockTelephonyConfigUpdateInstallReceiver;
+ @Mock private SatelliteConfigParser mMockConfigParser;
+ @Mock private SatelliteConfig mMockConfig;
+
private Semaphore mIIntegerConsumerSemaphore = new Semaphore(0);
private IIntegerConsumer mIIntegerConsumer = new IIntegerConsumer.Stub() {
@Override
@@ -459,6 +465,8 @@ public class SatelliteControllerTest extends TelephonyTest {
replaceInstance(SubscriptionManagerService.class, "sInstance", null,
mMockSubscriptionManagerService);
replaceInstance(PhoneFactory.class, "sPhones", null, new Phone[]{mPhone, mPhone2});
+ replaceInstance(TelephonyConfigUpdateInstallReceiver.class, "sReceiverAdaptorInstance",
+ null, mMockTelephonyConfigUpdateInstallReceiver);
mServiceState2 = Mockito.mock(ServiceState.class);
when(mPhone.getServiceState()).thenReturn(mServiceState);
@@ -536,6 +544,9 @@ public class SatelliteControllerTest extends TelephonyTest {
any(Handler.class),
eq(28) /* EVENT_SATELLITE_MODEM_STATE_CHANGED */,
eq(null));
+
+ doReturn(mMockConfigParser).when(mMockTelephonyConfigUpdateInstallReceiver)
+ .getConfigParser(ConfigProviderAdaptor.DOMAIN_SATELLITE);
}
@After
@@ -2761,41 +2772,116 @@ public class SatelliteControllerTest extends TelephonyTest {
eq(plmnListPerCarrier), eq(allSatellitePlmnList), any(Message.class));
}
+ private void setConfigData(List<String> plmnList) {
+ doReturn(plmnList).when(mMockConfig).getAllSatellitePlmnsForCarrier(anyInt());
+ doReturn(mMockConfig).when(mMockConfigParser).getConfig();
+
+ Map<String, List<Integer>> servicePerPlmn = new HashMap<>();
+ List<List<Integer>> serviceLists = Arrays.asList(
+ Arrays.asList(1),
+ Arrays.asList(3),
+ Arrays.asList(5)
+ );
+ for (int i = 0; i < plmnList.size(); i++) {
+ servicePerPlmn.put(plmnList.get(i), serviceLists.get(i));
+ }
+ doReturn(servicePerPlmn).when(mMockConfig).getSupportedSatelliteServices(anyInt());
+ doReturn(mMockConfig).when(mMockConfigParser).getConfig();
+ }
+
@Test
- public void testUpdatePlmnListPerCarrier() throws Exception {
- logd("testUpdatePlmnListPerCarrier");
+ public void testUpdateSupportedSatelliteServices() throws Exception {
+ logd("testUpdateSupportedSatelliteServices");
when(mFeatureFlags.carrierEnabledSatelliteFlag()).thenReturn(true);
replaceInstance(SatelliteController.class, "mMergedPlmnListPerCarrier",
mSatelliteControllerUT, new SparseArray<>());
replaceInstance(SatelliteController.class, "mSatelliteServicesSupportedByCarriers",
mSatelliteControllerUT, new HashMap<>());
+ List<Integer> servicesPerPlmn;
+
+ // verify whether an empty list is returned with conditions below
+ // the config data plmn list : empty
+ // the carrier config plmn list : empty
+ setConfigData(new ArrayList<>());
+ setCarrierConfigDataPlmnList(new ArrayList<>());
+ invokeCarrierConfigChanged();
+ servicesPerPlmn = mSatelliteControllerUT.getSupportedSatelliteServices(SUB_ID, "31016");
+ assertEquals(new ArrayList<>(), servicesPerPlmn);
+
+ // Verify whether the carrier config plmn list is returned with conditions below
+ // the config data plmn list : empty
+ // the carrier config plmn list : exist with services {{2}, {1, 3}, {2}}
+ setConfigData(new ArrayList<>());
+ setCarrierConfigDataPlmnList(Arrays.asList("00101", "00102", "00104"));
+ invokeCarrierConfigChanged();
+ servicesPerPlmn = mSatelliteControllerUT.getSupportedSatelliteServices(SUB_ID, "00101");
+ assertEquals(Arrays.asList(2).stream().sorted().toList(),
+ servicesPerPlmn.stream().sorted().toList());
+ servicesPerPlmn = mSatelliteControllerUT.getSupportedSatelliteServices(SUB_ID, "00102");
+ assertEquals(Arrays.asList(1, 3).stream().sorted().toList(),
+ servicesPerPlmn.stream().sorted().toList());
+ servicesPerPlmn = mSatelliteControllerUT.getSupportedSatelliteServices(SUB_ID, "00104");
+ assertEquals(Arrays.asList(2).stream().sorted().toList(),
+ servicesPerPlmn.stream().sorted().toList());
+
+ // Verify whether the carrier config plmn list is returned with conditions below
+ // the config data plmn list : exist with services {{1}, {3}, {5}}
+ // the carrier config plmn list : exist with services {{2}, {1, 3}, {2}}
+ setConfigData(Arrays.asList("00101", "00102", "31024"));
+ setCarrierConfigDataPlmnList(Arrays.asList("00101", "00102", "00104"));
+ invokeCarrierConfigChanged();
+ servicesPerPlmn = mSatelliteControllerUT.getSupportedSatelliteServices(SUB_ID, "00101");
+ assertEquals(Arrays.asList(1).stream().sorted().toList(),
+ servicesPerPlmn.stream().sorted().toList());
+ servicesPerPlmn = mSatelliteControllerUT.getSupportedSatelliteServices(SUB_ID, "00102");
+ assertEquals(Arrays.asList(3).stream().sorted().toList(),
+ servicesPerPlmn.stream().sorted().toList());
+ servicesPerPlmn = mSatelliteControllerUT.getSupportedSatelliteServices(SUB_ID, "00104");
+ assertEquals(new ArrayList<>(), servicesPerPlmn.stream().sorted().toList());
+ servicesPerPlmn = mSatelliteControllerUT.getSupportedSatelliteServices(SUB_ID, "31024");
+ assertEquals(Arrays.asList(5).stream().sorted().toList(),
+ servicesPerPlmn.stream().sorted().toList());
+ }
+ private void setEntitlementPlmnList(List<String> plmnList) throws Exception {
SparseArray<List<String>> entitlementPlmnListPerCarrier = new SparseArray<>();
+ if (!plmnList.isEmpty()) {
+ entitlementPlmnListPerCarrier.clear();
+ entitlementPlmnListPerCarrier.put(SUB_ID, plmnList);
+ }
replaceInstance(SatelliteController.class, "mEntitlementPlmnListPerCarrier",
mSatelliteControllerUT, entitlementPlmnListPerCarrier);
+ }
- // If the carrier config and the entitlement plmn list are empty, verify whether an empty
- // list is returned.
- mCarrierConfigBundle.putPersistableBundle(CarrierConfigManager
- .KEY_CARRIER_SUPPORTED_SATELLITE_SERVICES_PER_PROVIDER_BUNDLE,
- new PersistableBundle());
- for (Pair<Executor, CarrierConfigManager.CarrierConfigChangeListener> pair
- : mCarrierConfigChangedListenerList) {
- pair.first.execute(() -> pair.second.onCarrierConfigChanged(
- /*slotIndex*/ 0, /*subId*/ SUB_ID, /*carrierId*/ 0, /*specificCarrierId*/ 0)
- );
+ private void setConfigDataPlmnList(List<String> plmnList) {
+ doReturn(plmnList).when(mMockConfig).getAllSatellitePlmnsForCarrier(anyInt());
+ doReturn(mMockConfig).when(mMockConfigParser).getConfig();
+ }
+
+ private void setCarrierConfigDataPlmnList(List<String> plmnList) {
+ if (!plmnList.isEmpty()) {
+ mCarrierConfigBundle.putBoolean(
+ CarrierConfigManager.KEY_SATELLITE_ATTACH_SUPPORTED_BOOL,
+ true);
+ PersistableBundle carrierSupportedSatelliteServicesPerProvider =
+ new PersistableBundle();
+ List<String> carrierConfigPlmnList = plmnList;
+ carrierSupportedSatelliteServicesPerProvider.putIntArray(
+ carrierConfigPlmnList.get(0), new int[]{2});
+ carrierSupportedSatelliteServicesPerProvider.putIntArray(
+ carrierConfigPlmnList.get(1), new int[]{1, 3});
+ carrierSupportedSatelliteServicesPerProvider.putIntArray(
+ carrierConfigPlmnList.get(2), new int[]{2});
+ mCarrierConfigBundle.putPersistableBundle(CarrierConfigManager
+ .KEY_CARRIER_SUPPORTED_SATELLITE_SERVICES_PER_PROVIDER_BUNDLE,
+ carrierSupportedSatelliteServicesPerProvider);
+ } else {
+ mCarrierConfigBundle.putPersistableBundle(CarrierConfigManager
+ .KEY_CARRIER_SUPPORTED_SATELLITE_SERVICES_PER_PROVIDER_BUNDLE,
+ new PersistableBundle());
}
- processAllMessages();
-
- List<String> plmnListPerCarrier = mSatelliteControllerUT.getSatellitePlmnsForCarrier(
- SUB_ID);
- assertEquals(new ArrayList<>(), plmnListPerCarrier);
+ }
- // If the carrier config list is empty and the entitlement plmn list is exists, verify
- // whether the entitlement list is returned.
- entitlementPlmnListPerCarrier.clear();
- List<String> entitlementPlmnList = Arrays.asList("00101", "00102", "00104");
- entitlementPlmnListPerCarrier.put(SUB_ID, entitlementPlmnList);
- List<String> expectedPlmnListPerCarrier = entitlementPlmnList;
+ private void invokeCarrierConfigChanged() {
for (Pair<Executor, CarrierConfigManager.CarrierConfigChangeListener> pair
: mCarrierConfigChangedListenerList) {
pair.first.execute(() -> pair.second.onCarrierConfigChanged(
@@ -2803,58 +2889,61 @@ public class SatelliteControllerTest extends TelephonyTest {
);
}
processAllMessages();
+ }
+ @Test
+ public void testUpdatePlmnListPerCarrier() throws Exception {
+ logd("testUpdatePlmnListPerCarrier");
+ when(mFeatureFlags.carrierEnabledSatelliteFlag()).thenReturn(true);
+ replaceInstance(SatelliteController.class, "mMergedPlmnListPerCarrier",
+ mSatelliteControllerUT, new SparseArray<>());
+ List<String> plmnListPerCarrier;
+
+ // verify whether an empty list is returned with conditions below
+ // the entitlement plmn list : empty
+ // the config data plmn list : empty
+ // the carrier config plmn list : empty
+ setEntitlementPlmnList(new ArrayList<>());
+ setConfigDataPlmnList(new ArrayList<>());
+ setCarrierConfigDataPlmnList(new ArrayList<>());
+ invokeCarrierConfigChanged();
plmnListPerCarrier = mSatelliteControllerUT.getSatellitePlmnsForCarrier(SUB_ID);
- assertEquals(expectedPlmnListPerCarrier, plmnListPerCarrier);
-
- // If the carrier config list is exists and the entitlement plmn list is empty, verify
- // whether the carrier config list is returned.
- entitlementPlmnListPerCarrier.clear();
- entitlementPlmnList = new ArrayList<>();
- entitlementPlmnListPerCarrier.put(SUB_ID, entitlementPlmnList);
- mCarrierConfigBundle.putBoolean(CarrierConfigManager.KEY_SATELLITE_ATTACH_SUPPORTED_BOOL,
- true);
- PersistableBundle carrierSupportedSatelliteServicesPerProvider = new PersistableBundle();
- List<String> carrierConfigPlmnList = Arrays.asList("00102", "00103", "00105");
- carrierSupportedSatelliteServicesPerProvider.putIntArray(
- carrierConfigPlmnList.get(0), new int[]{2});
- carrierSupportedSatelliteServicesPerProvider.putIntArray(
- carrierConfigPlmnList.get(1), new int[]{1, 3});
- carrierSupportedSatelliteServicesPerProvider.putIntArray(
- carrierConfigPlmnList.get(2), new int[]{2});
- mCarrierConfigBundle.putPersistableBundle(CarrierConfigManager
- .KEY_CARRIER_SUPPORTED_SATELLITE_SERVICES_PER_PROVIDER_BUNDLE,
- carrierSupportedSatelliteServicesPerProvider);
- for (Pair<Executor, CarrierConfigManager.CarrierConfigChangeListener> pair
- : mCarrierConfigChangedListenerList) {
- pair.first.execute(() -> pair.second.onCarrierConfigChanged(
- /*slotIndex*/ 0, /*subId*/ SUB_ID, /*carrierId*/ 0, /*specificCarrierId*/ 0)
- );
- }
- processAllMessages();
-
- expectedPlmnListPerCarrier = carrierConfigPlmnList;
+ assertEquals(new ArrayList<>(), plmnListPerCarrier.stream().sorted().toList());
+
+ // Verify whether the carrier config plmn list is returned with conditions below
+ // the entitlement plmn list : empty
+ // the config data plmn list : empty
+ // the carrier config plmn list : exist
+ setEntitlementPlmnList(new ArrayList<>());
+ setConfigDataPlmnList(new ArrayList<>());
+ setCarrierConfigDataPlmnList(Arrays.asList("00101", "00102", "00104"));
+ invokeCarrierConfigChanged();
plmnListPerCarrier = mSatelliteControllerUT.getSatellitePlmnsForCarrier(SUB_ID);
- assertEquals(expectedPlmnListPerCarrier.stream().sorted().toList(),
+ assertEquals(Arrays.asList("00101", "00102", "00104").stream().sorted().toList(),
plmnListPerCarrier.stream().sorted().toList());
+ // Verify whether config data plmn list is returned with conditions below
+ // the entitlement plmn list : empty
+ // the config data plmn list : exist
+ // the carrier config plmn list : exist
+ setEntitlementPlmnList(new ArrayList<>());
+ setConfigDataPlmnList(Arrays.asList("11111", "22222", "33333"));
+ setCarrierConfigDataPlmnList(Arrays.asList("00101", "00102", "00104"));
+ invokeCarrierConfigChanged();
+ plmnListPerCarrier = mSatelliteControllerUT.getSatellitePlmnsForCarrier(SUB_ID);
+ assertEquals(Arrays.asList("11111", "22222", "33333").stream().sorted().toList(),
+ plmnListPerCarrier.stream().sorted().toList());
- // If the carrier config and the entitlement plmn list are exist, verify whether the
- // entitlement list is returned.
- entitlementPlmnList = Arrays.asList("00101", "00102", "00104");
- entitlementPlmnListPerCarrier.put(SUB_ID, entitlementPlmnList);
- for (Pair<Executor, CarrierConfigManager.CarrierConfigChangeListener> pair
- : mCarrierConfigChangedListenerList) {
- pair.first.execute(() -> pair.second.onCarrierConfigChanged(
- /*slotIndex*/ 0, /*subId*/ SUB_ID, /*carrierId*/ 0, /*specificCarrierId*/ 0)
- );
- }
- processAllMessages();
-
- expectedPlmnListPerCarrier = entitlementPlmnList;
- plmnListPerCarrier = mSatelliteControllerUT.getSatellitePlmnsForCarrier(
- SUB_ID);
- assertEquals(expectedPlmnListPerCarrier.stream().sorted().toList(),
+ // Verify whether the entitlement plmn list is returned with conditions below
+ // the entitlement plmn list : exist
+ // the config data plmn list : exist
+ // the carrier config plmn list : exist
+ setEntitlementPlmnList(Arrays.asList("99090", "88080", "77070"));
+ setConfigDataPlmnList(Arrays.asList("11111", "22222", "33333"));
+ setCarrierConfigDataPlmnList(Arrays.asList("00101", "00102", "00104"));
+ invokeCarrierConfigChanged();
+ plmnListPerCarrier = mSatelliteControllerUT.getSatellitePlmnsForCarrier(SUB_ID);
+ assertEquals(Arrays.asList("99090", "88080", "77070").stream().sorted().toList(),
plmnListPerCarrier.stream().sorted().toList());
}