diff options
| author | 2023-06-06 14:53:53 -0700 | |
|---|---|---|
| committer | 2023-08-22 21:21:44 +0000 | |
| commit | aafe0849b9ae77a2d802e26c380aa92bac4d2bda (patch) | |
| tree | 775e565274d64850d7de2a6bf42d1c6e6ba2018b | |
| parent | 6162ea96867142ee7ebffb6dd2655deded0c6f68 (diff) | |
Allow to customize BiometricsPromt for automative builds
- Allow to inflate different layouts for credential pin and password
- Use the same layout for credential pin and password so that the
layout stays the same for non-automative builds
- Specify the layout of CredentialPasswordView in its layout file instead of programmatically so that it can be customized easily
- Introduce IPinPad, which will used in automative variation of auth_credential_pin_view
Bug: 276918288
Test: manual
Change-Id: I3aec4081144b51014cdaf1cde70a04c8b2006240
13 files changed, 419 insertions, 255 deletions
diff --git a/packages/SystemUI/res/layout-land/auth_credential_password_pin_content_view.xml b/packages/SystemUI/res/layout-land/auth_credential_password_pin_content_view.xml new file mode 100644 index 000000000000..24222f7642be --- /dev/null +++ b/packages/SystemUI/res/layout-land/auth_credential_password_pin_content_view.xml @@ -0,0 +1,101 @@ +<!-- +  ~ Copyright (C) 2019 The Android Open Source Project +  ~ +  ~ Licensed under the Apache License, Version 2.0 (the "License"); +  ~ you may not use this file except in compliance with the License. +  ~ You may obtain a copy of the License at +  ~ +  ~      http://www.apache.org/licenses/LICENSE-2.0 +  ~ +  ~ Unless required by applicable law or agreed to in writing, software +  ~ distributed under the License is distributed on an "AS IS" BASIS, +  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +  ~ See the License for the specific language governing permissions and +  ~ limitations under the License. +  --> + +<merge xmlns:android="http://schemas.android.com/apk/res/android"> + +  <RelativeLayout +    android:id="@+id/auth_credential_header" +    style="?headerStyle" +    android:layout_width="0dp" +    android:layout_height="wrap_content" +    android:layout_weight="1"> + +    <ImageView +        android:id="@+id/icon" +        style="?headerIconStyle" +        android:layout_alignParentLeft="true" +        android:layout_alignParentTop="true" +        android:contentDescription="@null"/> + +    <TextView +        android:id="@+id/title" +        style="?titleTextAppearance" +        android:layout_below="@id/icon" +        android:layout_width="match_parent" +        android:layout_height="wrap_content" /> + +    <TextView +        android:id="@+id/subtitle" +        style="?subTitleTextAppearance" +        android:layout_below="@id/title" +        android:layout_alignParentLeft="true" +        android:layout_width="match_parent" +        android:layout_height="wrap_content" /> + +    <TextView +        android:id="@+id/description" +        style="?descriptionTextAppearance" +        android:layout_below="@id/subtitle" +        android:layout_alignParentLeft="true" +        android:layout_width="match_parent" +        android:layout_height="wrap_content" /> + +  </RelativeLayout> + +  <FrameLayout +      android:id="@+id/auth_credential_input" +      android:layout_width="0dp" +      android:layout_height="match_parent" +      android:layout_weight="1" +      android:orientation="vertical"> + +    <LinearLayout +        android:layout_width="wrap_content" +        android:layout_height="wrap_content" +        android:layout_gravity="center" +        android:orientation="vertical"> + +      <ImeAwareEditText +          android:id="@+id/lockPassword" +          style="?passwordTextAppearance" +          android:layout_width="208dp" +          android:layout_height="wrap_content" +          android:layout_gravity="center_horizontal" +          android:imeOptions="actionNext|flagNoFullscreen|flagForceAscii" +          android:inputType="textPassword" +          android:minHeight="48dp"/> + +      <TextView +          android:id="@+id/error" +          style="?errorTextAppearance" +          android:layout_gravity="center_horizontal" +          android:layout_width="wrap_content" +          android:layout_height="wrap_content"/> +    </LinearLayout> + +    <Button +        android:id="@+id/emergencyCallButton" +        style="@style/AuthCredentialEmergencyButtonStyle" +        android:layout_width="wrap_content" +        android:layout_height="wrap_content" +        android:visibility="gone" +        android:layout_gravity="center_horizontal|bottom" +        android:layout_marginTop="12dp" +        android:layout_marginBottom="12dp" +        android:text="@string/work_challenge_emergency_button_text"/> +  </FrameLayout> + +</merge> diff --git a/packages/SystemUI/res/layout-land/auth_credential_password_view.xml b/packages/SystemUI/res/layout-land/auth_credential_password_view.xml index e439f775f8ea..8ac7583088f9 100644 --- a/packages/SystemUI/res/layout-land/auth_credential_password_view.xml +++ b/packages/SystemUI/res/layout-land/auth_credential_password_view.xml @@ -23,84 +23,6 @@      android:elevation="@dimen/biometric_dialog_elevation"      android:theme="?app:attr/lockPinPasswordStyle"> -    <RelativeLayout -        android:id="@+id/auth_credential_header" -        style="?headerStyle" -        android:layout_width="wrap_content" -        android:layout_height="match_parent"> - -        <ImageView -            android:id="@+id/icon" -            style="?headerIconStyle" -            android:layout_alignParentLeft="true" -            android:layout_alignParentTop="true" -            android:contentDescription="@null"/> - -        <TextView -            android:id="@+id/title" -            style="?titleTextAppearance" -            android:layout_below="@id/icon" -            android:layout_width="match_parent" -            android:layout_height="wrap_content" /> - -        <TextView -            android:id="@+id/subtitle" -            style="?subTitleTextAppearance" -            android:layout_below="@id/title" -            android:layout_alignParentLeft="true" -            android:layout_width="match_parent" -            android:layout_height="wrap_content" /> - -        <TextView -            android:id="@+id/description" -            style="?descriptionTextAppearance" -            android:layout_below="@id/subtitle" -            android:layout_alignParentLeft="true" -            android:layout_width="match_parent" -            android:layout_height="wrap_content" /> - -    </RelativeLayout> - -    <FrameLayout -        android:id="@+id/auth_credential_input" -        android:layout_width="match_parent" -        android:layout_height="wrap_content" -        android:orientation="vertical"> - -        <LinearLayout -            android:layout_width="wrap_content" -            android:layout_height="wrap_content" -            android:layout_gravity="center_horizontal|top" -            android:orientation="vertical"> - -            <ImeAwareEditText -                android:id="@+id/lockPassword" -                style="?passwordTextAppearance" -                android:layout_width="208dp" -                android:layout_height="wrap_content" -                android:layout_gravity="center_horizontal" -                android:imeOptions="actionNext|flagNoFullscreen|flagForceAscii" -                android:inputType="textPassword" -                android:minHeight="48dp"/> - -            <TextView -                android:id="@+id/error" -                style="?errorTextAppearance" -                android:layout_gravity="center_horizontal" -                android:layout_width="wrap_content" -                android:layout_height="wrap_content"/> -        </LinearLayout> - -        <Button -            android:id="@+id/emergencyCallButton" -            style="@style/AuthCredentialEmergencyButtonStyle" -            android:layout_width="wrap_content" -            android:layout_height="wrap_content" -            android:visibility="gone" -            android:layout_gravity="center_horizontal|bottom" -            android:layout_marginTop="12dp" -            android:layout_marginBottom="12dp" -            android:text="@string/work_challenge_emergency_button_text"/> -    </FrameLayout> +    <include layout="@layout/auth_credential_password_pin_content_view" />  </com.android.systemui.biometrics.ui.CredentialPasswordView>
\ No newline at end of file diff --git a/packages/SystemUI/res/layout-land/auth_credential_pin_view.xml b/packages/SystemUI/res/layout-land/auth_credential_pin_view.xml new file mode 100644 index 000000000000..8ac7583088f9 --- /dev/null +++ b/packages/SystemUI/res/layout-land/auth_credential_pin_view.xml @@ -0,0 +1,28 @@ +<!-- +  ~ Copyright (C) 2020 The Android Open Source Project +  ~ +  ~ Licensed under the Apache License, Version 2.0 (the "License"); +  ~ you may not use this file except in compliance with the License. +  ~ You may obtain a copy of the License at +  ~ +  ~      http://www.apache.org/licenses/LICENSE-2.0 +  ~ +  ~ Unless required by applicable law or agreed to in writing, software +  ~ distributed under the License is distributed on an "AS IS" BASIS, +  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +  ~ See the License for the specific language governing permissions and +  ~ limitations under the License. +  --> + +<com.android.systemui.biometrics.ui.CredentialPasswordView +    xmlns:android="http://schemas.android.com/apk/res/android" +    xmlns:app="http://schemas.android.com/apk/res-auto" +    android:layout_width="match_parent" +    android:layout_height="match_parent" +    android:orientation="horizontal" +    android:elevation="@dimen/biometric_dialog_elevation" +    android:theme="?app:attr/lockPinPasswordStyle"> + +    <include layout="@layout/auth_credential_password_pin_content_view" /> + +</com.android.systemui.biometrics.ui.CredentialPasswordView>
\ No newline at end of file diff --git a/packages/SystemUI/res/layout/auth_credential_password_pin_content_view.xml b/packages/SystemUI/res/layout/auth_credential_password_pin_content_view.xml new file mode 100644 index 000000000000..11284fd2237b --- /dev/null +++ b/packages/SystemUI/res/layout/auth_credential_password_pin_content_view.xml @@ -0,0 +1,104 @@ +<!-- +  ~ Copyright (C) 2019 The Android Open Source Project +  ~ +  ~ Licensed under the Apache License, Version 2.0 (the "License"); +  ~ you may not use this file except in compliance with the License. +  ~ You may obtain a copy of the License at +  ~ +  ~      http://www.apache.org/licenses/LICENSE-2.0 +  ~ +  ~ Unless required by applicable law or agreed to in writing, software +  ~ distributed under the License is distributed on an "AS IS" BASIS, +  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +  ~ See the License for the specific language governing permissions and +  ~ limitations under the License. +  --> + +<merge xmlns:android="http://schemas.android.com/apk/res/android"> + +  <ScrollView +    android:layout_width="match_parent" +    android:layout_height="wrap_content"> + +    <RelativeLayout +      android:id="@+id/auth_credential_header" +      style="?headerStyle" +      android:layout_width="match_parent" +      android:layout_height="wrap_content" +      android:paddingBottom="0dp"> + +      <ImageView +          android:id="@+id/icon" +          style="?headerIconStyle" +          android:layout_alignParentLeft="true" +          android:layout_alignParentTop="true" +          android:contentDescription="@null" /> + +      <TextView +          android:id="@+id/title" +          style="?titleTextAppearance" +          android:layout_width="match_parent" +          android:layout_height="wrap_content" +          android:layout_below="@id/icon" /> + +      <TextView +          android:id="@+id/subtitle" +          style="?subTitleTextAppearance" +          android:layout_width="match_parent" +          android:layout_height="wrap_content" +          android:layout_below="@id/title" /> + +      <TextView +          android:id="@+id/description" +          style="?descriptionTextAppearance" +          android:layout_width="match_parent" +          android:layout_height="wrap_content" +          android:layout_below="@id/subtitle" /> + +    </RelativeLayout> + +  </ScrollView> + +  <FrameLayout +      android:id="@+id/auth_credential_input" +      android:layout_width="match_parent" +      android:layout_height="match_parent" +      android:orientation="vertical"> + +    <LinearLayout +        android:layout_width="match_parent" +        android:layout_height="wrap_content" +        android:layout_gravity="center" +        android:orientation="vertical"> + +      <ImeAwareEditText +          android:id="@+id/lockPassword" +          style="?passwordTextAppearance" +          android:layout_width="208dp" +          android:layout_height="wrap_content" +          android:layout_gravity="center_horizontal" +          android:imeOptions="actionNext|flagNoFullscreen|flagForceAscii" +          android:inputType="textPassword" +          android:minHeight="48dp"/> + +      <TextView +          android:id="@+id/error" +          style="?errorTextAppearance" +          android:layout_gravity="center_horizontal" +          android:layout_width="match_parent" +          android:layout_height="wrap_content"/> +    </LinearLayout> + +    <Button +        android:id="@+id/emergencyCallButton" +        style="@style/AuthCredentialEmergencyButtonStyle" +        android:layout_width="wrap_content" +        android:layout_height="wrap_content" +        android:visibility="gone" +        android:layout_gravity="center_horizontal|bottom" +        android:layout_marginTop="12dp" +        android:layout_marginBottom="12dp" +        android:text="@string/work_challenge_emergency_button_text"/> +  </FrameLayout> + +</merge> diff --git a/packages/SystemUI/res/layout/auth_credential_password_view.xml b/packages/SystemUI/res/layout/auth_credential_password_view.xml index 9336845f20f7..f8d9a87d5e54 100644 --- a/packages/SystemUI/res/layout/auth_credential_password_view.xml +++ b/packages/SystemUI/res/layout/auth_credential_password_view.xml @@ -23,88 +23,6 @@      android:orientation="vertical"      android:theme="?app:attr/lockPinPasswordStyle"> -    <ScrollView -        android:id="@+id/auth_credential_header" -        android:layout_width="match_parent" -        android:layout_height="wrap_content"> - -        <RelativeLayout -            style="?headerStyle" -            android:layout_width="match_parent" -            android:layout_height="wrap_content"> - -            <ImageView -                android:id="@+id/icon" -                style="?headerIconStyle" -                android:layout_alignParentLeft="true" -                android:layout_alignParentTop="true" -                android:contentDescription="@null" /> - -            <TextView -                android:id="@+id/title" -                style="?titleTextAppearance" -                android:layout_width="match_parent" -                android:layout_height="wrap_content" -                android:layout_below="@id/icon" /> - -            <TextView -                android:id="@+id/subtitle" -                style="?subTitleTextAppearance" -                android:layout_width="match_parent" -                android:layout_height="wrap_content" -                android:layout_below="@id/title" /> - -            <TextView -                android:id="@+id/description" -                style="?descriptionTextAppearance" -                android:layout_width="match_parent" -                android:layout_height="wrap_content" -                android:layout_below="@id/subtitle" /> - -        </RelativeLayout> - -    </ScrollView> - -    <FrameLayout -        android:id="@+id/auth_credential_input" -        android:layout_width="match_parent" -        android:layout_height="wrap_content" -        android:orientation="vertical"> - -        <LinearLayout -            android:layout_width="match_parent" -            android:layout_height="wrap_content" -            android:layout_gravity="center_horizontal|top" -            android:orientation="vertical"> - -            <ImeAwareEditText -                android:id="@+id/lockPassword" -                style="?passwordTextAppearance" -                android:layout_width="208dp" -                android:layout_height="wrap_content" -                android:layout_gravity="center_horizontal" -                android:imeOptions="actionNext|flagNoFullscreen|flagForceAscii" -                android:inputType="textPassword" -                android:minHeight="48dp"/> - -            <TextView -                android:id="@+id/error" -                style="?errorTextAppearance" -                android:layout_gravity="center_horizontal" -                android:layout_width="match_parent" -                android:layout_height="wrap_content"/> -        </LinearLayout> - -        <Button -            android:id="@+id/emergencyCallButton" -            style="@style/AuthCredentialEmergencyButtonStyle" -            android:layout_width="wrap_content" -            android:layout_height="wrap_content" -            android:visibility="gone" -            android:layout_gravity="center_horizontal|bottom" -            android:layout_marginTop="12dp" -            android:layout_marginBottom="12dp" -            android:text="@string/work_challenge_emergency_button_text"/> -    </FrameLayout> +    <include layout="@layout/auth_credential_password_pin_content_view" />  </com.android.systemui.biometrics.ui.CredentialPasswordView>
\ No newline at end of file diff --git a/packages/SystemUI/res/layout/auth_credential_pin_view.xml b/packages/SystemUI/res/layout/auth_credential_pin_view.xml new file mode 100644 index 000000000000..a1cf807af088 --- /dev/null +++ b/packages/SystemUI/res/layout/auth_credential_pin_view.xml @@ -0,0 +1,28 @@ +<!-- +  ~ Copyright (C) 2019 The Android Open Source Project +  ~ +  ~ Licensed under the Apache License, Version 2.0 (the "License"); +  ~ you may not use this file except in compliance with the License. +  ~ You may obtain a copy of the License at +  ~ +  ~      http://www.apache.org/licenses/LICENSE-2.0 +  ~ +  ~ Unless required by applicable law or agreed to in writing, software +  ~ distributed under the License is distributed on an "AS IS" BASIS, +  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +  ~ See the License for the specific language governing permissions and +  ~ limitations under the License. +  --> + +<com.android.systemui.biometrics.ui.CredentialPasswordView +    xmlns:android="http://schemas.android.com/apk/res/android" +    xmlns:app="http://schemas.android.com/apk/res-auto" +    android:layout_width="match_parent" +    android:layout_height="match_parent" +    android:elevation="@dimen/biometric_dialog_elevation" +    android:orientation="vertical" +    android:theme="?app:attr/lockPinPasswordStyle"> + +  <include layout="@layout/auth_credential_password_pin_content_view" /> + +</com.android.systemui.biometrics.ui.CredentialPasswordView>
\ No newline at end of file diff --git a/packages/SystemUI/res/values/ids.xml b/packages/SystemUI/res/values/ids.xml index fd1de25e8174..04eae64013b3 100644 --- a/packages/SystemUI/res/values/ids.xml +++ b/packages/SystemUI/res/values/ids.xml @@ -223,6 +223,9 @@      <!-- Communal mode -->      <item type="id" name="communal_widget_wrapper" /> +    <!-- Values assigned to the views in Biometrics Prompt --> +    <item type="id" name="pin_pad"/> +      <!--      Used to tag views programmatically added to the smartspace area so they can be more easily      removed later. diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java index 802a550c4d29..7464c8803c99 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java +++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java @@ -499,6 +499,8 @@ public class AuthContainerView extends LinearLayout                          R.layout.auth_credential_pattern_view, null, false);                  break;              case Utils.CREDENTIAL_PIN: +                mCredentialView = factory.inflate(R.layout.auth_credential_pin_view, null, false); +                break;              case Utils.CREDENTIAL_PASSWORD:                  mCredentialView = factory.inflate(                          R.layout.auth_credential_password_view, null, false); diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/ui/CredentialPasswordView.kt b/packages/SystemUI/src/com/android/systemui/biometrics/ui/CredentialPasswordView.kt index 709fe855fbfc..6c5cc4835787 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/ui/CredentialPasswordView.kt +++ b/packages/SystemUI/src/com/android/systemui/biometrics/ui/CredentialPasswordView.kt @@ -8,11 +8,8 @@ import android.view.View  import android.view.WindowInsets  import android.view.WindowInsets.Type.ime  import android.view.accessibility.AccessibilityManager -import android.widget.ImageView -import android.widget.ImeAwareEditText  import android.widget.LinearLayout  import android.widget.TextView -import androidx.core.view.isGone  import com.android.systemui.R  import com.android.systemui.biometrics.AuthPanelController  import com.android.systemui.biometrics.ui.binder.CredentialViewBinder @@ -22,14 +19,6 @@ import com.android.systemui.biometrics.ui.viewmodel.CredentialViewModel  class CredentialPasswordView(context: Context, attrs: AttributeSet?) :      LinearLayout(context, attrs), CredentialView, View.OnApplyWindowInsetsListener { -    private lateinit var titleView: TextView -    private lateinit var subtitleView: TextView -    private lateinit var descriptionView: TextView -    private lateinit var iconView: ImageView -    private lateinit var passwordField: ImeAwareEditText -    private lateinit var credentialHeader: View -    private lateinit var credentialInput: View -      private var bottomInset: Int = 0      private val accessibilityManager by lazy { @@ -48,90 +37,32 @@ class CredentialPasswordView(context: Context, attrs: AttributeSet?) :      override fun onFinishInflate() {          super.onFinishInflate() - -        titleView = requireViewById(R.id.title) -        subtitleView = requireViewById(R.id.subtitle) -        descriptionView = requireViewById(R.id.description) -        iconView = requireViewById(R.id.icon) -        passwordField = requireViewById(R.id.lockPassword) -        credentialHeader = requireViewById(R.id.auth_credential_header) -        credentialInput = requireViewById(R.id.auth_credential_input) -          setOnApplyWindowInsetsListener(this)      } -    override fun onLayout(changed: Boolean, l: Int, t: Int, r: Int, b: Int) { -        super.onLayout(changed, left, top, right, bottom) - -        val inputLeftBound: Int -        var inputTopBound: Int -        var headerRightBound = right -        var headerTopBounds = top -        var headerBottomBounds = bottom -        val subTitleBottom: Int = if (subtitleView.isGone) titleView.bottom else subtitleView.bottom -        val descBottom = if (descriptionView.isGone) subTitleBottom else descriptionView.bottom -        if (resources.configuration.orientation == ORIENTATION_LANDSCAPE) { -            inputTopBound = (bottom - credentialInput.height) / 2 -            inputLeftBound = (right - left) / 2 -            headerRightBound = inputLeftBound -            if (descriptionView.bottom > headerBottomBounds) { -                headerTopBounds -= iconView.bottom.coerceAtMost(bottomInset) -                credentialHeader.layout(left, headerTopBounds, headerRightBound, bottom) -            } -        } else { -            inputTopBound = descBottom + (bottom - descBottom - credentialInput.height) / 2 -            inputLeftBound = (right - left - credentialInput.width) / 2 - -            if (bottom - inputTopBound < credentialInput.height) { -                inputTopBound = bottom - credentialInput.height -            } - -            if (descriptionView.bottom > inputTopBound) { -                credentialHeader.layout(left, headerTopBounds, headerRightBound, inputTopBound) -            } -        } - -        credentialInput.layout(inputLeftBound, inputTopBound, right, bottom) -    } - -    override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) { -        super.onMeasure(widthMeasureSpec, heightMeasureSpec) - -        val newWidth = MeasureSpec.getSize(widthMeasureSpec) -        val newHeight = MeasureSpec.getSize(heightMeasureSpec) - bottomInset - -        setMeasuredDimension(newWidth, newHeight) - -        val halfWidthSpec = MeasureSpec.makeMeasureSpec(width / 2, MeasureSpec.AT_MOST) -        val fullHeightSpec = MeasureSpec.makeMeasureSpec(newHeight, MeasureSpec.UNSPECIFIED) -        if (resources.configuration.orientation == ORIENTATION_LANDSCAPE) { -            measureChildren(halfWidthSpec, fullHeightSpec) -        } else { -            measureChildren(widthMeasureSpec, fullHeightSpec) -        } -    } -      override fun onApplyWindowInsets(v: View, insets: WindowInsets): WindowInsets { -        val bottomInsets = insets.getInsets(ime()) -        if (bottomInset != bottomInsets.bottom) { -            bottomInset = bottomInsets.bottom - -            if (bottomInset > 0 && resources.configuration.orientation == ORIENTATION_LANDSCAPE) { -                titleView.isSingleLine = true -                titleView.ellipsize = TextUtils.TruncateAt.MARQUEE -                titleView.marqueeRepeatLimit = -1 -                // select to enable marquee unless a screen reader is enabled -                titleView.isSelected = accessibilityManager?.shouldMarquee() ?: false -            } else { -                titleView.isSingleLine = false -                titleView.ellipsize = null -                // select to enable marquee unless a screen reader is enabled -                titleView.isSelected = false +        val imeBottomInset = insets.getInsets(ime()).bottom +        if (bottomInset != imeBottomInset) { +            val titleView: TextView? = findViewById(R.id.title) +            if (titleView != null) { +                if ( +                    bottomInset > 0 && resources.configuration.orientation == ORIENTATION_LANDSCAPE +                ) { +                    titleView.isSingleLine = true +                    titleView.ellipsize = TextUtils.TruncateAt.MARQUEE +                    titleView.marqueeRepeatLimit = -1 +                    // select to enable marquee unless a screen reader is enabled +                    titleView.isSelected = accessibilityManager.shouldMarquee() +                } else { +                    titleView.isSingleLine = false +                    titleView.ellipsize = null +                    // select to enable marquee unless a screen reader is enabled +                    titleView.isSelected = false +                }              } - -            requestLayout()          } -        return insets +        setPadding(paddingLeft, paddingTop, paddingRight, imeBottomInset) +        return insets.inset(0, 0, 0, imeBottomInset)      }  } diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/ui/IPinPad.kt b/packages/SystemUI/src/com/android/systemui/biometrics/ui/IPinPad.kt new file mode 100644 index 000000000000..cf6865c0fe8e --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/biometrics/ui/IPinPad.kt @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *      http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.biometrics.ui + +/** + * Interface for PinPad in auth_credential_pin_view. This is needed when a custom pin pad is + * preferred to the IME To use a PinPad, one needs to implement IPinPad interface and provide it in + * auth_credential_pin_view and specify the id as [pin_pad] + */ +interface IPinPad { +    fun setPinPadClickListener(pinPadClickListener: PinPadClickListener) +} + +/** The call back interface for onClick event in the view. */ +interface PinPadClickListener { +    /** +     * One of the digit key has been clicked. +     * +     * @param digit A String representing a digit between 0 and 9. +     */ +    fun onDigitKeyClick(digit: String?) + +    /** The backspace key has been clicked. */ +    fun onBackspaceClick() + +    /** The enter key has been clicked. */ +    fun onEnterKeyClick() +} diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/CredentialPasswordViewBinder.kt b/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/CredentialPasswordViewBinder.kt index c27d71522c2f..996b62e084cb 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/CredentialPasswordViewBinder.kt +++ b/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/CredentialPasswordViewBinder.kt @@ -15,6 +15,7 @@ import androidx.lifecycle.repeatOnLifecycle  import com.android.systemui.R  import com.android.systemui.biometrics.ui.CredentialPasswordView  import com.android.systemui.biometrics.ui.CredentialView +import com.android.systemui.biometrics.ui.IPinPad  import com.android.systemui.biometrics.ui.viewmodel.CredentialViewModel  import com.android.systemui.lifecycle.repeatWhenAttached  import kotlinx.coroutines.awaitCancellation @@ -53,13 +54,19 @@ object CredentialPasswordViewBinder {                  }              )              passwordField.setOnKeyListener(OnBackButtonListener(onBackInvokedCallback)) - +            val pinPadView = view.findViewById(R.id.pin_pad) as? IPinPad +            if (pinPadView != null) { +                PinPadViewBinder.bind(pinPadView, view) +            }              repeatOnLifecycle(Lifecycle.State.STARTED) {                  // dismiss on a valid credential check                  launch {                      viewModel.validatedAttestation.collect { attestation ->                          if (attestation != null) { -                            imeManager.hideSoftInputFromWindow(view.windowToken, 0 /* flags */) +                            imeManager.hideSoftInputFromWindow( +                                view.windowToken, +                                0 // flag +                            )                              host.onCredentialMatched(attestation)                          } else {                              passwordField.setText("") diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/CredentialViewBinder.kt b/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/CredentialViewBinder.kt index 4ac9f967920f..25fe61916644 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/CredentialViewBinder.kt +++ b/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/CredentialViewBinder.kt @@ -47,6 +47,7 @@ object CredentialViewBinder {          val descriptionView: TextView = view.requireViewById(R.id.description)          val iconView: ImageView? = view.findViewById(R.id.icon)          val errorView: TextView = view.requireViewById(R.id.error) +        val cancelButton: Button? = view.findViewById(R.id.cancel_button)          val emergencyButtonView: Button = view.requireViewById(R.id.emergencyCallButton)          var errorTimer: Job? = null @@ -60,7 +61,7 @@ object CredentialViewBinder {                      updateForContentDimensions(                          containerWidth,                          containerHeight, -                        0 /* animateDurationMs */ +                        0 // animateDurationMs                      )                  }              } @@ -103,7 +104,18 @@ object CredentialViewBinder {                                  }                              }                          } -                        .collect { errorView.textOrHide = it } +                        .collect { it -> +                            val hasError = !it.isNullOrBlank() +                            errorView.visibility = +                                if (hasError) { +                                    View.VISIBLE +                                } else if (cancelButton != null) { +                                    View.INVISIBLE +                                } else { +                                    View.GONE +                                } +                            errorView.text = if (hasError) it else "" +                        }                  }                  // show an extra dialog if the remaining attempts becomes low @@ -117,6 +129,8 @@ object CredentialViewBinder {              }          } +        cancelButton?.setOnClickListener { host.onCredentialAborted() } +          // bind the auth widget          when (view) {              is CredentialPasswordView -> diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/PinPadViewBinder.kt b/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/PinPadViewBinder.kt new file mode 100644 index 000000000000..906206c27455 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/PinPadViewBinder.kt @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *      http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package com.android.systemui.biometrics.ui.binder + +import android.view.KeyEvent +import android.widget.ImeAwareEditText +import com.android.internal.widget.LockscreenCredential +import com.android.systemui.R +import com.android.systemui.biometrics.ui.CredentialPasswordView +import com.android.systemui.biometrics.ui.IPinPad +import com.android.systemui.biometrics.ui.PinPadClickListener + +/** Binder for IPinPad */ +object PinPadViewBinder { +    /** Implements a PinPadClickListener inside a pin pad */ +    @JvmStatic +    fun bind(view: IPinPad, credentialPasswordView: CredentialPasswordView) { +        val passwordField: ImeAwareEditText = +            credentialPasswordView.requireViewById(R.id.lockPassword) +        view.setPinPadClickListener( +            object : PinPadClickListener { + +                override fun onDigitKeyClick(digit: String?) { +                    passwordField.append(digit) +                } + +                override fun onBackspaceClick() { +                    val pin = LockscreenCredential.createPinOrNone(passwordField.text) +                    if (pin.size() > 0) { +                        passwordField.text.delete( +                            passwordField.selectionEnd - 1, +                            passwordField.selectionEnd +                        ) +                    } +                    pin.zeroize() +                } + +                override fun onEnterKeyClick() { +                    passwordField.dispatchKeyEvent( +                        KeyEvent(0, 0, KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_ENTER, 0) +                    ) +                    passwordField.dispatchKeyEvent( +                        KeyEvent(0, 0, KeyEvent.ACTION_UP, KeyEvent.KEYCODE_ENTER, 0) +                    ) +                } +            } +        ) +    } +}  |