Merge "Fix inconsistent behavior with backspace in the Emoji pallete."

main
Yohei Yukawa 2014-01-27 08:11:50 +00:00 committed by Android (Google) Code Review
commit 0b58617951
1 changed files with 97 additions and 59 deletions

View File

@ -23,12 +23,13 @@ import android.content.SharedPreferences;
import android.content.res.ColorStateList; import android.content.res.ColorStateList;
import android.content.res.Resources; import android.content.res.Resources;
import android.content.res.TypedArray; import android.content.res.TypedArray;
import android.graphics.Color;
import android.graphics.Rect; import android.graphics.Rect;
import android.os.Build; import android.os.Build;
import android.os.CountDownTimer;
import android.preference.PreferenceManager; import android.preference.PreferenceManager;
import android.support.v4.view.PagerAdapter; import android.support.v4.view.PagerAdapter;
import android.support.v4.view.ViewPager; import android.support.v4.view.ViewPager;
import android.text.format.DateUtils;
import android.util.AttributeSet; import android.util.AttributeSet;
import android.util.Log; import android.util.Log;
import android.util.Pair; import android.util.Pair;
@ -58,6 +59,7 @@ import java.util.Arrays;
import java.util.Comparator; import java.util.Comparator;
import java.util.HashMap; import java.util.HashMap;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
/** /**
* View class to implement Emoji palettes. * View class to implement Emoji palettes.
@ -752,9 +754,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 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 int mDeleteKeyPressedBackgroundColor;
private final long mKeyRepeatStartTimeout; private final long mKeyRepeatStartTimeout;
private final long mKeyRepeatInterval; private final long mKeyRepeatInterval;
@ -765,61 +766,36 @@ public final class EmojiPalettesView extends LinearLayout implements OnTabChange
res.getColor(R.color.emoji_key_pressed_background_color); res.getColor(R.color.emoji_key_pressed_background_color);
mKeyRepeatStartTimeout = res.getInteger(R.integer.config_key_repeat_start_timeout); mKeyRepeatStartTimeout = res.getInteger(R.integer.config_key_repeat_start_timeout);
mKeyRepeatInterval = res.getInteger(R.integer.config_key_repeat_interval); 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 = private KeyboardActionListener mKeyboardActionListener =
KeyboardActionListener.EMPTY_LISTENER; KeyboardActionListener.EMPTY_LISTENER;
private DummyRepeatKeyRepeatTimer mTimer;
private synchronized void startRepeat() { // TODO: Do the same things done in PointerTracker
if (mTimer != null) { private final CountDownTimer mTimer;
abortRepeat(); private int mState = KEY_REPEAT_STATE_INITIALIZED;
} private int mRepeatCount = 0;
mTimer = new DummyRepeatKeyRepeatTimer();
mTimer.start();
}
private synchronized void abortRepeat() {
mTimer.abort();
mTimer = null;
}
// 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) {
}
}
}
public void abort() {
mAborted = true;
}
}
public void pressDelete(final int repeatCount) {
mKeyboardActionListener.onPressKey(
Constants.CODE_DELETE, repeatCount, true /* isSinglePointer */);
mKeyboardActionListener.onCodeInput(
Constants.CODE_DELETE, NOT_A_COORDINATE, NOT_A_COORDINATE);
mKeyboardActionListener.onReleaseKey(
Constants.CODE_DELETE, false /* withSliding */);
}
public void setKeyboardActionListener(final KeyboardActionListener listener) { public void setKeyboardActionListener(final KeyboardActionListener listener) {
mKeyboardActionListener = listener; mKeyboardActionListener = listener;
@ -827,18 +803,80 @@ public final class EmojiPalettesView extends LinearLayout implements OnTabChange
@Override @Override
public boolean onTouch(final View v, final MotionEvent event) { public boolean onTouch(final View v, final MotionEvent event) {
switch(event.getAction()) { switch (event.getActionMasked()) {
case MotionEvent.ACTION_DOWN: case MotionEvent.ACTION_DOWN:
v.setBackgroundColor(mDeleteKeyPressedBackgroundColor); onTouchDown(v);
pressDelete(0 /* repeatCount */);
startRepeat();
return true; 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: case MotionEvent.ACTION_UP:
v.setBackgroundColor(0); onTouchUp(v);
abortRepeat();
return true; return true;
} }
return false; return false;
} }
private void handleKeyDown() {
mKeyboardActionListener.onPressKey(
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;
}
private void onTouchDown(final View v) {
mTimer.cancel();
mRepeatCount = 0;
handleKeyDown();
v.setBackgroundColor(mDeleteKeyPressedBackgroundColor);
mState = KEY_REPEAT_STATE_KEY_DOWN;
mTimer.start();
}
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;
}
}
} }
} }