Android FIDO PIN Authenticator

HYPR SDK for Android

This document provides a description of and integration guidelines for HYPR Android PIN Authenticator interface.

DescriptionValue
Standard PIN AAID (Authenticator ID)0045#0001
Library NameHyprPin-<version>.aar

πŸ“˜

PIN DROP

The PIN Authenticator's PIN is not the same as the PIN on your lock screen.

PIN Attributes

DescriptionValue
PIN Length6
Number of Attempts for Authentication3

Integration

🚧

DO THIS FIRST

Before any HYPR authenticator is added to a project, be sure to follow the HYPR SDK for Android Quick Start setup and integration.

The HYPR PIN Authenticator specifically requires the following app/commonlibraries/build.gradle file additions:

dependencies {
  ...
    // HYPR Common Dependency
    api(name: 'HyprCommon', version: "${hyprVersion}", ext: 'aar')
    // HYPR Crypto
    api(name: "crypto", version: "${cryptoVersion}", ext: 'aar') { transitive = true }
    // HYPR PIN Authenticator Dependency
    api(name: 'HyprPin', version: "${hyprVersion}", ext: 'aar')
  ...
}

User Interface

🚧

PINS MUST MATCH

You will be unable to enroll if there is a mismatch between the PIN and confirmation PIN as seen in the picture below.

1500

The following default authentication confirmation screen displays when a user authenticates.

1440

To enable/disable the confirmation screen for authentication and/or transactions, locate overrides.xml in app/<module_name>/src/main/res/values and append it with the following content:

<string name="hypr_pin_show_auth_conf_override">true</string>
<string name="hypr_pin_show_trans_conf_override">true</string>

UI Customization

We can customize the PIN Authenticator screens via XML overrides. Each screen has a corresponding XML layout file. By creating a layout file with the same name as the one you want to override, the SDK will present that layout file instead.

🚧

ID CHECK

If you are overriding the layout files, please make sure to keep all the android:ids with their respective view from the layout that you want to override as the SDK uses those IDs.

Overriding the PIN Enrollment Screen

Create a file called hypr_fragment_pin_double_enroll.xml in app/<module_name>/src/main/res/layout and you can now alter/add views and change the properties of those views.

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@drawable/hypr_common_auth_primary_background"
    tools:context=".ui.activities.HyprPinActivity"
    tools:ignore="Overdraw">

    <include layout="@layout/hypr_view_pin_overlay_title" />

    <RelativeLayout
        android:id="@+id/hypr_pin_layout_movable_parent"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_alignParentStart="true"
        android:layout_alignParentTop="true">

        <LinearLayout
            android:id="@+id/hypr_pin_layout_pin_one"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_above="@+id/hypr_pin_layout_pin_entry_text_one"
            android:layout_gravity="center_horizontal"
            android:gravity="center_horizontal"
            android:orientation="horizontal">

            <com.hypr.hyprandroidcommon.uiadapter.ui.views.HyprStatefullEditText
                android:id="@+id/hypr_pin_editview_pin_one_first"
                style="@style/PinEditTextStyle"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:textColor="@color/hyprColorPinFocusedLine" />

            <com.hypr.hyprandroidcommon.uiadapter.ui.views.HyprStatefullEditText
                android:id="@+id/hypr_pin_editview_pin_one_second"
                style="@style/PinEditTextStyle"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:textColor="@color/hyprColorPinFocusedLine" />

            <com.hypr.hyprandroidcommon.uiadapter.ui.views.HyprStatefullEditText
                android:id="@+id/hypr_pin_editview_pin_one_third"
                style="@style/PinEditTextStyle"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:textColor="@color/hyprColorPinFocusedLine" />

            <com.hypr.hyprandroidcommon.uiadapter.ui.views.HyprStatefullEditText
                android:id="@+id/hypr_pin_editview_pin_one_fourth"
                style="@style/PinEditTextStyle"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:textColor="@color/hyprColorPinFocusedLine" />

            <com.hypr.hyprandroidcommon.uiadapter.ui.views.HyprStatefullEditText
                android:id="@+id/hypr_pin_editview_pin_one_fifth"
                style="@style/PinEditTextStyle"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:textColor="@color/hyprColorPinFocusedLine" />

            <com.hypr.hyprandroidcommon.uiadapter.ui.views.HyprStatefullEditText
                android:id="@+id/hypr_pin_editview_pin_one_sixth"
                style="@style/PinEditTextStyle"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:textColor="@color/hyprColorPinFocusedLine" />
        </LinearLayout>

        <LinearLayout
            android:id="@+id/hypr_pin_layout_pin_entry_text_one"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_above="@+id/hypr_pin_layout_pin_two"
            android:layout_marginBottom="@dimen/hypr_pin_double_bottom_margin"
            android:layout_marginTop="@dimen/hypr_pin_double_top_margin"
            android:gravity="center_horizontal"
            android:orientation="vertical">

            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:fontFamily="@font/sharetech_regular"
                android:gravity="center_horizontal"
                android:text="@string/hypr_pin_entry_text"
                android:textColor="@color/hyprColorTextPrimary"
                android:textSize="@dimen/hypr_pin_entry_hint_size" />

        </LinearLayout>

        <LinearLayout
            android:id="@+id/hypr_pin_layout_pin_two"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_above="@+id/hypr_pin_layout_wrong_pin"
            android:layout_gravity="center_horizontal"
            android:gravity="center_horizontal"
            android:orientation="horizontal">

            <com.hypr.hyprandroidcommon.uiadapter.ui.views.HyprStatefullEditText
                android:id="@+id/hypr_pin_editview_pin_two_first"
                style="@style/PinEditTextStyle"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:textColor="@color/hyprColorPinFocusedLine" />

            <com.hypr.hyprandroidcommon.uiadapter.ui.views.HyprStatefullEditText
                android:id="@+id/hypr_pin_editview_pin_two_second"
                style="@style/PinEditTextStyle"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:textColor="@color/hyprColorPinFocusedLine" />

            <com.hypr.hyprandroidcommon.uiadapter.ui.views.HyprStatefullEditText
                android:id="@+id/hypr_pin_editview_pin_two_third"
                style="@style/PinEditTextStyle"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:textColor="@color/hyprColorPinFocusedLine" />

            <com.hypr.hyprandroidcommon.uiadapter.ui.views.HyprStatefullEditText
                android:id="@+id/hypr_pin_editview_pin_two_fourth"
                style="@style/PinEditTextStyle"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:textColor="@color/hyprColorPinFocusedLine" />

            <com.hypr.hyprandroidcommon.uiadapter.ui.views.HyprStatefullEditText
                android:id="@+id/hypr_pin_editview_pin_two_fifth"
                style="@style/PinEditTextStyle"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:textColor="@color/hyprColorPinFocusedLine" />

            <com.hypr.hyprandroidcommon.uiadapter.ui.views.HyprStatefullEditText
                android:id="@+id/hypr_pin_editview_pin_two_sixth"
                style="@style/PinEditTextStyle"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:textColor="@color/hyprColorPinFocusedLine" />
        </LinearLayout>

        <LinearLayout
            android:id="@+id/hypr_pin_layout_wrong_pin"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_above="@+id/hypr_pin_layout_pin_entry_text_two"
            android:layout_gravity="center_horizontal"
            android:layout_marginTop="@dimen/hypr_pin_double_top_margin"
            android:gravity="center_horizontal"
            android:orientation="horizontal"
            android:visibility="gone"
            tools:ignore="UseCompoundDrawables">

            <ImageView
                android:layout_width="@dimen/hypr_pin_wrong_icon_size"
                android:layout_height="@dimen/hypr_pin_wrong_icon_size"
                android:layout_gravity="center_vertical"
                android:layout_marginEnd="@dimen/hypr_pin_wrong_icon_margin_end"
                android:contentDescription="@string/hypr_todo_content_description"
                android:src="@drawable/hypr_pin_warning_icon" />

            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_gravity="center_vertical"
                android:fontFamily="@font/sharetech_regular"
                android:text="@string/hypr_error_display_pin_mismatch"
                android:textColor="@color/hyprColorRedFail"
                android:textSize="@dimen/hypr_pin_entry_hint_size" />
        </LinearLayout>

        <LinearLayout
            android:id="@+id/hypr_pin_layout_pin_entry_text_two"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_above="@+id/hypr_pin_view_pin_entry_text_buffer"
            android:layout_marginBottom="@dimen/hypr_pin_double_bottom_margin"
            android:gravity="center_horizontal"
            android:orientation="vertical">

            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:gravity="center_horizontal"
                android:text="@string/hypr_pin_confirm_text"
                android:textColor="@color/hyprColorTextPrimary"
                android:textSize="@dimen/hypr_pin_entry_hint_size" />

        </LinearLayout>

        <View
            android:id="@+id/hypr_pin_view_pin_entry_text_buffer"
            android:layout_width="match_parent"
            android:layout_height="@dimen/hypr_pin_buffer_view_height"
            android:layout_above="@+id/hypr_pin_view_button_layout"
            android:visibility="visible" />

        <RelativeLayout
            android:id="@+id/hypr_pin_view_button_layout"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_above="@+id/hypr_pin_view_bottom_anchor_2">

            <include
                layout="@layout/hypr_common_view_ok_button"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_marginBottom="@dimen/hypr_common_selection_button_margin_bottom" />

            <include
                android:id="@+id/hypr_pin_layout_button_cancel"
                layout="@layout/hypr_common_view_cancel_button"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_marginBottom="@dimen/hypr_common_selection_button_margin_bottom" />
        </RelativeLayout>

        <View
            android:id="@+id/hypr_pin_view_bottom_anchor_2"
            android:layout_width="match_parent"
            android:layout_height="@dimen/hypr_common_keyboard_divider_bar_height"
            android:layout_alignParentBottom="true"
            android:background="@color/hyprColorKeyboardAnchorView"
            android:visibility="invisible" />

    </RelativeLayout>

    <include layout="@layout/hypr_common_view_keyboard_layout" />

</RelativeLayout>
1226

PIN Enrollment UI Override

Overriding the Authentication Screen

In the same location, create a file called hypr_fragment_pin_single_verify.xml to alter/add views and change the properties of those views.

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@drawable/hypr_common_auth_primary_background"
    tools:context=".ui.activities.HyprPinActivity"
    tools:ignore="Overdraw">

    <include layout="@layout/hypr_view_pin_overlay_title" />

    <RelativeLayout
        android:id="@+id/hypr_layout_transaction"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:visibility="gone">

        <TextView
            android:id="@+id/hypr_text_transaction_amount"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerHorizontal="true"
            android:gravity="center_horizontal"
            android:textColor="@color/hyprColorGeneralInfoDesc"
            android:textSize="@dimen/hypr_common_general_rectangle_desc_text_size"
            android:visibility="gone" />

        <TextView
            android:id="@+id/hypr_text_transaction_type"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_below="@+id/hypr_text_transaction_amount"
            android:layout_centerHorizontal="true"
            android:gravity="center_horizontal"
            android:textColor="@color/hyprColorGeneralInfoDesc"
            android:textSize="@dimen/hypr_common_general_rectangle_desc_text_size"
            android:visibility="gone" />

        <TextView
            android:id="@+id/hypr_text_transaction_text"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_below="@+id/hypr_text_transaction_type"
            android:layout_centerHorizontal="true"
            android:gravity="center_horizontal"
            android:textColor="@color/hyprColorGeneralInfoDesc"
            android:textSize="@dimen/hypr_common_general_rectangle_desc_text_size"
            android:visibility="gone" />
    </RelativeLayout>

    <RelativeLayout
        android:id="@+id/hypr_pin_layout_movable_parent"
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <LinearLayout
            android:id="@+id/hypr_pin_layout_pin_one"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_above="@+id/hypr_pin_layout_pin_entry_layout"
            android:layout_gravity="center_horizontal"
            android:gravity="center_horizontal"
            android:orientation="horizontal">

            <com.hypr.hyprandroidcommon.uiadapter.ui.views.HyprStatefullEditText
                android:id="@+id/hypr_pin_editview_pin_one_first"
                style="@style/PinEditTextStyle"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:textColor="@color/hyprColorPinFocusedLine" />

            <com.hypr.hyprandroidcommon.uiadapter.ui.views.HyprStatefullEditText
                android:id="@+id/hypr_pin_editview_pin_one_second"
                style="@style/PinEditTextStyle"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:textColor="@color/hyprColorPinFocusedLine" />

            <com.hypr.hyprandroidcommon.uiadapter.ui.views.HyprStatefullEditText
                android:id="@+id/hypr_pin_editview_pin_one_third"
                style="@style/PinEditTextStyle"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:textColor="@color/hyprColorPinFocusedLine" />

            <com.hypr.hyprandroidcommon.uiadapter.ui.views.HyprStatefullEditText
                android:id="@+id/hypr_pin_editview_pin_one_fourth"
                style="@style/PinEditTextStyle"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:textColor="@color/hyprColorPinFocusedLine" />

            <com.hypr.hyprandroidcommon.uiadapter.ui.views.HyprStatefullEditText
                android:id="@+id/hypr_pin_editview_pin_one_fifth"
                style="@style/PinEditTextStyle"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:textColor="@color/hyprColorPinFocusedLine" />

            <com.hypr.hyprandroidcommon.uiadapter.ui.views.HyprStatefullEditText
                android:id="@+id/hypr_pin_editview_pin_one_sixth"
                style="@style/PinEditTextStyle"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:textColor="@color/hyprColorPinFocusedLine" />
        </LinearLayout>

        <LinearLayout
            android:id="@+id/hypr_pin_layout_pin_entry_layout"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_above="@+id/hypr_pin_layout_button_cancel"
            android:layout_marginBottom="@dimen/hypr_pin_text_margin_bottom"
            android:layout_marginTop="@dimen/hypr_pin_text_margin_top"
            android:gravity="center_horizontal"
            android:orientation="vertical">

            <TextView
                android:id="@+id/hypr_pin_layout_pin_entry_text"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:gravity="center_horizontal"
                android:text="@string/hypr_pin_entry_text"
                android:textColor="@color/hyprColorTextPrimary"
                android:textSize="@dimen/hypr_pin_entry_hint_size" />

        </LinearLayout>

        <include
            android:id="@+id/hypr_pin_layout_button_cancel"
            layout="@layout/hypr_common_view_cancel_button"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_above="@+id/hypr_pin_view_pin_entry_text_buffer"
            android:layout_marginBottom="@dimen/hypr_pin_cancel_margin_bottom" />

        <View
            android:id="@+id/hypr_pin_view_pin_entry_text_buffer"
            android:layout_width="match_parent"
            android:layout_height="@dimen/hypr_pin_buffer_view_height"
            android:layout_above="@+id/hypr_pin_view_bottom_anchor"
            android:visibility="visible" />

        <View
            android:id="@+id/hypr_pin_view_bottom_anchor"
            android:layout_width="match_parent"
            android:layout_height="@dimen/hypr_common_keyboard_divider_bar_height"
            android:layout_alignParentBottom="true"
            android:background="@color/hyprColorKeyboardAnchorView"
            android:visibility="invisible" />

    </RelativeLayout>

    <include layout="@layout/hypr_common_view_keyboard_layout" />

</RelativeLayout>
700

PIN Authentication UI override.

PIN Authenticator Configuration

Configurable values in the PIN Authenticator include the following:

  • The number of attempts the user has to enter the correct PIN
  • The time in milliseconds before the keyboard is automatically opened

To configure these values, create integers.xml in the app/<module_name>/src/main/res/values directory with the desired values:

<?xml version="1.0" encoding="utf-8"?>
<resources>
  
    // Amount of authentication attempts allowed before authentication fails
    // Default value is 3, minimum value is 1.
    <integer name="hypr_pin_authentication_retry_limit">3</integer>
    
    // Amount of time in milliseconds before keyboard is automatically opened
    // If set to -1, keyboard is not automatically opened
    <integer name="hypr_pin_keyboard_auto_open_delay_ms">250</integer>

</resources>

Integrating Additional Functionality

Additional functionality may also be added to the PIN enrollment and authentication fragments outside of UI customization.

Customizing the PIN Enrollment Fragment

Here is an example of the HyprPinDoubleEnrollFragment subclass:

package your.package.path;

public class CustomPinEnrollFragment extends HyprPinDoubleEnrollFragment {

  @Override
  public void onViewCreated(@NonNull View view,
                            @Nullable Bundle bundle) {
    super.onViewCreated(view, bundle);
    // If you want, find the views and attach listeners to them
  }
  
  @Override 
  public int getPinSize() {
    // Modify the PIN length
  }
  
  @Override
  public int getFragmentLayout() {
    // Return the layout file you want to use 
    // By default, the layout file here would be: R.layout.hypr_fragment_pin_double_enroll
  }
}

🚧

ID CHECK

If you are overriding getFrameLayout() to display a different layout file, please make sure to keep all the android:ids from the layout that you are replacing as the SDK uses those IDs.

To use your own HyprPinDoubleEnrollFragment subclass, make sure it is included in overrides.xml within the app/<module_name>/src/main/res/values directory. Provide the package path to your HyprPinDoubleEnrollFragment subclass along with the subclass name as the string value in overrides.xml.

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <string name="hypr_pin_double_enroll_fragment_class_override">your.package.path.CustomPinEnrollFragment</string>
</resources>

Customizing the PIN Authentication Screen

Following is an example of the HyprPinSingleVerifyFragment subclass:

package your.package.path;

public class CustomPinVerificationFragment extends HyprPinSingleVerifyFragment {
  
  @Override
  public void onViewCreated(@NonNull View view,
                            @Nullable Bundle bundle) {
    super.onViewCreated(view, bundle);
    // If you want, find the views and attach listeners to them
  }
  
  @Override 
  public int getPinSize() {
    // Modify the PIN length
  }
  
  @Override
  public int getFragmentLayout() {
    // Return the layout file you want to use 
    // By default, the layout file here would be: R.layout.hypr_fragment_pin_single_verify
  }
}

🚧

ID CHECK

If you are overriding getFrameLayout() to display a different layout file, please make sure to keep all the android:ids from the layout that you are replacing as the SDK uses those IDs.

To use your own HyprPinSingleVerifyFragment subclass, make sure it is included in overrides.xml within the app/<module_name>/src/main/res/values/ directory. Provide the package path to your HyprPinSingleVerifyFragment subclass along with the subclass name as the string value in overrides.xml.

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <string name="hypr_pin_single_verify_fragment_class_override">your.package.path.CustomPinVerificationFragment</string>
</resources>