541 lines
22 KiB
Java
541 lines
22 KiB
Java
![]() |
/*
|
||
|
* Copyright 2023 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 android.hardware.input;
|
||
|
|
||
|
import android.annotation.ColorInt;
|
||
|
import android.content.Context;
|
||
|
import android.content.res.Configuration;
|
||
|
import android.graphics.Canvas;
|
||
|
import android.graphics.ColorFilter;
|
||
|
import android.graphics.Paint;
|
||
|
import android.graphics.Path;
|
||
|
import android.graphics.PixelFormat;
|
||
|
import android.graphics.Rect;
|
||
|
import android.graphics.RectF;
|
||
|
import android.graphics.Typeface;
|
||
|
import android.graphics.drawable.Drawable;
|
||
|
import android.util.Slog;
|
||
|
import android.util.TypedValue;
|
||
|
import android.view.KeyEvent;
|
||
|
|
||
|
import androidx.annotation.NonNull;
|
||
|
import androidx.annotation.Nullable;
|
||
|
|
||
|
import java.util.ArrayList;
|
||
|
import java.util.List;
|
||
|
|
||
|
/**
|
||
|
* A custom drawable class that draws preview of a Physical keyboard layout.
|
||
|
*/
|
||
|
final class KeyboardLayoutPreviewDrawable extends Drawable {
|
||
|
|
||
|
private static final String TAG = "KeyboardLayoutPreview";
|
||
|
private static final int GRAVITY_LEFT = 0x1;
|
||
|
private static final int GRAVITY_RIGHT = 0x2;
|
||
|
private static final int GRAVITY_TOP = 0x4;
|
||
|
private static final int GRAVITY_BOTTOM = 0x8;
|
||
|
private static final int TEXT_PADDING_IN_DP = 1;
|
||
|
private static final int KEY_PADDING_IN_DP = 3;
|
||
|
private static final int KEYBOARD_PADDING_IN_DP = 10;
|
||
|
private static final int KEY_RADIUS_IN_DP = 5;
|
||
|
private static final int KEYBOARD_RADIUS_IN_DP = 10;
|
||
|
private static final int MIN_GLYPH_TEXT_SIZE_IN_SP = 10;
|
||
|
private static final int MAX_GLYPH_TEXT_SIZE_IN_SP = 20;
|
||
|
|
||
|
private final List<KeyDrawable> mKeyDrawables = new ArrayList<>();
|
||
|
|
||
|
private final int mWidth;
|
||
|
private final int mHeight;
|
||
|
private final RectF mKeyboardBackground = new RectF();
|
||
|
private final ResourceProvider mResourceProvider;
|
||
|
private final PhysicalKeyLayout mKeyLayout;
|
||
|
|
||
|
public KeyboardLayoutPreviewDrawable(Context context, PhysicalKeyLayout keyLayout, int width,
|
||
|
int height) {
|
||
|
mWidth = width;
|
||
|
mHeight = height;
|
||
|
mResourceProvider = new ResourceProvider(context);
|
||
|
mKeyLayout = keyLayout;
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public int getIntrinsicWidth() {
|
||
|
return mWidth;
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public int getIntrinsicHeight() {
|
||
|
return mHeight;
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
protected void onBoundsChange(@NonNull Rect bounds) {
|
||
|
super.onBoundsChange(bounds);
|
||
|
mKeyDrawables.clear();
|
||
|
final PhysicalKeyLayout.LayoutKey[][] keys = mKeyLayout.getKeys();
|
||
|
if (keys == null) {
|
||
|
return;
|
||
|
}
|
||
|
final PhysicalKeyLayout.EnterKey enterKey = mKeyLayout.getEnterKey();
|
||
|
int width = bounds.width();
|
||
|
int height = bounds.height();
|
||
|
final int keyboardPadding = mResourceProvider.getKeyboardPadding();
|
||
|
final int keyPadding = mResourceProvider.getKeyPadding();
|
||
|
final float keyRadius = mResourceProvider.getKeyRadius();
|
||
|
mKeyboardBackground.set(0, 0, width, height);
|
||
|
width -= keyboardPadding * 2;
|
||
|
height -= keyboardPadding * 2;
|
||
|
if (width <= 0 || height <= 0) {
|
||
|
Slog.e(TAG, "Invalid width and height to draw layout preview, width = " + width
|
||
|
+ ", height = " + height);
|
||
|
return;
|
||
|
}
|
||
|
int rowCount = keys.length;
|
||
|
float keyHeight = (float) (height - rowCount * 2 * keyPadding) / rowCount;
|
||
|
// Based on key height calculate the max text size that can fit for typing keys
|
||
|
mResourceProvider.calculateBestTextSizeForKey(keyHeight);
|
||
|
float isoEnterKeyLeft = 0;
|
||
|
float isoEnterKeyTop = 0;
|
||
|
float isoEnterWidthUnit = 0;
|
||
|
for (int i = 0; i < rowCount; i++) {
|
||
|
PhysicalKeyLayout.LayoutKey[] row = keys[i];
|
||
|
float totalRowWeight = 0;
|
||
|
int keysInRow = row.length;
|
||
|
for (PhysicalKeyLayout.LayoutKey layoutKey : row) {
|
||
|
totalRowWeight += layoutKey.keyWeight();
|
||
|
}
|
||
|
float keyWidthInPx = (width - keysInRow * 2 * keyPadding) / totalRowWeight;
|
||
|
float rowWeightOnLeft = 0;
|
||
|
float top = keyboardPadding + keyPadding * (2 * i + 1) + i * keyHeight;
|
||
|
for (int j = 0; j < keysInRow; j++) {
|
||
|
float left =
|
||
|
keyboardPadding + keyPadding * (2 * j + 1) + rowWeightOnLeft * keyWidthInPx;
|
||
|
rowWeightOnLeft += row[j].keyWeight();
|
||
|
RectF keyRect = new RectF(left, top, left + keyWidthInPx * row[j].keyWeight(),
|
||
|
top + keyHeight);
|
||
|
if (enterKey != null && row[j].keyCode() == KeyEvent.KEYCODE_ENTER) {
|
||
|
if (enterKey.row() == i && enterKey.column() == j) {
|
||
|
isoEnterKeyLeft = keyRect.left;
|
||
|
isoEnterKeyTop = keyRect.top;
|
||
|
isoEnterWidthUnit = keyWidthInPx;
|
||
|
}
|
||
|
continue;
|
||
|
}
|
||
|
if (PhysicalKeyLayout.isSpecialKey(row[j])) {
|
||
|
mKeyDrawables.add(new TypingKey(null, keyRect, keyRadius,
|
||
|
mResourceProvider.getTextPadding(),
|
||
|
mResourceProvider.getSpecialKeyPaint(),
|
||
|
mResourceProvider.getSpecialKeyPaint(),
|
||
|
mResourceProvider.getSpecialKeyPaint()));
|
||
|
} else if (PhysicalKeyLayout.isKeyPositionUnsure(row[j])) {
|
||
|
mKeyDrawables.add(new UnsureTypingKey(row[j].glyph(), keyRect,
|
||
|
keyRadius, mResourceProvider.getTextPadding(),
|
||
|
mResourceProvider.getTypingKeyPaint(),
|
||
|
mResourceProvider.getPrimaryGlyphPaint(),
|
||
|
mResourceProvider.getSecondaryGlyphPaint()));
|
||
|
} else {
|
||
|
mKeyDrawables.add(new TypingKey(row[j].glyph(), keyRect, keyRadius,
|
||
|
mResourceProvider.getTextPadding(),
|
||
|
mResourceProvider.getTypingKeyPaint(),
|
||
|
mResourceProvider.getPrimaryGlyphPaint(),
|
||
|
mResourceProvider.getSecondaryGlyphPaint()));
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
if (enterKey != null) {
|
||
|
IsoEnterKey.Builder isoEnterKeyBuilder = new IsoEnterKey.Builder(keyRadius,
|
||
|
mResourceProvider.getSpecialKeyPaint());
|
||
|
isoEnterKeyBuilder.setTopWidth(enterKey.topKeyWeight() * isoEnterWidthUnit)
|
||
|
.setStartPoint(isoEnterKeyLeft, isoEnterKeyTop)
|
||
|
.setVerticalEdges(keyHeight, 2 * (keyHeight + keyPadding))
|
||
|
.setBottomWidth(enterKey.bottomKeyWeight() * isoEnterWidthUnit);
|
||
|
mKeyDrawables.add(isoEnterKeyBuilder.build());
|
||
|
}
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public void draw(Canvas canvas) {
|
||
|
final float keyboardRadius = mResourceProvider.getBackgroundRadius();
|
||
|
canvas.drawRoundRect(mKeyboardBackground, keyboardRadius, keyboardRadius,
|
||
|
mResourceProvider.getBackgroundPaint());
|
||
|
for (KeyDrawable key : mKeyDrawables) {
|
||
|
key.draw(canvas);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public void setAlpha(int alpha) {
|
||
|
// Do nothing
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public void setColorFilter(@Nullable ColorFilter colorFilter) {
|
||
|
// Do nothing
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public int getOpacity() {
|
||
|
return PixelFormat.OPAQUE;
|
||
|
}
|
||
|
|
||
|
private static class TypingKey implements KeyDrawable {
|
||
|
|
||
|
private final RectF mKeyRect;
|
||
|
private final float mKeyRadius;
|
||
|
private final float mTextPadding;
|
||
|
private final Paint mKeyPaint;
|
||
|
private final Paint mBaseTextPaint;
|
||
|
private final Paint mModifierTextPaint;
|
||
|
private final List<GlyphDrawable> mGlyphDrawables = new ArrayList<>();
|
||
|
|
||
|
private TypingKey(@Nullable PhysicalKeyLayout.KeyGlyph glyphData, RectF keyRect,
|
||
|
float keyRadius, float textPadding, Paint keyPaint, Paint baseTextPaint,
|
||
|
Paint modifierTextPaint) {
|
||
|
mKeyRect = keyRect;
|
||
|
mKeyRadius = keyRadius;
|
||
|
mTextPadding = textPadding;
|
||
|
mKeyPaint = keyPaint;
|
||
|
mBaseTextPaint = baseTextPaint;
|
||
|
mModifierTextPaint = modifierTextPaint;
|
||
|
initGlyphs(glyphData);
|
||
|
}
|
||
|
|
||
|
private void initGlyphs(@Nullable PhysicalKeyLayout.KeyGlyph glyphData) {
|
||
|
createGlyphs(glyphData);
|
||
|
measureGlyphs();
|
||
|
}
|
||
|
|
||
|
private void createGlyphs(@Nullable PhysicalKeyLayout.KeyGlyph glyphData) {
|
||
|
if (glyphData == null) {
|
||
|
return;
|
||
|
}
|
||
|
if (!glyphData.hasBaseText()) {
|
||
|
return;
|
||
|
}
|
||
|
mGlyphDrawables.add(new GlyphDrawable(glyphData.getBaseText(), new RectF(),
|
||
|
GRAVITY_BOTTOM | GRAVITY_LEFT, mBaseTextPaint));
|
||
|
if (glyphData.hasValidShiftText()) {
|
||
|
mGlyphDrawables.add(new GlyphDrawable(glyphData.getShiftText(), new RectF(),
|
||
|
GRAVITY_TOP | GRAVITY_LEFT, mModifierTextPaint));
|
||
|
}
|
||
|
if (glyphData.hasValidAltGrText()) {
|
||
|
mGlyphDrawables.add(new GlyphDrawable(glyphData.getAltGrText(), new RectF(),
|
||
|
GRAVITY_BOTTOM | GRAVITY_RIGHT, mModifierTextPaint));
|
||
|
}
|
||
|
if (glyphData.hasValidAltGrShiftText()) {
|
||
|
mGlyphDrawables.add(new GlyphDrawable(glyphData.getAltGrShiftText(), new RectF(),
|
||
|
GRAVITY_TOP | GRAVITY_RIGHT, mModifierTextPaint));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
private void measureGlyphs() {
|
||
|
float keyWidth = mKeyRect.width();
|
||
|
float keyHeight = mKeyRect.height();
|
||
|
for (GlyphDrawable glyph : mGlyphDrawables) {
|
||
|
float centerX = keyWidth / 2;
|
||
|
float centerY = keyHeight / 2;
|
||
|
if ((glyph.gravity & GRAVITY_LEFT) != 0) {
|
||
|
centerX -= keyWidth / 4;
|
||
|
centerX += mTextPadding / 2;
|
||
|
}
|
||
|
if ((glyph.gravity & GRAVITY_RIGHT) != 0) {
|
||
|
centerX += keyWidth / 4;
|
||
|
centerX -= mTextPadding / 2;
|
||
|
}
|
||
|
if ((glyph.gravity & GRAVITY_TOP) != 0) {
|
||
|
centerY -= keyHeight / 4;
|
||
|
centerY += mTextPadding / 2;
|
||
|
}
|
||
|
if ((glyph.gravity & GRAVITY_BOTTOM) != 0) {
|
||
|
centerY += keyHeight / 4;
|
||
|
centerY -= mTextPadding / 2;
|
||
|
}
|
||
|
Rect textBounds = new Rect();
|
||
|
glyph.paint.getTextBounds(glyph.text, 0, glyph.text.length(), textBounds);
|
||
|
float textWidth = textBounds.width();
|
||
|
float textHeight = textBounds.height();
|
||
|
glyph.rect.set(centerX - textWidth / 2, centerY - textHeight / 2 - textBounds.top,
|
||
|
centerX + textWidth / 2, centerY + textHeight / 2 - textBounds.top);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public void draw(Canvas canvas) {
|
||
|
canvas.drawRoundRect(mKeyRect, mKeyRadius, mKeyRadius, mKeyPaint);
|
||
|
for (GlyphDrawable glyph : mGlyphDrawables) {
|
||
|
float textWidth = glyph.rect.width();
|
||
|
float textHeight = glyph.rect.height();
|
||
|
float keyWidth = mKeyRect.width();
|
||
|
float keyHeight = mKeyRect.height();
|
||
|
if (textWidth == 0 || textHeight == 0 || keyWidth == 0 || keyHeight == 0) {
|
||
|
return;
|
||
|
}
|
||
|
canvas.drawText(glyph.text, 0, glyph.text.length(), mKeyRect.left + glyph.rect.left,
|
||
|
mKeyRect.top + glyph.rect.top, glyph.paint);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
private static class UnsureTypingKey extends TypingKey {
|
||
|
|
||
|
private UnsureTypingKey(@Nullable PhysicalKeyLayout.KeyGlyph glyphData,
|
||
|
RectF keyRect, float keyRadius, float textPadding, Paint keyPaint,
|
||
|
Paint baseTextPaint, Paint modifierTextPaint) {
|
||
|
super(glyphData, keyRect, keyRadius, textPadding, createGreyedOutPaint(keyPaint),
|
||
|
createGreyedOutPaint(baseTextPaint), createGreyedOutPaint(modifierTextPaint));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
private static class IsoEnterKey implements KeyDrawable {
|
||
|
|
||
|
private final Paint mKeyPaint;
|
||
|
private final Path mPath;
|
||
|
|
||
|
private IsoEnterKey(Paint keyPaint, @NonNull Path path) {
|
||
|
mKeyPaint = keyPaint;
|
||
|
mPath = path;
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public void draw(Canvas canvas) {
|
||
|
canvas.drawPath(mPath, mKeyPaint);
|
||
|
}
|
||
|
|
||
|
private static class Builder {
|
||
|
private final float mKeyRadius;
|
||
|
private final Paint mKeyPaint;
|
||
|
private float mLeft;
|
||
|
private float mTop;
|
||
|
private float mTopWidth;
|
||
|
private float mBottomWidth;
|
||
|
private float mLeftHeight;
|
||
|
private float mRightHeight;
|
||
|
|
||
|
private Builder(float keyRadius, Paint keyPaint) {
|
||
|
mKeyRadius = keyRadius;
|
||
|
mKeyPaint = keyPaint;
|
||
|
}
|
||
|
|
||
|
private Builder setStartPoint(float left, float top) {
|
||
|
mLeft = left;
|
||
|
mTop = top;
|
||
|
return this;
|
||
|
}
|
||
|
|
||
|
private Builder setTopWidth(float width) {
|
||
|
mTopWidth = width;
|
||
|
return this;
|
||
|
}
|
||
|
|
||
|
private Builder setBottomWidth(float width) {
|
||
|
mBottomWidth = width;
|
||
|
return this;
|
||
|
}
|
||
|
|
||
|
private Builder setVerticalEdges(float leftHeight, float rightHeight) {
|
||
|
mLeftHeight = leftHeight;
|
||
|
mRightHeight = rightHeight;
|
||
|
return this;
|
||
|
}
|
||
|
|
||
|
private IsoEnterKey build() {
|
||
|
Path enterKey = new Path();
|
||
|
RectF oval = new RectF(-mKeyRadius, -mKeyRadius, mKeyRadius, mKeyRadius);
|
||
|
// Horizontal top line
|
||
|
enterKey.moveTo(mLeft + mKeyRadius, mTop);
|
||
|
enterKey.lineTo(mLeft + mTopWidth - mKeyRadius, mTop);
|
||
|
// Rounded top right corner
|
||
|
oval.offsetTo(mLeft + mTopWidth - 2 * mKeyRadius, mTop);
|
||
|
enterKey.arcTo(oval, 270, 90);
|
||
|
// Vertical right line
|
||
|
enterKey.lineTo(mLeft + mTopWidth, mTop + mRightHeight - mKeyRadius);
|
||
|
// Rounded bottom right corner
|
||
|
oval.offsetTo(mLeft + mTopWidth - 2 * mKeyRadius,
|
||
|
mTop + mRightHeight - 2 * mKeyRadius);
|
||
|
enterKey.arcTo(oval, 0, 90);
|
||
|
// Horizontal bottom line
|
||
|
enterKey.lineTo(mLeft + mTopWidth - mBottomWidth + mKeyRadius, mTop + mRightHeight);
|
||
|
// Rounded bottom left corner
|
||
|
oval.offsetTo(mLeft + mTopWidth - mBottomWidth,
|
||
|
mTop + mRightHeight - 2 * mKeyRadius);
|
||
|
enterKey.arcTo(oval, 90, 90);
|
||
|
// Vertical left line (bottom half)
|
||
|
enterKey.lineTo(mLeft + mTopWidth - mBottomWidth, mTop + mLeftHeight - mKeyRadius);
|
||
|
// Rounded corner
|
||
|
oval.offsetTo(mLeft + mTopWidth - mBottomWidth - 2 * mKeyRadius,
|
||
|
mTop + mLeftHeight);
|
||
|
enterKey.arcTo(oval, 0, -90);
|
||
|
// Horizontal line in the mid part
|
||
|
enterKey.lineTo(mLeft + mKeyRadius, mTop + mLeftHeight);
|
||
|
// Rounded corner
|
||
|
oval.offsetTo(mLeft, mTop + mLeftHeight - 2 * mKeyRadius);
|
||
|
enterKey.arcTo(oval, 90, 90);
|
||
|
// Vertical left line (top half)
|
||
|
enterKey.lineTo(mLeft, mTop + mKeyRadius);
|
||
|
// Rounded top left corner
|
||
|
oval.offsetTo(mLeft, mTop);
|
||
|
enterKey.arcTo(oval, 180, 90);
|
||
|
enterKey.close();
|
||
|
return new IsoEnterKey(mKeyPaint, enterKey);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
private record GlyphDrawable(String text, RectF rect, int gravity, Paint paint) {}
|
||
|
|
||
|
private interface KeyDrawable {
|
||
|
void draw(Canvas canvas);
|
||
|
}
|
||
|
|
||
|
private static class ResourceProvider {
|
||
|
// Resources
|
||
|
private final Paint mBackgroundPaint;
|
||
|
private final Paint mTypingKeyPaint;
|
||
|
private final Paint mSpecialKeyPaint;
|
||
|
private final Paint mPrimaryGlyphPaint;
|
||
|
private final Paint mSecondaryGlyphPaint;
|
||
|
private final int mKeyPadding;
|
||
|
private final int mKeyboardPadding;
|
||
|
private final float mTextPadding;
|
||
|
private final float mKeyRadius;
|
||
|
private final float mBackgroundRadius;
|
||
|
private final float mSpToPxMultiplier;
|
||
|
private final Paint.FontMetrics mFontMetrics;
|
||
|
|
||
|
private ResourceProvider(Context context) {
|
||
|
mKeyPadding = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
|
||
|
KEY_PADDING_IN_DP, context.getResources().getDisplayMetrics());
|
||
|
mKeyboardPadding = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
|
||
|
KEYBOARD_PADDING_IN_DP, context.getResources().getDisplayMetrics());
|
||
|
mKeyRadius = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
|
||
|
KEY_RADIUS_IN_DP, context.getResources().getDisplayMetrics());
|
||
|
mBackgroundRadius = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
|
||
|
KEYBOARD_RADIUS_IN_DP, context.getResources().getDisplayMetrics());
|
||
|
mSpToPxMultiplier = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, 1,
|
||
|
context.getResources().getDisplayMetrics());
|
||
|
mTextPadding = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
|
||
|
TEXT_PADDING_IN_DP, context.getResources().getDisplayMetrics());
|
||
|
boolean isDark = (context.getResources().getConfiguration().uiMode
|
||
|
& Configuration.UI_MODE_NIGHT_MASK) == Configuration.UI_MODE_NIGHT_YES;
|
||
|
int typingKeyColor = context.getColor(
|
||
|
isDark ? android.R.color.system_outline_variant_dark
|
||
|
: android.R.color.system_surface_container_lowest_light);
|
||
|
int specialKeyColor = context.getColor(isDark ? android.R.color.system_neutral1_800
|
||
|
: android.R.color.system_secondary_container_light);
|
||
|
int primaryGlyphColor = context.getColor(isDark ? android.R.color.system_on_surface_dark
|
||
|
: android.R.color.system_on_surface_light);
|
||
|
int secondaryGlyphColor = context.getColor(isDark ? android.R.color.system_outline_dark
|
||
|
: android.R.color.system_outline_light);
|
||
|
int backgroundColor = context.getColor(
|
||
|
isDark ? android.R.color.system_surface_container_dark
|
||
|
: android.R.color.system_surface_container_light);
|
||
|
mPrimaryGlyphPaint = createTextPaint(primaryGlyphColor,
|
||
|
MIN_GLYPH_TEXT_SIZE_IN_SP * mSpToPxMultiplier,
|
||
|
Typeface.create(Typeface.SANS_SERIF, Typeface.BOLD));
|
||
|
mSecondaryGlyphPaint = createTextPaint(secondaryGlyphColor,
|
||
|
MIN_GLYPH_TEXT_SIZE_IN_SP * mSpToPxMultiplier,
|
||
|
Typeface.create(Typeface.SANS_SERIF, Typeface.NORMAL));
|
||
|
mFontMetrics = mPrimaryGlyphPaint.getFontMetrics();
|
||
|
mTypingKeyPaint = createFillPaint(typingKeyColor);
|
||
|
mSpecialKeyPaint = createFillPaint(specialKeyColor);
|
||
|
mBackgroundPaint = createFillPaint(backgroundColor);
|
||
|
}
|
||
|
|
||
|
private void calculateBestTextSizeForKey(float keyHeight) {
|
||
|
int textSize = (int) (mSpToPxMultiplier * MIN_GLYPH_TEXT_SIZE_IN_SP) + 1;
|
||
|
while (textSize < mSpToPxMultiplier * MAX_GLYPH_TEXT_SIZE_IN_SP) {
|
||
|
updateTextSize(textSize);
|
||
|
if (mFontMetrics.bottom - mFontMetrics.top + 3 * mTextPadding > keyHeight / 2) {
|
||
|
textSize--;
|
||
|
break;
|
||
|
}
|
||
|
textSize++;
|
||
|
}
|
||
|
updateTextSize(textSize);
|
||
|
}
|
||
|
|
||
|
private void updateTextSize(float textSize) {
|
||
|
mPrimaryGlyphPaint.setTextSize(textSize);
|
||
|
mSecondaryGlyphPaint.setTextSize(textSize);
|
||
|
mPrimaryGlyphPaint.getFontMetrics(mFontMetrics);
|
||
|
}
|
||
|
|
||
|
private Paint getBackgroundPaint() {
|
||
|
return mBackgroundPaint;
|
||
|
}
|
||
|
|
||
|
private Paint getTypingKeyPaint() {
|
||
|
return mTypingKeyPaint;
|
||
|
}
|
||
|
|
||
|
private Paint getSpecialKeyPaint() {
|
||
|
return mSpecialKeyPaint;
|
||
|
}
|
||
|
|
||
|
private Paint getPrimaryGlyphPaint() {
|
||
|
return mPrimaryGlyphPaint;
|
||
|
}
|
||
|
|
||
|
private Paint getSecondaryGlyphPaint() {
|
||
|
return mSecondaryGlyphPaint;
|
||
|
}
|
||
|
|
||
|
private int getKeyPadding() {
|
||
|
return mKeyPadding;
|
||
|
}
|
||
|
|
||
|
private int getKeyboardPadding() {
|
||
|
return mKeyboardPadding;
|
||
|
}
|
||
|
|
||
|
private float getTextPadding() {
|
||
|
return mTextPadding;
|
||
|
}
|
||
|
|
||
|
private float getKeyRadius() {
|
||
|
return mKeyRadius;
|
||
|
}
|
||
|
|
||
|
private float getBackgroundRadius() {
|
||
|
return mBackgroundRadius;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
private static Paint createTextPaint(@ColorInt int textColor, float textSize,
|
||
|
Typeface typeface) {
|
||
|
Paint paint = new Paint();
|
||
|
paint.setColor(textColor);
|
||
|
paint.setStyle(Paint.Style.FILL);
|
||
|
paint.setTextSize(textSize);
|
||
|
paint.setTypeface(typeface);
|
||
|
return paint;
|
||
|
}
|
||
|
|
||
|
private static Paint createFillPaint(@ColorInt int color) {
|
||
|
Paint paint = new Paint();
|
||
|
paint.setColor(color);
|
||
|
paint.setStyle(Paint.Style.FILL);
|
||
|
return paint;
|
||
|
}
|
||
|
|
||
|
private static Paint createGreyedOutPaint(Paint paint) {
|
||
|
Paint result = new Paint(paint);
|
||
|
result.setAlpha(100);
|
||
|
return result;
|
||
|
}
|
||
|
}
|