Add text field content to semantics (#13000)

* Add text field content to semantics

* remove controller dup
diff --git a/packages/flutter/lib/src/rendering/editable.dart b/packages/flutter/lib/src/rendering/editable.dart
index d8ae24b..70db438 100644
--- a/packages/flutter/lib/src/rendering/editable.dart
+++ b/packages/flutter/lib/src/rendering/editable.dart
@@ -169,6 +169,7 @@
       return;
     _textPainter.text = value;
     markNeedsTextLayout();
+    markNeedsSemanticsUpdate();
   }
 
   /// How the text should be aligned horizontally.
@@ -203,6 +204,7 @@
       return;
     _textPainter.textDirection = value;
     markNeedsTextLayout();
+    markNeedsSemanticsUpdate();
   }
 
   /// The color to use when painting the cursor.
@@ -322,6 +324,8 @@
     super.describeSemanticsConfiguration(config);
 
     config
+      ..value = text.toPlainText()
+      ..textDirection = textDirection
       ..isFocused = hasFocus
       ..isTextField = true;
   }
diff --git a/packages/flutter/test/widgets/editable_text_test.dart b/packages/flutter/test/widgets/editable_text_test.dart
index a80f75d..c9158b4 100644
--- a/packages/flutter/test/widgets/editable_text_test.dart
+++ b/packages/flutter/test/widgets/editable_text_test.dart
@@ -284,6 +284,43 @@
     await tester.pump();
 
     expect(semantics, includesNodeWith(flags: <SemanticsFlags>[SemanticsFlags.isTextField, SemanticsFlags.isFocused]));
+  });
 
+  testWidgets('EditableText includes text as value in semantics', (WidgetTester tester) async {
+    final SemanticsTester semantics = new SemanticsTester(tester);
+
+    const String value1 = 'EditableText content';
+
+    controller.text = value1;
+
+    await tester.pumpWidget(
+      new Directionality(
+        textDirection: TextDirection.ltr,
+        child: new FocusScope(
+          node: focusScopeNode,
+          child: new EditableText(
+            controller: controller,
+            focusNode: focusNode,
+            style: textStyle,
+            cursorColor: cursorColor,
+          ),
+        ),
+      ),
+    );
+
+    expect(semantics, includesNodeWith(
+      flags: <SemanticsFlags>[SemanticsFlags.isTextField],
+      value: value1,
+    ));
+
+    const String value2 = 'Changed the EditableText content';
+    controller.text = value2;
+    await tester.idle();
+    await tester.pump();
+
+    expect(semantics, includesNodeWith(
+      flags: <SemanticsFlags>[SemanticsFlags.isTextField],
+      value: value2,
+    ));
   });
 }
diff --git a/packages/flutter/test/widgets/semantics_tester.dart b/packages/flutter/test/widgets/semantics_tester.dart
index 1632703..02a2c02 100644
--- a/packages/flutter/test/widgets/semantics_tester.dart
+++ b/packages/flutter/test/widgets/semantics_tester.dart
@@ -314,12 +314,14 @@
 class _IncludesNodeWith extends Matcher {
   const _IncludesNodeWith({
     this.label,
+    this.value,
     this.textDirection,
     this.actions,
     this.flags,
-}) : assert(label != null || actions != null || flags != null);
+}) : assert(label != null || value != null || actions != null || flags != null);
 
   final String label;
+  final String value;
   final TextDirection textDirection;
   final List<SemanticsAction> actions;
   final List<SemanticsFlags> flags;
@@ -344,6 +346,8 @@
   bool checkNode(SemanticsNode node) {
     if (label != null && node.label != label)
       return false;
+    if (value != null && node.value != value)
+      return false;
     if (textDirection != null && node.textDirection != textDirection)
       return false;
     if (actions != null) {
@@ -375,6 +379,8 @@
     final List<String> strings = <String>[];
     if (label != null)
       strings.add('label "$label"');
+    if (value != null)
+      strings.add('value "$value"');
     if (textDirection != null)
       strings.add(' (${describeEnum(textDirection)})');
     if (actions != null)
@@ -391,12 +397,14 @@
 /// If null is provided for an argument, it will match against any value.
 Matcher includesNodeWith({
   String label,
+  String value,
   TextDirection textDirection,
   List<SemanticsAction> actions,
   List<SemanticsFlags> flags,
 }) {
   return new _IncludesNodeWith(
     label: label,
+    value: value,
     textDirection: textDirection,
     actions: actions,
     flags: flags,