flutter / flutter

Flutter makes it easy and fast to build beautiful apps for mobile and beyond
https://flutter.dev
BSD 3-Clause "New" or "Revised" License
166.69k stars 27.61k forks source link

[Platform Views][accessibility] Android Talkback cannot focus webview content when disable and re-enable it. #158004

Open 551100kk opened 3 weeks ago

551100kk commented 3 weeks ago

Summary

The webview content cannot be focused when the talkback is on.

Steps to reproduce

  1. Start the minimal app with the webview and turn on the talkback.
  2. Observe that swiping right can move the focus inside the webview.
  3. Turn off talkback and turn on again.
  4. Observe that swiping right cannot move the focus inside the webview. Manually touch the webview also cannot move the focus into the webview.

See the attached recording for the above steps: https://github.com/user-attachments/assets/53f4fbd5-f359-41e2-97b8-d9b3bdfa689b

Minimal repro code

ran the following commands on 2024-11-01 and modified the code

flutter create testapp
flutter pub add webview_flutter
import 'package:flutter/material.dart';
import 'package:webview_flutter/webview_flutter.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return const MaterialApp(
      title: 'Flutter Demo',
      home: MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({super.key, required this.title});
  final String title;

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  final _controller = WebViewController()
    ..setJavaScriptMode(JavaScriptMode.unrestricted)
    ..loadRequest(Uri.parse('https://flutter.dev'));

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        backgroundColor: Theme.of(context).colorScheme.inversePrimary,
        title: Text(widget.title),
      ),
      body: WebViewWidget(controller: _controller),
    );
  }
}

Versions

Flutter [✓] Flutter (Channel stable, 3.24.4, on macOS 14.7 23H124 darwin-arm64, locale en)

dependencies webview_flutter: ^4.10.0

plugin id "com.android.application" version "8.4.1" apply false

gradle-wrapper.properties distributionUrl=https\://services.gradle.org/distributions/gradle-8.10-all.zip

Android module Pixel 6, Android 14

Impact

It is affecting google internal project release b/372690913

551100kk commented 3 weeks ago

Note: This issue does not appear in the native android weview.

https://github.com/user-attachments/assets/8d255041-71c4-4801-97d3-a7b08727a4dc

MainActivity.kt

package com.example.myapplication

import android.os.Bundle
import android.webkit.WebView
import androidx.appcompat.app.AppCompatActivity
import com.example.myapplication.databinding.ActivityMainBinding

class MainActivity : AppCompatActivity() {
  private lateinit var binding: ActivityMainBinding

  override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    title = "Hello native android"
    binding = ActivityMainBinding.inflate(layoutInflater)
    setContentView(binding.root)

    val myWebView: WebView = this.findViewById(R.id.web_view)
    myWebView.loadUrl("https://flutter.dev")
  }
}

content_main.xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    app:layout_behavior="@string/appbar_scrolling_view_behavior">

  <WebView
      android:id="@+id/web_view"
      android:layout_width="match_parent"
      android:layout_height="match_parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
darshankawar commented 3 weeks ago

Thanks for the report @551100kk I tried the same on S10+ device (Android 12) but wasn't able to replicate this. I verified on latest master. Can you switch to it and re-run your scenario to check if it still persist or not ?

551100kk commented 3 weeks ago

Hi @darshankawar,

I updated the pubspec.yaml to use the main branch as follow, but the issue is still there for android 11, 14, 15:

dependencies:
  flutter:
    sdk: flutter

  webview_flutter:
    git:
      url: https://github.com/flutter/packages.git
      ref: main
      path: packages/webview_flutter/webview_flutter

I tried to test on different android versions and verified that the issue cannot be reproduced in android 12, 13. Could you try to reproduce on android 14 or 15?

huycozy commented 3 weeks ago

I can reproduce this issue on Pixel 7, Android 14 with webview_flutter_android: 4.0.1. This seems to be a platform views issue as I see it appear with google_maps_flutter as well (can test with zoom in/out button inside map). You can test with maps plugin and please let me know if the issue also appears on your end then we can update the title respectively.

Furthermore, I don't see the issue appearing on iOS with VoiceOver.

Reproduced this on Flutter versions:

Channel stable, 3.24.4
Channel master, 3.27.0-1.0.pre.364
camsim99 commented 2 weeks ago

Accessibility team, please let the Android team know what you need from us to make progress on this bug!

551100kk commented 2 weeks ago

I can reproduce this issue on Pixel 7, Android 14 with webview_flutter_android: 4.0.1. This seems to be a platform views issue as I see it appear with google_maps_flutter as well (can test with zoom in/out button inside map). You can test with maps plugin and please let me know if the issue also appears on your end then we can update the title respectively.

Furthermore, I don't see the issue appearing on iOS with VoiceOver.

Reproduced this on Flutter versions:

Channel stable, 3.24.4
Channel master, 3.27.0-1.0.pre.364

@huycozy Yes, it also appears on my device (pixel 6, android 14) with the google_maps_flutter 2.9.0 plugin. Please proceed with updating the issue title :)

Minimal repro code:

import 'dart:async';

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

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return const MaterialApp(
      title: 'Flutter Demo',
      home: MapSample(),
    );
  }
}

class MapSample extends StatefulWidget {
  const MapSample({super.key});

  @override
  State<MapSample> createState() => MapSampleState();
}

class MapSampleState extends State<MapSample> {
  final Completer<GoogleMapController> _controller =
      Completer<GoogleMapController>();

  static const CameraPosition _kGooglePlex = CameraPosition(
    target: LatLng(37.42796133580664, -122.085749655962),
    zoom: 14.4746,
  );

  static const CameraPosition _kLake = CameraPosition(
      bearing: 192.8334901395799,
      target: LatLng(37.43296265331129, -122.08832357078792),
      tilt: 59.440717697143555,
      zoom: 19.151926040649414);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('Test Google Maps')),
      body: GoogleMap(
        mapType: MapType.hybrid,
        initialCameraPosition: _kGooglePlex,
        onMapCreated: (GoogleMapController controller) {
          _controller.complete(controller);
        },
      ),
      floatingActionButton: FloatingActionButton.extended(
        onPressed: _goToTheLake,
        label: const Text('To the lake!'),
        icon: const Icon(Icons.directions_boat),
      ),
    );
  }

  Future<void> _goToTheLake() async {
    final GoogleMapController controller = await _controller.future;
    await controller.animateCamera(CameraUpdate.newCameraPosition(_kLake));
  }
}

In the attached video, initially, the focus can be moved into the google map widgets (i.e., the zoom in/out are announced). However, the focus can be only moved to the appbar/floating action/talkback shortcut after disabling and enabling the talkback.

https://github.com/user-attachments/assets/1542c6ba-3ae7-4aeb-8e5f-0cd305918fe8

chunhtai commented 2 weeks ago

IIRC, a11ynodinfo of platformview is attached to the flutter's a11ynodeinfo tree in the android embedding. Once possibility is that it doesn't reattach correctly when accessibility is turned off and on. I think this is probably needed to be fixed in Android embedding.

As for impact, I don't think toggle the talkback off and on in the middle of the app is that common though