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.Locale;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
/**
* 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. */
private final int mY;
/** Hit bounding box of the key */
@Nonnull
private final Rect mHitBox = new Rect();
/** More keys. It is guaranteed that this is null or an array of one or more elements */
@Nullable
private final MoreKeySpec[] mMoreKeys;
/** More keys column number and flags */
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_ENABLE_LONG_PRESS = 0x08;
@Nullable
private final KeyVisualAttributes mKeyVisualAttributes;
@Nullable
private final OptionalAttributes mOptionalAttributes;
private static final class OptionalAttributes {
@ -181,6 +187,7 @@ public class Key implements Comparable<Key> {
mVisualInsetsRight = visualInsetsRight;
}
@Nullable
public static OptionalAttributes newInstance(final String outputText, final int altCode,
final int disabledIconId, final int visualInsetsLeft, final int visualInsetsRight) {
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>,
* and in a <GridRows/>.
*/
public Key(final String label, final int iconId, final int code, final String outputText,
final String hintLabel, final int labelFlags, final int backgroundType, final int x,
final int y, final int width, final int height, final int horizontalGap,
final int verticalGap) {
public Key(@Nullable final String label, final int iconId, final int code,
@Nullable final String outputText, @Nullable final String hintLabel,
final int labelFlags, final int backgroundType, final int x, final int y,
final int width, final int height, final int horizontalGap, final int verticalGap) {
mWidth = width - horizontalGap;
mHeight = height - verticalGap;
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
* this key.
*/
public Key(final String keySpec, final TypedArray keyAttr, final KeyStyle style,
final KeyboardParams params, final KeyboardRow row) {
public Key(@Nullable final String keySpec, @Nonnull final TypedArray keyAttr,
@Nonnull final KeyStyle style, @Nonnull final KeyboardParams params,
@Nonnull final KeyboardRow row) {
mHorizontalGap = isSpacer() ? 0 : params.mHorizontalGap;
mVerticalGap = params.mVerticalGap;
@ -403,11 +411,11 @@ public class Key implements Comparable<Key> {
*
* @param key the original key.
*/
protected Key(final Key key) {
protected Key(@Nonnull final Key key) {
this(key, key.mMoreKeys);
}
private Key(final Key key, final MoreKeySpec[] moreKeys) {
private Key(@Nonnull final Key key, @Nullable final MoreKeySpec[] moreKeys) {
// Final attributes.
mCode = key.mCode;
mLabel = key.mLabel;
@ -433,8 +441,9 @@ public class Key implements Comparable<Key> {
mEnabled = key.mEnabled;
}
public static Key removeRedundantMoreKeys(final Key key,
final MoreKeySpec.LettersOnBaseLayout lettersOnBaseLayout) {
@Nonnull
public static Key removeRedundantMoreKeys(@Nonnull final Key key,
@Nonnull final MoreKeySpec.LettersOnBaseLayout lettersOnBaseLayout) {
final MoreKeySpec[] moreKeys = key.getMoreKeys();
final MoreKeySpec[] filteredMoreKeys = MoreKeySpec.removeRedundantMoreKeys(
moreKeys, lettersOnBaseLayout);
@ -554,14 +563,17 @@ public class Key implements Comparable<Key> {
return mCode;
}
@Nullable
public String getLabel() {
return mLabel;
}
@Nullable
public String getHintLabel() {
return mHintLabel;
}
@Nullable
public MoreKeySpec[] getMoreKeys() {
return mMoreKeys;
}
@ -620,6 +632,7 @@ public class Key implements Comparable<Key> {
return mKeyVisualAttributes;
}
@Nonnull
public final Typeface selectTypeface(final KeyDrawParams params) {
switch (mLabelFlags & LABEL_FLAGS_FONT_MASK) {
case LABEL_FLAGS_FONT_NORMAL:
@ -696,6 +709,7 @@ public class Key implements Comparable<Key> {
return params.mLetterSize;
}
@Nonnull
public Typeface selectPreviewTypeface(final KeyDrawParams params) {
if (previewHasLetterSize()) {
return selectTypeface(params);
@ -780,6 +794,7 @@ public class Key implements Comparable<Key> {
return (mMoreKeysColumnAndFlags & MORE_KEYS_FLAGS_NO_PANEL_AUTO_MORE_KEY) != 0;
}
@Nullable
public final String getOutputText() {
final OptionalAttributes attrs = mOptionalAttributes;
return (attrs != null) ? attrs.mOutputText : null;
@ -794,6 +809,7 @@ public class Key implements Comparable<Key> {
return mIconId;
}
@Nullable
public Drawable getIcon(final KeyboardIconsSet iconSet, final int alpha) {
final OptionalAttributes attrs = mOptionalAttributes;
final int disabledIconId = (attrs != null) ? attrs.mDisabledIconId : ICON_UNDEFINED;
@ -805,6 +821,7 @@ public class Key implements Comparable<Key> {
return icon;
}
@Nullable
public Drawable getPreviewIcon(final KeyboardIconsSet iconSet) {
return iconSet.getIconDrawable(getIconId());
}
@ -897,6 +914,7 @@ public class Key implements Comparable<Key> {
mEnabled = enabled;
}
@Nonnull
public Rect getHitBox() {
return mHitBox;
}
@ -968,8 +986,10 @@ public class Key implements Comparable<Key> {
* @return the background drawable of the key.
* @see android.graphics.drawable.StateListDrawable#setState(int[])
*/
public final Drawable selectBackgroundDrawable(final Drawable keyBackground,
final Drawable functionalKeyBackground, final Drawable spacebarBackground) {
@Nonnull
public final Drawable selectBackgroundDrawable(@Nonnull final Drawable keyBackground,
@Nonnull final Drawable functionalKeyBackground,
@Nonnull final Drawable spacebarBackground) {
final Drawable background;
if (mBackgroundType == BACKGROUND_TYPE_FUNCTIONAL) {
background = functionalKeyBackground;

View file

@ -28,6 +28,9 @@ import java.util.ArrayList;
import java.util.Collections;
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
* consists of rows of keys.
@ -47,6 +50,7 @@ import java.util.List;
* </pre>
*/
public class Keyboard {
@Nonnull
public final KeyboardId mId;
public final int mThemeId;
@ -78,17 +82,22 @@ public class Keyboard {
public final int mMaxMoreKeysKeyboardColumn;
/** List of keys in this keyboard */
@Nonnull
private final List<Key> mSortedKeys;
@Nonnull
public final List<Key> mShiftKeys;
@Nonnull
public final List<Key> mAltCodeKeysWhileTyping;
@Nonnull
public final KeyboardIconsSet mIconsSet;
private final SparseArray<Key> mKeyCache = new SparseArray<>();
@Nonnull
private final ProximityInfo mProximityInfo;
private final boolean mProximityCharsCorrectionEnabled;
public Keyboard(final KeyboardParams params) {
public Keyboard(@Nonnull final KeyboardParams params) {
mId = params.mId;
mThemeId = params.mThemeId;
mOccupiedHeight = params.mOccupiedHeight;
@ -114,7 +123,7 @@ public class Keyboard {
mProximityCharsCorrectionEnabled = params.mProximityCharsCorrectionEnabled;
}
protected Keyboard(final Keyboard keyboard) {
protected Keyboard(@Nonnull final Keyboard keyboard) {
mId = keyboard.mId;
mThemeId = keyboard.mThemeId;
mOccupiedHeight = keyboard.mOccupiedHeight;
@ -150,6 +159,7 @@ public class Keyboard {
return canAssumeNativeHasProximityCharsInfoOfAllKeys || Character.isLetter(code);
}
@Nonnull
public ProximityInfo getProximityInfo() {
return mProximityInfo;
}
@ -160,10 +170,12 @@ public class Keyboard {
* The list may contain {@link Key.Spacer} object as well.
* @return the sorted unmodifiable list of {@link Key}s of this keyboard.
*/
@Nonnull
public List<Key> getSortedKeys() {
return mSortedKeys;
}
@Nullable
public Key getKey(final int code) {
if (code == Constants.CODE_UNSPECIFIED) {
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) {
return true;
}
@ -211,6 +223,7 @@ public class Keyboard {
* @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.
*/
@Nonnull
public List<Key> getNearestKeys(final int x, final int y) {
// Avoid dead pixels at edges of the keyboard
final int adjustedX = Math.max(0, Math.min(x, mOccupiedWidth - 1));
@ -218,7 +231,8 @@ public class Keyboard {
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[] coordinates = CoordinateUtils.newCoordinateArray(length);
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 final Context mContext;
@Nonnull
private final Params mParams;
// 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 HashMap<KeyboardId, SoftReference<Keyboard>> sKeyboardCache =
new HashMap<>();
@Nonnull
private static final KeysCache sKeysCache = new KeysCache();
private final static HashMap<InputMethodSubtype, Integer> sScriptIdsForSubtypes =
new HashMap<>();
@ -145,7 +147,8 @@ public final class KeyboardLayoutSet {
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);
if (null == value) {
final int scriptId = Builder.readScriptId(resources, subtype);
@ -155,11 +158,12 @@ public final class KeyboardLayoutSet {
return value;
}
KeyboardLayoutSet(final Context context, final Params params) {
KeyboardLayoutSet(final Context context, @Nonnull final Params params) {
mContext = context;
mParams = params;
}
@Nonnull
public Keyboard getKeyboard(final int baseKeyboardLayoutSetElementId) {
final int keyboardLayoutSetElementId;
switch (mParams.mMode) {
@ -203,6 +207,7 @@ public final class KeyboardLayoutSet {
}
}
@Nonnull
private Keyboard getKeyboard(final ElementParams elementParams, final KeyboardId id) {
final SoftReference<Keyboard> ref = sKeyboardCache.get(id);
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
@Nullable
private Keyboard mKeyboard;
protected final KeyDrawParams mKeyDrawParams = new KeyDrawParams();
@Nonnull
private final KeyDrawParams mKeyDrawParams = new KeyDrawParams();
// Drawing
/** True if all keys should be drawn */
@ -120,6 +121,7 @@ public class KeyboardView extends View {
@Nonnull
private final Paint mPaint = new Paint();
private final Paint.FontMetrics mFontMetrics = new Paint.FontMetrics();
public KeyboardView(final Context context, final AttributeSet attrs) {
this(context, attrs, R.attr.keyboardViewStyle);
}
@ -210,6 +212,11 @@ public class KeyboardView extends View {
return mVerticalCorrection;
}
@Nonnull
protected KeyDrawParams getKeyDrawParams() {
return mKeyDrawParams;
}
protected void updateKeyDrawParams(final int keyHeight) {
mKeyDrawParams.updateParams(keyHeight, mKeyVisualAttributes);
}

View file

@ -484,7 +484,7 @@ public final class MainKeyboardView extends KeyboardView implements DrawingProxy
locatePreviewPlacerView();
getLocationInWindow(mOriginCoords);
mKeyPreviewChoreographer.placeAndShowKeyPreview(key, keyboard.mIconsSet, mKeyDrawParams,
mKeyPreviewChoreographer.placeAndShowKeyPreview(key, keyboard.mIconsSet, getKeyDrawParams(),
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.utils.TypefaceUtils;
import javax.annotation.Nonnull;
public final class MoreKeysKeyboard extends Keyboard {
private final int mDefaultKeyCoordX;
@ -328,6 +330,7 @@ public final class MoreKeysKeyboard extends Keyboard {
}
@Override
@Nonnull
public MoreKeysKeyboard build() {
final MoreKeysKeyboardParams params = mParams;
final int moreKeyFlags = mParentKey.getMoreKeyLabelFlags();

View file

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

View file

@ -20,8 +20,12 @@ import android.graphics.Typeface;
import com.android.inputmethod.latin.utils.ResourceUtils;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
public final class KeyDrawParams {
public Typeface mTypeface;
@Nonnull
public Typeface mTypeface = Typeface.DEFAULT;
public int mLetterSize;
public int mLabelSize;
@ -49,7 +53,7 @@ public final class KeyDrawParams {
public KeyDrawParams() {}
private KeyDrawParams(final KeyDrawParams copyFrom) {
private KeyDrawParams(@Nonnull final KeyDrawParams copyFrom) {
mTypeface = copyFrom.mTypeface;
mLetterSize = copyFrom.mLetterSize;
@ -77,7 +81,7 @@ public final class KeyDrawParams {
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) {
return;
}
@ -117,8 +121,9 @@ public final class KeyDrawParams {
attr.mHintLabelOffCenterRatio, mHintLabelOffCenterRatio);
}
@Nonnull
public KeyDrawParams mayCloneAndUpdateParams(final int keyHeight,
final KeyVisualAttributes attr) {
@Nullable final KeyVisualAttributes attr) {
if (attr == null) {
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.StringUtils;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
/**
* The string parser of the key specification.
*
@ -53,11 +56,11 @@ public final class KeySpecParser {
// 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);
}
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()) {
return false;
}
@ -72,7 +75,8 @@ public final class KeySpecParser {
return false;
}
private static String parseEscape(final String text) {
@Nonnull
private static String parseEscape(@Nonnull final String text) {
if (text.indexOf(BACKSLASH) < 0) {
return text;
}
@ -91,7 +95,7 @@ public final class KeySpecParser {
return sb.toString();
}
private static int indexOfLabelEnd(final String keySpec) {
private static int indexOfLabelEnd(@Nonnull final String keySpec) {
final int length = keySpec.length();
if (keySpec.indexOf(BACKSLASH) < 0) {
final int labelEnd = keySpec.indexOf(VERTICAL_BAR);
@ -116,22 +120,25 @@ public final class KeySpecParser {
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);
}
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);
}
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) {
return;
}
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) {
// TODO: Throw {@link KeySpecParserError} once Key.keyLabel attribute becomes mandatory.
return null;
@ -147,7 +154,8 @@ public final class KeySpecParser {
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) {
return null;
}
@ -155,7 +163,8 @@ public final class KeySpecParser {
return parseEscape(getAfterLabelEnd(keySpec, labelEnd));
}
public static String getOutputText(final String keySpec) {
@Nullable
public static String getOutputText(@Nullable final String keySpec) {
if (keySpec == null) {
// TODO: Throw {@link KeySpecParserError} once Key.keyLabel attribute becomes mandatory.
return null;
@ -184,7 +193,7 @@ public final class KeySpecParser {
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) {
// TODO: Throw {@link KeySpecParserError} once Key.keyLabel attribute becomes mandatory.
return CODE_UNSPECIFIED;
@ -211,7 +220,7 @@ public final class KeySpecParser {
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) {
return defaultCode;
}
@ -226,7 +235,7 @@ public final class KeySpecParser {
return defaultCode;
}
public static int getIconId(final String keySpec) {
public static int getIconId(@Nullable final String keySpec) {
if (keySpec == null) {
// TODO: Throw {@link KeySpecParserError} once Key.keyLabel attribute becomes mandatory.
return KeyboardIconsSet.ICON_UNDEFINED;

View file

@ -18,18 +18,22 @@ package com.android.inputmethod.keyboard.internal;
import android.content.res.TypedArray;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
public abstract class KeyStyle {
private final KeyboardTextsSet mTextsSet;
public abstract String[] getStringArray(TypedArray a, int index);
public abstract String getString(TypedArray a, int index);
public abstract @Nullable String[] getStringArray(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 getFlags(TypedArray a, int index);
protected KeyStyle(final KeyboardTextsSet textsSet) {
protected KeyStyle(@Nonnull final KeyboardTextsSet textsSet) {
mTextsSet = textsSet;
}
@Nullable
protected String parseString(final TypedArray a, final int index) {
if (a.hasValue(index)) {
return mTextsSet.resolveTextReference(a.getString(index));
@ -37,6 +41,7 @@ public abstract class KeyStyle {
return null;
}
@Nullable
protected String[] parseStringArray(final TypedArray a, final int index) {
if (a.hasValue(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.HashMap;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
public final class KeyStylesSet {
private static final String TAG = KeyStylesSet.class.getSimpleName();
private static final boolean DEBUG = false;
@Nonnull
private final HashMap<String, KeyStyle> mStyles = new HashMap<>();
@Nonnull
private final KeyboardTextsSet mTextsSet;
@Nonnull
private final KeyStyle mEmptyKeyStyle;
@Nonnull
private static final String EMPTY_STYLE_NAME = "<empty>";
public KeyStylesSet(final KeyboardTextsSet textsSet) {
public KeyStylesSet(@Nonnull final KeyboardTextsSet textsSet) {
mTextsSet = textsSet;
mEmptyKeyStyle = new EmptyKeyStyle(textsSet);
mStyles.put(EMPTY_STYLE_NAME, mEmptyKeyStyle);
}
private static final class EmptyKeyStyle extends KeyStyle {
EmptyKeyStyle(final KeyboardTextsSet textsSet) {
EmptyKeyStyle(@Nonnull final KeyboardTextsSet textsSet) {
super(textsSet);
}
@Override
@Nullable
public String[] getStringArray(final TypedArray a, final int index) {
return parseStringArray(a, index);
}
@Override
@Nullable
public String getString(final TypedArray a, final int index) {
return parseString(a, index);
}
@ -76,14 +85,16 @@ public final class KeyStylesSet {
private final String mParentStyleName;
private final SparseArray<Object> mStyleAttributes = new SparseArray<>();
public DeclaredKeyStyle(final String parentStyleName, final KeyboardTextsSet textsSet,
final HashMap<String, KeyStyle> styles) {
public DeclaredKeyStyle(@Nonnull final String parentStyleName,
@Nonnull final KeyboardTextsSet textsSet,
@Nonnull final HashMap<String, KeyStyle> styles) {
super(textsSet);
mParentStyleName = parentStyleName;
mStyles = styles;
}
@Override
@Nullable
public String[] getStringArray(final TypedArray a, final int index) {
if (a.hasValue(index)) {
return parseStringArray(a, index);
@ -98,6 +109,7 @@ public final class KeyStylesSet {
}
@Override
@Nullable
public String getString(final TypedArray a, final int index) {
if (a.hasValue(index)) {
return parseString(a, index);
@ -176,37 +188,43 @@ public final class KeyStylesSet {
public void parseKeyStyleAttributes(final TypedArray keyStyleAttr, final TypedArray keyAttrs,
final XmlPullParser parser) throws XmlPullParserException {
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) {
Log.d(TAG, String.format("<%s styleName=%s />",
KeyboardBuilder.TAG_KEY_STYLE, 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());
}
}
String parentStyleName = EMPTY_STYLE_NAME;
if (keyStyleAttr.hasValue(R.styleable.Keyboard_KeyStyle_parentStyle)) {
parentStyleName = keyStyleAttr.getString(R.styleable.Keyboard_KeyStyle_parentStyle);
if (!mStyles.containsKey(parentStyleName)) {
throw new XmlParseUtils.ParseException(
"Unknown parentStyle " + parentStyleName, parser);
}
final String parentStyleInAttr = keyStyleAttr.getString(
R.styleable.Keyboard_KeyStyle_parentStyle);
if (parentStyleInAttr != null && !mStyles.containsKey(parentStyleInAttr)) {
throw new XmlParseUtils.ParseException(
"Unknown parentStyle " + parentStyleInAttr, parser);
}
final String parentStyleName = (parentStyleInAttr == null) ? EMPTY_STYLE_NAME
: parentStyleInAttr;
final DeclaredKeyStyle style = new DeclaredKeyStyle(parentStyleName, mTextsSet, mStyles);
style.readKeyAttributes(keyAttrs);
mStyles.put(styleName, style);
}
@Nonnull
public KeyStyle getKeyStyle(final TypedArray keyAttr, final XmlPullParser parser)
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;
}
final String styleName = keyAttr.getString(R.styleable.Keyboard_Key_keyStyle);
if (!mStyles.containsKey(styleName)) {
final KeyStyle style = mStyles.get(styleName);
if (style == null) {
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.utils.ResourceUtils;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
public final class KeyVisualAttributes {
@Nullable
public final Typeface mTypeface;
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();
for (int i = 0; i < indexCount; i++) {
final int attrId = keyAttr.getIndex(i);
@ -93,7 +98,7 @@ public final class KeyVisualAttributes {
return null;
}
private KeyVisualAttributes(final TypedArray keyAttr) {
private KeyVisualAttributes(@Nonnull final TypedArray keyAttr) {
if (keyAttr.hasValue(R.styleable.Keyboard_Key_keyTypeface)) {
mTypeface = Typeface.defaultFromStyle(
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_ROWS = 4;
@Nonnull
protected final KP mParams;
protected final Context mContext;
protected final Resources mResources;
@ -149,7 +150,7 @@ public class KeyboardBuilder<KP extends KeyboardParams> {
private boolean mTopEdge;
private Key mRightEdgeKey = null;
public KeyboardBuilder(final Context context, final KP params) {
public KeyboardBuilder(final Context context, @Nonnull final KP params) {
mContext = context;
final Resources res = context.getResources();
mResources = res;
@ -194,6 +195,7 @@ public class KeyboardBuilder<KP extends KeyboardParams> {
mParams.mProximityCharsCorrectionEnabled = enabled;
}
@Nonnull
public Keyboard build() {
return new Keyboard(mParams);
}

View file

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

View file

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

View file

@ -20,6 +20,7 @@ import com.android.inputmethod.keyboard.Key;
import java.util.HashMap;
// TODO: Rename more appropriate name.
public final class KeysCache {
private final HashMap<Key, Key> mMap = new HashMap<>();
@ -27,6 +28,7 @@ public final class KeysCache {
mMap.clear();
}
// TODO: Rename more descriptive name.
public Key get(final Key key) {
final Key existingKey = mMap.get(key);
if (existingKey != null) {
@ -37,6 +39,7 @@ public final class KeysCache {
return key;
}
// TODO: Rename more descriptive name.
public Key replace(final Key oldKey, final Key newKey) {
if (oldKey.equals(newKey)) {
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.Constants;
import com.android.inputmethod.latin.common.StringUtils;
import com.android.inputmethod.latin.define.DebugFlags;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Locale;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
/**
* 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.
public final class MoreKeySpec {
public final int mCode;
@Nullable
public final String mLabel;
@Nullable
public final String mOutputText;
public final int mIconId;
public MoreKeySpec(final String moreKeySpec, boolean needsToUpperCase, final Locale locale) {
if (TextUtils.isEmpty(moreKeySpec)) {
public MoreKeySpec(@Nonnull final String moreKeySpec, boolean needsToUpperCase,
@Nonnull final Locale locale) {
if (moreKeySpec.isEmpty()) {
throw new KeySpecParser.KeySpecParserError("Empty more key spec");
}
final String label = KeySpecParser.getLabel(moreKeySpec);
@ -76,7 +78,7 @@ public final class MoreKeySpec {
@Nonnull
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,
Key.BACKGROUND_TYPE_NORMAL, x, y, params.mDefaultKeyWidth, params.mDefaultRowHeight,
params.mHorizontalGap, params.mVerticalGap);
@ -87,14 +89,18 @@ public final class MoreKeySpec {
int hashCode = 1;
hashCode = 31 + mCode;
hashCode = hashCode * 31 + mIconId;
hashCode = hashCode * 31 + (mLabel == null ? 0 : mLabel.hashCode());
hashCode = hashCode * 31 + (mOutputText == null ? 0 : mOutputText.hashCode());
final String label = mLabel;
hashCode = hashCode * 31 + (label == null ? 0 : label.hashCode());
final String outputText = mOutputText;
hashCode = hashCode * 31 + (outputText == null ? 0 : outputText.hashCode());
return hashCode;
}
@Override
public boolean equals(final Object o) {
if (this == o) return true;
if (this == o) {
return true;
}
if (o instanceof MoreKeySpec) {
final MoreKeySpec other = (MoreKeySpec)o;
return mCode == other.mCode
@ -121,7 +127,7 @@ public final class MoreKeySpec {
private final SparseIntArray mCodes = new SparseIntArray();
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();
if (CharacterCompat.isAlphabetic(code)) {
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;
if (CharacterCompat.isAlphabetic(code) && mCodes.indexOfKey(code) >= 0) {
return true;
@ -141,8 +147,9 @@ public final class MoreKeySpec {
}
}
public static MoreKeySpec[] removeRedundantMoreKeys(final MoreKeySpec[] moreKeys,
final LettersOnBaseLayout lettersOnBaseLayout) {
@Nullable
public static MoreKeySpec[] removeRedundantMoreKeys(@Nullable final MoreKeySpec[] moreKeys,
@Nonnull final LettersOnBaseLayout lettersOnBaseLayout) {
if (moreKeys == null) {
return null;
}
@ -162,7 +169,6 @@ public final class MoreKeySpec {
return filteredMoreKeys.toArray(new MoreKeySpec[size]);
}
private static final boolean DEBUG = DebugFlags.DEBUG_ENABLED;
// Constants for parsing.
private static final char COMMA = Constants.CODE_COMMA;
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
* 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)) {
return null;
}
@ -222,9 +229,11 @@ public final class MoreKeySpec {
return list.toArray(new String[list.size()]);
}
@Nonnull
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) {
return EMPTY_STRING_ARRAY;
}
@ -245,8 +254,8 @@ public final class MoreKeySpec {
return out.toArray(new String[out.size()]);
}
public static String[] insertAdditionalMoreKeys(final String[] moreKeySpecs,
final String[] additionalMoreKeySpecs) {
public static String[] insertAdditionalMoreKeys(@Nullable final String[] moreKeySpecs,
@Nullable final String[] additionalMoreKeySpecs) {
final String[] moreKeys = filterOutEmptyString(moreKeySpecs);
final String[] additionalMoreKeys = filterOutEmptyString(additionalMoreKeySpecs);
final int moreKeysCount = moreKeys.length;
@ -280,11 +289,6 @@ public final class MoreKeySpec {
if (additionalCount > 0 && additionalIndex == 0) {
// No '%' marker is found in 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);
for (int i = 0; i < moreKeysCount; i++) {
out.add(moreKeys[i]);
@ -292,11 +296,6 @@ public final class MoreKeySpec {
} else if (additionalIndex < additionalCount) {
// The number of '%' markers are less than additional 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);
for (int i = additionalIndex; i < additionalCount; i++) {
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) {
if (moreKeys == null) {
return defaultValue;
@ -338,7 +337,7 @@ public final class MoreKeySpec {
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) {
return false;
}