Merge "[CB09] Pass events through the combiner chain"
diff --git a/java/src/com/android/inputmethod/event/Combiner.java b/java/src/com/android/inputmethod/event/Combiner.java
index ab6b70c..c3869a2 100644
--- a/java/src/com/android/inputmethod/event/Combiner.java
+++ b/java/src/com/android/inputmethod/event/Combiner.java
@@ -16,14 +16,22 @@
 
 package com.android.inputmethod.event;
 
+import java.util.ArrayList;
+
 /**
- * A generic interface for combiners.
+ * A generic interface for combiners. Combiners are objects that transform chains of input events
+ * into committable strings and manage feedback to show to the user on the combining state.
  */
 public interface Combiner {
     /**
-     * Combine an event with the existing state and return the new event.
+     * Process an event, possibly combining it with the existing state and return the new event.
+     *
+     * If this event does not result in any new event getting passed down the chain, this method
+     * returns null. It may also modify the previous event list if appropriate.
+     *
+     * @param previousEvents the previous events in this composition.
      * @param event the event to combine with the existing state.
      * @return the resulting event.
      */
-    Event combine(Event event);
+    Event processEvent(ArrayList<Event> previousEvents, Event event);
 }
diff --git a/java/src/com/android/inputmethod/event/CombinerChain.java b/java/src/com/android/inputmethod/event/CombinerChain.java
index 1deaed6..0e01c81 100644
--- a/java/src/com/android/inputmethod/event/CombinerChain.java
+++ b/java/src/com/android/inputmethod/event/CombinerChain.java
@@ -51,4 +51,19 @@
         // The dead key combiner is always active, and always first
         mCombiners.add(new DeadKeyCombiner());
     }
+
+    // Pass a new event through the whole chain.
+    public void processEvent(final ArrayList<Event> previousEvents, final Event newEvent) {
+        final ArrayList<Event> modifiablePreviousEvents = new ArrayList<Event>(previousEvents);
+        Event event = newEvent;
+        for (final Combiner combiner : mCombiners) {
+            // A combiner can never return more than one event; it can return several
+            // code points, but they should be encapsulated within one event.
+            event = combiner.processEvent(modifiablePreviousEvents, event);
+            if (null == event) {
+                // Combiners return null if they eat the event.
+                return;
+            }
+        }
+    }
 }
diff --git a/java/src/com/android/inputmethod/event/DeadKeyCombiner.java b/java/src/com/android/inputmethod/event/DeadKeyCombiner.java
index ae86397..f77ce63 100644
--- a/java/src/com/android/inputmethod/event/DeadKeyCombiner.java
+++ b/java/src/com/android/inputmethod/event/DeadKeyCombiner.java
@@ -21,14 +21,17 @@
 
 import com.android.inputmethod.latin.Constants;
 
+import java.util.ArrayList;
+
 /**
  * A combiner that handles dead keys.
  */
 public class DeadKeyCombiner implements Combiner {
+    // TODO: make this a list of events instead
     final StringBuilder mDeadSequence = new StringBuilder();
 
     @Override
-    public Event combine(final Event event) {
+    public Event processEvent(final ArrayList<Event> previousEvents, final Event event) {
         if (null == event) return null; // Just in case some combiner is broken
         if (TextUtils.isEmpty(mDeadSequence)) {
             if (event.isDead()) {
diff --git a/java/src/com/android/inputmethod/latin/WordComposer.java b/java/src/com/android/inputmethod/latin/WordComposer.java
index 9e5d920..29382fe 100644
--- a/java/src/com/android/inputmethod/latin/WordComposer.java
+++ b/java/src/com/android/inputmethod/latin/WordComposer.java
@@ -192,6 +192,7 @@
         final int keyX = event.mX;
         final int keyY = event.mY;
         final int newIndex = size();
+        mCombinerChain.processEvent(mEvents, event);
         mTypedWord.appendCodePoint(primaryCode);
         mEvents.add(event);
         refreshSize();
diff --git a/tools/dicttool/Android.mk b/tools/dicttool/Android.mk
index 91f8af7..0e9c14e 100644
--- a/tools/dicttool/Android.mk
+++ b/tools/dicttool/Android.mk
@@ -36,8 +36,6 @@
 # nearly-empty implementations, for parts that we don't use in Dicttool.
 LATINIME_SRCS_FOR_DICTTOOL := \
         event/Combiner.java \
-        event/CombinerChain.java \
-        event/DeadKeyCombiner.java \
         event/Event.java \
         latin/BinaryDictionary.java \
         latin/DicTraverseSession.java \
diff --git a/tools/dicttool/compat/com/android/inputmethod/event/CombinerChain.java b/tools/dicttool/compat/com/android/inputmethod/event/CombinerChain.java
new file mode 100644
index 0000000..66ad60c
--- /dev/null
+++ b/tools/dicttool/compat/com/android/inputmethod/event/CombinerChain.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2014 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.event;
+
+import com.android.inputmethod.latin.utils.CollectionUtils;
+
+import java.util.ArrayList;
+
+public class CombinerChain {
+    public CombinerChain(final Combiner... combinerList) {}
+    public void processEvent(final ArrayList<Event> previousEvents, final Event newEvent) {}
+}