Skip to content

[Android][A11y] voice access clear text causes crash if its value is attributed string #103354

@chunhtai

Description

@chunhtai

b/226320834

Steps to Reproduce

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

class Home extends StatelessWidget {

  @override
  Widget build(BuildContext context) {

    return Scaffold(
      appBar: AppBar(
        title: Semantics(
          link: true,
          child: Text('test'),
        ),
      ),
      body: ListView(
        children: [
          TextField(controller: SpellOutTextEditingController(),)
          // SelectionArea(child: Text('test1')),
          // SelectionArea(child:Text('test2')),
        ],
      ),
    );
  }
}

class SpellOutTextEditingController extends TextEditingController {
  SpellOutTextEditingController({String? text}) : super(text: text);

  @override
  TextSpan buildTextSpan({
    required BuildContext context,
    TextStyle? style,
    required bool withComposing,
  }) {
    if (text.isEmpty) {
      return super.buildTextSpan(
        context: context,
        style: style,
        withComposing: withComposing,
      );
    }

    return buildSpellOutTextSpan(withComposing: withComposing, style: style);
  }
  
  @visibleForTesting
  TextSpan buildSpellOutTextSpan({
    required bool withComposing,
    TextStyle? style,
  }) {
    assert(
    !value.composing.isValid || !withComposing || value.isComposingRangeValid,
    );
    // If the composing range is out of range for the current text, ignore it to
    // preserve the tree integrity, otherwise in release mode a RangeError will
    // be thrown and this EditableText will be built with a broken subtree.
    if (!value.isComposingRangeValid || !withComposing) {
      return TextSpan(style: style, text: text, spellOut: true);
    }
    final composingStyle =
        style?.merge(const TextStyle(decoration: TextDecoration.underline)) ??
            const TextStyle(decoration: TextDecoration.underline);
    return TextSpan(
      style: style,
      spellOut: true,
      children: <TextSpan>[
        TextSpan(text: value.composing.textBefore(value.text)),
        TextSpan(
          style: composingStyle,
          text: value.composing.textInside(value.text),
        ),
        TextSpan(text: value.composing.textAfter(value.text)),
      ],
    );
  }
}


void main() {
  runApp(MaterialApp(home: Home()));
}
  1. type something into textfield and turn on voice access.
  2. say 'clear text'

Logs

Logs
E/AndroidRuntime(14090): FATAL EXCEPTION: main
E/AndroidRuntime(14090): Process: com.example.test8, PID: 14090
E/AndroidRuntime(14090): java.lang.IndexOutOfBoundsException: setSpan (0 ... 3) ends beyond length 0
E/AndroidRuntime(14090): 	at android.text.SpannableStringInternal.checkRange(SpannableStringInternal.java:491)
E/AndroidRuntime(14090): 	at android.text.SpannableStringInternal.setSpan(SpannableStringInternal.java:197)
E/AndroidRuntime(14090): 	at android.text.SpannableStringInternal.setSpan(SpannableStringInternal.java:184)
E/AndroidRuntime(14090): 	at android.text.SpannableString.setSpan(SpannableString.java:60)
E/AndroidRuntime(14090): 	at io.flutter.view.AccessibilityBridge$SemanticsNode.createSpannableString(AccessibilityBridge.java:2726)
E/AndroidRuntime(14090): 	at io.flutter.view.AccessibilityBridge$SemanticsNode.getValueLabelHint(AccessibilityBridge.java:2695)
E/AndroidRuntime(14090): 	at io.flutter.view.AccessibilityBridge$SemanticsNode.access$3000(AccessibilityBridge.java:2172)
E/AndroidRuntime(14090): 	at io.flutter.view.AccessibilityBridge.createAccessibilityNodeInfo(AccessibilityBridge.java:816)
E/AndroidRuntime(14090): 	at android.view.AccessibilityInteractionController$AccessibilityNodePrefetcher.prefetchAccessibilityNodeInfos(AccessibilityInteractionController.java:1101)
E/AndroidRuntime(14090): 	at android.view.AccessibilityInteractionController.findAccessibilityNodeInfoByAccessibilityIdUiThread(AccessibilityInteractionController.java:342)
E/AndroidRuntime(14090): 	at android.view.AccessibilityInteractionController.access$400(AccessibilityInteractionController.java:75)
E/AndroidRuntime(14090): 	at android.view.AccessibilityInteractionController$PrivateHandler.handleMessage(AccessibilityInteractionController.java:1460)
E/AndroidRuntime(14090): 	at android.os.Handler.dispatchMessage(Handler.java:106)
E/AndroidRuntime(14090): 	at android.os.Looper.loop(Looper.java:233)
E/AndroidRuntime(14090): 	at android.app.ActivityThread.main(ActivityThread.java:7959)
E/AndroidRuntime(14090): 	at java.lang.reflect.Method.invoke(Native Method)
E/AndroidRuntime(14090): 	at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:631)
E/AndroidRuntime(14090): 	at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:978)

Metadata

Metadata

Assignees

Labels

P0Critical issues such as a build break or regressiona: accessibilityAccessibility, e.g. VoiceOver or TalkBack. (aka a11y)customer: money (g3)engineflutter/engine related. See also e: labels.platform-androidAndroid applications specifically

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions