Loading java/src/com/android/inputmethod/latin/LatinIME.java +39 −1 Original line number Diff line number Diff line Loading @@ -161,6 +161,8 @@ public final class LatinIME extends InputMethodService implements KeyboardAction mPositionalInfoForUserDictPendingAddition = null; private final WordComposer mWordComposer = new WordComposer(); private final RichInputConnection mConnection = new RichInputConnection(this); private RecapitalizeStatus mRecapitalizeStatus = new RecapitalizeStatus(-1, -1, "", Locale.getDefault(), ""); // Dummy object that will match no real recapitalize // Keep track of the last selection range to decide if we need to show word alternatives private static final int NOT_A_CURSOR_POSITION = -1; Loading Loading @@ -1387,8 +1389,13 @@ public final class LatinIME extends InputMethodService implements KeyboardAction LatinImeLogger.logOnDelete(x, y); break; case Constants.CODE_SHIFT: // Note: calling back to the keyboard on Shift key is handled in onPressKey() // and onReleaseKey(). handleRecapitalize(); break; case Constants.CODE_SWITCH_ALPHA_SYMBOL: // Shift and symbol key is handled in onPressKey() and onReleaseKey(). // Note: calling back to the keyboard on symbol key is handled in onPressKey() // and onReleaseKey(). break; case Constants.CODE_SETTINGS: onSettingsKeyPressed(); Loading Loading @@ -1943,6 +1950,37 @@ public final class LatinIME extends InputMethodService implements KeyboardAction } } private void handleRecapitalize() { if (mLastSelectionStart == mLastSelectionEnd) return; // No selection // If we have a recapitalize in progress, use it; otherwise, create a new one. if (null == mRecapitalizeStatus || !mRecapitalizeStatus.isSetAt(mLastSelectionStart, mLastSelectionEnd)) { mRecapitalizeStatus = new RecapitalizeStatus(mLastSelectionStart, mLastSelectionEnd, mConnection.getSelectedText(0 /* flags, 0 for no styles */).toString(), mSettings.getCurrentLocale(), mSettings.getWordSeparators()); // We trim leading and trailing whitespace. mRecapitalizeStatus.trim(); // Trimming the object may have changed the length of the string, and we need to // reposition the selection handles accordingly. As this result in an IPC call, // only do it if it's actually necessary, in other words if the recapitalize status // is not set at the same place as before. if (!mRecapitalizeStatus.isSetAt(mLastSelectionStart, mLastSelectionEnd)) { mLastSelectionStart = mRecapitalizeStatus.getNewCursorStart(); mLastSelectionEnd = mRecapitalizeStatus.getNewCursorEnd(); mConnection.setSelection(mLastSelectionStart, mLastSelectionEnd); } } mRecapitalizeStatus.rotate(); final int numCharsDeleted = mLastSelectionEnd - mLastSelectionStart; mConnection.setSelection(mLastSelectionEnd, mLastSelectionEnd); mConnection.deleteSurroundingText(numCharsDeleted, 0); mConnection.commitText(mRecapitalizeStatus.getRecapitalizedString(), 0); mLastSelectionStart = mRecapitalizeStatus.getNewCursorStart(); mLastSelectionEnd = mRecapitalizeStatus.getNewCursorEnd(); mConnection.setSelection(mLastSelectionStart, mLastSelectionEnd); } // Returns true if we did an autocorrection, false otherwise. private boolean handleSeparator(final int primaryCode, final int x, final int y, final int spaceState) { Loading java/src/com/android/inputmethod/latin/RecapitalizeStatus.java 0 → 100644 +169 −0 Original line number Diff line number Diff line /* * Copyright (C) 2013 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of * the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations under * the License. */ package com.android.inputmethod.latin; import com.android.inputmethod.latin.StringUtils; import java.util.Locale; /** * The status of the current recapitalize process. */ public class RecapitalizeStatus { public static final int CAPS_MODE_ORIGINAL_MIXED_CASE = 0; public static final int CAPS_MODE_ALL_LOWER = 1; public static final int CAPS_MODE_FIRST_WORD_UPPER = 2; public static final int CAPS_MODE_ALL_UPPER = 3; // When adding a new mode, don't forget to update the CAPS_MODE_LAST constant. public static final int CAPS_MODE_LAST = CAPS_MODE_ALL_UPPER; private static final int[] ROTATION_STYLE = { CAPS_MODE_ORIGINAL_MIXED_CASE, CAPS_MODE_ALL_LOWER, CAPS_MODE_FIRST_WORD_UPPER, CAPS_MODE_ALL_UPPER }; private static final int getStringMode(final String string, final String separators) { if (StringUtils.isIdenticalAfterUpcase(string)) { return CAPS_MODE_ALL_UPPER; } else if (StringUtils.isIdenticalAfterDowncase(string)) { return CAPS_MODE_ALL_LOWER; } else if (StringUtils.isIdenticalAfterCapitalizeEachWord(string, separators)) { return CAPS_MODE_FIRST_WORD_UPPER; } else { return CAPS_MODE_ORIGINAL_MIXED_CASE; } } /** * We store the location of the cursor and the string that was there before the undoable * action was done, and the location of the cursor and the string that was there after. */ private int mCursorStartBefore; private int mCursorEndBefore; private String mStringBefore; private int mCursorStartAfter; private int mCursorEndAfter; private int mRotationStyleCurrentIndex; private final boolean mSkipOriginalMixedCaseMode; private final Locale mLocale; private final String mSeparators; private String mStringAfter; public RecapitalizeStatus(final int cursorStart, final int cursorEnd, final String string, final Locale locale, final String separators) { mCursorStartBefore = cursorStart; mCursorEndBefore = cursorEnd; mStringBefore = string; mCursorStartAfter = cursorStart; mCursorEndAfter = cursorEnd; mStringAfter = string; final int initialMode = getStringMode(mStringBefore, separators); mLocale = locale; mSeparators = separators; if (CAPS_MODE_ORIGINAL_MIXED_CASE == initialMode) { mRotationStyleCurrentIndex = 0; mSkipOriginalMixedCaseMode = false; } else { // Find the current mode in the array. int currentMode; for (currentMode = ROTATION_STYLE.length - 1; currentMode > 0; --currentMode) { if (ROTATION_STYLE[currentMode] == initialMode) { break; } } mRotationStyleCurrentIndex = currentMode; mSkipOriginalMixedCaseMode = true; } } public boolean isSetAt(final int cursorStart, final int cursorEnd) { return cursorStart == mCursorStartAfter && cursorEnd == mCursorEndAfter; } /** * Rotate through the different possible capitalization modes. */ public void rotate() { final String oldResult = mStringAfter; int count = 0; // Protection against infinite loop. do { mRotationStyleCurrentIndex = (mRotationStyleCurrentIndex + 1) % ROTATION_STYLE.length; if (CAPS_MODE_ORIGINAL_MIXED_CASE == ROTATION_STYLE[mRotationStyleCurrentIndex] && mSkipOriginalMixedCaseMode) { mRotationStyleCurrentIndex = (mRotationStyleCurrentIndex + 1) % ROTATION_STYLE.length; } ++count; switch (ROTATION_STYLE[mRotationStyleCurrentIndex]) { case CAPS_MODE_ORIGINAL_MIXED_CASE: mStringAfter = mStringBefore; break; case CAPS_MODE_ALL_LOWER: mStringAfter = mStringBefore.toLowerCase(mLocale); break; case CAPS_MODE_FIRST_WORD_UPPER: mStringAfter = StringUtils.capitalizeEachWord(mStringBefore, mSeparators, mLocale); break; case CAPS_MODE_ALL_UPPER: mStringAfter = mStringBefore.toUpperCase(mLocale); break; default: mStringAfter = mStringBefore; } } while (mStringAfter.equals(oldResult) && count < 5); mCursorEndAfter = mCursorStartAfter + mStringAfter.length(); } /** * Remove leading/trailing whitespace from the considered string. */ public void trim() { final int len = mStringBefore.length(); int nonWhitespaceStart = 0; for (; nonWhitespaceStart < len; nonWhitespaceStart = mStringBefore.offsetByCodePoints(nonWhitespaceStart, 1)) { final int codePoint = mStringBefore.codePointAt(nonWhitespaceStart); if (!Character.isWhitespace(codePoint)) break; } int nonWhitespaceEnd = len; for (; nonWhitespaceEnd > 0; nonWhitespaceEnd = mStringBefore.offsetByCodePoints(nonWhitespaceEnd, -1)) { final int codePoint = mStringBefore.codePointBefore(nonWhitespaceEnd); if (!Character.isWhitespace(codePoint)) break; } if (0 != nonWhitespaceStart || len != nonWhitespaceEnd) { mCursorEndBefore = mCursorEndAfter = mCursorStartBefore + nonWhitespaceEnd; mCursorStartBefore = mCursorStartAfter = mCursorStartBefore + nonWhitespaceStart; mStringAfter = mStringBefore = mStringBefore.substring(nonWhitespaceStart, nonWhitespaceEnd); } } public String getRecapitalizedString() { return mStringAfter; } public int getNewCursorStart() { return mCursorStartAfter; } public int getNewCursorEnd() { return mCursorEndAfter; } } java/src/com/android/inputmethod/latin/RichInputConnection.java +5 −0 Original line number Diff line number Diff line Loading @@ -183,6 +183,11 @@ public final class RichInputConnection { } } public CharSequence getSelectedText(final int flags) { if (null == mIC) return null; return mIC.getSelectedText(flags); } /** * Gets the caps modes we should be in after this specific string. * Loading java/src/com/android/inputmethod/latin/Settings.java +4 −0 Original line number Diff line number Diff line Loading @@ -138,6 +138,10 @@ public final class Settings implements SharedPreferences.OnSharedPreferenceChang return mSettingsValues.mWordSeparators; } public Locale getCurrentLocale() { return mCurrentLocale; } // Accessed from the settings interface, hence public public static boolean readKeypressSoundEnabled(final SharedPreferences prefs, final Resources res) { Loading tests/src/com/android/inputmethod/latin/RecapitalizeStatusTests.java 0 → 100644 +203 −0 Original line number Diff line number Diff line /* * Copyright (C) 2013 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.inputmethod.latin; import android.test.AndroidTestCase; import android.test.suitebuilder.annotation.SmallTest; import java.util.Locale; @SmallTest public class RecapitalizeStatusTests extends AndroidTestCase { public void testTrim() { RecapitalizeStatus status = new RecapitalizeStatus(30, 40, "abcdefghij", Locale.ENGLISH, " "); status.trim(); assertEquals("abcdefghij", status.getRecapitalizedString()); assertEquals(30, status.getNewCursorStart()); assertEquals(40, status.getNewCursorEnd()); status = new RecapitalizeStatus(30, 44, " abcdefghij", Locale.ENGLISH, " "); status.trim(); assertEquals("abcdefghij", status.getRecapitalizedString()); assertEquals(34, status.getNewCursorStart()); assertEquals(44, status.getNewCursorEnd()); status = new RecapitalizeStatus(30, 40, "abcdefgh ", Locale.ENGLISH, " "); status.trim(); assertEquals("abcdefgh", status.getRecapitalizedString()); assertEquals(30, status.getNewCursorStart()); assertEquals(38, status.getNewCursorEnd()); status = new RecapitalizeStatus(30, 45, " abcdefghij ", Locale.ENGLISH, " "); status.trim(); assertEquals("abcdefghij", status.getRecapitalizedString()); assertEquals(33, status.getNewCursorStart()); assertEquals(43, status.getNewCursorEnd()); } public void testRotate() { RecapitalizeStatus status = new RecapitalizeStatus(29, 40, "abcd efghij", Locale.ENGLISH, " "); status.rotate(); assertEquals("Abcd Efghij", status.getRecapitalizedString()); assertEquals(29, status.getNewCursorStart()); assertEquals(40, status.getNewCursorEnd()); status.rotate(); assertEquals("ABCD EFGHIJ", status.getRecapitalizedString()); status.rotate(); assertEquals("abcd efghij", status.getRecapitalizedString()); status.rotate(); assertEquals("Abcd Efghij", status.getRecapitalizedString()); status = new RecapitalizeStatus(29, 40, "Abcd Efghij", Locale.ENGLISH, " "); status.rotate(); assertEquals("ABCD EFGHIJ", status.getRecapitalizedString()); assertEquals(29, status.getNewCursorStart()); assertEquals(40, status.getNewCursorEnd()); status.rotate(); assertEquals("abcd efghij", status.getRecapitalizedString()); status.rotate(); assertEquals("Abcd Efghij", status.getRecapitalizedString()); status.rotate(); assertEquals("ABCD EFGHIJ", status.getRecapitalizedString()); status = new RecapitalizeStatus(29, 40, "ABCD EFGHIJ", Locale.ENGLISH, " "); status.rotate(); assertEquals("abcd efghij", status.getRecapitalizedString()); assertEquals(29, status.getNewCursorStart()); assertEquals(40, status.getNewCursorEnd()); status.rotate(); assertEquals("Abcd Efghij", status.getRecapitalizedString()); status.rotate(); assertEquals("ABCD EFGHIJ", status.getRecapitalizedString()); status.rotate(); assertEquals("abcd efghij", status.getRecapitalizedString()); status = new RecapitalizeStatus(29, 39, "AbCDefghij", Locale.ENGLISH, " "); status.rotate(); assertEquals("abcdefghij", status.getRecapitalizedString()); assertEquals(29, status.getNewCursorStart()); assertEquals(39, status.getNewCursorEnd()); status.rotate(); assertEquals("Abcdefghij", status.getRecapitalizedString()); status.rotate(); assertEquals("ABCDEFGHIJ", status.getRecapitalizedString()); status.rotate(); assertEquals("AbCDefghij", status.getRecapitalizedString()); status.rotate(); assertEquals("abcdefghij", status.getRecapitalizedString()); status = new RecapitalizeStatus(29, 40, "Abcd efghij", Locale.ENGLISH, " "); status.rotate(); assertEquals("abcd efghij", status.getRecapitalizedString()); assertEquals(29, status.getNewCursorStart()); assertEquals(40, status.getNewCursorEnd()); status.rotate(); assertEquals("Abcd Efghij", status.getRecapitalizedString()); status.rotate(); assertEquals("ABCD EFGHIJ", status.getRecapitalizedString()); status.rotate(); assertEquals("Abcd efghij", status.getRecapitalizedString()); status.rotate(); assertEquals("abcd efghij", status.getRecapitalizedString()); status = new RecapitalizeStatus(30, 34, "grüß", Locale.GERMAN, " "); status.rotate(); assertEquals("Grüß", status.getRecapitalizedString()); assertEquals(30, status.getNewCursorStart()); assertEquals(34, status.getNewCursorEnd()); status.rotate(); assertEquals("GRÜSS", status.getRecapitalizedString()); assertEquals(30, status.getNewCursorStart()); assertEquals(35, status.getNewCursorEnd()); status.rotate(); assertEquals("grüß", status.getRecapitalizedString()); assertEquals(30, status.getNewCursorStart()); assertEquals(34, status.getNewCursorEnd()); status.rotate(); assertEquals("Grüß", status.getRecapitalizedString()); assertEquals(30, status.getNewCursorStart()); assertEquals(34, status.getNewCursorEnd()); status = new RecapitalizeStatus(30, 33, "œuf", Locale.FRENCH, " "); status.rotate(); assertEquals("Œuf", status.getRecapitalizedString()); assertEquals(30, status.getNewCursorStart()); assertEquals(33, status.getNewCursorEnd()); status.rotate(); assertEquals("ŒUF", status.getRecapitalizedString()); assertEquals(30, status.getNewCursorStart()); assertEquals(33, status.getNewCursorEnd()); status.rotate(); assertEquals("œuf", status.getRecapitalizedString()); assertEquals(30, status.getNewCursorStart()); assertEquals(33, status.getNewCursorEnd()); status.rotate(); assertEquals("Œuf", status.getRecapitalizedString()); assertEquals(30, status.getNewCursorStart()); assertEquals(33, status.getNewCursorEnd()); status = new RecapitalizeStatus(30, 33, "œUf", Locale.FRENCH, " "); status.rotate(); assertEquals("œuf", status.getRecapitalizedString()); assertEquals(30, status.getNewCursorStart()); assertEquals(33, status.getNewCursorEnd()); status.rotate(); assertEquals("Œuf", status.getRecapitalizedString()); assertEquals(30, status.getNewCursorStart()); assertEquals(33, status.getNewCursorEnd()); status.rotate(); assertEquals("ŒUF", status.getRecapitalizedString()); assertEquals(30, status.getNewCursorStart()); assertEquals(33, status.getNewCursorEnd()); status.rotate(); assertEquals("œUf", status.getRecapitalizedString()); assertEquals(30, status.getNewCursorStart()); assertEquals(33, status.getNewCursorEnd()); status.rotate(); assertEquals("œuf", status.getRecapitalizedString()); assertEquals(30, status.getNewCursorStart()); assertEquals(33, status.getNewCursorEnd()); status = new RecapitalizeStatus(30, 35, "école", Locale.FRENCH, " "); status.rotate(); assertEquals("École", status.getRecapitalizedString()); assertEquals(30, status.getNewCursorStart()); assertEquals(35, status.getNewCursorEnd()); status.rotate(); assertEquals("ÉCOLE", status.getRecapitalizedString()); assertEquals(30, status.getNewCursorStart()); assertEquals(35, status.getNewCursorEnd()); status.rotate(); assertEquals("école", status.getRecapitalizedString()); assertEquals(30, status.getNewCursorStart()); assertEquals(35, status.getNewCursorEnd()); status.rotate(); assertEquals("École", status.getRecapitalizedString()); assertEquals(30, status.getNewCursorStart()); assertEquals(35, status.getNewCursorEnd()); } } Loading
java/src/com/android/inputmethod/latin/LatinIME.java +39 −1 Original line number Diff line number Diff line Loading @@ -161,6 +161,8 @@ public final class LatinIME extends InputMethodService implements KeyboardAction mPositionalInfoForUserDictPendingAddition = null; private final WordComposer mWordComposer = new WordComposer(); private final RichInputConnection mConnection = new RichInputConnection(this); private RecapitalizeStatus mRecapitalizeStatus = new RecapitalizeStatus(-1, -1, "", Locale.getDefault(), ""); // Dummy object that will match no real recapitalize // Keep track of the last selection range to decide if we need to show word alternatives private static final int NOT_A_CURSOR_POSITION = -1; Loading Loading @@ -1387,8 +1389,13 @@ public final class LatinIME extends InputMethodService implements KeyboardAction LatinImeLogger.logOnDelete(x, y); break; case Constants.CODE_SHIFT: // Note: calling back to the keyboard on Shift key is handled in onPressKey() // and onReleaseKey(). handleRecapitalize(); break; case Constants.CODE_SWITCH_ALPHA_SYMBOL: // Shift and symbol key is handled in onPressKey() and onReleaseKey(). // Note: calling back to the keyboard on symbol key is handled in onPressKey() // and onReleaseKey(). break; case Constants.CODE_SETTINGS: onSettingsKeyPressed(); Loading Loading @@ -1943,6 +1950,37 @@ public final class LatinIME extends InputMethodService implements KeyboardAction } } private void handleRecapitalize() { if (mLastSelectionStart == mLastSelectionEnd) return; // No selection // If we have a recapitalize in progress, use it; otherwise, create a new one. if (null == mRecapitalizeStatus || !mRecapitalizeStatus.isSetAt(mLastSelectionStart, mLastSelectionEnd)) { mRecapitalizeStatus = new RecapitalizeStatus(mLastSelectionStart, mLastSelectionEnd, mConnection.getSelectedText(0 /* flags, 0 for no styles */).toString(), mSettings.getCurrentLocale(), mSettings.getWordSeparators()); // We trim leading and trailing whitespace. mRecapitalizeStatus.trim(); // Trimming the object may have changed the length of the string, and we need to // reposition the selection handles accordingly. As this result in an IPC call, // only do it if it's actually necessary, in other words if the recapitalize status // is not set at the same place as before. if (!mRecapitalizeStatus.isSetAt(mLastSelectionStart, mLastSelectionEnd)) { mLastSelectionStart = mRecapitalizeStatus.getNewCursorStart(); mLastSelectionEnd = mRecapitalizeStatus.getNewCursorEnd(); mConnection.setSelection(mLastSelectionStart, mLastSelectionEnd); } } mRecapitalizeStatus.rotate(); final int numCharsDeleted = mLastSelectionEnd - mLastSelectionStart; mConnection.setSelection(mLastSelectionEnd, mLastSelectionEnd); mConnection.deleteSurroundingText(numCharsDeleted, 0); mConnection.commitText(mRecapitalizeStatus.getRecapitalizedString(), 0); mLastSelectionStart = mRecapitalizeStatus.getNewCursorStart(); mLastSelectionEnd = mRecapitalizeStatus.getNewCursorEnd(); mConnection.setSelection(mLastSelectionStart, mLastSelectionEnd); } // Returns true if we did an autocorrection, false otherwise. private boolean handleSeparator(final int primaryCode, final int x, final int y, final int spaceState) { Loading
java/src/com/android/inputmethod/latin/RecapitalizeStatus.java 0 → 100644 +169 −0 Original line number Diff line number Diff line /* * Copyright (C) 2013 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of * the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations under * the License. */ package com.android.inputmethod.latin; import com.android.inputmethod.latin.StringUtils; import java.util.Locale; /** * The status of the current recapitalize process. */ public class RecapitalizeStatus { public static final int CAPS_MODE_ORIGINAL_MIXED_CASE = 0; public static final int CAPS_MODE_ALL_LOWER = 1; public static final int CAPS_MODE_FIRST_WORD_UPPER = 2; public static final int CAPS_MODE_ALL_UPPER = 3; // When adding a new mode, don't forget to update the CAPS_MODE_LAST constant. public static final int CAPS_MODE_LAST = CAPS_MODE_ALL_UPPER; private static final int[] ROTATION_STYLE = { CAPS_MODE_ORIGINAL_MIXED_CASE, CAPS_MODE_ALL_LOWER, CAPS_MODE_FIRST_WORD_UPPER, CAPS_MODE_ALL_UPPER }; private static final int getStringMode(final String string, final String separators) { if (StringUtils.isIdenticalAfterUpcase(string)) { return CAPS_MODE_ALL_UPPER; } else if (StringUtils.isIdenticalAfterDowncase(string)) { return CAPS_MODE_ALL_LOWER; } else if (StringUtils.isIdenticalAfterCapitalizeEachWord(string, separators)) { return CAPS_MODE_FIRST_WORD_UPPER; } else { return CAPS_MODE_ORIGINAL_MIXED_CASE; } } /** * We store the location of the cursor and the string that was there before the undoable * action was done, and the location of the cursor and the string that was there after. */ private int mCursorStartBefore; private int mCursorEndBefore; private String mStringBefore; private int mCursorStartAfter; private int mCursorEndAfter; private int mRotationStyleCurrentIndex; private final boolean mSkipOriginalMixedCaseMode; private final Locale mLocale; private final String mSeparators; private String mStringAfter; public RecapitalizeStatus(final int cursorStart, final int cursorEnd, final String string, final Locale locale, final String separators) { mCursorStartBefore = cursorStart; mCursorEndBefore = cursorEnd; mStringBefore = string; mCursorStartAfter = cursorStart; mCursorEndAfter = cursorEnd; mStringAfter = string; final int initialMode = getStringMode(mStringBefore, separators); mLocale = locale; mSeparators = separators; if (CAPS_MODE_ORIGINAL_MIXED_CASE == initialMode) { mRotationStyleCurrentIndex = 0; mSkipOriginalMixedCaseMode = false; } else { // Find the current mode in the array. int currentMode; for (currentMode = ROTATION_STYLE.length - 1; currentMode > 0; --currentMode) { if (ROTATION_STYLE[currentMode] == initialMode) { break; } } mRotationStyleCurrentIndex = currentMode; mSkipOriginalMixedCaseMode = true; } } public boolean isSetAt(final int cursorStart, final int cursorEnd) { return cursorStart == mCursorStartAfter && cursorEnd == mCursorEndAfter; } /** * Rotate through the different possible capitalization modes. */ public void rotate() { final String oldResult = mStringAfter; int count = 0; // Protection against infinite loop. do { mRotationStyleCurrentIndex = (mRotationStyleCurrentIndex + 1) % ROTATION_STYLE.length; if (CAPS_MODE_ORIGINAL_MIXED_CASE == ROTATION_STYLE[mRotationStyleCurrentIndex] && mSkipOriginalMixedCaseMode) { mRotationStyleCurrentIndex = (mRotationStyleCurrentIndex + 1) % ROTATION_STYLE.length; } ++count; switch (ROTATION_STYLE[mRotationStyleCurrentIndex]) { case CAPS_MODE_ORIGINAL_MIXED_CASE: mStringAfter = mStringBefore; break; case CAPS_MODE_ALL_LOWER: mStringAfter = mStringBefore.toLowerCase(mLocale); break; case CAPS_MODE_FIRST_WORD_UPPER: mStringAfter = StringUtils.capitalizeEachWord(mStringBefore, mSeparators, mLocale); break; case CAPS_MODE_ALL_UPPER: mStringAfter = mStringBefore.toUpperCase(mLocale); break; default: mStringAfter = mStringBefore; } } while (mStringAfter.equals(oldResult) && count < 5); mCursorEndAfter = mCursorStartAfter + mStringAfter.length(); } /** * Remove leading/trailing whitespace from the considered string. */ public void trim() { final int len = mStringBefore.length(); int nonWhitespaceStart = 0; for (; nonWhitespaceStart < len; nonWhitespaceStart = mStringBefore.offsetByCodePoints(nonWhitespaceStart, 1)) { final int codePoint = mStringBefore.codePointAt(nonWhitespaceStart); if (!Character.isWhitespace(codePoint)) break; } int nonWhitespaceEnd = len; for (; nonWhitespaceEnd > 0; nonWhitespaceEnd = mStringBefore.offsetByCodePoints(nonWhitespaceEnd, -1)) { final int codePoint = mStringBefore.codePointBefore(nonWhitespaceEnd); if (!Character.isWhitespace(codePoint)) break; } if (0 != nonWhitespaceStart || len != nonWhitespaceEnd) { mCursorEndBefore = mCursorEndAfter = mCursorStartBefore + nonWhitespaceEnd; mCursorStartBefore = mCursorStartAfter = mCursorStartBefore + nonWhitespaceStart; mStringAfter = mStringBefore = mStringBefore.substring(nonWhitespaceStart, nonWhitespaceEnd); } } public String getRecapitalizedString() { return mStringAfter; } public int getNewCursorStart() { return mCursorStartAfter; } public int getNewCursorEnd() { return mCursorEndAfter; } }
java/src/com/android/inputmethod/latin/RichInputConnection.java +5 −0 Original line number Diff line number Diff line Loading @@ -183,6 +183,11 @@ public final class RichInputConnection { } } public CharSequence getSelectedText(final int flags) { if (null == mIC) return null; return mIC.getSelectedText(flags); } /** * Gets the caps modes we should be in after this specific string. * Loading
java/src/com/android/inputmethod/latin/Settings.java +4 −0 Original line number Diff line number Diff line Loading @@ -138,6 +138,10 @@ public final class Settings implements SharedPreferences.OnSharedPreferenceChang return mSettingsValues.mWordSeparators; } public Locale getCurrentLocale() { return mCurrentLocale; } // Accessed from the settings interface, hence public public static boolean readKeypressSoundEnabled(final SharedPreferences prefs, final Resources res) { Loading
tests/src/com/android/inputmethod/latin/RecapitalizeStatusTests.java 0 → 100644 +203 −0 Original line number Diff line number Diff line /* * Copyright (C) 2013 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.inputmethod.latin; import android.test.AndroidTestCase; import android.test.suitebuilder.annotation.SmallTest; import java.util.Locale; @SmallTest public class RecapitalizeStatusTests extends AndroidTestCase { public void testTrim() { RecapitalizeStatus status = new RecapitalizeStatus(30, 40, "abcdefghij", Locale.ENGLISH, " "); status.trim(); assertEquals("abcdefghij", status.getRecapitalizedString()); assertEquals(30, status.getNewCursorStart()); assertEquals(40, status.getNewCursorEnd()); status = new RecapitalizeStatus(30, 44, " abcdefghij", Locale.ENGLISH, " "); status.trim(); assertEquals("abcdefghij", status.getRecapitalizedString()); assertEquals(34, status.getNewCursorStart()); assertEquals(44, status.getNewCursorEnd()); status = new RecapitalizeStatus(30, 40, "abcdefgh ", Locale.ENGLISH, " "); status.trim(); assertEquals("abcdefgh", status.getRecapitalizedString()); assertEquals(30, status.getNewCursorStart()); assertEquals(38, status.getNewCursorEnd()); status = new RecapitalizeStatus(30, 45, " abcdefghij ", Locale.ENGLISH, " "); status.trim(); assertEquals("abcdefghij", status.getRecapitalizedString()); assertEquals(33, status.getNewCursorStart()); assertEquals(43, status.getNewCursorEnd()); } public void testRotate() { RecapitalizeStatus status = new RecapitalizeStatus(29, 40, "abcd efghij", Locale.ENGLISH, " "); status.rotate(); assertEquals("Abcd Efghij", status.getRecapitalizedString()); assertEquals(29, status.getNewCursorStart()); assertEquals(40, status.getNewCursorEnd()); status.rotate(); assertEquals("ABCD EFGHIJ", status.getRecapitalizedString()); status.rotate(); assertEquals("abcd efghij", status.getRecapitalizedString()); status.rotate(); assertEquals("Abcd Efghij", status.getRecapitalizedString()); status = new RecapitalizeStatus(29, 40, "Abcd Efghij", Locale.ENGLISH, " "); status.rotate(); assertEquals("ABCD EFGHIJ", status.getRecapitalizedString()); assertEquals(29, status.getNewCursorStart()); assertEquals(40, status.getNewCursorEnd()); status.rotate(); assertEquals("abcd efghij", status.getRecapitalizedString()); status.rotate(); assertEquals("Abcd Efghij", status.getRecapitalizedString()); status.rotate(); assertEquals("ABCD EFGHIJ", status.getRecapitalizedString()); status = new RecapitalizeStatus(29, 40, "ABCD EFGHIJ", Locale.ENGLISH, " "); status.rotate(); assertEquals("abcd efghij", status.getRecapitalizedString()); assertEquals(29, status.getNewCursorStart()); assertEquals(40, status.getNewCursorEnd()); status.rotate(); assertEquals("Abcd Efghij", status.getRecapitalizedString()); status.rotate(); assertEquals("ABCD EFGHIJ", status.getRecapitalizedString()); status.rotate(); assertEquals("abcd efghij", status.getRecapitalizedString()); status = new RecapitalizeStatus(29, 39, "AbCDefghij", Locale.ENGLISH, " "); status.rotate(); assertEquals("abcdefghij", status.getRecapitalizedString()); assertEquals(29, status.getNewCursorStart()); assertEquals(39, status.getNewCursorEnd()); status.rotate(); assertEquals("Abcdefghij", status.getRecapitalizedString()); status.rotate(); assertEquals("ABCDEFGHIJ", status.getRecapitalizedString()); status.rotate(); assertEquals("AbCDefghij", status.getRecapitalizedString()); status.rotate(); assertEquals("abcdefghij", status.getRecapitalizedString()); status = new RecapitalizeStatus(29, 40, "Abcd efghij", Locale.ENGLISH, " "); status.rotate(); assertEquals("abcd efghij", status.getRecapitalizedString()); assertEquals(29, status.getNewCursorStart()); assertEquals(40, status.getNewCursorEnd()); status.rotate(); assertEquals("Abcd Efghij", status.getRecapitalizedString()); status.rotate(); assertEquals("ABCD EFGHIJ", status.getRecapitalizedString()); status.rotate(); assertEquals("Abcd efghij", status.getRecapitalizedString()); status.rotate(); assertEquals("abcd efghij", status.getRecapitalizedString()); status = new RecapitalizeStatus(30, 34, "grüß", Locale.GERMAN, " "); status.rotate(); assertEquals("Grüß", status.getRecapitalizedString()); assertEquals(30, status.getNewCursorStart()); assertEquals(34, status.getNewCursorEnd()); status.rotate(); assertEquals("GRÜSS", status.getRecapitalizedString()); assertEquals(30, status.getNewCursorStart()); assertEquals(35, status.getNewCursorEnd()); status.rotate(); assertEquals("grüß", status.getRecapitalizedString()); assertEquals(30, status.getNewCursorStart()); assertEquals(34, status.getNewCursorEnd()); status.rotate(); assertEquals("Grüß", status.getRecapitalizedString()); assertEquals(30, status.getNewCursorStart()); assertEquals(34, status.getNewCursorEnd()); status = new RecapitalizeStatus(30, 33, "œuf", Locale.FRENCH, " "); status.rotate(); assertEquals("Œuf", status.getRecapitalizedString()); assertEquals(30, status.getNewCursorStart()); assertEquals(33, status.getNewCursorEnd()); status.rotate(); assertEquals("ŒUF", status.getRecapitalizedString()); assertEquals(30, status.getNewCursorStart()); assertEquals(33, status.getNewCursorEnd()); status.rotate(); assertEquals("œuf", status.getRecapitalizedString()); assertEquals(30, status.getNewCursorStart()); assertEquals(33, status.getNewCursorEnd()); status.rotate(); assertEquals("Œuf", status.getRecapitalizedString()); assertEquals(30, status.getNewCursorStart()); assertEquals(33, status.getNewCursorEnd()); status = new RecapitalizeStatus(30, 33, "œUf", Locale.FRENCH, " "); status.rotate(); assertEquals("œuf", status.getRecapitalizedString()); assertEquals(30, status.getNewCursorStart()); assertEquals(33, status.getNewCursorEnd()); status.rotate(); assertEquals("Œuf", status.getRecapitalizedString()); assertEquals(30, status.getNewCursorStart()); assertEquals(33, status.getNewCursorEnd()); status.rotate(); assertEquals("ŒUF", status.getRecapitalizedString()); assertEquals(30, status.getNewCursorStart()); assertEquals(33, status.getNewCursorEnd()); status.rotate(); assertEquals("œUf", status.getRecapitalizedString()); assertEquals(30, status.getNewCursorStart()); assertEquals(33, status.getNewCursorEnd()); status.rotate(); assertEquals("œuf", status.getRecapitalizedString()); assertEquals(30, status.getNewCursorStart()); assertEquals(33, status.getNewCursorEnd()); status = new RecapitalizeStatus(30, 35, "école", Locale.FRENCH, " "); status.rotate(); assertEquals("École", status.getRecapitalizedString()); assertEquals(30, status.getNewCursorStart()); assertEquals(35, status.getNewCursorEnd()); status.rotate(); assertEquals("ÉCOLE", status.getRecapitalizedString()); assertEquals(30, status.getNewCursorStart()); assertEquals(35, status.getNewCursorEnd()); status.rotate(); assertEquals("école", status.getRecapitalizedString()); assertEquals(30, status.getNewCursorStart()); assertEquals(35, status.getNewCursorEnd()); status.rotate(); assertEquals("École", status.getRecapitalizedString()); assertEquals(30, status.getNewCursorStart()); assertEquals(35, status.getNewCursorEnd()); } }