diff --git a/aconfig/settings_datetime_flag_declarations.aconfig b/aconfig/settings_datetime_flag_declarations.aconfig
new file mode 100644
index 00000000000..3d9d8b317a5
--- /dev/null
+++ b/aconfig/settings_datetime_flag_declarations.aconfig
@@ -0,0 +1,11 @@
+package: "com.android.settings.flags"
+container: "system"
+
+flag {
+ name: "datetime_feedback"
+ # "location" is used by the Android System Time team for feature flags.
+ namespace: "location"
+ description: "Enable the time feedback feature, a button to launch feedback in Date & Time Settings"
+ bug: "283239837"
+}
+
diff --git a/res/layout/accessibility_color_contrast_preview.xml b/res/layout/accessibility_color_contrast_preview.xml
index 44f75840ac5..16035496e3f 100644
--- a/res/layout/accessibility_color_contrast_preview.xml
+++ b/res/layout/accessibility_color_contrast_preview.xml
@@ -21,17 +21,17 @@
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
+ android:background="@drawable/color_contrast_preview_background"
+ android:importantForAccessibility="no"
android:paddingLeft="24dp"
android:paddingRight="24dp"
- android:paddingBottom="24dp"
- android:background="@drawable/color_contrast_preview_background">
+ android:paddingBottom="24dp">
+ app:layout_constraintTop_toTopOf="parent" />
-
+ app:layout_constrainedWidth="true"
+ app:layout_constraintEnd_toStartOf="@+id/ic_star"
+ app:layout_constraintStart_toEndOf="@id/ic_group"
+ app:layout_constraintTop_toTopOf="@+id/email_background">
+
+
+
+
+
+
-
-
+ app:layout_constrainedWidth="true"
+ app:layout_constraintEnd_toEndOf="@+id/email_background"
+ app:layout_constraintHorizontal_bias="0.0"
+ app:layout_constraintStart_toStartOf="@+id/email_header"
+ app:layout_constraintTop_toBottomOf="@+id/email_header" />
+
+
+ app:layout_constrainedWidth="true"
+ app:layout_constraintEnd_toEndOf="@+id/email_main_background"
+ app:layout_constraintHorizontal_bias="0.0"
+ app:layout_constraintStart_toStartOf="@+id/email_main_background"
+ app:layout_constraintTop_toTopOf="@+id/email_main_background" />
+ app:layout_constraintTop_toBottomOf="@+id/email_title" />
@@ -175,25 +223,31 @@
android:id="@+id/email_attachment"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
+ android:layout_marginEnd="10dp"
+ android:ellipsize="end"
+ android:maxLines="1"
android:paddingEnd="10dp"
+ android:text="@string/color_contrast_preview_email_attachment_name"
android:textColor="?androidprv:attr/materialColorOnTertiaryContainer"
android:textSize="12sp"
- app:layout_constraintStart_toEndOf="@+id/ic_article_filled"
- app:layout_constraintTop_toTopOf="@+id/attachment_background"
+ app:layout_constrainedWidth="true"
app:layout_constraintBottom_toBottomOf="@+id/attachment_background"
- android:text="@string/color_contrast_preview_email_attachment_name" />
+ app:layout_constraintEnd_toStartOf="@+id/ic_edit"
+ app:layout_constraintHorizontal_bias="0.0"
+ app:layout_constraintStart_toEndOf="@+id/ic_article_filled"
+ app:layout_constraintTop_toTopOf="@+id/attachment_background" />
+ app:layout_constraintBottom_toBottomOf="@+id/email_background"
+ app:layout_constraintEnd_toEndOf="@+id/email_background" />
+ app:layout_constraintStart_toEndOf="@+id/ic_inbox"
+ app:layout_constraintTop_toTopOf="@id/ic_inbox" />
+ app:layout_constraintTop_toTopOf="@id/ic_inbox" />
diff --git a/res/layout/accessibility_color_contrast_selector.xml b/res/layout/accessibility_color_contrast_selector.xml
index 38bcf7a9630..18b085ac7c0 100644
--- a/res/layout/accessibility_color_contrast_selector.xml
+++ b/res/layout/accessibility_color_contrast_selector.xml
@@ -23,6 +23,7 @@
android:layout_height="wrap_content">
@@ -58,7 +59,7 @@
android:layout_gravity="center"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
- android:contentDescription="@string/contrast_default"
+ android:contentDescription="@null"
android:src="@drawable/ic_contrast_standard"/>
@@ -67,6 +68,8 @@
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/contrast_button_text_spacing"
android:gravity="center_horizontal|top"
+ android:ellipsize="end"
+ android:singleLine="true"
android:textSize="@dimen/contrast_button_text_size"
android:text="@string/contrast_default"
android:textColor="?androidprv:attr/materialColorOnSurface"/>
@@ -77,12 +80,12 @@
android:layout_height="match_parent" />
@@ -91,7 +94,7 @@
android:layout_gravity="center"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
- android:contentDescription="@string/contrast_medium"
+ android:contentDescription="@null"
android:src="@drawable/ic_contrast_medium"/>
@@ -100,6 +103,8 @@
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/contrast_button_text_spacing"
android:gravity="center_horizontal|top"
+ android:ellipsize="end"
+ android:singleLine="true"
android:textSize="@dimen/contrast_button_text_size"
android:text="@string/contrast_medium"
android:textColor="?androidprv:attr/materialColorOnSurface"/>
@@ -110,12 +115,12 @@
android:layout_height="match_parent" />
@@ -124,7 +129,7 @@
android:layout_gravity="center"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
- android:contentDescription="@string/contrast_high"
+ android:contentDescription="@null"
android:src="@drawable/ic_contrast_high"/>
@@ -133,6 +138,8 @@
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/contrast_button_text_spacing"
android:gravity="center_horizontal|top"
+ android:ellipsize="end"
+ android:singleLine="true"
android:textSize="@dimen/contrast_button_text_size"
android:text="@string/contrast_high"
android:textColor="?androidprv:attr/materialColorOnSurface"/>
diff --git a/res/layout/fingerprint_v2_udfps_enroll_enrolling.xml b/res/layout/fingerprint_v2_udfps_enroll_enrolling.xml
new file mode 100644
index 00000000000..32df66592f3
--- /dev/null
+++ b/res/layout/fingerprint_v2_udfps_enroll_enrolling.xml
@@ -0,0 +1,70 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/res/layout/locale_drag_cell.xml b/res/layout/locale_drag_cell.xml
index 98fc8dfeb9a..c3c46bc5bd3 100644
--- a/res/layout/locale_drag_cell.xml
+++ b/res/layout/locale_drag_cell.xml
@@ -38,7 +38,9 @@
style="@style/LanguageCheckboxAndLabel"
android:layout_marginRight="0dp"
android:minWidth="24dp"
- android:paddingEnd="-8dp"/>
+ android:paddingEnd="-8dp"
+ android:clickable="false"
+ android:focusable="false"/>
+
+
+
diff --git a/res/values/integers.xml b/res/values/integers.xml
index 9d28aaa53e9..7fb2afdf586 100644
--- a/res/values/integers.xml
+++ b/res/values/integers.xml
@@ -22,6 +22,7 @@
103
104
105
+ 106
1
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 909580d8192..db68a847033 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -614,6 +614,15 @@
Select by UTC offset
+
+ Feedback
+
+ feedback, bug, time, zone, timezone
+
+ Send feedback about time
+
+ feedback, bug, time, zone, timezone
+
@@ -4692,9 +4701,11 @@
Business trip report
- For further assistance, please reach out to \nmyself or Helen. This report will be
+ For further assistance, please reach out to myself or Helen. This report will be
Client Expenses
+
+ About color contrast
Turn screen darker
@@ -13168,4 +13179,11 @@
Show pointer while hovering
+
+
+ Media DRM settings
+
+ Force Software Secure Crypto
+
+ Force DRM key management to use software-based whitebox crypto
diff --git a/res/xml/accessibility_color_contrast.xml b/res/xml/accessibility_color_contrast.xml
index 67c939b6a43..5962b8dee2d 100644
--- a/res/xml/accessibility_color_contrast.xml
+++ b/res/xml/accessibility_color_contrast.xml
@@ -28,7 +28,7 @@
android:key="color_contrast_selector"
android:selectable="false"
android:layout="@layout/accessibility_color_contrast_selector"
- settings:controller="com.android.settings.accessibility.ContrastSelectorPreferenceController"/>
+ settings:controller="com.android.settings.accessibility.ContrastSelectorPreferenceController" />
+ settings:searchable="false"
+ settings:controller="com.android.settings.accessibility.ColorContrastFooterPreferenceController" />
diff --git a/res/xml/date_time_prefs.xml b/res/xml/date_time_prefs.xml
index 32684666b74..3fb4a065d7c 100644
--- a/res/xml/date_time_prefs.xml
+++ b/res/xml/date_time_prefs.xml
@@ -73,6 +73,21 @@
+
+
+
+
+
+
+
-
+
+ android:key="media_drm_settings"
+ android:title="@string/media_drm_settings_title"
+ android:fragment="com.android.settings.development.mediadrm.MediaDrmSettingsFragment" />
diff --git a/res/xml/widevine_settings.xml b/res/xml/media_drm_settings.xml
similarity index 70%
rename from res/xml/widevine_settings.xml
rename to res/xml/media_drm_settings.xml
index 3c577d81df4..2e4208c5f2f 100644
--- a/res/xml/widevine_settings.xml
+++ b/res/xml/media_drm_settings.xml
@@ -18,12 +18,12 @@
+ android:key="force_swcrypto_fallback"
+ android:title="@string/force_swcrypto_fallback_title"
+ android:summary="@string/force_swcrypto_fallback_summary"
+ settings:controller="com.android.settings.development.mediadrm.ForceSwSecureCryptoFallbackPreferenceController" />
\ No newline at end of file
diff --git a/res/xml/special_access.xml b/res/xml/special_access.xml
index d522ef60b61..572345c404e 100644
--- a/res/xml/special_access.xml
+++ b/res/xml/special_access.xml
@@ -23,6 +23,8 @@
android:key="run_backup_tasks"
android:title="@string/run_backup_tasks_title"
android:order="-2000"
+ settings:isPreferenceVisible="false"
+ settings:searchable="false"
settings:keywords="@string/keywords_run_backup_tasks"
settings:controller="com.android.settings.spa.app.specialaccess.BackupTasksAppsPreferenceController">
diff --git a/src/com/android/settings/accessibility/ColorContrastFooterPreferenceController.java b/src/com/android/settings/accessibility/ColorContrastFooterPreferenceController.java
new file mode 100644
index 00000000000..99f74183e69
--- /dev/null
+++ b/src/com/android/settings/accessibility/ColorContrastFooterPreferenceController.java
@@ -0,0 +1,37 @@
+/*
+ * 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.accessibility;
+
+import android.content.Context;
+
+import androidx.annotation.NonNull;
+
+import com.android.settings.R;
+
+/** Preference controller for footer in color contrast page. */
+public class ColorContrastFooterPreferenceController extends
+ AccessibilityFooterPreferenceController {
+ public ColorContrastFooterPreferenceController(@NonNull Context context,
+ @NonNull String key) {
+ super(context, key);
+ }
+
+ @Override
+ protected String getIntroductionTitle() {
+ return mContext.getString(R.string.color_contrast_about_title);
+ }
+}
diff --git a/src/com/android/settings/accessibility/ContrastSelectorPreferenceController.java b/src/com/android/settings/accessibility/ContrastSelectorPreferenceController.java
index b99680fa0b6..5b746cdd705 100644
--- a/src/com/android/settings/accessibility/ContrastSelectorPreferenceController.java
+++ b/src/com/android/settings/accessibility/ContrastSelectorPreferenceController.java
@@ -26,7 +26,7 @@ import android.app.UiModeManager;
import android.content.Context;
import android.provider.Settings;
import android.view.View;
-import android.widget.FrameLayout;
+import android.widget.LinearLayout;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
@@ -53,7 +53,7 @@ public class ContrastSelectorPreferenceController extends BasePreferenceControll
private final Executor mMainExecutor;
private final UiModeManager mUiModeManager;
- private Map mContrastButtons = new HashMap<>();
+ private Map mContrastButtons = new HashMap<>();
public ContrastSelectorPreferenceController(@NonNull Context context,
@NonNull String preferenceKey) {
diff --git a/src/com/android/settings/accessibility/RTTSettingPreferenceController.java b/src/com/android/settings/accessibility/RTTSettingPreferenceController.java
index 3ad2a3bc9d4..8ab8850470b 100644
--- a/src/com/android/settings/accessibility/RTTSettingPreferenceController.java
+++ b/src/com/android/settings/accessibility/RTTSettingPreferenceController.java
@@ -61,7 +61,8 @@ public class RTTSettingPreferenceController extends BasePreferenceController {
mDialerPackage = mContext.getString(R.string.config_rtt_setting_package_name);
mPackageManager = mContext.getPackageManager();
mCarrierConfigManager = mContext.getSystemService(CarrierConfigManager.class);
- mRTTIntent = new Intent(context.getString(R.string.config_rtt_setting_intent_action));
+ mRTTIntent = new Intent(context.getString(R.string.config_rtt_setting_intent_action))
+ .setPackage(mDialerPackage);
Log.d(TAG, "init controller");
}
diff --git a/src/com/android/settings/accessibility/ToggleAccessibilityServicePreferenceFragment.java b/src/com/android/settings/accessibility/ToggleAccessibilityServicePreferenceFragment.java
index 72e1ad8eb93..0e50a5c90d5 100644
--- a/src/com/android/settings/accessibility/ToggleAccessibilityServicePreferenceFragment.java
+++ b/src/com/android/settings/accessibility/ToggleAccessibilityServicePreferenceFragment.java
@@ -443,7 +443,8 @@ public class ToggleAccessibilityServicePreferenceFragment extends
final ApplicationInfo appInfo =
a11yServiceInfo.getResolveInfo().serviceInfo.applicationInfo;
final Uri packageUri = Uri.parse("package:" + appInfo.packageName);
- final Intent uninstallIntent = new Intent(Intent.ACTION_UNINSTALL_PACKAGE, packageUri);
+ final Intent uninstallIntent = new Intent(Intent.ACTION_UNINSTALL_PACKAGE, packageUri)
+ .setPackage(getString(R.string.config_package_installer_package_name));
return uninstallIntent;
}
diff --git a/src/com/android/settings/accessibility/ToggleFeaturePreferenceFragment.java b/src/com/android/settings/accessibility/ToggleFeaturePreferenceFragment.java
index b76e9a7e63c..137be210702 100644
--- a/src/com/android/settings/accessibility/ToggleFeaturePreferenceFragment.java
+++ b/src/com/android/settings/accessibility/ToggleFeaturePreferenceFragment.java
@@ -570,6 +570,7 @@ public abstract class ToggleFeaturePreferenceFragment extends DashboardFragment
}
Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
+ intent.setPackage(getContext().getPackageName());
intent.setData(Uri.parse("package:" + packageName));
final Preference appInfoPreference = new Preference(getPrefContext());
diff --git a/src/com/android/settings/biometrics/fingerprint2/ui/enrollment/activity/FingerprintEnrollmentV2Activity.kt b/src/com/android/settings/biometrics/fingerprint2/ui/enrollment/activity/FingerprintEnrollmentV2Activity.kt
index d26b812a686..70d58eab776 100644
--- a/src/com/android/settings/biometrics/fingerprint2/ui/enrollment/activity/FingerprintEnrollmentV2Activity.kt
+++ b/src/com/android/settings/biometrics/fingerprint2/ui/enrollment/activity/FingerprintEnrollmentV2Activity.kt
@@ -52,6 +52,8 @@ import com.android.settings.biometrics.fingerprint2.ui.enrollment.fragment.Finge
import com.android.settings.biometrics.fingerprint2.ui.enrollment.fragment.FingerprintEnrollIntroV2Fragment
import com.android.settings.biometrics.fingerprint2.ui.enrollment.modules.enrolling.rfps.ui.fragment.RFPSEnrollFragment
import com.android.settings.biometrics.fingerprint2.ui.enrollment.modules.enrolling.rfps.ui.viewmodel.RFPSViewModel
+import com.android.settings.biometrics.fingerprint2.ui.enrollment.modules.enrolling.udfps.ui.fragment.UdfpsEnrollFragment
+import com.android.settings.biometrics.fingerprint2.ui.enrollment.modules.enrolling.udfps.ui.viewmodel.UdfpsViewModel
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.BackgroundViewModel
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintAction
import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintEnrollConfirmationViewModel
@@ -100,6 +102,7 @@ class FingerprintEnrollmentV2Activity : FragmentActivity() {
private lateinit var fingerprintFlowViewModel: FingerprintFlowViewModel
private lateinit var fingerprintEnrollConfirmationViewModel:
FingerprintEnrollConfirmationViewModel
+ private lateinit var udfpsViewModel: UdfpsViewModel
private val coroutineDispatcher = Dispatchers.Default
/** Result listener for ChooseLock activity flow. */
@@ -306,6 +309,12 @@ class FingerprintEnrollmentV2Activity : FragmentActivity() {
),
)[RFPSViewModel::class.java]
+ udfpsViewModel =
+ ViewModelProvider(
+ this,
+ UdfpsViewModel.UdfpsEnrollmentFactory(),
+ )[UdfpsViewModel::class.java]
+
fingerprintEnrollConfirmationViewModel =
ViewModelProvider(
this,
@@ -344,6 +353,8 @@ class FingerprintEnrollmentV2Activity : FragmentActivity() {
is Enrollment -> {
when (step.sensor.sensorType) {
FingerprintSensorType.REAR -> RFPSEnrollFragment()
+ FingerprintSensorType.UDFPS_OPTICAL,
+ FingerprintSensorType.UDFPS_ULTRASONIC -> UdfpsEnrollFragment()
else -> FingerprintEnrollEnrollingV2Fragment()
}
}
diff --git a/src/com/android/settings/biometrics/fingerprint2/ui/enrollment/modules/enrolling/udfps/ui/fragment/UdfpsEnrollFragment.kt b/src/com/android/settings/biometrics/fingerprint2/ui/enrollment/modules/enrolling/udfps/ui/fragment/UdfpsEnrollFragment.kt
new file mode 100644
index 00000000000..61451287dc6
--- /dev/null
+++ b/src/com/android/settings/biometrics/fingerprint2/ui/enrollment/modules/enrolling/udfps/ui/fragment/UdfpsEnrollFragment.kt
@@ -0,0 +1,127 @@
+/*
+ * 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.ui.enrollment.modules.enrolling.udfps.ui.fragment
+
+import android.os.Bundle
+import android.util.Log
+import android.view.View
+import androidx.annotation.VisibleForTesting
+import androidx.fragment.app.Fragment
+import androidx.lifecycle.Lifecycle
+import androidx.lifecycle.ViewModelProvider
+import androidx.lifecycle.lifecycleScope
+import androidx.lifecycle.repeatOnLifecycle
+import com.airbnb.lottie.LottieAnimationView
+import com.airbnb.lottie.LottieCompositionFactory
+import com.android.settings.R
+import com.android.settings.biometrics.fingerprint2.ui.enrollment.modules.enrolling.udfps.ui.viewmodel.StageViewModel
+import com.android.settings.biometrics.fingerprint2.ui.enrollment.modules.enrolling.udfps.ui.viewmodel.UdfpsViewModel
+import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintNavigationStep
+import com.google.android.setupdesign.GlifLayout
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.withContext
+
+class UdfpsEnrollFragment() : Fragment(R.layout.fingerprint_v2_udfps_enroll_enrolling) {
+
+ /** Used for testing purposes */
+ private var factory: ViewModelProvider.Factory? = null
+ private val viewModel: UdfpsViewModel by lazy { viewModelProvider[UdfpsViewModel::class.java] }
+
+ @VisibleForTesting
+ constructor(theFactory: ViewModelProvider.Factory) : this() {
+ factory = theFactory
+ }
+
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ super.onViewCreated(view, savedInstanceState)
+ val layout = view as GlifLayout
+ val illustrationLottie: LottieAnimationView = layout.findViewById(R.id.illustration_lottie)!!
+
+ viewLifecycleOwner.lifecycleScope.launch {
+ repeatOnLifecycle(Lifecycle.State.RESUMED) {
+ viewLifecycleOwner.lifecycleScope.launch {
+ viewModel.stageFlow.collect {
+ layout.setHeaderText(getHeaderText(it))
+ getDescriptionText(it)?.let { descriptionText ->
+ layout.setDescriptionText(descriptionText)
+ }
+ getLottie(it)?.let { lottie ->
+ layout.descriptionText = ""
+ LottieCompositionFactory.fromRawRes(requireContext().applicationContext, lottie)
+ .addListener { comp ->
+ comp?.let { composition ->
+ viewLifecycleOwner.lifecycleScope.launch {
+ illustrationLottie.setComposition(composition)
+ illustrationLottie.visibility = View.VISIBLE
+ illustrationLottie.playAnimation()
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ private fun getHeaderText(stageViewModel: StageViewModel): Int {
+ return when (stageViewModel) {
+ StageViewModel.Center,
+ StageViewModel.Guided,
+ StageViewModel.Fingertip,
+ StageViewModel.Unknown -> R.string.security_settings_udfps_enroll_fingertip_title
+ StageViewModel.LeftEdge -> R.string.security_settings_udfps_enroll_left_edge_title
+ StageViewModel.RightEdge -> R.string.security_settings_udfps_enroll_right_edge_title
+ }
+ }
+
+ private fun getDescriptionText(stageViewModel: StageViewModel): Int? {
+ return when (stageViewModel) {
+ StageViewModel.Center,
+ StageViewModel.Guided,
+ StageViewModel.Fingertip,
+ StageViewModel.LeftEdge,
+ StageViewModel.RightEdge -> null
+ StageViewModel.Unknown -> R.string.security_settings_udfps_enroll_start_message
+ }
+ }
+
+ private fun getLottie(stageViewModel: StageViewModel): Int? {
+ return when (stageViewModel) {
+ StageViewModel.Center,
+ StageViewModel.Guided -> R.raw.udfps_center_hint_lottie
+ StageViewModel.Fingertip -> R.raw.udfps_tip_hint_lottie
+ StageViewModel.LeftEdge -> R.raw.udfps_left_edge_hint_lottie
+ StageViewModel.RightEdge -> R.raw.udfps_right_edge_hint_lottie
+ StageViewModel.Unknown -> null
+ }
+ }
+
+ private val viewModelProvider: ViewModelProvider by lazy {
+ if (factory != null) {
+ ViewModelProvider(requireActivity(), factory!!)
+ } else {
+ ViewModelProvider(requireActivity())
+ }
+ }
+
+ companion object {
+ private const val TAG = "UDFPSEnrollFragment"
+ private val navStep = FingerprintNavigationStep.Enrollment::class
+ }
+}
diff --git a/src/com/android/settings/biometrics/fingerprint2/ui/enrollment/modules/enrolling/udfps/ui/viewmodel/StageViewModel.kt b/src/com/android/settings/biometrics/fingerprint2/ui/enrollment/modules/enrolling/udfps/ui/viewmodel/StageViewModel.kt
new file mode 100644
index 00000000000..b879ce17e7b
--- /dev/null
+++ b/src/com/android/settings/biometrics/fingerprint2/ui/enrollment/modules/enrolling/udfps/ui/viewmodel/StageViewModel.kt
@@ -0,0 +1,36 @@
+/*
+ * 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.ui.enrollment.modules.enrolling.udfps.ui.viewmodel
+
+/**
+ * A view model that describes the various stages of UDFPS Enrollment. This stages typically update
+ * the enrollment UI in a major way, such as changing the lottie animation or changing the location
+ * of the where the user should press their fingerprint
+ */
+sealed class StageViewModel {
+ data object Unknown : StageViewModel()
+
+ data object Guided : StageViewModel()
+
+ data object Center : StageViewModel()
+
+ data object Fingertip : StageViewModel()
+
+ data object LeftEdge : StageViewModel()
+
+ data object RightEdge : StageViewModel()
+}
diff --git a/src/com/android/settings/biometrics/fingerprint2/ui/enrollment/modules/enrolling/udfps/ui/viewmodel/UdfpsViewModel.kt b/src/com/android/settings/biometrics/fingerprint2/ui/enrollment/modules/enrolling/udfps/ui/viewmodel/UdfpsViewModel.kt
new file mode 100644
index 00000000000..4fc3d1c5446
--- /dev/null
+++ b/src/com/android/settings/biometrics/fingerprint2/ui/enrollment/modules/enrolling/udfps/ui/viewmodel/UdfpsViewModel.kt
@@ -0,0 +1,42 @@
+/*
+ * 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.ui.enrollment.modules.enrolling.udfps.ui.viewmodel
+
+import androidx.lifecycle.ViewModel
+import androidx.lifecycle.ViewModelProvider
+import com.android.settings.biometrics.fingerprint2.ui.enrollment.viewmodel.FingerprintNavigationStep
+import kotlinx.coroutines.flow.flowOf
+
+/** ViewModel used to drive UDFPS Enrollment through [UdfpsEnrollFragment] */
+class UdfpsViewModel() : ViewModel() {
+
+ /** Indicates what stage UDFPS enrollment is in. */
+ val stageFlow = flowOf(StageViewModel.Center)
+
+ class UdfpsEnrollmentFactory() : ViewModelProvider.Factory {
+
+ @Suppress("UNCHECKED_CAST")
+ override fun create(modelClass: Class): T {
+ return UdfpsViewModel() as T
+ }
+ }
+
+ companion object {
+ private val navStep = FingerprintNavigationStep.Enrollment::class
+ private const val TAG = "UDFPSViewModel"
+ }
+}
diff --git a/src/com/android/settings/datetime/DateTimeSettings.java b/src/com/android/settings/datetime/DateTimeSettings.java
index fb1dd196e31..f3c11d43ac3 100644
--- a/src/com/android/settings/datetime/DateTimeSettings.java
+++ b/src/com/android/settings/datetime/DateTimeSettings.java
@@ -68,6 +68,12 @@ public class DateTimeSettings extends DashboardFragment implements
.setTimeAndDateCallback(this)
.setFromSUW(isFromSUW);
+ // All the elements in the category are optional, so we must ensure the category is only
+ // available if any of the elements are available.
+ TimeFeedbackPreferenceCategoryController helpAndFeedbackCategoryController =
+ use(TimeFeedbackPreferenceCategoryController.class);
+ use(TimeFeedbackPreferenceController.class)
+ .registerWithOptionalCategoryController(helpAndFeedbackCategoryController);
}
@Override
diff --git a/src/com/android/settings/datetime/TimeFeedbackLaunchUtils.java b/src/com/android/settings/datetime/TimeFeedbackLaunchUtils.java
new file mode 100644
index 00000000000..8a023cbfb68
--- /dev/null
+++ b/src/com/android/settings/datetime/TimeFeedbackLaunchUtils.java
@@ -0,0 +1,52 @@
+/*
+ * 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.datetime;
+
+import static android.provider.DeviceConfig.NAMESPACE_SETTINGS_UI;
+
+import android.provider.DeviceConfig;
+
+import com.android.settings.flags.Flags;
+
+/** A class to avoid duplication of launch-control logic for "time feedback" support. */
+final class TimeFeedbackLaunchUtils {
+ /**
+ * A {@link DeviceConfig} flag that influences whether the settings entries related to help and
+ * feedback are supported on this device / for this user.
+ */
+ public static final String KEY_HELP_AND_FEEDBACK_FEATURE_SUPPORTED =
+ "time_help_and_feedback_feature_supported";
+
+ private TimeFeedbackLaunchUtils() {}
+
+ static boolean isFeedbackFeatureSupported() {
+ // Support is determined according to:
+ // 1) A build-time flag to determine release feature availability.
+ // 2) A runtime / server-side flag to determine which devices / who gets to see the feature.
+ // This is launch control for limiting the feedback to droidfooding.
+ return isFeatureSupportedThisRelease() && isFeatureSupportedOnThisDevice();
+ }
+
+ private static boolean isFeatureSupportedThisRelease() {
+ return Flags.datetimeFeedback();
+ }
+
+ private static boolean isFeatureSupportedOnThisDevice() {
+ boolean defaultIsSupported = false;
+ return DeviceConfig.getBoolean(
+ NAMESPACE_SETTINGS_UI, KEY_HELP_AND_FEEDBACK_FEATURE_SUPPORTED, defaultIsSupported);
+ }
+}
diff --git a/src/com/android/settings/datetime/TimeFeedbackPreferenceCategoryController.java b/src/com/android/settings/datetime/TimeFeedbackPreferenceCategoryController.java
new file mode 100644
index 00000000000..0b70af7fc01
--- /dev/null
+++ b/src/com/android/settings/datetime/TimeFeedbackPreferenceCategoryController.java
@@ -0,0 +1,67 @@
+/*
+ * 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.datetime;
+
+import android.content.Context;
+
+import androidx.annotation.NonNull;
+
+import com.android.settings.core.BasePreferenceController;
+import com.android.settingslib.core.AbstractPreferenceController;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * A controller for the Settings category for "time feedback".
+ */
+public class TimeFeedbackPreferenceCategoryController extends BasePreferenceController {
+
+ private final List mChildControllers = new ArrayList<>();
+
+ public TimeFeedbackPreferenceCategoryController(
+ Context context, String preferenceKey) {
+ super(context, preferenceKey);
+ }
+
+ /**
+ * Adds a controller whose own availability can determine the category's availability status.
+ */
+ void addChildController(@NonNull AbstractPreferenceController childController) {
+ mChildControllers.add(Objects.requireNonNull(childController));
+ }
+
+ @Override
+ public int getAvailabilityStatus() {
+ // Firstly, hide the category if it is not enabled by flags.
+ if (!isTimeFeedbackFeatureEnabled()) {
+ return UNSUPPORTED_ON_DEVICE;
+ }
+
+ // Secondly, only show the category if there's one or more controllers available within it.
+ for (AbstractPreferenceController childController : mChildControllers) {
+ if (childController.isAvailable()) {
+ return AVAILABLE;
+ }
+ }
+ return UNSUPPORTED_ON_DEVICE;
+ }
+
+ protected boolean isTimeFeedbackFeatureEnabled() {
+ return TimeFeedbackLaunchUtils.isFeedbackFeatureSupported();
+ }
+}
diff --git a/src/com/android/settings/datetime/TimeFeedbackPreferenceController.java b/src/com/android/settings/datetime/TimeFeedbackPreferenceController.java
new file mode 100644
index 00000000000..5abe4af33cb
--- /dev/null
+++ b/src/com/android/settings/datetime/TimeFeedbackPreferenceController.java
@@ -0,0 +1,95 @@
+/*
+ * 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.datetime;
+
+import static android.content.Intent.URI_INTENT_SCHEME;
+
+import android.app.ActivityManager;
+import android.content.Context;
+import android.content.Intent;
+import android.text.TextUtils;
+
+import androidx.preference.Preference;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.settings.R;
+import com.android.settings.core.BasePreferenceController;
+import com.android.settings.core.PreferenceControllerMixin;
+
+import java.net.URISyntaxException;
+
+/**
+ * A controller for the Settings button that launches "time feedback". The intent launches is
+ * configured with an Intent URI.
+ */
+public class TimeFeedbackPreferenceController
+ extends BasePreferenceController
+ implements PreferenceControllerMixin {
+
+ private final String mIntentUri;
+ private final int mAvailabilityStatus;
+
+ public TimeFeedbackPreferenceController(Context context, String preferenceKey) {
+ this(context, preferenceKey, context.getResources().getString(
+ R.string.config_time_feedback_intent_uri));
+ }
+
+ @VisibleForTesting
+ TimeFeedbackPreferenceController(Context context, String preferenceKey, String intentUri) {
+ super(context, preferenceKey);
+ mIntentUri = intentUri;
+ mAvailabilityStatus = TextUtils.isEmpty(mIntentUri) ? UNSUPPORTED_ON_DEVICE : AVAILABLE;
+ }
+
+ /**
+ * Registers this controller with a category controller so that the category can be optionally
+ * displayed, i.e. if all the child controllers are not available, the category heading won't be
+ * available.
+ */
+ public void registerWithOptionalCategoryController(
+ TimeFeedbackPreferenceCategoryController categoryController) {
+ categoryController.addChildController(this);
+ }
+
+ @Override
+ public int getAvailabilityStatus() {
+ if (!TimeFeedbackLaunchUtils.isFeedbackFeatureSupported()) {
+ return UNSUPPORTED_ON_DEVICE;
+ }
+ return mAvailabilityStatus;
+ }
+
+ @Override
+ public boolean handlePreferenceTreeClick(Preference preference) {
+ if (!TextUtils.equals(preference.getKey(), getPreferenceKey())) {
+ return super.handlePreferenceTreeClick(preference);
+ }
+
+ // Don't allow a monkey user to launch feedback
+ if (ActivityManager.isUserAMonkey()) {
+ return true;
+ }
+
+ try {
+ Intent intent = Intent.parseUri(mIntentUri, URI_INTENT_SCHEME);
+ mContext.startActivity(intent);
+ return true;
+ } catch (URISyntaxException e) {
+ throw new IllegalArgumentException("Bad intent configuration: " + mIntentUri, e);
+ }
+ }
+}
diff --git a/src/com/android/settings/development/graphicsdriver/GraphicsDriverEnableAngleAsSystemDriverController.java b/src/com/android/settings/development/graphicsdriver/GraphicsDriverEnableAngleAsSystemDriverController.java
index e75ab1a53c4..b107501e9c1 100644
--- a/src/com/android/settings/development/graphicsdriver/GraphicsDriverEnableAngleAsSystemDriverController.java
+++ b/src/com/android/settings/development/graphicsdriver/GraphicsDriverEnableAngleAsSystemDriverController.java
@@ -195,7 +195,7 @@ public class GraphicsDriverEnableAngleAsSystemDriverController
@VisibleForTesting
void rebootDevice(Context context) {
- final Intent intent = new Intent(Intent.ACTION_REBOOT);
+ final Intent intent = new Intent(Intent.ACTION_REBOOT).setPackage("android");
context.startActivity(intent);
}
diff --git a/src/com/android/settings/development/widevine/ForceL3FallbackPreferenceController.java b/src/com/android/settings/development/mediadrm/ForceSwSecureCryptoFallbackPreferenceController.java
similarity index 82%
rename from src/com/android/settings/development/widevine/ForceL3FallbackPreferenceController.java
rename to src/com/android/settings/development/mediadrm/ForceSwSecureCryptoFallbackPreferenceController.java
index 78468c19f5f..59f5c51fac4 100644
--- a/src/com/android/settings/development/widevine/ForceL3FallbackPreferenceController.java
+++ b/src/com/android/settings/development/mediadrm/ForceSwSecureCryptoFallbackPreferenceController.java
@@ -14,9 +14,10 @@
* limitations under the License.
*/
-package com.android.settings.development.widevine;
+package com.android.settings.development.mediadrm;
import android.content.Context;
+import android.media.MediaDrm;
import android.sysprop.WidevineProperties;
import android.util.Log;
@@ -29,13 +30,12 @@ import com.android.settingslib.development.DevelopmentSettingsEnabler;
import com.android.settings.media_drm.Flags;
/**
- * The controller (in the Media Widevine settings) enforces L3 security level
-* of Widevine CDM.
+ * The controller (in the Media Drm settings) enforces software secure crypto.
*/
-public class ForceL3FallbackPreferenceController extends TogglePreferenceController {
- private static final String TAG = "ForceL3FallbackPreferenceController";
+public class ForceSwSecureCryptoFallbackPreferenceController extends TogglePreferenceController {
+ private static final String TAG = "ForceSwSecureCryptoFallbackPreferenceController";
- public ForceL3FallbackPreferenceController(Context context, String preferenceKey) {
+ public ForceSwSecureCryptoFallbackPreferenceController(Context context, String preferenceKey) {
super(context, preferenceKey);
}
diff --git a/src/com/android/settings/development/widevine/WidevineSettingsFragment.java b/src/com/android/settings/development/mediadrm/MediaDrmSettingsFragment.java
similarity index 80%
rename from src/com/android/settings/development/widevine/WidevineSettingsFragment.java
rename to src/com/android/settings/development/mediadrm/MediaDrmSettingsFragment.java
index 9eab9f50cca..9d747eeba79 100644
--- a/src/com/android/settings/development/widevine/WidevineSettingsFragment.java
+++ b/src/com/android/settings/development/mediadrm/MediaDrmSettingsFragment.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.settings.development.widevine;
+package com.android.settings.development.mediadrm;
import android.app.settings.SettingsEnums;
import android.content.Context;
@@ -27,12 +27,12 @@ import com.android.settingslib.development.DevelopmentSettingsEnabler;
import com.android.settingslib.search.SearchIndexable;
/**
- * Fragment for native widevine settings in Developer options.
+ * Fragment for native mediadrm settings in Developer options.
*/
@SearchIndexable
-public class WidevineSettingsFragment extends DashboardFragment implements
+public class MediaDrmSettingsFragment extends DashboardFragment implements
DeveloperOptionAwareMixin {
- private static final String TAG = "WidevineSettings";
+ private static final String TAG = "MediaDrmSettings";
@Override
protected String getLogTag() {
@@ -41,16 +41,16 @@ public class WidevineSettingsFragment extends DashboardFragment implements
@Override
protected int getPreferenceScreenResId() {
- return R.xml.widevine_settings;
+ return R.xml.media_drm_settings;
}
@Override
public int getMetricsCategory() {
- return SettingsEnums.WIDEVINE_SETTINGS;
+ return SettingsEnums.MEDIA_DRM_SETTINGS;
}
public static final BaseSearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
- new BaseSearchIndexProvider(R.xml.widevine_settings) {
+ new BaseSearchIndexProvider(R.xml.media_drm_settings) {
@Override
protected boolean isPageSearchEnabled(Context context) {
diff --git a/src/com/android/settings/display/AutoBrightnessPreferenceController.java b/src/com/android/settings/display/AutoBrightnessPreferenceController.java
index bf211837e69..3f9be2fd6cf 100644
--- a/src/com/android/settings/display/AutoBrightnessPreferenceController.java
+++ b/src/com/android/settings/display/AutoBrightnessPreferenceController.java
@@ -62,6 +62,10 @@ public class AutoBrightnessPreferenceController extends TogglePreferenceControll
@Override
public void updateState(Preference preference) {
super.updateState(preference);
+ if (!(preference instanceof PrimarySwitchPreference)) {
+ return;
+ }
+
PrimarySwitchPreference pref = (PrimarySwitchPreference) preference;
if (pref.isEnabled() && UserManager.get(mContext).hasBaseUserRestriction(
UserManager.DISALLOW_CONFIG_BRIGHTNESS, Process.myUserHandle())) {
diff --git a/src/com/android/settings/gestures/SystemNavigationGestureSettings.java b/src/com/android/settings/gestures/SystemNavigationGestureSettings.java
index 38597d12150..4e354607926 100644
--- a/src/com/android/settings/gestures/SystemNavigationGestureSettings.java
+++ b/src/com/android/settings/gestures/SystemNavigationGestureSettings.java
@@ -181,7 +181,8 @@ public class SystemNavigationGestureSettings extends RadioButtonPickerFragment i
if (KEY_SYSTEM_NAV_GESTURAL.equals(info.getKey())) {
pref.setExtraWidgetOnClickListener((v) -> startActivity(new Intent(
- GestureNavigationSettingsFragment.GESTURE_NAVIGATION_SETTINGS)));
+ GestureNavigationSettingsFragment.GESTURE_NAVIGATION_SETTINGS)
+ .setPackage(getContext().getPackageName())));
}
if ((KEY_SYSTEM_NAV_2BUTTONS.equals(info.getKey())
diff --git a/src/com/android/settings/homepage/SettingsHomepageActivity.java b/src/com/android/settings/homepage/SettingsHomepageActivity.java
index 6688831248c..5f091d99e61 100644
--- a/src/com/android/settings/homepage/SettingsHomepageActivity.java
+++ b/src/com/android/settings/homepage/SettingsHomepageActivity.java
@@ -187,6 +187,15 @@ public class SettingsHomepageActivity extends FragmentActivity implements
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
+ // Ensure device is provisioned in order to access Settings home
+ // TODO(b/331254029): This should later be replaced in favor of an allowlist
+ boolean unprovisioned = android.provider.Settings.Global.getInt(getContentResolver(),
+ android.provider.Settings.Global.DEVICE_PROVISIONED, 0) == 0;
+ if (unprovisioned) {
+ Log.e(TAG, "Device is not provisioned, exiting Settings");
+ finish();
+ }
+
mIsEmbeddingActivityEnabled = ActivityEmbeddingUtils.isEmbeddingActivityEnabled(this);
if (mIsEmbeddingActivityEnabled) {
final UserManager um = getSystemService(UserManager.class);
diff --git a/src/com/android/settings/localepicker/LocaleDragAndDropAdapter.java b/src/com/android/settings/localepicker/LocaleDragAndDropAdapter.java
index 24d992756ee..8d60ef2df3a 100644
--- a/src/com/android/settings/localepicker/LocaleDragAndDropAdapter.java
+++ b/src/com/android/settings/localepicker/LocaleDragAndDropAdapter.java
@@ -27,6 +27,7 @@ import android.util.TypedValue;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
+import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.CheckBox;
import android.widget.CompoundButton;
@@ -189,6 +190,13 @@ class LocaleDragAndDropAdapter
setCheckBoxDescription(dragCell, checkbox, isChecked);
}
});
+
+ dragCell.setOnClickListener(new OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ checkbox.toggle();
+ }
+ });
}
@VisibleForTesting
@@ -200,8 +208,6 @@ class LocaleDragAndDropAdapter
CharSequence checkedStatus = mContext.getText(
isChecked ? com.android.internal.R.string.checked
: com.android.internal.R.string.not_checked);
- // Talkback
- dragCell.setStateDescription(checkedStatus);
// Select to Speak
checkbox.setContentDescription(checkedStatus);
}
diff --git a/src/com/android/settings/network/SimOnboardingService.kt b/src/com/android/settings/network/SimOnboardingService.kt
index f99a2b982d4..b99f18d9667 100644
--- a/src/com/android/settings/network/SimOnboardingService.kt
+++ b/src/com/android/settings/network/SimOnboardingService.kt
@@ -338,11 +338,6 @@ class SimOnboardingService {
suspend fun startSetupPrimarySim(context: Context) {
withContext(Dispatchers.Default) {
- if (SubscriptionUtil.getActiveSubscriptions(subscriptionManager).size <= 1) {
- Log.d(TAG,
- "startSetupPrimarySim: number of active subscriptionInfo is less than 2"
- )
- } else {
setDefaultVoice(subscriptionManager, targetPrimarySimCalls)
setDefaultSms(subscriptionManager, targetPrimarySimTexts)
setDefaultData(
@@ -358,7 +353,6 @@ class SimOnboardingService {
}
// no next action, send finish
callback(CallbackType.CALLBACK_FINISH)
- }
}
suspend fun startEnableDsds(context: Context) {
diff --git a/src/com/android/settings/notification/zen/AbstractZenModeAutomaticRulePreferenceController.java b/src/com/android/settings/notification/zen/AbstractZenModeAutomaticRulePreferenceController.java
index e8d132998ad..097d9137985 100644
--- a/src/com/android/settings/notification/zen/AbstractZenModeAutomaticRulePreferenceController.java
+++ b/src/com/android/settings/notification/zen/AbstractZenModeAutomaticRulePreferenceController.java
@@ -19,6 +19,7 @@ package com.android.settings.notification.zen;
import static android.app.NotificationManager.EXTRA_AUTOMATIC_RULE_ID;
import android.app.AutomaticZenRule;
+import android.app.Flags;
import android.app.NotificationManager;
import android.app.settings.SettingsEnums;
import android.content.ComponentName;
@@ -28,11 +29,9 @@ import android.content.pm.ActivityInfo;
import android.content.pm.ComponentInfo;
import android.content.pm.PackageManager;
import android.content.pm.ServiceInfo;
-import android.os.Binder;
import android.provider.Settings;
import android.service.notification.ConditionProviderService;
import android.util.Log;
-import android.util.Slog;
import androidx.fragment.app.Fragment;
import androidx.preference.Preference;
@@ -41,7 +40,6 @@ import com.android.settings.core.PreferenceControllerMixin;
import com.android.settingslib.core.lifecycle.Lifecycle;
import java.util.Map;
-import java.util.Objects;
abstract public class AbstractZenModeAutomaticRulePreferenceController extends
AbstractZenModePreferenceController implements PreferenceControllerMixin {
@@ -166,9 +164,20 @@ abstract public class AbstractZenModeAutomaticRulePreferenceController extends
public void onOk(String ruleName, Fragment parent) {
mMetricsFeatureProvider.action(mContext,
SettingsEnums.ACTION_ZEN_MODE_RULE_NAME_CHANGE_OK);
- AutomaticZenRule rule = new AutomaticZenRule(ruleName, mRuleInfo.serviceComponent,
- mRuleInfo.configurationActivity, mRuleInfo.defaultConditionId, null,
- NotificationManager.INTERRUPTION_FILTER_PRIORITY, true);
+ AutomaticZenRule rule;
+ if (Flags.modesApi() && Flags.modesUi()) {
+ rule = new AutomaticZenRule.Builder(ruleName, mRuleInfo.defaultConditionId)
+ .setType(mRuleInfo.type)
+ .setOwner(mRuleInfo.serviceComponent)
+ .setConfigurationActivity(mRuleInfo.configurationActivity)
+ .setInterruptionFilter(NotificationManager.INTERRUPTION_FILTER_PRIORITY)
+ .setTriggerDescription(mRuleInfo.defaultTriggerDescription)
+ .build();
+ } else {
+ rule = new AutomaticZenRule(ruleName, mRuleInfo.serviceComponent,
+ mRuleInfo.configurationActivity, mRuleInfo.defaultConditionId, null,
+ NotificationManager.INTERRUPTION_FILTER_PRIORITY, true);
+ }
String savedRuleId = mBackend.addZenRule(rule);
if (savedRuleId != null) {
parent.startActivity(getRuleIntent(mRuleInfo.settingsAction, null,
diff --git a/src/com/android/settings/notification/zen/ZenModeEventRuleSettings.java b/src/com/android/settings/notification/zen/ZenModeEventRuleSettings.java
index 791021d441b..9b0f3fc88a6 100644
--- a/src/com/android/settings/notification/zen/ZenModeEventRuleSettings.java
+++ b/src/com/android/settings/notification/zen/ZenModeEventRuleSettings.java
@@ -138,7 +138,7 @@ public class ZenModeEventRuleSettings extends ZenModeRuleSettingsBase {
mEvent.userId = Integer.parseInt(key[0]);
mEvent.calendarId = key[1].equals("") ? null : Long.parseLong(key[1]);
mEvent.calName = key[2].equals("") ? null : key[2];
- updateRule(ZenModeConfig.toEventConditionId(mEvent));
+ updateEventRule(mEvent);
return true;
}
});
@@ -160,7 +160,7 @@ public class ZenModeEventRuleSettings extends ZenModeRuleSettingsBase {
final int reply = Integer.parseInt((String) newValue);
if (reply == mEvent.reply) return false;
mEvent.reply = reply;
- updateRule(ZenModeConfig.toEventConditionId(mEvent));
+ updateEventRule(mEvent);
return true;
}
});
diff --git a/src/com/android/settings/notification/zen/ZenModeRuleSettingsBase.java b/src/com/android/settings/notification/zen/ZenModeRuleSettingsBase.java
index ff217b50dba..4c647cce3b9 100644
--- a/src/com/android/settings/notification/zen/ZenModeRuleSettingsBase.java
+++ b/src/com/android/settings/notification/zen/ZenModeRuleSettingsBase.java
@@ -24,9 +24,10 @@ import android.app.NotificationManager;
import android.app.settings.SettingsEnums;
import android.content.Context;
import android.content.Intent;
-import android.net.Uri;
import android.os.Bundle;
import android.service.notification.ConditionProviderService;
+import android.service.notification.SystemZenRules;
+import android.service.notification.ZenModeConfig;
import android.util.Log;
import android.view.View;
import android.widget.Toast;
@@ -162,8 +163,21 @@ public abstract class ZenModeRuleSettingsBase extends ZenModeSettingsBase {
updatePreference(mActionButtons);
}
- protected void updateRule(Uri newConditionId) {
- mRule.setConditionId(newConditionId);
+ protected void updateScheduleRule(ZenModeConfig.ScheduleInfo schedule) {
+ mRule.setConditionId(ZenModeConfig.toScheduleConditionId(schedule));
+ if (Flags.modesApi() && Flags.modesUi()) {
+ mRule.setTriggerDescription(
+ SystemZenRules.getTriggerDescriptionForScheduleTime(mContext, schedule));
+ }
+ mBackend.updateZenRule(mId, mRule);
+ }
+
+ protected void updateEventRule(ZenModeConfig.EventInfo event) {
+ mRule.setConditionId(ZenModeConfig.toEventConditionId(event));
+ if (Flags.modesApi() && Flags.modesUi()) {
+ mRule.setTriggerDescription(
+ SystemZenRules.getTriggerDescriptionForScheduleEvent(mContext, event));
+ }
mBackend.updateZenRule(mId, mRule);
}
diff --git a/src/com/android/settings/notification/zen/ZenModeScheduleRuleSettings.java b/src/com/android/settings/notification/zen/ZenModeScheduleRuleSettings.java
index 577416d4f97..cad33d72899 100644
--- a/src/com/android/settings/notification/zen/ZenModeScheduleRuleSettings.java
+++ b/src/com/android/settings/notification/zen/ZenModeScheduleRuleSettings.java
@@ -108,7 +108,7 @@ public class ZenModeScheduleRuleSettings extends ZenModeRuleSettingsBase {
if (DEBUG) Log.d(TAG, "onPrefChange start h=" + hour + " m=" + minute);
mSchedule.startHour = hour;
mSchedule.startMinute = minute;
- updateRule(ZenModeConfig.toScheduleConditionId(mSchedule));
+ updateScheduleRule(mSchedule);
return true;
}
});
@@ -130,7 +130,7 @@ public class ZenModeScheduleRuleSettings extends ZenModeRuleSettingsBase {
if (DEBUG) Log.d(TAG, "onPrefChange end h=" + hour + " m=" + minute);
mSchedule.endHour = hour;
mSchedule.endMinute = minute;
- updateRule(ZenModeConfig.toScheduleConditionId(mSchedule));
+ updateScheduleRule(mSchedule);
return true;
}
});
@@ -142,7 +142,7 @@ public class ZenModeScheduleRuleSettings extends ZenModeRuleSettingsBase {
@Override
public boolean onPreferenceChange(Preference preference, Object o) {
mSchedule.exitAtAlarm = (Boolean) o;
- updateRule(ZenModeConfig.toScheduleConditionId(mSchedule));
+ updateScheduleRule(mSchedule);
return true;
}
});
@@ -214,7 +214,7 @@ public class ZenModeScheduleRuleSettings extends ZenModeRuleSettingsBase {
if (Arrays.equals(days, mSchedule.days)) return;
if (DEBUG) Log.d(TAG, "days.onChanged days=" + Arrays.toString(days));
mSchedule.days = days;
- updateRule(ZenModeConfig.toScheduleConditionId(mSchedule));
+ updateScheduleRule(mSchedule);
}
})
.setOnDismissListener(new OnDismissListener() {
diff --git a/src/com/android/settings/notification/zen/ZenModeSettingsBase.java b/src/com/android/settings/notification/zen/ZenModeSettingsBase.java
index 705e827035b..bd4119e0f17 100644
--- a/src/com/android/settings/notification/zen/ZenModeSettingsBase.java
+++ b/src/com/android/settings/notification/zen/ZenModeSettingsBase.java
@@ -29,6 +29,7 @@ import android.util.Log;
import androidx.preference.Preference;
import androidx.preference.PreferenceScreen;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.settings.dashboard.RestrictedDashboardFragment;
import com.android.settingslib.core.AbstractPreferenceController;
@@ -59,7 +60,12 @@ abstract public class ZenModeSettingsBase extends RestrictedDashboardFragment {
public void onAttach(Context context) {
super.onAttach(context);
mContext = context;
- mBackend = ZenModeBackend.getInstance(mContext);
+ setBackend(ZenModeBackend.getInstance(mContext));
+ }
+
+ @VisibleForTesting
+ void setBackend(ZenModeBackend backend) {
+ mBackend = backend;
}
@Override
diff --git a/src/com/android/settings/notification/zen/ZenRuleInfo.java b/src/com/android/settings/notification/zen/ZenRuleInfo.java
index a4c4de097cb..b2a1a959653 100644
--- a/src/com/android/settings/notification/zen/ZenRuleInfo.java
+++ b/src/com/android/settings/notification/zen/ZenRuleInfo.java
@@ -1,5 +1,7 @@
package com.android.settings.notification.zen;
+import android.annotation.Nullable;
+import android.app.AutomaticZenRule;
import android.content.ComponentName;
import android.net.Uri;
@@ -35,7 +37,9 @@ public class ZenRuleInfo {
public String title;
public String settingsAction;
public ComponentName configurationActivity;
+ @AutomaticZenRule.Type public int type;
public Uri defaultConditionId;
+ @Nullable public String defaultTriggerDescription;
public ComponentName serviceComponent;
public boolean isSystem;
public CharSequence packageLabel;
diff --git a/src/com/android/settings/notification/zen/ZenRulePreference.java b/src/com/android/settings/notification/zen/ZenRulePreference.java
index ed3033a9218..06302134eb3 100644
--- a/src/com/android/settings/notification/zen/ZenRulePreference.java
+++ b/src/com/android/settings/notification/zen/ZenRulePreference.java
@@ -17,6 +17,7 @@
package com.android.settings.notification.zen;
import android.app.AutomaticZenRule;
+import android.app.Flags;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
@@ -25,6 +26,7 @@ import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.service.notification.ZenModeConfig;
import android.service.notification.ZenModeConfig.ScheduleInfo;
+import android.text.TextUtils;
import android.util.Log;
import androidx.fragment.app.Fragment;
@@ -141,6 +143,11 @@ public class ZenRulePreference extends PrimarySwitchPreference {
private String computeRuleSummary(AutomaticZenRule rule) {
if (rule != null) {
+ if (Flags.modesApi() && Flags.modesUi()
+ && !TextUtils.isEmpty(rule.getTriggerDescription())) {
+ return rule.getTriggerDescription();
+ }
+
// handle schedule-based rules
ScheduleInfo schedule =
ZenModeConfig.tryParseScheduleConditionId(rule.getConditionId());
diff --git a/src/com/android/settings/notification/zen/ZenRuleSelectionDialog.java b/src/com/android/settings/notification/zen/ZenRuleSelectionDialog.java
index 71df0144d68..48960661972 100644
--- a/src/com/android/settings/notification/zen/ZenRuleSelectionDialog.java
+++ b/src/com/android/settings/notification/zen/ZenRuleSelectionDialog.java
@@ -16,7 +16,9 @@
package com.android.settings.notification.zen;
+import android.app.AutomaticZenRule;
import android.app.Dialog;
+import android.app.Flags;
import android.app.NotificationManager;
import android.app.settings.SettingsEnums;
import android.content.Context;
@@ -29,6 +31,7 @@ import android.content.pm.ResolveInfo;
import android.graphics.drawable.Drawable;
import android.os.AsyncTask;
import android.os.Bundle;
+import android.service.notification.SystemZenRules;
import android.service.notification.ZenModeConfig;
import android.util.Log;
import android.view.LayoutInflater;
@@ -178,6 +181,11 @@ public class ZenRuleSelectionDialog extends InstrumentedDialogFragment {
rt.title = mContext.getString(R.string.zen_schedule_rule_type_name);
rt.packageName = ZenModeConfig.getEventConditionProvider().getPackageName();
rt.defaultConditionId = ZenModeConfig.toScheduleConditionId(schedule);
+ if (Flags.modesApi() && Flags.modesUi()) {
+ rt.type = AutomaticZenRule.TYPE_SCHEDULE_TIME;
+ rt.defaultTriggerDescription = SystemZenRules.getTriggerDescriptionForScheduleTime(
+ mContext, schedule);
+ }
rt.serviceComponent = ZenModeConfig.getScheduleConditionProvider();
rt.isSystem = true;
return rt;
@@ -193,6 +201,11 @@ public class ZenRuleSelectionDialog extends InstrumentedDialogFragment {
rt.title = mContext.getString(R.string.zen_event_rule_type_name);
rt.packageName = ZenModeConfig.getScheduleConditionProvider().getPackageName();
rt.defaultConditionId = ZenModeConfig.toEventConditionId(event);
+ if (Flags.modesApi() && Flags.modesUi()) {
+ rt.type = AutomaticZenRule.TYPE_SCHEDULE_CALENDAR;
+ rt.defaultTriggerDescription = SystemZenRules.getTriggerDescriptionForScheduleEvent(
+ mContext, event);
+ }
rt.serviceComponent = ZenModeConfig.getEventConditionProvider();
rt.isSystem = true;
return rt;
diff --git a/src/com/android/settings/password/BiometricFragment.java b/src/com/android/settings/password/BiometricFragment.java
index 90a1feba1f1..2e4a317cbaf 100644
--- a/src/com/android/settings/password/BiometricFragment.java
+++ b/src/com/android/settings/password/BiometricFragment.java
@@ -143,7 +143,8 @@ public class BiometricFragment extends InstrumentedFragment {
.setShowEmergencyCallButton(promptInfo.isShowEmergencyCallButton())
.setReceiveSystemEvents(true);
- if (Flags.enableBiometricsToUnlockPrivateSpace()) {
+ if (android.os.Flags.allowPrivateProfile() && Flags.enablePrivateSpaceFeatures()
+ && Flags.enableBiometricsToUnlockPrivateSpace()) {
promptBuilder = promptBuilder.setAllowBackgroundAuthentication(true /* allow */,
promptInfo.shouldUseParentProfileForDeviceCredential());
} else {
diff --git a/src/com/android/settings/privatespace/PrivateSpaceMaintainer.java b/src/com/android/settings/privatespace/PrivateSpaceMaintainer.java
index 66235164fcb..9f85d68ca6e 100644
--- a/src/com/android/settings/privatespace/PrivateSpaceMaintainer.java
+++ b/src/com/android/settings/privatespace/PrivateSpaceMaintainer.java
@@ -87,7 +87,7 @@ public class PrivateSpaceMaintainer {
return true;
}
// a name indicating that the profile was created from the PS Settings page
- final String userName = "psSettingsUser";
+ final String userName = "Private space";
if (mUserHandle == null) {
try {
diff --git a/src/com/android/settings/spa/app/specialaccess/BackupTasksAppsPreferenceController.kt b/src/com/android/settings/spa/app/specialaccess/BackupTasksAppsPreferenceController.kt
index 8d6de4ef677..d209f0b415d 100644
--- a/src/com/android/settings/spa/app/specialaccess/BackupTasksAppsPreferenceController.kt
+++ b/src/com/android/settings/spa/app/specialaccess/BackupTasksAppsPreferenceController.kt
@@ -19,14 +19,11 @@ package com.android.settings.spa.app.specialaccess
import android.content.Context
import androidx.preference.Preference
import com.android.settings.core.BasePreferenceController
-import com.android.settings.flags.Flags
import com.android.settings.spa.SpaActivity.Companion.startSpaActivity
class BackupTasksAppsPreferenceController(context: Context, preferenceKey: String) :
BasePreferenceController(context, preferenceKey) {
- override fun getAvailabilityStatus() =
- if (Flags.enablePerformBackupTasksInSettings()) AVAILABLE
- else CONDITIONALLY_UNAVAILABLE
+ override fun getAvailabilityStatus() = CONDITIONALLY_UNAVAILABLE
override fun handlePreferenceTreeClick(preference: Preference): Boolean {
if (preference.key == mPreferenceKey) {
diff --git a/tests/robotests/src/com/android/settings/SettingsActivityTest.java b/tests/robotests/src/com/android/settings/SettingsActivityTest.java
index 89f84496a6e..a8796952761 100644
--- a/tests/robotests/src/com/android/settings/SettingsActivityTest.java
+++ b/tests/robotests/src/com/android/settings/SettingsActivityTest.java
@@ -27,6 +27,7 @@ import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
+import android.app.ActionBar;
import android.app.ActivityManager;
import android.content.Context;
import android.content.Intent;
@@ -114,6 +115,15 @@ public class SettingsActivityTest {
assertThat(((ListenerFragment) fragments.get(1)).mOnActivityResultCalled).isTrue();
}
+ @Test
+ public void getActionBar_hasNoActionBar() {
+ final SettingsActivity activity = Robolectric.buildActivity(SettingsActivity.class).get();
+
+ final ActionBar actionBar = activity.getActionBar();
+
+ assertThat(actionBar).isNull();
+ }
+
public static class ListenerFragment extends Fragment implements OnActivityResultListener {
private boolean mOnActivityResultCalled;
diff --git a/tests/robotests/src/com/android/settings/UtilsTest.java b/tests/robotests/src/com/android/settings/UtilsTest.java
index 0c555da2075..a4b0105e218 100644
--- a/tests/robotests/src/com/android/settings/UtilsTest.java
+++ b/tests/robotests/src/com/android/settings/UtilsTest.java
@@ -30,7 +30,6 @@ import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
-import android.app.ActionBar;
import android.app.admin.DevicePolicyManager;
import android.app.admin.DevicePolicyResourcesManager;
import android.content.ComponentName;
@@ -56,11 +55,9 @@ import android.os.storage.StorageManager;
import android.os.storage.VolumeInfo;
import android.util.IconDrawableFactory;
import android.widget.EditText;
-import android.widget.ScrollView;
import android.widget.TextView;
import androidx.core.graphics.drawable.IconCompat;
-import androidx.fragment.app.FragmentActivity;
import com.android.internal.widget.LockPatternUtils;
import com.android.settings.testutils.shadow.ShadowLockPatternUtils;
@@ -71,7 +68,6 @@ import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
-import org.robolectric.Robolectric;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment;
import org.robolectric.annotation.Config;
@@ -270,17 +266,6 @@ public class UtilsTest {
Utils.setActionBarShadowAnimation(null, null, null);
}
- @Test
- public void setActionBarShadowAnimation_shouldSetElevationToZero() {
- final FragmentActivity activity = Robolectric.setupActivity(FragmentActivity.class);
- final ActionBar actionBar = activity.getActionBar();
-
- Utils.setActionBarShadowAnimation(activity, activity.getLifecycle(),
- new ScrollView(mContext));
-
- assertThat(actionBar.getElevation()).isEqualTo(0.f);
- }
-
@Test
public void isSettingsIntelligence_IsSI_returnTrue() {
final String siPackageName = mContext.getString(
diff --git a/tests/robotests/src/com/android/settings/accessibility/ContrastSelectorPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/accessibility/ContrastSelectorPreferenceControllerTest.java
index 38d6e801538..83d9cb957b4 100644
--- a/tests/robotests/src/com/android/settings/accessibility/ContrastSelectorPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/accessibility/ContrastSelectorPreferenceControllerTest.java
@@ -27,7 +27,7 @@ import static org.mockito.Mockito.when;
import android.app.UiModeManager;
import android.content.Context;
-import android.widget.FrameLayout;
+import android.widget.LinearLayout;
import androidx.preference.PreferenceScreen;
import androidx.test.core.app.ApplicationProvider;
@@ -57,7 +57,7 @@ public class ContrastSelectorPreferenceControllerTest {
@Mock
private PreferenceScreen mScreen;
@Mock
- private FrameLayout mFrameLayout;
+ private LinearLayout mLinearLayout;
@Mock
private LayoutPreference mLayoutPreference;
private Context mContext;
@@ -72,7 +72,7 @@ public class ContrastSelectorPreferenceControllerTest {
when(mContext.getSystemService(UiModeManager.class)).thenReturn(mUiService);
mController = new ContrastSelectorPreferenceController(mContext, PREFERENCE_KEY);
when(mScreen.findPreference(PREFERENCE_KEY)).thenReturn(mLayoutPreference);
- when(mLayoutPreference.findViewById(anyInt())).thenReturn(mFrameLayout);
+ when(mLayoutPreference.findViewById(anyInt())).thenReturn(mLinearLayout);
}
@Test
@@ -102,7 +102,7 @@ public class ContrastSelectorPreferenceControllerTest {
public void displayPreference_shouldAddClickListener() {
mController.displayPreference(mScreen);
- verify(mFrameLayout, times(3)).setOnClickListener(any());
+ verify(mLinearLayout, times(3)).setOnClickListener(any());
}
@Test
@@ -110,6 +110,6 @@ public class ContrastSelectorPreferenceControllerTest {
mController.displayPreference(mScreen);
mController.onContrastChanged(1);
- verify(mFrameLayout, times(2)).setSelected(true);
+ verify(mLinearLayout, times(2)).setSelected(true);
}
}
diff --git a/tests/robotests/src/com/android/settings/datetime/TimeFeedbackPreferenceCategoryControllerTest.java b/tests/robotests/src/com/android/settings/datetime/TimeFeedbackPreferenceCategoryControllerTest.java
new file mode 100644
index 00000000000..1747f170bf4
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/datetime/TimeFeedbackPreferenceCategoryControllerTest.java
@@ -0,0 +1,97 @@
+/*
+ * 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.datetime;
+
+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 com.android.settingslib.core.AbstractPreferenceController;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.RuntimeEnvironment;
+
+@RunWith(RobolectricTestRunner.class)
+public class TimeFeedbackPreferenceCategoryControllerTest {
+
+ private TestTimeFeedbackPreferenceCategoryController mController;
+ @Mock private AbstractPreferenceController mChildController;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ Context context = RuntimeEnvironment.getApplication();
+
+ mController = new TestTimeFeedbackPreferenceCategoryController(context, "test_key");
+ mController.addChildController(mChildController);
+ }
+
+ @Test
+ public void getAvailabilityStatus_featureEnabledPrimary() {
+ mController.setTimeFeedbackFeatureEnabled(false);
+
+ when(mChildController.isAvailable()).thenReturn(true);
+
+ assertThat(mController.getAvailabilityStatus()).isEqualTo(UNSUPPORTED_ON_DEVICE);
+ }
+
+ @Test
+ public void getAvailabilityStatus_childControllerSecondary() {
+ mController.setTimeFeedbackFeatureEnabled(true);
+
+ when(mChildController.isAvailable()).thenReturn(false);
+
+ assertThat(mController.getAvailabilityStatus()).isEqualTo(UNSUPPORTED_ON_DEVICE);
+
+ when(mChildController.isAvailable()).thenReturn(true);
+
+ assertThat(mController.getAvailabilityStatus()).isEqualTo(AVAILABLE);
+ }
+
+ /**
+ * Extend class under test to change {@link #isTimeFeedbackFeatureEnabled} to not call
+ * {@link TimeFeedbackLaunchUtils} because that's non-trivial to fake.
+ */
+ private static class TestTimeFeedbackPreferenceCategoryController
+ extends TimeFeedbackPreferenceCategoryController {
+
+ private boolean mTimeFeedbackFeatureEnabled;
+
+ TestTimeFeedbackPreferenceCategoryController(Context context, String preferenceKey) {
+ super(context, preferenceKey);
+ }
+
+ void setTimeFeedbackFeatureEnabled(boolean value) {
+ this.mTimeFeedbackFeatureEnabled = value;
+ }
+
+ @Override
+ protected boolean isTimeFeedbackFeatureEnabled() {
+ return mTimeFeedbackFeatureEnabled;
+ }
+ }
+}
diff --git a/tests/robotests/src/com/android/settings/datetime/TimeFeedbackPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/datetime/TimeFeedbackPreferenceControllerTest.java
new file mode 100644
index 00000000000..f60e8319cb7
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/datetime/TimeFeedbackPreferenceControllerTest.java
@@ -0,0 +1,90 @@
+/*
+ * 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.datetime;
+
+import static com.android.settings.core.BasePreferenceController.UNSUPPORTED_ON_DEVICE;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+
+import android.app.Activity;
+import android.content.Context;
+import android.content.Intent;
+
+import androidx.preference.Preference;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.robolectric.Robolectric;
+import org.robolectric.RobolectricTestRunner;
+
+@RunWith(RobolectricTestRunner.class)
+public class TimeFeedbackPreferenceControllerTest {
+
+ private Context mContext;
+
+ @Before
+ public void setUp() {
+ mContext = spy(Robolectric.setupActivity(Activity.class));
+ }
+
+ @Test
+ public void emptyIntentUri_controllerNotAvailable() {
+ String emptyIntentUri = "";
+ TimeFeedbackPreferenceController controller =
+ new TimeFeedbackPreferenceController(mContext, "test_key", emptyIntentUri);
+ assertThat(controller.getAvailabilityStatus()).isEqualTo(UNSUPPORTED_ON_DEVICE);
+ }
+
+ @Test
+ public void clickPreference() {
+ Preference preference = new Preference(mContext);
+
+ String intentUri =
+ "intent:#Intent;"
+ + "action=com.android.settings.test.LAUNCH_USER_FEEDBACK;"
+ + "package=com.android.settings.test.target;"
+ + "end";
+ TimeFeedbackPreferenceController controller =
+ new TimeFeedbackPreferenceController(mContext, "test_key", intentUri);
+
+ // Click a preference that's not controlled by this controller.
+ preference.setKey("fake_key");
+ assertThat(controller.handlePreferenceTreeClick(preference)).isFalse();
+
+ // Check for startActivity() call.
+ verify(mContext, never()).startActivity(any());
+
+ // Click a preference controlled by this controller.
+ preference.setKey(controller.getPreferenceKey());
+ assertThat(controller.handlePreferenceTreeClick(preference)).isTrue();
+
+ // Check for startActivity() call.
+ ArgumentCaptor intentCaptor = ArgumentCaptor.forClass(Intent.class);
+ verify(mContext).startActivity(intentCaptor.capture());
+ Intent actualIntent = intentCaptor.getValue();
+ assertThat(actualIntent.getAction()).isEqualTo(
+ "com.android.settings.test.LAUNCH_USER_FEEDBACK");
+ assertThat(actualIntent.getPackage()).isEqualTo("com.android.settings.test.target");
+ }
+}
diff --git a/tests/robotests/src/com/android/settings/display/EvenDimmerPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/display/EvenDimmerPreferenceControllerTest.java
index af84ac06c5a..e3505872d11 100644
--- a/tests/robotests/src/com/android/settings/display/EvenDimmerPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/display/EvenDimmerPreferenceControllerTest.java
@@ -36,6 +36,7 @@ import android.provider.Settings;
import com.android.server.display.feature.flags.Flags;
import org.junit.Before;
+import org.junit.Ignore;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -85,6 +86,7 @@ public class EvenDimmerPreferenceControllerTest {
Settings.Secure.EVEN_DIMMER_ACTIVATED)).isEqualTo(0.0f); // false
}
+ @Ignore("b/331324279")
@RequiresFlagsEnabled(Flags.FLAG_EVEN_DIMMER)
@Test
public void testGetAvailabilityStatus_flagOnConfigTrue() {
@@ -97,6 +99,7 @@ public class EvenDimmerPreferenceControllerTest {
assertThat(mController.getAvailabilityStatus()).isEqualTo(AVAILABLE);
}
+ @Ignore("b/331324279")
@Test
@RequiresFlagsEnabled(Flags.FLAG_EVEN_DIMMER)
public void testSetChecked_enable() throws Settings.SettingNotFoundException {
@@ -113,6 +116,7 @@ public class EvenDimmerPreferenceControllerTest {
Settings.Secure.EVEN_DIMMER_ACTIVATED)).isEqualTo(0.0f); // false
}
+ @Ignore("b/331324279")
@Test
@RequiresFlagsEnabled(Flags.FLAG_EVEN_DIMMER)
public void testDisabledIfAutobrightnessIsOff() {
diff --git a/tests/robotests/src/com/android/settings/homepage/SettingsHomepageActivityTest.java b/tests/robotests/src/com/android/settings/homepage/SettingsHomepageActivityTest.java
index 6431306cbc3..0d1ee9c7caa 100644
--- a/tests/robotests/src/com/android/settings/homepage/SettingsHomepageActivityTest.java
+++ b/tests/robotests/src/com/android/settings/homepage/SettingsHomepageActivityTest.java
@@ -38,6 +38,7 @@ import android.content.Intent;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.Build;
+import android.provider.Settings;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
@@ -54,6 +55,7 @@ import com.android.settings.testutils.shadow.ShadowUserManager;
import com.android.settingslib.core.lifecycle.HideNonSystemOverlayMixin;
import org.junit.After;
+import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -80,11 +82,28 @@ public class SettingsHomepageActivityTest {
@Rule
public final MockitoRule mMockitoRule = MockitoJUnit.rule();
+ @Before
+ public void setup() {
+ Settings.Global.putInt(ApplicationProvider.getApplicationContext().getContentResolver(),
+ Settings.Global.DEVICE_PROVISIONED, 1);
+ }
+
@After
public void tearDown() {
ShadowPasswordUtils.reset();
}
+ @Test
+ public void launch_deviceUnprovisioned_finish() {
+ Settings.Global.putInt(ApplicationProvider.getApplicationContext().getContentResolver(),
+ Settings.Global.DEVICE_PROVISIONED, 0);
+
+ SettingsHomepageActivity activity = Robolectric.buildActivity(
+ SettingsHomepageActivity.class).create().get();
+
+ assertThat(activity.isFinishing()).isTrue();
+ }
+
@Test
public void launch_shouldHaveAnimationForIaFragment() {
final SettingsHomepageActivity activity = Robolectric.buildActivity(
diff --git a/tests/robotests/src/com/android/settings/notification/zen/ZenModeEventRuleSettingsTest.java b/tests/robotests/src/com/android/settings/notification/zen/ZenModeEventRuleSettingsTest.java
index f6df04d2767..05c3603b1ca 100644
--- a/tests/robotests/src/com/android/settings/notification/zen/ZenModeEventRuleSettingsTest.java
+++ b/tests/robotests/src/com/android/settings/notification/zen/ZenModeEventRuleSettingsTest.java
@@ -16,17 +16,26 @@
package com.android.settings.notification.zen;
+import static android.platform.test.flag.junit.SetFlagsRule.DefaultInitValueType.DEVICE_DEFAULT;
+
import static com.google.common.truth.Truth.assertThat;
+import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
+import android.app.AutomaticZenRule;
+import android.app.Flags;
import android.content.Context;
import android.content.Intent;
import android.content.res.Resources;
+import android.net.Uri;
import android.os.Looper;
+import android.platform.test.annotations.EnableFlags;
+import android.platform.test.flag.junit.SetFlagsRule;
+import android.service.notification.ZenModeConfig;
import androidx.fragment.app.FragmentActivity;
import androidx.test.core.app.ApplicationProvider;
@@ -34,6 +43,7 @@ import androidx.test.core.app.ApplicationProvider;
import com.android.settings.R;
import org.junit.Before;
+import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
@@ -51,11 +61,15 @@ import java.util.List;
})
public class ZenModeEventRuleSettingsTest {
- @Mock
- private FragmentActivity mActivity;
+ @Rule
+ public final SetFlagsRule mSetFlagsRule = new SetFlagsRule(DEVICE_DEFAULT);
+ @Mock
+ private FragmentActivity mActivity;
@Mock
private Intent mIntent;
+ @Mock
+ private ZenModeBackend mBackend;
private ZenModeEventRuleSettings mFragment;
private Context mContext;
@@ -92,6 +106,26 @@ public class ZenModeEventRuleSettingsTest {
//should not crash
}
+ @Test
+ @EnableFlags({Flags.FLAG_MODES_API, Flags.FLAG_MODES_UI})
+ public void updateEventRule_updatesConditionAndTriggerDescription() {
+ mFragment.setBackend(mBackend);
+ mFragment.mId = "id";
+ mFragment.mRule = new AutomaticZenRule.Builder("name", Uri.parse("condition")).build();
+
+ ZenModeConfig.EventInfo eventInfo = new ZenModeConfig.EventInfo();
+ eventInfo.calendarId = 1L;
+ eventInfo.calName = "My events";
+ mFragment.updateEventRule(eventInfo);
+
+ verify(mBackend).updateZenRule(eq("id"),
+ eq(new AutomaticZenRule.Builder(
+ "name",
+ ZenModeConfig.toEventConditionId(eventInfo))
+ .setTriggerDescription("My events")
+ .build()));
+ }
+
@Test
public void testNoDuplicateCalendars() {
List calendarsList = new ArrayList<>();
diff --git a/tests/robotests/src/com/android/settings/notification/zen/ZenModeScheduleRuleSettingsTest.java b/tests/robotests/src/com/android/settings/notification/zen/ZenModeScheduleRuleSettingsTest.java
index 4361eb3ded2..90e44e6e193 100644
--- a/tests/robotests/src/com/android/settings/notification/zen/ZenModeScheduleRuleSettingsTest.java
+++ b/tests/robotests/src/com/android/settings/notification/zen/ZenModeScheduleRuleSettingsTest.java
@@ -16,17 +16,26 @@
package com.android.settings.notification.zen;
+import static android.platform.test.flag.junit.SetFlagsRule.DefaultInitValueType.DEVICE_DEFAULT;
+
import static com.google.common.truth.Truth.assertThat;
+import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
+import android.app.AutomaticZenRule;
+import android.app.Flags;
import android.content.Context;
import android.content.Intent;
import android.content.res.Resources;
+import android.net.Uri;
import android.os.Looper;
+import android.platform.test.annotations.EnableFlags;
+import android.platform.test.flag.junit.SetFlagsRule;
+import android.service.notification.ZenModeConfig;
import androidx.fragment.app.FragmentActivity;
import androidx.test.core.app.ApplicationProvider;
@@ -34,25 +43,33 @@ import androidx.test.core.app.ApplicationProvider;
import com.android.settings.R;
import org.junit.Before;
+import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.annotation.Config;
import org.robolectric.shadows.ShadowToast;
+import java.util.Calendar;
+
@RunWith(RobolectricTestRunner.class)
@Config(shadows = {
com.android.settings.testutils.shadow.ShadowFragment.class,
})
public class ZenModeScheduleRuleSettingsTest {
- @Mock
- private FragmentActivity mActivity;
+ @Rule
+ public final SetFlagsRule mSetFlagsRule = new SetFlagsRule(DEVICE_DEFAULT);
+ @Mock
+ private FragmentActivity mActivity;
@Mock
private Intent mIntent;
+ @Mock
+ private ZenModeBackend mBackend;
private ZenModeScheduleRuleSettings mFragment;
private Context mContext;
@@ -88,4 +105,25 @@ public class ZenModeScheduleRuleSettingsTest {
//should not crash
}
+
+ @Test
+ @EnableFlags({Flags.FLAG_MODES_API, Flags.FLAG_MODES_UI})
+ public void updateScheduleRule_updatesConditionAndTriggerDescription() {
+ mFragment.setBackend(mBackend);
+ mFragment.mId = "id";
+ mFragment.mRule = new AutomaticZenRule.Builder("name", Uri.parse("condition")).build();
+
+ ZenModeConfig.ScheduleInfo scheduleInfo = new ZenModeConfig.ScheduleInfo();
+ scheduleInfo.days = new int[] { Calendar.MONDAY };
+ scheduleInfo.startHour = 1;
+ scheduleInfo.endHour = 2;
+ mFragment.updateScheduleRule(scheduleInfo);
+
+ ArgumentCaptor updatedRuleCaptor = ArgumentCaptor.forClass(
+ AutomaticZenRule.class);
+ verify(mBackend).updateZenRule(eq("id"), updatedRuleCaptor.capture());
+ assertThat(updatedRuleCaptor.getValue().getConditionId())
+ .isEqualTo(ZenModeConfig.toScheduleConditionId(scheduleInfo));
+ assertThat(updatedRuleCaptor.getValue().getTriggerDescription()).isNotEmpty();
+ }
}
diff --git a/tests/spa_unit/src/com/android/settings/spa/app/specialaccess/BackupTasksAppsPreferenceControllerTest.kt b/tests/spa_unit/src/com/android/settings/spa/app/specialaccess/BackupTasksAppsPreferenceControllerTest.kt
index 38f81fe8da8..9473b042e42 100644
--- a/tests/spa_unit/src/com/android/settings/spa/app/specialaccess/BackupTasksAppsPreferenceControllerTest.kt
+++ b/tests/spa_unit/src/com/android/settings/spa/app/specialaccess/BackupTasksAppsPreferenceControllerTest.kt
@@ -55,7 +55,8 @@ class BackupTasksAppsPreferenceControllerTest {
@Test
@RequiresFlagsEnabled(Flags.FLAG_ENABLE_PERFORM_BACKUP_TASKS_IN_SETTINGS)
fun getAvailabilityStatus_enableBackupTasksApps_returnAvailable() {
- assertThat(controller.isAvailable).isTrue()
+ // Feature is currently disabled so it should return false regardless of flag status.
+ assertThat(controller.isAvailable).isFalse()
}
@Test
diff --git a/tests/unit/src/com/android/settings/development/widevine/ForceL3FallbackPreferenceControllerTest.java b/tests/unit/src/com/android/settings/development/mediadrm/ForceSwSecureCryptoFallbackPreferenceControllerTest.java
similarity index 91%
rename from tests/unit/src/com/android/settings/development/widevine/ForceL3FallbackPreferenceControllerTest.java
rename to tests/unit/src/com/android/settings/development/mediadrm/ForceSwSecureCryptoFallbackPreferenceControllerTest.java
index f67a4af84fb..595ded92cee 100644
--- a/tests/unit/src/com/android/settings/development/widevine/ForceL3FallbackPreferenceControllerTest.java
+++ b/tests/unit/src/com/android/settings/development/mediadrm/ForceSwSecureCryptoFallbackPreferenceControllerTest.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.settings.development.widevine;
+package com.android.settings.development.mediadrm;
import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assume.assumeTrue;
@@ -43,23 +43,23 @@ import org.junit.runner.RunWith;
import java.util.UUID;
@RunWith(AndroidJUnit4.class)
-public class ForceL3FallbackPreferenceControllerTest {
+public class ForceSwSecureCryptoFallbackPreferenceControllerTest {
- private static final String PREF_KEY = "force_l3_fallback";
+ private static final String PREF_KEY = "force_swcrypto_fallback";
private static final UUID WIDEVINE_UUID =
new UUID(0xEDEF8BA979D64ACEL, 0xA3C827DCD51D21EDL);
- private static final String TAG = "ForceL3FallbackPreferenceControllerTest";
+ private static final String TAG = "ForceSwSecureCryptoFallbackPreferenceControllerTest";
@Rule public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
private Context mContext;
- private ForceL3FallbackPreferenceController mController;
+ private ForceSwSecureCryptoFallbackPreferenceController mController;
private SwitchPreference mPreference;
@Before
public void setUp() {
mContext = ApplicationProvider.getApplicationContext();
- mController = new ForceL3FallbackPreferenceController(mContext, PREF_KEY);
+ mController = new ForceSwSecureCryptoFallbackPreferenceController(mContext, PREF_KEY);
mPreference = new SwitchPreference(mContext);
WidevineProperties.forcel3_enabled(false);
}