diff --git a/res/layout/udfps_enroll_enrolling_v2.xml b/res/layout/udfps_enroll_enrolling_v2.xml
new file mode 100644
index 00000000000..96298f91d0b
--- /dev/null
+++ b/res/layout/udfps_enroll_enrolling_v2.xml
@@ -0,0 +1,104 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/res/values/strings.xml b/res/values/strings.xml
index bdf9107e0ab..72eba8b9e06 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -5350,6 +5350,8 @@
Breakdown by apps
Breakdown by system
+
+ < %1$s
diff --git a/src/com/android/settings/accessibility/MagnificationGesturesPreferenceController.java b/src/com/android/settings/accessibility/MagnificationGesturesPreferenceController.java
index 793ab5a8581..99e0dc035e8 100644
--- a/src/com/android/settings/accessibility/MagnificationGesturesPreferenceController.java
+++ b/src/com/android/settings/accessibility/MagnificationGesturesPreferenceController.java
@@ -14,7 +14,6 @@
package com.android.settings.accessibility;
import android.content.Context;
-import android.icu.text.MessageFormat;
import android.os.Bundle;
import android.provider.Settings;
import android.text.TextUtils;
@@ -94,19 +93,11 @@ public class MagnificationGesturesPreferenceController extends TogglePreferenceC
}
static void populateMagnificationGesturesPreferenceExtras(Bundle extras, Context context) {
- extras.putString(AccessibilitySettings.EXTRA_PREFERENCE_KEY,
- Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_ENABLED);
+ // TODO(b/270481978): It seems not necessary to put EXTRA_TITLE_RES.
extras.putInt(AccessibilitySettings.EXTRA_TITLE_RES,
R.string.accessibility_screen_magnification_gestures_title);
- String intro = context.getString(R.string.accessibility_screen_magnification_intro_text);
- extras.putCharSequence(AccessibilitySettings.EXTRA_INTRO, intro);
-
- String summary = context.getString(R.string.accessibility_screen_magnification_summary);
- final Object[] numberArguments = {1, 2, 3, 4, 5};
- summary = MessageFormat.format(summary, numberArguments);
- extras.putCharSequence(AccessibilitySettings.EXTRA_HTML_DESCRIPTION, summary);
-
+ // TODO(b/270481978): It seems not necessary to put EXTRA_VIDEO_RAW_RESOURCE_ID.
extras.putInt(AccessibilitySettings.EXTRA_VIDEO_RAW_RESOURCE_ID,
R.raw.accessibility_screen_magnification);
}
diff --git a/src/com/android/settings/accessibility/ToggleFeaturePreferenceFragment.java b/src/com/android/settings/accessibility/ToggleFeaturePreferenceFragment.java
index ca3c5f10e87..22c57b7a305 100644
--- a/src/com/android/settings/accessibility/ToggleFeaturePreferenceFragment.java
+++ b/src/com/android/settings/accessibility/ToggleFeaturePreferenceFragment.java
@@ -122,7 +122,7 @@ public abstract class ToggleFeaturePreferenceFragment extends DashboardFragment
private int mNeedsQSTooltipType = QuickSettingsTooltipType.GUIDE_TO_EDIT;
private boolean mSavedAccessibilityFloatingMenuEnabled;
private ImageView mImageGetterCacheView;
- private final Html.ImageGetter mImageGetter = (String str) -> {
+ protected final Html.ImageGetter mImageGetter = (String str) -> {
if (str != null && str.startsWith(IMG_PREFIX)) {
final String fileName = str.substring(IMG_PREFIX.length());
return getDrawableFromUri(Uri.parse(
diff --git a/src/com/android/settings/accessibility/ToggleScreenMagnificationPreferenceFragment.java b/src/com/android/settings/accessibility/ToggleScreenMagnificationPreferenceFragment.java
index 470e548d5d4..04a80dc489a 100644
--- a/src/com/android/settings/accessibility/ToggleScreenMagnificationPreferenceFragment.java
+++ b/src/com/android/settings/accessibility/ToggleScreenMagnificationPreferenceFragment.java
@@ -29,6 +29,7 @@ import android.content.Context;
import android.content.DialogInterface;
import android.content.pm.PackageManager;
import android.icu.text.CaseMap;
+import android.icu.text.MessageFormat;
import android.net.Uri;
import android.os.Bundle;
import android.provider.DeviceConfig;
@@ -220,6 +221,34 @@ public class ToggleScreenMagnificationPreferenceFragment extends
addJoystickSetting(generalCategory);
}
+ @Override
+ protected void onProcessArguments(Bundle arguments) {
+ Context context = getContext();
+
+ // This Fragment may get arguments from MagnificationGesturesPreferenceController or
+ // MagnificationNavbarPreferenceController and it's necessary to check if a key exists
+ // before putting a new value into arguments.
+
+ if (!arguments.containsKey(AccessibilitySettings.EXTRA_PREFERENCE_KEY)) {
+ arguments.putString(AccessibilitySettings.EXTRA_PREFERENCE_KEY,
+ Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_ENABLED);
+ }
+
+ if (!arguments.containsKey(AccessibilitySettings.EXTRA_INTRO)) {
+ arguments.putCharSequence(AccessibilitySettings.EXTRA_INTRO,
+ context.getString(R.string.accessibility_screen_magnification_intro_text));
+ }
+
+ if (!arguments.containsKey(AccessibilitySettings.EXTRA_HTML_DESCRIPTION)) {
+ String summary = MessageFormat.format(
+ context.getString(R.string.accessibility_screen_magnification_summary),
+ new Object[]{1, 2, 3, 4, 5});
+ arguments.putCharSequence(AccessibilitySettings.EXTRA_HTML_DESCRIPTION, summary);
+ }
+
+ super.onProcessArguments(arguments);
+ }
+
private void addAlwaysOnSetting(PreferenceCategory generalCategory) {
if (!DeviceConfig.getBoolean(
DeviceConfig.NAMESPACE_WINDOW_MANAGER,
diff --git a/src/com/android/settings/applications/appinfo/AppBatteryPreferenceController.java b/src/com/android/settings/applications/appinfo/AppBatteryPreferenceController.java
index 212a61903f9..8decbd99ff7 100644
--- a/src/com/android/settings/applications/appinfo/AppBatteryPreferenceController.java
+++ b/src/com/android/settings/applications/appinfo/AppBatteryPreferenceController.java
@@ -124,7 +124,7 @@ public class AppBatteryPreferenceController extends BasePreferenceController
mParent.getMetricsCategory(),
mBatteryDiffEntry,
Utils.formatPercentage(
- mBatteryDiffEntry.getPercentOfTotal(), /* round */ true),
+ mBatteryDiffEntry.getPercentage(), /* round */ true),
/*slotInformation=*/ null, /*showTimeInformation=*/ false);
return true;
}
@@ -190,7 +190,7 @@ public class AppBatteryPreferenceController extends BasePreferenceController
void updateBatteryWithDiffEntry() {
if (mBatteryDiffEntry != null && mBatteryDiffEntry.mConsumePower > 0) {
mBatteryPercent = Utils.formatPercentage(
- mBatteryDiffEntry.getPercentOfTotal(), /* round */ true);
+ mBatteryDiffEntry.getPercentage(), /* round */ true);
mPreference.setSummary(mContext.getString(
R.string.battery_summary, mBatteryPercent));
} else {
diff --git a/src/com/android/settings/biometrics2/ui/view/FingerprintEnrollEnrollingUdfpsFragment.java b/src/com/android/settings/biometrics2/ui/view/FingerprintEnrollEnrollingUdfpsFragment.java
index 4cf35736274..ad8a8ae3ae7 100644
--- a/src/com/android/settings/biometrics2/ui/view/FingerprintEnrollEnrollingUdfpsFragment.java
+++ b/src/com/android/settings/biometrics2/ui/view/FingerprintEnrollEnrollingUdfpsFragment.java
@@ -22,24 +22,19 @@ import android.annotation.RawRes;
import android.app.Activity;
import android.content.Context;
import android.content.res.Configuration;
-import android.graphics.Point;
-import android.graphics.Rect;
import android.graphics.drawable.Animatable2;
import android.graphics.drawable.Drawable;
-import android.hardware.fingerprint.FingerprintManager;
-import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
import android.os.Bundle;
import android.text.TextUtils;
+import android.util.DisplayMetrics;
import android.util.Log;
-import android.view.DisplayInfo;
import android.view.LayoutInflater;
import android.view.Surface;
import android.view.View;
import android.view.ViewGroup;
-import android.view.animation.AnimationUtils;
-import android.view.animation.Interpolator;
-import android.widget.FrameLayout;
-import android.widget.LinearLayout;
+import android.widget.Button;
+import android.widget.ImageView;
+import android.widget.RelativeLayout;
import android.widget.TextView;
import androidx.annotation.NonNull;
@@ -52,25 +47,16 @@ import androidx.transition.TransitionSet;
import com.android.settings.R;
import com.android.settings.biometrics.BiometricUtils;
-import com.android.settings.biometrics.fingerprint.UdfpsEnrollHelper;
-import com.android.settings.biometrics.fingerprint.UdfpsEnrollView;
import com.android.settings.biometrics2.ui.model.EnrollmentProgress;
import com.android.settings.biometrics2.ui.model.EnrollmentStatusMessage;
import com.android.settings.biometrics2.ui.viewmodel.DeviceRotationViewModel;
import com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollEnrollingViewModel;
import com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollProgressViewModel;
+import com.android.settings.biometrics2.ui.widget.UdfpsEnrollView;
import com.android.settingslib.display.DisplayDensityUtils;
-import com.android.settingslib.udfps.UdfpsOverlayParams;
-import com.android.settingslib.udfps.UdfpsUtils;
import com.airbnb.lottie.LottieAnimationView;
import com.airbnb.lottie.LottieCompositionFactory;
-import com.google.android.setupcompat.template.FooterActionButton;
-import com.google.android.setupcompat.template.FooterBarMixin;
-import com.google.android.setupcompat.template.FooterButton;
-import com.google.android.setupdesign.GlifLayout;
-
-import java.util.Locale;
/**
* Fragment is used to handle enrolling process for udfps
@@ -92,9 +78,6 @@ public class FingerprintEnrollEnrollingUdfpsFragment extends Fragment {
private DeviceRotationViewModel mRotationViewModel;
private FingerprintEnrollProgressViewModel mProgressViewModel;
- private Interpolator mFastOutSlowInInterpolator;
- private Interpolator mLinearOutSlowInInterpolator;
- private Interpolator mFastOutLinearInInterpolator;
private boolean mAnimationCancelled;
private LottieAnimationView mIllustrationLottie;
@@ -104,9 +87,13 @@ public class FingerprintEnrollEnrollingUdfpsFragment extends Fragment {
private boolean mHaveShownUdfpsCenterLottie;
private boolean mHaveShownUdfpsGuideLottie;
- private GlifLayout mView;
+ private RelativeLayout mView;
+ private ImageView mIcon;
private TextView mErrorText;
- private FooterBarMixin mFooterBarMixin;
+ private TextView mTitleText;
+ private TextView mSubTitleText;
+ private Button mSkipBtn;
+ private UdfpsEnrollView mUdfpsEnrollView;
private boolean mShouldShowLottie;
private boolean mIsAccessibilityEnabled;
@@ -145,13 +132,6 @@ public class FingerprintEnrollEnrollingUdfpsFragment extends Fragment {
private int mIconTouchCount;
- private UdfpsUtils mUdfpsUtils;
- private float mScaleFactor = 1.0f;
- //TODO UdfpsEnrollHelper should not be a Fragment, we should tell enrollview & progress
- // drawable enough information EnrollView & ProgressDrawable should draw themselves without
- // UdfpsEnrollHelper
- private UdfpsEnrollHelper mUdfpsEnrollHelper;
-
@Override
public void onAttach(@NonNull Context context) {
@@ -200,10 +180,6 @@ public class FingerprintEnrollEnrollingUdfpsFragment extends Fragment {
super.onCreate(savedInstanceState);
mEnrollingViewModel.restoreSavedState(savedInstanceState);
mIsAccessibilityEnabled = mEnrollingViewModel.isAccessibilityEnabled();
- mUdfpsUtils = new UdfpsUtils();
- mUdfpsEnrollHelper = new UdfpsEnrollHelper(getActivity(), getActivity().getSystemService(
- FingerprintManager.class
- ));
}
@Override
@@ -216,95 +192,85 @@ public class FingerprintEnrollEnrollingUdfpsFragment extends Fragment {
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
mView = initUdfpsLayout(inflater, container);
-
return mView;
}
- private GlifLayout initUdfpsLayout(LayoutInflater inflater, ViewGroup container) {
- final GlifLayout containView = (GlifLayout) inflater.inflate(
- R.layout.udfps_enroll_enrolling, container, false);
- final UdfpsEnrollView udfpsEnrollView = addUdfpsEnrollView(inflater,
- mEnrollingViewModel.getFirstFingerprintSensorPropertiesInternal());
- final int rotation = mRotationViewModel.getLiveData().getValue();
- if (rotation == Surface.ROTATION_90) {
- final boolean isLayoutRtl = (TextUtils.getLayoutDirectionFromLocale(
- Locale.getDefault()) == View.LAYOUT_DIRECTION_RTL);
- final LinearLayout layoutContainer = containView.findViewById(
- R.id.layout_container);
- layoutContainer.setPaddingRelative(
- (int) getResources().getDimension(R.dimen.rotation_90_enroll_padding_start),
- 0,
- isLayoutRtl ? 0 : (int) getResources().getDimension(
- R.dimen.rotation_90_enroll_padding_end),
- 0);
-
- final LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(
- LinearLayout.LayoutParams.MATCH_PARENT,
- LinearLayout.LayoutParams.MATCH_PARENT);
- lp.setMarginEnd((int) getResources().getDimension(
- R.dimen.rotation_90_enroll_margin_end));
- layoutContainer.setLayoutParams(lp);
- containView.addView(udfpsEnrollView);
- containView.setClipChildren(false);
- containView.setClipToPadding(false);
- containView.setLayoutParams(lp);
- setOnHoverListener(true, containView, udfpsEnrollView);
- } else if (rotation == Surface.ROTATION_270) {
- containView.addView(udfpsEnrollView);
- containView.setClipChildren(false);
- containView.setClipToPadding(false);
- setOnHoverListener(true, containView, udfpsEnrollView);
- } else {
- final FrameLayout portraitLayoutContainer = containView.findViewById(
- R.id.layout_container);
- portraitLayoutContainer.addView(udfpsEnrollView);
- ViewGroup parent = ((ViewGroup) portraitLayoutContainer.getParent());
- parent.setClipChildren(false);
- parent.setClipToPadding(false);
- setOnHoverListener(false, containView, udfpsEnrollView);
- }
+ private RelativeLayout initUdfpsLayout(LayoutInflater inflater, ViewGroup container) {
+ final RelativeLayout containView = (RelativeLayout) inflater.inflate(
+ R.layout.udfps_enroll_enrolling_v2, container, false);
final Activity activity = getActivity();
- new GlifLayoutHelper(activity, containView).setDescriptionText(
- getString(R.string.security_settings_udfps_enroll_start_message));
-
+ mIcon = containView.findViewById(R.id.sud_layout_icon);
+ mTitleText = containView.findViewById(R.id.suc_layout_title);
+ mSubTitleText = containView.findViewById(R.id.sud_layout_subtitle);
+ mErrorText = containView.findViewById(R.id.error_text);
+ mSkipBtn = containView.findViewById(R.id.skip_btn);
+ mSkipBtn.setOnClickListener(mOnSkipClickListener);
+ mUdfpsEnrollView = containView.findViewById(R.id.udfps_animation_view);
+ mUdfpsEnrollView.setSensorProperties(
+ mEnrollingViewModel.getFirstFingerprintSensorPropertiesInternal());
mShouldShowLottie = shouldShowLottie();
boolean isLandscape = BiometricUtils.isReverseLandscape(activity)
|| BiometricUtils.isLandscape(activity);
updateOrientation(containView, (isLandscape
? Configuration.ORIENTATION_LANDSCAPE : Configuration.ORIENTATION_PORTRAIT));
- mErrorText = containView.findViewById(R.id.error_text);
- mFooterBarMixin = containView.getMixin(FooterBarMixin.class);
- mFooterBarMixin.setSecondaryButton(
- new FooterButton.Builder(activity)
- .setText(R.string.security_settings_fingerprint_enroll_enrolling_skip)
- .setListener(mOnSkipClickListener)
- .setButtonType(FooterButton.ButtonType.SKIP)
- .setTheme(R.style.SudGlifButton_Secondary)
- .build()
- );
- mFastOutSlowInInterpolator = AnimationUtils.loadInterpolator(
- activity, android.R.interpolator.fast_out_slow_in);
- mLinearOutSlowInInterpolator = AnimationUtils.loadInterpolator(
- activity, android.R.interpolator.linear_out_slow_in);
- mFastOutLinearInInterpolator = AnimationUtils.loadInterpolator(
- activity, android.R.interpolator.fast_out_linear_in);
+ final int rotation = mRotationViewModel.getLiveData().getValue();
+ if (rotation == Surface.ROTATION_270) {
+ RelativeLayout.LayoutParams iconLP = new RelativeLayout.LayoutParams(-2, -2);
+ iconLP.addRule(RelativeLayout.ALIGN_PARENT_TOP);
+ iconLP.addRule(RelativeLayout.END_OF, R.id.udfps_animation_view);
+ iconLP.topMargin = (int) convertDpToPixel(76.64f, activity);
+ iconLP.leftMargin = (int) convertDpToPixel(151.54f, activity);
+ mIcon.setLayoutParams(iconLP);
- final LinearLayout buttonContainer = mFooterBarMixin.getButtonContainer();
- View spaceView = null;
- for (int i = 0; i < buttonContainer.getChildCount(); i++) {
- if (!(buttonContainer.getChildAt(i) instanceof FooterActionButton)) {
- spaceView = buttonContainer.getChildAt(i);
- break;
- }
- }
- if (spaceView != null) {
- spaceView.setVisibility(View.GONE);
- buttonContainer.getLayoutParams().width = ViewGroup.LayoutParams.WRAP_CONTENT;
+ RelativeLayout.LayoutParams titleLP = new RelativeLayout.LayoutParams(-1, -2);
+ titleLP.addRule(RelativeLayout.ALIGN_PARENT_TOP);
+ titleLP.addRule(RelativeLayout.END_OF, R.id.udfps_animation_view);
+ titleLP.topMargin = (int) convertDpToPixel(138f, activity);
+ titleLP.leftMargin = (int) convertDpToPixel(144f, activity);
+ mTitleText.setLayoutParams(titleLP);
+
+ RelativeLayout.LayoutParams subtitleLP = new RelativeLayout.LayoutParams(-1, -2);
+ subtitleLP.addRule(RelativeLayout.ALIGN_PARENT_TOP);
+ subtitleLP.addRule(RelativeLayout.END_OF, R.id.udfps_animation_view);
+ subtitleLP.topMargin = (int) convertDpToPixel(198f, activity);
+ subtitleLP.leftMargin = (int) convertDpToPixel(144f, activity);
+ mSubTitleText.setLayoutParams(subtitleLP);
+ } else if (rotation == Surface.ROTATION_90) {
+ DisplayMetrics metrics = activity.getResources().getDisplayMetrics();
+ RelativeLayout.LayoutParams iconLP = new RelativeLayout.LayoutParams(-2, -2);
+ iconLP.addRule(RelativeLayout.ALIGN_PARENT_TOP);
+ iconLP.addRule(RelativeLayout.ALIGN_PARENT_START);
+ iconLP.topMargin = (int) convertDpToPixel(76.64f, activity);
+ iconLP.leftMargin = (int) convertDpToPixel(71.99f, activity);
+ mIcon.setLayoutParams(iconLP);
+
+ RelativeLayout.LayoutParams titleLP = new RelativeLayout.LayoutParams(
+ metrics.widthPixels / 2, -2);
+ titleLP.addRule(RelativeLayout.ALIGN_PARENT_TOP);
+ titleLP.addRule(RelativeLayout.ALIGN_PARENT_START, R.id.udfps_animation_view);
+ titleLP.topMargin = (int) convertDpToPixel(138f, activity);
+ titleLP.leftMargin = (int) convertDpToPixel(66f, activity);
+ mTitleText.setLayoutParams(titleLP);
+
+ RelativeLayout.LayoutParams subtitleLP = new RelativeLayout.LayoutParams(
+ metrics.widthPixels / 2, -2);
+ subtitleLP.addRule(RelativeLayout.ALIGN_PARENT_TOP);
+ subtitleLP.addRule(RelativeLayout.ALIGN_PARENT_START);
+ subtitleLP.topMargin = (int) convertDpToPixel(198f, activity);
+ subtitleLP.leftMargin = (int) convertDpToPixel(66f, activity);
+ mSubTitleText.setLayoutParams(subtitleLP);
}
+ if (rotation == Surface.ROTATION_90 || rotation == Surface.ROTATION_270) {
+ RelativeLayout.LayoutParams skipBtnLP =
+ (RelativeLayout.LayoutParams) mIcon.getLayoutParams();
+ skipBtnLP.topMargin = (int) convertDpToPixel(26f, activity);
+ skipBtnLP.leftMargin = (int) convertDpToPixel(54f, activity);
+ mSkipBtn.requestLayout();
+ }
return containView;
}
@@ -358,8 +324,9 @@ public class FingerprintEnrollEnrollingUdfpsFragment extends Fragment {
final int progress = getProgress(enrollmentProgress);
- mUdfpsEnrollHelper.onEnrollmentProgress(enrollmentProgress.getSteps(),
- enrollmentProgress.getRemaining());
+
+ mUdfpsEnrollView.onEnrollmentProgress(enrollmentProgress.getRemaining(),
+ enrollmentProgress.getSteps());
if (animate) {
animateProgress(progress);
@@ -382,38 +349,6 @@ public class FingerprintEnrollEnrollingUdfpsFragment extends Fragment {
super.onDestroy();
}
- private UdfpsEnrollView addUdfpsEnrollView(LayoutInflater inflater,
- FingerprintSensorPropertiesInternal udfpsProps) {
-
- UdfpsEnrollView enrollView = (UdfpsEnrollView) inflater.inflate(R.layout.udfps_enroll_view,
- null, false);
- DisplayInfo displayInfo = new DisplayInfo();
- getActivity().getDisplay().getDisplayInfo(displayInfo);
- mScaleFactor = mUdfpsUtils.getScaleFactor(displayInfo);
- Rect udfpsBounds = udfpsProps.getLocation().getRect();
- udfpsBounds.scale(mScaleFactor);
-
- final Rect overlayBounds = new Rect(
- 0, /* left */
- displayInfo.getNaturalHeight() / 2, /* top */
- displayInfo.getNaturalWidth(), /* right */
- displayInfo.getNaturalHeight() /* botom */);
-
- UdfpsOverlayParams params = new UdfpsOverlayParams(
- udfpsBounds,
- overlayBounds,
- displayInfo.getNaturalWidth(),
- displayInfo.getNaturalHeight(),
- mScaleFactor,
- displayInfo.rotation);
-
- enrollView.setOverlayParams(params);
-
- enrollView.setEnrollHelper(mUdfpsEnrollHelper);
-
- return enrollView;
- }
-
private void animateProgress(int progress) {
// UDFPS animations are owned by SystemUI
if (progress >= PROGRESS_BAR_MAX) {
@@ -423,17 +358,11 @@ public class FingerprintEnrollEnrollingUdfpsFragment extends Fragment {
}
private void updateTitleAndDescription() {
-
- final Activity activity = getActivity();
- final GlifLayoutHelper glifLayoutHelper = new GlifLayoutHelper(activity, mView);
-
switch (getCurrentStage()) {
case STAGE_CENTER:
- glifLayoutHelper.setHeaderText(
- R.string.security_settings_fingerprint_enroll_repeat_title);
+ mTitleText.setText(R.string.security_settings_fingerprint_enroll_repeat_title);
if (mIsAccessibilityEnabled || mIllustrationLottie == null) {
- glifLayoutHelper.setDescriptionText(getString(
- R.string.security_settings_udfps_enroll_start_message));
+ mSubTitleText.setText(R.string.security_settings_udfps_enroll_start_message);
} else if (!mHaveShownUdfpsCenterLottie && mIllustrationLottie != null) {
mHaveShownUdfpsCenterLottie = true;
// Note: Update string reference when differentiate in between udfps & sfps
@@ -445,11 +374,10 @@ public class FingerprintEnrollEnrollingUdfpsFragment extends Fragment {
break;
case STAGE_GUIDED:
- glifLayoutHelper.setHeaderText(
- R.string.security_settings_fingerprint_enroll_repeat_title);
+ mTitleText.setText(R.string.security_settings_fingerprint_enroll_repeat_title);
if (mIsAccessibilityEnabled || mIllustrationLottie == null) {
- glifLayoutHelper.setDescriptionText(getString(
- R.string.security_settings_udfps_enroll_repeat_a11y_message));
+ mSubTitleText.setText(
+ R.string.security_settings_udfps_enroll_repeat_a11y_message);
} else if (!mHaveShownUdfpsGuideLottie && mIllustrationLottie != null) {
mHaveShownUdfpsGuideLottie = true;
mIllustrationLottie.setContentDescription(
@@ -460,8 +388,7 @@ public class FingerprintEnrollEnrollingUdfpsFragment extends Fragment {
}
break;
case STAGE_FINGERTIP:
- glifLayoutHelper.setHeaderText(
- R.string.security_settings_udfps_enroll_fingertip_title);
+ mTitleText.setText(R.string.security_settings_udfps_enroll_fingertip_title);
if (!mHaveShownUdfpsTipLottie && mIllustrationLottie != null) {
mHaveShownUdfpsTipLottie = true;
mIllustrationLottie.setContentDescription(
@@ -471,8 +398,7 @@ public class FingerprintEnrollEnrollingUdfpsFragment extends Fragment {
}
break;
case STAGE_LEFT_EDGE:
- glifLayoutHelper.setHeaderText(
- R.string.security_settings_udfps_enroll_left_edge_title);
+ mTitleText.setText(R.string.security_settings_udfps_enroll_left_edge_title);
if (!mHaveShownUdfpsLeftEdgeLottie && mIllustrationLottie != null) {
mHaveShownUdfpsLeftEdgeLottie = true;
mIllustrationLottie.setContentDescription(
@@ -481,17 +407,15 @@ public class FingerprintEnrollEnrollingUdfpsFragment extends Fragment {
configureEnrollmentStage("", R.raw.udfps_left_edge_hint_lottie);
} else if (mIllustrationLottie == null) {
if (isStageHalfCompleted()) {
- glifLayoutHelper.setDescriptionText(getString(
- R.string.security_settings_fingerprint_enroll_repeat_message));
+ mSubTitleText.setText(
+ R.string.security_settings_fingerprint_enroll_repeat_message);
} else {
- glifLayoutHelper.setDescriptionText(getString(
- R.string.security_settings_udfps_enroll_edge_message));
+ mSubTitleText.setText(R.string.security_settings_udfps_enroll_edge_message);
}
}
break;
case STAGE_RIGHT_EDGE:
- glifLayoutHelper.setHeaderText(
- R.string.security_settings_udfps_enroll_right_edge_title);
+ mTitleText.setText(R.string.security_settings_udfps_enroll_right_edge_title);
if (!mHaveShownUdfpsRightEdgeLottie && mIllustrationLottie != null) {
mHaveShownUdfpsRightEdgeLottie = true;
mIllustrationLottie.setContentDescription(
@@ -501,31 +425,22 @@ public class FingerprintEnrollEnrollingUdfpsFragment extends Fragment {
} else if (mIllustrationLottie == null) {
if (isStageHalfCompleted()) {
- glifLayoutHelper.setDescriptionText(getString(
- R.string.security_settings_fingerprint_enroll_repeat_message));
+ mSubTitleText.setText(
+ R.string.security_settings_fingerprint_enroll_repeat_message);
} else {
- glifLayoutHelper.setDescriptionText(getString(
- R.string.security_settings_udfps_enroll_edge_message));
+ mSubTitleText.setText(R.string.security_settings_udfps_enroll_edge_message);
}
}
break;
case STAGE_UNKNOWN:
default:
- // setHeaderText(R.string.security_settings_fingerprint_enroll_udfps_title);
- // Don't use BiometricEnrollBase#setHeaderText, since that invokes setTitle,
- // which gets announced for a11y upon entering the page. For UDFPS, we want to
- // announce a different string for a11y upon entering the page.
- glifLayoutHelper.setHeaderText(
- R.string.security_settings_fingerprint_enroll_udfps_title);
- glifLayoutHelper.setDescriptionText(getString(
- R.string.security_settings_udfps_enroll_start_message));
+ mTitleText.setText(R.string.security_settings_fingerprint_enroll_udfps_title);
+ mSubTitleText.setText(R.string.security_settings_udfps_enroll_start_message);
final CharSequence description = getString(
R.string.security_settings_udfps_enroll_a11y);
- mView.getHeaderTextView().setContentDescription(description);
- activity.setTitle(description);
+ getActivity().setTitle(description);
break;
-
}
}
@@ -538,7 +453,7 @@ public class FingerprintEnrollEnrollingUdfpsFragment extends Fragment {
return defaultDensity == currentDensity;
}
- private void updateOrientation(@NonNull GlifLayout glifLayout, int orientation) {
+ private void updateOrientation(@NonNull RelativeLayout content, int orientation) {
switch (orientation) {
case Configuration.ORIENTATION_LANDSCAPE: {
mIllustrationLottie = null;
@@ -546,7 +461,7 @@ public class FingerprintEnrollEnrollingUdfpsFragment extends Fragment {
}
case Configuration.ORIENTATION_PORTRAIT: {
if (mShouldShowLottie) {
- mIllustrationLottie = glifLayout.findViewById(R.id.illustration_lottie);
+ mIllustrationLottie = content.findViewById(R.id.illustration_lottie);
}
break;
}
@@ -625,7 +540,7 @@ public class FingerprintEnrollEnrollingUdfpsFragment extends Fragment {
}
private void configureEnrollmentStage(CharSequence description, @RawRes int lottie) {
- new GlifLayoutHelper(getActivity(), mView).setDescriptionText(description);
+ mSubTitleText.setText(description);
LottieCompositionFactory.fromRawRes(getActivity(), lottie)
.addListener((c) -> {
mIllustrationLottie.setComposition(c);
@@ -634,31 +549,6 @@ public class FingerprintEnrollEnrollingUdfpsFragment extends Fragment {
});
}
- private void setOnHoverListener(boolean isLandscape, GlifLayout enrollLayout,
- UdfpsEnrollView udfpsEnrollView) {
- if (!mIsAccessibilityEnabled) return;
-
- final Context context = getActivity();
- final View.OnHoverListener onHoverListener = (v, event) -> {
- // Map the touch to portrait mode if the device is in
- // landscape mode.
- final Point scaledTouch =
- mUdfpsUtils.getTouchInNativeCoordinates(event.getPointerId(0),
- event, udfpsEnrollView.getOverlayParams());
-
- final String theStr = mUdfpsUtils.onTouchOutsideOfSensorArea(
- mEnrollingViewModel.isTouchExplorationEnabled(), context,
- scaledTouch.x, scaledTouch.y, udfpsEnrollView.getOverlayParams());
- if (theStr != null) {
- v.announceForAccessibility(theStr);
- }
- return false;
- };
-
- enrollLayout.findManagedViewById(isLandscape ? R.id.sud_landscape_content_area
- : R.id.sud_layout_content).setOnHoverListener(onHoverListener);
- }
-
private void onEnrollmentProgressChange(@NonNull EnrollmentProgress progress) {
updateProgress(true /* animate */, progress);
@@ -678,34 +568,43 @@ public class FingerprintEnrollEnrollingUdfpsFragment extends Fragment {
private void onEnrollmentHelp(int helpMsgId, CharSequence helpString) {
if (!TextUtils.isEmpty(helpString)) {
showError(helpString);
- mUdfpsEnrollHelper.onEnrollmentHelp();
+ mUdfpsEnrollView.onEnrollmentHelp();
}
}
private void onAcquired(boolean isAcquiredGood) {
- if (mUdfpsEnrollHelper != null) {
- mUdfpsEnrollHelper.onAcquired(isAcquiredGood);
+ if (mUdfpsEnrollView != null) {
+ mUdfpsEnrollView.onAcquired(isAcquiredGood);
}
}
private void onPointerDown(int sensorId) {
- if (mUdfpsEnrollHelper != null) {
- mUdfpsEnrollHelper.onPointerDown(sensorId);
+ if (mUdfpsEnrollView != null) {
+ mUdfpsEnrollView.onPointerDown(sensorId);
}
}
private void onPointerUp(int sensorId) {
- if (mUdfpsEnrollHelper != null) {
- mUdfpsEnrollHelper.onPointerUp(sensorId);
+ if (mUdfpsEnrollView != null) {
+ mUdfpsEnrollView.onPointerUp(sensorId);
}
}
private void showError(CharSequence error) {
- mView.setHeaderText(error);
- mView.getHeaderTextView().setContentDescription(error);
- new GlifLayoutHelper(getActivity(), mView).setDescriptionText("");
+ mTitleText.setText(error);
+ mTitleText.setContentDescription(error);
+ mSubTitleText.setContentDescription("");
}
+ private float convertDpToPixel(float dp, Context context) {
+ float px = dp * getDensity(context);
+ return px;
+ }
+
+ private float getDensity(Context context) {
+ DisplayMetrics metrics = context.getResources().getDisplayMetrics();
+ return metrics.density;
+ }
private final Runnable mShowDialogRunnable = new Runnable() {
@Override
diff --git a/src/com/android/settings/biometrics2/ui/widget/UdfpsEnrollDrawable.java b/src/com/android/settings/biometrics2/ui/widget/UdfpsEnrollDrawable.java
new file mode 100644
index 00000000000..4b0b624f91e
--- /dev/null
+++ b/src/com/android/settings/biometrics2/ui/widget/UdfpsEnrollDrawable.java
@@ -0,0 +1,436 @@
+/*
+ * Copyright (C) 2023 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.biometrics2.ui.widget;
+
+import android.animation.Animator;
+import android.animation.AnimatorSet;
+import android.animation.ValueAnimator;
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.graphics.Canvas;
+import android.graphics.ColorFilter;
+import android.graphics.Paint;
+import android.graphics.PointF;
+import android.graphics.Rect;
+import android.graphics.RectF;
+import android.graphics.drawable.Drawable;
+import android.graphics.drawable.ShapeDrawable;
+import android.graphics.drawable.shapes.PathShape;
+import android.hardware.fingerprint.FingerprintManager;
+import android.os.Build;
+import android.os.UserHandle;
+import android.provider.Settings;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.util.PathParser;
+import android.util.TypedValue;
+import android.view.accessibility.AccessibilityManager;
+import android.view.animation.AccelerateDecelerateInterpolator;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+import com.android.settings.R;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * UDFPS fingerprint drawable that is shown when enrolling
+ */
+public class UdfpsEnrollDrawable extends Drawable {
+ private static final String TAG = "UdfpsAnimationEnroll";
+
+ private static final long TARGET_ANIM_DURATION_LONG = 800L;
+ private static final long TARGET_ANIM_DURATION_SHORT = 600L;
+ // 1 + SCALE_MAX is the maximum that the moving target will animate to
+ private static final float SCALE_MAX = 0.25f;
+ private static final float DEFAULT_STROKE_WIDTH = 3f;
+ private static final float SCALE = 0.5f;
+ private static final String SCALE_OVERRIDE =
+ "com.android.systemui.biometrics.UdfpsEnrollHelper.scale";
+ private static final String NEW_COORDS_OVERRIDE =
+ "com.android.systemui.biometrics.UdfpsNewCoords";
+
+ @NonNull
+ private final Drawable mMovingTargetFpIcon;
+ @NonNull
+ private final Paint mSensorOutlinePaint;
+ @NonNull
+ private final Paint mBlueFill;
+ @NonNull
+ private final ShapeDrawable mFingerprintDrawable;
+ private int mAlpha;
+ private boolean mSkipDraw = false;
+
+ @Nullable
+ private RectF mSensorRect;
+
+ // Moving target animator set
+ @Nullable
+ AnimatorSet mTargetAnimatorSet;
+ // Moving target location
+ float mCurrentX;
+ float mCurrentY;
+ // Moving target size
+ float mCurrentScale = 1.f;
+
+ @NonNull
+ private final Animator.AnimatorListener mTargetAnimListener;
+
+ private boolean mShouldShowTipHint = false;
+ private boolean mShouldShowEdgeHint = false;
+
+ private int mEnrollIcon;
+ private int mMovingTargetFill;
+
+ private int mTotalSteps = -1;
+ private int mRemainingSteps = -1;
+ private int mLocationsEnrolled = 0;
+ private int mCenterTouchCount = 0;
+
+ private FingerprintManager mFingerprintManager;
+
+ private boolean mAccessibilityEnabled;
+ private Context mContext;
+ private final List mGuidedEnrollmentPoints;
+
+ UdfpsEnrollDrawable(@NonNull Context context, @Nullable AttributeSet attrs) {
+ mFingerprintDrawable = defaultFactory(context);
+
+ loadResources(context, attrs);
+ mSensorOutlinePaint = new Paint(0 /* flags */);
+ mSensorOutlinePaint.setAntiAlias(true);
+ mSensorOutlinePaint.setColor(mMovingTargetFill);
+ mSensorOutlinePaint.setStyle(Paint.Style.FILL);
+
+ mBlueFill = new Paint(0 /* flags */);
+ mBlueFill.setAntiAlias(true);
+ mBlueFill.setColor(mMovingTargetFill);
+ mBlueFill.setStyle(Paint.Style.FILL);
+
+ mMovingTargetFpIcon = context.getResources()
+ .getDrawable(R.drawable.ic_enrollment_fingerprint, null);
+ mMovingTargetFpIcon.setTint(mEnrollIcon);
+ mMovingTargetFpIcon.mutate();
+
+ mFingerprintDrawable.setTint(mEnrollIcon);
+
+ setAlpha(255);
+ mTargetAnimListener = new Animator.AnimatorListener() {
+ @Override
+ public void onAnimationStart(Animator animation) {
+ }
+
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ updateTipHintVisibility();
+ }
+
+ @Override
+ public void onAnimationCancel(Animator animation) {
+ }
+
+ @Override
+ public void onAnimationRepeat(Animator animation) {
+ }
+ };
+ mContext = context;
+ mFingerprintManager = context.getSystemService(FingerprintManager.class);
+ final AccessibilityManager am = context.getSystemService(AccessibilityManager.class);
+ mAccessibilityEnabled = am.isEnabled();
+ mGuidedEnrollmentPoints = new ArrayList<>();
+ initEnrollPoint(context);
+ }
+
+ /** The [sensorRect] coordinates for the sensor area. */
+ void onSensorRectUpdated(@NonNull RectF sensorRect) {
+ int margin = ((int) sensorRect.height()) / 8;
+ Rect bounds = new Rect((int) (sensorRect.left) + margin, (int) (sensorRect.top) + margin,
+ (int) (sensorRect.right) - margin, (int) (sensorRect.bottom) - margin);
+ updateFingerprintIconBounds(bounds);
+ mSensorRect = sensorRect;
+ }
+
+ void setShouldSkipDraw(boolean skipDraw) {
+ if (mSkipDraw == skipDraw) {
+ return;
+ }
+ mSkipDraw = skipDraw;
+ invalidateSelf();
+ }
+
+ void updateFingerprintIconBounds(@NonNull Rect bounds) {
+ mFingerprintDrawable.setBounds(bounds);
+ invalidateSelf();
+ mMovingTargetFpIcon.setBounds(bounds);
+ invalidateSelf();
+ }
+
+ void onEnrollmentProgress(final int remaining, final int totalSteps) {
+ if (mTotalSteps == -1) {
+ mTotalSteps = totalSteps;
+ }
+
+ if (remaining != mRemainingSteps) {
+ mLocationsEnrolled++;
+ if (isCenterEnrollmentStage()) {
+ mCenterTouchCount++;
+ }
+ }
+ mRemainingSteps = remaining;
+
+ if (!isCenterEnrollmentStage()) {
+ if (mTargetAnimatorSet != null && mTargetAnimatorSet.isRunning()) {
+ mTargetAnimatorSet.end();
+ }
+
+ final PointF point = getNextGuidedEnrollmentPoint();
+ if (mCurrentX != point.x || mCurrentY != point.y) {
+ final ValueAnimator x = ValueAnimator.ofFloat(mCurrentX, point.x);
+ x.addUpdateListener(animation -> {
+ mCurrentX = (float) animation.getAnimatedValue();
+ invalidateSelf();
+ });
+
+ final ValueAnimator y = ValueAnimator.ofFloat(mCurrentY, point.y);
+ y.addUpdateListener(animation -> {
+ mCurrentY = (float) animation.getAnimatedValue();
+ invalidateSelf();
+ });
+
+ final boolean isMovingToCenter = point.x == 0f && point.y == 0f;
+ final long duration = isMovingToCenter
+ ? TARGET_ANIM_DURATION_SHORT
+ : TARGET_ANIM_DURATION_LONG;
+
+ final ValueAnimator scale = ValueAnimator.ofFloat(0, (float) Math.PI);
+ scale.setDuration(duration);
+ scale.addUpdateListener(animation -> {
+ // Grow then shrink
+ mCurrentScale = 1
+ + SCALE_MAX * (float) Math.sin((float) animation.getAnimatedValue());
+ invalidateSelf();
+ });
+
+ mTargetAnimatorSet = new AnimatorSet();
+
+ mTargetAnimatorSet.setInterpolator(new AccelerateDecelerateInterpolator());
+ mTargetAnimatorSet.setDuration(duration);
+ mTargetAnimatorSet.addListener(mTargetAnimListener);
+ mTargetAnimatorSet.playTogether(x, y, scale);
+ mTargetAnimatorSet.start();
+ } else {
+ updateTipHintVisibility();
+ }
+ } else {
+ updateTipHintVisibility();
+ }
+
+ updateEdgeHintVisibility();
+ }
+
+ @Override
+ public void draw(@NonNull Canvas canvas) {
+ if (mSkipDraw) {
+ return;
+ }
+
+ // Draw moving target
+ if (!isCenterEnrollmentStage()) {
+ canvas.save();
+ canvas.translate(mCurrentX, mCurrentY);
+
+ if (mSensorRect != null) {
+ canvas.scale(mCurrentScale, mCurrentScale,
+ mSensorRect.centerX(), mSensorRect.centerY());
+ canvas.drawOval(mSensorRect, mBlueFill);
+ }
+
+ mMovingTargetFpIcon.draw(canvas);
+ canvas.restore();
+ } else {
+ if (mSensorRect != null) {
+ canvas.drawOval(mSensorRect, mSensorOutlinePaint);
+ }
+ mFingerprintDrawable.draw(canvas);
+ mFingerprintDrawable.setAlpha(getAlpha());
+ mSensorOutlinePaint.setAlpha(getAlpha());
+ }
+
+ }
+
+ @Override
+ public void setAlpha(int alpha) {
+ mAlpha = alpha;
+ mFingerprintDrawable.setAlpha(alpha);
+ mSensorOutlinePaint.setAlpha(alpha);
+ mBlueFill.setAlpha(alpha);
+ mMovingTargetFpIcon.setAlpha(alpha);
+ invalidateSelf();
+ }
+
+ @Override
+ public int getAlpha() {
+ return mAlpha;
+ }
+
+ @Override
+ public void setColorFilter(@Nullable ColorFilter colorFilter) {
+ }
+
+ @Override
+ public int getOpacity() {
+ return 0;
+ }
+
+ private void updateTipHintVisibility() {
+ final boolean shouldShow = isTipEnrollmentStage();
+ // With the new update, we will git rid of most of this code, and instead
+ // we will change the fingerprint icon.
+ if (mShouldShowTipHint == shouldShow) {
+ return;
+ }
+ mShouldShowTipHint = shouldShow;
+ }
+
+ private void updateEdgeHintVisibility() {
+ final boolean shouldShow = isEdgeEnrollmentStage();
+ if (mShouldShowEdgeHint == shouldShow) {
+ return;
+ }
+ mShouldShowEdgeHint = shouldShow;
+ }
+
+ private ShapeDrawable defaultFactory(Context context) {
+ String fpPath = context.getResources().getString(R.string.config_udfpsIcon);
+ ShapeDrawable drawable = new ShapeDrawable(
+ new PathShape(PathParser.createPathFromPathData(fpPath), 72f, 72f)
+ );
+ drawable.mutate();
+ drawable.getPaint().setStyle(Paint.Style.STROKE);
+ drawable.getPaint().setStrokeCap(Paint.Cap.ROUND);
+ drawable.getPaint().setStrokeWidth(DEFAULT_STROKE_WIDTH);
+ return drawable;
+ }
+
+ private void loadResources(Context context, @Nullable AttributeSet attrs) {
+ final TypedArray ta = context.obtainStyledAttributes(attrs,
+ R.styleable.BiometricsEnrollView, R.attr.biometricsEnrollStyle,
+ R.style.BiometricsEnrollStyle);
+ mEnrollIcon = ta.getColor(R.styleable.BiometricsEnrollView_biometricsEnrollIcon, 0);
+ mMovingTargetFill = ta.getColor(
+ R.styleable.BiometricsEnrollView_biometricsMovingTargetFill, 0);
+ ta.recycle();
+ }
+
+ private boolean isCenterEnrollmentStage() {
+ if (mTotalSteps == -1 || mRemainingSteps == -1) {
+ return true;
+ }
+ return mTotalSteps - mRemainingSteps < getStageThresholdSteps(mTotalSteps, 0);
+ }
+
+ private int getStageThresholdSteps(int totalSteps, int stageIndex) {
+ return Math.round(totalSteps * mFingerprintManager.getEnrollStageThreshold(stageIndex));
+ }
+
+ private PointF getNextGuidedEnrollmentPoint() {
+ if (mAccessibilityEnabled || !isGuidedEnrollmentStage()) {
+ return new PointF(0f, 0f);
+ }
+
+ float scale = SCALE;
+ if (Build.IS_ENG || Build.IS_USERDEBUG) {
+ scale = Settings.Secure.getFloatForUser(mContext.getContentResolver(),
+ SCALE_OVERRIDE, SCALE,
+ UserHandle.USER_CURRENT);
+ }
+ final int index = mLocationsEnrolled - mCenterTouchCount;
+ final PointF originalPoint = mGuidedEnrollmentPoints
+ .get(index % mGuidedEnrollmentPoints.size());
+ return new PointF(originalPoint.x * scale, originalPoint.y * scale);
+ }
+
+ private boolean isGuidedEnrollmentStage() {
+ if (mAccessibilityEnabled || mTotalSteps == -1 || mRemainingSteps == -1) {
+ return false;
+ }
+ final int progressSteps = mTotalSteps - mRemainingSteps;
+ return progressSteps >= getStageThresholdSteps(mTotalSteps, 0)
+ && progressSteps < getStageThresholdSteps(mTotalSteps, 1);
+ }
+
+ private boolean isTipEnrollmentStage() {
+ if (mTotalSteps == -1 || mRemainingSteps == -1) {
+ return false;
+ }
+ final int progressSteps = mTotalSteps - mRemainingSteps;
+ return progressSteps >= getStageThresholdSteps(mTotalSteps, 1)
+ && progressSteps < getStageThresholdSteps(mTotalSteps, 2);
+ }
+
+ private boolean isEdgeEnrollmentStage() {
+ if (mTotalSteps == -1 || mRemainingSteps == -1) {
+ return false;
+ }
+ return mTotalSteps - mRemainingSteps >= getStageThresholdSteps(mTotalSteps, 2);
+ }
+
+ private void initEnrollPoint(Context context) {
+ // Number of pixels per mm
+ float px = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_MM, 1,
+ context.getResources().getDisplayMetrics());
+ boolean useNewCoords = Settings.Secure.getIntForUser(mContext.getContentResolver(),
+ NEW_COORDS_OVERRIDE, 0,
+ UserHandle.USER_CURRENT) != 0;
+ if (useNewCoords && (Build.IS_ENG || Build.IS_USERDEBUG)) {
+ Log.v(TAG, "Using new coordinates");
+ mGuidedEnrollmentPoints.add(new PointF(-0.15f * px, -1.02f * px));
+ mGuidedEnrollmentPoints.add(new PointF(-0.15f * px, 1.02f * px));
+ mGuidedEnrollmentPoints.add(new PointF(0.29f * px, 0.00f * px));
+ mGuidedEnrollmentPoints.add(new PointF(2.17f * px, -2.35f * px));
+ mGuidedEnrollmentPoints.add(new PointF(1.07f * px, -3.96f * px));
+ mGuidedEnrollmentPoints.add(new PointF(-0.37f * px, -4.31f * px));
+ mGuidedEnrollmentPoints.add(new PointF(-1.69f * px, -3.29f * px));
+ mGuidedEnrollmentPoints.add(new PointF(-2.48f * px, -1.23f * px));
+ mGuidedEnrollmentPoints.add(new PointF(-2.48f * px, 1.23f * px));
+ mGuidedEnrollmentPoints.add(new PointF(-1.69f * px, 3.29f * px));
+ mGuidedEnrollmentPoints.add(new PointF(-0.37f * px, 4.31f * px));
+ mGuidedEnrollmentPoints.add(new PointF(1.07f * px, 3.96f * px));
+ mGuidedEnrollmentPoints.add(new PointF(2.17f * px, 2.35f * px));
+ mGuidedEnrollmentPoints.add(new PointF(2.58f * px, 0.00f * px));
+ } else {
+ Log.v(TAG, "Using old coordinates");
+ mGuidedEnrollmentPoints.add(new PointF(2.00f * px, 0.00f * px));
+ mGuidedEnrollmentPoints.add(new PointF(0.87f * px, -2.70f * px));
+ mGuidedEnrollmentPoints.add(new PointF(-1.80f * px, -1.31f * px));
+ mGuidedEnrollmentPoints.add(new PointF(-1.80f * px, 1.31f * px));
+ mGuidedEnrollmentPoints.add(new PointF(0.88f * px, 2.70f * px));
+ mGuidedEnrollmentPoints.add(new PointF(3.94f * px, -1.06f * px));
+ mGuidedEnrollmentPoints.add(new PointF(2.90f * px, -4.14f * px));
+ mGuidedEnrollmentPoints.add(new PointF(-0.52f * px, -5.95f * px));
+ mGuidedEnrollmentPoints.add(new PointF(-3.33f * px, -3.33f * px));
+ mGuidedEnrollmentPoints.add(new PointF(-3.99f * px, -0.35f * px));
+ mGuidedEnrollmentPoints.add(new PointF(-3.62f * px, 2.54f * px));
+ mGuidedEnrollmentPoints.add(new PointF(-1.49f * px, 5.57f * px));
+ mGuidedEnrollmentPoints.add(new PointF(2.29f * px, 4.92f * px));
+ mGuidedEnrollmentPoints.add(new PointF(3.82f * px, 1.78f * px));
+ }
+ }
+
+}
diff --git a/src/com/android/settings/biometrics2/ui/widget/UdfpsEnrollProgressBarDrawable.java b/src/com/android/settings/biometrics2/ui/widget/UdfpsEnrollProgressBarDrawable.java
new file mode 100644
index 00000000000..3f8388fcb5e
--- /dev/null
+++ b/src/com/android/settings/biometrics2/ui/widget/UdfpsEnrollProgressBarDrawable.java
@@ -0,0 +1,424 @@
+/*
+ * Copyright (C) 2023 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.biometrics2.ui.widget;
+
+import android.animation.ValueAnimator;
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.graphics.Canvas;
+import android.graphics.ColorFilter;
+import android.graphics.Paint;
+import android.graphics.drawable.Drawable;
+import android.os.Process;
+import android.os.VibrationAttributes;
+import android.os.VibrationEffect;
+import android.os.Vibrator;
+import android.util.AttributeSet;
+import android.util.DisplayMetrics;
+import android.view.accessibility.AccessibilityManager;
+import android.view.animation.DecelerateInterpolator;
+import android.view.animation.Interpolator;
+import android.view.animation.OvershootInterpolator;
+
+import androidx.annotation.ColorInt;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.settings.R;
+
+/**
+ * UDFPS enrollment progress bar.
+ */
+public class UdfpsEnrollProgressBarDrawable extends Drawable {
+ private static final String TAG = "UdfpsProgressBar";
+
+ private static final long CHECKMARK_ANIMATION_DELAY_MS = 200L;
+ private static final long CHECKMARK_ANIMATION_DURATION_MS = 300L;
+ private static final long FILL_COLOR_ANIMATION_DURATION_MS = 350L;
+ private static final long PROGRESS_ANIMATION_DURATION_MS = 400L;
+ private static final float STROKE_WIDTH_DP = 12f;
+ private static final Interpolator DEACCEL = new DecelerateInterpolator();
+
+ private static final VibrationEffect VIBRATE_EFFECT_ERROR =
+ VibrationEffect.createWaveform(new long[]{0, 5, 55, 60}, -1);
+ private static final VibrationAttributes FINGERPRINT_ENROLLING_SONFICATION_ATTRIBUTES =
+ VibrationAttributes.createForUsage(VibrationAttributes.USAGE_ACCESSIBILITY);
+
+ private static final VibrationAttributes HARDWARE_FEEDBACK_VIBRATION_ATTRIBUTES =
+ VibrationAttributes.createForUsage(VibrationAttributes.USAGE_HARDWARE_FEEDBACK);
+
+ private static final VibrationEffect SUCCESS_VIBRATION_EFFECT =
+ VibrationEffect.get(VibrationEffect.EFFECT_CLICK);
+
+ private final float mStrokeWidthPx;
+ @ColorInt
+ private final int mProgressColor;
+ @ColorInt
+ private final int mHelpColor;
+ @ColorInt
+ private final int mOnFirstBucketFailedColor;
+ @NonNull
+ private final Drawable mCheckmarkDrawable;
+ @NonNull
+ private final Interpolator mCheckmarkInterpolator;
+ @NonNull
+ private final Paint mBackgroundPaint;
+ @VisibleForTesting
+ @NonNull
+ final Paint mFillPaint;
+ @NonNull
+ private final Vibrator mVibrator;
+ @NonNull
+ private final boolean mIsAccessibilityEnabled;
+ @NonNull
+ private final Context mContext;
+
+ private boolean mAfterFirstTouch;
+
+ private int mRemainingSteps = 0;
+ private int mTotalSteps = 0;
+ private float mProgress = 0f;
+ @Nullable
+ private ValueAnimator mProgressAnimator;
+ @NonNull
+ private final ValueAnimator.AnimatorUpdateListener mProgressUpdateListener;
+
+ private boolean mShowingHelp = false;
+ @Nullable
+ private ValueAnimator mFillColorAnimator;
+ @NonNull
+ private final ValueAnimator.AnimatorUpdateListener mFillColorUpdateListener;
+
+ @Nullable
+ private ValueAnimator mBackgroundColorAnimator;
+ @NonNull
+ private final ValueAnimator.AnimatorUpdateListener mBackgroundColorUpdateListener;
+
+ private boolean mComplete = false;
+ private float mCheckmarkScale = 0f;
+ @Nullable
+ private ValueAnimator mCheckmarkAnimator;
+ @NonNull
+ private final ValueAnimator.AnimatorUpdateListener mCheckmarkUpdateListener;
+
+ private int mMovingTargetFill;
+ private int mMovingTargetFillError;
+ private int mEnrollProgress;
+ private int mEnrollProgressHelp;
+ private int mEnrollProgressHelpWithTalkback;
+
+ public UdfpsEnrollProgressBarDrawable(@NonNull Context context, @Nullable AttributeSet attrs) {
+ mContext = context;
+
+ loadResources(context, attrs);
+ float density = context.getResources().getDisplayMetrics().densityDpi;
+ mStrokeWidthPx = STROKE_WIDTH_DP * (density / DisplayMetrics.DENSITY_DEFAULT);
+ mProgressColor = mEnrollProgress;
+ final AccessibilityManager am = context.getSystemService(AccessibilityManager.class);
+ mIsAccessibilityEnabled = am.isTouchExplorationEnabled();
+ mOnFirstBucketFailedColor = mMovingTargetFillError;
+ if (!mIsAccessibilityEnabled) {
+ mHelpColor = mEnrollProgressHelp;
+ } else {
+ mHelpColor = mEnrollProgressHelpWithTalkback;
+ }
+ mCheckmarkDrawable = context.getDrawable(R.drawable.udfps_enroll_checkmark);
+ mCheckmarkDrawable.mutate();
+ mCheckmarkInterpolator = new OvershootInterpolator();
+
+ mBackgroundPaint = new Paint();
+ mBackgroundPaint.setStrokeWidth(mStrokeWidthPx);
+ mBackgroundPaint.setColor(mMovingTargetFill);
+ mBackgroundPaint.setAntiAlias(true);
+ mBackgroundPaint.setStyle(Paint.Style.STROKE);
+ mBackgroundPaint.setStrokeCap(Paint.Cap.ROUND);
+
+ // Progress fill should *not* use the extracted system color.
+ mFillPaint = new Paint();
+ mFillPaint.setStrokeWidth(mStrokeWidthPx);
+ mFillPaint.setColor(mProgressColor);
+ mFillPaint.setAntiAlias(true);
+ mFillPaint.setStyle(Paint.Style.STROKE);
+ mFillPaint.setStrokeCap(Paint.Cap.ROUND);
+
+ mVibrator = mContext.getSystemService(Vibrator.class);
+
+ mProgressUpdateListener = animation -> {
+ mProgress = (float) animation.getAnimatedValue();
+ invalidateSelf();
+ };
+
+ mFillColorUpdateListener = animation -> {
+ mFillPaint.setColor((int) animation.getAnimatedValue());
+ invalidateSelf();
+ };
+
+ mCheckmarkUpdateListener = animation -> {
+ mCheckmarkScale = (float) animation.getAnimatedValue();
+ invalidateSelf();
+ };
+
+ mBackgroundColorUpdateListener = animation -> {
+ mBackgroundPaint.setColor((int) animation.getAnimatedValue());
+ invalidateSelf();
+ };
+ }
+
+ void onEnrollmentProgress(final int remaining, final int totalSteps) {
+ android.util.Log.e(TAG, "remaining =" + remaining);
+ android.util.Log.e(TAG, "totalSteps =" + totalSteps);
+ mAfterFirstTouch = true;
+ updateState(remaining, totalSteps, false /* showingHelp */);
+ }
+
+ void onEnrollmentHelp(int remaining, int totalSteps) {
+ updateState(remaining, totalSteps, true /* showingHelp */);
+ }
+
+ void onLastStepAcquired() {
+ updateState(0, mTotalSteps, false /* showingHelp */);
+ }
+
+ private void updateState(int remainingSteps, int totalSteps, boolean showingHelp) {
+ updateProgress(remainingSteps, totalSteps, showingHelp);
+ updateFillColor(showingHelp);
+ }
+
+ private void updateProgress(int remainingSteps, int totalSteps, boolean showingHelp) {
+ if (mRemainingSteps == remainingSteps && mTotalSteps == totalSteps) {
+ return;
+ }
+
+ if (mShowingHelp) {
+ if (mVibrator != null && mIsAccessibilityEnabled) {
+ mVibrator.vibrate(Process.myUid(), mContext.getOpPackageName(),
+ VIBRATE_EFFECT_ERROR, getClass().getSimpleName() + "::onEnrollmentHelp",
+ FINGERPRINT_ENROLLING_SONFICATION_ATTRIBUTES);
+ }
+ } else {
+ // If the first touch is an error, remainingSteps will be -1 and the callback
+ // doesn't come from onEnrollmentHelp. If we are in the accessibility flow,
+ // we still would like to vibrate.
+ if (mVibrator != null) {
+ if (remainingSteps == -1 && mIsAccessibilityEnabled) {
+ mVibrator.vibrate(Process.myUid(), mContext.getOpPackageName(),
+ VIBRATE_EFFECT_ERROR,
+ getClass().getSimpleName() + "::onFirstTouchError",
+ FINGERPRINT_ENROLLING_SONFICATION_ATTRIBUTES);
+ } else if (remainingSteps != -1 && !mIsAccessibilityEnabled) {
+ mVibrator.vibrate(Process.myUid(),
+ mContext.getOpPackageName(),
+ SUCCESS_VIBRATION_EFFECT,
+ getClass().getSimpleName() + "::OnEnrollmentProgress",
+ HARDWARE_FEEDBACK_VIBRATION_ATTRIBUTES);
+ }
+ }
+ }
+
+ mShowingHelp = showingHelp;
+ mRemainingSteps = remainingSteps;
+ mTotalSteps = totalSteps;
+
+ final int progressSteps = Math.max(0, totalSteps - remainingSteps);
+
+ // If needed, add 1 to progress and total steps to account for initial touch.
+ final int adjustedSteps = mAfterFirstTouch ? progressSteps + 1 : progressSteps;
+ final int adjustedTotal = mAfterFirstTouch ? mTotalSteps + 1 : mTotalSteps;
+
+ final float targetProgress = Math.min(1f, (float) adjustedSteps / (float) adjustedTotal);
+
+ if (mProgressAnimator != null && mProgressAnimator.isRunning()) {
+ mProgressAnimator.cancel();
+ }
+
+ mProgressAnimator = ValueAnimator.ofFloat(mProgress, targetProgress);
+ mProgressAnimator.setDuration(PROGRESS_ANIMATION_DURATION_MS);
+ mProgressAnimator.addUpdateListener(mProgressUpdateListener);
+ mProgressAnimator.start();
+
+ if (remainingSteps == 0) {
+ startCompletionAnimation();
+ } else if (remainingSteps > 0) {
+ rollBackCompletionAnimation();
+ }
+ }
+
+ private void animateBackgroundColor() {
+ if (mBackgroundColorAnimator != null && mBackgroundColorAnimator.isRunning()) {
+ mBackgroundColorAnimator.end();
+ }
+ mBackgroundColorAnimator = ValueAnimator.ofArgb(mBackgroundPaint.getColor(),
+ mOnFirstBucketFailedColor);
+ mBackgroundColorAnimator.setDuration(FILL_COLOR_ANIMATION_DURATION_MS);
+ mBackgroundColorAnimator.setRepeatCount(1);
+ mBackgroundColorAnimator.setRepeatMode(ValueAnimator.REVERSE);
+ mBackgroundColorAnimator.setInterpolator(DEACCEL);
+ mBackgroundColorAnimator.addUpdateListener(mBackgroundColorUpdateListener);
+ mBackgroundColorAnimator.start();
+ }
+
+ private void updateFillColor(boolean showingHelp) {
+ if (!mAfterFirstTouch && showingHelp) {
+ // If we are on the first touch, animate the background color
+ // instead of the progress color.
+ animateBackgroundColor();
+ return;
+ }
+
+ if (mFillColorAnimator != null && mFillColorAnimator.isRunning()) {
+ mFillColorAnimator.end();
+ }
+
+ @ColorInt final int targetColor = showingHelp ? mHelpColor : mProgressColor;
+ mFillColorAnimator = ValueAnimator.ofArgb(mFillPaint.getColor(), targetColor);
+ mFillColorAnimator.setDuration(FILL_COLOR_ANIMATION_DURATION_MS);
+ mFillColorAnimator.setRepeatCount(1);
+ mFillColorAnimator.setRepeatMode(ValueAnimator.REVERSE);
+ mFillColorAnimator.setInterpolator(DEACCEL);
+ mFillColorAnimator.addUpdateListener(mFillColorUpdateListener);
+ mFillColorAnimator.start();
+ }
+
+ private void startCompletionAnimation() {
+ if (mComplete) {
+ return;
+ }
+ mComplete = true;
+
+ if (mCheckmarkAnimator != null && mCheckmarkAnimator.isRunning()) {
+ mCheckmarkAnimator.cancel();
+ }
+
+ mCheckmarkAnimator = ValueAnimator.ofFloat(mCheckmarkScale, 1f);
+ mCheckmarkAnimator.setStartDelay(CHECKMARK_ANIMATION_DELAY_MS);
+ mCheckmarkAnimator.setDuration(CHECKMARK_ANIMATION_DURATION_MS);
+ mCheckmarkAnimator.setInterpolator(mCheckmarkInterpolator);
+ mCheckmarkAnimator.addUpdateListener(mCheckmarkUpdateListener);
+ mCheckmarkAnimator.start();
+ }
+
+ private void rollBackCompletionAnimation() {
+ if (!mComplete) {
+ return;
+ }
+ mComplete = false;
+
+ // Adjust duration based on how much of the completion animation has played.
+ final float animatedFraction = mCheckmarkAnimator != null
+ ? mCheckmarkAnimator.getAnimatedFraction()
+ : 0f;
+ final long durationMs = Math.round(CHECKMARK_ANIMATION_DELAY_MS * animatedFraction);
+
+ if (mCheckmarkAnimator != null && mCheckmarkAnimator.isRunning()) {
+ mCheckmarkAnimator.cancel();
+ }
+
+ mCheckmarkAnimator = ValueAnimator.ofFloat(mCheckmarkScale, 0f);
+ mCheckmarkAnimator.setDuration(durationMs);
+ mCheckmarkAnimator.addUpdateListener(mCheckmarkUpdateListener);
+ mCheckmarkAnimator.start();
+ }
+
+ private void loadResources(Context context, @Nullable AttributeSet attrs) {
+ final TypedArray ta = context.obtainStyledAttributes(attrs,
+ R.styleable.BiometricsEnrollView, R.attr.biometricsEnrollStyle,
+ R.style.BiometricsEnrollStyle);
+ mMovingTargetFill = ta.getColor(
+ R.styleable.BiometricsEnrollView_biometricsMovingTargetFill, 0);
+ mMovingTargetFillError = ta.getColor(
+ R.styleable.BiometricsEnrollView_biometricsMovingTargetFillError, 0);
+ mEnrollProgress = ta.getColor(
+ R.styleable.BiometricsEnrollView_biometricsEnrollProgress, 0);
+ mEnrollProgressHelp = ta.getColor(
+ R.styleable.BiometricsEnrollView_biometricsEnrollProgressHelp, 0);
+ mEnrollProgressHelpWithTalkback = ta.getColor(
+ R.styleable.BiometricsEnrollView_biometricsEnrollProgressHelpWithTalkback, 0);
+ ta.recycle();
+ }
+
+ @Override
+ public void draw(@NonNull Canvas canvas) {
+ canvas.save();
+
+ // Progress starts from the top, instead of the right
+ canvas.rotate(-90f, getBounds().centerX(), getBounds().centerY());
+
+ final float halfPaddingPx = mStrokeWidthPx / 2f;
+
+ if (mProgress < 1f) {
+ // Draw the background color of the progress circle.
+ canvas.drawArc(
+ halfPaddingPx,
+ halfPaddingPx,
+ getBounds().right - halfPaddingPx,
+ getBounds().bottom - halfPaddingPx,
+ 0f /* startAngle */,
+ 360f /* sweepAngle */,
+ false /* useCenter */,
+ mBackgroundPaint);
+ }
+
+ if (mProgress > 0f) {
+ // Draw the filled portion of the progress circle.
+ canvas.drawArc(
+ halfPaddingPx,
+ halfPaddingPx,
+ getBounds().right - halfPaddingPx,
+ getBounds().bottom - halfPaddingPx,
+ 0f /* startAngle */,
+ 360f * mProgress /* sweepAngle */,
+ false /* useCenter */,
+ mFillPaint);
+ }
+
+ canvas.restore();
+
+ if (mCheckmarkScale > 0f) {
+ final float offsetScale = (float) Math.sqrt(2) / 2f;
+ final float centerXOffset = (getBounds().width() - mStrokeWidthPx) / 2f * offsetScale;
+ final float centerYOffset = (getBounds().height() - mStrokeWidthPx) / 2f * offsetScale;
+ final float centerX = getBounds().centerX() + centerXOffset;
+ final float centerY = getBounds().centerY() + centerYOffset;
+
+ final float boundsXOffset =
+ mCheckmarkDrawable.getIntrinsicWidth() / 2f * mCheckmarkScale;
+ final float boundsYOffset =
+ mCheckmarkDrawable.getIntrinsicHeight() / 2f * mCheckmarkScale;
+
+ final int left = Math.round(centerX - boundsXOffset);
+ final int top = Math.round(centerY - boundsYOffset);
+ final int right = Math.round(centerX + boundsXOffset);
+ final int bottom = Math.round(centerY + boundsYOffset);
+ mCheckmarkDrawable.setBounds(left, top, right, bottom);
+ mCheckmarkDrawable.draw(canvas);
+ }
+ }
+
+ @Override
+ public void setAlpha(int alpha) {
+ }
+
+ @Override
+ public void setColorFilter(@Nullable ColorFilter colorFilter) {
+ }
+
+ @Override
+ public int getOpacity() {
+ return 0;
+ }
+}
diff --git a/src/com/android/settings/biometrics2/ui/widget/UdfpsEnrollView.java b/src/com/android/settings/biometrics2/ui/widget/UdfpsEnrollView.java
new file mode 100644
index 00000000000..a0d9b253fb3
--- /dev/null
+++ b/src/com/android/settings/biometrics2/ui/widget/UdfpsEnrollView.java
@@ -0,0 +1,260 @@
+/*
+ * Copyright (C) 2023 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.biometrics2.ui.widget;
+
+import android.content.Context;
+import android.graphics.Rect;
+import android.graphics.RectF;
+import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
+import android.os.Handler;
+import android.os.Looper;
+import android.util.AttributeSet;
+import android.util.RotationUtils;
+import android.view.DisplayInfo;
+import android.view.Surface;
+import android.view.ViewGroup;
+import android.view.ViewTreeObserver;
+import android.widget.FrameLayout;
+import android.widget.ImageView;
+import android.widget.RelativeLayout;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+import com.android.settings.R;
+import com.android.settingslib.udfps.UdfpsOverlayParams;
+import com.android.settingslib.udfps.UdfpsUtils;
+
+/**
+ * View corresponding with udfps_enroll_view.xml
+ */
+public class UdfpsEnrollView extends FrameLayout {
+ private static final String TAG = "UdfpsEnrollView";
+ @NonNull
+ private final UdfpsEnrollDrawable mFingerprintDrawable;
+ @NonNull
+ private final UdfpsEnrollProgressBarDrawable mFingerprintProgressDrawable;
+ @NonNull
+ private final Handler mHandler;
+
+ @NonNull
+ private ImageView mFingerprintProgressView;
+ private UdfpsUtils mUdfpsUtils;
+
+ private int mProgressBarRadius;
+
+ private Rect mSensorRect;
+ private UdfpsOverlayParams mOverlayParams;
+ private FingerprintSensorPropertiesInternal mSensorProperties;
+
+ private int mTotalSteps = -1;
+ private int mRemainingSteps = -1;
+ private int mLocationsEnrolled = 0;
+ private int mCenterTouchCount = 0;
+
+ public UdfpsEnrollView(Context context, @Nullable AttributeSet attrs) {
+ super(context, attrs);
+ mFingerprintDrawable = new UdfpsEnrollDrawable(mContext, attrs);
+ mFingerprintProgressDrawable = new UdfpsEnrollProgressBarDrawable(context, attrs);
+ mHandler = new Handler(Looper.getMainLooper());
+ mUdfpsUtils = new UdfpsUtils();
+ }
+
+ @Override
+ protected void onFinishInflate() {
+ ImageView fingerprintView = findViewById(R.id.udfps_enroll_animation_fp_view);
+ fingerprintView.setImageDrawable(mFingerprintDrawable);
+ mFingerprintProgressView = findViewById(R.id.udfps_enroll_animation_fp_progress_view);
+ mFingerprintProgressView.setImageDrawable(mFingerprintProgressDrawable);
+ }
+
+ /**
+ * Receive enroll progress information from FingerprintEnrollEnrollingUdfpsFragment
+ */
+ public void onEnrollmentProgress(int remaining, int totalSteps) {
+ if (mTotalSteps == -1) {
+ mTotalSteps = totalSteps;
+ }
+ mRemainingSteps = remaining;
+ mHandler.post(() -> {
+ mFingerprintProgressDrawable.onEnrollmentProgress(remaining, totalSteps);
+ mFingerprintDrawable.onEnrollmentProgress(remaining, totalSteps);
+ });
+ }
+
+ /**
+ * Receive enroll help information from FingerprintEnrollEnrollingUdfpsFragment
+ */
+ public void onEnrollmentHelp() {
+ mHandler.post(
+ () -> mFingerprintProgressDrawable.onEnrollmentHelp(mRemainingSteps, mTotalSteps));
+ }
+
+ /**
+ * Receive onAcquired from FingerprintEnrollEnrollingUdfpsFragment
+ */
+ public void onAcquired(boolean isAcquiredGood) {
+ final boolean animateIfLastStepGood =
+ isAcquiredGood && (mRemainingSteps <= 2 && mRemainingSteps >= 0);
+ mHandler.post(() -> {
+ onFingerUp();
+ if (animateIfLastStepGood) mFingerprintProgressDrawable.onLastStepAcquired();
+ });
+ }
+
+ /**
+ * Receive onPointerDown from FingerprintEnrollEnrollingUdfpsFragment
+ */
+ public void onPointerDown(int sensorId) {
+ onFingerDown();
+ }
+
+ /**
+ * Receive onPointerUp from FingerprintEnrollEnrollingUdfpsFragment
+ */
+ public void onPointerUp(int sensorId) {
+ onFingerUp();
+ }
+
+ /**
+ * setup SensorProperties
+ */
+ public void setSensorProperties(FingerprintSensorPropertiesInternal properties) {
+ mSensorProperties = properties;
+ ((ViewGroup) getParent()).getViewTreeObserver().addOnDrawListener(
+ new ViewTreeObserver.OnDrawListener() {
+ @Override
+ public void onDraw() {
+ updateOverlayParams();
+ }
+ });
+ }
+
+ private void onSensorRectUpdated() {
+ updateDimensions();
+
+ // Updates sensor rect in relation to the overlay view
+ mSensorRect.set(getPaddingX(), getPaddingY(),
+ (mOverlayParams.getSensorBounds().width() + getPaddingX()),
+ (mOverlayParams.getSensorBounds().height() + getPaddingY()));
+ mFingerprintDrawable.onSensorRectUpdated(new RectF(mSensorRect));
+ }
+
+ private void updateDimensions() {
+ // Original sensorBounds assume portrait mode.
+ final Rect rotatedBounds = new Rect(mOverlayParams.getSensorBounds());
+ int rotation = mOverlayParams.getRotation();
+ if (rotation == Surface.ROTATION_90 || rotation == Surface.ROTATION_270) {
+ RotationUtils.rotateBounds(
+ rotatedBounds,
+ mOverlayParams.getNaturalDisplayWidth(),
+ mOverlayParams.getNaturalDisplayHeight(),
+ rotation
+ );
+ }
+
+ RelativeLayout parent = ((RelativeLayout) getParent());
+ final int[] coords = parent.getLocationOnScreen();
+ final int parentLeft = coords[0];
+ final int parentTop = coords[1];
+ final int parentRight = parentLeft + parent.getWidth();
+ final int parentBottom = parentTop + parent.getHeight();
+
+
+ RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(getWidth(),
+ getHeight());
+ if (rotation == Surface.ROTATION_0 || rotation == Surface.ROTATION_180) {
+ params.addRule(RelativeLayout.ALIGN_PARENT_TOP);
+ params.addRule(RelativeLayout.ALIGN_PARENT_RIGHT);
+ params.rightMargin = parentRight - rotatedBounds.right - getPaddingX();
+ params.topMargin = rotatedBounds.top - parentTop - getPaddingY();
+ } else {
+ if (rotation == Surface.ROTATION_90) {
+ params.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM);
+ params.addRule(RelativeLayout.ALIGN_PARENT_RIGHT);
+ params.rightMargin = parentRight - rotatedBounds.right - getPaddingX();
+ params.bottomMargin = parentBottom - rotatedBounds.bottom - getPaddingY();
+ } else {
+ params.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM);
+ params.addRule(RelativeLayout.ALIGN_PARENT_LEFT);
+ params.bottomMargin = parentBottom - rotatedBounds.bottom - getPaddingY();
+ params.leftMargin = rotatedBounds.left - parentLeft - getPaddingX();
+ }
+ }
+ params.height = rotatedBounds.height() + 2 * getPaddingX();
+ params.width = rotatedBounds.width() + 2 * getPaddingY();
+ setLayoutParams(params);
+ }
+
+ private void onFingerDown() {
+ mFingerprintDrawable.setShouldSkipDraw(true);
+ mFingerprintDrawable.invalidateSelf();
+ }
+
+ private void onFingerUp() {
+ mFingerprintDrawable.setShouldSkipDraw(false);
+ mFingerprintDrawable.invalidateSelf();
+ }
+
+ private int getPaddingX() {
+ return mProgressBarRadius;
+ }
+
+ private int getPaddingY() {
+ return mProgressBarRadius;
+ }
+
+ private void updateOverlayParams() {
+
+ if (mSensorProperties == null) {
+ android.util.Log.e(TAG, "There is no sensor info!");
+ return;
+ }
+
+ DisplayInfo displayInfo = new DisplayInfo();
+ getDisplay().getDisplayInfo(displayInfo);
+ Rect udfpsBounds = mSensorProperties.getLocation().getRect();
+ float scaleFactor = mUdfpsUtils.getScaleFactor(displayInfo);
+ udfpsBounds.scale(scaleFactor);
+
+ final Rect overlayBounds = new Rect(
+ 0, /* left */
+ displayInfo.getNaturalHeight() / 2, /* top */
+ displayInfo.getNaturalWidth(), /* right */
+ displayInfo.getNaturalHeight() /* botom */);
+
+ mOverlayParams = new UdfpsOverlayParams(
+ udfpsBounds,
+ overlayBounds,
+ displayInfo.getNaturalWidth(),
+ displayInfo.getNaturalHeight(),
+ scaleFactor,
+ displayInfo.rotation);
+
+
+ post(() -> {
+ mProgressBarRadius =
+ (int) (mOverlayParams.getScaleFactor() * getContext().getResources().getInteger(
+ R.integer.config_udfpsEnrollProgressBar));
+ mSensorRect = new Rect(mOverlayParams.getSensorBounds());
+
+ onSensorRectUpdated();
+ });
+
+ }
+}
+
diff --git a/src/com/android/settings/datausage/DataSaverSummary.java b/src/com/android/settings/datausage/DataSaverSummary.java
index 9bd862aa219..67644a6c992 100644
--- a/src/com/android/settings/datausage/DataSaverSummary.java
+++ b/src/com/android/settings/datausage/DataSaverSummary.java
@@ -78,11 +78,7 @@ public class DataSaverSummary extends SettingsPreferenceFragment
addPreferencesFromResource(R.xml.data_saver);
mUnrestrictedAccess = findPreference(KEY_UNRESTRICTED_ACCESS);
- mApplicationsState = ApplicationsState.getInstance(
- (Application) getContext().getApplicationContext());
mDataSaverBackend = new DataSaverBackend(getContext());
- mDataUsageBridge = new AppStateDataUsageBridge(mApplicationsState, this, mDataSaverBackend);
- mSession = mApplicationsState.newSession(this, getSettingsLifecycle());
}
@Override
diff --git a/src/com/android/settings/fuelgauge/batteryusage/BatteryDiffData.java b/src/com/android/settings/fuelgauge/batteryusage/BatteryDiffData.java
index 67613ff406c..c5dfb0d357d 100644
--- a/src/com/android/settings/fuelgauge/batteryusage/BatteryDiffData.java
+++ b/src/com/android/settings/fuelgauge/batteryusage/BatteryDiffData.java
@@ -32,6 +32,8 @@ import java.util.Set;
/** Wraps the battery usage diff data for each entry used for battery usage app list. */
public class BatteryDiffData {
+ static final double SMALL_PERCENTAGE_THRESHOLD = 1f;
+
private final List mAppEntries;
private final List mSystemEntries;
@@ -52,8 +54,8 @@ public class BatteryDiffData {
combineBatteryDiffEntry(context, featureProvider, systemAppsSet);
}
- setTotalConsumePower();
- sortEntries();
+ processAndSortEntries(mAppEntries);
+ processAndSortEntries(mSystemEntries);
}
public List getAppDiffEntryList() {
@@ -77,18 +79,6 @@ public class BatteryDiffData {
combineSystemItemsIntoOthers(context, featureProvider, mSystemEntries);
}
- /** Sets total consume power for app and system entries separately. */
- private void setTotalConsumePower() {
- setTotalConsumePowerForAllEntries(mAppEntries);
- setTotalConsumePowerForAllEntries(mSystemEntries);
- }
-
- /** Sorts entries based on consumed percentage. */
- private void sortEntries() {
- Collections.sort(mAppEntries, BatteryDiffEntry.COMPARATOR);
- Collections.sort(mSystemEntries, BatteryDiffEntry.COMPARATOR);
- }
-
private static void purgeBatteryDiffData(
final PowerUsageFeatureProvider featureProvider,
final List entries) {
@@ -177,18 +167,6 @@ public class BatteryDiffData {
}
}
- // Sets total consume power for each entry.
- private static void setTotalConsumePowerForAllEntries(
- final List batteryDiffEntries) {
- double totalConsumePower = 0.0;
- for (BatteryDiffEntry batteryDiffEntry : batteryDiffEntries) {
- totalConsumePower += batteryDiffEntry.mConsumePower;
- }
- for (BatteryDiffEntry batteryDiffEntry : batteryDiffEntries) {
- batteryDiffEntry.setTotalConsumePower(totalConsumePower);
- }
- }
-
@VisibleForTesting
static boolean needsCombineInSystemApp(final BatteryDiffEntry batteryDiffEntry,
final List systemAppsAllowlist, final Set systemAppsSet) {
@@ -207,4 +185,51 @@ public class BatteryDiffData {
return systemAppsSet != null && systemAppsSet.contains(packageName);
}
+
+ /**
+ * Sets total consume power, and adjusts the percentages to ensure the total round percentage
+ * could be 100%, and then sorts entries based on the sorting key.
+ */
+ @VisibleForTesting
+ static void processAndSortEntries(final List batteryDiffEntries) {
+ if (batteryDiffEntries.isEmpty()) {
+ return;
+ }
+
+ // Sets total consume power.
+ double totalConsumePower = 0.0;
+ for (BatteryDiffEntry batteryDiffEntry : batteryDiffEntries) {
+ totalConsumePower += batteryDiffEntry.mConsumePower;
+ }
+ for (BatteryDiffEntry batteryDiffEntry : batteryDiffEntries) {
+ batteryDiffEntry.setTotalConsumePower(totalConsumePower);
+ }
+
+ // Adjusts percentages to show.
+ // The lower bound is treating all the small percentages as 0.
+ // The upper bound is treating all the small percentages as 1.
+ int totalLowerBound = 0;
+ int totalUpperBound = 0;
+ for (BatteryDiffEntry entry : batteryDiffEntries) {
+ if (entry.getPercentage() < SMALL_PERCENTAGE_THRESHOLD) {
+ totalUpperBound += 1;
+ } else {
+ int roundPercentage = Math.round((float) entry.getPercentage());
+ totalLowerBound += roundPercentage;
+ totalUpperBound += roundPercentage;
+ }
+ }
+ if (totalLowerBound > 100 || totalUpperBound < 100) {
+ Collections.sort(batteryDiffEntries, BatteryDiffEntry.COMPARATOR);
+ for (int i = 0; i < totalLowerBound - 100 && i < batteryDiffEntries.size(); i++) {
+ batteryDiffEntries.get(i).setAdjustPercentageOffset(-1);
+ }
+ for (int i = 0; i < 100 - totalUpperBound && i < batteryDiffEntries.size(); i++) {
+ batteryDiffEntries.get(i).setAdjustPercentageOffset(1);
+ }
+ }
+
+ // Sorts entries.
+ Collections.sort(batteryDiffEntries, BatteryDiffEntry.COMPARATOR);
+ }
}
diff --git a/src/com/android/settings/fuelgauge/batteryusage/BatteryDiffEntry.java b/src/com/android/settings/fuelgauge/batteryusage/BatteryDiffEntry.java
index d53afdf5b98..2ed91965b21 100644
--- a/src/com/android/settings/fuelgauge/batteryusage/BatteryDiffEntry.java
+++ b/src/com/android/settings/fuelgauge/batteryusage/BatteryDiffEntry.java
@@ -47,7 +47,7 @@ public class BatteryDiffEntry {
@VisibleForTesting(otherwise = VisibleForTesting.PACKAGE_PRIVATE)
public static final Map sValidForRestriction = new HashMap<>();
- /** A comparator for {@link BatteryDiffEntry} based on consumed percentage. */
+ /** A comparator for {@link BatteryDiffEntry} based on the sorting key. */
public static final Comparator COMPARATOR =
(a, b) -> Double.compare(b.getSortingKey(), a.getSortingKey());
@@ -65,7 +65,8 @@ public class BatteryDiffEntry {
protected Context mContext;
private double mTotalConsumePower;
- private double mPercentOfTotal;
+ private double mPercentage;
+ private int mAdjustPercentageOffset;
private UserManager mUserManager;
private String mDefaultPackageName = null;
@@ -107,8 +108,9 @@ public class BatteryDiffEntry {
/** Sets the total consumed power in a specific time slot. */
public void setTotalConsumePower(double totalConsumePower) {
mTotalConsumePower = totalConsumePower;
- mPercentOfTotal = totalConsumePower == 0
+ mPercentage = totalConsumePower == 0
? 0 : (mConsumePower / mTotalConsumePower) * 100.0;
+ mAdjustPercentageOffset = 0;
}
/** Gets the total consumed power in a specific time slot. */
@@ -117,13 +119,23 @@ public class BatteryDiffEntry {
}
/** Gets the percentage of total consumed power. */
- public double getPercentOfTotal() {
- return mPercentOfTotal;
+ public double getPercentage() {
+ return mPercentage;
+ }
+
+ /** Gets the percentage offset to adjust. */
+ public double getAdjustPercentageOffset() {
+ return mAdjustPercentageOffset;
+ }
+
+ /** Sets the percentage offset to adjust. */
+ public void setAdjustPercentageOffset(int offset) {
+ mAdjustPercentageOffset = offset;
}
/** Gets the key for sorting */
public double getSortingKey() {
- return getPercentOfTotal();
+ return getPercentage() + getAdjustPercentageOffset();
}
/** Clones a new instance. */
@@ -369,7 +381,7 @@ public class BatteryDiffEntry {
.append(String.format("\n\tname=%s restrictable=%b",
mAppLabel, mValidForRestriction))
.append(String.format("\n\tconsume=%.2f%% %f/%f",
- mPercentOfTotal, mConsumePower, mTotalConsumePower))
+ mPercentage, mConsumePower, mTotalConsumePower))
.append(String.format("\n\tconsume power= foreground:%f foregroundService:%f",
mForegroundUsageConsumePower, mForegroundServiceUsageConsumePower))
.append(String.format("\n\tconsume power= background:%f cached:%f",
diff --git a/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageBreakdownController.java b/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageBreakdownController.java
index 485c806850a..0be6c988ec7 100644
--- a/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageBreakdownController.java
+++ b/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageBreakdownController.java
@@ -35,6 +35,7 @@ import androidx.preference.PreferenceScreen;
import com.android.internal.annotations.VisibleForTesting;
import com.android.settings.R;
import com.android.settings.SettingsActivity;
+import com.android.settings.Utils;
import com.android.settings.core.BasePreferenceController;
import com.android.settings.core.InstrumentedPreferenceFragment;
import com.android.settings.fuelgauge.AdvancedPowerUsageDetail;
@@ -86,6 +87,8 @@ public class BatteryUsageBreakdownController extends BasePreferenceController
FooterPreference mFooterPreference;
@VisibleForTesting
BatteryDiffData mBatteryDiffData;
+ @VisibleForTesting
+ String mPercentLessThanThresholdText;
public BatteryUsageBreakdownController(
Context context, Lifecycle lifecycle, SettingsActivity activity,
@@ -147,11 +150,11 @@ public class BatteryUsageBreakdownController extends BasePreferenceController
: SettingsEnums.ACTION_BATTERY_USAGE_SYSTEM_ITEM,
/* pageId */ SettingsEnums.OPEN_BATTERY_USAGE,
TextUtils.isEmpty(packageName) ? PACKAGE_NAME_NONE : packageName,
- (int) Math.round(diffEntry.getPercentOfTotal()));
+ (int) Math.round(diffEntry.getPercentage()));
Log.d(TAG, String.format("handleClick() label=%s key=%s package=%s",
diffEntry.getAppLabel(), histEntry.getKey(), histEntry.mPackageName));
AdvancedPowerUsageDetail.startBatteryDetailPage(
- mActivity, mFragment, diffEntry, powerPref.getPercent(), mSlotTimestamp);
+ mActivity, mFragment, diffEntry, powerPref.getPercentage(), mSlotTimestamp);
return true;
}
@@ -163,6 +166,9 @@ public class BatteryUsageBreakdownController extends BasePreferenceController
mSpinnerPreference = screen.findPreference(SPINNER_PREFERENCE_KEY);
mAppListPreferenceGroup = screen.findPreference(APP_LIST_PREFERENCE_KEY);
mFooterPreference = screen.findPreference(FOOTER_PREFERENCE_KEY);
+ mPercentLessThanThresholdText = mPrefContext.getString(
+ R.string.battery_usage_less_than_percent,
+ Utils.formatPercentage(BatteryDiffData.SMALL_PERCENTAGE_THRESHOLD, false));
mAppListPreferenceGroup.setOrderingAsAdded(false);
mSpinnerPreference.initializeSpinner(
@@ -279,11 +285,11 @@ public class BatteryUsageBreakdownController extends BasePreferenceController
pref.setIcon(appIcon);
pref.setTitle(appLabel);
pref.setOrder(prefIndex);
- pref.setPercent(entry.getPercentOfTotal());
pref.setSingleLineTitle(true);
// Sets the BatteryDiffEntry to preference for launching detailed page.
pref.setBatteryDiffEntry(entry);
pref.setSelectable(entry.validForRestriction());
+ setPreferencePercentage(pref, entry);
setPreferenceSummary(pref, entry);
if (!isAdded) {
mAppListPreferenceGroup.addPreference(pref);
@@ -307,6 +313,17 @@ public class BatteryUsageBreakdownController extends BasePreferenceController
mAppListPreferenceGroup.removeAll();
}
+ @VisibleForTesting
+ void setPreferencePercentage(
+ PowerGaugePreference preference, BatteryDiffEntry entry) {
+ preference.setPercentage(
+ entry.getPercentage() < BatteryDiffData.SMALL_PERCENTAGE_THRESHOLD
+ ? mPercentLessThanThresholdText
+ : Utils.formatPercentage(
+ entry.getPercentage() + entry.getAdjustPercentageOffset(),
+ /* round= */ true));
+ }
+
@VisibleForTesting
void setPreferenceSummary(
PowerGaugePreference preference, BatteryDiffEntry entry) {
diff --git a/src/com/android/settings/fuelgauge/batteryusage/PowerGaugePreference.java b/src/com/android/settings/fuelgauge/batteryusage/PowerGaugePreference.java
index 0aee8a57671..56ada8eca59 100644
--- a/src/com/android/settings/fuelgauge/batteryusage/PowerGaugePreference.java
+++ b/src/com/android/settings/fuelgauge/batteryusage/PowerGaugePreference.java
@@ -38,7 +38,6 @@ import com.android.settingslib.widget.AppPreference;
*/
public class PowerGaugePreference extends AppPreference {
- private static final double PERCENTAGE_TO_SHOW_THRESHOLD = 1f;
// Please see go/battery-usage-app-list-alpha
private static final float SELECTABLE_ALPHA = 1f;
private static final float UNSELECTABLE_ALPHA_LIGHT_MODE = 0.65f;
@@ -81,29 +80,17 @@ public class PowerGaugePreference extends AppPreference {
notifyChanged();
}
- /** Sets the percent of total. */
- public void setPercent(double percentOfTotal) {
- mProgress = percentOfTotal < PERCENTAGE_TO_SHOW_THRESHOLD
- ? "-" : Utils.formatPercentage(percentOfTotal, true);
+ /** Sets the percentage to show. */
+ public void setPercentage(CharSequence percentage) {
+ mProgress = percentage;
notifyChanged();
}
- /** Gets the percent of total. */
- public String getPercent() {
+ /** Gets the percentage to show. */
+ public String getPercentage() {
return mProgress.toString();
}
- /** Sets the subtitle. */
- public void setSubtitle(CharSequence subtitle) {
- mProgress = subtitle;
- notifyChanged();
- }
-
- /** Gets the subtitle. */
- public CharSequence getSubtitle() {
- return mProgress;
- }
-
/** Sets whether to show anomaly icon */
public void shouldShowAnomalyIcon(boolean showAnomalyIcon) {
mShowAnomalyIcon = showAnomalyIcon;
diff --git a/src/com/android/settings/regionalpreferences/CalendarTypeController.java b/src/com/android/settings/regionalpreferences/CalendarTypeController.java
index 7905620ce7a..7d07cbdd4f4 100644
--- a/src/com/android/settings/regionalpreferences/CalendarTypeController.java
+++ b/src/com/android/settings/regionalpreferences/CalendarTypeController.java
@@ -17,6 +17,7 @@
package com.android.settings.regionalpreferences;
import android.content.Context;
+import android.os.SystemProperties;
import android.provider.Settings;
import com.android.settings.core.BasePreferenceController;
@@ -27,6 +28,8 @@ import java.util.Locale;
* A controller for the entry of Calendar types' page
*/
public class CalendarTypeController extends BasePreferenceController {
+ private static final String CALENDAR_FEATURE_PROPERTY =
+ "i18n-feature-locale-preference-calendar";
private static final String TAG = CalendarTypeController.class.getSimpleName();
public CalendarTypeController(Context context, String preferenceKey) {
super(context, preferenceKey);
@@ -45,7 +48,8 @@ public class CalendarTypeController extends BasePreferenceController {
*/
@Override
public int getAvailabilityStatus() {
- return AVAILABLE;
+ return SystemProperties.getBoolean(CALENDAR_FEATURE_PROPERTY, false)
+ ? AVAILABLE : CONDITIONALLY_UNAVAILABLE;
}
@Override
diff --git a/src/com/android/settings/spa/app/appinfo/AppBatteryPreference.kt b/src/com/android/settings/spa/app/appinfo/AppBatteryPreference.kt
index edb2a1eaa0f..c4a89179b08 100644
--- a/src/com/android/settings/spa/app/appinfo/AppBatteryPreference.kt
+++ b/src/com/android/settings/spa/app/appinfo/AppBatteryPreference.kt
@@ -108,7 +108,7 @@ private class AppBatteryPresenter(private val context: Context, private val app:
private fun BatteryDiffEntry?.getSummary(): String =
this?.takeIf { mConsumePower > 0 }?.let {
context.getString(
- R.string.battery_summary, Utils.formatPercentage(percentOfTotal, true)
+ R.string.battery_summary, Utils.formatPercentage(percentage, true)
)
} ?: context.getString(R.string.no_battery_summary)
@@ -127,7 +127,7 @@ private class AppBatteryPresenter(private val context: Context, private val app:
context,
AppInfoSettingsProvider.METRICS_CATEGORY,
this,
- Utils.formatPercentage(percentOfTotal, true),
+ Utils.formatPercentage(percentage, true),
null,
false,
)
diff --git a/tests/robotests/src/com/android/settings/accessibility/ToggleScreenMagnificationPreferenceFragmentTest.java b/tests/robotests/src/com/android/settings/accessibility/ToggleScreenMagnificationPreferenceFragmentTest.java
index 8697cb5aa91..9916dc9d7f4 100644
--- a/tests/robotests/src/com/android/settings/accessibility/ToggleScreenMagnificationPreferenceFragmentTest.java
+++ b/tests/robotests/src/com/android/settings/accessibility/ToggleScreenMagnificationPreferenceFragmentTest.java
@@ -23,6 +23,7 @@ import static com.android.settings.accessibility.ToggleFeaturePreferenceFragment
import static com.google.common.truth.Truth.assertThat;
+import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
@@ -405,6 +406,17 @@ public class ToggleScreenMagnificationPreferenceFragmentTest {
assertThat(mFragment.getHelpResource()).isEqualTo(R.string.help_url_magnification);
}
+ @Test
+ public void onProcessArguments_defaultArgumentUnavailable_shouldSetDefaultArguments() {
+ Bundle arguments = new Bundle();
+
+ mFragment.onProcessArguments(arguments);
+
+ assertTrue(arguments.containsKey(AccessibilitySettings.EXTRA_PREFERENCE_KEY));
+ assertTrue(arguments.containsKey(AccessibilitySettings.EXTRA_INTRO));
+ assertTrue(arguments.containsKey(AccessibilitySettings.EXTRA_HTML_DESCRIPTION));
+ }
+
private void putStringIntoSettings(String key, String componentName) {
Settings.Secure.putString(mContext.getContentResolver(), key, componentName);
}
diff --git a/tests/robotests/src/com/android/settings/applications/appinfo/AppBatteryPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/applications/appinfo/AppBatteryPreferenceControllerTest.java
index f4cb3f3948f..fc303c49470 100644
--- a/tests/robotests/src/com/android/settings/applications/appinfo/AppBatteryPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/applications/appinfo/AppBatteryPreferenceControllerTest.java
@@ -145,7 +145,7 @@ public class AppBatteryPreferenceControllerTest {
mController.displayPreference(mScreen);
mBatteryDiffEntry.mConsumePower = 1;
mController.mBatteryDiffEntry = mBatteryDiffEntry;
- when(mBatteryDiffEntry.getPercentOfTotal()).thenReturn(60.0);
+ when(mBatteryDiffEntry.getPercentage()).thenReturn(60.0);
mController.updateBatteryWithDiffEntry();
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryDiffDataTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryDiffDataTest.java
index 48a6e72a2a1..0985fe7d54b 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryDiffDataTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryDiffDataTest.java
@@ -37,6 +37,7 @@ import org.mockito.MockitoAnnotations;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment;
+import java.util.ArrayList;
import java.util.List;
import java.util.Set;
@@ -58,26 +59,10 @@ public class BatteryDiffDataTest {
@Test
public void needsCombineInSystemApp_isHidden_returnTrue() {
- final int currentUserId = mContext.getUserId();
- final BatteryHistEntry hiddenHistEntry = createBatteryHistEntry(
- ConvertUtils.FAKE_PACKAGE_NAME, "fake_label", /*consumePower=*/ 0,
- /*foregroundUsageConsumePower=*/ 0, /*foregroundServiceUsageConsumePower=*/ 0,
- /*backgroundUsageConsumePower=*/ 0, /*cachedUsageConsumePower=*/ 0,
- /*uid=*/ 0L, currentUserId, ConvertUtils.CONSUMER_TYPE_UID_BATTERY,
- /*foregroundUsageTimeInMs=*/ 0L, /*backgroundUsageTimeInMs=*/ 0L, true);
- final BatteryDiffEntry hiddenDiffEntry = new BatteryDiffEntry(
- mContext,
- /*foregroundUsageTimeInMs=*/ 0,
- /*backgroundUsageTimeInMs=*/ 0,
- /*screenOnTimeInMs=*/ 0,
- /*consumePower=*/ 0,
- /*foregroundUsageConsumePower=*/ 0,
- /*foregroundServiceUsageConsumePower=*/ 0,
- /*backgroundUsageConsumePower=*/ 0,
- /*cachedUsageConsumePower=*/ 0,
- hiddenHistEntry);
+ final BatteryDiffEntry hiddenDiffEntry =
+ createBatteryDiffEntry(mContext, /*consumePower=*/ 0, /*isHidden=*/ true);
- boolean needsCombineInSystemApp = BatteryDiffData.needsCombineInSystemApp(
+ final boolean needsCombineInSystemApp = BatteryDiffData.needsCombineInSystemApp(
hiddenDiffEntry, List.of(), Set.of());
assertThat(needsCombineInSystemApp).isTrue();
@@ -85,29 +70,13 @@ public class BatteryDiffDataTest {
@Test
public void needsCombineInSystemApp_isSystemApp_returnTrue() {
- final int currentUserId = mContext.getUserId();
- final BatteryHistEntry batteryHistEntry = createBatteryHistEntry(
- ConvertUtils.FAKE_PACKAGE_NAME, "fake_label", /*consumePower=*/ 0,
- /*foregroundUsageConsumePower=*/ 0, /*foregroundServiceUsageConsumePower=*/ 0,
- /*backgroundUsageConsumePower=*/ 0, /*cachedUsageConsumePower=*/ 0,
- /*uid=*/ 0L, currentUserId, ConvertUtils.CONSUMER_TYPE_UID_BATTERY,
- /*foregroundUsageTimeInMs=*/ 0L, /*backgroundUsageTimeInMs=*/ 0L, false);
- final BatteryDiffEntry batteryDiffEntry = new BatteryDiffEntry(
- mContext,
- /*foregroundUsageTimeInMs=*/ 0,
- /*backgroundUsageTimeInMs=*/ 0,
- /*screenOnTimeInMs=*/ 0,
- /*consumePower=*/ 0,
- /*foregroundUsageConsumePower=*/ 0,
- /*foregroundServiceUsageConsumePower=*/ 0,
- /*backgroundUsageConsumePower=*/ 0,
- /*cachedUsageConsumePower=*/ 0,
- batteryHistEntry);
+ final BatteryDiffEntry batteryDiffEntry =
+ createBatteryDiffEntry(mContext, /*consumePower=*/ 0, /*isHidden=*/ false);
doReturn(mAppEntry).when(mApplicationsState).getEntry(anyString(), anyInt());
mAppEntry.info = mApplicationInfo;
mApplicationInfo.flags = ApplicationInfo.FLAG_SYSTEM;
- boolean needsCombineInSystemApp = BatteryDiffData.needsCombineInSystemApp(
+ final boolean needsCombineInSystemApp = BatteryDiffData.needsCombineInSystemApp(
batteryDiffEntry, List.of(), Set.of(ConvertUtils.FAKE_PACKAGE_NAME));
assertThat(needsCombineInSystemApp).isTrue();
@@ -115,32 +84,78 @@ public class BatteryDiffDataTest {
@Test
public void needsCombineInSystemApp_notSystemApp_returnFalse() {
- final int currentUserId = mContext.getUserId();
+ final BatteryDiffEntry batteryDiffEntry =
+ createBatteryDiffEntry(mContext, /*consumePower=*/ 0, /*isHidden=*/ false);
+ doReturn(mAppEntry).when(mApplicationsState).getEntry(anyString(), anyInt());
+ mAppEntry.info = mApplicationInfo;
+ mApplicationInfo.flags = 0;
+
+ final boolean needsCombineInSystemApp = BatteryDiffData.needsCombineInSystemApp(
+ batteryDiffEntry, List.of(), Set.of());
+
+ assertThat(needsCombineInSystemApp).isFalse();
+ }
+
+ @Test
+ public void processPercentsAndSort_sumLessThan100_adjustTo100() {
+ List batteryDiffEntries = new ArrayList<>();
+ batteryDiffEntries.add(
+ createBatteryDiffEntry(mContext, /*consumePower=*/ 33.33, /*isHidden=*/ false));
+ batteryDiffEntries.add(
+ createBatteryDiffEntry(mContext, /*consumePower=*/ 33.34, /*isHidden=*/ false));
+ batteryDiffEntries.add(
+ createBatteryDiffEntry(mContext, /*consumePower=*/ 33.33, /*isHidden=*/ false));
+
+ BatteryDiffData.processAndSortEntries(batteryDiffEntries);
+
+ assertThat(batteryDiffEntries.get(0).getPercentage()).isEqualTo(33.34);
+ assertThat(batteryDiffEntries.get(0).getAdjustPercentageOffset()).isEqualTo(1);
+ assertThat(batteryDiffEntries.get(1).getPercentage()).isEqualTo(33.33);
+ assertThat(batteryDiffEntries.get(1).getAdjustPercentageOffset()).isEqualTo(0);
+ assertThat(batteryDiffEntries.get(2).getPercentage()).isEqualTo(33.33);
+ assertThat(batteryDiffEntries.get(2).getAdjustPercentageOffset()).isEqualTo(0);
+ }
+
+ @Test
+ public void processPercentsAndSort_sumGreaterThan100_adjustTo100() {
+ List batteryDiffEntries = new ArrayList<>();
+ batteryDiffEntries.add(
+ createBatteryDiffEntry(mContext, /*consumePower=*/ 48.5, /*isHidden=*/ false));
+ batteryDiffEntries.add(
+ createBatteryDiffEntry(mContext, /*consumePower=*/ 3, /*isHidden=*/ false));
+ batteryDiffEntries.add(
+ createBatteryDiffEntry(mContext, /*consumePower=*/ 48.5, /*isHidden=*/ false));
+
+ BatteryDiffData.processAndSortEntries(batteryDiffEntries);
+
+ assertThat(batteryDiffEntries.get(0).getPercentage()).isEqualTo(48.5);
+ assertThat(batteryDiffEntries.get(0).getAdjustPercentageOffset()).isEqualTo(0);
+ assertThat(batteryDiffEntries.get(1).getPercentage()).isEqualTo(48.5);
+ assertThat(batteryDiffEntries.get(1).getAdjustPercentageOffset()).isEqualTo(-1);
+ assertThat(batteryDiffEntries.get(2).getPercentage()).isEqualTo(3);
+ assertThat(batteryDiffEntries.get(2).getAdjustPercentageOffset()).isEqualTo(0);
+ }
+
+ private static BatteryDiffEntry createBatteryDiffEntry(
+ Context context, double consumePower, boolean isHidden) {
+ final int currentUserId = context.getUserId();
final BatteryHistEntry batteryHistEntry = createBatteryHistEntry(
- ConvertUtils.FAKE_PACKAGE_NAME, "fake_label", /*consumePower=*/ 0,
+ ConvertUtils.FAKE_PACKAGE_NAME, "fake_label", consumePower,
/*foregroundUsageConsumePower=*/ 0, /*foregroundServiceUsageConsumePower=*/ 0,
/*backgroundUsageConsumePower=*/ 0, /*cachedUsageConsumePower=*/ 0,
/*uid=*/ 0L, currentUserId, ConvertUtils.CONSUMER_TYPE_UID_BATTERY,
- /*foregroundUsageTimeInMs=*/ 0L, /*backgroundUsageTimeInMs=*/ 0L, false);
- final BatteryDiffEntry batteryDiffEntry = new BatteryDiffEntry(
- mContext,
+ /*foregroundUsageTimeInMs=*/ 0L, /*backgroundUsageTimeInMs=*/ 0L, isHidden);
+ return new BatteryDiffEntry(
+ context,
/*foregroundUsageTimeInMs=*/ 0,
/*backgroundUsageTimeInMs=*/ 0,
/*screenOnTimeInMs=*/ 0,
- /*consumePower=*/ 0,
+ /*consumePower=*/ consumePower,
/*foregroundUsageConsumePower=*/ 0,
/*foregroundServiceUsageConsumePower=*/ 0,
/*backgroundUsageConsumePower=*/ 0,
/*cachedUsageConsumePower=*/ 0,
batteryHistEntry);
- doReturn(mAppEntry).when(mApplicationsState).getEntry(anyString(), anyInt());
- mAppEntry.info = mApplicationInfo;
- mApplicationInfo.flags = 0;
-
- boolean needsCombineInSystemApp = BatteryDiffData.needsCombineInSystemApp(
- batteryDiffEntry, List.of(), Set.of());
-
- assertThat(needsCombineInSystemApp).isFalse();
}
private static BatteryHistEntry createBatteryHistEntry(
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryDiffEntryTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryDiffEntryTest.java
index 1085a6b6d73..655f1e41869 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryDiffEntryTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryDiffEntryTest.java
@@ -106,7 +106,7 @@ public final class BatteryDiffEntryTest {
/*batteryHistEntry=*/ null);
entry.setTotalConsumePower(100.0);
- assertThat(entry.getPercentOfTotal()).isEqualTo(22.0);
+ assertThat(entry.getPercentage()).isEqualTo(22.0);
}
@Test
@@ -125,21 +125,28 @@ public final class BatteryDiffEntryTest {
/*batteryHistEntry=*/ null);
entry.setTotalConsumePower(0);
- assertThat(entry.getPercentOfTotal()).isEqualTo(0);
+ assertThat(entry.getPercentage()).isEqualTo(0);
}
@Test
public void testComparator_sortCollectionsInDescOrder() {
final List entryList = new ArrayList<>();
// Generates fake testing data.
+ BatteryDiffEntry systemAppsBatteryDiffEntry =
+ new BatteryDiffEntry.SystemAppsBatteryDiffEntry(mContext);
+ systemAppsBatteryDiffEntry.mConsumePower = 16;
+ systemAppsBatteryDiffEntry.setTotalConsumePower(100);
+ entryList.add(systemAppsBatteryDiffEntry);
entryList.add(createBatteryDiffEntry(30, mBatteryHistEntry));
entryList.add(createBatteryDiffEntry(20, mBatteryHistEntry));
entryList.add(createBatteryDiffEntry(10, mBatteryHistEntry));
+
Collections.sort(entryList, BatteryDiffEntry.COMPARATOR);
- assertThat(entryList.get(0).getPercentOfTotal()).isEqualTo(30);
- assertThat(entryList.get(1).getPercentOfTotal()).isEqualTo(20);
- assertThat(entryList.get(2).getPercentOfTotal()).isEqualTo(10);
+ assertThat(entryList.get(0).getPercentage()).isEqualTo(30);
+ assertThat(entryList.get(1).getPercentage()).isEqualTo(20);
+ assertThat(entryList.get(2).getPercentage()).isEqualTo(10);
+ assertThat(entryList.get(3).getPercentage()).isEqualTo(16);
}
@Test
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageBreakdownControllerTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageBreakdownControllerTest.java
index f312936db7b..395f655d739 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageBreakdownControllerTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageBreakdownControllerTest.java
@@ -234,6 +234,40 @@ public final class BatteryUsageBreakdownControllerTest {
/* percentage of total */ 100);
}
+ @Test
+ public void setPreferencePercent_lessThanThreshold_expectedFormat() {
+ final PowerGaugePreference pref = new PowerGaugePreference(mContext);
+ final BatteryDiffEntry batteryDiffEntry = createBatteryDiffEntry(
+ /*isSystem=*/ true,
+ /*screenOnTimeInMs=*/ 0,
+ /*foregroundUsageTimeInMs=*/ 0,
+ /*backgroundUsageTimeInMs=*/ 0);
+ batteryDiffEntry.mConsumePower = 0.8;
+ batteryDiffEntry.setTotalConsumePower(100);
+ mBatteryUsageBreakdownController.mPercentLessThanThresholdText = "< 1%";
+
+ mBatteryUsageBreakdownController.setPreferencePercentage(pref, batteryDiffEntry);
+
+ assertThat(pref.getPercentage()).isEqualTo("< 1%");
+ }
+
+ @Test
+ public void setPreferencePercent_greaterThanThreshold_expectedFormat() {
+ final PowerGaugePreference pref = new PowerGaugePreference(mContext);
+ final BatteryDiffEntry batteryDiffEntry = createBatteryDiffEntry(
+ /*isSystem=*/ true,
+ /*screenOnTimeInMs=*/ 0,
+ /*foregroundUsageTimeInMs=*/ 0,
+ /*backgroundUsageTimeInMs=*/ 0);
+ batteryDiffEntry.mConsumePower = 16;
+ batteryDiffEntry.setTotalConsumePower(100);
+ mBatteryUsageBreakdownController.mPercentLessThanThresholdText = "< 1%";
+
+ mBatteryUsageBreakdownController.setPreferencePercentage(pref, batteryDiffEntry);
+
+ assertThat(pref.getPercentage()).isEqualTo("16%");
+ }
+
@Test
public void setPreferenceSummary_systemEntryTotalUsageTimeIsZero_emptySummary() {
final PowerGaugePreference pref = new PowerGaugePreference(mContext);
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/DataProcessorTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/DataProcessorTest.java
index 0ecf50ead18..1d3f72b8bfd 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/DataProcessorTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/DataProcessorTest.java
@@ -1993,7 +1993,7 @@ public final class DataProcessorTest {
assertThat(entry.mBatteryHistEntry.mUserId).isEqualTo(userId);
assertThat(entry.mBatteryHistEntry.mUid).isEqualTo(uid);
assertThat(entry.mBatteryHistEntry.mConsumerType).isEqualTo(consumerType);
- assertThat(entry.getPercentOfTotal()).isEqualTo(consumePercentage);
+ assertThat(entry.getPercentage()).isEqualTo(consumePercentage);
assertThat(entry.mForegroundUsageConsumePower).isEqualTo(foregroundUsageConsumePower);
assertThat(entry.mForegroundServiceUsageConsumePower)
.isEqualTo(foregroundServiceUsageConsumePower);
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/DatabaseUtilsTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/DatabaseUtilsTest.java
index 722f869bd7f..154497e8653 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/DatabaseUtilsTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/DatabaseUtilsTest.java
@@ -45,7 +45,6 @@ import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment;
-import org.robolectric.Shadows;
import java.util.ArrayList;
import java.util.List;
@@ -56,8 +55,8 @@ public final class DatabaseUtilsTest {
private Context mContext;
- @Mock
- private PackageManager mPackageManager;
+ @Mock private PackageManager mPackageManager;
+ @Mock private UserManager mUserManager;
@Mock private ContentResolver mMockContentResolver;
@Mock private ContentResolver mMockContentResolver2;
@Mock private BatteryUsageStats mBatteryUsageStats;
@@ -383,7 +382,11 @@ public final class DatabaseUtilsTest {
doReturn("com.fake.package").when(mContext).getPackageName();
doReturn(mMockContext).when(mContext).createPackageContextAsUser(
"com.fake.package", /*flags=*/ 0, UserHandle.OWNER);
- BatteryTestUtils.setWorkProfile(mContext);
+ doReturn(UserHandle.CURRENT).when(mContext).getUser();
+ doReturn(mUserManager).when(mContext).getSystemService(UserManager.class);
+ doReturn(true).when(mUserManager).isManagedProfile();
+ doReturn(UserHandle.SYSTEM).when(mUserManager).getProfileParent(UserHandle.CURRENT);
+
DatabaseUtils.sFakeBatteryStateSupplier = () -> getMatrixCursor();
final Map> batteryHistMap =
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/PowerGaugePreferenceTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/PowerGaugePreferenceTest.java
index e9573f1e436..bee30454060 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/PowerGaugePreferenceTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/PowerGaugePreferenceTest.java
@@ -65,15 +65,6 @@ public class PowerGaugePreferenceTest {
assertThat(mPowerGaugePreference.getLayoutResource()).isEqualTo(R.layout.preference_app);
}
- @Test
- public void testOnBindViewHolder_bindSubtitle() {
- mPowerGaugePreference.setSubtitle(SUBTITLE);
- mPowerGaugePreference.onBindViewHolder(mPreferenceViewHolder);
-
- TextView widgetSummary = (TextView) mPreferenceViewHolder.findViewById(R.id.widget_summary);
- assertThat(widgetSummary.getText()).isEqualTo(SUBTITLE);
- }
-
@Test
public void testOnBindViewHolder_showAnomaly_bindAnomalyIcon() {
mPowerGaugePreference.shouldShowAnomalyIcon(true);
@@ -104,18 +95,4 @@ public class PowerGaugePreferenceTest {
assertThat(mPreferenceViewHolder.findViewById(android.R.id.title).getContentDescription())
.isEqualTo(CONTENT_DESCRIPTION);
}
-
- @Test
- public void setPercent_greaterThanThreshold_showNumber() {
- mPowerGaugePreference.setPercent(99.5);
-
- assertThat(mPowerGaugePreference.getPercent()).isEqualTo("100%");
- }
-
- @Test
- public void setPercent_lessThanThreshold_showBar() {
- mPowerGaugePreference.setPercent(0.95);
-
- assertThat(mPowerGaugePreference.getPercent()).isEqualTo("-");
- }
}
diff --git a/tests/spa_unit/src/com/android/settings/spa/app/appinfo/AppBatteryPreferenceTest.kt b/tests/spa_unit/src/com/android/settings/spa/app/appinfo/AppBatteryPreferenceTest.kt
index 276b711a104..8dd494596f0 100644
--- a/tests/spa_unit/src/com/android/settings/spa/app/appinfo/AppBatteryPreferenceTest.kt
+++ b/tests/spa_unit/src/com/android/settings/spa/app/appinfo/AppBatteryPreferenceTest.kt
@@ -37,8 +37,6 @@ import com.android.settings.fuelgauge.AdvancedPowerUsageDetail
import com.android.settings.fuelgauge.batteryusage.BatteryChartPreferenceController
import com.android.settings.fuelgauge.batteryusage.BatteryDiffEntry
import com.android.settings.testutils.mockAsUser
-import com.android.settingslib.spaprivileged.framework.common.asUser
-import com.android.settingslib.spaprivileged.model.app.userHandle
import com.android.settingslib.spaprivileged.model.app.userId
import org.junit.After
import org.junit.Before
@@ -142,7 +140,7 @@ class AppBatteryPreferenceTest {
val batteryDiffEntry = mock(BatteryDiffEntry::class.java).apply {
mConsumePower = 12.3
}
- whenever(batteryDiffEntry.percentOfTotal).thenReturn(45.6)
+ whenever(batteryDiffEntry.percentage).thenReturn(45.6)
mockBatteryDiffEntry(batteryDiffEntry)
setContent()
@@ -153,7 +151,7 @@ class AppBatteryPreferenceTest {
@Test
fun whenClick_openDetailsPage() {
val batteryDiffEntry = mock(BatteryDiffEntry::class.java)
- whenever(batteryDiffEntry.percentOfTotal).thenReturn(10.0)
+ whenever(batteryDiffEntry.percentage).thenReturn(10.0)
mockBatteryDiffEntry(batteryDiffEntry)
setContent()