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;
205ef4fccbb90491e1f6c2e87b47ebf9f3659949fbTadashi G. Takaokaimport android.graphics.drawable.Drawable;
217ecc1081ab9b4e41e4b2aec7877aaaf8df29e611Tadashi G. Takaokaimport android.view.View;
2232572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka
2335ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaokaimport com.android.inputmethod.keyboard.internal.KeyboardBuilder;
245ef4fccbb90491e1f6c2e87b47ebf9f3659949fbTadashi G. Takaokaimport com.android.inputmethod.keyboard.internal.KeyboardIconsSet;
2535ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaokaimport com.android.inputmethod.keyboard.internal.KeyboardParams;
2635ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaokaimport com.android.inputmethod.keyboard.internal.MoreKeySpec;
2732572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaokaimport com.android.inputmethod.latin.R;
28cc8c8b99bd0463f5977dea82f5e2379ea1dd4e73Tadashi G. Takaokaimport com.android.inputmethod.latin.StringUtils;
2904c96ab966e8a58e5cd401362b49509751ce75d9Tadashi G. Takaoka
30a28a05e971cc242b338331a3b78276fa95188d19Tadashi G. Takaokapublic final class MoreKeysKeyboard extends Keyboard {
318da9a13760896cd78235b60d0ea680ea13620532Tadashi G. Takaoka    private final int mDefaultKeyCoordX;
3204c96ab966e8a58e5cd401362b49509751ce75d9Tadashi G. Takaoka
3335ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka    MoreKeysKeyboard(final MoreKeysKeyboardParams params) {
348da9a13760896cd78235b60d0ea680ea13620532Tadashi G. Takaoka        super(params);
358da9a13760896cd78235b60d0ea680ea13620532Tadashi G. Takaoka        mDefaultKeyCoordX = params.getDefaultKeyCoordX() + params.mDefaultKeyWidth / 2;
3604c96ab966e8a58e5cd401362b49509751ce75d9Tadashi G. Takaoka    }
3704c96ab966e8a58e5cd401362b49509751ce75d9Tadashi G. Takaoka
3804c96ab966e8a58e5cd401362b49509751ce75d9Tadashi G. Takaoka    public int getDefaultCoordX() {
3904c96ab966e8a58e5cd401362b49509751ce75d9Tadashi G. Takaoka        return mDefaultKeyCoordX;
4004c96ab966e8a58e5cd401362b49509751ce75d9Tadashi G. Takaoka    }
4132572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka
4235ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka    /* package for test */
4335ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka    static class MoreKeysKeyboardParams extends KeyboardParams {
4435ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka        public boolean mIsFixedOrder;
4535ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka        /* package */int mTopRowAdjustment;
4635ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka        public int mNumRows;
4735ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka        public int mNumColumns;
4835ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka        public int mTopKeys;
4935ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka        public int mLeftKeys;
5035ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka        public int mRightKeys; // includes default key.
5135ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka        public int mDividerWidth;
5235ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka        public int mColumnWidth;
5335ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka
5435ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka        public MoreKeysKeyboardParams() {
5535ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka            super();
5635ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka        }
57e4c45c6ef920b9cd1754f345446f53c504a64c5fTadashi G. Takaoka
5835ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka        /**
5935ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka         * Set keyboard parameters of more keys keyboard.
6035ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka         *
6135ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka         * @param numKeys number of keys in this more keys keyboard.
6235ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka         * @param maxColumns number of maximum columns of this more keys keyboard.
6335ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka         * @param keyWidth more keys keyboard key width in pixel, including horizontal gap.
6435ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka         * @param rowHeight more keys keyboard row height in pixel, including vertical gap.
6535ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka         * @param coordXInParent coordinate x of the key preview in parent keyboard.
6635ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka         * @param parentKeyboardWidth parent keyboard width in pixel.
6735ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka         * @param isFixedColumnOrder if true, more keys should be laid out in fixed order.
6835ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka         * @param dividerWidth width of divider, zero for no dividers.
6935ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka         */
7035ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka        public void setParameters(final int numKeys, final int maxColumns, final int keyWidth,
7135ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka                final int rowHeight, final int coordXInParent, final int parentKeyboardWidth,
7235ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka                final boolean isFixedColumnOrder, final int dividerWidth) {
7335ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka            mIsFixedOrder = isFixedColumnOrder;
7435ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka            if (parentKeyboardWidth / keyWidth < maxColumns) {
7535ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka                throw new IllegalArgumentException(
7635ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka                        "Keyboard is too small to hold more keys keyboard: "
7735ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka                                + parentKeyboardWidth + " " + keyWidth + " " + maxColumns);
7832572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka            }
7935ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka            mDefaultKeyWidth = keyWidth;
8035ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka            mDefaultRowHeight = rowHeight;
8135ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka
8235ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka            final int numRows = (numKeys + maxColumns - 1) / maxColumns;
8335ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka            mNumRows = numRows;
8435ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka            final int numColumns = mIsFixedOrder ? Math.min(numKeys, maxColumns)
8535ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka                    : getOptimizedColumns(numKeys, maxColumns);
8635ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka            mNumColumns = numColumns;
8735ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka            final int topKeys = numKeys % numColumns;
8835ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka            mTopKeys = topKeys == 0 ? numColumns : topKeys;
8935ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka
9035ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka            final int numLeftKeys = (numColumns - 1) / 2;
9135ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka            final int numRightKeys = numColumns - numLeftKeys; // including default key.
9235ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka            // Maximum number of keys we can layout both side of the parent key
9335ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka            final int maxLeftKeys = coordXInParent / keyWidth;
9435ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka            final int maxRightKeys = (parentKeyboardWidth - coordXInParent) / keyWidth;
9535ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka            int leftKeys, rightKeys;
9635ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka            if (numLeftKeys > maxLeftKeys) {
9735ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka                leftKeys = maxLeftKeys;
9835ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka                rightKeys = numColumns - leftKeys;
9935ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka            } else if (numRightKeys > maxRightKeys + 1) {
10035ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka                rightKeys = maxRightKeys + 1; // include default key
10135ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka                leftKeys = numColumns - rightKeys;
10235ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka            } else {
10335ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka                leftKeys = numLeftKeys;
10435ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka                rightKeys = numRightKeys;
10532572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka            }
10635ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka            // If the left keys fill the left side of the parent key, entire more keys keyboard
10735ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka            // should be shifted to the right unless the parent key is on the left edge.
10835ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka            if (maxLeftKeys == leftKeys && leftKeys > 0) {
10935ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka                leftKeys--;
11035ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka                rightKeys++;
111aeeed758480b0fac848f4556884d978f3004555bTadashi G. Takaoka            }
11235ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka            // If the right keys fill the right side of the parent key, entire more keys
11335ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka            // should be shifted to the left unless the parent key is on the right edge.
11435ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka            if (maxRightKeys == rightKeys - 1 && rightKeys > 1) {
11535ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka                leftKeys++;
11635ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka                rightKeys--;
117aeeed758480b0fac848f4556884d978f3004555bTadashi G. Takaoka            }
11835ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka            mLeftKeys = leftKeys;
11935ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka            mRightKeys = rightKeys;
12035ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka
12135ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka            // Adjustment of the top row.
12235ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka            mTopRowAdjustment = mIsFixedOrder ? getFixedOrderTopRowAdjustment()
12335ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka                    : getAutoOrderTopRowAdjustment();
12435ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka            mDividerWidth = dividerWidth;
12535ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka            mColumnWidth = mDefaultKeyWidth + mDividerWidth;
12635ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka            mBaseWidth = mOccupiedWidth = mNumColumns * mColumnWidth - mDividerWidth;
12735ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka            // Need to subtract the bottom row's gutter only.
12835ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka            mBaseHeight = mOccupiedHeight = mNumRows * mDefaultRowHeight - mVerticalGap
12935ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka                    + mTopPadding + mBottomPadding;
13035ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka        }
131aeeed758480b0fac848f4556884d978f3004555bTadashi G. Takaoka
13235ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka        private int getFixedOrderTopRowAdjustment() {
13335ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka            if (mNumRows == 1 || mTopKeys % 2 == 1 || mTopKeys == mNumColumns
13435ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka                    || mLeftKeys == 0  || mRightKeys == 1) {
13535ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka                return 0;
136aeeed758480b0fac848f4556884d978f3004555bTadashi G. Takaoka            }
13735ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka            return -1;
13835ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka        }
139aeeed758480b0fac848f4556884d978f3004555bTadashi G. Takaoka
14035ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka        private int getAutoOrderTopRowAdjustment() {
14135ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka            if (mNumRows == 1 || mTopKeys == 1 || mNumColumns % 2 == mTopKeys % 2
14235ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka                    || mLeftKeys == 0 || mRightKeys == 1) {
14335ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka                return 0;
144aeeed758480b0fac848f4556884d978f3004555bTadashi G. Takaoka            }
14535ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka            return -1;
14635ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka        }
147aeeed758480b0fac848f4556884d978f3004555bTadashi G. Takaoka
14835ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka        // Return key position according to column count (0 is default).
14935ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka        /* package */int getColumnPos(final int n) {
15035ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka            return mIsFixedOrder ? getFixedOrderColumnPos(n) : getAutomaticColumnPos(n);
15135ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka        }
152aeeed758480b0fac848f4556884d978f3004555bTadashi G. Takaoka
15335ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka        private int getFixedOrderColumnPos(final int n) {
15435ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka            final int col = n % mNumColumns;
15535ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka            final int row = n / mNumColumns;
15635ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka            if (!isTopRow(row)) {
15735ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka                return col - mLeftKeys;
15835ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka            }
15935ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka            final int rightSideKeys = mTopKeys / 2;
16035ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka            final int leftSideKeys = mTopKeys - (rightSideKeys + 1);
16135ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka            final int pos = col - leftSideKeys;
16235ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka            final int numLeftKeys = mLeftKeys + mTopRowAdjustment;
16335ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka            final int numRightKeys = mRightKeys - 1;
16435ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka            if (numRightKeys >= rightSideKeys && numLeftKeys >= leftSideKeys) {
16532572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka                return pos;
16635ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka            } else if (numRightKeys < rightSideKeys) {
16735ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka                return pos - (rightSideKeys - numRightKeys);
16835ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka            } else { // numLeftKeys < leftSideKeys
16935ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka                return pos + (leftSideKeys - numLeftKeys);
17032572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka            }
17135ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka        }
17232572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka
17335ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka        private int getAutomaticColumnPos(final int n) {
17435ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka            final int col = n % mNumColumns;
17535ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka            final int row = n / mNumColumns;
17635ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka            int leftKeys = mLeftKeys;
17735ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka            if (isTopRow(row)) {
17835ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka                leftKeys += mTopRowAdjustment;
17935ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka            }
18035ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka            if (col == 0) {
18135ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka                // default position.
18235ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka                return 0;
18332572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka            }
18432572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka
18535ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka            int pos = 0;
18635ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka            int right = 1; // include default position key.
18735ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka            int left = 0;
18835ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka            int i = 0;
18935ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka            while (true) {
19035ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka                // Assign right key if available.
19135ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka                if (right < mRightKeys) {
19235ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka                    pos = right;
19335ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka                    right++;
19435ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka                    i++;
19532572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka                }
19635ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka                if (i >= col)
19735ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka                    break;
19835ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka                // Assign left key if available.
19935ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka                if (left < leftKeys) {
20035ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka                    left++;
20135ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka                    pos = -left;
20235ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka                    i++;
20335ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka                }
20435ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka                if (i >= col)
20535ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka                    break;
20632572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka            }
20735ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka            return pos;
20835ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka        }
20932572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka
21035ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka        private static int getTopRowEmptySlots(final int numKeys, final int numColumns) {
21135ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka            final int remainings = numKeys % numColumns;
21235ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka            return remainings == 0 ? 0 : numColumns - remainings;
21335ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka        }
21432572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka
21535ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka        private int getOptimizedColumns(final int numKeys, final int maxColumns) {
21635ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka            int numColumns = Math.min(numKeys, maxColumns);
21735ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka            while (getTopRowEmptySlots(numKeys, numColumns) >= mNumRows) {
21835ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka                numColumns--;
21932572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka            }
22035ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka            return numColumns;
22135ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka        }
22232572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka
22335ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka        public int getDefaultKeyCoordX() {
22435ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka            return mLeftKeys * mColumnWidth;
22535ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka        }
22632572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka
22735ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka        public int getX(final int n, final int row) {
22835ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka            final int x = getColumnPos(n) * mColumnWidth + getDefaultKeyCoordX();
22935ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka            if (isTopRow(row)) {
23035ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka                return x + mTopRowAdjustment * (mColumnWidth / 2);
23132572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka            }
23235ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka            return x;
23335ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka        }
23432572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka
23535ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka        public int getY(final int row) {
23635ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka            return (mNumRows - 1 - row) * mDefaultRowHeight + mTopPadding;
23732572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka        }
23832572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka
23935ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka        public void markAsEdgeKey(final Key key, final int row) {
24035ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka            if (row == 0)
24135ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka                key.markAsTopEdge(this);
24235ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka            if (isTopRow(row))
24335ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka                key.markAsBottomEdge(this);
24435ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka        }
24535ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka
24635ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka        private boolean isTopRow(final int rowCount) {
24735ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka            return mNumRows > 1 && rowCount == mNumRows - 1;
24835ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka        }
24935ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka    }
25035ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka
25135ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka    public static class Builder extends KeyboardBuilder<MoreKeysKeyboardParams> {
25235ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka        private final Key mParentKey;
25335ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka        private final Drawable mDivider;
25435ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka
25535ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka        private static final float LABEL_PADDING_RATIO = 0.2f;
25635ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka        private static final float DIVIDER_RATIO = 0.2f;
25735ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka
25835ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka
2597ecc1081ab9b4e41e4b2aec7877aaaf8df29e611Tadashi G. Takaoka        /**
2607ecc1081ab9b4e41e4b2aec7877aaaf8df29e611Tadashi G. Takaoka         * The builder of MoreKeysKeyboard.
2617ecc1081ab9b4e41e4b2aec7877aaaf8df29e611Tadashi G. Takaoka         * @param containerView the container of {@link MoreKeysKeyboardView}.
2627ecc1081ab9b4e41e4b2aec7877aaaf8df29e611Tadashi G. Takaoka         * @param parentKey the {@link Key} that invokes more keys keyboard.
2637ecc1081ab9b4e41e4b2aec7877aaaf8df29e611Tadashi G. Takaoka         * @param parentKeyboardView the {@link KeyboardView} that contains the parentKey.
2647ecc1081ab9b4e41e4b2aec7877aaaf8df29e611Tadashi G. Takaoka         */
26535ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka        public Builder(final View containerView, final Key parentKey,
26635ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka                final KeyboardView parentKeyboardView) {
2677ecc1081ab9b4e41e4b2aec7877aaaf8df29e611Tadashi G. Takaoka            super(containerView.getContext(), new MoreKeysKeyboardParams());
2687ecc1081ab9b4e41e4b2aec7877aaaf8df29e611Tadashi G. Takaoka            final Keyboard parentKeyboard = parentKeyboardView.getKeyboard();
2697ecc1081ab9b4e41e4b2aec7877aaaf8df29e611Tadashi G. Takaoka            load(parentKeyboard.mMoreKeysTemplate, parentKeyboard.mId);
27032572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka
2712affaf91a04d63e0994102299816014a8bbe11e1Tadashi G. Takaoka            // TODO: More keys keyboard's vertical gap is currently calculated heuristically.
272ea0c567f86bd19015d53fc038c4579df776cfec3Tadashi G. Takaoka            // Should revise the algorithm.
273ea0c567f86bd19015d53fc038c4579df776cfec3Tadashi G. Takaoka            mParams.mVerticalGap = parentKeyboard.mVerticalGap / 2;
27442fd1d2d72c097b2227d4b22f0f824dbb34a4d0cTadashi G. Takaoka            mParentKey = parentKey;
27532572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka
276a0e4f40994f779ad98268921c63d6535ad04224fTadashi G. Takaoka            final int width, height;
2777ecc1081ab9b4e41e4b2aec7877aaaf8df29e611Tadashi G. Takaoka            final boolean singleMoreKeyWithPreview = parentKeyboardView.isKeyPreviewPopupEnabled()
2787ecc1081ab9b4e41e4b2aec7877aaaf8df29e611Tadashi G. Takaoka                    && !parentKey.noKeyPreview() && parentKey.mMoreKeys.length == 1;
27942fd1d2d72c097b2227d4b22f0f824dbb34a4d0cTadashi G. Takaoka            if (singleMoreKeyWithPreview) {
2807ecc1081ab9b4e41e4b2aec7877aaaf8df29e611Tadashi G. Takaoka                // Use pre-computed width and height if this more keys keyboard has only one key to
2817ecc1081ab9b4e41e4b2aec7877aaaf8df29e611Tadashi G. Takaoka                // mitigate visual flicker between key preview and more keys keyboard.
2827ecc1081ab9b4e41e4b2aec7877aaaf8df29e611Tadashi G. Takaoka                // Caveats for the visual assets: To achieve this effect, both the key preview
2837ecc1081ab9b4e41e4b2aec7877aaaf8df29e611Tadashi G. Takaoka                // backgrounds and the more keys keyboard panel background have the exact same
2847ecc1081ab9b4e41e4b2aec7877aaaf8df29e611Tadashi G. Takaoka                // left/right/top paddings. The bottom paddings of both backgrounds don't need to
2857ecc1081ab9b4e41e4b2aec7877aaaf8df29e611Tadashi G. Takaoka                // be considered because the vertical positions of both backgrounds were already
2867ecc1081ab9b4e41e4b2aec7877aaaf8df29e611Tadashi G. Takaoka                // adjusted with their bottom paddings deducted.
2877ecc1081ab9b4e41e4b2aec7877aaaf8df29e611Tadashi G. Takaoka                width = parentKeyboardView.mKeyPreviewDrawParams.mPreviewVisibleWidth;
2887ecc1081ab9b4e41e4b2aec7877aaaf8df29e611Tadashi G. Takaoka                height = parentKeyboardView.mKeyPreviewDrawParams.mPreviewVisibleHeight
2897ecc1081ab9b4e41e4b2aec7877aaaf8df29e611Tadashi G. Takaoka                        + mParams.mVerticalGap;
290a0e4f40994f779ad98268921c63d6535ad04224fTadashi G. Takaoka            } else {
2917ecc1081ab9b4e41e4b2aec7877aaaf8df29e611Tadashi G. Takaoka                width = getMaxKeyWidth(parentKeyboardView, parentKey, mParams.mDefaultKeyWidth);
292a0e4f40994f779ad98268921c63d6535ad04224fTadashi G. Takaoka                height = parentKeyboard.mMostCommonKeyHeight;
293a0e4f40994f779ad98268921c63d6535ad04224fTadashi G. Takaoka            }
2945ef4fccbb90491e1f6c2e87b47ebf9f3659949fbTadashi G. Takaoka            final int dividerWidth;
2955ef4fccbb90491e1f6c2e87b47ebf9f3659949fbTadashi G. Takaoka            if (parentKey.needsDividersInMoreKeys()) {
2965ef4fccbb90491e1f6c2e87b47ebf9f3659949fbTadashi G. Takaoka                mDivider = mResources.getDrawable(R.drawable.more_keys_divider);
2975ef4fccbb90491e1f6c2e87b47ebf9f3659949fbTadashi G. Takaoka                dividerWidth = (int)(width * DIVIDER_RATIO);
2985ef4fccbb90491e1f6c2e87b47ebf9f3659949fbTadashi G. Takaoka            } else {
2995ef4fccbb90491e1f6c2e87b47ebf9f3659949fbTadashi G. Takaoka                mDivider = null;
3005ef4fccbb90491e1f6c2e87b47ebf9f3659949fbTadashi G. Takaoka                dividerWidth = 0;
3015ef4fccbb90491e1f6c2e87b47ebf9f3659949fbTadashi G. Takaoka            }
30242fd1d2d72c097b2227d4b22f0f824dbb34a4d0cTadashi G. Takaoka            mParams.setParameters(parentKey.mMoreKeys.length, parentKey.getMoreKeysColumn(),
3037ecc1081ab9b4e41e4b2aec7877aaaf8df29e611Tadashi G. Takaoka                    width, height, parentKey.mX + parentKey.mWidth / 2,
3047ecc1081ab9b4e41e4b2aec7877aaaf8df29e611Tadashi G. Takaoka                    parentKeyboardView.getMeasuredWidth(), parentKey.isFixedColumnOrderMoreKeys(),
3057ecc1081ab9b4e41e4b2aec7877aaaf8df29e611Tadashi G. Takaoka                    dividerWidth);
30632572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka        }
30732572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka
30835ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka        private static int getMaxKeyWidth(final KeyboardView view, final Key parentKey,
30935ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka                final int minKeyWidth) {
310e4c45c6ef920b9cd1754f345446f53c504a64c5fTadashi G. Takaoka            final int padding = (int)(view.getResources()
311e4c45c6ef920b9cd1754f345446f53c504a64c5fTadashi G. Takaoka                    .getDimension(R.dimen.more_keys_keyboard_key_horizontal_padding)
312e4c45c6ef920b9cd1754f345446f53c504a64c5fTadashi G. Takaoka                    + (parentKey.hasLabelsInMoreKeys() ? minKeyWidth * LABEL_PADDING_RATIO : 0));
31372913f97edb74e877f78b25418a568a4b0f5ae5cTadashi G. Takaoka            final Paint paint = view.newDefaultLabelPaint();
314dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka            paint.setTypeface(parentKey.selectTypeface(view.mKeyDrawParams));
315dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka            paint.setTextSize(parentKey.selectMoreKeyTextSize(view.mKeyDrawParams));
3162315bfc7c8df0f6d9fb627456f2a298f5580b52dTadashi G. Takaoka            int maxWidth = minKeyWidth;
317ed3bac91f242850c6d1833a5f8981b9cc208c5ddTadashi G. Takaoka            for (final MoreKeySpec spec : parentKey.mMoreKeys) {
318ed3bac91f242850c6d1833a5f8981b9cc208c5ddTadashi G. Takaoka                final String label = spec.mLabel;
319bd7b160cfb05ee543e3cb6ddc7bd231b3f3aba0bTadashi G. Takaoka                // If the label is single letter, minKeyWidth is enough to hold the label.
320cc8c8b99bd0463f5977dea82f5e2379ea1dd4e73Tadashi G. Takaoka                if (label != null && StringUtils.codePointCount(label) > 1) {
32172913f97edb74e877f78b25418a568a4b0f5ae5cTadashi G. Takaoka                    final int width = (int)view.getLabelWidth(label, paint) + padding;
3222315bfc7c8df0f6d9fb627456f2a298f5580b52dTadashi G. Takaoka                    if (maxWidth < width) {
3232315bfc7c8df0f6d9fb627456f2a298f5580b52dTadashi G. Takaoka                        maxWidth = width;
3242315bfc7c8df0f6d9fb627456f2a298f5580b52dTadashi G. Takaoka                    }
32532572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka                }
32632572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka            }
327be34d973349909196dc3427a5653f4e119092ea7Tadashi G. Takaoka            return maxWidth;
32832572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka        }
32932572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka
33032572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka        @Override
3312affaf91a04d63e0994102299816014a8bbe11e1Tadashi G. Takaoka        public MoreKeysKeyboard build() {
3322affaf91a04d63e0994102299816014a8bbe11e1Tadashi G. Takaoka            final MoreKeysKeyboardParams params = mParams;
333ab0d0d8a021a9b0f179281ac9e18604ad331cc43Tadashi G. Takaoka            final int moreKeyFlags = mParentKey.getMoreKeyLabelFlags();
334ed3bac91f242850c6d1833a5f8981b9cc208c5ddTadashi G. Takaoka            final MoreKeySpec[] moreKeys = mParentKey.mMoreKeys;
33542fd1d2d72c097b2227d4b22f0f824dbb34a4d0cTadashi G. Takaoka            for (int n = 0; n < moreKeys.length; n++) {
336ed3bac91f242850c6d1833a5f8981b9cc208c5ddTadashi G. Takaoka                final MoreKeySpec moreKeySpec = moreKeys[n];
33732572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka                final int row = n / params.mNumColumns;
3385ef4fccbb90491e1f6c2e87b47ebf9f3659949fbTadashi G. Takaoka                final int x = params.getX(n, row);
3395ef4fccbb90491e1f6c2e87b47ebf9f3659949fbTadashi G. Takaoka                final int y = params.getY(row);
340ed3bac91f242850c6d1833a5f8981b9cc208c5ddTadashi G. Takaoka                final Key key = new Key(params, moreKeySpec, x, y,
3415ef4fccbb90491e1f6c2e87b47ebf9f3659949fbTadashi G. Takaoka                        params.mDefaultKeyWidth, params.mDefaultRowHeight, moreKeyFlags);
3422fc4248700023853980b0006c12425079e3f9257Tadashi G. Takaoka                params.markAsEdgeKey(key, row);
34332572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka                params.onAddKey(key);
3445ef4fccbb90491e1f6c2e87b47ebf9f3659949fbTadashi G. Takaoka
3455ef4fccbb90491e1f6c2e87b47ebf9f3659949fbTadashi G. Takaoka                final int pos = params.getColumnPos(n);
3465ef4fccbb90491e1f6c2e87b47ebf9f3659949fbTadashi G. Takaoka                // The "pos" value represents the offset from the default position. Negative means
3475ef4fccbb90491e1f6c2e87b47ebf9f3659949fbTadashi G. Takaoka                // left of the default position.
3485ef4fccbb90491e1f6c2e87b47ebf9f3659949fbTadashi G. Takaoka                if (params.mDividerWidth > 0 && pos != 0) {
3495ef4fccbb90491e1f6c2e87b47ebf9f3659949fbTadashi G. Takaoka                    final int dividerX = (pos > 0) ? x - params.mDividerWidth
3505ef4fccbb90491e1f6c2e87b47ebf9f3659949fbTadashi G. Takaoka                            : x + params.mDefaultKeyWidth;
3515ef4fccbb90491e1f6c2e87b47ebf9f3659949fbTadashi G. Takaoka                    final Key divider = new MoreKeyDivider(params, mDivider, dividerX, y);
3525ef4fccbb90491e1f6c2e87b47ebf9f3659949fbTadashi G. Takaoka                    params.onAddKey(divider);
3535ef4fccbb90491e1f6c2e87b47ebf9f3659949fbTadashi G. Takaoka                }
35432572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka            }
3552affaf91a04d63e0994102299816014a8bbe11e1Tadashi G. Takaoka            return new MoreKeysKeyboard(params);
35632572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka        }
35732572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka    }
35835ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka
35935ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka    private static class MoreKeyDivider extends Key.Spacer {
36035ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka        private final Drawable mIcon;
36135ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka
36235ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka        public MoreKeyDivider(final MoreKeysKeyboardParams params, final Drawable icon,
36335ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka                final int x, final int y) {
36435ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka            super(params, x, y, params.mDividerWidth, params.mDefaultRowHeight);
36535ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka            mIcon = icon;
36635ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka        }
36735ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka
36835ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka        @Override
36935ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka        public Drawable getIcon(final KeyboardIconsSet iconSet, final int alpha) {
37035ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka            // KeyboardIconsSet and alpha are unused. Use the icon that has been passed to the
37135ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka            // constructor.
37235ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka            // TODO: Drawable itself should have an alpha value.
37335ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka            mIcon.setAlpha(128);
37435ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka            return mIcon;
37535ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka        }
37635ff94547c16c84c5b6fafdae0b4a683be782b97Tadashi G. Takaoka    }
37704c96ab966e8a58e5cd401362b49509751ce75d9Tadashi G. Takaoka}
378