/* * Copyright (C) 2015 Red Hat, Inc. and/or its affiliates. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jboss.errai.ui.cordova.events.touch.longtap; import java.util.ArrayList; import java.util.List; import org.jboss.errai.ui.cordova.events.touch.AbstractRecognizer; import org.jboss.errai.ui.cordova.events.touch.GwtTimerExecutor; import org.jboss.errai.ui.cordova.events.touch.TimerExecutor; import com.google.gwt.core.client.JsArray; import com.google.gwt.dom.client.Touch; import com.google.gwt.event.dom.client.TouchCancelEvent; import com.google.gwt.event.dom.client.TouchEndEvent; import com.google.gwt.event.dom.client.TouchMoveEvent; import com.google.gwt.event.dom.client.TouchStartEvent; import com.google.gwt.event.shared.HasHandlers; import org.jboss.errai.ui.cordova.events.touch.TouchPoint; /** * @author edewit@redhat.com */ public class LongTapRecognizer extends AbstractRecognizer { public static final int DEFAULT_WAIT_TIME_IN_MS = 1500; public static final int DEFAULT_MAX_DISTANCE = 15; private final HasHandlers source; private State state = State.READY; private TimerExecutor timerExecutor; private final int numberOfFingers; private List<TouchPoint> startPositions; private int touchCount; public LongTapRecognizer(HasHandlers source) { this(source, new GwtTimerExecutor(), 1); } public LongTapRecognizer(HasHandlers source, int numberOfFingers) { this(source, new GwtTimerExecutor(), numberOfFingers); } protected LongTapRecognizer(HasHandlers source, TimerExecutor timerExecutor, int numberOfFingers) { this.source = source; this.timerExecutor = timerExecutor; this.numberOfFingers = numberOfFingers; this.startPositions = new ArrayList<TouchPoint>(); } @Override public void onTouchStart(final TouchStartEvent event) { JsArray<Touch> touches = event.getTouches(); touchCount++; switch (state) { case INVALID: break; case READY: startPositions.add(new TouchPoint(touches.get(touchCount - 1))); state = State.FINGERS_DOWN; break; case FINGERS_DOWN: startPositions.add(new TouchPoint(touches.get(touchCount - 1))); break; case FINGERS_UP: default: state = State.INVALID; break; } if (touchCount == numberOfFingers) { state = State.WAITING; timerExecutor.execute(new TimerExecutor.CodeToRun() { @Override public void onExecution() { if (state != State.WAITING) { // something else happened forget it return; } source.fireEvent(new LongTapEvent(source, numberOfFingers, DEFAULT_WAIT_TIME_IN_MS, startPositions)); reset(); } }, DEFAULT_WAIT_TIME_IN_MS); } if (touchCount > numberOfFingers) { state = State.INVALID; } } @Override public void onTouchMove(TouchMoveEvent event) { switch (state) { case WAITING: case FINGERS_DOWN: case FINGERS_UP: // compare positions JsArray<Touch> currentTouches = event.getTouches(); for (int i = 0; i < currentTouches.length(); i++) { Touch currentTouch = currentTouches.get(i); for (TouchPoint startTouch : startPositions) { if (currentTouch.getIdentifier() == startTouch.getId()) { if (Math.abs(currentTouch.getPageX() - startTouch.getX()) > DEFAULT_MAX_DISTANCE || Math.abs(currentTouch.getPageY() - startTouch.getY()) > DEFAULT_MAX_DISTANCE) { state = State.INVALID; break; } } if (state == State.INVALID) { break; } } } break; default: state = State.INVALID; break; } } @Override public void onTouchEnd(TouchEndEvent event) { int currentTouches = event.getTouches().length(); switch (state) { case WAITING: state = State.INVALID; break; case FINGERS_DOWN: state = State.FINGERS_UP; break; case FINGERS_UP: // are we ready? if (currentTouches == 0 && touchCount == numberOfFingers) { // fire and reset reset(); } break; case INVALID: default: if (currentTouches == 0) reset(); break; } } @Override public void onTouchCancel(TouchCancelEvent event) { state = State.INVALID; int currentTouches = event.getTouches().length(); if (currentTouches == 0) reset(); } protected void reset() { state = State.READY; touchCount = 0; } }