WordComposer.java revision 5c641a9f59735f0eaa772bde027993275b1bdfd7
1923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project/*
2443c360d0afdbab091994244f045f4756feaf2b4Jean-Baptiste Queru * Copyright (C) 2008 The Android Open Source Project
30fd625bcfdfac1c10e7bd7f9088bf425fec08989Jean Chalard *
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
70fd625bcfdfac1c10e7bd7f9088bf425fec08989Jean Chalard *
8923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * http://www.apache.org/licenses/LICENSE-2.0
90fd625bcfdfac1c10e7bd7f9088bf425fec08989Jean Chalard *
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
196b1f500da451de56932a8b2a99c63857994ece85Jean Chalardimport com.android.inputmethod.keyboard.Key;
20887f11ee43ad621aa6ad93d535ab7f48dec73fc7Tadashi G. Takaokaimport com.android.inputmethod.keyboard.KeyDetector;
213708787fe91227083d2a1874fa41493d3bc9fe10Tadashi G. Takaokaimport com.android.inputmethod.keyboard.Keyboard;
22887f11ee43ad621aa6ad93d535ab7f48dec73fc7Tadashi G. Takaoka
23c83359f9746ca6f0269a1a7017b585c1a5cab9b8Jean Chalardimport java.util.Arrays;
24923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
25923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project/**
26923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * A place to store the currently composing word with information such as adjacent key codes as well
27923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project */
28923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Projectpublic class WordComposer {
298fbd55229243cb66c03d5ea1f79dfb39f596590dsatok
30887f11ee43ad621aa6ad93d535ab7f48dec73fc7Tadashi G. Takaoka    public static final int NOT_A_CODE = KeyDetector.NOT_A_CODE;
318fbd55229243cb66c03d5ea1f79dfb39f596590dsatok    public static final int NOT_A_COORDINATE = -1;
32887f11ee43ad621aa6ad93d535ab7f48dec73fc7Tadashi G. Takaoka
3301ab7c8b59a7f12862fbd95fb252e56719f1757fsatok    private static final int N = BinaryDictionary.MAX_WORD_LENGTH;
348fbd55229243cb66c03d5ea1f79dfb39f596590dsatok
3501ab7c8b59a7f12862fbd95fb252e56719f1757fsatok    private int[] mPrimaryKeyCodes;
3671538b08e4e08d556f700ad344562ca2c7b74d82Satoshi Kataoka    private final InputPointers mInputPointers = new InputPointers();
37be79227dc99421ff7be62224c51c553b3fa73777Jean Chalard    private StringBuilder mTypedWord;
38be79227dc99421ff7be62224c51c553b3fa73777Jean Chalard    private CharSequence mAutoCorrection;
394b5b46bb66bf74ef5edd65c55e186b02f3c56e5dJean Chalard    private boolean mIsResumed;
404a7ff90d513f8b6cbf39688c08be0828a57e311bAmith Yamasani
41be79227dc99421ff7be62224c51c553b3fa73777Jean Chalard    // Cache these values for performance
424a7ff90d513f8b6cbf39688c08be0828a57e311bAmith Yamasani    private int mCapsCount;
431c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani    private boolean mAutoCapitalized;
44117fc18ed46496c81596f8207bba30a09c7317d1Jean Chalard    private int mTrailingSingleQuotesCount;
4501ab7c8b59a7f12862fbd95fb252e56719f1757fsatok    private int mCodePointSize;
46c83359f9746ca6f0269a1a7017b585c1a5cab9b8Jean Chalard
47923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    /**
480b4ae1f578e768eec4ada90aeb81d11acb10eb2eKen Wakasa     * Whether the user chose to capitalize the first char of the word.
49923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project     */
500b4ae1f578e768eec4ada90aeb81d11acb10eb2eKen Wakasa    private boolean mIsFirstCharCapitalized;
51923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
52979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    public WordComposer() {
5301ab7c8b59a7f12862fbd95fb252e56719f1757fsatok        mPrimaryKeyCodes = new int[N];
54be79227dc99421ff7be62224c51c553b3fa73777Jean Chalard        mTypedWord = new StringBuilder(N);
55be79227dc99421ff7be62224c51c553b3fa73777Jean Chalard        mAutoCorrection = null;
56117fc18ed46496c81596f8207bba30a09c7317d1Jean Chalard        mTrailingSingleQuotesCount = 0;
574b5b46bb66bf74ef5edd65c55e186b02f3c56e5dJean Chalard        mIsResumed = false;
5801ab7c8b59a7f12862fbd95fb252e56719f1757fsatok        refreshSize();
59923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
60923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
61f733074aaecdfd6e89cfee2daff8a9c1233b60f1satok    public WordComposer(WordComposer source) {
629fbfd5877305ed19a20663630b498b6b3fdae942satok        init(source);
639fbfd5877305ed19a20663630b498b6b3fdae942satok    }
649fbfd5877305ed19a20663630b498b6b3fdae942satok
659fbfd5877305ed19a20663630b498b6b3fdae942satok    public void init(WordComposer source) {
6601ab7c8b59a7f12862fbd95fb252e56719f1757fsatok        mPrimaryKeyCodes = Arrays.copyOf(source.mPrimaryKeyCodes, source.mPrimaryKeyCodes.length);
67be79227dc99421ff7be62224c51c553b3fa73777Jean Chalard        mTypedWord = new StringBuilder(source.mTypedWord);
6871538b08e4e08d556f700ad344562ca2c7b74d82Satoshi Kataoka        mInputPointers.copy(source.mInputPointers);
69ea843f2a2404f4bc04fda494e475520162cfca27Tadashi G. Takaoka        mCapsCount = source.mCapsCount;
70ea843f2a2404f4bc04fda494e475520162cfca27Tadashi G. Takaoka        mIsFirstCharCapitalized = source.mIsFirstCharCapitalized;
71ea843f2a2404f4bc04fda494e475520162cfca27Tadashi G. Takaoka        mAutoCapitalized = source.mAutoCapitalized;
72117fc18ed46496c81596f8207bba30a09c7317d1Jean Chalard        mTrailingSingleQuotesCount = source.mTrailingSingleQuotesCount;
734b5b46bb66bf74ef5edd65c55e186b02f3c56e5dJean Chalard        mIsResumed = source.mIsResumed;
7401ab7c8b59a7f12862fbd95fb252e56719f1757fsatok        refreshSize();
75979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    }
76979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
77923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    /**
78923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project     * Clear out the keys registered so far.
79923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project     */
80923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    public void reset() {
81be79227dc99421ff7be62224c51c553b3fa73777Jean Chalard        mTypedWord.setLength(0);
82be79227dc99421ff7be62224c51c553b3fa73777Jean Chalard        mAutoCorrection = null;
834a7ff90d513f8b6cbf39688c08be0828a57e311bAmith Yamasani        mCapsCount = 0;
84ea843f2a2404f4bc04fda494e475520162cfca27Tadashi G. Takaoka        mIsFirstCharCapitalized = false;
85117fc18ed46496c81596f8207bba30a09c7317d1Jean Chalard        mTrailingSingleQuotesCount = 0;
864b5b46bb66bf74ef5edd65c55e186b02f3c56e5dJean Chalard        mIsResumed = false;
8701ab7c8b59a7f12862fbd95fb252e56719f1757fsatok        refreshSize();
8801ab7c8b59a7f12862fbd95fb252e56719f1757fsatok    }
8901ab7c8b59a7f12862fbd95fb252e56719f1757fsatok
90e55c23e4b0b8d9d66349a3b275d0fa1540d7450aKen Wakasa    private final void refreshSize() {
9101ab7c8b59a7f12862fbd95fb252e56719f1757fsatok        mCodePointSize = mTypedWord.codePointCount(0, mTypedWord.length());
92923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
93923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
94923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    /**
95923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project     * Number of keystrokes in the composing word.
96923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project     * @return the number of keystrokes
97923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project     */
98ea843f2a2404f4bc04fda494e475520162cfca27Tadashi G. Takaoka    public final int size() {
9901ab7c8b59a7f12862fbd95fb252e56719f1757fsatok        return mCodePointSize;
100923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
101923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
102196d82cdd740580ed79d801483dbc282be85d076Jean Chalard    public final boolean isComposingWord() {
10301ab7c8b59a7f12862fbd95fb252e56719f1757fsatok        return size() > 0;
104196d82cdd740580ed79d801483dbc282be85d076Jean Chalard    }
105196d82cdd740580ed79d801483dbc282be85d076Jean Chalard
1069611b281e18ac71d825ff5bc771a111423772cb3satok    // TODO: make sure that the index should not exceed MAX_WORD_LENGTH
10701ab7c8b59a7f12862fbd95fb252e56719f1757fsatok    public int getCodeAt(int index) {
1089611b281e18ac71d825ff5bc771a111423772cb3satok        if (index >= BinaryDictionary.MAX_WORD_LENGTH) {
1099611b281e18ac71d825ff5bc771a111423772cb3satok            return -1;
1109611b281e18ac71d825ff5bc771a111423772cb3satok        }
11101ab7c8b59a7f12862fbd95fb252e56719f1757fsatok        return mPrimaryKeyCodes[index];
112923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
113923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
11471538b08e4e08d556f700ad344562ca2c7b74d82Satoshi Kataoka    public InputPointers getInputPointers() {
11571538b08e4e08d556f700ad344562ca2c7b74d82Satoshi Kataoka        return mInputPointers;
1168fbd55229243cb66c03d5ea1f79dfb39f596590dsatok    }
1178fbd55229243cb66c03d5ea1f79dfb39f596590dsatok
118ea843f2a2404f4bc04fda494e475520162cfca27Tadashi G. Takaoka    private static boolean isFirstCharCapitalized(int index, int codePoint, boolean previous) {
119ea843f2a2404f4bc04fda494e475520162cfca27Tadashi G. Takaoka        if (index == 0) return Character.isUpperCase(codePoint);
120436a645ea837d36f7e0f81948d343fa6e166f33aTadashi G. Takaoka        return previous && !Character.isUpperCase(codePoint);
121ea843f2a2404f4bc04fda494e475520162cfca27Tadashi G. Takaoka    }
122ea843f2a2404f4bc04fda494e475520162cfca27Tadashi G. Takaoka
123923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    /**
124c61cd79229b1871d0f603a23389695d7f7751e66Tadashi G. Takaoka     * Add a new keystroke, with the pressed key's code point with the touch point coordinates.
125923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project     */
1265c641a9f59735f0eaa772bde027993275b1bdfd7Tadashi G. Takaoka    public void add(int primaryCode, int keyX, int keyY) {
12701ab7c8b59a7f12862fbd95fb252e56719f1757fsatok        final int newIndex = size();
1289159b9953d857de83ae2f90a121fcd259f5ee01dJean Chalard        mTypedWord.appendCodePoint(primaryCode);
12901ab7c8b59a7f12862fbd95fb252e56719f1757fsatok        refreshSize();
130ea843f2a2404f4bc04fda494e475520162cfca27Tadashi G. Takaoka        if (newIndex < BinaryDictionary.MAX_WORD_LENGTH) {
13167094f5bdece00994f70c6f1fa9a6ff7b8f3c3c1satok            mPrimaryKeyCodes[newIndex] = primaryCode >= Keyboard.CODE_SPACE
13267094f5bdece00994f70c6f1fa9a6ff7b8f3c3c1satok                    ? Character.toLowerCase(primaryCode) : primaryCode;
13371538b08e4e08d556f700ad344562ca2c7b74d82Satoshi Kataoka            // TODO: Set correct pointer id and time
13471538b08e4e08d556f700ad344562ca2c7b74d82Satoshi Kataoka            mInputPointers.addPointer(newIndex, keyX, keyY, 0, 0);
1358fbd55229243cb66c03d5ea1f79dfb39f596590dsatok        }
136ea843f2a2404f4bc04fda494e475520162cfca27Tadashi G. Takaoka        mIsFirstCharCapitalized = isFirstCharCapitalized(
137ea843f2a2404f4bc04fda494e475520162cfca27Tadashi G. Takaoka                newIndex, primaryCode, mIsFirstCharCapitalized);
138ea843f2a2404f4bc04fda494e475520162cfca27Tadashi G. Takaoka        if (Character.isUpperCase(primaryCode)) mCapsCount++;
139117fc18ed46496c81596f8207bba30a09c7317d1Jean Chalard        if (Keyboard.CODE_SINGLE_QUOTE == primaryCode) {
140117fc18ed46496c81596f8207bba30a09c7317d1Jean Chalard            ++mTrailingSingleQuotesCount;
141117fc18ed46496c81596f8207bba30a09c7317d1Jean Chalard        } else {
142117fc18ed46496c81596f8207bba30a09c7317d1Jean Chalard            mTrailingSingleQuotesCount = 0;
143117fc18ed46496c81596f8207bba30a09c7317d1Jean Chalard        }
144be79227dc99421ff7be62224c51c553b3fa73777Jean Chalard        mAutoCorrection = null;
145923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
146923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
147923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    /**
1486b1f500da451de56932a8b2a99c63857994ece85Jean Chalard     * Internal method to retrieve reasonable proximity info for a character.
1496b1f500da451de56932a8b2a99c63857994ece85Jean Chalard     */
150a492790982c6d7df62f66344db30b31995800e1bJean Chalard    private void addKeyInfo(final int codePoint, final Keyboard keyboard) {
1516b1f500da451de56932a8b2a99c63857994ece85Jean Chalard        for (final Key key : keyboard.mKeys) {
1526b1f500da451de56932a8b2a99c63857994ece85Jean Chalard            if (key.mCode == codePoint) {
1536b1f500da451de56932a8b2a99c63857994ece85Jean Chalard                final int x = key.mX + key.mWidth / 2;
1546b1f500da451de56932a8b2a99c63857994ece85Jean Chalard                final int y = key.mY + key.mHeight / 2;
1556ba8de2a608dfe4865b0b59a753f2d2abbedeeffsatok                add(codePoint, x, y);
1566b1f500da451de56932a8b2a99c63857994ece85Jean Chalard                return;
1576b1f500da451de56932a8b2a99c63857994ece85Jean Chalard            }
1586b1f500da451de56932a8b2a99c63857994ece85Jean Chalard        }
1596ba8de2a608dfe4865b0b59a753f2d2abbedeeffsatok        add(codePoint, WordComposer.NOT_A_COORDINATE, WordComposer.NOT_A_COORDINATE);
1606b1f500da451de56932a8b2a99c63857994ece85Jean Chalard    }
1616b1f500da451de56932a8b2a99c63857994ece85Jean Chalard
1626b1f500da451de56932a8b2a99c63857994ece85Jean Chalard    /**
1636b1f500da451de56932a8b2a99c63857994ece85Jean Chalard     * Set the currently composing word to the one passed as an argument.
1646b1f500da451de56932a8b2a99c63857994ece85Jean Chalard     * This will register NOT_A_COORDINATE for X and Ys, and use the passed keyboard for proximity.
1656b1f500da451de56932a8b2a99c63857994ece85Jean Chalard     */
166a492790982c6d7df62f66344db30b31995800e1bJean Chalard    public void setComposingWord(final CharSequence word, final Keyboard keyboard) {
1676b1f500da451de56932a8b2a99c63857994ece85Jean Chalard        reset();
1686b1f500da451de56932a8b2a99c63857994ece85Jean Chalard        final int length = word.length();
1699159b9953d857de83ae2f90a121fcd259f5ee01dJean Chalard        for (int i = 0; i < length; i = Character.offsetByCodePoints(word, i, 1)) {
1709159b9953d857de83ae2f90a121fcd259f5ee01dJean Chalard            int codePoint = Character.codePointAt(word, i);
171a492790982c6d7df62f66344db30b31995800e1bJean Chalard            addKeyInfo(codePoint, keyboard);
1726b1f500da451de56932a8b2a99c63857994ece85Jean Chalard        }
1734b5b46bb66bf74ef5edd65c55e186b02f3c56e5dJean Chalard        mIsResumed = true;
1746b1f500da451de56932a8b2a99c63857994ece85Jean Chalard    }
1756b1f500da451de56932a8b2a99c63857994ece85Jean Chalard
1766b1f500da451de56932a8b2a99c63857994ece85Jean Chalard    /**
177923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project     * Delete the last keystroke as a result of hitting backspace.
178923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project     */
179923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    public void deleteLast() {
18001ab7c8b59a7f12862fbd95fb252e56719f1757fsatok        final int size = size();
181ea843f2a2404f4bc04fda494e475520162cfca27Tadashi G. Takaoka        if (size > 0) {
1829159b9953d857de83ae2f90a121fcd259f5ee01dJean Chalard            // Note: mTypedWord.length() and mCodes.length differ when there are surrogate pairs
1839159b9953d857de83ae2f90a121fcd259f5ee01dJean Chalard            final int stringBuilderLength = mTypedWord.length();
1849159b9953d857de83ae2f90a121fcd259f5ee01dJean Chalard            if (stringBuilderLength < size) {
1859159b9953d857de83ae2f90a121fcd259f5ee01dJean Chalard                throw new RuntimeException(
1869159b9953d857de83ae2f90a121fcd259f5ee01dJean Chalard                        "In WordComposer: mCodes and mTypedWords have non-matching lengths");
1879159b9953d857de83ae2f90a121fcd259f5ee01dJean Chalard            }
1889159b9953d857de83ae2f90a121fcd259f5ee01dJean Chalard            final int lastChar = mTypedWord.codePointBefore(stringBuilderLength);
1899159b9953d857de83ae2f90a121fcd259f5ee01dJean Chalard            if (Character.isSupplementaryCodePoint(lastChar)) {
1909159b9953d857de83ae2f90a121fcd259f5ee01dJean Chalard                mTypedWord.delete(stringBuilderLength - 2, stringBuilderLength);
1919159b9953d857de83ae2f90a121fcd259f5ee01dJean Chalard            } else {
1929159b9953d857de83ae2f90a121fcd259f5ee01dJean Chalard                mTypedWord.deleteCharAt(stringBuilderLength - 1);
1939159b9953d857de83ae2f90a121fcd259f5ee01dJean Chalard            }
194ea843f2a2404f4bc04fda494e475520162cfca27Tadashi G. Takaoka            if (Character.isUpperCase(lastChar)) mCapsCount--;
19501ab7c8b59a7f12862fbd95fb252e56719f1757fsatok            refreshSize();
196d1a8e3088bb6267a31e3351d304796d1507e3af6Tadashi G. Takaoka        }
1979159b9953d857de83ae2f90a121fcd259f5ee01dJean Chalard        // We may have deleted the last one.
19801ab7c8b59a7f12862fbd95fb252e56719f1757fsatok        if (0 == size()) {
199ea843f2a2404f4bc04fda494e475520162cfca27Tadashi G. Takaoka            mIsFirstCharCapitalized = false;
200117fc18ed46496c81596f8207bba30a09c7317d1Jean Chalard        }
201117fc18ed46496c81596f8207bba30a09c7317d1Jean Chalard        if (mTrailingSingleQuotesCount > 0) {
202117fc18ed46496c81596f8207bba30a09c7317d1Jean Chalard            --mTrailingSingleQuotesCount;
203c83359f9746ca6f0269a1a7017b585c1a5cab9b8Jean Chalard        } else {
204825e2bbd910cce3055a4ca808d3744bc0b2ceddaJean Chalard            int i = mTypedWord.length();
205825e2bbd910cce3055a4ca808d3744bc0b2ceddaJean Chalard            while (i > 0) {
206825e2bbd910cce3055a4ca808d3744bc0b2ceddaJean Chalard                i = mTypedWord.offsetByCodePoints(i, -1);
207be79227dc99421ff7be62224c51c553b3fa73777Jean Chalard                if (Keyboard.CODE_SINGLE_QUOTE != mTypedWord.codePointAt(i)) break;
208117fc18ed46496c81596f8207bba30a09c7317d1Jean Chalard                ++mTrailingSingleQuotesCount;
209117fc18ed46496c81596f8207bba30a09c7317d1Jean Chalard            }
2108fbd55229243cb66c03d5ea1f79dfb39f596590dsatok        }
211be79227dc99421ff7be62224c51c553b3fa73777Jean Chalard        mAutoCorrection = null;
212923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
213923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
214923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    /**
215923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project     * Returns the word as it was typed, without any correction applied.
216117fc93f373cb86d4120c1261f9d0562c6529fecJean Chalard     * @return the word that was typed so far. Never returns null.
217923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project     */
2185c08151c227d98031abe27c3f0a8f43a7126ae9dJean Chalard    public String getTypedWord() {
219be79227dc99421ff7be62224c51c553b3fa73777Jean Chalard        return mTypedWord.toString();
220923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
221923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
222923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    /**
223923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project     * Whether or not the user typed a capital letter as the first letter in the word
224923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project     * @return capitalization preference
225923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project     */
2260b4ae1f578e768eec4ada90aeb81d11acb10eb2eKen Wakasa    public boolean isFirstCharCapitalized() {
2270b4ae1f578e768eec4ada90aeb81d11acb10eb2eKen Wakasa        return mIsFirstCharCapitalized;
228923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
2290b4ae1f578e768eec4ada90aeb81d11acb10eb2eKen Wakasa
230117fc18ed46496c81596f8207bba30a09c7317d1Jean Chalard    public int trailingSingleQuotesCount() {
231117fc18ed46496c81596f8207bba30a09c7317d1Jean Chalard        return mTrailingSingleQuotesCount;
232c83359f9746ca6f0269a1a7017b585c1a5cab9b8Jean Chalard    }
233c83359f9746ca6f0269a1a7017b585c1a5cab9b8Jean Chalard
2340b4ae1f578e768eec4ada90aeb81d11acb10eb2eKen Wakasa    /**
2350b4ae1f578e768eec4ada90aeb81d11acb10eb2eKen Wakasa     * Whether or not all of the user typed chars are upper case
2360b4ae1f578e768eec4ada90aeb81d11acb10eb2eKen Wakasa     * @return true if all user typed chars are upper case, false otherwise
2370b4ae1f578e768eec4ada90aeb81d11acb10eb2eKen Wakasa     */
2380b4ae1f578e768eec4ada90aeb81d11acb10eb2eKen Wakasa    public boolean isAllUpperCase() {
2390b4ae1f578e768eec4ada90aeb81d11acb10eb2eKen Wakasa        return (mCapsCount > 0) && (mCapsCount == size());
2400b4ae1f578e768eec4ada90aeb81d11acb10eb2eKen Wakasa    }
2410b4ae1f578e768eec4ada90aeb81d11acb10eb2eKen Wakasa
242923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    /**
2434a7ff90d513f8b6cbf39688c08be0828a57e311bAmith Yamasani     * Returns true if more than one character is upper case, otherwise returns false.
2444a7ff90d513f8b6cbf39688c08be0828a57e311bAmith Yamasani     */
2454a7ff90d513f8b6cbf39688c08be0828a57e311bAmith Yamasani    public boolean isMostlyCaps() {
2464a7ff90d513f8b6cbf39688c08be0828a57e311bAmith Yamasani        return mCapsCount > 1;
2474a7ff90d513f8b6cbf39688c08be0828a57e311bAmith Yamasani    }
2481c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani
2490fd625bcfdfac1c10e7bd7f9088bf425fec08989Jean Chalard    /**
2501c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani     * Saves the reason why the word is capitalized - whether it was automatic or
2511c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani     * due to the user hitting shift in the middle of a sentence.
2521c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani     * @param auto whether it was an automatic capitalization due to start of sentence
2531c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani     */
2541c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani    public void setAutoCapitalized(boolean auto) {
2551c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani        mAutoCapitalized = auto;
2561c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani    }
2571c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani
2581c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani    /**
2591c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani     * Returns whether the word was automatically capitalized.
2601c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani     * @return whether the word was automatically capitalized
2611c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani     */
2621c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani    public boolean isAutoCapitalized() {
2631c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani        return mAutoCapitalized;
2641c551251106e506c70fad7ba0cb8b1e2a7dff3a9Amith Yamasani    }
265117fc93f373cb86d4120c1261f9d0562c6529fecJean Chalard
266117fc93f373cb86d4120c1261f9d0562c6529fecJean Chalard    /**
267117fc93f373cb86d4120c1261f9d0562c6529fecJean Chalard     * Sets the auto-correction for this word.
268117fc93f373cb86d4120c1261f9d0562c6529fecJean Chalard     */
269117fc93f373cb86d4120c1261f9d0562c6529fecJean Chalard    public void setAutoCorrection(final CharSequence correction) {
270be79227dc99421ff7be62224c51c553b3fa73777Jean Chalard        mAutoCorrection = correction;
271117fc93f373cb86d4120c1261f9d0562c6529fecJean Chalard    }
272117fc93f373cb86d4120c1261f9d0562c6529fecJean Chalard
273117fc93f373cb86d4120c1261f9d0562c6529fecJean Chalard    /**
274f7d6517d6b1a1dd88e2142e1a15703bb839be01bJean Chalard     * @return the auto-correction for this word, or null if none.
275117fc93f373cb86d4120c1261f9d0562c6529fecJean Chalard     */
276117fc93f373cb86d4120c1261f9d0562c6529fecJean Chalard    public CharSequence getAutoCorrectionOrNull() {
277be79227dc99421ff7be62224c51c553b3fa73777Jean Chalard        return mAutoCorrection;
278117fc93f373cb86d4120c1261f9d0562c6529fecJean Chalard    }
279c73c26790fa9dcd836a918774d6efa39a05c0152Jean Chalard
2804b5b46bb66bf74ef5edd65c55e186b02f3c56e5dJean Chalard    /**
2814b5b46bb66bf74ef5edd65c55e186b02f3c56e5dJean Chalard     * @return whether we started composing this word by resuming suggestion on an existing string
2824b5b46bb66bf74ef5edd65c55e186b02f3c56e5dJean Chalard     */
2834b5b46bb66bf74ef5edd65c55e186b02f3c56e5dJean Chalard    public boolean isResumed() {
2844b5b46bb66bf74ef5edd65c55e186b02f3c56e5dJean Chalard        return mIsResumed;
2854b5b46bb66bf74ef5edd65c55e186b02f3c56e5dJean Chalard    }
2864b5b46bb66bf74ef5edd65c55e186b02f3c56e5dJean Chalard
287267563d1bb4d8091293fbd8774f0f95ef59f03c4Jean Chalard    // `type' should be one of the LastComposedWord.COMMIT_TYPE_* constants above.
28866bb563535dbe3672f99f75bd71763a551444867Jean Chalard    public LastComposedWord commitWord(final int type, final String committedWord,
289c54d558e2e70bdfb2c1078cae7b88440d421dc67satok            final int separatorCode, final CharSequence prevWord) {
2909271b770e81350e232c351f76f9f7a2ec23dff5fJean Chalard        // Note: currently, we come here whenever we commit a word. If it's a MANUAL_PICK
2919271b770e81350e232c351f76f9f7a2ec23dff5fJean Chalard        // or a DECIDED_WORD we may cancel the commit later; otherwise, we should deactivate
2929271b770e81350e232c351f76f9f7a2ec23dff5fJean Chalard        // the last composed word to ensure this does not happen.
29301ab7c8b59a7f12862fbd95fb252e56719f1757fsatok        final int[] primaryKeyCodes = mPrimaryKeyCodes;
29401ab7c8b59a7f12862fbd95fb252e56719f1757fsatok        mPrimaryKeyCodes = new int[N];
29501ab7c8b59a7f12862fbd95fb252e56719f1757fsatok        final LastComposedWord lastComposedWord = new LastComposedWord(primaryKeyCodes,
29671538b08e4e08d556f700ad344562ca2c7b74d82Satoshi Kataoka                mInputPointers, mTypedWord.toString(), committedWord, separatorCode,
297c54d558e2e70bdfb2c1078cae7b88440d421dc67satok                prevWord);
29871538b08e4e08d556f700ad344562ca2c7b74d82Satoshi Kataoka        mInputPointers.reset();
2999271b770e81350e232c351f76f9f7a2ec23dff5fJean Chalard        if (type != LastComposedWord.COMMIT_TYPE_DECIDED_WORD
3009271b770e81350e232c351f76f9f7a2ec23dff5fJean Chalard                && type != LastComposedWord.COMMIT_TYPE_MANUAL_PICK) {
301449415c72f437f523a49a9ccfcde8a3c0f583a18Jean Chalard            lastComposedWord.deactivate();
302449415c72f437f523a49a9ccfcde8a3c0f583a18Jean Chalard        }
303be79227dc99421ff7be62224c51c553b3fa73777Jean Chalard        mTypedWord.setLength(0);
30401ab7c8b59a7f12862fbd95fb252e56719f1757fsatok        refreshSize();
305be79227dc99421ff7be62224c51c553b3fa73777Jean Chalard        mAutoCorrection = null;
3064b5b46bb66bf74ef5edd65c55e186b02f3c56e5dJean Chalard        mIsResumed = false;
3071f8fc62ccb5018716457dc309ab11ad3e1506ad1Jean Chalard        return lastComposedWord;
308c73c26790fa9dcd836a918774d6efa39a05c0152Jean Chalard    }
309c73c26790fa9dcd836a918774d6efa39a05c0152Jean Chalard
3102712f23acbb197af3b125da4cc47108e71b7446dJean Chalard    public void resumeSuggestionOnLastComposedWord(final LastComposedWord lastComposedWord) {
31101ab7c8b59a7f12862fbd95fb252e56719f1757fsatok        mPrimaryKeyCodes = lastComposedWord.mPrimaryKeyCodes;
31271538b08e4e08d556f700ad344562ca2c7b74d82Satoshi Kataoka        mInputPointers.set(lastComposedWord.mInputPointers);
313be79227dc99421ff7be62224c51c553b3fa73777Jean Chalard        mTypedWord.setLength(0);
314be79227dc99421ff7be62224c51c553b3fa73777Jean Chalard        mTypedWord.append(lastComposedWord.mTypedWord);
31501ab7c8b59a7f12862fbd95fb252e56719f1757fsatok        refreshSize();
316cf9d92629cae88273805eaf7984fcfdd8afd11f5Jean Chalard        mAutoCorrection = null; // This will be filled by the next call to updateSuggestion.
3174b5b46bb66bf74ef5edd65c55e186b02f3c56e5dJean Chalard        mIsResumed = true;
3189e8761c4402ddc11c942ed2e583bd7d58f70c5eaJean Chalard    }
319923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project}
320