Merge "[Audiosharing] Fix tests for hysteresis mode" into main
diff --git a/aconfig/catalyst/system.aconfig b/aconfig/catalyst/system.aconfig
new file mode 100644
index 0000000..f87ff44
--- /dev/null
+++ b/aconfig/catalyst/system.aconfig
@@ -0,0 +1,9 @@
+package: "com.android.settings.flags"
+container: "system"
+
+flag {
+ name: "catalyst_language_setting"
+ namespace: "android_settings"
+ description: "Flag for System -> Languages screen"
+ bug: "323791114"
+}
diff --git a/aconfig/settings_telephony_flag_declarations.aconfig b/aconfig/settings_telephony_flag_declarations.aconfig
index dab1b45..0279125 100644
--- a/aconfig/settings_telephony_flag_declarations.aconfig
+++ b/aconfig/settings_telephony_flag_declarations.aconfig
@@ -14,3 +14,19 @@
description: "Control the Dual SIM onobarding feature"
bug: "298898436"
}
+
+# OWNER=yomna TARGET=25Q2
+flag {
+ name: "mobile_network_security_2g"
+ namespace: "cellular_security"
+ description: "Exposing 2G toggles in Mobile Network Security page"
+ bug: "355062720"
+}
+
+# OWNER=yomna TARGET=25Q2
+flag {
+ name: "add_security_transparency_to_eng_menu"
+ namespace: "cellular_security"
+ description: "Exposing security transparency features to field engineering menu"
+ bug: "355062720"
+}
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 2ee6d60..4831543 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -5995,6 +5995,10 @@
<!-- Title for the battery summary tip [CHAR LIMIT=NONE] -->
<string name="battery_tip_summary_title">Apps are running normally</string>
+ <!-- Title for the battery replacement tip [CHAR LIMIT=NONE] -->
+ <string name="battery_tip_replacement_title">Battery replacement recommended</string>
+ <!-- Summary for the battery replacement tip [CHAR LIMIT=NONE] -->
+ <string name="battery_tip_replacement_summary">Battery capacity and charging performance are reduced, and battery replacement is recommended.</string>
<!-- Title for the low battery tip [CHAR LIMIT=NONE] -->
<string name="battery_tip_low_battery_title">Battery level low</string>
<!-- Summary for the low battery tip [CHAR LIMIT=NONE] -->
@@ -7417,6 +7421,8 @@
<string name="help_url_battery" translatable="false"></string>
<!-- Help URL, Battery Defender [DO NOT TRANSLATE] -->
<string name="help_url_battery_defender" translatable="false"></string>
+ <!-- Help URL, Battery Replacement [DO NOT TRANSLATE] -->
+ <string name="help_url_battery_replacement" translatable="false"></string>
<!-- Help URL, Dock Defender [DO NOT TRANSLATE] -->
<string name="help_url_dock_defender" translatable="false"></string>
<!-- Help URL, Incompatible charging [DO NOT TRANSLATE] -->
diff --git a/res/xml/language_settings.xml b/res/xml/language_settings.xml
index 4613cb0..7618399 100644
--- a/res/xml/language_settings.xml
+++ b/res/xml/language_settings.xml
@@ -19,7 +19,7 @@
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:settings="http://schemas.android.com/apk/res-auto"
android:title="@string/languages_settings"
- android:key="languages_settings">
+ android:key="language_settings">
<PreferenceCategory
android:key="languages_category"
android:title="@string/locale_picker_category_title">
diff --git a/src/com/android/settings/Utils.java b/src/com/android/settings/Utils.java
index 481ad65..adda094 100644
--- a/src/com/android/settings/Utils.java
+++ b/src/com/android/settings/Utils.java
@@ -1516,13 +1516,13 @@
final UserManager userManager = context.getSystemService(
UserManager.class);
final int status = biometricManager.canAuthenticate(getEffectiveUserId(
- userManager, userId), BiometricManager.Authenticators.MANDATORY_BIOMETRICS);
+ userManager, userId), BiometricManager.Authenticators.IDENTITY_CHECK);
switch(status) {
case BiometricManager.BIOMETRIC_SUCCESS:
return BiometricStatus.OK;
case BiometricManager.BIOMETRIC_ERROR_LOCKOUT:
return BiometricStatus.LOCKOUT;
- case BiometricManager.BIOMETRIC_ERROR_MANDATORY_NOT_ACTIVE:
+ case BiometricManager.BIOMETRIC_ERROR_IDENTITY_CHECK_NOT_ACTIVE:
case BiometricManager.BIOMETRIC_ERROR_NOT_ENABLED_FOR_APPS:
return BiometricStatus.NOT_ACTIVE;
default:
@@ -1582,7 +1582,7 @@
final Intent intent = new Intent();
if (android.hardware.biometrics.Flags.mandatoryBiometrics()) {
intent.putExtra(BIOMETRIC_PROMPT_AUTHENTICATORS,
- BiometricManager.Authenticators.MANDATORY_BIOMETRICS);
+ BiometricManager.Authenticators.IDENTITY_CHECK);
}
intent.putExtra(BIOMETRIC_PROMPT_NEGATIVE_BUTTON_TEXT,
resources.getString(R.string.cancel));
diff --git a/src/com/android/settings/biometrics/fingerprint2/BiometricsEnvironment.kt b/src/com/android/settings/biometrics/fingerprint2/BiometricsEnvironment.kt
index 50ac3cd..5d58fc1 100644
--- a/src/com/android/settings/biometrics/fingerprint2/BiometricsEnvironment.kt
+++ b/src/com/android/settings/biometrics/fingerprint2/BiometricsEnvironment.kt
@@ -45,6 +45,7 @@
import com.android.settings.biometrics.fingerprint2.domain.interactor.EnrollStageInteractor
import com.android.settings.biometrics.fingerprint2.domain.interactor.EnrollStageInteractorImpl
import com.android.settings.biometrics.fingerprint2.domain.interactor.EnrolledFingerprintsInteractorImpl
+import com.android.settings.biometrics.fingerprint2.domain.interactor.FingerprintEnrollStageCountInteractor
import com.android.settings.biometrics.fingerprint2.domain.interactor.FingerprintSensorInteractor
import com.android.settings.biometrics.fingerprint2.domain.interactor.FingerprintSensorInteractorImpl
import com.android.settings.biometrics.fingerprint2.domain.interactor.FoldStateInteractor
@@ -113,6 +114,9 @@
fun createCanEnrollFingerprintsInteractor(): CanEnrollFingerprintsInteractor =
CanEnrollFingerprintsInteractorImpl(fingerprintEnrollmentRepository)
+ fun createFingerprintEnrollStageCountInteractor(): FingerprintEnrollStageCountInteractor =
+ FingerprintEnrollStageCountInteractor(fingerprintEnrollmentRepository)
+
fun createGenerateChallengeInteractor(): GenerateChallengeInteractor =
GenerateChallengeInteractorImpl(fingerprintManager, context.userId, gateKeeperPasswordProvider)
diff --git a/src/com/android/settings/biometrics/fingerprint2/data/repository/FingerprintEnrollmentRepo.kt b/src/com/android/settings/biometrics/fingerprint2/data/repository/FingerprintEnrollmentRepo.kt
index 0bb4eea..23ad8ef 100644
--- a/src/com/android/settings/biometrics/fingerprint2/data/repository/FingerprintEnrollmentRepo.kt
+++ b/src/com/android/settings/biometrics/fingerprint2/data/repository/FingerprintEnrollmentRepo.kt
@@ -46,6 +46,8 @@
/** Indicates if a user can enroll another fingerprint */
val canEnrollUser: Flow<Boolean>
+ val enrollStageCount: Int
+
/**
* Indicates if we should use the default settings for maximum enrollments or the sensor props
* from the fingerprint sensor
@@ -115,4 +117,7 @@
?.map { (FingerprintData(it.name.toString(), it.biometricId, it.deviceId)) }
?.toList()
}
+
+ override val enrollStageCount: Int
+ get() = fingerprintManager.enrollStageCount
}
diff --git a/src/com/android/settings/biometrics/fingerprint2/domain/interactor/FingerprintEnrollStageCountInteractor.kt b/src/com/android/settings/biometrics/fingerprint2/domain/interactor/FingerprintEnrollStageCountInteractor.kt
new file mode 100644
index 0000000..6148158
--- /dev/null
+++ b/src/com/android/settings/biometrics/fingerprint2/domain/interactor/FingerprintEnrollStageCountInteractor.kt
@@ -0,0 +1,32 @@
+/*
+ * 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.biometrics.fingerprint2.domain.interactor
+
+import com.android.settings.biometrics.fingerprint2.data.repository.FingerprintEnrollmentRepository
+
+/**
+ * Interactor class for retrieving the total number of enrollment stages.
+ *
+ * This class interacts with the `FingerprintsRepository` to obtain the count
+ * of stages involved in the fingerprint enrollment process.
+ */
+class FingerprintEnrollStageCountInteractor (
+ fingerprintEnrollmentRepository: FingerprintEnrollmentRepository
+) {
+ /** The total number of enrollment stages. */
+ val count: Int = fingerprintEnrollmentRepository.enrollStageCount
+}
diff --git a/src/com/android/settings/bluetooth/BluetoothDeviceDetailsFragment.java b/src/com/android/settings/bluetooth/BluetoothDeviceDetailsFragment.java
index 2860ce8..a1a22be 100644
--- a/src/com/android/settings/bluetooth/BluetoothDeviceDetailsFragment.java
+++ b/src/com/android/settings/bluetooth/BluetoothDeviceDetailsFragment.java
@@ -123,6 +123,14 @@
}
}
}
+
+ @Override
+ public void onDeviceBondStateChanged(
+ @NonNull CachedBluetoothDevice cachedDevice, int bondState) {
+ if (cachedDevice.equals(mCachedDevice)) {
+ finishFragmentIfNecessary();
+ }
+ }
};
private final BluetoothAdapter.OnMetadataChangedListener mExtraControlMetadataListener =
diff --git a/src/com/android/settings/bluetooth/domain/interactor/SpatialAudioInteractor.kt b/src/com/android/settings/bluetooth/domain/interactor/SpatialAudioInteractor.kt
index 4b91716a..cade566 100644
--- a/src/com/android/settings/bluetooth/domain/interactor/SpatialAudioInteractor.kt
+++ b/src/com/android/settings/bluetooth/domain/interactor/SpatialAudioInteractor.kt
@@ -30,10 +30,13 @@
import com.android.settingslib.media.domain.interactor.SpatializerInteractor
import kotlin.coroutines.CoroutineContext
import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.channels.awaitClose
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.SharingStarted
-import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.flow.callbackFlow
+import kotlinx.coroutines.flow.combine
+import kotlinx.coroutines.flow.flowOn
import kotlinx.coroutines.flow.onStart
import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.launch
@@ -41,9 +44,7 @@
/** Provides device setting for spatial audio. */
interface SpatialAudioInteractor {
/** Gets device setting for spatial audio */
- fun getDeviceSetting(
- cachedDevice: CachedBluetoothDevice,
- ): Flow<DeviceSettingModel?>
+ fun getDeviceSetting(cachedDevice: CachedBluetoothDevice): Flow<DeviceSettingModel?>
}
class SpatialAudioInteractorImpl(
@@ -56,33 +57,55 @@
private val spatialAudioOffToggle =
ToggleModel(
context.getString(R.string.spatial_audio_multi_toggle_off),
- DeviceSettingIcon.ResourceIcon(R.drawable.ic_spatial_audio_off))
+ DeviceSettingIcon.ResourceIcon(R.drawable.ic_spatial_audio_off),
+ )
private val spatialAudioOnToggle =
ToggleModel(
context.getString(R.string.spatial_audio_multi_toggle_on),
- DeviceSettingIcon.ResourceIcon(R.drawable.ic_spatial_audio))
+ DeviceSettingIcon.ResourceIcon(R.drawable.ic_spatial_audio),
+ )
private val headTrackingOnToggle =
ToggleModel(
context.getString(R.string.spatial_audio_multi_toggle_head_tracking_on),
- DeviceSettingIcon.ResourceIcon(R.drawable.ic_head_tracking))
+ DeviceSettingIcon.ResourceIcon(R.drawable.ic_head_tracking),
+ )
private val changes = MutableSharedFlow<Unit>()
- override fun getDeviceSetting(
- cachedDevice: CachedBluetoothDevice,
- ): Flow<DeviceSettingModel?> =
+ override fun getDeviceSetting(cachedDevice: CachedBluetoothDevice): Flow<DeviceSettingModel?> =
changes
.onStart { emit(Unit) }
- .map { getSpatialAudioDeviceSettingModel(cachedDevice) }
+ .combine(
+ isDeviceConnected(cachedDevice),
+ ) { _, connected ->
+ if (connected) {
+ getSpatialAudioDeviceSettingModel(cachedDevice)
+ } else {
+ null
+ }
+ }
+ .flowOn(backgroundCoroutineContext)
.stateIn(coroutineScope, SharingStarted.WhileSubscribed(), initialValue = null)
+ private fun isDeviceConnected(cachedDevice: CachedBluetoothDevice): Flow<Boolean> =
+ callbackFlow {
+ val listener =
+ CachedBluetoothDevice.Callback { launch { send(cachedDevice.isConnected) } }
+ cachedDevice.registerCallback(context.mainExecutor, listener)
+ awaitClose { cachedDevice.unregisterCallback(listener) }
+ }
+ .onStart { emit(cachedDevice.isConnected) }
+ .flowOn(backgroundCoroutineContext)
+
private suspend fun getSpatialAudioDeviceSettingModel(
- cachedDevice: CachedBluetoothDevice,
+ cachedDevice: CachedBluetoothDevice
): DeviceSettingModel? {
// TODO(b/343317785): use audio repository instead of calling AudioManager directly.
Log.i(TAG, "CachedDevice: $cachedDevice profiles: ${cachedDevice.profiles}")
val attributes =
BluetoothUtils.getAudioDeviceAttributesForSpatialAudio(
- cachedDevice, audioManager.getBluetoothAudioDeviceCategory(cachedDevice.address))
+ cachedDevice,
+ audioManager.getBluetoothAudioDeviceCategory(cachedDevice.address),
+ )
?: run {
Log.i(TAG, "No audio profiles in cachedDevice: ${cachedDevice.address}.")
return null
@@ -116,7 +139,8 @@
TAG,
"Head tracking available: $headTrackingAvailable, " +
"spatial audio enabled: $spatialAudioEnabled, " +
- "head tracking enabled: $headTrackingEnabled")
+ "head tracking enabled: $headTrackingEnabled",
+ )
return DeviceSettingModel.MultiTogglePreference(
cachedDevice = cachedDevice,
id = DeviceSettingId.DEVICE_SETTING_ID_SPATIAL_AUDIO_MULTI_TOGGLE,
@@ -143,7 +167,8 @@
}
changes.emit(Unit)
}
- })
+ },
+ )
}
companion object {
diff --git a/src/com/android/settings/language/LanguageSettingScreen.kt b/src/com/android/settings/language/LanguageSettingScreen.kt
new file mode 100644
index 0000000..09ca11b
--- /dev/null
+++ b/src/com/android/settings/language/LanguageSettingScreen.kt
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.settings.language
+
+import android.content.ComponentName
+import android.content.Context
+import android.content.pm.PackageManager
+import com.android.settings.R
+import com.android.settings.Settings.LanguageSettingsActivity
+import com.android.settings.flags.Flags
+import com.android.settingslib.metadata.PreferenceAvailabilityProvider
+import com.android.settingslib.metadata.ProvidePreferenceScreen
+import com.android.settingslib.metadata.preferenceHierarchy
+import com.android.settingslib.preference.PreferenceScreenCreator
+
+@ProvidePreferenceScreen
+class LanguageSettingScreen: PreferenceScreenCreator {
+ override val key: String
+ get() = KEY
+
+ override val title: Int
+ get() = R.string.languages_settings
+
+ override val summary: Int
+ get() = R.string.languages_setting_summary
+
+ override val icon: Int
+ get() = R.drawable.ic_settings_languages
+
+ override fun isFlagEnabled(context: Context) = Flags.catalystLanguageSetting()
+
+ override fun hasCompleteHierarchy() = false
+
+ override fun fragmentClass() = LanguageSettings::class.java
+
+ override fun getPreferenceHierarchy(context: Context) = preferenceHierarchy(this) {}
+
+ companion object {
+ const val KEY = "language_setting"
+ }
+}
diff --git a/src/com/android/settings/language/LanguageSettings.java b/src/com/android/settings/language/LanguageSettings.java
index a5adb02..d992ff2 100644
--- a/src/com/android/settings/language/LanguageSettings.java
+++ b/src/com/android/settings/language/LanguageSettings.java
@@ -67,6 +67,11 @@
}
@Override
+ public @Nullable String getPreferenceScreenBindingKey(@NonNull Context context) {
+ return LanguageSettingScreen.KEY;
+ }
+
+ @Override
protected int getPreferenceScreenResId() {
return R.xml.language_settings;
}
diff --git a/src/com/android/settings/notification/app/BundleListPreferenceController.java b/src/com/android/settings/notification/app/BundleListPreferenceController.java
index 82e910c..9ada049 100644
--- a/src/com/android/settings/notification/app/BundleListPreferenceController.java
+++ b/src/com/android/settings/notification/app/BundleListPreferenceController.java
@@ -91,14 +91,27 @@
public void updateState(Preference preference) {
PreferenceCategory category = (PreferenceCategory) preference;
- createOrUpdatePrefForChannel(category,
- mBackend.getChannel(mAppRow.pkg, mAppRow.uid, PROMOTIONS_ID));
- createOrUpdatePrefForChannel(category,
- mBackend.getChannel(mAppRow.pkg, mAppRow.uid, RECS_ID));
- createOrUpdatePrefForChannel(category,
- mBackend.getChannel(mAppRow.pkg, mAppRow.uid, SOCIAL_MEDIA_ID));
- createOrUpdatePrefForChannel(category,
- mBackend.getChannel(mAppRow.pkg, mAppRow.uid, NEWS_ID));
+ NotificationChannel promos = mBackend.getChannel(mAppRow.pkg, mAppRow.uid, PROMOTIONS_ID);
+ if (promos != null) {
+ createOrUpdatePrefForChannel(category, promos);
+ }
+ NotificationChannel recs = mBackend.getChannel(mAppRow.pkg, mAppRow.uid, RECS_ID);
+ if (recs != null) {
+ createOrUpdatePrefForChannel(category, recs);
+ }
+ NotificationChannel social = mBackend.getChannel(mAppRow.pkg, mAppRow.uid, SOCIAL_MEDIA_ID);
+ if (social != null) {
+ createOrUpdatePrefForChannel(category, social);
+ }
+ NotificationChannel news = mBackend.getChannel(mAppRow.pkg, mAppRow.uid, NEWS_ID);
+ if (news != null) {
+ createOrUpdatePrefForChannel(category, news);
+ }
+
+ int preferenceCount = ((PreferenceGroup) preference).getPreferenceCount();
+ if (preferenceCount == 0) {
+ preference.setVisible(false);
+ }
}
@NonNull
@@ -167,5 +180,4 @@
icon.setTintList(Utils.getColorAccent(mContext));
return icon;
}
-
}
diff --git a/src/com/android/settings/notification/modes/ZenModeTriggerUpdatePreferenceController.java b/src/com/android/settings/notification/modes/ZenModeTriggerUpdatePreferenceController.java
index 014a190..13d5c6e 100644
--- a/src/com/android/settings/notification/modes/ZenModeTriggerUpdatePreferenceController.java
+++ b/src/com/android/settings/notification/modes/ZenModeTriggerUpdatePreferenceController.java
@@ -40,6 +40,7 @@
import androidx.preference.Preference;
import com.android.settings.R;
+import com.android.settings.Utils;
import com.android.settingslib.PrimarySwitchPreference;
import com.android.settingslib.notification.modes.ZenMode;
import com.android.settingslib.notification.modes.ZenModesBackend;
@@ -108,7 +109,9 @@
tryParseScheduleConditionId(mode.getRule().getConditionId());
if (schedule != null) {
preference.setTitle(SystemZenRules.getTimeSummary(mContext, schedule));
- preference.setSummary(SystemZenRules.getShortDaysSummary(mContext, schedule));
+ preference.setSummary(Utils.createAccessibleSequence(
+ SystemZenRules.getDaysOfWeekShort(mContext, schedule),
+ SystemZenRules.getDaysOfWeekFull(mContext, schedule)));
} else {
// Fallback, but shouldn't happen.
Log.wtf(TAG, "SCHEDULE_TIME mode without schedule: " + mode);
diff --git a/tests/robotests/src/com/android/settings/MainClearTest.java b/tests/robotests/src/com/android/settings/MainClearTest.java
index 0f823d6..4c2b266 100644
--- a/tests/robotests/src/com/android/settings/MainClearTest.java
+++ b/tests/robotests/src/com/android/settings/MainClearTest.java
@@ -149,8 +149,8 @@
doReturn(mMockActivity).when(mMainClear).getActivity();
when(mMockActivity.getSystemService(BiometricManager.class)).thenReturn(mBiometricManager);
when(mBiometricManager.canAuthenticate(anyInt(),
- eq(BiometricManager.Authenticators.MANDATORY_BIOMETRICS)))
- .thenReturn(BiometricManager.BIOMETRIC_ERROR_MANDATORY_NOT_ACTIVE);
+ eq(BiometricManager.Authenticators.IDENTITY_CHECK)))
+ .thenReturn(BiometricManager.BIOMETRIC_ERROR_IDENTITY_CHECK_NOT_ACTIVE);
}
@After
@@ -379,7 +379,7 @@
when(mMockActivity.getSystemService(BiometricManager.class)).thenReturn(mBiometricManager);
when(mResources.getString(anyInt())).thenReturn(TEST_ACCOUNT_NAME);
when(mBiometricManager.canAuthenticate(anyInt(),
- eq(BiometricManager.Authenticators.MANDATORY_BIOMETRICS)))
+ eq(BiometricManager.Authenticators.IDENTITY_CHECK)))
.thenReturn(BiometricManager.BIOMETRIC_SUCCESS);
doReturn(true).when(mMainClear).isValidRequestCode(eq(MainClear.KEYGUARD_REQUEST));
doNothing().when(mMainClear).startActivityForResult(any(), anyInt());
@@ -406,7 +406,7 @@
when(mMockActivity.getSystemService(BiometricManager.class)).thenReturn(mBiometricManager);
when(mResources.getString(anyInt())).thenReturn(TEST_ACCOUNT_NAME);
when(mBiometricManager.canAuthenticate(anyInt(),
- eq(BiometricManager.Authenticators.MANDATORY_BIOMETRICS)))
+ eq(BiometricManager.Authenticators.IDENTITY_CHECK)))
.thenReturn(BiometricManager.BIOMETRIC_ERROR_LOCKOUT);
doReturn(true).when(mMainClear).isValidRequestCode(eq(MainClear.KEYGUARD_REQUEST));
doNothing().when(mMainClear).startActivityForResult(any(), anyInt());
diff --git a/tests/robotests/src/com/android/settings/UtilsTest.java b/tests/robotests/src/com/android/settings/UtilsTest.java
index 8f4b83e..b91ad6d 100644
--- a/tests/robotests/src/com/android/settings/UtilsTest.java
+++ b/tests/robotests/src/com/android/settings/UtilsTest.java
@@ -541,7 +541,7 @@
@EnableFlags(Flags.FLAG_MANDATORY_BIOMETRICS)
public void testRequestBiometricAuthentication_biometricManagerReturnsSuccess_shouldReturnOk() {
when(mBiometricManager.canAuthenticate(USER_ID,
- BiometricManager.Authenticators.MANDATORY_BIOMETRICS))
+ BiometricManager.Authenticators.IDENTITY_CHECK))
.thenReturn(BiometricManager.BIOMETRIC_SUCCESS);
final Utils.BiometricStatus requestBiometricAuthenticationForMandatoryBiometrics =
Utils.requestBiometricAuthenticationForMandatoryBiometrics(mContext,
@@ -554,7 +554,7 @@
@EnableFlags(Flags.FLAG_MANDATORY_BIOMETRICS)
public void testRequestBiometricAuthentication_biometricManagerReturnsError_shouldReturnError() {
when(mBiometricManager.canAuthenticate(anyInt(),
- eq(BiometricManager.Authenticators.MANDATORY_BIOMETRICS)))
+ eq(BiometricManager.Authenticators.IDENTITY_CHECK)))
.thenReturn(BiometricManager.BIOMETRIC_ERROR_HW_UNAVAILABLE);
assertThat(Utils.requestBiometricAuthenticationForMandatoryBiometrics(mContext,
false /* biometricsAuthenticationRequested */, USER_ID)).isEqualTo(
@@ -567,10 +567,10 @@
when(mContext.getSystemService(UserManager.class)).thenReturn(mMockUserManager);
when(mMockUserManager.getCredentialOwnerProfile(USER_ID)).thenReturn(USER_ID);
when(mBiometricManager.canAuthenticate(anyInt(),
- eq(BiometricManager.Authenticators.MANDATORY_BIOMETRICS)))
+ eq(BiometricManager.Authenticators.IDENTITY_CHECK)))
.thenReturn(BiometricManager.BIOMETRIC_ERROR_HW_UNAVAILABLE);
when(mBiometricManager.canAuthenticate(0 /* userId */,
- BiometricManager.Authenticators.MANDATORY_BIOMETRICS))
+ BiometricManager.Authenticators.IDENTITY_CHECK))
.thenReturn(BiometricManager.BIOMETRIC_SUCCESS);
assertThat(Utils.requestBiometricAuthenticationForMandatoryBiometrics(mContext,
false /* biometricsAuthenticationRequested */, USER_ID)).isEqualTo(
@@ -594,7 +594,7 @@
final Intent intent = intentArgumentCaptor.getValue();
assertThat(intent.getExtra(BIOMETRIC_PROMPT_AUTHENTICATORS)).isEqualTo(
- BiometricManager.Authenticators.MANDATORY_BIOMETRICS);
+ BiometricManager.Authenticators.IDENTITY_CHECK);
assertThat(intent.getExtra(BIOMETRIC_PROMPT_NEGATIVE_BUTTON_TEXT)).isNotNull();
assertThat(intent.getExtra(KeyguardManager.EXTRA_DESCRIPTION)).isNotNull();
assertThat(intent.getBooleanExtra(ChooseLockSettingsHelper.EXTRA_KEY_ALLOW_ANY_USER, false))
diff --git a/tests/robotests/src/com/android/settings/biometrics/combination/CombinedBiometricProfileSettingsTest.java b/tests/robotests/src/com/android/settings/biometrics/combination/CombinedBiometricProfileSettingsTest.java
index b4605c7..3dc011e 100644
--- a/tests/robotests/src/com/android/settings/biometrics/combination/CombinedBiometricProfileSettingsTest.java
+++ b/tests/robotests/src/com/android/settings/biometrics/combination/CombinedBiometricProfileSettingsTest.java
@@ -128,8 +128,8 @@
doReturn(mActivity).when(mFragment).getActivity();
doReturn(mBiometricManager).when(mActivity).getSystemService(BiometricManager.class);
when(mBiometricManager.canAuthenticate(anyInt(),
- eq(BiometricManager.Authenticators.MANDATORY_BIOMETRICS)))
- .thenReturn(BiometricManager.BIOMETRIC_ERROR_MANDATORY_NOT_ACTIVE);
+ eq(BiometricManager.Authenticators.IDENTITY_CHECK)))
+ .thenReturn(BiometricManager.BIOMETRIC_ERROR_IDENTITY_CHECK_NOT_ACTIVE);
ReflectionHelpers.setField(mFragment, "mDashboardFeatureProvider",
FakeFeatureFactory.setupForTest().dashboardFeatureProvider);
@@ -182,7 +182,7 @@
ArgumentCaptor<Intent> intentArgumentCaptor = ArgumentCaptor.forClass(Intent.class);
doNothing().when(mFragment).startActivityForResult(any(), anyInt());
when(mBiometricManager.canAuthenticate(anyInt(),
- eq(BiometricManager.Authenticators.MANDATORY_BIOMETRICS)))
+ eq(BiometricManager.Authenticators.IDENTITY_CHECK)))
.thenReturn(BiometricManager.BIOMETRIC_SUCCESS);
mFragment.onAttach(mContext);
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 0e1bcf6..1086f85 100644
--- a/tests/robotests/src/com/android/settings/biometrics/fingerprint/FingerprintSettingsFragmentTest.java
+++ b/tests/robotests/src/com/android/settings/biometrics/fingerprint/FingerprintSettingsFragmentTest.java
@@ -149,7 +149,7 @@
doReturn(true).when(mFingerprintManager).isHardwareDetected();
doReturn(mVibrator).when(mContext).getSystemService(Vibrator.class);
when(mBiometricManager.canAuthenticate(PRIMARY_USER_ID,
- BiometricManager.Authenticators.MANDATORY_BIOMETRICS))
+ BiometricManager.Authenticators.IDENTITY_CHECK))
.thenReturn(BiometricManager.BIOMETRIC_ERROR_HW_UNAVAILABLE);
}
@@ -176,7 +176,7 @@
@EnableFlags(Flags.FLAG_MANDATORY_BIOMETRICS)
public void testLaunchBiometricPromptForFingerprint() {
when(mBiometricManager.canAuthenticate(PRIMARY_USER_ID,
- BiometricManager.Authenticators.MANDATORY_BIOMETRICS))
+ BiometricManager.Authenticators.IDENTITY_CHECK))
.thenReturn(BiometricManager.BIOMETRIC_SUCCESS);
doNothing().when(mFingerprintManager).generateChallenge(anyInt(), any());
when(mFingerprintManager.hasEnrolledFingerprints(anyInt())).thenReturn(true);
diff --git a/tests/robotests/src/com/android/settings/bluetooth/domain/interactor/SpatialAudioInteractorTest.kt b/tests/robotests/src/com/android/settings/bluetooth/domain/interactor/SpatialAudioInteractorTest.kt
index a83b7c2..28e0581 100644
--- a/tests/robotests/src/com/android/settings/bluetooth/domain/interactor/SpatialAudioInteractorTest.kt
+++ b/tests/robotests/src/com/android/settings/bluetooth/domain/interactor/SpatialAudioInteractorTest.kt
@@ -83,6 +83,7 @@
@Test
fun getDeviceSetting_noAudioProfile_returnNull() {
testScope.runTest {
+ `when`(cachedDevice.isConnected).thenReturn(true)
val setting = getLatestValue(underTest.getDeviceSetting(cachedDevice))
assertThat(setting).isNull()
@@ -93,6 +94,7 @@
@Test
fun getDeviceSetting_audioProfileNotEnabled_returnNull() {
testScope.runTest {
+ `when`(cachedDevice.isConnected).thenReturn(true)
`when`(cachedDevice.profiles).thenReturn(listOf(leAudioProfile))
`when`(leAudioProfile.isEnabled(bluetoothDevice)).thenReturn(false)
@@ -104,8 +106,23 @@
}
@Test
+ fun getDeviceSetting_deviceNotConnected_returnNull() {
+ testScope.runTest {
+ `when`(cachedDevice.isConnected).thenReturn(false)
+ `when`(cachedDevice.profiles).thenReturn(listOf(leAudioProfile))
+ `when`(leAudioProfile.isEnabled(bluetoothDevice)).thenReturn(true)
+
+ val setting = getLatestValue(underTest.getDeviceSetting(cachedDevice))
+
+ assertThat(setting).isNull()
+ verifyNoInteractions(spatializerRepository)
+ }
+ }
+
+ @Test
fun getDeviceSetting_spatialAudioNotSupported_returnNull() {
testScope.runTest {
+ `when`(cachedDevice.isConnected).thenReturn(true)
`when`(cachedDevice.profiles).thenReturn(listOf(leAudioProfile))
`when`(leAudioProfile.isEnabled(bluetoothDevice)).thenReturn(true)
`when`(
@@ -122,6 +139,7 @@
@Test
fun getDeviceSetting_spatialAudioSupported_returnTwoToggles() {
testScope.runTest {
+ `when`(cachedDevice.isConnected).thenReturn(true)
`when`(cachedDevice.profiles).thenReturn(listOf(leAudioProfile))
`when`(leAudioProfile.isEnabled(bluetoothDevice)).thenReturn(true)
`when`(
@@ -150,6 +168,7 @@
@Test
fun getDeviceSetting_headTrackingSupported_returnThreeToggles() {
testScope.runTest {
+ `when`(cachedDevice.isConnected).thenReturn(true)
`when`(cachedDevice.profiles).thenReturn(listOf(leAudioProfile))
`when`(leAudioProfile.isEnabled(bluetoothDevice)).thenReturn(true)
`when`(
@@ -178,6 +197,7 @@
@Test
fun getDeviceSetting_updateState_enableSpatialAudio() {
testScope.runTest {
+ `when`(cachedDevice.isConnected).thenReturn(true)
`when`(cachedDevice.profiles).thenReturn(listOf(leAudioProfile))
`when`(leAudioProfile.isEnabled(bluetoothDevice)).thenReturn(true)
`when`(
@@ -207,6 +227,7 @@
@Test
fun getDeviceSetting_updateState_enableHeadTracking() {
testScope.runTest {
+ `when`(cachedDevice.isConnected).thenReturn(true)
`when`(cachedDevice.profiles).thenReturn(listOf(leAudioProfile))
`when`(leAudioProfile.isEnabled(bluetoothDevice)).thenReturn(true)
`when`(
diff --git a/tests/robotests/src/com/android/settings/notification/app/BundleListPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/notification/app/BundleListPreferenceControllerTest.java
index 8b8c77e..a8de8ef 100644
--- a/tests/robotests/src/com/android/settings/notification/app/BundleListPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/notification/app/BundleListPreferenceControllerTest.java
@@ -89,15 +89,6 @@
mPreferenceScreen = mPreferenceManager.createPreferenceScreen(mContext);
mGroupList = new PreferenceCategory(mContext);
mPreferenceScreen.addPreference(mGroupList);
-
- when(mBackend.getChannel(mAppRow.pkg, mAppRow.uid, PROMOTIONS_ID)).thenReturn(
- new NotificationChannel(PROMOTIONS_ID, PROMOTIONS_ID, 2));
- when(mBackend.getChannel(mAppRow.pkg, mAppRow.uid, NEWS_ID)).thenReturn(
- new NotificationChannel(NEWS_ID, NEWS_ID, 2));
- when(mBackend.getChannel(mAppRow.pkg, mAppRow.uid, SOCIAL_MEDIA_ID)).thenReturn(
- new NotificationChannel(SOCIAL_MEDIA_ID, SOCIAL_MEDIA_ID, 2));
- when(mBackend.getChannel(mAppRow.pkg, mAppRow.uid, RECS_ID)).thenReturn(
- new NotificationChannel(RECS_ID, RECS_ID, 2));
}
@Test
@@ -132,6 +123,14 @@
@Test
public void updateState() {
+ when(mBackend.getChannel(mAppRow.pkg, mAppRow.uid, PROMOTIONS_ID)).thenReturn(
+ new NotificationChannel(PROMOTIONS_ID, PROMOTIONS_ID, 2));
+ when(mBackend.getChannel(mAppRow.pkg, mAppRow.uid, NEWS_ID)).thenReturn(
+ new NotificationChannel(NEWS_ID, NEWS_ID, 2));
+ when(mBackend.getChannel(mAppRow.pkg, mAppRow.uid, SOCIAL_MEDIA_ID)).thenReturn(
+ new NotificationChannel(SOCIAL_MEDIA_ID, SOCIAL_MEDIA_ID, 2));
+ when(mBackend.getChannel(mAppRow.pkg, mAppRow.uid, RECS_ID)).thenReturn(
+ new NotificationChannel(RECS_ID, RECS_ID, 2));
mController.updateState(mGroupList);
assertThat(mGroupList.getPreferenceCount()).isEqualTo(4);
assertThat(mGroupList.findPreference(PROMOTIONS_ID).getTitle()).isEqualTo(PROMOTIONS_ID);
@@ -142,19 +141,38 @@
}
@Test
- public void updateState_updateChildren() {
+ public void updateState_noBundles() {
mController.updateState(mGroupList);
- assertThat(mGroupList.getPreferenceCount()).isEqualTo(4);
+ assertThat(mGroupList.getPreferenceCount()).isEqualTo(0);
+ assertThat(mGroupList.isVisible()).isFalse();
+ }
+ @Test
+ public void updateState_onlySomeBundlesUsed() {
when(mBackend.getChannel(mAppRow.pkg, mAppRow.uid, PROMOTIONS_ID)).thenReturn(
new NotificationChannel(PROMOTIONS_ID, PROMOTIONS_ID, 2));
+ mController.updateState(mGroupList);
+ assertThat(mGroupList.getPreferenceCount()).isEqualTo(1);
+ assertThat(mGroupList.findPreference(PROMOTIONS_ID).getTitle()).isEqualTo(PROMOTIONS_ID);
+ }
+
+ @Test
+ public void updateState_noDuplicateChannelsOnReload() {
+ when(mBackend.getChannel(mAppRow.pkg, mAppRow.uid, PROMOTIONS_ID)).thenReturn(
+ new NotificationChannel(PROMOTIONS_ID, PROMOTIONS_ID, 2));
+ when(mBackend.getChannel(mAppRow.pkg, mAppRow.uid, NEWS_ID)).thenReturn(
+ new NotificationChannel(NEWS_ID, NEWS_ID, 2));
+ when(mBackend.getChannel(mAppRow.pkg, mAppRow.uid, SOCIAL_MEDIA_ID)).thenReturn(
+ new NotificationChannel(SOCIAL_MEDIA_ID, SOCIAL_MEDIA_ID, 2));
+ when(mBackend.getChannel(mAppRow.pkg, mAppRow.uid, RECS_ID)).thenReturn(
+ new NotificationChannel(RECS_ID, RECS_ID, 2));
mController.updateState(mGroupList);
assertThat(mGroupList.getPreferenceCount()).isEqualTo(4);
+ mController.updateState(mGroupList);
+ assertThat(mGroupList.getPreferenceCount()).isEqualTo(4);
assertThat(((PrimarySwitchPreference) mGroupList.findPreference(NEWS_ID)).isChecked())
.isEqualTo(false);
- assertThat(((PrimarySwitchPreference) mGroupList.findPreference(NEWS_ID)).isChecked())
- .isEqualTo(false);
}
}
diff --git a/tests/robotests/src/com/android/settings/notification/modes/ZenModeTriggerUpdatePreferenceControllerTest.java b/tests/robotests/src/com/android/settings/notification/modes/ZenModeTriggerUpdatePreferenceControllerTest.java
index b7af71b..d916dcf 100644
--- a/tests/robotests/src/com/android/settings/notification/modes/ZenModeTriggerUpdatePreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/notification/modes/ZenModeTriggerUpdatePreferenceControllerTest.java
@@ -44,6 +44,8 @@
import android.platform.test.flag.junit.SetFlagsRule;
import android.service.notification.SystemZenRules;
import android.service.notification.ZenModeConfig;
+import android.text.Spanned;
+import android.text.style.TtsSpan;
import android.widget.TextView;
import androidx.preference.PreferenceManager;
@@ -293,7 +295,14 @@
assertThat(mPreference.isVisible()).isTrue();
assertThat(mPreference.getTitle()).isEqualTo("1:00 AM - 3:00 PM");
- assertThat(mPreference.getSummary()).isEqualTo("Mon - Tue, Thu");
+ Spanned summary = (Spanned) mPreference.getSummary();
+ assertThat(summary.toString()).isEqualTo("Mon - Tue, Thu");
+ TtsSpan[] ttsSpans = summary.getSpans(0, summary.length(), TtsSpan.class);
+ assertThat(ttsSpans).hasLength(1);
+ assertThat(ttsSpans[0].getType()).isEqualTo(TtsSpan.TYPE_TEXT);
+ assertThat(ttsSpans[0].getArgs().getString(TtsSpan.ARG_TEXT)).isEqualTo(
+ "Monday to Tuesday, Thursday");
+
// Destination as written into the intent by SubSettingLauncher
assertThat(
mPreference.getIntent().getStringExtra(SettingsActivity.EXTRA_SHOW_FRAGMENT))
diff --git a/tests/unit/Android.bp b/tests/unit/Android.bp
index be43f8e..07df3c8 100644
--- a/tests/unit/Android.bp
+++ b/tests/unit/Android.bp
@@ -26,11 +26,14 @@
"androidx.test.ext.junit",
"androidx.test.rules",
"flag-junit",
+ "kotlin-test",
+ "mockito-kotlin2",
"mockito-target-minus-junit4",
"platform-test-annotations",
"platform-test-rules",
"truth",
"kotlinx_coroutines_test",
+ "SettingsLibPreference-testutils",
"Settings-testutils2",
"servicestests-utils",
// Don't add SettingsLib libraries here - you can use them directly as they are in the
diff --git a/tests/unit/src/com/android/settings/deviceinfo/BuildNumberPreferenceControllerTest.java b/tests/unit/src/com/android/settings/deviceinfo/BuildNumberPreferenceControllerTest.java
index 7e942d9..9a09bf1 100644
--- a/tests/unit/src/com/android/settings/deviceinfo/BuildNumberPreferenceControllerTest.java
+++ b/tests/unit/src/com/android/settings/deviceinfo/BuildNumberPreferenceControllerTest.java
@@ -93,7 +93,7 @@
doReturn(mUserManager).when(mContext).getSystemService(Context.USER_SERVICE);
when(mContext.getSystemService(BiometricManager.class)).thenReturn(mBiometricManager);
when(mBiometricManager.canAuthenticate(mContext.getUserId(),
- BiometricManager.Authenticators.MANDATORY_BIOMETRICS))
+ BiometricManager.Authenticators.IDENTITY_CHECK))
.thenReturn(BiometricManager.BIOMETRIC_ERROR_HW_UNAVAILABLE);
mFactory = FakeFeatureFactory.setupForTest();
@@ -213,7 +213,7 @@
public void onActivityResult_confirmPasswordRequestCompleted_launchBiometricPrompt() {
when(mUserManager.isAdminUser()).thenReturn(true);
when(mBiometricManager.canAuthenticate(mContext.getUserId(),
- BiometricManager.Authenticators.MANDATORY_BIOMETRICS))
+ BiometricManager.Authenticators.IDENTITY_CHECK))
.thenReturn(BiometricManager.BIOMETRIC_SUCCESS);
final boolean activityResultHandled = mController.onActivityResult(
@@ -233,8 +233,8 @@
public void onActivityResult_confirmPasswordRequestCompleted_mandatoryBiometricsError() {
when(mUserManager.isAdminUser()).thenReturn(true);
when(mBiometricManager.canAuthenticate(mContext.getUserId(),
- BiometricManager.Authenticators.MANDATORY_BIOMETRICS))
- .thenReturn(BiometricManager.BIOMETRIC_ERROR_MANDATORY_NOT_ACTIVE);
+ BiometricManager.Authenticators.IDENTITY_CHECK))
+ .thenReturn(BiometricManager.BIOMETRIC_ERROR_IDENTITY_CHECK_NOT_ACTIVE);
final boolean activityResultHandled = mController.onActivityResult(
BuildNumberPreferenceController.REQUEST_CONFIRM_PASSWORD_FOR_DEV_PREF,
diff --git a/tests/unit/src/com/android/settings/language/LanguageSettingScreenTest.kt b/tests/unit/src/com/android/settings/language/LanguageSettingScreenTest.kt
new file mode 100644
index 0000000..7b519a2
--- /dev/null
+++ b/tests/unit/src/com/android/settings/language/LanguageSettingScreenTest.kt
@@ -0,0 +1,46 @@
+/*
+ * 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.language
+
+import android.content.ComponentName
+import android.content.Context
+import android.content.ContextWrapper
+import android.content.pm.PackageManager
+import android.content.res.Resources
+import com.android.settings.Settings.LanguageSettingsActivity
+import com.android.settings.flags.Flags
+import com.android.settingslib.preference.CatalystScreenTestCase
+import com.google.common.truth.Truth.assertThat
+import org.junit.Assert
+import org.junit.Test
+import org.mockito.ArgumentMatchers.anyInt
+import org.mockito.kotlin.doReturn
+import org.mockito.kotlin.mock
+import org.mockito.kotlin.stub
+
+class LanguageSettingScreenTest: CatalystScreenTestCase() {
+ override val preferenceScreenCreator = LanguageSettingScreen()
+
+ override val flagName: String
+ get() = Flags.FLAG_CATALYST_LANGUAGE_SETTING
+
+ @Test
+ fun key() {
+ assertThat(preferenceScreenCreator.key).isEqualTo(LanguageSettingScreen.KEY)
+ }
+
+ override fun migration() {}
+}