MoreKeysKeyboard.java revision be34d973349909196dc3427a5653f4e119092ea7
104c96ab966e8a58e5cd401362b49509751ce75d9Tadashi G. Takaoka/* 28632bff2d5a8e1160989008dea6eff4b94b065ddTadashi G. Takaoka * Copyright (C) 2011 The Android Open Source Project 304c96ab966e8a58e5cd401362b49509751ce75d9Tadashi G. Takaoka * 404c96ab966e8a58e5cd401362b49509751ce75d9Tadashi G. Takaoka * Licensed under the Apache License, Version 2.0 (the "License"); you may not 504c96ab966e8a58e5cd401362b49509751ce75d9Tadashi G. Takaoka * use this file except in compliance with the License. You may obtain a copy of 604c96ab966e8a58e5cd401362b49509751ce75d9Tadashi G. Takaoka * the License at 704c96ab966e8a58e5cd401362b49509751ce75d9Tadashi G. Takaoka * 804c96ab966e8a58e5cd401362b49509751ce75d9Tadashi G. Takaoka * http://www.apache.org/licenses/LICENSE-2.0 904c96ab966e8a58e5cd401362b49509751ce75d9Tadashi G. Takaoka * 1004c96ab966e8a58e5cd401362b49509751ce75d9Tadashi G. Takaoka * Unless required by applicable law or agreed to in writing, software 1104c96ab966e8a58e5cd401362b49509751ce75d9Tadashi G. Takaoka * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 1204c96ab966e8a58e5cd401362b49509751ce75d9Tadashi G. Takaoka * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 1304c96ab966e8a58e5cd401362b49509751ce75d9Tadashi G. Takaoka * License for the specific language governing permissions and limitations under 1404c96ab966e8a58e5cd401362b49509751ce75d9Tadashi G. Takaoka * the License. 1504c96ab966e8a58e5cd401362b49509751ce75d9Tadashi G. Takaoka */ 1604c96ab966e8a58e5cd401362b49509751ce75d9Tadashi G. Takaoka 1704c96ab966e8a58e5cd401362b49509751ce75d9Tadashi G. Takaokapackage com.android.inputmethod.keyboard; 1804c96ab966e8a58e5cd401362b49509751ce75d9Tadashi G. Takaoka 1932572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaokaimport android.graphics.Paint; 2032572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka 2132572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaokaimport com.android.inputmethod.keyboard.internal.KeyboardBuilder; 2232572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaokaimport com.android.inputmethod.keyboard.internal.KeyboardParams; 2332572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaokaimport com.android.inputmethod.keyboard.internal.PopupCharactersParser; 2432572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaokaimport com.android.inputmethod.latin.R; 2504c96ab966e8a58e5cd401362b49509751ce75d9Tadashi G. Takaoka 2604c96ab966e8a58e5cd401362b49509751ce75d9Tadashi G. Takaokapublic class MiniKeyboard extends Keyboard { 278da9a13760896cd78235b60d0ea680ea13620532Tadashi G. Takaoka private final int mDefaultKeyCoordX; 2804c96ab966e8a58e5cd401362b49509751ce75d9Tadashi G. Takaoka 2932572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka private MiniKeyboard(Builder.MiniKeyboardParams params) { 308da9a13760896cd78235b60d0ea680ea13620532Tadashi G. Takaoka super(params); 318da9a13760896cd78235b60d0ea680ea13620532Tadashi G. Takaoka mDefaultKeyCoordX = params.getDefaultKeyCoordX() + params.mDefaultKeyWidth / 2; 3204c96ab966e8a58e5cd401362b49509751ce75d9Tadashi G. Takaoka } 3304c96ab966e8a58e5cd401362b49509751ce75d9Tadashi G. Takaoka 3404c96ab966e8a58e5cd401362b49509751ce75d9Tadashi G. Takaoka public int getDefaultCoordX() { 3504c96ab966e8a58e5cd401362b49509751ce75d9Tadashi G. Takaoka return mDefaultKeyCoordX; 3604c96ab966e8a58e5cd401362b49509751ce75d9Tadashi G. Takaoka } 3732572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka 3832572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka public static class Builder extends KeyboardBuilder<Builder.MiniKeyboardParams> { 3932572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka private final CharSequence[] mPopupCharacters; 4032572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka 4132572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka public static class MiniKeyboardParams extends KeyboardParams { 4232572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka /* package */int mTopRowAdjustment; 4332572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka public int mNumRows; 4432572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka public int mNumColumns; 4532572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka public int mLeftKeys; 4632572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka public int mRightKeys; // includes default key. 4732572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka 4832572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka public MiniKeyboardParams() { 4932572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka super(); 5032572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka } 5132572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka 5232572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka /* package for test */MiniKeyboardParams(int numKeys, int maxColumns, int keyWidth, 5332572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka int rowHeight, int coordXInParent, int parentKeyboardWidth) { 5432572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka super(); 5532572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka setParameters(numKeys, maxColumns, keyWidth, rowHeight, coordXInParent, 5632572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka parentKeyboardWidth); 5732572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka } 5832572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka 5932572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka /** 6032572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka * Set keyboard parameters of mini keyboard. 6132572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka * 6232572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka * @param numKeys number of keys in this mini keyboard. 6332572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka * @param maxColumns number of maximum columns of this mini keyboard. 6432572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka * @param keyWidth mini keyboard key width in pixel, including horizontal gap. 6532572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka * @param rowHeight mini keyboard row height in pixel, including vertical gap. 6632572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka * @param coordXInParent coordinate x of the popup key in parent keyboard. 6732572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka * @param parentKeyboardWidth parent keyboard width in pixel. 6832572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka */ 6932572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka public void setParameters(int numKeys, int maxColumns, int keyWidth, int rowHeight, 7032572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka int coordXInParent, int parentKeyboardWidth) { 7132572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka if (parentKeyboardWidth / keyWidth < maxColumns) { 7232572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka throw new IllegalArgumentException( 7332572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka "Keyboard is too small to hold mini keyboard: " + parentKeyboardWidth 7432572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka + " " + keyWidth + " " + maxColumns); 7532572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka } 7632572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka mDefaultKeyWidth = keyWidth; 7732572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka mDefaultRowHeight = rowHeight; 7832572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka 7932572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka final int numRows = (numKeys + maxColumns - 1) / maxColumns; 8032572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka mNumRows = numRows; 8132572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka final int numColumns = getOptimizedColumns(numKeys, maxColumns); 8232572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka mNumColumns = numColumns; 8332572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka 8432572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka final int numLeftKeys = (numColumns - 1) / 2; 8532572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka final int numRightKeys = numColumns - numLeftKeys; // including default key. 8632572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka final int maxLeftKeys = coordXInParent / keyWidth; 8732572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka final int maxRightKeys = Math.max(1, (parentKeyboardWidth - coordXInParent) 8832572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka / keyWidth); 8932572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka int leftKeys, rightKeys; 9032572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka if (numLeftKeys > maxLeftKeys) { 9132572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka leftKeys = maxLeftKeys; 9232572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka rightKeys = numColumns - maxLeftKeys; 9332572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka } else if (numRightKeys > maxRightKeys) { 9432572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka leftKeys = numColumns - maxRightKeys; 9532572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka rightKeys = maxRightKeys; 9632572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka } else { 9732572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka leftKeys = numLeftKeys; 9832572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka rightKeys = numRightKeys; 9932572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka } 10032572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka // Shift right if the left edge of mini keyboard is on the edge of parent keyboard 10132572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka // unless the parent key is on the left edge. 10232572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka if (leftKeys * keyWidth >= coordXInParent && leftKeys > 0) { 10332572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka leftKeys--; 10432572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka rightKeys++; 10532572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka } 10632572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka // Shift left if the right edge of mini keyboard is on the edge of parent keyboard 10732572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka // unless the parent key is on the right edge. 10832572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka if (rightKeys * keyWidth + coordXInParent >= parentKeyboardWidth && rightKeys > 1) { 10932572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka leftKeys++; 11032572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka rightKeys--; 11132572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka } 11232572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka mLeftKeys = leftKeys; 11332572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka mRightKeys = rightKeys; 11432572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka 11532572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka // Centering of the top row. 11632572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka final boolean onEdge = (leftKeys == 0 || rightKeys == 1); 11732572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka if (numRows < 2 || onEdge || getTopRowEmptySlots(numKeys, numColumns) % 2 == 0) { 11832572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka mTopRowAdjustment = 0; 11932572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka } else if (mLeftKeys < mRightKeys - 1) { 12032572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka mTopRowAdjustment = 1; 12132572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka } else { 12232572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka mTopRowAdjustment = -1; 12332572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka } 12432572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka 12532572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka mWidth = mOccupiedWidth = mNumColumns * mDefaultKeyWidth; 12632572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka mHeight = mOccupiedHeight = mNumRows * mDefaultRowHeight + mVerticalGap; 12732572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka } 12832572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka 12932572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka // Return key position according to column count (0 is default). 13032572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka /* package */int getColumnPos(int n) { 13132572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka final int col = n % mNumColumns; 13232572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka if (col == 0) { 13332572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka // default position. 13432572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka return 0; 13532572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka } 13632572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka int pos = 0; 13732572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka int right = 1; // include default position key. 13832572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka int left = 0; 13932572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka int i = 0; 14032572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka while (true) { 14132572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka // Assign right key if available. 14232572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka if (right < mRightKeys) { 14332572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka pos = right; 14432572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka right++; 14532572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka i++; 14632572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka } 14732572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka if (i >= col) 14832572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka break; 14932572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka // Assign left key if available. 15032572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka if (left < mLeftKeys) { 15132572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka left++; 15232572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka pos = -left; 15332572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka i++; 15432572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka } 15532572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka if (i >= col) 15632572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka break; 15732572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka } 15832572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka return pos; 15932572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka } 16032572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka 16132572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka private static int getTopRowEmptySlots(int numKeys, int numColumns) { 16232572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka final int remainingKeys = numKeys % numColumns; 16332572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka if (remainingKeys == 0) { 16432572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka return 0; 16532572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka } else { 16632572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka return numColumns - remainingKeys; 16732572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka } 16832572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka } 16932572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka 17032572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka private int getOptimizedColumns(int numKeys, int maxColumns) { 17132572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka int numColumns = Math.min(numKeys, maxColumns); 17232572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka while (getTopRowEmptySlots(numKeys, numColumns) >= mNumRows) { 17332572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka numColumns--; 17432572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka } 17532572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka return numColumns; 17632572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka } 17732572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka 17832572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka public int getDefaultKeyCoordX() { 17932572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka return mLeftKeys * mDefaultKeyWidth; 18032572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka } 18132572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka 18232572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka public int getX(int n, int row) { 18332572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka final int x = getColumnPos(n) * mDefaultKeyWidth + getDefaultKeyCoordX(); 18432572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka if (isTopRow(row)) { 18532572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka return x + mTopRowAdjustment * (mDefaultKeyWidth / 2); 18632572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka } 18732572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka return x; 18832572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka } 18932572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka 19032572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka public int getY(int row) { 19132572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka return (mNumRows - 1 - row) * mDefaultRowHeight + mTopPadding; 19232572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka } 19332572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka 19432572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka public int getRowFlags(int row) { 19532572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka int rowFlags = 0; 19632572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka if (row == 0) 19732572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka rowFlags |= Keyboard.EDGE_TOP; 19832572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka if (isTopRow(row)) 19932572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka rowFlags |= Keyboard.EDGE_BOTTOM; 20032572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka return rowFlags; 20132572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka } 20232572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka 20332572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka private boolean isTopRow(int rowCount) { 20432572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka return rowCount == mNumRows - 1; 20532572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka } 20632572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka } 20732572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka 20832572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka public Builder(KeyboardView view, int xmlId, Key parentKey, Keyboard parentKeyboard) { 20932572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka super(view.getContext(), new MiniKeyboardParams()); 21032572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka load(parentKeyboard.mId.cloneWithNewXml(mResources.getResourceEntryName(xmlId), xmlId)); 21132572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka 21232572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka // HACK: Current mini keyboard design totally relies on the 9-patch 21332572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka // padding about horizontal 21432572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka // and vertical key spacing. To keep the visual of mini keyboard as 21532572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka // is, these hacks are 21632572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka // needed to keep having the same horizontal and vertical key 21732572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka // spacing. 21832572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka mParams.mHorizontalGap = 0; 21932572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka mParams.mVerticalGap = mParams.mTopPadding = parentKeyboard.mVerticalGap / 2; 22032572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka // TODO: When we have correctly padded key background 9-patch 22132572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka // drawables for mini keyboard, 22232572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka // revert the above hacks and uncomment the following lines. 22332572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka // mParams.mHorizontalGap = parentKeyboard.mHorizontalGap; 22432572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka // mParams.mVerticalGap = parentKeyboard.mVerticalGap; 22532572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka 22632572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka mParams.mIsRtlKeyboard = parentKeyboard.mIsRtlKeyboard; 22732572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka mPopupCharacters = parentKey.mPopupCharacters; 22832572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka 22932572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka final int keyWidth = getMaxKeyWidth(view, mPopupCharacters, mParams.mDefaultKeyWidth); 23032572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka mParams.setParameters(mPopupCharacters.length, parentKey.mMaxPopupColumn, keyWidth, 23132572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka parentKeyboard.mDefaultRowHeight, parentKey.mX 23232572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka + (mParams.mDefaultKeyWidth - keyWidth) / 2, view.getMeasuredWidth()); 23332572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka } 23432572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka 23532572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka private static int getMaxKeyWidth(KeyboardView view, CharSequence[] popupCharacters, 23632572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka int minKeyWidth) { 237be34d973349909196dc3427a5653f4e119092ea7Tadashi G. Takaoka final int padding = (int) view.getContext().getResources() 238be34d973349909196dc3427a5653f4e119092ea7Tadashi G. Takaoka .getDimension(R.dimen.mini_keyboard_key_horizontal_padding); 23932572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka Paint paint = null; 2402315bfc7c8df0f6d9fb627456f2a298f5580b52dTadashi G. Takaoka int maxWidth = minKeyWidth; 24132572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka for (CharSequence popupSpec : popupCharacters) { 24232572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka final CharSequence label = PopupCharactersParser.getLabel(popupSpec.toString()); 24332572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka // If the label is single letter, minKeyWidth is enough to hold 24432572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka // the label. 24532572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka if (label != null && label.length() > 1) { 24632572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka if (paint == null) { 24732572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka paint = new Paint(); 24832572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka paint.setAntiAlias(true); 24932572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka } 250be34d973349909196dc3427a5653f4e119092ea7Tadashi G. Takaoka final int width = (int)view.getDefaultLabelWidth(label, paint) + padding; 2512315bfc7c8df0f6d9fb627456f2a298f5580b52dTadashi G. Takaoka if (maxWidth < width) { 2522315bfc7c8df0f6d9fb627456f2a298f5580b52dTadashi G. Takaoka maxWidth = width; 2532315bfc7c8df0f6d9fb627456f2a298f5580b52dTadashi G. Takaoka } 25432572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka } 25532572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka } 256be34d973349909196dc3427a5653f4e119092ea7Tadashi G. Takaoka return maxWidth; 25732572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka } 25832572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka 25932572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka @Override 26032572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka public MiniKeyboard build() { 26132572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka final MiniKeyboardParams params = mParams; 26232572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka for (int n = 0; n < mPopupCharacters.length; n++) { 26332572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka final CharSequence label = mPopupCharacters[n]; 26432572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka final int row = n / params.mNumColumns; 265be34d973349909196dc3427a5653f4e119092ea7Tadashi G. Takaoka final Key key = new Key(mResources, params, label, null, params.getX(n, row), 26632572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka params.getY(row), params.mDefaultKeyWidth, params.mDefaultRowHeight, 26732572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka params.getRowFlags(row)); 26832572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka params.onAddKey(key); 26932572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka } 27032572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka return new MiniKeyboard(params); 27132572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka } 27232572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka } 27304c96ab966e8a58e5cd401362b49509751ce75d9Tadashi G. Takaoka} 274