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

5 6
// @dart = 2.8

7 8
import 'dart:ui' as ui;

9
import 'package:flutter/foundation.dart';
10
import 'package:flutter/gestures.dart';
11 12

import '../flutter_test_alternative.dart';
13

14
typedef HandleEventCallback = void Function(PointerEvent event);
15

16
class TestGestureFlutterBinding extends BindingBase with GestureBinding {
17 18 19 20
  HandleEventCallback callback;

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

27
TestGestureFlutterBinding _binding = TestGestureFlutterBinding();
28

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

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

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

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

48
    ui.window.onPointerDataPacket(packet);
49
    expect(events.length, 2);
50 51 52 53
    expect(events[0].runtimeType, equals(PointerDownEvent));
    expect(events[1].runtimeType, equals(PointerUpEvent));
  });

54
  test('Pointer move events', () {
55 56 57 58 59
    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),
60
      ],
61
    );
62

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

66
    ui.window.onPointerDataPacket(packet);
67 68 69 70 71 72
    expect(events.length, 3);
    expect(events[0].runtimeType, equals(PointerDownEvent));
    expect(events[1].runtimeType, equals(PointerMoveEvent));
    expect(events[2].runtimeType, equals(PointerUpEvent));
  });

73 74 75
  test('Pointer hover events', () {
    const ui.PointerDataPacket packet = ui.PointerDataPacket(
        data: <ui.PointerData>[
76
          ui.PointerData(change: ui.PointerChange.add),
77 78 79
          ui.PointerData(change: ui.PointerChange.hover),
          ui.PointerData(change: ui.PointerChange.hover),
          ui.PointerData(change: ui.PointerChange.remove),
80
          ui.PointerData(change: ui.PointerChange.add),
81
          ui.PointerData(change: ui.PointerChange.hover),
82
        ],
83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102
    );

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

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

    ui.window.onPointerDataPacket(packet);
    expect(events.length, 0);
    expect(pointerRouterEvents.length, 6,
        reason: 'pointerRouterEvents contains: $pointerRouterEvents');
    expect(pointerRouterEvents[0].runtimeType, equals(PointerAddedEvent));
    expect(pointerRouterEvents[1].runtimeType, equals(PointerHoverEvent));
    expect(pointerRouterEvents[2].runtimeType, equals(PointerHoverEvent));
    expect(pointerRouterEvents[3].runtimeType, equals(PointerRemovedEvent));
    expect(pointerRouterEvents[4].runtimeType, equals(PointerAddedEvent));
    expect(pointerRouterEvents[5].runtimeType, equals(PointerHoverEvent));
  });

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

111
    final List<PointerEvent> events = <PointerEvent>[];
112
    _binding.callback = events.add;
113

114
    ui.window.onPointerDataPacket(packet);
115 116 117 118 119 120
    expect(events.length, 2);
    expect(events[0].runtimeType, equals(PointerDownEvent));
    expect(events[1].runtimeType, equals(PointerCancelEvent));
  });

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

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

135
    ui.window.onPointerDataPacket(packet);
136
    expect(events.length, 2);
137 138 139
    expect(events[0].runtimeType, equals(PointerDownEvent));
    expect(events[1].runtimeType, equals(PointerCancelEvent));
  });
140 141

  test('Can expand add and hover pointers', () {
142 143 144 145 146
    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),
147
        ui.PointerData(change: ui.PointerChange.add, device: 24),
148
        ui.PointerData(change: ui.PointerChange.hover, device: 24),
149
      ],
150 151
    );

152
    final List<PointerEvent> events = PointerEventConverter.expand(
153 154 155 156 157 158 159 160 161 162
      packet.data, ui.window.devicePixelRatio).toList();

    expect(events.length, 5);
    expect(events[0].runtimeType, equals(PointerAddedEvent));
    expect(events[1].runtimeType, equals(PointerHoverEvent));
    expect(events[2].runtimeType, equals(PointerRemovedEvent));
    expect(events[3].runtimeType, equals(PointerAddedEvent));
    expect(events[4].runtimeType, equals(PointerHoverEvent));
  });

163 164 165 166 167
  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),
168
        ],
169 170 171 172 173 174 175 176 177 178
    );

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

    expect(events.length, 2);
    expect(events[0].runtimeType, equals(PointerAddedEvent));
    expect(events[1].runtimeType, equals(PointerScrollEvent));
  });

179
  test('Should synthesize kPrimaryButton for touch', () {
180 181 182 183 184 185 186 187 188
    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),
189
      ],
190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207
    );

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

    expect(events.length, 5);
    expect(events[0].runtimeType, equals(PointerAddedEvent));
    expect(events[0].buttons, equals(0));
    expect(events[1].runtimeType, equals(PointerHoverEvent));
    expect(events[1].buttons, equals(0));
    expect(events[2].runtimeType, equals(PointerDownEvent));
    expect(events[2].buttons, equals(kPrimaryButton));
    expect(events[3].runtimeType, equals(PointerMoveEvent));
    expect(events[3].buttons, equals(kPrimaryButton));
    expect(events[4].runtimeType, equals(PointerUpEvent));
    expect(events[4].buttons, equals(0));
  });

208
  test('Should synthesize kPrimaryButton for stylus', () {
209
    final Offset location = const Offset(10.0, 10.0) * ui.window.devicePixelRatio;
210
    for (final PointerDeviceKind kind in <PointerDeviceKind>[
211 212 213 214 215 216 217 218 219 220 221
      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),
222
        ],
223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241
      );

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

      expect(events.length, 5);
      expect(events[0].runtimeType, equals(PointerAddedEvent));
      expect(events[0].buttons, equals(0));
      expect(events[1].runtimeType, equals(PointerHoverEvent));
      expect(events[1].buttons, equals(0));
      expect(events[2].runtimeType, equals(PointerDownEvent));
      expect(events[2].buttons, equals(kPrimaryButton));
      expect(events[3].runtimeType, equals(PointerMoveEvent));
      expect(events[3].buttons, equals(kPrimaryButton | kSecondaryStylusButton));
      expect(events[4].runtimeType, equals(PointerUpEvent));
      expect(events[4].buttons, equals(0));
    }
  });

242
  test('Should synthesize kPrimaryButton for unknown devices', () {
243 244 245 246 247 248 249 250 251
    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),
252
      ],
253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270
    );

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

    expect(events.length, 5);
    expect(events[0].runtimeType, equals(PointerAddedEvent));
    expect(events[0].buttons, equals(0));
    expect(events[1].runtimeType, equals(PointerHoverEvent));
    expect(events[1].buttons, equals(0));
    expect(events[2].runtimeType, equals(PointerDownEvent));
    expect(events[2].buttons, equals(kPrimaryButton));
    expect(events[3].runtimeType, equals(PointerMoveEvent));
    expect(events[3].buttons, equals(kPrimaryButton));
    expect(events[4].runtimeType, equals(PointerUpEvent));
    expect(events[4].buttons, equals(0));
  });

271
  test('Should not synthesize kPrimaryButton for mouse', () {
272
    final Offset location = const Offset(10.0, 10.0) * ui.window.devicePixelRatio;
273
    for (final PointerDeviceKind kind in <PointerDeviceKind>[
274 275 276 277 278 279 280 281 282
      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),
283
        ],
284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301
      );

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

      expect(events.length, 5);
      expect(events[0].runtimeType, equals(PointerAddedEvent));
      expect(events[0].buttons, equals(0));
      expect(events[1].runtimeType, equals(PointerHoverEvent));
      expect(events[1].buttons, equals(0));
      expect(events[2].runtimeType, equals(PointerDownEvent));
      expect(events[2].buttons, equals(kMiddleMouseButton));
      expect(events[3].runtimeType, equals(PointerMoveEvent));
      expect(events[3].buttons, equals(kMiddleMouseButton | kSecondaryMouseButton));
      expect(events[4].runtimeType, equals(PointerUpEvent));
      expect(events[4].buttons, equals(0));
    }
  });
302
}