Add null analysis annotations to keyboard package

Change-Id: I6f020ece3c45d584d413e4265d6d3fbdf1ea8bd8
This commit is contained in:
Tadashi G. Takaoka 2014-11-20 16:07:54 +09:00
parent bb4075bc93
commit 9d5d01a543
17 changed files with 219 additions and 100 deletions

View file

@ -43,6 +43,9 @@ import com.android.inputmethod.latin.common.StringUtils;
import java.util.Arrays; import java.util.Arrays;
import java.util.Locale; import java.util.Locale;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
/** /**
* Class for describing the position and characteristics of a single key in the keyboard. * Class for describing the position and characteristics of a single key in the keyboard.
*/ */
@ -113,9 +116,11 @@ public class Key implements Comparable<Key> {
/** Y coordinate of the top-left corner of the key in the keyboard layout, excluding the gap. */ /** Y coordinate of the top-left corner of the key in the keyboard layout, excluding the gap. */
private final int mY; private final int mY;
/** Hit bounding box of the key */ /** Hit bounding box of the key */
@Nonnull
private final Rect mHitBox = new Rect(); private final Rect mHitBox = new Rect();
/** More keys. It is guaranteed that this is null or an array of one or more elements */ /** More keys. It is guaranteed that this is null or an array of one or more elements */
@Nullable
private final MoreKeySpec[] mMoreKeys; private final MoreKeySpec[] mMoreKeys;
/** More keys column number and flags */ /** More keys column number and flags */
private final int mMoreKeysColumnAndFlags; private final int mMoreKeysColumnAndFlags;
@ -158,8 +163,9 @@ public class Key implements Comparable<Key> {
private static final int ACTION_FLAGS_ALT_CODE_WHILE_TYPING = 0x04; private static final int ACTION_FLAGS_ALT_CODE_WHILE_TYPING = 0x04;
private static final int ACTION_FLAGS_ENABLE_LONG_PRESS = 0x08; private static final int ACTION_FLAGS_ENABLE_LONG_PRESS = 0x08;
@Nullable
private final KeyVisualAttributes mKeyVisualAttributes; private final KeyVisualAttributes mKeyVisualAttributes;
@Nullable
private final OptionalAttributes mOptionalAttributes; private final OptionalAttributes mOptionalAttributes;
private static final class OptionalAttributes { private static final class OptionalAttributes {
@ -181,6 +187,7 @@ public class Key implements Comparable<Key> {
mVisualInsetsRight = visualInsetsRight; mVisualInsetsRight = visualInsetsRight;
} }
@Nullable
public static OptionalAttributes newInstance(final String outputText, final int altCode, public static OptionalAttributes newInstance(final String outputText, final int altCode,
final int disabledIconId, final int visualInsetsLeft, final int visualInsetsRight) { final int disabledIconId, final int visualInsetsLeft, final int visualInsetsRight) {
if (outputText == null && altCode == CODE_UNSPECIFIED if (outputText == null && altCode == CODE_UNSPECIFIED
@ -204,10 +211,10 @@ public class Key implements Comparable<Key> {
* Constructor for a key on <code>MoreKeyKeyboard</code>, on <code>MoreSuggestions</code>, * Constructor for a key on <code>MoreKeyKeyboard</code>, on <code>MoreSuggestions</code>,
* and in a <GridRows/>. * and in a <GridRows/>.
*/ */
public Key(final String label, final int iconId, final int code, final String outputText, public Key(@Nullable final String label, final int iconId, final int code,
final String hintLabel, final int labelFlags, final int backgroundType, final int x, @Nullable final String outputText, @Nullable final String hintLabel,
final int y, final int width, final int height, final int horizontalGap, final int labelFlags, final int backgroundType, final int x, final int y,
final int verticalGap) { final int width, final int height, final int horizontalGap, final int verticalGap) {
mWidth = width - horizontalGap; mWidth = width - horizontalGap;
mHeight = height - verticalGap; mHeight = height - verticalGap;
mHorizontalGap = horizontalGap; mHorizontalGap = horizontalGap;
@ -245,8 +252,9 @@ public class Key implements Comparable<Key> {
* @param row the row that this key belongs to. row's x-coordinate will be the right edge of * @param row the row that this key belongs to. row's x-coordinate will be the right edge of
* this key. * this key.
*/ */
public Key(final String keySpec, final TypedArray keyAttr, final KeyStyle style, public Key(@Nullable final String keySpec, @Nonnull final TypedArray keyAttr,
final KeyboardParams params, final KeyboardRow row) { @Nonnull final KeyStyle style, @Nonnull final KeyboardParams params,
@Nonnull final KeyboardRow row) {
mHorizontalGap = isSpacer() ? 0 : params.mHorizontalGap; mHorizontalGap = isSpacer() ? 0 : params.mHorizontalGap;
mVerticalGap = params.mVerticalGap; mVerticalGap = params.mVerticalGap;
@ -403,11 +411,11 @@ public class Key implements Comparable<Key> {
* *
* @param key the original key. * @param key the original key.
*/ */
protected Key(final Key key) { protected Key(@Nonnull final Key key) {
this(key, key.mMoreKeys); this(key, key.mMoreKeys);
} }
private Key(final Key key, final MoreKeySpec[] moreKeys) { private Key(@Nonnull final Key key, @Nullable final MoreKeySpec[] moreKeys) {
// Final attributes. // Final attributes.
mCode = key.mCode; mCode = key.mCode;
mLabel = key.mLabel; mLabel = key.mLabel;
@ -433,8 +441,9 @@ public class Key implements Comparable<Key> {
mEnabled = key.mEnabled; mEnabled = key.mEnabled;
} }
public static Key removeRedundantMoreKeys(final Key key, @Nonnull
final MoreKeySpec.LettersOnBaseLayout lettersOnBaseLayout) { public static Key removeRedundantMoreKeys(@Nonnull final Key key,
@Nonnull final MoreKeySpec.LettersOnBaseLayout lettersOnBaseLayout) {
final MoreKeySpec[] moreKeys = key.getMoreKeys(); final MoreKeySpec[] moreKeys = key.getMoreKeys();
final MoreKeySpec[] filteredMoreKeys = MoreKeySpec.removeRedundantMoreKeys( final MoreKeySpec[] filteredMoreKeys = MoreKeySpec.removeRedundantMoreKeys(
moreKeys, lettersOnBaseLayout); moreKeys, lettersOnBaseLayout);
@ -554,14 +563,17 @@ public class Key implements Comparable<Key> {
return mCode; return mCode;
} }
@Nullable
public String getLabel() { public String getLabel() {
return mLabel; return mLabel;
} }
@Nullable
public String getHintLabel() { public String getHintLabel() {
return mHintLabel; return mHintLabel;
} }
@Nullable
public MoreKeySpec[] getMoreKeys() { public MoreKeySpec[] getMoreKeys() {
return mMoreKeys; return mMoreKeys;
} }
@ -620,6 +632,7 @@ public class Key implements Comparable<Key> {
return mKeyVisualAttributes; return mKeyVisualAttributes;
} }
@Nonnull
public final Typeface selectTypeface(final KeyDrawParams params) { public final Typeface selectTypeface(final KeyDrawParams params) {
switch (mLabelFlags & LABEL_FLAGS_FONT_MASK) { switch (mLabelFlags & LABEL_FLAGS_FONT_MASK) {
case LABEL_FLAGS_FONT_NORMAL: case LABEL_FLAGS_FONT_NORMAL:
@ -696,6 +709,7 @@ public class Key implements Comparable<Key> {
return params.mLetterSize; return params.mLetterSize;
} }
@Nonnull
public Typeface selectPreviewTypeface(final KeyDrawParams params) { public Typeface selectPreviewTypeface(final KeyDrawParams params) {
if (previewHasLetterSize()) { if (previewHasLetterSize()) {
return selectTypeface(params); return selectTypeface(params);
@ -780,6 +794,7 @@ public class Key implements Comparable<Key> {
return (mMoreKeysColumnAndFlags & MORE_KEYS_FLAGS_NO_PANEL_AUTO_MORE_KEY) != 0; return (mMoreKeysColumnAndFlags & MORE_KEYS_FLAGS_NO_PANEL_AUTO_MORE_KEY) != 0;
} }
@Nullable
public final String getOutputText() { public final String getOutputText() {
final OptionalAttributes attrs = mOptionalAttributes; final OptionalAttributes attrs = mOptionalAttributes;
return (attrs != null) ? attrs.mOutputText : null; return (attrs != null) ? attrs.mOutputText : null;
@ -794,6 +809,7 @@ public class Key implements Comparable<Key> {
return mIconId; return mIconId;
} }
@Nullable
public Drawable getIcon(final KeyboardIconsSet iconSet, final int alpha) { public Drawable getIcon(final KeyboardIconsSet iconSet, final int alpha) {
final OptionalAttributes attrs = mOptionalAttributes; final OptionalAttributes attrs = mOptionalAttributes;
final int disabledIconId = (attrs != null) ? attrs.mDisabledIconId : ICON_UNDEFINED; final int disabledIconId = (attrs != null) ? attrs.mDisabledIconId : ICON_UNDEFINED;
@ -805,6 +821,7 @@ public class Key implements Comparable<Key> {
return icon; return icon;
} }
@Nullable
public Drawable getPreviewIcon(final KeyboardIconsSet iconSet) { public Drawable getPreviewIcon(final KeyboardIconsSet iconSet) {
return iconSet.getIconDrawable(getIconId()); return iconSet.getIconDrawable(getIconId());
} }
@ -897,6 +914,7 @@ public class Key implements Comparable<Key> {
mEnabled = enabled; mEnabled = enabled;
} }
@Nonnull
public Rect getHitBox() { public Rect getHitBox() {
return mHitBox; return mHitBox;
} }
@ -968,8 +986,10 @@ public class Key implements Comparable<Key> {
* @return the background drawable of the key. * @return the background drawable of the key.
* @see android.graphics.drawable.StateListDrawable#setState(int[]) * @see android.graphics.drawable.StateListDrawable#setState(int[])
*/ */
public final Drawable selectBackgroundDrawable(final Drawable keyBackground, @Nonnull
final Drawable functionalKeyBackground, final Drawable spacebarBackground) { public final Drawable selectBackgroundDrawable(@Nonnull final Drawable keyBackground,
@Nonnull final Drawable functionalKeyBackground,
@Nonnull final Drawable spacebarBackground) {
final Drawable background; final Drawable background;
if (mBackgroundType == BACKGROUND_TYPE_FUNCTIONAL) { if (mBackgroundType == BACKGROUND_TYPE_FUNCTIONAL) {
background = functionalKeyBackground; background = functionalKeyBackground;

View file

@ -28,6 +28,9 @@ import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
/** /**
* Loads an XML description of a keyboard and stores the attributes of the keys. A keyboard * Loads an XML description of a keyboard and stores the attributes of the keys. A keyboard
* consists of rows of keys. * consists of rows of keys.
@ -47,6 +50,7 @@ import java.util.List;
* </pre> * </pre>
*/ */
public class Keyboard { public class Keyboard {
@Nonnull
public final KeyboardId mId; public final KeyboardId mId;
public final int mThemeId; public final int mThemeId;
@ -78,17 +82,22 @@ public class Keyboard {
public final int mMaxMoreKeysKeyboardColumn; public final int mMaxMoreKeysKeyboardColumn;
/** List of keys in this keyboard */ /** List of keys in this keyboard */
@Nonnull
private final List<Key> mSortedKeys; private final List<Key> mSortedKeys;
@Nonnull
public final List<Key> mShiftKeys; public final List<Key> mShiftKeys;
@Nonnull
public final List<Key> mAltCodeKeysWhileTyping; public final List<Key> mAltCodeKeysWhileTyping;
@Nonnull
public final KeyboardIconsSet mIconsSet; public final KeyboardIconsSet mIconsSet;
private final SparseArray<Key> mKeyCache = new SparseArray<>(); private final SparseArray<Key> mKeyCache = new SparseArray<>();
@Nonnull
private final ProximityInfo mProximityInfo; private final ProximityInfo mProximityInfo;
private final boolean mProximityCharsCorrectionEnabled; private final boolean mProximityCharsCorrectionEnabled;
public Keyboard(final KeyboardParams params) { public Keyboard(@Nonnull final KeyboardParams params) {
mId = params.mId; mId = params.mId;
mThemeId = params.mThemeId; mThemeId = params.mThemeId;
mOccupiedHeight = params.mOccupiedHeight; mOccupiedHeight = params.mOccupiedHeight;
@ -114,7 +123,7 @@ public class Keyboard {
mProximityCharsCorrectionEnabled = params.mProximityCharsCorrectionEnabled; mProximityCharsCorrectionEnabled = params.mProximityCharsCorrectionEnabled;
} }
protected Keyboard(final Keyboard keyboard) { protected Keyboard(@Nonnull final Keyboard keyboard) {
mId = keyboard.mId; mId = keyboard.mId;
mThemeId = keyboard.mThemeId; mThemeId = keyboard.mThemeId;
mOccupiedHeight = keyboard.mOccupiedHeight; mOccupiedHeight = keyboard.mOccupiedHeight;
@ -150,6 +159,7 @@ public class Keyboard {
return canAssumeNativeHasProximityCharsInfoOfAllKeys || Character.isLetter(code); return canAssumeNativeHasProximityCharsInfoOfAllKeys || Character.isLetter(code);
} }
@Nonnull
public ProximityInfo getProximityInfo() { public ProximityInfo getProximityInfo() {
return mProximityInfo; return mProximityInfo;
} }
@ -160,10 +170,12 @@ public class Keyboard {
* The list may contain {@link Key.Spacer} object as well. * The list may contain {@link Key.Spacer} object as well.
* @return the sorted unmodifiable list of {@link Key}s of this keyboard. * @return the sorted unmodifiable list of {@link Key}s of this keyboard.
*/ */
@Nonnull
public List<Key> getSortedKeys() { public List<Key> getSortedKeys() {
return mSortedKeys; return mSortedKeys;
} }
@Nullable
public Key getKey(final int code) { public Key getKey(final int code) {
if (code == Constants.CODE_UNSPECIFIED) { if (code == Constants.CODE_UNSPECIFIED) {
return null; return null;
@ -185,7 +197,7 @@ public class Keyboard {
} }
} }
public boolean hasKey(final Key aKey) { public boolean hasKey(@Nonnull final Key aKey) {
if (mKeyCache.indexOfValue(aKey) >= 0) { if (mKeyCache.indexOfValue(aKey) >= 0) {
return true; return true;
} }
@ -211,6 +223,7 @@ public class Keyboard {
* @return the list of the nearest keys to the given point. If the given * @return the list of the nearest keys to the given point. If the given
* point is out of range, then an array of size zero is returned. * point is out of range, then an array of size zero is returned.
*/ */
@Nonnull
public List<Key> getNearestKeys(final int x, final int y) { public List<Key> getNearestKeys(final int x, final int y) {
// Avoid dead pixels at edges of the keyboard // Avoid dead pixels at edges of the keyboard
final int adjustedX = Math.max(0, Math.min(x, mOccupiedWidth - 1)); final int adjustedX = Math.max(0, Math.min(x, mOccupiedWidth - 1));
@ -218,7 +231,8 @@ public class Keyboard {
return mProximityInfo.getNearestKeys(adjustedX, adjustedY); return mProximityInfo.getNearestKeys(adjustedX, adjustedY);
} }
public int[] getCoordinates(final int[] codePoints) { @Nonnull
public int[] getCoordinates(@Nonnull final int[] codePoints) {
final int length = codePoints.length; final int length = codePoints.length;
final int[] coordinates = CoordinateUtils.newCoordinateArray(length); final int[] coordinates = CoordinateUtils.newCoordinateArray(length);
for (int i = 0; i < length; ++i) { for (int i = 0; i < length; ++i) {

View file

@ -72,6 +72,7 @@ public final class KeyboardLayoutSet {
private static final String KEYBOARD_LAYOUT_SET_RESOURCE_PREFIX = "keyboard_layout_set_"; private static final String KEYBOARD_LAYOUT_SET_RESOURCE_PREFIX = "keyboard_layout_set_";
private final Context mContext; private final Context mContext;
@Nonnull
private final Params mParams; private final Params mParams;
// How many layouts we forcibly keep in cache. This only includes ALPHABET (default) and // How many layouts we forcibly keep in cache. This only includes ALPHABET (default) and
@ -84,6 +85,7 @@ public final class KeyboardLayoutSet {
private static final Keyboard[] sForcibleKeyboardCache = new Keyboard[FORCIBLE_CACHE_SIZE]; private static final Keyboard[] sForcibleKeyboardCache = new Keyboard[FORCIBLE_CACHE_SIZE];
private static final HashMap<KeyboardId, SoftReference<Keyboard>> sKeyboardCache = private static final HashMap<KeyboardId, SoftReference<Keyboard>> sKeyboardCache =
new HashMap<>(); new HashMap<>();
@Nonnull
private static final KeysCache sKeysCache = new KeysCache(); private static final KeysCache sKeysCache = new KeysCache();
private final static HashMap<InputMethodSubtype, Integer> sScriptIdsForSubtypes = private final static HashMap<InputMethodSubtype, Integer> sScriptIdsForSubtypes =
new HashMap<>(); new HashMap<>();
@ -145,7 +147,8 @@ public final class KeyboardLayoutSet {
sKeysCache.clear(); sKeysCache.clear();
} }
public static int getScriptId(final Resources resources, final InputMethodSubtype subtype) { public static int getScriptId(final Resources resources,
@Nonnull final InputMethodSubtype subtype) {
final Integer value = sScriptIdsForSubtypes.get(subtype); final Integer value = sScriptIdsForSubtypes.get(subtype);
if (null == value) { if (null == value) {
final int scriptId = Builder.readScriptId(resources, subtype); final int scriptId = Builder.readScriptId(resources, subtype);
@ -155,11 +158,12 @@ public final class KeyboardLayoutSet {
return value; return value;
} }
KeyboardLayoutSet(final Context context, final Params params) { KeyboardLayoutSet(final Context context, @Nonnull final Params params) {
mContext = context; mContext = context;
mParams = params; mParams = params;
} }
@Nonnull
public Keyboard getKeyboard(final int baseKeyboardLayoutSetElementId) { public Keyboard getKeyboard(final int baseKeyboardLayoutSetElementId) {
final int keyboardLayoutSetElementId; final int keyboardLayoutSetElementId;
switch (mParams.mMode) { switch (mParams.mMode) {
@ -203,6 +207,7 @@ public final class KeyboardLayoutSet {
} }
} }
@Nonnull
private Keyboard getKeyboard(final ElementParams elementParams, final KeyboardId id) { private Keyboard getKeyboard(final ElementParams elementParams, final KeyboardId id) {
final SoftReference<Keyboard> ref = sKeyboardCache.get(id); final SoftReference<Keyboard> ref = sKeyboardCache.get(id);
final Keyboard cachedKeyboard = (ref == null) ? null : ref.get(); final Keyboard cachedKeyboard = (ref == null) ? null : ref.get();

View file

@ -103,7 +103,8 @@ public class KeyboardView extends View {
// TODO: Consider having a dummy keyboard object to make this @Nonnull // TODO: Consider having a dummy keyboard object to make this @Nonnull
@Nullable @Nullable
private Keyboard mKeyboard; private Keyboard mKeyboard;
protected final KeyDrawParams mKeyDrawParams = new KeyDrawParams(); @Nonnull
private final KeyDrawParams mKeyDrawParams = new KeyDrawParams();
// Drawing // Drawing
/** True if all keys should be drawn */ /** True if all keys should be drawn */
@ -120,6 +121,7 @@ public class KeyboardView extends View {
@Nonnull @Nonnull
private final Paint mPaint = new Paint(); private final Paint mPaint = new Paint();
private final Paint.FontMetrics mFontMetrics = new Paint.FontMetrics(); private final Paint.FontMetrics mFontMetrics = new Paint.FontMetrics();
public KeyboardView(final Context context, final AttributeSet attrs) { public KeyboardView(final Context context, final AttributeSet attrs) {
this(context, attrs, R.attr.keyboardViewStyle); this(context, attrs, R.attr.keyboardViewStyle);
} }
@ -210,6 +212,11 @@ public class KeyboardView extends View {
return mVerticalCorrection; return mVerticalCorrection;
} }
@Nonnull
protected KeyDrawParams getKeyDrawParams() {
return mKeyDrawParams;
}
protected void updateKeyDrawParams(final int keyHeight) { protected void updateKeyDrawParams(final int keyHeight) {
mKeyDrawParams.updateParams(keyHeight, mKeyVisualAttributes); mKeyDrawParams.updateParams(keyHeight, mKeyVisualAttributes);
} }

View file

@ -484,7 +484,7 @@ public final class MainKeyboardView extends KeyboardView implements DrawingProxy
locatePreviewPlacerView(); locatePreviewPlacerView();
getLocationInWindow(mOriginCoords); getLocationInWindow(mOriginCoords);
mKeyPreviewChoreographer.placeAndShowKeyPreview(key, keyboard.mIconsSet, mKeyDrawParams, mKeyPreviewChoreographer.placeAndShowKeyPreview(key, keyboard.mIconsSet, getKeyDrawParams(),
getWidth(), mOriginCoords, mDrawingPreviewPlacerView, isHardwareAccelerated()); getWidth(), mOriginCoords, mDrawingPreviewPlacerView, isHardwareAccelerated());
} }

View file

@ -27,6 +27,8 @@ import com.android.inputmethod.latin.R;
import com.android.inputmethod.latin.common.StringUtils; import com.android.inputmethod.latin.common.StringUtils;
import com.android.inputmethod.latin.utils.TypefaceUtils; import com.android.inputmethod.latin.utils.TypefaceUtils;
import javax.annotation.Nonnull;
public final class MoreKeysKeyboard extends Keyboard { public final class MoreKeysKeyboard extends Keyboard {
private final int mDefaultKeyCoordX; private final int mDefaultKeyCoordX;
@ -328,6 +330,7 @@ public final class MoreKeysKeyboard extends Keyboard {
} }
@Override @Override
@Nonnull
public MoreKeysKeyboard build() { public MoreKeysKeyboard build() {
final MoreKeysKeyboardParams params = mParams; final MoreKeysKeyboardParams params = mParams;
final int moreKeyFlags = mParentKey.getMoreKeyLabelFlags(); final int moreKeyFlags = mParentKey.getMoreKeyLabelFlags();

View file

@ -28,6 +28,8 @@ import java.util.Arrays;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import javax.annotation.Nonnull;
public class ProximityInfo { public class ProximityInfo {
private static final String TAG = ProximityInfo.class.getSimpleName(); private static final String TAG = ProximityInfo.class.getSimpleName();
private static final boolean DEBUG = false; private static final boolean DEBUG = false;
@ -36,6 +38,7 @@ public class ProximityInfo {
public static final int MAX_PROXIMITY_CHARS_SIZE = 16; public static final int MAX_PROXIMITY_CHARS_SIZE = 16;
/** Number of key widths from current touch point to search for nearest keys. */ /** Number of key widths from current touch point to search for nearest keys. */
private static final float SEARCH_DISTANCE = 1.2f; private static final float SEARCH_DISTANCE = 1.2f;
@Nonnull
private static final List<Key> EMPTY_KEY_LIST = Collections.emptyList(); private static final List<Key> EMPTY_KEY_LIST = Collections.emptyList();
private static final float DEFAULT_TOUCH_POSITION_CORRECTION_RADIUS = 0.15f; private static final float DEFAULT_TOUCH_POSITION_CORRECTION_RADIUS = 0.15f;
@ -49,13 +52,16 @@ public class ProximityInfo {
private final int mKeyboardHeight; private final int mKeyboardHeight;
private final int mMostCommonKeyWidth; private final int mMostCommonKeyWidth;
private final int mMostCommonKeyHeight; private final int mMostCommonKeyHeight;
@Nonnull
private final List<Key> mSortedKeys; private final List<Key> mSortedKeys;
@Nonnull
private final List<Key>[] mGridNeighbors; private final List<Key>[] mGridNeighbors;
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
ProximityInfo(final int gridWidth, final int gridHeight, final int minWidth, final int height, ProximityInfo(final int gridWidth, final int gridHeight, final int minWidth, final int height,
final int mostCommonKeyWidth, final int mostCommonKeyHeight, final List<Key> sortedKeys, final int mostCommonKeyWidth, final int mostCommonKeyHeight,
final TouchPositionCorrection touchPositionCorrection) { @Nonnull final List<Key> sortedKeys,
@Nonnull final TouchPositionCorrection touchPositionCorrection) {
mGridWidth = gridWidth; mGridWidth = gridWidth;
mGridHeight = gridHeight; mGridHeight = gridHeight;
mGridSize = mGridWidth * mGridHeight; mGridSize = mGridWidth * mGridHeight;
@ -104,7 +110,8 @@ public class ProximityInfo {
return count; return count;
} }
private long createNativeProximityInfo(final TouchPositionCorrection touchPositionCorrection) { private long createNativeProximityInfo(
@Nonnull final TouchPositionCorrection touchPositionCorrection) {
final List<Key>[] gridNeighborKeys = mGridNeighbors; final List<Key>[] gridNeighborKeys = mGridNeighbors;
final int[] proximityCharsArray = new int[mGridSize * MAX_PROXIMITY_CHARS_SIZE]; final int[] proximityCharsArray = new int[mGridSize * MAX_PROXIMITY_CHARS_SIZE];
Arrays.fill(proximityCharsArray, Constants.NOT_A_CODE); Arrays.fill(proximityCharsArray, Constants.NOT_A_CODE);
@ -163,7 +170,7 @@ public class ProximityInfo {
infoIndex++; infoIndex++;
} }
if (touchPositionCorrection != null && touchPositionCorrection.isValid()) { if (touchPositionCorrection.isValid()) {
if (DEBUG) { if (DEBUG) {
Log.d(TAG, "touchPositionCorrection: ON"); Log.d(TAG, "touchPositionCorrection: ON");
} }
@ -385,10 +392,8 @@ y |---+---+---+---+-v-+-|-+---+---+---+---+---| | thresholdBase and get
} }
} }
@Nonnull
public List<Key> getNearestKeys(final int x, final int y) { public List<Key> getNearestKeys(final int x, final int y) {
if (mGridNeighbors == null) {
return EMPTY_KEY_LIST;
}
if (x >= 0 && x < mKeyboardMinWidth && y >= 0 && y < mKeyboardHeight) { if (x >= 0 && x < mKeyboardMinWidth && y >= 0 && y < mKeyboardHeight) {
int index = (y / mCellHeight) * mGridWidth + (x / mCellWidth); int index = (y / mCellHeight) * mGridWidth + (x / mCellWidth);
if (index < mGridSize) { if (index < mGridSize) {

View file

@ -20,8 +20,12 @@ import android.graphics.Typeface;
import com.android.inputmethod.latin.utils.ResourceUtils; import com.android.inputmethod.latin.utils.ResourceUtils;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
public final class KeyDrawParams { public final class KeyDrawParams {
public Typeface mTypeface; @Nonnull
public Typeface mTypeface = Typeface.DEFAULT;
public int mLetterSize; public int mLetterSize;
public int mLabelSize; public int mLabelSize;
@ -49,7 +53,7 @@ public final class KeyDrawParams {
public KeyDrawParams() {} public KeyDrawParams() {}
private KeyDrawParams(final KeyDrawParams copyFrom) { private KeyDrawParams(@Nonnull final KeyDrawParams copyFrom) {
mTypeface = copyFrom.mTypeface; mTypeface = copyFrom.mTypeface;
mLetterSize = copyFrom.mLetterSize; mLetterSize = copyFrom.mLetterSize;
@ -77,7 +81,7 @@ public final class KeyDrawParams {
mAnimAlpha = copyFrom.mAnimAlpha; mAnimAlpha = copyFrom.mAnimAlpha;
} }
public void updateParams(final int keyHeight, final KeyVisualAttributes attr) { public void updateParams(final int keyHeight, @Nullable final KeyVisualAttributes attr) {
if (attr == null) { if (attr == null) {
return; return;
} }
@ -117,8 +121,9 @@ public final class KeyDrawParams {
attr.mHintLabelOffCenterRatio, mHintLabelOffCenterRatio); attr.mHintLabelOffCenterRatio, mHintLabelOffCenterRatio);
} }
@Nonnull
public KeyDrawParams mayCloneAndUpdateParams(final int keyHeight, public KeyDrawParams mayCloneAndUpdateParams(final int keyHeight,
final KeyVisualAttributes attr) { @Nullable final KeyVisualAttributes attr) {
if (attr == null) { if (attr == null) {
return this; return this;
} }

View file

@ -22,6 +22,9 @@ import static com.android.inputmethod.latin.common.Constants.CODE_UNSPECIFIED;
import com.android.inputmethod.latin.common.Constants; import com.android.inputmethod.latin.common.Constants;
import com.android.inputmethod.latin.common.StringUtils; import com.android.inputmethod.latin.common.StringUtils;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
/** /**
* The string parser of the key specification. * The string parser of the key specification.
* *
@ -53,11 +56,11 @@ public final class KeySpecParser {
// Intentional empty constructor for utility class. // Intentional empty constructor for utility class.
} }
private static boolean hasIcon(final String keySpec) { private static boolean hasIcon(@Nonnull final String keySpec) {
return keySpec.startsWith(KeyboardIconsSet.PREFIX_ICON); return keySpec.startsWith(KeyboardIconsSet.PREFIX_ICON);
} }
private static boolean hasCode(final String keySpec, final int labelEnd) { private static boolean hasCode(@Nonnull final String keySpec, final int labelEnd) {
if (labelEnd <= 0 || labelEnd + 1 >= keySpec.length()) { if (labelEnd <= 0 || labelEnd + 1 >= keySpec.length()) {
return false; return false;
} }
@ -72,7 +75,8 @@ public final class KeySpecParser {
return false; return false;
} }
private static String parseEscape(final String text) { @Nonnull
private static String parseEscape(@Nonnull final String text) {
if (text.indexOf(BACKSLASH) < 0) { if (text.indexOf(BACKSLASH) < 0) {
return text; return text;
} }
@ -91,7 +95,7 @@ public final class KeySpecParser {
return sb.toString(); return sb.toString();
} }
private static int indexOfLabelEnd(final String keySpec) { private static int indexOfLabelEnd(@Nonnull final String keySpec) {
final int length = keySpec.length(); final int length = keySpec.length();
if (keySpec.indexOf(BACKSLASH) < 0) { if (keySpec.indexOf(BACKSLASH) < 0) {
final int labelEnd = keySpec.indexOf(VERTICAL_BAR); final int labelEnd = keySpec.indexOf(VERTICAL_BAR);
@ -116,22 +120,25 @@ public final class KeySpecParser {
return -1; return -1;
} }
private static String getBeforeLabelEnd(final String keySpec, final int labelEnd) { @Nonnull
private static String getBeforeLabelEnd(@Nonnull final String keySpec, final int labelEnd) {
return (labelEnd < 0) ? keySpec : keySpec.substring(0, labelEnd); return (labelEnd < 0) ? keySpec : keySpec.substring(0, labelEnd);
} }
private static String getAfterLabelEnd(final String keySpec, final int labelEnd) { @Nonnull
private static String getAfterLabelEnd(@Nonnull final String keySpec, final int labelEnd) {
return keySpec.substring(labelEnd + /* VERTICAL_BAR */1); return keySpec.substring(labelEnd + /* VERTICAL_BAR */1);
} }
private static void checkDoubleLabelEnd(final String keySpec, final int labelEnd) { private static void checkDoubleLabelEnd(@Nonnull final String keySpec, final int labelEnd) {
if (indexOfLabelEnd(getAfterLabelEnd(keySpec, labelEnd)) < 0) { if (indexOfLabelEnd(getAfterLabelEnd(keySpec, labelEnd)) < 0) {
return; return;
} }
throw new KeySpecParserError("Multiple " + VERTICAL_BAR + ": " + keySpec); throw new KeySpecParserError("Multiple " + VERTICAL_BAR + ": " + keySpec);
} }
public static String getLabel(final String keySpec) { @Nullable
public static String getLabel(@Nullable final String keySpec) {
if (keySpec == null) { if (keySpec == null) {
// TODO: Throw {@link KeySpecParserError} once Key.keyLabel attribute becomes mandatory. // TODO: Throw {@link KeySpecParserError} once Key.keyLabel attribute becomes mandatory.
return null; return null;
@ -147,7 +154,8 @@ public final class KeySpecParser {
return label; return label;
} }
private static String getOutputTextInternal(final String keySpec, final int labelEnd) { @Nullable
private static String getOutputTextInternal(@Nonnull final String keySpec, final int labelEnd) {
if (labelEnd <= 0) { if (labelEnd <= 0) {
return null; return null;
} }
@ -155,7 +163,8 @@ public final class KeySpecParser {
return parseEscape(getAfterLabelEnd(keySpec, labelEnd)); return parseEscape(getAfterLabelEnd(keySpec, labelEnd));
} }
public static String getOutputText(final String keySpec) { @Nullable
public static String getOutputText(@Nullable final String keySpec) {
if (keySpec == null) { if (keySpec == null) {
// TODO: Throw {@link KeySpecParserError} once Key.keyLabel attribute becomes mandatory. // TODO: Throw {@link KeySpecParserError} once Key.keyLabel attribute becomes mandatory.
return null; return null;
@ -184,7 +193,7 @@ public final class KeySpecParser {
return (StringUtils.codePointCount(label) == 1) ? null : label; return (StringUtils.codePointCount(label) == 1) ? null : label;
} }
public static int getCode(final String keySpec) { public static int getCode(@Nullable final String keySpec) {
if (keySpec == null) { if (keySpec == null) {
// TODO: Throw {@link KeySpecParserError} once Key.keyLabel attribute becomes mandatory. // TODO: Throw {@link KeySpecParserError} once Key.keyLabel attribute becomes mandatory.
return CODE_UNSPECIFIED; return CODE_UNSPECIFIED;
@ -211,7 +220,7 @@ public final class KeySpecParser {
return (StringUtils.codePointCount(label) == 1) ? label.codePointAt(0) : CODE_OUTPUT_TEXT; return (StringUtils.codePointCount(label) == 1) ? label.codePointAt(0) : CODE_OUTPUT_TEXT;
} }
public static int parseCode(final String text, final int defaultCode) { public static int parseCode(@Nullable final String text, final int defaultCode) {
if (text == null) { if (text == null) {
return defaultCode; return defaultCode;
} }
@ -226,7 +235,7 @@ public final class KeySpecParser {
return defaultCode; return defaultCode;
} }
public static int getIconId(final String keySpec) { public static int getIconId(@Nullable final String keySpec) {
if (keySpec == null) { if (keySpec == null) {
// TODO: Throw {@link KeySpecParserError} once Key.keyLabel attribute becomes mandatory. // TODO: Throw {@link KeySpecParserError} once Key.keyLabel attribute becomes mandatory.
return KeyboardIconsSet.ICON_UNDEFINED; return KeyboardIconsSet.ICON_UNDEFINED;

View file

@ -18,18 +18,22 @@ package com.android.inputmethod.keyboard.internal;
import android.content.res.TypedArray; import android.content.res.TypedArray;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
public abstract class KeyStyle { public abstract class KeyStyle {
private final KeyboardTextsSet mTextsSet; private final KeyboardTextsSet mTextsSet;
public abstract String[] getStringArray(TypedArray a, int index); public abstract @Nullable String[] getStringArray(TypedArray a, int index);
public abstract String getString(TypedArray a, int index); public abstract @Nullable String getString(TypedArray a, int index);
public abstract int getInt(TypedArray a, int index, int defaultValue); public abstract int getInt(TypedArray a, int index, int defaultValue);
public abstract int getFlags(TypedArray a, int index); public abstract int getFlags(TypedArray a, int index);
protected KeyStyle(final KeyboardTextsSet textsSet) { protected KeyStyle(@Nonnull final KeyboardTextsSet textsSet) {
mTextsSet = textsSet; mTextsSet = textsSet;
} }
@Nullable
protected String parseString(final TypedArray a, final int index) { protected String parseString(final TypedArray a, final int index) {
if (a.hasValue(index)) { if (a.hasValue(index)) {
return mTextsSet.resolveTextReference(a.getString(index)); return mTextsSet.resolveTextReference(a.getString(index));
@ -37,6 +41,7 @@ public abstract class KeyStyle {
return null; return null;
} }
@Nullable
protected String[] parseStringArray(final TypedArray a, final int index) { protected String[] parseStringArray(final TypedArray a, final int index) {
if (a.hasValue(index)) { if (a.hasValue(index)) {
final String text = mTextsSet.resolveTextReference(a.getString(index)); final String text = mTextsSet.resolveTextReference(a.getString(index));

View file

@ -29,33 +29,42 @@ import org.xmlpull.v1.XmlPullParserException;
import java.util.Arrays; import java.util.Arrays;
import java.util.HashMap; import java.util.HashMap;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
public final class KeyStylesSet { public final class KeyStylesSet {
private static final String TAG = KeyStylesSet.class.getSimpleName(); private static final String TAG = KeyStylesSet.class.getSimpleName();
private static final boolean DEBUG = false; private static final boolean DEBUG = false;
@Nonnull
private final HashMap<String, KeyStyle> mStyles = new HashMap<>(); private final HashMap<String, KeyStyle> mStyles = new HashMap<>();
@Nonnull
private final KeyboardTextsSet mTextsSet; private final KeyboardTextsSet mTextsSet;
@Nonnull
private final KeyStyle mEmptyKeyStyle; private final KeyStyle mEmptyKeyStyle;
@Nonnull
private static final String EMPTY_STYLE_NAME = "<empty>"; private static final String EMPTY_STYLE_NAME = "<empty>";
public KeyStylesSet(final KeyboardTextsSet textsSet) { public KeyStylesSet(@Nonnull final KeyboardTextsSet textsSet) {
mTextsSet = textsSet; mTextsSet = textsSet;
mEmptyKeyStyle = new EmptyKeyStyle(textsSet); mEmptyKeyStyle = new EmptyKeyStyle(textsSet);
mStyles.put(EMPTY_STYLE_NAME, mEmptyKeyStyle); mStyles.put(EMPTY_STYLE_NAME, mEmptyKeyStyle);
} }
private static final class EmptyKeyStyle extends KeyStyle { private static final class EmptyKeyStyle extends KeyStyle {
EmptyKeyStyle(final KeyboardTextsSet textsSet) { EmptyKeyStyle(@Nonnull final KeyboardTextsSet textsSet) {
super(textsSet); super(textsSet);
} }
@Override @Override
@Nullable
public String[] getStringArray(final TypedArray a, final int index) { public String[] getStringArray(final TypedArray a, final int index) {
return parseStringArray(a, index); return parseStringArray(a, index);
} }
@Override @Override
@Nullable
public String getString(final TypedArray a, final int index) { public String getString(final TypedArray a, final int index) {
return parseString(a, index); return parseString(a, index);
} }
@ -76,14 +85,16 @@ public final class KeyStylesSet {
private final String mParentStyleName; private final String mParentStyleName;
private final SparseArray<Object> mStyleAttributes = new SparseArray<>(); private final SparseArray<Object> mStyleAttributes = new SparseArray<>();
public DeclaredKeyStyle(final String parentStyleName, final KeyboardTextsSet textsSet, public DeclaredKeyStyle(@Nonnull final String parentStyleName,
final HashMap<String, KeyStyle> styles) { @Nonnull final KeyboardTextsSet textsSet,
@Nonnull final HashMap<String, KeyStyle> styles) {
super(textsSet); super(textsSet);
mParentStyleName = parentStyleName; mParentStyleName = parentStyleName;
mStyles = styles; mStyles = styles;
} }
@Override @Override
@Nullable
public String[] getStringArray(final TypedArray a, final int index) { public String[] getStringArray(final TypedArray a, final int index) {
if (a.hasValue(index)) { if (a.hasValue(index)) {
return parseStringArray(a, index); return parseStringArray(a, index);
@ -98,6 +109,7 @@ public final class KeyStylesSet {
} }
@Override @Override
@Nullable
public String getString(final TypedArray a, final int index) { public String getString(final TypedArray a, final int index) {
if (a.hasValue(index)) { if (a.hasValue(index)) {
return parseString(a, index); return parseString(a, index);
@ -176,37 +188,43 @@ public final class KeyStylesSet {
public void parseKeyStyleAttributes(final TypedArray keyStyleAttr, final TypedArray keyAttrs, public void parseKeyStyleAttributes(final TypedArray keyStyleAttr, final TypedArray keyAttrs,
final XmlPullParser parser) throws XmlPullParserException { final XmlPullParser parser) throws XmlPullParserException {
final String styleName = keyStyleAttr.getString(R.styleable.Keyboard_KeyStyle_styleName); final String styleName = keyStyleAttr.getString(R.styleable.Keyboard_KeyStyle_styleName);
if (styleName == null) {
throw new XmlParseUtils.ParseException(
KeyboardBuilder.TAG_KEY_STYLE + " has no styleName attribute", parser);
}
if (DEBUG) { if (DEBUG) {
Log.d(TAG, String.format("<%s styleName=%s />", Log.d(TAG, String.format("<%s styleName=%s />",
KeyboardBuilder.TAG_KEY_STYLE, styleName)); KeyboardBuilder.TAG_KEY_STYLE, styleName));
if (mStyles.containsKey(styleName)) { if (mStyles.containsKey(styleName)) {
Log.d(TAG, "key-style " + styleName + " is overridden at " Log.d(TAG, KeyboardBuilder.TAG_KEY_STYLE + " " + styleName + " is overridden at "
+ parser.getPositionDescription()); + parser.getPositionDescription());
} }
} }
String parentStyleName = EMPTY_STYLE_NAME; final String parentStyleInAttr = keyStyleAttr.getString(
if (keyStyleAttr.hasValue(R.styleable.Keyboard_KeyStyle_parentStyle)) { R.styleable.Keyboard_KeyStyle_parentStyle);
parentStyleName = keyStyleAttr.getString(R.styleable.Keyboard_KeyStyle_parentStyle); if (parentStyleInAttr != null && !mStyles.containsKey(parentStyleInAttr)) {
if (!mStyles.containsKey(parentStyleName)) { throw new XmlParseUtils.ParseException(
throw new XmlParseUtils.ParseException( "Unknown parentStyle " + parentStyleInAttr, parser);
"Unknown parentStyle " + parentStyleName, parser);
}
} }
final String parentStyleName = (parentStyleInAttr == null) ? EMPTY_STYLE_NAME
: parentStyleInAttr;
final DeclaredKeyStyle style = new DeclaredKeyStyle(parentStyleName, mTextsSet, mStyles); final DeclaredKeyStyle style = new DeclaredKeyStyle(parentStyleName, mTextsSet, mStyles);
style.readKeyAttributes(keyAttrs); style.readKeyAttributes(keyAttrs);
mStyles.put(styleName, style); mStyles.put(styleName, style);
} }
@Nonnull
public KeyStyle getKeyStyle(final TypedArray keyAttr, final XmlPullParser parser) public KeyStyle getKeyStyle(final TypedArray keyAttr, final XmlPullParser parser)
throws XmlParseUtils.ParseException { throws XmlParseUtils.ParseException {
if (!keyAttr.hasValue(R.styleable.Keyboard_Key_keyStyle)) { final String styleName = keyAttr.getString(R.styleable.Keyboard_Key_keyStyle);
if (styleName == null) {
return mEmptyKeyStyle; return mEmptyKeyStyle;
} }
final String styleName = keyAttr.getString(R.styleable.Keyboard_Key_keyStyle); final KeyStyle style = mStyles.get(styleName);
if (!mStyles.containsKey(styleName)) { if (style == null) {
throw new XmlParseUtils.ParseException("Unknown key style: " + styleName, parser); throw new XmlParseUtils.ParseException("Unknown key style: " + styleName, parser);
} }
return mStyles.get(styleName); return style;
} }
} }

View file

@ -23,7 +23,11 @@ import android.util.SparseIntArray;
import com.android.inputmethod.latin.R; import com.android.inputmethod.latin.R;
import com.android.inputmethod.latin.utils.ResourceUtils; import com.android.inputmethod.latin.utils.ResourceUtils;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
public final class KeyVisualAttributes { public final class KeyVisualAttributes {
@Nullable
public final Typeface mTypeface; public final Typeface mTypeface;
public final float mLetterRatio; public final float mLetterRatio;
@ -81,7 +85,8 @@ public final class KeyVisualAttributes {
} }
} }
public static KeyVisualAttributes newInstance(final TypedArray keyAttr) { @Nullable
public static KeyVisualAttributes newInstance(@Nonnull final TypedArray keyAttr) {
final int indexCount = keyAttr.getIndexCount(); final int indexCount = keyAttr.getIndexCount();
for (int i = 0; i < indexCount; i++) { for (int i = 0; i < indexCount; i++) {
final int attrId = keyAttr.getIndex(i); final int attrId = keyAttr.getIndex(i);
@ -93,7 +98,7 @@ public final class KeyVisualAttributes {
return null; return null;
} }
private KeyVisualAttributes(final TypedArray keyAttr) { private KeyVisualAttributes(@Nonnull final TypedArray keyAttr) {
if (keyAttr.hasValue(R.styleable.Keyboard_Key_keyTypeface)) { if (keyAttr.hasValue(R.styleable.Keyboard_Key_keyTypeface)) {
mTypeface = Typeface.defaultFromStyle( mTypeface = Typeface.defaultFromStyle(
keyAttr.getInt(R.styleable.Keyboard_Key_keyTypeface, Typeface.NORMAL)); keyAttr.getInt(R.styleable.Keyboard_Key_keyTypeface, Typeface.NORMAL));

View file

@ -139,6 +139,7 @@ public class KeyboardBuilder<KP extends KeyboardParams> {
private static final int DEFAULT_KEYBOARD_COLUMNS = 10; private static final int DEFAULT_KEYBOARD_COLUMNS = 10;
private static final int DEFAULT_KEYBOARD_ROWS = 4; private static final int DEFAULT_KEYBOARD_ROWS = 4;
@Nonnull
protected final KP mParams; protected final KP mParams;
protected final Context mContext; protected final Context mContext;
protected final Resources mResources; protected final Resources mResources;
@ -149,7 +150,7 @@ public class KeyboardBuilder<KP extends KeyboardParams> {
private boolean mTopEdge; private boolean mTopEdge;
private Key mRightEdgeKey = null; private Key mRightEdgeKey = null;
public KeyboardBuilder(final Context context, final KP params) { public KeyboardBuilder(final Context context, @Nonnull final KP params) {
mContext = context; mContext = context;
final Resources res = context.getResources(); final Resources res = context.getResources();
mResources = res; mResources = res;
@ -194,6 +195,7 @@ public class KeyboardBuilder<KP extends KeyboardParams> {
mParams.mProximityCharsCorrectionEnabled = enabled; mParams.mProximityCharsCorrectionEnabled = enabled;
} }
@Nonnull
public Keyboard build() { public Keyboard build() {
return new Keyboard(mParams); return new Keyboard(mParams);
} }

View file

@ -26,6 +26,9 @@ import com.android.inputmethod.latin.R;
import java.util.HashMap; import java.util.HashMap;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
public final class KeyboardIconsSet { public final class KeyboardIconsSet {
private static final String TAG = KeyboardIconsSet.class.getSimpleName(); private static final String TAG = KeyboardIconsSet.class.getSimpleName();
@ -127,6 +130,7 @@ public final class KeyboardIconsSet {
return iconId >= 0 && iconId < ICON_NAMES.length; return iconId >= 0 && iconId < ICON_NAMES.length;
} }
@Nonnull
public static String getIconName(final int iconId) { public static String getIconName(final int iconId) {
return isValidIconId(iconId) ? ICON_NAMES[iconId] : "unknown<" + iconId + ">"; return isValidIconId(iconId) ? ICON_NAMES[iconId] : "unknown<" + iconId + ">";
} }
@ -147,6 +151,7 @@ public final class KeyboardIconsSet {
throw new RuntimeException("unknown icon name: " + name); throw new RuntimeException("unknown icon name: " + name);
} }
@Nullable
public Drawable getIconDrawable(final int iconId) { public Drawable getIconDrawable(final int iconId) {
if (isValidIconId(iconId)) { if (isValidIconId(iconId)) {
return mIcons[iconId]; return mIcons[iconId];

View file

@ -49,6 +49,7 @@ public class KeyboardParams {
public int mLeftPadding; public int mLeftPadding;
public int mRightPadding; public int mRightPadding;
@Nullable
public KeyVisualAttributes mKeyVisualAttributes; public KeyVisualAttributes mKeyVisualAttributes;
public int mDefaultRowHeight; public int mDefaultRowHeight;
@ -63,14 +64,22 @@ public class KeyboardParams {
public int GRID_HEIGHT; public int GRID_HEIGHT;
// Keys are sorted from top-left to bottom-right order. // Keys are sorted from top-left to bottom-right order.
@Nonnull
public final SortedSet<Key> mSortedKeys = new TreeSet<>(ROW_COLUMN_COMPARATOR); public final SortedSet<Key> mSortedKeys = new TreeSet<>(ROW_COLUMN_COMPARATOR);
@Nonnull
public final ArrayList<Key> mShiftKeys = new ArrayList<>(); public final ArrayList<Key> mShiftKeys = new ArrayList<>();
@Nonnull
public final ArrayList<Key> mAltCodeKeysWhileTyping = new ArrayList<>(); public final ArrayList<Key> mAltCodeKeysWhileTyping = new ArrayList<>();
@Nonnull
public final KeyboardIconsSet mIconsSet = new KeyboardIconsSet(); public final KeyboardIconsSet mIconsSet = new KeyboardIconsSet();
@Nonnull
public final KeyboardTextsSet mTextsSet = new KeyboardTextsSet(); public final KeyboardTextsSet mTextsSet = new KeyboardTextsSet();
@Nonnull
public final KeyStylesSet mKeyStyles = new KeyStylesSet(mTextsSet); public final KeyStylesSet mKeyStyles = new KeyStylesSet(mTextsSet);
@Nullable public KeysCache mKeysCache; // TODO: Make this @Nonnull
@Nullable
public KeysCache mKeysCache;
public boolean mAllowRedundantMoreKeys; public boolean mAllowRedundantMoreKeys;
public int mMostCommonKeyHeight = 0; public int mMostCommonKeyHeight = 0;
@ -78,6 +87,7 @@ public class KeyboardParams {
public boolean mProximityCharsCorrectionEnabled; public boolean mProximityCharsCorrectionEnabled;
@Nonnull
public final TouchPositionCorrection mTouchPositionCorrection = public final TouchPositionCorrection mTouchPositionCorrection =
new TouchPositionCorrection(); new TouchPositionCorrection();
@ -100,7 +110,9 @@ public class KeyboardParams {
} }
public void onAddKey(@Nonnull final Key newKey) { public void onAddKey(@Nonnull final Key newKey) {
final Key key = (mKeysCache != null) ? mKeysCache.get(newKey) : newKey; // To avoid possible null pointer access.
final KeysCache keysCache = mKeysCache;
final Key key = (keysCache != null) ? keysCache.get(newKey) : newKey;
final boolean isSpacer = key.isSpacer(); final boolean isSpacer = key.isSpacer();
if (isSpacer && key.getWidth() == 0) { if (isSpacer && key.getWidth() == 0) {
// Ignore zero width {@link Spacer}. // Ignore zero width {@link Spacer}.
@ -128,12 +140,14 @@ public class KeyboardParams {
for (final Key key : mSortedKeys) { for (final Key key : mSortedKeys) {
lettersOnBaseLayout.addLetter(key); lettersOnBaseLayout.addLetter(key);
} }
// To avoid possible null pointer access.
final KeysCache keysCache = mKeysCache;
final ArrayList<Key> allKeys = new ArrayList<>(mSortedKeys); final ArrayList<Key> allKeys = new ArrayList<>(mSortedKeys);
mSortedKeys.clear(); mSortedKeys.clear();
for (final Key key : allKeys) { for (final Key key : allKeys) {
final Key filteredKey = Key.removeRedundantMoreKeys(key, lettersOnBaseLayout); final Key filteredKey = Key.removeRedundantMoreKeys(key, lettersOnBaseLayout);
if (mKeysCache != null) { if (keysCache != null) {
mKeysCache.replace(key, filteredKey); keysCache.replace(key, filteredKey);
} }
mSortedKeys.add(filteredKey); mSortedKeys.add(filteredKey);
} }

View file

@ -20,6 +20,7 @@ import com.android.inputmethod.keyboard.Key;
import java.util.HashMap; import java.util.HashMap;
// TODO: Rename more appropriate name.
public final class KeysCache { public final class KeysCache {
private final HashMap<Key, Key> mMap = new HashMap<>(); private final HashMap<Key, Key> mMap = new HashMap<>();
@ -27,6 +28,7 @@ public final class KeysCache {
mMap.clear(); mMap.clear();
} }
// TODO: Rename more descriptive name.
public Key get(final Key key) { public Key get(final Key key) {
final Key existingKey = mMap.get(key); final Key existingKey = mMap.get(key);
if (existingKey != null) { if (existingKey != null) {
@ -37,6 +39,7 @@ public final class KeysCache {
return key; return key;
} }
// TODO: Rename more descriptive name.
public Key replace(final Key oldKey, final Key newKey) { public Key replace(final Key oldKey, final Key newKey) {
if (oldKey.equals(newKey)) { if (oldKey.equals(newKey)) {
return oldKey; return oldKey;

View file

@ -24,14 +24,13 @@ import com.android.inputmethod.keyboard.Key;
import com.android.inputmethod.latin.common.CollectionUtils; import com.android.inputmethod.latin.common.CollectionUtils;
import com.android.inputmethod.latin.common.Constants; import com.android.inputmethod.latin.common.Constants;
import com.android.inputmethod.latin.common.StringUtils; import com.android.inputmethod.latin.common.StringUtils;
import com.android.inputmethod.latin.define.DebugFlags;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet; import java.util.HashSet;
import java.util.Locale; import java.util.Locale;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import javax.annotation.Nullable;
/** /**
* The more key specification object. The more keys are an array of {@link MoreKeySpec}. * The more key specification object. The more keys are an array of {@link MoreKeySpec}.
@ -47,12 +46,15 @@ import javax.annotation.Nonnull;
// TODO: Should extend the key specification object. // TODO: Should extend the key specification object.
public final class MoreKeySpec { public final class MoreKeySpec {
public final int mCode; public final int mCode;
@Nullable
public final String mLabel; public final String mLabel;
@Nullable
public final String mOutputText; public final String mOutputText;
public final int mIconId; public final int mIconId;
public MoreKeySpec(final String moreKeySpec, boolean needsToUpperCase, final Locale locale) { public MoreKeySpec(@Nonnull final String moreKeySpec, boolean needsToUpperCase,
if (TextUtils.isEmpty(moreKeySpec)) { @Nonnull final Locale locale) {
if (moreKeySpec.isEmpty()) {
throw new KeySpecParser.KeySpecParserError("Empty more key spec"); throw new KeySpecParser.KeySpecParserError("Empty more key spec");
} }
final String label = KeySpecParser.getLabel(moreKeySpec); final String label = KeySpecParser.getLabel(moreKeySpec);
@ -76,7 +78,7 @@ public final class MoreKeySpec {
@Nonnull @Nonnull
public Key buildKey(final int x, final int y, final int labelFlags, public Key buildKey(final int x, final int y, final int labelFlags,
final KeyboardParams params) { @Nonnull final KeyboardParams params) {
return new Key(mLabel, mIconId, mCode, mOutputText, null /* hintLabel */, labelFlags, return new Key(mLabel, mIconId, mCode, mOutputText, null /* hintLabel */, labelFlags,
Key.BACKGROUND_TYPE_NORMAL, x, y, params.mDefaultKeyWidth, params.mDefaultRowHeight, Key.BACKGROUND_TYPE_NORMAL, x, y, params.mDefaultKeyWidth, params.mDefaultRowHeight,
params.mHorizontalGap, params.mVerticalGap); params.mHorizontalGap, params.mVerticalGap);
@ -87,14 +89,18 @@ public final class MoreKeySpec {
int hashCode = 1; int hashCode = 1;
hashCode = 31 + mCode; hashCode = 31 + mCode;
hashCode = hashCode * 31 + mIconId; hashCode = hashCode * 31 + mIconId;
hashCode = hashCode * 31 + (mLabel == null ? 0 : mLabel.hashCode()); final String label = mLabel;
hashCode = hashCode * 31 + (mOutputText == null ? 0 : mOutputText.hashCode()); hashCode = hashCode * 31 + (label == null ? 0 : label.hashCode());
final String outputText = mOutputText;
hashCode = hashCode * 31 + (outputText == null ? 0 : outputText.hashCode());
return hashCode; return hashCode;
} }
@Override @Override
public boolean equals(final Object o) { public boolean equals(final Object o) {
if (this == o) return true; if (this == o) {
return true;
}
if (o instanceof MoreKeySpec) { if (o instanceof MoreKeySpec) {
final MoreKeySpec other = (MoreKeySpec)o; final MoreKeySpec other = (MoreKeySpec)o;
return mCode == other.mCode return mCode == other.mCode
@ -121,7 +127,7 @@ public final class MoreKeySpec {
private final SparseIntArray mCodes = new SparseIntArray(); private final SparseIntArray mCodes = new SparseIntArray();
private final HashSet<String> mTexts = new HashSet<>(); private final HashSet<String> mTexts = new HashSet<>();
public void addLetter(final Key key) { public void addLetter(@Nonnull final Key key) {
final int code = key.getCode(); final int code = key.getCode();
if (CharacterCompat.isAlphabetic(code)) { if (CharacterCompat.isAlphabetic(code)) {
mCodes.put(code, 0); mCodes.put(code, 0);
@ -130,7 +136,7 @@ public final class MoreKeySpec {
} }
} }
public boolean contains(final MoreKeySpec moreKey) { public boolean contains(@Nonnull final MoreKeySpec moreKey) {
final int code = moreKey.mCode; final int code = moreKey.mCode;
if (CharacterCompat.isAlphabetic(code) && mCodes.indexOfKey(code) >= 0) { if (CharacterCompat.isAlphabetic(code) && mCodes.indexOfKey(code) >= 0) {
return true; return true;
@ -141,8 +147,9 @@ public final class MoreKeySpec {
} }
} }
public static MoreKeySpec[] removeRedundantMoreKeys(final MoreKeySpec[] moreKeys, @Nullable
final LettersOnBaseLayout lettersOnBaseLayout) { public static MoreKeySpec[] removeRedundantMoreKeys(@Nullable final MoreKeySpec[] moreKeys,
@Nonnull final LettersOnBaseLayout lettersOnBaseLayout) {
if (moreKeys == null) { if (moreKeys == null) {
return null; return null;
} }
@ -162,7 +169,6 @@ public final class MoreKeySpec {
return filteredMoreKeys.toArray(new MoreKeySpec[size]); return filteredMoreKeys.toArray(new MoreKeySpec[size]);
} }
private static final boolean DEBUG = DebugFlags.DEBUG_ENABLED;
// Constants for parsing. // Constants for parsing.
private static final char COMMA = Constants.CODE_COMMA; private static final char COMMA = Constants.CODE_COMMA;
private static final char BACKSLASH = Constants.CODE_BACKSLASH; private static final char BACKSLASH = Constants.CODE_BACKSLASH;
@ -180,7 +186,8 @@ public final class MoreKeySpec {
* @return an array of key specification text. Null if the specified <code>text</code> is empty * @return an array of key specification text. Null if the specified <code>text</code> is empty
* or has no key specifications. * or has no key specifications.
*/ */
public static String[] splitKeySpecs(final String text) { @Nullable
public static String[] splitKeySpecs(@Nullable final String text) {
if (TextUtils.isEmpty(text)) { if (TextUtils.isEmpty(text)) {
return null; return null;
} }
@ -222,9 +229,11 @@ public final class MoreKeySpec {
return list.toArray(new String[list.size()]); return list.toArray(new String[list.size()]);
} }
@Nonnull
private static final String[] EMPTY_STRING_ARRAY = new String[0]; private static final String[] EMPTY_STRING_ARRAY = new String[0];
private static String[] filterOutEmptyString(final String[] array) { @Nonnull
private static String[] filterOutEmptyString(@Nullable final String[] array) {
if (array == null) { if (array == null) {
return EMPTY_STRING_ARRAY; return EMPTY_STRING_ARRAY;
} }
@ -245,8 +254,8 @@ public final class MoreKeySpec {
return out.toArray(new String[out.size()]); return out.toArray(new String[out.size()]);
} }
public static String[] insertAdditionalMoreKeys(final String[] moreKeySpecs, public static String[] insertAdditionalMoreKeys(@Nullable final String[] moreKeySpecs,
final String[] additionalMoreKeySpecs) { @Nullable final String[] additionalMoreKeySpecs) {
final String[] moreKeys = filterOutEmptyString(moreKeySpecs); final String[] moreKeys = filterOutEmptyString(moreKeySpecs);
final String[] additionalMoreKeys = filterOutEmptyString(additionalMoreKeySpecs); final String[] additionalMoreKeys = filterOutEmptyString(additionalMoreKeySpecs);
final int moreKeysCount = moreKeys.length; final int moreKeysCount = moreKeys.length;
@ -280,11 +289,6 @@ public final class MoreKeySpec {
if (additionalCount > 0 && additionalIndex == 0) { if (additionalCount > 0 && additionalIndex == 0) {
// No '%' marker is found in more keys. // No '%' marker is found in more keys.
// Insert all additional more keys to the head of more keys. // Insert all additional more keys to the head of more keys.
if (DEBUG && out != null) {
throw new RuntimeException("Internal logic error:"
+ " moreKeys=" + Arrays.toString(moreKeys)
+ " additionalMoreKeys=" + Arrays.toString(additionalMoreKeys));
}
out = CollectionUtils.arrayAsList(additionalMoreKeys, additionalIndex, additionalCount); out = CollectionUtils.arrayAsList(additionalMoreKeys, additionalIndex, additionalCount);
for (int i = 0; i < moreKeysCount; i++) { for (int i = 0; i < moreKeysCount; i++) {
out.add(moreKeys[i]); out.add(moreKeys[i]);
@ -292,11 +296,6 @@ public final class MoreKeySpec {
} else if (additionalIndex < additionalCount) { } else if (additionalIndex < additionalCount) {
// The number of '%' markers are less than additional more keys. // The number of '%' markers are less than additional more keys.
// Append remained additional more keys to the tail of more keys. // Append remained additional more keys to the tail of more keys.
if (DEBUG && out != null) {
throw new RuntimeException("Internal logic error:"
+ " moreKeys=" + Arrays.toString(moreKeys)
+ " additionalMoreKeys=" + Arrays.toString(additionalMoreKeys));
}
out = CollectionUtils.arrayAsList(moreKeys, 0, moreKeysCount); out = CollectionUtils.arrayAsList(moreKeys, 0, moreKeysCount);
for (int i = additionalIndex; i < additionalCount; i++) { for (int i = additionalIndex; i < additionalCount; i++) {
out.add(additionalMoreKeys[additionalIndex]); out.add(additionalMoreKeys[additionalIndex]);
@ -311,7 +310,7 @@ public final class MoreKeySpec {
} }
} }
public static int getIntValue(final String[] moreKeys, final String key, public static int getIntValue(@Nullable final String[] moreKeys, final String key,
final int defaultValue) { final int defaultValue) {
if (moreKeys == null) { if (moreKeys == null) {
return defaultValue; return defaultValue;
@ -338,7 +337,7 @@ public final class MoreKeySpec {
return value; return value;
} }
public static boolean getBooleanValue(final String[] moreKeys, final String key) { public static boolean getBooleanValue(@Nullable final String[] moreKeys, final String key) {
if (moreKeys == null) { if (moreKeys == null) {
return false; return false;
} }