Make auth dialog in large size expand into cutout area
1. Set cutout mode always and ignore systemBars insets in
AuthContainerView to extend its content area into cutout and system
bars areas.
2. In AuthBiometricView:
- Account for navigation bar insets to calculate the actual dialog
width/height.
- Set the paddings for dialog with size other than Large according to
the navigation bar insets.
3. Exclude the navigation bar insets when calculating auth panel outline
for non fullscreen dialog.
Make the UI more consistance in the status bar & cutout region.
Bug: 256966736
Bug: 206761077
Bug: 159687661
Bug: 269056111
Test: build and manual check BP visual in portrait & landscape
Test: atest AuthContainerViewTest CredentialPasswordViewScreenshotTest CredentialPatternViewScreenshotTest
Change-Id: I250dff8885465d378074fd919d7b24456ba7a4e0
This commit is contained in:
@@ -28,6 +28,7 @@ import android.annotation.Nullable;
|
||||
import android.annotation.StringRes;
|
||||
import android.content.Context;
|
||||
import android.content.res.Configuration;
|
||||
import android.graphics.Insets;
|
||||
import android.hardware.biometrics.BiometricAuthenticator.Modality;
|
||||
import android.hardware.biometrics.BiometricPrompt;
|
||||
import android.hardware.biometrics.PromptInfo;
|
||||
@@ -299,9 +300,25 @@ public abstract class AuthBiometricView extends LinearLayout {
|
||||
mJankListener = jankListener;
|
||||
}
|
||||
|
||||
private void updatePaddings(int size) {
|
||||
final Insets navBarInsets = Utils.getNavbarInsets(mContext);
|
||||
if (size != AuthDialog.SIZE_LARGE) {
|
||||
if (mPanelController.getPosition() == AuthPanelController.POSITION_LEFT) {
|
||||
setPadding(navBarInsets.left, 0, 0, 0);
|
||||
} else if (mPanelController.getPosition() == AuthPanelController.POSITION_RIGHT) {
|
||||
setPadding(0, 0, navBarInsets.right, 0);
|
||||
} else {
|
||||
setPadding(0, 0, 0, navBarInsets.bottom);
|
||||
}
|
||||
} else {
|
||||
setPadding(0, 0, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
final void updateSize(@AuthDialog.DialogSize int newSize) {
|
||||
Log.v(TAG, "Current size: " + mSize + " New size: " + newSize);
|
||||
updatePaddings(newSize);
|
||||
if (newSize == AuthDialog.SIZE_SMALL) {
|
||||
mTitleView.setVisibility(View.GONE);
|
||||
mSubtitleView.setVisibility(View.GONE);
|
||||
@@ -521,6 +538,11 @@ public abstract class AuthBiometricView extends LinearLayout {
|
||||
mState = newState;
|
||||
}
|
||||
|
||||
void onOrientationChanged() {
|
||||
// Update padding and AuthPanel outline by calling updateSize when the orientation changed.
|
||||
updateSize(mSize);
|
||||
}
|
||||
|
||||
public void onDialogAnimatedIn() {
|
||||
updateState(STATE_AUTHENTICATING);
|
||||
}
|
||||
@@ -864,6 +886,25 @@ public abstract class AuthBiometricView extends LinearLayout {
|
||||
}
|
||||
|
||||
mLayoutParams = onMeasureInternal(width, height);
|
||||
|
||||
final Insets navBarInsets = Utils.getNavbarInsets(mContext);
|
||||
final int navBarHeight = navBarInsets.bottom;
|
||||
final int navBarWidth;
|
||||
if (mPanelController.getPosition() == AuthPanelController.POSITION_LEFT) {
|
||||
navBarWidth = navBarInsets.left;
|
||||
} else if (mPanelController.getPosition() == AuthPanelController.POSITION_RIGHT) {
|
||||
navBarWidth = navBarInsets.right;
|
||||
} else {
|
||||
navBarWidth = 0;
|
||||
}
|
||||
|
||||
// The actual auth dialog w/h should include navigation bar size.
|
||||
if (navBarWidth != 0 || navBarHeight != 0) {
|
||||
mLayoutParams = new AuthDialog.LayoutParams(
|
||||
mLayoutParams.mMediumWidth + navBarWidth,
|
||||
mLayoutParams.mMediumHeight + navBarInsets.bottom);
|
||||
}
|
||||
|
||||
setMeasuredDimension(mLayoutParams.mMediumWidth, mLayoutParams.mMediumHeight);
|
||||
}
|
||||
|
||||
|
||||
@@ -19,6 +19,7 @@ package com.android.systemui.biometrics;
|
||||
import static android.hardware.biometrics.BiometricManager.BIOMETRIC_MULTI_SENSOR_DEFAULT;
|
||||
import static android.hardware.biometrics.BiometricManager.BiometricMultiSensorMode;
|
||||
import static android.hardware.biometrics.SensorProperties.STRENGTH_STRONG;
|
||||
import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
|
||||
|
||||
import static com.android.internal.jank.InteractionJankMonitor.CUJ_BIOMETRIC_PROMPT_TRANSITION;
|
||||
|
||||
@@ -497,6 +498,9 @@ public class AuthContainerView extends LinearLayout
|
||||
@Override
|
||||
public void onOrientationChanged() {
|
||||
maybeUpdatePositionForUdfps(true /* invalidate */);
|
||||
if (mBiometricView != null) {
|
||||
mBiometricView.onOrientationChanged();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -884,7 +888,9 @@ public class AuthContainerView extends LinearLayout
|
||||
windowFlags,
|
||||
PixelFormat.TRANSLUCENT);
|
||||
lp.privateFlags |= WindowManager.LayoutParams.SYSTEM_FLAG_SHOW_FOR_ALL_USERS;
|
||||
lp.setFitInsetsTypes(lp.getFitInsetsTypes() & ~WindowInsets.Type.ime());
|
||||
lp.setFitInsetsTypes(lp.getFitInsetsTypes() & ~WindowInsets.Type.ime()
|
||||
& ~WindowInsets.Type.systemBars());
|
||||
lp.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
|
||||
lp.setTitle("BiometricPrompt");
|
||||
lp.accessibilityTitle = title;
|
||||
lp.dimAmount = BACKGROUND_DIM_AMOUNT;
|
||||
|
||||
@@ -20,6 +20,7 @@ import android.animation.AnimatorSet;
|
||||
import android.animation.ValueAnimator;
|
||||
import android.annotation.IntDef;
|
||||
import android.content.Context;
|
||||
import android.graphics.Insets;
|
||||
import android.graphics.Outline;
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
@@ -64,13 +65,12 @@ public class AuthPanelController extends ViewOutlineProvider {
|
||||
@Override
|
||||
public void getOutline(View view, Outline outline) {
|
||||
final int left = getLeftBound(mPosition);
|
||||
final int right = left + mContentWidth;
|
||||
final int right = getRightBound(mPosition, left);
|
||||
|
||||
// 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);
|
||||
|
||||
final int bottom = getBottomBound(top);
|
||||
outline.setRoundRect(left, top, right, bottom, mCornerRadius);
|
||||
}
|
||||
|
||||
@@ -79,6 +79,10 @@ public class AuthPanelController extends ViewOutlineProvider {
|
||||
case POSITION_BOTTOM:
|
||||
return (mContainerWidth - mContentWidth) / 2;
|
||||
case POSITION_LEFT:
|
||||
if (!mUseFullScreen) {
|
||||
final Insets navBarInsets = Utils.getNavbarInsets(mContext);
|
||||
return mMargin + navBarInsets.left;
|
||||
}
|
||||
return mMargin;
|
||||
case POSITION_RIGHT:
|
||||
return mContainerWidth - mContentWidth - mMargin;
|
||||
@@ -88,6 +92,27 @@ public class AuthPanelController extends ViewOutlineProvider {
|
||||
}
|
||||
}
|
||||
|
||||
private int getRightBound(@Position int position, int left) {
|
||||
if (!mUseFullScreen) {
|
||||
final Insets navBarInsets = Utils.getNavbarInsets(mContext);
|
||||
if (position == POSITION_RIGHT) {
|
||||
return left + mContentWidth - navBarInsets.right;
|
||||
} else if (position == POSITION_LEFT) {
|
||||
return left + mContentWidth - navBarInsets.left;
|
||||
}
|
||||
}
|
||||
return left + mContentWidth;
|
||||
}
|
||||
|
||||
private int getBottomBound(int top) {
|
||||
if (!mUseFullScreen) {
|
||||
final Insets navBarInsets = Utils.getNavbarInsets(mContext);
|
||||
return Math.min(top + mContentHeight - navBarInsets.bottom,
|
||||
mContainerHeight - mMargin - navBarInsets.bottom);
|
||||
}
|
||||
return Math.min(top + mContentHeight, mContainerHeight - mMargin);
|
||||
}
|
||||
|
||||
private int getTopBound(@Position int position) {
|
||||
switch (position) {
|
||||
case POSITION_BOTTOM:
|
||||
@@ -113,6 +138,10 @@ public class AuthPanelController extends ViewOutlineProvider {
|
||||
mPosition = position;
|
||||
}
|
||||
|
||||
public @Position int getPosition() {
|
||||
return mPosition;
|
||||
}
|
||||
|
||||
public void setUseFullScreen(boolean fullScreen) {
|
||||
mUseFullScreen = fullScreen;
|
||||
}
|
||||
|
||||
@@ -26,13 +26,16 @@ import android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_NUMERIC_COMPLEX
|
||||
import android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_SOMETHING
|
||||
import android.content.Context
|
||||
import android.content.pm.PackageManager
|
||||
import android.graphics.Insets
|
||||
import android.hardware.biometrics.BiometricManager.Authenticators
|
||||
import android.hardware.biometrics.PromptInfo
|
||||
import android.hardware.biometrics.SensorPropertiesInternal
|
||||
import android.os.UserManager
|
||||
import android.util.DisplayMetrics
|
||||
import android.view.ViewGroup
|
||||
import android.view.WindowInsets
|
||||
import android.view.WindowManager
|
||||
import android.view.WindowMetrics
|
||||
import android.view.accessibility.AccessibilityEvent
|
||||
import android.view.accessibility.AccessibilityManager
|
||||
import com.android.internal.widget.LockPatternUtils
|
||||
@@ -114,6 +117,14 @@ object Utils {
|
||||
return hasPermission && "android" == clientPackage
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun getNavbarInsets(context: Context): Insets {
|
||||
val windowManager: WindowManager? = context.getSystemService(WindowManager::class.java)
|
||||
val windowMetrics: WindowMetrics? = windowManager?.maximumWindowMetrics
|
||||
return windowMetrics?.windowInsets?.getInsets(WindowInsets.Type.navigationBars())
|
||||
?: Insets.NONE
|
||||
}
|
||||
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
@IntDef(CREDENTIAL_PIN, CREDENTIAL_PATTERN, CREDENTIAL_PASSWORD)
|
||||
internal annotation class CredentialType
|
||||
|
||||
@@ -483,6 +483,21 @@ class AuthContainerViewTest : SysuiTestCase() {
|
||||
waitForIdleSync()
|
||||
assertThat(isAttachedToWindow()).isTrue()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testLayoutParams_hasCutoutModeAlwaysFlag() {
|
||||
val layoutParams = AuthContainerView.getLayoutParams(windowToken, "")
|
||||
val lpFlags = layoutParams.flags
|
||||
|
||||
assertThat((lpFlags and WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS)
|
||||
!= 0).isTrue()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testLayoutParams_excludesSystemBarInsets() {
|
||||
val layoutParams = AuthContainerView.getLayoutParams(windowToken, "")
|
||||
assertThat((layoutParams.fitInsetsTypes and WindowInsets.Type.systemBars()) == 0).isTrue()
|
||||
}
|
||||
}
|
||||
|
||||
private fun AuthContainerView.hasBiometricPrompt() =
|
||||
|
||||
Reference in New Issue
Block a user