Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 5d542c24 authored by Tadashi G. Takaoka's avatar Tadashi G. Takaoka
Browse files

Auto mini keyboard layout

Bug: 4280617
Change-Id: I34c344cbf350fe125589aa14ad69e4bd1f4e6f66
parent 72a82d7e
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -63,7 +63,7 @@
    <!-- This configuration is the index of the array {@link KeyboardSwitcher.KEYBOARD_THEMES}. -->
    <string name="config_default_keyboard_theme_id" translatable="false">4</string>
    <string name="config_text_size_of_language_on_spacebar" translatable="false">small</string>
    <integer name="config_max_popup_keyboard_column">10</integer>
    <integer name="config_max_popup_keyboard_column">5</integer>
    <!-- Whether or not auto-correction should be enabled by default -->
    <bool name="enable_autocorrect">true</bool>
    <string-array name="auto_correction_threshold_values" translatable="false">
+0 −28
Original line number Diff line number Diff line
@@ -17,7 +17,6 @@
package com.android.inputmethod.keyboard;

import java.util.Arrays;
import java.util.HashMap;
import java.util.List;

public abstract class KeyDetector {
@@ -110,31 +109,4 @@ public abstract class KeyDetector {
     * @return The nearest key index
     */
    abstract public int getKeyIndexAndNearbyCodes(int x, int y, final int[] allCodes);

    /**
     * Compute the most common key width in order to use it as proximity key detection threshold.
     *
     * @param keyboard The keyboard to compute the most common key width
     * @return The most common key width in the keyboard
     */
    public static int getMostCommonKeyWidth(final Keyboard keyboard) {
        if (keyboard == null) return 0;
        final List<Key> keys = keyboard.getKeys();
        if (keys == null || keys.size() == 0) return 0;
        final HashMap<Integer, Integer> histogram = new HashMap<Integer, Integer>();
        int maxCount = 0;
        int mostCommonWidth = 0;
        for (final Key key : keys) {
            final Integer width = key.mWidth + key.mGap;
            Integer count = histogram.get(width);
            if (count == null)
                count = 0;
            histogram.put(width, ++count);
            if (count > maxCount) {
                maxCount = count;
                mostCommonWidth = width;
            }
        }
        return mostCommonWidth + keyboard.getHorizontalGap();
    }
}
+23 −0
Original line number Diff line number Diff line
@@ -405,6 +405,29 @@ public class Keyboard {
        return EMPTY_INT_ARRAY;
    }

    /**
     * Compute the most common key width in order to use it as proximity key detection threshold.
     *
     * @return The most common key width in the keyboard
     */
    public int getMostCommonKeyWidth() {
        final HashMap<Integer, Integer> histogram = new HashMap<Integer, Integer>();
        int maxCount = 0;
        int mostCommonWidth = 0;
        for (final Key key : mKeys) {
            final Integer width = key.mWidth + key.mGap;
            Integer count = histogram.get(width);
            if (count == null)
                count = 0;
            histogram.put(width, ++count);
            if (count > maxCount) {
                maxCount = count;
                mostCommonWidth = width;
            }
        }
        return mostCommonWidth;
    }

    private void loadKeyboard(Context context, int xmlLayoutResId) {
        try {
            KeyboardParser parser = new KeyboardParser(this, context.getResources());
+1 −1
Original line number Diff line number Diff line
@@ -501,7 +501,7 @@ public class KeyboardView extends View implements PointerTracker.UIProxy {
        requestLayout();
        mKeyboardChanged = true;
        invalidateAllKeys();
        mKeyDetector.setProximityThreshold(KeyDetector.getMostCommonKeyWidth(keyboard));
        mKeyDetector.setProximityThreshold(keyboard.getMostCommonKeyWidth());
        mMiniKeyboardCache.clear();
    }

+61 −20
Original line number Diff line number Diff line
@@ -34,7 +34,7 @@ public class MiniKeyboardBuilder {
    /* package */ static class MiniKeyboardLayoutParams {
        public final int mKeyWidth;
        public final int mRowHeight;
        /* package */ final boolean mTopRowNeedsCentering;
        /* package */ final int mTopRowAdjustment;
        public final int mNumRows;
        public final int mNumColumns;
        public final int mLeftKeys;
@@ -55,29 +55,52 @@ public class MiniKeyboardBuilder {
            if (parentKeyboardWidth / keyWidth < maxColumns)
                throw new IllegalArgumentException("Keyboard is too small to hold mini keyboard: "
                        + parentKeyboardWidth + " " + keyWidth + " " + maxColumns);
            final int numRows = (numKeys + maxColumns - 1) / maxColumns;
            mKeyWidth = keyWidth;
            mRowHeight = rowHeight;
            mNumRows = numRows;

            final int numColumns = Math.min(numKeys, maxColumns);
            final int topRowKeys = numKeys % numColumns;
            final int numRows = (numKeys + maxColumns - 1) / maxColumns;
            mNumRows = numRows;
            final int numColumns = getOptimizedColumns(numKeys, maxColumns);
            mNumColumns = numColumns;
            mTopRowNeedsCentering = topRowKeys != 0 && (numColumns - topRowKeys) % 2 != 0;

            final int numLeftKeys = (numColumns - 1) / 2;
            final int numRightKeys = numColumns - numLeftKeys; // including default key.
            final int maxLeftKeys = coordXInParent / keyWidth;
            final int maxRightKeys = Math.max(1, (parentKeyboardWidth - coordXInParent) / keyWidth);
            int leftKeys, rightKeys;
            if (numLeftKeys > maxLeftKeys) {
                mLeftKeys = maxLeftKeys;
                mRightKeys = numColumns - maxLeftKeys;
                leftKeys = maxLeftKeys;
                rightKeys = numColumns - maxLeftKeys;
            } else if (numRightKeys > maxRightKeys) {
                mLeftKeys = numColumns - maxRightKeys;
                mRightKeys = maxRightKeys;
                leftKeys = numColumns - maxRightKeys;
                rightKeys = maxRightKeys;
            } else {
                mLeftKeys = numLeftKeys;
                mRightKeys = numRightKeys;
                leftKeys = numLeftKeys;
                rightKeys = numRightKeys;
            }
            // Shift right if the left edge of mini keyboard is on the edge of parent keyboard
            // unless the parent key is on the left edge.
            if (leftKeys * keyWidth >= coordXInParent && leftKeys > 0) {
                leftKeys--;
                rightKeys++;
            }
            // Shift left if the right edge of mini keyboard is on the edge of parent keyboard
            // unless the parent key is on the right edge.
            if (rightKeys * keyWidth + coordXInParent >= parentKeyboardWidth && rightKeys > 1) {
                leftKeys++;
                rightKeys--;
            }
            mLeftKeys = leftKeys;
            mRightKeys = rightKeys;

            // Centering of the top row.
            final boolean onEdge = (leftKeys == 0 || rightKeys == 1);
            if (numRows < 2 || onEdge || getTopRowEmptySlots(numKeys, numColumns) % 2 == 0) {
                mTopRowAdjustment = 0;
            } else if (mLeftKeys < mRightKeys - 1) {
                mTopRowAdjustment = 1;
            } else {
                mTopRowAdjustment = -1;
            }
        }

@@ -113,14 +136,32 @@ public class MiniKeyboardBuilder {
            return pos;
        }

        private static int getTopRowEmptySlots(int numKeys, int numColumns) {
            final int remainingKeys = numKeys % numColumns;
            if (remainingKeys == 0) {
                return 0;
            } else {
                return numColumns - remainingKeys;
            }
        }

        private int getOptimizedColumns(int numKeys, int maxColumns) {
            int numColumns = Math.min(numKeys, maxColumns);
            while (getTopRowEmptySlots(numKeys, numColumns) >= mNumRows) {
                numColumns--;
            }
            return numColumns;
        }

        public int getDefaultKeyCoordX() {
            return mLeftKeys * mKeyWidth;
        }

        public int getX(int n, int row) {
            final int x = getColumnPos(n) * mKeyWidth + getDefaultKeyCoordX();
            if (isLastRow(row) && mTopRowNeedsCentering)
                return x - mKeyWidth / 2;
            if (isTopRow(row)) {
                return x + mTopRowAdjustment * (mKeyWidth / 2);
            }
            return x;
        }

@@ -131,27 +172,27 @@ public class MiniKeyboardBuilder {
        public int getRowFlags(int row) {
            int rowFlags = 0;
            if (row == 0) rowFlags |= Keyboard.EDGE_TOP;
            if (isLastRow(row)) rowFlags |= Keyboard.EDGE_BOTTOM;
            if (isTopRow(row)) rowFlags |= Keyboard.EDGE_BOTTOM;
            return rowFlags;
        }

        private boolean isLastRow(int rowCount) {
        private boolean isTopRow(int rowCount) {
            return rowCount == mNumRows - 1;
        }
    }

    public MiniKeyboardBuilder(KeyboardView view, int layoutTemplateResId, Key popupKey) {
    public MiniKeyboardBuilder(KeyboardView view, int layoutTemplateResId, Key parentKey) {
        final Context context = view.getContext();
        mRes = context.getResources();
        final MiniKeyboard keyboard = new MiniKeyboard(context, layoutTemplateResId, null);
        mKeyboard = keyboard;
        mPopupCharacters = popupKey.mPopupCharacters;
        mPopupCharacters = parentKey.mPopupCharacters;

        final int keyWidth = getMaxKeyWidth(view, mPopupCharacters, keyboard.getKeyWidth());
        final MiniKeyboardLayoutParams params = new MiniKeyboardLayoutParams(
                mPopupCharacters.length, popupKey.mMaxPopupColumn,
                mPopupCharacters.length, parentKey.mMaxPopupColumn,
                keyWidth, keyboard.getRowHeight(),
                popupKey.mX + (popupKey.mWidth + popupKey.mGap) / 2 - keyWidth / 2,
                parentKey.mX + (parentKey.mWidth + parentKey.mGap) / 2 - keyWidth / 2,
                view.getMeasuredWidth());
        mParams = params;

Loading