From 5ce39dfa782031fd53af167c0fd9a9bc63d21149 Mon Sep 17 00:00:00 2001 From: Jean Chalard Date: Wed, 14 May 2014 20:19:16 +0900 Subject: [PATCH] Fix a bug where changing languages kills the composition. Bug: 14926896 Change-Id: Id2a06c68a51f833db4d8bbc858a232c2696afb6e --- .../android/inputmethod/event/CombinerChain.java | 8 +++++--- .../android/inputmethod/latin/WordComposer.java | 15 +++++++-------- .../inputmethod/latin/inputlogic/InputLogic.java | 4 ++-- .../inputmethod/latin/InputLogicTests.java | 12 ++++++++++++ .../android/inputmethod/event/CombinerChain.java | 6 ++++-- 5 files changed, 30 insertions(+), 15 deletions(-) diff --git a/java/src/com/android/inputmethod/event/CombinerChain.java b/java/src/com/android/inputmethod/event/CombinerChain.java index 990f7deea..9e7f04d4f 100644 --- a/java/src/com/android/inputmethod/event/CombinerChain.java +++ b/java/src/com/android/inputmethod/event/CombinerChain.java @@ -56,18 +56,20 @@ public class CombinerChain { * * The combiner chain takes events as inputs and outputs code points and combining state. * For example, if the input language is Japanese, the combining chain will typically perform - * kana conversion. + * kana conversion. This takes a string for initial text, taken to be present before the + * cursor: we'll start after this. * + * @param initialText The text that has already been combined so far. * @param combinerList A list of combiners to be applied in order. */ - public CombinerChain(final Combiner... combinerList) { + public CombinerChain(final String initialText, final Combiner... combinerList) { mCombiners = CollectionUtils.newArrayList(); // The dead key combiner is always active, and always first mCombiners.add(new DeadKeyCombiner()); for (final Combiner combiner : combinerList) { mCombiners.add(combiner); } - mCombinedText = new StringBuilder(); + mCombinedText = new StringBuilder(initialText); mStateFeedback = new SpannableStringBuilder(); } diff --git a/java/src/com/android/inputmethod/latin/WordComposer.java b/java/src/com/android/inputmethod/latin/WordComposer.java index cdee496a8..ac6972928 100644 --- a/java/src/com/android/inputmethod/latin/WordComposer.java +++ b/java/src/com/android/inputmethod/latin/WordComposer.java @@ -80,7 +80,7 @@ public final class WordComposer { private boolean mIsFirstCharCapitalized; public WordComposer() { - mCombinerChain = new CombinerChain(); + mCombinerChain = new CombinerChain(""); mEvents = CollectionUtils.newArrayList(); mAutoCorrection = null; mIsResumed = false; @@ -92,18 +92,17 @@ public final class WordComposer { } /** - * Restart input with a new combining spec. + * Restart the combiners, possibly with a new spec. * @param combiningSpec The spec string for combining. This is found in the extra value. */ - public void restart(final String combiningSpec) { + public void restartCombining(final String combiningSpec) { final String nonNullCombiningSpec = null == combiningSpec ? "" : combiningSpec; - if (nonNullCombiningSpec.equals(mCombiningSpec)) { - mCombinerChain.reset(); - } else { - mCombinerChain = new CombinerChain(CombinerChain.createCombiners(nonNullCombiningSpec)); + if (!nonNullCombiningSpec.equals(mCombiningSpec)) { + mCombinerChain = new CombinerChain( + mCombinerChain.getComposingWordWithCombiningFeedback().toString(), + CombinerChain.createCombiners(nonNullCombiningSpec)); mCombiningSpec = nonNullCombiningSpec; } - reset(); } /** diff --git a/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java b/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java index 1156c7737..ea58abc14 100644 --- a/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java +++ b/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java @@ -127,7 +127,7 @@ public final class InputLogic { public void startInput(final boolean restarting, final EditorInfo editorInfo, final String combiningSpec) { mEnteredText = null; - mWordComposer.restart(combiningSpec); + mWordComposer.restartCombining(combiningSpec); resetComposingState(true /* alsoResetLastComposedWord */); mDeleteCount = 0; mSpaceState = SpaceState.NONE; @@ -150,7 +150,7 @@ public final class InputLogic { * @param combiningSpec the spec string for the combining rules */ public void onSubtypeChanged(final String combiningSpec) { - mWordComposer.restart(combiningSpec); + mWordComposer.restartCombining(combiningSpec); } /** diff --git a/tests/src/com/android/inputmethod/latin/InputLogicTests.java b/tests/src/com/android/inputmethod/latin/InputLogicTests.java index 29423e8e3..a9444160f 100644 --- a/tests/src/com/android/inputmethod/latin/InputLogicTests.java +++ b/tests/src/com/android/inputmethod/latin/InputLogicTests.java @@ -600,4 +600,16 @@ public class InputLogicTests extends InputTestsBase { assertEquals("type words letter by letter", EXPECTED_RESULT, mEditText.getText().toString()); } + + public void testSwitchLanguages() { + final String WORD_TO_TYPE_FIRST_PART = "com"; + final String WORD_TO_TYPE_SECOND_PART = "md "; + final String EXPECTED_RESULT = "comme "; + changeLanguage("en"); + type(WORD_TO_TYPE_FIRST_PART); + changeLanguage("fr"); + type(WORD_TO_TYPE_SECOND_PART); + assertEquals("Composing continues after switching languages", EXPECTED_RESULT, + mEditText.getText().toString()); + } } diff --git a/tools/dicttool/compat/com/android/inputmethod/event/CombinerChain.java b/tools/dicttool/compat/com/android/inputmethod/event/CombinerChain.java index 47f781e62..538d759c8 100644 --- a/tools/dicttool/compat/com/android/inputmethod/event/CombinerChain.java +++ b/tools/dicttool/compat/com/android/inputmethod/event/CombinerChain.java @@ -28,8 +28,10 @@ import java.util.ArrayList; // TODO: there should not be a dependency to this in dicttool, so there // should be a sensible way to separate them cleanly. public class CombinerChain { - private StringBuilder mComposingWord = new StringBuilder(); - public CombinerChain(final Combiner... combinerList) {} + private StringBuilder mComposingWord; + public CombinerChain(final String initialText, final Combiner... combinerList) { + mComposingWord = new StringBuilder(initialText); + } public void processEvent(final ArrayList previousEvents, final Event newEvent) { mComposingWord.append(newEvent.getTextToCommit());