• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2010 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License"); you may not
5  * use this file except in compliance with the License. You may obtain a copy of
6  * the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13  * License for the specific language governing permissions and limitations under
14  * the License.
15  */
16 
17 package com.android.inputmethod.keyboard;
18 
19 import android.content.res.Resources;
20 import android.content.res.TypedArray;
21 import android.graphics.Rect;
22 import android.graphics.Typeface;
23 import android.graphics.drawable.Drawable;
24 import android.text.TextUtils;
25 import android.util.Xml;
26 
27 import com.android.inputmethod.keyboard.internal.KeyStyles;
28 import com.android.inputmethod.keyboard.internal.KeyStyles.KeyStyle;
29 import com.android.inputmethod.keyboard.internal.KeyboardBuilder;
30 import com.android.inputmethod.keyboard.internal.KeyboardBuilder.ParseException;
31 import com.android.inputmethod.keyboard.internal.KeyboardIconsSet;
32 import com.android.inputmethod.keyboard.internal.KeyboardParams;
33 import com.android.inputmethod.keyboard.internal.MoreKeySpecParser;
34 import com.android.inputmethod.latin.R;
35 
36 import org.xmlpull.v1.XmlPullParser;
37 
38 import java.util.HashMap;
39 import java.util.Map;
40 
41 /**
42  * Class for describing the position and characteristics of a single key in the keyboard.
43  */
44 public class Key {
45     /**
46      * The key code (unicode or custom code) that this key generates.
47      */
48     public final int mCode;
49 
50     /** Label to display */
51     public final CharSequence mLabel;
52     /** Hint label to display on the key in conjunction with the label */
53     public final CharSequence mHintLabel;
54     /** Option of the label */
55     private final int mLabelOption;
56     private static final int LABEL_OPTION_ALIGN_LEFT = 0x01;
57     private static final int LABEL_OPTION_ALIGN_RIGHT = 0x02;
58     private static final int LABEL_OPTION_ALIGN_LEFT_OF_CENTER = 0x08;
59     private static final int LABEL_OPTION_LARGE_LETTER = 0x10;
60     private static final int LABEL_OPTION_FONT_NORMAL = 0x20;
61     private static final int LABEL_OPTION_FONT_MONO_SPACE = 0x40;
62     private static final int LABEL_OPTION_FOLLOW_KEY_LETTER_RATIO = 0x80;
63     private static final int LABEL_OPTION_FOLLOW_KEY_HINT_LABEL_RATIO = 0x100;
64     private static final int LABEL_OPTION_HAS_POPUP_HINT = 0x200;
65     private static final int LABEL_OPTION_HAS_UPPERCASE_LETTER = 0x400;
66     private static final int LABEL_OPTION_HAS_HINT_LABEL = 0x800;
67     private static final int LABEL_OPTION_WITH_ICON_LEFT = 0x1000;
68     private static final int LABEL_OPTION_WITH_ICON_RIGHT = 0x2000;
69     private static final int LABEL_OPTION_AUTO_X_SCALE = 0x4000;
70 
71     /** Icon to display instead of a label. Icon takes precedence over a label */
72     private Drawable mIcon;
73     /** Preview version of the icon, for the preview popup */
74     private Drawable mPreviewIcon;
75 
76     /** Width of the key, not including the gap */
77     public final int mWidth;
78     /** Height of the key, not including the gap */
79     public final int mHeight;
80     /** The horizontal gap around this key */
81     public final int mHorizontalGap;
82     /** The vertical gap below this key */
83     public final int mVerticalGap;
84     /** The visual insets */
85     public final int mVisualInsetsLeft;
86     public final int mVisualInsetsRight;
87     /** X coordinate of the key in the keyboard layout */
88     public final int mX;
89     /** Y coordinate of the key in the keyboard layout */
90     public final int mY;
91     /** Hit bounding box of the key */
92     public final Rect mHitBox = new Rect();
93 
94     /** Text to output when pressed. This can be multiple characters, like ".com" */
95     public final CharSequence mOutputText;
96     /** More keys */
97     public final CharSequence[] mMoreKeys;
98     /** More keys maximum column number */
99     public final int mMaxMoreKeysColumn;
100 
101     /** Background type that represents different key background visual than normal one. */
102     public final int mBackgroundType;
103     public static final int BACKGROUND_TYPE_NORMAL = 0;
104     public static final int BACKGROUND_TYPE_FUNCTIONAL = 1;
105     public static final int BACKGROUND_TYPE_ACTION = 2;
106     public static final int BACKGROUND_TYPE_STICKY = 3;
107 
108     /** Whether this key repeats itself when held down */
109     public final boolean mRepeatable;
110 
111     /** The current pressed state of this key */
112     private boolean mPressed;
113     /** If this is a sticky key, is its highlight on? */
114     private boolean mHighlightOn;
115     /** Key is enabled and responds on press */
116     private boolean mEnabled = true;
117     /** Whether this key needs to show the "..." popup hint for special purposes */
118     private boolean mNeedsSpecialPopupHint;
119 
120     // RTL parenthesis character swapping map.
121     private static final Map<Integer, Integer> sRtlParenthesisMap = new HashMap<Integer, Integer>();
122 
123     static {
124         // The all letters need to be mirrored are found at
125         // http://www.unicode.org/Public/6.0.0/ucd/extracted/DerivedBinaryProperties.txt
126         addRtlParenthesisPair('(', ')');
127         addRtlParenthesisPair('[', ']');
128         addRtlParenthesisPair('{', '}');
129         addRtlParenthesisPair('<', '>');
130         // \u00ab: LEFT-POINTING DOUBLE ANGLE QUOTATION MARK
131         // \u00bb: RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK
132         addRtlParenthesisPair('\u00ab', '\u00bb');
133         // \u2039: SINGLE LEFT-POINTING ANGLE QUOTATION MARK
134         // \u203a: SINGLE RIGHT-POINTING ANGLE QUOTATION MARK
135         addRtlParenthesisPair('\u2039', '\u203a');
136         // \u2264: LESS-THAN OR EQUAL TO
137         // \u2265: GREATER-THAN OR EQUAL TO
138         addRtlParenthesisPair('\u2264', '\u2265');
139     }
140 
addRtlParenthesisPair(int left, int right)141     private static void addRtlParenthesisPair(int left, int right) {
142         sRtlParenthesisMap.put(left, right);
143         sRtlParenthesisMap.put(right, left);
144     }
145 
getRtlParenthesisCode(int code, boolean isRtl)146     public static int getRtlParenthesisCode(int code, boolean isRtl) {
147         if (isRtl && sRtlParenthesisMap.containsKey(code)) {
148             return sRtlParenthesisMap.get(code);
149         } else {
150             return code;
151         }
152     }
153 
getCode(Resources res, KeyboardParams params, String moreKeySpec)154     private static int getCode(Resources res, KeyboardParams params, String moreKeySpec) {
155         return getRtlParenthesisCode(
156                 MoreKeySpecParser.getCode(res, moreKeySpec), params.mIsRtlKeyboard);
157     }
158 
getIcon(KeyboardParams params, String moreKeySpec)159     private static Drawable getIcon(KeyboardParams params, String moreKeySpec) {
160         return params.mIconsSet.getIcon(MoreKeySpecParser.getIconId(moreKeySpec));
161     }
162 
163     /**
164      * This constructor is being used only for key in more keys keyboard.
165      */
Key(Resources res, KeyboardParams params, String moreKeySpec, int x, int y, int width, int height)166     public Key(Resources res, KeyboardParams params, String moreKeySpec,
167             int x, int y, int width, int height) {
168         this(params, MoreKeySpecParser.getLabel(moreKeySpec), null, getIcon(params, moreKeySpec),
169                 getCode(res, params, moreKeySpec), MoreKeySpecParser.getOutputText(moreKeySpec),
170                 x, y, width, height);
171     }
172 
173     /**
174      * This constructor is being used only for key in popup suggestions pane.
175      */
Key(KeyboardParams params, CharSequence label, CharSequence hintLabel, Drawable icon, int code, CharSequence outputText, int x, int y, int width, int height)176     public Key(KeyboardParams params, CharSequence label, CharSequence hintLabel, Drawable icon,
177             int code, CharSequence outputText, int x, int y, int width, int height) {
178         mHeight = height - params.mVerticalGap;
179         mHorizontalGap = params.mHorizontalGap;
180         mVerticalGap = params.mVerticalGap;
181         mVisualInsetsLeft = mVisualInsetsRight = 0;
182         mWidth = width - mHorizontalGap;
183         mHintLabel = hintLabel;
184         mLabelOption = 0;
185         mBackgroundType = BACKGROUND_TYPE_NORMAL;
186         mRepeatable = false;
187         mMoreKeys = null;
188         mMaxMoreKeysColumn = 0;
189         mLabel = label;
190         mOutputText = outputText;
191         mCode = code;
192         mIcon = icon;
193         // Horizontal gap is divided equally to both sides of the key.
194         mX = x + mHorizontalGap / 2;
195         mY = y;
196         mHitBox.set(x, y, x + width + 1, y + height);
197     }
198 
199     /**
200      * Create a key with the given top-left coordinate and extract its attributes from the XML
201      * parser.
202      * @param res resources associated with the caller's context
203      * @param params the keyboard building parameters.
204      * @param row the row that this key belongs to. row's x-coordinate will be the right edge of
205      *        this key.
206      * @param parser the XML parser containing the attributes for this key
207      * @param keyStyles active key styles set
208      */
Key(Resources res, KeyboardParams params, KeyboardBuilder.Row row, XmlPullParser parser, KeyStyles keyStyles)209     public Key(Resources res, KeyboardParams params, KeyboardBuilder.Row row,
210             XmlPullParser parser, KeyStyles keyStyles) {
211         final float horizontalGap = isSpacer() ? 0 : params.mHorizontalGap;
212         final int keyHeight = row.mRowHeight;
213         mVerticalGap = params.mVerticalGap;
214         mHeight = keyHeight - mVerticalGap;
215 
216         final TypedArray keyAttr = res.obtainAttributes(Xml.asAttributeSet(parser),
217                 R.styleable.Keyboard_Key);
218 
219         final KeyStyle style;
220         if (keyAttr.hasValue(R.styleable.Keyboard_Key_keyStyle)) {
221             String styleName = keyAttr.getString(R.styleable.Keyboard_Key_keyStyle);
222             style = keyStyles.getKeyStyle(styleName);
223             if (style == null)
224                 throw new ParseException("Unknown key style: " + styleName, parser);
225         } else {
226             style = keyStyles.getEmptyKeyStyle();
227         }
228 
229         final float keyXPos = row.getKeyX(keyAttr);
230         final float keyWidth = row.getKeyWidth(keyAttr, keyXPos);
231         final int keyYPos = row.getKeyY();
232 
233         // Horizontal gap is divided equally to both sides of the key.
234         mX = (int) (keyXPos + horizontalGap / 2);
235         mY = keyYPos;
236         mWidth = (int) (keyWidth - horizontalGap);
237         mHorizontalGap = (int) horizontalGap;
238         mHitBox.set((int)keyXPos, keyYPos, (int)(keyXPos + keyWidth) + 1, keyYPos + keyHeight);
239         // Update row to have current x coordinate.
240         row.setXPos(keyXPos + keyWidth);
241 
242         final CharSequence[] moreKeys = style.getTextArray(keyAttr,
243                 R.styleable.Keyboard_Key_moreKeys);
244         // In Arabic symbol layouts, we'd like to keep digits in more keys regardless of
245         // config_digit_more_keys_enabled.
246         if (params.mId.isAlphabetKeyboard()
247                 && !res.getBoolean(R.bool.config_digit_more_keys_enabled)) {
248             mMoreKeys = MoreKeySpecParser.filterOut(res, moreKeys, MoreKeySpecParser.DIGIT_FILTER);
249         } else {
250             mMoreKeys = moreKeys;
251         }
252         mMaxMoreKeysColumn = style.getInt(keyAttr,
253                 R.styleable.Keyboard_Key_maxMoreKeysColumn, params.mMaxMiniKeyboardColumn);
254 
255         mBackgroundType = style.getInt(keyAttr,
256                 R.styleable.Keyboard_Key_backgroundType, BACKGROUND_TYPE_NORMAL);
257         mRepeatable = style.getBoolean(keyAttr, R.styleable.Keyboard_Key_isRepeatable, false);
258         mEnabled = style.getBoolean(keyAttr, R.styleable.Keyboard_Key_enabled, true);
259 
260         final KeyboardIconsSet iconsSet = params.mIconsSet;
261         mVisualInsetsLeft = (int) KeyboardBuilder.getDimensionOrFraction(keyAttr,
262                 R.styleable.Keyboard_Key_visualInsetsLeft, params.mBaseWidth, 0);
263         mVisualInsetsRight = (int) KeyboardBuilder.getDimensionOrFraction(keyAttr,
264                 R.styleable.Keyboard_Key_visualInsetsRight, params.mBaseWidth, 0);
265         mPreviewIcon = iconsSet.getIcon(style.getInt(keyAttr,
266                 R.styleable.Keyboard_Key_keyIconPreview, KeyboardIconsSet.ICON_UNDEFINED));
267         mIcon = iconsSet.getIcon(style.getInt(keyAttr, R.styleable.Keyboard_Key_keyIcon,
268                 KeyboardIconsSet.ICON_UNDEFINED));
269         final int shiftedIconId = style.getInt(keyAttr, R.styleable.Keyboard_Key_keyIconShifted,
270                 KeyboardIconsSet.ICON_UNDEFINED);
271         if (shiftedIconId != KeyboardIconsSet.ICON_UNDEFINED) {
272             final Drawable shiftedIcon = iconsSet.getIcon(shiftedIconId);
273             params.addShiftedIcon(this, shiftedIcon);
274         }
275         mHintLabel = style.getText(keyAttr, R.styleable.Keyboard_Key_keyHintLabel);
276 
277         mLabel = style.getText(keyAttr, R.styleable.Keyboard_Key_keyLabel);
278         mLabelOption = style.getFlag(keyAttr, R.styleable.Keyboard_Key_keyLabelOption, 0);
279         mOutputText = style.getText(keyAttr, R.styleable.Keyboard_Key_keyOutputText);
280         // Choose the first letter of the label as primary code if not
281         // specified.
282         final int code = style.getInt(keyAttr, R.styleable.Keyboard_Key_code,
283                 Keyboard.CODE_UNSPECIFIED);
284         if (code == Keyboard.CODE_UNSPECIFIED && !TextUtils.isEmpty(mLabel)) {
285             final int firstChar = mLabel.charAt(0);
286             mCode = getRtlParenthesisCode(firstChar, params.mIsRtlKeyboard);
287         } else if (code != Keyboard.CODE_UNSPECIFIED) {
288             mCode = code;
289         } else {
290             mCode = Keyboard.CODE_DUMMY;
291         }
292 
293         keyAttr.recycle();
294     }
295 
markAsLeftEdge(KeyboardParams params)296     public void markAsLeftEdge(KeyboardParams params) {
297         mHitBox.left = params.mHorizontalEdgesPadding;
298     }
299 
markAsRightEdge(KeyboardParams params)300     public void markAsRightEdge(KeyboardParams params) {
301         mHitBox.right = params.mOccupiedWidth - params.mHorizontalEdgesPadding;
302     }
303 
markAsTopEdge(KeyboardParams params)304     public void markAsTopEdge(KeyboardParams params) {
305         mHitBox.top = params.mTopPadding;
306     }
307 
markAsBottomEdge(KeyboardParams params)308     public void markAsBottomEdge(KeyboardParams params) {
309         mHitBox.bottom = params.mOccupiedHeight + params.mBottomPadding;
310     }
311 
isSticky()312     public boolean isSticky() {
313         return mBackgroundType == BACKGROUND_TYPE_STICKY;
314     }
315 
isSpacer()316     public boolean isSpacer() {
317         return false;
318     }
319 
selectTypeface(Typeface defaultTypeface)320     public Typeface selectTypeface(Typeface defaultTypeface) {
321         // TODO: Handle "bold" here too?
322         if ((mLabelOption & LABEL_OPTION_FONT_NORMAL) != 0) {
323             return Typeface.DEFAULT;
324         } else if ((mLabelOption & LABEL_OPTION_FONT_MONO_SPACE) != 0) {
325             return Typeface.MONOSPACE;
326         } else {
327             return defaultTypeface;
328         }
329     }
330 
selectTextSize(int letter, int largeLetter, int label, int hintLabel)331     public int selectTextSize(int letter, int largeLetter, int label, int hintLabel) {
332         if (mLabel.length() > 1
333                 && (mLabelOption & (LABEL_OPTION_FOLLOW_KEY_LETTER_RATIO
334                         | LABEL_OPTION_FOLLOW_KEY_HINT_LABEL_RATIO)) == 0) {
335             return label;
336         } else if ((mLabelOption & LABEL_OPTION_FOLLOW_KEY_HINT_LABEL_RATIO) != 0) {
337             return hintLabel;
338         } else if ((mLabelOption & LABEL_OPTION_LARGE_LETTER) != 0) {
339             return largeLetter;
340         } else {
341             return letter;
342         }
343     }
344 
isAlignLeft()345     public boolean isAlignLeft() {
346         return (mLabelOption & LABEL_OPTION_ALIGN_LEFT) != 0;
347     }
348 
isAlignRight()349     public boolean isAlignRight() {
350         return (mLabelOption & LABEL_OPTION_ALIGN_RIGHT) != 0;
351     }
352 
isAlignLeftOfCenter()353     public boolean isAlignLeftOfCenter() {
354         return (mLabelOption & LABEL_OPTION_ALIGN_LEFT_OF_CENTER) != 0;
355     }
356 
hasPopupHint()357     public boolean hasPopupHint() {
358         return (mLabelOption & LABEL_OPTION_HAS_POPUP_HINT) != 0;
359     }
360 
setNeedsSpecialPopupHint(boolean needsSpecialPopupHint)361     public void setNeedsSpecialPopupHint(boolean needsSpecialPopupHint) {
362         mNeedsSpecialPopupHint = needsSpecialPopupHint;
363     }
364 
needsSpecialPopupHint()365     public boolean needsSpecialPopupHint() {
366         return mNeedsSpecialPopupHint;
367     }
368 
hasUppercaseLetter()369     public boolean hasUppercaseLetter() {
370         return (mLabelOption & LABEL_OPTION_HAS_UPPERCASE_LETTER) != 0;
371     }
372 
hasHintLabel()373     public boolean hasHintLabel() {
374         return (mLabelOption & LABEL_OPTION_HAS_HINT_LABEL) != 0;
375     }
376 
hasLabelWithIconLeft()377     public boolean hasLabelWithIconLeft() {
378         return (mLabelOption & LABEL_OPTION_WITH_ICON_LEFT) != 0;
379     }
380 
hasLabelWithIconRight()381     public boolean hasLabelWithIconRight() {
382         return (mLabelOption & LABEL_OPTION_WITH_ICON_RIGHT) != 0;
383     }
384 
needsXScale()385     public boolean needsXScale() {
386         return (mLabelOption & LABEL_OPTION_AUTO_X_SCALE) != 0;
387     }
388 
getIcon()389     public Drawable getIcon() {
390         return mIcon;
391     }
392 
getPreviewIcon()393     public Drawable getPreviewIcon() {
394         return mPreviewIcon;
395     }
396 
setIcon(Drawable icon)397     public void setIcon(Drawable icon) {
398         mIcon = icon;
399     }
400 
setPreviewIcon(Drawable icon)401     public void setPreviewIcon(Drawable icon) {
402         mPreviewIcon = icon;
403     }
404 
405     /**
406      * Informs the key that it has been pressed, in case it needs to change its appearance or
407      * state.
408      * @see #onReleased()
409      */
onPressed()410     public void onPressed() {
411         mPressed = true;
412     }
413 
414     /**
415      * Informs the key that it has been released, in case it needs to change its appearance or
416      * state.
417      * @see #onPressed()
418      */
onReleased()419     public void onReleased() {
420         mPressed = false;
421     }
422 
setHighlightOn(boolean highlightOn)423     public void setHighlightOn(boolean highlightOn) {
424         mHighlightOn = highlightOn;
425     }
426 
isEnabled()427     public boolean isEnabled() {
428         return mEnabled;
429     }
430 
setEnabled(boolean enabled)431     public void setEnabled(boolean enabled) {
432         mEnabled = enabled;
433     }
434 
435     /**
436      * Detects if a point falls on this key.
437      * @param x the x-coordinate of the point
438      * @param y the y-coordinate of the point
439      * @return whether or not the point falls on the key. If the key is attached to an edge, it will
440      * assume that all points between the key and the edge are considered to be on the key.
441      * @see {@link #markAsLeftEdge(KeyboardParams)} etc.
442      */
isOnKey(int x, int y)443     public boolean isOnKey(int x, int y) {
444         return mHitBox.contains(x, y);
445     }
446 
447     /**
448      * Returns the square of the distance to the nearest edge of the key and the given point.
449      * @param x the x-coordinate of the point
450      * @param y the y-coordinate of the point
451      * @return the square of the distance of the point from the nearest edge of the key
452      */
squaredDistanceToEdge(int x, int y)453     public int squaredDistanceToEdge(int x, int y) {
454         final int left = mX;
455         final int right = left + mWidth;
456         final int top = mY;
457         final int bottom = top + mHeight;
458         final int edgeX = x < left ? left : (x > right ? right : x);
459         final int edgeY = y < top ? top : (y > bottom ? bottom : y);
460         final int dx = x - edgeX;
461         final int dy = y - edgeY;
462         return dx * dx + dy * dy;
463     }
464 
465     private final static int[] KEY_STATE_NORMAL_HIGHLIGHT_ON = {
466         android.R.attr.state_checkable,
467         android.R.attr.state_checked
468     };
469 
470     private final static int[] KEY_STATE_PRESSED_HIGHLIGHT_ON = {
471         android.R.attr.state_pressed,
472         android.R.attr.state_checkable,
473         android.R.attr.state_checked
474     };
475 
476     private final static int[] KEY_STATE_NORMAL_HIGHLIGHT_OFF = {
477         android.R.attr.state_checkable
478     };
479 
480     private final static int[] KEY_STATE_PRESSED_HIGHLIGHT_OFF = {
481         android.R.attr.state_pressed,
482         android.R.attr.state_checkable
483     };
484 
485     private final static int[] KEY_STATE_NORMAL = {
486     };
487 
488     private final static int[] KEY_STATE_PRESSED = {
489         android.R.attr.state_pressed
490     };
491 
492     // functional normal state (with properties)
493     private static final int[] KEY_STATE_FUNCTIONAL_NORMAL = {
494             android.R.attr.state_single
495     };
496 
497     // functional pressed state (with properties)
498     private static final int[] KEY_STATE_FUNCTIONAL_PRESSED = {
499             android.R.attr.state_single,
500             android.R.attr.state_pressed
501     };
502 
503     // action normal state (with properties)
504     private static final int[] KEY_STATE_ACTIVE_NORMAL = {
505             android.R.attr.state_active
506     };
507 
508     // action pressed state (with properties)
509     private static final int[] KEY_STATE_ACTIVE_PRESSED = {
510             android.R.attr.state_active,
511             android.R.attr.state_pressed
512     };
513 
514     /**
515      * Returns the drawable state for the key, based on the current state and type of the key.
516      * @return the drawable state of the key.
517      * @see android.graphics.drawable.StateListDrawable#setState(int[])
518      */
getCurrentDrawableState()519     public int[] getCurrentDrawableState() {
520         final boolean pressed = mPressed;
521 
522         switch (mBackgroundType) {
523         case BACKGROUND_TYPE_FUNCTIONAL:
524             return pressed ? KEY_STATE_FUNCTIONAL_PRESSED : KEY_STATE_FUNCTIONAL_NORMAL;
525         case BACKGROUND_TYPE_ACTION:
526             return pressed ? KEY_STATE_ACTIVE_PRESSED : KEY_STATE_ACTIVE_NORMAL;
527         case BACKGROUND_TYPE_STICKY:
528             if (mHighlightOn) {
529                 return pressed ? KEY_STATE_PRESSED_HIGHLIGHT_ON : KEY_STATE_NORMAL_HIGHLIGHT_ON;
530             } else {
531                 return pressed ? KEY_STATE_PRESSED_HIGHLIGHT_OFF : KEY_STATE_NORMAL_HIGHLIGHT_OFF;
532             }
533         default: /* BACKGROUND_TYPE_NORMAL */
534             return pressed ? KEY_STATE_PRESSED : KEY_STATE_NORMAL;
535         }
536     }
537 
538     public static class Spacer extends Key {
Spacer(Resources res, KeyboardParams params, KeyboardBuilder.Row row, XmlPullParser parser, KeyStyles keyStyles)539         public Spacer(Resources res, KeyboardParams params, KeyboardBuilder.Row row,
540                 XmlPullParser parser, KeyStyles keyStyles) {
541             super(res, params, row, parser, keyStyles);
542         }
543 
544         /**
545          * This constructor is being used only for divider in more keys keyboard.
546          */
Spacer(KeyboardParams params, Drawable icon, int x, int y, int width, int height)547         public Spacer(KeyboardParams params, Drawable icon, int x, int y, int width, int height) {
548             super(params, null, null, icon, Keyboard.CODE_DUMMY, null, x, y, width, height);
549         }
550 
551         @Override
isSpacer()552         public boolean isSpacer() {
553             return true;
554         }
555     }
556 }
557