gesture_binding_test.dart 12.5 KB
Newer Older
Ian Hickson's avatar
Ian Hickson committed
1
// Copyright 2014 The Flutter Authors. All rights reserved.
2 3 4 5 6
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

import 'dart:ui' as ui;

7
import 'package:flutter/foundation.dart';
8
import 'package:flutter/gestures.dart';
9
import 'package:flutter/scheduler.dart';
10
import 'package:flutter_test/flutter_test.dart';
11

12
typedef HandleEventCallback = void Function(PointerEvent event);
13

14
class TestGestureFlutterBinding extends BindingBase with GestureBinding, SchedulerBinding {
15
  HandleEventCallback? callback;
16 17 18

  @override
  void handleEvent(PointerEvent event, HitTestEntry entry) {
19
    super.handleEvent(event, entry);
20
    if (callback != null)
21
      callback?.call(event);
22
  }
23 24
}

25
TestGestureFlutterBinding? _binding;
26

27
void ensureTestGestureBinding() {
28
  _binding ??= TestGestureFlutterBinding();
29
  assert(GestureBinding.instance != null);
30
  assert(SchedulerBinding.instance != null);
31 32 33
}

void main() {
34
  setUp(ensureTestGestureBinding);
35 36

  test('Pointer tap events', () {
37 38 39 40
    const ui.PointerDataPacket packet = ui.PointerDataPacket(
      data: <ui.PointerData>[
        ui.PointerData(change: ui.PointerChange.down),
        ui.PointerData(change: ui.PointerChange.up),
41
      ],
42
    );
43

44
    final List<PointerEvent> events = <PointerEvent>[];
45
    _binding!.callback = events.add;
46

47
    ui.window.onPointerDataPacket?.call(packet);
48
    expect(events.length, 2);
49 50
    expect(events[0], isA<PointerDownEvent>());
    expect(events[1], isA<PointerUpEvent>());
51 52
  });

53
  test('Pointer move events', () {
54 55 56 57 58
    const ui.PointerDataPacket packet = ui.PointerDataPacket(
      data: <ui.PointerData>[
        ui.PointerData(change: ui.PointerChange.down),
        ui.PointerData(change: ui.PointerChange.move),
        ui.PointerData(change: ui.PointerChange.up),
59
      ],
60
    );
61

62
    final List<PointerEvent> events = <PointerEvent>[];
63
    _binding!.callback = events.add;
64

65
    ui.window.onPointerDataPacket?.call(packet);
66
    expect(events.length, 3);
67 68 69
    expect(events[0], isA<PointerDownEvent>());
    expect(events[1], isA<PointerMoveEvent>());
    expect(events[2], isA<PointerUpEvent>());
70 71
  });

72 73 74
  test('Pointer hover events', () {
    const ui.PointerDataPacket packet = ui.PointerDataPacket(
        data: <ui.PointerData>[
75
          ui.PointerData(change: ui.PointerChange.add),
76 77 78
          ui.PointerData(change: ui.PointerChange.hover),
          ui.PointerData(change: ui.PointerChange.hover),
          ui.PointerData(change: ui.PointerChange.remove),
79
          ui.PointerData(change: ui.PointerChange.add),
80
          ui.PointerData(change: ui.PointerChange.hover),
81
        ],
82 83 84
    );

    final List<PointerEvent> pointerRouterEvents = <PointerEvent>[];
85
    GestureBinding.instance!.pointerRouter.addGlobalRoute(pointerRouterEvents.add);
86 87

    final List<PointerEvent> events = <PointerEvent>[];
88
    _binding!.callback = events.add;
89

90
    ui.window.onPointerDataPacket?.call(packet);
91 92 93 94
    expect(events.length, 3);
    expect(events[0], isA<PointerHoverEvent>());
    expect(events[1], isA<PointerHoverEvent>());
    expect(events[2], isA<PointerHoverEvent>());
95 96
    expect(pointerRouterEvents.length, 6,
        reason: 'pointerRouterEvents contains: $pointerRouterEvents');
97 98 99 100 101 102
    expect(pointerRouterEvents[0], isA<PointerAddedEvent>());
    expect(pointerRouterEvents[1], isA<PointerHoverEvent>());
    expect(pointerRouterEvents[2], isA<PointerHoverEvent>());
    expect(pointerRouterEvents[3], isA<PointerRemovedEvent>());
    expect(pointerRouterEvents[4], isA<PointerAddedEvent>());
    expect(pointerRouterEvents[5], isA<PointerHoverEvent>());
103 104
  });

105
  test('Pointer cancel events', () {
106 107 108 109
    const ui.PointerDataPacket packet = ui.PointerDataPacket(
      data: <ui.PointerData>[
        ui.PointerData(change: ui.PointerChange.down),
        ui.PointerData(change: ui.PointerChange.cancel),
110
      ],
111
    );
112

113
    final List<PointerEvent> events = <PointerEvent>[];
114
    _binding!.callback = events.add;
115

116
    ui.window.onPointerDataPacket?.call(packet);
117
    expect(events.length, 2);
118 119
    expect(events[0], isA<PointerDownEvent>());
    expect(events[1], isA<PointerCancelEvent>());
120 121 122
  });

  test('Can cancel pointers', () {
123 124 125 126
    const ui.PointerDataPacket packet = ui.PointerDataPacket(
      data: <ui.PointerData>[
        ui.PointerData(change: ui.PointerChange.down),
        ui.PointerData(change: ui.PointerChange.up),
127
      ],
128
    );
129

130
    final List<PointerEvent> events = <PointerEvent>[];
131
    _binding!.callback = (PointerEvent event) {
132 133
      events.add(event);
      if (event is PointerDownEvent)
134
        _binding!.cancelPointer(event.pointer);
135 136
    };

137
    ui.window.onPointerDataPacket?.call(packet);
138
    expect(events.length, 2);
139 140
    expect(events[0], isA<PointerDownEvent>());
    expect(events[1], isA<PointerCancelEvent>());
141
  });
142 143

  test('Can expand add and hover pointers', () {
144 145 146 147 148
    const ui.PointerDataPacket packet = ui.PointerDataPacket(
      data: <ui.PointerData>[
        ui.PointerData(change: ui.PointerChange.add, device: 24),
        ui.PointerData(change: ui.PointerChange.hover, device: 24),
        ui.PointerData(change: ui.PointerChange.remove, device: 24),
149
        ui.PointerData(change: ui.PointerChange.add, device: 24),
150
        ui.PointerData(change: ui.PointerChange.hover, device: 24),
151
      ],
152 153
    );

154
    final List<PointerEvent> events = PointerEventConverter.expand(
155 156 157
      packet.data, ui.window.devicePixelRatio).toList();

    expect(events.length, 5);
158 159 160 161 162
    expect(events[0], isA<PointerAddedEvent>());
    expect(events[1], isA<PointerHoverEvent>());
    expect(events[2], isA<PointerRemovedEvent>());
    expect(events[3], isA<PointerAddedEvent>());
    expect(events[4], isA<PointerHoverEvent>());
163 164
  });

165 166 167 168 169
  test('Can expand pointer scroll events', () {
    const ui.PointerDataPacket packet = ui.PointerDataPacket(
        data: <ui.PointerData>[
          ui.PointerData(change: ui.PointerChange.add),
          ui.PointerData(change: ui.PointerChange.hover, signalKind: ui.PointerSignalKind.scroll),
170
        ],
171 172 173 174 175 176
    );

    final List<PointerEvent> events = PointerEventConverter.expand(
      packet.data, ui.window.devicePixelRatio).toList();

    expect(events.length, 2);
177 178
    expect(events[0], isA<PointerAddedEvent>());
    expect(events[1], isA<PointerScrollEvent>());
179 180
  });

181
  test('Should synthesize kPrimaryButton for touch', () {
182 183 184 185 186 187 188 189 190
    final Offset location = const Offset(10.0, 10.0) * ui.window.devicePixelRatio;
    const PointerDeviceKind kind = PointerDeviceKind.touch;
    final ui.PointerDataPacket packet = ui.PointerDataPacket(
      data: <ui.PointerData>[
        ui.PointerData(change: ui.PointerChange.add, kind: kind, physicalX: location.dx, physicalY: location.dy),
        ui.PointerData(change: ui.PointerChange.hover, kind: kind, physicalX: location.dx, physicalY: location.dy),
        ui.PointerData(change: ui.PointerChange.down, kind: kind, physicalX: location.dx, physicalY: location.dy),
        ui.PointerData(change: ui.PointerChange.move, kind: kind, physicalX: location.dx, physicalY: location.dy),
        ui.PointerData(change: ui.PointerChange.up, kind: kind, physicalX: location.dx, physicalY: location.dy),
191
      ],
192 193 194 195 196 197
    );

    final List<PointerEvent> events = PointerEventConverter.expand(
      packet.data, ui.window.devicePixelRatio).toList();

    expect(events.length, 5);
198
    expect(events[0], isA<PointerAddedEvent>());
199
    expect(events[0].buttons, equals(0));
200
    expect(events[1], isA<PointerHoverEvent>());
201
    expect(events[1].buttons, equals(0));
202
    expect(events[2], isA<PointerDownEvent>());
203
    expect(events[2].buttons, equals(kPrimaryButton));
204
    expect(events[3], isA<PointerMoveEvent>());
205
    expect(events[3].buttons, equals(kPrimaryButton));
206
    expect(events[4], isA<PointerUpEvent>());
207 208 209
    expect(events[4].buttons, equals(0));
  });

210
  test('Should synthesize kPrimaryButton for stylus', () {
211
    final Offset location = const Offset(10.0, 10.0) * ui.window.devicePixelRatio;
212
    for (final PointerDeviceKind kind in <PointerDeviceKind>[
213 214 215 216 217 218 219 220 221 222 223
      PointerDeviceKind.stylus,
      PointerDeviceKind.invertedStylus,
    ]) {

      final ui.PointerDataPacket packet = ui.PointerDataPacket(
        data: <ui.PointerData>[
          ui.PointerData(change: ui.PointerChange.add, kind: kind, physicalX: location.dx, physicalY: location.dy),
          ui.PointerData(change: ui.PointerChange.hover, kind: kind, physicalX: location.dx, physicalY: location.dy),
          ui.PointerData(change: ui.PointerChange.down, kind: kind, physicalX: location.dx, physicalY: location.dy),
          ui.PointerData(change: ui.PointerChange.move, buttons: kSecondaryStylusButton, kind: kind, physicalX: location.dx, physicalY: location.dy),
          ui.PointerData(change: ui.PointerChange.up, kind: kind, physicalX: location.dx, physicalY: location.dy),
224
        ],
225 226 227 228 229 230
      );

      final List<PointerEvent> events = PointerEventConverter.expand(
        packet.data, ui.window.devicePixelRatio).toList();

      expect(events.length, 5);
231
      expect(events[0], isA<PointerAddedEvent>());
232
      expect(events[0].buttons, equals(0));
233
      expect(events[1], isA<PointerHoverEvent>());
234
      expect(events[1].buttons, equals(0));
235
      expect(events[2], isA<PointerDownEvent>());
236
      expect(events[2].buttons, equals(kPrimaryButton));
237
      expect(events[3], isA<PointerMoveEvent>());
238
      expect(events[3].buttons, equals(kPrimaryButton | kSecondaryStylusButton));
239
      expect(events[4], isA<PointerUpEvent>());
240 241 242 243
      expect(events[4].buttons, equals(0));
    }
  });

244
  test('Should synthesize kPrimaryButton for unknown devices', () {
245 246 247 248 249 250 251 252 253
    final Offset location = const Offset(10.0, 10.0) * ui.window.devicePixelRatio;
    const PointerDeviceKind kind = PointerDeviceKind.unknown;
    final ui.PointerDataPacket packet = ui.PointerDataPacket(
      data: <ui.PointerData>[
        ui.PointerData(change: ui.PointerChange.add, kind: kind, physicalX: location.dx, physicalY: location.dy),
        ui.PointerData(change: ui.PointerChange.hover, kind: kind, physicalX: location.dx, physicalY: location.dy),
        ui.PointerData(change: ui.PointerChange.down, kind: kind, physicalX: location.dx, physicalY: location.dy),
        ui.PointerData(change: ui.PointerChange.move, kind: kind, physicalX: location.dx, physicalY: location.dy),
        ui.PointerData(change: ui.PointerChange.up, kind: kind, physicalX: location.dx, physicalY: location.dy),
254
      ],
255 256 257 258 259 260
    );

    final List<PointerEvent> events = PointerEventConverter.expand(
      packet.data, ui.window.devicePixelRatio).toList();

    expect(events.length, 5);
261
    expect(events[0], isA<PointerAddedEvent>());
262
    expect(events[0].buttons, equals(0));
263
    expect(events[1], isA<PointerHoverEvent>());
264
    expect(events[1].buttons, equals(0));
265
    expect(events[2], isA<PointerDownEvent>());
266
    expect(events[2].buttons, equals(kPrimaryButton));
267
    expect(events[3], isA<PointerMoveEvent>());
268
    expect(events[3].buttons, equals(kPrimaryButton));
269
    expect(events[4], isA<PointerUpEvent>());
270 271 272
    expect(events[4].buttons, equals(0));
  });

273
  test('Should not synthesize kPrimaryButton for mouse', () {
274
    final Offset location = const Offset(10.0, 10.0) * ui.window.devicePixelRatio;
275
    for (final PointerDeviceKind kind in <PointerDeviceKind>[
276 277 278 279 280 281 282 283 284
      PointerDeviceKind.mouse,
    ]) {
      final ui.PointerDataPacket packet = ui.PointerDataPacket(
        data: <ui.PointerData>[
          ui.PointerData(change: ui.PointerChange.add, kind: kind, physicalX: location.dx, physicalY: location.dy),
          ui.PointerData(change: ui.PointerChange.hover, kind: kind, physicalX: location.dx, physicalY: location.dy),
          ui.PointerData(change: ui.PointerChange.down, kind: kind, buttons: kMiddleMouseButton, physicalX: location.dx, physicalY: location.dy),
          ui.PointerData(change: ui.PointerChange.move, kind: kind, buttons: kMiddleMouseButton | kSecondaryMouseButton, physicalX: location.dx, physicalY: location.dy),
          ui.PointerData(change: ui.PointerChange.up, kind: kind, physicalX: location.dx, physicalY: location.dy),
285
        ],
286 287 288 289 290 291
      );

      final List<PointerEvent> events = PointerEventConverter.expand(
        packet.data, ui.window.devicePixelRatio).toList();

      expect(events.length, 5);
292
      expect(events[0], isA<PointerAddedEvent>());
293
      expect(events[0].buttons, equals(0));
294
      expect(events[1], isA<PointerHoverEvent>());
295
      expect(events[1].buttons, equals(0));
296
      expect(events[2], isA<PointerDownEvent>());
297
      expect(events[2].buttons, equals(kMiddleMouseButton));
298
      expect(events[3], isA<PointerMoveEvent>());
299
      expect(events[3].buttons, equals(kMiddleMouseButton | kSecondaryMouseButton));
300
      expect(events[4], isA<PointerUpEvent>());
301 302 303
      expect(events[4].buttons, equals(0));
    }
  });
304
}