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); }