Support keyboardAppearance field for iOS (#19244)

diff --git a/packages/flutter/lib/src/material/text_field.dart b/packages/flutter/lib/src/material/text_field.dart
index f974642..f82f011 100644
--- a/packages/flutter/lib/src/material/text_field.dart
+++ b/packages/flutter/lib/src/material/text_field.dart
@@ -115,6 +115,7 @@
     this.onSubmitted,
     this.inputFormatters,
     this.enabled,
+    this.keyboardAppearance,
   }) : assert(keyboardType != null),
        assert(textInputAction != null),
        assert(textAlign != null),
@@ -278,6 +279,13 @@
   /// [Decoration.enabled] property.
   final bool enabled;
 
+  /// The appearance of the keyboard.
+  /// 
+  /// This setting is only honored on iOS devices.
+  /// 
+  /// If unset, defaults to the brightness of [ThemeData.primaryColorBrightness].
+  final Brightness keyboardAppearance;
+
   @override
   _TextFieldState createState() => new _TextFieldState();
 
@@ -468,6 +476,7 @@
     assert(debugCheckHasMaterial(context));
     final ThemeData themeData = Theme.of(context);
     final TextStyle style = widget.style ?? themeData.textTheme.subhead;
+    final Brightness keyboardAppearance = widget.keyboardAppearance ?? themeData.primaryColorBrightness;
     final TextEditingController controller = _effectiveController;
     final FocusNode focusNode = _effectiveFocusNode;
     final List<TextInputFormatter> formatters = widget.inputFormatters ?? <TextInputFormatter>[];
@@ -497,6 +506,7 @@
         onSelectionChanged: _handleSelectionChanged,
         inputFormatters: formatters,
         rendererIgnoresPointer: true,
+        keyboardAppearance: keyboardAppearance,
       ),
     );
 
diff --git a/packages/flutter/lib/src/material/text_form_field.dart b/packages/flutter/lib/src/material/text_form_field.dart
index e8f0aa2..d9afab1 100644
--- a/packages/flutter/lib/src/material/text_form_field.dart
+++ b/packages/flutter/lib/src/material/text_form_field.dart
@@ -69,6 +69,7 @@
     FormFieldValidator<String> validator,
     List<TextInputFormatter> inputFormatters,
     bool enabled,
+    Brightness keyboardAppearance,
   }) : assert(initialValue == null || controller == null),
        assert(keyboardType != null),
        assert(textAlign != null),
@@ -106,6 +107,7 @@
         onSubmitted: onFieldSubmitted,
         inputFormatters: inputFormatters,
         enabled: enabled,
+        keyboardAppearance: keyboardAppearance,
       );
     },
   );
diff --git a/packages/flutter/lib/src/services/text_input.dart b/packages/flutter/lib/src/services/text_input.dart
index 702e4f5..20e38c8 100644
--- a/packages/flutter/lib/src/services/text_input.dart
+++ b/packages/flutter/lib/src/services/text_input.dart
@@ -10,6 +10,7 @@
 
 import 'message_codec.dart';
 import 'system_channels.dart';
+import 'system_chrome.dart';
 import 'text_editing.dart';
 
 export 'dart:ui' show TextAffinity;
@@ -104,7 +105,7 @@
   String get _name => 'TextInputType.${_names[index]}';
 
   /// Returns a representation of this object as a JSON object.
-  Map<String, dynamic> toJSON() {
+  Map<String, dynamic> toJson() {
     return <String, dynamic>{
       'name': _name,
       'signed': signed,
@@ -341,9 +342,11 @@
     this.autocorrect = true,
     this.actionLabel,
     this.inputAction = TextInputAction.done,
+    this.keyboardAppearance = Brightness.light,
   }) : assert(inputType != null),
        assert(obscureText != null),
        assert(autocorrect != null),
+       assert(keyboardAppearance != null),
        assert(inputAction != null);
 
   /// The type of information for which to optimize the text input control.
@@ -365,14 +368,22 @@
   /// What kind of action to request for the action button on the IME.
   final TextInputAction inputAction;
 
+  /// The appearance of the keyboard.
+  /// 
+  /// This setting is only honored on iOS devices.
+  /// 
+  /// Defaults to [Brightness.light].
+  final Brightness keyboardAppearance;
+
   /// Returns a representation of this object as a JSON object.
-  Map<String, dynamic> toJSON() {
+  Map<String, dynamic> toJson() {
     return <String, dynamic>{
-      'inputType': inputType.toJSON(),
+      'inputType': inputType.toJson(),
       'obscureText': obscureText,
       'autocorrect': autocorrect,
       'actionLabel': actionLabel,
       'inputAction': inputAction.toString(),
+      'keyboardAppearance': keyboardAppearance.toString(),
     };
   }
 }
@@ -675,7 +686,7 @@
     _clientHandler._currentConnection = connection;
     SystemChannels.textInput.invokeMethod(
       'TextInput.setClient',
-      <dynamic>[ connection._id, configuration.toJSON() ],
+      <dynamic>[ connection._id, configuration.toJson() ],
     );
     return connection;
   }
diff --git a/packages/flutter/lib/src/widgets/editable_text.dart b/packages/flutter/lib/src/widgets/editable_text.dart
index 1c821ae..ed2262e 100644
--- a/packages/flutter/lib/src/widgets/editable_text.dart
+++ b/packages/flutter/lib/src/widgets/editable_text.dart
@@ -210,6 +210,7 @@
     this.rendererIgnoresPointer = false,
     this.cursorWidth = 1.0,
     this.cursorRadius,
+    this.keyboardAppearance = Brightness.light,
   }) : assert(controller != null),
        assert(focusNode != null),
        assert(obscureText != null),
@@ -365,6 +366,13 @@
   /// By default, the cursor has a Radius of zero.
   final Radius cursorRadius;
 
+  /// The appearance of the keyboard.
+  /// 
+  /// This setting is only honored on iOS devices.
+  /// 
+  /// Defaults to [Brightness.light].
+  final Brightness keyboardAppearance;
+
   @override
   EditableTextState createState() => new EditableTextState();
 
@@ -557,6 +565,7 @@
               inputType: widget.keyboardType,
               obscureText: widget.obscureText,
               autocorrect: widget.autocorrect,
+              keyboardAppearance: widget.keyboardAppearance,
               inputAction: widget.keyboardType == TextInputType.multiline
                   ? TextInputAction.newline
                   : widget.textInputAction,
diff --git a/packages/flutter/test/services/text_input_test.dart b/packages/flutter/test/services/text_input_test.dart
index 49be2a6..159176d 100644
--- a/packages/flutter/test/services/text_input_test.dart
+++ b/packages/flutter/test/services/text_input_test.dart
@@ -13,6 +13,7 @@
       expect(configuration.obscureText, false);
       expect(configuration.autocorrect, true);
       expect(configuration.actionLabel, null);
+      expect(configuration.keyboardAppearance, Brightness.light);
     });
 
     test('text serializes to JSON', () async {
@@ -22,7 +23,7 @@
         autocorrect: false,
         actionLabel: 'xyzzy',
       );
-      final Map<String, dynamic> json = configuration.toJSON();
+      final Map<String, dynamic> json = configuration.toJson();
       expect(json['inputType'], <String, dynamic>{
         'name': 'TextInputType.text', 'signed': null, 'decimal': null
       });
@@ -38,7 +39,7 @@
         autocorrect: false,
         actionLabel: 'xyzzy',
       );
-      final Map<String, dynamic> json = configuration.toJSON();
+      final Map<String, dynamic> json = configuration.toJson();
       expect(json['inputType'], <String, dynamic>{
         'name': 'TextInputType.number', 'signed': false, 'decimal': true
       });