Merge "Add autoGenerateFromAlphabet enum to KeyboardSet.Element.elementKeyboard"
diff --git a/java/src/com/android/inputmethod/keyboard/Keyboard.java b/java/src/com/android/inputmethod/keyboard/Keyboard.java
index 5816e56..c548f11 100644
--- a/java/src/com/android/inputmethod/keyboard/Keyboard.java
+++ b/java/src/com/android/inputmethod/keyboard/Keyboard.java
@@ -680,7 +680,7 @@
             a.recycle();
             if (resourceId == 0) {
                 if (LatinImeLogger.sDBG)
-                    throw new RuntimeException("touchPositionCorrectionData is not defined");
+                    Log.e(TAG, "touchPositionCorrectionData is not defined");
                 return;
             }
 
diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java
index a053b9b..31cbc4e 100644
--- a/java/src/com/android/inputmethod/latin/LatinIME.java
+++ b/java/src/com/android/inputmethod/latin/LatinIME.java
@@ -203,9 +203,11 @@
     private WordComposer mWordComposer = new WordComposer();
 
     private int mCorrectionMode;
+
     // Keep track of the last selection range to decide if we need to show word alternatives
-    private int mLastSelectionStart;
-    private int mLastSelectionEnd;
+    private static final int NOT_A_CURSOR_POSITION = -1;
+    private int mLastSelectionStart = NOT_A_CURSOR_POSITION;
+    private int mLastSelectionEnd = NOT_A_CURSOR_POSITION;
 
     // Whether we are expecting an onUpdateSelection event to fire. If it does when we don't
     // "expect" it, it means the user actually moved the cursor.
@@ -1401,9 +1403,29 @@
                 // inconsistent with backspacing after selecting other suggestions.
                 restartSuggestionsOnManuallyPickedTypedWord(ic);
             } else {
-                ic.deleteSurroundingText(1, 0);
-                if (mDeleteCount > DELETE_ACCELERATE_AT) {
-                    ic.deleteSurroundingText(1, 0);
+                // Here we must check whether there is a selection. If so we should remove the
+                // selected text, otherwise we should just delete the character before the cursor.
+                if (mLastSelectionStart != mLastSelectionEnd) {
+                    final int lengthToDelete = mLastSelectionEnd - mLastSelectionStart;
+                    ic.setSelection(mLastSelectionEnd, mLastSelectionEnd);
+                    ic.deleteSurroundingText(lengthToDelete, 0);
+                } else {
+                    if (NOT_A_CURSOR_POSITION == mLastSelectionEnd) {
+                        // We don't know whether there is a selection or not. We just send a false
+                        // hardware key event and let TextView sort it out for us. The problem
+                        // here is, this is asynchronous with respect to the input connection
+                        // batch edit, so it may flicker. But this only ever happens if backspace
+                        // is pressed just after the IME is invoked, and then again only once.
+                        // TODO: add an API call that gets the selection indices. This is available
+                        // to the IME in the general case via onUpdateSelection anyway, and would
+                        // allow us to remove this race condition.
+                        sendDownUpKeyEvents(KeyEvent.KEYCODE_DEL);
+                    } else {
+                        ic.deleteSurroundingText(1, 0);
+                    }
+                    if (mDeleteCount > DELETE_ACCELERATE_AT) {
+                        ic.deleteSurroundingText(1, 0);
+                    }
                 }
                 if (isSuggestionsRequested()) {
                     restartSuggestionsOnWordBeforeCursorIfAtEndOfWord(ic);
diff --git a/tests/src/com/android/inputmethod/latin/InputLogicTests.java b/tests/src/com/android/inputmethod/latin/InputLogicTests.java
index 06ee5bf..0d5e42b 100644
--- a/tests/src/com/android/inputmethod/latin/InputLogicTests.java
+++ b/tests/src/com/android/inputmethod/latin/InputLogicTests.java
@@ -41,6 +41,7 @@
 
     private LatinIME mLatinIME;
     private TextView mTextView;
+    private InputConnection mInputConnection;
 
     public InputLogicTests() {
         super(LatinIME.class);
@@ -82,6 +83,7 @@
         mLatinIME.onCreateInputView();
         mLatinIME.onStartInputView(ei, false);
         mLatinIME.onCreateInputMethodInterface().startInput(ic, ei);
+        mInputConnection = ic;
     }
 
     // type(int) and type(String): helper methods to send a code point resp. a string to LatinIME.
@@ -106,17 +108,35 @@
     }
 
     public void testTypeWord() {
-        final String wordToType = "abcd";
-        type(wordToType);
-        assertEquals("type word", wordToType, mTextView.getText().toString());
+        final String WORD_TO_TYPE = "abcd";
+        type(WORD_TO_TYPE);
+        assertEquals("type word", WORD_TO_TYPE, mTextView.getText().toString());
     }
 
     public void testPickSuggestionThenBackspace() {
-        final String wordToType = "tgis";
-        type(wordToType);
-        mLatinIME.pickSuggestionManually(0, wordToType);
+        final String WORD_TO_TYPE = "tgis";
+        type(WORD_TO_TYPE);
+        mLatinIME.pickSuggestionManually(0, WORD_TO_TYPE);
         type(Keyboard.CODE_DELETE);
-        assertEquals("press suggestion then backspace", wordToType, mTextView.getText().toString());
+        assertEquals("press suggestion then backspace", WORD_TO_TYPE,
+                mTextView.getText().toString());
     }
 
+    public void testDeleteSelection() {
+        final String STRING_TO_TYPE = "some text delete me some text";
+        final int SELECTION_START = 10;
+        final int SELECTION_END = 19;
+        final String EXPECTED_RESULT = "some text  some text";
+        type(STRING_TO_TYPE);
+        // There is no IMF to call onUpdateSelection for us so we must do it by hand.
+        // Send once to simulate the cursor actually responding to the move caused by typing.
+        // This is necessary because LatinIME is bookkeeping to avoid confusing a real cursor
+        // move with a move triggered by LatinIME inputting stuff.
+        mLatinIME.onUpdateSelection(0, 0, STRING_TO_TYPE.length(), STRING_TO_TYPE.length(), -1, -1);
+        mInputConnection.setSelection(SELECTION_START, SELECTION_END);
+        // And now we simulate the user actually selecting some text.
+        mLatinIME.onUpdateSelection(0, 0, SELECTION_START, SELECTION_END, -1, -1);
+        type(Keyboard.CODE_DELETE);
+        assertEquals("delete selection", EXPECTED_RESULT, mTextView.getText().toString());
+    }
 }