[local_auth] Fix default deviceSupportsBiometrics (#5321)
diff --git a/packages/local_auth/local_auth_platform_interface/CHANGELOG.md b/packages/local_auth/local_auth_platform_interface/CHANGELOG.md
index 0ff4d16..9a2ae7a 100644
--- a/packages/local_auth/local_auth_platform_interface/CHANGELOG.md
+++ b/packages/local_auth/local_auth_platform_interface/CHANGELOG.md
@@ -1,3 +1,9 @@
+## 1.0.3
+
+* Fixes regression in the default method channel implementation of
+ `deviceSupportsBiometrics` from federation that would cause it to return true
+ only if something is enrolled.
+
## 1.0.2
* Adopts `Object.hash`.
diff --git a/packages/local_auth/local_auth_platform_interface/lib/default_method_channel_platform.dart b/packages/local_auth/local_auth_platform_interface/lib/default_method_channel_platform.dart
index c68a3bf..3e695fa 100644
--- a/packages/local_auth/local_auth_platform_interface/lib/default_method_channel_platform.dart
+++ b/packages/local_auth/local_auth_platform_interface/lib/default_method_channel_platform.dart
@@ -57,6 +57,8 @@
biometrics.add(BiometricType.iris);
break;
case 'undefined':
+ // Sentinel value for the case when nothing is enrolled, but hardware
+ // support for biometrics is available.
break;
}
}
@@ -65,7 +67,14 @@
@override
Future<bool> deviceSupportsBiometrics() async {
- return (await getEnrolledBiometrics()).isNotEmpty;
+ final List<String> availableBiometrics =
+ (await _channel.invokeListMethod<String>(
+ 'getAvailableBiometrics',
+ )) ??
+ <String>[];
+ // If anything, including the 'undefined' sentinel, is returned, then there
+ // is device support for biometrics.
+ return availableBiometrics.isNotEmpty;
}
@override
diff --git a/packages/local_auth/local_auth_platform_interface/pubspec.yaml b/packages/local_auth/local_auth_platform_interface/pubspec.yaml
index b5d476d..ee6c1e9 100644
--- a/packages/local_auth/local_auth_platform_interface/pubspec.yaml
+++ b/packages/local_auth/local_auth_platform_interface/pubspec.yaml
@@ -4,7 +4,7 @@
issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+local_auth%22
# NOTE: We strongly prefer non-breaking changes, even at the expense of a
# less-clean API. See https://flutter.dev/go/platform-interface-breaking-changes
-version: 1.0.2
+version: 1.0.3
environment:
sdk: ">=2.14.0 <3.0.0"
diff --git a/packages/local_auth/local_auth_platform_interface/test/default_method_channel_platform_test.dart b/packages/local_auth/local_auth_platform_interface/test/default_method_channel_platform_test.dart
index 3853fd8..96e78e1 100644
--- a/packages/local_auth/local_auth_platform_interface/test/default_method_channel_platform_test.dart
+++ b/packages/local_auth/local_auth_platform_interface/test/default_method_channel_platform_test.dart
@@ -10,7 +10,6 @@
import 'package:local_auth_platform_interface/local_auth_platform_interface.dart';
import 'package:local_auth_platform_interface/types/auth_messages.dart';
import 'package:local_auth_platform_interface/types/auth_options.dart';
-import 'package:local_auth_platform_interface/types/biometric_type.dart';
void main() {
TestWidgetsFlutterBinding.ensureInitialized();
@@ -19,9 +18,13 @@
'plugins.flutter.io/local_auth',
);
- final List<MethodCall> log = <MethodCall>[];
+ late List<MethodCall> log;
late LocalAuthPlatform localAuthentication;
+ setUp(() async {
+ log = <MethodCall>[];
+ });
+
test(
'DefaultLocalAuthPlatform is registered as the default platform implementation',
() async {
@@ -32,10 +35,9 @@
test('getAvailableBiometrics', () async {
channel.setMockMethodCallHandler((MethodCall methodCall) {
log.add(methodCall);
- return Future<dynamic>.value(<BiometricType>[]);
+ return Future<dynamic>.value(<String>[]);
});
localAuthentication = DefaultLocalAuthPlatform();
- log.clear();
await localAuthentication.getEnrolledBiometrics();
expect(
log,
@@ -45,6 +47,29 @@
);
});
+ test('deviceSupportsBiometrics handles special sentinal value', () async {
+ // The pre-federation implementation of the platform channels, which the
+ // default implementation retains compatibility with for the benefit of any
+ // existing unendorsed implementations, used 'undefined' as a special
+ // return value from `getAvailableBiometrics` to indicate that nothing was
+ // enrolled, but that the hardware does support biometrics.
+ channel.setMockMethodCallHandler((MethodCall methodCall) {
+ log.add(methodCall);
+ return Future<dynamic>.value(<String>['undefined']);
+ });
+
+ localAuthentication = DefaultLocalAuthPlatform();
+ final bool supportsBiometrics =
+ await localAuthentication.deviceSupportsBiometrics();
+ expect(supportsBiometrics, true);
+ expect(
+ log,
+ <Matcher>[
+ isMethodCall('getAvailableBiometrics', arguments: null),
+ ],
+ );
+ });
+
group('Boolean returning methods', () {
setUp(() {
channel.setMockMethodCallHandler((MethodCall methodCall) {
@@ -52,7 +77,6 @@
return Future<dynamic>.value(true);
});
localAuthentication = DefaultLocalAuthPlatform();
- log.clear();
});
test('isDeviceSupported', () async {