diff options
12 files changed, 418 insertions, 288 deletions
diff --git a/packages/SystemUI/res/layout-land/biometric_prompt_constraint_layout.xml b/packages/SystemUI/res/layout-land/biometric_prompt_constraint_layout.xml index 1777bdf92786..dabfe9df6d2e 100644 --- a/packages/SystemUI/res/layout-land/biometric_prompt_constraint_layout.xml +++ b/packages/SystemUI/res/layout-land/biometric_prompt_constraint_layout.xml @@ -39,7 +39,6 @@ android:layout_height="match_parent"> android:layout_height="wrap_content" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" - app:layout_constraintHorizontal_bias="0.8" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" tools:srcCompat="@tools:sample/avatars" /> @@ -60,11 +59,12 @@ android:layout_height="match_parent"> android:id="@+id/scrollView" android:layout_width="0dp" android:layout_height="0dp" - android:fillViewport="true" - android:padding="24dp" - app:layout_constrainedHeight="true" - app:layout_constrainedWidth="true" - app:layout_constraintBottom_toTopOf="@+id/buttonBarrier" + android:paddingBottom="16dp" + android:paddingLeft="24dp" + android:paddingRight="12dp" + android:paddingTop="24dp" + android:fadeScrollbars="false" + app:layout_constraintBottom_toTopOf="@+id/button_bar" app:layout_constraintEnd_toStartOf="@+id/midGuideline" app:layout_constraintStart_toStartOf="@id/leftGuideline" app:layout_constraintTop_toTopOf="@+id/topGuideline"> @@ -91,7 +91,7 @@ android:layout_height="match_parent"> android:layout_width="0dp" android:layout_height="wrap_content" android:textAlignment="viewStart" - android:paddingLeft="8dp" + android:paddingLeft="16dp" app:layout_constraintBottom_toBottomOf="@+id/logo" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toEndOf="@+id/logo" @@ -119,7 +119,7 @@ android:layout_height="match_parent"> style="@style/TextAppearance.AuthCredential.Subtitle" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:layout_marginTop="12dp" + android:layout_marginTop="16dp" android:gravity="@integer/biometric_dialog_text_gravity" android:paddingHorizontal="0dp" android:textAlignment="viewStart" @@ -133,6 +133,7 @@ android:layout_height="match_parent"> android:id="@+id/customized_view_container" android:layout_width="match_parent" android:layout_height="wrap_content" + android:layout_marginTop="24dp" android:gravity="center_vertical" android:orientation="vertical" android:visibility="gone" @@ -148,6 +149,7 @@ android:layout_height="match_parent"> style="@style/TextAppearance.AuthCredential.Description" android:layout_width="wrap_content" android:layout_height="wrap_content" + android:layout_marginTop="24dp" android:gravity="@integer/biometric_dialog_text_gravity" android:paddingHorizontal="0dp" android:textAlignment="viewStart" @@ -179,7 +181,7 @@ android:layout_height="match_parent"> android:fadingEdge="horizontal" android:gravity="center_horizontal" android:scrollHorizontally="true" - app:layout_constraintBottom_toTopOf="@+id/buttonBarrier" + app:layout_constraintBottom_toTopOf="@+id/button_bar" app:layout_constraintEnd_toEndOf="@+id/biometric_icon" app:layout_constraintStart_toStartOf="@+id/biometric_icon" app:layout_constraintTop_toBottomOf="@+id/biometric_icon" @@ -189,7 +191,7 @@ android:layout_height="match_parent"> android:id="@+id/button_bar" layout="@layout/biometric_prompt_button_bar" android:layout_width="0dp" - android:layout_height="0dp" + android:layout_height="wrap_content" app:layout_constraintBottom_toTopOf="@id/bottomGuideline" app:layout_constraintEnd_toEndOf="@id/scrollView" app:layout_constraintStart_toStartOf="@id/scrollView" @@ -204,14 +206,6 @@ android:layout_height="match_parent"> app:barrierDirection="top" app:constraint_referenced_ids="scrollView" /> - <androidx.constraintlayout.widget.Barrier - android:id="@+id/buttonBarrier" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - app:barrierAllowsGoneWidgets="false" - app:barrierDirection="top" - app:constraint_referenced_ids="button_bar" /> - <androidx.constraintlayout.widget.Guideline android:id="@+id/leftGuideline" android:layout_width="wrap_content" @@ -238,13 +232,13 @@ android:layout_height="match_parent"> android:layout_width="wrap_content" android:layout_height="wrap_content" android:orientation="horizontal" - app:layout_constraintGuide_end="@dimen/biometric_dialog_border_padding" /> + app:layout_constraintGuide_end="40dp" /> <androidx.constraintlayout.widget.Guideline android:id="@+id/topGuideline" android:layout_width="0dp" android:layout_height="0dp" android:orientation="horizontal" - app:layout_constraintGuide_begin="@dimen/biometric_dialog_border_padding" /> + app:layout_constraintGuide_begin="0dp" /> </androidx.constraintlayout.widget.ConstraintLayout> diff --git a/packages/SystemUI/res/layout-sw600dp/biometric_prompt_constraint_layout.xml b/packages/SystemUI/res/layout-sw600dp/biometric_prompt_constraint_layout.xml index 8b886a7fdffb..240ababc7da4 100644 --- a/packages/SystemUI/res/layout-sw600dp/biometric_prompt_constraint_layout.xml +++ b/packages/SystemUI/res/layout-sw600dp/biometric_prompt_constraint_layout.xml @@ -29,28 +29,31 @@ app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toStartOf="@+id/rightGuideline" app:layout_constraintStart_toStartOf="@+id/leftGuideline" - app:layout_constraintTop_toTopOf="@+id/topBarrier" /> + app:layout_constraintTop_toTopOf="@+id/topBarrier" + app:layout_constraintWidth_max="640dp" /> <include - layout="@layout/biometric_prompt_button_bar" android:id="@+id/button_bar" + layout="@layout/biometric_prompt_button_bar" android:layout_width="0dp" - android:layout_height="match_parent" - app:layout_constraintBottom_toTopOf="@id/bottomGuideline" + android:layout_height="wrap_content" + android:layout_marginBottom="40dp" + app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="@id/panel" - app:layout_constraintStart_toStartOf="@id/panel"/> + app:layout_constraintStart_toStartOf="@id/panel" /> <ScrollView android:id="@+id/scrollView" android:layout_width="0dp" android:layout_height="wrap_content" + android:fadeScrollbars="false" android:fillViewport="true" - android:paddingBottom="36dp" - android:paddingHorizontal="24dp" + android:paddingBottom="32dp" + android:paddingHorizontal="32dp" android:paddingTop="24dp" app:layout_constrainedHeight="true" app:layout_constrainedWidth="true" - app:layout_constraintBottom_toTopOf="@+id/biometric_icon" + app:layout_constraintBottom_toTopOf="@+id/scrollBarrier" app:layout_constraintEnd_toEndOf="@id/panel" app:layout_constraintStart_toStartOf="@id/panel" app:layout_constraintTop_toTopOf="@+id/topGuideline" @@ -63,10 +66,10 @@ <ImageView android:id="@+id/logo" - android:contentDescription="@string/biometric_dialog_logo" android:layout_width="@dimen/biometric_prompt_logo_size" android:layout_height="@dimen/biometric_prompt_logo_size" android:layout_gravity="center" + android:contentDescription="@string/biometric_dialog_logo" android:scaleType="fitXY" android:visibility="visible" app:layout_constraintBottom_toTopOf="@+id/logo_description" @@ -79,6 +82,7 @@ style="@style/TextAppearance.AuthCredential.LogoDescription" android:layout_width="match_parent" android:layout_height="wrap_content" + android:paddingTop="16dp" app:layout_constraintBottom_toTopOf="@+id/title" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" @@ -114,6 +118,7 @@ android:layout_height="wrap_content" android:gravity="center_vertical" android:orientation="vertical" + android:paddingTop="24dp" android:visibility="gone" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" @@ -126,6 +131,8 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:gravity="@integer/biometric_dialog_text_gravity" + android:paddingTop="16dp" + android:textAlignment="viewStart" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" @@ -153,7 +160,7 @@ android:fadingEdge="horizontal" android:gravity="center_horizontal" android:scrollHorizontally="true" - app:layout_constraintBottom_toTopOf="@+id/buttonBarrier" + app:layout_constraintBottom_toTopOf="@+id/button_bar" app:layout_constraintEnd_toEndOf="@+id/panel" app:layout_constraintStart_toStartOf="@+id/panel" app:layout_constraintTop_toBottomOf="@+id/biometric_icon" @@ -172,12 +179,12 @@ <!-- Try Again Button --> <androidx.constraintlayout.widget.Barrier - android:id="@+id/buttonBarrier" + android:id="@+id/scrollBarrier" android:layout_width="wrap_content" android:layout_height="wrap_content" app:barrierAllowsGoneWidgets="false" app:barrierDirection="top" - app:constraint_referenced_ids="button_bar" /> + app:constraint_referenced_ids="biometric_icon, button_bar" /> <!-- Guidelines for setting panel border --> <androidx.constraintlayout.widget.Guideline @@ -199,14 +206,14 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:orientation="horizontal" - app:layout_constraintGuide_end="@dimen/biometric_dialog_border_padding" /> + app:layout_constraintGuide_end="40dp" /> <androidx.constraintlayout.widget.Guideline android:id="@+id/topGuideline" android:layout_width="0dp" android:layout_height="0dp" android:orientation="horizontal" - app:layout_constraintGuide_percent="0.25171" /> + app:layout_constraintGuide_begin="56dp" /> <com.android.systemui.biometrics.BiometricPromptLottieViewWrapper android:id="@+id/biometric_icon" @@ -216,7 +223,7 @@ app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" - app:layout_constraintVertical_bias="0.8" + app:layout_constraintVertical_bias="1.0" tools:srcCompat="@tools:sample/avatars" /> <com.android.systemui.biometrics.BiometricPromptLottieViewWrapper diff --git a/packages/SystemUI/res/layout/biometric_prompt_button_bar.xml b/packages/SystemUI/res/layout/biometric_prompt_button_bar.xml index 810c7433e4ad..4d2310a2a6ca 100644 --- a/packages/SystemUI/res/layout/biometric_prompt_button_bar.xml +++ b/packages/SystemUI/res/layout/biometric_prompt_button_bar.xml @@ -17,12 +17,13 @@ <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" + android:theme="@style/Theme.SystemUI.Dialog" xmlns:app="http://schemas.android.com/apk/res-auto"> <!-- Negative Button, reserved for app --> <Button android:id="@+id/button_negative" - style="@*android:style/Widget.DeviceDefault.Button.Borderless.Colored" + style="@style/Widget.Dialog.Button.BorderButton" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_vertical" @@ -36,7 +37,7 @@ <!-- Cancel Button, replaces negative button when biometric is accepted --> <Button android:id="@+id/button_cancel" - style="@*android:style/Widget.DeviceDefault.Button.Borderless.Colored" + style="@style/Widget.Dialog.Button.BorderButton" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_vertical" @@ -49,7 +50,7 @@ <!-- "Use Credential" Button, replaces if device credential is allowed --> <Button android:id="@+id/button_use_credential" - style="@*android:style/Widget.DeviceDefault.Button.Borderless.Colored" + style="@style/Widget.Dialog.Button.BorderButton" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_vertical" @@ -61,7 +62,7 @@ <!-- Positive Button --> <Button android:id="@+id/button_confirm" - style="@*android:style/Widget.DeviceDefault.Button.Colored" + style="@style/Widget.Dialog.Button" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_vertical" @@ -76,7 +77,7 @@ <!-- Try Again Button --> <Button android:id="@+id/button_try_again" - style="@*android:style/Widget.DeviceDefault.Button.Colored" + style="@style/Widget.Dialog.Button" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_vertical" diff --git a/packages/SystemUI/res/layout/biometric_prompt_constraint_layout.xml b/packages/SystemUI/res/layout/biometric_prompt_constraint_layout.xml index 74bf318465b6..4aa609207312 100644 --- a/packages/SystemUI/res/layout/biometric_prompt_constraint_layout.xml +++ b/packages/SystemUI/res/layout/biometric_prompt_constraint_layout.xml @@ -35,24 +35,26 @@ android:id="@+id/button_bar" layout="@layout/biometric_prompt_button_bar" android:layout_width="0dp" - android:layout_height="match_parent" - app:layout_constraintBottom_toTopOf="@id/bottomGuideline" + android:layout_height="wrap_content" + android:layout_marginBottom="40dp" + app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="@id/panel" app:layout_constraintStart_toStartOf="@id/panel" /> <ScrollView android:id="@+id/scrollView" - android:layout_width="match_parent" + android:layout_width="0dp" android:layout_height="wrap_content" android:fillViewport="true" + android:fadeScrollbars="false" android:paddingBottom="36dp" android:paddingHorizontal="24dp" android:paddingTop="24dp" app:layout_constrainedHeight="true" app:layout_constrainedWidth="true" - app:layout_constraintBottom_toTopOf="@+id/biometric_icon" - app:layout_constraintEnd_toEndOf="@id/rightGuideline" - app:layout_constraintStart_toStartOf="@id/leftGuideline" + app:layout_constraintBottom_toTopOf="@+id/scrollBarrier" + app:layout_constraintEnd_toEndOf="@id/panel" + app:layout_constraintStart_toStartOf="@id/panel" app:layout_constraintTop_toTopOf="@+id/topGuideline" app:layout_constraintVertical_bias="1.0"> @@ -79,6 +81,7 @@ style="@style/TextAppearance.AuthCredential.LogoDescription" android:layout_width="match_parent" android:layout_height="wrap_content" + android:paddingTop="8dp" app:layout_constraintBottom_toTopOf="@+id/title" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" @@ -114,8 +117,8 @@ android:layout_height="wrap_content" android:gravity="center_vertical" android:orientation="vertical" - android:visibility="gone" android:paddingTop="24dp" + android:visibility="gone" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" @@ -127,7 +130,8 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:gravity="@integer/biometric_dialog_text_gravity" - android:paddingTop="24dp" + android:textAlignment="viewStart" + android:paddingTop="16dp" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" @@ -154,7 +158,7 @@ android:fadingEdge="horizontal" android:gravity="center_horizontal" android:scrollHorizontally="true" - app:layout_constraintBottom_toTopOf="@+id/buttonBarrier" + app:layout_constraintBottom_toTopOf="@+id/button_bar" app:layout_constraintEnd_toEndOf="@+id/panel" app:layout_constraintStart_toStartOf="@+id/panel" app:layout_constraintTop_toBottomOf="@+id/biometric_icon" @@ -169,12 +173,12 @@ app:constraint_referenced_ids="scrollView" /> <androidx.constraintlayout.widget.Barrier - android:id="@+id/buttonBarrier" + android:id="@+id/scrollBarrier" android:layout_width="wrap_content" android:layout_height="wrap_content" app:barrierAllowsGoneWidgets="false" app:barrierDirection="top" - app:constraint_referenced_ids="button_bar" /> + app:constraint_referenced_ids="biometric_icon, button_bar" /> <androidx.constraintlayout.widget.Guideline android:id="@+id/leftGuideline" @@ -195,14 +199,14 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:orientation="horizontal" - app:layout_constraintGuide_end="@dimen/biometric_dialog_border_padding" /> + app:layout_constraintGuide_end="40dp" /> <androidx.constraintlayout.widget.Guideline android:id="@+id/topGuideline" android:layout_width="0dp" android:layout_height="0dp" android:orientation="horizontal" - app:layout_constraintGuide_percent="0.25" /> + app:layout_constraintGuide_begin="119dp" /> <com.android.systemui.biometrics.BiometricPromptLottieViewWrapper android:id="@+id/biometric_icon" @@ -212,7 +216,7 @@ app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" - app:layout_constraintVertical_bias="0.8" + app:layout_constraintVertical_bias="1.0" tools:srcCompat="@tools:sample/avatars" /> <com.android.systemui.biometrics.BiometricPromptLottieViewWrapper diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml index fe8f2fff550a..50786c515002 100644 --- a/packages/SystemUI/res/values/dimens.xml +++ b/packages/SystemUI/res/values/dimens.xml @@ -1085,7 +1085,7 @@ <dimen name="remote_input_history_extra_height">60dp</dimen> <!-- Biometric Dialog values --> - <dimen name="biometric_dialog_face_icon_size">64dp</dimen> + <dimen name="biometric_dialog_face_icon_size">54dp</dimen> <dimen name="biometric_dialog_fingerprint_icon_width">80dp</dimen> <dimen name="biometric_dialog_fingerprint_icon_height">80dp</dimen> <dimen name="biometric_dialog_button_negative_max_width">160dp</dimen> @@ -1103,6 +1103,22 @@ <dimen name="biometric_dialog_width">240dp</dimen> <dimen name="biometric_dialog_height">240dp</dimen> + <!-- Dimensions for biometric prompt panel padding --> + <dimen name="biometric_prompt_small_horizontal_guideline_padding">344dp</dimen> + <dimen name="biometric_prompt_udfps_horizontal_guideline_padding">114dp</dimen> + <dimen name="biometric_prompt_udfps_mid_guideline_padding">409dp</dimen> + <dimen name="biometric_prompt_medium_horizontal_guideline_padding">640dp</dimen> + <dimen name="biometric_prompt_medium_mid_guideline_padding">330dp</dimen> + + <!-- Dimensions for biometric prompt icon padding --> + <dimen name="biometric_prompt_portrait_small_bottom_padding">60dp</dimen> + <dimen name="biometric_prompt_portrait_medium_bottom_padding">160dp</dimen> + <dimen name="biometric_prompt_portrait_large_screen_bottom_padding">176dp</dimen> + <dimen name="biometric_prompt_landscape_small_bottom_padding">192dp</dimen> + <dimen name="biometric_prompt_landscape_small_horizontal_padding">145dp</dimen> + <dimen name="biometric_prompt_landscape_medium_bottom_padding">148dp</dimen> + <dimen name="biometric_prompt_landscape_medium_horizontal_padding">125dp</dimen> + <!-- Dimensions for biometric prompt custom content view. --> <dimen name="biometric_prompt_logo_size">32dp</dimen> <dimen name="biometric_prompt_content_corner_radius">28dp</dimen> diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/BiometricViewBinder.kt b/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/BiometricViewBinder.kt index b2ade4fa1e8a..76d46ed9889f 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/BiometricViewBinder.kt +++ b/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/BiometricViewBinder.kt @@ -288,12 +288,14 @@ object BiometricViewBinder { // set padding launch { viewModel.promptPadding.collect { promptPadding -> - view.setPadding( - promptPadding.left, - promptPadding.top, - promptPadding.right, - promptPadding.bottom - ) + if (!constraintBp()) { + view.setPadding( + promptPadding.left, + promptPadding.top, + promptPadding.right, + promptPadding.bottom + ) + } } } diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/BiometricViewSizeBinder.kt b/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/BiometricViewSizeBinder.kt index e3c0cba42e2d..f380746105ed 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/BiometricViewSizeBinder.kt +++ b/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/BiometricViewSizeBinder.kt @@ -20,7 +20,6 @@ import android.animation.Animator import android.animation.AnimatorSet import android.animation.ValueAnimator import android.graphics.Outline -import android.graphics.Rect import android.transition.AutoTransition import android.transition.TransitionManager import android.util.TypedValue @@ -47,17 +46,14 @@ import com.android.systemui.biometrics.Utils import com.android.systemui.biometrics.ui.viewmodel.PromptPosition import com.android.systemui.biometrics.ui.viewmodel.PromptSize import com.android.systemui.biometrics.ui.viewmodel.PromptViewModel -import com.android.systemui.biometrics.ui.viewmodel.isBottom import com.android.systemui.biometrics.ui.viewmodel.isLarge import com.android.systemui.biometrics.ui.viewmodel.isLeft import com.android.systemui.biometrics.ui.viewmodel.isMedium import com.android.systemui.biometrics.ui.viewmodel.isNullOrNotSmall -import com.android.systemui.biometrics.ui.viewmodel.isRight import com.android.systemui.biometrics.ui.viewmodel.isSmall -import com.android.systemui.biometrics.ui.viewmodel.isTop import com.android.systemui.lifecycle.repeatWhenAttached import com.android.systemui.res.R -import kotlin.math.min +import kotlin.math.abs import kotlinx.coroutines.flow.combine import kotlinx.coroutines.launch @@ -97,8 +93,6 @@ object BiometricViewSizeBinder { if (constraintBp()) { val leftGuideline = view.requireViewById<Guideline>(R.id.leftGuideline) val rightGuideline = view.requireViewById<Guideline>(R.id.rightGuideline) - val bottomGuideline = view.requireViewById<Guideline>(R.id.bottomGuideline) - val topGuideline = view.requireViewById<Guideline>(R.id.topGuideline) val midGuideline = view.findViewById<Guideline>(R.id.midGuideline) val iconHolderView = view.requireViewById<View>(R.id.biometric_icon) @@ -121,165 +115,12 @@ object BiometricViewSizeBinder { val largeConstraintSet = ConstraintSet() largeConstraintSet.clone(mediumConstraintSet) + largeConstraintSet.constrainMaxWidth(R.id.panel, view.width) // TODO: Investigate better way to handle 180 rotations val flipConstraintSet = ConstraintSet() - flipConstraintSet.clone(mediumConstraintSet) - flipConstraintSet.connect( - R.id.scrollView, - ConstraintSet.START, - R.id.midGuideline, - ConstraintSet.START - ) - flipConstraintSet.connect( - R.id.scrollView, - ConstraintSet.END, - R.id.rightGuideline, - ConstraintSet.END - ) - flipConstraintSet.setHorizontalBias(R.id.biometric_icon, .2f) - - // Round the panel outline - panelView.outlineProvider = - object : ViewOutlineProvider() { - override fun getOutline(view: View, outline: Outline) { - outline.setRoundRect( - 0, - 0, - view.width, - view.height + cornerRadiusPx, - cornerRadiusPx.toFloat() - ) - } - } view.doOnLayout { - val windowBounds = windowManager.maximumWindowMetrics.bounds - val bottomInset = - windowManager.maximumWindowMetrics.windowInsets - .getInsets(WindowInsets.Type.navigationBars()) - .bottom - - // TODO: Move to viewmodel - fun measureBounds(position: PromptPosition) { - val density = windowManager.currentWindowMetrics.density - val width = min((640 * density).toInt(), windowBounds.width()) - - var left = -1 - var right = -1 - var bottom = -1 - var mid = -1 - - when { - position.isTop -> { - // Round bottom corners - panelView.outlineProvider = - object : ViewOutlineProvider() { - override fun getOutline(view: View, outline: Outline) { - outline.setRoundRect( - 0, - -cornerRadiusPx, - view.width, - view.height, - cornerRadiusPx.toFloat() - ) - } - } - left = windowBounds.centerX() - width / 2 + viewModel.promptMargin - right = windowBounds.centerX() - width / 2 + viewModel.promptMargin - bottom = iconHolderView.centerY() * 2 - iconHolderView.centerY() / 4 - } - position.isBottom -> { - // Round top corners - panelView.outlineProvider = - object : ViewOutlineProvider() { - override fun getOutline(view: View, outline: Outline) { - outline.setRoundRect( - 0, - 0, - view.width, - view.height + cornerRadiusPx, - cornerRadiusPx.toFloat() - ) - } - } - - left = windowBounds.centerX() - width / 2 - right = windowBounds.centerX() - width / 2 - bottom = if (view.isLandscape()) bottomInset else 0 - } - position.isLeft -> { - // Round right corners - panelView.outlineProvider = - object : ViewOutlineProvider() { - override fun getOutline(view: View, outline: Outline) { - outline.setRoundRect( - -cornerRadiusPx, - 0, - view.width, - view.height, - cornerRadiusPx.toFloat() - ) - } - } - - left = 0 - mid = (windowBounds.width() * .85).toInt() / 2 - right = windowBounds.width() - (windowBounds.width() * .85).toInt() - bottom = if (view.isLandscape()) bottomInset else 0 - } - position.isRight -> { - // Round left corners - panelView.outlineProvider = - object : ViewOutlineProvider() { - override fun getOutline(view: View, outline: Outline) { - outline.setRoundRect( - 0, - 0, - view.width + cornerRadiusPx, - view.height, - cornerRadiusPx.toFloat() - ) - } - } - - left = windowBounds.width() - (windowBounds.width() * .85).toInt() - right = 0 - bottom = if (view.isLandscape()) bottomInset else 0 - mid = windowBounds.width() - (windowBounds.width() * .85).toInt() / 2 - } - } - - val bounds = Rect(left, mid, right, bottom) - if (bounds.shouldAdjustLeftGuideline()) { - leftGuideline.setGuidelineBegin(bounds.left) - smallConstraintSet.setGuidelineBegin(leftGuideline.id, bounds.left) - mediumConstraintSet.setGuidelineBegin(leftGuideline.id, bounds.left) - } - if (bounds.shouldAdjustRightGuideline()) { - rightGuideline.setGuidelineEnd(bounds.right) - smallConstraintSet.setGuidelineEnd(rightGuideline.id, bounds.right) - mediumConstraintSet.setGuidelineEnd(rightGuideline.id, bounds.right) - } - if (bounds.shouldAdjustBottomGuideline()) { - bottomGuideline.setGuidelineEnd(bounds.bottom) - smallConstraintSet.setGuidelineEnd(bottomGuideline.id, bounds.bottom) - mediumConstraintSet.setGuidelineEnd(bottomGuideline.id, bounds.bottom) - } - - if (position.isBottom) { - topGuideline.setGuidelinePercent(.25f) - mediumConstraintSet.setGuidelinePercent(topGuideline.id, .25f) - } else { - topGuideline.setGuidelinePercent(0f) - mediumConstraintSet.setGuidelinePercent(topGuideline.id, 0f) - } - - if (mid != -1 && midGuideline != null) { - midGuideline.setGuidelineBegin(mid) - } - } - fun setVisibilities(size: PromptSize) { viewsToHideWhenSmall.forEach { it.showContentOrHide(forceHide = size.isSmall) } largeConstraintSet.setVisibility(iconHolderView.id, View.GONE) @@ -297,36 +138,151 @@ object BiometricViewSizeBinder { } } + fun roundCorners(size: PromptSize, position: PromptPosition) { + var left = 0 + var top = 0 + var right = 0 + var bottom = 0 + when (size) { + PromptSize.SMALL, + PromptSize.MEDIUM -> + when (position) { + PromptPosition.Right -> { + left = 0 + top = 0 + right = view.width + cornerRadiusPx + bottom = view.height + } + PromptPosition.Left -> { + left = -cornerRadiusPx + top = 0 + right = view.width + bottom = view.height + } + PromptPosition.Top -> { + left = 0 + top = -cornerRadiusPx + right = panelView.width + bottom = view.height + } + PromptPosition.Bottom -> { + left = 0 + top = 0 + right = panelView.width + bottom = view.height + cornerRadiusPx + } + } + PromptSize.LARGE -> { + left = 0 + top = 0 + right = view.width + bottom = view.height + } + } + + // Round the panel outline + panelView.outlineProvider = + object : ViewOutlineProvider() { + override fun getOutline(view: View, outline: Outline) { + outline.setRoundRect( + left, + top, + right, + bottom, + cornerRadiusPx.toFloat() + ) + } + } + } + view.repeatWhenAttached { var currentSize: PromptSize? = null lifecycleScope.launch { + viewModel.guidelineBounds.collect { bounds -> + if (bounds.left >= 0) { + mediumConstraintSet.setGuidelineBegin(leftGuideline.id, bounds.left) + smallConstraintSet.setGuidelineBegin(leftGuideline.id, bounds.left) + } else if (bounds.left < 0) { + mediumConstraintSet.setGuidelineEnd( + leftGuideline.id, + abs(bounds.left) + ) + smallConstraintSet.setGuidelineEnd( + leftGuideline.id, + abs(bounds.left) + ) + } + + if (bounds.right >= 0) { + mediumConstraintSet.setGuidelineEnd(rightGuideline.id, bounds.right) + smallConstraintSet.setGuidelineEnd(rightGuideline.id, bounds.right) + } else if (bounds.right < 0) { + mediumConstraintSet.setGuidelineBegin( + rightGuideline.id, + abs(bounds.right) + ) + smallConstraintSet.setGuidelineBegin( + rightGuideline.id, + abs(bounds.right) + ) + } + + if (midGuideline != null) { + if (bounds.bottom >= 0) { + midGuideline.setGuidelineEnd(bounds.bottom) + mediumConstraintSet.setGuidelineEnd( + midGuideline.id, + bounds.bottom + ) + } else if (bounds.bottom < 0) { + midGuideline.setGuidelineBegin(abs(bounds.bottom)) + mediumConstraintSet.setGuidelineBegin( + midGuideline.id, + abs(bounds.bottom) + ) + } + } + } + } + + lifecycleScope.launch { combine(viewModel.position, viewModel.size, ::Pair).collect { (position, size) -> view.doOnAttach { + setVisibilities(size) + if (position.isLeft) { - flipConstraintSet.applyTo(view) - } else if (position.isRight) { - mediumConstraintSet.applyTo(view) + if (size.isSmall) { + flipConstraintSet.clone(smallConstraintSet) + } else { + flipConstraintSet.clone(mediumConstraintSet) + } + + // Move all content to other panel + flipConstraintSet.connect( + R.id.scrollView, + ConstraintSet.START, + R.id.midGuideline, + ConstraintSet.START + ) + flipConstraintSet.connect( + R.id.scrollView, + ConstraintSet.END, + R.id.rightGuideline, + ConstraintSet.END + ) } - measureBounds(position) - setVisibilities(size) + roundCorners(size, position) + when { size.isSmall -> { - val ratio = - if (view.isLandscape()) { - (windowBounds.height() - - bottomInset - - viewModel.promptMargin) - .toFloat() / windowBounds.height() - } else { - (windowBounds.height() - viewModel.promptMargin) - .toFloat() / windowBounds.height() - } - smallConstraintSet.setVerticalBias(iconHolderView.id, ratio) - - smallConstraintSet.applyTo(view as ConstraintLayout?) + if (position.isLeft) { + flipConstraintSet.applyTo(view) + } else { + smallConstraintSet.applyTo(view) + } } size.isMedium && currentSize.isSmall -> { val autoTransition = AutoTransition() @@ -338,7 +294,19 @@ object BiometricViewSizeBinder { view, autoTransition ) - mediumConstraintSet.applyTo(view) + + if (position.isLeft) { + flipConstraintSet.applyTo(view) + } else { + mediumConstraintSet.applyTo(view) + } + } + size.isMedium -> { + if (position.isLeft) { + flipConstraintSet.applyTo(view) + } else { + mediumConstraintSet.applyTo(view) + } } size.isLarge -> { val autoTransition = AutoTransition() @@ -551,20 +519,6 @@ private fun View.showContentOrHide(forceHide: Boolean = false) { } } -private fun View.centerX(): Int { - return (x + width / 2).toInt() -} - -private fun View.centerY(): Int { - return (y + height / 2).toInt() -} - -private fun Rect.shouldAdjustLeftGuideline(): Boolean = left != -1 - -private fun Rect.shouldAdjustRightGuideline(): Boolean = right != -1 - -private fun Rect.shouldAdjustBottomGuideline(): Boolean = bottom != -1 - private fun View.asVerticalAnimator( duration: Long, toY: Float, diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/PromptIconViewBinder.kt b/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/PromptIconViewBinder.kt index d8265c7d40e8..66b7d7afb8c4 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/PromptIconViewBinder.kt +++ b/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/PromptIconViewBinder.kt @@ -37,7 +37,6 @@ import com.android.systemui.util.kotlin.Utils.Companion.toQuint import com.android.systemui.util.kotlin.Utils.Companion.toTriple import com.android.systemui.util.kotlin.sample import kotlinx.coroutines.flow.combine -import kotlinx.coroutines.flow.first import kotlinx.coroutines.launch /** Sub-binder for [BiometricPromptLayout.iconView]. */ @@ -127,14 +126,22 @@ object PromptIconViewBinder { if (constraintBp() && position != Rect()) { val iconParams = iconView.layoutParams as ConstraintLayout.LayoutParams - if (position.left != -1) { + if (position.left != 0) { iconParams.endToEnd = ConstraintSet.UNSET iconParams.leftMargin = position.left } - if (position.top != -1) { + if (position.top != 0) { iconParams.bottomToBottom = ConstraintSet.UNSET iconParams.topMargin = position.top } + if (position.right != 0) { + iconParams.startToStart = ConstraintSet.UNSET + iconParams.rightMargin = position.right + } + if (position.bottom != 0) { + iconParams.topToTop = ConstraintSet.UNSET + iconParams.bottomMargin = position.bottom + } iconView.layoutParams = iconParams } } diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/PromptIconViewModel.kt b/packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/PromptIconViewModel.kt index d0c140b353e2..8dbed5f2e323 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/PromptIconViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/PromptIconViewModel.kt @@ -94,25 +94,76 @@ constructor( params.naturalDisplayHeight, rotation.ordinal ) - rotatedBounds + Rect( + rotatedBounds.left, + rotatedBounds.top, + params.logicalDisplayWidth - rotatedBounds.right, + params.logicalDisplayHeight - rotatedBounds.bottom + ) } .distinctUntilChanged() val iconPosition: Flow<Rect> = - combine(udfpsSensorBounds, promptViewModel.size, promptViewModel.modalities) { - sensorBounds, - size, - modalities -> - // If not Udfps, icon does not change from default layout position - if (!modalities.hasUdfps) { - Rect() // Empty rect, don't offset from default position - } else if (size.isSmall) { - // When small with Udfps, only set horizontal position - Rect(sensorBounds.left, -1, sensorBounds.right, -1) - } else { - sensorBounds + combine( + udfpsSensorBounds, + promptViewModel.size, + promptViewModel.position, + promptViewModel.modalities + ) { sensorBounds, size, position, modalities -> + when (position) { + PromptPosition.Bottom -> + if (size.isSmall) { + Rect(0, 0, 0, promptViewModel.portraitSmallBottomPadding) + } else if (size.isMedium && modalities.hasUdfps) { + Rect(0, 0, 0, sensorBounds.bottom) + } else if (size.isMedium) { + Rect(0, 0, 0, promptViewModel.portraitMediumBottomPadding) + } else { + // Large screen + Rect(0, 0, 0, promptViewModel.portraitLargeScreenBottomPadding) + } + PromptPosition.Right -> + if (size.isSmall || modalities.hasFaceOnly) { + Rect( + 0, + 0, + promptViewModel.landscapeSmallHorizontalPadding, + promptViewModel.landscapeSmallBottomPadding + ) + } else if (size.isMedium && modalities.hasUdfps) { + Rect(0, 0, sensorBounds.right, sensorBounds.bottom) + } else { + // SFPS + Rect( + 0, + 0, + promptViewModel.landscapeMediumHorizontalPadding, + promptViewModel.landscapeMediumBottomPadding + ) + } + PromptPosition.Left -> + if (size.isSmall || modalities.hasFaceOnly) { + Rect( + promptViewModel.landscapeSmallHorizontalPadding, + 0, + 0, + promptViewModel.landscapeSmallBottomPadding + ) + } else if (size.isMedium && modalities.hasUdfps) { + Rect(sensorBounds.left, 0, 0, sensorBounds.bottom) + } else { + // SFPS + Rect( + promptViewModel.landscapeMediumHorizontalPadding, + 0, + 0, + promptViewModel.landscapeMediumBottomPadding + ) + } + PromptPosition.Top -> Rect() + } } - } + .distinctUntilChanged() /** Whether an error message is currently being shown. */ val showingError = promptViewModel.showingError @@ -162,10 +213,11 @@ constructor( val iconSize: Flow<Pair<Int, Int>> = combine( + promptViewModel.position, activeAuthType, promptViewModel.fingerprintSensorWidth, promptViewModel.fingerprintSensorHeight, - ) { activeAuthType, fingerprintSensorWidth, fingerprintSensorHeight -> + ) { _, activeAuthType, fingerprintSensorWidth, fingerprintSensorHeight -> if (activeAuthType == AuthType.Face) { Pair(promptViewModel.faceIconWidth, promptViewModel.faceIconHeight) } else { diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModel.kt b/packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModel.kt index fbd87fd3a9f5..21ebff4d0b71 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModel.kt @@ -86,6 +86,36 @@ constructor( val faceIconHeight: Int = context.resources.getDimensionPixelSize(R.dimen.biometric_dialog_face_icon_size) + /** Padding for placing icons */ + val portraitSmallBottomPadding = + context.resources.getDimensionPixelSize( + R.dimen.biometric_prompt_portrait_small_bottom_padding + ) + val portraitMediumBottomPadding = + context.resources.getDimensionPixelSize( + R.dimen.biometric_prompt_portrait_medium_bottom_padding + ) + val portraitLargeScreenBottomPadding = + context.resources.getDimensionPixelSize( + R.dimen.biometric_prompt_portrait_large_screen_bottom_padding + ) + val landscapeSmallBottomPadding = + context.resources.getDimensionPixelSize( + R.dimen.biometric_prompt_landscape_small_bottom_padding + ) + val landscapeSmallHorizontalPadding = + context.resources.getDimensionPixelSize( + R.dimen.biometric_prompt_landscape_small_horizontal_padding + ) + val landscapeMediumBottomPadding = + context.resources.getDimensionPixelSize( + R.dimen.biometric_prompt_landscape_medium_bottom_padding + ) + val landscapeMediumHorizontalPadding = + context.resources.getDimensionPixelSize( + R.dimen.biometric_prompt_landscape_medium_horizontal_padding + ) + val fingerprintSensorWidth: Flow<Int> = combine(modalities, udfpsOverlayInteractor.udfpsOverlayParams) { modalities, overlayParams -> @@ -111,9 +141,6 @@ constructor( /** Hint for talkback directional guidance */ val accessibilityHint: Flow<String> = _accessibilityHint.asSharedFlow() - val promptMargin: Int = - context.resources.getDimensionPixelSize(R.dimen.biometric_dialog_border_padding) - private val _isAuthenticating: MutableStateFlow<Boolean> = MutableStateFlow(false) /** If the user is currently authenticating (i.e. at least one biometric is scanning). */ @@ -205,6 +232,66 @@ constructor( } .distinctUntilChanged() + /** Prompt panel size padding */ + private val smallHorizontalGuidelinePadding = + context.resources.getDimensionPixelSize( + R.dimen.biometric_prompt_small_horizontal_guideline_padding + ) + private val udfpsHorizontalGuidelinePadding = + context.resources.getDimensionPixelSize( + R.dimen.biometric_prompt_udfps_horizontal_guideline_padding + ) + private val udfpsMidGuidelinePadding = + context.resources.getDimensionPixelSize( + R.dimen.biometric_prompt_udfps_mid_guideline_padding + ) + private val mediumHorizontalGuidelinePadding = + context.resources.getDimensionPixelSize( + R.dimen.biometric_prompt_medium_horizontal_guideline_padding + ) + private val mediumMidGuidelinePadding = + context.resources.getDimensionPixelSize( + R.dimen.biometric_prompt_medium_mid_guideline_padding + ) + + /** + * Rect for positioning prompt guidelines (left, top, right, mid) + * + * Negative values are used to signify that guideline measuring should be flipped, measuring + * from opposite side of the screen + */ + val guidelineBounds: Flow<Rect> = + combine(size, position, modalities) { size, position, modalities -> + if (position.isBottom) { + Rect(0, 0, 0, 0) + } else if (position.isRight) { + if (size.isSmall) { + Rect(-smallHorizontalGuidelinePadding, 0, 0, 0) + } else if (modalities.hasUdfps) { + Rect(udfpsHorizontalGuidelinePadding, 0, 0, udfpsMidGuidelinePadding) + } else if (modalities.isEmpty) { + // TODO: Temporary fix until no biometric landscape layout is added + Rect(-mediumHorizontalGuidelinePadding, 0, 0, 6) + } else { + Rect(-mediumHorizontalGuidelinePadding, 0, 0, mediumMidGuidelinePadding) + } + } else if (position.isLeft) { + if (size.isSmall) { + Rect(0, 0, -smallHorizontalGuidelinePadding, 0) + } else if (modalities.hasUdfps) { + Rect(0, 0, udfpsHorizontalGuidelinePadding, -udfpsMidGuidelinePadding) + } else if (modalities.isEmpty) { + // TODO: Temporary fix until no biometric landscape layout is added + Rect(0, 0, -mediumHorizontalGuidelinePadding, -6) + } else { + Rect(0, 0, -mediumHorizontalGuidelinePadding, -mediumMidGuidelinePadding) + } + } else { + Rect() + } + } + .distinctUntilChanged() + /** * If the API caller or the user's personal preferences require explicit confirmation after * successful authentication. Confirmation always required when in explicit flow. @@ -424,7 +511,7 @@ constructor( isAuthenticated, promptSelectorInteractor.isCredentialAllowed, ) { size, _, authState, credentialAllowed -> - size.isNotSmall && authState.isNotAuthenticated && credentialAllowed + size.isMedium && authState.isNotAuthenticated && credentialAllowed } private val history = PromptHistoryImpl() diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/SideFpsOverlayViewModel.kt b/packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/SideFpsOverlayViewModel.kt index cfda75c7851a..b72b1f35595a 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/SideFpsOverlayViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/SideFpsOverlayViewModel.kt @@ -28,6 +28,7 @@ import android.view.WindowManager import android.view.WindowManager.LayoutParams.PRIVATE_FLAG_NO_MOVE_ANIMATION import android.view.WindowManager.LayoutParams.PRIVATE_FLAG_TRUSTED_OVERLAY import com.airbnb.lottie.model.KeyPath +import com.android.systemui.Flags.constraintBp import com.android.systemui.biometrics.Utils import com.android.systemui.biometrics.domain.interactor.BiometricStatusInteractor import com.android.systemui.biometrics.domain.interactor.DisplayStateInteractor @@ -155,17 +156,19 @@ constructor( -> val topLeft = Point(sensorLocation.left, sensorLocation.top) - if (sensorLocation.isSensorVerticalInDefaultOrientation) { - if (displayRotation == DisplayRotation.ROTATION_0) { - topLeft.x -= bounds!!.width() - } else if (displayRotation == DisplayRotation.ROTATION_270) { - topLeft.y -= bounds!!.height() - } - } else { - if (displayRotation == DisplayRotation.ROTATION_180) { - topLeft.y -= bounds!!.height() - } else if (displayRotation == DisplayRotation.ROTATION_270) { - topLeft.x -= bounds!!.width() + if (!constraintBp()) { + if (sensorLocation.isSensorVerticalInDefaultOrientation) { + if (displayRotation == DisplayRotation.ROTATION_0) { + topLeft.x -= bounds!!.width() + } else if (displayRotation == DisplayRotation.ROTATION_270) { + topLeft.y -= bounds!!.height() + } + } else { + if (displayRotation == DisplayRotation.ROTATION_180) { + topLeft.y -= bounds!!.height() + } else if (displayRotation == DisplayRotation.ROTATION_270) { + topLeft.x -= bounds!!.width() + } } } defaultOverlayViewParams.apply { diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/ui/viewmodel/SideFpsOverlayViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/ui/viewmodel/SideFpsOverlayViewModelTest.kt index ae20c703b93d..826d7299201d 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/ui/viewmodel/SideFpsOverlayViewModelTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/ui/viewmodel/SideFpsOverlayViewModelTest.kt @@ -33,6 +33,7 @@ import com.airbnb.lottie.model.KeyPath import com.android.keyguard.KeyguardSecurityModel import com.android.keyguard.KeyguardUpdateMonitor import com.android.settingslib.Utils +import com.android.systemui.Flags.FLAG_CONSTRAINT_BP import com.android.systemui.SysuiTestCase import com.android.systemui.biometrics.FingerprintInteractiveToAuthProvider import com.android.systemui.biometrics.data.repository.FakeBiometricStatusRepository @@ -347,6 +348,7 @@ class SideFpsOverlayViewModelTest : SysuiTestCase() { @Test fun updatesOverlayViewParams_onDisplayRotationChange_xAlignedSensor() { testScope.runTest { + mSetFlagsRule.disableFlags(FLAG_CONSTRAINT_BP) setupTestConfiguration( DeviceConfig.X_ALIGNED, rotation = DisplayRotation.ROTATION_0, @@ -388,6 +390,7 @@ class SideFpsOverlayViewModelTest : SysuiTestCase() { @Test fun updatesOverlayViewParams_onDisplayRotationChange_yAlignedSensor() { testScope.runTest { + mSetFlagsRule.disableFlags(FLAG_CONSTRAINT_BP) setupTestConfiguration( DeviceConfig.Y_ALIGNED, rotation = DisplayRotation.ROTATION_0, |