WordComposer.java revision f7d6517d6b1a1dd88e2142e1a15703bb839be01b
1923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project/*
2443c360d0afdbab091994244f045f4756feaf2b4Jean-Baptiste Queru * Copyright (C) 2008 The Android Open Source Project
3923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project *
4923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License"); you may not
5923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * use this file except in compliance with the License. You may obtain a copy of
6923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * the License at
7923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project *
8923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * http://www.apache.org/licenses/LICENSE-2.0
9923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project *
10923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * Unless required by applicable law or agreed to in writing, software
11923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * License for the specific language governing permissions and limitations under
14923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * the License.
15923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project */
16923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
17923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectpackage com.android.inputmethod.latin;
18923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
19c83359f9746ca6f0269a1a7017b585c1a5cab9b8Jean Chalardimport com.android.inputmethod.keyboard.Keyboard;
206b1f500da451de56932a8b2a99c63857994ece85Jean Chalardimport com.android.inputmethod.keyboard.Key;
21887f11ee43ad621aa6ad93d535ab7f48dec73fc7Tadashi G. Takaokaimport com.android.inputmethod.keyboard.KeyDetector;
226b1f500da451de56932a8b2a99c63857994ece85Jean Chalardimport com.android.inputmethod.keyboard.LatinKeyboard;
23887f11ee43ad621aa6ad93d535ab7f48dec73fc7Tadashi G. Takaoka
24923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectimport java.util.ArrayList;
25c83359f9746ca6f0269a1a7017b585c1a5cab9b8Jean Chalardimport java.util.Arrays;
26923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
27923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project/**
28923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * A place to store the currently composing word with information such as adjacent key codes as well
29923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project */
30923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectpublic class WordComposer {
318fbd55229243cb66c03d5ea1f79dfb39f596590dsatok
32887f11ee43ad621aa6ad93d535ab7f48dec73fc7Tadashi G. Takaoka    public static final int NOT_A_CODE = KeyDetector.NOT_A_CODE;
338fbd55229243cb66c03d5ea1f79dfb39f596590dsatok    public static final int NOT_A_COORDINATE = -1;
34887f11ee43ad621aa6ad93d535ab7f48dec73fc7Tadashi G. Takaoka
35923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    /**
36923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project     * The list of unicode values for each keystroke (including surrounding keys)
37923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project     */
389fbfd5877305ed19a20663630b498b6b3fdae942satok    private ArrayList<int[]> mCodes;
398fbd55229243cb66c03d5ea1f79dfb39f596590dsatok
409fbfd5877305ed19a20663630b498b6b3fdae942satok    private int[] mXCoordinates;
419fbfd5877305ed19a20663630b498b6b3fdae942satok    private int[] mYCoordinates;
428fbd55229243cb66c03d5ea1f79dfb39f596590dsatok
439fbfd5877305ed19a20663630b498b6b3fdae942satok    private StringBuilder mTypedWord;
44117fc93f373cb86d4120c1261f9d0562c6529fecJean Chalard    // An auto-correction for this word out of the dictionary.
45117fc93f373cb86d4120c1261f9d0562c6529fecJean Chalard    private CharSequence mAutoCorrection;
464a7ff90d513f8b6cbf39688c08be0828a57e311bAmith Yamasani
474a7ff90d513f8b6cbf39688c08be0828a57e311bAmith Yamasani    private int mCapsCount;
481c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani
491c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani    private boolean mAutoCapitalized;
50c83359f9746ca6f0269a1a7017b585c1a5cab9b8Jean Chalard    // Cache this value for performance
51117fc18ed46496c81596f8207bba30a09c7317d1Jean Chalard    private int mTrailingSingleQuotesCount;
52c83359f9746ca6f0269a1a7017b585c1a5cab9b8Jean Chalard
53923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    /**
540b4ae1f578e768eec4ada90aeb81d11acb10eb2eKen Wakasa     * Whether the user chose to capitalize the first char of the word.
55923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project     */
560b4ae1f578e768eec4ada90aeb81d11acb10eb2eKen Wakasa    private boolean mIsFirstCharCapitalized;
57923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
58979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    public WordComposer() {
598fbd55229243cb66c03d5ea1f79dfb39f596590dsatok        final int N = BinaryDictionary.MAX_WORD_LENGTH;
608fbd55229243cb66c03d5ea1f79dfb39f596590dsatok        mCodes = new ArrayList<int[]>(N);
618fbd55229243cb66c03d5ea1f79dfb39f596590dsatok        mTypedWord = new StringBuilder(N);
628fbd55229243cb66c03d5ea1f79dfb39f596590dsatok        mXCoordinates = new int[N];
638fbd55229243cb66c03d5ea1f79dfb39f596590dsatok        mYCoordinates = new int[N];
64117fc18ed46496c81596f8207bba30a09c7317d1Jean Chalard        mTrailingSingleQuotesCount = 0;
65117fc93f373cb86d4120c1261f9d0562c6529fecJean Chalard        mAutoCorrection = null;
66923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
67923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
68f733074aaecdfd6e89cfee2daff8a9c1233b60f1satok    public WordComposer(WordComposer source) {
699fbfd5877305ed19a20663630b498b6b3fdae942satok        init(source);
709fbfd5877305ed19a20663630b498b6b3fdae942satok    }
719fbfd5877305ed19a20663630b498b6b3fdae942satok
729fbfd5877305ed19a20663630b498b6b3fdae942satok    public void init(WordComposer source) {
738fbd55229243cb66c03d5ea1f79dfb39f596590dsatok        mCodes = new ArrayList<int[]>(source.mCodes);
748fbd55229243cb66c03d5ea1f79dfb39f596590dsatok        mTypedWord = new StringBuilder(source.mTypedWord);
75c83359f9746ca6f0269a1a7017b585c1a5cab9b8Jean Chalard        mXCoordinates = Arrays.copyOf(source.mXCoordinates, source.mXCoordinates.length);
76c83359f9746ca6f0269a1a7017b585c1a5cab9b8Jean Chalard        mYCoordinates = Arrays.copyOf(source.mYCoordinates, source.mYCoordinates.length);
77ea843f2a2404f4bc04fda494e475520162cfca27Tadashi G. Takaoka        mCapsCount = source.mCapsCount;
78ea843f2a2404f4bc04fda494e475520162cfca27Tadashi G. Takaoka        mIsFirstCharCapitalized = source.mIsFirstCharCapitalized;
79ea843f2a2404f4bc04fda494e475520162cfca27Tadashi G. Takaoka        mAutoCapitalized = source.mAutoCapitalized;
80117fc18ed46496c81596f8207bba30a09c7317d1Jean Chalard        mTrailingSingleQuotesCount = source.mTrailingSingleQuotesCount;
81117fc93f373cb86d4120c1261f9d0562c6529fecJean Chalard        mAutoCorrection = null;
82979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    }
83979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
84923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    /**
85923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project     * Clear out the keys registered so far.
86923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project     */
87923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    public void reset() {
88923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        mCodes.clear();
89923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        mTypedWord.setLength(0);
904a7ff90d513f8b6cbf39688c08be0828a57e311bAmith Yamasani        mCapsCount = 0;
91ea843f2a2404f4bc04fda494e475520162cfca27Tadashi G. Takaoka        mIsFirstCharCapitalized = false;
92117fc18ed46496c81596f8207bba30a09c7317d1Jean Chalard        mTrailingSingleQuotesCount = 0;
93117fc93f373cb86d4120c1261f9d0562c6529fecJean Chalard        mAutoCorrection = null;
94923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
95923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
96923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    /**
97923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project     * Number of keystrokes in the composing word.
98923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project     * @return the number of keystrokes
99923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project     */
100ea843f2a2404f4bc04fda494e475520162cfca27Tadashi G. Takaoka    public final int size() {
101ea843f2a2404f4bc04fda494e475520162cfca27Tadashi G. Takaoka        return mTypedWord.length();
102923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
103923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
104923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    /**
105923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project     * Returns the codes at a particular position in the word.
106923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project     * @param index the position in the word
107923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project     * @return the unicode for the pressed and surrounding keys
108923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project     */
109923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    public int[] getCodesAt(int index) {
110923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        return mCodes.get(index);
111923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
112923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
1138fbd55229243cb66c03d5ea1f79dfb39f596590dsatok    public int[] getXCoordinates() {
1148fbd55229243cb66c03d5ea1f79dfb39f596590dsatok        return mXCoordinates;
1158fbd55229243cb66c03d5ea1f79dfb39f596590dsatok    }
1168fbd55229243cb66c03d5ea1f79dfb39f596590dsatok
1178fbd55229243cb66c03d5ea1f79dfb39f596590dsatok    public int[] getYCoordinates() {
1188fbd55229243cb66c03d5ea1f79dfb39f596590dsatok        return mYCoordinates;
1198fbd55229243cb66c03d5ea1f79dfb39f596590dsatok    }
1208fbd55229243cb66c03d5ea1f79dfb39f596590dsatok
121ea843f2a2404f4bc04fda494e475520162cfca27Tadashi G. Takaoka    private static boolean isFirstCharCapitalized(int index, int codePoint, boolean previous) {
122ea843f2a2404f4bc04fda494e475520162cfca27Tadashi G. Takaoka        if (index == 0) return Character.isUpperCase(codePoint);
123436a645ea837d36f7e0f81948d343fa6e166f33aTadashi G. Takaoka        return previous && !Character.isUpperCase(codePoint);
124ea843f2a2404f4bc04fda494e475520162cfca27Tadashi G. Takaoka    }
125ea843f2a2404f4bc04fda494e475520162cfca27Tadashi G. Takaoka
126923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    /**
127923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project     * Add a new keystroke, with codes[0] containing the pressed key's unicode and the rest of
128923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project     * the array containing unicode for adjacent keys, sorted by reducing probability/proximity.
129923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project     * @param codes the array of unicode values
130923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project     */
1318fbd55229243cb66c03d5ea1f79dfb39f596590dsatok    public void add(int primaryCode, int[] codes, int x, int y) {
132ea843f2a2404f4bc04fda494e475520162cfca27Tadashi G. Takaoka        final int newIndex = size();
133923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        mTypedWord.append((char) primaryCode);
134231cacd08075e88a2bcdf25f025206de524e880bAmith Yamasani        correctPrimaryJuxtapos(primaryCode, codes);
135923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        mCodes.add(codes);
136ea843f2a2404f4bc04fda494e475520162cfca27Tadashi G. Takaoka        if (newIndex < BinaryDictionary.MAX_WORD_LENGTH) {
137ea843f2a2404f4bc04fda494e475520162cfca27Tadashi G. Takaoka            mXCoordinates[newIndex] = x;
138ea843f2a2404f4bc04fda494e475520162cfca27Tadashi G. Takaoka            mYCoordinates[newIndex] = y;
1398fbd55229243cb66c03d5ea1f79dfb39f596590dsatok        }
140ea843f2a2404f4bc04fda494e475520162cfca27Tadashi G. Takaoka        mIsFirstCharCapitalized = isFirstCharCapitalized(
141ea843f2a2404f4bc04fda494e475520162cfca27Tadashi G. Takaoka                newIndex, primaryCode, mIsFirstCharCapitalized);
142ea843f2a2404f4bc04fda494e475520162cfca27Tadashi G. Takaoka        if (Character.isUpperCase(primaryCode)) mCapsCount++;
143117fc18ed46496c81596f8207bba30a09c7317d1Jean Chalard        if (Keyboard.CODE_SINGLE_QUOTE == primaryCode) {
144117fc18ed46496c81596f8207bba30a09c7317d1Jean Chalard            ++mTrailingSingleQuotesCount;
145117fc18ed46496c81596f8207bba30a09c7317d1Jean Chalard        } else {
146117fc18ed46496c81596f8207bba30a09c7317d1Jean Chalard            mTrailingSingleQuotesCount = 0;
147117fc18ed46496c81596f8207bba30a09c7317d1Jean Chalard        }
148117fc93f373cb86d4120c1261f9d0562c6529fecJean Chalard        mAutoCorrection = null;
149923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
150923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
151923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    /**
1526b1f500da451de56932a8b2a99c63857994ece85Jean Chalard     * Internal method to retrieve reasonable proximity info for a character.
1536b1f500da451de56932a8b2a99c63857994ece85Jean Chalard     */
1546b1f500da451de56932a8b2a99c63857994ece85Jean Chalard    private void addKeyInfo(final int codePoint, final LatinKeyboard keyboard,
1556b1f500da451de56932a8b2a99c63857994ece85Jean Chalard            final KeyDetector keyDetector) {
1566b1f500da451de56932a8b2a99c63857994ece85Jean Chalard        for (final Key key : keyboard.mKeys) {
1576b1f500da451de56932a8b2a99c63857994ece85Jean Chalard            if (key.mCode == codePoint) {
1586b1f500da451de56932a8b2a99c63857994ece85Jean Chalard                final int x = key.mX + key.mWidth / 2;
1596b1f500da451de56932a8b2a99c63857994ece85Jean Chalard                final int y = key.mY + key.mHeight / 2;
1606b1f500da451de56932a8b2a99c63857994ece85Jean Chalard                final int[] codes = keyDetector.newCodeArray();
161e22baaadd314c80f835e2e96fb0dfc73838ac2cdTadashi G. Takaoka                keyDetector.getKeyAndNearbyCodes(x, y, codes);
1626b1f500da451de56932a8b2a99c63857994ece85Jean Chalard                add(codePoint, codes, x, y);
1636b1f500da451de56932a8b2a99c63857994ece85Jean Chalard                return;
1646b1f500da451de56932a8b2a99c63857994ece85Jean Chalard            }
1656b1f500da451de56932a8b2a99c63857994ece85Jean Chalard        }
1666b1f500da451de56932a8b2a99c63857994ece85Jean Chalard        add(codePoint, new int[] { codePoint },
1676b1f500da451de56932a8b2a99c63857994ece85Jean Chalard                WordComposer.NOT_A_COORDINATE, WordComposer.NOT_A_COORDINATE);
1686b1f500da451de56932a8b2a99c63857994ece85Jean Chalard    }
1696b1f500da451de56932a8b2a99c63857994ece85Jean Chalard
1706b1f500da451de56932a8b2a99c63857994ece85Jean Chalard    /**
1716b1f500da451de56932a8b2a99c63857994ece85Jean Chalard     * Set the currently composing word to the one passed as an argument.
1726b1f500da451de56932a8b2a99c63857994ece85Jean Chalard     * This will register NOT_A_COORDINATE for X and Ys, and use the passed keyboard for proximity.
1736b1f500da451de56932a8b2a99c63857994ece85Jean Chalard     */
1746b1f500da451de56932a8b2a99c63857994ece85Jean Chalard    public void setComposingWord(final CharSequence word, final LatinKeyboard keyboard,
1756b1f500da451de56932a8b2a99c63857994ece85Jean Chalard            final KeyDetector keyDetector) {
1766b1f500da451de56932a8b2a99c63857994ece85Jean Chalard        reset();
1776b1f500da451de56932a8b2a99c63857994ece85Jean Chalard        final int length = word.length();
1786b1f500da451de56932a8b2a99c63857994ece85Jean Chalard        for (int i = 0; i < length; ++i) {
1796b1f500da451de56932a8b2a99c63857994ece85Jean Chalard            int codePoint = word.charAt(i);
1806b1f500da451de56932a8b2a99c63857994ece85Jean Chalard            addKeyInfo(codePoint, keyboard, keyDetector);
1816b1f500da451de56932a8b2a99c63857994ece85Jean Chalard        }
182117fc93f373cb86d4120c1261f9d0562c6529fecJean Chalard        mAutoCorrection = null;
1836b1f500da451de56932a8b2a99c63857994ece85Jean Chalard    }
1846b1f500da451de56932a8b2a99c63857994ece85Jean Chalard
1856b1f500da451de56932a8b2a99c63857994ece85Jean Chalard    /**
1866b1f500da451de56932a8b2a99c63857994ece85Jean Chalard     * Shortcut for the above method, this will create a new KeyDetector for the passed keyboard.
1876b1f500da451de56932a8b2a99c63857994ece85Jean Chalard     */
1886b1f500da451de56932a8b2a99c63857994ece85Jean Chalard    public void setComposingWord(final CharSequence word, final LatinKeyboard keyboard) {
1896b1f500da451de56932a8b2a99c63857994ece85Jean Chalard        final KeyDetector keyDetector = new KeyDetector(0);
1906b1f500da451de56932a8b2a99c63857994ece85Jean Chalard        keyDetector.setKeyboard(keyboard, 0, 0);
1916b1f500da451de56932a8b2a99c63857994ece85Jean Chalard        keyDetector.setProximityCorrectionEnabled(true);
1926b1f500da451de56932a8b2a99c63857994ece85Jean Chalard        keyDetector.setProximityThreshold(keyboard.mMostCommonKeyWidth);
1936b1f500da451de56932a8b2a99c63857994ece85Jean Chalard        setComposingWord(word, keyboard, keyDetector);
1946b1f500da451de56932a8b2a99c63857994ece85Jean Chalard    }
1956b1f500da451de56932a8b2a99c63857994ece85Jean Chalard
1966b1f500da451de56932a8b2a99c63857994ece85Jean Chalard    /**
197231cacd08075e88a2bcdf25f025206de524e880bAmith Yamasani     * Swaps the first and second values in the codes array if the primary code is not the first
198231cacd08075e88a2bcdf25f025206de524e880bAmith Yamasani     * value in the array but the second. This happens when the preferred key is not the key that
199231cacd08075e88a2bcdf25f025206de524e880bAmith Yamasani     * the user released the finger on.
200231cacd08075e88a2bcdf25f025206de524e880bAmith Yamasani     * @param primaryCode the preferred character
201231cacd08075e88a2bcdf25f025206de524e880bAmith Yamasani     * @param codes array of codes based on distance from touch point
202231cacd08075e88a2bcdf25f025206de524e880bAmith Yamasani     */
2038fbf29e2d54027a17993cd0d4ad486e3454b56f6Tadashi G. Takaoka    private static void correctPrimaryJuxtapos(int primaryCode, int[] codes) {
204231cacd08075e88a2bcdf25f025206de524e880bAmith Yamasani        if (codes.length < 2) return;
205231cacd08075e88a2bcdf25f025206de524e880bAmith Yamasani        if (codes[0] > 0 && codes[1] > 0 && codes[0] != primaryCode && codes[1] == primaryCode) {
206231cacd08075e88a2bcdf25f025206de524e880bAmith Yamasani            codes[1] = codes[0];
207231cacd08075e88a2bcdf25f025206de524e880bAmith Yamasani            codes[0] = primaryCode;
208231cacd08075e88a2bcdf25f025206de524e880bAmith Yamasani        }
209231cacd08075e88a2bcdf25f025206de524e880bAmith Yamasani    }
210231cacd08075e88a2bcdf25f025206de524e880bAmith Yamasani
211231cacd08075e88a2bcdf25f025206de524e880bAmith Yamasani    /**
212923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project     * Delete the last keystroke as a result of hitting backspace.
213923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project     */
214923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    public void deleteLast() {
215ea843f2a2404f4bc04fda494e475520162cfca27Tadashi G. Takaoka        final int size = size();
216ea843f2a2404f4bc04fda494e475520162cfca27Tadashi G. Takaoka        if (size > 0) {
217ea843f2a2404f4bc04fda494e475520162cfca27Tadashi G. Takaoka            final int lastPos = size - 1;
218ea843f2a2404f4bc04fda494e475520162cfca27Tadashi G. Takaoka            char lastChar = mTypedWord.charAt(lastPos);
219ea843f2a2404f4bc04fda494e475520162cfca27Tadashi G. Takaoka            mCodes.remove(lastPos);
220d1a8e3088bb6267a31e3351d304796d1507e3af6Tadashi G. Takaoka            mTypedWord.deleteCharAt(lastPos);
221ea843f2a2404f4bc04fda494e475520162cfca27Tadashi G. Takaoka            if (Character.isUpperCase(lastChar)) mCapsCount--;
222d1a8e3088bb6267a31e3351d304796d1507e3af6Tadashi G. Takaoka        }
223ea843f2a2404f4bc04fda494e475520162cfca27Tadashi G. Takaoka        if (size() == 0) {
224ea843f2a2404f4bc04fda494e475520162cfca27Tadashi G. Takaoka            mIsFirstCharCapitalized = false;
225117fc18ed46496c81596f8207bba30a09c7317d1Jean Chalard        }
226117fc18ed46496c81596f8207bba30a09c7317d1Jean Chalard        if (mTrailingSingleQuotesCount > 0) {
227117fc18ed46496c81596f8207bba30a09c7317d1Jean Chalard            --mTrailingSingleQuotesCount;
228c83359f9746ca6f0269a1a7017b585c1a5cab9b8Jean Chalard        } else {
229117fc18ed46496c81596f8207bba30a09c7317d1Jean Chalard            for (int i = mTypedWord.length() - 1; i >= 0; --i) {
230117fc18ed46496c81596f8207bba30a09c7317d1Jean Chalard                if (Keyboard.CODE_SINGLE_QUOTE != mTypedWord.codePointAt(i)) break;
231117fc18ed46496c81596f8207bba30a09c7317d1Jean Chalard                ++mTrailingSingleQuotesCount;
232117fc18ed46496c81596f8207bba30a09c7317d1Jean Chalard            }
2338fbd55229243cb66c03d5ea1f79dfb39f596590dsatok        }
234117fc93f373cb86d4120c1261f9d0562c6529fecJean Chalard        mAutoCorrection = null;
235923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
236923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
237923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    /**
238923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project     * Returns the word as it was typed, without any correction applied.
239117fc93f373cb86d4120c1261f9d0562c6529fecJean Chalard     * @return the word that was typed so far. Never returns null.
240923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project     */
2415c08151c227d98031abe27c3f0a8f43a7126ae9dJean Chalard    public String getTypedWord() {
2425c08151c227d98031abe27c3f0a8f43a7126ae9dJean Chalard        return mTypedWord.toString();
243923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
244923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
245923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    /**
246923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project     * Whether or not the user typed a capital letter as the first letter in the word
247923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project     * @return capitalization preference
248923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project     */
2490b4ae1f578e768eec4ada90aeb81d11acb10eb2eKen Wakasa    public boolean isFirstCharCapitalized() {
2500b4ae1f578e768eec4ada90aeb81d11acb10eb2eKen Wakasa        return mIsFirstCharCapitalized;
251923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
2520b4ae1f578e768eec4ada90aeb81d11acb10eb2eKen Wakasa
253117fc18ed46496c81596f8207bba30a09c7317d1Jean Chalard    public int trailingSingleQuotesCount() {
254117fc18ed46496c81596f8207bba30a09c7317d1Jean Chalard        return mTrailingSingleQuotesCount;
255c83359f9746ca6f0269a1a7017b585c1a5cab9b8Jean Chalard    }
256c83359f9746ca6f0269a1a7017b585c1a5cab9b8Jean Chalard
2570b4ae1f578e768eec4ada90aeb81d11acb10eb2eKen Wakasa    /**
2580b4ae1f578e768eec4ada90aeb81d11acb10eb2eKen Wakasa     * Whether or not all of the user typed chars are upper case
2590b4ae1f578e768eec4ada90aeb81d11acb10eb2eKen Wakasa     * @return true if all user typed chars are upper case, false otherwise
2600b4ae1f578e768eec4ada90aeb81d11acb10eb2eKen Wakasa     */
2610b4ae1f578e768eec4ada90aeb81d11acb10eb2eKen Wakasa    public boolean isAllUpperCase() {
2620b4ae1f578e768eec4ada90aeb81d11acb10eb2eKen Wakasa        return (mCapsCount > 0) && (mCapsCount == size());
2630b4ae1f578e768eec4ada90aeb81d11acb10eb2eKen Wakasa    }
2640b4ae1f578e768eec4ada90aeb81d11acb10eb2eKen Wakasa
265923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    /**
2664a7ff90d513f8b6cbf39688c08be0828a57e311bAmith Yamasani     * Returns true if more than one character is upper case, otherwise returns false.
2674a7ff90d513f8b6cbf39688c08be0828a57e311bAmith Yamasani     */
2684a7ff90d513f8b6cbf39688c08be0828a57e311bAmith Yamasani    public boolean isMostlyCaps() {
2694a7ff90d513f8b6cbf39688c08be0828a57e311bAmith Yamasani        return mCapsCount > 1;
2704a7ff90d513f8b6cbf39688c08be0828a57e311bAmith Yamasani    }
2711c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani
2721c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani    /**
2731c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani     * Saves the reason why the word is capitalized - whether it was automatic or
2741c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani     * due to the user hitting shift in the middle of a sentence.
2751c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani     * @param auto whether it was an automatic capitalization due to start of sentence
2761c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani     */
2771c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani    public void setAutoCapitalized(boolean auto) {
2781c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani        mAutoCapitalized = auto;
2791c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani    }
2801c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani
2811c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani    /**
2821c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani     * Returns whether the word was automatically capitalized.
2831c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani     * @return whether the word was automatically capitalized
2841c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani     */
2851c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani    public boolean isAutoCapitalized() {
2861c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani        return mAutoCapitalized;
2871c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani    }
288117fc93f373cb86d4120c1261f9d0562c6529fecJean Chalard
289117fc93f373cb86d4120c1261f9d0562c6529fecJean Chalard    /**
290117fc93f373cb86d4120c1261f9d0562c6529fecJean Chalard     * Sets the auto-correction for this word.
291117fc93f373cb86d4120c1261f9d0562c6529fecJean Chalard     */
292117fc93f373cb86d4120c1261f9d0562c6529fecJean Chalard    public void setAutoCorrection(final CharSequence correction) {
293117fc93f373cb86d4120c1261f9d0562c6529fecJean Chalard        mAutoCorrection = correction;
294117fc93f373cb86d4120c1261f9d0562c6529fecJean Chalard    }
295117fc93f373cb86d4120c1261f9d0562c6529fecJean Chalard
296117fc93f373cb86d4120c1261f9d0562c6529fecJean Chalard    /**
297117fc93f373cb86d4120c1261f9d0562c6529fecJean Chalard     * Remove any auto-correction that may have been set.
298117fc93f373cb86d4120c1261f9d0562c6529fecJean Chalard     */
299117fc93f373cb86d4120c1261f9d0562c6529fecJean Chalard    public void deleteAutoCorrection() {
300117fc93f373cb86d4120c1261f9d0562c6529fecJean Chalard        mAutoCorrection = null;
301117fc93f373cb86d4120c1261f9d0562c6529fecJean Chalard    }
302117fc93f373cb86d4120c1261f9d0562c6529fecJean Chalard
303117fc93f373cb86d4120c1261f9d0562c6529fecJean Chalard    /**
304f7d6517d6b1a1dd88e2142e1a15703bb839be01bJean Chalard     * @return the auto-correction for this word, or null if none.
305117fc93f373cb86d4120c1261f9d0562c6529fecJean Chalard     */
306117fc93f373cb86d4120c1261f9d0562c6529fecJean Chalard    public CharSequence getAutoCorrectionOrNull() {
307117fc93f373cb86d4120c1261f9d0562c6529fecJean Chalard        return mAutoCorrection;
308117fc93f373cb86d4120c1261f9d0562c6529fecJean Chalard    }
309923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project}
310