aboutsummaryrefslogtreecommitdiffstats
path: root/java/src
diff options
context:
space:
mode:
authorTadashi G. Takaoka <takaoka@google.com>2011-08-23 12:08:36 +0900
committerTadashi G. Takaoka <takaoka@google.com>2011-08-23 17:51:57 +0900
commit32572948d7e3956efebcbd69d7c7d8403bb659e6 (patch)
tree1be05c192a454a4dc5105eecfaa6b8b8688d0588 /java/src
parent2d306a225c4a9c0ea7b78a022c9dcc986ddffa46 (diff)
downloadlatinime-32572948d7e3956efebcbd69d7c7d8403bb659e6.tar.gz
latinime-32572948d7e3956efebcbd69d7c7d8403bb659e6.tar.xz
latinime-32572948d7e3956efebcbd69d7c7d8403bb659e6.zip
Refactor and rename popup mini keyoard related classes
Change-Id: Ia92ec4612090b03829db9a87ce68d701db6e15bc
Diffstat (limited to 'java/src')
-rw-r--r--java/src/com/android/inputmethod/keyboard/KeyDetector.java4
-rw-r--r--java/src/com/android/inputmethod/keyboard/LatinKeyboardBaseView.java3
-rw-r--r--java/src/com/android/inputmethod/keyboard/MiniKeyboard.java250
-rw-r--r--java/src/com/android/inputmethod/keyboard/MiniKeyboardKeyDetector.java59
-rw-r--r--java/src/com/android/inputmethod/keyboard/PointerTracker.java4
-rw-r--r--java/src/com/android/inputmethod/keyboard/PopupMiniKeyboardView.java52
-rw-r--r--java/src/com/android/inputmethod/keyboard/internal/MiniKeyboardBuilder.java259
7 files changed, 302 insertions, 329 deletions
diff --git a/java/src/com/android/inputmethod/keyboard/KeyDetector.java b/java/src/com/android/inputmethod/keyboard/KeyDetector.java
index 0a3acb48b..3298c41cf 100644
--- a/java/src/com/android/inputmethod/keyboard/KeyDetector.java
+++ b/java/src/com/android/inputmethod/keyboard/KeyDetector.java
@@ -91,6 +91,10 @@ public class KeyDetector {
mProximityThresholdSquare = threshold * threshold;
}
+ public boolean alwaysAllowsSlidingInput() {
+ return false;
+ }
+
/**
* Computes maximum size of the array that can contain all nearby key indices returned by
* {@link #getKeyIndexAndNearbyCodes}.
diff --git a/java/src/com/android/inputmethod/keyboard/LatinKeyboardBaseView.java b/java/src/com/android/inputmethod/keyboard/LatinKeyboardBaseView.java
index 4b85bcbec..2af4594f4 100644
--- a/java/src/com/android/inputmethod/keyboard/LatinKeyboardBaseView.java
+++ b/java/src/com/android/inputmethod/keyboard/LatinKeyboardBaseView.java
@@ -38,7 +38,6 @@ import com.android.inputmethod.accessibility.AccessibleKeyboardViewProxy;
import com.android.inputmethod.deprecated.VoiceProxy;
import com.android.inputmethod.keyboard.PointerTracker.DrawingProxy;
import com.android.inputmethod.keyboard.PointerTracker.TimerProxy;
-import com.android.inputmethod.keyboard.internal.MiniKeyboardBuilder;
import com.android.inputmethod.latin.LatinIME;
import com.android.inputmethod.latin.R;
import com.android.inputmethod.latin.StaticInnerHandlerWrapper;
@@ -374,7 +373,7 @@ public class LatinKeyboardBaseView extends KeyboardView implements PointerTracke
final PopupMiniKeyboardView miniKeyboardView =
(PopupMiniKeyboardView)container.findViewById(R.id.mini_keyboard_view);
final Keyboard parentKeyboard = getKeyboard();
- final Keyboard miniKeyboard = new MiniKeyboardBuilder(
+ final Keyboard miniKeyboard = new MiniKeyboard.Builder(
this, parentKeyboard.mPopupKeyboardResId, parentKey, parentKeyboard).build();
miniKeyboardView.setKeyboard(miniKeyboard);
diff --git a/java/src/com/android/inputmethod/keyboard/MiniKeyboard.java b/java/src/com/android/inputmethod/keyboard/MiniKeyboard.java
index 08e7d7e19..17c253963 100644
--- a/java/src/com/android/inputmethod/keyboard/MiniKeyboard.java
+++ b/java/src/com/android/inputmethod/keyboard/MiniKeyboard.java
@@ -16,12 +16,18 @@
package com.android.inputmethod.keyboard;
-import com.android.inputmethod.keyboard.internal.MiniKeyboardBuilder.MiniKeyboardParams;
+import android.graphics.Paint;
+import android.graphics.Rect;
+
+import com.android.inputmethod.keyboard.internal.KeyboardBuilder;
+import com.android.inputmethod.keyboard.internal.KeyboardParams;
+import com.android.inputmethod.keyboard.internal.PopupCharactersParser;
+import com.android.inputmethod.latin.R;
public class MiniKeyboard extends Keyboard {
private final int mDefaultKeyCoordX;
- public MiniKeyboard(MiniKeyboardParams params) {
+ private MiniKeyboard(Builder.MiniKeyboardParams params) {
super(params);
mDefaultKeyCoordX = params.getDefaultKeyCoordX() + params.mDefaultKeyWidth / 2;
}
@@ -29,4 +35,244 @@ public class MiniKeyboard extends Keyboard {
public int getDefaultCoordX() {
return mDefaultKeyCoordX;
}
+
+ public static class Builder extends KeyboardBuilder<Builder.MiniKeyboardParams> {
+ private final CharSequence[] mPopupCharacters;
+
+ public static class MiniKeyboardParams extends KeyboardParams {
+ /* package */int mTopRowAdjustment;
+ public int mNumRows;
+ public int mNumColumns;
+ public int mLeftKeys;
+ public int mRightKeys; // includes default key.
+
+ public MiniKeyboardParams() {
+ super();
+ }
+
+ /* package for test */MiniKeyboardParams(int numKeys, int maxColumns, int keyWidth,
+ int rowHeight, int coordXInParent, int parentKeyboardWidth) {
+ super();
+ setParameters(numKeys, maxColumns, keyWidth, rowHeight, coordXInParent,
+ parentKeyboardWidth);
+ }
+
+ /**
+ * Set keyboard parameters of mini keyboard.
+ *
+ * @param numKeys number of keys in this mini keyboard.
+ * @param maxColumns number of maximum columns of this mini keyboard.
+ * @param keyWidth mini keyboard key width in pixel, including horizontal gap.
+ * @param rowHeight mini keyboard row height in pixel, including vertical gap.
+ * @param coordXInParent coordinate x of the popup key in parent keyboard.
+ * @param parentKeyboardWidth parent keyboard width in pixel.
+ */
+ public void setParameters(int numKeys, int maxColumns, int keyWidth, int rowHeight,
+ int coordXInParent, int parentKeyboardWidth) {
+ if (parentKeyboardWidth / keyWidth < maxColumns) {
+ throw new IllegalArgumentException(
+ "Keyboard is too small to hold mini keyboard: " + parentKeyboardWidth
+ + " " + keyWidth + " " + maxColumns);
+ }
+ mDefaultKeyWidth = keyWidth;
+ mDefaultRowHeight = rowHeight;
+
+ final int numRows = (numKeys + maxColumns - 1) / maxColumns;
+ mNumRows = numRows;
+ final int numColumns = getOptimizedColumns(numKeys, maxColumns);
+ mNumColumns = numColumns;
+
+ final int numLeftKeys = (numColumns - 1) / 2;
+ final int numRightKeys = numColumns - numLeftKeys; // including default key.
+ final int maxLeftKeys = coordXInParent / keyWidth;
+ final int maxRightKeys = Math.max(1, (parentKeyboardWidth - coordXInParent)
+ / keyWidth);
+ int leftKeys, rightKeys;
+ if (numLeftKeys > maxLeftKeys) {
+ leftKeys = maxLeftKeys;
+ rightKeys = numColumns - maxLeftKeys;
+ } else if (numRightKeys > maxRightKeys) {
+ leftKeys = numColumns - maxRightKeys;
+ rightKeys = maxRightKeys;
+ } else {
+ leftKeys = numLeftKeys;
+ rightKeys = numRightKeys;
+ }
+ // Shift right if the left edge of mini keyboard is on the edge of parent keyboard
+ // unless the parent key is on the left edge.
+ if (leftKeys * keyWidth >= coordXInParent && leftKeys > 0) {
+ leftKeys--;
+ rightKeys++;
+ }
+ // Shift left if the right edge of mini keyboard is on the edge of parent keyboard
+ // unless the parent key is on the right edge.
+ if (rightKeys * keyWidth + coordXInParent >= parentKeyboardWidth && rightKeys > 1) {
+ leftKeys++;
+ rightKeys--;
+ }
+ mLeftKeys = leftKeys;
+ mRightKeys = rightKeys;
+
+ // Centering of the top row.
+ final boolean onEdge = (leftKeys == 0 || rightKeys == 1);
+ if (numRows < 2 || onEdge || getTopRowEmptySlots(numKeys, numColumns) % 2 == 0) {
+ mTopRowAdjustment = 0;
+ } else if (mLeftKeys < mRightKeys - 1) {
+ mTopRowAdjustment = 1;
+ } else {
+ mTopRowAdjustment = -1;
+ }
+
+ mWidth = mOccupiedWidth = mNumColumns * mDefaultKeyWidth;
+ mHeight = mOccupiedHeight = mNumRows * mDefaultRowHeight + mVerticalGap;
+ }
+
+ // Return key position according to column count (0 is default).
+ /* package */int getColumnPos(int n) {
+ final int col = n % mNumColumns;
+ if (col == 0) {
+ // default position.
+ return 0;
+ }
+ int pos = 0;
+ int right = 1; // include default position key.
+ int left = 0;
+ int i = 0;
+ while (true) {
+ // Assign right key if available.
+ if (right < mRightKeys) {
+ pos = right;
+ right++;
+ i++;
+ }
+ if (i >= col)
+ break;
+ // Assign left key if available.
+ if (left < mLeftKeys) {
+ left++;
+ pos = -left;
+ i++;
+ }
+ if (i >= col)
+ break;
+ }
+ return pos;
+ }
+
+ private static int getTopRowEmptySlots(int numKeys, int numColumns) {
+ final int remainingKeys = numKeys % numColumns;
+ if (remainingKeys == 0) {
+ return 0;
+ } else {
+ return numColumns - remainingKeys;
+ }
+ }
+
+ private int getOptimizedColumns(int numKeys, int maxColumns) {
+ int numColumns = Math.min(numKeys, maxColumns);
+ while (getTopRowEmptySlots(numKeys, numColumns) >= mNumRows) {
+ numColumns--;
+ }
+ return numColumns;
+ }
+
+ public int getDefaultKeyCoordX() {
+ return mLeftKeys * mDefaultKeyWidth;
+ }
+
+ public int getX(int n, int row) {
+ final int x = getColumnPos(n) * mDefaultKeyWidth + getDefaultKeyCoordX();
+ if (isTopRow(row)) {
+ return x + mTopRowAdjustment * (mDefaultKeyWidth / 2);
+ }
+ return x;
+ }
+
+ public int getY(int row) {
+ return (mNumRows - 1 - row) * mDefaultRowHeight + mTopPadding;
+ }
+
+ public int getRowFlags(int row) {
+ int rowFlags = 0;
+ if (row == 0)
+ rowFlags |= Keyboard.EDGE_TOP;
+ if (isTopRow(row))
+ rowFlags |= Keyboard.EDGE_BOTTOM;
+ return rowFlags;
+ }
+
+ private boolean isTopRow(int rowCount) {
+ return rowCount == mNumRows - 1;
+ }
+ }
+
+ public Builder(KeyboardView view, int xmlId, Key parentKey, Keyboard parentKeyboard) {
+ super(view.getContext(), new MiniKeyboardParams());
+ load(parentKeyboard.mId.cloneWithNewXml(mResources.getResourceEntryName(xmlId), xmlId));
+
+ // HACK: Current mini keyboard design totally relies on the 9-patch
+ // padding about horizontal
+ // and vertical key spacing. To keep the visual of mini keyboard as
+ // is, these hacks are
+ // needed to keep having the same horizontal and vertical key
+ // spacing.
+ mParams.mHorizontalGap = 0;
+ mParams.mVerticalGap = mParams.mTopPadding = parentKeyboard.mVerticalGap / 2;
+ // TODO: When we have correctly padded key background 9-patch
+ // drawables for mini keyboard,
+ // revert the above hacks and uncomment the following lines.
+ // mParams.mHorizontalGap = parentKeyboard.mHorizontalGap;
+ // mParams.mVerticalGap = parentKeyboard.mVerticalGap;
+
+ mParams.mIsRtlKeyboard = parentKeyboard.mIsRtlKeyboard;
+ mPopupCharacters = parentKey.mPopupCharacters;
+
+ final int keyWidth = getMaxKeyWidth(view, mPopupCharacters, mParams.mDefaultKeyWidth);
+ mParams.setParameters(mPopupCharacters.length, parentKey.mMaxPopupColumn, keyWidth,
+ parentKeyboard.mDefaultRowHeight, parentKey.mX
+ + (mParams.mDefaultKeyWidth - keyWidth) / 2, view.getMeasuredWidth());
+ }
+
+ private static int getMaxKeyWidth(KeyboardView view, CharSequence[] popupCharacters,
+ int minKeyWidth) {
+ Paint paint = null;
+ Rect bounds = null;
+ int maxWidth = 0;
+ for (CharSequence popupSpec : popupCharacters) {
+ final CharSequence label = PopupCharactersParser.getLabel(popupSpec.toString());
+ // If the label is single letter, minKeyWidth is enough to hold
+ // the label.
+ if (label != null && label.length() > 1) {
+ if (paint == null) {
+ paint = new Paint();
+ paint.setAntiAlias(true);
+ }
+ final int labelSize = view.getDefaultLabelSizeAndSetPaint(paint);
+ paint.setTextSize(labelSize);
+ if (bounds == null)
+ bounds = new Rect();
+ paint.getTextBounds(label.toString(), 0, label.length(), bounds);
+ if (maxWidth < bounds.width())
+ maxWidth = bounds.width();
+ }
+ }
+ final int horizontalPadding = (int) view.getContext().getResources()
+ .getDimension(R.dimen.mini_keyboard_key_horizontal_padding);
+ return Math.max(minKeyWidth, maxWidth + horizontalPadding);
+ }
+
+ @Override
+ public MiniKeyboard build() {
+ final MiniKeyboardParams params = mParams;
+ for (int n = 0; n < mPopupCharacters.length; n++) {
+ final CharSequence label = mPopupCharacters[n];
+ final int row = n / params.mNumColumns;
+ final Key key = new Key(mResources, params, label, params.getX(n, row),
+ params.getY(row), params.mDefaultKeyWidth, params.mDefaultRowHeight,
+ params.getRowFlags(row));
+ params.onAddKey(key);
+ }
+ return new MiniKeyboard(params);
+ }
+ }
}
diff --git a/java/src/com/android/inputmethod/keyboard/MiniKeyboardKeyDetector.java b/java/src/com/android/inputmethod/keyboard/MiniKeyboardKeyDetector.java
deleted file mode 100644
index 84bd44c30..000000000
--- a/java/src/com/android/inputmethod/keyboard/MiniKeyboardKeyDetector.java
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * 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.List;
-
-public class MiniKeyboardKeyDetector extends KeyDetector {
- private final int mSlideAllowanceSquare;
- private final int mSlideAllowanceSquareTop;
-
- public MiniKeyboardKeyDetector(float slideAllowance) {
- super(/* keyHysteresisDistance */0);
- mSlideAllowanceSquare = (int)(slideAllowance * slideAllowance);
- // Top slide allowance is slightly longer (sqrt(2) times) than other edges.
- mSlideAllowanceSquareTop = mSlideAllowanceSquare * 2;
- }
-
- @Override
- protected int getMaxNearbyKeys() {
- // No nearby key will be returned.
- return 1;
- }
-
- @Override
- public int getKeyIndexAndNearbyCodes(int x, int y, final int[] allCodes) {
- final List<Key> keys = getKeyboard().mKeys;
- final int touchX = getTouchX(x);
- final int touchY = getTouchY(y);
-
- int nearestIndex = NOT_A_KEY;
- int nearestDist = (y < 0) ? mSlideAllowanceSquareTop : mSlideAllowanceSquare;
- final int keyCount = keys.size();
- for (int index = 0; index < keyCount; index++) {
- final int dist = keys.get(index).squaredDistanceToEdge(touchX, touchY);
- if (dist < nearestDist) {
- nearestIndex = index;
- nearestDist = dist;
- }
- }
-
- if (allCodes != null && nearestIndex != NOT_A_KEY)
- allCodes[0] = keys.get(nearestIndex).mCode;
- return nearestIndex;
- }
-}
diff --git a/java/src/com/android/inputmethod/keyboard/PointerTracker.java b/java/src/com/android/inputmethod/keyboard/PointerTracker.java
index 1f8119a0f..d33cb442b 100644
--- a/java/src/com/android/inputmethod/keyboard/PointerTracker.java
+++ b/java/src/com/android/inputmethod/keyboard/PointerTracker.java
@@ -438,9 +438,9 @@ public class PointerTracker {
private void onDownEventInternal(int x, int y, long eventTime) {
int keyIndex = onDownKey(x, y, eventTime);
// Sliding key is allowed when 1) enabled by configuration, 2) this pointer starts sliding
- // from modifier key, or 3) this pointer is on mini-keyboard.
+ // from modifier key, or 3) this pointer's KeyDetector always allows sliding input.
mIsAllowedSlidingKeyInput = sConfigSlidingKeyInputEnabled || isModifierInternal(keyIndex)
- || mKeyDetector instanceof MiniKeyboardKeyDetector;
+ || mKeyDetector.alwaysAllowsSlidingInput();
mKeyboardLayoutHasBeenChanged = false;
mKeyAlreadyProcessed = false;
mIsRepeatableKey = false;
diff --git a/java/src/com/android/inputmethod/keyboard/PopupMiniKeyboardView.java b/java/src/com/android/inputmethod/keyboard/PopupMiniKeyboardView.java
index fb932e3e8..1230dfb44 100644
--- a/java/src/com/android/inputmethod/keyboard/PopupMiniKeyboardView.java
+++ b/java/src/com/android/inputmethod/keyboard/PopupMiniKeyboardView.java
@@ -28,6 +28,8 @@ import com.android.inputmethod.keyboard.PointerTracker.DrawingProxy;
import com.android.inputmethod.keyboard.PointerTracker.TimerProxy;
import com.android.inputmethod.latin.R;
+import java.util.List;
+
/**
* A view that renders a virtual {@link MiniKeyboard}. It handles rendering of keys and detecting
* key presses and touch movements.
@@ -43,6 +45,51 @@ public class PopupMiniKeyboardView extends KeyboardView implements PopupPanel {
private int mOriginX;
private int mOriginY;
+ private static class MiniKeyboardKeyDetector extends KeyDetector {
+ private final int mSlideAllowanceSquare;
+ private final int mSlideAllowanceSquareTop;
+
+ public MiniKeyboardKeyDetector(float slideAllowance) {
+ super(/* keyHysteresisDistance */0);
+ mSlideAllowanceSquare = (int)(slideAllowance * slideAllowance);
+ // Top slide allowance is slightly longer (sqrt(2) times) than other edges.
+ mSlideAllowanceSquareTop = mSlideAllowanceSquare * 2;
+ }
+
+ @Override
+ public boolean alwaysAllowsSlidingInput() {
+ return true;
+ }
+
+ @Override
+ protected int getMaxNearbyKeys() {
+ // No nearby key will be returned.
+ return 1;
+ }
+
+ @Override
+ public int getKeyIndexAndNearbyCodes(int x, int y, final int[] allCodes) {
+ final List<Key> keys = getKeyboard().mKeys;
+ final int touchX = getTouchX(x);
+ final int touchY = getTouchY(y);
+
+ int nearestIndex = NOT_A_KEY;
+ int nearestDist = (y < 0) ? mSlideAllowanceSquareTop : mSlideAllowanceSquare;
+ final int keyCount = keys.size();
+ for (int index = 0; index < keyCount; index++) {
+ final int dist = keys.get(index).squaredDistanceToEdge(touchX, touchY);
+ if (dist < nearestDist) {
+ nearestIndex = index;
+ nearestDist = dist;
+ }
+ }
+
+ if (allCodes != null && nearestIndex != NOT_A_KEY)
+ allCodes[0] = keys.get(nearestIndex).mCode;
+ return nearestIndex;
+ }
+ }
+
private static final TimerProxy EMPTY_TIMER_PROXY = new TimerProxy() {
@Override
public void startKeyRepeatTimer(long delay, int keyIndex, PointerTracker tracker) {}
@@ -146,11 +193,6 @@ public class PopupMiniKeyboardView extends KeyboardView implements PopupPanel {
}
@Override
- protected void onSizeChanged(int w, int h, int oldw, int oldh) {
- // Do nothing for the mini keyboard.
- }
-
- @Override
public void setKeyPreviewPopupEnabled(boolean previewEnabled, int delay) {
// Mini keyboard needs no pop-up key preview displayed, so we pass always false with a
// delay of 0. The delay does not matter actually since the popup is not shown anyway.
diff --git a/java/src/com/android/inputmethod/keyboard/internal/MiniKeyboardBuilder.java b/java/src/com/android/inputmethod/keyboard/internal/MiniKeyboardBuilder.java
deleted file mode 100644
index 31a291cef..000000000
--- a/java/src/com/android/inputmethod/keyboard/internal/MiniKeyboardBuilder.java
+++ /dev/null
@@ -1,259 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * 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.internal;
-
-import android.graphics.Paint;
-import android.graphics.Rect;
-
-import com.android.inputmethod.keyboard.Key;
-import com.android.inputmethod.keyboard.Keyboard;
-import com.android.inputmethod.keyboard.KeyboardView;
-import com.android.inputmethod.keyboard.MiniKeyboard;
-import com.android.inputmethod.latin.R;
-
-public class MiniKeyboardBuilder extends
- KeyboardBuilder<MiniKeyboardBuilder.MiniKeyboardParams> {
- private final CharSequence[] mPopupCharacters;
-
- public static class MiniKeyboardParams extends KeyboardParams {
- /* package */ int mTopRowAdjustment;
- public int mNumRows;
- public int mNumColumns;
- public int mLeftKeys;
- public int mRightKeys; // includes default key.
-
- public MiniKeyboardParams() {
- super();
- }
-
- /* package for test */ MiniKeyboardParams(int numKeys, int maxColumns, int keyWidth,
- int rowHeight, int coordXInParent, int parentKeyboardWidth) {
- super();
- setParameters(
- numKeys, maxColumns, keyWidth, rowHeight, coordXInParent, parentKeyboardWidth);
- }
-
- /**
- * Set keyboard parameters of mini keyboard.
- *
- * @param numKeys number of keys in this mini keyboard.
- * @param maxColumns number of maximum columns of this mini keyboard.
- * @param keyWidth mini keyboard key width in pixel, including horizontal gap.
- * @param rowHeight mini keyboard row height in pixel, including vertical gap.
- * @param coordXInParent coordinate x of the popup key in parent keyboard.
- * @param parentKeyboardWidth parent keyboard width in pixel.
- */
- public void setParameters(int numKeys, int maxColumns, int keyWidth, int rowHeight,
- int coordXInParent, int parentKeyboardWidth) {
- if (parentKeyboardWidth / keyWidth < maxColumns) {
- throw new IllegalArgumentException("Keyboard is too small to hold mini keyboard: "
- + parentKeyboardWidth + " " + keyWidth + " " + maxColumns);
- }
- mDefaultKeyWidth = keyWidth;
- mDefaultRowHeight = rowHeight;
-
- final int numRows = (numKeys + maxColumns - 1) / maxColumns;
- mNumRows = numRows;
- final int numColumns = getOptimizedColumns(numKeys, maxColumns);
- mNumColumns = numColumns;
-
- final int numLeftKeys = (numColumns - 1) / 2;
- final int numRightKeys = numColumns - numLeftKeys; // including default key.
- final int maxLeftKeys = coordXInParent / keyWidth;
- final int maxRightKeys = Math.max(1, (parentKeyboardWidth - coordXInParent) / keyWidth);
- int leftKeys, rightKeys;
- if (numLeftKeys > maxLeftKeys) {
- leftKeys = maxLeftKeys;
- rightKeys = numColumns - maxLeftKeys;
- } else if (numRightKeys > maxRightKeys) {
- leftKeys = numColumns - maxRightKeys;
- rightKeys = maxRightKeys;
- } else {
- leftKeys = numLeftKeys;
- rightKeys = numRightKeys;
- }
- // Shift right if the left edge of mini keyboard is on the edge of parent keyboard
- // unless the parent key is on the left edge.
- if (leftKeys * keyWidth >= coordXInParent && leftKeys > 0) {
- leftKeys--;
- rightKeys++;
- }
- // Shift left if the right edge of mini keyboard is on the edge of parent keyboard
- // unless the parent key is on the right edge.
- if (rightKeys * keyWidth + coordXInParent >= parentKeyboardWidth && rightKeys > 1) {
- leftKeys++;
- rightKeys--;
- }
- mLeftKeys = leftKeys;
- mRightKeys = rightKeys;
-
- // Centering of the top row.
- final boolean onEdge = (leftKeys == 0 || rightKeys == 1);
- if (numRows < 2 || onEdge || getTopRowEmptySlots(numKeys, numColumns) % 2 == 0) {
- mTopRowAdjustment = 0;
- } else if (mLeftKeys < mRightKeys - 1) {
- mTopRowAdjustment = 1;
- } else {
- mTopRowAdjustment = -1;
- }
-
- mWidth = mOccupiedWidth = mNumColumns * mDefaultKeyWidth;
- mHeight = mOccupiedHeight = mNumRows * mDefaultRowHeight + mVerticalGap;
- }
-
- // Return key position according to column count (0 is default).
- /* package */ int getColumnPos(int n) {
- final int col = n % mNumColumns;
- if (col == 0) {
- // default position.
- return 0;
- }
- int pos = 0;
- int right = 1; // include default position key.
- int left = 0;
- int i = 0;
- while (true) {
- // Assign right key if available.
- if (right < mRightKeys) {
- pos = right;
- right++;
- i++;
- }
- if (i >= col)
- break;
- // Assign left key if available.
- if (left < mLeftKeys) {
- left++;
- pos = -left;
- i++;
- }
- if (i >= col)
- break;
- }
- return pos;
- }
-
- private static int getTopRowEmptySlots(int numKeys, int numColumns) {
- final int remainingKeys = numKeys % numColumns;
- if (remainingKeys == 0) {
- return 0;
- } else {
- return numColumns - remainingKeys;
- }
- }
-
- private int getOptimizedColumns(int numKeys, int maxColumns) {
- int numColumns = Math.min(numKeys, maxColumns);
- while (getTopRowEmptySlots(numKeys, numColumns) >= mNumRows) {
- numColumns--;
- }
- return numColumns;
- }
-
- public int getDefaultKeyCoordX() {
- return mLeftKeys * mDefaultKeyWidth;
- }
-
- public int getX(int n, int row) {
- final int x = getColumnPos(n) * mDefaultKeyWidth + getDefaultKeyCoordX();
- if (isTopRow(row)) {
- return x + mTopRowAdjustment * (mDefaultKeyWidth / 2);
- }
- return x;
- }
-
- public int getY(int row) {
- return (mNumRows - 1 - row) * mDefaultRowHeight + mTopPadding;
- }
-
- public int getRowFlags(int row) {
- int rowFlags = 0;
- if (row == 0) rowFlags |= Keyboard.EDGE_TOP;
- if (isTopRow(row)) rowFlags |= Keyboard.EDGE_BOTTOM;
- return rowFlags;
- }
-
- private boolean isTopRow(int rowCount) {
- return rowCount == mNumRows - 1;
- }
- }
-
- public MiniKeyboardBuilder(KeyboardView view, int xmlId, Key parentKey,
- Keyboard parentKeyboard) {
- super(view.getContext(), new MiniKeyboardParams());
- load(parentKeyboard.mId.cloneWithNewXml(mResources.getResourceEntryName(xmlId), xmlId));
-
- // HACK: Current mini keyboard design totally relies on the 9-patch padding about horizontal
- // and vertical key spacing. To keep the visual of mini keyboard as is, these hacks are
- // needed to keep having the same horizontal and vertical key spacing.
- mParams.mHorizontalGap = 0;
- mParams.mVerticalGap = mParams.mTopPadding = parentKeyboard.mVerticalGap / 2;
- // TODO: When we have correctly padded key background 9-patch drawables for mini keyboard,
- // revert the above hacks and uncomment the following lines.
- //mParams.mHorizontalGap = parentKeyboard.mHorizontalGap;
- //mParams.mVerticalGap = parentKeyboard.mVerticalGap;
-
- mParams.mIsRtlKeyboard = parentKeyboard.mIsRtlKeyboard;
- mPopupCharacters = parentKey.mPopupCharacters;
-
- final int keyWidth = getMaxKeyWidth(view, mPopupCharacters, mParams.mDefaultKeyWidth);
- mParams.setParameters(
- mPopupCharacters.length, parentKey.mMaxPopupColumn,
- keyWidth, parentKeyboard.mDefaultRowHeight,
- parentKey.mX + (mParams.mDefaultKeyWidth - keyWidth) / 2,
- view.getMeasuredWidth());
- }
-
- private static int getMaxKeyWidth(KeyboardView view, CharSequence[] popupCharacters,
- int minKeyWidth) {
- Paint paint = null;
- Rect bounds = null;
- int maxWidth = 0;
- for (CharSequence popupSpec : popupCharacters) {
- final CharSequence label = PopupCharactersParser.getLabel(popupSpec.toString());
- // If the label is single letter, minKeyWidth is enough to hold the label.
- if (label != null && label.length() > 1) {
- if (paint == null) {
- paint = new Paint();
- paint.setAntiAlias(true);
- }
- final int labelSize = view.getDefaultLabelSizeAndSetPaint(paint);
- paint.setTextSize(labelSize);
- if (bounds == null) bounds = new Rect();
- paint.getTextBounds(label.toString(), 0, label.length(), bounds);
- if (maxWidth < bounds.width())
- maxWidth = bounds.width();
- }
- }
- final int horizontalPadding = (int)view.getContext().getResources().getDimension(
- R.dimen.mini_keyboard_key_horizontal_padding);
- return Math.max(minKeyWidth, maxWidth + horizontalPadding);
- }
-
- @Override
- public MiniKeyboard build() {
- final MiniKeyboardParams params = mParams;
- for (int n = 0; n < mPopupCharacters.length; n++) {
- final CharSequence label = mPopupCharacters[n];
- final int row = n / params.mNumColumns;
- final Key key = new Key(mResources, params, label, params.getX(n, row), params.getY(row),
- params.mDefaultKeyWidth, params.mDefaultRowHeight, params.getRowFlags(row));
- params.onAddKey(key);
- }
- return new MiniKeyboard(params);
- }
-}