diff --git a/app/src/main/java/io/github/sspanak/tt9/ui/main/keys/SoftKey.java b/app/src/main/java/io/github/sspanak/tt9/ui/main/keys/SoftKey.java index df1fe09f..331d7177 100644 --- a/app/src/main/java/io/github/sspanak/tt9/ui/main/keys/SoftKey.java +++ b/app/src/main/java/io/github/sspanak/tt9/ui/main/keys/SoftKey.java @@ -89,6 +89,7 @@ public class SoftKey extends androidx.appcompat.widget.AppCompatButton implement } else if (action == MotionEvent.ACTION_UP) { if (!repeat || hold) { hold = false; + repeat = false; boolean result = handleRelease(); lastPressedKey = ignoreLastPressedKey ? -1 : getId(); return result; diff --git a/app/src/main/java/io/github/sspanak/tt9/ui/main/keys/SoftKeyBackspace.java b/app/src/main/java/io/github/sspanak/tt9/ui/main/keys/SoftKeyBackspace.java index 69c7a735..67e8e0b2 100644 --- a/app/src/main/java/io/github/sspanak/tt9/ui/main/keys/SoftKeyBackspace.java +++ b/app/src/main/java/io/github/sspanak/tt9/ui/main/keys/SoftKeyBackspace.java @@ -12,8 +12,11 @@ import io.github.sspanak.tt9.ui.Vibration; public class SoftKeyBackspace extends SwipeableKey { private int repeat = 0; + + private boolean isActionPerformed = false; private final Handler waitForSwipe = new Handler(); + public SoftKeyBackspace(Context context) { super(context); } @@ -63,20 +66,36 @@ public class SoftKeyBackspace extends SwipeableKey { @Override final protected boolean handlePress() { super.handlePress(); - waitForSwipe.postDelayed(this::handlePressDebounced, 15); + isActionPerformed = false; + waitForSwipe.postDelayed(this::handlePressDebounced, 1 + getAverageSwipeProcessingTime()); return true; } + /** + * Avoids deleting text twice when swiping - first, when the user touches the screen, and then, + * when they finish the swipe gesture. + */ private void handlePressDebounced() { - if (notSwiped()) { + if (!isActionPerformed) { + isActionPerformed = true; deleteText(); } } + @Override + protected void handleStartSwipeX(float position, float delta) { + if (!isActionPerformed && validateTT9Handler()) { + isActionPerformed = true; + tt9.onBackspace(SettingsStore.BACKSPACE_ACCELERATION_REPEAT_DEBOUNCE); + } + } + + @Override final protected void handleHold() { + isActionPerformed = true; repeat++; deleteText(); } @@ -86,24 +105,11 @@ public class SoftKeyBackspace extends SwipeableKey { final protected boolean handleRelease() { vibrate(repeat > 0 ? Vibration.getReleaseVibration() : Vibration.getNoVibration()); repeat = 0; + return true; } - @Override - protected void handleStartSwipeX(float position, float delta) { - waitForSwipe.removeCallbacksAndMessages(null); - } - - - @Override - protected void handleEndSwipeX(float position, float delta) { - if (validateTT9Handler()) { - tt9.onBackspace(SettingsStore.BACKSPACE_ACCELERATION_REPEAT_DEBOUNCE); - } - } - - private void deleteText() { if (validateTT9Handler() && !tt9.onBackspace(repeat)) { // Limited or special numeric field (e.g. formatted money or dates) cannot always return diff --git a/app/src/main/java/io/github/sspanak/tt9/ui/main/keys/SwipeableKey.java b/app/src/main/java/io/github/sspanak/tt9/ui/main/keys/SwipeableKey.java index 30c16dd8..5a5819fc 100644 --- a/app/src/main/java/io/github/sspanak/tt9/ui/main/keys/SwipeableKey.java +++ b/app/src/main/java/io/github/sspanak/tt9/ui/main/keys/SwipeableKey.java @@ -7,8 +7,11 @@ import android.view.View; import io.github.sspanak.tt9.R; import io.github.sspanak.tt9.preferences.settings.SettingsStore; +import io.github.sspanak.tt9.util.Timer; abstract public class SwipeableKey extends SoftKey { + private static final String LOG_TAG = SwipeableKey.class.getSimpleName(); + private float HOLD_DURATION_THRESHOLD; protected float SWIPE_X_THRESHOLD; protected float SWIPE_Y_THRESHOLD; @@ -22,6 +25,10 @@ abstract public class SwipeableKey extends SoftKey { private float startY; private long startTime; + private int swipeCount = 0; + private long swipeProcessingTime = 0; + private long swipeProcessingTimeAverage = 40; + public SwipeableKey(Context context) { super(context); @@ -53,10 +60,31 @@ abstract public class SwipeableKey extends SoftKey { protected float getSwipeYThreshold(Context context) { return context.getResources().getDimensionPixelSize(R.dimen.numpad_key_height) / 10.0f; } + private void updateSwipeTimingStats() { + long time = Timer.get(LOG_TAG); + + long deltaT = time - swipeProcessingTimeAverage; + if (deltaT < -swipeProcessingTimeAverage || deltaT > 5) { + swipeCount = 0; + swipeProcessingTime = 0; + } + + swipeCount++; + swipeProcessingTime += time; + swipeProcessingTimeAverage = swipeProcessingTime / swipeCount; + } + + + protected long getAverageSwipeProcessingTime() { + return swipeProcessingTimeAverage; + } + + @Override public boolean onTouch(View v, MotionEvent event) { switch(event.getAction() & MotionEvent.ACTION_MASK) { case MotionEvent.ACTION_DOWN: + Timer.start(LOG_TAG); onPress(event); break; case MotionEvent.ACTION_MOVE: @@ -107,9 +135,11 @@ abstract public class SwipeableKey extends SoftKey { handleSwipeX(event.getRawX(), deltaX); } else if (Math.abs(deltaY) >= SWIPE_Y_THRESHOLD) { isSwipingY = true; + updateSwipeTimingStats(); handleStartSwipeY(event.getRawY(), deltaY); } else if (Math.abs(deltaX) >= SWIPE_X_THRESHOLD) { isSwipingX = true; + updateSwipeTimingStats(); handleStartSwipeX(event.getRawX(), deltaX); } else if (!isHolding && Math.abs(deltaX) < SWIPE_X_THRESHOLD && Math.abs(deltaY) < SWIPE_Y_THRESHOLD) { onLongClick(v);