Loading packages/SystemUI/res/layout/auth_biometric_contents.xml +8 −10 Original line number Diff line number Diff line Loading @@ -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/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" Loading @@ -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" Loading packages/SystemUI/res/values/styles.xml +6 −0 Original line number Diff line number Diff line Loading @@ -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"> Loading @@ -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"> Loading @@ -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"> Loading packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricUdfpsView.java +226 −52 Original line number Diff line number Diff line Loading @@ -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; /** Loading @@ -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 View spaceBelowIcon = findViewById(R.id.space_below_icon); spaceBelowIcon.setVisibility(View.VISIBLE); 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); } } @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; Loading @@ -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), Loading @@ -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), Loading @@ -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; } } packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricView.java +1 −0 Original line number Diff line number Diff line Loading @@ -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(); Loading packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java +32 −0 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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 { Loading Loading @@ -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(); Loading Loading
packages/SystemUI/res/layout/auth_biometric_contents.xml +8 −10 Original line number Diff line number Diff line Loading @@ -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/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" Loading @@ -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" Loading
packages/SystemUI/res/values/styles.xml +6 −0 Original line number Diff line number Diff line Loading @@ -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"> Loading @@ -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"> Loading @@ -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"> Loading
packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricUdfpsView.java +226 −52 Original line number Diff line number Diff line Loading @@ -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; /** Loading @@ -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 View spaceBelowIcon = findViewById(R.id.space_below_icon); spaceBelowIcon.setVisibility(View.VISIBLE); 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); } } @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; Loading @@ -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), Loading @@ -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), Loading @@ -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; } }
packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricView.java +1 −0 Original line number Diff line number Diff line Loading @@ -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(); Loading
packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java +32 −0 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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 { Loading Loading @@ -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(); Loading