Unexpected-Keyboard/srcs/juloo.keyboard2/Keyboard2View.java
2015-10-24 16:32:49 +02:00

440 lines
13 KiB
Java

package juloo.keyboard2;
import android.content.Context;
import android.content.SharedPreferences;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.RectF;
import android.graphics.Typeface;
import android.os.Handler;
import android.os.Message;
import android.os.Vibrator;
import android.preference.PreferenceManager;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.util.TypedValue;
import android.view.MotionEvent;
import android.view.View;
import java.util.ArrayList;
public class Keyboard2View extends View
implements View.OnTouchListener, Handler.Callback
{
private static final float KEY_PER_ROW = 10;
private static final long VIBRATE_MIN_INTERVAL = 100;
private KeyboardData _keyboard;
private ArrayList<KeyDown> _downKeys = new ArrayList<KeyDown>();
private int _flags = 0;
private Vibrator _vibratorService;
private long _lastVibration = 0;
private Handler _handler;
private static int _currentWhat = 0;
/*
** TODO: move config values in a Config object
*/
private float _marginTop;
private float _keyWidth;
private float _keyPadding;
private float _keyBgPadding;
private float _keyRound;
private float _subValueDist = 10f;
private boolean _vibrateEnabled = true;
private long _vibrateDuration = 20;
private long _longPressTimeout = 600;
private long _longPressInterval = 65;
private float _marginBottom;
private float _keyHeight;
private float _horizontalMargin;
private static Paint _keyBgPaint = new Paint();
private static Paint _keyDownBgPaint = new Paint();
private static Paint _keyLabelPaint;
private static Paint _keyLabelLockedPaint;
private static Paint _keySubLabelPaint;
private static Paint _keySubLabelRightPaint;
private static Paint _specialKeyLabelPaint;
private static Paint _specialKeyLabelLockedPaint;
private static Paint _specialKeySubLabelPaint;
private static Paint _specialKeySubLabelRightPaint;
private static RectF _tmpRect = new RectF();
public Keyboard2View(Context context, AttributeSet attrs)
{
super(context, attrs);
_vibratorService = (Vibrator)context.getSystemService(Context.VIBRATOR_SERVICE);
_handler = new Handler(this);
_horizontalMargin = getResources().getDimension(R.dimen.horizontal_margin);
_marginTop = getResources().getDimension(R.dimen.margin_top);
_marginBottom = getResources().getDimension(R.dimen.margin_bottom);
_keyHeight = getResources().getDimension(R.dimen.key_height);
_keyPadding = getResources().getDimension(R.dimen.key_padding);
_keyBgPadding = getResources().getDimension(R.dimen.key_bg_padding);
_keyRound = getResources().getDimension(R.dimen.key_round);
_keyBgPaint.setColor(getResources().getColor(R.color.key_bg));
_keyDownBgPaint.setColor(getResources().getColor(R.color.key_down_bg));
_keyLabelPaint = initLabelPaint(_keyLabelPaint, Paint.Align.CENTER, R.color.key_label, R.dimen.label_text_size, null);
_keyLabelLockedPaint = initLabelPaint(_keyLabelLockedPaint, Paint.Align.CENTER, R.color.key_label_locked, R.dimen.label_text_size, null);
_keySubLabelPaint = initLabelPaint(_keySubLabelPaint, Paint.Align.LEFT, R.color.key_sub_label, R.dimen.sublabel_text_size, null);
_keySubLabelRightPaint = initLabelPaint(_keySubLabelRightPaint, Paint.Align.RIGHT, R.color.key_sub_label, R.dimen.sublabel_text_size, null);
Typeface specialKeysFont = ((Keyboard2)getContext()).getSpecialKeyFont();
_specialKeyLabelPaint = initLabelPaint(_specialKeyLabelPaint, Paint.Align.CENTER, R.color.key_label, R.dimen.label_text_size, specialKeysFont);
_specialKeyLabelLockedPaint = initLabelPaint(_specialKeyLabelLockedPaint, Paint.Align.CENTER, R.color.key_label_locked, R.dimen.label_text_size, specialKeysFont);
_specialKeySubLabelPaint = initLabelPaint(_specialKeySubLabelPaint, Paint.Align.LEFT, R.color.key_sub_label, R.dimen.sublabel_text_size, specialKeysFont);
_specialKeySubLabelRightPaint = initLabelPaint(_specialKeySubLabelRightPaint, Paint.Align.RIGHT, R.color.key_sub_label, R.dimen.sublabel_text_size, specialKeysFont);
setOnTouchListener(this);
}
private Paint initLabelPaint(Paint paint, Paint.Align align, int color, int size, Typeface font)
{
if (paint == null)
{
paint = new Paint(Paint.ANTI_ALIAS_FLAG);
paint.setTextAlign(align);
paint.setColor(getResources().getColor(color));
paint.setTextSize(getResources().getDimension(size));
if (font != null)
paint.setTypeface(font);
}
return (paint);
}
public void reset_prefs()
{
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getContext());
_subValueDist = prefs.getFloat("sub_value_dist", _subValueDist);
_vibrateEnabled = prefs.getBoolean("vibrate_enabled", _vibrateEnabled);
_vibrateDuration = prefs.getInt("vibrate_duration", (int)_vibrateDuration);
_longPressTimeout = prefs.getInt("longpress_timeout", (int)_longPressTimeout);
_longPressInterval = prefs.getInt("longpress_interval", (int)_longPressInterval);
_marginBottom = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
prefs.getInt("margin_bottom", (int)_marginBottom), getResources().getDisplayMetrics());
_keyHeight = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
prefs.getInt("key_height", (int)_keyHeight), getResources().getDisplayMetrics());
_horizontalMargin = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
prefs.getInt("horizontal_margin", (int)_horizontalMargin), getResources().getDisplayMetrics());
reset();
}
public void setKeyboard(KeyboardData keyboard)
{
_keyboard = keyboard;
reset();
}
public void reset()
{
_flags = 0;
_downKeys.clear();
requestLayout();
invalidate();
}
@Override
public boolean onTouch(View v, MotionEvent event)
{
float x;
float y;
float keyW;
int p;
switch (event.getActionMasked())
{
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_POINTER_UP:
onTouchUp(event.getPointerId(event.getActionIndex()));
break ;
case MotionEvent.ACTION_DOWN:
case MotionEvent.ACTION_POINTER_DOWN:
p = event.getActionIndex();
onTouchDown(event.getX(p), event.getY(p), event.getPointerId(p));
break ;
case MotionEvent.ACTION_MOVE:
for (p = 0; p < event.getPointerCount(); p++)
onTouchMove(event.getX(p), event.getY(p), event.getPointerId(p));
break ;
default:
return (false);
}
return (true);
}
private KeyDown getKeyDown(int pointerId)
{
for (KeyDown k : _downKeys)
{
if (k.pointerId == pointerId)
return (k);
}
return (null);
}
private KeyDown getKeyDown(KeyboardData.Key key)
{
for (KeyDown k : _downKeys)
{
if (k.key == key)
return (k);
}
return (null);
}
private void onTouchMove(float moveX, float moveY, int pointerId)
{
KeyDown key = getKeyDown(pointerId);
KeyValue newValue;
if (key != null)
{
moveX -= key.downX;
moveY -= key.downY;
if ((Math.abs(moveX) + Math.abs(moveY)) < _subValueDist)
newValue = key.key.key0;
else if (moveX < 0)
newValue = (moveY < 0) ? key.key.key1 : key.key.key3;
else if (moveY < 0)
newValue = key.key.key2;
else
newValue = key.key.key4;
if (newValue != null && newValue != key.value)
{
if (key.timeoutWhat != -1)
{
_handler.removeMessages(key.timeoutWhat);
if ((newValue.getFlags() & KeyValue.FLAG_NOCHAR) == 0)
_handler.sendEmptyMessageDelayed(key.timeoutWhat, _longPressTimeout);
}
key.value = newValue;
key.flags = newValue.getFlags();
updateFlags();
invalidate();
vibrate();
}
}
}
private void onTouchDown(float touchX, float touchY, int pointerId)
{
float x;
float y;
float keyW;
y = _marginTop - _keyHeight;
for (KeyboardData.Row row : _keyboard.getRows())
{
y += _keyHeight;
if (touchY < y || touchY >= (y + _keyHeight))
continue ;
x = (KEY_PER_ROW * _keyWidth - row.getWidth(_keyWidth)) / 2 + _horizontalMargin;
for (KeyboardData.Key key : row)
{
keyW = _keyWidth * key.width;
if (touchX >= x && touchX < (x + keyW))
{
KeyDown down = getKeyDown(key);
if (down != null)
{
if ((down.flags & KeyValue.FLAG_LOCK) != 0)
{
down.flags ^= KeyValue.FLAG_LOCK;
down.flags |= KeyValue.FLAG_LOCKED;
}
else if (down.pointerId == -1)
down.pointerId = pointerId;
}
else
{
int what = _currentWhat++;
if (key.key0 != null && (key.key0.getFlags() & KeyValue.FLAG_NOCHAR) == 0)
_handler.sendEmptyMessageDelayed(what, _longPressTimeout);
_downKeys.add(new KeyDown(pointerId, key, touchX, touchY, what));
}
vibrate();
updateFlags();
invalidate();
return ;
}
x += keyW;
}
}
}
private void onTouchUp(int pointerId)
{
KeyDown k = getKeyDown(pointerId);
if (k != null)
{
if (k.timeoutWhat != -1)
{
_handler.removeMessages(k.timeoutWhat);
k.timeoutWhat = -1;
}
if ((k.flags & KeyValue.FLAG_KEEP_ON) != 0)
{
k.flags ^= KeyValue.FLAG_KEEP_ON;
k.pointerId = -1;
return ;
}
for (int i = 0; i < _downKeys.size(); i++)
{
KeyDown downKey = _downKeys.get(i);
if (downKey.pointerId == -1 && (downKey.flags & KeyValue.FLAG_LOCKED) == 0)
_downKeys.remove(i--);
else if ((downKey.flags & KeyValue.FLAG_KEEP_ON) != 0)
downKey.flags ^= KeyValue.FLAG_KEEP_ON;
}
if (k.value != null && (k.flags & (KeyValue.FLAG_LOCKED | KeyValue.FLAG_NOCHAR)) == 0)
((Keyboard2)getContext()).handleKeyUp(k.value, _flags);
_downKeys.remove(k);
updateFlags();
invalidate();
return ;
}
}
private void updateFlags()
{
_flags = 0;
for (KeyDown k : _downKeys)
_flags |= k.flags;
}
private void vibrate()
{
if (!_vibrateEnabled)
return ;
long now = System.currentTimeMillis();
if ((now - _lastVibration) > VIBRATE_MIN_INTERVAL)
{
_lastVibration = now;
try
{
_vibratorService.vibrate(_vibrateDuration);
}
catch (Exception e)
{
e.printStackTrace();
}
}
}
@Override
public boolean handleMessage(Message msg)
{
long now = System.currentTimeMillis();
for (KeyDown key : _downKeys)
{
if (key.timeoutWhat == msg.what)
{
_handler.sendEmptyMessageDelayed(msg.what, _longPressInterval);
((Keyboard2)getContext()).handleKeyUp(key.value, _flags);
vibrate();
return (true);
}
}
return (false);
}
@Override
public void onMeasure(int wSpec, int hSpec)
{
DisplayMetrics dm = getContext().getResources().getDisplayMetrics();
int height;
if (_keyboard.getRows() == null)
height = 0;
else
height = (int)(_keyHeight * ((float)_keyboard.getRows().size())
+ _marginTop + _marginBottom);
setMeasuredDimension(dm.widthPixels, height);
_keyWidth = (getWidth() - (_horizontalMargin * 2)) / KEY_PER_ROW;
}
@Override
protected void onDraw(Canvas canvas)
{
float x;
float y;
y = _marginTop;
for (KeyboardData.Row row : _keyboard.getRows())
{
x = (KEY_PER_ROW * _keyWidth - row.getWidth(_keyWidth)) / 2f + _horizontalMargin;
for (KeyboardData.Key k : row)
{
float keyW = _keyWidth * k.width;
KeyDown keyDown = getKeyDown(k);
_tmpRect.set(x + _keyBgPadding, y + _keyBgPadding,
x + keyW - _keyBgPadding, y + _keyHeight - _keyBgPadding);
if (keyDown != null)
canvas.drawRect(_tmpRect, _keyDownBgPaint);
else
canvas.drawRoundRect(_tmpRect, _keyRound, _keyRound, _keyBgPaint);
if (k.key0 != null)
drawLabel(canvas, k.key0, keyW / 2f + x, (_keyHeight + _keyLabelPaint.getTextSize()) / 2f + y,
(keyDown != null && (keyDown.flags & KeyValue.FLAG_LOCKED) != 0));
float subPadding = _keyBgPadding + _keyPadding;
if (k.key1 != null)
drawSubLabel(canvas, k.key1, x + subPadding, y + subPadding - _keySubLabelPaint.ascent(), false);
if (k.key3 != null)
drawSubLabel(canvas, k.key3, x + subPadding, y + _keyHeight - subPadding - _keySubLabelPaint.descent(), false);
if (k.key2 != null)
drawSubLabel(canvas, k.key2, x + keyW - subPadding, y + subPadding - _keySubLabelRightPaint.ascent(), true);
if (k.key4 != null)
drawSubLabel(canvas, k.key4, x + keyW - subPadding, y + _keyHeight - subPadding - _keySubLabelRightPaint.descent(), true);
x += keyW;
}
y += _keyHeight;
}
}
private void drawLabel(Canvas canvas, KeyValue k, float x, float y, boolean locked)
{
if ((k.getFlags() & KeyValue.FLAG_KEY_FONT) != 0)
canvas.drawText(k.getSymbol(_flags), x, y, locked ? _specialKeyLabelLockedPaint : _specialKeyLabelPaint);
else
canvas.drawText(k.getSymbol(_flags), x, y, locked ? _keyLabelLockedPaint : _keyLabelPaint);
}
private void drawSubLabel(Canvas canvas, KeyValue k, float x, float y, boolean right)
{
if ((k.getFlags() & KeyValue.FLAG_KEY_FONT) != 0)
canvas.drawText(k.getSymbol(_flags), x, y, right ? _specialKeySubLabelRightPaint : _specialKeySubLabelPaint);
else
canvas.drawText(k.getSymbol(_flags), x, y, right ? _keySubLabelRightPaint : _keySubLabelPaint);
}
private static class KeyDown
{
public int pointerId;
public KeyValue value;
public KeyboardData.Key key;
public float downX;
public float downY;
public int flags;
public int timeoutWhat;
public KeyDown(int pointerId, KeyboardData.Key key, float x, float y, int what)
{
this.pointerId = pointerId;
value = key.key0;
this.key = key;
downX = x;
downY = y;
flags = (value == null) ? 0 : value.getFlags();
timeoutWhat = what;
}
}
}