Snap for 12658558 from 93e24594c5 to 25Q1-release

Change-Id: Ia7c5bc302e67780332894eb9521f65711a334812
This commit is contained in:
Android Build Coastguard Worker
2024-11-15 00:17:13 +00:00
33 changed files with 1285 additions and 76 deletions

View File

@@ -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"

View File

@@ -0,0 +1,26 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
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.
-->
<com.google.android.setupcompat.view.StatusBarBackgroundLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/suc_layout_status"
android:layout_width="match_parent"
android:layout_height="match_parent">
<include layout="@layout/biometrics_glif_content" />
</com.google.android.setupcompat.view.StatusBarBackgroundLayout>

View File

@@ -0,0 +1,82 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
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.
-->
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/sud_layout_template_content"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clipChildren="true"
android:clipToPadding="true"
android:orientation="vertical">
<ViewStub
android:id="@+id/sud_layout_sticky_header"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<com.google.android.setupdesign.view.BottomScrollView
android:id="@+id/sud_header_scroll_view"
android:layout_width="match_parent"
android:layout_height="@dimen/biometrics_glif_header_height"
android:fillViewport="true"
android:orientation="vertical"
tools:ignore="UnusedAttribute">
<include layout="@layout/sud_glif_header" />
</com.google.android.setupdesign.view.BottomScrollView>
<com.google.android.setupdesign.view.BottomScrollView
android:id="@+id/sud_scroll_view"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:fillViewport="true"
android:scrollIndicators="?attr/sudScrollIndicators"
tools:ignore="UnusedAttribute">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<ViewStub
android:id="@+id/sud_layout_illustration_progress_stub"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inflatedId="@+id/sud_layout_progress_illustration"
android:layout="@layout/sud_progress_illustration_layout" />
<FrameLayout
android:id="@+id/sud_layout_content"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1" />
</LinearLayout>
</com.google.android.setupdesign.view.BottomScrollView>
<ViewStub
android:id="@+id/suc_layout_footer"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>

View File

@@ -24,58 +24,66 @@
android:layout_height="match_parent"
style="?attr/fingerprint_layout_theme">
<LinearLayout
<androidx.constraintlayout.widget.ConstraintLayout
style="@style/SudContentFrame"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clipToPadding="false"
android:clipChildren="false"
android:orientation="vertical">
android:clipChildren="false">
<com.airbnb.lottie.LottieAnimationView
android:id="@+id/illustration_lottie"
android:layout_width="match_parent"
android:layout_height="200dp"
app:layout_constraintTop_toTopOf="@id/udfps_view"
android:scaleType="centerInside"
android:visibility="gone"
app:lottie_autoPlay="true"
app:lottie_loop="true"
android:clipChildren="false"
android:clipToPadding="false"
app:lottie_speed=".85" />
<LinearLayout
style="@style/SudContentFrame"
android:id="@+id/udfps_view"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:gravity="center|bottom"
android:layout_height="match_parent"
android:clipToPadding="false"
android:clipChildren="false"
android:orientation="vertical">
<FrameLayout
android:id="@+id/layout_container"
android:layout_width="match_parent"
android:layout_height="0dp"
android:clipChildren="false"
android:clipToPadding="false"
android:layout_gravity="center_horizontal|bottom"
tools:ignore="Suspicious0dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:gravity="center|bottom"
android:orientation="vertical">
<!-- Animation res MUST be set in code -->
<com.airbnb.lottie.LottieAnimationView
android:id="@+id/illustration_lottie"
android:layout_width="match_parent"
android:layout_height="200dp"
android:layout_marginTop="@dimen/udfps_lottie_translate_y"
android:scaleType="centerInside"
android:visibility="gone"
app:lottie_autoPlay="true"
app:lottie_loop="true"
android:clipChildren="false"
android:clipToPadding="false"
app:lottie_speed=".85" />
<FrameLayout
android:id="@+id/layout_container"
android:layout_width="match_parent"
android:layout_height="0dp"
android:clipChildren="false"
android:clipToPadding="false"
android:layout_gravity="center_horizontal|bottom"
tools:ignore="Suspicious0dp">
<include layout="@layout/udfps_enroll_view" />
<include layout="@layout/udfps_enroll_view" />
</FrameLayout>
</FrameLayout>
<TextView
android:id="@+id/error_text"
style="@style/TextAppearance.ErrorText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal|bottom"
android:accessibilityLiveRegion="polite"
android:gravity="center_horizontal"
android:visibility="invisible" />
</LinearLayout>
</LinearLayout>
<TextView
android:id="@+id/error_text"
style="@style/TextAppearance.ErrorText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal|bottom"
android:accessibilityLiveRegion="polite"
android:gravity="center_horizontal"
android:visibility="invisible" />
</LinearLayout>
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
</com.android.settings.biometrics.fingerprint.UdfpsEnrollEnrollingView>

View File

@@ -0,0 +1,81 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ 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.
-->
<com.android.settings.biometrics.fingerprint.UdfpsEnrollEnrollingView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/setup_wizard_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
style="?attr/fingerprint_layout_theme">
<LinearLayout
style="@style/SudContentFrame"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clipToPadding="false"
android:clipChildren="false"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:gravity="center|bottom"
android:orientation="vertical">
<FrameLayout
android:id="@+id/layout_container"
android:layout_width="match_parent"
android:layout_height="0dp"
android:clipChildren="false"
android:clipToPadding="false"
android:layout_gravity="center_horizontal|bottom"
tools:ignore="Suspicious0dp">
<!-- Animation res MUST be set in code -->
<com.airbnb.lottie.LottieAnimationView
android:id="@+id/illustration_lottie"
android:layout_width="match_parent"
android:layout_height="200dp"
android:layout_marginTop="@dimen/udfps_lottie_translate_y"
android:scaleType="centerInside"
android:visibility="gone"
app:lottie_autoPlay="true"
app:lottie_loop="true"
android:clipChildren="false"
android:clipToPadding="false"
app:lottie_speed=".85" />
<include layout="@layout/udfps_enroll_view" />
</FrameLayout>
<TextView
android:id="@+id/error_text"
style="@style/TextAppearance.ErrorText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal|bottom"
android:accessibilityLiveRegion="polite"
android:gravity="center_horizontal"
android:visibility="invisible" />
</LinearLayout>
</LinearLayout>
</com.android.settings.biometrics.fingerprint.UdfpsEnrollEnrollingView>

View File

@@ -0,0 +1,25 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- 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.
-->
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:id="@+id/locale_search_menu"
android:title="@string/locale_search_menu"
android:icon="@drawable/ic_search_24dp"
android:showAsAction="always|collapseActionView"
android:actionViewClass="android.widget.SearchView" />
</menu>

View File

@@ -772,6 +772,9 @@
58.0001 29.2229,56.9551 26.8945,55.195
</string>
<!-- Duration in milliseconds of the udfps title/sub-title scrolling once animation. -->
<integer name="config_biometrics_header_scroll_duration">1000</integer>
<!-- Whether auto data switching on secondary SIM enables cross-SIM calling on both SIMs. -->
<bool name="config_auto_data_switch_enables_cross_sim_calling">false</bool>

View File

@@ -159,6 +159,10 @@
<dimen name="sfps_enroll_finish_icon_margin_top">-24dp</dimen>
<dimen name="udfps_lottie_translate_y">0dp</dimen>
<dimen name="udfps_lottie_padding_top">20dp</dimen>
<dimen name="biometrics_glif_header_height">274dp</dimen>
<item name="biometrics_glif_header_height_ratio" format="float" type="dimen">0.27</item>
<!-- For showing when Display / Font size set to largest -->
<item name="biometrics_glif_header_height_ratio_large" format="float" type="dimen">0.37</item>
<!-- Face -->
<item name="face_preview_translate_y" format="float" type="dimen">0</item>

View File

@@ -402,6 +402,18 @@
<!-- Category for the app's locale picker activity. [CHAR LIMIT=50]-->
<string name="all_supported_app_locales_title">All languages</string>
<!-- Category for suggested locales. [CHAR LIMIT=50]-->
<string name="suggested_locales_title">Suggested</string>
<!-- Category for the locale picker. [CHAR LIMIT=50]-->
<string name="all_supported_locales_title">All languages</string>
<!-- Category for the locale region picker. [CHAR LIMIT=50]-->
<string name="all_supported_locales_regions_title">All regions</string>
<!-- Category for the numbering system of locale region picker. [CHAR LIMIT=50]-->
<string name="all_supported_numbering_system_title">All numbering systems</string>
<!-- Title for preference of the system default locale. [CHAR LIMIT=50]-->
<string name="preference_of_system_locale_title">System language</string>
@@ -450,6 +462,15 @@
<!-- The text of the confirmation dialog for saying this selected locale is unavailable to use. [CHAR LIMIT=NONE]-->
<string name="desc_unavailable_locale">This language cant be used as a system language, but youve let apps and websites know you prefer this language.</string>
<!-- Menu item in the locale menu [CHAR LIMIT=30] -->
<string name="locale_search_menu">Search</string>
<!-- Title for the language selection screen [CHAR LIMIT=25] -->
<string name="language_selection_title">Add a language</string>
<!-- Title for the region selection screen [CHAR LIMIT=25] -->
<string name="country_selection_title">Region preference</string>
<!-- Hint text in a search edit box (used to filter long language / country lists) [CHAR LIMIT=25] -->
<string name="search_language_hint">Type language name</string>
<!-- Regional Preferences begin -->
<!-- The title of the menu entry of regional preferences. [CHAR LIMIT=50] -->
<string name="regional_preferences_title">Regional preferences</string>

View File

@@ -64,6 +64,7 @@
</PreferenceCategory>
<PreferenceCategory
android:key="legal_category"
android:title="@string/my_device_info_legal_category_title">
<!-- Legal information -->
@@ -157,6 +158,7 @@
</PreferenceCategory>
<PreferenceCategory
android:key="device_identifiers_category"
android:title="@string/my_device_info_device_identifiers_category_title">
<!--IP address -->

View File

@@ -59,7 +59,7 @@
settings:keywords="@string/keywords_battery_adaptive_preferences" />
<SwitchPreferenceCompat
android:key="battery_percentage"
android:key="status_bar_show_battery_percent"
android:title="@string/battery_percentage"
android:summary="@string/battery_percentage_description"
settings:controller="com.android.settings.display.BatteryPercentagePreferenceController" />

View File

@@ -0,0 +1,30 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- 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.
-->
<PreferenceScreen
xmlns:android="http://schemas.android.com/apk/res/android"
android:title="@string/language_selection_title"
android:key="key_system_language_picker_page">
<PreferenceCategory
android:key="system_language_suggested_category"
android:title="@string/suggested_locales_title"/>
<PreferenceCategory
android:key="system_language_all_supported_category"
android:title="@string/all_supported_locales_title"/>
</PreferenceScreen>

View File

@@ -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<PreferenceSetterRequest> {
override fun hasPermission(
application: Application,
myUid: Int,
callingUid: Int,
request: PreferenceSetterRequest,
) = true
}

View File

@@ -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

View File

@@ -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() {

View File

@@ -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();

View File

@@ -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)

View File

@@ -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<String>(settingsStore), KeyValueStore {
override fun contains(key: String) = settingsStore.contains(KEY)
override fun <T : Any> getValue(key: String, valueType: Class<T>) =
(settingsStore.getBoolean(key) ?: getDefaultValue(key, valueType)) as T
override fun <T : Any> setValue(key: String, valueType: Class<T>, value: T?) {
settingsStore.setBoolean(key, value as Boolean)
}
override fun <T : Any> getDefaultValue(key: String, valueType: Class<T>) =
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)

View File

@@ -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

View File

@@ -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"
}
}
}

View File

@@ -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.
*
* <p>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.</p>
*/
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<LocaleStore.LocaleInfo> mLocaleList;
@Nullable private List<LocaleStore.LocaleInfo> mLocaleOptions;
@Nullable private List<LocaleStore.LocaleInfo> 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<LocaleStore.LocaleInfo> 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<LocaleStore.LocaleInfo>) 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<AbstractPreferenceController> createPreferenceControllers(Context context) {
return buildPreferenceControllers(context, getSettingsLifecycle());
}
private List<AbstractPreferenceController> buildPreferenceControllers(
@NonNull Context context, @Nullable Lifecycle lifecycle) {
final List<AbstractPreferenceController> 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);
}

View File

@@ -500,10 +500,13 @@ class ZenModeSummaryHelper {
Locale.getDefault());
return buildModesSummary(msgFormat, activeModes);
} else {
List<ZenMode> 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);
}
}

View File

@@ -0,0 +1,24 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ 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.
-->
<com.android.settings.biometrics.fingerprint.TestUdfpsEnrollEnrollingView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/test_setup_wizard_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"/>

View File

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

View File

@@ -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<UdfpsEnrollEnrollingViewTest.TestFingerprintEnrollEnrolling>
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);
}
}
}

View File

@@ -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)

View File

@@ -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<Resources>()
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)

View File

@@ -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()
}
}

View File

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

View File

@@ -526,6 +526,18 @@ public class ZenModeSummaryHelperTest {
assertThat(summary).isEqualTo("Juggling, Rhyming, Meandering");
}
@Test
public void getModesSummary_excludesImplicitModes() {
ImmutableList<ZenMode> 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<ZenMode> modes = ImmutableList.of(

View File

@@ -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<ResolveInfo> 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

View File

@@ -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) {

View File

@@ -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,