diff --git a/res/drawable/ic_pin_outline.xml b/res/drawable/ic_pin_outline.xml new file mode 100644 index 00000000000..d7e5f71ebcd --- /dev/null +++ b/res/drawable/ic_pin_outline.xml @@ -0,0 +1,25 @@ + + + + diff --git a/res/values/strings.xml b/res/values/strings.xml index fc4d7536524..0c5bedca93d 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -1358,6 +1358,10 @@ Skip setup for pattern and fingerprint? Skip setup for pattern, face, and fingerprint? + + Resume animation + + Pause animation Set up screen lock @@ -5934,6 +5938,10 @@ Pair hearing device You can pair ASHA and LE Audio hearing devices on this page. Make sure your hearing device is turned on and ready to pair. + + You can pair ASHA hearing devices on this page. Make sure your hearing device is turned on and ready to pair. + + You can pair LE Audio hearing devices on this page. Make sure your hearing device is turned on and ready to pair. Available hearing devices @@ -12764,6 +12772,10 @@ Data usage charges may apply. see all apps Supported apps on your phone + + Can\u2019t add a SIM + + End the satellite connection before you add a SIM Access Point Names diff --git a/res/xml/hearing_device_pairing_fragment.xml b/res/xml/hearing_device_pairing_fragment.xml index d84f22bd5d7..782d7c0cdc5 100644 --- a/res/xml/hearing_device_pairing_fragment.xml +++ b/res/xml/hearing_device_pairing_fragment.xml @@ -20,8 +20,10 @@ android:title="@string/bluetooth_pairing_pref_title"> + android:title="@string/accessibility_hearing_device_pairing_intro" + settings:controller="com.android.settings.accessibility.HearingDevicePairingIntroPreferenceController"/> 0) { scrollToPreference(fpPrefKey); addFingerprintUnlockCategory(); } @@ -1266,6 +1271,16 @@ public class FingerprintSettings extends SubSettings { } } + + if (mFingerprintUnlockCategoryPreferenceController == null + && getExtPreferenceProvider().getSize() > 0 && controllers != null) { + for (AbstractPreferenceController controller : controllers) { + if (KEY_FINGERPRINT_UNLOCK_CATEGORY.equals(controller.getPreferenceKey())) { + mFingerprintUnlockCategoryPreferenceController = + (FingerprintUnlockCategoryController) controller; + } + } + } return controllers; } @@ -1654,7 +1669,10 @@ public class FingerprintSettings extends SubSettings { private static final String KEY_USER_ID = "user_id"; private static final String KEY_SENSOR_PROPERTIES = "sensor_properties"; + private static final String EXTRA_FAILURE_COUNT = "failure_count"; + private static final int MAX_FAILURE_COUNT = 3; private int mUserId; + private int mFailureCount; private @Nullable CancellationSignal mCancellationSignal; private @Nullable FingerprintSensorPropertiesInternal mSensorPropertiesInternal; @@ -1663,6 +1681,9 @@ public class FingerprintSettings extends SubSettings { @NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { + if (savedInstanceState != null) { + mFailureCount = savedInstanceState.getInt(EXTRA_FAILURE_COUNT, 0); + } return inflater.inflate( R.layout.fingerprint_check_enrolled_dialog, container, false); } @@ -1682,12 +1703,22 @@ public class FingerprintSettings extends SubSettings { final UdfpsCheckEnrolledView v = dialog.findViewById(R.id.udfps_check_enrolled_view); v.setSensorProperties(mSensorPropertiesInternal); + v.setOnTouchListener((view, event) -> { + Log.d(TAG, "CheckEnrollDialog dismissed: touch outside"); + dialog.dismiss(); + return false; + }); }); } - return dialog; } + @Override + public void onSaveInstanceState(@NonNull Bundle outState) { + super.onSaveInstanceState(outState); + outState.putInt(EXTRA_FAILURE_COUNT, mFailureCount); + } + @Override public void onStart() { super.onStart(); @@ -1752,6 +1783,11 @@ public class FingerprintSettings extends SubSettings { message.postDelayed(() -> { message.setText(R.string.fingerprint_check_enroll_touch_sensor); }, 2000); + mFailureCount++; + if (mFailureCount >= MAX_FAILURE_COUNT) { + Log.d(TAG, "CheckEnrollDialog dismissed: failed 3 times"); + dialog.dismiss(); + } } }, null /* handler */, diff --git a/src/com/android/settings/biometrics/fingerprint/UdfpsCheckEnrolledView.java b/src/com/android/settings/biometrics/fingerprint/UdfpsCheckEnrolledView.java index 52a28c75ea1..028fccd44db 100644 --- a/src/com/android/settings/biometrics/fingerprint/UdfpsCheckEnrolledView.java +++ b/src/com/android/settings/biometrics/fingerprint/UdfpsCheckEnrolledView.java @@ -24,6 +24,7 @@ import android.util.AttributeSet; import android.util.Log; import android.util.RotationUtils; import android.view.DisplayInfo; +import android.view.MotionEvent; import android.view.Surface; import android.widget.ImageView; import android.widget.RelativeLayout; @@ -61,6 +62,13 @@ public class UdfpsCheckEnrolledView extends RelativeLayout { super.onFinishInflate(); mFingerprintView = findViewById(R.id.udfps_fingerprint_sensor_view); mFingerprintView.setImageDrawable(mFingerprintDrawable); + mFingerprintView.setOnTouchListener((v, event) -> { + if (event.getAction() == MotionEvent.ACTION_DOWN) { + Log.d(TAG, "Fingerprint view touched!"); + return true; + } + return false; + }); } /** diff --git a/src/com/android/settings/biometrics/fingerprint/feature/FingerprintExtPreferencesProvider.kt b/src/com/android/settings/biometrics/fingerprint/feature/FingerprintExtPreferencesProvider.kt index 1e3b38c3f5e..c88e1669950 100644 --- a/src/com/android/settings/biometrics/fingerprint/feature/FingerprintExtPreferencesProvider.kt +++ b/src/com/android/settings/biometrics/fingerprint/feature/FingerprintExtPreferencesProvider.kt @@ -27,14 +27,13 @@ import com.android.settingslib.RestrictedPreference * * @see com.android.settings.biometrics.fingerprint.FingerprintSettings */ -open class FingerprintExtPreferencesProvider { +open class FingerprintExtPreferencesProvider(protected val context: Context) { open val size: Int = 0 open fun newPreference( index: Int, inflater: PreferenceInflater, - context: Context ): RestrictedPreference? = null interface PreferenceInflater { diff --git a/src/com/android/settings/bluetooth/BluetoothDeviceDetailsFragment.java b/src/com/android/settings/bluetooth/BluetoothDeviceDetailsFragment.java index 66c39d63108..2ba5fd8850e 100644 --- a/src/com/android/settings/bluetooth/BluetoothDeviceDetailsFragment.java +++ b/src/com/android/settings/bluetooth/BluetoothDeviceDetailsFragment.java @@ -60,6 +60,8 @@ import com.android.settingslib.core.AbstractPreferenceController; import com.android.settingslib.core.instrumentation.MetricsFeatureProvider; import com.android.settingslib.core.lifecycle.Lifecycle; +import com.google.common.collect.ImmutableList; + import java.util.ArrayList; import java.util.List; import java.util.function.Consumer; @@ -417,13 +419,17 @@ public class BluetoothDeviceDetailsFragment extends BluetoothDetailsConfigurable @Nullable private List generateDisplayedPreferenceKeys(boolean bondingLoss) { if (bondingLoss) { - return List.of( - use(BluetoothDetailsBannerController.class).getPreferenceKey(), - use(AdvancedBluetoothDetailsHeaderController.class).getPreferenceKey(), - use(BluetoothDetailsHeaderController.class).getPreferenceKey(), - use(LeAudioBluetoothDetailsHeaderController.class).getPreferenceKey(), - use(BluetoothDetailsButtonsController.class).getPreferenceKey(), - use(BluetoothDetailsMacAddressController.class).getPreferenceKey()); + ImmutableList.Builder visibleKeys = new ImmutableList.Builder<>(); + visibleKeys + .add(use(BluetoothDetailsBannerController.class).getPreferenceKey()) + .add(use(AdvancedBluetoothDetailsHeaderController.class).getPreferenceKey()) + .add(use(BluetoothDetailsHeaderController.class).getPreferenceKey()) + .add(use(LeAudioBluetoothDetailsHeaderController.class).getPreferenceKey()) + .add(use(BluetoothDetailsButtonsController.class).getPreferenceKey()); + if (!BluetoothUtils.isHeadset(mCachedDevice.getDevice())) { + visibleKeys.add(use(BluetoothDetailsMacAddressController.class).getPreferenceKey()); + } + return visibleKeys.build(); } return null; } diff --git a/src/com/android/settings/bluetooth/BluetoothDevicePreference.java b/src/com/android/settings/bluetooth/BluetoothDevicePreference.java index d5f5cb06854..f716d974716 100644 --- a/src/com/android/settings/bluetooth/BluetoothDevicePreference.java +++ b/src/com/android/settings/bluetooth/BluetoothDevicePreference.java @@ -296,6 +296,10 @@ public final class BluetoothDevicePreference extends GearPreference { void onPreferenceAttributesChanged() { try { ThreadUtils.postOnBackgroundThread(() -> { + if (mCachedDevice.getDevice() != null) { + Log.d(TAG, "onPreferenceAttributesChanged, start updating for device " + + mCachedDevice.getDevice().getAnonymizedAddress()); + } @Nullable String name = mCachedDevice.getName(); // Null check is done at the framework @Nullable String connectionSummary = getConnectionSummary(); @@ -325,6 +329,7 @@ public final class BluetoothDevicePreference extends GearPreference { notifyHierarchyChanged(); } }); + Log.d(TAG, "onPreferenceAttributesChanged, complete updating for device " + name); }); } catch (RejectedExecutionException e) { Log.w(TAG, "Handler thread unavailable, skipping getConnectionSummary!"); diff --git a/src/com/android/settings/connecteddevice/AvailableMediaDeviceGroupController.java b/src/com/android/settings/connecteddevice/AvailableMediaDeviceGroupController.java index b6ca425aa17..5074a3cba94 100644 --- a/src/com/android/settings/connecteddevice/AvailableMediaDeviceGroupController.java +++ b/src/com/android/settings/connecteddevice/AvailableMediaDeviceGroupController.java @@ -335,6 +335,7 @@ public class AvailableMediaDeviceGroupController extends BasePreferenceControlle var unused = ThreadUtils.postOnBackgroundThread( () -> { + Log.d(TAG, "updateTitle, check current status"); int titleResId; if (isAudioModeOngoingCall(mContext)) { // in phone call @@ -347,6 +348,7 @@ public class AvailableMediaDeviceGroupController extends BasePreferenceControlle // without phone call, not audio sharing titleResId = R.string.connected_device_media_device_title; } + Log.d(TAG, "updateTitle, title = " + titleResId); mContext.getMainExecutor() .execute( () -> { diff --git a/src/com/android/settings/connecteddevice/ConnectedDeviceDashboardFragment.java b/src/com/android/settings/connecteddevice/ConnectedDeviceDashboardFragment.java index 65258fc7257..36c7a4af137 100644 --- a/src/com/android/settings/connecteddevice/ConnectedDeviceDashboardFragment.java +++ b/src/com/android/settings/connecteddevice/ConnectedDeviceDashboardFragment.java @@ -17,6 +17,7 @@ package com.android.settings.connecteddevice; import android.app.settings.SettingsEnums; import android.content.Context; +import android.content.Intent; import android.net.Uri; import android.text.TextUtils; import android.util.Log; @@ -34,18 +35,25 @@ import com.android.settings.search.BaseSearchIndexProvider; import com.android.settings.slices.SlicePreferenceController; import com.android.settingslib.bluetooth.BluetoothUtils; import com.android.settingslib.bluetooth.HearingAidStatsLogUtils; + +import com.android.settingslib.core.instrumentation.MetricsFeatureProvider; import com.android.settingslib.search.SearchIndexable; @SearchIndexable(forTarget = SearchIndexable.ALL & ~SearchIndexable.ARC) public class ConnectedDeviceDashboardFragment extends DashboardFragment { private static final String TAG = "ConnectedDeviceFrag"; - private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); - private static final String SLICE_ACTION = "com.android.settings.SEARCH_RESULT_TRAMPOLINE"; - + private static final String SETTINGS_SEARCH_ACTION = + "com.android.settings.SEARCH_RESULT_TRAMPOLINE"; @VisibleForTesting static final String KEY_CONNECTED_DEVICES = "connected_device_list"; @VisibleForTesting static final String KEY_AVAILABLE_DEVICES = "available_device_list"; + private static final String ENTRYPOINT_SYSUI = "bt_settings_entrypoint_sysui"; + private static final String ENTRYPOINT_SETTINGS = "bt_settings_entrypoint_settings_click"; + private static final String ENTRYPOINT_SETTINGS_SEARCH = + "bt_settings_entrypoint_settings_search"; + private static final String ENTRYPOINT_OTHER = "bt_settings_entrypoint_other"; + @Override public int getMetricsCategory() { return SettingsEnums.SETTINGS_CONNECTED_DEVICE_CATEGORY; @@ -71,15 +79,16 @@ public class ConnectedDeviceDashboardFragment extends DashboardFragment { super.onAttach(context); String callingAppPackageName = ((SettingsActivity) getActivity()).getInitialCallingPackage(); - String action = getIntent() != null ? getIntent().getAction() : ""; - if (DEBUG) { - Log.d( - TAG, - "onAttach() calling package name is : " - + callingAppPackageName - + ", action : " - + action); - } + Intent intent = getIntent(); + String action = intent != null ? intent.getAction() : ""; + + Log.d( + TAG, + "onAttach() calling package name is : " + + callingAppPackageName + + ", action : " + + action); + if (BluetoothUtils.isAudioSharingUIAvailable(context)) { use(AudioSharingDevicePreferenceController.class).init(this); } @@ -100,16 +109,51 @@ public class ConnectedDeviceDashboardFragment extends DashboardFragment { provider.sendActivityIfAvailable(category); } } + + logPageEntrypoint(context, callingAppPackageName, intent); } @VisibleForTesting boolean isAlwaysDiscoverable(String callingAppPackageName, String action) { - return TextUtils.equals(SLICE_ACTION, action) + return TextUtils.equals(SETTINGS_SEARCH_ACTION, action) ? false : TextUtils.equals(Utils.SETTINGS_PACKAGE_NAME, callingAppPackageName) || TextUtils.equals(Utils.SYSTEMUI_PACKAGE_NAME, callingAppPackageName); } + private void logPageEntrypoint(Context context, String callingAppPackageName, Intent intent) { + String action = intent != null ? intent.getAction() : ""; + if (TextUtils.equals(Utils.SYSTEMUI_PACKAGE_NAME, callingAppPackageName)) { + mMetricsFeatureProvider.action( + context, SettingsEnums.SETTINGS_CONNECTED_DEVICES_ENTRYPOINT, ENTRYPOINT_SYSUI); + } else if (TextUtils.equals(Utils.SETTINGS_PACKAGE_NAME, callingAppPackageName) + && TextUtils.equals(Intent.ACTION_MAIN, action)) { + String sourceCategory = + intent != null + ? Integer.toString( + getIntent() + .getIntExtra( + MetricsFeatureProvider + .EXTRA_SOURCE_METRICS_CATEGORY, + SettingsEnums.PAGE_UNKNOWN)) + : ""; + mMetricsFeatureProvider.action( + context, + SettingsEnums.SETTINGS_CONNECTED_DEVICES_ENTRYPOINT, + ENTRYPOINT_SETTINGS + "_" + sourceCategory); + } else if (TextUtils.equals(Utils.SETTINGS_PACKAGE_NAME, callingAppPackageName) + && TextUtils.equals(SETTINGS_SEARCH_ACTION, action)) { + mMetricsFeatureProvider.action( + context, + SettingsEnums.SETTINGS_CONNECTED_DEVICES_ENTRYPOINT, + ENTRYPOINT_SETTINGS_SEARCH); + + } else { + mMetricsFeatureProvider.action( + context, SettingsEnums.SETTINGS_CONNECTED_DEVICES_ENTRYPOINT, ENTRYPOINT_OTHER); + } + } + /** For Search. */ public static final BaseSearchIndexProvider SEARCH_INDEX_DATA_PROVIDER = new BaseSearchIndexProvider(R.xml.connected_devices); diff --git a/src/com/android/settings/localepicker/LocalePickerWithRegionActivity.java b/src/com/android/settings/localepicker/LocalePickerWithRegionActivity.java index 9f67251e6bb..ab5017868a3 100644 --- a/src/com/android/settings/localepicker/LocalePickerWithRegionActivity.java +++ b/src/com/android/settings/localepicker/LocalePickerWithRegionActivity.java @@ -18,6 +18,14 @@ package com.android.settings.localepicker; import static android.window.OnBackInvokedDispatcher.PRIORITY_DEFAULT; +import static com.android.settings.regionalpreferences.RegionDialogFragment.ARG_CALLING_PAGE; +import static com.android.settings.regionalpreferences.RegionDialogFragment.CALLING_PAGE_LANGUAGE_CHOOSE_A_REGION; +import static com.android.settings.regionalpreferences.RegionDialogFragment.DIALOG_CHANGE_SYSTEM_LOCALE_REGION; +import static com.android.settings.regionalpreferences.RegionDialogFragment.DIALOG_CHANGE_PREFERRED_LOCALE_REGION; +import static com.android.settings.regionalpreferences.RegionDialogFragment.ARG_DIALOG_TYPE; +import static com.android.settings.regionalpreferences.RegionDialogFragment.ARG_TARGET_LOCALE; +import static com.android.settings.regionalpreferences.RegionDialogFragment.ARG_REPLACED_TARGET_LOCALE; + import android.app.FragmentTransaction; import android.content.Intent; import android.os.Bundle; @@ -50,11 +58,6 @@ public class LocalePickerWithRegionActivity extends SettingsBaseActivity private static final String TAG = LocalePickerWithRegionActivity.class.getSimpleName(); private static final String PARENT_FRAGMENT_NAME = "localeListEditor"; private static final String CHILD_FRAGMENT_NAME = "LocalePickerWithRegion"; - private static final int DIALOG_CHANGE_SYSTEM_LOCALE_REGION = 1; - private static final int DIALOG_CHANGE_PREFERRED_LOCALE_REGION = 2; - private static final String ARG_DIALOG_TYPE = "arg_dialog_type"; - private static final String ARG_TARGET_LOCALE = "arg_target_locale"; - private static final String ARG_REPLACED_TARGET_LOCALE = "arg_replaced_target_locale"; private static final String TAG_DIALOG_CHANGE_REGION = "dialog_change_region"; private static final int DISPOSE = -1; private static final int SHOW_DIALOG_FOR_SYSTEM_LANGUAGE = 0; @@ -139,6 +142,7 @@ public class LocalePickerWithRegionActivity extends SettingsBaseActivity LocaleStore.LocaleInfo locale, FragmentManager fragmentManager) { Bundle args = new Bundle(); args.putInt(ARG_DIALOG_TYPE, DIALOG_CHANGE_SYSTEM_LOCALE_REGION); + args.putInt(ARG_CALLING_PAGE, CALLING_PAGE_LANGUAGE_CHOOSE_A_REGION); args.putSerializable(ARG_TARGET_LOCALE, locale); RegionDialogFragment regionDialogFragment = RegionDialogFragment.newInstance(); regionDialogFragment.setArguments(args); @@ -149,6 +153,7 @@ public class LocalePickerWithRegionActivity extends SettingsBaseActivity LocaleStore.LocaleInfo locale, Locale replacedLocale, FragmentManager fragmentManager) { Bundle args = new Bundle(); args.putInt(ARG_DIALOG_TYPE, DIALOG_CHANGE_PREFERRED_LOCALE_REGION); + args.putInt(ARG_CALLING_PAGE, CALLING_PAGE_LANGUAGE_CHOOSE_A_REGION); args.putSerializable(ARG_TARGET_LOCALE, locale); args.putSerializable(ARG_REPLACED_TARGET_LOCALE, replacedLocale); RegionDialogFragment regionDialogFragment = RegionDialogFragment.newInstance(); diff --git a/src/com/android/settings/network/AdaptiveMobileNetworkTogglePreference.kt b/src/com/android/settings/network/AdaptiveMobileNetworkTogglePreference.kt index 2b6ec916dc3..c2c2c445e80 100644 --- a/src/com/android/settings/network/AdaptiveMobileNetworkTogglePreference.kt +++ b/src/com/android/settings/network/AdaptiveMobileNetworkTogglePreference.kt @@ -16,11 +16,11 @@ package com.android.settings.network -import android.app.settings.SettingsEnums.ACTION_ADAPTIVE_CONNECTIVITY +import android.app.settings.SettingsEnums.ACTION_ADAPTIVE_MOBILE_NETWORK import android.content.Context import android.provider.Settings.Secure.ADAPTIVE_CONNECTIVITY_MOBILE_NETWORK_ENABLED import com.android.settings.R -import com.android.settings.contract.KEY_ADAPTIVE_CONNECTIVITY +import com.android.settings.contract.KEY_ADAPTIVE_MOBILE_NETWORK import com.android.settings.metrics.PreferenceActionMetricsProvider import com.android.settingslib.datastore.KeyValueStore import com.android.settingslib.datastore.KeyValueStoreDelegate @@ -38,12 +38,12 @@ class AdaptiveMobileNetworkTogglePreference() : PreferenceActionMetricsProvider { override val preferenceActionMetrics: Int - get() = ACTION_ADAPTIVE_CONNECTIVITY + get() = ACTION_ADAPTIVE_MOBILE_NETWORK override val key: String get() = KEY - override fun tags(context: Context) = arrayOf(KEY_ADAPTIVE_CONNECTIVITY) + override fun tags(context: Context) = arrayOf(KEY_ADAPTIVE_MOBILE_NETWORK) override fun storage(context: Context): KeyValueStore = AdaptiveMobileNetworkToggleStorage(context) diff --git a/src/com/android/settings/network/MobileNetworkListScreen.kt b/src/com/android/settings/network/MobileNetworkListScreen.kt index 18dc8970123..ebbe9758999 100644 --- a/src/com/android/settings/network/MobileNetworkListScreen.kt +++ b/src/com/android/settings/network/MobileNetworkListScreen.kt @@ -25,6 +25,7 @@ import androidx.preference.Preference.OnPreferenceClickListener import com.android.settings.R import com.android.settings.flags.Flags import com.android.settings.network.AirplaneModePreference.Companion.isAirplaneModeOn +import com.android.settings.network.SatelliteRepository.Companion.isSatelliteOn import com.android.settings.network.SubscriptionUtil.getUniqueSubscriptionDisplayName import com.android.settings.network.telephony.SimRepository import com.android.settings.network.telephony.SubscriptionRepository @@ -32,6 +33,7 @@ import com.android.settings.network.telephony.euicc.EuiccRepository import com.android.settings.restriction.PreferenceRestrictionMixin import com.android.settings.spa.network.getAddSimIntent import com.android.settings.spa.network.startAddSimFlow +import com.android.settings.spa.network.startSatelliteWarningDialogFlow import com.android.settingslib.RestrictedPreference import com.android.settingslib.datastore.HandlerExecutor import com.android.settingslib.datastore.KeyedObserver @@ -120,7 +122,11 @@ class MobileNetworkListScreen : val summary = preference.summary ?: return true // no-op val context = preference.context if (summary == context.getString(R.string.mobile_network_summary_add_a_network)) { - startAddSimFlow(context) // start intent + if (isSatelliteOn(context, 3000)) { + startSatelliteWarningDialogFlow(context) // start intent + } else { + startAddSimFlow(context) // start intent + } return true } return false // start fragment diff --git a/src/com/android/settings/network/MobileNetworkSummaryController.kt b/src/com/android/settings/network/MobileNetworkSummaryController.kt index 62c57661809..850a08dc0c7 100644 --- a/src/com/android/settings/network/MobileNetworkSummaryController.kt +++ b/src/com/android/settings/network/MobileNetworkSummaryController.kt @@ -27,6 +27,7 @@ import com.android.settings.dashboard.DashboardFragment import com.android.settings.network.telephony.SimRepository import com.android.settings.overlay.FeatureFactory.Companion.featureFactory import com.android.settings.spa.network.startAddSimFlow +import com.android.settings.spa.network.startSatelliteWarningDialogFlow import com.android.settingslib.RestrictedPreference import com.android.settingslib.spa.framework.util.collectLatestWithLifecycle import com.android.settingslib.spaprivileged.settingsprovider.settingsGlobalBooleanFlow @@ -51,11 +52,13 @@ constructor( MobileNetworkSummaryRepository(context), private val airplaneModeOnFlow: Flow = context.settingsGlobalBooleanFlow(Settings.Global.AIRPLANE_MODE_ON), + private val satelliteIsStartedFlow: Flow = SatelliteRepository(context).getIsSessionStartedFlow() ) : BasePreferenceController(context, preferenceKey) { private val metricsFeatureProvider = featureFactory.metricsFeatureProvider private var preference: RestrictedPreference? = null private var isAirplaneModeOn = false + private var isSatelliteOn = false override fun getAvailabilityStatus() = if (SimRepository(mContext).showMobileNetworkPageEntrance()) AVAILABLE @@ -74,6 +77,9 @@ constructor( isAirplaneModeOn = it updateEnabled() } + satelliteIsStartedFlow.collectLatestWithLifecycle(viewLifecycleOwner) { + isSatelliteOn = it + } } private fun update(state: MobileNetworkSummaryRepository.SubscriptionsState) { @@ -87,7 +93,10 @@ constructor( preference.onPreferenceClickListener = Preference.OnPreferenceClickListener { logPreferenceClick() - startAddSimFlow(context) + if (isSatelliteOn) + startSatelliteWarningDialogFlow(context) + else + startAddSimFlow(context) true } } diff --git a/src/com/android/settings/network/SatelliteWarningDialogActivity.kt b/src/com/android/settings/network/SatelliteWarningDialogActivity.kt index 3f1d416951d..b86e4f1210e 100644 --- a/src/com/android/settings/network/SatelliteWarningDialogActivity.kt +++ b/src/com/android/settings/network/SatelliteWarningDialogActivity.kt @@ -32,11 +32,20 @@ import com.android.settingslib.wifi.WifiUtils /** A dialog to show the warning message when device is under satellite mode. */ class SatelliteWarningDialogActivity : SpaDialogWindowTypeActivity() { private var warningType = TYPE_IS_UNKNOWN - + private var customizedContent: HashMap = HashMap() + private var isCustomizedContent = false override fun onCreate(savedInstanceState: Bundle?) { - warningType = intent.getIntExtra(EXTRA_TYPE_OF_SATELLITE_WARNING_DIALOG, TYPE_IS_UNKNOWN) - if (warningType == TYPE_IS_UNKNOWN) { - finish() + isCustomizedContent = intent.hasExtra(EXTRA_TYPE_OF_SATELLITE_CUSTOMIZED_CONTENT) + if (isCustomizedContent) { + customizedContent = + intent.getSerializableExtra(EXTRA_TYPE_OF_SATELLITE_CUSTOMIZED_CONTENT) + as HashMap + } else { + warningType = + intent.getIntExtra(EXTRA_TYPE_OF_SATELLITE_WARNING_DIALOG, TYPE_IS_UNKNOWN) + if (warningType == TYPE_IS_UNKNOWN) { + finish() + } } super.onCreate(savedInstanceState) } @@ -48,23 +57,52 @@ class SatelliteWarningDialogActivity : SpaDialogWindowTypeActivity() { ) } + fun getBodyString(): String { + if (isCustomizedContent) { + // For customized content + return customizedContent.get(CUSTOM_CONTENT_DESCRIPTION).toString() + } else { + // For wifi, bluetooth, airplane mode + return String.format( + getString(R.string.satellite_warning_dialog_content), + getTypeString(warningType) + ) + } + } + + fun getButtonString(): String { + if (isCustomizedContent) + // For customized content + return customizedContent.get(CUSTOM_CONTENT_BUTTON_NAME).toString() + else + // For wifi, bluetooth, airplane mode + return getString(com.android.settingslib.R.string.okay) + } + + fun getTitleString(): String { + if (isCustomizedContent) + // For customized content + return customizedContent.get(CUSTOM_CONTENT_TITLE).toString() + else + // For wifi, bluetooth, airplane mode + return String.format( + getString(R.string.satellite_warning_dialog_title), + getTypeString(warningType) + ) + + } + @Composable override fun Content() { SettingsAlertDialogContent( dismissButton = null, confirmButton = AlertDialogButton( - getString(com.android.settingslib.R.string.okay) + getButtonString() ) { finish() }, - title = String.format( - getString(R.string.satellite_warning_dialog_title), - getTypeString(warningType) - ), + title = getTitleString(), text = { Text( - String.format( - getString(R.string.satellite_warning_dialog_content), - getTypeString(warningType) - ), + getBodyString(), modifier = Modifier.fillMaxWidth(), textAlign = TextAlign.Center ) @@ -83,9 +121,14 @@ class SatelliteWarningDialogActivity : SpaDialogWindowTypeActivity() { companion object { const val EXTRA_TYPE_OF_SATELLITE_WARNING_DIALOG: String = "extra_type_of_satellite_warning_dialog" + const val EXTRA_TYPE_OF_SATELLITE_CUSTOMIZED_CONTENT: String = + "extra_type_of_satellite_customized_content" const val TYPE_IS_UNKNOWN = -1 const val TYPE_IS_WIFI = 0 const val TYPE_IS_BLUETOOTH = 1 const val TYPE_IS_AIRPLANE_MODE = 2 + const val CUSTOM_CONTENT_TITLE = 0 + const val CUSTOM_CONTENT_DESCRIPTION = 1 + const val CUSTOM_CONTENT_BUTTON_NAME = 2 } } \ No newline at end of file diff --git a/src/com/android/settings/network/WifiScorerTogglePreference.kt b/src/com/android/settings/network/WifiScorerTogglePreference.kt index b94f6217dad..30e09602c17 100644 --- a/src/com/android/settings/network/WifiScorerTogglePreference.kt +++ b/src/com/android/settings/network/WifiScorerTogglePreference.kt @@ -17,13 +17,13 @@ package com.android.settings.network import android.Manifest -import android.app.settings.SettingsEnums.ACTION_ADAPTIVE_CONNECTIVITY +import android.app.settings.SettingsEnums.ACTION_ADAPTIVE_WIFI_SCORER import android.content.Context import android.net.wifi.WifiManager import android.provider.Settings.Secure.ADAPTIVE_CONNECTIVITY_WIFI_ENABLED import androidx.annotation.RequiresPermission import com.android.settings.R -import com.android.settings.contract.KEY_ADAPTIVE_CONNECTIVITY +import com.android.settings.contract.KEY_ADAPTIVE_WIFI_SCORER import com.android.settings.metrics.PreferenceActionMetricsProvider import com.android.settingslib.datastore.KeyValueStore import com.android.settingslib.datastore.KeyValueStoreDelegate @@ -42,12 +42,12 @@ class WifiScorerTogglePreference() : PreferenceActionMetricsProvider { override val preferenceActionMetrics: Int - get() = ACTION_ADAPTIVE_CONNECTIVITY + get() = ACTION_ADAPTIVE_WIFI_SCORER override val key: String get() = KEY - override fun tags(context: Context) = arrayOf(KEY_ADAPTIVE_CONNECTIVITY) + override fun tags(context: Context) = arrayOf(KEY_ADAPTIVE_WIFI_SCORER) override fun storage(context: Context): KeyValueStore = WifiScorerToggleStorage(context) diff --git a/src/com/android/settings/network/telephony/satellite/SatelliteSettingAccountInfoController.java b/src/com/android/settings/network/telephony/satellite/SatelliteSettingAccountInfoController.java index f688a92305e..c3ddbe953f5 100644 --- a/src/com/android/settings/network/telephony/satellite/SatelliteSettingAccountInfoController.java +++ b/src/com/android/settings/network/telephony/satellite/SatelliteSettingAccountInfoController.java @@ -101,6 +101,10 @@ public class SatelliteSettingAccountInfoController extends TelephonyBasePreferen @Override public int getAvailabilityStatus(int subId) { + if (mConfigBundle.getInt(KEY_CARRIER_ROAMING_NTN_CONNECT_TYPE_INT) + == CARRIER_ROAMING_NTN_CONNECT_MANUAL) { + return AVAILABLE; + } return mConfigBundle.getBoolean(KEY_SATELLITE_ENTITLEMENT_SUPPORTED_BOOL) ? AVAILABLE : CONDITIONALLY_UNAVAILABLE; diff --git a/src/com/android/settings/privatespace/PrivateSpaceAccessibilityUtils.java b/src/com/android/settings/privatespace/PrivateSpaceAccessibilityUtils.java new file mode 100644 index 00000000000..c9c976dd791 --- /dev/null +++ b/src/com/android/settings/privatespace/PrivateSpaceAccessibilityUtils.java @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.settings.privatespace; + +import static com.android.settingslib.widget.preference.illustration.R.string.settingslib_action_label_pause; +import static com.android.settingslib.widget.preference.illustration.R.string.settingslib_action_label_resume; +import static com.android.settingslib.widget.preference.illustration.R.string.settingslib_illustration_content_description; + +import android.content.Context; +import android.view.View; +import android.view.accessibility.AccessibilityNodeInfo; + +import androidx.core.view.AccessibilityDelegateCompat; +import androidx.core.view.ViewCompat; +import androidx.core.view.accessibility.AccessibilityNodeInfoCompat; + +import com.airbnb.lottie.LottieAnimationView; + +public class PrivateSpaceAccessibilityUtils { + + static void updateAccessibilityActionForAnimation(Context context, + LottieAnimationView animationView, boolean isAnimationPlaying) { + animationView.setContentDescription( + context.getString(settingslib_illustration_content_description)); + ViewCompat.setAccessibilityDelegate(animationView, new AccessibilityDelegateCompat() { + @Override + public void onInitializeAccessibilityNodeInfo( + View host, AccessibilityNodeInfoCompat info) { + super.onInitializeAccessibilityNodeInfo(host, info); + // Clearing the class name to ensure the animation is not called out as "button" + // inside the TalkBack flows + info.setClassName(""); + info.removeAction( + AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_CLICK); + + final AccessibilityNodeInfoCompat.AccessibilityActionCompat clickAction = + new AccessibilityNodeInfoCompat.AccessibilityActionCompat( + AccessibilityNodeInfo.ACTION_CLICK, + getActionLabelForAnimation(context, isAnimationPlaying)); + info.addAction(clickAction); + } + }); + } + + private static String getActionLabelForAnimation(Context context, boolean isAnimationPlaying) { + if (isAnimationPlaying) { + return context.getString(settingslib_action_label_pause); + } else { + return context.getString(settingslib_action_label_resume); + } + } +} diff --git a/src/com/android/settings/privatespace/PrivateSpaceEducation.java b/src/com/android/settings/privatespace/PrivateSpaceEducation.java index 093d7a5eed2..2e157780f24 100644 --- a/src/com/android/settings/privatespace/PrivateSpaceEducation.java +++ b/src/com/android/settings/privatespace/PrivateSpaceEducation.java @@ -76,6 +76,8 @@ public class PrivateSpaceEducation extends InstrumentedFragment { LottieAnimationView lottieAnimationView = rootView.findViewById(R.id.lottie_animation); LottieColorUtils.applyDynamicColors(getContext(), lottieAnimationView); lottieAnimationView.setOnClickListener(v -> handleAnimationClick(lottieAnimationView)); + PrivateSpaceAccessibilityUtils.updateAccessibilityActionForAnimation(getContext(), + lottieAnimationView, mIsAnimationPlaying); TextView infoTextView = rootView.findViewById(R.id.learn_more); Pattern pattern = Pattern.compile(infoTextView.getText().toString()); @@ -121,5 +123,7 @@ public class PrivateSpaceEducation extends InstrumentedFragment { lottieAnimationView.playAnimation(); } mIsAnimationPlaying = !mIsAnimationPlaying; + PrivateSpaceAccessibilityUtils.updateAccessibilityActionForAnimation(getContext(), + lottieAnimationView, mIsAnimationPlaying); } } diff --git a/src/com/android/settings/privatespace/PrivateSpaceSetLockFragment.java b/src/com/android/settings/privatespace/PrivateSpaceSetLockFragment.java index 47cf3baa76c..701f43b00ef 100644 --- a/src/com/android/settings/privatespace/PrivateSpaceSetLockFragment.java +++ b/src/com/android/settings/privatespace/PrivateSpaceSetLockFragment.java @@ -94,6 +94,8 @@ public class PrivateSpaceSetLockFragment extends InstrumentedFragment { LottieAnimationView lottieAnimationView = rootView.findViewById(R.id.lottie_animation); LottieColorUtils.applyDynamicColors(getContext(), lottieAnimationView); lottieAnimationView.setOnClickListener(v -> handleAnimationClick(lottieAnimationView)); + PrivateSpaceAccessibilityUtils.updateAccessibilityActionForAnimation(getContext(), + lottieAnimationView, mIsAnimationPlaying); return rootView; } @@ -141,5 +143,7 @@ public class PrivateSpaceSetLockFragment extends InstrumentedFragment { lottieAnimationView.playAnimation(); } mIsAnimationPlaying = !mIsAnimationPlaying; + PrivateSpaceAccessibilityUtils.updateAccessibilityActionForAnimation(getContext(), + lottieAnimationView, mIsAnimationPlaying); } } diff --git a/src/com/android/settings/privatespace/SetupSuccessFragment.java b/src/com/android/settings/privatespace/SetupSuccessFragment.java index 538912e1c65..1b60d924490 100644 --- a/src/com/android/settings/privatespace/SetupSuccessFragment.java +++ b/src/com/android/settings/privatespace/SetupSuccessFragment.java @@ -83,6 +83,8 @@ public class SetupSuccessFragment extends InstrumentedFragment { LottieAnimationView lottieAnimationView = rootView.findViewById(R.id.lottie_animation); LottieColorUtils.applyDynamicColors(getContext(), lottieAnimationView); lottieAnimationView.setOnClickListener(v -> handleAnimationClick(lottieAnimationView)); + PrivateSpaceAccessibilityUtils.updateAccessibilityActionForAnimation(getContext(), + lottieAnimationView, mIsAnimationPlaying); return rootView; } @@ -152,5 +154,7 @@ public class SetupSuccessFragment extends InstrumentedFragment { lottieAnimationView.playAnimation(); } mIsAnimationPlaying = !mIsAnimationPlaying; + PrivateSpaceAccessibilityUtils.updateAccessibilityActionForAnimation(getContext(), + lottieAnimationView, mIsAnimationPlaying); } } diff --git a/src/com/android/settings/regionalpreferences/RegionDialogFragment.java b/src/com/android/settings/regionalpreferences/RegionDialogFragment.java index aff85b59171..b0ff7399f46 100644 --- a/src/com/android/settings/regionalpreferences/RegionDialogFragment.java +++ b/src/com/android/settings/regionalpreferences/RegionDialogFragment.java @@ -16,8 +16,13 @@ package com.android.settings.regionalpreferences; +import static android.app.settings.SettingsEnums.ACTION_CHANGE_PREFERRED_LANGUAGE_REGION_POSITIVE_BTN_CLICKED; +import static android.app.settings.SettingsEnums.ACTION_CHANGE_PREFERRED_LANGUAGE_REGION_NEGATIVE_BTN_CLICKED; +import static android.app.settings.SettingsEnums.ACTION_CHANGE_REGION_DIALOG_NEGATIVE_BTN_CLICKED; +import static android.app.settings.SettingsEnums.ACTION_CHANGE_REGION_DIALOG_POSITIVE_BTN_CLICKED; +import static android.app.settings.SettingsEnums.CHANGE_REGION_DIALOG; + import android.app.Dialog; -import android.app.settings.SettingsEnums; import android.content.Context; import android.content.DialogInterface; import android.os.Bundle; @@ -46,12 +51,17 @@ import java.util.Set; * Create a dialog for system region events. */ public class RegionDialogFragment extends InstrumentedDialogFragment { + + public static final String ARG_CALLING_PAGE = "arg_calling_page"; + public static final int CALLING_PAGE_LANGUAGE_CHOOSE_A_REGION = 0; + public static final int CALLING_PAGE_REGIONAL_PREFERENCES_REGION_PICKER = 1; + public static final int DIALOG_CHANGE_SYSTEM_LOCALE_REGION = 1; + public static final int DIALOG_CHANGE_PREFERRED_LOCALE_REGION = 2; + public static final String ARG_DIALOG_TYPE = "arg_dialog_type"; + public static final String ARG_TARGET_LOCALE = "arg_target_locale"; + public static final String ARG_REPLACED_TARGET_LOCALE = "arg_replaced_target_locale"; + private static final String TAG = "RegionDialogFragment"; - static final int DIALOG_CHANGE_SYSTEM_LOCALE_REGION = 1; - static final int DIALOG_CHANGE_PREFERRED_LOCALE_REGION = 2; - static final String ARG_DIALOG_TYPE = "arg_dialog_type"; - static final String ARG_TARGET_LOCALE = "arg_target_locale"; - static final String ARG_REPLACED_TARGET_LOCALE = "arg_replaced_target_locale"; /** * Use this factory method to create a new instance of @@ -66,7 +76,7 @@ public class RegionDialogFragment extends InstrumentedDialogFragment { @Override public int getMetricsCategory() { - return SettingsEnums.CHANGE_REGION_DIALOG; + return CHANGE_REGION_DIALOG; } @NonNull @@ -114,6 +124,7 @@ public class RegionDialogFragment extends InstrumentedDialogFragment { class RegionDialogController implements DialogInterface.OnClickListener { private final Context mContext; private final int mDialogType; + private final int mCallingPage; private final LocaleStore.LocaleInfo mLocaleInfo; private final Locale mReplacedLocale; private final MetricsFeatureProvider mMetricsFeatureProvider; @@ -123,6 +134,7 @@ public class RegionDialogFragment extends InstrumentedDialogFragment { mContext = context; Bundle arguments = dialogFragment.getArguments(); mDialogType = arguments.getInt(ARG_DIALOG_TYPE); + mCallingPage = arguments.getInt(ARG_CALLING_PAGE); mLocaleInfo = (LocaleStore.LocaleInfo) arguments.getSerializable(ARG_TARGET_LOCALE); mReplacedLocale = (Locale) arguments.getSerializable(ARG_REPLACED_TARGET_LOCALE); mMetricsFeatureProvider = @@ -137,8 +149,10 @@ public class RegionDialogFragment extends InstrumentedDialogFragment { updateRegion(mLocaleInfo.getLocale().toLanguageTag()); mMetricsFeatureProvider.action( mContext, - SettingsEnums.ACTION_CHANGE_REGION_DIALOG_POSITIVE_BTN_CLICKED); - // TODO: add new metrics for DIALOG_CHANGE_PREFERRED_LOCALE_REGION + mDialogType == DIALOG_CHANGE_SYSTEM_LOCALE_REGION + ? ACTION_CHANGE_REGION_DIALOG_POSITIVE_BTN_CLICKED + : ACTION_CHANGE_PREFERRED_LANGUAGE_REGION_POSITIVE_BTN_CLICKED, + mCallingPage); dismiss(); if (getActivity() != null) { getActivity().finish(); @@ -146,8 +160,10 @@ public class RegionDialogFragment extends InstrumentedDialogFragment { } else { mMetricsFeatureProvider.action( mContext, - SettingsEnums.ACTION_CHANGE_REGION_DIALOG_NEGATIVE_BTN_CLICKED); - // TODO: add new metrics for DIALOG_CHANGE_PREFERRED_LOCALE_REGION + mDialogType == DIALOG_CHANGE_SYSTEM_LOCALE_REGION + ? ACTION_CHANGE_REGION_DIALOG_NEGATIVE_BTN_CLICKED + : ACTION_CHANGE_PREFERRED_LANGUAGE_REGION_NEGATIVE_BTN_CLICKED, + mCallingPage); dismiss(); } } diff --git a/src/com/android/settings/regionalpreferences/RegionPickerBaseListPreferenceController.java b/src/com/android/settings/regionalpreferences/RegionPickerBaseListPreferenceController.java index 5768421b11f..8385a7a4f05 100644 --- a/src/com/android/settings/regionalpreferences/RegionPickerBaseListPreferenceController.java +++ b/src/com/android/settings/regionalpreferences/RegionPickerBaseListPreferenceController.java @@ -167,8 +167,12 @@ public abstract class RegionPickerBaseListPreferenceController extends BasePrefe mFragmentManager = mParent.getChildFragmentManager(); Bundle args = new Bundle(); - args.putInt(RegionDialogFragment.ARG_DIALOG_TYPE, + args.putInt( + RegionDialogFragment.ARG_DIALOG_TYPE, RegionDialogFragment.DIALOG_CHANGE_SYSTEM_LOCALE_REGION); + args.putInt( + RegionDialogFragment.ARG_CALLING_PAGE, + RegionDialogFragment.CALLING_PAGE_REGIONAL_PREFERENCES_REGION_PICKER); args.putSerializable(RegionDialogFragment.ARG_TARGET_LOCALE, localeInfo); RegionDialogFragment regionDialogFragment = RegionDialogFragment.newInstance(); regionDialogFragment.setArguments(args); diff --git a/src/com/android/settings/spa/network/SimsSection.kt b/src/com/android/settings/spa/network/SimsSection.kt index fa7fa448950..cd1541fb4a1 100644 --- a/src/com/android/settings/spa/network/SimsSection.kt +++ b/src/com/android/settings/spa/network/SimsSection.kt @@ -35,6 +35,10 @@ import androidx.compose.ui.res.stringResource import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.android.settings.R import com.android.settings.Utils +import com.android.settings.network.SatelliteWarningDialogActivity +import com.android.settings.network.SatelliteWarningDialogActivity.Companion.CUSTOM_CONTENT_BUTTON_NAME +import com.android.settings.network.SatelliteWarningDialogActivity.Companion.CUSTOM_CONTENT_DESCRIPTION +import com.android.settings.network.SatelliteWarningDialogActivity.Companion.CUSTOM_CONTENT_TITLE import com.android.settings.network.SubscriptionUtil import com.android.settings.network.telephony.MobileNetworkUtils import com.android.settings.network.telephony.SubscriptionActivationRepository @@ -143,3 +147,14 @@ fun getAddSimIntent() = Intent(EuiccManager.ACTION_PROVISION_EMBEDDED_SUBSCRIPTI setPackage(Utils.PHONE_PACKAGE_NAME) putExtra(EuiccManager.EXTRA_FORCE_PROVISION, true) } + +fun startSatelliteWarningDialogFlow(context: Context) = context.startActivity(getSatelliteWarningDialogIntent(context)) + +fun getSatelliteWarningDialogIntent(context: Context) = Intent(context, + SatelliteWarningDialogActivity::class.java).apply { + val content = HashMap() + content.put(CUSTOM_CONTENT_TITLE, context.getString(R.string.title_satellite_dialog_for_sim_restriction)) + content.put(CUSTOM_CONTENT_DESCRIPTION, context.getString(R.string.description_satellite_dialog_for_sim_restriction)) + content.put(CUSTOM_CONTENT_BUTTON_NAME, context.getString(R.string.okay)) + putExtra(SatelliteWarningDialogActivity.EXTRA_TYPE_OF_SATELLITE_CUSTOMIZED_CONTENT, content) +} diff --git a/src/com/android/settings/supervision/SupervisionHelper.kt b/src/com/android/settings/supervision/SupervisionHelper.kt new file mode 100644 index 00000000000..8b9b325cb7c --- /dev/null +++ b/src/com/android/settings/supervision/SupervisionHelper.kt @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2025 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.supervision + +import android.app.KeyguardManager +import android.content.Context +import android.os.UserHandle +import android.os.UserManager +import android.os.UserManager.USER_TYPE_PROFILE_SUPERVISING +import androidx.annotation.VisibleForTesting + +/** Convenience methods for interacting with the supervising user profile. */ +open class SupervisionHelper private constructor(context: Context) { + private val mUserManager = context.getSystemService(UserManager::class.java) + private val mKeyguardManager = context.getSystemService(KeyguardManager::class.java) + + fun getSupervisingUserHandle(): UserHandle? { + for (user in (mUserManager?.users ?: emptyList())) { + if (user.userType.equals(USER_TYPE_PROFILE_SUPERVISING)) { + return user.userHandle + } + } + return null + } + + fun isSupervisingCredentialSet(): Boolean { + val supervisingUserId = getSupervisingUserHandle()?.identifier ?: return false + return mKeyguardManager?.isDeviceSecure(supervisingUserId) ?: false + } + + companion object { + @Volatile @VisibleForTesting var sInstance: SupervisionHelper? = null + + fun getInstance(context: Context): SupervisionHelper { + return sInstance + ?: synchronized(this) { + sInstance ?: SupervisionHelper(context).also { sInstance = it } + } + } + } +} diff --git a/src/com/android/settings/supervision/SupervisionMainSwitchPreference.kt b/src/com/android/settings/supervision/SupervisionMainSwitchPreference.kt index 88afc55147c..57591f9aee5 100644 --- a/src/com/android/settings/supervision/SupervisionMainSwitchPreference.kt +++ b/src/com/android/settings/supervision/SupervisionMainSwitchPreference.kt @@ -83,6 +83,7 @@ class SupervisionMainSwitchPreference(context: Context) : val newValue = !supervisionMainSwitchStorage.getBoolean(KEY)!! mainSwitchPreference.setChecked(newValue) updateDependentPreferencesEnabledState(mainSwitchPreference, newValue) + context.notifyPreferenceChange(SupervisionPinManagementScreen.KEY) } return true @@ -110,10 +111,7 @@ class SupervisionMainSwitchPreference(context: Context) : isChecked: Boolean, ) { preference?.parent?.forEachRecursively { - if ( - it.parent?.key == SupervisionDashboardScreen.SUPERVISION_DYNAMIC_GROUP_1 || - it.key == SupervisionPinManagementScreen.KEY - ) { + if (it.parent?.key == SupervisionDashboardScreen.SUPERVISION_DYNAMIC_GROUP_1) { it.isEnabled = isChecked } } diff --git a/src/com/android/settings/supervision/SupervisionPinManagementScreen.kt b/src/com/android/settings/supervision/SupervisionPinManagementScreen.kt index 6d9874a69b7..f3cb2e3c782 100644 --- a/src/com/android/settings/supervision/SupervisionPinManagementScreen.kt +++ b/src/com/android/settings/supervision/SupervisionPinManagementScreen.kt @@ -17,16 +17,20 @@ package com.android.settings.supervision import android.content.Context import com.android.settings.R +import com.android.settingslib.metadata.PreferenceAvailabilityProvider import com.android.settingslib.metadata.ProvidePreferenceScreen import com.android.settingslib.metadata.preferenceHierarchy import com.android.settingslib.preference.PreferenceScreenCreator /** Pin Management landing page (Settings > Supervision > Manage Pin). */ @ProvidePreferenceScreen(SupervisionPinManagementScreen.KEY) -class SupervisionPinManagementScreen : PreferenceScreenCreator { +class SupervisionPinManagementScreen : PreferenceScreenCreator, PreferenceAvailabilityProvider { override val key: String get() = KEY + override fun isAvailable(context: Context) = + SupervisionHelper.getInstance(context).isSupervisingCredentialSet() + override val title: Int get() = R.string.supervision_pin_management_preference_title @@ -36,7 +40,7 @@ class SupervisionPinManagementScreen : PreferenceScreenCreator { // TODO(b/391994031): dynamically update the icon according to PIN status. override val icon: Int - get() = R.drawable.ic_pin + get() = R.drawable.ic_pin_outline override fun fragmentClass() = SupervisionPinManagementFragment::class.java diff --git a/tests/robotests/src/com/android/settings/accessibility/HearingDevicePairingIntroPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/accessibility/HearingDevicePairingIntroPreferenceControllerTest.java new file mode 100644 index 00000000000..85b339f27e7 --- /dev/null +++ b/tests/robotests/src/com/android/settings/accessibility/HearingDevicePairingIntroPreferenceControllerTest.java @@ -0,0 +1,122 @@ +/* + * Copyright (C) 2025 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.accessibility; + +import static com.android.settings.core.BasePreferenceController.AVAILABLE; +import static com.android.settings.core.BasePreferenceController.UNSUPPORTED_ON_DEVICE; + +import static com.google.common.truth.Truth.assertThat; + +import static org.mockito.Mockito.when; + +import android.content.Context; +import android.content.res.Resources; + +import androidx.preference.PreferenceScreen; +import androidx.test.core.app.ApplicationProvider; + +import com.android.settings.R; +import com.android.settingslib.widget.TopIntroPreference; + +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.Spy; +import org.mockito.junit.MockitoJUnit; +import org.mockito.junit.MockitoRule; +import org.robolectric.RobolectricTestRunner; + +/** + * Tests for {@link HearingDevicePairingIntroPreferenceController}. + */ +@RunWith(RobolectricTestRunner.class) +public class HearingDevicePairingIntroPreferenceControllerTest { + + @Rule + public final MockitoRule mockito = MockitoJUnit.rule(); + + @Spy + private final Context mContext = ApplicationProvider.getApplicationContext(); + @Spy + private final Resources mResources = mContext.getResources(); + @Mock + private PreferenceScreen mScreen; + @Mock + private HearingAidHelper mHelper; + private HearingDevicePairingIntroPreferenceController mController; + private TopIntroPreference mPreference; + + @Before + public void setUp() { + mController = new HearingDevicePairingIntroPreferenceController(mContext, "test_key", + mHelper); + mPreference = new TopIntroPreference(mContext); + mPreference.setKey("test_key"); + + when(mScreen.findPreference(mController.getPreferenceKey())).thenReturn(mPreference); + when(mContext.getResources()).thenReturn(mResources); + } + + @Test + public void getAvailabilityStatus_hearingAidSupported_available() { + when(mHelper.isHearingAidSupported()).thenReturn(true); + + assertThat(mController.getAvailabilityStatus()).isEqualTo(AVAILABLE); + } + + @Test + public void getAvailabilityStatus_hearingAidNotSupported_unsupportedOnDevice() { + when(mHelper.isHearingAidSupported()).thenReturn(false); + + assertThat(mController.getAvailabilityStatus()).isEqualTo(UNSUPPORTED_ON_DEVICE); + } + + @Test + public void displayPreference_ashaHapSupported_expectedTitle() { + when(mHelper.isAshaProfileSupported()).thenReturn(true); + when(mHelper.isHapClientProfileSupported()).thenReturn(true); + + mController.displayPreference(mScreen); + + assertThat(mPreference.getTitle().toString()).isEqualTo( + mContext.getString(R.string.accessibility_hearing_device_pairing_intro)); + } + + @Test + public void displayPreference_ashaSupported_expectedTitle() { + when(mHelper.isAshaProfileSupported()).thenReturn(true); + when(mHelper.isHapClientProfileSupported()).thenReturn(false); + + mController.displayPreference(mScreen); + + assertThat(mPreference.getTitle().toString()).isEqualTo( + mContext.getString(R.string.accessibility_hearing_device_pairing_asha_only_intro)); + } + + @Test + public void displayPreference_hapSupported_expectedTitle() { + when(mHelper.isAshaProfileSupported()).thenReturn(false); + when(mHelper.isHapClientProfileSupported()).thenReturn(true); + + mController.displayPreference(mScreen); + + assertThat(mPreference.getTitle().toString()).isEqualTo( + mContext.getString(R.string.accessibility_hearing_device_pairing_hap_only_intro)); + } +} diff --git a/tests/robotests/src/com/android/settings/biometrics/fingerprint/FingerprintSettingsFragmentTest.java b/tests/robotests/src/com/android/settings/biometrics/fingerprint/FingerprintSettingsFragmentTest.java index 47ba523c7b2..495d5ec7a3a 100644 --- a/tests/robotests/src/com/android/settings/biometrics/fingerprint/FingerprintSettingsFragmentTest.java +++ b/tests/robotests/src/com/android/settings/biometrics/fingerprint/FingerprintSettingsFragmentTest.java @@ -70,6 +70,7 @@ import androidx.fragment.app.FragmentTransaction; import androidx.preference.Preference; import androidx.test.core.app.ApplicationProvider; +import com.android.settings.biometrics.fingerprint.feature.FingerprintExtPreferencesProvider; import com.android.settings.password.ChooseLockSettingsHelper; import com.android.settings.password.ConfirmDeviceCredentialActivity; import com.android.settings.search.BaseSearchIndexProvider; @@ -79,6 +80,7 @@ import com.android.settings.testutils.shadow.ShadowLockPatternUtils; import com.android.settings.testutils.shadow.ShadowSettingsPreferenceFragment; import com.android.settings.testutils.shadow.ShadowUserManager; import com.android.settings.testutils.shadow.ShadowUtils; +import com.android.settingslib.RestrictedPreference; import com.android.settingslib.RestrictedSwitchPreference; import org.junit.After; @@ -123,6 +125,12 @@ public class FingerprintSettingsFragmentTest { private PackageManager mPackageManager; @Mock private BiometricManager mBiometricManager; + @Mock + private FingerprintExtPreferencesProvider mExtPreferencesProvider; + @Mock + private RestrictedPreference mRestrictedPreference0; + @Mock + private RestrictedPreference mRestrictedPreference1; @Captor private ArgumentCaptor mCancellationSignalArgumentCaptor = @@ -159,6 +167,11 @@ public class FingerprintSettingsFragmentTest { when(mFakeFeatureFactory.getFingerprintFeatureProvider() .getFingerprintSettingsFeatureProvider()) .thenReturn(mFingerprintSettingsFeatureProvider); + + when(mFakeFeatureFactory.getFingerprintFeatureProvider() + .getExtPreferenceProvider(mContext)) + .thenReturn(mExtPreferencesProvider); + when(mExtPreferencesProvider.getSize()).thenReturn(0); } @After @@ -417,6 +430,33 @@ public class FingerprintSettingsFragmentTest { assertThat(checkEnrolledPerf).isNull(); } + @Test + public void testHasExtPreferences() { + String key0 = "ExtKey0"; + String key1 = "ExtKey1"; + when(mRestrictedPreference0.getKey()).thenReturn(key0); + when(mRestrictedPreference1.getKey()).thenReturn(key1); + when(mExtPreferencesProvider.getSize()).thenReturn(2); + when(mExtPreferencesProvider.newPreference(eq(0), + any(FingerprintExtPreferencesProvider.PreferenceInflater.class))) + .thenReturn(mRestrictedPreference0); + when(mExtPreferencesProvider.newPreference(eq(1), + any(FingerprintExtPreferencesProvider.PreferenceInflater.class))) + .thenReturn(mRestrictedPreference1); + + Fingerprint fingerprint = new Fingerprint("Test", 0, 0); + doReturn(List.of(fingerprint)).when(mFingerprintManager).getEnrolledFingerprints(anyInt()); + setUpFragment(false, PRIMARY_USER_ID, TYPE_UDFPS_OPTICAL, 5); + + shadowOf(Looper.getMainLooper()).idle(); + + Preference preference0 = mFragment.findPreference(key0); + assertThat(preference0).isEqualTo(mRestrictedPreference0); + + Preference preference1 = mFragment.findPreference(key1); + assertThat(preference1).isEqualTo(mRestrictedPreference1); + } + private void setSensor(@FingerprintSensorProperties.SensorType int sensorType, int maxFingerprints) { final ArrayList props = new ArrayList<>(); diff --git a/tests/robotests/src/com/android/settings/supervision/SupervisionDashboardScreenTest.kt b/tests/robotests/src/com/android/settings/supervision/SupervisionDashboardScreenTest.kt index bf579d9fd89..c112b934c0d 100644 --- a/tests/robotests/src/com/android/settings/supervision/SupervisionDashboardScreenTest.kt +++ b/tests/robotests/src/com/android/settings/supervision/SupervisionDashboardScreenTest.kt @@ -65,7 +65,7 @@ class SupervisionDashboardScreenTest { val mainSwitchPreference = fragment.findPreference(SupervisionMainSwitchPreference.KEY)!! val childPreference = - fragment.findPreference(SupervisionPinManagementScreen.KEY)!! + fragment.findPreference(SupervisionWebContentFiltersScreen.KEY)!! assertThat(childPreference.isEnabled).isFalse() @@ -89,7 +89,7 @@ class SupervisionDashboardScreenTest { val mainSwitchPreference = fragment.findPreference(SupervisionMainSwitchPreference.KEY)!! val childPreference = - fragment.findPreference(SupervisionPinManagementScreen.KEY)!! + fragment.findPreference(SupervisionWebContentFiltersScreen.KEY)!! assertThat(childPreference.isEnabled).isFalse() diff --git a/tests/robotests/src/com/android/settings/supervision/SupervisionPinManagementScreenTest.kt b/tests/robotests/src/com/android/settings/supervision/SupervisionPinManagementScreenTest.kt index 90719fba908..294f0ec0cf6 100644 --- a/tests/robotests/src/com/android/settings/supervision/SupervisionPinManagementScreenTest.kt +++ b/tests/robotests/src/com/android/settings/supervision/SupervisionPinManagementScreenTest.kt @@ -15,25 +15,73 @@ */ package com.android.settings.supervision +import android.app.KeyguardManager import android.content.Context +import android.content.ContextWrapper +import android.content.pm.UserInfo +import android.os.UserManager +import android.os.UserManager.USER_TYPE_PROFILE_SUPERVISING 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.mock +import org.mockito.kotlin.whenever @RunWith(AndroidJUnit4::class) class SupervisionPinManagementScreenTest { - private val context: Context = ApplicationProvider.getApplicationContext() + private val mockKeyguardManager = mock() + private val mockUserManager = mock() + + private val context: Context = + object : ContextWrapper(ApplicationProvider.getApplicationContext()) { + override fun getSystemService(name: String): Any? = + when (name) { + Context.KEYGUARD_SERVICE -> mockKeyguardManager + Context.USER_SERVICE -> mockUserManager + else -> super.getSystemService(name) + } + } private val supervisionPinManagementScreen = SupervisionPinManagementScreen() + @Before + fun setup() { + SupervisionHelper.sInstance = null + } + @Test fun key() { assertThat(supervisionPinManagementScreen.key).isEqualTo(SupervisionPinManagementScreen.KEY) } + @Test + fun isAvailable() { + whenever(mockUserManager.users).thenReturn(listOf(SUPERVISING_USER_INFO)) + whenever(mockKeyguardManager.isDeviceSecure(SUPERVISING_USER_ID)).thenReturn(true) + + assertThat(supervisionPinManagementScreen.isAvailable(context)).isTrue() + } + + @Test + fun isAvailable_noSupervisingUser_returnsFalse() { + whenever(mockUserManager.users).thenReturn(emptyList()) + whenever(mockKeyguardManager.isDeviceSecure(SUPERVISING_USER_ID)).thenReturn(true) + + assertThat(supervisionPinManagementScreen.isAvailable(context)).isFalse() + } + + @Test + fun isAvailable_noSupervisingCredential_returnsFalse() { + whenever(mockUserManager.users).thenReturn(listOf(SUPERVISING_USER_INFO)) + whenever(mockKeyguardManager.isDeviceSecure(SUPERVISING_USER_ID)).thenReturn(false) + + assertThat(supervisionPinManagementScreen.isAvailable(context)).isFalse() + } + @Test fun getTitle() { assertThat(supervisionPinManagementScreen.title) @@ -45,4 +93,16 @@ class SupervisionPinManagementScreenTest { assertThat(supervisionPinManagementScreen.summary) .isEqualTo(R.string.supervision_pin_management_preference_summary_add) } + + private companion object { + const val SUPERVISING_USER_ID = 5 + val SUPERVISING_USER_INFO = + UserInfo( + SUPERVISING_USER_ID, + /* name */ "supervising", + /* iconPath */ "", + /* flags */ 0, + USER_TYPE_PROFILE_SUPERVISING, + ) + } } diff --git a/tests/spa_unit/src/com/android/settings/spa/network/SatelliteWarningDialogActivityTest.kt b/tests/spa_unit/src/com/android/settings/spa/network/SatelliteWarningDialogActivityTest.kt index 04e83f5daf8..8defdb1ae05 100644 --- a/tests/spa_unit/src/com/android/settings/spa/network/SatelliteWarningDialogActivityTest.kt +++ b/tests/spa_unit/src/com/android/settings/spa/network/SatelliteWarningDialogActivityTest.kt @@ -28,6 +28,10 @@ import androidx.test.core.app.ApplicationProvider import androidx.test.ext.junit.runners.AndroidJUnit4 import com.android.settings.R import com.android.settings.network.SatelliteWarningDialogActivity +import com.android.settings.network.SatelliteWarningDialogActivity.Companion.CUSTOM_CONTENT_BUTTON_NAME +import com.android.settings.network.SatelliteWarningDialogActivity.Companion.CUSTOM_CONTENT_DESCRIPTION +import com.android.settings.network.SatelliteWarningDialogActivity.Companion.CUSTOM_CONTENT_TITLE +import com.android.settings.network.SatelliteWarningDialogActivity.Companion.EXTRA_TYPE_OF_SATELLITE_CUSTOMIZED_CONTENT import com.android.settings.network.SatelliteWarningDialogActivity.Companion.EXTRA_TYPE_OF_SATELLITE_WARNING_DIALOG import com.android.settings.network.SatelliteWarningDialogActivity.Companion.TYPE_IS_AIRPLANE_MODE import com.android.settings.network.SatelliteWarningDialogActivity.Companion.TYPE_IS_BLUETOOTH @@ -74,6 +78,33 @@ class SatelliteWarningDialogActivityTest { scenario.close() } + @Test + fun launchActivity_checkCustomizedContent_hasContentIntent() { + val scenario = launchCustomizedDialogActivity() + + scenario.onActivity { activity -> + assert(activity.intent.hasExtra(EXTRA_TYPE_OF_SATELLITE_CUSTOMIZED_CONTENT)) + } + scenario.close() + } + + @Test + fun testCustomizedDialogIsExisted() { + val scenario = launchCustomizedDialogActivity() + + composeTestRule.onNodeWithText( + getSatelliteTestContent().get(CUSTOM_CONTENT_BUTTON_NAME).toString() + ).assertIsDisplayed() + composeTestRule.onNodeWithText( + getSatelliteTestContent().get(CUSTOM_CONTENT_TITLE).toString() + ).assertIsDisplayed() + composeTestRule.onNodeWithText( + getSatelliteTestContent().get(CUSTOM_CONTENT_DESCRIPTION).toString() + ).assertIsDisplayed() + + scenario.close() + } + @Test fun launchActivity_unknownType_destroyActivity() { val scenario = launchDialogActivity(TYPE_IS_UNKNOWN) @@ -117,10 +148,31 @@ class SatelliteWarningDialogActivityTest { scenario.close() } - private fun launchDialogActivity(type: Int): ActivityScenario = launch( - Intent( + private fun launchDialogActivity(type: Int): ActivityScenario = + launch(Intent( context, SatelliteWarningDialogActivity::class.java ).putExtra(EXTRA_TYPE_OF_SATELLITE_WARNING_DIALOG, type) ) + + private fun launchCustomizedDialogActivity(): ActivityScenario = + launch(Intent( + context, + SatelliteWarningDialogActivity::class.java + ).putExtra(EXTRA_TYPE_OF_SATELLITE_CUSTOMIZED_CONTENT, getSatelliteTestContent()) + ) + + private fun getSatelliteTestContent(): HashMap { + val content = HashMap() + content.put(CUSTOM_CONTENT_TITLE, TEST_TITLE) + content.put(CUSTOM_CONTENT_DESCRIPTION, TEST_DESCRIPTION) + content.put(CUSTOM_CONTENT_BUTTON_NAME, TEST_BUTTON_NAME) + return content + } + + companion object { + const val TEST_TITLE = "TEST_TITLE" + const val TEST_DESCRIPTION = "TEST_DESCRIPTION" + const val TEST_BUTTON_NAME = "TEST_BUTTON_NAME" + } } diff --git a/tests/unit/src/com/android/settings/network/telephony/satellite/SatelliteSettingAccountInfoControllerTest.java b/tests/unit/src/com/android/settings/network/telephony/satellite/SatelliteSettingAccountInfoControllerTest.java index 331a74c8b5c..bab43aeaa32 100644 --- a/tests/unit/src/com/android/settings/network/telephony/satellite/SatelliteSettingAccountInfoControllerTest.java +++ b/tests/unit/src/com/android/settings/network/telephony/satellite/SatelliteSettingAccountInfoControllerTest.java @@ -16,6 +16,9 @@ package com.android.settings.network.telephony.satellite; +import static android.telephony.CarrierConfigManager.CARRIER_ROAMING_NTN_CONNECT_AUTOMATIC; +import static android.telephony.CarrierConfigManager.CARRIER_ROAMING_NTN_CONNECT_MANUAL; +import static android.telephony.CarrierConfigManager.KEY_CARRIER_ROAMING_NTN_CONNECT_TYPE_INT; import static android.telephony.CarrierConfigManager.KEY_SATELLITE_ENTITLEMENT_SUPPORTED_BOOL; import static com.android.settings.core.BasePreferenceController.AVAILABLE; @@ -81,6 +84,8 @@ public class SatelliteSettingAccountInfoControllerTest { @Test public void getAvailabilityStatus_entitlementNotSupport_returnConditionalUnavailable() { + mPersistableBundle.putInt(KEY_CARRIER_ROAMING_NTN_CONNECT_TYPE_INT, + CARRIER_ROAMING_NTN_CONNECT_AUTOMATIC); when(mContext.getSystemService(SatelliteManager.class)).thenReturn(null); mController.init(TEST_SUB_ID, mPersistableBundle, false, false); @@ -91,6 +96,8 @@ public class SatelliteSettingAccountInfoControllerTest { @Test public void getAvailabilityStatus_entitlementIsSupported_returnConditionalUnavailable() { + mPersistableBundle.putInt(KEY_CARRIER_ROAMING_NTN_CONNECT_TYPE_INT, + CARRIER_ROAMING_NTN_CONNECT_AUTOMATIC); mPersistableBundle.putBoolean(KEY_SATELLITE_ENTITLEMENT_SUPPORTED_BOOL, true); mController.init(TEST_SUB_ID, mPersistableBundle, false, false); @@ -99,6 +106,17 @@ public class SatelliteSettingAccountInfoControllerTest { assertThat(result).isEqualTo(AVAILABLE); } + @Test + public void getAvailabilityStatus_connectionTypeISManual_returnAvailable() { + mPersistableBundle.putInt(KEY_CARRIER_ROAMING_NTN_CONNECT_TYPE_INT, + CARRIER_ROAMING_NTN_CONNECT_MANUAL); + mController.init(TEST_SUB_ID, mPersistableBundle, false, false); + + int result = mController.getAvailabilityStatus(TEST_SUB_ID); + + assertThat(result).isEqualTo(AVAILABLE); + } + @Test public void displayPreference_showCategoryTitle_correctOperatorName() { mPersistableBundle.putBoolean(KEY_SATELLITE_ENTITLEMENT_SUPPORTED_BOOL, true); diff --git a/tests/unit/src/com/android/settings/network/telephony/satellite/SatelliteSettingFooterControllerTest.java b/tests/unit/src/com/android/settings/network/telephony/satellite/SatelliteSettingFooterControllerTest.java index a5873474765..58cb4ed23db 100644 --- a/tests/unit/src/com/android/settings/network/telephony/satellite/SatelliteSettingFooterControllerTest.java +++ b/tests/unit/src/com/android/settings/network/telephony/satellite/SatelliteSettingFooterControllerTest.java @@ -40,6 +40,7 @@ import com.android.settings.testutils.ResourcesUtils; import com.android.settingslib.widget.FooterPreference; import org.junit.Before; +import org.junit.Ignore; import org.junit.Rule; import org.junit.Test; import org.mockito.Mock; @@ -115,6 +116,7 @@ public class SatelliteSettingFooterControllerTest { } @Test + @Ignore("b/405279842") public void displayPreferenceScreen_emergencyMsgSupport_noEmergencyContent() { mPersistableBundle.putBoolean(KEY_EMERGENCY_MESSAGING_SUPPORTED_BOOL, true); PreferenceScreen screen = new PreferenceManager(mContext).createPreferenceScreen(mContext);