Commit 800a6e16 authored by Ian Hickson's avatar Ian Hickson Committed by jslavitz

Quick fix for tap-to-show-keyboard regression (#26629)

* Fixes Android keyboard bug
parent 4c99958d
...@@ -98,22 +98,21 @@ typedef GestureForceInterpolation = double Function(double pressureMin, double p ...@@ -98,22 +98,21 @@ typedef GestureForceInterpolation = double Function(double pressureMin, double p
/// force touch functionality, with the exception of the iPhone XR. In addition, /// force touch functionality, with the exception of the iPhone XR. In addition,
/// a small handful of Android devices have this functionality as well. /// a small handful of Android devices have this functionality as well.
/// ///
/// Reported pressure will always be in the range [0.0, 1.0], where 1.0 is /// Reported pressure will always be in the range 0.0 to 1.0, where 1.0 is
/// maximum pressure and 0.0 is minimum pressure. If using a non-linear /// maximum pressure and 0.0 is minimum pressure. If using a custom
/// interpolation equation, the pressure reported will correspond with the /// [interpolation] callback, the pressure reported will correspond to that
/// custom curve. (ie. if the interpolation maps t(0.5) -> 0.1, a value of 0.1 /// custom curve.
/// will be reported at a device pressure value of 0.5).
///
class ForcePressGestureRecognizer extends OneSequenceGestureRecognizer { class ForcePressGestureRecognizer extends OneSequenceGestureRecognizer {
/// Creates a force press gesture recognizer. /// Creates a force press gesture recognizer.
/// ///
/// The [startPressure] defaults to 0.4, and [peakPressure] defaults to 0.85 /// The [startPressure] defaults to 0.4, and [peakPressure] defaults to 0.85
/// where a value of 0.0 is no pressure and a value of 1.0 is maximum pressure. /// where a value of 0.0 is no pressure and a value of 1.0 is maximum pressure.
/// ///
/// [startPressure], [peakPressure] and [interpolation] must not be null. /// The [startPressure], [peakPressure] and [interpolation] arguments must not
/// [peakPressure] must be greater than [startPressure]. [interpolation] must /// be null. The [peakPressure] argument must be greater than [startPressure].
/// always return a value in the range [0.0, 1.0] where /// The [interpolation] callback must always return a value in the range 0.0
/// pressureMin <= pressure <= pressureMax. /// to 1.0 for values of `pressure` that are between `pressureMin` and
/// `pressureMax`.
ForcePressGestureRecognizer({ ForcePressGestureRecognizer({
this.startPressure = 0.4, this.startPressure = 0.4,
this.peakPressure = 0.85, this.peakPressure = 0.85,
...@@ -172,21 +171,22 @@ class ForcePressGestureRecognizer extends OneSequenceGestureRecognizer { ...@@ -172,21 +171,22 @@ class ForcePressGestureRecognizer extends OneSequenceGestureRecognizer {
final double peakPressure; final double peakPressure;
/// The function used to convert the raw device pressure values into a value /// The function used to convert the raw device pressure values into a value
/// in the range [0, 1]. /// in the range 0.0 to 1.0.
/// ///
/// The function takes in the device's min, max and raw touch /// The function takes in the device's minimum, maximum and raw touch pressure
/// pressure and returns a value in the range [0.0, 1.0] denoting the /// and returns a value in the range 0.0 to 1.0 denoting the interpolated
/// interpolated touch pressure. /// touch pressure.
/// ///
/// This function must always return values in the range [0, 1] when /// This function must always return values in the range 0.0 to 1.0 given a
/// pressureMin <= pressure <= pressureMax. /// pressure that is between the minimum and maximum pressures. It may return
/// [double.NaN] for values that it does not want to support.
/// ///
/// By default, the the function is a simple linear interpolation, however, /// By default, the function is a linear interpolation; however, changing the
/// changing the function could be useful to accommodate variations in the way /// function could be useful to accommodate variations in the way different
/// different devices respond to pressure, change how animations from pressure /// devices respond to pressure, or to change how animations from pressure
/// feedback are rendered or for other custom functionality. /// feedback are rendered.
/// ///
/// For example, an ease in curve can be used to determine the interpolated /// For example, an ease-in curve can be used to determine the interpolated
/// value: /// value:
/// ///
/// ```dart /// ```dart
...@@ -216,7 +216,12 @@ class ForcePressGestureRecognizer extends OneSequenceGestureRecognizer { ...@@ -216,7 +216,12 @@ class ForcePressGestureRecognizer extends OneSequenceGestureRecognizer {
// A static pointer with changes in pressure creates PointerMoveEvent events. // A static pointer with changes in pressure creates PointerMoveEvent events.
if (event is PointerMoveEvent || event is PointerDownEvent) { if (event is PointerMoveEvent || event is PointerDownEvent) {
final double pressure = interpolation(event.pressureMin, event.pressureMax, event.pressure); final double pressure = interpolation(event.pressureMin, event.pressureMax, event.pressure);
assert(pressure.isNaN ? true : (pressure <= 1.0 && pressure >= 0.0)); assert(
event.pressure < event.pressureMin || // contract is undefined for underflowing pressures...
event.pressure > event.pressureMax || // contract is undefined for overflowing pressures...
pressure.isNaN || // and interpolation may return NaN for values it doesn't want to support...
(pressure <= 1.0 && pressure >= 0.0) // but if everything is going well, it must be in the range 1.0..0.0.
);
_lastPosition = event.position; _lastPosition = event.position;
_lastPressure = pressure; _lastPressure = pressure;
...@@ -300,6 +305,7 @@ class ForcePressGestureRecognizer extends OneSequenceGestureRecognizer { ...@@ -300,6 +305,7 @@ class ForcePressGestureRecognizer extends OneSequenceGestureRecognizer {
} }
static double _inverseLerp(double min, double max, double t) { static double _inverseLerp(double min, double max, double t) {
assert(min <= max);
return (t - min) / (max - min); return (t - min) / (max - min);
} }
......
...@@ -280,7 +280,7 @@ abstract class DragGestureRecognizer extends OneSequenceGestureRecognizer { ...@@ -280,7 +280,7 @@ abstract class DragGestureRecognizer extends OneSequenceGestureRecognizer {
@override @override
void debugFillProperties(DiagnosticPropertiesBuilder properties) { void debugFillProperties(DiagnosticPropertiesBuilder properties) {
super.debugFillProperties(properties); super.debugFillProperties(properties);
properties.add(EnumProperty<DragStartBehavior>('Start Behavior', dragStartBehavior)); properties.add(EnumProperty<DragStartBehavior>('start behavior', dragStartBehavior));
} }
} }
......
...@@ -613,16 +613,9 @@ class _TextFieldState extends State<TextField> with AutomaticKeepAliveClientMixi ...@@ -613,16 +613,9 @@ class _TextFieldState extends State<TextField> with AutomaticKeepAliveClientMixi
void _handleForcePressStarted(ForcePressDetails details) { void _handleForcePressStarted(ForcePressDetails details) {
if (widget.selectionEnabled) { if (widget.selectionEnabled) {
switch (Theme.of(context).platform) { // The cause is not technically double tap, but we would like to show
case TargetPlatform.iOS: // the toolbar.
// The cause is not technically double tap, but we would like to show _renderEditable.selectWordsInRange(from: details.globalPosition, cause: SelectionChangedCause.doubleTap);
// the toolbar.
_renderEditable.selectWordsInRange(from: details.globalPosition, cause: SelectionChangedCause.doubleTap);
break;
case TargetPlatform.android:
case TargetPlatform.fuchsia:
break;
}
} }
} }
...@@ -724,6 +717,20 @@ class _TextFieldState extends State<TextField> with AutomaticKeepAliveClientMixi ...@@ -724,6 +717,20 @@ class _TextFieldState extends State<TextField> with AutomaticKeepAliveClientMixi
if (widget.maxLength != null && widget.maxLengthEnforced) if (widget.maxLength != null && widget.maxLengthEnforced)
formatters.add(LengthLimitingTextInputFormatter(widget.maxLength)); formatters.add(LengthLimitingTextInputFormatter(widget.maxLength));
bool forcePressEnabled;
TextSelectionControls textSelectionControls;
switch (themeData.platform) {
case TargetPlatform.iOS:
forcePressEnabled = true;
textSelectionControls = cupertinoTextSelectionControls;
break;
case TargetPlatform.android:
case TargetPlatform.fuchsia:
forcePressEnabled = false;
textSelectionControls = materialTextSelectionControls;
break;
}
Widget child = RepaintBoundary( Widget child = RepaintBoundary(
child: EditableText( child: EditableText(
key: _editableTextKey, key: _editableTextKey,
...@@ -740,11 +747,7 @@ class _TextFieldState extends State<TextField> with AutomaticKeepAliveClientMixi ...@@ -740,11 +747,7 @@ class _TextFieldState extends State<TextField> with AutomaticKeepAliveClientMixi
autocorrect: widget.autocorrect, autocorrect: widget.autocorrect,
maxLines: widget.maxLines, maxLines: widget.maxLines,
selectionColor: themeData.textSelectionColor, selectionColor: themeData.textSelectionColor,
selectionControls: widget.selectionEnabled selectionControls: widget.selectionEnabled ? textSelectionControls : null,
? (themeData.platform == TargetPlatform.iOS
? cupertinoTextSelectionControls
: materialTextSelectionControls)
: null,
onChanged: widget.onChanged, onChanged: widget.onChanged,
onEditingComplete: widget.onEditingComplete, onEditingComplete: widget.onEditingComplete,
onSubmitted: widget.onSubmitted, onSubmitted: widget.onSubmitted,
...@@ -789,7 +792,7 @@ class _TextFieldState extends State<TextField> with AutomaticKeepAliveClientMixi ...@@ -789,7 +792,7 @@ class _TextFieldState extends State<TextField> with AutomaticKeepAliveClientMixi
ignoring: !(widget.enabled ?? widget.decoration?.enabled ?? true), ignoring: !(widget.enabled ?? widget.decoration?.enabled ?? true),
child: TextSelectionGestureDetector( child: TextSelectionGestureDetector(
onTapDown: _handleTapDown, onTapDown: _handleTapDown,
onForcePressStart: _handleForcePressStarted, onForcePressStart: forcePressEnabled ? _handleForcePressStarted : null,
onSingleTapUp: _handleSingleTapUp, onSingleTapUp: _handleSingleTapUp,
onSingleTapCancel: _handleSingleTapCancel, onSingleTapCancel: _handleSingleTapCancel,
onSingleLongTapDown: _handleSingleLongTapDown, onSingleLongTapDown: _handleSingleLongTapDown,
......
...@@ -725,8 +725,8 @@ class _TextSelectionGestureDetectorState extends State<TextSelectionGestureDetec ...@@ -725,8 +725,8 @@ class _TextSelectionGestureDetectorState extends State<TextSelectionGestureDetec
void _forcePressStarted(ForcePressDetails details) { void _forcePressStarted(ForcePressDetails details) {
_doubleTapTimer?.cancel(); _doubleTapTimer?.cancel();
_doubleTapTimer = null; _doubleTapTimer = null;
if (widget.onForcePressStart != null) if (widget.onForcePressStart != null)
widget.onForcePressStart(details); widget.onForcePressStart(details);
} }
void _forcePressEnded(ForcePressDetails details) { void _forcePressEnded(ForcePressDetails details) {
...@@ -761,8 +761,8 @@ class _TextSelectionGestureDetectorState extends State<TextSelectionGestureDetec ...@@ -761,8 +761,8 @@ class _TextSelectionGestureDetectorState extends State<TextSelectionGestureDetec
return GestureDetector( return GestureDetector(
onTapDown: _handleTapDown, onTapDown: _handleTapDown,
onTapUp: _handleTapUp, onTapUp: _handleTapUp,
onForcePressStart: _forcePressStarted, onForcePressStart: widget.onForcePressStart != null ? _forcePressStarted : null,
onForcePressEnd: _forcePressEnded, onForcePressEnd: widget.onForcePressEnd != null ? _forcePressEnded : null,
onTapCancel: _handleTapCancel, onTapCancel: _handleTapCancel,
onLongPress: _handleLongPress, onLongPress: _handleLongPress,
excludeFromSemantics: true, excludeFromSemantics: true,
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment