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,