Merge "Adjust UDFPS prompt for 3-button nav and landscape" into sc-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
81219cb73b
@@ -39,37 +39,34 @@
|
||||
|
||||
<Space android:id="@+id/space_above_icon"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="48dp"
|
||||
android:visibility="visible" />
|
||||
android:layout_height="48dp" />
|
||||
|
||||
<!-- Use a frame layout since certain biometrics (such as UDFPS) require the icon to be centered
|
||||
within a certain area on the display. This makes it easy to 1) guarantee max size, and
|
||||
2) center the icon within the reserved area. -->
|
||||
<FrameLayout android:id="@+id/biometric_icon_frame"
|
||||
<FrameLayout
|
||||
android:id="@+id/biometric_icon_frame"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_gravity="center_horizontal">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/biometric_icon"
|
||||
android:layout_width="@dimen/biometric_dialog_biometric_icon_size"
|
||||
android:layout_height="@dimen/biometric_dialog_biometric_icon_size"
|
||||
android:layout_gravity="center"
|
||||
android:scaleType="fitXY" />
|
||||
|
||||
</FrameLayout>
|
||||
|
||||
<!-- For sensors such as UDFPS, this view is used during custom measurement/layoutto add extra
|
||||
<!-- For sensors such as UDFPS, this view is used during custom measurement/layout to add extra
|
||||
padding so that the biometric icon is always in the right physical position. -->
|
||||
<Space android:id="@+id/space_below_icon"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
android:visibility="gone" />
|
||||
android:layout_height="12dp" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/indicator"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingHorizontal="24dp"
|
||||
android:paddingVertical="12dp"
|
||||
android:textSize="12sp"
|
||||
android:gravity="center_horizontal"
|
||||
android:accessibilityLiveRegion="polite"
|
||||
@@ -84,6 +81,7 @@
|
||||
style="?android:attr/buttonBarStyle"
|
||||
android:orientation="horizontal"
|
||||
android:paddingTop="16dp">
|
||||
|
||||
<Space android:id="@+id/leftSpacer"
|
||||
android:layout_width="8dp"
|
||||
android:layout_height="match_parent"
|
||||
|
||||
@@ -244,6 +244,8 @@
|
||||
<item name="android:paddingTop">12dp</item>
|
||||
<item name="android:paddingHorizontal">24dp</item>
|
||||
<item name="android:textSize">24sp</item>
|
||||
<item name="android:singleLine">true</item>
|
||||
<item name="android:ellipsize">marquee</item>
|
||||
</style>
|
||||
|
||||
<style name="TextAppearance.AuthCredential.Subtitle">
|
||||
@@ -251,6 +253,8 @@
|
||||
<item name="android:paddingTop">8dp</item>
|
||||
<item name="android:paddingHorizontal">24dp</item>
|
||||
<item name="android:textSize">16sp</item>
|
||||
<item name="android:singleLine">true</item>
|
||||
<item name="android:ellipsize">marquee</item>
|
||||
</style>
|
||||
|
||||
<style name="TextAppearance.AuthCredential.Description">
|
||||
@@ -258,6 +262,8 @@
|
||||
<item name="android:paddingTop">8dp</item>
|
||||
<item name="android:paddingHorizontal">24dp</item>
|
||||
<item name="android:textSize">14sp</item>
|
||||
<item name="android:singleLine">true</item>
|
||||
<item name="android:ellipsize">marquee</item>
|
||||
</style>
|
||||
|
||||
<style name="TextAppearance.AuthCredential.Error">
|
||||
|
||||
@@ -16,17 +16,22 @@
|
||||
|
||||
package com.android.systemui.biometrics;
|
||||
|
||||
import android.annotation.IdRes;
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.content.Context;
|
||||
import android.graphics.Insets;
|
||||
import android.graphics.Rect;
|
||||
import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.Log;
|
||||
import android.view.Surface;
|
||||
import android.view.View;
|
||||
import android.view.WindowInsets;
|
||||
import android.view.WindowManager;
|
||||
import android.widget.FrameLayout;
|
||||
|
||||
import com.android.internal.annotations.VisibleForTesting;
|
||||
import com.android.systemui.R;
|
||||
|
||||
/**
|
||||
@@ -51,53 +56,38 @@ public class AuthBiometricUdfpsView extends AuthBiometricFingerprintView {
|
||||
mSensorProps = prop;
|
||||
}
|
||||
|
||||
/**
|
||||
* For devices where the sensor is too high up, calculates the amount of padding necessary to
|
||||
* move/center the biometric icon within the sensor's physical location.
|
||||
*/
|
||||
static int calculateBottomSpacerHeight(int displayHeightPx, int navbarHeightPx,
|
||||
int dialogBottomMarginPx, @NonNull View buttonBar, @NonNull View textIndicator,
|
||||
@NonNull FingerprintSensorPropertiesInternal sensorProperties) {
|
||||
final int sensorDistanceFromBottom = displayHeightPx - sensorProperties.sensorLocationY
|
||||
- sensorProperties.sensorRadius;
|
||||
|
||||
final int spacerHeight = sensorDistanceFromBottom
|
||||
- textIndicator.getMeasuredHeight()
|
||||
- buttonBar.getMeasuredHeight()
|
||||
- dialogBottomMarginPx
|
||||
- navbarHeightPx;
|
||||
|
||||
Log.d(TAG, "Display height: " + displayHeightPx
|
||||
+ ", Distance from bottom: " + sensorDistanceFromBottom
|
||||
+ ", Bottom margin: " + dialogBottomMarginPx
|
||||
+ ", Navbar height: " + navbarHeightPx
|
||||
+ ", Spacer height: " + spacerHeight);
|
||||
|
||||
return spacerHeight;
|
||||
@Override
|
||||
@NonNull
|
||||
AuthDialog.LayoutParams onMeasureInternal(int width, int height) {
|
||||
final int displayRotation = getDisplay().getRotation();
|
||||
switch (displayRotation) {
|
||||
case Surface.ROTATION_0:
|
||||
return onMeasureInternalPortrait(width, height);
|
||||
case Surface.ROTATION_90:
|
||||
case Surface.ROTATION_270:
|
||||
return onMeasureInternalLandscape(width, height);
|
||||
default:
|
||||
Log.e(TAG, "Unsupported display rotation: " + displayRotation);
|
||||
return super.onMeasureInternal(width, height);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
AuthDialog.LayoutParams onMeasureInternal(int width, int height) {
|
||||
final View spaceBelowIcon = findViewById(R.id.space_below_icon);
|
||||
spaceBelowIcon.setVisibility(View.VISIBLE);
|
||||
|
||||
@NonNull
|
||||
private AuthDialog.LayoutParams onMeasureInternalPortrait(int width, int height) {
|
||||
// Get the height of the everything below the icon. Currently, that's the indicator and
|
||||
// button bar
|
||||
final View textIndicator = findViewById(R.id.indicator);
|
||||
final View buttonBar = findViewById(R.id.button_bar);
|
||||
// button bar.
|
||||
final int textIndicatorHeight = getViewHeightPx(R.id.indicator);
|
||||
final int buttonBarHeight = getViewHeightPx(R.id.button_bar);
|
||||
|
||||
// Figure out where the bottom of the sensor anim should be.
|
||||
// Navbar + dialogMargin + buttonBar + textIndicator + spacerHeight = sensorDistFromBottom
|
||||
final int dialogBottomMarginPx = getResources()
|
||||
.getDimensionPixelSize(R.dimen.biometric_dialog_border_padding);
|
||||
final WindowManager wm = getContext().getSystemService(WindowManager.class);
|
||||
final Rect bounds = wm.getCurrentWindowMetrics().getBounds();
|
||||
final int navbarHeight = wm.getCurrentWindowMetrics().getWindowInsets()
|
||||
.getInsets(WindowInsets.Type.navigationBars()).toRect().height();
|
||||
final int displayHeight = bounds.height();
|
||||
|
||||
final int spacerHeight = calculateBottomSpacerHeight(displayHeight, navbarHeight,
|
||||
dialogBottomMarginPx, buttonBar, textIndicator, mSensorProps);
|
||||
final int dialogMargin = getDialogMarginPx();
|
||||
final WindowManager windowManager = getContext().getSystemService(WindowManager.class);
|
||||
final int displayHeight = getWindowBounds(windowManager).height();
|
||||
final Insets navbarInsets = getNavbarInsets(windowManager);
|
||||
final int bottomSpacerHeight = calculateBottomSpacerHeightForPortrait(
|
||||
mSensorProps, displayHeight, textIndicatorHeight, buttonBarHeight,
|
||||
dialogMargin, navbarInsets.bottom);
|
||||
|
||||
// Go through each of the children and do the custom measurement.
|
||||
int totalHeight = 0;
|
||||
@@ -105,22 +95,25 @@ public class AuthBiometricUdfpsView extends AuthBiometricFingerprintView {
|
||||
final int sensorDiameter = mSensorProps.sensorRadius * 2;
|
||||
for (int i = 0; i < numChildren; i++) {
|
||||
final View child = getChildAt(i);
|
||||
|
||||
if (child.getId() == R.id.biometric_icon_frame) {
|
||||
// Create a frame that's exactly the size of the sensor circle
|
||||
child.measure(
|
||||
MeasureSpec.makeMeasureSpec(sensorDiameter, MeasureSpec.EXACTLY),
|
||||
MeasureSpec.makeMeasureSpec(sensorDiameter, MeasureSpec.EXACTLY));
|
||||
} else if (child.getId() == R.id.biometric_icon) {
|
||||
// Icon should never be larger than the circle
|
||||
child.measure(
|
||||
final FrameLayout iconFrame = (FrameLayout) child;
|
||||
final View icon = iconFrame.getChildAt(0);
|
||||
|
||||
// Ensure that the icon is never larger than the sensor.
|
||||
icon.measure(
|
||||
MeasureSpec.makeMeasureSpec(sensorDiameter, MeasureSpec.AT_MOST),
|
||||
MeasureSpec.makeMeasureSpec(sensorDiameter, MeasureSpec.AT_MOST));
|
||||
|
||||
// Create a frame that's exactly the height of the sensor circle.
|
||||
iconFrame.measure(
|
||||
MeasureSpec.makeMeasureSpec(
|
||||
child.getLayoutParams().width, MeasureSpec.EXACTLY),
|
||||
MeasureSpec.makeMeasureSpec(sensorDiameter, MeasureSpec.EXACTLY));
|
||||
} else if (child.getId() == R.id.space_above_icon) {
|
||||
child.measure(
|
||||
MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY),
|
||||
MeasureSpec.makeMeasureSpec(child.getLayoutParams().height,
|
||||
MeasureSpec.EXACTLY));
|
||||
MeasureSpec.makeMeasureSpec(
|
||||
child.getLayoutParams().height, MeasureSpec.EXACTLY));
|
||||
} else if (child.getId() == R.id.button_bar) {
|
||||
child.measure(
|
||||
MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY),
|
||||
@@ -128,8 +121,9 @@ public class AuthBiometricUdfpsView extends AuthBiometricFingerprintView {
|
||||
MeasureSpec.EXACTLY));
|
||||
} else if (child.getId() == R.id.space_below_icon) {
|
||||
// Set the spacer height so the fingerprint icon is on the physical sensor area
|
||||
child.measure(MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY),
|
||||
MeasureSpec.makeMeasureSpec(spacerHeight, MeasureSpec.EXACTLY));
|
||||
child.measure(
|
||||
MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY),
|
||||
MeasureSpec.makeMeasureSpec(bottomSpacerHeight, MeasureSpec.EXACTLY));
|
||||
} else {
|
||||
child.measure(
|
||||
MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY),
|
||||
@@ -143,4 +137,184 @@ public class AuthBiometricUdfpsView extends AuthBiometricFingerprintView {
|
||||
|
||||
return new AuthDialog.LayoutParams(width, totalHeight);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
private AuthDialog.LayoutParams onMeasureInternalLandscape(int width, int height) {
|
||||
// Find the spacer height needed to vertically align the icon with the sensor.
|
||||
final int titleHeight = getViewHeightPx(R.id.title);
|
||||
final int subtitleHeight = getViewHeightPx(R.id.subtitle);
|
||||
final int descriptionHeight = getViewHeightPx(R.id.description);
|
||||
final int topSpacerHeight = getViewHeightPx(R.id.space_above_icon);
|
||||
final int textIndicatorHeight = getViewHeightPx(R.id.indicator);
|
||||
final int buttonBarHeight = getViewHeightPx(R.id.button_bar);
|
||||
final WindowManager windowManager = getContext().getSystemService(WindowManager.class);
|
||||
final Insets navbarInsets = getNavbarInsets(windowManager);
|
||||
final int bottomSpacerHeight = calculateBottomSpacerHeightForLandscape(titleHeight,
|
||||
subtitleHeight, descriptionHeight, topSpacerHeight, textIndicatorHeight,
|
||||
buttonBarHeight, navbarInsets.bottom);
|
||||
|
||||
// Find the spacer width needed to horizontally align the icon with the sensor.
|
||||
final int displayWidth = getWindowBounds(windowManager).width();
|
||||
final int dialogMargin = getDialogMarginPx();
|
||||
final int horizontalInset = navbarInsets.left + navbarInsets.right;
|
||||
final int horizontalSpacerWidth = calculateHorizontalSpacerWidthForLandscape(
|
||||
mSensorProps, displayWidth, dialogMargin, horizontalInset);
|
||||
|
||||
final int sensorDiameter = mSensorProps.sensorRadius * 2;
|
||||
final int remeasuredWidth = sensorDiameter + 2 * horizontalSpacerWidth;
|
||||
|
||||
int remeasuredHeight = 0;
|
||||
final int numChildren = getChildCount();
|
||||
for (int i = 0; i < numChildren; i++) {
|
||||
final View child = getChildAt(i);
|
||||
if (child.getId() == R.id.biometric_icon_frame) {
|
||||
final FrameLayout iconFrame = (FrameLayout) child;
|
||||
final View icon = iconFrame.getChildAt(0);
|
||||
|
||||
// Ensure that the icon is never larger than the sensor.
|
||||
icon.measure(
|
||||
MeasureSpec.makeMeasureSpec(sensorDiameter, MeasureSpec.AT_MOST),
|
||||
MeasureSpec.makeMeasureSpec(sensorDiameter, MeasureSpec.AT_MOST));
|
||||
|
||||
// Create a frame that's exactly the height of the sensor circle.
|
||||
iconFrame.measure(
|
||||
MeasureSpec.makeMeasureSpec(remeasuredWidth, MeasureSpec.EXACTLY),
|
||||
MeasureSpec.makeMeasureSpec(sensorDiameter, MeasureSpec.EXACTLY));
|
||||
} else if (child.getId() == R.id.space_above_icon || child.getId() == R.id.button_bar) {
|
||||
// Adjust the width of the top spacer and button bar while preserving their heights.
|
||||
child.measure(
|
||||
MeasureSpec.makeMeasureSpec(remeasuredWidth, MeasureSpec.EXACTLY),
|
||||
MeasureSpec.makeMeasureSpec(
|
||||
child.getLayoutParams().height, MeasureSpec.EXACTLY));
|
||||
} else if (child.getId() == R.id.space_below_icon) {
|
||||
// Adjust the bottom spacer height to align the fingerprint icon with the sensor.
|
||||
child.measure(
|
||||
MeasureSpec.makeMeasureSpec(remeasuredWidth, MeasureSpec.EXACTLY),
|
||||
MeasureSpec.makeMeasureSpec(bottomSpacerHeight, MeasureSpec.EXACTLY));
|
||||
} else {
|
||||
// Use the remeasured width for all other child views.
|
||||
child.measure(
|
||||
MeasureSpec.makeMeasureSpec(remeasuredWidth, MeasureSpec.EXACTLY),
|
||||
MeasureSpec.makeMeasureSpec(height, MeasureSpec.AT_MOST));
|
||||
}
|
||||
|
||||
if (child.getVisibility() != View.GONE) {
|
||||
remeasuredHeight += child.getMeasuredHeight();
|
||||
}
|
||||
}
|
||||
|
||||
return new AuthDialog.LayoutParams(remeasuredWidth, remeasuredHeight);
|
||||
}
|
||||
|
||||
private int getViewHeightPx(@IdRes int viewId) {
|
||||
final View view = findViewById(viewId);
|
||||
return view != null ? view.getMeasuredHeight() : 0;
|
||||
}
|
||||
|
||||
private int getDialogMarginPx() {
|
||||
return getResources().getDimensionPixelSize(R.dimen.biometric_dialog_border_padding);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
private static Insets getNavbarInsets(@Nullable WindowManager windowManager) {
|
||||
return windowManager != null && windowManager.getCurrentWindowMetrics() != null
|
||||
? windowManager.getCurrentWindowMetrics().getWindowInsets()
|
||||
.getInsets(WindowInsets.Type.navigationBars())
|
||||
: Insets.NONE;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
private static Rect getWindowBounds(@Nullable WindowManager windowManager) {
|
||||
return windowManager != null && windowManager.getCurrentWindowMetrics() != null
|
||||
? windowManager.getCurrentWindowMetrics().getBounds()
|
||||
: new Rect();
|
||||
}
|
||||
|
||||
/**
|
||||
* For devices in portrait orientation where the sensor is too high up, calculates the amount of
|
||||
* padding necessary to center the biometric icon within the sensor's physical location.
|
||||
*/
|
||||
@VisibleForTesting
|
||||
static int calculateBottomSpacerHeightForPortrait(
|
||||
@NonNull FingerprintSensorPropertiesInternal sensorProperties, int displayHeightPx,
|
||||
int textIndicatorHeightPx, int buttonBarHeightPx, int dialogMarginPx,
|
||||
int navbarBottomInsetPx) {
|
||||
|
||||
final int sensorDistanceFromBottom = displayHeightPx
|
||||
- sensorProperties.sensorLocationY
|
||||
- sensorProperties.sensorRadius;
|
||||
|
||||
final int spacerHeight = sensorDistanceFromBottom
|
||||
- textIndicatorHeightPx
|
||||
- buttonBarHeightPx
|
||||
- dialogMarginPx
|
||||
- navbarBottomInsetPx;
|
||||
|
||||
Log.d(TAG, "Display height: " + displayHeightPx
|
||||
+ ", Distance from bottom: " + sensorDistanceFromBottom
|
||||
+ ", Bottom margin: " + dialogMarginPx
|
||||
+ ", Navbar bottom inset: " + navbarBottomInsetPx
|
||||
+ ", Bottom spacer height (portrait): " + spacerHeight);
|
||||
|
||||
return spacerHeight;
|
||||
}
|
||||
|
||||
/**
|
||||
* For devices in landscape orientation where the sensor is too high up, calculates the amount
|
||||
* of padding necessary to center the biometric icon within the sensor's physical location.
|
||||
*/
|
||||
@VisibleForTesting
|
||||
static int calculateBottomSpacerHeightForLandscape(int titleHeightPx, int subtitleHeightPx,
|
||||
int descriptionHeightPx, int topSpacerHeightPx, int textIndicatorHeightPx,
|
||||
int buttonBarHeightPx, int navbarBottomInsetPx) {
|
||||
|
||||
final int dialogHeightAboveIcon = titleHeightPx
|
||||
+ subtitleHeightPx
|
||||
+ descriptionHeightPx
|
||||
+ topSpacerHeightPx;
|
||||
|
||||
final int dialogHeightBelowIcon = textIndicatorHeightPx + buttonBarHeightPx;
|
||||
|
||||
final int bottomSpacerHeight = dialogHeightAboveIcon
|
||||
- dialogHeightBelowIcon
|
||||
- navbarBottomInsetPx;
|
||||
|
||||
Log.d(TAG, "Title height: " + titleHeightPx
|
||||
+ ", Subtitle height: " + subtitleHeightPx
|
||||
+ ", Description height: " + descriptionHeightPx
|
||||
+ ", Top spacer height: " + topSpacerHeightPx
|
||||
+ ", Text indicator height: " + textIndicatorHeightPx
|
||||
+ ", Button bar height: " + buttonBarHeightPx
|
||||
+ ", Navbar bottom inset: " + navbarBottomInsetPx
|
||||
+ ", Bottom spacer height (landscape): " + bottomSpacerHeight);
|
||||
|
||||
return bottomSpacerHeight;
|
||||
}
|
||||
|
||||
/**
|
||||
* For devices in landscape orientation where the sensor is too left/right, calculates the
|
||||
* amount of padding necessary to center the biometric icon within the sensor's physical
|
||||
* location.
|
||||
*/
|
||||
@VisibleForTesting
|
||||
static int calculateHorizontalSpacerWidthForLandscape(
|
||||
@NonNull FingerprintSensorPropertiesInternal sensorProperties, int displayWidthPx,
|
||||
int dialogMarginPx, int navbarHorizontalInsetPx) {
|
||||
|
||||
final int sensorDistanceFromEdge = displayWidthPx
|
||||
- sensorProperties.sensorLocationY
|
||||
- sensorProperties.sensorRadius;
|
||||
|
||||
final int horizontalPadding = sensorDistanceFromEdge
|
||||
- dialogMarginPx
|
||||
- navbarHorizontalInsetPx;
|
||||
|
||||
Log.d(TAG, "Display width: " + displayWidthPx
|
||||
+ ", Distance from edge: " + sensorDistanceFromEdge
|
||||
+ ", Dialog margin: " + dialogMarginPx
|
||||
+ ", Navbar horizontal inset: " + navbarHorizontalInsetPx
|
||||
+ ", Horizontal spacer width (landscape): " + horizontalPadding);
|
||||
|
||||
return horizontalPadding;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -742,6 +742,7 @@ public abstract class AuthBiometricView extends LinearLayout {
|
||||
* @param height Height to constrain the measurements to.
|
||||
* @return See {@link AuthDialog.LayoutParams}
|
||||
*/
|
||||
@NonNull
|
||||
AuthDialog.LayoutParams onMeasureInternal(int width, int height) {
|
||||
int totalHeight = 0;
|
||||
final int numChildren = getChildCount();
|
||||
|
||||
@@ -32,8 +32,10 @@ import android.os.IBinder;
|
||||
import android.os.Looper;
|
||||
import android.os.UserManager;
|
||||
import android.util.Log;
|
||||
import android.view.Gravity;
|
||||
import android.view.KeyEvent;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.Surface;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.WindowInsets;
|
||||
@@ -433,6 +435,29 @@ public class AuthContainerView extends LinearLayout
|
||||
+ mConfig.mPromptInfo.getAuthenticators());
|
||||
}
|
||||
|
||||
if (mBiometricView instanceof AuthBiometricUdfpsView) {
|
||||
final int displayRotation = getDisplay().getRotation();
|
||||
switch (displayRotation) {
|
||||
case Surface.ROTATION_0:
|
||||
mPanelController.setPosition(AuthPanelController.POSITION_BOTTOM);
|
||||
setScrollViewGravity(Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM);
|
||||
break;
|
||||
case Surface.ROTATION_90:
|
||||
mPanelController.setPosition(AuthPanelController.POSITION_RIGHT);
|
||||
setScrollViewGravity(Gravity.CENTER_VERTICAL | Gravity.RIGHT);
|
||||
break;
|
||||
case Surface.ROTATION_270:
|
||||
mPanelController.setPosition(AuthPanelController.POSITION_LEFT);
|
||||
setScrollViewGravity(Gravity.CENTER_VERTICAL | Gravity.LEFT);
|
||||
break;
|
||||
default:
|
||||
Log.e(TAG, "Unsupported display rotation: " + displayRotation);
|
||||
mPanelController.setPosition(AuthPanelController.POSITION_BOTTOM);
|
||||
setScrollViewGravity(Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (mConfig.mSkipIntro) {
|
||||
mContainerState = STATE_SHOWING;
|
||||
} else {
|
||||
@@ -476,6 +501,13 @@ public class AuthContainerView extends LinearLayout
|
||||
}
|
||||
}
|
||||
|
||||
private void setScrollViewGravity(int gravity) {
|
||||
final FrameLayout.LayoutParams params =
|
||||
(FrameLayout.LayoutParams) mBiometricScrollView.getLayoutParams();
|
||||
params.gravity = gravity;
|
||||
mBiometricScrollView.setLayoutParams(params);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDetachedFromWindow() {
|
||||
super.onDetachedFromWindow();
|
||||
|
||||
@@ -18,6 +18,7 @@ package com.android.systemui.biometrics;
|
||||
|
||||
import android.animation.AnimatorSet;
|
||||
import android.animation.ValueAnimator;
|
||||
import android.annotation.IntDef;
|
||||
import android.content.Context;
|
||||
import android.graphics.Outline;
|
||||
import android.util.Log;
|
||||
@@ -27,10 +28,20 @@ import android.view.animation.AccelerateDecelerateInterpolator;
|
||||
|
||||
import com.android.systemui.R;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
|
||||
/**
|
||||
* Controls the back panel and its animations for the BiometricPrompt UI.
|
||||
*/
|
||||
public class AuthPanelController extends ViewOutlineProvider {
|
||||
public static final int POSITION_BOTTOM = 1;
|
||||
public static final int POSITION_LEFT = 2;
|
||||
public static final int POSITION_RIGHT = 3;
|
||||
|
||||
@IntDef({POSITION_BOTTOM, POSITION_LEFT, POSITION_RIGHT})
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
public @interface Position {}
|
||||
|
||||
private static final String TAG = "BiometricPrompt/AuthPanelController";
|
||||
private static final boolean DEBUG = false;
|
||||
@@ -38,6 +49,7 @@ public class AuthPanelController extends ViewOutlineProvider {
|
||||
private final Context mContext;
|
||||
private final View mPanelView;
|
||||
|
||||
@Position private int mPosition = POSITION_BOTTOM;
|
||||
private boolean mUseFullScreen;
|
||||
|
||||
private int mContainerWidth;
|
||||
@@ -51,21 +63,44 @@ public class AuthPanelController extends ViewOutlineProvider {
|
||||
|
||||
@Override
|
||||
public void getOutline(View view, Outline outline) {
|
||||
final int left = (mContainerWidth - mContentWidth) / 2;
|
||||
final int right = mContainerWidth - left;
|
||||
final int left = getLeftBound(mPosition);
|
||||
final int right = left + mContentWidth;
|
||||
|
||||
// If the content fits within the container, shrink the height to wrap the content.
|
||||
// Otherwise, set the outline to be the display size minus the margin - the content within
|
||||
// is scrollable.
|
||||
final int top = mContentHeight < mContainerHeight
|
||||
? mContainerHeight - mContentHeight - mMargin
|
||||
: mMargin;
|
||||
// If the content fits in the container, shrink the height to wrap it. Otherwise, expand to
|
||||
// fill the display (minus the margin), since the content is scrollable.
|
||||
final int top = getTopBound(mPosition);
|
||||
final int bottom = Math.min(top + mContentHeight, mContainerHeight - mMargin);
|
||||
|
||||
// TODO(b/139954942) Likely don't need to "+1" after we resolve the navbar styling.
|
||||
final int bottom = mContainerHeight - mMargin + 1;
|
||||
outline.setRoundRect(left, top, right, bottom, mCornerRadius);
|
||||
}
|
||||
|
||||
private int getLeftBound(@Position int position) {
|
||||
switch (position) {
|
||||
case POSITION_BOTTOM:
|
||||
return (mContainerWidth - mContentWidth) / 2;
|
||||
case POSITION_LEFT:
|
||||
return mMargin;
|
||||
case POSITION_RIGHT:
|
||||
return mContainerWidth - mContentWidth - mMargin;
|
||||
default:
|
||||
Log.e(TAG, "Unrecognized position: " + position);
|
||||
return getLeftBound(POSITION_BOTTOM);
|
||||
}
|
||||
}
|
||||
|
||||
private int getTopBound(@Position int position) {
|
||||
switch (position) {
|
||||
case POSITION_BOTTOM:
|
||||
return Math.max(mContainerHeight - mContentHeight - mMargin, mMargin);
|
||||
case POSITION_LEFT:
|
||||
case POSITION_RIGHT:
|
||||
return Math.max((mContainerHeight - mContentHeight) / 2, mMargin);
|
||||
default:
|
||||
Log.e(TAG, "Unrecognized position: " + position);
|
||||
return getTopBound(POSITION_BOTTOM);
|
||||
}
|
||||
}
|
||||
|
||||
public void setContainerDimensions(int containerWidth, int containerHeight) {
|
||||
if (DEBUG) {
|
||||
Log.v(TAG, "Container Width: " + containerWidth + " Height: " + containerHeight);
|
||||
@@ -74,6 +109,10 @@ public class AuthPanelController extends ViewOutlineProvider {
|
||||
mContainerHeight = containerHeight;
|
||||
}
|
||||
|
||||
public void setPosition(@Position int position) {
|
||||
mPosition = position;
|
||||
}
|
||||
|
||||
public void setUseFullScreen(boolean fullScreen) {
|
||||
mUseFullScreen = fullScreen;
|
||||
}
|
||||
|
||||
@@ -22,10 +22,8 @@ import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.mockito.ArgumentMatchers.anyInt;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.never;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import android.content.Context;
|
||||
import android.hardware.biometrics.PromptInfo;
|
||||
@@ -333,16 +331,12 @@ public class AuthBiometricViewTest extends SysuiTestCase {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUdfpsBottomSpacerCalculation() {
|
||||
public void testUdfpsBottomSpacerHeightForPortrait() {
|
||||
final int displayHeightPx = 3000;
|
||||
final int navbarHeightPx = 10;
|
||||
final int dialogBottomMarginPx = 20;
|
||||
|
||||
final View buttonBar = mock(View.class);
|
||||
when(buttonBar.getMeasuredHeight()).thenReturn(100);
|
||||
|
||||
final View textIndicator = mock(View.class);
|
||||
when(textIndicator.getMeasuredHeight()).thenReturn(200);
|
||||
final int buttonBarHeightPx = 100;
|
||||
final int textIndicatorHeightPx = 200;
|
||||
|
||||
final int sensorLocationX = 540;
|
||||
final int sensorLocationY = 1600;
|
||||
@@ -353,9 +347,47 @@ public class AuthBiometricViewTest extends SysuiTestCase {
|
||||
true /* resetLockoutRequiresHardwareAuthToken */, sensorLocationX, sensorLocationY,
|
||||
sensorRadius);
|
||||
|
||||
assertEquals(970, AuthBiometricUdfpsView.calculateBottomSpacerHeight(
|
||||
displayHeightPx, navbarHeightPx, dialogBottomMarginPx, buttonBar, textIndicator,
|
||||
props));
|
||||
assertEquals(970,
|
||||
AuthBiometricUdfpsView.calculateBottomSpacerHeightForPortrait(
|
||||
props, displayHeightPx, textIndicatorHeightPx, buttonBarHeightPx,
|
||||
dialogBottomMarginPx, navbarHeightPx
|
||||
));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUdfpsBottomSpacerHeightForLandscape() {
|
||||
final int titleHeightPx = 320;
|
||||
final int subtitleHeightPx = 240;
|
||||
final int descriptionHeightPx = 200;
|
||||
final int topSpacerHeightPx = 550;
|
||||
final int textIndicatorHeightPx = 190;
|
||||
final int buttonBarHeightPx = 160;
|
||||
final int navbarBottomInsetPx = 75;
|
||||
|
||||
assertEquals(885,
|
||||
AuthBiometricUdfpsView.calculateBottomSpacerHeightForLandscape(
|
||||
titleHeightPx, subtitleHeightPx, descriptionHeightPx, topSpacerHeightPx,
|
||||
textIndicatorHeightPx, buttonBarHeightPx, navbarBottomInsetPx));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUdfpsHorizontalSpacerWidthForLandscape() {
|
||||
final int displayWidthPx = 3000;
|
||||
final int dialogMarginPx = 20;
|
||||
final int navbarHorizontalInsetPx = 75;
|
||||
|
||||
final int sensorLocationX = 540;
|
||||
final int sensorLocationY = 1600;
|
||||
final int sensorRadius = 100;
|
||||
final FingerprintSensorPropertiesInternal props = new FingerprintSensorPropertiesInternal(
|
||||
0 /* sensorId */, SensorProperties.STRENGTH_STRONG, 5 /* maxEnrollmentsPerUser */,
|
||||
FingerprintSensorProperties.TYPE_UDFPS_OPTICAL,
|
||||
true /* resetLockoutRequiresHardwareAuthToken */, sensorLocationX, sensorLocationY,
|
||||
sensorRadius);
|
||||
|
||||
assertEquals(1205,
|
||||
AuthBiometricUdfpsView.calculateHorizontalSpacerWidthForLandscape(
|
||||
props, displayWidthPx, dialogMarginPx, navbarHorizontalInsetPx));
|
||||
}
|
||||
|
||||
private PromptInfo buildPromptInfo(boolean allowDeviceCredential) {
|
||||
|
||||
Reference in New Issue
Block a user