Unverified Commit a6aaad34 authored by Kostia Sokolovskyi's avatar Kostia Sokolovskyi Committed by GitHub

GestureRecognizer should dispatch creation and disposal events. (#138223)

parent 28ea2f84
......@@ -685,6 +685,7 @@ class _CupertinoContextMenuState extends State<CupertinoContextMenu> with Ticker
@override
void dispose() {
_tapGestureRecognizer.dispose();
_openController.dispose();
super.dispose();
}
......
......@@ -80,7 +80,17 @@ abstract class GestureRecognizer extends GestureArenaMember with DiagnosticableT
this.debugOwner,
this.supportedDevices,
AllowedButtonsFilter? allowedButtonsFilter,
}) : _allowedButtonsFilter = allowedButtonsFilter ?? _defaultButtonAcceptBehavior;
}) : _allowedButtonsFilter = allowedButtonsFilter ?? _defaultButtonAcceptBehavior {
// TODO(polina-c): stop duplicating code across disposables
// https://github.com/flutter/flutter/issues/137435
if (kFlutterMemoryAllocationsEnabled) {
MemoryAllocations.instance.dispatchObjectCreated(
library: 'package:flutter/gestures.dart',
className: '$GestureRecognizer',
object: this,
);
}
}
/// The recognizer's owner.
///
......@@ -242,7 +252,13 @@ abstract class GestureRecognizer extends GestureArenaMember with DiagnosticableT
/// recognizer is being unregistered from a [GestureDetector], the
/// GestureDetector widget calls this method).
@mustCallSuper
void dispose() { }
void dispose() {
// TODO(polina-c): stop duplicating code across disposables
// https://github.com/flutter/flutter/issues/137435
if (kFlutterMemoryAllocationsEnabled) {
MemoryAllocations.instance.dispatchObjectDisposed(object: this);
}
}
/// Returns a very short pretty description of the gesture that the
/// recognizer looks for, like 'tap' or 'horizontal drag'.
......
......@@ -1193,6 +1193,8 @@ class _RenderRangeSlider extends RenderBox with RelayoutWhenSystemFontsChangeMix
@override
void dispose() {
_drag.dispose();
_tap.dispose();
_startLabelPainter.dispose();
_endLabelPainter.dispose();
super.dispose();
......
......@@ -1457,6 +1457,8 @@ class _RenderSlider extends RenderBox with RelayoutWhenSystemFontsChangeMixin {
@override
void dispose() {
_drag.dispose();
_tap.dispose();
_labelPainter.dispose();
super.dispose();
}
......
......@@ -441,6 +441,12 @@ class RenderUiKitView extends RenderDarwinPlatformView<UiKitViewController> {
_gestureRecognizer!.reset();
super.detach();
}
@override
void dispose() {
_gestureRecognizer?.dispose();
super.dispose();
}
}
/// A render object for a macOS platform view.
......@@ -810,4 +816,10 @@ mixin _PlatformViewGestureMixin on RenderBox implements MouseTrackerAnnotation {
_gestureRecognizer!.reset();
super.detach();
}
@override
void dispose() {
_gestureRecognizer?.dispose();
super.dispose();
}
}
......@@ -671,6 +671,7 @@ class SliverReorderableListState extends State<SliverReorderableList> with Ticke
@override
void dispose() {
_dragReset();
_recognizer?.dispose();
super.dispose();
}
......
......@@ -6,6 +6,7 @@ import 'dart:ui' show VoidCallback;
import 'package:flutter/gestures.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart';
import 'gesture_tester.dart';
......@@ -49,6 +50,16 @@ void main() {
expect(recognizer, hasAGoodToStringDeep);
});
test('GestureRecognizer dispatches memory events', () async {
await expectLater(
await memoryEvents(
() => TestGestureRecognizer().dispose(),
TestGestureRecognizer
,),
areCreateAndDispose,
);
});
test('OffsetPair', () {
const OffsetPair offset1 = OffsetPair(
local: Offset(10, 20),
......
......@@ -1568,6 +1568,7 @@ void main() {
),
);
},
buildDefaultDragHandles: false,
itemCount: items.length,
onReorder: handleReorder,
),
......@@ -1634,6 +1635,7 @@ void main() {
),
);
},
buildDefaultDragHandles: false,
itemCount: items.length,
onReorder: handleReorder,
onReorderStart: (int index) {
......
......@@ -3650,6 +3650,7 @@ void main() {
double value = 0.0;
final ValueNotifier<bool> shouldShowSliderListenable =
ValueNotifier<bool>(true);
addTearDown(shouldShowSliderListenable.dispose);
await tester.pumpWidget(
MaterialApp(
......
......@@ -2189,13 +2189,15 @@ void main() {
testWidgetsWithLeakTracking('Tooltip should not ignore users tap on richMessage', (WidgetTester tester) async {
bool isTapped = false;
final TapGestureRecognizer recognizer = TapGestureRecognizer();
addTearDown(recognizer.dispose);
await tester.pumpWidget(
MaterialApp(
home: Tooltip(
richMessage: TextSpan(
text: tooltipText,
recognizer: TapGestureRecognizer()..onTap = () {
recognizer: recognizer..onTap = () {
isTapped = true;
}
),
......
......@@ -14,12 +14,14 @@ void main() {
..onTap = () {
didTapLeft = true;
};
addTearDown(tapLeft.dispose);
bool didTapRight = false;
final TapGestureRecognizer tapRight = TapGestureRecognizer()
..onTap = () {
didTapRight = true;
};
addTearDown(tapRight.dispose);
const Key textKey = Key('text');
......
......@@ -638,7 +638,9 @@ void main() {
gestureRecognizers: <Factory<OneSequenceGestureRecognizer>>{
Factory<VerticalDragGestureRecognizer>(
() {
return VerticalDragGestureRecognizer();
final VerticalDragGestureRecognizer recognizer = VerticalDragGestureRecognizer();
addTearDown(recognizer.dispose);
return recognizer;
},
),
},
......@@ -684,7 +686,9 @@ void main() {
gestureRecognizers: <Factory<OneSequenceGestureRecognizer>>{
Factory<LongPressGestureRecognizer>(
() {
return LongPressGestureRecognizer();
final LongPressGestureRecognizer recognizer = LongPressGestureRecognizer();
addTearDown(recognizer.dispose);
return recognizer;
},
),
},
......@@ -727,7 +731,9 @@ void main() {
gestureRecognizers: <Factory<OneSequenceGestureRecognizer>>{
Factory<TapGestureRecognizer>(
() {
return TapGestureRecognizer();
final TapGestureRecognizer recognizer = TapGestureRecognizer();
addTearDown(recognizer.dispose);
return recognizer;
},
),
},
......@@ -853,7 +859,11 @@ void main() {
viewType: 'webview',
gestureRecognizers: <Factory<OneSequenceGestureRecognizer>>{
Factory<OneSequenceGestureRecognizer>(
() => EagerGestureRecognizer(),
() {
final EagerGestureRecognizer recognizer = EagerGestureRecognizer();
addTearDown(recognizer.dispose);
return recognizer;
},
),
},
layoutDirection: TextDirection.ltr,
......@@ -893,7 +903,11 @@ void main() {
viewType: 'webview',
gestureRecognizers: <Factory<OneSequenceGestureRecognizer>>{
Factory<EagerGestureRecognizer>(
() => EagerGestureRecognizer(),
() {
final EagerGestureRecognizer recognizer = EagerGestureRecognizer();
addTearDown(recognizer.dispose);
return recognizer;
},
),
},
layoutDirection: TextDirection.ltr,
......@@ -912,7 +926,9 @@ void main() {
int factoryInvocationCount = 0;
EagerGestureRecognizer constructRecognizer() {
factoryInvocationCount += 1;
return EagerGestureRecognizer();
final EagerGestureRecognizer recognizer = EagerGestureRecognizer();
addTearDown(recognizer.dispose);
return recognizer;
}
await tester.pumpWidget(
......@@ -1728,7 +1744,9 @@ void main() {
gestureRecognizers: <Factory<OneSequenceGestureRecognizer>>{
Factory<VerticalDragGestureRecognizer>(
() {
return VerticalDragGestureRecognizer();
final VerticalDragGestureRecognizer recognizer = VerticalDragGestureRecognizer();
addTearDown(recognizer.dispose);
return recognizer;
},
),
},
......@@ -1772,7 +1790,9 @@ void main() {
gestureRecognizers: <Factory<OneSequenceGestureRecognizer>>{
Factory<LongPressGestureRecognizer>(
() {
return LongPressGestureRecognizer();
final LongPressGestureRecognizer recognizer = LongPressGestureRecognizer();
addTearDown(recognizer.dispose);
return recognizer;
},
),
},
......@@ -1814,7 +1834,9 @@ void main() {
gestureRecognizers: <Factory<OneSequenceGestureRecognizer>>{
Factory<TapGestureRecognizer>(
() {
return TapGestureRecognizer();
final TapGestureRecognizer recognizer = TapGestureRecognizer();
addTearDown(recognizer.dispose);
return recognizer;
},
),
},
......@@ -1937,7 +1959,11 @@ void main() {
viewType: 'webview',
gestureRecognizers: <Factory<OneSequenceGestureRecognizer>>{
Factory<OneSequenceGestureRecognizer>(
() => EagerGestureRecognizer(),
() {
final EagerGestureRecognizer recognizer = EagerGestureRecognizer();
addTearDown(recognizer.dispose);
return recognizer;
},
),
},
layoutDirection: TextDirection.ltr,
......@@ -2052,7 +2078,9 @@ void main() {
int factoryInvocationCount = 0;
EagerGestureRecognizer constructRecognizer() {
factoryInvocationCount += 1;
return EagerGestureRecognizer();
final EagerGestureRecognizer recognizer = EagerGestureRecognizer();
addTearDown(recognizer.dispose);
return recognizer;
}
await tester.pumpWidget(
......@@ -2653,7 +2681,9 @@ void main() {
gestureRecognizers: <Factory<OneSequenceGestureRecognizer>>{
Factory<VerticalDragGestureRecognizer>(
() {
return VerticalDragGestureRecognizer();
final VerticalDragGestureRecognizer recognizer = VerticalDragGestureRecognizer();
addTearDown(recognizer.dispose);
return recognizer;
},
),
},
......@@ -2697,7 +2727,9 @@ void main() {
gestureRecognizers: <Factory<OneSequenceGestureRecognizer>>{
Factory<LongPressGestureRecognizer>(
() {
return LongPressGestureRecognizer();
final LongPressGestureRecognizer recognizer = LongPressGestureRecognizer();
addTearDown(recognizer.dispose);
return recognizer;
},
),
},
......@@ -2739,7 +2771,9 @@ void main() {
gestureRecognizers: <Factory<OneSequenceGestureRecognizer>>{
Factory<TapGestureRecognizer>(
() {
return TapGestureRecognizer();
final TapGestureRecognizer recognizer = TapGestureRecognizer();
addTearDown(recognizer.dispose);
return recognizer;
},
),
},
......@@ -2862,7 +2896,11 @@ void main() {
viewType: 'webview',
gestureRecognizers: <Factory<OneSequenceGestureRecognizer>>{
Factory<OneSequenceGestureRecognizer>(
() => EagerGestureRecognizer(),
() {
final EagerGestureRecognizer recognizer = EagerGestureRecognizer();
addTearDown(recognizer.dispose);
return recognizer;
},
),
},
layoutDirection: TextDirection.ltr,
......@@ -2977,7 +3015,9 @@ void main() {
int factoryInvocationCount = 0;
EagerGestureRecognizer constructRecognizer() {
factoryInvocationCount += 1;
return EagerGestureRecognizer();
final EagerGestureRecognizer recognizer = EagerGestureRecognizer();
addTearDown(recognizer.dispose);
return recognizer;
}
await tester.pumpWidget(
......@@ -3241,7 +3281,9 @@ void main() {
gestureRecognizers: <Factory<OneSequenceGestureRecognizer>>{
Factory<VerticalDragGestureRecognizer>(
() {
return VerticalDragGestureRecognizer();
final VerticalDragGestureRecognizer recognizer = VerticalDragGestureRecognizer();
addTearDown(recognizer.dispose);
return recognizer;
},
),
},
......@@ -3353,7 +3395,11 @@ void main() {
hitTestBehavior: PlatformViewHitTestBehavior.opaque,
gestureRecognizers: <Factory<OneSequenceGestureRecognizer>>{
Factory<OneSequenceGestureRecognizer>(
() => EagerGestureRecognizer(),
() {
final EagerGestureRecognizer recognizer = EagerGestureRecognizer();
addTearDown(recognizer.dispose);
return recognizer;
},
),
},
),
......@@ -3382,7 +3428,9 @@ void main() {
int factoryInvocationCount = 0;
EagerGestureRecognizer constructRecognizer() {
++factoryInvocationCount;
return EagerGestureRecognizer();
final EagerGestureRecognizer recognizer = EagerGestureRecognizer();
addTearDown(recognizer.dispose);
return recognizer;
}
final PlatformViewSurface platformViewSurface = PlatformViewSurface(
......@@ -3406,7 +3454,9 @@ void main() {
int factoryInvocationCount = 0;
EagerGestureRecognizer constructRecognizer() {
++factoryInvocationCount;
return EagerGestureRecognizer();
final EagerGestureRecognizer recognizer = EagerGestureRecognizer();
addTearDown(recognizer.dispose);
return recognizer;
}
await tester.pumpWidget(
......
......@@ -10,14 +10,21 @@ import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart';
void main() {
testWidgetsWithLeakTracking('RichText with recognizers without handlers does not throw', (WidgetTester tester) async {
final TapGestureRecognizer recognizer1 = TapGestureRecognizer();
addTearDown(recognizer1.dispose);
final LongPressGestureRecognizer recognizer2 = LongPressGestureRecognizer();
addTearDown(recognizer2.dispose);
final DoubleTapGestureRecognizer recognizer3 = DoubleTapGestureRecognizer();
addTearDown(recognizer3.dispose);
await tester.pumpWidget(
Directionality(
textDirection: TextDirection.ltr,
child: RichText(
text: TextSpan(text: 'root', children: <InlineSpan>[
TextSpan(text: 'one', recognizer: TapGestureRecognizer()),
TextSpan(text: 'two', recognizer: LongPressGestureRecognizer()),
TextSpan(text: 'three', recognizer: DoubleTapGestureRecognizer()),
TextSpan(text: 'one', recognizer: recognizer1),
TextSpan(text: 'two', recognizer: recognizer2),
TextSpan(text: 'three', recognizer: recognizer3),
]),
),
),
......@@ -42,6 +49,11 @@ void main() {
});
testWidgetsWithLeakTracking('TextSpan Locale works', (WidgetTester tester) async {
final TapGestureRecognizer recognizer1 = TapGestureRecognizer();
addTearDown(recognizer1.dispose);
final DoubleTapGestureRecognizer recognizer2 = DoubleTapGestureRecognizer();
addTearDown(recognizer2.dispose);
await tester.pumpWidget(
Directionality(
textDirection: TextDirection.ltr,
......@@ -50,11 +62,11 @@ void main() {
text: 'root',
locale: const Locale('es', 'MX'),
children: <InlineSpan>[
TextSpan(text: 'one', recognizer: TapGestureRecognizer()),
TextSpan(text: 'one', recognizer: recognizer1),
const WidgetSpan(
child: SizedBox(),
),
TextSpan(text: 'three', recognizer: DoubleTapGestureRecognizer()),
TextSpan(text: 'three', recognizer: recognizer2),
]
),
),
......@@ -91,6 +103,11 @@ void main() {
});
testWidgetsWithLeakTracking('TextSpan spellOut works', (WidgetTester tester) async {
final TapGestureRecognizer recognizer1 = TapGestureRecognizer();
addTearDown(recognizer1.dispose);
final DoubleTapGestureRecognizer recognizer2 = DoubleTapGestureRecognizer();
addTearDown(recognizer2.dispose);
await tester.pumpWidget(
Directionality(
textDirection: TextDirection.ltr,
......@@ -99,11 +116,11 @@ void main() {
text: 'root',
spellOut: true,
children: <InlineSpan>[
TextSpan(text: 'one', recognizer: TapGestureRecognizer()),
TextSpan(text: 'one', recognizer: recognizer1),
const WidgetSpan(
child: SizedBox(),
),
TextSpan(text: 'three', recognizer: DoubleTapGestureRecognizer()),
TextSpan(text: 'three', recognizer: recognizer2),
]
),
),
......
......@@ -1573,6 +1573,9 @@ void main() {
testWidgetsWithLeakTracking('Selectable rich text with gesture recognizer has correct semantics', (WidgetTester tester) async {
final SemanticsTester semantics = SemanticsTester(tester);
final TapGestureRecognizer recognizer = TapGestureRecognizer();
addTearDown(recognizer.dispose);
await tester.pumpWidget(
overlay(
child: SelectableText.rich(
......@@ -1581,8 +1584,7 @@ void main() {
const TextSpan(text: 'text'),
TextSpan(
text: 'link',
recognizer: TapGestureRecognizer()
..onTap = () { },
recognizer: recognizer..onTap = () { },
),
],
),
......@@ -2467,6 +2469,8 @@ void main() {
const String offScreenText = 'off screen';
final ScrollController controller = ScrollController();
addTearDown(controller.dispose);
final TapGestureRecognizer recognizer = TapGestureRecognizer();
addTearDown(recognizer.dispose);
await tester.pumpWidget(
MaterialApp(
......@@ -2478,7 +2482,7 @@ void main() {
const TextSpan(text: onScreenText),
TextSpan(
text: offScreenText,
recognizer: TapGestureRecognizer()..onTap = () { },
recognizer: recognizer..onTap = () { },
),
],
style: textStyle,
......@@ -4640,6 +4644,8 @@ void main() {
..onTap = () {
spyTaps += 1;
};
addTearDown(spyRecognizer.dispose);
await tester.pumpWidget(
MaterialApp(
home: Material(
......@@ -4690,6 +4696,8 @@ void main() {
..onLongPress = () {
spyLongPress += 1;
};
addTearDown(spyRecognizer.dispose);
await tester.pumpWidget(
MaterialApp(
home: Material(
......
......@@ -13,12 +13,15 @@ void main() {
testWidgetsWithLeakTracking('Semantics tester visits last child', (WidgetTester tester) async {
final SemanticsTester semantics = SemanticsTester(tester);
const TextStyle textStyle = TextStyle();
final TapGestureRecognizer recognizer = TapGestureRecognizer();
addTearDown(recognizer.dispose);
await tester.pumpWidget(
Text.rich(
TextSpan(
children: <TextSpan>[
const TextSpan(text: 'hello'),
TextSpan(text: 'world', recognizer: TapGestureRecognizer()..onTap = () { }),
TextSpan(text: 'world', recognizer: recognizer..onTap = () { }),
],
style: textStyle,
),
......
......@@ -14,20 +14,27 @@ void main() {
testWidgetsWithLeakTracking('SemanticsNode ids are stable', (WidgetTester tester) async {
// Regression test for b/151732341.
final SemanticsTester semantics = SemanticsTester(tester);
final TapGestureRecognizer recognizer1 = TapGestureRecognizer();
addTearDown(recognizer1.dispose);
final TapGestureRecognizer recognizer2 = TapGestureRecognizer();
addTearDown(recognizer2.dispose);
final TapGestureRecognizer recognizer3 = TapGestureRecognizer();
addTearDown(recognizer3.dispose);
await tester.pumpWidget(Directionality(
textDirection: TextDirection.ltr,
child: Text.rich(
TextSpan(
text: 'Hallo ',
recognizer: TapGestureRecognizer()..onTap = () {},
recognizer: recognizer1..onTap = () {},
children: <TextSpan>[
TextSpan(
text: 'Welt ',
recognizer: TapGestureRecognizer()..onTap = () {},
recognizer: recognizer2..onTap = () {},
),
TextSpan(
text: '!!!',
recognizer: TapGestureRecognizer()..onTap = () {},
recognizer: recognizer3..onTap = () {},
),
],
),
......@@ -64,17 +71,22 @@ void main() {
expect(labelToNodeIdAfterRebuild['!!!'], labelToNodeId['!!!']);
expect(labelToNodeIdAfterRebuild.length, 3);
final TapGestureRecognizer recognizer4 = TapGestureRecognizer();
addTearDown(recognizer4.dispose);
final TapGestureRecognizer recognizer5 = TapGestureRecognizer();
addTearDown(recognizer5.dispose);
// Remove one node.
await tester.pumpWidget(Directionality(
textDirection: TextDirection.ltr,
child: Text.rich(
TextSpan(
text: 'Hallo ',
recognizer: TapGestureRecognizer()..onTap = () {},
recognizer: recognizer4..onTap = () {},
children: <TextSpan>[
TextSpan(
text: 'Welt ',
recognizer: TapGestureRecognizer()..onTap = () {},
recognizer: recognizer5..onTap = () {},
),
],
),
......@@ -94,20 +106,27 @@ void main() {
expect(labelToNodeIdAfterRemoval['Welt '], labelToNodeId['Welt ']);
expect(labelToNodeIdAfterRemoval.length, 2);
final TapGestureRecognizer recognizer6 = TapGestureRecognizer();
addTearDown(recognizer6.dispose);
final TapGestureRecognizer recognizer7 = TapGestureRecognizer();
addTearDown(recognizer7.dispose);
final TapGestureRecognizer recognizer8 = TapGestureRecognizer();
addTearDown(recognizer8.dispose);
await tester.pumpWidget(Directionality(
textDirection: TextDirection.ltr,
child: Text.rich(
TextSpan(
text: 'Hallo ',
recognizer: TapGestureRecognizer()..onTap = () {},
recognizer: recognizer6..onTap = () {},
children: <TextSpan>[
TextSpan(
text: 'Welt ',
recognizer: TapGestureRecognizer()..onTap = () {},
recognizer: recognizer7..onTap = () {},
),
TextSpan(
text: '!!!',
recognizer: TapGestureRecognizer()..onTap = () {},
recognizer: recognizer8..onTap = () {},
),
],
),
......
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