Android PIN Complexity
HYPR SDK for Android: Android Authenticators
HYPR SDK for Android includes new Personal Identification Number (PIN) rules and a new User Interface (UI).
We use the same layout for enrolling, confirming, and authorizing. If you want just to change the UI and not the behavior, reimplement the .XML
file.
Don't Forget
The app now verifies PIN complexity on the fly during input; if you override this class, you must verify PIN complexity in your own code.
If you change the layout, remember to retain the class types and ids.
User Interface (UI)
Enroll (Create PIN) | Confirm | Authorize |
---|---|---|
![]() | ![]() | ![]() |
A Rule Is Broken | Incorrect PIN on Confirmation | Incorrect PIN on Authorization |
---|---|---|
![]() | ![]() | ![]() |

All three fragments are based on one .XML
file. Fields are set in proper fragments to adjust or customize the view.
hypr_header_layout_button_cancel
: ImageView in thehypr_pin_layout_header
layout that calls the cancel action. Image source is@drawable/hypr_common_view_exit_selector drawables
:
<item android:drawable="@drawable/hypr_common_view_exit_pressed" android:state_pressed="true" /><item android:drawable="@drawable/hypr_common_view_exit_default" />
-
hypr_title_logo
: ImageView with a logo image (in the SDK this is a placeholder). The image source is@drawable/hypr_logo_small_blue
-
hypr_pin_layout_title
: Title of the fragment:- Enroll:
@string/hypr_enroll_pin_title
- Confirm:
@string/hypr_confirm_pin_title
- Authorize:
@string/hypr_authorize_pin_title
- Enroll:
-
hypr_pin_layout_hint_second
: Hint about the repeating rule@string/hypr_enroll_pin_repeating_error
, which is in the Enroll fragment -
hypr_pin_layout_hint_first
: Hint about the sequential rule@string/hypr_enroll_pin_sequence_error
, which is in the Enroll fragment -
hypr_pin_layout_prompt
: Prompt for PIN input,@string/hypr_authorize_pin_hint
, which is in the Authorize fragment
Hints are instances of com.hypr.hyprandroidpinframework.ui.screens.pinentry.HintTextView
and its action when the rule(s) are violated: change of font color and addition of the X icon; the image source is @drawable/hypr_common_cross_red_small
-
hypr_pin_layout_input
: The input field should be an instance ofcom.hypr.hyprandroidpinframework.ui.screens.pinentry.PinTextEditor
;hypr_pin_layout_input
works withcom.hypr.hyprandroidpinframework.ui.screens.pinentry.SecretWatcher
and masks the input;hypr_pin_layout_input
will auto-submit upon typing the sixth digit unless a rule is broken -
hypr_pin_keyboard_separator
: The line to which the top of the keyboard is anchored
Fragment Layout
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/hypr_pin_background"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/hyprColorWhiteBackground"
tools:context="com.hypr.hyprandroidpinframework.ui.activities.HyprPinActivity"
tools:ignore="Overdraw">
<androidx.constraintlayout.widget.Guideline
android:id="@+id/hypr_pin_header_separator"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
app:layout_constraintGuide_percent="0.12" />
<include
android:id="@+id/hypr_pin_layout_header"
layout="@layout/hypr_common_screen_header"
android:layout_width="match_parent"
android:layout_height="0dp"
app:layout_constraintBottom_toTopOf="@id/hypr_pin_header_separator"
app:layout_constraintTop_toTopOf="parent" />
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:orientation="vertical"
app:layout_constraintBottom_toTopOf="@id/hypr_pin_layout_input"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="@id/hypr_pin_header_separator">
<TextView
android:id="@+id/hypr_pin_layout_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_horizontal"
android:text="TITLE"
android:textColor="@color/hyprColorHyprBlueDark"
android:textSize="@dimen/hypr_complex_pin_hint_text_size"
android:textStyle="bold"
tools:ignore="HardcodedText" />
<com.hypr.hyprandroidpinframework.ui.screens.pinentry.HintTextView
android:id="@+id/hypr_pin_layout_hint_second"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:drawablePadding="@dimen/hypr_complex_pin_rule_violation_img_padding"
android:text="@string/hypr_enroll_pin_repeating_error"
android:textColor="@color/hyprColorGrey"
android:textSize="@dimen/hypr_complex_pin_hint_text_size"
app:defaultPromptColor="@color/hyprColorGrey"
app:failPromptColor="@color/hyprColorRedFail"
app:failPromptLeftIcon="@drawable/hypr_common_cross_red_small"
tools:ignore="UseCompatTextViewDrawableXml" />
<com.hypr.hyprandroidpinframework.ui.screens.pinentry.HintTextView
android:id="@+id/hypr_pin_layout_hint_first"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text="@string/hypr_enroll_pin_sequence_error"
android:textColor="@color/hyprColorGrey"
android:textSize="@dimen/hypr_complex_pin_hint_text_size"
app:defaultPromptColor="@color/hyprColorGrey"
app:failPromptColor="@color/hyprColorRedFail"
app:failPromptLeftIcon="@drawable/hypr_common_cross_red_small" />
<com.hypr.hyprandroidpinframework.ui.screens.pinentry.HintTextView
android:id="@+id/hypr_pin_layout_prompt"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_horizontal"
android:labelFor="@+id/hypr_pin_layout_input"
android:text="@string/hypr_authorize_pin_hint"
android:textColor="@color/hyprColorGrey"
android:textSize="@dimen/hypr_complex_pin_hint_text_size"
app:defaultPromptColor="@color/hyprColorGrey"
app:failPromptColor="@color/hyprColorRedFail"
app:failPromptLeftIcon="@drawable/hypr_common_cross_red_small" />
</LinearLayout>
<com.hypr.hyprandroidpinframework.ui.screens.pinentry.PinTextEditor
android:id="@+id/hypr_pin_layout_input"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:layout_marginStart="@dimen/hypr_complex_pin_input_center"
android:layout_marginEnd="@dimen/hypr_complex_pin_input_center"
android:backgroundTint="@color/hyprColorLogoBlue"
android:inputType="number"
android:letterSpacing="0.3"
android:maxLength="6"
android:text="******"
android:textColor="@color/hyprColorLogoBlue"
android:textSize="@dimen/hypr_complex_pin_input_text_size"
app:layout_constraintBottom_toBottomOf="@+id/hypr_pin_keyboard_separator"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="@id/hypr_pin_header_separator"
android:textColorHint="@color/hyprColorTrans"
android:importantForAccessibility="yes"
android:accessibilityTraversalAfter="@+id/hypr_pin_layout_title"
tools:ignore="HardcodedText" />
<androidx.constraintlayout.widget.Guideline
android:id="@+id/hypr_pin_keyboard_separator"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
app:layout_constraintGuide_percent="0.6" />
<View
android:id="@+id/hypr_pin_view_bottom_anchor"
android:layout_width="match_parent"
android:layout_height="@dimen/hypr_common_keyboard_divider_bar_height"
app:layout_constraintBottom_toBottomOf="parent" />
<include layout="@layout/hypr_numeric_keyboard_view_layout" />
</androidx.constraintlayout.widget.ConstraintLayout>
Rules
- Repeating rules: PINs may have no more than two consecutive numbers. Example: 11632 will pass (two repeating 1s), but 145558 will not (three repeating 5s).
- Sequential rules: PINs must have no more than two sequential numbers, ascending or descending. Example: 124587 will work, but 123900 and 348765 will not.
- Pattern rules: Repeating patterns in pairs and triplets will also be detected and rejected. Repeating a separate set of pairs will also fail. Example: 123123 or 121212 will both fail; and 112266 will fail.
A message will warn the user if one or more of the rules is broken as they type.
Keyboard
The Android keyboard is implemented in com.hypr.hyprandroidcommon.uiadapter.ui.views.keyboard.HyprNumericKeyboardView
, and uses the hypr_numeric_keyboard_view_layout.xml
layout with labels from hypr_numeric_keyboard_view
.

You can change separate elements as follows:
- Background color:
#E9EAEE
- Default key background color:
#@color/hyprColorWhite
- Backspace key background color:
#FFCBCED5
- Ack key background:
#FF1A73E9
- Button shadow color:
#09000000
Shadow is defined in the hypr_numeric_key_shadow.xml
file.
Mapping for keyLabels
, which extends labels
, is hardcoded:
private val labels = mapOf(
"2" to "ABC",
"3" to "DEF",
"4" to "GHI",
"5" to "JKL",
"6" to "MNO",
"7" to "PQRS",
"8" to "TUV",
"9" to "WXYZ",
"0" to " + "
)
For other buttons we use images:
private val icons = mapOf(
-5 to R.drawable.hypr_common_backspace,
-6 to R.drawable.hypr_common_success_vector
)
Colors
@color/hyprPinInput
: The input field text color (hypr_pin_layout_input
)@color/hyprPinTitle
: The title color (hypr_pin_layout_title
)@color/hyprPinHint
: The default hint color@color/hyprPinHintViolation
: The color of a hint when it is related to the violated rule. The X icon displays in this color@color/hyprHeaderExitDefault
: The default color of the exit X (hypr_header_layout_button_cancel
)@color/hyprHeaderExitPressed
: The pressed color of exit X (hypr_header_layout_button_cancel
)@color/hyprComplexPinDialogLabel
: Error dialog label color
Drawables
@drawable/hypr_logo_header_placeholder
: A placeholder for the logo on the screen header, currently with transparent paths@drawable/hypr_common_view_exit_selector
: A source set in the screen header. It includes the following:
--@drawable/hypr_common_view_exit_default
: The default image selector
--@drawable/hypr_common_view_exit_pressed
: The image for the pressed state@drawable/hypr_cross_red_small
: A small red X shown when the rule is violated@drawable/hypr_numeric_key_ack
: The keyboard success button background (without shadow)@drawable/hypr_numeric_key_backspace
@drawable/hypr_numeric_key_background
Strings
Error Dialog Strings
<string name="hypr_complex_pin_not_confirmed">PINs did not match. Try creating a PIN again.</string>
<string name="hypr_complex_pin_not_match_title">Incorrect PIN</string>
<string name="hypr_complex_pin_not_match">Please check your PIN and try again!</string>
@string/hypr_complex_pin_not_confirmed
: A message shown in the Confirm fragment when the PIN does not match what was previously set.@string/hypr_complex_pin_not_match_title
: The title on a dialog shown when the authorization PIN does not pass.@string/hypr_complex_pin_not_match
: A message shown when the authorization PIN does not pass.
Other Strings
<string name="hypr_enroll_pin_title">Create a 6 digit PIN</string>
<string name="hypr_confirm_pin_title">Confirm PIN</string>
<string name="hypr_authorize_pin_title">Pin Authentication</string>
<string name="hypr_authorize_pin_hint">Enter your 6 digit PIN</string>
<string name="hypr_enroll_pin_repeating_error">No more than 2 repeating numbers</string>
<string name="hypr_enroll_pin_sequence_error">No more than 2 consecutive numbers</string>
<string name="hypr_content_description_enroll_pin_input">Input for create your 6 digit PIN.</string>
<string name="hypr_content_description_confirm_pin_input">Input for confirm 6 digit PIN.</string>
<string name="hypr_content_description_auth_pin_input">Input for enter 6 digit authorization PIN.</string>
@string/hypr_enroll_pin_title
@string/hypr_confirm_pin_title
: The fragment title@string/hypr_authorize_pin_title
@string/hypr_authorize_pin_hint
: The Enroll prompt@string/hypr_enroll_pin_repeating_error
: The Enroll hint and error message when the repeating rule is violated (color changed to@color/hyprPinHintViolation
)@string/hypr_enroll_pin_sequence_error
: An Enroll hint and error message when the sequential rule is violated (color changed to@color/hyprPinHintViolation
)
Reminder
If you want to override the rules, you must override the entire fragment.
@string/hypr_content_description_enroll_pin_input
@string/hypr_content_description_confirm_pin_input
: A content description set into the proper fragment for the accessibility feature@string/hypr_content_description_auth_pin_input
Updated 4 months ago