@aparajita/capacitor-biometric-auth 1.0.7 โ†’ 2.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -12,7 +12,7 @@
12
12
  s.author = package['author']
13
13
  s.source = { :git => package['repository']['url'], :tag => s.version.to_s }
14
14
  s.source_files = 'ios/Plugin/**/*.{swift,h,m,c,cc,mm,cpp}'
15
- s.ios.deployment_target = '11.0'
15
+ s.ios.deployment_target = '12.0'
16
16
  s.dependency 'Capacitor'
17
- s.swift_version = '5.0'
17
+ s.swift_version = '5.1'
18
18
  end
package/README.md CHANGED
@@ -1,48 +1,45 @@
1
+ <div class="markdown-body">
2
+
1
3
  # capacitor-biometric-auth
2
4
 
3
- This plugin for [Capacitor 2](https://capacitorjs.com) provides access to native biometry on iOS and Android. In addition, biometry is simulated on the web so you can test your logic without making any changes to your code.
5
+ This plugin for [Capacitor 3](https://capacitorjs.com) provides access to native biometry on iOS and Android. It supports every type of biometry and every configuration option on both platforms. In addition, biometry is simulated on the web so you can test your logic without making any changes to your code.
4
6
 
5
- ๐Ÿ‘‰ **NOTE:** This plugin has only been tested with Capacitor 2.
7
+ ๐Ÿ‘‰ **NOTE:** This plugin only works with Capacitor 3. If you are upgrading from the Capacitor 2 version, note that the plugin name has changed to `BiometricAuth`.
6
8
 
7
9
  ## Installation
8
10
 
9
11
  ```sh
10
- pnpm install @aparajita/capacitor-biometric-auth # 'pnpm add' also works
11
- npm install @aparajita/capacitor-biometric-auth
12
- yarn add @aparajita/capacitor-biometric-auth
12
+ pnpm add @aparajita/capacitor-biometric-auth
13
13
  ```
14
14
 
15
15
  Not using [pnpm](https://pnpm.js.org/)? You owe it to yourself to give it a try. Itโ€™s faster, better with monorepos, and uses *way, way* less disk space than the alternatives.
16
16
 
17
17
  ## Usage
18
18
 
19
- The API is documented [here](src/definitions.ts) and [below](#api). For a complete example of how to use this plugin in practice, see the [demo app](https://github.com/aparajita/capacitor-biometric-auth-demo).
19
+ The API is extensively documented in the [TypeScript definitions file](src/definitions.ts). There is also (somewhat incomplete auto-generated) documentation [below](#api). For a complete example of how to use this plugin in practice, see the [demo app](https://github.com/aparajita/capacitor-biometric-auth-demo).
20
20
 
21
21
  ### Checking availability
22
22
 
23
23
  Before giving the user the option to use biometry (such as displaying a biometry icon), call [`checkBiometry`](#checkbiometry) and inspect the [`CheckBiometryResult`](#checkbiometryresult) to see what (if any) biometry is available on the device. Note that `isAvailable` may be `false` but `biometryType` may indicate the presence of biometry on the device. This occurs if the current user is not enrolled in biometry, or if biometry has been disabled for the current app. In such cases the `reason` will tell you why.
24
24
 
25
- Because the availability of biometry can change while your app is in the background, itโ€™s important to recheck availability when your app resumes. By calling [`addResumeListener`](#addresumelistener) you can register a callback that is passed a [`CheckBiometryResult`](#checkbiometryresult) when your app resumes.
25
+ Because the availability of biometry can change while your app is in the background, itโ€™s important to check availability when your app resumes. By calling [`addResumeListener`](#addresumelistener) you can register a callback that is passed a [`CheckBiometryResult`](#checkbiometryresult) when your app resumes.
26
26
 
27
27
  ### Authenticating
28
28
 
29
- Once you have determined that biometry is available, to initiate biometric authentication call [authenticate](#authenticate). `authenticate` takes an [AuthenticateOptions](#authenticateoptions) object which you will want to use in order to control the behavior and appearance of the biometric prompt.
29
+ Once you have determined that biometry is available, to initiate biometric authentication call [`authenticate`](#authenticate). `authenticate` takes an [`AuthenticateOptions`](#authenticateoptions) object which you will want to use in order to control the behavior and appearance of the biometric prompt.
30
30
 
31
31
  If authentication succeeds, the Promise resolves. If authentication fails, the Promise is rejected with a `BiometryError`, which has two properties:
32
32
 
33
- | Property | Type | Description |
34
- | :---------- | :------ | :------------- |
35
- | message | string | A description of the error suitable for debugging |
36
- | code | BiometryErrorType | What caused the error |
33
+ | Property | Type | Description |
34
+ | :---------- |:--------------------------------------------------------------------------------------------------------| :------------- |
35
+ | message | string | A description of the error suitable for debugging |
36
+ | code | [BiometryErrorType](https://github.com/aparajita/capacitor-biometric-auth/blob/main/src/definitions.ts) | What caused the error |
37
37
 
38
38
  ## Biometry support
39
39
 
40
40
  ### web
41
41
 
42
- On the web, you can fake any of the supported biometry types by one of two methods:
43
-
44
- - Set the environment variable `WS_BIOMETRY_TYPE` to one of the `BiometryType` enums. This value is case-sensitive; for example to simulate Touch ID on the web, set `WS_BIOMETRY_TYPE` to `touchId`.
45
- - Call `setBiometryType()`.
42
+ On the web, you can fake any of the supported biometry types by calling [`setBiometryType()`](#setbiometrytype).
46
43
 
47
44
  ### iOS
48
45
 
@@ -53,18 +50,16 @@ On iOS, Touch ID and Face ID are supported.
53
50
  On Android, fingerprint, face, and iris authentication are supported. Note that if a device supports more than one type of biometry, the plugin will only present the primary type, which is determined by the system.
54
51
 
55
52
  ## API
56
-
57
53
  <docgen-index>
58
54
 
59
- **Methods**<br>
60
- [checkBiometry()](#checkbiometry)<br>
61
- [setBiometryType(...)](#setbiometrytype)<br>
62
- [authenticate(...)](#authenticate)<br>
55
+ [checkBiometry()](#checkbiometry)
56
+ [setBiometryType(...)](#setbiometrytype)
57
+ [authenticate(...)](#authenticate)
63
58
  [addResumeListener(...)](#addresumelistener)
64
59
 
65
-
66
- [Interfaces](#interfaces)<br>
67
- [Enums](#enums)<br>
60
+ [Interfaces](#interfaces)
61
+ [Type Aliases](#type-aliases)
62
+ [Enums](#enums)
68
63
 
69
64
  </docgen-index>
70
65
  <docgen-api>
@@ -76,7 +71,7 @@ On Android, fingerprint, face, and iris authentication are supported. Note that
76
71
  checkBiometry() => Promise<CheckBiometryResult>
77
72
  ```
78
73
 
79
- Check to see what biometry type (if any) is available. For testing on the web, a <a href="#biometrytype">BiometryType</a> name (case-sensitive) may be specified as an environment variable. For example:<br><br>WS_BIOMETRY_TYPE=touchId
74
+ Check to see what biometry type (if any) is available.
80
75
 
81
76
  **Returns:** Promise&lt;<a href="#checkbiometryresult">CheckBiometryResult</a>&gt;
82
77
 
@@ -89,11 +84,11 @@ Check to see what biometry type (if any) is available. For testing on the web, a
89
84
  setBiometryType(type: BiometryType | string | undefined) => void
90
85
  ```
91
86
 
92
- web only<br><br>On the web, this method allows you to dynamically simulate different types of biometry. You may either pass a <a href="#biometrytype">BiometryType</a> enum or the string name of a <a href="#biometrytype">BiometryType</a>. If a string is passed and it isn't a valid
87
+ web only<br><br>On the web, this method allows you to dynamically simulate different types of biometry. You may either pass a <a href="#biometrytype">`BiometryType`</a> enum or the string name of a <a href="#biometrytype">`BiometryType`</a>. If a string is passed and it isn't a valid value, nothing happens.
93
88
 
94
- | Param | Type |
95
- | :---- | :------------------------------------------------- |
96
- | type | string \| <a href="#biometrytype">BiometryType</a> |
89
+ | Param | Type |
90
+ | :---------- | :--------------------------------------------------------------- |
91
+ |type|string \| <a href="#biometrytype">BiometryType</a>|
97
92
 
98
93
  --------------------
99
94
 
@@ -101,14 +96,14 @@ web only<br><br>On the web, this method allows you to dynamically simulate diffe
101
96
  ### authenticate(...)
102
97
 
103
98
  ```typescript
104
- authenticate(options?: AuthenticateOptions | undefined) => Promise<void>
99
+ authenticate(options?: AuthenticateOptions) => Promise<void>
105
100
  ```
106
101
 
107
- Prompt the user for authentication. If authorization fails for any reason, the promise is rejected with a BiometryError.
102
+ Prompt the user for authentication. If authorization fails for any reason, the promise is rejected with a `BiometryError`.
108
103
 
109
- | Param | Type |
110
- | :------ | :----------------------------------------------------- |
111
- | options | <a href="#authenticateoptions">AuthenticateOptions</a> |
104
+ | Param | Type |
105
+ | :------------- | :------------------------------------------------------------------- |
106
+ |options|<a href="#authenticateoptions">AuthenticateOptions</a>|
112
107
 
113
108
  --------------------
114
109
 
@@ -116,14 +111,16 @@ Prompt the user for authentication. If authorization fails for any reason, the p
116
111
  ### addResumeListener(...)
117
112
 
118
113
  ```typescript
119
- addResumeListener(listener: ResumeListener) => void
114
+ addResumeListener(listener: ResumeListener) => Promise<PluginListenerHandle>
120
115
  ```
121
116
 
122
- Register a function that will be called when the app resumes. The function will be passed the result of checkBiometry().
117
+ Register a function that will be called when the app resumes. The function will be passed the result of `checkBiometry()`.
123
118
 
124
- | Param | Type |
125
- | :------- | :------------------------------------------------------------------------ |
126
- | listener | (info: <a href="#checkbiometryresult">CheckBiometryResult</a>) =&gt; void |
119
+ | Param | Type |
120
+ | :-------------- | :--------------------------------------------------------- |
121
+ |listener|<a href="#resumelistener">ResumeListener</a>|
122
+
123
+ **Returns:** Promise&lt;<a href="#pluginlistenerhandle">PluginListenerHandle</a>&gt;
127
124
 
128
125
  --------------------
129
126
 
@@ -133,25 +130,41 @@ Register a function that will be called when the app resumes. The function will
133
130
 
134
131
  #### CheckBiometryResult
135
132
 
136
- | Prop | Type | Description |
137
- | :----------- | :--------------------------------------- | :------------------------------------------------------------------------------------------------------------------------ |
138
- | isAvailable | boolean | True if the device has biometric authentication capability and the current user has enrolled in biometry. |
139
- | biometryType | <a href="#biometrytype">BiometryType</a> | The type of biometry available on the device. |
140
- | reason | string | If biometry is not available and the system gives a reason why, it will be returned here. Otherwise it's an empty string. |
133
+ | Prop | Type | Description |
134
+ | :------------------ | :----------------------------------------------------- | :------------------------------------------------------------------------------------------------------------------------- |
135
+ |isAvailable|boolean| True if the device has biometric authentication capability and the current user has enrolled in biometry. |
136
+ |biometryType|<a href="#biometrytype">BiometryType</a>| The type of biometry available on the device. |
137
+ |reason|string| If biometry is not available and the system gives a reason why, it will be returned here. Otherwise it's an empty string. |
141
138
 
142
- <br>
143
139
 
144
140
  #### AuthenticateOptions
145
141
 
146
- | Prop | Type | Description |
147
- | :-------------------- | :------ | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
148
- | reason | string | The reason for requesting authentication. Displays in the authentication dialog presented to the user. If not supplied, a default message is displayed. |
149
- | cancelTitle | string | iOS: The system presents a cancel button during biometric authentication to let the user abort the authentication attempt. The button appears every time the system asks the user to present a finger registered with Touch ID. For Face ID, the button only appears if authentication fails and the user is prompted to try again. Either way, the user can stop trying to authenticate by tapping the button.<br><br>Android: The text for the negative button. This would typically be used as a "Cancel" button, but may be also used to show an alternative method for authentication, such as a screen that asks for a backup password.<br><br>Default: "Cancel" |
150
- | allowDeviceCredential | boolean | * If true, allows for authentication using device unlock credentials. Default is false.<br><br>iOS: If biometry is available, enrolled, and not disabled, the system uses that first. After the first Touch ID failure or second Face ID failure, if iosFallbackTitle is not an empty string, a fallback button appears in the authentication dialog. If the user taps the fallback button, the system prompts the user for the device passcode or the userโ€™s password. If iosFallbackTitle is an empty string, no fallback button will appear.<br><br>If biometry is not available, enrolled and enabled, and a passcode is set, the system immediately prompts the user for the device passcode or userโ€™s password. Authentication fails with the error code passcodeNotSet if the device passcode isnโ€™t enabled.<br><br>If a passcode is not set on the device, a passcodeNotSet error is returned.<br><br>The system disables passcode authentication after 6 unsuccessful attempts, with progressively increasing delays between attempts.<br><br>The title of the fallback button may be customized by setting iosFallbackTitle to a non-empty string.<br><br>Android: The user will first be prompted to authenticate with biometrics, but also given the option to authenticate with their device PIN, pattern, or password by tapping a button in the authentication dialog. The title of the button is supplied by the system. |
151
- | iosFallbackTitle | string | The system presents a fallback button when biometric authentication fails โ€” for example, because the system doesnโ€™t recognize the presented finger, or after several failed attempts to recognize the userโ€™s face.<br><br>If allowDeviceCredential is false, tapping this button dismisses the authentication dialog and returns the error code userFallback. If undefined, the localized systetm default title is used. Passing an empty string hides the fallback button completely.<br><br>If allowDeviceCredential is true and this is undefined, the localized system default title is used. |
152
- | androidTitle | string | Title for the Android dialog. If not supplied, the system default is used. |
153
- | androidSubtitle | string | Subtitle for the Android dialog. If not supplied, the system default is used. |
154
- | androidMaxAttempts | number | The maximum number of failed biometric verification attempts before returning BiometryError.authenticationFailed. The default is 3. |
142
+ | Prop | Type | Description |
143
+ | :--------------------------- | :-------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
144
+ |reason|string| The reason for requesting authentication. Displays in the authentication dialog presented to the user. If not supplied, a default message is displayed. |
145
+ |cancelTitle|string| iOS: The system presents a cancel button during biometric authentication to let the user abort the authentication attempt. The button appears every time the system asks the user to present a finger registered with Touch ID. For Face ID, the button only appears if authentication fails and the user is prompted to try again. Either way, the user can stop trying to authenticate by tapping the button.<br><br>Android: The text for the negative button. This would typically be used as a "Cancel" button, but may be also used to show an alternative method for authentication, such as a screen that asks for a backup password.<br><br>Default: "Cancel" |
146
+ |allowDeviceCredential|boolean| If true, allows for authentication using device unlock credentials. Default is false.<br><br>iOS: If biometry is available, enrolled, and not disabled, the system uses that first. After the first Touch ID failure or second Face ID failure, if `iosFallbackTitle` is not an empty string, a fallback button appears in the authentication dialog. If the user taps the fallback button, the system prompts the user for the device passcode or the userโ€™s password. If `iosFallbackTitle` is an empty string, no fallback button will appear.<br><br>If biometry is not available, enrolled and enabled, and a passcode is set, the system immediately prompts the user for the device passcode or userโ€™s password. Authentication fails with the error code `passcodeNotSet` if the device passcode isnโ€™t enabled.<br><br>If a passcode is not set on the device, a `passcodeNotSet` error is returned.<br><br>The system disables passcode authentication after 6 unsuccessful attempts, with progressively increasing delays between attempts.<br><br>The title of the fallback button may be customized by setting `iosFallbackTitle` to a non-empty string.<br><br>Android: The user will first be prompted to authenticate with biometrics, but also given the option to authenticate with their device PIN, pattern, or password by tapping a button in the authentication dialog. The title of the button is supplied by the system. |
147
+ |iosFallbackTitle|string| The system presents a fallback button when biometric authentication fails โ€” for example, because the system doesnโ€™t recognize the presented finger, or after several failed attempts to recognize the userโ€™s face.<br><br>If `allowDeviceCredential` is false, tapping this button dismisses the authentication dialog and returns the error code userFallback. If undefined, the localized systetm default title is used. Passing an empty string hides the fallback button completely.<br><br>If `allowDeviceCredential` is true and this is undefined, the localized system default title is used. |
148
+ |androidTitle|string| Title for the Android dialog. If not supplied, the system default is used. |
149
+ |androidSubtitle|string| Subtitle for the Android dialog. If not supplied, the system default is used. |
150
+ |androidMaxAttempts|number| The maximum number of failed biometric verification attempts before returning `BiometryError.authenticationFailed`. The default is 3. |
151
+
152
+
153
+ #### PluginListenerHandle
154
+
155
+ | Method | Signature |
156
+ | :---------- | :---------------------------- |
157
+ | **remove** | () =&gt; Promise&lt;void&gt; |
158
+
159
+
160
+ ### Type Aliases
161
+
162
+
163
+ #### ResumeListener
164
+
165
+ The signature of the callback passed to `addResumeListener()`.
166
+
167
+ <code>(info: <a href="#checkbiometryresult">CheckBiometryResult</a>): void</code>
155
168
 
156
169
 
157
170
  ### Enums
@@ -159,13 +172,14 @@ Register a function that will be called when the app resumes. The function will
159
172
 
160
173
  #### BiometryType
161
174
 
162
- | Members | Description |
163
- | :------------------------ | :---------------------------------------------- |
164
- | none | No biometry is available |
165
- | touchId | iOS Touch ID is available |
166
- | faceId | iOS Face ID is available |
167
- | fingerprintAuthentication | Android fingerprint authentication is available |
168
- | faceAuthentication | Android face authentication is available |
169
- | irisAuthentication | Android iris authentication is available |
175
+ | Members | Description |
176
+ | :------------------------------- | :----------------------------------------------- |
177
+ |none| No biometry is available |
178
+ |touchId| iOS Touch ID is available |
179
+ |faceId| iOS Face ID is available |
180
+ |fingerprintAuthentication| Android fingerprint authentication is available |
181
+ |faceAuthentication| Android face authentication is available |
182
+ |irisAuthentication| Android iris authentication is available |
170
183
 
171
184
  </docgen-api>
185
+ </div>
@@ -13,110 +13,138 @@ import java.util.concurrent.Executor;
13
13
 
14
14
  public class AuthActivity extends AppCompatActivity {
15
15
 
16
- static int attemptCount;
17
- static boolean allowDeviceCredential;
16
+ static int attemptCount;
17
+ static boolean allowDeviceCredential;
18
18
 
19
- @Override
20
- protected void onCreate(Bundle savedInstanceState) {
21
- super.onCreate(savedInstanceState);
22
- setContentView(R.layout.activity_auth_activity);
19
+ @Override
20
+ protected void onCreate(Bundle savedInstanceState) {
21
+ super.onCreate(savedInstanceState);
22
+ setContentView(R.layout.activity_auth_activity);
23
23
 
24
- Executor executor;
24
+ Executor executor;
25
25
 
26
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
27
- executor = this.getMainExecutor();
28
- } else {
29
- executor = command -> new Handler(this.getMainLooper()).post(command);
30
- }
31
-
32
- BiometricPrompt.PromptInfo.Builder builder = new BiometricPrompt.PromptInfo.Builder();
33
- Intent intent = getIntent();
34
- String title = intent.getStringExtra(WSBiometricAuth.TITLE);
35
- String subtitle = intent.getStringExtra(WSBiometricAuth.SUBTITLE);
36
- String description = intent.getStringExtra(WSBiometricAuth.REASON);
37
- final int maxAttempts = intent.getIntExtra(WSBiometricAuth.MAX_ATTEMPTS, WSBiometricAuth.DEFAULT_MAX_ATTEMPTS);
38
- allowDeviceCredential = false;
39
-
40
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
41
- // Android docs say we should check if the device is secure before enabling device credential fallback
42
- KeyguardManager manager = (KeyguardManager) getSystemService(KEYGUARD_SERVICE);
43
-
44
- if (manager.isDeviceSecure()) {
45
- allowDeviceCredential = intent.getBooleanExtra(WSBiometricAuth.DEVICE_CREDENTIAL, false);
46
- }
47
- }
48
-
49
- // The title must be non-null and non-empty
50
- if (title == null || title.isEmpty()) {
51
- title = "Authenticate";
52
- }
53
-
54
- builder.setTitle(title);
55
- builder.setSubtitle(subtitle);
56
- builder.setDescription(description);
57
- builder.setDeviceCredentialAllowed(allowDeviceCredential);
26
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
27
+ executor = this.getMainExecutor();
28
+ } else {
29
+ executor = command -> new Handler(this.getMainLooper()).post(command);
30
+ }
58
31
 
59
- // Android docs say that negative button text should not be set if device credential is allowed
60
- if (!allowDeviceCredential) {
61
- String negativeButtonText = intent.getStringExtra(WSBiometricAuth.CANCEL_TITLE);
62
- builder.setNegativeButtonText(negativeButtonText == null || negativeButtonText.isEmpty() ? "Cancel" : negativeButtonText);
63
- }
32
+ BiometricPrompt.PromptInfo.Builder builder = new BiometricPrompt.PromptInfo.Builder();
33
+ Intent intent = getIntent();
34
+ String title = intent.getStringExtra(BiometricAuth.TITLE);
35
+ String subtitle = intent.getStringExtra(BiometricAuth.SUBTITLE);
36
+ String description = intent.getStringExtra(BiometricAuth.REASON);
37
+ final int maxAttempts = intent.getIntExtra(
38
+ BiometricAuth.MAX_ATTEMPTS,
39
+ BiometricAuth.DEFAULT_MAX_ATTEMPTS
40
+ );
41
+ allowDeviceCredential = false;
42
+
43
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
44
+ // Android docs say we should check if the device is secure before enabling device credential fallback
45
+ KeyguardManager manager = (KeyguardManager) getSystemService(
46
+ KEYGUARD_SERVICE
47
+ );
48
+
49
+ if (manager.isDeviceSecure()) {
50
+ allowDeviceCredential =
51
+ intent.getBooleanExtra(BiometricAuth.DEVICE_CREDENTIAL, false);
52
+ }
53
+ }
64
54
 
65
- BiometricPrompt.PromptInfo promptInfo = builder.build();
66
- attemptCount = 0;
67
-
68
- BiometricPrompt prompt = new BiometricPrompt(
69
- this,
70
- executor,
71
- new BiometricPrompt.AuthenticationCallback() {
72
- @Override
73
- public void onAuthenticationError(int errorCode, @NonNull CharSequence errorMessage) {
74
- super.onAuthenticationError(errorCode, errorMessage);
75
- finishActivity(BiometryResultType.ERROR, errorCode, (String) errorMessage);
76
- }
77
-
78
- @Override
79
- public void onAuthenticationSucceeded(@NonNull BiometricPrompt.AuthenticationResult result) {
80
- super.onAuthenticationSucceeded(result);
81
- finishActivity();
82
- }
83
-
84
- @SuppressLint("DefaultLocale")
85
- @Override
86
- public void onAuthenticationFailed() {
87
- super.onAuthenticationFailed();
88
- attemptCount += 1;
89
-
90
- // When allowDeviceCredential is true, I can't seem to force the prompt
91
- // to go away, so skip attempt counting.
92
- if (!allowDeviceCredential && attemptCount > maxAttempts) {
93
- finishActivity(
94
- BiometryResultType.FAILURE,
95
- 0,
96
- String.format("The user exceeded the maximum of %d attempt(s)", maxAttempts)
97
- );
98
- }
99
- }
100
- }
101
- );
102
-
103
- prompt.authenticate(promptInfo);
55
+ // The title must be non-null and non-empty
56
+ if (title == null || title.isEmpty()) {
57
+ title = "Authenticate";
104
58
  }
105
59
 
106
- void finishActivity() {
107
- finishActivity(BiometryResultType.SUCCESS, 0, "");
60
+ builder.setTitle(title);
61
+ builder.setSubtitle(subtitle);
62
+ builder.setDescription(description);
63
+ builder.setDeviceCredentialAllowed(allowDeviceCredential);
64
+
65
+ // Android docs say that negative button text should not be set if device credential is allowed
66
+ if (!allowDeviceCredential) {
67
+ String negativeButtonText = intent.getStringExtra(
68
+ BiometricAuth.CANCEL_TITLE
69
+ );
70
+ builder.setNegativeButtonText(
71
+ negativeButtonText == null || negativeButtonText.isEmpty()
72
+ ? "Cancel"
73
+ : negativeButtonText
74
+ );
108
75
  }
109
76
 
110
- void finishActivity(BiometryResultType resultType, int errorCode, String errorMessage) {
111
- Intent intent = new Intent();
112
- String prefix = WSBiometricAuth.RESULT_EXTRA_PREFIX;
77
+ BiometricPrompt.PromptInfo promptInfo = builder.build();
78
+ attemptCount = 0;
79
+
80
+ BiometricPrompt prompt = new BiometricPrompt(
81
+ this,
82
+ executor,
83
+ new BiometricPrompt.AuthenticationCallback() {
84
+ @Override
85
+ public void onAuthenticationError(
86
+ int errorCode,
87
+ @NonNull CharSequence errorMessage
88
+ ) {
89
+ super.onAuthenticationError(errorCode, errorMessage);
90
+ finishActivity(
91
+ BiometryResultType.ERROR,
92
+ errorCode,
93
+ (String) errorMessage
94
+ );
95
+ }
113
96
 
114
- intent
115
- .putExtra(prefix + WSBiometricAuth.RESULT_TYPE, resultType.toString())
116
- .putExtra(prefix + WSBiometricAuth.RESULT_ERROR_CODE, errorCode)
117
- .putExtra(prefix + WSBiometricAuth.RESULT_ERROR_MESSAGE, errorMessage);
97
+ @Override
98
+ public void onAuthenticationSucceeded(
99
+ @NonNull BiometricPrompt.AuthenticationResult result
100
+ ) {
101
+ super.onAuthenticationSucceeded(result);
102
+ finishActivity();
103
+ }
118
104
 
119
- setResult(RESULT_OK, intent);
120
- finish();
121
- }
105
+ @SuppressLint("DefaultLocale")
106
+ @Override
107
+ public void onAuthenticationFailed() {
108
+ super.onAuthenticationFailed();
109
+ attemptCount += 1;
110
+
111
+ // When allowDeviceCredential is true, I can't seem to force the prompt
112
+ // to go away, so skip attempt counting.
113
+ if (!allowDeviceCredential && attemptCount > maxAttempts) {
114
+ finishActivity(
115
+ BiometryResultType.FAILURE,
116
+ 0,
117
+ String.format(
118
+ "The user exceeded the maximum of %d attempt(s)",
119
+ maxAttempts
120
+ )
121
+ );
122
+ }
123
+ }
124
+ }
125
+ );
126
+
127
+ prompt.authenticate(promptInfo);
128
+ }
129
+
130
+ void finishActivity() {
131
+ finishActivity(BiometryResultType.SUCCESS, 0, "");
132
+ }
133
+
134
+ void finishActivity(
135
+ BiometryResultType resultType,
136
+ int errorCode,
137
+ String errorMessage
138
+ ) {
139
+ Intent intent = new Intent();
140
+ String prefix = BiometricAuth.RESULT_EXTRA_PREFIX;
141
+
142
+ intent
143
+ .putExtra(prefix + BiometricAuth.RESULT_TYPE, resultType.toString())
144
+ .putExtra(prefix + BiometricAuth.RESULT_ERROR_CODE, errorCode)
145
+ .putExtra(prefix + BiometricAuth.RESULT_ERROR_MESSAGE, errorMessage);
146
+
147
+ setResult(RESULT_OK, intent);
148
+ finish();
149
+ }
122
150
  }