Merge "Move some inner static class to top class in new package"

main
Tadashi G. Takaoka 2010-12-02 03:07:43 -08:00 committed by Android (Google) Code Review
commit 26dae3f4e8
50 changed files with 1722 additions and 1449 deletions

View File

@ -26,9 +26,9 @@
android:paddingLeft="40dip"
android:paddingRight="40dip"
>
<com.android.inputmethod.latin.BaseKeyboardView
<com.android.inputmethod.keyboard.KeyboardView
xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
android:id="@+id/BaseKeyboardView"
android:id="@+id/KeyboardView"
android:layout_alignParentBottom="true"
android:layout_width="match_parent"
android:layout_height="wrap_content"

View File

@ -18,7 +18,7 @@
*/
-->
<com.android.inputmethod.latin.LatinKeyboardView
<com.android.inputmethod.keyboard.LatinKeyboardView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
android:id="@+id/LatinkeyboardBaseView"

View File

@ -18,7 +18,7 @@
*/
-->
<com.android.inputmethod.latin.LatinKeyboardView
<com.android.inputmethod.keyboard.LatinKeyboardView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"

View File

@ -18,7 +18,7 @@
*/
-->
<com.android.inputmethod.latin.LatinKeyboardView
<com.android.inputmethod.keyboard.LatinKeyboardView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
android:id="@+id/LatinkeyboardBaseView"

View File

@ -18,7 +18,7 @@
*/
-->
<com.android.inputmethod.latin.LatinKeyboardView
<com.android.inputmethod.keyboard.LatinKeyboardView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
android:id="@+id/LatinkeyboardBaseView"

View File

@ -18,7 +18,7 @@
*/
-->
<com.android.inputmethod.latin.LatinKeyboardView
<com.android.inputmethod.keyboard.LatinKeyboardView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
android:id="@+id/LatinkeyboardBaseView"

View File

@ -18,7 +18,7 @@
*/
-->
<com.android.inputmethod.latin.LatinKeyboardView
<com.android.inputmethod.keyboard.LatinKeyboardView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
android:id="@+id/LatinkeyboardBaseView"

View File

@ -25,9 +25,9 @@
android:orientation="horizontal"
android:background="@drawable/keyboard_popup_panel_background"
>
<com.android.inputmethod.latin.BaseKeyboardView
<com.android.inputmethod.keyboard.KeyboardView
xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
android:id="@+id/BaseKeyboardView"
android:id="@+id/KeyboardView"
android:layout_alignParentBottom="true"
android:layout_width="match_parent"
android:layout_height="wrap_content"

View File

@ -26,9 +26,9 @@
android:paddingLeft="16dip"
android:paddingRight="16dip"
>
<com.android.inputmethod.latin.BaseKeyboardView
<com.android.inputmethod.keyboard.KeyboardView
xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
android:id="@+id/BaseKeyboardView"
android:id="@+id/KeyboardView"
android:layout_alignParentBottom="true"
android:layout_width="match_parent"
android:layout_height="wrap_content"

View File

@ -26,9 +26,9 @@
android:paddingLeft="24dip"
android:paddingRight="24dip"
>
<com.android.inputmethod.latin.BaseKeyboardView
<com.android.inputmethod.keyboard.KeyboardView
xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
android:id="@+id/BaseKeyboardView"
android:id="@+id/KeyboardView"
android:layout_alignParentBottom="true"
android:layout_width="match_parent"
android:layout_height="wrap_content"

View File

@ -16,7 +16,7 @@
<resources>
<declare-styleable name="BaseKeyboardView">
<declare-styleable name="KeyboardView">
<!-- Default KeyboardView style. -->
<attr name="keyboardViewStyle" format="reference" />
@ -68,14 +68,14 @@
</attr>
<attr name="colorScheme">
<!-- This should be aligned with BaseKeyboardView.COLOR_SCHEME_* -->
<!-- This should be aligned with KeyboardView.COLOR_SCHEME_* -->
<enum name="white" value="0" />
<enum name="black" value="1" />
</attr>
</declare-styleable>
<declare-styleable name="BaseKeyboard">
<declare-styleable name="Keyboard">
<!-- Default width of a key, in pixels or percentage of display width. -->
<attr name="keyWidth" format="dimension|fraction" />
<!-- Default height of a key, in pixels or percentage of display width. -->
@ -86,7 +86,7 @@
<attr name="verticalGap" format="dimension|fraction" />
</declare-styleable>
<declare-styleable name="BaseKeyboard_Key">
<declare-styleable name="Keyboard_Key">
<!-- The unicode value or comma-separated values that this key outputs. -->
<attr name="codes" format="integer|string" />
<!-- The XML keyboard layout of any popup keyboard. -->
@ -114,7 +114,7 @@
<attr name="keyLabel" format="string" />
<!-- The key label option -->
<attr name="keyLabelOption">
<!-- This should be aligned with BaseKeyboardView.KEY_LABEL_OPTION_* -->
<!-- This should be aligned with KeyboardView.KEY_LABEL_OPTION_* -->
<flag name="alignLeft" value="1" />
<flag name="alignRight" value="2" />
<flag name="alignBottom" value="8" />
@ -135,7 +135,7 @@
<attr name="shiftedIcon" format="reference" />
</declare-styleable>
<declare-styleable name="BaseKeyboard_Row">
<declare-styleable name="Keyboard_Row">
<!-- Row edge flags. -->
<attr name="rowEdgeFlags">
<!-- Row is anchored to the top of the keyboard. -->
@ -145,12 +145,12 @@
</attr>
</declare-styleable>
<declare-styleable name="BaseKeyboard_Include">
<declare-styleable name="Keyboard_Include">
<attr name="keyboardLayout" format="reference" />
</declare-styleable>
<declare-styleable name="BaseKeyboard_Case">
<!-- This should be aligned with KeyboardSwitcher.MODE_* -->
<declare-styleable name="Keyboard_Case">
<!-- This should be aligned with KeyboardId.MODE_* -->
<attr name="mode">
<enum name="text" value="0" />
<enum name="url" value="1" />
@ -175,7 +175,7 @@
</attr>
</declare-styleable>
<declare-styleable name="BaseKeyboard_KeyStyle">
<declare-styleable name="Keyboard_KeyStyle">
<attr name="styleName" format="string" />
<attr name="parentStyle" format="string" />
</declare-styleable>

View File

@ -15,7 +15,7 @@
-->
<resources>
<style name="BaseKeyboardView">
<style name="KeyboardView">
<item name="android:background">@drawable/keyboard_background</item>
<item name="keyBackground">@drawable/btn_keyboard_key</item>

View File

@ -0,0 +1,305 @@
/*
* Copyright (C) 2010 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 com.android.inputmethod.keyboard;
import com.android.inputmethod.keyboard.KeyboardParser.ParseException;
import com.android.inputmethod.keyboard.KeyStyles.KeyStyle;
import com.android.inputmethod.latin.R;
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.Xml;
/**
* Class for describing the position and characteristics of a single key in the keyboard.
*/
public class Key {
/**
* All the key codes (unicode or custom code) that this key could generate, zero'th
* being the most important.
*/
public int[] codes;
/** The unicode that this key generates in manual temporary upper case mode. */
public int manualTemporaryUpperCaseCode;
/** Label to display */
public CharSequence label;
/** Option of the label */
public int labelOption;
/** Icon to display instead of a label. Icon takes precedence over a label */
public Drawable icon;
/** Hint icon to display on the key in conjunction with the label */
public Drawable hintIcon;
/** Preview version of the icon, for the preview popup */
/**
* The hint icon to display on the key when keyboard is in manual temporary upper case
* mode.
*/
public Drawable manualTemporaryUpperCaseHintIcon;
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 */
protected final 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;
height = parent.defaultHeight;
gap = parent.defaultHorizontalGap;
width = parent.defaultWidth - gap;
edgeFlags = parent.rowEdgeFlags;
}
/** 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,
KeyStyles keyStyles) {
this(parent);
TypedArray a = res.obtainAttributes(Xml.asAttributeSet(parser),
R.styleable.Keyboard);
height = KeyboardParser.getDimensionOrFraction(a,
R.styleable.Keyboard_keyHeight,
keyboard.mDisplayHeight, parent.defaultHeight);
gap = KeyboardParser.getDimensionOrFraction(a,
R.styleable.Keyboard_horizontalGap,
keyboard.mDisplayWidth, parent.defaultHorizontalGap);
width = KeyboardParser.getDimensionOrFraction(a,
R.styleable.Keyboard_keyWidth,
keyboard.mDisplayWidth, parent.defaultWidth) - gap;
a.recycle();
a = res.obtainAttributes(Xml.asAttributeSet(parser), R.styleable.Keyboard_Key);
final KeyStyle style;
if (a.hasValue(R.styleable.Keyboard_Key_keyStyle)) {
String styleName = a.getString(R.styleable.Keyboard_Key_keyStyle);
style = keyStyles.getKeyStyle(styleName);
if (style == null)
throw new ParseException("Unknown key style: " + styleName, parser);
} else {
style = keyStyles.getEmptyKeyStyle();
}
// Horizontal gap is divided equally to both sides of the key.
this.x = x + gap / 2;
this.y = y;
codes = style.getIntArray(a, R.styleable.Keyboard_Key_codes);
iconPreview = style.getDrawable(a, R.styleable.Keyboard_Key_iconPreview);
Keyboard.setDefaultBounds(iconPreview);
popupCharacters = style.getText(a, R.styleable.Keyboard_Key_popupCharacters);
popupResId = style.getResourceId(a, R.styleable.Keyboard_Key_popupKeyboard, 0);
repeatable = style.getBoolean(a, R.styleable.Keyboard_Key_isRepeatable, false);
modifier = style.getBoolean(a, R.styleable.Keyboard_Key_isModifier, false);
sticky = style.getBoolean(a, R.styleable.Keyboard_Key_isSticky, false);
edgeFlags = style.getFlag(a, R.styleable.Keyboard_Key_keyEdgeFlags, 0);
edgeFlags |= parent.rowEdgeFlags;
icon = style.getDrawable(a, R.styleable.Keyboard_Key_keyIcon);
Keyboard.setDefaultBounds(icon);
hintIcon = style.getDrawable(a, R.styleable.Keyboard_Key_keyHintIcon);
Keyboard.setDefaultBounds(hintIcon);
manualTemporaryUpperCaseHintIcon = style.getDrawable(a,
R.styleable.Keyboard_Key_manualTemporaryUpperCaseHintIcon);
Keyboard.setDefaultBounds(manualTemporaryUpperCaseHintIcon);
label = style.getText(a, R.styleable.Keyboard_Key_keyLabel);
labelOption = style.getFlag(a, R.styleable.Keyboard_Key_keyLabelOption, 0);
manualTemporaryUpperCaseCode = style.getInt(a,
R.styleable.Keyboard_Key_manualTemporaryUpperCaseCode, 0);
text = style.getText(a, R.styleable.Keyboard_Key_keyOutputText);
final Drawable shiftedIcon = style.getDrawable(a,
R.styleable.Keyboard_Key_shiftedIcon);
if (shiftedIcon != null)
keyboard.getShiftedIcons().put(this, shiftedIcon);
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;
}
}
/**
* 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 & Keyboard.EDGE_LEFT) > 0;
boolean rightEdge = (edgeFlags & Keyboard.EDGE_RIGHT) > 0;
boolean topEdge = (edgeFlags & Keyboard.EDGE_TOP) > 0;
boolean bottomEdge = (edgeFlags & Keyboard.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 to the nearest edge 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 nearest edge of the key
*/
public int squaredDistanceToEdge(int x, int y) {
final int left = this.x;
final int right = left + this.width;
final int top = this.y;
final int bottom = top + this.height;
final int edgeX = x < left ? left : (x > right ? right : x);
final int edgeY = y < top ? top : (y > bottom ? bottom : y);
final int dx = x - edgeX;
final int dy = y - edgeY;
return dx * dx + dy * dy;
}
/**
* 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;
}
}

View File

@ -14,15 +14,15 @@
* the License.
*/
package com.android.inputmethod.latin;
import com.android.inputmethod.latin.BaseKeyboard.Key;
package com.android.inputmethod.keyboard;
import java.util.Arrays;
import java.util.List;
abstract class KeyDetector {
protected BaseKeyboard mKeyboard;
public abstract class KeyDetector {
public static final int NOT_A_KEY = -1;
protected Keyboard mKeyboard;
private Key[] mKeys;
@ -34,7 +34,7 @@ abstract class KeyDetector {
protected int mProximityThresholdSquare;
public Key[] setKeyboard(BaseKeyboard keyboard, float correctionX, float correctionY) {
public Key[] setKeyboard(Keyboard keyboard, float correctionX, float correctionY) {
if (keyboard == null)
throw new NullPointerException();
mCorrectionX = (int)correctionX;
@ -84,7 +84,7 @@ abstract class KeyDetector {
*/
public int[] newCodeArray() {
int[] codes = new int[getMaxNearbyKeys()];
Arrays.fill(codes, BaseKeyboardView.NOT_A_KEY);
Arrays.fill(codes, NOT_A_KEY);
return codes;
}

View File

@ -14,9 +14,10 @@
* the License.
*/
package com.android.inputmethod.latin;
package com.android.inputmethod.keyboard;
import com.android.inputmethod.latin.BaseKeyboardParser.ParseException;
import com.android.inputmethod.keyboard.KeyboardParser.ParseException;
import com.android.inputmethod.latin.R;
import android.content.res.TypedArray;
import android.content.res.XmlResourceParser;
@ -48,30 +49,37 @@ public class KeyStyles {
private EmptyKeyStyle() {
}
@Override
public int[] getIntArray(TypedArray a, int index) {
return parseIntArray(a, index);
}
@Override
public Drawable getDrawable(TypedArray a, int index) {
return a.getDrawable(index);
}
@Override
public CharSequence getText(TypedArray a, int index) {
return a.getText(index);
}
@Override
public int getResourceId(TypedArray a, int index, int defaultValue) {
return a.getResourceId(index, defaultValue);
}
@Override
public int getInt(TypedArray a, int index, int defaultValue) {
return a.getInt(index, defaultValue);
}
@Override
public int getFlag(TypedArray a, int index, int defaultValue) {
return a.getInt(index, defaultValue);
}
@Override
public boolean getBoolean(TypedArray a, int index, boolean defaultValue) {
return a.getBoolean(index, defaultValue);
}
@ -156,18 +164,18 @@ public class KeyStyles {
private void parseKeyStyleAttributes(TypedArray a) {
// TODO: Currently not all Key attributes can be declared as style.
readIntArray(a, R.styleable.BaseKeyboard_Key_codes);
readText(a, R.styleable.BaseKeyboard_Key_keyLabel);
readFlag(a, R.styleable.BaseKeyboard_Key_keyLabelOption);
readText(a, R.styleable.BaseKeyboard_Key_keyOutputText);
readDrawable(a, R.styleable.BaseKeyboard_Key_keyIcon);
readDrawable(a, R.styleable.BaseKeyboard_Key_iconPreview);
readDrawable(a, R.styleable.BaseKeyboard_Key_keyHintIcon);
readDrawable(a, R.styleable.BaseKeyboard_Key_shiftedIcon);
readResourceId(a, R.styleable.BaseKeyboard_Key_popupKeyboard);
readBoolean(a, R.styleable.BaseKeyboard_Key_isModifier);
readBoolean(a, R.styleable.BaseKeyboard_Key_isSticky);
readBoolean(a, R.styleable.BaseKeyboard_Key_isRepeatable);
readIntArray(a, R.styleable.Keyboard_Key_codes);
readText(a, R.styleable.Keyboard_Key_keyLabel);
readFlag(a, R.styleable.Keyboard_Key_keyLabelOption);
readText(a, R.styleable.Keyboard_Key_keyOutputText);
readDrawable(a, R.styleable.Keyboard_Key_keyIcon);
readDrawable(a, R.styleable.Keyboard_Key_iconPreview);
readDrawable(a, R.styleable.Keyboard_Key_keyHintIcon);
readDrawable(a, R.styleable.Keyboard_Key_shiftedIcon);
readResourceId(a, R.styleable.Keyboard_Key_popupKeyboard);
readBoolean(a, R.styleable.Keyboard_Key_isModifier);
readBoolean(a, R.styleable.Keyboard_Key_isSticky);
readBoolean(a, R.styleable.Keyboard_Key_isRepeatable);
}
private void readDrawable(TypedArray a, int index) {
@ -211,14 +219,14 @@ public class KeyStyles {
public void parseKeyStyleAttributes(TypedArray a, TypedArray keyAttrs,
XmlResourceParser parser) {
String styleName = a.getString(R.styleable.BaseKeyboard_KeyStyle_styleName);
String styleName = a.getString(R.styleable.Keyboard_KeyStyle_styleName);
if (mStyles.containsKey(styleName))
throw new ParseException("duplicate key style declared: " + styleName, parser);
final DeclaredKeyStyle style = new DeclaredKeyStyle();
if (a.hasValue(R.styleable.BaseKeyboard_KeyStyle_parentStyle)) {
if (a.hasValue(R.styleable.Keyboard_KeyStyle_parentStyle)) {
String parentStyle = a.getString(
R.styleable.BaseKeyboard_KeyStyle_parentStyle);
R.styleable.Keyboard_KeyStyle_parentStyle);
final DeclaredKeyStyle parent = mStyles.get(parentStyle);
if (parent == null)
throw new ParseException("Unknown parentStyle " + parent, parser);

View File

@ -0,0 +1,386 @@
/*
* Copyright (C) 2010 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 com.android.inputmethod.keyboard;
import com.android.inputmethod.latin.R;
import org.xmlpull.v1.XmlPullParserException;
import android.content.Context;
import android.content.res.Resources;
import android.content.res.XmlResourceParser;
import android.graphics.drawable.Drawable;
import android.util.Log;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* 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
* latin:keyWidth="%10p"
* latin:keyHeight="50px"
* latin:horizontalGap="2px"
* latin:verticalGap="2px" &gt;
* &lt;Row latin:keyWidth="32px" &gt;
* &lt;Key latin:keyLabel="A" /&gt;
* ...
* &lt;/Row&gt;
* ...
* &lt;/Keyboard&gt;
* </pre>
*/
public class Keyboard {
static final String TAG = "Keyboard";
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;
/** Horizontal gap default for all rows */
int mDefaultHorizontalGap;
/** Default key width */
int mDefaultWidth;
/** Default key height */
int mDefaultHeight;
/** Default gap between rows */
int mDefaultVerticalGap;
/** Is the keyboard in the shifted state */
private boolean mShifted;
/** List of shift keys in this keyboard */
private final List<Key> mShiftKeys = new ArrayList<Key>();
/** List of shift keys and its shifted state icon */
private final HashMap<Key, Drawable> mShiftedIcons = new HashMap<Key, Drawable>();
/** 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 final List<Key> mKeys = new ArrayList<Key>();
/** Width of the screen available to fit the keyboard */
final int mDisplayWidth;
/** Height of the screen */
final int mDisplayHeight;
protected final KeyboardId mId;
// Variables for pre-computing nearest keys.
public final int GRID_WIDTH;
public final int GRID_HEIGHT;
private final int GRID_SIZE;
private int mCellWidth;
private int mCellHeight;
private int[][] mGridNeighbors;
private int mProximityThreshold;
private static int[] EMPTY_INT_ARRAY = new int[0];
/** Number of key widths from current touch point to search for nearest keys. */
private static float SEARCH_DISTANCE = 1.2f;
/**
* 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, null);
}
/**
* Creates a keyboard from the given keyboard identifier.
* @param context the application or service context
* @param id keyboard identifier
*/
public Keyboard(Context context, KeyboardId id) {
this(context, id.getXmlId(), id);
}
/**
* 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.
* @param id keyboard identifier
*/
private Keyboard(Context context, int xmlLayoutResId, KeyboardId id) {
this(context, xmlLayoutResId, id,
context.getResources().getDisplayMetrics().widthPixels,
context.getResources().getDisplayMetrics().heightPixels);
}
private Keyboard(Context context, int xmlLayoutResId, KeyboardId id, int width,
int height) {
Resources res = context.getResources();
GRID_WIDTH = res.getInteger(R.integer.config_keyboard_grid_width);
GRID_HEIGHT = res.getInteger(R.integer.config_keyboard_grid_height);
GRID_SIZE = GRID_WIDTH * GRID_HEIGHT;
mDisplayWidth = width;
mDisplayHeight = height;
mDefaultHorizontalGap = 0;
setKeyWidth(mDisplayWidth / 10);
mDefaultVerticalGap = 0;
mDefaultHeight = mDefaultWidth;
mId = id;
loadKeyboard(context, 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);
// Horizontal gap is divided equally to both sides of the key.
key.x = x + key.gap / 2;
key.y = y;
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 KeyboardId getKeyboardId() {
return mId;
}
public List<Key> getKeys() {
return mKeys;
}
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;
final int threshold = (int) (width * SEARCH_DISTANCE);
mProximityThreshold = threshold * threshold;
}
/**
* 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 int getKeyboardHeight() {
return mDisplayHeight;
}
public int getKeyboardWidth() {
return mDisplayWidth;
}
public boolean setShifted(boolean shiftState) {
for (final Key key : mShiftKeys) {
key.on = shiftState;
}
if (mShifted != shiftState) {
mShifted = shiftState;
return true;
}
return false;
}
public boolean isShiftedOrShiftLocked() {
return mShifted;
}
public List<Key> getShiftKeys() {
return mShiftKeys;
}
public Map<Key, Drawable> getShiftedIcons() {
return mShiftedIcons;
}
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][];
final int[] indices = new int[mKeys.size()];
final int gridWidth = GRID_WIDTH * mCellWidth;
final int gridHeight = GRID_HEIGHT * mCellHeight;
final int threshold = mProximityThreshold;
for (int x = 0; x < gridWidth; x += mCellWidth) {
for (int y = 0; y < gridHeight; y += mCellHeight) {
final int centerX = x + mCellWidth / 2;
final int centerY = y + mCellHeight / 2;
int count = 0;
for (int i = 0; i < mKeys.size(); i++) {
final Key key = mKeys.get(i);
if (key.squaredDistanceToEdge(centerX, centerY) < threshold)
indices[count++] = i;
}
final 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 EMPTY_INT_ARRAY;
}
// TODO should be private
protected Row createRowFromXml(Resources res, XmlResourceParser parser) {
return new Row(res, this, parser);
}
// TODO should be private
protected Key createKeyFromXml(Resources res, Row parent, int x, int y,
XmlResourceParser parser, KeyStyles keyStyles) {
return new Key(res, parent, x, y, parser, keyStyles);
}
private void loadKeyboard(Context context, int xmlLayoutResId) {
try {
final Resources res = context.getResources();
KeyboardParser parser = new KeyboardParser(this, res);
parser.parseKeyboard(res.getXml(xmlLayoutResId));
// mTotalWidth is the width of this keyboard which is maximum width of row.
mTotalWidth = parser.getMaxRowWidth();
mTotalHeight = parser.getTotalHeight();
} catch (XmlPullParserException e) {
Log.w(TAG, "keyboard XML parse error: " + e);
throw new IllegalArgumentException(e);
} catch (IOException e) {
Log.w(TAG, "keyboard XML parse error: " + e);
throw new RuntimeException(e);
}
}
protected static void setDefaultBounds(Drawable drawable) {
if (drawable != null)
drawable.setBounds(0, 0, drawable.getIntrinsicWidth(),
drawable.getIntrinsicHeight());
}
}

View File

@ -0,0 +1,99 @@
/*
* Copyright (C) 2010 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 com.android.inputmethod.keyboard;
public interface KeyboardActionListener {
/**
* Called when the user presses a key. This is sent before the
* {@link #onKey} is called. For keys that repeat, this is only
* called once.
*
* @param primaryCode
* the unicode of the key being pressed. If the touch is
* not on a valid key, the value will be zero.
*/
void onPress(int primaryCode);
/**
* Called when the user releases a key. This is sent after the
* {@link #onKey} is called. For keys that repeat, this is only
* called once.
*
* @param primaryCode
* the code of the key that was released
*/
void onRelease(int primaryCode);
/**
* Send a key press to the listener.
*
* @param primaryCode
* this is the key that was pressed
* @param keyCodes
* the codes for all the possible alternative keys with
* the primary code being the first. If the primary key
* code is a single character such as an alphabet or
* number or symbol, the alternatives will include other
* characters that may be on the same key or adjacent
* keys. These codes are useful to correct for
* accidental presses of a key adjacent to the intended
* key.
* @param x
* x-coordinate pixel of touched event. If onKey is not called by onTouchEvent,
* the value should be NOT_A_TOUCH_COORDINATE.
* @param y
* y-coordinate pixel of touched event. If onKey is not called by onTouchEvent,
* the value should be NOT_A_TOUCH_COORDINATE.
*/
void onKey(int primaryCode, int[] keyCodes, int x, int y);
/**
* Sends a sequence of characters to the listener.
*
* @param text
* the sequence of characters to be displayed.
*/
void onText(CharSequence text);
/**
* Called when user released a finger outside any key.
*/
void onCancel();
/**
* Called when the user quickly moves the finger from right to
* left.
*/
void swipeLeft();
/**
* Called when the user quickly moves the finger from left to
* right.
*/
void swipeRight();
/**
* Called when the user quickly moves the finger from up to down.
*/
void swipeDown();
/**
* Called when the user quickly moves the finger from down to up.
*/
void swipeUp();
}

View File

@ -0,0 +1,148 @@
/*
* Copyright (C) 2010 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 com.android.inputmethod.keyboard;
import com.android.inputmethod.latin.R;
import android.view.inputmethod.EditorInfo;
import java.util.Arrays;
import java.util.Locale;
/**
* Represents the parameters necessary to construct a new LatinKeyboard,
* which also serve as a unique identifier for each keyboard type.
*/
public class KeyboardId {
public static final int MODE_TEXT = 0;
public static final int MODE_URL = 1;
public static final int MODE_EMAIL = 2;
public static final int MODE_IM = 3;
public static final int MODE_WEB = 4;
public static final int MODE_PHONE = 5;
public static final int MODE_NUMBER = 6;
public final Locale mLocale;
public final int mOrientation;
public final int mMode;
public final int mXmlId;
public final int mColorScheme;
public final boolean mHasSettingsKey;
public final boolean mVoiceKeyEnabled;
public final boolean mHasVoiceKey;
public final int mImeOptions;
public final boolean mEnableShiftLock;
private final int mHashCode;
public KeyboardId(Locale locale, int orientation, int mode,
int xmlId, int colorScheme, boolean hasSettingsKey, boolean voiceKeyEnabled,
boolean hasVoiceKey, int imeOptions, boolean enableShiftLock) {
this.mLocale = locale;
this.mOrientation = orientation;
this.mMode = mode;
this.mXmlId = xmlId;
this.mColorScheme = colorScheme;
this.mHasSettingsKey = hasSettingsKey;
this.mVoiceKeyEnabled = voiceKeyEnabled;
this.mHasVoiceKey = hasVoiceKey;
// We are interested only in IME_MASK_ACTION enum value and IME_FLAG_NO_ENTER_ACTION.
this.mImeOptions = imeOptions
& (EditorInfo.IME_MASK_ACTION | EditorInfo.IME_FLAG_NO_ENTER_ACTION);
this.mEnableShiftLock = enableShiftLock;
this.mHashCode = Arrays.hashCode(new Object[] {
locale,
orientation,
mode,
xmlId,
colorScheme,
hasSettingsKey,
voiceKeyEnabled,
hasVoiceKey,
imeOptions,
enableShiftLock,
});
}
public int getXmlId() {
return mXmlId;
}
public boolean isAlphabetMode() {
return mXmlId == R.xml.kbd_qwerty;
}
@Override
public boolean equals(Object other) {
return other instanceof KeyboardId && equals((KeyboardId) other);
}
boolean equals(KeyboardId other) {
return other.mLocale.equals(this.mLocale)
&& other.mOrientation == this.mOrientation
&& other.mMode == this.mMode
&& other.mXmlId == this.mXmlId
&& other.mColorScheme == this.mColorScheme
&& other.mHasSettingsKey == this.mHasSettingsKey
&& other.mVoiceKeyEnabled == this.mVoiceKeyEnabled
&& other.mHasVoiceKey == this.mHasVoiceKey
&& other.mImeOptions == this.mImeOptions
&& other.mEnableShiftLock == this.mEnableShiftLock;
}
@Override
public int hashCode() {
return mHashCode;
}
@Override
public String toString() {
return String.format("[%s %s %5s imeOptions=0x%08x xml=0x%08x %s%s%s%s%s]",
mLocale,
(mOrientation == 1 ? "port" : "land"),
modeName(mMode),
mImeOptions,
mXmlId,
colorSchemeName(mColorScheme),
(mHasSettingsKey ? " hasSettingsKey" : ""),
(mVoiceKeyEnabled ? " voiceKeyEnabled" : ""),
(mHasVoiceKey ? " hasVoiceKey" : ""),
(mEnableShiftLock ? " enableShiftLock" : ""));
}
private static String modeName(int mode) {
switch (mode) {
case MODE_TEXT: return "text";
case MODE_URL: return "url";
case MODE_EMAIL: return "email";
case MODE_IM: return "im";
case MODE_WEB: return "web";
case MODE_PHONE: return "phone";
case MODE_NUMBER: return "number";
}
return null;
}
private static String colorSchemeName(int colorScheme) {
switch (colorScheme) {
case KeyboardView.COLOR_SCHEME_WHITE: return "white";
case KeyboardView.COLOR_SCHEME_BLACK: return "black";
}
return null;
}
}

View File

@ -14,11 +14,9 @@
* the License.
*/
package com.android.inputmethod.latin;
package com.android.inputmethod.keyboard;
import com.android.inputmethod.latin.BaseKeyboard.Key;
import com.android.inputmethod.latin.BaseKeyboard.Row;
import com.android.inputmethod.latin.KeyboardSwitcher.KeyboardId;
import com.android.inputmethod.latin.R;
import org.xmlpull.v1.XmlPullParserException;
@ -36,7 +34,7 @@ import java.util.List;
/**
* Parser for BaseKeyboard.
*
* This class parses Keyboard XML file and fill out keys in BaseKeyboard.
* This class parses Keyboard XML file and fill out keys in Keyboard.
* The Keyboard XML file looks like:
* <pre>
* &gt;!-- xml/keyboard.xml --&lt;
@ -102,8 +100,8 @@ import java.util.List;
* </pre>
*/
public class BaseKeyboardParser {
private static final String TAG = "BaseKeyboardParser";
public class KeyboardParser {
private static final String TAG = "KeyboardParser";
private static final boolean DEBUG_TAG = false;
// Keyboard XML Tags
@ -118,7 +116,7 @@ public class BaseKeyboardParser {
private static final String TAG_DEFAULT = "default";
private static final String TAG_KEY_STYLE = "key-style";
private final BaseKeyboard mKeyboard;
private final Keyboard mKeyboard;
private final Resources mResources;
private int mCurrentX = 0;
@ -128,7 +126,7 @@ public class BaseKeyboardParser {
private Row mCurrentRow = null;
private final KeyStyles mKeyStyles = new KeyStyles();
public BaseKeyboardParser(BaseKeyboard keyboard, Resources res) {
public KeyboardParser(Keyboard keyboard, Resources res) {
mKeyboard = keyboard;
mResources = res;
}
@ -160,19 +158,19 @@ public class BaseKeyboardParser {
}
private void parseKeyboardAttributes(XmlResourceParser parser) {
final BaseKeyboard keyboard = mKeyboard;
final Keyboard keyboard = mKeyboard;
final TypedArray a = mResources.obtainAttributes(Xml.asAttributeSet(parser),
R.styleable.BaseKeyboard);
R.styleable.Keyboard);
final int width = keyboard.getKeyboardWidth();
final int height = keyboard.getKeyboardHeight();
keyboard.setKeyWidth(getDimensionOrFraction(a,
R.styleable.BaseKeyboard_keyWidth, width, width / 10));
R.styleable.Keyboard_keyWidth, width, width / 10));
keyboard.setKeyHeight(getDimensionOrFraction(a,
R.styleable.BaseKeyboard_keyHeight, height, 50));
R.styleable.Keyboard_keyHeight, height, 50));
keyboard.setHorizontalGap(getDimensionOrFraction(a,
R.styleable.BaseKeyboard_horizontalGap, width, 0));
R.styleable.Keyboard_horizontalGap, width, 0));
keyboard.setVerticalGap(getDimensionOrFraction(a,
R.styleable.BaseKeyboard_verticalGap, height, 0));
R.styleable.Keyboard_verticalGap, height, 0));
a.recycle();
if (DEBUG_TAG) Log.d(TAG, "id=" + keyboard.mId);
}
@ -266,7 +264,7 @@ public class BaseKeyboardParser {
mKeyStyles);
checkEndTag(TAG_KEY, parser);
keys.add(key);
if (key.codes[0] == BaseKeyboard.KEYCODE_SHIFT)
if (key.codes[0] == Keyboard.KEYCODE_SHIFT)
mKeyboard.getShiftKeys().add(key);
endKey(key);
}
@ -278,8 +276,8 @@ public class BaseKeyboardParser {
checkEndTag(TAG_SPACER, parser);
} else {
final TypedArray a = mResources.obtainAttributes(Xml.asAttributeSet(parser),
R.styleable.BaseKeyboard);
final int gap = getDimensionOrFraction(a, R.styleable.BaseKeyboard_horizontalGap,
R.styleable.Keyboard);
final int gap = getDimensionOrFraction(a, R.styleable.Keyboard_horizontalGap,
mKeyboard.getKeyboardWidth(), 0);
a.recycle();
checkEndTag(TAG_SPACER, parser);
@ -303,9 +301,9 @@ public class BaseKeyboardParser {
checkEndTag(TAG_INCLUDE, parser);
} else {
final TypedArray a = mResources.obtainAttributes(Xml.asAttributeSet(parser),
R.styleable.BaseKeyboard_Include);
R.styleable.Keyboard_Include);
final int keyboardLayout = a.getResourceId(
R.styleable.BaseKeyboard_Include_keyboardLayout, 0);
R.styleable.Keyboard_Include_keyboardLayout, 0);
a.recycle();
checkEndTag(TAG_INCLUDE, parser);
@ -395,25 +393,25 @@ public class BaseKeyboardParser {
return true;
final TypedArray a = mResources.obtainAttributes(Xml.asAttributeSet(parser),
R.styleable.BaseKeyboard_Case);
R.styleable.Keyboard_Case);
final TypedArray viewAttr = mResources.obtainAttributes(Xml.asAttributeSet(parser),
R.styleable.BaseKeyboardView);
R.styleable.KeyboardView);
try {
final boolean modeMatched = matchInteger(a,
R.styleable.BaseKeyboard_Case_mode, id.mMode);
R.styleable.Keyboard_Case_mode, id.mMode);
final boolean settingsKeyMatched = matchBoolean(a,
R.styleable.BaseKeyboard_Case_hasSettingsKey, id.mHasSettingsKey);
R.styleable.Keyboard_Case_hasSettingsKey, id.mHasSettingsKey);
final boolean voiceEnabledMatched = matchBoolean(a,
R.styleable.BaseKeyboard_Case_voiceKeyEnabled, id.mVoiceKeyEnabled);
R.styleable.Keyboard_Case_voiceKeyEnabled, id.mVoiceKeyEnabled);
final boolean voiceKeyMatched = matchBoolean(a,
R.styleable.BaseKeyboard_Case_hasVoiceKey, id.mHasVoiceKey);
R.styleable.Keyboard_Case_hasVoiceKey, id.mHasVoiceKey);
final boolean colorSchemeMatched = matchInteger(viewAttr,
R.styleable.BaseKeyboardView_colorScheme, id.mColorScheme);
R.styleable.KeyboardView_colorScheme, id.mColorScheme);
// As noted at KeyboardSwitcher.KeyboardId class, we are interested only in
// enum value masked by IME_MASK_ACTION and IME_FLAG_NO_ENTER_ACTION. So matching
// this attribute with id.mImeOptions as integer value is enough for our purpose.
final boolean imeOptionsMatched = matchInteger(a,
R.styleable.BaseKeyboard_Case_imeOptions, id.mImeOptions);
R.styleable.Keyboard_Case_imeOptions, id.mImeOptions);
final boolean selected = modeMatched && settingsKeyMatched && voiceEnabledMatched
&& voiceKeyMatched && colorSchemeMatched && imeOptionsMatched;
@ -421,15 +419,15 @@ public class BaseKeyboardParser {
Log.d(TAG, String.format(
"parseCaseCondition: %s%s%s%s%s%s%s",
Boolean.toString(selected).toUpperCase(),
debugInteger(a, R.styleable.BaseKeyboard_Case_mode, "mode"),
debugBoolean(a, R.styleable.BaseKeyboard_Case_hasSettingsKey,
debugInteger(a, R.styleable.Keyboard_Case_mode, "mode"),
debugBoolean(a, R.styleable.Keyboard_Case_hasSettingsKey,
"hasSettingsKey"),
debugBoolean(a, R.styleable.BaseKeyboard_Case_voiceKeyEnabled,
debugBoolean(a, R.styleable.Keyboard_Case_voiceKeyEnabled,
"voiceKeyEnabled"),
debugBoolean(a, R.styleable.BaseKeyboard_Case_hasVoiceKey, "hasVoiceKey"),
debugInteger(viewAttr, R.styleable.BaseKeyboardView_colorScheme,
debugBoolean(a, R.styleable.Keyboard_Case_hasVoiceKey, "hasVoiceKey"),
debugInteger(viewAttr, R.styleable.KeyboardView_colorScheme,
"colorScheme"),
debugInteger(a, R.styleable.BaseKeyboard_Case_imeOptions, "imeOptions")));
debugInteger(a, R.styleable.Keyboard_Case_imeOptions, "imeOptions")));
}
return selected;
@ -464,11 +462,11 @@ public class BaseKeyboardParser {
private void parseKeyStyle(XmlResourceParser parser, List<Key> keys)
throws XmlPullParserException, IOException {
TypedArray a = mResources.obtainAttributes(Xml.asAttributeSet(parser),
R.styleable.BaseKeyboard_KeyStyle);
R.styleable.Keyboard_KeyStyle);
TypedArray keyAttrs = mResources.obtainAttributes(Xml.asAttributeSet(parser),
R.styleable.BaseKeyboard_Key);
R.styleable.Keyboard_Key);
try {
if (!a.hasValue(R.styleable.BaseKeyboard_KeyStyle_styleName))
if (!a.hasValue(R.styleable.Keyboard_KeyStyle_styleName))
throw new ParseException("<" + TAG_KEY_STYLE
+ "/> needs styleName attribute", parser);
if (keys != null)

View File

@ -14,9 +14,11 @@
* limitations under the License.
*/
package com.android.inputmethod.latin;
package com.android.inputmethod.keyboard;
import com.android.inputmethod.latin.BaseKeyboard.Key;
import com.android.inputmethod.latin.LatinImeLogger;
import com.android.inputmethod.latin.R;
import com.android.inputmethod.latin.SubtypeSwitcher;
import android.content.Context;
import android.content.pm.PackageManager;
@ -49,27 +51,26 @@ import android.widget.TextView;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.WeakHashMap;
/**
* A view that renders a virtual {@link LatinKeyboard}. It handles rendering of keys and
* detecting key presses and touch movements.
* A view that renders a virtual {@link Keyboard}. It handles rendering of keys and detecting key
* presses and touch movements.
*
* TODO: References to LatinKeyboard in this class should be replaced with ones to its base class.
*
* @attr ref R.styleable#BaseKeyboardView_keyBackground
* @attr ref R.styleable#BaseKeyboardView_keyPreviewLayout
* @attr ref R.styleable#BaseKeyboardView_keyPreviewOffset
* @attr ref R.styleable#BaseKeyboardView_labelTextSize
* @attr ref R.styleable#BaseKeyboardView_keyTextSize
* @attr ref R.styleable#BaseKeyboardView_keyTextColor
* @attr ref R.styleable#BaseKeyboardView_verticalCorrection
* @attr ref R.styleable#BaseKeyboardView_popupLayout
* @attr ref R.styleable#KeyboardView_keyBackground
* @attr ref R.styleable#KeyboardView_keyPreviewLayout
* @attr ref R.styleable#KeyboardView_keyPreviewOffset
* @attr ref R.styleable#KeyboardView_labelTextSize
* @attr ref R.styleable#KeyboardView_keyTextSize
* @attr ref R.styleable#KeyboardView_keyTextColor
* @attr ref R.styleable#KeyboardView_verticalCorrection
* @attr ref R.styleable#KeyboardView_popupLayout
*/
public class BaseKeyboardView extends View implements PointerTracker.UIProxy {
private static final String TAG = "BaseKeyboardView";
public class KeyboardView extends View implements PointerTracker.UIProxy {
private static final String TAG = "KeyboardView";
private static final boolean DEBUG = false;
private static final boolean DEBUG_SHOW_ALIGN = false;
private static final boolean DEBUG_KEYBOARD_GRID = false;
@ -79,93 +80,10 @@ public class BaseKeyboardView extends View implements PointerTracker.UIProxy {
public static final int NOT_A_TOUCH_COORDINATE = -1;
public interface OnKeyboardActionListener {
/**
* Called when the user presses a key. This is sent before the
* {@link #onKey} is called. For keys that repeat, this is only
* called once.
*
* @param primaryCode
* the unicode of the key being pressed. If the touch is
* not on a valid key, the value will be zero.
*/
void onPress(int primaryCode);
/**
* Called when the user releases a key. This is sent after the
* {@link #onKey} is called. For keys that repeat, this is only
* called once.
*
* @param primaryCode
* the code of the key that was released
*/
void onRelease(int primaryCode);
/**
* Send a key press to the listener.
*
* @param primaryCode
* this is the key that was pressed
* @param keyCodes
* the codes for all the possible alternative keys with
* the primary code being the first. If the primary key
* code is a single character such as an alphabet or
* number or symbol, the alternatives will include other
* characters that may be on the same key or adjacent
* keys. These codes are useful to correct for
* accidental presses of a key adjacent to the intended
* key.
* @param x
* x-coordinate pixel of touched event. If onKey is not called by onTouchEvent,
* the value should be NOT_A_TOUCH_COORDINATE.
* @param y
* y-coordinate pixel of touched event. If onKey is not called by onTouchEvent,
* the value should be NOT_A_TOUCH_COORDINATE.
*/
void onKey(int primaryCode, int[] keyCodes, int x, int y);
/**
* Sends a sequence of characters to the listener.
*
* @param text
* the sequence of characters to be displayed.
*/
void onText(CharSequence text);
/**
* Called when user released a finger outside any key.
*/
void onCancel();
/**
* Called when the user quickly moves the finger from right to
* left.
*/
void swipeLeft();
/**
* Called when the user quickly moves the finger from left to
* right.
*/
void swipeRight();
/**
* Called when the user quickly moves the finger from up to down.
*/
void swipeDown();
/**
* Called when the user quickly moves the finger from down to up.
*/
void swipeUp();
}
// Timing constants
private final int mKeyRepeatInterval;
// Miscellaneous constants
/* package */ static final int NOT_A_KEY = -1;
private static final int[] LONG_PRESSABLE_STATE_SET = { android.R.attr.state_long_pressable };
private static final int HINT_ICON_VERTICAL_ADJUSTMENT_PIXEL = -1;
@ -187,7 +105,7 @@ public class BaseKeyboardView extends View implements PointerTracker.UIProxy {
private int mPopupLayout;
// Main keyboard
private BaseKeyboard mKeyboard;
private Keyboard mKeyboard;
private Key[] mKeys;
// Key preview popup
@ -196,7 +114,7 @@ public class BaseKeyboardView extends View implements PointerTracker.UIProxy {
private PopupWindow mPreviewPopup;
private int mPreviewTextSizeLarge;
private int[] mOffsetInWindow;
private int mOldPreviewKeyIndex = NOT_A_KEY;
private int mOldPreviewKeyIndex = KeyDetector.NOT_A_KEY;
private boolean mShowPreview = true;
private boolean mShowTouchPoints = true;
private int mPopupPreviewOffsetX;
@ -208,7 +126,7 @@ public class BaseKeyboardView extends View implements PointerTracker.UIProxy {
// Popup mini keyboard
private PopupWindow mMiniKeyboardPopup;
private BaseKeyboardView mMiniKeyboard;
private KeyboardView mMiniKeyboard;
private View mMiniKeyboardParent;
private final WeakHashMap<Key, View> mMiniKeyboardCache = new WeakHashMap<Key, View>();
private int mMiniKeyboardOriginX;
@ -218,13 +136,13 @@ public class BaseKeyboardView extends View implements PointerTracker.UIProxy {
private final float mMiniKeyboardSlideAllowance;
private int mMiniKeyboardTrackerId;
/** Listener for {@link OnKeyboardActionListener}. */
private OnKeyboardActionListener mKeyboardActionListener;
/** Listener for {@link KeyboardActionListener}. */
private KeyboardActionListener mKeyboardActionListener;
private final ArrayList<PointerTracker> mPointerTrackers = new ArrayList<PointerTracker>();
// TODO: Let the PointerTracker class manage this pointer queue
private final PointerQueue mPointerQueue = new PointerQueue();
private final PointerTrackerQueue mPointerQueue = new PointerTrackerQueue();
private final boolean mHasDistinctMultitouch;
private int mOldPointerCount = 1;
@ -370,63 +288,15 @@ public class BaseKeyboardView extends View implements PointerTracker.UIProxy {
}
};
static class PointerQueue {
private LinkedList<PointerTracker> mQueue = new LinkedList<PointerTracker>();
public void add(PointerTracker tracker) {
mQueue.add(tracker);
}
public int lastIndexOf(PointerTracker tracker) {
LinkedList<PointerTracker> queue = mQueue;
for (int index = queue.size() - 1; index >= 0; index--) {
PointerTracker t = queue.get(index);
if (t == tracker)
return index;
}
return -1;
}
public void releaseAllPointersOlderThan(PointerTracker tracker, long eventTime) {
LinkedList<PointerTracker> queue = mQueue;
int oldestPos = 0;
for (PointerTracker t = queue.get(oldestPos); t != tracker; t = queue.get(oldestPos)) {
if (t.isModifier()) {
oldestPos++;
} else {
t.onUpEvent(t.getLastX(), t.getLastY(), eventTime);
t.setAlreadyProcessed();
queue.remove(oldestPos);
}
}
}
public void releaseAllPointersExcept(PointerTracker tracker, long eventTime) {
for (PointerTracker t : mQueue) {
if (t == tracker)
continue;
t.onUpEvent(t.getLastX(), t.getLastY(), eventTime);
t.setAlreadyProcessed();
}
mQueue.clear();
if (tracker != null)
mQueue.add(tracker);
}
public void remove(PointerTracker tracker) {
mQueue.remove(tracker);
}
}
public BaseKeyboardView(Context context, AttributeSet attrs) {
public KeyboardView(Context context, AttributeSet attrs) {
this(context, attrs, R.attr.keyboardViewStyle);
}
public BaseKeyboardView(Context context, AttributeSet attrs, int defStyle) {
public KeyboardView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
TypedArray a = context.obtainStyledAttributes(
attrs, R.styleable.BaseKeyboardView, defStyle, R.style.BaseKeyboardView);
attrs, R.styleable.KeyboardView, defStyle, R.style.KeyboardView);
LayoutInflater inflate =
(LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
int previewLayout = 0;
@ -438,53 +308,53 @@ public class BaseKeyboardView extends View implements PointerTracker.UIProxy {
int attr = a.getIndex(i);
switch (attr) {
case R.styleable.BaseKeyboardView_keyBackground:
case R.styleable.KeyboardView_keyBackground:
mKeyBackground = a.getDrawable(attr);
break;
case R.styleable.BaseKeyboardView_keyHysteresisDistance:
case R.styleable.KeyboardView_keyHysteresisDistance:
mKeyHysteresisDistance = a.getDimensionPixelOffset(attr, 0);
break;
case R.styleable.BaseKeyboardView_verticalCorrection:
case R.styleable.KeyboardView_verticalCorrection:
mVerticalCorrection = a.getDimensionPixelOffset(attr, 0);
break;
case R.styleable.BaseKeyboardView_keyPreviewLayout:
case R.styleable.KeyboardView_keyPreviewLayout:
previewLayout = a.getResourceId(attr, 0);
break;
case R.styleable.BaseKeyboardView_keyPreviewOffset:
case R.styleable.KeyboardView_keyPreviewOffset:
mPreviewOffset = a.getDimensionPixelOffset(attr, 0);
break;
case R.styleable.BaseKeyboardView_keyPreviewHeight:
case R.styleable.KeyboardView_keyPreviewHeight:
mPreviewHeight = a.getDimensionPixelSize(attr, 80);
break;
case R.styleable.BaseKeyboardView_keyLetterSize:
case R.styleable.KeyboardView_keyLetterSize:
mKeyLetterSize = a.getDimensionPixelSize(attr, 18);
break;
case R.styleable.BaseKeyboardView_keyTextColor:
case R.styleable.KeyboardView_keyTextColor:
mKeyTextColor = a.getColor(attr, 0xFF000000);
break;
case R.styleable.BaseKeyboardView_keyTextColorDisabled:
case R.styleable.KeyboardView_keyTextColorDisabled:
mKeyTextColorDisabled = a.getColor(attr, 0xFF000000);
break;
case R.styleable.BaseKeyboardView_labelTextSize:
case R.styleable.KeyboardView_labelTextSize:
mLabelTextSize = a.getDimensionPixelSize(attr, 14);
break;
case R.styleable.BaseKeyboardView_popupLayout:
case R.styleable.KeyboardView_popupLayout:
mPopupLayout = a.getResourceId(attr, 0);
break;
case R.styleable.BaseKeyboardView_shadowColor:
case R.styleable.KeyboardView_shadowColor:
mShadowColor = a.getColor(attr, 0);
break;
case R.styleable.BaseKeyboardView_shadowRadius:
case R.styleable.KeyboardView_shadowRadius:
mShadowRadius = a.getFloat(attr, 0f);
break;
// TODO: Use Theme (android.R.styleable.Theme_backgroundDimAmount)
case R.styleable.BaseKeyboardView_backgroundDimAmount:
case R.styleable.KeyboardView_backgroundDimAmount:
mBackgroundDimAmount = a.getFloat(attr, 0.5f);
break;
case R.styleable.BaseKeyboardView_keyLetterStyle:
case R.styleable.KeyboardView_keyLetterStyle:
mKeyLetterStyle = Typeface.defaultFromStyle(a.getInt(attr, Typeface.NORMAL));
break;
case R.styleable.BaseKeyboardView_colorScheme:
case R.styleable.KeyboardView_colorScheme:
mColorScheme = a.getInt(attr, COLOR_SCHEME_WHITE);
break;
}
@ -575,7 +445,7 @@ public class BaseKeyboardView extends View implements PointerTracker.UIProxy {
mKeyRepeatInterval = res.getInteger(R.integer.config_key_repeat_interval);
}
public void setOnKeyboardActionListener(OnKeyboardActionListener listener) {
public void setOnKeyboardActionListener(KeyboardActionListener listener) {
mKeyboardActionListener = listener;
for (PointerTracker tracker : mPointerTrackers) {
tracker.setOnKeyboardActionListener(listener);
@ -583,21 +453,21 @@ public class BaseKeyboardView extends View implements PointerTracker.UIProxy {
}
/**
* Returns the {@link OnKeyboardActionListener} object.
* Returns the {@link KeyboardActionListener} object.
* @return the listener attached to this keyboard
*/
protected OnKeyboardActionListener getOnKeyboardActionListener() {
protected KeyboardActionListener getOnKeyboardActionListener() {
return mKeyboardActionListener;
}
/**
* Attaches a keyboard to this view. The keyboard can be switched at any time and the
* view will re-layout itself to accommodate the keyboard.
* @see BaseKeyboard
* @see Keyboard
* @see #getKeyboard()
* @param keyboard the keyboard to display in this view
*/
protected void setKeyboard(BaseKeyboard keyboard) {
public void setKeyboard(Keyboard keyboard) {
if (mKeyboard != null) {
dismissKeyPreview();
}
@ -622,9 +492,9 @@ public class BaseKeyboardView extends View implements PointerTracker.UIProxy {
/**
* Returns the current keyboard being displayed by this view.
* @return the currently attached keyboard
* @see #setKeyboard(BaseKeyboard)
* @see #setKeyboard(Keyboard)
*/
protected BaseKeyboard getKeyboard() {
public Keyboard getKeyboard() {
return mKeyboard;
}
@ -632,6 +502,7 @@ public class BaseKeyboardView extends View implements PointerTracker.UIProxy {
* Return whether the device has distinct multi-touch panel.
* @return true if the device has distinct multi-touch panel.
*/
@Override
public boolean hasDistinctMultitouch() {
return mHasDistinctMultitouch;
}
@ -670,7 +541,7 @@ public class BaseKeyboardView extends View implements PointerTracker.UIProxy {
}
/**
* When enabled, calls to {@link OnKeyboardActionListener#onKey} will include key
* When enabled, calls to {@link KeyboardActionListener#onKey} will include key
* codes for adjacent keys. When disabled, only the primary key code will be
* reported.
* @param enabled whether or not the proximity correction is enabled
@ -715,7 +586,7 @@ public class BaseKeyboardView extends View implements PointerTracker.UIProxy {
* @param keyboard
* @param keys
*/
private void computeProximityThreshold(BaseKeyboard keyboard, Key[] keys) {
private void computeProximityThreshold(Keyboard keyboard, Key[] keys) {
if (keyboard == null || keys == null || keys.length == 0) return;
final HashMap<Integer, Integer> histogram = new HashMap<Integer, Integer>();
int maxCount = 0;
@ -750,6 +621,7 @@ public class BaseKeyboardView extends View implements PointerTracker.UIProxy {
canvas.drawBitmap(mBuffer, 0, 0, null);
}
@SuppressWarnings("unused")
private void onBufferDraw() {
if (mBuffer == null || mKeyboardChanged) {
if (mBuffer == null || mKeyboardChanged &&
@ -1020,22 +892,24 @@ public class BaseKeyboardView extends View implements PointerTracker.UIProxy {
private void dismissKeyPreview() {
for (PointerTracker tracker : mPointerTrackers)
tracker.releaseKey();
showPreview(NOT_A_KEY, null);
showPreview(KeyDetector.NOT_A_KEY, null);
}
@Override
public void showPreview(int keyIndex, PointerTracker tracker) {
int oldKeyIndex = mOldPreviewKeyIndex;
mOldPreviewKeyIndex = keyIndex;
// We should re-draw popup preview when 1) we need to hide the preview, 2) we will show
// the space key preview and 3) pointer moves off the space key to other letter key, we
// should hide the preview of the previous key.
@SuppressWarnings("unused")
final boolean hidePreviewOrShowSpaceKeyPreview = (tracker == null)
|| (SubtypeSwitcher.USE_SPACEBAR_LANGUAGE_SWITCHER
&& SubtypeSwitcher.getInstance().needsToDisplayLanguage()
&& (tracker.isSpaceKey(keyIndex) || tracker.isSpaceKey(oldKeyIndex)));
// If key changed and preview is on or the key is space (language switch is enabled)
if (oldKeyIndex != keyIndex && (mShowPreview || (hidePreviewOrShowSpaceKeyPreview))) {
if (keyIndex == NOT_A_KEY) {
if (keyIndex == KeyDetector.NOT_A_KEY) {
mHandler.cancelPopupPreview();
mHandler.dismissPreview(mDelayAfterPreview);
} else if (tracker != null) {
@ -1145,9 +1019,10 @@ public class BaseKeyboardView extends View implements PointerTracker.UIProxy {
* Invalidates a key so that it will be redrawn on the next repaint. Use this method if only
* one key is changing it's content. Any changes that affect the position or size of the key
* may not be honored.
* @param key key in the attached {@link BaseKeyboard}.
* @param key key in the attached {@link Keyboard}.
* @see #invalidateAllKeys
*/
@Override
public void invalidateKey(Key key) {
if (key == null)
return;
@ -1183,7 +1058,7 @@ public class BaseKeyboardView extends View implements PointerTracker.UIProxy {
private void onLongPressShiftKey(PointerTracker tracker) {
tracker.setAlreadyProcessed();
mPointerQueue.remove(tracker);
mKeyboardActionListener.onKey(LatinKeyboardView.KEYCODE_CAPSLOCK, null, 0, 0);
mKeyboardActionListener.onKey(LatinKeyboard.KEYCODE_CAPSLOCK, null, 0, 0);
}
private View inflateMiniKeyboardContainer(Key popupKey) {
@ -1194,34 +1069,43 @@ public class BaseKeyboardView extends View implements PointerTracker.UIProxy {
if (container == null)
throw new NullPointerException();
BaseKeyboardView miniKeyboard =
(BaseKeyboardView)container.findViewById(R.id.BaseKeyboardView);
miniKeyboard.setOnKeyboardActionListener(new OnKeyboardActionListener() {
KeyboardView miniKeyboard =
(KeyboardView)container.findViewById(R.id.KeyboardView);
miniKeyboard.setOnKeyboardActionListener(new KeyboardActionListener() {
@Override
public void onKey(int primaryCode, int[] keyCodes, int x, int y) {
mKeyboardActionListener.onKey(primaryCode, keyCodes, x, y);
dismissPopupKeyboard();
}
@Override
public void onText(CharSequence text) {
mKeyboardActionListener.onText(text);
dismissPopupKeyboard();
}
@Override
public void onCancel() {
dismissPopupKeyboard();
}
@Override
public void swipeLeft() {
}
@Override
public void swipeRight() {
}
@Override
public void swipeUp() {
}
@Override
public void swipeDown() {
}
@Override
public void onPress(int primaryCode) {
mKeyboardActionListener.onPress(primaryCode);
}
@Override
public void onRelease(int primaryCode) {
mKeyboardActionListener.onRelease(primaryCode);
}
@ -1231,12 +1115,12 @@ public class BaseKeyboardView extends View implements PointerTracker.UIProxy {
// Remove gesture detector on mini-keyboard
miniKeyboard.mGestureDetector = null;
BaseKeyboard keyboard;
Keyboard keyboard;
if (popupKey.popupCharacters != null) {
keyboard = new BaseKeyboard(getContext(), popupKeyboardId, popupKey.popupCharacters,
keyboard = new Keyboard(getContext(), popupKeyboardId, popupKey.popupCharacters,
-1, getPaddingLeft() + getPaddingRight());
} else {
keyboard = new BaseKeyboard(getContext(), popupKeyboardId);
keyboard = new Keyboard(getContext(), popupKeyboardId);
}
miniKeyboard.setKeyboard(keyboard);
miniKeyboard.setPopupParent(this);
@ -1256,8 +1140,8 @@ public class BaseKeyboardView extends View implements PointerTracker.UIProxy {
// and bottom edge flags on.
// When you want to use one row mini-keyboard from xml file, make sure that the row has
// both top and bottom edge flags set.
return (edgeFlags & BaseKeyboard.EDGE_TOP) != 0
&& (edgeFlags & BaseKeyboard.EDGE_BOTTOM) != 0;
return (edgeFlags & Keyboard.EDGE_TOP) != 0
&& (edgeFlags & Keyboard.EDGE_BOTTOM) != 0;
}
/**
@ -1279,7 +1163,7 @@ public class BaseKeyboardView extends View implements PointerTracker.UIProxy {
container = inflateMiniKeyboardContainer(popupKey);
mMiniKeyboardCache.put(popupKey, container);
}
mMiniKeyboard = (BaseKeyboardView)container.findViewById(R.id.BaseKeyboardView);
mMiniKeyboard = (KeyboardView)container.findViewById(R.id.KeyboardView);
if (mWindowOffset == null) {
mWindowOffset = new int[2];
getLocationInWindow(mWindowOffset);
@ -1325,7 +1209,7 @@ public class BaseKeyboardView extends View implements PointerTracker.UIProxy {
mMiniKeyboardOriginY = y + container.getPaddingTop() - mWindowOffset[1];
mMiniKeyboard.setPopupOffset(adjustedX, y);
// TODO: change the below line to use getLatinKeyboard() instead of getKeyboard()
BaseKeyboard baseMiniKeyboard = mMiniKeyboard.getKeyboard();
Keyboard baseMiniKeyboard = mMiniKeyboard.getKeyboard();
if (baseMiniKeyboard != null && baseMiniKeyboard.setShifted(mKeyboard == null
? false : mKeyboard.isShiftedOrShiftLocked())) {
mMiniKeyboard.invalidateAllKeys();
@ -1376,7 +1260,7 @@ public class BaseKeyboardView extends View implements PointerTracker.UIProxy {
private PointerTracker getPointerTracker(final int id) {
final ArrayList<PointerTracker> pointers = mPointerTrackers;
final Key[] keys = mKeys;
final OnKeyboardActionListener listener = mKeyboardActionListener;
final KeyboardActionListener listener = mKeyboardActionListener;
// Create pointer trackers until we can get 'id+1'-th tracker, if needed.
for (int i = pointers.size(); i <= id; i++) {

View File

@ -0,0 +1,90 @@
/*
* Copyright (C) 2010 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 com.android.inputmethod.keyboard;
import android.content.res.Resources;
import android.content.res.XmlResourceParser;
public class LatinKey extends Key {
// functional normal state (with properties)
private final int[] KEY_STATE_FUNCTIONAL_NORMAL = {
android.R.attr.state_single
};
// functional pressed state (with properties)
private final int[] KEY_STATE_FUNCTIONAL_PRESSED = {
android.R.attr.state_single,
android.R.attr.state_pressed
};
private boolean mShiftLockEnabled;
public LatinKey(Resources res, Row parent, int x, int y,
XmlResourceParser parser, KeyStyles keyStyles) {
super(res, parent, x, y, parser, keyStyles);
if (popupCharacters != null && popupCharacters.length() == 0) {
// If there is a keyboard with no keys specified in popupCharacters
popupResId = 0;
}
}
void enableShiftLock() {
mShiftLockEnabled = true;
}
// sticky is used for shift key. If a key is not sticky and is modifier,
// the key will be treated as functional.
private boolean isFunctionalKey() {
return !sticky && modifier;
}
@Override
public void onReleased(boolean inside) {
if (!mShiftLockEnabled) {
super.onReleased(inside);
} else {
pressed = !pressed;
}
}
/**
* Overriding this method so that we can reduce the target area for certain keys.
*/
@Override
public boolean isInside(int x, int y) {
boolean result = (keyboard instanceof LatinKeyboard)
&& ((LatinKeyboard)keyboard).isInside(this, x, y);
return result;
}
boolean isInsideSuper(int x, int y) {
return super.isInside(x, y);
}
@Override
public int[] getCurrentDrawableState() {
if (isFunctionalKey()) {
if (pressed) {
return KEY_STATE_FUNCTIONAL_PRESSED;
} else {
return KEY_STATE_FUNCTIONAL_NORMAL;
}
}
return super.getCurrentDrawableState();
}
}

View File

@ -14,7 +14,11 @@
* the License.
*/
package com.android.inputmethod.latin;
package com.android.inputmethod.keyboard;
import com.android.inputmethod.latin.LatinIME;
import com.android.inputmethod.latin.R;
import com.android.inputmethod.latin.SubtypeSwitcher;
import android.content.Context;
import android.content.res.Resources;
@ -22,28 +26,33 @@ import android.content.res.TypedArray;
import android.content.res.XmlResourceParser;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.ColorFilter;
import android.graphics.Paint;
import android.graphics.Paint.Align;
import android.graphics.PixelFormat;
import android.graphics.PorterDuff;
import android.graphics.Rect;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.text.TextPaint;
import android.util.Log;
import android.view.ViewConfiguration;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
public class LatinKeyboard extends BaseKeyboard {
public class LatinKeyboard extends Keyboard {
private static final boolean DEBUG_PREFERRED_LETTER = false;
private static final String TAG = "LatinKeyboard";
private static final int OPACITY_FULLY_OPAQUE = 255;
public static final int KEYCODE_OPTIONS = -100;
public static final int KEYCODE_OPTIONS_LONGPRESS = -101;
// TODO: remove this once LatinIME stops referring to this.
public static final int KEYCODE_VOICE = -102;
public static final int KEYCODE_NEXT_LANGUAGE = -104;
public static final int KEYCODE_PREV_LANGUAGE = -105;
public static final int KEYCODE_CAPSLOCK = -106;
static final int OPACITY_FULLY_OPAQUE = 255;
private static final int SPACE_LED_LENGTH_PERCENT = 80;
private Drawable mShiftLockPreviewIcon;
@ -76,22 +85,22 @@ public class LatinKeyboard extends BaseKeyboard {
// Minimum width of space key preview (proportional to keyboard width)
private static final float SPACEBAR_POPUP_MIN_RATIO = 0.4f;
// Height in space key the language name will be drawn. (proportional to space key height)
private static final float SPACEBAR_LANGUAGE_BASELINE = 0.6f;
public static final float SPACEBAR_LANGUAGE_BASELINE = 0.6f;
// If the full language name needs to be smaller than this value to be drawn on space key,
// its short language name will be used instead.
private static final float MINIMUM_SCALE_OF_LANGUAGE_NAME = 0.8f;
private static int sSpacebarVerticalCorrection;
public LatinKeyboard(Context context, KeyboardSwitcher.KeyboardId id) {
public LatinKeyboard(Context context, KeyboardId id) {
super(context, id);
final Resources res = context.getResources();
mContext = context;
mRes = res;
if (id.mColorScheme == BaseKeyboardView.COLOR_SCHEME_BLACK) {
if (id.mColorScheme == KeyboardView.COLOR_SCHEME_BLACK) {
mSpaceBarTextShadowColor = res.getColor(
R.color.latinkeyboard_bar_language_shadow_black);
} else { // default color scheme is BaseKeyboardView.COLOR_SCHEME_WHITE
} else { // default color scheme is KeyboardView.COLOR_SCHEME_WHITE
mSpaceBarTextShadowColor = res.getColor(
R.color.latinkeyboard_bar_language_shadow_white);
}
@ -181,7 +190,7 @@ public class LatinKeyboard extends BaseKeyboard {
return isAlphaKeyboard() && mShiftState.isManualTemporaryUpperCase();
}
/* package */ LatinKeyboardShiftState getKeyboardShiftState() {
public LatinKeyboardShiftState getKeyboardShiftState() {
return mShiftState;
}
@ -190,11 +199,11 @@ public class LatinKeyboard extends BaseKeyboard {
}
public boolean isPhoneKeyboard() {
return mId.mMode == KeyboardSwitcher.MODE_PHONE;
return mId.mMode == KeyboardId.MODE_PHONE;
}
public boolean isNumberKeyboard() {
return mId.mMode == KeyboardSwitcher.MODE_NUMBER;
return mId.mMode == KeyboardId.MODE_NUMBER;
}
/**
@ -272,6 +281,7 @@ public class LatinKeyboard extends BaseKeyboard {
return language;
}
@SuppressWarnings("unused")
private Bitmap drawSpaceBar(int opacity, boolean isAutoCompletion) {
final int width = mSpaceKey.width;
final int height = mSpaceIcon.getIntrinsicHeight();
@ -334,7 +344,8 @@ public class LatinKeyboard extends BaseKeyboard {
final int width = Math.max(mSpaceKey.width,
(int)(getMinWidth() * SPACEBAR_POPUP_MIN_RATIO));
final int height = mSpacePreviewIcon.getIntrinsicHeight();
mSlidingLocaleIcon = new SlidingLocaleDrawable(mSpacePreviewIcon, width, height);
mSlidingLocaleIcon =
new SlidingLocaleDrawable(mContext, mSpacePreviewIcon, width, height);
mSlidingLocaleIcon.setBounds(0, 0, width, height);
mSpaceKey.iconPreview = mSlidingLocaleIcon;
}
@ -380,6 +391,7 @@ public class LatinKeyboard extends BaseKeyboard {
* Does the magic of locking the touch gesture into the spacebar when
* switching input languages.
*/
@SuppressWarnings("unused")
public boolean isInside(LatinKey key, int x, int y) {
final int code = key.codes[0];
if (code == KEYCODE_SHIFT || code == KEYCODE_DELETE) {
@ -528,193 +540,4 @@ public class LatinKeyboard extends BaseKeyboard {
int textSize = array.getDimensionPixelSize(array.getResourceId(0, 0), defValue);
return textSize;
}
public static class LatinKey extends BaseKeyboard.Key {
// functional normal state (with properties)
private final int[] KEY_STATE_FUNCTIONAL_NORMAL = {
android.R.attr.state_single
};
// functional pressed state (with properties)
private final int[] KEY_STATE_FUNCTIONAL_PRESSED = {
android.R.attr.state_single,
android.R.attr.state_pressed
};
private boolean mShiftLockEnabled;
public LatinKey(Resources res, BaseKeyboard.Row parent, int x, int y,
XmlResourceParser parser, KeyStyles keyStyles) {
super(res, parent, x, y, parser, keyStyles);
if (popupCharacters != null && popupCharacters.length() == 0) {
// If there is a keyboard with no keys specified in popupCharacters
popupResId = 0;
}
}
private void enableShiftLock() {
mShiftLockEnabled = true;
}
// sticky is used for shift key. If a key is not sticky and is modifier,
// the key will be treated as functional.
private boolean isFunctionalKey() {
return !sticky && modifier;
}
@Override
public void onReleased(boolean inside) {
if (!mShiftLockEnabled) {
super.onReleased(inside);
} else {
pressed = !pressed;
}
}
/**
* Overriding this method so that we can reduce the target area for certain keys.
*/
@Override
public boolean isInside(int x, int y) {
boolean result = (keyboard instanceof LatinKeyboard)
&& ((LatinKeyboard)keyboard).isInside(this, x, y);
return result;
}
private boolean isInsideSuper(int x, int y) {
return super.isInside(x, y);
}
@Override
public int[] getCurrentDrawableState() {
if (isFunctionalKey()) {
if (pressed) {
return KEY_STATE_FUNCTIONAL_PRESSED;
} else {
return KEY_STATE_FUNCTIONAL_NORMAL;
}
}
return super.getCurrentDrawableState();
}
}
/**
* Animation to be displayed on the spacebar preview popup when switching
* languages by swiping the spacebar. It draws the current, previous and
* next languages and moves them by the delta of touch movement on the spacebar.
*/
private class SlidingLocaleDrawable extends Drawable {
private final int mWidth;
private final int mHeight;
private final Drawable mBackground;
private final TextPaint mTextPaint;
private final int mMiddleX;
private final Drawable mLeftDrawable;
private final Drawable mRightDrawable;
private final int mThreshold;
private int mDiff;
private boolean mHitThreshold;
private String mCurrentLanguage;
private String mNextLanguage;
private String mPrevLanguage;
public SlidingLocaleDrawable(Drawable background, int width, int height) {
mBackground = background;
setDefaultBounds(mBackground);
mWidth = width;
mHeight = height;
final TextPaint textPaint = new TextPaint();
textPaint.setTextSize(getTextSizeFromTheme(android.R.style.TextAppearance_Medium, 18));
textPaint.setColor(R.color.latinkeyboard_transparent);
textPaint.setTextAlign(Align.CENTER);
textPaint.setAlpha(OPACITY_FULLY_OPAQUE);
textPaint.setAntiAlias(true);
mTextPaint = textPaint;
mMiddleX = (mWidth - mBackground.getIntrinsicWidth()) / 2;
final Resources res = mRes;
mLeftDrawable = res.getDrawable(
R.drawable.sym_keyboard_feedback_language_arrows_left);
mRightDrawable = res.getDrawable(
R.drawable.sym_keyboard_feedback_language_arrows_right);
mThreshold = ViewConfiguration.get(mContext).getScaledTouchSlop();
}
private void setDiff(int diff) {
if (diff == Integer.MAX_VALUE) {
mHitThreshold = false;
mCurrentLanguage = null;
return;
}
mDiff = diff;
if (mDiff > mWidth) mDiff = mWidth;
if (mDiff < -mWidth) mDiff = -mWidth;
if (Math.abs(mDiff) > mThreshold) mHitThreshold = true;
invalidateSelf();
}
@Override
public void draw(Canvas canvas) {
canvas.save();
if (mHitThreshold) {
Paint paint = mTextPaint;
final int width = mWidth;
final int height = mHeight;
final int diff = mDiff;
final Drawable lArrow = mLeftDrawable;
final Drawable rArrow = mRightDrawable;
canvas.clipRect(0, 0, width, height);
if (mCurrentLanguage == null) {
SubtypeSwitcher subtypeSwitcher = SubtypeSwitcher.getInstance();
mCurrentLanguage = subtypeSwitcher.getInputLanguageName();
mNextLanguage = subtypeSwitcher.getNextInputLanguageName();
mPrevLanguage = subtypeSwitcher.getPreviousInputLanguageName();
}
// Draw language text with shadow
final float baseline = mHeight * SPACEBAR_LANGUAGE_BASELINE - paint.descent();
paint.setColor(mRes.getColor(R.color.latinkeyboard_feedback_language_text));
canvas.drawText(mCurrentLanguage, width / 2 + diff, baseline, paint);
canvas.drawText(mNextLanguage, diff - width / 2, baseline, paint);
canvas.drawText(mPrevLanguage, diff + width + width / 2, baseline, paint);
setDefaultBounds(lArrow);
rArrow.setBounds(width - rArrow.getIntrinsicWidth(), 0, width,
rArrow.getIntrinsicHeight());
lArrow.draw(canvas);
rArrow.draw(canvas);
}
if (mBackground != null) {
canvas.translate(mMiddleX, 0);
mBackground.draw(canvas);
}
canvas.restore();
}
@Override
public int getOpacity() {
return PixelFormat.TRANSLUCENT;
}
@Override
public void setAlpha(int alpha) {
// Ignore
}
@Override
public void setColorFilter(ColorFilter cf) {
// Ignore
}
@Override
public int getIntrinsicWidth() {
return mWidth;
}
@Override
public int getIntrinsicHeight() {
return mHeight;
}
}
}

View File

@ -1,4 +1,22 @@
package com.android.inputmethod.latin;
/*
* Copyright (C) 2010 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 com.android.inputmethod.keyboard;
import com.android.inputmethod.latin.KeyboardSwitcher;
import android.util.Log;

View File

@ -14,9 +14,9 @@
* the License.
*/
package com.android.inputmethod.latin;
package com.android.inputmethod.keyboard;
import com.android.inputmethod.latin.BaseKeyboard.Key;
import com.android.inputmethod.latin.LatinIMEUtil;
import com.android.inputmethod.voice.VoiceIMEConnector;
import android.content.Context;
@ -31,15 +31,7 @@ import android.view.MotionEvent;
import java.util.List;
public class LatinKeyboardView extends BaseKeyboardView {
public static final int KEYCODE_OPTIONS = -100;
public static final int KEYCODE_OPTIONS_LONGPRESS = -101;
// TODO: remove this once LatinIME stops referring to this.
public static final int KEYCODE_VOICE = -102;
public static final int KEYCODE_NEXT_LANGUAGE = -104;
public static final int KEYCODE_PREV_LANGUAGE = -105;
public static final int KEYCODE_CAPSLOCK = -106;
public class LatinKeyboardView extends KeyboardView {
/** Whether we've started dropping move events because we found a big jump */
private boolean mDroppingEvents;
@ -84,7 +76,7 @@ public class LatinKeyboardView extends BaseKeyboardView {
}
public LatinKeyboard getLatinKeyboard() {
BaseKeyboard keyboard = getKeyboard();
Keyboard keyboard = getKeyboard();
if (keyboard instanceof LatinKeyboard) {
return (LatinKeyboard)keyboard;
} else {
@ -95,8 +87,8 @@ public class LatinKeyboardView extends BaseKeyboardView {
@Override
protected boolean onLongPress(Key key) {
int primaryCode = key.codes[0];
if (primaryCode == KEYCODE_OPTIONS) {
return invokeOnKey(KEYCODE_OPTIONS_LONGPRESS);
if (primaryCode == LatinKeyboard.KEYCODE_OPTIONS) {
return invokeOnKey(LatinKeyboard.KEYCODE_OPTIONS_LONGPRESS);
} else if (primaryCode == '0' && getLatinKeyboard().isPhoneKeyboard()) {
// Long pressing on 0 in phone number keypad gives you a '+'.
return invokeOnKey('+');
@ -107,8 +99,8 @@ public class LatinKeyboardView extends BaseKeyboardView {
private boolean invokeOnKey(int primaryCode) {
getOnKeyboardActionListener().onKey(primaryCode, null,
BaseKeyboardView.NOT_A_TOUCH_COORDINATE,
BaseKeyboardView.NOT_A_TOUCH_COORDINATE);
KeyboardView.NOT_A_TOUCH_COORDINATE,
KeyboardView.NOT_A_TOUCH_COORDINATE);
return true;
}
@ -223,7 +215,8 @@ public class LatinKeyboardView extends BaseKeyboardView {
int languageDirection = keyboard.getLanguageChangeDirection();
if (languageDirection != 0) {
getOnKeyboardActionListener().onKey(
languageDirection == 1 ? KEYCODE_NEXT_LANGUAGE : KEYCODE_PREV_LANGUAGE,
languageDirection == 1
? LatinKeyboard.KEYCODE_NEXT_LANGUAGE : LatinKeyboard.KEYCODE_PREV_LANGUAGE,
null, mLastX, mLastY);
me.setAction(MotionEvent.ACTION_CANCEL);
keyboard.keyReleased();
@ -236,8 +229,8 @@ public class LatinKeyboardView extends BaseKeyboardView {
/**************************** INSTRUMENTATION *******************************/
static final boolean DEBUG_AUTO_PLAY = false;
static final boolean DEBUG_LINE = false;
public static final boolean DEBUG_AUTO_PLAY = false;
public static final boolean DEBUG_LINE = false;
private static final int MSG_TOUCH_DOWN = 1;
private static final int MSG_TOUCH_UP = 2;

View File

@ -14,11 +14,9 @@
* the License.
*/
package com.android.inputmethod.latin;
package com.android.inputmethod.keyboard;
import com.android.inputmethod.latin.BaseKeyboard.Key;
class MiniKeyboardKeyDetector extends KeyDetector {
public class MiniKeyboardKeyDetector extends KeyDetector {
private static final int MAX_NEARBY_KEYS = 1;
private final int mSlideAllowanceSquare;
@ -42,7 +40,7 @@ class MiniKeyboardKeyDetector extends KeyDetector {
final int touchX = getTouchX(x);
final int touchY = getTouchY(y);
int closestKeyIndex = BaseKeyboardView.NOT_A_KEY;
int closestKeyIndex = NOT_A_KEY;
int closestKeyDist = (y < 0) ? mSlideAllowanceSquareTop : mSlideAllowanceSquare;
final int keyCount = keys.length;
for (int index = 0; index < keyCount; index++) {
@ -53,7 +51,7 @@ class MiniKeyboardKeyDetector extends KeyDetector {
}
}
if (allKeys != null && closestKeyIndex != BaseKeyboardView.NOT_A_KEY)
if (allKeys != null && closestKeyIndex != NOT_A_KEY)
allKeys[0] = keys[closestKeyIndex].codes[0];
return closestKeyIndex;
}

View File

@ -14,11 +14,11 @@
* the License.
*/
package com.android.inputmethod.latin;
package com.android.inputmethod.keyboard;
import com.android.inputmethod.latin.BaseKeyboard.Key;
import com.android.inputmethod.latin.BaseKeyboardView.OnKeyboardActionListener;
import com.android.inputmethod.latin.BaseKeyboardView.UIHandler;
import com.android.inputmethod.keyboard.KeyboardView.UIHandler;
import com.android.inputmethod.latin.LatinIME;
import com.android.inputmethod.latin.R;
import android.content.res.Resources;
import android.util.Log;
@ -44,16 +44,16 @@ public class PointerTracker {
private final int mMultiTapKeyTimeout;
// Miscellaneous constants
private static final int NOT_A_KEY = BaseKeyboardView.NOT_A_KEY;
private static final int[] KEY_DELETE = { BaseKeyboard.KEYCODE_DELETE };
private static final int NOT_A_KEY = KeyDetector.NOT_A_KEY;
private static final int[] KEY_DELETE = { Keyboard.KEYCODE_DELETE };
private final UIProxy mProxy;
private final UIHandler mHandler;
private final KeyDetector mKeyDetector;
private OnKeyboardActionListener mListener;
private KeyboardActionListener mListener;
private final boolean mHasDistinctMultitouch;
private BaseKeyboard mKeyboard;
private Keyboard mKeyboard;
private Key[] mKeys;
private int mKeyHysteresisDistanceSquared = -1;
@ -181,11 +181,11 @@ public class PointerTracker {
resetMultiTap();
}
public void setOnKeyboardActionListener(OnKeyboardActionListener listener) {
public void setOnKeyboardActionListener(KeyboardActionListener listener) {
mListener = listener;
}
public void setKeyboard(BaseKeyboard keyboard, Key[] keys, float keyHysteresisDistance) {
public void setKeyboard(Keyboard keyboard, Key[] keys, float keyHysteresisDistance) {
if (keyboard == null || keys == null || keyHysteresisDistance < 0)
throw new IllegalArgumentException();
mKeyboard = keyboard;
@ -208,8 +208,8 @@ public class PointerTracker {
if (key == null)
return false;
int primaryCode = key.codes[0];
return primaryCode == BaseKeyboard.KEYCODE_SHIFT
|| primaryCode == BaseKeyboard.KEYCODE_MODE_CHANGE;
return primaryCode == Keyboard.KEYCODE_SHIFT
|| primaryCode == Keyboard.KEYCODE_MODE_CHANGE;
}
public boolean isModifier() {
@ -420,7 +420,7 @@ public class PointerTracker {
private void startLongPressTimer(int keyIndex) {
Key key = getKey(keyIndex);
if (key.codes[0] == BaseKeyboard.KEYCODE_SHIFT) {
if (key.codes[0] == Keyboard.KEYCODE_SHIFT) {
mHandler.startLongPressShiftTimer(mLongPressShiftKeyTimeout, keyIndex, this);
} else {
mHandler.startLongPressTimer(mLongPressKeyTimeout, keyIndex, this);
@ -433,7 +433,7 @@ public class PointerTracker {
}
private void detectAndSendKey(int index, int x, int y, long eventTime) {
final OnKeyboardActionListener listener = mListener;
final KeyboardActionListener listener = mListener;
final Key key = getKey(index);
if (key == null) {
@ -453,7 +453,7 @@ public class PointerTracker {
// Multi-tap
if (mInMultiTap) {
if (mTapCount != -1) {
mListener.onKey(BaseKeyboard.KEYCODE_DELETE, KEY_DELETE, x, y);
mListener.onKey(Keyboard.KEYCODE_DELETE, KEY_DELETE, x, y);
} else {
mTapCount = 0;
}

View File

@ -0,0 +1,67 @@
/*
* Copyright (C) 2010 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 com.android.inputmethod.keyboard;
import java.util.LinkedList;
public class PointerTrackerQueue {
private LinkedList<PointerTracker> mQueue = new LinkedList<PointerTracker>();
public void add(PointerTracker tracker) {
mQueue.add(tracker);
}
public int lastIndexOf(PointerTracker tracker) {
LinkedList<PointerTracker> queue = mQueue;
for (int index = queue.size() - 1; index >= 0; index--) {
PointerTracker t = queue.get(index);
if (t == tracker)
return index;
}
return -1;
}
public void releaseAllPointersOlderThan(PointerTracker tracker, long eventTime) {
LinkedList<PointerTracker> queue = mQueue;
int oldestPos = 0;
for (PointerTracker t = queue.get(oldestPos); t != tracker; t = queue.get(oldestPos)) {
if (t.isModifier()) {
oldestPos++;
} else {
t.onUpEvent(t.getLastX(), t.getLastY(), eventTime);
t.setAlreadyProcessed();
queue.remove(oldestPos);
}
}
}
public void releaseAllPointersExcept(PointerTracker tracker, long eventTime) {
for (PointerTracker t : mQueue) {
if (t == tracker)
continue;
t.onUpEvent(t.getLastX(), t.getLastY(), eventTime);
t.setAlreadyProcessed();
}
mQueue.clear();
if (tracker != null)
mQueue.add(tracker);
}
public void remove(PointerTracker tracker) {
mQueue.remove(tracker);
}
}

View File

@ -14,13 +14,11 @@
* the License.
*/
package com.android.inputmethod.latin;
import com.android.inputmethod.latin.BaseKeyboard.Key;
package com.android.inputmethod.keyboard;
import java.util.Arrays;
class ProximityKeyDetector extends KeyDetector {
public class ProximityKeyDetector extends KeyDetector {
private static final int MAX_NEARBY_KEYS = 12;
// working area
@ -37,8 +35,8 @@ class ProximityKeyDetector extends KeyDetector {
final int touchX = getTouchX(x);
final int touchY = getTouchY(y);
int primaryIndex = BaseKeyboardView.NOT_A_KEY;
int closestKeyIndex = BaseKeyboardView.NOT_A_KEY;
int primaryIndex = NOT_A_KEY;
int closestKeyIndex = NOT_A_KEY;
int closestKeyDist = mProximityThresholdSquare + 1;
final int[] distances = mDistances;
Arrays.fill(distances, Integer.MAX_VALUE);
@ -72,6 +70,6 @@ class ProximityKeyDetector extends KeyDetector {
}
}
return primaryIndex == BaseKeyboardView.NOT_A_KEY ? closestKeyIndex : primaryIndex;
return primaryIndex == NOT_A_KEY ? closestKeyIndex : primaryIndex;
}
}

View File

@ -0,0 +1,73 @@
/*
* Copyright (C) 2010 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 com.android.inputmethod.keyboard;
import com.android.inputmethod.latin.R;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.content.res.XmlResourceParser;
import android.util.Xml;
/**
* 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.
*/
public 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;
final Keyboard parent;
Row(Keyboard parent) {
this.parent = parent;
}
public Row(Resources res, Keyboard parent, XmlResourceParser parser) {
this.parent = parent;
TypedArray a = res.obtainAttributes(Xml.asAttributeSet(parser),
R.styleable.Keyboard);
defaultWidth = KeyboardParser.getDimensionOrFraction(a,
R.styleable.Keyboard_keyWidth,
parent.mDisplayWidth, parent.mDefaultWidth);
defaultHeight = KeyboardParser.getDimensionOrFraction(a,
R.styleable.Keyboard_keyHeight,
parent.mDisplayHeight, parent.mDefaultHeight);
defaultHorizontalGap = KeyboardParser.getDimensionOrFraction(a,
R.styleable.Keyboard_horizontalGap,
parent.mDisplayWidth, parent.mDefaultHorizontalGap);
verticalGap = KeyboardParser.getDimensionOrFraction(a,
R.styleable.Keyboard_verticalGap,
parent.mDisplayHeight, parent.mDefaultVerticalGap);
a.recycle();
a = res.obtainAttributes(Xml.asAttributeSet(parser),
R.styleable.Keyboard_Row);
rowEdgeFlags = a.getInt(R.styleable.Keyboard_Row_rowEdgeFlags, 0);
}
}

View File

@ -0,0 +1,163 @@
/*
* Copyright (C) 2010 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 com.android.inputmethod.keyboard;
import com.android.inputmethod.latin.R;
import com.android.inputmethod.latin.SubtypeSwitcher;
import android.content.Context;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.ColorFilter;
import android.graphics.Paint;
import android.graphics.PixelFormat;
import android.graphics.Paint.Align;
import android.graphics.drawable.Drawable;
import android.text.TextPaint;
import android.view.ViewConfiguration;
/**
* Animation to be displayed on the spacebar preview popup when switching languages by swiping the
* spacebar. It draws the current, previous and next languages and moves them by the delta of touch
* movement on the spacebar.
*/
public class SlidingLocaleDrawable extends Drawable {
private final Context mContext;
private final Resources mRes;
private final int mWidth;
private final int mHeight;
private final Drawable mBackground;
private final TextPaint mTextPaint;
private final int mMiddleX;
private final Drawable mLeftDrawable;
private final Drawable mRightDrawable;
private final int mThreshold;
private int mDiff;
private boolean mHitThreshold;
private String mCurrentLanguage;
private String mNextLanguage;
private String mPrevLanguage;
public SlidingLocaleDrawable(Context context, Drawable background, int width, int height) {
mContext = context;
mRes = context.getResources();
mBackground = background;
LatinKeyboard.setDefaultBounds(mBackground);
mWidth = width;
mHeight = height;
final TextPaint textPaint = new TextPaint();
textPaint.setTextSize(getTextSizeFromTheme(android.R.style.TextAppearance_Medium, 18));
textPaint.setColor(R.color.latinkeyboard_transparent);
textPaint.setTextAlign(Align.CENTER);
textPaint.setAlpha(LatinKeyboard.OPACITY_FULLY_OPAQUE);
textPaint.setAntiAlias(true);
mTextPaint = textPaint;
mMiddleX = (mWidth - mBackground.getIntrinsicWidth()) / 2;
final Resources res = mRes;
mLeftDrawable = res.getDrawable(
R.drawable.sym_keyboard_feedback_language_arrows_left);
mRightDrawable = res.getDrawable(
R.drawable.sym_keyboard_feedback_language_arrows_right);
mThreshold = ViewConfiguration.get(mContext).getScaledTouchSlop();
}
private int getTextSizeFromTheme(int style, int defValue) {
TypedArray array = mContext.getTheme().obtainStyledAttributes(
style, new int[] { android.R.attr.textSize });
int textSize = array.getDimensionPixelSize(array.getResourceId(0, 0), defValue);
return textSize;
}
void setDiff(int diff) {
if (diff == Integer.MAX_VALUE) {
mHitThreshold = false;
mCurrentLanguage = null;
return;
}
mDiff = diff;
if (mDiff > mWidth) mDiff = mWidth;
if (mDiff < -mWidth) mDiff = -mWidth;
if (Math.abs(mDiff) > mThreshold) mHitThreshold = true;
invalidateSelf();
}
@Override
public void draw(Canvas canvas) {
canvas.save();
if (mHitThreshold) {
Paint paint = mTextPaint;
final int width = mWidth;
final int height = mHeight;
final int diff = mDiff;
final Drawable lArrow = mLeftDrawable;
final Drawable rArrow = mRightDrawable;
canvas.clipRect(0, 0, width, height);
if (mCurrentLanguage == null) {
SubtypeSwitcher subtypeSwitcher = SubtypeSwitcher.getInstance();
mCurrentLanguage = subtypeSwitcher.getInputLanguageName();
mNextLanguage = subtypeSwitcher.getNextInputLanguageName();
mPrevLanguage = subtypeSwitcher.getPreviousInputLanguageName();
}
// Draw language text with shadow
final float baseline = mHeight * LatinKeyboard.SPACEBAR_LANGUAGE_BASELINE
- paint.descent();
paint.setColor(mRes.getColor(R.color.latinkeyboard_feedback_language_text));
canvas.drawText(mCurrentLanguage, width / 2 + diff, baseline, paint);
canvas.drawText(mNextLanguage, diff - width / 2, baseline, paint);
canvas.drawText(mPrevLanguage, diff + width + width / 2, baseline, paint);
LatinKeyboard.setDefaultBounds(lArrow);
rArrow.setBounds(width - rArrow.getIntrinsicWidth(), 0, width,
rArrow.getIntrinsicHeight());
lArrow.draw(canvas);
rArrow.draw(canvas);
}
if (mBackground != null) {
canvas.translate(mMiddleX, 0);
mBackground.draw(canvas);
}
canvas.restore();
}
@Override
public int getOpacity() {
return PixelFormat.TRANSLUCENT;
}
@Override
public void setAlpha(int alpha) {
// Ignore
}
@Override
public void setColorFilter(ColorFilter cf) {
// Ignore
}
@Override
public int getIntrinsicWidth() {
return mWidth;
}
@Override
public int getIntrinsicHeight() {
return mHeight;
}
}

View File

@ -14,11 +14,11 @@
* the License.
*/
package com.android.inputmethod.latin;
package com.android.inputmethod.keyboard;
import android.view.MotionEvent;
class SwipeTracker {
public class SwipeTracker {
private static final int NUM_PAST = 4;
private static final int LONGEST_PAST_TIME = 200;
@ -91,7 +91,7 @@ class SwipeTracker {
return mYVelocity;
}
static class EventRingBuffer {
public static class EventRingBuffer {
private final int bufSize;
private final float xBuf[];
private final float yBuf[];

View File

@ -1,717 +0,0 @@
/*
* Copyright (C) 2010 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 com.android.inputmethod.latin;
import com.android.inputmethod.latin.BaseKeyboardParser.ParseException;
import com.android.inputmethod.latin.KeyStyles.KeyStyle;
import com.android.inputmethod.latin.KeyboardSwitcher.KeyboardId;
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.Xml;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* 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
* latin:keyWidth="%10p"
* latin:keyHeight="50px"
* latin:horizontalGap="2px"
* latin:verticalGap="2px" &gt;
* &lt;Row latin:keyWidth="32px" &gt;
* &lt;Key latin:keyLabel="A" /&gt;
* ...
* &lt;/Row&gt;
* ...
* &lt;/Keyboard&gt;
* </pre>
*/
public class BaseKeyboard {
static final String TAG = "BaseKeyboard";
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;
/** 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;
/** List of shift keys in this keyboard */
private final List<Key> mShiftKeys = new ArrayList<Key>();
/** List of shift keys and its shifted state icon */
private final HashMap<Key, Drawable> mShiftedIcons = new HashMap<Key, Drawable>();
/** 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 final List<Key> mKeys = new ArrayList<Key>();
/** Width of the screen available to fit the keyboard */
private final int mDisplayWidth;
/** Height of the screen */
private final int mDisplayHeight;
protected final KeyboardId mId;
// Variables for pre-computing nearest keys.
public final int GRID_WIDTH;
public final int GRID_HEIGHT;
private final int GRID_SIZE;
private int mCellWidth;
private int mCellHeight;
private int[][] mGridNeighbors;
private int mProximityThreshold;
private static int[] EMPTY_INT_ARRAY = new int[0];
/** Number of key widths from current touch point to search for nearest keys. */
private static float SEARCH_DISTANCE = 1.2f;
/**
* 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 BaseKeyboard}
* defines.
*/
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 BaseKeyboard#EDGE_TOP EDGE_TOP} and {@link BaseKeyboard#EDGE_BOTTOM EDGE_BOTTOM}
*/
public int rowEdgeFlags;
private final BaseKeyboard parent;
private Row(BaseKeyboard parent) {
this.parent = parent;
}
public Row(Resources res, BaseKeyboard parent, XmlResourceParser parser) {
this.parent = parent;
TypedArray a = res.obtainAttributes(Xml.asAttributeSet(parser),
R.styleable.BaseKeyboard);
defaultWidth = BaseKeyboardParser.getDimensionOrFraction(a,
R.styleable.BaseKeyboard_keyWidth,
parent.mDisplayWidth, parent.mDefaultWidth);
defaultHeight = BaseKeyboardParser.getDimensionOrFraction(a,
R.styleable.BaseKeyboard_keyHeight,
parent.mDisplayHeight, parent.mDefaultHeight);
defaultHorizontalGap = BaseKeyboardParser.getDimensionOrFraction(a,
R.styleable.BaseKeyboard_horizontalGap,
parent.mDisplayWidth, parent.mDefaultHorizontalGap);
verticalGap = BaseKeyboardParser.getDimensionOrFraction(a,
R.styleable.BaseKeyboard_verticalGap,
parent.mDisplayHeight, parent.mDefaultVerticalGap);
a.recycle();
a = res.obtainAttributes(Xml.asAttributeSet(parser),
R.styleable.BaseKeyboard_Row);
rowEdgeFlags = a.getInt(R.styleable.BaseKeyboard_Row_rowEdgeFlags, 0);
}
}
/**
* Class for describing the position and characteristics of a single key in the keyboard.
*/
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;
/** The unicode that this key generates in manual temporary upper case mode. */
public int manualTemporaryUpperCaseCode;
/** Label to display */
public CharSequence label;
/** Option of the label */
public int labelOption;
/** Icon to display instead of a label. Icon takes precedence over a label */
public Drawable icon;
/** Hint icon to display on the key in conjunction with the label */
public Drawable hintIcon;
/** Preview version of the icon, for the preview popup */
/**
* The hint icon to display on the key when keyboard is in manual temporary upper case
* mode.
*/
public Drawable manualTemporaryUpperCaseHintIcon;
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 BaseKeyboard#EDGE_LEFT}, {@link BaseKeyboard#EDGE_RIGHT},
* {@link BaseKeyboard#EDGE_TOP} and {@link BaseKeyboard#EDGE_BOTTOM}.
*/
public int edgeFlags;
/** Whether this is a modifier key, such as Shift or Alt */
public boolean modifier;
/** The BaseKeyboard that this key belongs to */
protected final BaseKeyboard 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;
height = parent.defaultHeight;
gap = parent.defaultHorizontalGap;
width = parent.defaultWidth - gap;
edgeFlags = parent.rowEdgeFlags;
}
/** 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 BaseKeyboard}.
* @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,
KeyStyles keyStyles) {
this(parent);
TypedArray a = res.obtainAttributes(Xml.asAttributeSet(parser),
R.styleable.BaseKeyboard);
height = BaseKeyboardParser.getDimensionOrFraction(a,
R.styleable.BaseKeyboard_keyHeight,
keyboard.mDisplayHeight, parent.defaultHeight);
gap = BaseKeyboardParser.getDimensionOrFraction(a,
R.styleable.BaseKeyboard_horizontalGap,
keyboard.mDisplayWidth, parent.defaultHorizontalGap);
width = BaseKeyboardParser.getDimensionOrFraction(a,
R.styleable.BaseKeyboard_keyWidth,
keyboard.mDisplayWidth, parent.defaultWidth) - gap;
a.recycle();
a = res.obtainAttributes(Xml.asAttributeSet(parser), R.styleable.BaseKeyboard_Key);
final KeyStyle style;
if (a.hasValue(R.styleable.BaseKeyboard_Key_keyStyle)) {
String styleName = a.getString(R.styleable.BaseKeyboard_Key_keyStyle);
style = keyStyles.getKeyStyle(styleName);
if (style == null)
throw new ParseException("Unknown key style: " + styleName, parser);
} else {
style = keyStyles.getEmptyKeyStyle();
}
// Horizontal gap is divided equally to both sides of the key.
this.x = x + gap / 2;
this.y = y;
codes = style.getIntArray(a, R.styleable.BaseKeyboard_Key_codes);
iconPreview = style.getDrawable(a, R.styleable.BaseKeyboard_Key_iconPreview);
setDefaultBounds(iconPreview);
popupCharacters = style.getText(a, R.styleable.BaseKeyboard_Key_popupCharacters);
popupResId = style.getResourceId(a, R.styleable.BaseKeyboard_Key_popupKeyboard, 0);
repeatable = style.getBoolean(a, R.styleable.BaseKeyboard_Key_isRepeatable, false);
modifier = style.getBoolean(a, R.styleable.BaseKeyboard_Key_isModifier, false);
sticky = style.getBoolean(a, R.styleable.BaseKeyboard_Key_isSticky, false);
edgeFlags = style.getFlag(a, R.styleable.BaseKeyboard_Key_keyEdgeFlags, 0);
edgeFlags |= parent.rowEdgeFlags;
icon = style.getDrawable(a, R.styleable.BaseKeyboard_Key_keyIcon);
setDefaultBounds(icon);
hintIcon = style.getDrawable(a, R.styleable.BaseKeyboard_Key_keyHintIcon);
setDefaultBounds(hintIcon);
manualTemporaryUpperCaseHintIcon = style.getDrawable(a,
R.styleable.BaseKeyboard_Key_manualTemporaryUpperCaseHintIcon);
setDefaultBounds(manualTemporaryUpperCaseHintIcon);
label = style.getText(a, R.styleable.BaseKeyboard_Key_keyLabel);
labelOption = style.getFlag(a, R.styleable.BaseKeyboard_Key_keyLabelOption, 0);
manualTemporaryUpperCaseCode = style.getInt(a,
R.styleable.BaseKeyboard_Key_manualTemporaryUpperCaseCode, 0);
text = style.getText(a, R.styleable.BaseKeyboard_Key_keyOutputText);
final Drawable shiftedIcon = style.getDrawable(a,
R.styleable.BaseKeyboard_Key_shiftedIcon);
if (shiftedIcon != null)
keyboard.getShiftedIcons().put(this, shiftedIcon);
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;
}
}
/**
* 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 to the nearest edge 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 nearest edge of the key
*/
public int squaredDistanceToEdge(int x, int y) {
final int left = this.x;
final int right = left + this.width;
final int top = this.y;
final int bottom = top + this.height;
final int edgeX = x < left ? left : (x > right ? right : x);
final int edgeY = y < top ? top : (y > bottom ? bottom : y);
final int dx = x - edgeX;
final int dy = y - edgeY;
return dx * dx + dy * dy;
}
/**
* 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 BaseKeyboard(Context context, int xmlLayoutResId) {
this(context, xmlLayoutResId, null);
}
/**
* Creates a keyboard from the given keyboard identifier.
* @param context the application or service context
* @param id keyboard identifier
*/
public BaseKeyboard(Context context, KeyboardId id) {
this(context, id.getXmlId(), id);
}
/**
* 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.
* @param id keyboard identifier
*/
private BaseKeyboard(Context context, int xmlLayoutResId, KeyboardId id) {
this(context, xmlLayoutResId, id,
context.getResources().getDisplayMetrics().widthPixels,
context.getResources().getDisplayMetrics().heightPixels);
}
private BaseKeyboard(Context context, int xmlLayoutResId, KeyboardId id, int width,
int height) {
Resources res = context.getResources();
GRID_WIDTH = res.getInteger(R.integer.config_keyboard_grid_width);
GRID_HEIGHT = res.getInteger(R.integer.config_keyboard_grid_height);
GRID_SIZE = GRID_WIDTH * GRID_HEIGHT;
mDisplayWidth = width;
mDisplayHeight = height;
mDefaultHorizontalGap = 0;
setKeyWidth(mDisplayWidth / 10);
mDefaultVerticalGap = 0;
mDefaultHeight = mDefaultWidth;
mId = id;
loadKeyboard(context, 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 BaseKeyboard(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);
// Horizontal gap is divided equally to both sides of the key.
key.x = x + key.gap / 2;
key.y = y;
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 KeyboardId getKeyboardId() {
return mId;
}
public List<Key> getKeys() {
return mKeys;
}
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;
final int threshold = (int) (width * SEARCH_DISTANCE);
mProximityThreshold = threshold * threshold;
}
/**
* 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 int getKeyboardHeight() {
return mDisplayHeight;
}
public int getKeyboardWidth() {
return mDisplayWidth;
}
public boolean setShifted(boolean shiftState) {
for (final Key key : mShiftKeys) {
key.on = shiftState;
}
if (mShifted != shiftState) {
mShifted = shiftState;
return true;
}
return false;
}
public boolean isShiftedOrShiftLocked() {
return mShifted;
}
public List<Key> getShiftKeys() {
return mShiftKeys;
}
public Map<Key, Drawable> getShiftedIcons() {
return mShiftedIcons;
}
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][];
final int[] indices = new int[mKeys.size()];
final int gridWidth = GRID_WIDTH * mCellWidth;
final int gridHeight = GRID_HEIGHT * mCellHeight;
final int threshold = mProximityThreshold;
for (int x = 0; x < gridWidth; x += mCellWidth) {
for (int y = 0; y < gridHeight; y += mCellHeight) {
final int centerX = x + mCellWidth / 2;
final int centerY = y + mCellHeight / 2;
int count = 0;
for (int i = 0; i < mKeys.size(); i++) {
final Key key = mKeys.get(i);
if (key.squaredDistanceToEdge(centerX, centerY) < threshold)
indices[count++] = i;
}
final 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 EMPTY_INT_ARRAY;
}
// TODO should be private
protected BaseKeyboard.Row createRowFromXml(Resources res, XmlResourceParser parser) {
return new BaseKeyboard.Row(res, this, parser);
}
// TODO should be private
protected BaseKeyboard.Key createKeyFromXml(Resources res, Row parent, int x, int y,
XmlResourceParser parser, KeyStyles keyStyles) {
return new BaseKeyboard.Key(res, parent, x, y, parser, keyStyles);
}
private void loadKeyboard(Context context, int xmlLayoutResId) {
try {
final Resources res = context.getResources();
BaseKeyboardParser parser = new BaseKeyboardParser(this, res);
parser.parseKeyboard(res.getXml(xmlLayoutResId));
// mTotalWidth is the width of this keyboard which is maximum width of row.
mTotalWidth = parser.getMaxRowWidth();
mTotalHeight = parser.getTotalHeight();
} catch (XmlPullParserException e) {
Log.w(TAG, "keyboard XML parse error: " + e);
throw new IllegalArgumentException(e);
} catch (IOException e) {
Log.w(TAG, "keyboard XML parse error: " + e);
throw new RuntimeException(e);
}
}
protected static void setDefaultBounds(Drawable drawable) {
if (drawable != null)
drawable.setBounds(0, 0, drawable.getIntrinsicWidth(),
drawable.getIntrinsicHeight());
}
}

View File

@ -57,6 +57,7 @@ public class InputLanguageSelection extends PreferenceActivity {
return this.label;
}
@Override
public int compareTo(Object o) {
return sCollator.compare(this.label, ((Loc) o).label);
}

View File

@ -16,16 +16,19 @@
package com.android.inputmethod.latin;
import com.android.inputmethod.keyboard.KeyboardView;
import com.android.inputmethod.keyboard.KeyboardId;
import com.android.inputmethod.keyboard.LatinKeyboard;
import com.android.inputmethod.keyboard.LatinKeyboardView;
import android.content.Context;
import android.content.SharedPreferences;
import android.content.res.Resources;
import android.util.Log;
import android.view.InflateException;
import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputMethodManager;
import java.lang.ref.SoftReference;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Locale;
@ -34,14 +37,6 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha
private static final boolean DEBUG = false;
public static final boolean DEBUG_STATE = false;
public static final int MODE_TEXT = 0;
public static final int MODE_URL = 1;
public static final int MODE_EMAIL = 2;
public static final int MODE_IM = 3;
public static final int MODE_WEB = 4;
public static final int MODE_PHONE = 5;
public static final int MODE_NUMBER = 6;
// Changing DEFAULT_LAYOUT_ID also requires prefs_for_debug.xml to be matched with.
public static final String DEFAULT_LAYOUT_ID = "5";
public static final String PREF_KEYBOARD_LAYOUT = "pref_keyboard_layout_20100902";
@ -74,7 +69,7 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha
private final HashMap<KeyboardId, SoftReference<LatinKeyboard>> mKeyboardCache =
new HashMap<KeyboardId, SoftReference<LatinKeyboard>>();
private int mMode = MODE_TEXT; /* default value */
private int mMode = KeyboardId.MODE_TEXT; /* default value */
private int mImeOptions;
private boolean mIsSymbols;
/** mIsAutoCompletionActive indicates that auto completed word will be input instead of
@ -132,129 +127,13 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha
// mSymbolsId and mSymbolsShiftedId to "phone keyboard" and "phone symbols keyboard"
// respectively here for xlarge device's layout switching.
mSymbolsId = new KeyboardId(locale, orientation, mode,
mode == MODE_PHONE ? R.xml.kbd_phone : R.xml.kbd_symbols,
mode == KeyboardId.MODE_PHONE ? R.xml.kbd_phone : R.xml.kbd_symbols,
colorScheme, hasSettingsKey, voiceKeyEnabled, hasVoiceKey, imeOptions, true);
mSymbolsShiftedId = new KeyboardId(locale, orientation, mode,
mode == MODE_PHONE ? R.xml.kbd_phone_symbols : R.xml.kbd_symbols_shift,
mode == KeyboardId.MODE_PHONE ? R.xml.kbd_phone_symbols : R.xml.kbd_symbols_shift,
colorScheme, hasSettingsKey, voiceKeyEnabled, hasVoiceKey, imeOptions, true);
}
/**
* Represents the parameters necessary to construct a new LatinKeyboard,
* which also serve as a unique identifier for each keyboard type.
*/
public static class KeyboardId {
public final Locale mLocale;
public final int mOrientation;
public final int mMode;
public final int mXmlId;
public final int mColorScheme;
public final boolean mHasSettingsKey;
public final boolean mVoiceKeyEnabled;
public final boolean mHasVoiceKey;
public final int mImeOptions;
public final boolean mEnableShiftLock;
private final int mHashCode;
public KeyboardId(Locale locale, int orientation, int mode,
int xmlId, int colorScheme, boolean hasSettingsKey, boolean voiceKeyEnabled,
boolean hasVoiceKey, int imeOptions, boolean enableShiftLock) {
this.mLocale = locale;
this.mOrientation = orientation;
this.mMode = mode;
this.mXmlId = xmlId;
this.mColorScheme = colorScheme;
this.mHasSettingsKey = hasSettingsKey;
this.mVoiceKeyEnabled = voiceKeyEnabled;
this.mHasVoiceKey = hasVoiceKey;
// We are interested only in IME_MASK_ACTION enum value and IME_FLAG_NO_ENTER_ACTION.
this.mImeOptions = imeOptions
& (EditorInfo.IME_MASK_ACTION | EditorInfo.IME_FLAG_NO_ENTER_ACTION);
this.mEnableShiftLock = enableShiftLock;
this.mHashCode = Arrays.hashCode(new Object[] {
locale,
orientation,
mode,
xmlId,
colorScheme,
hasSettingsKey,
voiceKeyEnabled,
hasVoiceKey,
imeOptions,
enableShiftLock,
});
}
public int getXmlId() {
return mXmlId;
}
public boolean isAlphabetMode() {
return mXmlId == R.xml.kbd_qwerty;
}
@Override
public boolean equals(Object other) {
return other instanceof KeyboardId && equals((KeyboardId) other);
}
private boolean equals(KeyboardId other) {
return other.mLocale.equals(this.mLocale)
&& other.mOrientation == this.mOrientation
&& other.mMode == this.mMode
&& other.mXmlId == this.mXmlId
&& other.mColorScheme == this.mColorScheme
&& other.mHasSettingsKey == this.mHasSettingsKey
&& other.mVoiceKeyEnabled == this.mVoiceKeyEnabled
&& other.mHasVoiceKey == this.mHasVoiceKey
&& other.mImeOptions == this.mImeOptions
&& other.mEnableShiftLock == this.mEnableShiftLock;
}
@Override
public int hashCode() {
return mHashCode;
}
@Override
public String toString() {
return String.format("[%s %s %5s imeOptions=0x%08x xml=0x%08x %s%s%s%s%s]",
mLocale,
(mOrientation == 1 ? "port" : "land"),
modeName(mMode),
mImeOptions,
mXmlId,
colorSchemeName(mColorScheme),
(mHasSettingsKey ? " hasSettingsKey" : ""),
(mVoiceKeyEnabled ? " voiceKeyEnabled" : ""),
(mHasVoiceKey ? " hasVoiceKey" : ""),
(mEnableShiftLock ? " enableShiftLock" : ""));
}
private static String modeName(int mode) {
switch (mode) {
case MODE_TEXT: return "text";
case MODE_URL: return "url";
case MODE_EMAIL: return "email";
case MODE_IM: return "im";
case MODE_WEB: return "web";
case MODE_PHONE: return "phone";
case MODE_NUMBER: return "number";
}
return null;
}
private static String colorSchemeName(int colorScheme) {
switch (colorScheme) {
case BaseKeyboardView.COLOR_SCHEME_WHITE: return "white";
case BaseKeyboardView.COLOR_SCHEME_BLACK: return "black";
}
return null;
}
}
private boolean hasVoiceKey(boolean isSymbols) {
return mVoiceKeyEnabled && (isSymbols != mVoiceButtonOnPrimary);
}
@ -327,9 +206,9 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha
final boolean enableShiftLock;
if (isSymbols) {
if (mode == MODE_PHONE) {
if (mode == KeyboardId.MODE_PHONE) {
xmlId = R.xml.kbd_phone_symbols;
} else if (mode == MODE_NUMBER) {
} else if (mode == KeyboardId.MODE_NUMBER) {
// Note: MODE_NUMBER keyboard layout has no "switch alpha symbol" key.
xmlId = R.xml.kbd_number;
} else {
@ -337,10 +216,10 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha
}
enableShiftLock = false;
} else {
if (mode == MODE_PHONE) {
if (mode == KeyboardId.MODE_PHONE) {
xmlId = R.xml.kbd_phone;
enableShiftLock = false;
} else if (mode == MODE_NUMBER) {
} else if (mode == KeyboardId.MODE_NUMBER) {
xmlId = R.xml.kbd_number;
enableShiftLock = false;
} else {
@ -731,7 +610,7 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha
private int getColorScheme() {
return (mInputView != null)
? mInputView.getColorScheme() : BaseKeyboardView.COLOR_SCHEME_WHITE;
? mInputView.getColorScheme() : KeyboardView.COLOR_SCHEME_WHITE;
}
public void onAutoCompletionStateChanged(boolean isAutoCompletion) {

View File

@ -16,6 +16,12 @@
package com.android.inputmethod.latin;
import com.android.inputmethod.keyboard.Keyboard;
import com.android.inputmethod.keyboard.KeyboardActionListener;
import com.android.inputmethod.keyboard.KeyboardId;
import com.android.inputmethod.keyboard.KeyboardView;
import com.android.inputmethod.keyboard.LatinKeyboard;
import com.android.inputmethod.keyboard.LatinKeyboardView;
import com.android.inputmethod.latin.LatinIMEUtil.RingCharBuffer;
import com.android.inputmethod.voice.VoiceIMEConnector;
@ -73,7 +79,7 @@ import java.util.Locale;
* Input method implementation for Qwerty'ish keyboard.
*/
public class LatinIME extends InputMethodService
implements BaseKeyboardView.OnKeyboardActionListener,
implements KeyboardActionListener,
SharedPreferences.OnSharedPreferenceChangeListener,
Tutorial.TutorialListener {
private static final String TAG = "LatinIME";
@ -548,10 +554,10 @@ public class LatinIME extends InputMethodService
switch (attribute.inputType & EditorInfo.TYPE_MASK_CLASS) {
case EditorInfo.TYPE_CLASS_NUMBER:
case EditorInfo.TYPE_CLASS_DATETIME:
mode = KeyboardSwitcher.MODE_NUMBER;
mode = KeyboardId.MODE_NUMBER;
break;
case EditorInfo.TYPE_CLASS_PHONE:
mode = KeyboardSwitcher.MODE_PHONE;
mode = KeyboardId.MODE_PHONE;
break;
case EditorInfo.TYPE_CLASS_TEXT:
//startPrediction();
@ -568,24 +574,24 @@ public class LatinIME extends InputMethodService
}
if (isEmailVariation(variation)) {
mPredictionOn = false;
mode = KeyboardSwitcher.MODE_EMAIL;
mode = KeyboardId.MODE_EMAIL;
} else if (variation == EditorInfo.TYPE_TEXT_VARIATION_URI) {
mPredictionOn = false;
mode = KeyboardSwitcher.MODE_URL;
mode = KeyboardId.MODE_URL;
} else if (variation == EditorInfo.TYPE_TEXT_VARIATION_SHORT_MESSAGE) {
mode = KeyboardSwitcher.MODE_IM;
mode = KeyboardId.MODE_IM;
} else if (variation == EditorInfo.TYPE_TEXT_VARIATION_FILTER) {
mPredictionOn = false;
mode = KeyboardSwitcher.MODE_TEXT;
mode = KeyboardId.MODE_TEXT;
} else if (variation == EditorInfo.TYPE_TEXT_VARIATION_WEB_EDIT_TEXT) {
mode = KeyboardSwitcher.MODE_WEB;
mode = KeyboardId.MODE_WEB;
// If it's a browser edit field and auto correct is not ON explicitly, then
// disable auto correction, but keep suggestions on.
if ((attribute.inputType & EditorInfo.TYPE_TEXT_FLAG_AUTO_CORRECT) == 0) {
mInputTypeNoAutoCorrect = true;
}
} else {
mode = KeyboardSwitcher.MODE_TEXT;
mode = KeyboardId.MODE_TEXT;
}
// If NO_SUGGESTIONS is set, don't do prediction.
@ -604,7 +610,7 @@ public class LatinIME extends InputMethodService
}
break;
default:
mode = KeyboardSwitcher.MODE_TEXT;
mode = KeyboardId.MODE_TEXT;
break;
}
inputView.closing();
@ -675,7 +681,7 @@ public class LatinIME extends InputMethodService
mVoiceConnector.flushVoiceInputLogs(mConfigurationChanging);
BaseKeyboardView inputView = mKeyboardSwitcher.getInputView();
KeyboardView inputView = mKeyboardSwitcher.getInputView();
if (inputView != null)
inputView.closing();
if (mAutoDictionary != null) mAutoDictionary.flushPendingWrites();
@ -685,7 +691,7 @@ public class LatinIME extends InputMethodService
@Override
public void onFinishInputView(boolean finishingInput) {
super.onFinishInputView(finishingInput);
BaseKeyboardView inputView = mKeyboardSwitcher.getInputView();
KeyboardView inputView = mKeyboardSwitcher.getInputView();
if (inputView != null)
inputView.setForeground(false);
// Remove pending messages related to update suggestions
@ -1073,51 +1079,52 @@ public class LatinIME extends InputMethodService
// Implementation of KeyboardViewListener
@Override
public void onKey(int primaryCode, int[] keyCodes, int x, int y) {
long when = SystemClock.uptimeMillis();
if (primaryCode != BaseKeyboard.KEYCODE_DELETE || when > mLastKeyTime + QUICK_PRESS) {
if (primaryCode != Keyboard.KEYCODE_DELETE || when > mLastKeyTime + QUICK_PRESS) {
mDeleteCount = 0;
}
mLastKeyTime = when;
KeyboardSwitcher switcher = mKeyboardSwitcher;
final boolean distinctMultiTouch = switcher.hasDistinctMultitouch();
switch (primaryCode) {
case BaseKeyboard.KEYCODE_DELETE:
case Keyboard.KEYCODE_DELETE:
handleBackspace();
mDeleteCount++;
LatinImeLogger.logOnDelete();
break;
case BaseKeyboard.KEYCODE_SHIFT:
case Keyboard.KEYCODE_SHIFT:
// Shift key is handled in onPress() when device has distinct multi-touch panel.
if (!distinctMultiTouch)
switcher.toggleShift();
break;
case BaseKeyboard.KEYCODE_MODE_CHANGE:
case Keyboard.KEYCODE_MODE_CHANGE:
// Symbol key is handled in onPress() when device has distinct multi-touch panel.
if (!distinctMultiTouch)
switcher.changeKeyboardMode();
break;
case BaseKeyboard.KEYCODE_CANCEL:
case Keyboard.KEYCODE_CANCEL:
if (!isShowingOptionDialog()) {
handleClose();
}
break;
case LatinKeyboardView.KEYCODE_OPTIONS:
case LatinKeyboard.KEYCODE_OPTIONS:
onOptionKeyPressed();
break;
case LatinKeyboardView.KEYCODE_OPTIONS_LONGPRESS:
case LatinKeyboard.KEYCODE_OPTIONS_LONGPRESS:
onOptionKeyLongPressed();
break;
case LatinKeyboardView.KEYCODE_NEXT_LANGUAGE:
case LatinKeyboard.KEYCODE_NEXT_LANGUAGE:
toggleLanguage(false, true);
break;
case LatinKeyboardView.KEYCODE_PREV_LANGUAGE:
case LatinKeyboard.KEYCODE_PREV_LANGUAGE:
toggleLanguage(false, false);
break;
case LatinKeyboardView.KEYCODE_CAPSLOCK:
case LatinKeyboard.KEYCODE_CAPSLOCK:
switcher.toggleCapsLock();
break;
case LatinKeyboardView.KEYCODE_VOICE: /* was a button press, was not a swipe */
case LatinKeyboard.KEYCODE_VOICE: /* was a button press, was not a swipe */
mVoiceConnector.startListening(false,
mKeyboardSwitcher.getInputView().getWindowToken(), mConfigurationChanging);
break;
@ -1143,6 +1150,7 @@ public class LatinIME extends InputMethodService
mEnteredText = null;
}
@Override
public void onText(CharSequence text) {
mVoiceConnector.commitVoiceInput();
InputConnection ic = getCurrentInputConnection();
@ -1161,6 +1169,7 @@ public class LatinIME extends InputMethodService
mEnteredText = text;
}
@Override
public void onCancel() {
// User released a finger outside any key
}
@ -1421,6 +1430,7 @@ public class LatinIME extends InputMethodService
public void switchToKeyboardView() {
mHandler.post(new Runnable() {
@Override
public void run() {
if (DEBUG) {
Log.d(TAG, "Switch to keyboard view.");
@ -1437,7 +1447,8 @@ public class LatinIME extends InputMethodService
setCandidatesViewShown(isCandidateStripVisible());
updateInputViewShown();
mHandler.postUpdateSuggestions();
}});
}
});
}
public void clearSuggestions() {
@ -1586,8 +1597,8 @@ public class LatinIME extends InputMethodService
LatinImeLogger.logOnManualSuggestion(
"", suggestion.toString(), index, suggestions);
final char primaryCode = suggestion.charAt(0);
onKey(primaryCode, new int[]{primaryCode}, BaseKeyboardView.NOT_A_TOUCH_COORDINATE,
BaseKeyboardView.NOT_A_TOUCH_COORDINATE);
onKey(primaryCode, new int[]{primaryCode}, KeyboardView.NOT_A_TOUCH_COORDINATE,
KeyboardView.NOT_A_TOUCH_COORDINATE);
if (ic != null) {
ic.endBatchEdit();
}
@ -1877,6 +1888,7 @@ public class LatinIME extends InputMethodService
switcher.updateShiftState();
}
@Override
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences,
String key) {
mSubtypeSwitcher.onSharedPreferenceChanged(sharedPreferences, key);
@ -1888,6 +1900,7 @@ public class LatinIME extends InputMethodService
}
}
@Override
public void swipeRight() {
if (LatinKeyboardView.DEBUG_AUTO_PLAY) {
CharSequence text = ((android.text.ClipboardManager)getSystemService(
@ -1898,38 +1911,43 @@ public class LatinIME extends InputMethodService
}
}
@Override
public void swipeLeft() {
}
@Override
public void swipeDown() {
handleClose();
}
@Override
public void swipeUp() {
}
@Override
public void onPress(int primaryCode) {
vibrate();
playKeyClick(primaryCode);
KeyboardSwitcher switcher = mKeyboardSwitcher;
final boolean distinctMultiTouch = switcher.hasDistinctMultitouch();
if (distinctMultiTouch && primaryCode == BaseKeyboard.KEYCODE_SHIFT) {
if (distinctMultiTouch && primaryCode == Keyboard.KEYCODE_SHIFT) {
switcher.onPressShift();
} else if (distinctMultiTouch && primaryCode == BaseKeyboard.KEYCODE_MODE_CHANGE) {
} else if (distinctMultiTouch && primaryCode == Keyboard.KEYCODE_MODE_CHANGE) {
switcher.onPressSymbol();
} else {
switcher.onOtherKeyPressed();
}
}
@Override
public void onRelease(int primaryCode) {
KeyboardSwitcher switcher = mKeyboardSwitcher;
// Reset any drag flags in the keyboard
switcher.keyReleased();
final boolean distinctMultiTouch = switcher.hasDistinctMultitouch();
if (distinctMultiTouch && primaryCode == BaseKeyboard.KEYCODE_SHIFT) {
if (distinctMultiTouch && primaryCode == Keyboard.KEYCODE_SHIFT) {
switcher.onReleaseShift();
} else if (distinctMultiTouch && primaryCode == BaseKeyboard.KEYCODE_MODE_CHANGE) {
} else if (distinctMultiTouch && primaryCode == Keyboard.KEYCODE_MODE_CHANGE) {
switcher.onReleaseSymbol();
}
}
@ -1966,7 +1984,7 @@ public class LatinIME extends InputMethodService
// FIXME: These should be triggered after auto-repeat logic
int sound = AudioManager.FX_KEYPRESS_STANDARD;
switch (primaryCode) {
case BaseKeyboard.KEYCODE_DELETE:
case Keyboard.KEYCODE_DELETE:
sound = AudioManager.FX_KEYPRESS_DELETE;
break;
case KEYCODE_ENTER:
@ -2006,6 +2024,7 @@ public class LatinIME extends InputMethodService
}
// Tutorial.TutorialListener
@Override
public void onTutorialDone() {
sendDownUpKeyEvents(-1); // Inform the setupwizard that tutorial is in last bubble
mTutorial = null;
@ -2171,6 +2190,7 @@ public class LatinIME extends InputMethodService
itemInputMethod, itemSettings},
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface di, int position) {
di.dismiss();
switch (position) {

View File

@ -43,6 +43,7 @@ public class LatinIMEDebugSettings extends PreferenceActivity
updateDebugMode();
}
@Override
public void onSharedPreferenceChanged(SharedPreferences prefs, String key) {
if (key.equals(DEBUG_MODE_KEY)) {
if (mDebugMode != null) {

View File

@ -137,6 +137,7 @@ public class LatinIMESettings extends PreferenceActivity
super.onDestroy();
}
@Override
public void onSharedPreferenceChanged(SharedPreferences prefs, String key) {
(new BackupManager(this)).dataChanged();
// If turning on voice input, show dialog
@ -181,6 +182,7 @@ public class LatinIMESettings extends PreferenceActivity
switch (id) {
case VOICE_INPUT_CONFIRM_DIALOG:
DialogInterface.OnClickListener listener = new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int whichButton) {
if (whichButton == DialogInterface.BUTTON_NEGATIVE) {
mVoicePreference.setValue(mVoiceModeOff);
@ -226,6 +228,7 @@ public class LatinIMESettings extends PreferenceActivity
}
}
@Override
public void onDismiss(DialogInterface dialog) {
mLogger.settingsWarningDialogDismissed();
if (!mOkClicked) {

View File

@ -310,6 +310,7 @@ public class LatinIMEUtil {
public void write(final String log) {
mLoggingHandler.post(new Runnable() {
@Override
public void run() {
createLogFileIfNotExist();
final long currentTime = System.currentTimeMillis();
@ -327,6 +328,7 @@ public class LatinIMEUtil {
public void printAll() {
mLoggingHandler.post(new Runnable() {
@Override
public void run() {
mWriter.flush();
StringBuilder sb = new StringBuilder();
@ -355,6 +357,7 @@ public class LatinIMEUtil {
public void clearAll() {
mLoggingHandler.post(new Runnable() {
@Override
public void run() {
if (mFile != null && mFile.exists()) {
if (LatinImeLogger.sDBG) {

View File

@ -16,6 +16,7 @@
package com.android.inputmethod.latin;
import com.android.inputmethod.keyboard.Keyboard;
import com.android.inputmethod.latin.Dictionary.DataType;
import android.content.Context;
@ -27,6 +28,7 @@ public class LatinImeLogger implements SharedPreferences.OnSharedPreferenceChang
public static boolean sDBG = false;
@Override
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
}
@ -67,7 +69,7 @@ public class LatinImeLogger implements SharedPreferences.OnSharedPreferenceChang
public static void onAddSuggestedWord(String word, int typeId, DataType dataType) {
}
public static void onSetKeyboard(BaseKeyboard kb) {
public static void onSetKeyboard(Keyboard kb) {
}
public static void onPrintAllUsabilityStudtyLogs() {

View File

@ -16,6 +16,7 @@
package com.android.inputmethod.latin;
import com.android.inputmethod.keyboard.LatinKeyboard;
import com.android.inputmethod.voice.SettingsUtil;
import com.android.inputmethod.voice.VoiceIMEConnector;
import com.android.inputmethod.voice.VoiceInput;
@ -197,7 +198,7 @@ public class SubtypeSwitcher {
|| VoiceIMEConnector.getInstance().needsToShowWarningDialog()) {
if (mVoiceInput != null) {
// TODO: Call proper function to trigger VoiceIME
mService.onKey(LatinKeyboardView.KEYCODE_VOICE, null, 0, 0);
mService.onKey(LatinKeyboard.KEYCODE_VOICE, null, 0, 0);
}
}
} else {
@ -350,7 +351,7 @@ public class SubtypeSwitcher {
if (DBG) {
Log.d(TAG, "Set and call voice input.");
}
mService.onKey(LatinKeyboardView.KEYCODE_VOICE, null, 0, 0);
mService.onKey(LatinKeyboard.KEYCODE_VOICE, null, 0, 0);
return true;
}
}

View File

@ -423,6 +423,7 @@ public class Suggest implements Dictionary.WordCallback {
return false;
}
@Override
public boolean addWord(final char[] word, final int offset, final int length, int freq,
final int dicTypeId, final Dictionary.DataType dataType) {
Dictionary.DataType dataTypeForLog = dataType;

View File

@ -16,7 +16,7 @@
package com.android.inputmethod.latin;
import com.android.inputmethod.latin.BaseKeyboard.Key;
import com.android.inputmethod.keyboard.Key;
import android.content.Context;
import android.text.format.DateFormat;

View File

@ -16,6 +16,8 @@
package com.android.inputmethod.latin;
import com.android.inputmethod.keyboard.LatinKeyboardView;
import android.content.Context;
import android.graphics.drawable.Drawable;
import android.os.Handler;
@ -133,6 +135,7 @@ public class Tutorial implements OnTouchListener {
if ((gravity & Gravity.BOTTOM) == Gravity.BOTTOM) offy -= window.getHeight();
if ((gravity & Gravity.RIGHT) == Gravity.RIGHT) offx -= window.getWidth();
textView.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View view, MotionEvent me) {
Tutorial.this.next();
return true;
@ -237,6 +240,7 @@ public class Tutorial implements OnTouchListener {
return true;
}
@Override
public boolean onTouch(View v, MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
next();

View File

@ -97,6 +97,7 @@ public class UserDictionary extends ExpandableDictionary {
final ContentResolver contentResolver = getContext().getContentResolver();
new Thread("addWord") {
@Override
public void run() {
contentResolver.insert(Words.CONTENT_URI, values);
}

View File

@ -73,6 +73,7 @@ public class FieldContext {
bundle.putInt(IME_OPTIONS, info.imeOptions);
}
@SuppressWarnings("static-access")
private static void addInputConnectionToBundle(
InputConnection conn, Bundle bundle) {
if (conn == null) {
@ -96,6 +97,7 @@ public class FieldContext {
return mFieldInfo;
}
@Override
public String toString() {
return mFieldInfo.toString();
}

View File

@ -51,6 +51,7 @@ import java.util.List;
* plays beeps, shows errors, etc.
*/
public class RecognitionView {
@SuppressWarnings("unused")
private static final String TAG = "RecognitionView";
private Handler mUiHandler; // Reference to UI thread
@ -78,6 +79,7 @@ public class RecognitionView {
/** Updates the microphone icon to show user their volume.*/
private Runnable mUpdateVolumeRunnable = new Runnable() {
@Override
public void run() {
if (mState != State.LISTENING) {
return;
@ -141,6 +143,7 @@ public class RecognitionView {
public void restoreState() {
mUiHandler.post(new Runnable() {
@Override
public void run() {
// Restart the spinner
if (mState == State.WORKING) {
@ -153,6 +156,7 @@ public class RecognitionView {
public void showInitializing() {
mUiHandler.post(new Runnable() {
@Override
public void run() {
prepareDialog(false, mContext.getText(R.string.voice_initializing), mInitializing,
mContext.getText(R.string.cancel));
@ -162,6 +166,7 @@ public class RecognitionView {
public void showListening() {
mUiHandler.post(new Runnable() {
@Override
public void run() {
mState = State.LISTENING;
prepareDialog(false, mContext.getText(R.string.voice_listening), mSpeakNow.get(0),
@ -177,6 +182,7 @@ public class RecognitionView {
public void showError(final String message) {
mUiHandler.post(new Runnable() {
@Override
public void run() {
mState = State.READY;
prepareDialog(false, message, mError, mContext.getText(R.string.ok));
@ -190,6 +196,7 @@ public class RecognitionView {
final int speechEndPosition) {
mUiHandler.post(new Runnable() {
@Override
public void run() {
mState = State.WORKING;
prepareDialog(true, mContext.getText(R.string.voice_working), null, mContext
@ -309,6 +316,7 @@ public class RecognitionView {
public void finish() {
mUiHandler.post(new Runnable() {
@Override
public void run() {
mState = State.READY;
exitWorking();

View File

@ -39,7 +39,6 @@ import android.text.Selection;
import android.text.Spannable;
import android.text.TextUtils;
import android.text.method.LinkMovementMethod;
import android.text.method.MovementMethod;
import android.text.style.ClickableSpan;
import android.text.style.URLSpan;
import android.view.LayoutInflater;
@ -120,6 +119,7 @@ public class VoiceIMEConnector implements VoiceInput.UiListener {
if (VOICE_INSTALLED) {
mVoiceInput = new VoiceInput(context, this);
mHints = new Hints(context, prefs, new Hints.Display() {
@Override
public void showHint(int viewResource) {
LayoutInflater inflater = (LayoutInflater) mContext.getSystemService(
Context.LAYOUT_INFLATER_SERVICE);
@ -519,6 +519,7 @@ public class VoiceIMEConnector implements VoiceInput.UiListener {
public void switchToRecognitionStatusView(final boolean configurationChanging) {
final boolean configChanged = configurationChanging;
mHandler.post(new Runnable() {
@Override
public void run() {
mContext.setCandidatesViewShown(false);
mRecognizing = true;

View File

@ -86,6 +86,7 @@ public class VoiceInput implements OnClickListener {
private static final String ALTERNATES_BUNDLE = "alternates_bundle";
// This is copied from the VoiceSearch app.
@SuppressWarnings("unused")
private static final class AlternatesBundleKeys {
public static final String ALTERNATES = "alternates";
public static final String CONFIDENCE = "confidence";
@ -405,6 +406,7 @@ public class VoiceInput implements OnClickListener {
/**
* Handle the cancel button.
*/
@Override
public void onClick(View view) {
switch(view.getId()) {
case R.id.button:
@ -556,36 +558,43 @@ public class VoiceInput implements OnClickListener {
int mSpeechStart;
private boolean mEndpointed = false;
@Override
public void onReadyForSpeech(Bundle noiseParams) {
mRecognitionView.showListening();
}
@Override
public void onBeginningOfSpeech() {
mEndpointed = false;
mSpeechStart = mWaveBuffer.size();
}
@Override
public void onRmsChanged(float rmsdB) {
mRecognitionView.updateVoiceMeter(rmsdB);
}
@Override
public void onBufferReceived(byte[] buf) {
try {
mWaveBuffer.write(buf);
} catch (IOException e) {}
}
@Override
public void onEndOfSpeech() {
mEndpointed = true;
mState = WORKING;
mRecognitionView.showWorking(mWaveBuffer, mSpeechStart, mWaveBuffer.size());
}
@Override
public void onError(int errorType) {
mState = ERROR;
VoiceInput.this.onError(errorType, mEndpointed);
}
@Override
public void onResults(Bundle resultsBundle) {
List<String> results = resultsBundle
.getStringArrayList(SpeechRecognizer.RESULTS_RECOGNITION);
@ -638,10 +647,12 @@ public class VoiceInput implements OnClickListener {
mRecognitionView.finish();
}
@Override
public void onPartialResults(final Bundle partialResults) {
// currently - do nothing
}
@Override
public void onEvent(int eventType, Bundle params) {
// do nothing - reserved for events that might be added in the future
}

View File

@ -31,6 +31,7 @@ import android.content.Intent;
* on on the VoiceSearch side.
*/
public class VoiceInputLogger {
@SuppressWarnings("unused")
private static final String TAG = VoiceInputLogger.class.getSimpleName();
private static VoiceInputLogger sVoiceInputLogger;

View File

@ -16,7 +16,7 @@
package com.android.inputmethod.latin;
import com.android.inputmethod.latin.SwipeTracker.EventRingBuffer;
import com.android.inputmethod.keyboard.SwipeTracker.EventRingBuffer;
import android.test.AndroidTestCase;