Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Android] Autofill from saved credentials doesn't work #137760

Closed
2 tasks done
TatsuUkraine opened this issue Nov 2, 2023 · 43 comments
Closed
2 tasks done

[Android] Autofill from saved credentials doesn't work #137760

TatsuUkraine opened this issue Nov 2, 2023 · 43 comments
Labels
a: text input Entering text in a text field or keyboard related problems customer: crowd Affects or could affect many people, though not necessarily a specific customer. found in release: 3.13 Found to occur in 3.13 found in release: 3.16 Found to occur in 3.16 framework flutter/packages/flutter repository. See also f: labels. has reproducible steps The issue has been confirmed reproducible and is ready to work on P2 Important issues not at the top of the work list platform-android Android applications specifically team-android Owned by Android platform team triaged-android Triaged by Android platform team

Comments

@TatsuUkraine
Copy link

TatsuUkraine commented Nov 2, 2023

Is there an existing issue for this?

Steps to reproduce

  1. Create a form with username and password field
  2. Try to use password manager such as Google Password Manager
  3. Ensure that password usage requires biometric auth (not sure if it changes anything)
  4. Click in Key icon on keyboard and select password

Device for testing

Google Pixel 7 pro, Android 14 (34)

Expected results

Form prepopulates with the selected username/password combination

Actual results

Input loses focus and nothing happens.

Form can be prepopulated only if login/password combination is selected from Keyboard quick actions and no biometric check is requested

Code sample

Code sample (very simple autofillgroup with 2 inputs)
           AutofillGroup(
              child: Column(
                children: [
                  TextField(
                    autofillHints: [AutofillHints.username],
                  ),
                  TextField(
                    autofillHints: [AutofillHints.password],
                  ),
                ],
              ),
            ),

Screenshots or Video

Video
screen-20231103-102820.2.mp4

Logs

Logs
[+1656 ms] I/ImeTracker(29289): com.example.flutter_three_thirteen:355d8ebd: onRequestShow at ORIGIN_CLIENT_SHOW_SOFT_INPUT reason SHOW_SOFT_INPUT
[        ] D/InputMethodManager(29289): showSoftInput() view=io.flutter.embedding.android.FlutterView{5267c32 VFE...... .F...... 0,0-1440,3036 #1 aid=1073741824} flags=0 reason=SHOW_SOFT_INPUT
[  +21 ms] D/InputConnectionAdaptor(29289): The input method toggled cursor monitoring on
[  +43 ms] D/InsetsController(29289): show(ime(), fromIme=true)
[ +298 ms] I/ImeTracker(29289): com.example.flutter_three_thirteen:355d8ebd: onShown
[+1871 ms] D/InputConnectionAdaptor(29289): The input method toggled cursor monitoring off
[        ] W/WindowOnBackDispatcher(29289): sendCancelIfRunning: isInProgress=falsecallback=ImeCallback=ImeOnBackInvokedCallback@122401794 Callback=android.window.IOnBackInvokedCallback$Stub$Proxy@dd07025
[        ] I/ImeTracker(29289): com.google.android.gms:418f75e2: onCancelled at PHASE_CLIENT_ANIMATION_CANCEL
[   +9 ms] I/ImeTracker(29289): com.example.flutter_three_thirteen:f278d0eb: onRequestHide at ORIGIN_CLIENT_HIDE_SOFT_INPUT reason HIDE_SOFT_INPUT_BY_INSETS_API
[        ] I/ImeTracker(29289): com.example.flutter_three_thirteen:f278d0eb: onFailed at PHASE_CLIENT_VIEW_SERVED

Flutter Doctor output

Doctor output
[✓] Flutter (Channel stable, 3.13.9, on macOS 13.5.2 22G91 darwin-arm64, locale ru)
    • Flutter version 3.13.9 on channel stable at /Users/tatsu/flutter
    • Upstream repository https://github.com/flutter/flutter.git
    • Framework revision d211f42860 (8 days ago), 2023-10-25 13:42:25 -0700
    • Engine revision 0545f8705d
    • Dart version 3.1.5
    • DevTools version 2.25.0

[✓] Android toolchain - develop for Android devices (Android SDK version 33.0.0)
    • Android SDK at ****
    • Platform android-33, build-tools 33.0.0
    • ANDROID_HOME = ****
    • Java binary at: ****
    • Java version OpenJDK Runtime Environment (build 17.0.6+0-17.0.6b829.9-10027231)
    • All Android licenses accepted.

[✓] Xcode - develop for iOS and macOS (Xcode 15.0.1)
    • Xcode at /Applications/Xcode.app/Contents/Developer
    • Build 15A507
    • CocoaPods version 1.13.0

[✓] Android Studio (version 2022.3)
    • Android Studio at /Applications/Android Studio.app/Contents
    • Flutter plugin can be installed from:
      🔨 https://plugins.jetbrains.com/plugin/9212-flutter
    • Dart plugin can be installed from:
      🔨 https://plugins.jetbrains.com/plugin/6351-dart
    • Java version OpenJDK Runtime Environment (build 17.0.6+0-17.0.6b829.9-10027231)

[✓] Connected device (4 available)


[✓] Network resources
    • All expected network resources are available.
@dam-ease dam-ease added the in triage Presently being triaged by the triage team label Nov 2, 2023
@dam-ease
Copy link

dam-ease commented Nov 2, 2023

Hi @TatsuUkraine. When you setup details, have you also set those up in the system "autofill service" settings and provide relevant information to the autofill service for it to work ?

@TatsuUkraine
Copy link
Author

@dam-ease sorry, not sure that I understood the question( for this example I didn't do any native configuration for Android, basically this issue appears only when app looses focus either because of biometric auth or because you go into the password manager. If biometric auth is not requested, and you using password suggestions from the keyboard quick action - all works fine

@dam-ease dam-ease added the waiting for customer response The Flutter team cannot make further progress on this issue until the original reporter responds label Nov 2, 2023
@TatsuUkraine
Copy link
Author

@dam-ease I already replied😅

@github-actions github-actions bot removed the waiting for customer response The Flutter team cannot make further progress on this issue until the original reporter responds label Nov 2, 2023
@TatsuUkraine
Copy link
Author

TatsuUkraine commented Nov 3, 2023

@dam-ease I added video to the description to better explain what is going on. On a video when screen goes black - it asks for biometric verification. On a video there are 3 attempts:

  1. Using Key icon to go to the password manager.
  2. Using quick action with biometric verification
  3. Using quick action without biometric verification

Autofill works only when app doesn't go to background (3rd try)

@dam-ease
Copy link

dam-ease commented Nov 3, 2023

I guess the time you replied and the time the label updated were the same.
We can reproduce the issue when clicking on Key icon > select saved account (without needing biometric verification). We tested with a Realme 6, Android 11.
Can you confirm again if you also can see the issue when removing biometric verification or not?

Screen.Recording.2023-11-03.at.17.55.12.mov

@dam-ease dam-ease added the waiting for customer response The Flutter team cannot make further progress on this issue until the original reporter responds label Nov 3, 2023
@TatsuUkraine
Copy link
Author

TatsuUkraine commented Nov 3, 2023

It seems biometric verification doesn't affect behavior a lot. If I disable biometric check for password usages only one difference is that there is no scenario 2 (from my prev comment). So it seems autofill just stops working when the app goes to background and the text field loses focus, either because of password manager bottom sheet or because of biometric check

screen-20231103-160500.2.mp4

Also, one note, I'm not entirely sure, since I didn't check this explicitly, but I think all was working in prev stable release

@github-actions github-actions bot removed the waiting for customer response The Flutter team cannot make further progress on this issue until the original reporter responds label Nov 3, 2023
@dam-ease dam-ease added a: text input Entering text in a text field or keyboard related problems platform-android Android applications specifically framework flutter/packages/flutter repository. See also f: labels. team-android Owned by Android platform team found in release: 3.13 Found to occur in 3.13 found in release: 3.16 Found to occur in 3.16 has reproducible steps The issue has been confirmed reproducible and is ready to work on and removed in triage Presently being triaged by the triage team labels Nov 6, 2023
@camsim99 camsim99 added P2 Important issues not at the top of the work list triaged-android Triaged by Android platform team labels Nov 9, 2023
@davidpryor
Copy link

davidpryor commented Nov 20, 2023

I am seeing this same behavior while using 1password.
When required to first unlock the manager AND/OR attempting to fill the password from the "open 1password" option, the fields will not fill.

Once the manager is unlocked, 1password can fill as expected from the small "account choosing" modal, but still cannot fill from the "open 1password" option.

It seems this happens any time my app is pushed to the background by the password manager.

IF I force the focusNode for the username field to never loose focus by requesting focus when the focusNode is not in focus, it will autofill. It seems like the password manager does not/cannot regain focus on the textfield before it attempts to push the username/password text.

➜ flutter doctor -v
[✓] Flutter (Channel stable, 3.13.9, on macOS 14.0 23A344 darwin-arm64, locale en-US)
    • Flutter version 3.13.9 on channel stable at /opt/homebrew/Caskroom/flutter/3.13.9/flutter
    • Upstream repository https://github.com/flutter/flutter.git
    • Framework revision d211f42860 (4 weeks ago), 2023-10-25 13:42:25 -0700
    • Engine revision 0545f8705d
    • Dart version 3.1.5
    • DevTools version 2.25.0

[✓] Android toolchain - develop for Android devices (Android SDK version 34.0.0)
    • Android SDK at /Users/****/Library/Android/sdk
    • Platform android-34, build-tools 34.0.0
    • Java binary at: /Applications/Android Studio.app/Contents/jbr/Contents/Home/bin/java
    • Java version OpenJDK Runtime Environment (build 17.0.6+0-17.0.6b829.9-10027231)
    • All Android licenses accepted.

[✓] Xcode - develop for iOS and macOS (Xcode 15.0.1)
    • Xcode at /Applications/Xcode.app/Contents/Developer
    • Build 15A507
    • CocoaPods version 1.14.2

[✓] Chrome - develop for the web
    • Chrome at /Applications/Google Chrome.app/Contents/MacOS/Google Chrome

[✓] Android Studio (version 2022.3)
    • Android Studio at /Applications/Android Studio.app/Contents
    • Flutter plugin can be installed from:
      🔨 https://plugins.jetbrains.com/plugin/9212-flutter
    • Dart plugin can be installed from:
      🔨 https://plugins.jetbrains.com/plugin/6351-dart
    • Java version OpenJDK Runtime Environment (build 17.0.6+0-17.0.6b829.9-10027231)

[✓] VS Code (version 1.84.2)
    • VS Code at /Applications/Visual Studio Code.app/Contents
    • Flutter extension version 3.76.0
    
[✓] Network resources
    • All expected network resources are available.

• No issues found!

Edit:
Attaching a video from a sample app.
The black screen is the 1password biometric auth popup, then the login selector.

Screen_Recording_20231120_152145.mp4

@AhmadHusein5853
Copy link

I started to notice this issue once my device got Android 14 update. on Android 13 it was working fine.

@djsjr
Copy link

djsjr commented Feb 18, 2024

Developed a workaround using a combination of FocusNodes, listeners, and watching LifeCycle changes. It seems to be working for me.

  1. Initialize FocusNodes and pass them to your text inputs.
  2. Create a AppLifecycleState state variable.
  3. Implement the didChangeAppLifecycleState method, and update state each time it changes.
  4. Create a listener for each node, in which you requestFocus() if state == AppLifecycleState.inactive.

Example:

class _SignInFormState extends State<SignInForm> with WidgetsBindingObserver {
  late FocusNode passwordNode;
  late FocusNode emailNode;
  AppLifecycleState state = AppLifecycleState.resumed;

  @override
  void didChangeAppLifecycleState(AppLifecycleState state) {
    super.didChangeAppLifecycleState(state);
    this.state = state;
  }

  @override
  void initState() {
    WidgetsBinding.instance.addObserver(this);
    passwordNode = FocusNode();
    passwordNode.addListener(() async {
      if (state == AppLifecycleState.inactive)
        passwordNode.requestFocus();

    });
    emailNode = FocusNode();
    emailNode.addListener(() async {
      if (state == AppLifecycleState.inactive) 
        emailNode.requestFocus();
    });
    super.initState();
  }

  @override
  void dispose() {
    WidgetsBinding.instance.removeObserver(this);
    passwordNode.dispose();
    emailNode.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return 
        ...
        TextField(
            focusNode: emailNode, 
        ...
        TextField(
            focusNode: passwordNode,
        ...
    }
}

(Thanks to @davidpryor for mentioning forcing focus).

@tiltmaster

This comment was marked as duplicate.

@VladPetruM

This comment was marked as duplicate.

@dam-ease dam-ease added the customer: crowd Affects or could affect many people, though not necessarily a specific customer. label Feb 19, 2024
@VladPetruM

This comment was marked as resolved.

@tototo23

This comment was marked as resolved.

@vbuberen
Copy link

Can also confirm that the workaround works. Thanks a lot for this!

However, I also have a small nitpick to it - super.initState() should be called first in the override as mentioned in the documentation:

/// Implementations of this method should start with a call to the inherited
/// method, as in `super.initState()`.

So the initState() should look like this and it works fine 😉 :

@override
  void initState() {
    super.initState();
    WidgetsBinding.instance.addObserver(this);
    passwordNode = FocusNode();
    passwordNode.addListener(() async {
      if (state == AppLifecycleState.inactive)
        passwordNode.requestFocus();

    });
    emailNode = FocusNode();
    emailNode.addListener(() async {
      if (state == AppLifecycleState.inactive) 
        emailNode.requestFocus();
    });
  }

@jtmcdole
Copy link

Can also confirm that the workaround works. Thanks a lot for this!

This works for TextField but not for TextFormField in a form. That's fine though; I don't need the whole form.

@TatsuUkraine
Copy link
Author

TatsuUkraine commented Feb 21, 2024

Developed a workaround using a combination of FocusNodes, listeners, and watching LifeCycle changes. […]

another possible workaround (depends on what kind of form you have on the screen)

import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';

class InactiveFocusScopeObserver extends StatefulWidget {
  final Widget child;

  const InactiveFocusScopeObserver({
    super.key,
    required this.child,
  });

  @override
  State<InactiveFocusScopeObserver> createState() => _InactiveFocusScopeObserverState();
}

class _InactiveFocusScopeObserverState extends State<InactiveFocusScopeObserver> {
  final FocusScopeNode _focusScope = FocusScopeNode();

  AppLifecycleListener? _listener;
  FocusNode? _lastFocusedNode;

  @override
  void initState() {
    _registerListener();

    super.initState();
  }

  @override
  Widget build(BuildContext context) => FocusScope(
    node: _focusScope,
    child: widget.child,
  );

  @override
  void dispose() {
    _listener?.dispose();
    _focusScope.dispose();

    super.dispose();
  }

  void _registerListener() {
    /// optional if you want this workaround for any platform and not just for android
    if (defaultTargetPlatform != TargetPlatform.android) {
      return;
    }

    _listener = AppLifecycleListener(
      onInactive: () {
        _lastFocusedNode = _focusScope.focusedChild;
      },
      onResume: () {
        _lastFocusedNode = null;
      },
    );

    _focusScope.addListener(_onFocusChanged);
  }

  void _onFocusChanged() {
    if (_lastFocusedNode?.hasFocus == false) {
      _lastFocusedNode?.requestFocus();
      _lastFocusedNode = null;
    }
  }
}

so it can be used with any number of fields that may potentially suffer from this bug

InactiveFocusScopeObserver(
  child: FormWithTheFeildsThatMayLooseFocus(),
)

@rsiva229
Copy link

rsiva229 commented Mar 9, 2024

The workaround mentioned in this thread works fine for android. But I haven't been able to get iOS to work. The save password prompt doesn't show up. Does any one here have a working solution for iOS? Please share.

@zigapovhe
Copy link

Our clients reported exactly the same issue, but we can replicate it even without having biometric auth enabled for autofill. Using inline autofill (via keyboard), try to not directly autofill credentials, but via IME, open autofill app, and try autofilling from there.

It indeed looks like the issue is lost focus. We replicated that on Google Password Manager and on Bitwarden everytime.

@LongCatIsLooong
Copy link
Contributor

I can't reproduce the issue with biometric authentication on:

video.mp4

@LongCatIsLooong LongCatIsLooong added the waiting for customer response The Flutter team cannot make further progress on this issue until the original reporter responds label May 15, 2024
@LongCatIsLooong
Copy link
Contributor

Additional note:

if (kIsWeb || defaultTargetPlatform != TargetPlatform.android) {
// It appears that some Android keyboard implementations can cause
// app lifecycle state changes: adding this listener would cause the
// text field to unfocus as the user is trying to type.
//
// Until this is resolved, we won't be adding the listener to Android apps.
// https://github.com/flutter/flutter/pull/142930#issuecomment-1981750069
_appLifecycleListener = _AppLifecycleListener(_appLifecycleChange);
WidgetsBinding.instance.addObserver(_appLifecycleListener!);
}

It doesn't seem that moving the app to the background affects the in-app focus on Android (at least not in the framework).

@adonisRodxander
Copy link

@LongCatIsLooong In which version of flutter did you test it? I am testing it on version 3.19.6, and I can reproduce the issue, in my case it happens with Samsung Account on a physical device, using biometric authentication, it does not autocomplete the textfields (email and password).

@adonisRodxander
Copy link

UPDATE: On version 3.22.0 works fine

@LongCatIsLooong
Copy link
Contributor

Looks like the first bad commit is 04e284a. The issue went away when the commit was reverted.

@catalunha

This comment was marked as off-topic.

@gnprice

This comment was marked as off-topic.

@gnprice
Copy link
Member

gnprice commented May 31, 2024

Looks like the first bad commit is 04e284a. The issue went away when the commit was reverted.

To unpack this a bit:
Commit 04e284a was an engine roll, pulling in flutter/engine@c97a0deccbc1.

That engine commit was reverted in flutter/engine@500ae6c.

That revert rolled into flutter/flutter in commit d35c08e, which was part of Flutter 3.22.0 but not 3.19.6 (the previous release).

@udaychandra
Copy link

We're facing the same issue with password autofill.

Using Flutter 3.22.1

@TatsuUkraine
Copy link
Author

TatsuUkraine commented Jun 3, 2024

All works fine for me on Android after update to 3.22.1. Fields aren't loosing focus during biometric verification in password manager. Login and password prefilled correctly in the form

@github-actions github-actions bot removed the waiting for customer response The Flutter team cannot make further progress on this issue until the original reporter responds label Jun 3, 2024
@github-actions github-actions bot reopened this Jun 3, 2024
@TatsuUkraine
Copy link
Author

@LongCatIsLooong I don't know why bot reopened the issue, sorry 😅

@AristideVB
Copy link

@LongCatIsLooong I don't know why bot reopened the issue, sorry 😅

Might be a sign ! 😄 On Android Username is not saved to Google Password Manager for me, only suggested password

While on iOS existing password autofill does not fill the fields anymore (but I will investigate and open an issue)

@zigapovhe
Copy link

Jup, works for me on android, but I still have the same old issues on iOS build

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
a: text input Entering text in a text field or keyboard related problems customer: crowd Affects or could affect many people, though not necessarily a specific customer. found in release: 3.13 Found to occur in 3.13 found in release: 3.16 Found to occur in 3.16 framework flutter/packages/flutter repository. See also f: labels. has reproducible steps The issue has been confirmed reproducible and is ready to work on P2 Important issues not at the top of the work list platform-android Android applications specifically team-android Owned by Android platform team triaged-android Triaged by Android platform team
Projects
None yet
Development

No branches or pull requests