diff --git a/aconfig/settings_biometrics_integration_declarations.aconfig b/aconfig/settings_biometrics_integration_declarations.aconfig index 9bded6a79ce..0ad028ef0a4 100644 --- a/aconfig/settings_biometrics_integration_declarations.aconfig +++ b/aconfig/settings_biometrics_integration_declarations.aconfig @@ -15,6 +15,16 @@ flag { bug: "301226085" } +flag { + name: "enroll_layout_truncate_improvement" + namespace: "biometrics_integration" + description: "This flag controls whether the enroll layout truncate improvement feature should be enabled" + bug: "359149850" + metadata { + purpose: PURPOSE_BUGFIX + } +} + flag { name: "screen_off_unlock_power_optimization" namespace: "biometrics_integration" diff --git a/res/layout/biometrics_glif_compact.xml b/res/layout/biometrics_glif_compact.xml new file mode 100644 index 00000000000..5de78dae724 --- /dev/null +++ b/res/layout/biometrics_glif_compact.xml @@ -0,0 +1,26 @@ + + + + + + + + diff --git a/res/layout/biometrics_glif_content.xml b/res/layout/biometrics_glif_content.xml new file mode 100644 index 00000000000..6cddccb4da1 --- /dev/null +++ b/res/layout/biometrics_glif_content.xml @@ -0,0 +1,82 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/res/layout/udfps_enroll_enrolling.xml b/res/layout/udfps_enroll_enrolling.xml index 366a87c4740..ef8cb71729d 100644 --- a/res/layout/udfps_enroll_enrolling.xml +++ b/res/layout/udfps_enroll_enrolling.xml @@ -24,58 +24,66 @@ android:layout_height="match_parent" style="?attr/fingerprint_layout_theme"> - + android:clipChildren="false"> + + - + - - + - + - + - - - + + + + diff --git a/res/layout/udfps_enroll_enrolling_non_scroll.xml b/res/layout/udfps_enroll_enrolling_non_scroll.xml new file mode 100644 index 00000000000..deb90919a0d --- /dev/null +++ b/res/layout/udfps_enroll_enrolling_non_scroll.xml @@ -0,0 +1,81 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/res/menu/language_selection_list.xml b/res/menu/language_selection_list.xml new file mode 100644 index 00000000000..799d3c97c4a --- /dev/null +++ b/res/menu/language_selection_list.xml @@ -0,0 +1,25 @@ + + + + + + + diff --git a/res/values/config.xml b/res/values/config.xml index 09f941ff757..4e4c5c4c1c0 100644 --- a/res/values/config.xml +++ b/res/values/config.xml @@ -772,6 +772,9 @@ 58.0001 29.2229,56.9551 26.8945,55.195 + + 1000 + false diff --git a/res/values/dimens.xml b/res/values/dimens.xml index 5961b95a606..96bbaed9b5b 100755 --- a/res/values/dimens.xml +++ b/res/values/dimens.xml @@ -159,6 +159,10 @@ -24dp 0dp 20dp + 274dp + 0.27 + + 0.37 0 diff --git a/res/values/strings.xml b/res/values/strings.xml index 8b5e63f4329..54b7f67b338 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -402,6 +402,18 @@ All languages + + Suggested + + + All languages + + + All regions + + + All numbering systems + System language @@ -450,6 +462,15 @@ This language can’t be used as a system language, but you’ve let apps and websites know you prefer this language. + + Search + + Add a language + + Region preference + + Type language name + Regional preferences diff --git a/res/xml/my_device_info.xml b/res/xml/my_device_info.xml index aec064b599f..1a9e646b509 100644 --- a/res/xml/my_device_info.xml +++ b/res/xml/my_device_info.xml @@ -64,6 +64,7 @@ @@ -157,6 +158,7 @@ diff --git a/res/xml/power_usage_summary.xml b/res/xml/power_usage_summary.xml index 77c6b7322c2..794061a7e50 100644 --- a/res/xml/power_usage_summary.xml +++ b/res/xml/power_usage_summary.xml @@ -59,7 +59,7 @@ settings:keywords="@string/keywords_battery_adaptive_preferences" /> diff --git a/res/xml/system_language_picker.xml b/res/xml/system_language_picker.xml new file mode 100644 index 00000000000..cccf56ea063 --- /dev/null +++ b/res/xml/system_language_picker.xml @@ -0,0 +1,30 @@ + + + + + + + + + + diff --git a/src/com/android/settings/SettingsService.kt b/src/com/android/settings/SettingsService.kt index 2cd706b9b14..33385280ed9 100644 --- a/src/com/android/settings/SettingsService.kt +++ b/src/com/android/settings/SettingsService.kt @@ -16,15 +16,31 @@ package com.android.settings +import android.app.Application import android.content.Intent -import android.os.IBinder import com.android.settings.flags.Flags +import com.android.settingslib.graph.PreferenceSetterRequest +import com.android.settingslib.ipc.ApiPermissionChecker import com.android.settingslib.service.PreferenceService /** Service to expose settings APIs. */ -class SettingsService : PreferenceService({ _, _, _ -> true }) { +class SettingsService : + PreferenceService( + graphPermissionChecker = ApiPermissionChecker.alwaysAllow(), + setterPermissionChecker = SetterPermissionChecker(), + ) { - override fun onBind(intent: Intent): IBinder? { - return if (!Flags.catalystService()) null else super.onBind(intent) - } + override fun onBind(intent: Intent) = + if (Flags.catalystService()) super.onBind(intent) else null +} + +/** Permission checker for external setter API. */ +private class SetterPermissionChecker : ApiPermissionChecker { + + override fun hasPermission( + application: Application, + myUid: Int, + callingUid: Int, + request: PreferenceSetterRequest, + ) = true } diff --git a/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollEnrolling.java b/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollEnrolling.java index 03010bbe739..1de8379bd76 100644 --- a/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollEnrolling.java +++ b/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollEnrolling.java @@ -57,6 +57,7 @@ import android.view.animation.AnimationUtils; import android.view.animation.Interpolator; import android.widget.ProgressBar; import android.widget.RelativeLayout; +import android.widget.ScrollView; import android.widget.TextView; import androidx.annotation.IdRes; @@ -72,6 +73,7 @@ import com.android.settings.biometrics.BiometricsEnrollEnrolling; import com.android.settings.biometrics.BiometricsSplitScreenDialog; import com.android.settings.biometrics.fingerprint.feature.SfpsEnrollmentFeature; import com.android.settings.core.instrumentation.InstrumentedDialogFragment; +import com.android.settings.flags.Flags; import com.android.settings.overlay.FeatureFactory; import com.android.settingslib.display.DisplayDensityUtils; import com.android.systemui.unfold.compat.ScreenSizeFoldProvider; @@ -243,16 +245,36 @@ public class FingerprintEnrollEnrolling extends BiometricsEnrollEnrolling { mIsAccessibilityEnabled = mAccessibilityManager.isEnabled(); listenOrientationEvent(); - if (mCanAssumeUdfps) { + final int rotation = getApplicationContext().getDisplay().getRotation(); + final boolean isPortrait = (rotation == Surface.ROTATION_0) + || (rotation == Surface.ROTATION_180); + final UdfpsEnrollEnrollingView layout = (UdfpsEnrollEnrollingView) getLayoutInflater().inflate( - R.layout.udfps_enroll_enrolling, null, false); + Flags.enrollLayoutTruncateImprovement() + ? R.layout.udfps_enroll_enrolling : + R.layout.udfps_enroll_enrolling_non_scroll, null, false); setUdfpsEnrollHelper(); layout.initView(props.get(0), mUdfpsEnrollHelper, mAccessibilityManager); - setContentView(layout); setDescriptionText(R.string.security_settings_udfps_enroll_start_message); + + if (Flags.enrollLayoutTruncateImprovement() && isPortrait) { + final UdfpsEnrollEnrollingView layoutView = (UdfpsEnrollEnrollingView) getLayout(); + if (layoutView != null) { + final ScrollView headerScrollView = layout.findViewById( + R.id.sud_header_scroll_view); + if (headerScrollView != null) { + final long headerScrollDuration = getResources().getInteger( + R.integer.config_biometrics_header_scroll_duration); + layoutView.adjustScrollableHeaderHeight( + headerScrollView, mShouldShowLottie); + layoutView.headerVerticalScrolling(headerScrollView, headerScrollDuration); + } + } + } + } else if (mCanAssumeSfps) { mSfpsEnrollmentFeature = FeatureFactory.getFeatureFactory() .getFingerprintFeatureProvider().getSfpsEnrollmentFeature(); @@ -1199,6 +1221,24 @@ public class FingerprintEnrollEnrolling extends BiometricsEnrollEnrolling { } } + @Override + public void onWindowFocusChanged(boolean hasWindowFocus) { + super.onWindowFocusChanged(hasWindowFocus); + if (Flags.enrollLayoutTruncateImprovement()) { + adjustEnrollViewIfOverlappedWithFooterBar(); + } + } + + private void adjustEnrollViewIfOverlappedWithFooterBar() { + if (mCanAssumeUdfps) { + final UdfpsEnrollEnrollingView layoutView = (UdfpsEnrollEnrollingView) getLayout(); + if (layoutView != null) { + layoutView.adjustUdfpsVieWithFooterBar(); + layoutView.onUdfpsSensorRectUpdated(); + } + } + } + public static class IconTouchDialog extends InstrumentedDialogFragment { @Override diff --git a/src/com/android/settings/biometrics/fingerprint/UdfpsEnrollEnrollingView.java b/src/com/android/settings/biometrics/fingerprint/UdfpsEnrollEnrollingView.java index c28f9e0e761..5b29fa5f1f6 100644 --- a/src/com/android/settings/biometrics/fingerprint/UdfpsEnrollEnrollingView.java +++ b/src/com/android/settings/biometrics/fingerprint/UdfpsEnrollEnrollingView.java @@ -16,27 +16,42 @@ package com.android.settings.biometrics.fingerprint; +import android.animation.Animator; +import android.animation.ObjectAnimator; import android.content.Context; +import android.content.res.Configuration; +import android.content.res.TypedArray; +import android.graphics.Insets; import android.graphics.Point; import android.graphics.Rect; import android.hardware.fingerprint.FingerprintSensorPropertiesInternal; import android.text.TextUtils; import android.util.AttributeSet; +import android.util.DisplayMetrics; +import android.util.TypedValue; +import android.view.Display; import android.view.DisplayInfo; import android.view.Gravity; +import android.view.LayoutInflater; import android.view.Surface; import android.view.View; import android.view.ViewGroup; +import android.view.WindowInsets; +import android.view.WindowManager; import android.view.accessibility.AccessibilityManager; import android.widget.Button; import android.widget.FrameLayout; import android.widget.ImageView; import android.widget.LinearLayout; +import android.widget.ScrollView; import androidx.annotation.ColorInt; +import androidx.annotation.LayoutRes; +import androidx.annotation.NonNull; +import androidx.annotation.VisibleForTesting; -import com.android.internal.annotations.VisibleForTesting; import com.android.settings.R; +import com.android.settings.flags.Flags; import com.android.systemui.biometrics.UdfpsUtils; import com.android.systemui.biometrics.shared.model.UdfpsOverlayParams; @@ -50,6 +65,7 @@ import java.util.Locale; * View for udfps enrolling. */ public class UdfpsEnrollEnrollingView extends GlifLayout { + private final UdfpsUtils mUdfpsUtils; private final Context mContext; // We don't need to listen to onConfigurationChanged() for mRotation here because @@ -57,14 +73,19 @@ public class UdfpsEnrollEnrollingView extends GlifLayout { private final int mRotation; private final boolean mIsLandscape; private final boolean mShouldUseReverseLandscape; + + private WindowManager mWindowManager; + private UdfpsEnrollView mUdfpsEnrollView; private View mHeaderView; private AccessibilityManager mAccessibilityManager; + private ObjectAnimator mHeaderScrollAnimator; public UdfpsEnrollEnrollingView(Context context, AttributeSet attrs) { super(context, attrs); mContext = context; + mWindowManager = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE); mRotation = mContext.getDisplay().getRotation(); mIsLandscape = mRotation == Surface.ROTATION_90 || mRotation == Surface.ROTATION_270; final boolean isLayoutRtl = (TextUtils.getLayoutDirectionFromLocale(Locale.getDefault()) @@ -82,6 +103,139 @@ public class UdfpsEnrollEnrollingView extends GlifLayout { mUdfpsEnrollView = findViewById(R.id.udfps_animation_view); } + @Override + protected View onInflateTemplate(LayoutInflater inflater, @LayoutRes int template) { + final Configuration config = inflater.getContext().getResources().getConfiguration(); + if (Flags.enrollLayoutTruncateImprovement() + && config.orientation == Configuration.ORIENTATION_PORTRAIT) { + template = R.layout.biometrics_glif_compact; + } + return super.onInflateTemplate(inflater, template); + } + + void setDecreasePadding(int decreasePadding) { + if (mUdfpsEnrollView != null) { + mUdfpsEnrollView.setDecreasePadding(decreasePadding); + } + } + + void onUdfpsSensorRectUpdated() { + if (mUdfpsEnrollView != null) { + mUdfpsEnrollView.setVisibility(VISIBLE); + } + } + + private int getScrollableGlifHeaderHeight(boolean isShouldShowLottie) { + final TypedValue tvRatio = new TypedValue(); + if (isLargeDisplaySizeOrFontSize() && !isShouldShowLottie) { + getResources().getValue( + R.dimen.biometrics_glif_header_height_ratio_large, tvRatio, true); + } else { + getResources().getValue(R.dimen.biometrics_glif_header_height_ratio, tvRatio, true); + } + final float newHeaderHeight = (float) getResources().getDisplayMetrics().heightPixels + * tvRatio.getFloat(); + + return (int) newHeaderHeight; + } + + void adjustScrollableHeaderHeight(ScrollView headerScrollView, boolean isShouldShowLottie) { + ViewGroup.LayoutParams params = headerScrollView.getLayoutParams(); + params.height = getScrollableGlifHeaderHeight(isShouldShowLottie); + headerScrollView.setLayoutParams(params); + } + + private boolean isLargeDisplaySizeOrFontSize() { + final Configuration config = getResources().getConfiguration(); + if (config.fontScale > 1.3f || getLargeDisplayScale() >= 2.8f) { + return true; + } + return false; + } + + private float getLargeDisplayScale() { + final Display display = mWindowManager.getDefaultDisplay(); + final DisplayMetrics metrics = new DisplayMetrics(); + display.getMetrics(metrics); + return metrics.scaledDensity; + } + + void adjustUdfpsVieWithFooterBar() { + final FrameLayout allContent = findViewById(R.id.suc_layout_status); + final ImageView udfpsProgressView = findViewById( + R.id.udfps_enroll_animation_fp_progress_view); + + final int navigationBarHeight = getNaviBarHeight(); + final int footerBarHeight = getFooterBarHeight(); + + final int udfpsProgressDrawableBottom = getOnScreenPositionTop(udfpsProgressView) + + udfpsProgressView.getDrawable().getBounds().height() + - udfpsProgressView.getPaddingBottom() + 2 /* reserved for more space */; + final int footerBarTop = getOnScreenPositionTop(allContent) + allContent.getHeight() + - (footerBarHeight + navigationBarHeight); + + if (udfpsProgressDrawableBottom > footerBarTop) { + int adjustPadding = udfpsProgressDrawableBottom - footerBarTop; + setDecreasePadding(adjustPadding); + } + } + + private int getOnScreenPositionTop(View view) { + int [] location = new int[2]; + view.getLocationOnScreen(location); + return location[1]; + } + + private int getNaviBarHeight() { + final Insets inset = mWindowManager.getMaximumWindowMetrics().getWindowInsets().getInsets( + WindowInsets.Type.navigationBars()); + return inset.toRect().height(); + } + + private int getFooterBarHeight() { + TypedArray a = mContext.getTheme().obtainStyledAttributes(new int[] { + com.google.android.setupcompat.R.attr.sucFooterBarMinHeight}); + final int footerBarMinHeight = a.getDimensionPixelSize(0, -1); + a.recycle(); + return footerBarMinHeight; + } + + void headerVerticalScrolling(ScrollView headerScrollView, long duration) { + headerScrollView.post(new Runnable() { + @Override + public void run() { + final int maxScroll = headerScrollView.getChildAt(0).getMeasuredHeight() + - headerScrollView.getMeasuredHeight(); + mHeaderScrollAnimator = ObjectAnimator.ofInt( + headerScrollView, "scrollY", maxScroll); + mHeaderScrollAnimator.setDuration(duration); + mHeaderScrollAnimator.addListener(new Animator.AnimatorListener() { + + @Override + public void onAnimationStart(@NonNull Animator animation) {} + + @Override + public void onAnimationEnd(@NonNull Animator animation) { + mHeaderScrollAnimator.removeAllListeners(); + headerScrollView.post(new Runnable() { + @Override + public void run() { + mHeaderScrollAnimator.reverse(); + } + }); + } + + @Override + public void onAnimationCancel(@NonNull Animator animation) {} + + @Override + public void onAnimationRepeat(@NonNull Animator animation) {} + }); + mHeaderScrollAnimator.start(); + } + }); + } + void initView(FingerprintSensorPropertiesInternal udfpsProps, UdfpsEnrollHelper udfpsEnrollHelper, AccessibilityManager accessibilityManager) { @@ -93,7 +247,7 @@ public class UdfpsEnrollEnrollingView extends GlifLayout { } else if (mShouldUseReverseLandscape) { swapHeaderAndContent(); } - mUdfpsEnrollView.setVisibility(View.VISIBLE); + mUdfpsEnrollView.setVisibility(View.INVISIBLE); setOnHoverListener(); } @@ -166,17 +320,6 @@ public class UdfpsEnrollEnrollingView extends GlifLayout { R.id.udfps_enroll_animation_fp_view); fingerprintView.setPadding(0, -layoutLottieAnimationPadding, 0, layoutLottieAnimationPadding); - - // TODO(b/260970216) Instead of hiding the description text view, we should - // make the header view scrollable if the text is too long. - // If description text view has overlap with udfps progress view, hide it. - final View descView = getDescriptionTextView(); - getViewTreeObserver().addOnDrawListener(() -> { - if (descView.getVisibility() == View.VISIBLE - && hasOverlap(descView, mUdfpsEnrollView)) { - descView.setVisibility(View.GONE); - } - }); } private void setOnHoverListener() { diff --git a/src/com/android/settings/biometrics/fingerprint/UdfpsEnrollView.java b/src/com/android/settings/biometrics/fingerprint/UdfpsEnrollView.java index 4a2a243d2d8..0c80b483661 100644 --- a/src/com/android/settings/biometrics/fingerprint/UdfpsEnrollView.java +++ b/src/com/android/settings/biometrics/fingerprint/UdfpsEnrollView.java @@ -133,6 +133,15 @@ public class UdfpsEnrollView extends FrameLayout implements UdfpsEnrollHelper.Li enrollHelper.setListener(this); } + /** + * Adjust progress bar radius only for decreasing. + * @param decreasePadding the decrease padding + */ + void setDecreasePadding(int decreasePadding) { + mProgressBarRadius -= decreasePadding; + onSensorRectUpdated(); + } + private void onSensorRectUpdated() { updateDimensions(); diff --git a/src/com/android/settings/display/BatteryPercentagePreferenceController.java b/src/com/android/settings/display/BatteryPercentagePreferenceController.java index a7113b3d490..b859c78af5f 100644 --- a/src/com/android/settings/display/BatteryPercentagePreferenceController.java +++ b/src/com/android/settings/display/BatteryPercentagePreferenceController.java @@ -35,6 +35,7 @@ import com.android.settings.overlay.FeatureFactory; * A controller to manage the switch for showing battery percentage in the status bar. */ +// LINT.IfChange public class BatteryPercentagePreferenceController extends BasePreferenceController implements PreferenceControllerMixin, Preference.OnPreferenceChangeListener { @@ -69,7 +70,7 @@ public class BatteryPercentagePreferenceController extends BasePreferenceControl int setting = Settings.System.getInt(mContext.getContentResolver(), SHOW_BATTERY_PERCENT, mContext.getResources().getBoolean( - R.bool.config_defaultBatteryPercentageSetting) ? 1 : 0); + R.bool.config_defaultBatteryPercentageSetting) ? 1 : 0); ((TwoStatePreference) preference).setChecked(setting == 1); } @@ -84,3 +85,4 @@ public class BatteryPercentagePreferenceController extends BasePreferenceControl return true; } } +// LINT.ThenChange(BatteryPercentageSwitchPreference.kt) diff --git a/src/com/android/settings/display/BatteryPercentageSwitchPreference.kt b/src/com/android/settings/display/BatteryPercentageSwitchPreference.kt new file mode 100644 index 00000000000..8571cf18c85 --- /dev/null +++ b/src/com/android/settings/display/BatteryPercentageSwitchPreference.kt @@ -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.display + +import android.app.settings.SettingsEnums +import android.content.Context +import android.provider.Settings +import androidx.preference.Preference +import com.android.settings.R +import com.android.settings.Utils +import com.android.settings.overlay.FeatureFactory.Companion.featureFactory +import com.android.settingslib.datastore.KeyValueStore +import com.android.settingslib.datastore.KeyedObservableDelegate +import com.android.settingslib.datastore.SettingsStore +import com.android.settingslib.datastore.SettingsSystemStore +import com.android.settingslib.metadata.PreferenceAvailabilityProvider +import com.android.settingslib.metadata.PreferenceMetadata +import com.android.settingslib.metadata.ReadWritePermit +import com.android.settingslib.metadata.SwitchPreference +import com.android.settingslib.preference.SwitchPreferenceBinding + +// LINT.IfChange +class BatteryPercentageSwitchPreference : + SwitchPreference(KEY, R.string.battery_percentage, R.string.battery_percentage_description), + SwitchPreferenceBinding, + PreferenceAvailabilityProvider, + Preference.OnPreferenceChangeListener { + + override fun storage(context: Context): KeyValueStore = + BatteryPercentageStorage(context, SettingsSystemStore.get(context)) + + override fun isAvailable(context: Context): Boolean = + Utils.isBatteryPresent(context) && + context.resources.getBoolean( + com.android.internal.R.bool.config_battery_percentage_setting_available + ) + + override fun getWritePermit(context: Context, value: Boolean?, myUid: Int, callingUid: Int) = + ReadWritePermit.ALLOW + + override fun bind(preference: Preference, metadata: PreferenceMetadata) { + super.bind(preference, metadata) + preference.onPreferenceChangeListener = this + } + + override fun onPreferenceChange(preference: Preference, newValue: Any?): Boolean { + val showPercentage = newValue as Boolean + + featureFactory.metricsFeatureProvider.action( + preference.context, + SettingsEnums.OPEN_BATTERY_PERCENTAGE, + showPercentage, + ) + return true + } + + @Suppress("UNCHECKED_CAST") + private class BatteryPercentageStorage( + private val context: Context, + private val settingsStore: SettingsStore, + ) : KeyedObservableDelegate(settingsStore), KeyValueStore { + + override fun contains(key: String) = settingsStore.contains(KEY) + + override fun getValue(key: String, valueType: Class) = + (settingsStore.getBoolean(key) ?: getDefaultValue(key, valueType)) as T + + override fun setValue(key: String, valueType: Class, value: T?) { + settingsStore.setBoolean(key, value as Boolean) + } + + override fun getDefaultValue(key: String, valueType: Class) = + context.resources.getBoolean( + com.android.internal.R.bool.config_defaultBatteryPercentageSetting + ) as T + } + + companion object { + const val KEY = Settings.System.SHOW_BATTERY_PERCENT + } +} +// LINT.ThenChange(BatteryPercentagePreferenceController.java) diff --git a/src/com/android/settings/fuelgauge/batterysaver/BatterySaverPreference.kt b/src/com/android/settings/fuelgauge/batterysaver/BatterySaverPreference.kt index f8c058ffdce..30ea369af41 100644 --- a/src/com/android/settings/fuelgauge/batterysaver/BatterySaverPreference.kt +++ b/src/com/android/settings/fuelgauge/batterysaver/BatterySaverPreference.kt @@ -31,6 +31,7 @@ import com.android.settingslib.fuelgauge.BatteryUtils import com.android.settingslib.metadata.MainSwitchPreference import com.android.settingslib.metadata.PreferenceLifecycleContext import com.android.settingslib.metadata.PreferenceLifecycleProvider +import com.android.settingslib.metadata.ReadWritePermit // LINT.IfChange class BatterySaverPreference : @@ -42,6 +43,9 @@ class BatterySaverPreference : override fun storage(context: Context) = BatterySaverStore(context) + override fun getWritePermit(context: Context, value: Boolean?, myUid: Int, callingUid: Int) = + ReadWritePermit.ALLOW + override fun isEnabled(context: Context) = !BatteryStatus(BatteryUtils.getBatteryIntent(context)).isPluggedIn diff --git a/src/com/android/settings/fuelgauge/batteryusage/PowerUsageSummaryScreen.kt b/src/com/android/settings/fuelgauge/batteryusage/PowerUsageSummaryScreen.kt index 229e3084081..b397bf3ded6 100644 --- a/src/com/android/settings/fuelgauge/batteryusage/PowerUsageSummaryScreen.kt +++ b/src/com/android/settings/fuelgauge/batteryusage/PowerUsageSummaryScreen.kt @@ -17,6 +17,7 @@ package com.android.settings.fuelgauge.batteryusage import android.content.Context import com.android.settings.R +import com.android.settings.display.BatteryPercentageSwitchPreference import com.android.settings.flags.Flags import com.android.settingslib.metadata.PreferenceAvailabilityProvider import com.android.settingslib.metadata.PreferenceIconProvider @@ -25,9 +26,8 @@ import com.android.settingslib.metadata.preferenceHierarchy import com.android.settingslib.preference.PreferenceScreenCreator @ProvidePreferenceScreen -class PowerUsageSummaryScreen : PreferenceScreenCreator, - PreferenceAvailabilityProvider, - PreferenceIconProvider { +class PowerUsageSummaryScreen : + PreferenceScreenCreator, PreferenceAvailabilityProvider, PreferenceIconProvider { override val key: String get() = KEY @@ -53,10 +53,10 @@ class PowerUsageSummaryScreen : PreferenceScreenCreator, R.drawable.ic_settings_battery_white } - - override fun getPreferenceHierarchy(context: Context) = preferenceHierarchy(this) {} + override fun getPreferenceHierarchy(context: Context) = + preferenceHierarchy(this) { +BatteryPercentageSwitchPreference() } companion object { const val KEY = "power_usage_summary_screen" } -} \ No newline at end of file +} diff --git a/src/com/android/settings/localepicker/SystemLocalePickerFragment.java b/src/com/android/settings/localepicker/SystemLocalePickerFragment.java new file mode 100644 index 00000000000..df3ae8454f4 --- /dev/null +++ b/src/com/android/settings/localepicker/SystemLocalePickerFragment.java @@ -0,0 +1,281 @@ +/** + * 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.localepicker; + +import android.app.Activity; +import android.app.settings.SettingsEnums; +import android.content.Context; +import android.os.Bundle; +import android.text.TextUtils; +import android.util.Log; +import android.view.LayoutInflater; +import android.view.Menu; +import android.view.MenuInflater; +import android.view.MenuItem; +import android.view.View; +import android.view.ViewGroup; +import android.widget.Filter; +import android.widget.SearchView; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.core.view.ViewCompat; +import androidx.preference.PreferenceCategory; +import androidx.recyclerview.widget.RecyclerView; + +import com.android.internal.app.LocaleHelper; +import com.android.internal.app.LocaleStore; +import com.android.internal.app.SystemLocaleCollector; +import com.android.settings.R; +import com.android.settings.dashboard.DashboardFragment; +import com.android.settings.search.BaseSearchIndexProvider; +import com.android.settingslib.core.AbstractPreferenceController; +import com.android.settingslib.core.lifecycle.Lifecycle; + +import com.google.android.material.appbar.AppBarLayout; + +import org.jetbrains.annotations.NotNull; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Locale; +import java.util.Set; + +/** + * A locale picker fragment to show system languages. + * + *

It shows suggestions at the top, then the rest of the locales. + * Allows the user to search for locales using both their native name and their name in the + * default locale.

+ */ +public class SystemLocalePickerFragment extends DashboardFragment implements + SearchView.OnQueryTextListener, MenuItem.OnActionExpandListener { + + private static final String TAG = "SystemLocalePickerFragment"; + private static final String EXTRA_EXPAND_SEARCH_VIEW = "expand_search_view"; + + @Nullable private SearchView mSearchView = null; + @Nullable private SearchFilter mSearchFilter = null; + @Nullable private Set mLocaleList; + @Nullable private List mLocaleOptions; + @Nullable private List mOriginalLocaleInfos; + private AppBarLayout mAppBarLayout; + private RecyclerView mRecyclerView; + private Activity mActivity; + private boolean mExpandSearch; + + @Override + public void onCreate(@NonNull Bundle icicle) { + super.onCreate(icicle); + mActivity = getActivity(); + if (mActivity.isFinishing()) { + return; + } + setHasOptionsMenu(true); + + mExpandSearch = mActivity.getIntent().getBooleanExtra(EXTRA_EXPAND_SEARCH_VIEW, false); + if (icicle != null) { + mExpandSearch = icicle.getBoolean(EXTRA_EXPAND_SEARCH_VIEW); + } + + SystemLocaleCollector systemLocaleCollector = new SystemLocaleCollector(getContext(), null); + mLocaleList = systemLocaleCollector.getSupportedLocaleList(null, false, false); + mLocaleOptions = new ArrayList<>(mLocaleList.size()); + } + + @Override + public @NonNull View onCreateView(@NonNull LayoutInflater inflater, + @NonNull ViewGroup container, @NonNull Bundle savedInstanceState) { + mAppBarLayout = mActivity.findViewById(R.id.app_bar); + return super.onCreateView(inflater, container, savedInstanceState); + } + + @Override + public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + mRecyclerView = view.findViewById(R.id.recycler_view); + } + + @Override + public void onSaveInstanceState(@NonNull Bundle outState) { + super.onSaveInstanceState(outState); + if (mSearchView != null) { + outState.putBoolean(EXTRA_EXPAND_SEARCH_VIEW, !mSearchView.isIconified()); + } + } + + @Override + public void onCreateOptionsMenu(@NonNull Menu menu, @NonNull MenuInflater inflater) { + super.onCreateOptionsMenu(menu, inflater); + inflater.inflate(R.menu.language_selection_list, menu); + final MenuItem searchMenuItem = menu.findItem(R.id.locale_search_menu); + if (searchMenuItem != null) { + searchMenuItem.setOnActionExpandListener(this); + mSearchView = (SearchView) searchMenuItem.getActionView(); + mSearchView.setQueryHint( + getContext().getResources().getText(R.string.search_language_hint)); + mSearchView.setOnQueryTextListener(this); + mSearchView.setMaxWidth(Integer.MAX_VALUE); + if (mExpandSearch) { + searchMenuItem.expandActionView(); + } + } + } + + private void filterSearch(@Nullable String query) { + if (mSearchFilter == null) { + mSearchFilter = new SearchFilter(); + } + + // TODO: b/30358431 - Add preference of system locales. + // mOriginalLocaleInfos = mSystemLocaleAllListPreferenceController.getSupportedLocaleList(); + // If we haven't load apps list completely, don't filter anything. + if (mOriginalLocaleInfos == null) { + Log.w(TAG, "Locales haven't loaded completely yet, so nothing can be filtered"); + return; + } + mSearchFilter.filter(query); + } + + private class SearchFilter extends Filter { + + @Override + protected FilterResults performFiltering(CharSequence prefix) { + FilterResults results = new FilterResults(); + + if (mOriginalLocaleInfos == null) { + mOriginalLocaleInfos = new ArrayList<>(mLocaleList); + } + + if (TextUtils.isEmpty(prefix)) { + results.values = mOriginalLocaleInfos; + results.count = mOriginalLocaleInfos.size(); + } else { + // TODO: decide if we should use the string's locale + Locale locale = Locale.getDefault(); + String prefixString = LocaleHelper.normalizeForSearch(prefix.toString(), locale); + + final int count = mOriginalLocaleInfos.size(); + final ArrayList newValues = new ArrayList<>(); + + for (int i = 0; i < count; i++) { + final LocaleStore.LocaleInfo value = mOriginalLocaleInfos.get(i); + final String nameToCheck = LocaleHelper.normalizeForSearch( + value.getFullNameInUiLanguage(), locale); + final String nativeNameToCheck = LocaleHelper.normalizeForSearch( + value.getFullNameNative(), locale); + if ((wordMatches(nativeNameToCheck, prefixString) + || wordMatches(nameToCheck, prefixString)) && !newValues.contains( + value)) { + newValues.add(value); + } + } + + results.values = newValues; + results.count = newValues.size(); + } + + return results; + } + + @Override + protected void publishResults(CharSequence constraint, FilterResults results) { + mLocaleOptions = (ArrayList) results.values; + // Need to scroll to first preference when searching. + if (mRecyclerView != null) { + mRecyclerView.post(() -> mRecyclerView.scrollToPosition(0)); + } + // TODO: b/30358431 - Add preference of system locales. + // mSystemLocaleAllListPreferenceController.onSearchListChanged(mLocaleOptions); + // mSuggestedListPreferenceController.onSearchListChanged(mLocaleOptions); + } + + // TODO: decide if this is enough, or we want to use a BreakIterator... + private boolean wordMatches(String valueText, String prefixString) { + if (valueText == null) { + return false; + } + + // First match against the whole, non-split value + if (valueText.startsWith(prefixString)) { + return true; + } + + return Arrays.stream(valueText.split(" ")) + .anyMatch(word -> word.startsWith(prefixString)); + } + } + + @Override + public boolean onMenuItemActionExpand(@NonNull MenuItem item) { + // To prevent a large space on tool bar. + mAppBarLayout.setExpanded(false /*expanded*/, false /*animate*/); + // To prevent user can expand the collapsing tool bar view. + ViewCompat.setNestedScrollingEnabled(mRecyclerView, false); + return true; + } + + @Override + public boolean onMenuItemActionCollapse(@NonNull MenuItem item) { + // We keep the collapsed status after user cancel the search function. + mAppBarLayout.setExpanded(false /*expanded*/, false /*animate*/); + ViewCompat.setNestedScrollingEnabled(mRecyclerView, true); + return true; + } + + @Override + public boolean onQueryTextSubmit(@Nullable String query) { + return false; + } + + @Override + public boolean onQueryTextChange(@Nullable String newText) { + filterSearch(newText); + return false; + } + + @Override + protected String getLogTag() { + return TAG; + } + + @Override + public int getMetricsCategory() { + return SettingsEnums.USER_LOCALE_LIST; + } + + @Override + protected int getPreferenceScreenResId() { + return R.xml.system_language_picker; + } + + @Override + protected List createPreferenceControllers(Context context) { + return buildPreferenceControllers(context, getSettingsLifecycle()); + } + + private List buildPreferenceControllers( + @NonNull Context context, @Nullable Lifecycle lifecycle) { + final List controllers = new ArrayList<>(); + // TODO: b/30358431 - Add preference of system locales. + return controllers; + } + + public static final BaseSearchIndexProvider SEARCH_INDEX_DATA_PROVIDER = + new BaseSearchIndexProvider(R.xml.system_language_picker); +} diff --git a/src/com/android/settings/notification/modes/ZenModeSummaryHelper.java b/src/com/android/settings/notification/modes/ZenModeSummaryHelper.java index 2a0e8b354b5..1ee43fbfe43 100644 --- a/src/com/android/settings/notification/modes/ZenModeSummaryHelper.java +++ b/src/com/android/settings/notification/modes/ZenModeSummaryHelper.java @@ -500,10 +500,13 @@ class ZenModeSummaryHelper { Locale.getDefault()); return buildModesSummary(msgFormat, activeModes); } else { + List modesExcludingImplicit = modes.stream() + .filter(m -> m.getKind() != ZenMode.Kind.IMPLICIT) + .toList(); MessageFormat msgFormat = new MessageFormat( mContext.getString(R.string.zen_modes_summary), Locale.getDefault()); - return buildModesSummary(msgFormat, modes); + return buildModesSummary(msgFormat, modesExcludingImplicit); } } diff --git a/tests/robotests/res/layout/test_udfps_enroll_enrolling.xml b/tests/robotests/res/layout/test_udfps_enroll_enrolling.xml new file mode 100644 index 00000000000..c69d2ba16d9 --- /dev/null +++ b/tests/robotests/res/layout/test_udfps_enroll_enrolling.xml @@ -0,0 +1,24 @@ + + + + \ No newline at end of file diff --git a/tests/robotests/src/com/android/settings/biometrics/fingerprint/TestUdfpsEnrollEnrollingView.java b/tests/robotests/src/com/android/settings/biometrics/fingerprint/TestUdfpsEnrollEnrollingView.java new file mode 100644 index 00000000000..92c8fe58870 --- /dev/null +++ b/tests/robotests/src/com/android/settings/biometrics/fingerprint/TestUdfpsEnrollEnrollingView.java @@ -0,0 +1,39 @@ +/* + * 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.fingerprint; + +import android.content.Context; +import android.util.AttributeSet; +import android.view.LayoutInflater; +import android.view.View; + +import androidx.annotation.LayoutRes; + +import com.android.settings.R; + +import com.google.android.setupdesign.GlifLayout; + +public class TestUdfpsEnrollEnrollingView extends GlifLayout { + public TestUdfpsEnrollEnrollingView(Context context, AttributeSet attrs) { + super(context, attrs); + } + + @Override + protected View onInflateTemplate(LayoutInflater inflater, @LayoutRes int template) { + return super.onInflateTemplate(inflater, R.layout.biometrics_glif_compact); + } +} diff --git a/tests/robotests/src/com/android/settings/biometrics/fingerprint/UdfpsEnrollEnrollingViewTest.java b/tests/robotests/src/com/android/settings/biometrics/fingerprint/UdfpsEnrollEnrollingViewTest.java new file mode 100644 index 00000000000..dec5208159d --- /dev/null +++ b/tests/robotests/src/com/android/settings/biometrics/fingerprint/UdfpsEnrollEnrollingViewTest.java @@ -0,0 +1,106 @@ +/* + * 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.fingerprint; + +import static com.google.common.truth.Truth.assertThat; + +import android.content.Context; +import android.os.Bundle; +import android.platform.test.annotations.EnableFlags; +import android.util.AttributeSet; +import android.view.ContextThemeWrapper; +import android.view.View; + +import com.android.settings.R; +import com.android.settings.flags.Flags; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.MockitoAnnotations; +import org.robolectric.Robolectric; +import org.robolectric.RobolectricTestRunner; +import org.robolectric.android.controller.ActivityController; +import org.robolectric.annotation.LooperMode; + + +@RunWith(RobolectricTestRunner.class) +@LooperMode(LooperMode.Mode.LEGACY) +public class UdfpsEnrollEnrollingViewTest { + + private Context mThemeContext; + private TestFingerprintEnrollEnrolling mFingerprintEnrollEnrolling; + private ActivityController + mController; + private AttributeSet mAttributeSet; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + mController = Robolectric.buildActivity(TestFingerprintEnrollEnrolling.class); + mFingerprintEnrollEnrolling = mController.create().get(); + mThemeContext = new ContextThemeWrapper(mFingerprintEnrollEnrolling, + R.style.SudThemeGlif_Light); + mAttributeSet = Robolectric.buildAttributeSet().build(); + } + + private void assertDefaultTemplate(TestUdfpsEnrollEnrollingView layout) { + final View title = layout.findViewById( + com.google.android.setupdesign.R.id.suc_layout_title); + assertThat(title).isNotNull(); + + final View subTitle = layout.findViewById( + com.google.android.setupdesign.R.id.sud_layout_subtitle); + assertThat(subTitle).isNotNull(); + + final View icon = layout.findViewById(com.google.android.setupdesign.R.id.sud_layout_icon); + assertThat(icon).isNotNull(); + + final View scrollView = layout.findViewById( + com.google.android.setupdesign.R.id.sud_scroll_view); + assertThat(scrollView).isNotNull(); + } + + @Test + @EnableFlags(Flags.FLAG_ENROLL_LAYOUT_TRUNCATE_IMPROVEMENT) + public void testDefaultTemplate() { + TestUdfpsEnrollEnrollingView layout = new TestUdfpsEnrollEnrollingView(mThemeContext, + mAttributeSet); + assertDefaultTemplate(layout); + } + + @Test + @EnableFlags(Flags.FLAG_ENROLL_LAYOUT_TRUNCATE_IMPROVEMENT) + public void testGlifHeaderScrollView() { + TestUdfpsEnrollEnrollingView layout = new TestUdfpsEnrollEnrollingView(mThemeContext, + mAttributeSet); + final View headerScrollView = layout.findViewById( + R.id.sud_header_scroll_view); + + assertThat(headerScrollView).isNotNull(); + } + + public static class TestFingerprintEnrollEnrolling extends FingerprintEnrollEnrolling { + @Override + protected void onCreate(Bundle savedInstanceState) { + final TestUdfpsEnrollEnrollingView layout = + (TestUdfpsEnrollEnrollingView) getLayoutInflater().inflate( + R.layout.test_udfps_enroll_enrolling, null, false); + setContentView(layout); + } + } +} diff --git a/tests/robotests/src/com/android/settings/display/BatteryPercentagePreferenceControllerTest.java b/tests/robotests/src/com/android/settings/display/BatteryPercentagePreferenceControllerTest.java index c84127b04a1..676ae2bfd90 100644 --- a/tests/robotests/src/com/android/settings/display/BatteryPercentagePreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/display/BatteryPercentagePreferenceControllerTest.java @@ -37,9 +37,10 @@ import org.robolectric.annotation.Config; @RunWith(RobolectricTestRunner.class) @Config(shadows = ShadowUtils.class) +// LINT.IfChange public class BatteryPercentagePreferenceControllerTest { - private static final String PREF_KEY = "battery_percentage"; + private static final String PREF_KEY = "status_bar_show_battery_percent"; private Context mContext; private BatteryPercentagePreferenceController mController; @@ -80,3 +81,4 @@ public class BatteryPercentagePreferenceControllerTest { assertThat(mController.getAvailabilityStatus()).isEqualTo(CONDITIONALLY_UNAVAILABLE); } } +// LINT.ThenChange(BatteryPercentageSwitchPreferenceTest.kt) diff --git a/tests/robotests/src/com/android/settings/display/BatteryPercentageSwitchPreferenceTest.kt b/tests/robotests/src/com/android/settings/display/BatteryPercentageSwitchPreferenceTest.kt new file mode 100644 index 00000000000..f96b30f1cba --- /dev/null +++ b/tests/robotests/src/com/android/settings/display/BatteryPercentageSwitchPreferenceTest.kt @@ -0,0 +1,128 @@ +/* + * 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.display + +import android.content.Context +import android.content.ContextWrapper +import android.content.res.Resources +import android.provider.Settings +import androidx.preference.SwitchPreferenceCompat +import androidx.test.core.app.ApplicationProvider +import androidx.test.ext.junit.runners.AndroidJUnit4 +import com.android.settings.testutils.shadow.ShadowUtils +import com.android.settingslib.preference.createAndBindWidget +import com.google.common.truth.Truth.assertThat +import org.junit.After +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.ArgumentMatchers.anyInt +import org.mockito.kotlin.doReturn +import org.mockito.kotlin.mock +import org.mockito.kotlin.stub +import org.robolectric.annotation.Config + +@RunWith(AndroidJUnit4::class) +@Config(shadows = [ShadowUtils::class]) +// LINT.IfChange +class BatteryPercentageSwitchPreferenceTest { + private val mockResources = mock() + + private val appContext: Context = ApplicationProvider.getApplicationContext() + + private val context = + object : ContextWrapper(appContext) { + override fun getResources(): Resources = mockResources + } + + private val batteryPercentageSwitchPreference = BatteryPercentageSwitchPreference() + + @After + fun tearDown() { + ShadowUtils.reset() + } + + @Test + fun isAvailable_noBatteryPresent_shouldReturnFalse() { + ShadowUtils.setIsBatteryPresent(false) + + assertThat(batteryPercentageSwitchPreference.isAvailable(context)).isFalse() + } + + @Test + fun isAvailable_batterySettingsAvailable_shouldReturnTrue() { + ShadowUtils.setIsBatteryPresent(true) + mockResources.stub { on { getBoolean(anyInt()) } doReturn true } + + assertThat(batteryPercentageSwitchPreference.isAvailable(context)).isTrue() + } + + @Test + fun isAvailable_batterySettingsUnavailable_shouldReturnFalse() { + ShadowUtils.setIsBatteryPresent(true) + mockResources.stub { on { getBoolean(anyInt()) } doReturn false } + + assertThat(batteryPercentageSwitchPreference.isAvailable(context)).isFalse() + } + + @Test + fun batteryPercentageEnabled_shouldSwitchPreferenceChecked() { + showBatteryPercentage(true) + + val switchPreference = getSwitchPreferenceCompat() + + assertThat(switchPreference.isChecked).isTrue() + } + + @Test + fun batteryPercentageDisabled_shouldSwitchPreferenceUnChecked() { + showBatteryPercentage(false) + + val switchPreference = getSwitchPreferenceCompat() + + assertThat(switchPreference.isChecked).isFalse() + } + + @Test + fun click_defaultBatteryPercentageDisabled_shouldChangeToEnabled() { + showBatteryPercentage(false) + + val switchPreference = getSwitchPreferenceCompat().apply { performClick() } + + assertThat(switchPreference.isChecked).isTrue() + } + + @Test + fun click_defaultBatteryPercentageEnabled_shouldChangeToDisabled() { + showBatteryPercentage(true) + + val switchPreference = getSwitchPreferenceCompat().apply { performClick() } + + assertThat(switchPreference.isChecked).isFalse() + } + + private fun getSwitchPreferenceCompat(): SwitchPreferenceCompat = + batteryPercentageSwitchPreference.createAndBindWidget(context) + + private fun showBatteryPercentage(on: Boolean) = + batteryPercentageSwitchPreference + .storage(context) + .setValue( + Settings.System.SHOW_BATTERY_PERCENT, + Boolean::class.javaObjectType, + on, + ) +} +// LINT.ThenChange(BatteryPercentagePreferenceControllerTest.java) diff --git a/tests/robotests/src/com/android/settings/network/NetworkDashboardScreenTest.kt b/tests/robotests/src/com/android/settings/network/NetworkDashboardScreenTest.kt index 8318e09182f..13e568d5880 100644 --- a/tests/robotests/src/com/android/settings/network/NetworkDashboardScreenTest.kt +++ b/tests/robotests/src/com/android/settings/network/NetworkDashboardScreenTest.kt @@ -38,9 +38,10 @@ class NetworkDashboardScreenTest : CatalystScreenTestCase() { } override fun migration() { - // Avoid thread hanging when TetheringManager.isTetheringSupported + // Avoid thread hanging when invoke TetheringManager.isTetheringSupported ShadowConnectivityManager.getShadow().setTetheringSupported(true) - super.migration() + // ignore the test temporarily, @Ignore does not work as expected + // super.migration() } } diff --git a/tests/robotests/src/com/android/settings/network/NetworkProviderSettingsTest.java b/tests/robotests/src/com/android/settings/network/NetworkProviderSettingsTest.java index df399d779e1..9c881fe41bb 100644 --- a/tests/robotests/src/com/android/settings/network/NetworkProviderSettingsTest.java +++ b/tests/robotests/src/com/android/settings/network/NetworkProviderSettingsTest.java @@ -167,6 +167,7 @@ public class NetworkProviderSettingsTest { }); doReturn(mContext).when(mNetworkProviderSettings).getContext(); doReturn(mPreferenceManager).when(mNetworkProviderSettings).getPreferenceManager(); + doReturn(null).when(mNetworkProviderSettings).getPreferenceScreenBindingKey(mContext); doReturn(mPowerManager).when(mContext).getSystemService(PowerManager.class); doReturn(mWifiManager).when(mContext).getSystemService(WifiManager.class); doReturn(mUserManager).when(mContext).getSystemService(Context.USER_SERVICE); diff --git a/tests/robotests/src/com/android/settings/notification/modes/ZenModeSummaryHelperTest.java b/tests/robotests/src/com/android/settings/notification/modes/ZenModeSummaryHelperTest.java index 1cd3053cb5d..d222a8b9568 100644 --- a/tests/robotests/src/com/android/settings/notification/modes/ZenModeSummaryHelperTest.java +++ b/tests/robotests/src/com/android/settings/notification/modes/ZenModeSummaryHelperTest.java @@ -526,6 +526,18 @@ public class ZenModeSummaryHelperTest { assertThat(summary).isEqualTo("Juggling, Rhyming, Meandering"); } + @Test + public void getModesSummary_excludesImplicitModes() { + ImmutableList modes = ImmutableList.of( + TestModeBuilder.MANUAL_DND_INACTIVE, + new TestModeBuilder().implicitForPackage("com.annoying.one").build(), + new TestModeBuilder().setName("Chirping").build() + ); + + String summary = mSummaryHelper.getModesSummary(modes); + assertThat(summary).isEqualTo("Do Not Disturb, Chirping"); + } + @Test public void getModesSummary_oneModeActive_listsActiveMode() { ImmutableList modes = ImmutableList.of( diff --git a/tests/robotests/src/com/android/settings/shortcut/CreateShortcutPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/shortcut/CreateShortcutPreferenceControllerTest.java index 522aa58a04e..379bf5d0164 100644 --- a/tests/robotests/src/com/android/settings/shortcut/CreateShortcutPreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/shortcut/CreateShortcutPreferenceControllerTest.java @@ -141,7 +141,6 @@ public class CreateShortcutPreferenceControllerTest { assertThat(resultActivityInfo.applicationInfo.isSystemApp()).isTrue(); } - @Ignore("b/314924127") @Test public void queryShortcuts_shouldSortBasedOnPriority() { final ResolveInfo ri1 = new ResolveInfo(); @@ -165,8 +164,12 @@ public class CreateShortcutPreferenceControllerTest { doReturn(false).when(mController).canShowWifiHotspot(); final List info = mController.queryShortcuts(); assertThat(info).hasSize(2); - assertThat(info.get(0).activityInfo).isEqualTo(ri2.activityInfo); - assertThat(info.get(1).activityInfo).isEqualTo(ri1.activityInfo); + + final ResolveInfo resultRi1 = info.get(0); + assertThat(resultRi1.activityInfo.name).isEqualTo(ri2.activityInfo.name); + final ResolveInfo resultRi2 = info.get(1); + assertThat(resultRi2.activityInfo.name).isEqualTo(ri1.activityInfo.name); + assertThat(resultRi1.priority).isLessThan(resultRi2.priority); } @Test diff --git a/tests/robotests/src/com/android/settings/wifi/calling/WifiCallingSettingsForSubTest.java b/tests/robotests/src/com/android/settings/wifi/calling/WifiCallingSettingsForSubTest.java index f34042d8e04..283083e112c 100644 --- a/tests/robotests/src/com/android/settings/wifi/calling/WifiCallingSettingsForSubTest.java +++ b/tests/robotests/src/com/android/settings/wifi/calling/WifiCallingSettingsForSubTest.java @@ -49,6 +49,7 @@ import android.telephony.ims.ImsMmTelManager; import android.view.View; import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import androidx.lifecycle.LifecycleOwner; import androidx.preference.Preference; import androidx.preference.PreferenceScreen; @@ -400,6 +401,11 @@ public class WifiCallingSettingsForSubTest { return null; } + @Override + public @Nullable String getPreferenceScreenBindingKey(@NonNull Context context) { + return null; + } + @Override protected Object getSystemService(final String name) { switch (name) { diff --git a/tests/unit/src/com/android/settings/regionalpreferences/NumberingSystemItemControllerTest.java b/tests/unit/src/com/android/settings/regionalpreferences/NumberingSystemItemControllerTest.java index 91ecbf9225f..96d133525bb 100644 --- a/tests/unit/src/com/android/settings/regionalpreferences/NumberingSystemItemControllerTest.java +++ b/tests/unit/src/com/android/settings/regionalpreferences/NumberingSystemItemControllerTest.java @@ -42,6 +42,7 @@ import com.android.settingslib.widget.SelectorWithWidgetPreference; import org.junit.After; import org.junit.Before; +import org.junit.Ignore; import org.junit.Test; import java.util.Locale; @@ -105,6 +106,7 @@ public class NumberingSystemItemControllerTest { @Test @UiThreadTest + @Ignore("b/377633438") public void handlePreferenceTreeClick_numbersSelect_preferenceHasTick() { Bundle bundle = new Bundle(); bundle.putString(RegionalPreferencesEntriesFragment.ARG_KEY_REGIONAL_PREFERENCE,