Backed out changeset 87551f39e8bf (bug 1353799) for android failures in testInputConnection | Can reuse composition in Gecko
authorCarsten "Tomcat" Book <cbook@mozilla.com>
Wed, 10 May 2017 17:17:13 +0200
changeset 396221 221eb9429454777a1e741ce07cabb40c25fe7b33
parent 396220 6b0cf48f6481fc2d27b888a2e35878f7f57b75a9
child 396222 c8bf3336431b1faea494fc582854e1e295f411f2
push id1468
push userasasaki@mozilla.com
push dateMon, 05 Jun 2017 19:31:07 +0000
treeherdermozilla-release@0641fc6ee9d1 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs1353799
milestone54.0
backs out87551f39e8bff109c05160cc39c124dac81f54c4
Backed out changeset 87551f39e8bf (bug 1353799) for android failures in testInputConnection | Can reuse composition in Gecko
mobile/android/geckoview/src/main/aidl/org/mozilla/gecko/IGeckoEditableChild.aidl
mobile/android/geckoview/src/main/java/org/mozilla/gecko/GeckoEditable.java
mobile/android/geckoview/src/main/java/org/mozilla/gecko/GeckoEditableChild.java
mobile/android/tests/browser/robocop/robocop_input.html
mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testInputConnection.java
widget/android/GeckoEditableSupport.cpp
widget/android/GeckoEditableSupport.h
widget/android/GeneratedJNIWrappers.h
--- a/mobile/android/geckoview/src/main/aidl/org/mozilla/gecko/IGeckoEditableChild.aidl
+++ b/mobile/android/geckoview/src/main/aidl/org/mozilla/gecko/IGeckoEditableChild.aidl
@@ -21,13 +21,13 @@ interface IGeckoEditableChild {
     void onImeReplaceText(int start, int end, String text);
 
     // Store a composition range.
     void onImeAddCompositionRange(int start, int end, int rangeType, int rangeStyles,
                                   int rangeLineStyle, boolean rangeBoldLine,
                                   int rangeForeColor, int rangeBackColor, int rangeLineColor);
 
     // Change to a new composition using previously added ranges.
-    void onImeUpdateComposition(int start, int end, int flags);
+    void onImeUpdateComposition(int start, int end);
 
     // Request cursor updates from the child.
     void onImeRequestCursorUpdates(int requestMode);
 }
--- a/mobile/android/geckoview/src/main/java/org/mozilla/gecko/GeckoEditable.java
+++ b/mobile/android/geckoview/src/main/java/org/mozilla/gecko/GeckoEditable.java
@@ -456,60 +456,49 @@ final class GeckoEditable extends IGecko
 
     private void icPerformAction(final Action action) throws RemoteException {
         switch (action.mType) {
         case Action.TYPE_EVENT:
         case Action.TYPE_SET_HANDLER:
             mEditableChild.onImeSynchronize();
             break;
 
-        case Action.TYPE_SET_SPAN: {
-            final boolean needUpdate = (action.mSpanFlags & Spanned.SPAN_INTERMEDIATE) == 0 &&
-                                       ((action.mSpanFlags & Spanned.SPAN_COMPOSING) != 0 ||
-                                        action.mSpanObject == Selection.SELECTION_START ||
-                                        action.mSpanObject == Selection.SELECTION_END);
-
+        case Action.TYPE_SET_SPAN:
             mText.shadowSetSpan(action.mSpanObject, action.mStart,
                                 action.mEnd, action.mSpanFlags);
             action.mSequence = TextUtils.substring(
                     mText.getShadowText(), action.mStart, action.mEnd);
 
-            mNeedUpdateComposition |= needUpdate;
-            if (needUpdate) {
-                icMaybeSendComposition(mText.getShadowText(), SEND_COMPOSITION_NOTIFY_GECKO |
-                                                              SEND_COMPOSITION_KEEP_CURRENT);
-            }
+            mNeedUpdateComposition |= (action.mSpanFlags & Spanned.SPAN_INTERMEDIATE) == 0 &&
+                    ((action.mSpanFlags & Spanned.SPAN_COMPOSING) != 0 ||
+                     action.mSpanObject == Selection.SELECTION_START ||
+                     action.mSpanObject == Selection.SELECTION_END);
 
             mEditableChild.onImeSynchronize();
             break;
-        }
-        case Action.TYPE_REMOVE_SPAN: {
+
+        case Action.TYPE_REMOVE_SPAN:
             final int flags = mText.getShadowText().getSpanFlags(action.mSpanObject);
-            final boolean needUpdate = (flags & Spanned.SPAN_INTERMEDIATE) == 0 &&
-                                       (flags & Spanned.SPAN_COMPOSING) != 0;
             mText.shadowRemoveSpan(action.mSpanObject);
 
-            mNeedUpdateComposition |= needUpdate;
-            if (needUpdate) {
-                icMaybeSendComposition(mText.getShadowText(), SEND_COMPOSITION_NOTIFY_GECKO |
-                                                              SEND_COMPOSITION_KEEP_CURRENT);
-            }
+            mNeedUpdateComposition |= (flags & Spanned.SPAN_INTERMEDIATE) == 0 &&
+                    (flags & Spanned.SPAN_COMPOSING) != 0;
 
             mEditableChild.onImeSynchronize();
             break;
-        }
+
         case Action.TYPE_REPLACE_TEXT:
             // Always sync text after a replace action, so that if the Gecko
             // text is not changed, we will revert the shadow text to before.
             mNeedSync = true;
 
             // Because we get composition styling here essentially for free,
             // we don't need to check if we're in batch mode.
             if (!icMaybeSendComposition(
-                    action.mSequence, SEND_COMPOSITION_USE_ENTIRE_TEXT)) {
+                    action.mSequence, /* useEntireText */ true, /* notifyGecko */ false)) {
                 // Since we don't have a composition, we can try sending key events.
                 sendCharKeyEvents(action);
             }
             mText.shadowReplace(action.mStart, action.mEnd, action.mSequence);
             mEditableChild.onImeReplaceText(
                     action.mStart, action.mEnd, action.mSequence.toString());
             break;
 
@@ -648,47 +637,42 @@ final class GeckoEditable extends IGecko
     private Object getField(Object obj, String field, Object def) {
         try {
             return obj.getClass().getField(field).get(obj);
         } catch (Exception e) {
             return def;
         }
     }
 
-    // Flags for icMaybeSendComposition
-    // If text has composing spans, treat the entire text as a Gecko composition,
-    // instead of just the spanned part.
-    private static final int SEND_COMPOSITION_USE_ENTIRE_TEXT = 1;
-    // Notify Gecko of the new composition ranges;
-    // otherwise, the caller is responsible for notifying Gecko.
-    private static final int SEND_COMPOSITION_NOTIFY_GECKO = 2;
-    // Keep the current composition when updating;
-    // composition is not updated if there is no current composition.
-    private static final int SEND_COMPOSITION_KEEP_CURRENT = 4;
+    /**
+     * Send composition ranges to Gecko for the entire shadow text.
+     */
+    private void icMaybeSendComposition() throws RemoteException {
+        if (!mNeedUpdateComposition) {
+            return;
+        }
+
+        icMaybeSendComposition(mText.getShadowText(),
+                               /* useEntireText */ false, /* notifyGecko */ true);
+    }
 
     /**
      * Send composition ranges to Gecko if the text has composing spans.
      *
      * @param sequence Text with possible composing spans
-     * @param flags Bitmask of SEND_COMPOSITION_* flags for updating composition.
+     * @param useEntireText If text has composing spans, treat the entire text as
+     *                      a Gecko composition, instead of just the spanned part.
+     * @param notifyGecko Notify Gecko of the new composition ranges;
+     *                    otherwise, the caller is responsible for notifying Gecko.
      * @return Whether there was a composition
      */
     private boolean icMaybeSendComposition(final CharSequence sequence,
-                                           final int flags) throws RemoteException {
-        final boolean useEntireText = (flags & SEND_COMPOSITION_USE_ENTIRE_TEXT) != 0;
-        final boolean notifyGecko = (flags & SEND_COMPOSITION_NOTIFY_GECKO) != 0;
-        final boolean keepCurrent = (flags & SEND_COMPOSITION_KEEP_CURRENT) != 0;
-        final int updateFlags = keepCurrent ?
-                GeckoEditableChild.FLAG_KEEP_CURRENT_COMPOSITION : 0;
-
-        if (!keepCurrent) {
-            // If keepCurrent is true, the composition may not actually be updated;
-            // so we may still need to update the composition in the future.
-            mNeedUpdateComposition = false;
-        }
+                                           final boolean useEntireText,
+                                           final boolean notifyGecko) throws RemoteException {
+        mNeedUpdateComposition = false;
 
         int selStart = Selection.getSelectionStart(sequence);
         int selEnd = Selection.getSelectionEnd(sequence);
 
         if (sequence instanceof Spanned) {
             final Spanned text = (Spanned) sequence;
             final Object[] spans = text.getSpans(0, text.length(), Object.class);
             boolean found = false;
@@ -712,26 +696,25 @@ final class GeckoEditable extends IGecko
             if (useEntireText && (selStart < 0 || selEnd < 0)) {
                 selStart = composingEnd;
                 selEnd = composingEnd;
             }
 
             if (found) {
                 icSendComposition(text, selStart, selEnd, composingStart, composingEnd);
                 if (notifyGecko) {
-                    mEditableChild.onImeUpdateComposition(
-                            composingStart, composingEnd, updateFlags);
+                    mEditableChild.onImeUpdateComposition(composingStart, composingEnd);
                 }
                 return true;
             }
         }
 
         if (notifyGecko) {
             // Set the selection by using a composition without ranges
-            mEditableChild.onImeUpdateComposition(selStart, selEnd, updateFlags);
+            mEditableChild.onImeUpdateComposition(selStart, selEnd);
         }
 
         if (DEBUG) {
             Log.d(LOGTAG, "icSendComposition(): no composition");
         }
         return false;
     }
 
@@ -850,19 +833,17 @@ final class GeckoEditable extends IGecko
            We are actually sending two events to Gecko here,
            1. Event from the event parameter (key event)
            2. Sync event from the icOfferAction call
            The first event is a normal event that does not reply back to us,
            the second sync event will have a reply, during which we see that there is a pending
            event-type action, and update the shadow text accordingly.
         */
         try {
-            if (mNeedUpdateComposition) {
-                icMaybeSendComposition(mText.getShadowText(), SEND_COMPOSITION_NOTIFY_GECKO);
-            }
+            icMaybeSendComposition();
             onKeyEvent(event, action, metaState, /* isSynthesizedImeKey */ false);
             icOfferAction(new Action(Action.TYPE_EVENT));
         } catch (final RemoteException e) {
             Log.e(LOGTAG, "Remote call failed", e);
         }
     }
 
     @Override
@@ -1221,20 +1202,18 @@ final class GeckoEditable extends IGecko
                 // side-effect of the replace-text event we sent.
                 mIgnoreSelectionChange = true;
             }
 
         } else if (geckoIsSameText(start, oldEnd, text)) {
             // Nothing to do because the text is the same. This could happen when
             // the composition is updated for example, in which case we want to keep the
             // Java selection.
-            mIgnoreSelectionChange = mIgnoreSelectionChange || (action != null &&
-                    (action.mType == Action.TYPE_REPLACE_TEXT ||
-                     action.mType == Action.TYPE_SET_SPAN ||
-                     action.mType == Action.TYPE_REMOVE_SPAN));
+            mIgnoreSelectionChange = mIgnoreSelectionChange ||
+                    (action != null && action.mType == Action.TYPE_REPLACE_TEXT);
             return;
 
         } else {
             // Gecko side initiated the text change. Replace in two steps to properly
             // clear composing spans that span the whole range.
             mText.currentReplace(start, oldEnd, "");
             mText.currentReplace(start, start, text);
 
--- a/mobile/android/geckoview/src/main/java/org/mozilla/gecko/GeckoEditableChild.java
+++ b/mobile/android/geckoview/src/main/java/org/mozilla/gecko/GeckoEditableChild.java
@@ -48,22 +48,18 @@ final class GeckoEditableChild extends J
     public native void onImeReplaceText(int start, int end, String text);
 
     @WrapForJNI(dispatchTo = "proxy") @Override // IGeckoEditableChild
     public native void onImeAddCompositionRange(int start, int end, int rangeType,
                                                 int rangeStyles, int rangeLineStyle,
                                                 boolean rangeBoldLine, int rangeForeColor,
                                                 int rangeBackColor, int rangeLineColor);
 
-    // Don't update to the new composition if it's different than the current composition.
-    @WrapForJNI
-    public static final int FLAG_KEEP_CURRENT_COMPOSITION = 1;
-
     @WrapForJNI(dispatchTo = "proxy") @Override // IGeckoEditableChild
-    public native void onImeUpdateComposition(int start, int end, int flags);
+    public native void onImeUpdateComposition(int start, int end);
 
     @WrapForJNI(dispatchTo = "proxy") @Override // IGeckoEditableChild
     public native void onImeRequestCursorUpdates(int requestMode);
 
     @Override // JNIObject
     protected void disposeNative() {
         // Disposal happens in native code.
         throw new UnsupportedOperationException();
--- a/mobile/android/tests/browser/robocop/robocop_input.html
+++ b/mobile/android/tests/browser/robocop/robocop_input.html
@@ -23,18 +23,16 @@
         designMode.contentDocument.designMode = "on";
       } catch (e) {
         // Setting designMode above sometimes fails, so try again later.
         setTimeout(function() { designMode.contentDocument.designMode = "on" }, 0);
       }
 
       // Spatial navigation interferes with design-mode key event tests.
       SpecialPowers.setBoolPref("snav.enabled", false);
-      // Enable "selectionchange" events for input/textarea.
-      SpecialPowers.setBoolPref("dom.select_events.textcontrols.enabled", true);
 
       // An input that resets the editor on every input by resetting the value property.
       let resetting_input = document.getElementById("resetting-input");
       resetting_input.addEventListener('input', function() {
         this.value = this.value;
       });
 
       // An input that hides on input.
@@ -43,48 +41,16 @@
         if (e.key === "!") { // '!' key event as sent by testInputConnection.java.
           this.value = "";
           this.style.display = "none";
         }
       });
 
       let getEditor, setValue, setSelection;
 
-      let events_log;
-      function log_event(event) {
-        switch (event.type) {
-          case "compositionstart":
-            events_log += "<";
-            break;
-          case "compositionupdate":
-            events_log += "=";
-            break;
-          case "compositionend":
-            events_log += ">";
-            break;
-          case "selectionchange":
-            events_log += "|";
-            break;
-          default:
-            events_log += "?";
-            break;
-        }
-      }
-
-      function get_event_target() {
-        var editor = getEditor();
-        var parent = SpecialPowers.unwrap(editor.rootElement.parentElement);
-        if (parent instanceof HTMLInputElement || parent instanceof HTMLTextAreaElement) {
-          // "selectionchange" is only dispatched to the element itself,
-          // so use the element as the target instead of using the document.
-          return parent;
-        }
-        return editor.document;
-      }
-
       let test = {
         focus_input: function(val) {
           getEditor = function() {
             return SpecialPowers.wrap(input).QueryInterface(
                 SpecialPowers.Ci.nsIDOMNSEditableElement).editor;
           };
           setValue = function(val) {
             input.value = val;
@@ -159,37 +125,16 @@
         test_set_selection: function() {
           do_check_true(getEditor().composing);
 
           // Ending the composition then setting the selection triggers the bug.
           getEditor().forceCompositionEnd();
           setSelection(3); // Offsets that testInputConnection.java expects.
         },
 
-        start_events_log: function() {
-          // Reset the log
-          events_log = "";
-
-          let target = get_event_target();
-          target.addEventListener("compositionstart", log_event);
-          target.addEventListener("compositionupdate", log_event);
-          target.addEventListener("compositionend", log_event);
-          target.addEventListener("selectionchange", log_event);
-        },
-
-        end_events_log: function() {
-          java.asyncCall("setEventsLog", events_log);
-
-          let target = get_event_target();
-          target.removeEventListener("compositionstart", log_event);
-          target.removeEventListener("compositionupdate", log_event);
-          target.removeEventListener("compositionend", log_event);
-          target.removeEventListener("selectionchange", log_event);
-        },
-
         test_bug1123514: function() {
           document.activeElement.addEventListener('input', function() {
             // Only works on input and textarea.
             if (this.value === 'b') {
               this.value = 'abc';
             }
           }, {once: true});
         },
--- a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testInputConnection.java
+++ b/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testInputConnection.java
@@ -8,91 +8,74 @@ import static org.mozilla.gecko.tests.he
 import static org.mozilla.gecko.tests.helpers.WaitHelper.waitFor;
 
 import org.mozilla.gecko.tests.components.GeckoViewComponent.InputConnectionTest;
 import org.mozilla.gecko.tests.helpers.GeckoHelper;
 import org.mozilla.gecko.tests.helpers.NavigationHelper;
 
 import com.robotium.solo.Condition;
 
-import android.os.SystemClock;
 import android.view.KeyEvent;
 import android.view.inputmethod.EditorInfo;
 import android.view.inputmethod.InputConnection;
 
 /**
  * Tests the proper operation of GeckoInputConnection
  */
 public class testInputConnection extends JavascriptBridgeTest {
 
     private static final String INITIAL_TEXT = "foo";
 
-    private String mEventsLog;
-
     public void testInputConnection() throws InterruptedException {
         GeckoHelper.blockForReady();
 
         final String url = mStringHelper.ROBOCOP_INPUT_URL;
         NavigationHelper.enterAndLoadUrl(url);
         mToolbar.assertTitle(url);
 
         // First run tests inside the normal input field.
         getJS().syncCall("focus_input", INITIAL_TEXT);
         mGeckoView.mTextInput
             .waitForInputConnection()
-            .testInputConnection(new BasicInputConnectionTest("input"));
+            .testInputConnection(new BasicInputConnectionTest());
 
         // Then switch focus to the text area and rerun tests.
         getJS().syncCall("focus_text_area", INITIAL_TEXT);
         mGeckoView.mTextInput
             .waitForInputConnection()
-            .testInputConnection(new BasicInputConnectionTest("textarea"));
+            .testInputConnection(new BasicInputConnectionTest());
 
         // Then switch focus to the content editable and rerun tests.
         getJS().syncCall("focus_content_editable", INITIAL_TEXT);
         mGeckoView.mTextInput
             .waitForInputConnection()
-            .testInputConnection(new BasicInputConnectionTest("contentEditable"));
+            .testInputConnection(new BasicInputConnectionTest());
 
         // Then switch focus to the design mode document and rerun tests.
         getJS().syncCall("focus_design_mode", INITIAL_TEXT);
         mGeckoView.mTextInput
             .waitForInputConnection()
-            .testInputConnection(new BasicInputConnectionTest("designMode"));
+            .testInputConnection(new BasicInputConnectionTest());
 
         // Then switch focus to the resetting input field, and run tests there.
         getJS().syncCall("focus_resetting_input", "");
         mGeckoView.mTextInput
             .waitForInputConnection()
             .testInputConnection(new ResettingInputConnectionTest());
 
         // Then switch focus to the hiding input field, and run tests there.
         getJS().syncCall("focus_hiding_input", "");
         mGeckoView.mTextInput
             .waitForInputConnection()
             .testInputConnection(new HidingInputConnectionTest());
 
         getJS().syncCall("finish_test");
     }
 
-    public void setEventsLog(final String log) {
-        mEventsLog = log;
-    }
-
-    public String getEventsLog() {
-        return mEventsLog;
-    }
-
     private class BasicInputConnectionTest extends InputConnectionTest {
-        private final String mType;
-
-        BasicInputConnectionTest(final String type) {
-            mType = type;
-        }
-
         @Override
         public void test(final InputConnection ic, EditorInfo info) {
             waitFor("focus change", new Condition() {
                 @Override
                 public boolean isSatisfied() {
                     return INITIAL_TEXT.equals(getText(ic));
                 }
             });
@@ -156,23 +139,20 @@ public class testInputConnection extends
 
             // Test getTextAfterCursor
             fAssertEquals("Can retrieve text after cursor", "", ic.getTextAfterCursor(3, 0));
 
             ic.finishComposingText();
             assertTextAndSelectionAt("Can finish composition", ic, "frabar", 6);
 
             // Test sendKeyEvent
-            final long time = SystemClock.uptimeMillis();
-            final KeyEvent shiftKey = new KeyEvent(time, time, KeyEvent.ACTION_DOWN,
-                                                   KeyEvent.KEYCODE_SHIFT_LEFT, 0);
-            final KeyEvent leftKey = new KeyEvent(time, time, KeyEvent.ACTION_DOWN,
-                                                  KeyEvent.KEYCODE_DPAD_LEFT, 0);
-            final KeyEvent tKey = new KeyEvent(time, time, KeyEvent.ACTION_DOWN,
-                                               KeyEvent.KEYCODE_T, 0);
+            final KeyEvent shiftKey = new KeyEvent(KeyEvent.ACTION_DOWN,
+                                                   KeyEvent.KEYCODE_SHIFT_LEFT);
+            final KeyEvent leftKey = new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DPAD_LEFT);
+            final KeyEvent tKey = new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_T);
 
             ic.sendKeyEvent(shiftKey);
             ic.sendKeyEvent(leftKey);
             ic.sendKeyEvent(KeyEvent.changeAction(leftKey, KeyEvent.ACTION_UP));
             ic.sendKeyEvent(KeyEvent.changeAction(shiftKey, KeyEvent.ACTION_UP));
             assertTextAndSelection("Can select using key event", ic, "frabar", 6, 5);
 
             ic.sendKeyEvent(tKey);
@@ -236,18 +216,18 @@ public class testInputConnection extends
             ic.deleteSurroundingText(1, 1);
             ic.endBatchEdit();
             assertTextAndSelectionAt("Can delete after committing", ic, "baoo", 2);
 
             ic.deleteSurroundingText(2, 2);
             assertTextAndSelectionAt("Can clear text", ic, "", 0);
 
             // Bug 1275371 - shift+backspace should not forward delete on Android.
-            final KeyEvent delKey = new KeyEvent(time, time, KeyEvent.ACTION_DOWN,
-                                                 KeyEvent.KEYCODE_DEL, 0);
+            final KeyEvent delKey = new KeyEvent(KeyEvent.ACTION_DOWN,
+                                                 KeyEvent.KEYCODE_DEL);
 
             ic.beginBatchEdit();
             ic.commitText("foo", 1);
             ic.setSelection(1, 1);
             ic.endBatchEdit();
             assertTextAndSelectionAt("Can commit text", ic, "foo", 1);
 
             ic.sendKeyEvent(shiftKey);
@@ -263,67 +243,24 @@ public class testInputConnection extends
             ic.deleteSurroundingText(0, 2);
             assertTextAndSelectionAt("Can clear text", ic, "", 0);
 
             // Bug 1123514 - exception due to incorrect text replacement offsets.
             getJS().syncCall("test_bug1123514");
             // Gecko will change text to 'abc' when we input 'b', potentially causing
             // incorrect calculation of text replacement offsets.
             ic.commitText("b", 1);
-            // This test only works for input/textarea,
-            if (mType.equals("input") || mType.equals("textarea")) {
-                assertTextAndSelectionAt("Can handle text replacement", ic, "abc", 2);
-            } else {
-                processGeckoEvents();
-                processInputConnectionEvents();
-            }
+            // We don't assert text here because this test only works for input/textarea,
+            // so an assertion would fail for contentEditable/designMode.
+            processGeckoEvents();
+            processInputConnectionEvents();
 
             ic.deleteSurroundingText(2, 1);
             assertTextAndSelectionAt("Can clear text", ic, "", 0);
 
-            // Bug 1307816 - Don't end then start composition when setting
-            // composing text, which can confuse the Facebook comment box.
-            getJS().syncCall("start_events_log");
-            ic.setComposingText("f", 1);
-            processGeckoEvents();
-            ic.setComposingText("fo", 1);
-            processGeckoEvents();
-            ic.setComposingText("foo", 1);
-            processGeckoEvents();
-            ic.finishComposingText();
-            assertTextAndSelectionAt("Can reuse composition in Java", ic, "foo", 3);
-
-            getJS().syncCall("end_events_log");
-            if (mType.equals("textarea")) {
-                // textarea has a buggy selectionchange behavior.
-                fAssertEquals("Can reuse composition in Gecko", "<=|==", getEventsLog());
-            } else {
-                // compositionstart > (compositionchange > selectionchange) x3
-                fAssertEquals("Can reuse composition in Gecko", "<=|=|=|", getEventsLog());
-            }
-
-            ic.deleteSurroundingText(3, 0);
-            assertTextAndSelectionAt("Can clear text", ic, "", 0);
-
-            // Bug 1353799 - Can set selection while having a composition, so
-            // the caret can be moved to the start of the composition.
-            getJS().syncCall("start_events_log");
-            ic.setComposingText("foo", 1);
-            assertTextAndSelectionAt("Can set composition before selection", ic, "foo", 3);
-            ic.setSelection(0, 0);
-            assertTextAndSelectionAt("Can set selection after composition", ic, "foo", 0);
-
-            getJS().syncCall("end_events_log");
-            // compositionstart > compositionchange > selectionchange x2
-            fAssertEquals("Can update composition caret", "<=||", getEventsLog());
-
-            ic.finishComposingText();
-            ic.deleteSurroundingText(0, 3);
-            assertTextAndSelectionAt("Can clear text", ic, "", 0);
-
             // Make sure we don't leave behind stale events for the following test.
             processGeckoEvents();
             processInputConnectionEvents();
         }
     }
 
     /**
      * ResettingInputConnectionTest performs tests on the resetting input in
--- a/widget/android/GeckoEditableSupport.cpp
+++ b/widget/android/GeckoEditableSupport.cpp
@@ -875,38 +875,29 @@ GeckoEditableSupport::OnImeAddCompositio
     range.mRangeStyle.mBackgroundColor =
             ConvertAndroidColor(uint32_t(aRangeBackColor));
     range.mRangeStyle.mUnderlineColor =
             ConvertAndroidColor(uint32_t(aRangeLineColor));
     mIMERanges->AppendElement(range);
 }
 
 void
-GeckoEditableSupport::OnImeUpdateComposition(int32_t aStart, int32_t aEnd,
-                                             int32_t aFlags)
+GeckoEditableSupport::OnImeUpdateComposition(int32_t aStart, int32_t aEnd)
 {
     if (mIMEMaskEventsCount > 0) {
         // Not focused.
         return;
     }
 
     nsCOMPtr<nsIWidget> widget = GetWidget();
     nsEventStatus status = nsEventStatus_eIgnore;
     NS_ENSURE_TRUE_VOID(mDispatcher && widget);
 
-    const bool keepCurrent = !!(aFlags &
-            java::GeckoEditableChild::FLAG_KEEP_CURRENT_COMPOSITION);
-
     // A composition with no ranges means we want to set the selection.
     if (mIMERanges->IsEmpty()) {
-        if (keepCurrent && mDispatcher->IsComposing()) {
-            // Don't set selection if we want to keep current composition.
-            return;
-        }
-
         MOZ_ASSERT(aStart >= 0 && aEnd >= 0);
         RemoveComposition();
 
         WidgetSelectionEvent selEvent(true, eSetSelection, widget);
         selEvent.mOffset = std::min(aStart, aEnd);
         selEvent.mLength = std::max(aStart, aEnd) - selEvent.mOffset;
         selEvent.mReversed = aStart > aEnd;
         selEvent.mExpandToClusterBoundary = false;
@@ -924,22 +915,16 @@ GeckoEditableSupport::OnImeUpdateComposi
     nsString string;
     RefPtr<TextComposition> composition(GetComposition());
     MOZ_ASSERT(!composition || !composition->IsEditorHandlingEvent());
 
     if (!mDispatcher->IsComposing() ||
         uint32_t(aStart) != composition->NativeOffsetOfStartComposition() ||
         uint32_t(aEnd) != composition->NativeOffsetOfStartComposition() +
                           composition->String().Length()) {
-        if (keepCurrent) {
-            // Don't start a new composition if we want to keep the current one.
-            mIMERanges->Clear();
-            return;
-        }
-
         // Only start new composition if we don't have an existing one,
         // or if the existing composition doesn't match the new one.
         RemoveComposition();
 
         {
             WidgetSelectionEvent event(true, eSetSelection, widget);
             event.mOffset = uint32_t(aStart);
             event.mLength = uint32_t(aEnd - aStart);
@@ -962,20 +947,17 @@ GeckoEditableSupport::OnImeUpdateComposi
 
 #ifdef DEBUG_ANDROID_IME
     const NS_ConvertUTF16toUTF8 data(event.mData);
     const char* text = data.get();
     ALOGIME("IME: IME_SET_TEXT: text=\"%s\", length=%u, range=%u",
             text, event.mData.Length(), event.mRanges->Length());
 #endif // DEBUG_ANDROID_IME
 
-    if (NS_WARN_IF(NS_FAILED(mDispatcher->BeginNativeInputTransaction()))) {
-        mIMERanges->Clear();
-        return;
-    }
+    NS_ENSURE_SUCCESS_VOID(mDispatcher->BeginNativeInputTransaction());
     mDispatcher->SetPendingComposition(string, mIMERanges);
     mDispatcher->FlushPendingComposition(status);
     mIMERanges->Clear();
 }
 
 void
 GeckoEditableSupport::OnImeRequestCursorUpdates(int aRequestMode)
 {
--- a/widget/android/GeckoEditableSupport.h
+++ b/widget/android/GeckoEditableSupport.h
@@ -216,17 +216,17 @@ public:
 
     // Add styling for a range within the active composition.
     void OnImeAddCompositionRange(int32_t aStart, int32_t aEnd,
             int32_t aRangeType, int32_t aRangeStyle, int32_t aRangeLineStyle,
             bool aRangeBoldLine, int32_t aRangeForeColor,
             int32_t aRangeBackColor, int32_t aRangeLineColor);
 
     // Update styling for the active composition using previous-added ranges.
-    void OnImeUpdateComposition(int32_t aStart, int32_t aEnd, int32_t aFlags);
+    void OnImeUpdateComposition(int32_t aStart, int32_t aEnd);
 
     // Set cursor mode whether IME requests
     void OnImeRequestCursorUpdates(int aRequestMode);
 };
 
 } // namespace widget
 } // namespace mozill
 
--- a/widget/android/GeneratedJNIWrappers.h
+++ b/widget/android/GeneratedJNIWrappers.h
@@ -2314,21 +2314,20 @@ public:
     };
 
     struct OnImeUpdateComposition_t {
         typedef GeckoEditableChild Owner;
         typedef void ReturnType;
         typedef void SetterType;
         typedef mozilla::jni::Args<
                 int32_t,
-                int32_t,
                 int32_t> Args;
         static constexpr char name[] = "onImeUpdateComposition";
         static constexpr char signature[] =
-                "(III)V";
+                "(II)V";
         static const bool isStatic = false;
         static const mozilla::jni::ExceptionMode exceptionMode =
                 mozilla::jni::ExceptionMode::ABORT;
         static const mozilla::jni::CallingThread callingThread =
                 mozilla::jni::CallingThread::ANY;
         static const mozilla::jni::DispatchTarget dispatchTarget =
                 mozilla::jni::DispatchTarget::PROXY;
     };
@@ -2420,18 +2419,16 @@ public:
         static const mozilla::jni::CallingThread callingThread =
                 mozilla::jni::CallingThread::GECKO;
         static const mozilla::jni::DispatchTarget dispatchTarget =
                 mozilla::jni::DispatchTarget::CURRENT;
     };
 
     auto UpdateCompositionRects(mozilla::jni::ObjectArray::Param) const -> void;
 
-    static const int32_t FLAG_KEEP_CURRENT_COMPOSITION = 1;
-
     static const mozilla::jni::CallingThread callingThread =
             mozilla::jni::CallingThread::ANY;
 
     template<class Impl> class Natives;
 };
 
 class GeckoEditableClient : public mozilla::jni::ObjectBase<GeckoEditableClient>
 {