summaryrefslogtreecommitdiffstats
path: root/core/java/android/inputmethodservice/Keyboard.java
diff options
context:
space:
mode:
authorThe Android Open Source Project <initial-contribution@android.com>2009-03-03 18:28:45 -0800
committerThe Android Open Source Project <initial-contribution@android.com>2009-03-03 18:28:45 -0800
commitd83a98f4ce9cfa908f5c54bbd70f03eec07e7553 (patch)
tree4b825dc642cb6eb9a060e54bf8d69288fbee4904 /core/java/android/inputmethodservice/Keyboard.java
parent076357b8567458d4b6dfdcf839ef751634cd2bfb (diff)
downloadframeworks_base-d83a98f4ce9cfa908f5c54bbd70f03eec07e7553.zip
frameworks_base-d83a98f4ce9cfa908f5c54bbd70f03eec07e7553.tar.gz
frameworks_base-d83a98f4ce9cfa908f5c54bbd70f03eec07e7553.tar.bz2
auto import from //depot/cupcake/@135843
Diffstat (limited to 'core/java/android/inputmethodservice/Keyboard.java')
-rwxr-xr-xcore/java/android/inputmethodservice/Keyboard.java815
1 files changed, 0 insertions, 815 deletions
diff --git a/core/java/android/inputmethodservice/Keyboard.java b/core/java/android/inputmethodservice/Keyboard.java
deleted file mode 100755
index 6a560ce..0000000
--- a/core/java/android/inputmethodservice/Keyboard.java
+++ /dev/null
@@ -1,815 +0,0 @@
-/*
- * Copyright (C) 2008-2009 Google Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not
- * use this file except in compliance with the License. You may obtain a copy of
- * the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations under
- * the License.
- */
-
-package android.inputmethodservice;
-
-import org.xmlpull.v1.XmlPullParserException;
-
-import android.content.Context;
-import android.content.res.Resources;
-import android.content.res.TypedArray;
-import android.content.res.XmlResourceParser;
-import android.graphics.drawable.Drawable;
-import android.text.TextUtils;
-import android.util.Log;
-import android.util.TypedValue;
-import android.util.Xml;
-import android.view.Display;
-import android.view.WindowManager;
-
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.StringTokenizer;
-
-
-/**
- * Loads an XML description of a keyboard and stores the attributes of the keys. A keyboard
- * consists of rows of keys.
- * <p>The layout file for a keyboard contains XML that looks like the following snippet:</p>
- * <pre>
- * &lt;Keyboard
- * android:keyWidth="%10p"
- * android:keyHeight="50px"
- * android:horizontalGap="2px"
- * android:verticalGap="2px" &gt;
- * &lt;Row android:keyWidth="32px" &gt;
- * &lt;Key android:keyLabel="A" /&gt;
- * ...
- * &lt;/Row&gt;
- * ...
- * &lt;/Keyboard&gt;
- * </pre>
- * @attr ref android.R.styleable#Keyboard_keyWidth
- * @attr ref android.R.styleable#Keyboard_keyHeight
- * @attr ref android.R.styleable#Keyboard_horizontalGap
- * @attr ref android.R.styleable#Keyboard_verticalGap
- */
-public class Keyboard {
-
- static final String TAG = "Keyboard";
-
- // Keyboard XML Tags
- private static final String TAG_KEYBOARD = "Keyboard";
- private static final String TAG_ROW = "Row";
- private static final String TAG_KEY = "Key";
-
- public static final int EDGE_LEFT = 0x01;
- public static final int EDGE_RIGHT = 0x02;
- public static final int EDGE_TOP = 0x04;
- public static final int EDGE_BOTTOM = 0x08;
-
- public static final int KEYCODE_SHIFT = -1;
- public static final int KEYCODE_MODE_CHANGE = -2;
- public static final int KEYCODE_CANCEL = -3;
- public static final int KEYCODE_DONE = -4;
- public static final int KEYCODE_DELETE = -5;
- public static final int KEYCODE_ALT = -6;
-
- /** Keyboard label **/
- private CharSequence mLabel;
-
- /** Horizontal gap default for all rows */
- private int mDefaultHorizontalGap;
-
- /** Default key width */
- private int mDefaultWidth;
-
- /** Default key height */
- private int mDefaultHeight;
-
- /** Default gap between rows */
- private int mDefaultVerticalGap;
-
- /** Is the keyboard in the shifted state */
- private boolean mShifted;
-
- /** Key instance for the shift key, if present */
- private Key mShiftKey;
-
- /** Key index for the shift key, if present */
- private int mShiftKeyIndex = -1;
-
- /** Current key width, while loading the keyboard */
- private int mKeyWidth;
-
- /** Current key height, while loading the keyboard */
- private int mKeyHeight;
-
- /** Total height of the keyboard, including the padding and keys */
- private int mTotalHeight;
-
- /**
- * Total width of the keyboard, including left side gaps and keys, but not any gaps on the
- * right side.
- */
- private int mTotalWidth;
-
- /** List of keys in this keyboard */
- private List<Key> mKeys;
-
- /** List of modifier keys such as Shift & Alt, if any */
- private List<Key> mModifierKeys;
-
- /** Width of the screen available to fit the keyboard */
- private int mDisplayWidth;
-
- /** Height of the screen */
- private int mDisplayHeight;
-
- /** Keyboard mode, or zero, if none. */
- private int mKeyboardMode;
-
- // Variables for pre-computing nearest keys.
-
- private static final int GRID_WIDTH = 10;
- private static final int GRID_HEIGHT = 5;
- private static final int GRID_SIZE = GRID_WIDTH * GRID_HEIGHT;
- private int mCellWidth;
- private int mCellHeight;
- private int[][] mGridNeighbors;
- private int mProximityThreshold;
- /** Number of key widths from current touch point to search for nearest keys. */
- private static float SEARCH_DISTANCE = 1.4f;
-
- /**
- * Container for keys in the keyboard. All keys in a row are at the same Y-coordinate.
- * Some of the key size defaults can be overridden per row from what the {@link Keyboard}
- * defines.
- * @attr ref android.R.styleable#Keyboard_keyWidth
- * @attr ref android.R.styleable#Keyboard_keyHeight
- * @attr ref android.R.styleable#Keyboard_horizontalGap
- * @attr ref android.R.styleable#Keyboard_verticalGap
- * @attr ref android.R.styleable#Keyboard_Row_rowEdgeFlags
- * @attr ref android.R.styleable#Keyboard_Row_keyboardMode
- */
- public static class Row {
- /** Default width of a key in this row. */
- public int defaultWidth;
- /** Default height of a key in this row. */
- public int defaultHeight;
- /** Default horizontal gap between keys in this row. */
- public int defaultHorizontalGap;
- /** Vertical gap following this row. */
- public int verticalGap;
- /**
- * Edge flags for this row of keys. Possible values that can be assigned are
- * {@link Keyboard#EDGE_TOP EDGE_TOP} and {@link Keyboard#EDGE_BOTTOM EDGE_BOTTOM}
- */
- public int rowEdgeFlags;
-
- /** The keyboard mode for this row */
- public int mode;
-
- private Keyboard parent;
-
- public Row(Keyboard parent) {
- this.parent = parent;
- }
-
- public Row(Resources res, Keyboard parent, XmlResourceParser parser) {
- this.parent = parent;
- TypedArray a = res.obtainAttributes(Xml.asAttributeSet(parser),
- com.android.internal.R.styleable.Keyboard);
- defaultWidth = getDimensionOrFraction(a,
- com.android.internal.R.styleable.Keyboard_keyWidth,
- parent.mDisplayWidth, parent.mDefaultWidth);
- defaultHeight = getDimensionOrFraction(a,
- com.android.internal.R.styleable.Keyboard_keyHeight,
- parent.mDisplayHeight, parent.mDefaultHeight);
- defaultHorizontalGap = getDimensionOrFraction(a,
- com.android.internal.R.styleable.Keyboard_horizontalGap,
- parent.mDisplayWidth, parent.mDefaultHorizontalGap);
- verticalGap = getDimensionOrFraction(a,
- com.android.internal.R.styleable.Keyboard_verticalGap,
- parent.mDisplayHeight, parent.mDefaultVerticalGap);
- a.recycle();
- a = res.obtainAttributes(Xml.asAttributeSet(parser),
- com.android.internal.R.styleable.Keyboard_Row);
- rowEdgeFlags = a.getInt(com.android.internal.R.styleable.Keyboard_Row_rowEdgeFlags, 0);
- mode = a.getResourceId(com.android.internal.R.styleable.Keyboard_Row_keyboardMode,
- 0);
- }
- }
-
- /**
- * Class for describing the position and characteristics of a single key in the keyboard.
- *
- * @attr ref android.R.styleable#Keyboard_keyWidth
- * @attr ref android.R.styleable#Keyboard_keyHeight
- * @attr ref android.R.styleable#Keyboard_horizontalGap
- * @attr ref android.R.styleable#Keyboard_Key_codes
- * @attr ref android.R.styleable#Keyboard_Key_keyIcon
- * @attr ref android.R.styleable#Keyboard_Key_keyLabel
- * @attr ref android.R.styleable#Keyboard_Key_iconPreview
- * @attr ref android.R.styleable#Keyboard_Key_isSticky
- * @attr ref android.R.styleable#Keyboard_Key_isRepeatable
- * @attr ref android.R.styleable#Keyboard_Key_isModifier
- * @attr ref android.R.styleable#Keyboard_Key_popupKeyboard
- * @attr ref android.R.styleable#Keyboard_Key_popupCharacters
- * @attr ref android.R.styleable#Keyboard_Key_keyOutputText
- * @attr ref android.R.styleable#Keyboard_Key_keyEdgeFlags
- */
- public static class Key {
- /**
- * All the key codes (unicode or custom code) that this key could generate, zero'th
- * being the most important.
- */
- public int[] codes;
-
- /** Label to display */
- public CharSequence label;
-
- /** Icon to display instead of a label. Icon takes precedence over a label */
- public Drawable icon;
- /** Preview version of the icon, for the preview popup */
- public Drawable iconPreview;
- /** Width of the key, not including the gap */
- public int width;
- /** Height of the key, not including the gap */
- public int height;
- /** The horizontal gap before this key */
- public int gap;
- /** Whether this key is sticky, i.e., a toggle key */
- public boolean sticky;
- /** X coordinate of the key in the keyboard layout */
- public int x;
- /** Y coordinate of the key in the keyboard layout */
- public int y;
- /** The current pressed state of this key */
- public boolean pressed;
- /** If this is a sticky key, is it on? */
- public boolean on;
- /** Text to output when pressed. This can be multiple characters, like ".com" */
- public CharSequence text;
- /** Popup characters */
- public CharSequence popupCharacters;
-
- /**
- * Flags that specify the anchoring to edges of the keyboard for detecting touch events
- * that are just out of the boundary of the key. This is a bit mask of
- * {@link Keyboard#EDGE_LEFT}, {@link Keyboard#EDGE_RIGHT}, {@link Keyboard#EDGE_TOP} and
- * {@link Keyboard#EDGE_BOTTOM}.
- */
- public int edgeFlags;
- /** Whether this is a modifier key, such as Shift or Alt */
- public boolean modifier;
- /** The keyboard that this key belongs to */
- private Keyboard keyboard;
- /**
- * If this key pops up a mini keyboard, this is the resource id for the XML layout for that
- * keyboard.
- */
- public int popupResId;
- /** Whether this key repeats itself when held down */
- public boolean repeatable;
-
-
- private final static int[] KEY_STATE_NORMAL_ON = {
- android.R.attr.state_checkable,
- android.R.attr.state_checked
- };
-
- private final static int[] KEY_STATE_PRESSED_ON = {
- android.R.attr.state_pressed,
- android.R.attr.state_checkable,
- android.R.attr.state_checked
- };
-
- private final static int[] KEY_STATE_NORMAL_OFF = {
- android.R.attr.state_checkable
- };
-
- private final static int[] KEY_STATE_PRESSED_OFF = {
- android.R.attr.state_pressed,
- android.R.attr.state_checkable
- };
-
- private final static int[] KEY_STATE_NORMAL = {
- };
-
- private final static int[] KEY_STATE_PRESSED = {
- android.R.attr.state_pressed
- };
-
- /** Create an empty key with no attributes. */
- public Key(Row parent) {
- keyboard = parent.parent;
- }
-
- /** Create a key with the given top-left coordinate and extract its attributes from
- * the XML parser.
- * @param res resources associated with the caller's context
- * @param parent the row that this key belongs to. The row must already be attached to
- * a {@link Keyboard}.
- * @param x the x coordinate of the top-left
- * @param y the y coordinate of the top-left
- * @param parser the XML parser containing the attributes for this key
- */
- public Key(Resources res, Row parent, int x, int y, XmlResourceParser parser) {
- this(parent);
-
- this.x = x;
- this.y = y;
-
- TypedArray a = res.obtainAttributes(Xml.asAttributeSet(parser),
- com.android.internal.R.styleable.Keyboard);
-
- width = getDimensionOrFraction(a,
- com.android.internal.R.styleable.Keyboard_keyWidth,
- keyboard.mDisplayWidth, parent.defaultWidth);
- height = getDimensionOrFraction(a,
- com.android.internal.R.styleable.Keyboard_keyHeight,
- keyboard.mDisplayHeight, parent.defaultHeight);
- gap = getDimensionOrFraction(a,
- com.android.internal.R.styleable.Keyboard_horizontalGap,
- keyboard.mDisplayWidth, parent.defaultHorizontalGap);
- a.recycle();
- a = res.obtainAttributes(Xml.asAttributeSet(parser),
- com.android.internal.R.styleable.Keyboard_Key);
- this.x += gap;
- TypedValue codesValue = new TypedValue();
- a.getValue(com.android.internal.R.styleable.Keyboard_Key_codes,
- codesValue);
- if (codesValue.type == TypedValue.TYPE_INT_DEC
- || codesValue.type == TypedValue.TYPE_INT_HEX) {
- codes = new int[] { codesValue.data };
- } else if (codesValue.type == TypedValue.TYPE_STRING) {
- codes = parseCSV(codesValue.string.toString());
- }
-
- iconPreview = a.getDrawable(com.android.internal.R.styleable.Keyboard_Key_iconPreview);
- if (iconPreview != null) {
- iconPreview.setBounds(0, 0, iconPreview.getIntrinsicWidth(),
- iconPreview.getIntrinsicHeight());
- }
- popupCharacters = a.getText(
- com.android.internal.R.styleable.Keyboard_Key_popupCharacters);
- popupResId = a.getResourceId(
- com.android.internal.R.styleable.Keyboard_Key_popupKeyboard, 0);
- repeatable = a.getBoolean(
- com.android.internal.R.styleable.Keyboard_Key_isRepeatable, false);
- modifier = a.getBoolean(
- com.android.internal.R.styleable.Keyboard_Key_isModifier, false);
- sticky = a.getBoolean(
- com.android.internal.R.styleable.Keyboard_Key_isSticky, false);
- edgeFlags = a.getInt(com.android.internal.R.styleable.Keyboard_Key_keyEdgeFlags, 0);
- edgeFlags |= parent.rowEdgeFlags;
-
- icon = a.getDrawable(
- com.android.internal.R.styleable.Keyboard_Key_keyIcon);
- if (icon != null) {
- icon.setBounds(0, 0, icon.getIntrinsicWidth(), icon.getIntrinsicHeight());
- }
- label = a.getText(com.android.internal.R.styleable.Keyboard_Key_keyLabel);
- text = a.getText(com.android.internal.R.styleable.Keyboard_Key_keyOutputText);
-
- if (codes == null && !TextUtils.isEmpty(label)) {
- codes = new int[] { label.charAt(0) };
- }
- a.recycle();
- }
-
- /**
- * Informs the key that it has been pressed, in case it needs to change its appearance or
- * state.
- * @see #onReleased(boolean)
- */
- public void onPressed() {
- pressed = !pressed;
- }
-
- /**
- * Changes the pressed state of the key. If it is a sticky key, it will also change the
- * toggled state of the key if the finger was release inside.
- * @param inside whether the finger was released inside the key
- * @see #onPressed()
- */
- public void onReleased(boolean inside) {
- pressed = !pressed;
- if (sticky) {
- on = !on;
- }
- }
-
- int[] parseCSV(String value) {
- int count = 0;
- int lastIndex = 0;
- if (value.length() > 0) {
- count++;
- while ((lastIndex = value.indexOf(",", lastIndex + 1)) > 0) {
- count++;
- }
- }
- int[] values = new int[count];
- count = 0;
- StringTokenizer st = new StringTokenizer(value, ",");
- while (st.hasMoreTokens()) {
- try {
- values[count++] = Integer.parseInt(st.nextToken());
- } catch (NumberFormatException nfe) {
- Log.e(TAG, "Error parsing keycodes " + value);
- }
- }
- return values;
- }
-
- /**
- * Detects if a point falls inside this key.
- * @param x the x-coordinate of the point
- * @param y the y-coordinate of the point
- * @return whether or not the point falls inside the key. If the key is attached to an edge,
- * it will assume that all points between the key and the edge are considered to be inside
- * the key.
- */
- public boolean isInside(int x, int y) {
- boolean leftEdge = (edgeFlags & EDGE_LEFT) > 0;
- boolean rightEdge = (edgeFlags & EDGE_RIGHT) > 0;
- boolean topEdge = (edgeFlags & EDGE_TOP) > 0;
- boolean bottomEdge = (edgeFlags & EDGE_BOTTOM) > 0;
- if ((x >= this.x || (leftEdge && x <= this.x + this.width))
- && (x < this.x + this.width || (rightEdge && x >= this.x))
- && (y >= this.y || (topEdge && y <= this.y + this.height))
- && (y < this.y + this.height || (bottomEdge && y >= this.y))) {
- return true;
- } else {
- return false;
- }
- }
-
- /**
- * Returns the square of the distance between the center of the key and the given point.
- * @param x the x-coordinate of the point
- * @param y the y-coordinate of the point
- * @return the square of the distance of the point from the center of the key
- */
- public int squaredDistanceFrom(int x, int y) {
- int xDist = this.x + width / 2 - x;
- int yDist = this.y + height / 2 - y;
- return xDist * xDist + yDist * yDist;
- }
-
- /**
- * Returns the drawable state for the key, based on the current state and type of the key.
- * @return the drawable state of the key.
- * @see android.graphics.drawable.StateListDrawable#setState(int[])
- */
- public int[] getCurrentDrawableState() {
- int[] states = KEY_STATE_NORMAL;
-
- if (on) {
- if (pressed) {
- states = KEY_STATE_PRESSED_ON;
- } else {
- states = KEY_STATE_NORMAL_ON;
- }
- } else {
- if (sticky) {
- if (pressed) {
- states = KEY_STATE_PRESSED_OFF;
- } else {
- states = KEY_STATE_NORMAL_OFF;
- }
- } else {
- if (pressed) {
- states = KEY_STATE_PRESSED;
- }
- }
- }
- return states;
- }
- }
-
- /**
- * Creates a keyboard from the given xml key layout file.
- * @param context the application or service context
- * @param xmlLayoutResId the resource file that contains the keyboard layout and keys.
- */
- public Keyboard(Context context, int xmlLayoutResId) {
- this(context, xmlLayoutResId, 0);
- }
-
- /**
- * Creates a keyboard from the given xml key layout file. Weeds out rows
- * that have a keyboard mode defined but don't match the specified mode.
- * @param context the application or service context
- * @param xmlLayoutResId the resource file that contains the keyboard layout and keys.
- * @param modeId keyboard mode identifier
- */
- public Keyboard(Context context, int xmlLayoutResId, int modeId) {
- WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
- final Display display = wm.getDefaultDisplay();
- mDisplayWidth = display.getWidth();
- mDisplayHeight = display.getHeight();
- mDefaultHorizontalGap = 0;
- mDefaultWidth = mDisplayWidth / 10;
- mDefaultVerticalGap = 0;
- mDefaultHeight = mDefaultWidth;
- mKeys = new ArrayList<Key>();
- mModifierKeys = new ArrayList<Key>();
- mKeyboardMode = modeId;
- loadKeyboard(context, context.getResources().getXml(xmlLayoutResId));
- }
-
- /**
- * <p>Creates a blank keyboard from the given resource file and populates it with the specified
- * characters in left-to-right, top-to-bottom fashion, using the specified number of columns.
- * </p>
- * <p>If the specified number of columns is -1, then the keyboard will fit as many keys as
- * possible in each row.</p>
- * @param context the application or service context
- * @param layoutTemplateResId the layout template file, containing no keys.
- * @param characters the list of characters to display on the keyboard. One key will be created
- * for each character.
- * @param columns the number of columns of keys to display. If this number is greater than the
- * number of keys that can fit in a row, it will be ignored. If this number is -1, the
- * keyboard will fit as many keys as possible in each row.
- */
- public Keyboard(Context context, int layoutTemplateResId,
- CharSequence characters, int columns, int horizontalPadding) {
- this(context, layoutTemplateResId);
- int x = 0;
- int y = 0;
- int column = 0;
- mTotalWidth = 0;
-
- Row row = new Row(this);
- row.defaultHeight = mDefaultHeight;
- row.defaultWidth = mDefaultWidth;
- row.defaultHorizontalGap = mDefaultHorizontalGap;
- row.verticalGap = mDefaultVerticalGap;
- row.rowEdgeFlags = EDGE_TOP | EDGE_BOTTOM;
- final int maxColumns = columns == -1 ? Integer.MAX_VALUE : columns;
- for (int i = 0; i < characters.length(); i++) {
- char c = characters.charAt(i);
- if (column >= maxColumns
- || x + mDefaultWidth + horizontalPadding > mDisplayWidth) {
- x = 0;
- y += mDefaultVerticalGap + mDefaultHeight;
- column = 0;
- }
- final Key key = new Key(row);
- key.x = x;
- key.y = y;
- key.width = mDefaultWidth;
- key.height = mDefaultHeight;
- key.gap = mDefaultHorizontalGap;
- key.label = String.valueOf(c);
- key.codes = new int[] { c };
- column++;
- x += key.width + key.gap;
- mKeys.add(key);
- if (x > mTotalWidth) {
- mTotalWidth = x;
- }
- }
- mTotalHeight = y + mDefaultHeight;
- }
-
- public List<Key> getKeys() {
- return mKeys;
- }
-
- public List<Key> getModifierKeys() {
- return mModifierKeys;
- }
-
- protected int getHorizontalGap() {
- return mDefaultHorizontalGap;
- }
-
- protected void setHorizontalGap(int gap) {
- mDefaultHorizontalGap = gap;
- }
-
- protected int getVerticalGap() {
- return mDefaultVerticalGap;
- }
-
- protected void setVerticalGap(int gap) {
- mDefaultVerticalGap = gap;
- }
-
- protected int getKeyHeight() {
- return mDefaultHeight;
- }
-
- protected void setKeyHeight(int height) {
- mDefaultHeight = height;
- }
-
- protected int getKeyWidth() {
- return mDefaultWidth;
- }
-
- protected void setKeyWidth(int width) {
- mDefaultWidth = width;
- }
-
- /**
- * Returns the total height of the keyboard
- * @return the total height of the keyboard
- */
- public int getHeight() {
- return mTotalHeight;
- }
-
- public int getMinWidth() {
- return mTotalWidth;
- }
-
- public boolean setShifted(boolean shiftState) {
- if (mShiftKey != null) {
- mShiftKey.on = shiftState;
- }
- if (mShifted != shiftState) {
- mShifted = shiftState;
- return true;
- }
- return false;
- }
-
- public boolean isShifted() {
- return mShifted;
- }
-
- public int getShiftKeyIndex() {
- return mShiftKeyIndex;
- }
-
- private void computeNearestNeighbors() {
- // Round-up so we don't have any pixels outside the grid
- mCellWidth = (getMinWidth() + GRID_WIDTH - 1) / GRID_WIDTH;
- mCellHeight = (getHeight() + GRID_HEIGHT - 1) / GRID_HEIGHT;
- mGridNeighbors = new int[GRID_SIZE][];
- int[] indices = new int[mKeys.size()];
- final int gridWidth = GRID_WIDTH * mCellWidth;
- final int gridHeight = GRID_HEIGHT * mCellHeight;
- for (int x = 0; x < gridWidth; x += mCellWidth) {
- for (int y = 0; y < gridHeight; y += mCellHeight) {
- int count = 0;
- for (int i = 0; i < mKeys.size(); i++) {
- final Key key = mKeys.get(i);
- if (key.squaredDistanceFrom(x, y) < mProximityThreshold ||
- key.squaredDistanceFrom(x + mCellWidth - 1, y) < mProximityThreshold ||
- key.squaredDistanceFrom(x + mCellWidth - 1, y + mCellHeight - 1)
- < mProximityThreshold ||
- key.squaredDistanceFrom(x, y + mCellHeight - 1) < mProximityThreshold) {
- indices[count++] = i;
- }
- }
- int [] cell = new int[count];
- System.arraycopy(indices, 0, cell, 0, count);
- mGridNeighbors[(y / mCellHeight) * GRID_WIDTH + (x / mCellWidth)] = cell;
- }
- }
- }
-
- /**
- * Returns the indices of the keys that are closest to the given point.
- * @param x the x-coordinate of the point
- * @param y the y-coordinate of the point
- * @return the array of integer indices for the nearest keys to the given point. If the given
- * point is out of range, then an array of size zero is returned.
- */
- public int[] getNearestKeys(int x, int y) {
- if (mGridNeighbors == null) computeNearestNeighbors();
- if (x >= 0 && x < getMinWidth() && y >= 0 && y < getHeight()) {
- int index = (y / mCellHeight) * GRID_WIDTH + (x / mCellWidth);
- if (index < GRID_SIZE) {
- return mGridNeighbors[index];
- }
- }
- return new int[0];
- }
-
- protected Row createRowFromXml(Resources res, XmlResourceParser parser) {
- return new Row(res, this, parser);
- }
-
- protected Key createKeyFromXml(Resources res, Row parent, int x, int y,
- XmlResourceParser parser) {
- return new Key(res, parent, x, y, parser);
- }
-
- private void loadKeyboard(Context context, XmlResourceParser parser) {
- boolean inKey = false;
- boolean inRow = false;
- boolean leftMostKey = false;
- int row = 0;
- int x = 0;
- int y = 0;
- Key key = null;
- Row currentRow = null;
- Resources res = context.getResources();
- boolean skipRow = false;
-
- try {
- int event;
- while ((event = parser.next()) != XmlResourceParser.END_DOCUMENT) {
- if (event == XmlResourceParser.START_TAG) {
- String tag = parser.getName();
- if (TAG_ROW.equals(tag)) {
- inRow = true;
- x = 0;
- currentRow = createRowFromXml(res, parser);
- skipRow = currentRow.mode != 0 && currentRow.mode != mKeyboardMode;
- if (skipRow) {
- skipToEndOfRow(parser);
- inRow = false;
- }
- } else if (TAG_KEY.equals(tag)) {
- inKey = true;
- key = createKeyFromXml(res, currentRow, x, y, parser);
- mKeys.add(key);
- if (key.codes[0] == KEYCODE_SHIFT) {
- mShiftKey = key;
- mShiftKeyIndex = mKeys.size()-1;
- mModifierKeys.add(key);
- } else if (key.codes[0] == KEYCODE_ALT) {
- mModifierKeys.add(key);
- }
- } else if (TAG_KEYBOARD.equals(tag)) {
- parseKeyboardAttributes(res, parser);
- }
- } else if (event == XmlResourceParser.END_TAG) {
- if (inKey) {
- inKey = false;
- x += key.gap + key.width;
- if (x > mTotalWidth) {
- mTotalWidth = x;
- }
- } else if (inRow) {
- inRow = false;
- y += currentRow.verticalGap;
- y += currentRow.defaultHeight;
- row++;
- } else {
- // TODO: error or extend?
- }
- }
- }
- } catch (Exception e) {
- Log.e(TAG, "Parse error:" + e);
- e.printStackTrace();
- }
- mTotalHeight = y - mDefaultVerticalGap;
- }
-
- private void skipToEndOfRow(XmlResourceParser parser)
- throws XmlPullParserException, IOException {
- int event;
- while ((event = parser.next()) != XmlResourceParser.END_DOCUMENT) {
- if (event == XmlResourceParser.END_TAG
- && parser.getName().equals(TAG_ROW)) {
- break;
- }
- }
- }
-
- private void parseKeyboardAttributes(Resources res, XmlResourceParser parser) {
- TypedArray a = res.obtainAttributes(Xml.asAttributeSet(parser),
- com.android.internal.R.styleable.Keyboard);
-
- mDefaultWidth = getDimensionOrFraction(a,
- com.android.internal.R.styleable.Keyboard_keyWidth,
- mDisplayWidth, mDisplayWidth / 10);
- mDefaultHeight = getDimensionOrFraction(a,
- com.android.internal.R.styleable.Keyboard_keyHeight,
- mDisplayHeight, 50);
- mDefaultHorizontalGap = getDimensionOrFraction(a,
- com.android.internal.R.styleable.Keyboard_horizontalGap,
- mDisplayWidth, 0);
- mDefaultVerticalGap = getDimensionOrFraction(a,
- com.android.internal.R.styleable.Keyboard_verticalGap,
- mDisplayHeight, 0);
- mProximityThreshold = (int) (mDefaultWidth * SEARCH_DISTANCE);
- mProximityThreshold = mProximityThreshold * mProximityThreshold; // Square it for comparison
- a.recycle();
- }
-
- static int getDimensionOrFraction(TypedArray a, int index, int base, int defValue) {
- TypedValue value = a.peekValue(index);
- if (value == null) return defValue;
- if (value.type == TypedValue.TYPE_DIMENSION) {
- return a.getDimensionPixelOffset(index, defValue);
- } else if (value.type == TypedValue.TYPE_FRACTION) {
- // Round it to avoid values like 47.9999 from getting truncated
- return Math.round(a.getFraction(index, base, base, defValue));
- }
- return defValue;
- }
-}