LatinIME/java/src/com/android/inputmethod/latin/LatinKeyboard.java

784 lines
30 KiB
Java
Raw Normal View History

/*
* Copyright (C) 2008 The Android Open Source Project
*
* 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 com.android.inputmethod.latin;
import java.util.List;
import java.util.Locale;
import android.content.Context;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.content.res.XmlResourceParser;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.ColorFilter;
import android.graphics.Paint;
import android.graphics.PixelFormat;
import android.graphics.PorterDuff;
import android.graphics.Rect;
import android.graphics.Paint.Align;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.inputmethodservice.Keyboard;
import android.text.TextPaint;
import android.util.Log;
import android.view.ViewConfiguration;
import android.view.inputmethod.EditorInfo;
public class LatinKeyboard extends Keyboard {
private static final boolean DEBUG_PREFERRED_LETTER = false;
private static final String TAG = "LatinKeyboard";
private Drawable mShiftLockIcon;
private Drawable mShiftLockPreviewIcon;
private Drawable mOldShiftIcon;
private Drawable mSpaceIcon;
private Drawable mSpacePreviewIcon;
private Drawable mMicIcon;
private Drawable mMicPreviewIcon;
private Drawable m123MicIcon;
private Drawable m123MicPreviewIcon;
private Drawable mButtonArrowLeftIcon;
private Drawable mButtonArrowRightIcon;
private Key mShiftKey;
private Key mEnterKey;
private Key mF1Key;
private Key mSpaceKey;
private Key m123Key;
private int mSpaceKeyIndex = -1;
private int mSpaceDragStartX;
private int mSpaceDragLastDiff;
/* package */ Locale mLocale;
private LanguageSwitcher mLanguageSwitcher;
private Resources mRes;
private Context mContext;
// Whether this keyboard has voice icon on it
private boolean mHasVoiceButton;
// Whether voice icon is enabled at all
private boolean mVoiceEnabled;
private boolean mIsAlphaKeyboard;
private CharSequence m123Label;
private boolean mCurrentlyInSpace;
private SlidingLocaleDrawable mSlidingLocaleIcon;
private int[] mPrefLetterFrequencies;
private int mPrefLetter;
private int mPrefLetterX;
private int mPrefLetterY;
private int mPrefDistance;
// TODO: generalize for any keyboardId
private boolean mIsBlackSym;
private static final int SHIFT_OFF = 0;
private static final int SHIFT_ON = 1;
private static final int SHIFT_LOCKED = 2;
private int mShiftState = SHIFT_OFF;
private static final float SPACEBAR_DRAG_THRESHOLD = 0.8f;
private static final float OVERLAP_PERCENTAGE_LOW_PROB = 0.70f;
private static final float OVERLAP_PERCENTAGE_HIGH_PROB = 0.85f;
static int sSpacebarVerticalCorrection;
public LatinKeyboard(Context context, int xmlLayoutResId) {
this(context, xmlLayoutResId, 0);
}
public LatinKeyboard(Context context, int xmlLayoutResId, int mode) {
super(context, xmlLayoutResId, mode);
final Resources res = context.getResources();
mContext = context;
mRes = res;
mShiftLockIcon = res.getDrawable(R.drawable.sym_keyboard_shift_locked);
mShiftLockPreviewIcon = res.getDrawable(R.drawable.sym_keyboard_feedback_shift_locked);
mShiftLockPreviewIcon.setBounds(0, 0,
mShiftLockPreviewIcon.getIntrinsicWidth(),
mShiftLockPreviewIcon.getIntrinsicHeight());
mSpaceIcon = res.getDrawable(R.drawable.sym_keyboard_space);
mSpacePreviewIcon = res.getDrawable(R.drawable.sym_keyboard_feedback_space);
mMicIcon = res.getDrawable(R.drawable.sym_keyboard_mic);
mMicPreviewIcon = res.getDrawable(R.drawable.sym_keyboard_feedback_mic);
setDefaultBounds(mMicPreviewIcon);
mButtonArrowLeftIcon = res.getDrawable(R.drawable.sym_keyboard_language_arrows_left);
mButtonArrowRightIcon = res.getDrawable(R.drawable.sym_keyboard_language_arrows_right);
m123MicIcon = res.getDrawable(R.drawable.sym_keyboard_123_mic);
m123MicPreviewIcon = res.getDrawable(R.drawable.sym_keyboard_feedback_123_mic);
setDefaultBounds(m123MicPreviewIcon);
sSpacebarVerticalCorrection = res.getDimensionPixelOffset(
R.dimen.spacebar_vertical_correction);
mIsAlphaKeyboard = xmlLayoutResId == R.xml.kbd_qwerty
|| xmlLayoutResId == R.xml.kbd_qwerty_black;
mSpaceKeyIndex = indexOf((int) ' ');
}
public LatinKeyboard(Context context, int layoutTemplateResId,
CharSequence characters, int columns, int horizontalPadding) {
super(context, layoutTemplateResId, characters, columns, horizontalPadding);
}
@Override
protected Key createKeyFromXml(Resources res, Row parent, int x, int y,
XmlResourceParser parser) {
Key key = new LatinKey(res, parent, x, y, parser);
switch (key.codes[0]) {
case 10:
mEnterKey = key;
break;
case LatinKeyboardView.KEYCODE_F1:
mF1Key = key;
break;
case 32:
mSpaceKey = key;
break;
case KEYCODE_MODE_CHANGE:
m123Key = key;
m123Label = key.label;
break;
}
return key;
}
void setImeOptions(Resources res, int mode, int options) {
if (mEnterKey != null) {
// Reset some of the rarely used attributes.
mEnterKey.popupCharacters = null;
mEnterKey.popupResId = 0;
mEnterKey.text = null;
switch (options&(EditorInfo.IME_MASK_ACTION|EditorInfo.IME_FLAG_NO_ENTER_ACTION)) {
case EditorInfo.IME_ACTION_GO:
mEnterKey.iconPreview = null;
mEnterKey.icon = null;
mEnterKey.label = res.getText(R.string.label_go_key);
break;
case EditorInfo.IME_ACTION_NEXT:
mEnterKey.iconPreview = null;
mEnterKey.icon = null;
mEnterKey.label = res.getText(R.string.label_next_key);
break;
case EditorInfo.IME_ACTION_DONE:
mEnterKey.iconPreview = null;
mEnterKey.icon = null;
mEnterKey.label = res.getText(R.string.label_done_key);
break;
case EditorInfo.IME_ACTION_SEARCH:
mEnterKey.iconPreview = res.getDrawable(
R.drawable.sym_keyboard_feedback_search);
mEnterKey.icon = res.getDrawable(mIsBlackSym ?
R.drawable.sym_bkeyboard_search : R.drawable.sym_keyboard_search);
mEnterKey.label = null;
break;
case EditorInfo.IME_ACTION_SEND:
mEnterKey.iconPreview = null;
mEnterKey.icon = null;
mEnterKey.label = res.getText(R.string.label_send_key);
break;
default:
if (mode == KeyboardSwitcher.MODE_IM) {
mEnterKey.icon = null;
mEnterKey.iconPreview = null;
mEnterKey.label = ":-)";
mEnterKey.text = ":-) ";
mEnterKey.popupResId = R.xml.popup_smileys;
} else {
mEnterKey.iconPreview = res.getDrawable(
R.drawable.sym_keyboard_feedback_return);
mEnterKey.icon = res.getDrawable(mIsBlackSym ?
R.drawable.sym_bkeyboard_return : R.drawable.sym_keyboard_return);
mEnterKey.label = null;
}
break;
}
// Set the initial size of the preview icon
if (mEnterKey.iconPreview != null) {
mEnterKey.iconPreview.setBounds(0, 0,
mEnterKey.iconPreview.getIntrinsicWidth(),
mEnterKey.iconPreview.getIntrinsicHeight());
}
}
}
void enableShiftLock() {
int index = getShiftKeyIndex();
if (index >= 0) {
mShiftKey = getKeys().get(index);
if (mShiftKey instanceof LatinKey) {
((LatinKey)mShiftKey).enableShiftLock();
}
mOldShiftIcon = mShiftKey.icon;
}
}
void setShiftLocked(boolean shiftLocked) {
if (mShiftKey != null) {
if (shiftLocked) {
mShiftKey.on = true;
mShiftKey.icon = mShiftLockIcon;
mShiftState = SHIFT_LOCKED;
} else {
mShiftKey.on = false;
mShiftKey.icon = mShiftLockIcon;
mShiftState = SHIFT_ON;
}
}
}
boolean isShiftLocked() {
return mShiftState == SHIFT_LOCKED;
}
@Override
public boolean setShifted(boolean shiftState) {
boolean shiftChanged = false;
if (mShiftKey != null) {
if (shiftState == false) {
shiftChanged = mShiftState != SHIFT_OFF;
mShiftState = SHIFT_OFF;
mShiftKey.on = false;
mShiftKey.icon = mOldShiftIcon;
} else {
if (mShiftState == SHIFT_OFF) {
shiftChanged = mShiftState == SHIFT_OFF;
mShiftState = SHIFT_ON;
mShiftKey.icon = mShiftLockIcon;
}
}
} else {
return super.setShifted(shiftState);
}
return shiftChanged;
}
@Override
public boolean isShifted() {
if (mShiftKey != null) {
return mShiftState != SHIFT_OFF;
} else {
return super.isShifted();
}
}
/* package */ boolean isAlphaKeyboard() {
return mIsAlphaKeyboard;
}
public void setBlackFlag(boolean f) {
mIsBlackSym = f;
if (f) {
mShiftLockIcon = mRes.getDrawable(R.drawable.sym_bkeyboard_shift_locked);
mSpaceIcon = mRes.getDrawable(R.drawable.sym_bkeyboard_space);
mMicIcon = mRes.getDrawable(R.drawable.sym_bkeyboard_mic);
m123MicIcon = mRes.getDrawable(R.drawable.sym_bkeyboard_123_mic);
} else {
mShiftLockIcon = mRes.getDrawable(R.drawable.sym_keyboard_shift_locked);
mSpaceIcon = mRes.getDrawable(R.drawable.sym_keyboard_space);
mMicIcon = mRes.getDrawable(R.drawable.sym_keyboard_mic);
m123MicIcon = mRes.getDrawable(R.drawable.sym_keyboard_123_mic);
}
updateF1Key();
if (mSpaceKey != null) {
mSpaceKey.icon = mSpaceIcon;
updateSpaceBarForLocale(f);
}
}
private void setDefaultBounds(Drawable drawable) {
drawable.setBounds(0, 0, drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight());
}
public void setVoiceMode(boolean hasVoiceButton, boolean hasVoice) {
mHasVoiceButton = hasVoiceButton;
mVoiceEnabled = hasVoice;
updateF1Key();
}
private void updateF1Key() {
if (mF1Key == null) return;
if (m123Key != null && mIsAlphaKeyboard) {
if (mVoiceEnabled && !mHasVoiceButton) {
m123Key.icon = m123MicIcon;
m123Key.iconPreview = m123MicPreviewIcon;
m123Key.label = null;
} else {
m123Key.icon = null;
m123Key.iconPreview = null;
m123Key.label = m123Label;
}
}
if (mHasVoiceButton && mVoiceEnabled) {
mF1Key.codes = new int[] { LatinKeyboardView.KEYCODE_VOICE };
mF1Key.label = null;
mF1Key.icon = mMicIcon;
mF1Key.iconPreview = mMicPreviewIcon;
} else {
mF1Key.label = ",";
mF1Key.codes = new int[] { ',' };
mF1Key.icon = null;
mF1Key.iconPreview = null;
}
}
private void updateSpaceBarForLocale(boolean isBlack) {
if (mLocale != null) {
// Create the graphic for spacebar
Bitmap buffer = Bitmap.createBitmap(mSpaceKey.width, mSpaceIcon.getIntrinsicHeight(),
Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(buffer);
drawSpaceBar(canvas, buffer.getWidth(), buffer.getHeight(), 255, isBlack);
mSpaceKey.icon = new BitmapDrawable(mRes, buffer);
mSpaceKey.repeatable = mLanguageSwitcher.getLocaleCount() < 2;
} else {
mSpaceKey.icon = isBlack ? mRes.getDrawable(R.drawable.sym_bkeyboard_space)
: mRes.getDrawable(R.drawable.sym_keyboard_space);
mSpaceKey.repeatable = true;
}
}
private void drawSpaceBar(Canvas canvas, int width, int height, int opacity, boolean isBlack) {
canvas.drawColor(mRes.getColor(R.color.latinkeyboard_transparent), PorterDuff.Mode.CLEAR);
Paint paint = new Paint();
paint.setAntiAlias(true);
paint.setAlpha(opacity);
// Get the text size from the theme
paint.setTextSize(getTextSizeFromTheme(android.R.style.TextAppearance_Small, 14));
paint.setTextAlign(Align.CENTER);
final String language = getInputLanguage(mSpaceKey.width, paint);
final int ascent = (int) -paint.ascent();
int shadowColor = isBlack ? mRes.getColor(R.color.latinkeyboard_bar_language_shadow_black)
: mRes.getColor(R.color.latinkeyboard_bar_language_shadow_white);
paint.setColor(shadowColor);
canvas.drawText(language, width / 2, ascent - 1, paint);
paint.setColor(mRes.getColor(R.color.latinkeyboard_bar_language_text));
canvas.drawText(language, width / 2, ascent, paint);
// Put arrows on either side of the text
if (mLanguageSwitcher.getLocaleCount() > 1) {
Rect bounds = new Rect();
paint.getTextBounds(language, 0, language.length(), bounds);
drawButtonArrow(mButtonArrowLeftIcon, canvas,
(mSpaceKey.width - bounds.right) / 2
- mButtonArrowLeftIcon.getIntrinsicWidth(),
(int) paint.getTextSize());
drawButtonArrow(mButtonArrowRightIcon, canvas,
(mSpaceKey.width + bounds.right) / 2, (int) paint.getTextSize());
}
// Draw the spacebar icon at the bottom
int x = (width - mSpaceIcon.getIntrinsicWidth()) / 2;
int y = height - mSpaceIcon.getIntrinsicHeight();
mSpaceIcon.setBounds(x, y,
x + mSpaceIcon.getIntrinsicWidth(), y + mSpaceIcon.getIntrinsicHeight());
mSpaceIcon.draw(canvas);
}
private void drawButtonArrow(Drawable arrow, Canvas canvas, int x, int bottomY) {
arrow.setBounds(x, bottomY - arrow.getIntrinsicHeight(), x + arrow.getIntrinsicWidth(),
bottomY);
arrow.draw(canvas);
}
private String getInputLanguage(int widthAvail, Paint paint) {
return chooseDisplayName(mLanguageSwitcher.getInputLocale(), widthAvail, paint);
}
private String getNextInputLanguage(int widthAvail, Paint paint) {
return chooseDisplayName(mLanguageSwitcher.getNextInputLocale(), widthAvail, paint);
}
private String getPrevInputLanguage(int widthAvail, Paint paint) {
return chooseDisplayName(mLanguageSwitcher.getPrevInputLocale(), widthAvail, paint);
}
private String chooseDisplayName(Locale locale, int widthAvail, Paint paint) {
if (widthAvail < (int) (.35 * getMinWidth())) {
return LanguageSwitcher.toTitleCase(locale.getLanguage().substring(0, 2));
} else {
return LanguageSwitcher.toTitleCase(locale.getDisplayLanguage(locale));
}
}
private void updateLocaleDrag(int diff) {
if (mSlidingLocaleIcon == null) {
mSlidingLocaleIcon = new SlidingLocaleDrawable(mSpacePreviewIcon, mSpaceKey.width,
mSpacePreviewIcon.getIntrinsicHeight());
mSlidingLocaleIcon.setBounds(0, 0, mSpaceKey.width,
mSpacePreviewIcon.getIntrinsicHeight());
mSpaceKey.iconPreview = mSlidingLocaleIcon;
}
mSlidingLocaleIcon.setDiff(diff);
if (Math.abs(diff) == Integer.MAX_VALUE) {
mSpaceKey.iconPreview = mSpacePreviewIcon;
} else {
mSpaceKey.iconPreview = mSlidingLocaleIcon;
}
mSpaceKey.iconPreview.invalidateSelf();
}
public int getLanguageChangeDirection() {
if (mSpaceKey == null || mLanguageSwitcher.getLocaleCount() < 2
|| Math.abs(mSpaceDragLastDiff) < mSpaceKey.width * SPACEBAR_DRAG_THRESHOLD ) {
return 0; // No change
}
return mSpaceDragLastDiff > 0 ? 1 : -1;
}
public void setLanguageSwitcher(LanguageSwitcher switcher) {
mLanguageSwitcher = switcher;
Locale locale = mLanguageSwitcher.getLocaleCount() > 0
? mLanguageSwitcher.getInputLocale()
: null;
// If the language count is 1 and is the same as the system language, don't show it.
if (locale != null
&& mLanguageSwitcher.getLocaleCount() == 1
&& mLanguageSwitcher.getSystemLocale().getLanguage()
.equalsIgnoreCase(locale.getLanguage())) {
locale = null;
}
if (mLocale != null && mLocale.equals(locale)) return;
mLocale = locale;
updateSpaceBarForLocale(mIsBlackSym);
}
boolean isCurrentlyInSpace() {
return mCurrentlyInSpace;
}
void setPreferredLetters(int[] frequencies) {
mPrefLetterFrequencies = frequencies;
mPrefLetter = 0;
}
void keyReleased() {
mCurrentlyInSpace = false;
mSpaceDragLastDiff = 0;
mPrefLetter = 0;
mPrefLetterX = 0;
mPrefLetterY = 0;
mPrefDistance = Integer.MAX_VALUE;
if (mSpaceKey != null) {
updateLocaleDrag(Integer.MAX_VALUE);
}
}
/**
* Does the magic of locking the touch gesture into the spacebar when
* switching input languages.
*/
boolean isInside(LatinKey key, int x, int y) {
final int code = key.codes[0];
if (code == KEYCODE_SHIFT ||
code == KEYCODE_DELETE) {
y -= key.height / 10;
if (code == KEYCODE_SHIFT) x += key.width / 6;
if (code == KEYCODE_DELETE) x -= key.width / 6;
} else if (code == LatinIME.KEYCODE_SPACE) {
y += LatinKeyboard.sSpacebarVerticalCorrection;
if (mLanguageSwitcher.getLocaleCount() > 1) {
if (mCurrentlyInSpace) {
int diff = x - mSpaceDragStartX;
if (Math.abs(diff - mSpaceDragLastDiff) > 0) {
updateLocaleDrag(diff);
}
mSpaceDragLastDiff = diff;
return true;
} else {
boolean insideSpace = key.isInsideSuper(x, y);
if (insideSpace) {
mCurrentlyInSpace = true;
mSpaceDragStartX = x;
updateLocaleDrag(0);
}
return insideSpace;
}
}
} else if (mPrefLetterFrequencies != null) {
// New coordinate? Reset
if (mPrefLetterX != x || mPrefLetterY != y) {
mPrefLetter = 0;
mPrefDistance = Integer.MAX_VALUE;
}
// Handle preferred next letter
final int[] pref = mPrefLetterFrequencies;
if (mPrefLetter > 0) {
if (DEBUG_PREFERRED_LETTER) {
if (mPrefLetter == code && !key.isInsideSuper(x, y)) {
Log.d(TAG, "CORRECTED !!!!!!");
}
}
return mPrefLetter == code;
} else {
final boolean inside = key.isInsideSuper(x, y);
int[] nearby = getNearestKeys(x, y);
List<Key> nearbyKeys = getKeys();
if (inside) {
// If it's a preferred letter
if (inPrefList(code, pref)) {
// Check if its frequency is much lower than a nearby key
mPrefLetter = code;
mPrefLetterX = x;
mPrefLetterY = y;
for (int i = 0; i < nearby.length; i++) {
Key k = nearbyKeys.get(nearby[i]);
if (k != key && inPrefList(k.codes[0], pref)) {
final int dist = distanceFrom(k, x, y);
if (dist < (int) (k.width * OVERLAP_PERCENTAGE_LOW_PROB) &&
(pref[k.codes[0]] > pref[mPrefLetter] * 3)) {
mPrefLetter = k.codes[0];
mPrefDistance = dist;
if (DEBUG_PREFERRED_LETTER) {
Log.d(TAG, "CORRECTED ALTHOUGH PREFERRED !!!!!!");
}
break;
}
}
}
return mPrefLetter == code;
}
}
// Get the surrounding keys and intersect with the preferred list
// For all in the intersection
// if distance from touch point is within a reasonable distance
// make this the pref letter
// If no pref letter
// return inside;
// else return thiskey == prefletter;
for (int i = 0; i < nearby.length; i++) {
Key k = nearbyKeys.get(nearby[i]);
if (inPrefList(k.codes[0], pref)) {
final int dist = distanceFrom(k, x, y);
if (dist < (int) (k.width * OVERLAP_PERCENTAGE_HIGH_PROB)
&& dist < mPrefDistance) {
mPrefLetter = k.codes[0];
mPrefLetterX = x;
mPrefLetterY = y;
mPrefDistance = dist;
}
}
}
// Didn't find any
if (mPrefLetter == 0) {
return inside;
} else {
return mPrefLetter == code;
}
}
}
// Lock into the spacebar
if (mCurrentlyInSpace) return false;
return key.isInsideSuper(x, y);
}
private boolean inPrefList(int code, int[] pref) {
if (code < pref.length && code >= 0) return pref[code] > 0;
return false;
}
private int distanceFrom(Key k, int x, int y) {
if (y > k.y && y < k.y + k.height) {
return Math.abs(k.x + k.width / 2 - x);
} else {
return Integer.MAX_VALUE;
}
}
@Override
public int[] getNearestKeys(int x, int y) {
if (mCurrentlyInSpace) {
return new int[] { mSpaceKeyIndex };
} else {
return super.getNearestKeys(x, y);
}
}
private int indexOf(int code) {
List<Key> keys = getKeys();
int count = keys.size();
for (int i = 0; i < count; i++) {
if (keys.get(i).codes[0] == code) return i;
}
return -1;
}
private int getTextSizeFromTheme(int style, int defValue) {
TypedArray array = mContext.getTheme().obtainStyledAttributes(
style, new int[] { android.R.attr.textSize });
int textSize = array.getDimensionPixelSize(array.getResourceId(0, 0), defValue);
return textSize;
}
class LatinKey extends Keyboard.Key {
private boolean mShiftLockEnabled;
public LatinKey(Resources res, Keyboard.Row parent, int x, int y,
XmlResourceParser parser) {
super(res, parent, x, y, parser);
if (popupCharacters != null && popupCharacters.length() == 0) {
// If there is a keyboard with no keys specified in popupCharacters
popupResId = 0;
}
}
void enableShiftLock() {
mShiftLockEnabled = true;
}
@Override
public void onReleased(boolean inside) {
if (!mShiftLockEnabled) {
super.onReleased(inside);
} else {
pressed = !pressed;
}
}
/**
* Overriding this method so that we can reduce the target area for certain keys.
*/
@Override
public boolean isInside(int x, int y) {
boolean result = LatinKeyboard.this.isInside(this, x, y);
return result;
}
boolean isInsideSuper(int x, int y) {
return super.isInside(x, y);
}
}
/**
* Animation to be displayed on the spacebar preview popup when switching
* languages by swiping the spacebar. It draws the current, previous and
* next languages and moves them by the delta of touch movement on the spacebar.
*/
class SlidingLocaleDrawable extends Drawable {
private int mWidth;
private int mHeight;
private Drawable mBackground;
private int mDiff;
private TextPaint mTextPaint;
private int mMiddleX;
private int mAscent;
private Drawable mLeftDrawable;
private Drawable mRightDrawable;
private boolean mHitThreshold;
private int mThreshold;
private String mCurrentLanguage;
private String mNextLanguage;
private String mPrevLanguage;
public SlidingLocaleDrawable(Drawable background, int width, int height) {
mBackground = background;
mBackground.setBounds(0, 0,
mBackground.getIntrinsicWidth(), mBackground.getIntrinsicHeight());
mWidth = width;
mHeight = height;
mTextPaint = new TextPaint();
int textSize = getTextSizeFromTheme(android.R.style.TextAppearance_Medium, 18);
mTextPaint.setTextSize(textSize);
mTextPaint.setColor(R.color.latinkeyboard_transparent);
mTextPaint.setTextAlign(Align.CENTER);
mTextPaint.setAlpha(255);
mTextPaint.setAntiAlias(true);
mAscent = (int) mTextPaint.ascent();
mMiddleX = (mWidth - mBackground.getIntrinsicWidth()) / 2;
mLeftDrawable =
mRes.getDrawable(R.drawable.sym_keyboard_feedback_language_arrows_left);
mRightDrawable =
mRes.getDrawable(R.drawable.sym_keyboard_feedback_language_arrows_right);
mLeftDrawable.setBounds(0, 0,
mLeftDrawable.getIntrinsicWidth(), mLeftDrawable.getIntrinsicHeight());
mRightDrawable.setBounds(mWidth - mRightDrawable.getIntrinsicWidth(), 0,
mWidth, mRightDrawable.getIntrinsicHeight());
mThreshold = ViewConfiguration.get(mContext).getScaledTouchSlop();
}
void setDiff(int diff) {
if (diff == Integer.MAX_VALUE) {
mHitThreshold = false;
mCurrentLanguage = null;
return;
}
mDiff = diff;
if (mDiff > mWidth) mDiff = mWidth;
if (mDiff < -mWidth) mDiff = -mWidth;
if (Math.abs(mDiff) > mThreshold) mHitThreshold = true;
invalidateSelf();
}
@Override
public void draw(Canvas canvas) {
canvas.save();
if (mHitThreshold) {
mTextPaint.setColor(mRes.getColor(R.color.latinkeyboard_feedback_language_text));
canvas.clipRect(0, 0, mWidth, mHeight);
if (mCurrentLanguage == null) {
mCurrentLanguage = getInputLanguage(mWidth, mTextPaint);
mNextLanguage = getNextInputLanguage(mWidth, mTextPaint);
mPrevLanguage = getPrevInputLanguage(mWidth, mTextPaint);
}
canvas.drawText(mCurrentLanguage,
mWidth / 2 + mDiff, -mAscent + 4, mTextPaint);
canvas.drawText(mNextLanguage,
mDiff - mWidth / 2, -mAscent + 4, mTextPaint);
canvas.drawText(mPrevLanguage,
mDiff + mWidth + mWidth / 2, -mAscent + 4, mTextPaint);
mLeftDrawable.draw(canvas);
mRightDrawable.draw(canvas);
}
if (mBackground != null) {
canvas.translate(mMiddleX, 0);
mBackground.draw(canvas);
}
canvas.restore();
}
@Override
public int getOpacity() {
return PixelFormat.TRANSLUCENT;
}
@Override
public void setAlpha(int alpha) {
// Ignore
}
@Override
public void setColorFilter(ColorFilter cf) {
// Ignore
}
@Override
public int getIntrinsicWidth() {
return mWidth;
}
@Override
public int getIntrinsicHeight() {
return mHeight;
}
}
}