summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorYohei Yukawa <yukawa@google.com>2014-01-24 15:31:41 +0900
committerAdnan <adnan@cyngn.com>2015-02-19 13:26:45 -0800
commit6739ba40a7c030810088d58c9122600f0d94494f (patch)
treeed1ebeba8b1d082fbf5d8da71c226976275caf2c
parent1b4dd691c77ecb11bbb12e5e6078d34492460095 (diff)
downloadandroid_packages_inputmethods_LatinIME-6739ba40a7c030810088d58c9122600f0d94494f.tar.gz
android_packages_inputmethods_LatinIME-6739ba40a7c030810088d58c9122600f0d94494f.tar.bz2
android_packages_inputmethods_LatinIME-6739ba40a7c030810088d58c9122600f0d94494f.zip
Fix inconsistent behavior with backspace in the Emoji pallete.
In some ways, the delete key on the Emoji palette was inconsistent with that in other keyboard layouts. - It deletes a character in down events, not up events. - A user cannot cancel the event by moving the finger away from the key. This patch fixes these inconsistencies by revisin EmojiPalettesView.DeleteKeyOnTouchListener. Notable changes are: - An explicit state machine is introduced because there are different event sequences to be considered. - Background thread is replaced with CountDownTimer so tha key-repeat events can be naturally generated in the UI thread. - MotionEvent.ACTION_MOVE is now handled to cancel the subsequent delete key events when the finger is moved away from the key area. Bug: 12464067 Change-Id: Ibc360a1394afef368a8d9af7b4c0e99e8ce1d83c
-rw-r--r--java/src/com/android/inputmethod/keyboard/EmojiPalettesView.java148
1 files changed, 93 insertions, 55 deletions
diff --git a/java/src/com/android/inputmethod/keyboard/EmojiPalettesView.java b/java/src/com/android/inputmethod/keyboard/EmojiPalettesView.java
index f12373503..d1ee53cdb 100644
--- a/java/src/com/android/inputmethod/keyboard/EmojiPalettesView.java
+++ b/java/src/com/android/inputmethod/keyboard/EmojiPalettesView.java
@@ -23,12 +23,13 @@ import android.content.SharedPreferences;
import android.content.res.ColorStateList;
import android.content.res.Resources;
import android.content.res.TypedArray;
+import android.graphics.Color;
import android.graphics.Rect;
import android.os.Build;
+import android.os.CountDownTimer;
import android.preference.PreferenceManager;
import android.support.v4.view.PagerAdapter;
import android.support.v4.view.ViewPager;
-import android.text.format.DateUtils;
import android.util.AttributeSet;
import android.util.Log;
import android.util.Pair;
@@ -58,6 +59,7 @@ import java.util.Arrays;
import java.util.Comparator;
import java.util.HashMap;
import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.TimeUnit;
/**
* View class to implement Emoji palettes.
@@ -735,9 +737,8 @@ public final class EmojiPalettesView extends LinearLayout implements OnTabChange
}
}
- // TODO: Do the same things done in PointerTracker
private static class DeleteKeyOnTouchListener implements OnTouchListener {
- private static final long MAX_REPEAT_COUNT_TIME = 30 * DateUtils.SECOND_IN_MILLIS;
+ private static final long MAX_REPEAT_COUNT_TIME = TimeUnit.SECONDS.toMillis(30);
private final int mDeleteKeyPressedBackgroundColor;
private final long mKeyRepeatStartTimeout;
private final long mKeyRepeatInterval;
@@ -748,80 +749,117 @@ public final class EmojiPalettesView extends LinearLayout implements OnTabChange
res.getColor(R.color.emoji_key_pressed_background_color);
mKeyRepeatStartTimeout = res.getInteger(R.integer.config_key_repeat_start_timeout);
mKeyRepeatInterval = res.getInteger(R.integer.config_key_repeat_interval);
+ mTimer = new CountDownTimer(MAX_REPEAT_COUNT_TIME, mKeyRepeatInterval) {
+ @Override
+ public void onTick(long millisUntilFinished) {
+ final long elapsed = MAX_REPEAT_COUNT_TIME - millisUntilFinished;
+ if (elapsed < mKeyRepeatStartTimeout) {
+ return;
+ }
+ onKeyRepeat();
+ }
+ @Override
+ public void onFinish() {
+ onKeyRepeat();
+ }
+ };
}
+ /** Key-repeat state. */
+ private static final int KEY_REPEAT_STATE_INITIALIZED = 0;
+ // The key is touched but auto key-repeat is not started yet.
+ private static final int KEY_REPEAT_STATE_KEY_DOWN = 1;
+ // At least one key-repeat event has already been triggered and the key is not released.
+ private static final int KEY_REPEAT_STATE_KEY_REPEAT = 2;
+
private KeyboardActionListener mKeyboardActionListener =
KeyboardActionListener.EMPTY_LISTENER;
- private DummyRepeatKeyRepeatTimer mTimer;
- private synchronized void startRepeat() {
- if (mTimer != null) {
- abortRepeat();
- }
- mTimer = new DummyRepeatKeyRepeatTimer();
- mTimer.start();
- }
+ // TODO: Do the same things done in PointerTracker
+ private final CountDownTimer mTimer;
+ private int mState = KEY_REPEAT_STATE_INITIALIZED;
+ private int mRepeatCount = 0;
- private synchronized void abortRepeat() {
- mTimer.abort();
- mTimer = null;
+ public void setKeyboardActionListener(final KeyboardActionListener listener) {
+ mKeyboardActionListener = listener;
}
- // TODO: Remove
- // This function is mimicking the repeat code in PointerTracker.
- // Specifically referring to PointerTracker#startRepeatKey and PointerTracker#onKeyRepeat.
- private class DummyRepeatKeyRepeatTimer extends Thread {
- public boolean mAborted = false;
-
- @Override
- public void run() {
- int repeatCount = 1;
- int timeCount = 0;
- while (timeCount < MAX_REPEAT_COUNT_TIME && !mAborted) {
- if (timeCount > mKeyRepeatStartTimeout) {
- pressDelete(repeatCount);
- }
- timeCount += mKeyRepeatInterval;
- ++repeatCount;
- try {
- Thread.sleep(mKeyRepeatInterval);
- } catch (InterruptedException e) {
- }
+ @Override
+ public boolean onTouch(final View v, final MotionEvent event) {
+ switch (event.getActionMasked()) {
+ case MotionEvent.ACTION_DOWN:
+ onTouchDown(v);
+ return true;
+ case MotionEvent.ACTION_MOVE:
+ final float x = event.getX();
+ final float y = event.getY();
+ if (x < 0.0f || v.getWidth() < x || y < 0.0f || v.getHeight() < y) {
+ // Stop generating key events once the finger moves away from the view area.
+ onTouchCanceled(v);
}
+ return true;
+ case MotionEvent.ACTION_CANCEL:
+ case MotionEvent.ACTION_UP:
+ onTouchUp(v);
+ return true;
}
-
- public void abort() {
- mAborted = true;
- }
+ return false;
}
- public void pressDelete(int repeatCount) {
+ private void handleKeyDown() {
mKeyboardActionListener.onPressKey(
- Constants.CODE_DELETE, repeatCount, true /* isSinglePointer */);
+ Constants.CODE_DELETE, mRepeatCount, true /* isSinglePointer */);
+ }
+
+ private void handleKeyUp() {
mKeyboardActionListener.onCodeInput(
Constants.CODE_DELETE, NOT_A_COORDINATE, NOT_A_COORDINATE);
mKeyboardActionListener.onReleaseKey(
Constants.CODE_DELETE, false /* withSliding */);
+ ++mRepeatCount;
}
- public void setKeyboardActionListener(KeyboardActionListener listener) {
- mKeyboardActionListener = listener;
+ private void onTouchDown(final View v) {
+ mTimer.cancel();
+ mRepeatCount = 0;
+ handleKeyDown();
+ v.setBackgroundColor(mDeleteKeyPressedBackgroundColor);
+ mState = KEY_REPEAT_STATE_KEY_DOWN;
+ mTimer.start();
}
- @Override
- public boolean onTouch(View v, MotionEvent event) {
- switch(event.getAction()) {
- case MotionEvent.ACTION_DOWN:
- v.setBackgroundColor(mDeleteKeyPressedBackgroundColor);
- pressDelete(0 /* repeatCount */);
- startRepeat();
- return true;
- case MotionEvent.ACTION_UP:
- v.setBackgroundColor(0);
- abortRepeat();
- return true;
+ private void onTouchUp(final View v) {
+ mTimer.cancel();
+ if (mState == KEY_REPEAT_STATE_KEY_DOWN) {
+ handleKeyUp();
+ }
+ v.setBackgroundColor(Color.TRANSPARENT);
+ mState = KEY_REPEAT_STATE_INITIALIZED;
+ }
+
+ private void onTouchCanceled(final View v) {
+ mTimer.cancel();
+ v.setBackgroundColor(Color.TRANSPARENT);
+ mState = KEY_REPEAT_STATE_INITIALIZED;
+ }
+
+ // Called by {@link #mTimer} in the UI thread as an auto key-repeat signal.
+ private void onKeyRepeat() {
+ switch (mState) {
+ case KEY_REPEAT_STATE_INITIALIZED:
+ // Basically this should not happen.
+ break;
+ case KEY_REPEAT_STATE_KEY_DOWN:
+ // Do not call {@link #handleKeyDown} here because it has already been called
+ // in {@link #onTouchDown}.
+ handleKeyUp();
+ mState = KEY_REPEAT_STATE_KEY_REPEAT;
+ break;
+ case KEY_REPEAT_STATE_KEY_REPEAT:
+ handleKeyDown();
+ handleKeyUp();
+ break;
}
- return false;
}
}
}