Merge "Draw language name on spacebar on the fly"

This commit is contained in:
Tadashi G. Takaoka 2012-01-25 02:37:22 -08:00 committed by Android (Google) Code Review
commit 9650e85662

View file

@ -20,14 +20,11 @@ import android.content.Context;
import android.content.pm.PackageManager; import android.content.pm.PackageManager;
import android.content.res.Resources; import android.content.res.Resources;
import android.content.res.TypedArray; import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.Canvas; import android.graphics.Canvas;
import android.graphics.Color; import android.graphics.Color;
import android.graphics.Paint; import android.graphics.Paint;
import android.graphics.Paint.Align; import android.graphics.Paint.Align;
import android.graphics.PorterDuff; import android.graphics.Typeface;
import android.graphics.Rect;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable; import android.graphics.drawable.Drawable;
import android.os.Message; import android.os.Message;
import android.text.TextUtils; import android.text.TextUtils;
@ -54,8 +51,6 @@ import com.android.inputmethod.latin.StaticInnerHandlerWrapper;
import com.android.inputmethod.latin.Utils; import com.android.inputmethod.latin.Utils;
import com.android.inputmethod.latin.Utils.UsabilityStudyLogUtils; import com.android.inputmethod.latin.Utils.UsabilityStudyLogUtils;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Locale; import java.util.Locale;
import java.util.WeakHashMap; import java.util.WeakHashMap;
@ -72,38 +67,33 @@ public class LatinKeyboardView extends KeyboardView implements PointerTracker.Ke
private static final boolean ENABLE_CAPSLOCK_BY_DOUBLETAP = true; private static final boolean ENABLE_CAPSLOCK_BY_DOUBLETAP = true;
/* Space key and its icons, drawables and colors. */ // TODO: Kill process when the usability study mode was changed.
private static final boolean ENABLE_USABILITY_STUDY_LOG = LatinImeLogger.sUsabilityStudy;
/** Listener for {@link KeyboardActionListener}. */
private KeyboardActionListener mKeyboardActionListener;
/* Space key and its icons */
private Key mSpaceKey; private Key mSpaceKey;
private Drawable mSpaceIcon; private Drawable mSpaceIcon;
private final boolean mIsSpacebarTriggeringPopupByLongPress; // Stuff to draw language name on spacebar.
private static final int SPACE_LED_LENGTH_PERCENT = 80; private boolean mNeedsToDisplayLanguage;
private final boolean mAutoCorrectionSpacebarLedEnabled; private Locale mSpacebarLocale;
private final Drawable mAutoCorrectionSpacebarLedIcon; private float mSpacebarTextFadeFactor = 0.0f;
private final float mSpacebarTextRatio; private final float mSpacebarTextRatio;
private float mSpacebarTextSize; private float mSpacebarTextSize;
private final int mSpacebarTextColor; private final int mSpacebarTextColor;
private final int mSpacebarTextShadowColor; private final int mSpacebarTextShadowColor;
private final HashMap<Integer, BitmapDrawable> mSpacebarDrawableCache =
new HashMap<Integer, BitmapDrawable>();
private boolean mAutoCorrectionSpacebarLedOn;
private boolean mNeedsToDisplayLanguage;
private Locale mSpacebarLocale;
private float mSpacebarTextFadeFactor = 0.0f;
// Height in space key the language name will be drawn. (proportional to space key height) // Height in space key the language name will be drawn. (proportional to space key height)
public static final float SPACEBAR_LANGUAGE_BASELINE = 0.6f; private static final float SPACEBAR_LANGUAGE_BASELINE = 0.6f;
// If the full language name needs to be smaller than this value to be drawn on space key, // If the full language name needs to be smaller than this value to be drawn on space key,
// its short language name will be used instead. // its short language name will be used instead.
private static final float MINIMUM_SCALE_OF_LANGUAGE_NAME = 0.8f; private static final float MINIMUM_SCALE_OF_LANGUAGE_NAME = 0.8f;
// Stuff to draw auto correction LED on spacebar.
private final SuddenJumpingTouchEventHandler mTouchScreenRegulator; private boolean mAutoCorrectionSpacebarLedOn;
private final boolean mAutoCorrectionSpacebarLedEnabled;
// Timing constants private final Drawable mAutoCorrectionSpacebarLedIcon;
private final int mKeyRepeatInterval; private static final int SPACE_LED_LENGTH_PERCENT = 80;
// TODO: Kill process when the usability study mode was changed.
private static final boolean ENABLE_USABILITY_STUDY_LOG = LatinImeLogger.sUsabilityStudy;
// Mini keyboard // Mini keyboard
private PopupWindow mMoreKeysWindow; private PopupWindow mMoreKeysWindow;
@ -111,17 +101,16 @@ public class LatinKeyboardView extends KeyboardView implements PointerTracker.Ke
private int mMoreKeysPanelPointerTrackerId; private int mMoreKeysPanelPointerTrackerId;
private final WeakHashMap<Key, MoreKeysPanel> mMoreKeysPanelCache = private final WeakHashMap<Key, MoreKeysPanel> mMoreKeysPanelCache =
new WeakHashMap<Key, MoreKeysPanel>(); new WeakHashMap<Key, MoreKeysPanel>();
private final boolean mConfigShowMiniKeyboardAtTouchedPoint;
/** Listener for {@link KeyboardActionListener}. */ private final boolean mIsSpacebarTriggeringPopupByLongPress;
private KeyboardActionListener mKeyboardActionListener; private final SuddenJumpingTouchEventHandler mTouchScreenRegulator;
protected KeyDetector mKeyDetector;
private boolean mHasDistinctMultitouch; private boolean mHasDistinctMultitouch;
private int mOldPointerCount = 1; private int mOldPointerCount = 1;
private Key mOldKey; private Key mOldKey;
private final boolean mConfigShowMiniKeyboardAtTouchedPoint;
protected KeyDetector mKeyDetector;
// To detect double tap. // To detect double tap.
protected GestureDetector mGestureDetector; protected GestureDetector mGestureDetector;
@ -134,10 +123,14 @@ public class LatinKeyboardView extends KeyboardView implements PointerTracker.Ke
private static final int MSG_IGNORE_DOUBLE_TAP = 3; private static final int MSG_IGNORE_DOUBLE_TAP = 3;
private static final int MSG_KEY_TYPED = 4; private static final int MSG_KEY_TYPED = 4;
private final int mKeyRepeatInterval;
private boolean mInKeyRepeat; private boolean mInKeyRepeat;
public KeyTimerHandler(LatinKeyboardView outerInstance) { public KeyTimerHandler(LatinKeyboardView outerInstance) {
super(outerInstance); super(outerInstance);
// TODO: This should be the attribute of LatinKeyboardView.
final Resources res = outerInstance.getContext().getResources();
mKeyRepeatInterval = res.getInteger(R.integer.config_key_repeat_interval);
} }
@Override @Override
@ -147,7 +140,7 @@ public class LatinKeyboardView extends KeyboardView implements PointerTracker.Ke
switch (msg.what) { switch (msg.what) {
case MSG_REPEAT_KEY: case MSG_REPEAT_KEY:
tracker.onRepeatKey(tracker.getKey()); tracker.onRepeatKey(tracker.getKey());
startKeyRepeatTimer(keyboardView.mKeyRepeatInterval, tracker); startKeyRepeatTimer(mKeyRepeatInterval, tracker);
break; break;
case MSG_LONGPRESS_KEY: case MSG_LONGPRESS_KEY:
keyboardView.openMiniKeyboardIfRequired(tracker.getKey(), tracker); keyboardView.openMiniKeyboardIfRequired(tracker.getKey(), tracker);
@ -213,7 +206,7 @@ public class LatinKeyboardView extends KeyboardView implements PointerTracker.Ke
} }
} }
private class DoubleTapListener extends GestureDetector.SimpleOnGestureListener { class DoubleTapListener extends GestureDetector.SimpleOnGestureListener {
private boolean mProcessingShiftDoubleTapEvent = false; private boolean mProcessingShiftDoubleTapEvent = false;
@Override @Override
@ -270,8 +263,10 @@ public class LatinKeyboardView extends KeyboardView implements PointerTracker.Ke
mTouchScreenRegulator = new SuddenJumpingTouchEventHandler(getContext(), this); mTouchScreenRegulator = new SuddenJumpingTouchEventHandler(getContext(), this);
final Resources res = getResources(); final Resources res = getResources();
// TODO: This should be the attribute of LatinKeyboardView.
mConfigShowMiniKeyboardAtTouchedPoint = res.getBoolean( mConfigShowMiniKeyboardAtTouchedPoint = res.getBoolean(
R.bool.config_show_mini_keyboard_at_touched_point); R.bool.config_show_mini_keyboard_at_touched_point);
// TODO: This should be the attribute of LatinKeyboardView.
final float keyHysteresisDistance = res.getDimension(R.dimen.key_hysteresis_distance); final float keyHysteresisDistance = res.getDimension(R.dimen.key_hysteresis_distance);
mKeyDetector = new KeyDetector(keyHysteresisDistance); mKeyDetector = new KeyDetector(keyHysteresisDistance);
@ -282,10 +277,10 @@ public class LatinKeyboardView extends KeyboardView implements PointerTracker.Ke
mHasDistinctMultitouch = context.getPackageManager() mHasDistinctMultitouch = context.getPackageManager()
.hasSystemFeature(PackageManager.FEATURE_TOUCHSCREEN_MULTITOUCH_DISTINCT); .hasSystemFeature(PackageManager.FEATURE_TOUCHSCREEN_MULTITOUCH_DISTINCT);
mKeyRepeatInterval = res.getInteger(R.integer.config_key_repeat_interval);
PointerTracker.init(mHasDistinctMultitouch, getContext()); PointerTracker.init(mHasDistinctMultitouch, getContext());
// TODO: This should be the attribute of LatinKeyboardView.
final int longPressSpaceKeyTimeout = final int longPressSpaceKeyTimeout =
res.getInteger(R.integer.config_long_press_space_key_timeout); res.getInteger(R.integer.config_long_press_space_key_timeout);
mIsSpacebarTriggeringPopupByLongPress = (longPressSpaceKeyTimeout > 0); mIsSpacebarTriggeringPopupByLongPress = (longPressSpaceKeyTimeout > 0);
@ -362,7 +357,6 @@ public class LatinKeyboardView extends KeyboardView implements PointerTracker.Ke
final int keyHeight = keyboard.mMostCommonKeyHeight - keyboard.mVerticalGap; final int keyHeight = keyboard.mMostCommonKeyHeight - keyboard.mVerticalGap;
mSpacebarTextSize = keyHeight * mSpacebarTextRatio; mSpacebarTextSize = keyHeight * mSpacebarTextRatio;
mSpacebarLocale = keyboard.mId.mLocale; mSpacebarLocale = keyboard.mId.mLocale;
clearSpacebarDrawableCache();
} }
/** /**
@ -759,14 +753,12 @@ public class LatinKeyboardView extends KeyboardView implements PointerTracker.Ke
public void updateSpacebar(float fadeFactor, boolean needsToDisplayLanguage) { public void updateSpacebar(float fadeFactor, boolean needsToDisplayLanguage) {
mSpacebarTextFadeFactor = fadeFactor; mSpacebarTextFadeFactor = fadeFactor;
mNeedsToDisplayLanguage = needsToDisplayLanguage; mNeedsToDisplayLanguage = needsToDisplayLanguage;
updateSpacebarIcon();
invalidateKey(mSpaceKey); invalidateKey(mSpaceKey);
} }
public void updateAutoCorrectionState(boolean isAutoCorrection) { public void updateAutoCorrectionState(boolean isAutoCorrection) {
if (!mAutoCorrectionSpacebarLedEnabled) return; if (!mAutoCorrectionSpacebarLedEnabled) return;
mAutoCorrectionSpacebarLedOn = isAutoCorrection; mAutoCorrectionSpacebarLedOn = isAutoCorrection;
updateSpacebarIcon();
invalidateKey(mSpaceKey); invalidateKey(mSpaceKey);
} }
@ -775,27 +767,16 @@ public class LatinKeyboardView extends KeyboardView implements PointerTracker.Ke
super.onDrawKeyTopVisuals(key, canvas, paint, params); super.onDrawKeyTopVisuals(key, canvas, paint, params);
if (key.mCode == Keyboard.CODE_SPACE) { if (key.mCode == Keyboard.CODE_SPACE) {
drawSpacebar(key, canvas, paint);
// Whether space key needs to show the "..." popup hint for special purposes // Whether space key needs to show the "..." popup hint for special purposes
if (mIsSpacebarTriggeringPopupByLongPress if (mIsSpacebarTriggeringPopupByLongPress
&& Utils.hasMultipleEnabledIMEsOrSubtypes(true /* include aux subtypes */)) { && Utils.hasMultipleEnabledIMEsOrSubtypes(true /* include aux subtypes */)) {
super.drawKeyPopupHint(key, canvas, paint, params); drawKeyPopupHint(key, canvas, paint, params);
} }
} }
} }
// TODO: Get rid of this method and draw spacebar locale and auto correction spacebar LED
// in onDrawKeyTopVisuals.
private void updateSpacebarIcon() {
if (mSpaceKey == null) return;
if (mNeedsToDisplayLanguage) {
mSpaceKey.setIcon(getSpaceDrawable(mSpacebarLocale));
} else if (mAutoCorrectionSpacebarLedOn) {
mSpaceKey.setIcon(getSpaceDrawable(null));
} else {
mSpaceKey.setIcon(mSpaceIcon);
}
}
private static int getSpacebarTextColor(int color, float fadeFactor) { private static int getSpacebarTextColor(int color, float fadeFactor) {
final int newColor = Color.argb((int)(Color.alpha(color) * fadeFactor), final int newColor = Color.argb((int)(Color.alpha(color) * fadeFactor),
Color.red(color), Color.green(color), Color.blue(color)); Color.red(color), Color.green(color), Color.blue(color));
@ -803,24 +784,23 @@ public class LatinKeyboardView extends KeyboardView implements PointerTracker.Ke
} }
// Compute width of text with specified text size using paint. // Compute width of text with specified text size using paint.
private static int getTextWidth(Paint paint, String text, float textSize, Rect bounds) { private int getTextWidth(Paint paint, String text, float textSize) {
paint.setTextSize(textSize); paint.setTextSize(textSize);
paint.getTextBounds(text, 0, text.length(), bounds); return (int)getLabelWidth(text, paint);
return bounds.width();
} }
// Layout locale language name on spacebar. // Layout locale language name on spacebar.
private static String layoutSpacebar(Paint paint, Locale locale, int width, private String layoutLanguageOnSpacebar(Paint paint, Locale locale, int width,
float origTextSize) { float origTextSize) {
final Rect bounds = new Rect(); paint.setTextAlign(Align.CENTER);
paint.setTypeface(Typeface.DEFAULT);
// Estimate appropriate language name text size to fit in maxTextWidth. // Estimate appropriate language name text size to fit in maxTextWidth.
String language = Utils.getFullDisplayName(locale, true); String language = Utils.getFullDisplayName(locale, true);
int textWidth = getTextWidth(paint, language, origTextSize, bounds); int textWidth = getTextWidth(paint, language, origTextSize);
// Assuming text width and text size are proportional to each other. // Assuming text width and text size are proportional to each other.
float textSize = origTextSize * Math.min(width / textWidth, 1.0f); float textSize = origTextSize * Math.min(width / textWidth, 1.0f);
// allow variable text size // allow variable text size
textWidth = getTextWidth(paint, language, textSize, bounds); textWidth = getTextWidth(paint, language, textSize);
// If text size goes too small or text does not fit, use middle or short name // If text size goes too small or text does not fit, use middle or short name
final boolean useMiddleName = (textSize / origTextSize < MINIMUM_SCALE_OF_LANGUAGE_NAME) final boolean useMiddleName = (textSize / origTextSize < MINIMUM_SCALE_OF_LANGUAGE_NAME)
|| (textWidth > width); || (textWidth > width);
@ -828,7 +808,7 @@ public class LatinKeyboardView extends KeyboardView implements PointerTracker.Ke
final boolean useShortName; final boolean useShortName;
if (useMiddleName) { if (useMiddleName) {
language = Utils.getMiddleDisplayLanguage(locale); language = Utils.getMiddleDisplayLanguage(locale);
textWidth = getTextWidth(paint, language, origTextSize, bounds); textWidth = getTextWidth(paint, language, origTextSize);
textSize = origTextSize * Math.min(width / textWidth, 1.0f); textSize = origTextSize * Math.min(width / textWidth, 1.0f);
useShortName = (textSize / origTextSize < MINIMUM_SCALE_OF_LANGUAGE_NAME) useShortName = (textSize / origTextSize < MINIMUM_SCALE_OF_LANGUAGE_NAME)
|| (textWidth > width); || (textWidth > width);
@ -838,7 +818,7 @@ public class LatinKeyboardView extends KeyboardView implements PointerTracker.Ke
if (useShortName) { if (useShortName) {
language = Utils.getShortDisplayLanguage(locale); language = Utils.getShortDisplayLanguage(locale);
textWidth = getTextWidth(paint, language, origTextSize, bounds); textWidth = getTextWidth(paint, language, origTextSize);
textSize = origTextSize * Math.min(width / textWidth, 1.0f); textSize = origTextSize * Math.min(width / textWidth, 1.0f);
} }
paint.setTextSize(textSize); paint.setTextSize(textSize);
@ -846,50 +826,14 @@ public class LatinKeyboardView extends KeyboardView implements PointerTracker.Ke
return language; return language;
} }
private Integer getSpaceDrawableKey(Locale locale) { private void drawSpacebar(Key key, Canvas canvas, Paint paint) {
return Arrays.hashCode(new Object[] { final int width = key.mWidth;
locale, final int height = mSpaceIcon != null ? mSpaceIcon.getIntrinsicHeight() : key.mHeight;
mAutoCorrectionSpacebarLedOn,
mSpacebarTextFadeFactor
});
}
private void clearSpacebarDrawableCache() {
for (final BitmapDrawable drawable : mSpacebarDrawableCache.values()) {
final Bitmap bitmap = drawable.getBitmap();
bitmap.recycle();
}
mSpacebarDrawableCache.clear();
}
private BitmapDrawable getSpaceDrawable(Locale locale) {
final Integer hashCode = getSpaceDrawableKey(locale);
final BitmapDrawable cached = mSpacebarDrawableCache.get(hashCode);
if (cached != null) {
return cached;
}
final BitmapDrawable drawable = new BitmapDrawable(getResources(), drawSpacebar(
locale, mAutoCorrectionSpacebarLedOn, mSpacebarTextFadeFactor));
mSpacebarDrawableCache.put(hashCode, drawable);
return drawable;
}
private Bitmap drawSpacebar(Locale inputLocale, boolean isAutoCorrection,
float textFadeFactor) {
final int width = mSpaceKey.mWidth;
final int height = mSpaceIcon != null ? mSpaceIcon.getIntrinsicHeight() : mSpaceKey.mHeight;
final Bitmap buffer = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
final Canvas canvas = new Canvas(buffer);
canvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR);
// If application locales are explicitly selected. // If application locales are explicitly selected.
if (inputLocale != null) { if (mNeedsToDisplayLanguage) {
final Paint paint = new Paint(); final String language = layoutLanguageOnSpacebar(paint, mSpacebarLocale, width,
paint.setAntiAlias(true); mSpacebarTextSize);
paint.setTextAlign(Align.CENTER);
final String language = layoutSpacebar(paint, inputLocale, width, mSpacebarTextSize);
// Draw language text with shadow // Draw language text with shadow
// In case there is no space icon, we will place the language text at the center of // In case there is no space icon, we will place the language text at the center of
// spacebar. // spacebar.
@ -897,28 +841,25 @@ public class LatinKeyboardView extends KeyboardView implements PointerTracker.Ke
final float textHeight = -paint.ascent() + descent; final float textHeight = -paint.ascent() + descent;
final float baseline = (mSpaceIcon != null) ? height * SPACEBAR_LANGUAGE_BASELINE final float baseline = (mSpaceIcon != null) ? height * SPACEBAR_LANGUAGE_BASELINE
: height / 2 + textHeight / 2; : height / 2 + textHeight / 2;
paint.setColor(getSpacebarTextColor(mSpacebarTextShadowColor, textFadeFactor)); paint.setColor(getSpacebarTextColor(mSpacebarTextShadowColor, mSpacebarTextFadeFactor));
canvas.drawText(language, width / 2, baseline - descent - 1, paint); canvas.drawText(language, width / 2, baseline - descent - 1, paint);
paint.setColor(getSpacebarTextColor(mSpacebarTextColor, textFadeFactor)); paint.setColor(getSpacebarTextColor(mSpacebarTextColor, mSpacebarTextFadeFactor));
canvas.drawText(language, width / 2, baseline - descent, paint); canvas.drawText(language, width / 2, baseline - descent, paint);
} }
// Draw the spacebar icon at the bottom // Draw the spacebar icon at the bottom
if (isAutoCorrection) { if (mAutoCorrectionSpacebarLedOn) {
final int iconWidth = width * SPACE_LED_LENGTH_PERCENT / 100; final int iconWidth = width * SPACE_LED_LENGTH_PERCENT / 100;
final int iconHeight = mAutoCorrectionSpacebarLedIcon.getIntrinsicHeight(); final int iconHeight = mAutoCorrectionSpacebarLedIcon.getIntrinsicHeight();
int x = (width - iconWidth) / 2; int x = (width - iconWidth) / 2;
int y = height - iconHeight; int y = height - iconHeight;
mAutoCorrectionSpacebarLedIcon.setBounds(x, y, x + iconWidth, y + iconHeight); drawIcon(canvas, mAutoCorrectionSpacebarLedIcon, x, y, iconWidth, iconHeight);
mAutoCorrectionSpacebarLedIcon.draw(canvas);
} else if (mSpaceIcon != null) { } else if (mSpaceIcon != null) {
final int iconWidth = mSpaceIcon.getIntrinsicWidth(); final int iconWidth = mSpaceIcon.getIntrinsicWidth();
final int iconHeight = mSpaceIcon.getIntrinsicHeight(); final int iconHeight = mSpaceIcon.getIntrinsicHeight();
int x = (width - iconWidth) / 2; int x = (width - iconWidth) / 2;
int y = height - iconHeight; int y = height - iconHeight;
mSpaceIcon.setBounds(x, y, x + iconWidth, y + iconHeight); drawIcon(canvas, mSpaceIcon, x, y, iconWidth, iconHeight);
mSpaceIcon.draw(canvas); }
}
return buffer;
} }
} }