()
override fun getBoolean(key: String): Boolean {
- check(key.endsWith("_bool")) { "Boolean key should ends with _bool" }
+ checkBooleanKey(key)
val value = cache[key]
return if (value == null) {
keysToRetrieve += key to KeyType.BOOLEAN
@@ -186,9 +186,18 @@ class CarrierConfigRepository(private val context: Context) {
ListenerRegistered.getAndSet(false)
}
+ private val BooleanKeysWhichNotFollowingsNamingConventions =
+ listOf(CarrierConfigManager.KEY_IGNORE_DATA_ENABLED_CHANGED_FOR_VIDEO_CALLS)
+
+ private fun checkBooleanKey(key: String) {
+ check(key.endsWith("_bool") || key in BooleanKeysWhichNotFollowingsNamingConventions) {
+ "Boolean key should ends with _bool"
+ }
+ }
+
@VisibleForTesting
fun setBooleanForTest(subId: Int, key: String, value: Boolean) {
- check(key.endsWith("_bool")) { "Boolean key should ends with _bool" }
+ checkBooleanKey(key)
getPerSubCache(subId)[key] = BooleanConfigValue(value)
}
diff --git a/src/com/android/settings/network/telephony/MobileNetworkSettingsSearchIndex.kt b/src/com/android/settings/network/telephony/MobileNetworkSettingsSearchIndex.kt
index c63e7d23bf1..4f31e0f71c7 100644
--- a/src/com/android/settings/network/telephony/MobileNetworkSettingsSearchIndex.kt
+++ b/src/com/android/settings/network/telephony/MobileNetworkSettingsSearchIndex.kt
@@ -26,6 +26,7 @@ import com.android.settings.network.telephony.DataUsagePreferenceController.Comp
import com.android.settings.network.telephony.MmsMessagePreferenceController.Companion.MmsMessageSearchItem
import com.android.settings.network.telephony.NrAdvancedCallingPreferenceController.Companion.NrAdvancedCallingSearchItem
import com.android.settings.network.telephony.RoamingPreferenceController.Companion.RoamingSearchItem
+import com.android.settings.network.telephony.VideoCallingPreferenceController.Companion.VideoCallingSearchItem
import com.android.settings.network.telephony.WifiCallingPreferenceController.Companion.WifiCallingSearchItem
import com.android.settings.spa.SpaSearchLanding.BundleValue
import com.android.settings.spa.SpaSearchLanding.SpaSearchLandingFragment
@@ -122,6 +123,7 @@ class MobileNetworkSettingsSearchIndex(
NrAdvancedCallingSearchItem(context),
PreferredNetworkModeSearchItem(context),
RoamingSearchItem(context),
+ VideoCallingSearchItem(context),
WifiCallingSearchItem(context),
)
}
diff --git a/src/com/android/settings/network/telephony/MobileNetworkUtils.java b/src/com/android/settings/network/telephony/MobileNetworkUtils.java
index 517f66ad60a..235418ebb55 100644
--- a/src/com/android/settings/network/telephony/MobileNetworkUtils.java
+++ b/src/com/android/settings/network/telephony/MobileNetworkUtils.java
@@ -32,7 +32,6 @@ import static com.android.settings.network.telephony.TelephonyConstants.Telephon
import static com.android.settings.network.telephony.TelephonyConstants.TelephonyManagerConstants.NETWORK_MODE_NR_LTE_GSM_WCDMA;
import android.app.KeyguardManager;
-import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
@@ -51,8 +50,6 @@ import android.os.CancellationSignal;
import android.os.Handler;
import android.os.Looper;
import android.os.PersistableBundle;
-import android.os.SystemClock;
-import android.os.SystemProperties;
import android.os.UserHandle;
import android.os.UserManager;
import android.provider.Settings;
@@ -89,32 +86,17 @@ import com.android.settings.network.ims.WifiCallingQueryImsState;
import com.android.settings.network.telephony.TelephonyConstants.TelephonyManagerConstants;
import com.android.settings.network.telephony.wificalling.WifiCallingRepository;
import com.android.settingslib.core.instrumentation.Instrumentable;
-import com.android.settingslib.development.DevelopmentSettingsEnabler;
import com.android.settingslib.graph.SignalDrawable;
import com.android.settingslib.mobile.dataservice.SubscriptionInfoEntity;
-import com.android.settingslib.utils.ThreadUtils;
-import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
-import java.util.concurrent.ExecutionException;
-import java.util.concurrent.Future;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.TimeoutException;
public class MobileNetworkUtils {
private static final String TAG = "MobileNetworkUtils";
- // CID of the device.
- private static final String KEY_CID = "ro.boot.cid";
- // CIDs of devices which should not show anything related to eSIM.
- private static final String KEY_ESIM_CID_IGNORE = "ro.setupwizard.esim_cid_ignore";
- // System Property which is used to decide whether the default eSIM UI will be shown,
- // the default value is false.
- private static final String KEY_ENABLE_ESIM_UI_BY_DEFAULT =
- "esim.enable_esim_system_ui_by_default";
private static final String LEGACY_ACTION_CONFIGURE_PHONE_ACCOUNT =
"android.telecom.action.CONNECTION_SERVICE_CONFIGURE";
private static final String RTL_MARK = "\u200F";
@@ -282,64 +264,6 @@ public class MobileNetworkUtils {
return intent;
}
- /**
- * Whether to show the entry point to eUICC settings.
- *
- * We show the entry point on any device which supports eUICC as long as either the eUICC
- * was ever provisioned (that is, at least one profile was ever downloaded onto it), or if
- * the user has enabled development mode.
- */
- public static boolean showEuiccSettings(Context context) {
- if (!SubscriptionUtil.isSimHardwareVisible(context)) {
- return false;
- }
- long timeForAccess = SystemClock.elapsedRealtime();
- try {
- Boolean isShow = ((Future) ThreadUtils.postOnBackgroundThread(() -> {
- try {
- return showEuiccSettingsDetecting(context);
- } catch (Exception threadException) {
- Log.w(TAG, "Accessing Euicc failure", threadException);
- }
- return Boolean.FALSE;
- })).get(3, TimeUnit.SECONDS);
- return ((isShow != null) && isShow.booleanValue());
- } catch (ExecutionException | InterruptedException | TimeoutException exception) {
- timeForAccess = SystemClock.elapsedRealtime() - timeForAccess;
- Log.w(TAG, "Accessing Euicc takes too long: +" + timeForAccess + "ms");
- }
- return false;
- }
-
- // The same as #showEuiccSettings(Context context)
- public static Boolean showEuiccSettingsDetecting(Context context) {
- final EuiccManager euiccManager =
- (EuiccManager) context.getSystemService(EuiccManager.class);
- if (euiccManager == null || !euiccManager.isEnabled()) {
- Log.w(TAG, "EuiccManager is not enabled.");
- return false;
- }
-
- final ContentResolver cr = context.getContentResolver();
- final boolean esimIgnoredDevice =
- Arrays.asList(TextUtils.split(SystemProperties.get(KEY_ESIM_CID_IGNORE, ""), ","))
- .contains(SystemProperties.get(KEY_CID));
- final boolean enabledEsimUiByDefault =
- SystemProperties.getBoolean(KEY_ENABLE_ESIM_UI_BY_DEFAULT, true);
- final boolean euiccProvisioned =
- Settings.Global.getInt(cr, Settings.Global.EUICC_PROVISIONED, 0) != 0;
- final boolean inDeveloperMode =
- DevelopmentSettingsEnabler.isDevelopmentSettingsEnabled(context);
- Log.i(TAG,
- String.format("showEuiccSettings: esimIgnoredDevice: %b, enabledEsimUiByDefault: "
- + "%b, euiccProvisioned: %b, inDeveloperMode: %b.",
- esimIgnoredDevice, enabledEsimUiByDefault, euiccProvisioned, inDeveloperMode));
- return (euiccProvisioned
- || (!esimIgnoredDevice && inDeveloperMode)
- || (!esimIgnoredDevice && enabledEsimUiByDefault
- && isCurrentCountrySupported(context)));
- }
-
/**
* Return {@code true} if mobile data is enabled
*/
diff --git a/src/com/android/settings/network/telephony/VideoCallingPreferenceController.java b/src/com/android/settings/network/telephony/VideoCallingPreferenceController.java
deleted file mode 100644
index f803efdc1b0..00000000000
--- a/src/com/android/settings/network/telephony/VideoCallingPreferenceController.java
+++ /dev/null
@@ -1,234 +0,0 @@
-/*
- * Copyright (C) 2018 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.settings.network.telephony;
-
-import android.content.Context;
-import android.content.pm.PackageManager;
-import android.os.PersistableBundle;
-import android.telephony.CarrierConfigManager;
-import android.telephony.SubscriptionManager;
-import android.telephony.TelephonyCallback;
-import android.telephony.TelephonyManager;
-import android.telephony.ims.ImsMmTelManager;
-import android.util.Log;
-
-import androidx.annotation.VisibleForTesting;
-import androidx.preference.Preference;
-import androidx.preference.PreferenceScreen;
-import androidx.preference.TwoStatePreference;
-
-import com.android.internal.telephony.flags.Flags;
-import com.android.settings.network.CarrierConfigCache;
-import com.android.settings.network.MobileDataEnabledListener;
-import com.android.settings.network.ims.VolteQueryImsState;
-import com.android.settings.network.ims.VtQueryImsState;
-import com.android.settingslib.core.lifecycle.LifecycleObserver;
-import com.android.settingslib.core.lifecycle.events.OnStart;
-import com.android.settingslib.core.lifecycle.events.OnStop;
-
-/**
- * Preference controller for "Video Calling"
- */
-public class VideoCallingPreferenceController extends TelephonyTogglePreferenceController implements
- LifecycleObserver, OnStart, OnStop,
- MobileDataEnabledListener.Client,
- Enhanced4gBasePreferenceController.On4gLteUpdateListener {
-
- private static final String TAG = "VideoCallingPreference";
-
- private Preference mPreference;
- private PhoneTelephonyCallback mTelephonyCallback;
- @VisibleForTesting
- Integer mCallState;
- private MobileDataEnabledListener mDataContentObserver;
- private CallingPreferenceCategoryController mCallingPreferenceCategoryController;
-
- public VideoCallingPreferenceController(Context context, String key) {
- super(context, key);
- mDataContentObserver = new MobileDataEnabledListener(context, this);
- mTelephonyCallback = new PhoneTelephonyCallback();
- }
-
- @Override
- public int getAvailabilityStatus(int subId) {
- return SubscriptionManager.isValidSubscriptionId(subId)
- && isVideoCallEnabled(subId)
- ? AVAILABLE
- : CONDITIONALLY_UNAVAILABLE;
- }
-
- @Override
- public void displayPreference(PreferenceScreen screen) {
- super.displayPreference(screen);
- mPreference = screen.findPreference(getPreferenceKey());
- }
-
- @Override
- public void onStart() {
- mTelephonyCallback.register(mContext, mSubId);
- mDataContentObserver.start(mSubId);
- }
-
- @Override
- public void onStop() {
- mTelephonyCallback.unregister();
- mDataContentObserver.stop();
- }
-
- @Override
- public void updateState(Preference preference) {
- super.updateState(preference);
- if ((mCallState == null) || (preference == null)) {
- Log.d(TAG, "Skip update under mCallState=" + mCallState);
- return;
- }
- final TwoStatePreference switchPreference = (TwoStatePreference) preference;
- final boolean videoCallEnabled = isVideoCallEnabled(mSubId);
- switchPreference.setVisible(videoCallEnabled);
- mCallingPreferenceCategoryController
- .updateChildVisible(getPreferenceKey(), videoCallEnabled);
- if (videoCallEnabled) {
- final boolean videoCallEditable = queryVoLteState(mSubId).isEnabledByUser()
- && queryImsState(mSubId).isAllowUserControl();
- preference.setEnabled(videoCallEditable
- && mCallState == TelephonyManager.CALL_STATE_IDLE);
- switchPreference.setChecked(videoCallEditable && isChecked());
- }
- }
-
- @Override
- public boolean setChecked(boolean isChecked) {
- if (!SubscriptionManager.isValidSubscriptionId(mSubId)) {
- return false;
- }
- final ImsMmTelManager imsMmTelManager = ImsMmTelManager.createForSubscriptionId(mSubId);
- if (imsMmTelManager == null) {
- return false;
- }
- try {
- imsMmTelManager.setVtSettingEnabled(isChecked);
- return true;
- } catch (IllegalArgumentException exception) {
- Log.w(TAG, "Unable to set VT status " + isChecked + ". subId=" + mSubId,
- exception);
- }
- return false;
- }
-
- @Override
- public boolean isChecked() {
- return queryImsState(mSubId).isEnabledByUser();
- }
-
- @VisibleForTesting
- protected boolean isImsSupported() {
- return mContext.getPackageManager().hasSystemFeature(
- PackageManager.FEATURE_TELEPHONY_IMS);
- }
-
- /**
- * Init instance of VideoCallingPreferenceController.
- */
- public VideoCallingPreferenceController init(
- int subId, CallingPreferenceCategoryController callingPreferenceCategoryController) {
- mSubId = subId;
- mCallingPreferenceCategoryController = callingPreferenceCategoryController;
-
- return this;
- }
-
- @VisibleForTesting
- boolean isVideoCallEnabled(int subId) {
- if (!SubscriptionManager.isValidSubscriptionId(subId)) {
- return false;
- }
-
- final PersistableBundle carrierConfig =
- CarrierConfigCache.getInstance(mContext).getConfigForSubId(subId);
- if (carrierConfig == null) {
- return false;
- }
-
- if (!carrierConfig.getBoolean(
- CarrierConfigManager.KEY_IGNORE_DATA_ENABLED_CHANGED_FOR_VIDEO_CALLS)
- && (!mContext.getSystemService(TelephonyManager.class)
- .createForSubscriptionId(subId).isDataEnabled())) {
- return false;
- }
-
- return isImsSupported() && queryImsState(subId).isReadyToVideoCall();
- }
-
- @Override
- public void on4gLteUpdated() {
- updateState(mPreference);
- }
-
- private class PhoneTelephonyCallback extends TelephonyCallback implements
- TelephonyCallback.CallStateListener {
-
- private TelephonyManager mTelephonyManager;
-
- @Override
- public void onCallStateChanged(int state) {
- mCallState = state;
- updateState(mPreference);
- }
-
- public void register(Context context, int subId) {
- mTelephonyManager = context.getSystemService(TelephonyManager.class);
- if (SubscriptionManager.isValidSubscriptionId(subId)) {
- mTelephonyManager = mTelephonyManager.createForSubscriptionId(subId);
- }
- // assign current call state so that it helps to show correct preference state even
- // before first onCallStateChanged() by initial registration.
- if (Flags.enforceTelephonyFeatureMappingForPublicApis()) {
- try {
- mCallState = mTelephonyManager.getCallState(subId);
- } catch (UnsupportedOperationException e) {
- // Device doesn't support FEATURE_TELEPHONY_CALLING
- mCallState = TelephonyManager.CALL_STATE_IDLE;
- }
- } else {
- mCallState = mTelephonyManager.getCallState(subId);
- }
- mTelephonyManager.registerTelephonyCallback(context.getMainExecutor(), this);
- }
-
- public void unregister() {
- mCallState = null;
- mTelephonyManager.unregisterTelephonyCallback(this);
- }
- }
-
- /**
- * Implementation of MobileDataEnabledListener.Client
- */
- public void onMobileDataEnabledChange() {
- updateState(mPreference);
- }
-
- @VisibleForTesting
- VtQueryImsState queryImsState(int subId) {
- return new VtQueryImsState(mContext, subId);
- }
-
- @VisibleForTesting
- VolteQueryImsState queryVoLteState(int subId) {
- return new VolteQueryImsState(mContext, subId);
- }
-}
diff --git a/src/com/android/settings/network/telephony/VideoCallingPreferenceController.kt b/src/com/android/settings/network/telephony/VideoCallingPreferenceController.kt
new file mode 100644
index 00000000000..e6b3f315425
--- /dev/null
+++ b/src/com/android/settings/network/telephony/VideoCallingPreferenceController.kt
@@ -0,0 +1,147 @@
+/*
+ * 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.settings.network.telephony
+
+import android.content.Context
+import android.telephony.SubscriptionManager
+import android.telephony.TelephonyManager
+import android.telephony.ims.ImsManager
+import android.util.Log
+import androidx.annotation.VisibleForTesting
+import androidx.lifecycle.LifecycleOwner
+import androidx.preference.Preference
+import androidx.preference.PreferenceScreen
+import androidx.preference.TwoStatePreference
+import com.android.settings.R
+import com.android.settings.core.TogglePreferenceController
+import com.android.settings.network.ims.VolteQueryImsState
+import com.android.settings.network.ims.VtQueryImsState
+import com.android.settings.network.telephony.Enhanced4gBasePreferenceController.On4gLteUpdateListener
+import com.android.settings.network.telephony.MobileNetworkSettingsSearchIndex.MobileNetworkSettingsSearchItem
+import com.android.settings.network.telephony.MobileNetworkSettingsSearchIndex.MobileNetworkSettingsSearchResult
+import com.android.settingslib.spa.framework.util.collectLatestWithLifecycle
+import kotlinx.coroutines.flow.first
+import kotlinx.coroutines.runBlocking
+
+/** Preference controller for "Video Calling" */
+class VideoCallingPreferenceController
+@JvmOverloads
+constructor(
+ context: Context,
+ key: String,
+ private val callStateRepository: CallStateRepository = CallStateRepository(context),
+) : TogglePreferenceController(context, key), On4gLteUpdateListener {
+
+ private var subId = SubscriptionManager.INVALID_SUBSCRIPTION_ID
+ private var preference: TwoStatePreference? = null
+ private var callingPreferenceCategoryController: CallingPreferenceCategoryController? = null
+ private val repository = VideoCallingRepository(context)
+
+ private var videoCallEditable = false
+ private var isInCall = false
+
+ /** Init instance of VideoCallingPreferenceController. */
+ fun init(
+ subId: Int,
+ callingPreferenceCategoryController: CallingPreferenceCategoryController?,
+ ): VideoCallingPreferenceController {
+ this.subId = subId
+ this.callingPreferenceCategoryController = callingPreferenceCategoryController
+
+ return this
+ }
+
+ // Availability is controlled in onViewCreated() and VideoCallingSearchItem.
+ override fun getAvailabilityStatus() = AVAILABLE
+
+ override fun displayPreference(screen: PreferenceScreen) {
+ super.displayPreference(screen)
+ preference = screen.findPreference(preferenceKey)
+ }
+
+ override fun onViewCreated(viewLifecycleOwner: LifecycleOwner) {
+ repository.isVideoCallReadyFlow(subId).collectLatestWithLifecycle(viewLifecycleOwner) {
+ isReady ->
+ preference?.isVisible = isReady
+ callingPreferenceCategoryController?.updateChildVisible(preferenceKey, isReady)
+ }
+ callStateRepository.callStateFlow(subId).collectLatestWithLifecycle(viewLifecycleOwner) {
+ callState ->
+ isInCall = callState != TelephonyManager.CALL_STATE_IDLE
+ updatePreference()
+ }
+ }
+
+ override fun updateState(preference: Preference) {
+ super.updateState(preference)
+ videoCallEditable =
+ queryVoLteState(subId).isEnabledByUser && queryImsState(subId).isAllowUserControl
+ updatePreference()
+ }
+
+ private fun updatePreference() {
+ preference?.isEnabled = videoCallEditable && !isInCall
+ preference?.isChecked = videoCallEditable && isChecked
+ }
+
+ override fun getSliceHighlightMenuRes() = NO_RES
+
+ override fun setChecked(isChecked: Boolean): Boolean {
+ if (!SubscriptionManager.isValidSubscriptionId(subId)) {
+ return false
+ }
+ val imsMmTelManager = ImsManager(mContext).getImsMmTelManager(subId)
+ try {
+ imsMmTelManager.isVtSettingEnabled = isChecked
+ return true
+ } catch (exception: IllegalArgumentException) {
+ Log.w(TAG, "[$subId] Unable to set VT status $isChecked", exception)
+ }
+ return false
+ }
+
+ override fun isChecked(): Boolean = queryImsState(subId).isEnabledByUser
+
+ override fun on4gLteUpdated() {
+ preference?.let { updateState(it) }
+ }
+
+ @VisibleForTesting fun queryImsState(subId: Int) = VtQueryImsState(mContext, subId)
+
+ @VisibleForTesting fun queryVoLteState(subId: Int) = VolteQueryImsState(mContext, subId)
+
+ companion object {
+ private const val TAG = "VideoCallingPreferenceController"
+
+ class VideoCallingSearchItem(private val context: Context) :
+ MobileNetworkSettingsSearchItem {
+ private val repository = VideoCallingRepository(context)
+
+ private fun isAvailable(subId: Int): Boolean = runBlocking {
+ repository.isVideoCallReadyFlow(subId).first()
+ }
+
+ override fun getSearchResult(subId: Int): MobileNetworkSettingsSearchResult? {
+ if (!isAvailable(subId)) return null
+ return MobileNetworkSettingsSearchResult(
+ key = "video_calling_key",
+ title = context.getString(R.string.video_calling_settings_title),
+ )
+ }
+ }
+ }
+}
diff --git a/src/com/android/settings/network/telephony/VideoCallingRepository.kt b/src/com/android/settings/network/telephony/VideoCallingRepository.kt
new file mode 100644
index 00000000000..634eb285cdd
--- /dev/null
+++ b/src/com/android/settings/network/telephony/VideoCallingRepository.kt
@@ -0,0 +1,65 @@
+/*
+ * 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.settings.network.telephony
+
+import android.content.Context
+import android.telephony.AccessNetworkConstants
+import android.telephony.CarrierConfigManager
+import android.telephony.SubscriptionManager
+import android.telephony.ims.feature.MmTelFeature
+import android.telephony.ims.stub.ImsRegistrationImplBase
+import com.android.settings.network.telephony.ims.ImsFeatureRepository
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.flatMapLatest
+import kotlinx.coroutines.flow.flowOf
+
+@OptIn(ExperimentalCoroutinesApi::class)
+class VideoCallingRepository(
+ context: Context,
+ private val mobileDataRepository: MobileDataRepository = MobileDataRepository(context),
+ private val imsFeatureRepositoryFactory: (Int) -> ImsFeatureRepository = { subId ->
+ ImsFeatureRepository(context, subId)
+ },
+) {
+ private val carrierConfigRepository = CarrierConfigRepository(context)
+
+ fun isVideoCallReadyFlow(subId: Int): Flow {
+ if (!SubscriptionManager.isValidSubscriptionId(subId)) return flowOf(false)
+
+ return isPreconditionMeetFlow(subId).flatMapLatest { isPreconditionMeet ->
+ if (isPreconditionMeet) {
+ imsFeatureRepositoryFactory(subId)
+ .isReadyFlow(
+ capability = MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VIDEO,
+ tech = ImsRegistrationImplBase.REGISTRATION_TECH_LTE,
+ transportType = AccessNetworkConstants.TRANSPORT_TYPE_WWAN,
+ )
+ } else {
+ flowOf(false)
+ }
+ }
+ }
+
+ private fun isPreconditionMeetFlow(subId: Int): Flow =
+ if (carrierConfigRepository.getBoolean(
+ subId, CarrierConfigManager.KEY_IGNORE_DATA_ENABLED_CHANGED_FOR_VIDEO_CALLS)) {
+ flowOf(true)
+ } else {
+ mobileDataRepository.isMobileDataEnabledFlow(subId)
+ }
+}
diff --git a/src/com/android/settings/network/telephony/euicc/EuiccRepository.kt b/src/com/android/settings/network/telephony/euicc/EuiccRepository.kt
new file mode 100644
index 00000000000..74b531351b8
--- /dev/null
+++ b/src/com/android/settings/network/telephony/euicc/EuiccRepository.kt
@@ -0,0 +1,129 @@
+/*
+ * 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.settings.network.telephony.euicc
+
+import android.content.Context
+import android.os.SystemProperties
+import android.provider.Settings
+import android.telephony.TelephonyManager
+import android.telephony.euicc.EuiccManager
+import android.util.Log
+import com.android.settings.network.SubscriptionUtil
+import com.android.settingslib.development.DevelopmentSettingsEnabler
+import com.android.settingslib.spaprivileged.settingsprovider.settingsGlobalBoolean
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.flow.conflate
+import kotlinx.coroutines.flow.distinctUntilChanged
+import kotlinx.coroutines.flow.flow
+import kotlinx.coroutines.flow.flowOn
+
+class EuiccRepository
+@JvmOverloads
+constructor(
+ private val context: Context,
+ private val isEuiccProvisioned: () -> Boolean = {
+ val euiccProvisioned by context.settingsGlobalBoolean(Settings.Global.EUICC_PROVISIONED)
+ euiccProvisioned
+ },
+ private val isDevelopmentSettingsEnabled: () -> Boolean = {
+ DevelopmentSettingsEnabler.isDevelopmentSettingsEnabled(context)
+ },
+) {
+
+ private val euiccManager = context.getSystemService(EuiccManager::class.java)
+ private val telephonyManager = context.getSystemService(TelephonyManager::class.java)
+
+ fun showEuiccSettingsFlow() =
+ flow { emit(showEuiccSettings()) }
+ .distinctUntilChanged()
+ .conflate()
+ .flowOn(Dispatchers.Default)
+
+ /**
+ * Whether to show the entry point to eUICC settings.
+ *
+ * We show the entry point on any device which supports eUICC as long as either the eUICC was
+ * ever provisioned (that is, at least one profile was ever downloaded onto it), or if the user
+ * has enabled development mode.
+ */
+ fun showEuiccSettings(): Boolean {
+ if (!SubscriptionUtil.isSimHardwareVisible(context)) return false
+ if (euiccManager == null || !euiccManager.isEnabled) {
+ Log.w(TAG, "EuiccManager is not enabled.")
+ return false
+ }
+ if (isEuiccProvisioned()) {
+ Log.i(TAG, "showEuiccSettings: euicc provisioned")
+ return true
+ }
+ val ignoredCids =
+ SystemProperties.get(KEY_ESIM_CID_IGNORE).split(',').filter { it.isNotEmpty() }
+ val cid = SystemProperties.get(KEY_CID)
+ if (cid in ignoredCids) {
+ Log.i(TAG, "showEuiccSettings: cid ignored")
+ return false
+ }
+ if (isDevelopmentSettingsEnabled()) {
+ Log.i(TAG, "showEuiccSettings: development settings enabled")
+ return true
+ }
+ val enabledEsimUiByDefault =
+ SystemProperties.getBoolean(KEY_ENABLE_ESIM_UI_BY_DEFAULT, true)
+ Log.i(TAG, "showEuiccSettings: enabledEsimUiByDefault=$enabledEsimUiByDefault")
+ return enabledEsimUiByDefault && isCurrentCountrySupported()
+ }
+
+ /**
+ * Loop through all the device logical slots to check whether the user's current country
+ * supports eSIM.
+ */
+ private fun isCurrentCountrySupported(): Boolean {
+ val euiccManager = euiccManager ?: return false
+ val telephonyManager = telephonyManager ?: return false
+ val visitedCountrySet = mutableSetOf()
+ for (slotIndex in 0 until telephonyManager.getActiveModemCount()) {
+ val countryCode = telephonyManager.getNetworkCountryIso(slotIndex)
+ if (
+ countryCode.isNotEmpty() &&
+ visitedCountrySet.add(countryCode) &&
+ euiccManager.isSupportedCountry(countryCode)
+ ) {
+ Log.i(TAG, "isCurrentCountrySupported: $countryCode is supported")
+ return true
+ }
+ }
+ Log.i(TAG, "isCurrentCountrySupported: no country is supported")
+ return false
+ }
+
+ companion object {
+ private const val TAG = "EuiccRepository"
+
+ /** CID of the device. */
+ private const val KEY_CID: String = "ro.boot.cid"
+
+ /** CIDs of devices which should not show anything related to eSIM. */
+ private const val KEY_ESIM_CID_IGNORE: String = "ro.setupwizard.esim_cid_ignore"
+
+ /**
+ * System Property which is used to decide whether the default eSIM UI will be shown, the
+ * default value is false.
+ */
+ private const val KEY_ENABLE_ESIM_UI_BY_DEFAULT: String =
+ "esim.enable_esim_system_ui_by_default"
+ }
+}
diff --git a/src/com/android/settings/notification/modes/ZenModesLinkPreferenceController.java b/src/com/android/settings/notification/modes/ZenModesLinkPreferenceController.java
index aba82c823ec..48a441adec2 100644
--- a/src/com/android/settings/notification/modes/ZenModesLinkPreferenceController.java
+++ b/src/com/android/settings/notification/modes/ZenModesLinkPreferenceController.java
@@ -18,6 +18,7 @@ package com.android.settings.notification.modes;
import android.app.Flags;
import android.content.Context;
+import android.util.Log;
import androidx.preference.Preference;
import androidx.preference.PreferenceScreen;
@@ -30,6 +31,7 @@ import com.android.settingslib.notification.modes.ZenModesBackend;
public class ZenModesLinkPreferenceController extends BasePreferenceController
implements LifecycleObserver, OnStart, OnStop {
+ private static final String TAG = "ModesLinkPrefController";
private final ZenModesBackend mBackend;
private final ZenSettingsObserver mSettingObserver;
@@ -71,7 +73,13 @@ public class ZenModesLinkPreferenceController extends BasePreferenceController
@Override
public void updateState(Preference preference) {
- preference.setSummary(mSummaryBuilder.getModesSummary(mBackend.getModes()));
+ try {
+ preference.setSummary(mSummaryBuilder.getModesSummary(mBackend.getModes()));
+ } catch (SecurityException e) {
+ // Standard usage should have the correct permissions to read zen state. But if we don't
+ // for whatever reason, don't crash.
+ Log.w(TAG, "No permission to read mode state");
+ }
}
@Override
diff --git a/src/com/android/settings/spa/network/SimsSection.kt b/src/com/android/settings/spa/network/SimsSection.kt
index 842656e28bd..276d121c24f 100644
--- a/src/com/android/settings/spa/network/SimsSection.kt
+++ b/src/com/android/settings/spa/network/SimsSection.kt
@@ -40,6 +40,7 @@ import com.android.settings.network.SubscriptionUtil
import com.android.settings.network.telephony.MobileNetworkUtils
import com.android.settings.network.telephony.SubscriptionActivationRepository
import com.android.settings.network.telephony.SubscriptionRepository
+import com.android.settings.network.telephony.euicc.EuiccRepository
import com.android.settings.network.telephony.phoneNumberFlow
import com.android.settingslib.spa.widget.preference.PreferenceModel
import com.android.settingslib.spa.widget.preference.SwitchPreferenceModel
@@ -120,13 +121,17 @@ fun phoneNumber(subInfo: SubscriptionInfo): State {
@Composable
private fun AddSim() {
val context = LocalContext.current
- if (remember { MobileNetworkUtils.showEuiccSettings(context) }) {
+ val isShow by
+ remember { EuiccRepository(context).showEuiccSettingsFlow() }
+ .collectAsStateWithLifecycle(initialValue = false)
+ if (isShow) {
RestrictedPreference(
- model = object : PreferenceModel {
- override val title = stringResource(id = R.string.mobile_network_list_add_more)
- override val icon = @Composable { SettingsIcon(Icons.Outlined.Add) }
- override val onClick = { startAddSimFlow(context) }
- },
+ model =
+ object : PreferenceModel {
+ override val title = stringResource(id = R.string.mobile_network_list_add_more)
+ override val icon = @Composable { SettingsIcon(Icons.Outlined.Add) }
+ override val onClick = { startAddSimFlow(context) }
+ },
restrictions = Restrictions(keys = listOf(UserManager.DISALLOW_CONFIG_MOBILE_NETWORKS)),
)
}
diff --git a/src/com/android/settings/wifi/details2/WifiDetailPreferenceController2.java b/src/com/android/settings/wifi/details2/WifiDetailPreferenceController2.java
index 9992cc047c2..927d2ee93e6 100644
--- a/src/com/android/settings/wifi/details2/WifiDetailPreferenceController2.java
+++ b/src/com/android/settings/wifi/details2/WifiDetailPreferenceController2.java
@@ -556,6 +556,7 @@ public class WifiDetailPreferenceController2 extends AbstractPreferenceControlle
return mContext.getDrawable(getHotspotIconResource(deviceType));
}
if (mWifiEntry.getLevel() == WifiEntry.WIFI_LEVEL_UNREACHABLE) {
+ Log.w(TAG, "WiFi level is WIFI_LEVEL_UNREACHABLE(-1)");
return mContext.getDrawable(R.drawable.empty_icon);
}
return mIconInjector.getIcon(wifiEntry.shouldShowXLevelIcon(), wifiEntry.getLevel());
diff --git a/tests/robotests/src/com/android/settings/connecteddevice/ConnectedDeviceDashboardFragmentTest.java b/tests/robotests/src/com/android/settings/connecteddevice/ConnectedDeviceDashboardFragmentTest.java
index 33292af8cb5..ecf6d003cef 100644
--- a/tests/robotests/src/com/android/settings/connecteddevice/ConnectedDeviceDashboardFragmentTest.java
+++ b/tests/robotests/src/com/android/settings/connecteddevice/ConnectedDeviceDashboardFragmentTest.java
@@ -36,7 +36,6 @@ import com.android.settings.R;
import com.android.settings.connecteddevice.fastpair.FastPairDeviceUpdater;
import com.android.settings.core.BasePreferenceController;
import com.android.settings.core.PreferenceControllerListHelper;
-import com.android.settings.flags.Flags;
import com.android.settings.slices.SlicePreferenceController;
import com.android.settings.testutils.FakeFeatureFactory;
import com.android.settings.testutils.shadow.ShadowBluetoothAdapter;
@@ -94,7 +93,6 @@ public class ConnectedDeviceDashboardFragmentTest {
mContext = spy(RuntimeEnvironment.application);
mFragment = new ConnectedDeviceDashboardFragment();
- mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_SUBSEQUENT_PAIR_SETTINGS_INTEGRATION);
mSetFlagsRule.enableFlags(com.android.settingslib.flags.Flags.FLAG_ENABLE_LE_AUDIO_SHARING);
mFeatureFactory = FakeFeatureFactory.setupForTest();
when(mFeatureFactory
diff --git a/tests/robotests/src/com/android/settings/connecteddevice/fastpair/FastPairDeviceGroupControllerTest.java b/tests/robotests/src/com/android/settings/connecteddevice/fastpair/FastPairDeviceGroupControllerTest.java
index 25e927b14e2..2b140ea4e1e 100644
--- a/tests/robotests/src/com/android/settings/connecteddevice/fastpair/FastPairDeviceGroupControllerTest.java
+++ b/tests/robotests/src/com/android/settings/connecteddevice/fastpair/FastPairDeviceGroupControllerTest.java
@@ -33,8 +33,6 @@ import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.os.Looper;
-import android.platform.test.annotations.RequiresFlagsDisabled;
-import android.platform.test.annotations.RequiresFlagsEnabled;
import android.platform.test.flag.junit.CheckFlagsRule;
import android.platform.test.flag.junit.DeviceFlagsValueProvider;
@@ -45,7 +43,6 @@ import androidx.preference.PreferenceManager;
import androidx.preference.PreferenceScreen;
import com.android.settings.dashboard.DashboardFragment;
-import com.android.settings.flags.Flags;
import com.android.settings.testutils.FakeFeatureFactory;
import com.android.settings.testutils.shadow.ShadowBluetoothAdapter;
import com.android.settings.widget.GearPreference;
@@ -107,7 +104,6 @@ public class FastPairDeviceGroupControllerTest {
}
@Test
- @RequiresFlagsEnabled(Flags.FLAG_ENABLE_SUBSEQUENT_PAIR_SETTINGS_INTEGRATION)
public void onStart_flagOn_registerCallback() {
// register the callback in onStart()
mFastPairDeviceGroupController.onStart(mLifecycleOwner);
@@ -120,7 +116,6 @@ public class FastPairDeviceGroupControllerTest {
}
@Test
- @RequiresFlagsEnabled(Flags.FLAG_ENABLE_SUBSEQUENT_PAIR_SETTINGS_INTEGRATION)
public void onStop_flagOn_unregisterCallback() {
// register broadcast first
mContext.registerReceiver(
@@ -133,51 +128,6 @@ public class FastPairDeviceGroupControllerTest {
}
@Test
- @RequiresFlagsDisabled(Flags.FLAG_ENABLE_SUBSEQUENT_PAIR_SETTINGS_INTEGRATION)
- public void onStart_flagOff_registerCallback() {
- // register the callback in onStart()
- mFastPairDeviceGroupController.onStart(mLifecycleOwner);
- assertThat(mFastPairDeviceUpdater).isNull();
- verify(mContext)
- .registerReceiver(
- mFastPairDeviceGroupController.mReceiver,
- mFastPairDeviceGroupController.mIntentFilter,
- Context.RECEIVER_EXPORTED);
- }
-
- @Test
- @RequiresFlagsDisabled(Flags.FLAG_ENABLE_SUBSEQUENT_PAIR_SETTINGS_INTEGRATION)
- public void onStop_flagOff_unregisterCallback() {
- // register broadcast first
- mContext.registerReceiver(
- mFastPairDeviceGroupController.mReceiver, null, Context.RECEIVER_EXPORTED);
-
- // unregister the callback in onStop()
- mFastPairDeviceGroupController.onStop(mLifecycleOwner);
- assertThat(mFastPairDeviceUpdater).isNull();
- verify(mContext).unregisterReceiver(mFastPairDeviceGroupController.mReceiver);
- }
-
- @Test
- @RequiresFlagsDisabled(Flags.FLAG_ENABLE_SUBSEQUENT_PAIR_SETTINGS_INTEGRATION)
- public void getAvailabilityStatus_noFastPairFeature_returnUnSupported() {
- doReturn(true).when(mPackageManager).hasSystemFeature(PackageManager.FEATURE_BLUETOOTH);
-
- assertThat(mFastPairDeviceGroupController.getAvailabilityStatus())
- .isEqualTo(UNSUPPORTED_ON_DEVICE);
- }
-
- @Test
- @RequiresFlagsDisabled(Flags.FLAG_ENABLE_SUBSEQUENT_PAIR_SETTINGS_INTEGRATION)
- public void getAvailabilityStatus_noBluetoothFastPairFeature_returnUnSupported() {
- doReturn(false).when(mPackageManager).hasSystemFeature(PackageManager.FEATURE_BLUETOOTH);
-
- assertThat(mFastPairDeviceGroupController.getAvailabilityStatus())
- .isEqualTo(UNSUPPORTED_ON_DEVICE);
- }
-
- @Test
- @RequiresFlagsEnabled(Flags.FLAG_ENABLE_SUBSEQUENT_PAIR_SETTINGS_INTEGRATION)
public void getAvailabilityStatus_noBluetoothFeature_returnUnSupported() {
doReturn(false).when(mPackageManager).hasSystemFeature(PackageManager.FEATURE_BLUETOOTH);
@@ -186,7 +136,6 @@ public class FastPairDeviceGroupControllerTest {
}
@Test
- @RequiresFlagsEnabled(Flags.FLAG_ENABLE_SUBSEQUENT_PAIR_SETTINGS_INTEGRATION)
public void getAvailabilityStatus_withBluetoothFastPairFeature_returnSupported() {
doReturn(true).when(mPackageManager).hasSystemFeature(PackageManager.FEATURE_BLUETOOTH);
@@ -231,14 +180,6 @@ public class FastPairDeviceGroupControllerTest {
}
@Test
- @RequiresFlagsDisabled(Flags.FLAG_ENABLE_SUBSEQUENT_PAIR_SETTINGS_INTEGRATION)
- public void displayPreference_notAvailable_doNothing() {
- mFastPairDeviceGroupController.displayPreference(mScreen);
- assertThat(mPreferenceGroup.isVisible()).isFalse();
- }
-
- @Test
- @RequiresFlagsEnabled(Flags.FLAG_ENABLE_SUBSEQUENT_PAIR_SETTINGS_INTEGRATION)
public void displayPreference_isAvailable_fetchFastPairDevices() {
doReturn(true).when(mPackageManager).hasSystemFeature(PackageManager.FEATURE_BLUETOOTH);
diff --git a/tests/robotests/src/com/android/settings/connecteddevice/fastpair/FastPairDevicePreferenceControllerTest.java b/tests/robotests/src/com/android/settings/connecteddevice/fastpair/FastPairDevicePreferenceControllerTest.java
index be2ed564811..8a84e2399f2 100644
--- a/tests/robotests/src/com/android/settings/connecteddevice/fastpair/FastPairDevicePreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/connecteddevice/fastpair/FastPairDevicePreferenceControllerTest.java
@@ -32,8 +32,6 @@ import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.os.Looper;
-import android.platform.test.annotations.RequiresFlagsDisabled;
-import android.platform.test.annotations.RequiresFlagsEnabled;
import android.platform.test.flag.junit.CheckFlagsRule;
import android.platform.test.flag.junit.DeviceFlagsValueProvider;
@@ -44,7 +42,6 @@ import androidx.preference.PreferenceGroup;
import androidx.preference.PreferenceManager;
import com.android.settings.dashboard.DashboardFragment;
-import com.android.settings.flags.Flags;
import com.android.settings.testutils.FakeFeatureFactory;
import com.android.settings.testutils.shadow.ShadowBluetoothAdapter;
import com.android.settings.widget.GearPreference;
@@ -108,7 +105,6 @@ public class FastPairDevicePreferenceControllerTest {
}
@Test
- @RequiresFlagsEnabled(Flags.FLAG_ENABLE_SUBSEQUENT_PAIR_SETTINGS_INTEGRATION)
public void onStart_flagOn_registerCallback() {
// register the callback in onStart()
mFastPairDevicePrefController.onStart(mLifecycleOwner);
@@ -121,20 +117,6 @@ public class FastPairDevicePreferenceControllerTest {
}
@Test
- @RequiresFlagsDisabled(Flags.FLAG_ENABLE_SUBSEQUENT_PAIR_SETTINGS_INTEGRATION)
- public void onStart_flagOff_registerCallback() {
- // register the callback in onStart()
- mFastPairDevicePrefController.onStart(mLifecycleOwner);
- assertThat(mFastPairDeviceUpdater).isNull();
- verify(mContext)
- .registerReceiver(
- mFastPairDevicePrefController.mReceiver,
- mFastPairDevicePrefController.mIntentFilter,
- Context.RECEIVER_EXPORTED_UNAUDITED);
- }
-
- @Test
- @RequiresFlagsEnabled(Flags.FLAG_ENABLE_SUBSEQUENT_PAIR_SETTINGS_INTEGRATION)
public void onStop_flagOn_unregisterCallback() {
// register broadcast first
mContext.registerReceiver(
@@ -147,20 +129,6 @@ public class FastPairDevicePreferenceControllerTest {
}
@Test
- @RequiresFlagsDisabled(Flags.FLAG_ENABLE_SUBSEQUENT_PAIR_SETTINGS_INTEGRATION)
- public void onStop_flagOff_unregisterCallback() {
- // register broadcast first
- mContext.registerReceiver(
- mFastPairDevicePrefController.mReceiver, null, Context.RECEIVER_EXPORTED_UNAUDITED);
-
- // unregister the callback in onStop()
- mFastPairDevicePrefController.onStop(mLifecycleOwner);
- assertThat(mFastPairDeviceUpdater).isNull();
- verify(mContext).unregisterReceiver(mFastPairDevicePrefController.mReceiver);
- }
-
- @Test
- @RequiresFlagsEnabled(Flags.FLAG_ENABLE_SUBSEQUENT_PAIR_SETTINGS_INTEGRATION)
public void getAvailabilityStatus_noBluetoothFeature_returnUnsupported() {
doReturn(false).when(mPackageManager).hasSystemFeature(PackageManager.FEATURE_BLUETOOTH);
@@ -169,25 +137,6 @@ public class FastPairDevicePreferenceControllerTest {
}
@Test
- @RequiresFlagsDisabled(Flags.FLAG_ENABLE_SUBSEQUENT_PAIR_SETTINGS_INTEGRATION)
- public void getAvailabilityStatus_noFastPairFeature_returnUnsupported() {
- doReturn(true).when(mPackageManager).hasSystemFeature(PackageManager.FEATURE_BLUETOOTH);
-
- assertThat(mFastPairDevicePrefController.getAvailabilityStatus())
- .isEqualTo(UNSUPPORTED_ON_DEVICE);
- }
-
- @Test
- @RequiresFlagsDisabled(Flags.FLAG_ENABLE_SUBSEQUENT_PAIR_SETTINGS_INTEGRATION)
- public void getAvailabilityStatus_noBluetoothFastPairFeature_returnUnsupported() {
- doReturn(false).when(mPackageManager).hasSystemFeature(PackageManager.FEATURE_BLUETOOTH);
-
- assertThat(mFastPairDevicePrefController.getAvailabilityStatus())
- .isEqualTo(UNSUPPORTED_ON_DEVICE);
- }
-
- @Test
- @RequiresFlagsEnabled(Flags.FLAG_ENABLE_SUBSEQUENT_PAIR_SETTINGS_INTEGRATION)
public void getAvailabilityStatus_bothBluetoothFastPairFeature_returnSupported() {
doReturn(true).when(mPackageManager).hasSystemFeature(PackageManager.FEATURE_BLUETOOTH);
diff --git a/tests/robotests/src/com/android/settings/dashboard/suggestions/SuggestionFeatureProviderImplTest.java b/tests/robotests/src/com/android/settings/dashboard/suggestions/SuggestionFeatureProviderImplTest.java
index 0c8af12db29..6d2193cb760 100644
--- a/tests/robotests/src/com/android/settings/dashboard/suggestions/SuggestionFeatureProviderImplTest.java
+++ b/tests/robotests/src/com/android/settings/dashboard/suggestions/SuggestionFeatureProviderImplTest.java
@@ -25,12 +25,19 @@ import android.content.Context;
import android.content.pm.ActivityInfo;
import android.content.pm.PackageManager;
import android.hardware.fingerprint.FingerprintManager;
+import android.platform.test.annotations.DisableFlags;
+import android.platform.test.annotations.EnableFlags;
+import android.platform.test.flag.junit.SetFlagsRule;
import android.service.settings.suggestions.Suggestion;
+import androidx.fragment.app.Fragment;
+
+import com.android.settings.flags.Flags;
import com.android.settings.testutils.FakeFeatureFactory;
import com.android.settings.testutils.shadow.ShadowSecureSettings;
import org.junit.Before;
+import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
@@ -43,6 +50,9 @@ import org.robolectric.annotation.Config;
@Config(shadows = ShadowSecureSettings.class)
public class SuggestionFeatureProviderImplTest {
+ @Rule
+ public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
+
@Mock
private Context mContext;
@Mock
@@ -94,4 +104,20 @@ public class SuggestionFeatureProviderImplTest {
when(mActivityManager.isLowRamDevice()).thenReturn(false);
assertThat(mProvider.isSuggestionEnabled(mContext)).isTrue();
}
+
+ @DisableFlags(Flags.FLAG_UPDATED_SUGGESTION_CARD_AOSP)
+ @Test
+ public void getSuggestionFragment_withFlagDisabled_shouldReturnNull() {
+ Class extends Fragment> fragment = mProvider.getSuggestionFragment();
+
+ assertThat(fragment).isNull();
+ }
+
+ @EnableFlags(Flags.FLAG_UPDATED_SUGGESTION_CARD_AOSP)
+ @Test
+ public void getSuggestionFragment_withFlagEnabled_shouldReturnFragment() {
+ Class extends Fragment> fragment = mProvider.getSuggestionFragment();
+
+ assertThat(fragment).isEqualTo(SuggestionFragment.class);
+ }
}
diff --git a/tests/robotests/src/com/android/settings/homepage/SettingsHomepageActivityTest.java b/tests/robotests/src/com/android/settings/homepage/SettingsHomepageActivityTest.java
index 31ac9446612..2cf93e4fb3b 100644
--- a/tests/robotests/src/com/android/settings/homepage/SettingsHomepageActivityTest.java
+++ b/tests/robotests/src/com/android/settings/homepage/SettingsHomepageActivityTest.java
@@ -444,7 +444,7 @@ public class SettingsHomepageActivityTest {
public static class ShadowSuggestionFeatureProviderImpl {
@Implementation
- public Class extends Fragment> getContextualSuggestionFragment() {
+ public Class extends Fragment> getSuggestionFragment() {
return Fragment.class;
}
}
diff --git a/tests/robotests/src/com/android/settings/network/ims/MockVolteQueryImsState.java b/tests/robotests/src/com/android/settings/network/ims/MockVolteQueryImsState.java
deleted file mode 100644
index 515ab5b659b..00000000000
--- a/tests/robotests/src/com/android/settings/network/ims/MockVolteQueryImsState.java
+++ /dev/null
@@ -1,105 +0,0 @@
-/*
- * Copyright (C) 2020 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.settings.network.ims;
-
-import android.content.Context;
-import android.telephony.ims.ImsException;
-
-/**
- * Controller class for mock VoLte status
- */
-public class MockVolteQueryImsState extends VolteQueryImsState {
-
- private Boolean mIsTtyOnVolteEnabled;
- private Boolean mIsSupported;
- private Boolean mIsProvisionedOnDevice;
- private Boolean mIsServiceStateReady;
- private Boolean mIsEnabledByUser;
-
- /**
- * Constructor
- *
- * @param context {@link Context}
- * @param subId subscription's id
- */
- public MockVolteQueryImsState(Context context, int subId) {
- super(context, subId);
- }
-
- public void setIsTtyOnVolteEnabled(boolean enabled) {
- mIsTtyOnVolteEnabled = enabled;
- }
-
- @Override
- boolean isTtyOnVolteEnabled(int subId) {
- if (mIsTtyOnVolteEnabled != null) {
- return mIsTtyOnVolteEnabled;
- }
- return super.isTtyOnVolteEnabled(subId);
- }
-
- public void setEnabledByPlatform(boolean isSupported) {
- mIsSupported = isSupported;
- }
-
- @Override
- boolean isEnabledByPlatform(int subId) throws InterruptedException, ImsException,
- IllegalArgumentException {
- if (mIsSupported != null) {
- return mIsSupported;
- }
- return super.isEnabledByPlatform(subId);
- }
-
- public void setIsProvisionedOnDevice(boolean isProvisioned) {
- mIsProvisionedOnDevice = isProvisioned;
- }
-
- @Override
- boolean isProvisionedOnDevice(int subId) {
- if (mIsProvisionedOnDevice != null) {
- return mIsProvisionedOnDevice;
- }
- return super.isProvisionedOnDevice(subId);
- }
-
- public void setServiceStateReady(boolean isReady) {
- mIsServiceStateReady = isReady;
- }
-
- @Override
- boolean isServiceStateReady(int subId) throws InterruptedException, ImsException,
- IllegalArgumentException {
- if (mIsServiceStateReady != null) {
- return mIsServiceStateReady;
- }
- return super.isServiceStateReady(subId);
- }
-
- public void setIsEnabledByUser(boolean enabled) {
- mIsEnabledByUser = enabled;
- }
-
- @Override
- boolean isEnabledByUser(int subId) {
- if (mIsEnabledByUser != null) {
- return mIsEnabledByUser;
- }
- return super.isEnabledByUser(subId);
- }
-
-}
diff --git a/tests/robotests/src/com/android/settings/network/ims/MockVtQueryImsState.java b/tests/robotests/src/com/android/settings/network/ims/MockVtQueryImsState.java
deleted file mode 100644
index 0949f1c0262..00000000000
--- a/tests/robotests/src/com/android/settings/network/ims/MockVtQueryImsState.java
+++ /dev/null
@@ -1,104 +0,0 @@
-/*
- * Copyright (C) 2020 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.settings.network.ims;
-
-import android.content.Context;
-import android.telephony.ims.ImsException;
-
-/**
- * Controller class for mock VT status
- */
-public class MockVtQueryImsState extends VtQueryImsState {
-
- private Boolean mIsTtyOnVolteEnabled;
- private Boolean mIsEnabledOnPlatform;
- private Boolean mIsProvisionedOnDevice;
- private Boolean mIsEnabledByUser;
- private Boolean mIsServiceStateReady;
-
- /**
- * Constructor
- *
- * @param context {@link Context}
- * @param subId subscription's id
- */
- public MockVtQueryImsState(Context context, int subId) {
- super(context, subId);
- }
-
- public void setIsTtyOnVolteEnabled(boolean enabled) {
- mIsTtyOnVolteEnabled = enabled;
- }
-
- @Override
- boolean isTtyOnVolteEnabled(int subId) {
- if (mIsTtyOnVolteEnabled != null) {
- return mIsTtyOnVolteEnabled;
- }
- return super.isTtyOnVolteEnabled(subId);
- }
-
- public void setIsEnabledByPlatform(boolean isEnabled) {
- mIsEnabledOnPlatform = isEnabled;
- }
-
- @Override
- boolean isEnabledByPlatform(int subId) throws InterruptedException, ImsException,
- IllegalArgumentException {
- if (mIsEnabledOnPlatform != null) {
- return mIsEnabledOnPlatform;
- }
- return super.isEnabledByPlatform(subId);
- }
-
- public void setIsProvisionedOnDevice(boolean isProvisioned) {
- mIsProvisionedOnDevice = isProvisioned;
- }
-
- @Override
- boolean isProvisionedOnDevice(int subId) {
- if (mIsProvisionedOnDevice != null) {
- return mIsProvisionedOnDevice;
- }
- return super.isProvisionedOnDevice(subId);
- }
-
- public void setServiceStateReady(boolean isReady) {
- mIsServiceStateReady = isReady;
- }
-
- @Override
- boolean isServiceStateReady(int subId) throws InterruptedException, ImsException,
- IllegalArgumentException {
- if (mIsServiceStateReady != null) {
- return mIsServiceStateReady;
- }
- return super.isServiceStateReady(subId);
- }
-
- public void setIsEnabledByUser(boolean enabled) {
- mIsEnabledByUser = enabled;
- }
-
- @Override
- boolean isEnabledByUser(int subId) {
- if (mIsEnabledByUser != null) {
- return mIsEnabledByUser;
- }
- return super.isEnabledByUser(subId);
- }
-}
diff --git a/tests/robotests/src/com/android/settings/network/telephony/VideoCallingPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/network/telephony/VideoCallingPreferenceControllerTest.java
deleted file mode 100644
index da8958dff2e..00000000000
--- a/tests/robotests/src/com/android/settings/network/telephony/VideoCallingPreferenceControllerTest.java
+++ /dev/null
@@ -1,160 +0,0 @@
-/*
- * Copyright (C) 2018 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.settings.network.telephony;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import static org.mockito.ArgumentMatchers.anyInt;
-import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.spy;
-
-import android.content.Context;
-import android.os.PersistableBundle;
-import android.telephony.CarrierConfigManager;
-import android.telephony.TelephonyManager;
-import android.telephony.ims.ProvisioningManager;
-
-import androidx.preference.PreferenceScreen;
-import androidx.preference.SwitchPreference;
-
-import com.android.settings.network.CarrierConfigCache;
-import com.android.settings.network.ims.MockVolteQueryImsState;
-import com.android.settings.network.ims.MockVtQueryImsState;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-import org.robolectric.RobolectricTestRunner;
-import org.robolectric.RuntimeEnvironment;
-
-@RunWith(RobolectricTestRunner.class)
-public class VideoCallingPreferenceControllerTest {
- private static final int SUB_ID = 2;
-
- @Mock
- private TelephonyManager mTelephonyManager;
- @Mock
- private ProvisioningManager mProvisioningManager;
- @Mock
- private CarrierConfigCache mCarrierConfigCache;
- @Mock
- private PreferenceScreen mPreferenceScreen;
-
- private MockVtQueryImsState mQueryImsState;
- private MockVolteQueryImsState mQueryVoLteState;
-
- private VideoCallingPreferenceController mController;
- private PersistableBundle mCarrierConfig;
- private SwitchPreference mPreference;
- private Context mContext;
-
- @Before
- public void setUp() throws Exception {
- MockitoAnnotations.initMocks(this);
-
- mContext = spy(RuntimeEnvironment.application);
- doReturn(mTelephonyManager).when(mContext).getSystemService(TelephonyManager.class);
- CarrierConfigCache.setTestInstance(mContext, mCarrierConfigCache);
- doReturn(mTelephonyManager).when(mTelephonyManager).createForSubscriptionId(SUB_ID);
-
- mCarrierConfig = new PersistableBundle();
- mCarrierConfig.putBoolean(
- CarrierConfigManager.KEY_IGNORE_DATA_ENABLED_CHANGED_FOR_VIDEO_CALLS, true);
- doReturn(mCarrierConfig).when(mCarrierConfigCache).getConfigForSubId(SUB_ID);
-
- mQueryImsState = new MockVtQueryImsState(mContext, SUB_ID);
- mQueryImsState.setIsEnabledByUser(true);
-
- mQueryVoLteState = new MockVolteQueryImsState(mContext, SUB_ID);
- mQueryVoLteState.setIsEnabledByUser(true);
-
- mPreference = new SwitchPreference(mContext);
- mController = spy(new VideoCallingPreferenceController(mContext, "wifi_calling"));
- mController.init(
- SUB_ID, new CallingPreferenceCategoryController(mContext, "calling_category"));
- doReturn(mQueryImsState).when(mController).queryImsState(anyInt());
- doReturn(mQueryVoLteState).when(mController).queryVoLteState(anyInt());
- doReturn(true).when(mController).isImsSupported();
- mPreference.setKey(mController.getPreferenceKey());
-
- mQueryImsState.setIsEnabledByPlatform(true);
- mQueryImsState.setIsProvisionedOnDevice(true);
- mQueryImsState.setServiceStateReady(true);
- doReturn(true).when(mTelephonyManager).isDataEnabled();
-
- mController.mCallState = TelephonyManager.CALL_STATE_IDLE;
- }
-
- @Test
- public void isVideoCallEnabled_allFlagsOn_returnTrue() {
- assertThat(mController.isVideoCallEnabled(SUB_ID)).isTrue();
- }
-
- @Test
- public void isVideoCallEnabled_disabledByPlatform_returnFalse() {
- mQueryImsState.setIsProvisionedOnDevice(false);
- mQueryImsState.setIsEnabledByPlatform(false);
-
- assertThat(mController.isVideoCallEnabled(SUB_ID)).isFalse();
- }
-
- @Test
- public void isVideoCallEnabled_dataDisabled_returnFalse() {
- mCarrierConfig.putBoolean(
- CarrierConfigManager.KEY_IGNORE_DATA_ENABLED_CHANGED_FOR_VIDEO_CALLS, false);
- doReturn(false).when(mTelephonyManager).isDataEnabled();
-
- assertThat(mController.isVideoCallEnabled(SUB_ID)).isFalse();
- }
-
- @Test
- public void updateState_4gLteOff_disabled() {
- mQueryImsState.setIsEnabledByUser(false);
- mQueryVoLteState.setIsEnabledByUser(false);
-
- mController.updateState(mPreference);
-
- assertThat(mPreference.isEnabled()).isFalse();
- assertThat(mPreference.isChecked()).isFalse();
- }
-
- @Test
- public void updateState_4gLteOnWithoutCall_checked() {
- mQueryImsState.setIsEnabledByUser(true);
- mQueryVoLteState.setIsEnabledByUser(true);
- mQueryImsState.setIsTtyOnVolteEnabled(true);
- mController.mCallState = TelephonyManager.CALL_STATE_IDLE;
-
- mController.updateState(mPreference);
-
- assertThat(mPreference.isEnabled()).isTrue();
- assertThat(mPreference.isChecked()).isTrue();
- }
-
-
- @Test
- public void displayPreference_notAvailable_setPreferenceInvisible() {
- mQueryImsState.setIsEnabledByPlatform(false);
-
- mController.displayPreference(mPreferenceScreen);
-
- assertThat(mPreferenceScreen.isVisible()).isFalse();
- }
-
-}
diff --git a/tests/spa_unit/src/com/android/settings/network/telephony/VideoCallingPreferenceControllerTest.kt b/tests/spa_unit/src/com/android/settings/network/telephony/VideoCallingPreferenceControllerTest.kt
new file mode 100644
index 00000000000..4babfaae301
--- /dev/null
+++ b/tests/spa_unit/src/com/android/settings/network/telephony/VideoCallingPreferenceControllerTest.kt
@@ -0,0 +1,125 @@
+/*
+ * 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.settings.network.telephony
+
+import android.content.Context
+import android.telephony.TelephonyManager
+import androidx.lifecycle.testing.TestLifecycleOwner
+import androidx.preference.PreferenceManager
+import androidx.preference.SwitchPreferenceCompat
+import androidx.test.core.app.ApplicationProvider
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import com.android.settings.network.ims.VolteQueryImsState
+import com.android.settings.network.ims.VtQueryImsState
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.delay
+import kotlinx.coroutines.flow.flowOf
+import kotlinx.coroutines.runBlocking
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.kotlin.doReturn
+import org.mockito.kotlin.mock
+import org.mockito.kotlin.spy
+import org.mockito.kotlin.stub
+
+@RunWith(AndroidJUnit4::class)
+class VideoCallingPreferenceControllerTest {
+
+ private val mockVtQueryImsState = mock {}
+
+ private var mockQueryVoLteState = mock {}
+
+ private val context: Context = ApplicationProvider.getApplicationContext()
+
+ private val mockCallStateRepository = mock {}
+
+ private var controller =
+ spy(
+ VideoCallingPreferenceController(
+ context = context,
+ key = TEST_KEY,
+ callStateRepository = mockCallStateRepository,
+ )
+ ) {
+ on { queryImsState(SUB_ID) } doReturn mockVtQueryImsState
+ on { queryVoLteState(SUB_ID) } doReturn mockQueryVoLteState
+ }
+
+ private val preference = SwitchPreferenceCompat(context).apply { key = TEST_KEY }
+ private val preferenceScreen = PreferenceManager(context).createPreferenceScreen(context)
+
+ @Before
+ fun setUp() {
+ controller.init(SUB_ID, CallingPreferenceCategoryController(context, "calling_category"))
+ preferenceScreen.addPreference(preference)
+ controller.displayPreference(preferenceScreen)
+ }
+
+ @Test
+ fun updateState_4gLteOff_disabledAndUnchecked() {
+ mockQueryVoLteState.stub { on { isEnabledByUser } doReturn false }
+
+ controller.updateState(preference)
+
+ assertThat(preference.isEnabled).isFalse()
+ assertThat(preference.isChecked).isFalse()
+ }
+
+ @Test
+ fun updateState_4gLteOnWithoutCall_enabledAndChecked() = runBlocking {
+ mockVtQueryImsState.stub {
+ on { isEnabledByUser } doReturn true
+ on { isAllowUserControl } doReturn true
+ }
+ mockQueryVoLteState.stub { on { isEnabledByUser } doReturn true }
+ mockCallStateRepository.stub {
+ on { callStateFlow(SUB_ID) } doReturn flowOf(TelephonyManager.CALL_STATE_IDLE)
+ }
+
+ controller.onViewCreated(TestLifecycleOwner())
+ delay(100)
+ controller.updateState(preference)
+
+ assertThat(preference.isEnabled).isTrue()
+ assertThat(preference.isChecked).isTrue()
+ }
+
+ @Test
+ fun updateState_4gLteOnWithCall_disabledAndChecked() = runBlocking {
+ mockVtQueryImsState.stub {
+ on { isEnabledByUser } doReturn true
+ on { isAllowUserControl } doReturn true
+ }
+ mockQueryVoLteState.stub { on { isEnabledByUser } doReturn true }
+ mockCallStateRepository.stub {
+ on { callStateFlow(SUB_ID) } doReturn flowOf(TelephonyManager.CALL_STATE_RINGING)
+ }
+
+ controller.onViewCreated(TestLifecycleOwner())
+ delay(100)
+ controller.updateState(preference)
+
+ assertThat(preference.isEnabled).isFalse()
+ assertThat(preference.isChecked).isTrue()
+ }
+
+ private companion object {
+ const val TEST_KEY = "test_key"
+ const val SUB_ID = 10
+ }
+}
diff --git a/tests/spa_unit/src/com/android/settings/network/telephony/VideoCallingRepositoryTest.kt b/tests/spa_unit/src/com/android/settings/network/telephony/VideoCallingRepositoryTest.kt
new file mode 100644
index 00000000000..063e1918a89
--- /dev/null
+++ b/tests/spa_unit/src/com/android/settings/network/telephony/VideoCallingRepositoryTest.kt
@@ -0,0 +1,166 @@
+/*
+ * 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.settings.network.telephony
+
+import android.content.Context
+import android.telephony.AccessNetworkConstants
+import android.telephony.CarrierConfigManager
+import android.telephony.SubscriptionManager
+import android.telephony.ims.feature.MmTelFeature
+import android.telephony.ims.stub.ImsRegistrationImplBase
+import androidx.test.core.app.ApplicationProvider
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import com.android.settings.network.telephony.ims.ImsFeatureRepository
+import com.android.settingslib.spa.testutils.firstWithTimeoutOrNull
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.flow.flowOf
+import kotlinx.coroutines.runBlocking
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.kotlin.doReturn
+import org.mockito.kotlin.mock
+import org.mockito.kotlin.stub
+
+@RunWith(AndroidJUnit4::class)
+class VideoCallingRepositoryTest {
+
+ private val context: Context = ApplicationProvider.getApplicationContext()
+
+ private val mockMobileDataRepository = mock()
+ private val mockImsFeatureRepository = mock()
+
+ private val repository =
+ VideoCallingRepository(
+ context = context,
+ mobileDataRepository = mockMobileDataRepository,
+ imsFeatureRepositoryFactory = { mockImsFeatureRepository },
+ )
+
+ @Before
+ fun setUp() {
+ CarrierConfigRepository.resetForTest()
+ }
+
+ @Test
+ fun isVideoCallReadyFlow_invalidSubId() = runBlocking {
+ val isVideoCallReady =
+ repository
+ .isVideoCallReadyFlow(subId = SubscriptionManager.INVALID_SUBSCRIPTION_ID)
+ .firstWithTimeoutOrNull()
+
+ assertThat(isVideoCallReady).isFalse()
+ }
+
+ @Test
+ fun isVideoCallReadyFlow_ignoreDataEnabledChangedAndIsReady_returnTrue() = runBlocking {
+ CarrierConfigRepository.setBooleanForTest(
+ subId = SUB_ID,
+ key = CarrierConfigManager.KEY_IGNORE_DATA_ENABLED_CHANGED_FOR_VIDEO_CALLS,
+ value = true,
+ )
+ mockImsFeatureRepository.stub {
+ on {
+ isReadyFlow(
+ capability = MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VIDEO,
+ tech = ImsRegistrationImplBase.REGISTRATION_TECH_LTE,
+ transportType = AccessNetworkConstants.TRANSPORT_TYPE_WWAN,
+ )
+ } doReturn flowOf(true)
+ }
+
+ val isVideoCallReady = repository.isVideoCallReadyFlow(SUB_ID).firstWithTimeoutOrNull()
+
+ assertThat(isVideoCallReady).isTrue()
+ }
+
+ @Test
+ fun isVideoCallReadyFlow_ignoreDataEnabledChangedAndNotReady_returnFalse() = runBlocking {
+ CarrierConfigRepository.setBooleanForTest(
+ subId = SUB_ID,
+ key = CarrierConfigManager.KEY_IGNORE_DATA_ENABLED_CHANGED_FOR_VIDEO_CALLS,
+ value = true,
+ )
+ mockImsFeatureRepository.stub {
+ on {
+ isReadyFlow(
+ capability = MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VIDEO,
+ tech = ImsRegistrationImplBase.REGISTRATION_TECH_LTE,
+ transportType = AccessNetworkConstants.TRANSPORT_TYPE_WWAN,
+ )
+ } doReturn flowOf(false)
+ }
+
+ val isVideoCallReady = repository.isVideoCallReadyFlow(SUB_ID).firstWithTimeoutOrNull()
+
+ assertThat(isVideoCallReady).isFalse()
+ }
+
+ @Test
+ fun isVideoCallReadyFlow_mobileDataEnabledAndIsReady_returnTrue() = runBlocking {
+ CarrierConfigRepository.setBooleanForTest(
+ subId = SUB_ID,
+ key = CarrierConfigManager.KEY_IGNORE_DATA_ENABLED_CHANGED_FOR_VIDEO_CALLS,
+ value = false,
+ )
+ mockMobileDataRepository.stub {
+ on { isMobileDataEnabledFlow(SUB_ID) } doReturn flowOf(true)
+ }
+ mockImsFeatureRepository.stub {
+ on {
+ isReadyFlow(
+ capability = MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VIDEO,
+ tech = ImsRegistrationImplBase.REGISTRATION_TECH_LTE,
+ transportType = AccessNetworkConstants.TRANSPORT_TYPE_WWAN,
+ )
+ } doReturn flowOf(true)
+ }
+
+ val isVideoCallReady = repository.isVideoCallReadyFlow(SUB_ID).firstWithTimeoutOrNull()
+
+ assertThat(isVideoCallReady).isTrue()
+ }
+
+ @Test
+ fun isVideoCallReadyFlow_ignoreDataEnabledChangedAndIsReady_returnFalse() = runBlocking {
+ CarrierConfigRepository.setBooleanForTest(
+ subId = SUB_ID,
+ key = CarrierConfigManager.KEY_IGNORE_DATA_ENABLED_CHANGED_FOR_VIDEO_CALLS,
+ value = false,
+ )
+ mockMobileDataRepository.stub {
+ on { isMobileDataEnabledFlow(SUB_ID) } doReturn flowOf(false)
+ }
+ mockImsFeatureRepository.stub {
+ on {
+ isReadyFlow(
+ capability = MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VIDEO,
+ tech = ImsRegistrationImplBase.REGISTRATION_TECH_LTE,
+ transportType = AccessNetworkConstants.TRANSPORT_TYPE_WWAN,
+ )
+ } doReturn flowOf(true)
+ }
+
+ val isVideoCallReady = repository.isVideoCallReadyFlow(SUB_ID).firstWithTimeoutOrNull()
+
+ assertThat(isVideoCallReady).isFalse()
+ }
+
+ private companion object {
+ const val SUB_ID = 10
+ }
+}
diff --git a/tests/spa_unit/src/com/android/settings/network/telephony/euicc/EuiccRepositoryTest.kt b/tests/spa_unit/src/com/android/settings/network/telephony/euicc/EuiccRepositoryTest.kt
new file mode 100644
index 00000000000..24e6fd6ac16
--- /dev/null
+++ b/tests/spa_unit/src/com/android/settings/network/telephony/euicc/EuiccRepositoryTest.kt
@@ -0,0 +1,117 @@
+/*
+ * 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.settings.network.telephony.euicc
+
+import android.content.Context
+import android.telephony.TelephonyManager
+import android.telephony.euicc.EuiccManager
+import androidx.test.core.app.ApplicationProvider
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import com.android.settings.R
+import com.google.common.truth.Truth.assertThat
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.kotlin.any
+import org.mockito.kotlin.doReturn
+import org.mockito.kotlin.mock
+import org.mockito.kotlin.spy
+import org.mockito.kotlin.stub
+
+@RunWith(AndroidJUnit4::class)
+class EuiccRepositoryTest {
+
+ private val mockEuiccManager = mock { on { isEnabled } doReturn true }
+
+ private val mockTelephonyManager =
+ mock {
+ on { activeModemCount } doReturn 1
+ on { getNetworkCountryIso(any()) } doReturn COUNTRY_CODE
+ }
+
+ private val context: Context =
+ spy(ApplicationProvider.getApplicationContext()) {
+ on { getSystemService(EuiccManager::class.java) } doReturn mockEuiccManager
+ on { getSystemService(TelephonyManager::class.java) } doReturn mockTelephonyManager
+ }
+
+ private val resources =
+ spy(context.resources) { on { getBoolean(R.bool.config_show_sim_info) } doReturn true }
+
+ private var euiccProvisioned = false
+
+ private val repository =
+ EuiccRepository(
+ context,
+ isEuiccProvisioned = { euiccProvisioned },
+ isDevelopmentSettingsEnabled = { false },
+ )
+
+ @Before
+ fun setUp() {
+ context.stub { on { resources } doReturn resources }
+ }
+
+ @Test
+ fun showEuiccSettings_noSim_returnFalse() {
+ resources.stub { on { getBoolean(R.bool.config_show_sim_info) } doReturn false }
+
+ val showEuiccSettings = repository.showEuiccSettings()
+
+ assertThat(showEuiccSettings).isFalse()
+ }
+
+ @Test
+ fun showEuiccSettings_euiccDisabled_returnFalse() {
+ mockEuiccManager.stub { on { isEnabled } doReturn false }
+
+ val showEuiccSettings = repository.showEuiccSettings()
+
+ assertThat(showEuiccSettings).isFalse()
+ }
+
+ @Test
+ fun showEuiccSettings_euiccProvisioned_returnTrue() {
+ euiccProvisioned = true
+
+ val showEuiccSettings = repository.showEuiccSettings()
+
+ assertThat(showEuiccSettings).isTrue()
+ }
+
+ @Test
+ fun showEuiccSettings_countryNotSupported_returnFalse() {
+ mockEuiccManager.stub { on { isSupportedCountry(COUNTRY_CODE) } doReturn false }
+
+ val showEuiccSettings = repository.showEuiccSettings()
+
+ assertThat(showEuiccSettings).isFalse()
+ }
+
+ @Test
+ fun showEuiccSettings_countrySupported_returnTrue() {
+ mockEuiccManager.stub { on { isSupportedCountry(COUNTRY_CODE) } doReturn true }
+
+ val showEuiccSettings = repository.showEuiccSettings()
+
+ assertThat(showEuiccSettings).isTrue()
+ }
+
+ private companion object {
+ const val COUNTRY_CODE = "us"
+ }
+}
diff --git a/tests/unit/src/com/android/settings/network/ims/MockVtQueryImsState.java b/tests/unit/src/com/android/settings/network/ims/MockVtQueryImsState.java
deleted file mode 100644
index 0949f1c0262..00000000000
--- a/tests/unit/src/com/android/settings/network/ims/MockVtQueryImsState.java
+++ /dev/null
@@ -1,104 +0,0 @@
-/*
- * Copyright (C) 2020 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.settings.network.ims;
-
-import android.content.Context;
-import android.telephony.ims.ImsException;
-
-/**
- * Controller class for mock VT status
- */
-public class MockVtQueryImsState extends VtQueryImsState {
-
- private Boolean mIsTtyOnVolteEnabled;
- private Boolean mIsEnabledOnPlatform;
- private Boolean mIsProvisionedOnDevice;
- private Boolean mIsEnabledByUser;
- private Boolean mIsServiceStateReady;
-
- /**
- * Constructor
- *
- * @param context {@link Context}
- * @param subId subscription's id
- */
- public MockVtQueryImsState(Context context, int subId) {
- super(context, subId);
- }
-
- public void setIsTtyOnVolteEnabled(boolean enabled) {
- mIsTtyOnVolteEnabled = enabled;
- }
-
- @Override
- boolean isTtyOnVolteEnabled(int subId) {
- if (mIsTtyOnVolteEnabled != null) {
- return mIsTtyOnVolteEnabled;
- }
- return super.isTtyOnVolteEnabled(subId);
- }
-
- public void setIsEnabledByPlatform(boolean isEnabled) {
- mIsEnabledOnPlatform = isEnabled;
- }
-
- @Override
- boolean isEnabledByPlatform(int subId) throws InterruptedException, ImsException,
- IllegalArgumentException {
- if (mIsEnabledOnPlatform != null) {
- return mIsEnabledOnPlatform;
- }
- return super.isEnabledByPlatform(subId);
- }
-
- public void setIsProvisionedOnDevice(boolean isProvisioned) {
- mIsProvisionedOnDevice = isProvisioned;
- }
-
- @Override
- boolean isProvisionedOnDevice(int subId) {
- if (mIsProvisionedOnDevice != null) {
- return mIsProvisionedOnDevice;
- }
- return super.isProvisionedOnDevice(subId);
- }
-
- public void setServiceStateReady(boolean isReady) {
- mIsServiceStateReady = isReady;
- }
-
- @Override
- boolean isServiceStateReady(int subId) throws InterruptedException, ImsException,
- IllegalArgumentException {
- if (mIsServiceStateReady != null) {
- return mIsServiceStateReady;
- }
- return super.isServiceStateReady(subId);
- }
-
- public void setIsEnabledByUser(boolean enabled) {
- mIsEnabledByUser = enabled;
- }
-
- @Override
- boolean isEnabledByUser(int subId) {
- if (mIsEnabledByUser != null) {
- return mIsEnabledByUser;
- }
- return super.isEnabledByUser(subId);
- }
-}