This commit is contained in:
Adam Velebil 2022-11-30 08:58:27 +01:00
commit 6bd3bffbc0
No known key found for this signature in database
GPG Key ID: AC6D6B9D715FC084
7 changed files with 60 additions and 19 deletions

View File

@ -25,6 +25,7 @@ class AppPreferences(context: Context) {
const val PREF_NFC_OPEN_APP = "flutter.prefNfcOpenApp"
const val PREF_NFC_BYPASS_TOUCH = "flutter.prefNfcBypassTouch"
const val PREF_NFC_COPY_OTP = "flutter.prefNfcCopyOtp"
const val PREF_USB_OPEN_APP = "flutter.prefUsbOpenApp"
const val PREF_CLIP_KBD_LAYOUT = "flutter.prefClipKbdLayout"
const val DEFAULT_CLIP_KBD_LAYOUT = "US"
@ -47,4 +48,7 @@ class AppPreferences(context: Context) {
PREF_CLIP_KBD_LAYOUT,
DEFAULT_CLIP_KBD_LAYOUT
)!!
val openAppOnUsb: Boolean
get() = prefs.getBoolean(PREF_USB_OPEN_APP, false)
}

View File

@ -159,7 +159,9 @@ class MainActivity : FlutterFragmentActivity() {
override fun onPause() {
stopNfcDiscovery()
enableAliasMainActivityComponent(false)
if (!appPreferences.openAppOnUsb) {
enableAliasMainActivityComponent(false)
}
super.onPause()
}

View File

@ -19,11 +19,11 @@ import 'package:shared_preferences/shared_preferences.dart';
import 'package:yubico_authenticator/android/init.dart';
import 'package:yubico_authenticator/android/keys.dart' as android_keys;
import 'package:yubico_authenticator/android/qr_scanner/qr_scanner_view.dart';
import 'package:yubico_authenticator/android/preferences.dart';
import 'package:yubico_authenticator/app/views/device_avatar.dart';
import 'package:yubico_authenticator/app/views/keys.dart' as app_keys;
import '../test_util.dart';
import 'constants.dart';
void _setShowBetaDialogPref(bool value) async {
SharedPreferences.setMockInitialValues({betaDialogPrefName: value});

View File

@ -23,6 +23,7 @@ const betaDialogView = Key('$_prefix.beta_dialog');
const nfcTapSetting = Key('$_prefix.nfc_tap');
const nfcKeyboardLayoutSetting = Key('$_prefix.nfc_keyboard_layout');
const nfcBypassTouchSetting = Key('$_prefix.nfc_bypass_touch');
const usbOpenApp = Key('$_prefix.usb_open_app');
const themeModeSetting = Key('$_prefix.theme_mode');
const okButton = Key('$_prefix.ok');

View File

@ -20,4 +20,5 @@ const prefNfcOpenApp = 'prefNfcOpenApp';
const prefNfcBypassTouch = 'prefNfcBypassTouch';
const prefNfcCopyOtp = 'prefNfcCopyOtp';
const prefClipKbdLayout = 'prefClipKbdLayout';
const prefUsbOpenApp = 'prefUsbOpenApp';
const prefTheme = 'APP_STATE_THEME';

View File

@ -23,11 +23,7 @@ import '../../core/state.dart';
import '../../widgets/list_title.dart';
import '../../widgets/responsive_dialog.dart';
import '../keys.dart' as keys;
const String _prefNfcOpenApp = 'prefNfcOpenApp';
const String _prefNfcBypassTouch = 'prefNfcBypassTouch';
const String _prefNfcCopyOtp = 'prefNfcCopyOtp';
const String _prefClipKbdLayout = 'prefClipKbdLayout';
import '../preferences.dart';
// TODO: Get these from Android
const List<String> _keyboardLayouts = ['US', 'DE', 'DE-CH'];
@ -61,8 +57,8 @@ enum _TapAction {
}
static _TapAction load(SharedPreferences prefs) {
final launchApp = prefs.getBool(_prefNfcOpenApp) ?? true;
final copyOtp = prefs.getBool(_prefNfcCopyOtp) ?? false;
final launchApp = prefs.getBool(prefNfcOpenApp) ?? true;
final copyOtp = prefs.getBool(prefNfcCopyOtp) ?? false;
if (launchApp && copyOtp) {
return both;
}
@ -74,8 +70,8 @@ enum _TapAction {
}
void save(SharedPreferences prefs) {
prefs.setBool(_prefNfcOpenApp, this != copy);
prefs.setBool(_prefNfcCopyOtp, this != launch);
prefs.setBool(prefNfcOpenApp, this != copy);
prefs.setBool(prefNfcCopyOtp, this != launch);
}
}
@ -107,8 +103,9 @@ class _AndroidSettingsPageState extends ConsumerState<AndroidSettingsPage> {
final tapAction = _TapAction.load(prefs);
final clipKbdLayout =
prefs.getString(_prefClipKbdLayout) ?? _defaultClipKbdLayout;
final nfcBypassTouch = prefs.getBool(_prefNfcBypassTouch) ?? false;
prefs.getString(prefClipKbdLayout) ?? _defaultClipKbdLayout;
final nfcBypassTouch = prefs.getBool(prefNfcBypassTouch) ?? false;
final usbOpenApp = prefs.getBool(prefUsbOpenApp) ?? false;
final themeMode = ref.watch(themeModeProvider);
final theme = Theme.of(context);
@ -146,7 +143,7 @@ class _AndroidSettingsPageState extends ConsumerState<AndroidSettingsPage> {
onTap: () async {
var newValue = await _selectKbdLayout(context, clipKbdLayout);
if (newValue != clipKbdLayout) {
await prefs.setString(_prefClipKbdLayout, newValue);
await prefs.setString(prefClipKbdLayout, newValue);
setState(() {});
}
},
@ -155,13 +152,26 @@ class _AndroidSettingsPageState extends ConsumerState<AndroidSettingsPage> {
title: const Text('Bypass touch requirement'),
subtitle: nfcBypassTouch
? const Text(
'Accounts that require touch are automatically shown over NFC.')
'Accounts that require touch are automatically shown over NFC')
: const Text(
'Accounts that require touch need an additional tap over NFC.'),
'Accounts that require touch need an additional tap over NFC'),
value: nfcBypassTouch,
key: keys.nfcBypassTouchSetting,
onChanged: (value) {
prefs.setBool(_prefNfcBypassTouch, value);
prefs.setBool(prefNfcBypassTouch, value);
setState(() {});
}),
const ListTitle('USB options'),
SwitchListTile(
title: const Text('Launch when YubiKey is connected'),
subtitle: usbOpenApp
? const Text(
'This prevents other apps from using the YubiKey over USB')
: const Text('Other apps can use the YubiKey over USB.'),
value: usbOpenApp,
key: keys.usbOpenApp,
onChanged: (value) {
prefs.setBool(prefUsbOpenApp, value);
setState(() {});
}),
const ListTitle('Appearance'),

View File

@ -23,11 +23,10 @@ import 'package:shared_preferences/shared_preferences.dart';
import 'package:yubico_authenticator/android/keys.dart' as keys;
import 'package:yubico_authenticator/android/state.dart';
import 'package:yubico_authenticator/android/views/android_settings_page.dart';
import 'package:yubico_authenticator/android/preferences.dart';
import 'package:yubico_authenticator/app/state.dart';
import 'package:yubico_authenticator/core/state.dart';
import '../integration_test/android/constants.dart';
Widget createMaterialApp({required Widget child}) {
return MaterialApp(
localizationsDelegates: const [
@ -103,10 +102,16 @@ extension _WidgetTesterHelper on WidgetTester {
await pumpAndSettle();
}
Future<void> tapOpenAppOnUsb() async {
await tap(find.byKey(keys.usbOpenApp));
await pumpAndSettle();
}
ListTile themeModeListTile() =>
find.byKey(keys.themeModeSetting).evaluate().single.widget as ListTile;
Future<void> openAppThemeOptionSelection() async {
await ensureVisible(find.byKey(keys.themeModeSetting));
var widget = find.byKey(keys.themeModeSetting).hitTestable();
expect(widget, findsOneWidget);
await tap(widget);
@ -290,4 +295,22 @@ void main() {
expect(sharedPrefs.getString(prefTheme), equals('dark'));
});
});
testWidgets('Open app on USB', (WidgetTester tester) async {
SharedPreferences.setMockInitialValues({prefUsbOpenApp: false});
SharedPreferences sharedPrefs = await SharedPreferences.getInstance();
await tester.pumpWidget(androidWidget(
sharedPrefs: sharedPrefs,
child: widget,
));
// change to true
await tester.tapOpenAppOnUsb();
expect(sharedPrefs.getBool(prefUsbOpenApp), equals(true));
// change to false
await tester.tapOpenAppOnUsb();
expect(sharedPrefs.getBool(prefUsbOpenApp), equals(false));
});
}