104c96ab966e8a58e5cd401362b49509751ce75d9Tadashi G. Takaoka/*
28632bff2d5a8e1160989008dea6eff4b94b065ddTadashi G. Takaoka * Copyright (C) 2011 The Android Open Source Project
304c96ab966e8a58e5cd401362b49509751ce75d9Tadashi G. Takaoka *
48aa9963a895f9dd5bb1bc92ab2e4f461e058f87aTadashi G. Takaoka * Licensed under the Apache License, Version 2.0 (the "License");
58aa9963a895f9dd5bb1bc92ab2e4f461e058f87aTadashi G. Takaoka * you may not use this file except in compliance with the License.
68aa9963a895f9dd5bb1bc92ab2e4f461e058f87aTadashi G. Takaoka * You may obtain a copy of the License at
704c96ab966e8a58e5cd401362b49509751ce75d9Tadashi G. Takaoka *
88aa9963a895f9dd5bb1bc92ab2e4f461e058f87aTadashi 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
118aa9963a895f9dd5bb1bc92ab2e4f461e058f87aTadashi G. Takaoka * distributed under the License is distributed on an "AS IS" BASIS,
128aa9963a895f9dd5bb1bc92ab2e4f461e058f87aTadashi G. Takaoka * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
138aa9963a895f9dd5bb1bc92ab2e4f461e058f87aTadashi G. Takaoka * See the License for the specific language governing permissions and
148aa9963a895f9dd5bb1bc92ab2e4f461e058f87aTadashi G. Takaoka * limitations under the License.
1504c96ab966e8a58e5cd401362b49509751ce75d9Tadashi G. Takaoka */
1604c96ab966e8a58e5cd401362b49509751ce75d9Tadashi G. Takaoka
1704c96ab966e8a58e5cd401362b49509751ce75d9Tadashi G. Takaokapackage com.android.inputmethod.keyboard;
1804c96ab966e8a58e5cd401362b49509751ce75d9Tadashi G. Takaoka
19a729377395967f7652d93992cbcf50cd2ff522d1Tadashi G. Takaokaimport android.content.Context;
2008ae0d5ca03ed455827e82222df249d1cafb5d71Tadashi G. Takaokaimport android.content.res.Resources;
2132572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaokaimport android.graphics.Paint;
225ef4fccbb90491e1f6c2e87b47ebf9f3659949fbTadashi G. Takaokaimport android.graphics.drawable.Drawable;
2332572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka
2415f6d4ae34664ea3d92827a2c3003198c0bac70bTadashi G. Takaokaimport com.android.inputmethod.annotations.UsedForTesting;
250e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaokaimport com.android.inputmethod.keyboard.internal.KeyPreviewDrawParams;
2635ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaokaimport com.android.inputmethod.keyboard.internal.KeyboardBuilder;
275ef4fccbb90491e1f6c2e87b47ebf9f3659949fbTadashi G. Takaokaimport com.android.inputmethod.keyboard.internal.KeyboardIconsSet;
2835ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaokaimport com.android.inputmethod.keyboard.internal.KeyboardParams;
2935ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaokaimport com.android.inputmethod.keyboard.internal.MoreKeySpec;
3032572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaokaimport com.android.inputmethod.latin.R;
31cc8c8b99bd0463f5977dea82f5e2379ea1dd4e73Tadashi G. Takaokaimport com.android.inputmethod.latin.StringUtils;
3204c96ab966e8a58e5cd401362b49509751ce75d9Tadashi G. Takaoka
33a28a05e971cc242b338331a3b78276fa95188d19Tadashi G. Takaokapublic final class MoreKeysKeyboard extends Keyboard {
348da9a13760896cd78235b60d0ea680ea13620532Tadashi G. Takaoka    private final int mDefaultKeyCoordX;
3504c96ab966e8a58e5cd401362b49509751ce75d9Tadashi G. Takaoka
3635ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka    MoreKeysKeyboard(final MoreKeysKeyboardParams params) {
378da9a13760896cd78235b60d0ea680ea13620532Tadashi G. Takaoka        super(params);
388da9a13760896cd78235b60d0ea680ea13620532Tadashi G. Takaoka        mDefaultKeyCoordX = params.getDefaultKeyCoordX() + params.mDefaultKeyWidth / 2;
3904c96ab966e8a58e5cd401362b49509751ce75d9Tadashi G. Takaoka    }
4004c96ab966e8a58e5cd401362b49509751ce75d9Tadashi G. Takaoka
4104c96ab966e8a58e5cd401362b49509751ce75d9Tadashi G. Takaoka    public int getDefaultCoordX() {
4204c96ab966e8a58e5cd401362b49509751ce75d9Tadashi G. Takaoka        return mDefaultKeyCoordX;
4304c96ab966e8a58e5cd401362b49509751ce75d9Tadashi G. Takaoka    }
4432572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka
4515f6d4ae34664ea3d92827a2c3003198c0bac70bTadashi G. Takaoka    @UsedForTesting
4635ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka    static class MoreKeysKeyboardParams extends KeyboardParams {
4735ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka        public boolean mIsFixedOrder;
4835ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka        /* package */int mTopRowAdjustment;
4935ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka        public int mNumRows;
5035ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka        public int mNumColumns;
5135ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka        public int mTopKeys;
5235ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka        public int mLeftKeys;
5335ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka        public int mRightKeys; // includes default key.
5435ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka        public int mDividerWidth;
5535ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka        public int mColumnWidth;
5635ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka
5735ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka        public MoreKeysKeyboardParams() {
5835ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka            super();
5935ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka        }
60e4c45c6ef920b9cd1754f345446f53c504a64c5fTadashi G. Takaoka
6135ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka        /**
6235ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka         * Set keyboard parameters of more keys keyboard.
6335ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka         *
6435ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka         * @param numKeys number of keys in this more keys keyboard.
6535ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka         * @param maxColumns number of maximum columns of this more keys keyboard.
6635ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka         * @param keyWidth more keys keyboard key width in pixel, including horizontal gap.
6735ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka         * @param rowHeight more keys keyboard row height in pixel, including vertical gap.
6835ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka         * @param coordXInParent coordinate x of the key preview in parent keyboard.
6935ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka         * @param parentKeyboardWidth parent keyboard width in pixel.
7035ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka         * @param isFixedColumnOrder if true, more keys should be laid out in fixed order.
7135ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka         * @param dividerWidth width of divider, zero for no dividers.
7235ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka         */
7335ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka        public void setParameters(final int numKeys, final int maxColumns, final int keyWidth,
7435ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka                final int rowHeight, final int coordXInParent, final int parentKeyboardWidth,
7535ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka                final boolean isFixedColumnOrder, final int dividerWidth) {
7635ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka            mIsFixedOrder = isFixedColumnOrder;
77a4463d7a9a9b97ad0fba764698f75cd3bf036c12Tadashi G. Takaoka            if (parentKeyboardWidth / keyWidth < Math.min(numKeys, maxColumns)) {
7835ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka                throw new IllegalArgumentException(
7935ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka                        "Keyboard is too small to hold more keys keyboard: "
80a4463d7a9a9b97ad0fba764698f75cd3bf036c12Tadashi G. Takaoka                                + parentKeyboardWidth + " " + keyWidth + " "
81a4463d7a9a9b97ad0fba764698f75cd3bf036c12Tadashi G. Takaoka                                + numKeys + " " + maxColumns);
8232572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka            }
8335ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka            mDefaultKeyWidth = keyWidth;
8435ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka            mDefaultRowHeight = rowHeight;
8535ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka
8635ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka            final int numRows = (numKeys + maxColumns - 1) / maxColumns;
8735ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka            mNumRows = numRows;
8835ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka            final int numColumns = mIsFixedOrder ? Math.min(numKeys, maxColumns)
8935ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka                    : getOptimizedColumns(numKeys, maxColumns);
9035ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka            mNumColumns = numColumns;
9135ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka            final int topKeys = numKeys % numColumns;
9235ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka            mTopKeys = topKeys == 0 ? numColumns : topKeys;
9335ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka
9435ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka            final int numLeftKeys = (numColumns - 1) / 2;
9535ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka            final int numRightKeys = numColumns - numLeftKeys; // including default key.
9635ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka            // Maximum number of keys we can layout both side of the parent key
9735ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka            final int maxLeftKeys = coordXInParent / keyWidth;
9835ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka            final int maxRightKeys = (parentKeyboardWidth - coordXInParent) / keyWidth;
9935ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka            int leftKeys, rightKeys;
10035ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka            if (numLeftKeys > maxLeftKeys) {
10135ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka                leftKeys = maxLeftKeys;
10235ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka                rightKeys = numColumns - leftKeys;
10335ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka            } else if (numRightKeys > maxRightKeys + 1) {
10435ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka                rightKeys = maxRightKeys + 1; // include default key
10535ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka                leftKeys = numColumns - rightKeys;
10635ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka            } else {
10735ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka                leftKeys = numLeftKeys;
10835ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka                rightKeys = numRightKeys;
10932572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka            }
11035ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka            // If the left keys fill the left side of the parent key, entire more keys keyboard
11135ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka            // should be shifted to the right unless the parent key is on the left edge.
11235ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka            if (maxLeftKeys == leftKeys && leftKeys > 0) {
11335ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka                leftKeys--;
11435ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka                rightKeys++;
115aeeed758480b0fac848f4556884d978f3004555bTadashi G. Takaoka            }
11635ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka            // If the right keys fill the right side of the parent key, entire more keys
11735ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka            // should be shifted to the left unless the parent key is on the right edge.
11835ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka            if (maxRightKeys == rightKeys - 1 && rightKeys > 1) {
11935ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka                leftKeys++;
12035ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka                rightKeys--;
121aeeed758480b0fac848f4556884d978f3004555bTadashi G. Takaoka            }
12235ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka            mLeftKeys = leftKeys;
12335ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka            mRightKeys = rightKeys;
12435ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka
12535ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka            // Adjustment of the top row.
12635ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka            mTopRowAdjustment = mIsFixedOrder ? getFixedOrderTopRowAdjustment()
12735ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka                    : getAutoOrderTopRowAdjustment();
12835ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka            mDividerWidth = dividerWidth;
12935ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka            mColumnWidth = mDefaultKeyWidth + mDividerWidth;
13035ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka            mBaseWidth = mOccupiedWidth = mNumColumns * mColumnWidth - mDividerWidth;
13135ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka            // Need to subtract the bottom row's gutter only.
13235ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka            mBaseHeight = mOccupiedHeight = mNumRows * mDefaultRowHeight - mVerticalGap
13335ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka                    + mTopPadding + mBottomPadding;
13435ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka        }
135aeeed758480b0fac848f4556884d978f3004555bTadashi G. Takaoka
13635ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka        private int getFixedOrderTopRowAdjustment() {
13735ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka            if (mNumRows == 1 || mTopKeys % 2 == 1 || mTopKeys == mNumColumns
13835ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka                    || mLeftKeys == 0  || mRightKeys == 1) {
13935ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka                return 0;
140aeeed758480b0fac848f4556884d978f3004555bTadashi G. Takaoka            }
14135ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka            return -1;
14235ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka        }
143aeeed758480b0fac848f4556884d978f3004555bTadashi G. Takaoka
14435ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka        private int getAutoOrderTopRowAdjustment() {
14535ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka            if (mNumRows == 1 || mTopKeys == 1 || mNumColumns % 2 == mTopKeys % 2
14635ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka                    || mLeftKeys == 0 || mRightKeys == 1) {
14735ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka                return 0;
148aeeed758480b0fac848f4556884d978f3004555bTadashi G. Takaoka            }
14935ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka            return -1;
15035ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka        }
151aeeed758480b0fac848f4556884d978f3004555bTadashi G. Takaoka
15235ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka        // Return key position according to column count (0 is default).
15335ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka        /* package */int getColumnPos(final int n) {
15435ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka            return mIsFixedOrder ? getFixedOrderColumnPos(n) : getAutomaticColumnPos(n);
15535ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka        }
156aeeed758480b0fac848f4556884d978f3004555bTadashi G. Takaoka
15735ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka        private int getFixedOrderColumnPos(final int n) {
15835ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka            final int col = n % mNumColumns;
15935ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka            final int row = n / mNumColumns;
16035ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka            if (!isTopRow(row)) {
16135ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka                return col - mLeftKeys;
16235ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka            }
16335ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka            final int rightSideKeys = mTopKeys / 2;
16435ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka            final int leftSideKeys = mTopKeys - (rightSideKeys + 1);
16535ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka            final int pos = col - leftSideKeys;
16635ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka            final int numLeftKeys = mLeftKeys + mTopRowAdjustment;
16735ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka            final int numRightKeys = mRightKeys - 1;
16835ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka            if (numRightKeys >= rightSideKeys && numLeftKeys >= leftSideKeys) {
16932572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka                return pos;
17035ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka            } else if (numRightKeys < rightSideKeys) {
17135ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka                return pos - (rightSideKeys - numRightKeys);
17235ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka            } else { // numLeftKeys < leftSideKeys
17335ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka                return pos + (leftSideKeys - numLeftKeys);
17432572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka            }
17535ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka        }
17632572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka
17735ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka        private int getAutomaticColumnPos(final int n) {
17835ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka            final int col = n % mNumColumns;
17935ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka            final int row = n / mNumColumns;
18035ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka            int leftKeys = mLeftKeys;
18135ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka            if (isTopRow(row)) {
18235ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka                leftKeys += mTopRowAdjustment;
18335ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka            }
18435ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka            if (col == 0) {
18535ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka                // default position.
18635ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka                return 0;
18732572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka            }
18832572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka
18935ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka            int pos = 0;
19035ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka            int right = 1; // include default position key.
19135ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka            int left = 0;
19235ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka            int i = 0;
19335ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka            while (true) {
19435ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka                // Assign right key if available.
19535ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka                if (right < mRightKeys) {
19635ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka                    pos = right;
19735ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka                    right++;
19835ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka                    i++;
19932572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka                }
20035ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka                if (i >= col)
20135ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka                    break;
20235ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka                // Assign left key if available.
20335ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka                if (left < leftKeys) {
20435ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka                    left++;
20535ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka                    pos = -left;
20635ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka                    i++;
20735ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka                }
20835ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka                if (i >= col)
20935ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka                    break;
21032572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka            }
21135ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka            return pos;
21235ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka        }
21332572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka
21435ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka        private static int getTopRowEmptySlots(final int numKeys, final int numColumns) {
21535ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka            final int remainings = numKeys % numColumns;
21635ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka            return remainings == 0 ? 0 : numColumns - remainings;
21735ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka        }
21832572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka
21935ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka        private int getOptimizedColumns(final int numKeys, final int maxColumns) {
22035ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka            int numColumns = Math.min(numKeys, maxColumns);
22135ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka            while (getTopRowEmptySlots(numKeys, numColumns) >= mNumRows) {
22235ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka                numColumns--;
22332572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka            }
22435ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka            return numColumns;
22535ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka        }
22632572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka
22735ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka        public int getDefaultKeyCoordX() {
22835ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka            return mLeftKeys * mColumnWidth;
22935ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka        }
23032572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka
23135ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka        public int getX(final int n, final int row) {
23235ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka            final int x = getColumnPos(n) * mColumnWidth + getDefaultKeyCoordX();
23335ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka            if (isTopRow(row)) {
23435ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka                return x + mTopRowAdjustment * (mColumnWidth / 2);
23532572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka            }
23635ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka            return x;
23735ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka        }
23832572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka
23935ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka        public int getY(final int row) {
24035ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka            return (mNumRows - 1 - row) * mDefaultRowHeight + mTopPadding;
24132572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka        }
24232572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka
24335ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka        public void markAsEdgeKey(final Key key, final int row) {
24435ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka            if (row == 0)
24535ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka                key.markAsTopEdge(this);
24635ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka            if (isTopRow(row))
24735ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka                key.markAsBottomEdge(this);
24835ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka        }
24935ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka
25035ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka        private boolean isTopRow(final int rowCount) {
25135ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka            return mNumRows > 1 && rowCount == mNumRows - 1;
25235ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka        }
25335ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka    }
25435ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka
25535ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka    public static class Builder extends KeyboardBuilder<MoreKeysKeyboardParams> {
25635ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka        private final Key mParentKey;
25735ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka        private final Drawable mDivider;
25835ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka
25935ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka        private static final float LABEL_PADDING_RATIO = 0.2f;
26035ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka        private static final float DIVIDER_RATIO = 0.2f;
26135ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka
2627ecc1081ab9b4e41e4b2aec7877aaaf8df29e611Tadashi G. Takaoka        /**
2637ecc1081ab9b4e41e4b2aec7877aaaf8df29e611Tadashi G. Takaoka         * The builder of MoreKeysKeyboard.
264a729377395967f7652d93992cbcf50cd2ff522d1Tadashi G. Takaoka         * @param context the context of {@link MoreKeysKeyboardView}.
2657ecc1081ab9b4e41e4b2aec7877aaaf8df29e611Tadashi G. Takaoka         * @param parentKey the {@link Key} that invokes more keys keyboard.
2667ecc1081ab9b4e41e4b2aec7877aaaf8df29e611Tadashi G. Takaoka         * @param parentKeyboardView the {@link KeyboardView} that contains the parentKey.
2670e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka         * @param keyPreviewDrawParams the parameter to place key preview.
2687ecc1081ab9b4e41e4b2aec7877aaaf8df29e611Tadashi G. Takaoka         */
269a729377395967f7652d93992cbcf50cd2ff522d1Tadashi G. Takaoka        public Builder(final Context context, final Key parentKey,
2700e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka                final MainKeyboardView parentKeyboardView,
2710e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka                final KeyPreviewDrawParams keyPreviewDrawParams) {
272a729377395967f7652d93992cbcf50cd2ff522d1Tadashi G. Takaoka            super(context, new MoreKeysKeyboardParams());
2737ecc1081ab9b4e41e4b2aec7877aaaf8df29e611Tadashi G. Takaoka            final Keyboard parentKeyboard = parentKeyboardView.getKeyboard();
2747ecc1081ab9b4e41e4b2aec7877aaaf8df29e611Tadashi G. Takaoka            load(parentKeyboard.mMoreKeysTemplate, parentKeyboard.mId);
27532572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka
2762affaf91a04d63e0994102299816014a8bbe11e1Tadashi G. Takaoka            // TODO: More keys keyboard's vertical gap is currently calculated heuristically.
277ea0c567f86bd19015d53fc038c4579df776cfec3Tadashi G. Takaoka            // Should revise the algorithm.
278ea0c567f86bd19015d53fc038c4579df776cfec3Tadashi G. Takaoka            mParams.mVerticalGap = parentKeyboard.mVerticalGap / 2;
27942fd1d2d72c097b2227d4b22f0f824dbb34a4d0cTadashi G. Takaoka            mParentKey = parentKey;
28032572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka
281a0e4f40994f779ad98268921c63d6535ad04224fTadashi G. Takaoka            final int width, height;
2827ecc1081ab9b4e41e4b2aec7877aaaf8df29e611Tadashi G. Takaoka            final boolean singleMoreKeyWithPreview = parentKeyboardView.isKeyPreviewPopupEnabled()
2837ecc1081ab9b4e41e4b2aec7877aaaf8df29e611Tadashi G. Takaoka                    && !parentKey.noKeyPreview() && parentKey.mMoreKeys.length == 1;
28442fd1d2d72c097b2227d4b22f0f824dbb34a4d0cTadashi G. Takaoka            if (singleMoreKeyWithPreview) {
2857ecc1081ab9b4e41e4b2aec7877aaaf8df29e611Tadashi G. Takaoka                // Use pre-computed width and height if this more keys keyboard has only one key to
2867ecc1081ab9b4e41e4b2aec7877aaaf8df29e611Tadashi G. Takaoka                // mitigate visual flicker between key preview and more keys keyboard.
2877ecc1081ab9b4e41e4b2aec7877aaaf8df29e611Tadashi G. Takaoka                // Caveats for the visual assets: To achieve this effect, both the key preview
2887ecc1081ab9b4e41e4b2aec7877aaaf8df29e611Tadashi G. Takaoka                // backgrounds and the more keys keyboard panel background have the exact same
2897ecc1081ab9b4e41e4b2aec7877aaaf8df29e611Tadashi G. Takaoka                // left/right/top paddings. The bottom paddings of both backgrounds don't need to
2907ecc1081ab9b4e41e4b2aec7877aaaf8df29e611Tadashi G. Takaoka                // be considered because the vertical positions of both backgrounds were already
2917ecc1081ab9b4e41e4b2aec7877aaaf8df29e611Tadashi G. Takaoka                // adjusted with their bottom paddings deducted.
2920e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka                width = keyPreviewDrawParams.mPreviewVisibleWidth;
29308ae0d5ca03ed455827e82222df249d1cafb5d71Tadashi G. Takaoka                height = keyPreviewDrawParams.mPreviewVisibleHeight + mParams.mVerticalGap;
294bd8e92d8431418929276fb739f0113e2297c9d00Tadashi G. Takaoka                // TODO: Remove this check.
295bd8e92d8431418929276fb739f0113e2297c9d00Tadashi G. Takaoka                if (width == 0) {
296bd8e92d8431418929276fb739f0113e2297c9d00Tadashi G. Takaoka                    throw new IllegalArgumentException(
297bd8e92d8431418929276fb739f0113e2297c9d00Tadashi G. Takaoka                            "Zero width key detected: " + parentKey + " in " + parentKeyboard.mId);
298bd8e92d8431418929276fb739f0113e2297c9d00Tadashi G. Takaoka                }
299a0e4f40994f779ad98268921c63d6535ad04224fTadashi G. Takaoka            } else {
30008ae0d5ca03ed455827e82222df249d1cafb5d71Tadashi G. Takaoka                width = getMaxKeyWidth(parentKeyboardView, parentKey, mParams.mDefaultKeyWidth,
30108ae0d5ca03ed455827e82222df249d1cafb5d71Tadashi G. Takaoka                        context.getResources());
302a0e4f40994f779ad98268921c63d6535ad04224fTadashi G. Takaoka                height = parentKeyboard.mMostCommonKeyHeight;
303bd8e92d8431418929276fb739f0113e2297c9d00Tadashi G. Takaoka                // TODO: Remove this check.
304bd8e92d8431418929276fb739f0113e2297c9d00Tadashi G. Takaoka                if (width == 0) {
305bd8e92d8431418929276fb739f0113e2297c9d00Tadashi G. Takaoka                    throw new IllegalArgumentException(
306bd8e92d8431418929276fb739f0113e2297c9d00Tadashi G. Takaoka                            "Zero width calculated: " + parentKey
307bd8e92d8431418929276fb739f0113e2297c9d00Tadashi G. Takaoka                            + " moreKeys=" + java.util.Arrays.toString(parentKey.mMoreKeys)
308bd8e92d8431418929276fb739f0113e2297c9d00Tadashi G. Takaoka                            + " in " + parentKeyboard.mId);
309bd8e92d8431418929276fb739f0113e2297c9d00Tadashi G. Takaoka                }
310a0e4f40994f779ad98268921c63d6535ad04224fTadashi G. Takaoka            }
3115ef4fccbb90491e1f6c2e87b47ebf9f3659949fbTadashi G. Takaoka            final int dividerWidth;
3125ef4fccbb90491e1f6c2e87b47ebf9f3659949fbTadashi G. Takaoka            if (parentKey.needsDividersInMoreKeys()) {
3135ef4fccbb90491e1f6c2e87b47ebf9f3659949fbTadashi G. Takaoka                mDivider = mResources.getDrawable(R.drawable.more_keys_divider);
3145ef4fccbb90491e1f6c2e87b47ebf9f3659949fbTadashi G. Takaoka                dividerWidth = (int)(width * DIVIDER_RATIO);
3155ef4fccbb90491e1f6c2e87b47ebf9f3659949fbTadashi G. Takaoka            } else {
3165ef4fccbb90491e1f6c2e87b47ebf9f3659949fbTadashi G. Takaoka                mDivider = null;
3175ef4fccbb90491e1f6c2e87b47ebf9f3659949fbTadashi G. Takaoka                dividerWidth = 0;
3185ef4fccbb90491e1f6c2e87b47ebf9f3659949fbTadashi G. Takaoka            }
31942fd1d2d72c097b2227d4b22f0f824dbb34a4d0cTadashi G. Takaoka            mParams.setParameters(parentKey.mMoreKeys.length, parentKey.getMoreKeysColumn(),
3207ecc1081ab9b4e41e4b2aec7877aaaf8df29e611Tadashi G. Takaoka                    width, height, parentKey.mX + parentKey.mWidth / 2,
3217ecc1081ab9b4e41e4b2aec7877aaaf8df29e611Tadashi G. Takaoka                    parentKeyboardView.getMeasuredWidth(), parentKey.isFixedColumnOrderMoreKeys(),
3227ecc1081ab9b4e41e4b2aec7877aaaf8df29e611Tadashi G. Takaoka                    dividerWidth);
32332572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka        }
32432572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka
32535ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka        private static int getMaxKeyWidth(final KeyboardView view, final Key parentKey,
32608ae0d5ca03ed455827e82222df249d1cafb5d71Tadashi G. Takaoka                final int minKeyWidth, final Resources res) {
32708ae0d5ca03ed455827e82222df249d1cafb5d71Tadashi G. Takaoka            final float padding =
32808ae0d5ca03ed455827e82222df249d1cafb5d71Tadashi G. Takaoka                    res.getDimension(R.dimen.more_keys_keyboard_key_horizontal_padding)
32908ae0d5ca03ed455827e82222df249d1cafb5d71Tadashi G. Takaoka                    + (parentKey.hasLabelsInMoreKeys() ? minKeyWidth * LABEL_PADDING_RATIO : 0.0f);
33008ae0d5ca03ed455827e82222df249d1cafb5d71Tadashi G. Takaoka            final Paint paint = view.newLabelPaint(parentKey);
3312315bfc7c8df0f6d9fb627456f2a298f5580b52dTadashi G. Takaoka            int maxWidth = minKeyWidth;
332ed3bac91f242850c6d1833a5f8981b9cc208c5ddTadashi G. Takaoka            for (final MoreKeySpec spec : parentKey.mMoreKeys) {
333ed3bac91f242850c6d1833a5f8981b9cc208c5ddTadashi G. Takaoka                final String label = spec.mLabel;
334bd7b160cfb05ee543e3cb6ddc7bd231b3f3aba0bTadashi G. Takaoka                // If the label is single letter, minKeyWidth is enough to hold the label.
335cc8c8b99bd0463f5977dea82f5e2379ea1dd4e73Tadashi G. Takaoka                if (label != null && StringUtils.codePointCount(label) > 1) {
33608ae0d5ca03ed455827e82222df249d1cafb5d71Tadashi G. Takaoka                    maxWidth = Math.max(maxWidth,
33708ae0d5ca03ed455827e82222df249d1cafb5d71Tadashi G. Takaoka                            (int)(TypefaceUtils.getLabelWidth(label, paint) + padding));
33832572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka                }
33932572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka            }
340be34d973349909196dc3427a5653f4e119092ea7Tadashi G. Takaoka            return maxWidth;
34132572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka        }
34232572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka
34332572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka        @Override
3442affaf91a04d63e0994102299816014a8bbe11e1Tadashi G. Takaoka        public MoreKeysKeyboard build() {
3452affaf91a04d63e0994102299816014a8bbe11e1Tadashi G. Takaoka            final MoreKeysKeyboardParams params = mParams;
346ab0d0d8a021a9b0f179281ac9e18604ad331cc43Tadashi G. Takaoka            final int moreKeyFlags = mParentKey.getMoreKeyLabelFlags();
347ed3bac91f242850c6d1833a5f8981b9cc208c5ddTadashi G. Takaoka            final MoreKeySpec[] moreKeys = mParentKey.mMoreKeys;
34842fd1d2d72c097b2227d4b22f0f824dbb34a4d0cTadashi G. Takaoka            for (int n = 0; n < moreKeys.length; n++) {
349ed3bac91f242850c6d1833a5f8981b9cc208c5ddTadashi G. Takaoka                final MoreKeySpec moreKeySpec = moreKeys[n];
35032572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka                final int row = n / params.mNumColumns;
3515ef4fccbb90491e1f6c2e87b47ebf9f3659949fbTadashi G. Takaoka                final int x = params.getX(n, row);
3525ef4fccbb90491e1f6c2e87b47ebf9f3659949fbTadashi G. Takaoka                final int y = params.getY(row);
353ed3bac91f242850c6d1833a5f8981b9cc208c5ddTadashi G. Takaoka                final Key key = new Key(params, moreKeySpec, x, y,
3545ef4fccbb90491e1f6c2e87b47ebf9f3659949fbTadashi G. Takaoka                        params.mDefaultKeyWidth, params.mDefaultRowHeight, moreKeyFlags);
3552fc4248700023853980b0006c12425079e3f9257Tadashi G. Takaoka                params.markAsEdgeKey(key, row);
35632572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka                params.onAddKey(key);
3575ef4fccbb90491e1f6c2e87b47ebf9f3659949fbTadashi G. Takaoka
3585ef4fccbb90491e1f6c2e87b47ebf9f3659949fbTadashi G. Takaoka                final int pos = params.getColumnPos(n);
3595ef4fccbb90491e1f6c2e87b47ebf9f3659949fbTadashi G. Takaoka                // The "pos" value represents the offset from the default position. Negative means
3605ef4fccbb90491e1f6c2e87b47ebf9f3659949fbTadashi G. Takaoka                // left of the default position.
3615ef4fccbb90491e1f6c2e87b47ebf9f3659949fbTadashi G. Takaoka                if (params.mDividerWidth > 0 && pos != 0) {
3625ef4fccbb90491e1f6c2e87b47ebf9f3659949fbTadashi G. Takaoka                    final int dividerX = (pos > 0) ? x - params.mDividerWidth
3635ef4fccbb90491e1f6c2e87b47ebf9f3659949fbTadashi G. Takaoka                            : x + params.mDefaultKeyWidth;
3645ef4fccbb90491e1f6c2e87b47ebf9f3659949fbTadashi G. Takaoka                    final Key divider = new MoreKeyDivider(params, mDivider, dividerX, y);
3655ef4fccbb90491e1f6c2e87b47ebf9f3659949fbTadashi G. Takaoka                    params.onAddKey(divider);
3665ef4fccbb90491e1f6c2e87b47ebf9f3659949fbTadashi G. Takaoka                }
36732572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka            }
3682affaf91a04d63e0994102299816014a8bbe11e1Tadashi G. Takaoka            return new MoreKeysKeyboard(params);
36932572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka        }
37032572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka    }
37135ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka
37235ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka    private static class MoreKeyDivider extends Key.Spacer {
37335ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka        private final Drawable mIcon;
37435ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka
37535ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka        public MoreKeyDivider(final MoreKeysKeyboardParams params, final Drawable icon,
37635ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka                final int x, final int y) {
37735ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka            super(params, x, y, params.mDividerWidth, params.mDefaultRowHeight);
37835ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka            mIcon = icon;
37935ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka        }
38035ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka
38135ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka        @Override
38235ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka        public Drawable getIcon(final KeyboardIconsSet iconSet, final int alpha) {
38335ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka            // KeyboardIconsSet and alpha are unused. Use the icon that has been passed to the
38435ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka            // constructor.
38535ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka            // TODO: Drawable itself should have an alpha value.
38635ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka            mIcon.setAlpha(128);
38735ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka            return mIcon;
38835ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka        }
38935ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka    }
39004c96ab966e8a58e5cd401362b49509751ce75d9Tadashi G. Takaoka}
391