Fix a bug on rotation with selection.

The symptom : when text is selected and the device is rotated,
sometimes the keyboard sets the word as being composed around
the start of the selection. Upon the next rotation this ends up
with the keyboard committing some text in place of the selection.

The cause : another bug in the framework with rotation >.>
The keyboard receives a call to startInput with a wrong cursor
position, namely one that does not represent a selection. The
keyboard sets a composition according to this wrong data. When
the keyboard is rotated again, it commits the text, which takes
the place of the selection.

The solution : actually when restarting input the keyboard
realizes that the cursor position is wrong. We cancel composition
at that time.
For robustness, this change also implements two other defensive
changes : upon call to onUpdateSelection, we actually realize
that the previous values were wrong, so we also fix it at that
time, and in addition, when rotating, we finishComposingText()
instead of commitText() which is less dangerous. Implementing
this later change also allows us to let less internal variables
from InputLogic escape to LatinIME, so it's also a good change
for design.

Bug: 14140799

Change-Id: Ib10de18e53e376ac1bbc8487e13d969828483346
diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java
index d329d2c..4293d4f 100644
--- a/java/src/com/android/inputmethod/latin/LatinIME.java
+++ b/java/src/com/android/inputmethod/latin/LatinIME.java
@@ -640,14 +640,10 @@
 
     @Override
     public void onConfigurationChanged(final Configuration conf) {
-        // If orientation changed while predicting, commit the change
         final SettingsValues settingsValues = mSettings.getCurrent();
         if (settingsValues.mDisplayOrientation != conf.orientation) {
             mHandler.startOrientationChanging();
-            mInputLogic.mConnection.beginBatchEdit();
-            mInputLogic.commitTyped(mSettings.getCurrent(), LastComposedWord.NOT_A_SEPARATOR);
-            mInputLogic.mConnection.finishComposingText();
-            mInputLogic.mConnection.endBatchEdit();
+            mInputLogic.finishInput();
         }
         PersonalizationDictionarySessionRegistrar.onConfigurationChanged(this, conf,
                 mDictionaryFacilitator);
diff --git a/java/src/com/android/inputmethod/latin/RichInputConnection.java b/java/src/com/android/inputmethod/latin/RichInputConnection.java
index 9d72c64..96476b2 100644
--- a/java/src/com/android/inputmethod/latin/RichInputConnection.java
+++ b/java/src/com/android/inputmethod/latin/RichInputConnection.java
@@ -891,4 +891,8 @@
     public boolean hasSelection() {
         return mExpectedSelEnd != mExpectedSelStart;
     }
+
+    public boolean isCursorPositionKnown() {
+        return INVALID_CURSOR_POSITION != mExpectedSelStart;
+    }
 }
diff --git a/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java b/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java
index dbbe1a0..6c32275 100644
--- a/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java
+++ b/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java
@@ -319,8 +319,16 @@
                 || !mWordComposer.isComposingWord(); // safe to reset
         final boolean hasOrHadSelection = (oldSelStart != oldSelEnd || newSelStart != newSelEnd);
         final int moveAmount = newSelStart - oldSelStart;
-        if (selectionChangedOrSafeToReset && (hasOrHadSelection
-                || !mWordComposer.moveCursorByAndReturnIfInsideComposingWord(moveAmount))) {
+        // As an added small gift from the framework, it happens upon rotation when there
+        // is a selection that we get a wrong cursor position delivered to startInput() that
+        // does not get reflected in the oldSel{Start,End} parameters to the next call to
+        // onUpdateSelection. In this case, we may have set a composition, and when we're here
+        // we realize we shouldn't have. In theory, in this case, selectionChangedOrSafeToReset
+        // should be true, but that is if the framework had taken that wrong cursor position
+        // into account, which means we have to reset the entire composing state whenever there
+        // is or was a selection regardless of whether it changed or not.
+        if (hasOrHadSelection || (selectionChangedOrSafeToReset
+                && !mWordComposer.moveCursorByAndReturnIfInsideComposingWord(moveAmount))) {
             // If we are composing a word and moving the cursor, we would want to set a
             // suggestion span for recorrection to work correctly. Unfortunately, that
             // would involve the keyboard committing some new text, which would move the
@@ -1922,9 +1930,11 @@
             final boolean tryResumeSuggestions, final int remainingTries,
             // TODO: remove these arguments
             final LatinIME.UIHandler handler) {
+        final boolean shouldFinishComposition = mConnection.hasSelection()
+                || !mConnection.isCursorPositionKnown();
         if (!mConnection.resetCachesUponCursorMoveAndReturnSuccess(
                 mConnection.getExpectedSelectionStart(), mConnection.getExpectedSelectionEnd(),
-                false /* shouldFinishComposition */)) {
+                shouldFinishComposition)) {
             if (0 < remainingTries) {
                 handler.postResetCaches(tryResumeSuggestions, remainingTries - 1);
                 return false;