Commit d923a8c3 authored by krisgiesing's avatar krisgiesing

Merge pull request #1617 from krisgiesing/arena_sweep

Arena sweep
parents 21d74257 e8a0ea35
...@@ -45,6 +45,8 @@ class GestureArenaEntry { ...@@ -45,6 +45,8 @@ class GestureArenaEntry {
class _GestureArenaState { class _GestureArenaState {
final List<GestureArenaMember> members = new List<GestureArenaMember>(); final List<GestureArenaMember> members = new List<GestureArenaMember>();
bool isOpen = true; bool isOpen = true;
bool isHeld = false;
bool hasPendingSweep = false;
void add(GestureArenaMember member) { void add(GestureArenaMember member) {
assert(isOpen); assert(isOpen);
...@@ -72,6 +74,46 @@ class GestureArena { ...@@ -72,6 +74,46 @@ class GestureArena {
_tryToResolveArena(key, state); _tryToResolveArena(key, state);
} }
/// Force resolution on this arena, giving the win to the first member
void sweep(Object key) {
_GestureArenaState state = _arenas[key];
if (state == null)
return; // This arena either never existed or has been resolved.
assert(!state.isOpen);
if (state.isHeld) {
state.hasPendingSweep = true;
return; // This arena is being held for a long-lived member
}
_arenas.remove(key);
if (!state.members.isEmpty) {
// First member wins
state.members.first.acceptGesture(key);
// Give all the other members the bad news
for (int i = 1; i < state.members.length; i++)
state.members[i].rejectGesture(key);
}
}
/// Prevent the arena from being swept
void hold(Object key) {
_GestureArenaState state = _arenas[key];
if (state == null)
return; // This arena either never existed or has been resolved.
state.isHeld = true;
}
/// Release a hold, allowing the arena to be swept
/// If a sweep was attempted on a held arena, the sweep will be done
/// on release
void release(Object key) {
_GestureArenaState state = _arenas[key];
if (state == null)
return; // This arena either never existed or has been resolved.
state.isHeld = false;
if (state.hasPendingSweep)
sweep(key);
}
void _tryToResolveArena(Object key, _GestureArenaState state) { void _tryToResolveArena(Object key, _GestureArenaState state) {
assert(_arenas[key] == state); assert(_arenas[key] == state);
assert(!state.isOpen); assert(!state.isOpen);
......
...@@ -244,6 +244,8 @@ class FlutterBinding extends HitTestTarget { ...@@ -244,6 +244,8 @@ class FlutterBinding extends HitTestTarget {
pointerRouter.route(event); pointerRouter.route(event);
if (event.type == 'pointerdown') if (event.type == 'pointerdown')
GestureArena.instance.close(event.pointer); GestureArena.instance.close(event.pointer);
else if (event.type == 'pointerup')
GestureArena.instance.sweep(event.pointer);
} }
} }
} }
......
...@@ -66,4 +66,176 @@ void main() { ...@@ -66,4 +66,176 @@ void main() {
expect(secondAcceptRan, isFalse); expect(secondAcceptRan, isFalse);
expect(secondRejectRan, isTrue); expect(secondRejectRan, isTrue);
}); });
test('Should win by sweep', () {
GestureArena arena = new GestureArena();
int primaryKey = 4;
bool firstAcceptRan = false;
bool firstRejectRan = false;
bool secondAcceptRan = false;
bool secondRejectRan = false;
TestGestureArenaMember first = new TestGestureArenaMember(
onAcceptGesture: (int key) {
expect(key, equals(primaryKey));
firstAcceptRan = true;
},
onRejectGesture: (int key) {
expect(key, equals(primaryKey));
firstRejectRan = true;
}
);
TestGestureArenaMember second = new TestGestureArenaMember(
onAcceptGesture: (int key) {
expect(key, equals(primaryKey));
secondAcceptRan = true;
},
onRejectGesture: (int key) {
expect(key, equals(primaryKey));
secondRejectRan = true;
}
);
arena.add(primaryKey, first);
arena.add(primaryKey, second);
arena.close(primaryKey);
expect(firstAcceptRan, isFalse);
expect(firstRejectRan, isFalse);
expect(secondAcceptRan, isFalse);
expect(secondRejectRan, isFalse);
arena.sweep(primaryKey);
expect(firstAcceptRan, isTrue);
expect(firstRejectRan, isFalse);
expect(secondAcceptRan, isFalse);
expect(secondRejectRan, isTrue);
});
test('Should win on release after hold sweep release', () {
GestureArena arena = new GestureArena();
int primaryKey = 4;
bool firstAcceptRan = false;
bool firstRejectRan = false;
bool secondAcceptRan = false;
bool secondRejectRan = false;
TestGestureArenaMember first = new TestGestureArenaMember(
onAcceptGesture: (int key) {
expect(key, equals(primaryKey));
firstAcceptRan = true;
},
onRejectGesture: (int key) {
expect(key, equals(primaryKey));
firstRejectRan = true;
}
);
TestGestureArenaMember second = new TestGestureArenaMember(
onAcceptGesture: (int key) {
expect(key, equals(primaryKey));
secondAcceptRan = true;
},
onRejectGesture: (int key) {
expect(key, equals(primaryKey));
secondRejectRan = true;
}
);
arena.add(primaryKey, first);
arena.add(primaryKey, second);
arena.close(primaryKey);
expect(firstAcceptRan, isFalse);
expect(firstRejectRan, isFalse);
expect(secondAcceptRan, isFalse);
expect(secondRejectRan, isFalse);
arena.hold(primaryKey);
expect(firstAcceptRan, isFalse);
expect(firstRejectRan, isFalse);
expect(secondAcceptRan, isFalse);
expect(secondRejectRan, isFalse);
arena.sweep(primaryKey);
expect(firstAcceptRan, isFalse);
expect(firstRejectRan, isFalse);
expect(secondAcceptRan, isFalse);
expect(secondRejectRan, isFalse);
arena.release(primaryKey);
expect(firstAcceptRan, isTrue);
expect(firstRejectRan, isFalse);
expect(secondAcceptRan, isFalse);
expect(secondRejectRan, isTrue);
});
test('Should win on sweep after hold release sweep', () {
GestureArena arena = new GestureArena();
int primaryKey = 4;
bool firstAcceptRan = false;
bool firstRejectRan = false;
bool secondAcceptRan = false;
bool secondRejectRan = false;
TestGestureArenaMember first = new TestGestureArenaMember(
onAcceptGesture: (int key) {
expect(key, equals(primaryKey));
firstAcceptRan = true;
},
onRejectGesture: (int key) {
expect(key, equals(primaryKey));
firstRejectRan = true;
}
);
TestGestureArenaMember second = new TestGestureArenaMember(
onAcceptGesture: (int key) {
expect(key, equals(primaryKey));
secondAcceptRan = true;
},
onRejectGesture: (int key) {
expect(key, equals(primaryKey));
secondRejectRan = true;
}
);
arena.add(primaryKey, first);
arena.add(primaryKey, second);
arena.close(primaryKey);
expect(firstAcceptRan, isFalse);
expect(firstRejectRan, isFalse);
expect(secondAcceptRan, isFalse);
expect(secondRejectRan, isFalse);
arena.hold(primaryKey);
expect(firstAcceptRan, isFalse);
expect(firstRejectRan, isFalse);
expect(secondAcceptRan, isFalse);
expect(secondRejectRan, isFalse);
arena.release(primaryKey);
expect(firstAcceptRan, isFalse);
expect(firstRejectRan, isFalse);
expect(secondAcceptRan, isFalse);
expect(secondRejectRan, isFalse);
arena.sweep(primaryKey);
expect(firstAcceptRan, isTrue);
expect(firstRejectRan, isFalse);
expect(secondAcceptRan, isFalse);
expect(secondRejectRan, isTrue);
});
} }
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