11516d055df0d939c76ab8f2739f7fb1cdd3956d0Tadashi G. Takaoka/*
21516d055df0d939c76ab8f2739f7fb1cdd3956d0Tadashi G. Takaoka * Copyright (C) 2011 The Android Open Source Project
31516d055df0d939c76ab8f2739f7fb1cdd3956d0Tadashi G. Takaoka *
41516d055df0d939c76ab8f2739f7fb1cdd3956d0Tadashi G. Takaoka * Licensed under the Apache License, Version 2.0 (the "License"); you may not
51516d055df0d939c76ab8f2739f7fb1cdd3956d0Tadashi G. Takaoka * use this file except in compliance with the License. You may obtain a copy of
61516d055df0d939c76ab8f2739f7fb1cdd3956d0Tadashi G. Takaoka * the License at
71516d055df0d939c76ab8f2739f7fb1cdd3956d0Tadashi G. Takaoka *
81516d055df0d939c76ab8f2739f7fb1cdd3956d0Tadashi G. Takaoka * http://www.apache.org/licenses/LICENSE-2.0
91516d055df0d939c76ab8f2739f7fb1cdd3956d0Tadashi G. Takaoka *
101516d055df0d939c76ab8f2739f7fb1cdd3956d0Tadashi G. Takaoka * Unless required by applicable law or agreed to in writing, software
111516d055df0d939c76ab8f2739f7fb1cdd3956d0Tadashi G. Takaoka * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
121516d055df0d939c76ab8f2739f7fb1cdd3956d0Tadashi G. Takaoka * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
131516d055df0d939c76ab8f2739f7fb1cdd3956d0Tadashi G. Takaoka * License for the specific language governing permissions and limitations under
141516d055df0d939c76ab8f2739f7fb1cdd3956d0Tadashi G. Takaoka * the License.
151516d055df0d939c76ab8f2739f7fb1cdd3956d0Tadashi G. Takaoka */
161516d055df0d939c76ab8f2739f7fb1cdd3956d0Tadashi G. Takaoka
171516d055df0d939c76ab8f2739f7fb1cdd3956d0Tadashi G. Takaokapackage com.android.inputmethod.keyboard.internal;
181516d055df0d939c76ab8f2739f7fb1cdd3956d0Tadashi G. Takaoka
191516d055df0d939c76ab8f2739f7fb1cdd3956d0Tadashi G. Takaokaimport android.graphics.drawable.Drawable;
201516d055df0d939c76ab8f2739f7fb1cdd3956d0Tadashi G. Takaoka
211516d055df0d939c76ab8f2739f7fb1cdd3956d0Tadashi G. Takaokaimport com.android.inputmethod.keyboard.Key;
228da9a13760896cd78235b60d0ea680ea13620532Tadashi G. Takaokaimport com.android.inputmethod.keyboard.Keyboard;
231516d055df0d939c76ab8f2739f7fb1cdd3956d0Tadashi G. Takaokaimport com.android.inputmethod.keyboard.KeyboardId;
24294e1b4a5abb86e58deefc8eee40e6b661524b28Yusuke Nojimaimport com.android.inputmethod.latin.LatinImeLogger;
251516d055df0d939c76ab8f2739f7fb1cdd3956d0Tadashi G. Takaoka
261516d055df0d939c76ab8f2739f7fb1cdd3956d0Tadashi G. Takaokaimport java.util.ArrayList;
271516d055df0d939c76ab8f2739f7fb1cdd3956d0Tadashi G. Takaokaimport java.util.HashMap;
281516d055df0d939c76ab8f2739f7fb1cdd3956d0Tadashi G. Takaokaimport java.util.HashSet;
291516d055df0d939c76ab8f2739f7fb1cdd3956d0Tadashi G. Takaokaimport java.util.List;
301516d055df0d939c76ab8f2739f7fb1cdd3956d0Tadashi G. Takaokaimport java.util.Map;
311516d055df0d939c76ab8f2739f7fb1cdd3956d0Tadashi G. Takaokaimport java.util.Set;
321516d055df0d939c76ab8f2739f7fb1cdd3956d0Tadashi G. Takaoka
331516d055df0d939c76ab8f2739f7fb1cdd3956d0Tadashi G. Takaokapublic class KeyboardParams {
341516d055df0d939c76ab8f2739f7fb1cdd3956d0Tadashi G. Takaoka    public KeyboardId mId;
3563584323cab56c76debf6bb000621f2c605329a9Tadashi G. Takaoka    public int mThemeId;
361516d055df0d939c76ab8f2739f7fb1cdd3956d0Tadashi G. Takaoka
378fbfac4ffb7079e8e71fd4e3ddc04e362239ebb3Tadashi G. Takaoka    /** Total height and width of the keyboard, including the paddings and keys */
388da9a13760896cd78235b60d0ea680ea13620532Tadashi G. Takaoka    public int mOccupiedHeight;
398da9a13760896cd78235b60d0ea680ea13620532Tadashi G. Takaoka    public int mOccupiedWidth;
401516d055df0d939c76ab8f2739f7fb1cdd3956d0Tadashi G. Takaoka
418fbfac4ffb7079e8e71fd4e3ddc04e362239ebb3Tadashi G. Takaoka    /** Base height and width of the keyboard used to calculate rows' or keys' heights and widths */
428fbfac4ffb7079e8e71fd4e3ddc04e362239ebb3Tadashi G. Takaoka    public int mBaseHeight;
438fbfac4ffb7079e8e71fd4e3ddc04e362239ebb3Tadashi G. Takaoka    public int mBaseWidth;
441516d055df0d939c76ab8f2739f7fb1cdd3956d0Tadashi G. Takaoka
451516d055df0d939c76ab8f2739f7fb1cdd3956d0Tadashi G. Takaoka    public int mTopPadding;
461516d055df0d939c76ab8f2739f7fb1cdd3956d0Tadashi G. Takaoka    public int mBottomPadding;
471516d055df0d939c76ab8f2739f7fb1cdd3956d0Tadashi G. Takaoka    public int mHorizontalEdgesPadding;
481516d055df0d939c76ab8f2739f7fb1cdd3956d0Tadashi G. Takaoka    public int mHorizontalCenterPadding;
491516d055df0d939c76ab8f2739f7fb1cdd3956d0Tadashi G. Takaoka
501516d055df0d939c76ab8f2739f7fb1cdd3956d0Tadashi G. Takaoka    public int mDefaultRowHeight;
511516d055df0d939c76ab8f2739f7fb1cdd3956d0Tadashi G. Takaoka    public int mDefaultKeyWidth;
521516d055df0d939c76ab8f2739f7fb1cdd3956d0Tadashi G. Takaoka    public int mHorizontalGap;
531516d055df0d939c76ab8f2739f7fb1cdd3956d0Tadashi G. Takaoka    public int mVerticalGap;
541516d055df0d939c76ab8f2739f7fb1cdd3956d0Tadashi G. Takaoka
551516d055df0d939c76ab8f2739f7fb1cdd3956d0Tadashi G. Takaoka    public boolean mIsRtlKeyboard;
569d5601e9013c5ec9a7ac75db16f4a0a8218b02bfTadashi G. Takaoka    public int mMoreKeysTemplate;
579237a72634be821c22911633ef0848130e162d58Tadashi G. Takaoka    public int mMaxMiniKeyboardColumn;
581516d055df0d939c76ab8f2739f7fb1cdd3956d0Tadashi G. Takaoka
591516d055df0d939c76ab8f2739f7fb1cdd3956d0Tadashi G. Takaoka    public int GRID_WIDTH;
601516d055df0d939c76ab8f2739f7fb1cdd3956d0Tadashi G. Takaoka    public int GRID_HEIGHT;
611516d055df0d939c76ab8f2739f7fb1cdd3956d0Tadashi G. Takaoka
621516d055df0d939c76ab8f2739f7fb1cdd3956d0Tadashi G. Takaoka    public final List<Key> mKeys = new ArrayList<Key>();
631516d055df0d939c76ab8f2739f7fb1cdd3956d0Tadashi G. Takaoka    public final List<Key> mShiftKeys = new ArrayList<Key>();
641516d055df0d939c76ab8f2739f7fb1cdd3956d0Tadashi G. Takaoka    public final Set<Key> mShiftLockKeys = new HashSet<Key>();
651516d055df0d939c76ab8f2739f7fb1cdd3956d0Tadashi G. Takaoka    public final Map<Key, Drawable> mShiftedIcons = new HashMap<Key, Drawable>();
661516d055df0d939c76ab8f2739f7fb1cdd3956d0Tadashi G. Takaoka    public final Map<Key, Drawable> mUnshiftedIcons = new HashMap<Key, Drawable>();
671516d055df0d939c76ab8f2739f7fb1cdd3956d0Tadashi G. Takaoka    public final KeyboardIconsSet mIconsSet = new KeyboardIconsSet();
681516d055df0d939c76ab8f2739f7fb1cdd3956d0Tadashi G. Takaoka
698fbfac4ffb7079e8e71fd4e3ddc04e362239ebb3Tadashi G. Takaoka    public int mMostCommonKeyHeight = 0;
708da9a13760896cd78235b60d0ea680ea13620532Tadashi G. Takaoka    public int mMostCommonKeyWidth = 0;
718da9a13760896cd78235b60d0ea680ea13620532Tadashi G. Takaoka
72294e1b4a5abb86e58deefc8eee40e6b661524b28Yusuke Nojima    public final TouchPositionCorrection mTouchPositionCorrection = new TouchPositionCorrection();
73294e1b4a5abb86e58deefc8eee40e6b661524b28Yusuke Nojima
74294e1b4a5abb86e58deefc8eee40e6b661524b28Yusuke Nojima    public static class TouchPositionCorrection {
75294e1b4a5abb86e58deefc8eee40e6b661524b28Yusuke Nojima        private static final int TOUCH_POSITION_CORRECTION_RECORD_SIZE = 3;
76294e1b4a5abb86e58deefc8eee40e6b661524b28Yusuke Nojima
77294e1b4a5abb86e58deefc8eee40e6b661524b28Yusuke Nojima        public boolean mEnabled;
78294e1b4a5abb86e58deefc8eee40e6b661524b28Yusuke Nojima        public float[] mXs;
79294e1b4a5abb86e58deefc8eee40e6b661524b28Yusuke Nojima        public float[] mYs;
80294e1b4a5abb86e58deefc8eee40e6b661524b28Yusuke Nojima        public float[] mRadii;
81294e1b4a5abb86e58deefc8eee40e6b661524b28Yusuke Nojima
82294e1b4a5abb86e58deefc8eee40e6b661524b28Yusuke Nojima        public void load(String[] data) {
83294e1b4a5abb86e58deefc8eee40e6b661524b28Yusuke Nojima            final int dataLength = data.length;
84294e1b4a5abb86e58deefc8eee40e6b661524b28Yusuke Nojima            if (dataLength % TOUCH_POSITION_CORRECTION_RECORD_SIZE != 0) {
85294e1b4a5abb86e58deefc8eee40e6b661524b28Yusuke Nojima                if (LatinImeLogger.sDBG)
86294e1b4a5abb86e58deefc8eee40e6b661524b28Yusuke Nojima                    throw new RuntimeException(
87294e1b4a5abb86e58deefc8eee40e6b661524b28Yusuke Nojima                            "the size of touch position correction data is invalid");
88294e1b4a5abb86e58deefc8eee40e6b661524b28Yusuke Nojima                return;
89294e1b4a5abb86e58deefc8eee40e6b661524b28Yusuke Nojima            }
90294e1b4a5abb86e58deefc8eee40e6b661524b28Yusuke Nojima
91294e1b4a5abb86e58deefc8eee40e6b661524b28Yusuke Nojima            final int length = dataLength / TOUCH_POSITION_CORRECTION_RECORD_SIZE;
92294e1b4a5abb86e58deefc8eee40e6b661524b28Yusuke Nojima            mXs = new float[length];
93294e1b4a5abb86e58deefc8eee40e6b661524b28Yusuke Nojima            mYs = new float[length];
94294e1b4a5abb86e58deefc8eee40e6b661524b28Yusuke Nojima            mRadii = new float[length];
95294e1b4a5abb86e58deefc8eee40e6b661524b28Yusuke Nojima            try {
96294e1b4a5abb86e58deefc8eee40e6b661524b28Yusuke Nojima                for (int i = 0; i < dataLength; ++i) {
97294e1b4a5abb86e58deefc8eee40e6b661524b28Yusuke Nojima                    final int type = i % TOUCH_POSITION_CORRECTION_RECORD_SIZE;
98294e1b4a5abb86e58deefc8eee40e6b661524b28Yusuke Nojima                    final int index = i / TOUCH_POSITION_CORRECTION_RECORD_SIZE;
99294e1b4a5abb86e58deefc8eee40e6b661524b28Yusuke Nojima                    final float value = Float.parseFloat(data[i]);
100294e1b4a5abb86e58deefc8eee40e6b661524b28Yusuke Nojima                    if (type == 0) {
101294e1b4a5abb86e58deefc8eee40e6b661524b28Yusuke Nojima                        mXs[index] = value;
102294e1b4a5abb86e58deefc8eee40e6b661524b28Yusuke Nojima                    } else if (type == 1) {
103294e1b4a5abb86e58deefc8eee40e6b661524b28Yusuke Nojima                        mYs[index] = value;
104294e1b4a5abb86e58deefc8eee40e6b661524b28Yusuke Nojima                    } else {
105294e1b4a5abb86e58deefc8eee40e6b661524b28Yusuke Nojima                        mRadii[index] = value;
106294e1b4a5abb86e58deefc8eee40e6b661524b28Yusuke Nojima                    }
107294e1b4a5abb86e58deefc8eee40e6b661524b28Yusuke Nojima                }
108294e1b4a5abb86e58deefc8eee40e6b661524b28Yusuke Nojima            } catch (NumberFormatException e) {
109294e1b4a5abb86e58deefc8eee40e6b661524b28Yusuke Nojima                if (LatinImeLogger.sDBG) {
110294e1b4a5abb86e58deefc8eee40e6b661524b28Yusuke Nojima                    throw new RuntimeException(
111294e1b4a5abb86e58deefc8eee40e6b661524b28Yusuke Nojima                            "the number format for touch position correction data is invalid");
112294e1b4a5abb86e58deefc8eee40e6b661524b28Yusuke Nojima                }
113294e1b4a5abb86e58deefc8eee40e6b661524b28Yusuke Nojima                mXs = null;
114294e1b4a5abb86e58deefc8eee40e6b661524b28Yusuke Nojima                mYs = null;
115294e1b4a5abb86e58deefc8eee40e6b661524b28Yusuke Nojima                mRadii = null;
116294e1b4a5abb86e58deefc8eee40e6b661524b28Yusuke Nojima            }
117294e1b4a5abb86e58deefc8eee40e6b661524b28Yusuke Nojima        }
118294e1b4a5abb86e58deefc8eee40e6b661524b28Yusuke Nojima
119294e1b4a5abb86e58deefc8eee40e6b661524b28Yusuke Nojima        public void setEnabled(boolean enabled) {
120294e1b4a5abb86e58deefc8eee40e6b661524b28Yusuke Nojima            mEnabled = enabled;
121294e1b4a5abb86e58deefc8eee40e6b661524b28Yusuke Nojima        }
122294e1b4a5abb86e58deefc8eee40e6b661524b28Yusuke Nojima
123294e1b4a5abb86e58deefc8eee40e6b661524b28Yusuke Nojima        public boolean isValid() {
124294e1b4a5abb86e58deefc8eee40e6b661524b28Yusuke Nojima            return mEnabled && mXs != null && mYs != null && mRadii != null
125294e1b4a5abb86e58deefc8eee40e6b661524b28Yusuke Nojima                && mXs.length > 0 && mYs.length > 0 && mRadii.length > 0;
126294e1b4a5abb86e58deefc8eee40e6b661524b28Yusuke Nojima        }
127294e1b4a5abb86e58deefc8eee40e6b661524b28Yusuke Nojima    }
128d6339639c39cbe0a833361623bf6963cff526784Yusuke Nojima
129c06d0ef01ddf286080fd421829a587741b1ebc1bTadashi G. Takaoka    protected void clearKeys() {
130c06d0ef01ddf286080fd421829a587741b1ebc1bTadashi G. Takaoka        mKeys.clear();
131c06d0ef01ddf286080fd421829a587741b1ebc1bTadashi G. Takaoka        mShiftKeys.clear();
132c06d0ef01ddf286080fd421829a587741b1ebc1bTadashi G. Takaoka        mShiftLockKeys.clear();
133c06d0ef01ddf286080fd421829a587741b1ebc1bTadashi G. Takaoka        mShiftedIcons.clear();
134c06d0ef01ddf286080fd421829a587741b1ebc1bTadashi G. Takaoka        mUnshiftedIcons.clear();
135c06d0ef01ddf286080fd421829a587741b1ebc1bTadashi G. Takaoka        clearHistogram();
136c06d0ef01ddf286080fd421829a587741b1ebc1bTadashi G. Takaoka    }
137c06d0ef01ddf286080fd421829a587741b1ebc1bTadashi G. Takaoka
1388da9a13760896cd78235b60d0ea680ea13620532Tadashi G. Takaoka    public void onAddKey(Key key) {
1398da9a13760896cd78235b60d0ea680ea13620532Tadashi G. Takaoka        mKeys.add(key);
1408da9a13760896cd78235b60d0ea680ea13620532Tadashi G. Takaoka        updateHistogram(key);
1418da9a13760896cd78235b60d0ea680ea13620532Tadashi G. Takaoka        if (key.mCode == Keyboard.CODE_SHIFT) {
1428da9a13760896cd78235b60d0ea680ea13620532Tadashi G. Takaoka            mShiftKeys.add(key);
1435b0c124ca888ee4ecbde9a51f11c4e9887a96636Tadashi G. Takaoka            if (key.isSticky()) {
1448da9a13760896cd78235b60d0ea680ea13620532Tadashi G. Takaoka                mShiftLockKeys.add(key);
1458da9a13760896cd78235b60d0ea680ea13620532Tadashi G. Takaoka            }
1461516d055df0d939c76ab8f2739f7fb1cdd3956d0Tadashi G. Takaoka        }
1471516d055df0d939c76ab8f2739f7fb1cdd3956d0Tadashi G. Takaoka    }
1481516d055df0d939c76ab8f2739f7fb1cdd3956d0Tadashi G. Takaoka
1491516d055df0d939c76ab8f2739f7fb1cdd3956d0Tadashi G. Takaoka    public void addShiftedIcon(Key key, Drawable icon) {
1501516d055df0d939c76ab8f2739f7fb1cdd3956d0Tadashi G. Takaoka        mUnshiftedIcons.put(key, key.getIcon());
1511516d055df0d939c76ab8f2739f7fb1cdd3956d0Tadashi G. Takaoka        mShiftedIcons.put(key, icon);
1521516d055df0d939c76ab8f2739f7fb1cdd3956d0Tadashi G. Takaoka    }
1531516d055df0d939c76ab8f2739f7fb1cdd3956d0Tadashi G. Takaoka
1548fbfac4ffb7079e8e71fd4e3ddc04e362239ebb3Tadashi G. Takaoka    private int mMaxHeightCount = 0;
1558fbfac4ffb7079e8e71fd4e3ddc04e362239ebb3Tadashi G. Takaoka    private int mMaxWidthCount = 0;
1568fbfac4ffb7079e8e71fd4e3ddc04e362239ebb3Tadashi G. Takaoka    private final Map<Integer, Integer> mHeightHistogram = new HashMap<Integer, Integer>();
1578fbfac4ffb7079e8e71fd4e3ddc04e362239ebb3Tadashi G. Takaoka    private final Map<Integer, Integer> mWidthHistogram = new HashMap<Integer, Integer>();
1588da9a13760896cd78235b60d0ea680ea13620532Tadashi G. Takaoka
159c06d0ef01ddf286080fd421829a587741b1ebc1bTadashi G. Takaoka    private void clearHistogram() {
1608fbfac4ffb7079e8e71fd4e3ddc04e362239ebb3Tadashi G. Takaoka        mMostCommonKeyHeight = 0;
1618fbfac4ffb7079e8e71fd4e3ddc04e362239ebb3Tadashi G. Takaoka        mMaxHeightCount = 0;
1628fbfac4ffb7079e8e71fd4e3ddc04e362239ebb3Tadashi G. Takaoka        mHeightHistogram.clear();
1638fbfac4ffb7079e8e71fd4e3ddc04e362239ebb3Tadashi G. Takaoka
1648fbfac4ffb7079e8e71fd4e3ddc04e362239ebb3Tadashi G. Takaoka        mMaxWidthCount = 0;
165c06d0ef01ddf286080fd421829a587741b1ebc1bTadashi G. Takaoka        mMostCommonKeyWidth = 0;
1668fbfac4ffb7079e8e71fd4e3ddc04e362239ebb3Tadashi G. Takaoka        mWidthHistogram.clear();
1678fbfac4ffb7079e8e71fd4e3ddc04e362239ebb3Tadashi G. Takaoka    }
1688fbfac4ffb7079e8e71fd4e3ddc04e362239ebb3Tadashi G. Takaoka
1698fbfac4ffb7079e8e71fd4e3ddc04e362239ebb3Tadashi G. Takaoka    private static int updateHistogramCounter(Map<Integer, Integer> histogram, Integer key) {
1708fbfac4ffb7079e8e71fd4e3ddc04e362239ebb3Tadashi G. Takaoka        final int count = (histogram.containsKey(key) ? histogram.get(key) : 0) + 1;
1718fbfac4ffb7079e8e71fd4e3ddc04e362239ebb3Tadashi G. Takaoka        histogram.put(key, count);
1728fbfac4ffb7079e8e71fd4e3ddc04e362239ebb3Tadashi G. Takaoka        return count;
173c06d0ef01ddf286080fd421829a587741b1ebc1bTadashi G. Takaoka    }
174c06d0ef01ddf286080fd421829a587741b1ebc1bTadashi G. Takaoka
1758da9a13760896cd78235b60d0ea680ea13620532Tadashi G. Takaoka    private void updateHistogram(Key key) {
1768fbfac4ffb7079e8e71fd4e3ddc04e362239ebb3Tadashi G. Takaoka        final Integer height = key.mHeight + key.mVerticalGap;
1778fbfac4ffb7079e8e71fd4e3ddc04e362239ebb3Tadashi G. Takaoka        final int heightCount = updateHistogramCounter(mHeightHistogram, height);
1788fbfac4ffb7079e8e71fd4e3ddc04e362239ebb3Tadashi G. Takaoka        if (heightCount > mMaxHeightCount) {
1798fbfac4ffb7079e8e71fd4e3ddc04e362239ebb3Tadashi G. Takaoka            mMaxHeightCount = heightCount;
1808fbfac4ffb7079e8e71fd4e3ddc04e362239ebb3Tadashi G. Takaoka            mMostCommonKeyHeight = height;
1818fbfac4ffb7079e8e71fd4e3ddc04e362239ebb3Tadashi G. Takaoka        }
1828fbfac4ffb7079e8e71fd4e3ddc04e362239ebb3Tadashi G. Takaoka
1838da9a13760896cd78235b60d0ea680ea13620532Tadashi G. Takaoka        final Integer width = key.mWidth + key.mHorizontalGap;
1848fbfac4ffb7079e8e71fd4e3ddc04e362239ebb3Tadashi G. Takaoka        final int widthCount = updateHistogramCounter(mWidthHistogram, width);
1858fbfac4ffb7079e8e71fd4e3ddc04e362239ebb3Tadashi G. Takaoka        if (widthCount > mMaxWidthCount) {
1868fbfac4ffb7079e8e71fd4e3ddc04e362239ebb3Tadashi G. Takaoka            mMaxWidthCount = widthCount;
1878da9a13760896cd78235b60d0ea680ea13620532Tadashi G. Takaoka            mMostCommonKeyWidth = width;
1881516d055df0d939c76ab8f2739f7fb1cdd3956d0Tadashi G. Takaoka        }
1891516d055df0d939c76ab8f2739f7fb1cdd3956d0Tadashi G. Takaoka    }
1901516d055df0d939c76ab8f2739f7fb1cdd3956d0Tadashi G. Takaoka}
191