Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -340,7 +340,10 @@ export default abstract class GestureHandler implements IGestureHandler {
//

protected onPointerDown(event: AdaptedEvent): void {
GestureHandlerOrchestrator.instance.recordHandlerIfNotPresent(this);
GestureHandlerOrchestrator.instance.recordHandlerIfNotPresent(
this,
event.pointerId
);
this._pointerType = event.pointerType;

if (this.pointerType === PointerType.TOUCH) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -231,6 +231,103 @@ describe('GestureHandlerOrchestrator idle handlers', () => {
});
});

describe('GestureHandlerOrchestrator recorded handlers passed to a new one', () => {
// Mimics a button: refuses to begin next to any handler it was told about.
class ExclusiveTestGestureHandler extends TestGestureHandler {
public override shouldBeginWithRecordedHandlers(
recorded: IGestureHandler[]
): boolean {
return recorded.length === 0;
}
}

const delegate = {
onEnabledChange: jest.fn(),
onCancel: jest.fn(),
reset: jest.fn(),
} as unknown as GestureHandlerDelegate<unknown, IGestureHandler>;

const pointerDown = (pointerId: number): AdaptedEvent => ({
x: 10,
y: 10,
offsetX: 10,
offsetY: 10,
pointerId,
eventType: EventTypes.DOWN,
pointerType: PointerType.TOUCH,
time: 0,
});

function setup() {
const other = new TestGestureHandler(delegate);
const button = new ExclusiveTestGestureHandler(delegate);
other.setGestureConfig({ enabled: true });
button.setGestureConfig({ enabled: true });
other.sendEvent = jest.fn();
button.sendEvent = jest.fn();
const cancel = jest.spyOn(button, 'cancel');

return { other, button, cancel };
}

afterEach(() => {
(
GestureHandlerOrchestrator.instance as unknown as {
gestureHandlers: IGestureHandler[];
}
).gestureHandlers = [];
});

test('a handler left in BEGAN with no pointers does not block a new one', () => {
const { other, button, cancel } = setup();

other.tracker.addToTracker(pointerDown(1));
GestureHandlerOrchestrator.instance.recordHandlerIfNotPresent(other, 1);
other.begin();
other.tracker.removeFromTracker(1);

button.tracker.addToTracker(pointerDown(1));
GestureHandlerOrchestrator.instance.recordHandlerIfNotPresent(button, 1);

expect(cancel).not.toHaveBeenCalled();
});

test('a handler tracking another pointer does not block a new one', () => {
const { other, button, cancel } = setup();

other.tracker.addToTracker(pointerDown(1));
GestureHandlerOrchestrator.instance.recordHandlerIfNotPresent(other, 1);

button.tracker.addToTracker(pointerDown(2));
GestureHandlerOrchestrator.instance.recordHandlerIfNotPresent(button, 2);

expect(cancel).not.toHaveBeenCalled();
});

test('a handler tracking the same pointer is passed to the new one', () => {
const { other, button, cancel } = setup();

other.tracker.addToTracker(pointerDown(1));
GestureHandlerOrchestrator.instance.recordHandlerIfNotPresent(other, 1);

button.tracker.addToTracker(pointerDown(1));
GestureHandlerOrchestrator.instance.recordHandlerIfNotPresent(button, 1);

expect(cancel).toHaveBeenCalledTimes(1);
});

test('recording without a pointer passes no handlers', () => {
const { other, button, cancel } = setup();

other.tracker.addToTracker(pointerDown(1));
GestureHandlerOrchestrator.instance.recordHandlerIfNotPresent(other, 1);

GestureHandlerOrchestrator.instance.recordHandlerIfNotPresent(button);

expect(cancel).not.toHaveBeenCalled();
});
});

describe('GestureHandler web touch events', () => {
afterEach(() => {
(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -291,7 +291,10 @@ export default class GestureHandlerOrchestrator {
}
}

public recordHandlerIfNotPresent(handler: IGestureHandler): void {
public recordHandlerIfNotPresent(
handler: IGestureHandler,
pointerId?: number
): void {
this.dropIdleHandlers();

if (this.isHandlerRecorded(handler)) {
Expand All @@ -302,7 +305,16 @@ export default class GestureHandlerOrchestrator {
handler.awaiting = false;
handler.activationIndex = Number.MAX_SAFE_INTEGER;

if (!handler.shouldBeginWithRecordedHandlers(this.gestureHandlers)) {
// Only handlers recorded for the same pointer (they already track it) may
// block this one
const recorded =
pointerId === undefined
? []
: this.gestureHandlers.filter((other) =>
other.tracker.isTrackingPointer(pointerId)
);

if (!handler.shouldBeginWithRecordedHandlers(recorded)) {
handler.cancel();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,12 @@ export default class PointerTracker {
}
}

public isTrackingPointer(pointerId: number): boolean {
return this.trackedPointers.has(pointerId);
}

public addToTracker(event: AdaptedEvent): void {
if (this.trackedPointers.has(event.pointerId)) {
if (this.isTrackingPointer(event.pointerId)) {
return;
}

Expand Down Expand Up @@ -121,7 +125,7 @@ export default class PointerTracker {
}

public getVelocityAt(pointerId: number, time: number) {
if (!this.trackedPointers.has(pointerId)) {
if (!this.isTrackingPointer(pointerId)) {
return null;
}

Expand Down
Loading