Merge "Use same session id for typing and gesture."
diff --git a/java/res/xml/kbd_thai_symbols.xml b/java/res/xml/kbd_thai_symbols.xml
deleted file mode 100644
index 4d9861b..0000000
--- a/java/res/xml/kbd_thai_symbols.xml
+++ /dev/null
@@ -1,27 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-**
-** Copyright 2012, 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.
-*/
--->
-
-<Keyboard
-    xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
-    latin:touchPositionCorrectionData="@array/touch_position_correction_data_default"
->
-    <include
-        latin:keyboardLayout="@xml/rows_symbols" />
-</Keyboard>
diff --git a/java/res/xml/kbd_thai_symbols_shift.xml b/java/res/xml/kbd_thai_symbols_shift.xml
deleted file mode 100644
index a2d67ca..0000000
--- a/java/res/xml/kbd_thai_symbols_shift.xml
+++ /dev/null
@@ -1,27 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-**
-** Copyright 2012, 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.
-*/
--->
-
-<Keyboard
-    xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
-    latin:touchPositionCorrectionData="@array/touch_position_correction_data_default"
->
-    <include
-        latin:keyboardLayout="@xml/rows_symbols_shift" />
-</Keyboard>
diff --git a/java/res/xml/keyboard_layout_set_thai.xml b/java/res/xml/keyboard_layout_set_thai.xml
index 94713e3..b8f9997 100644
--- a/java/res/xml/keyboard_layout_set_thai.xml
+++ b/java/res/xml/keyboard_layout_set_thai.xml
@@ -42,10 +42,10 @@
         latin:elementKeyboard="@xml/kbd_thai" />
     <Element
         latin:elementName="symbols"
-        latin:elementKeyboard="@xml/kbd_thai_symbols" />
+        latin:elementKeyboard="@xml/kbd_symbols" />
     <Element
         latin:elementName="symbolsShifted"
-        latin:elementKeyboard="@xml/kbd_thai_symbols_shift" />
+        latin:elementKeyboard="@xml/kbd_symbols_shift" />
     <Element
         latin:elementName="phone"
         latin:elementKeyboard="@xml/kbd_phone" />
diff --git a/java/src/com/android/inputmethod/latin/makedict/BinaryDictEncoderUtils.java b/java/src/com/android/inputmethod/latin/makedict/BinaryDictEncoderUtils.java
index 5a21341..21e9811 100644
--- a/java/src/com/android/inputmethod/latin/makedict/BinaryDictEncoderUtils.java
+++ b/java/src/com/android/inputmethod/latin/makedict/BinaryDictEncoderUtils.java
@@ -198,6 +198,27 @@
         }
     }
 
+    static int writeUIntToBuffer(final byte[] buffer, int position, final int value,
+            final int size) {
+        switch(size) {
+            case 4:
+                buffer[position++] = (byte) ((value >> 24) & 0xFF);
+                /* fall through */
+            case 3:
+                buffer[position++] = (byte) ((value >> 16) & 0xFF);
+                /* fall through */
+            case 2:
+                buffer[position++] = (byte) ((value >> 8) & 0xFF);
+                /* fall through */
+            case 1:
+                buffer[position++] = (byte) (value & 0xFF);
+                break;
+            default:
+                /* nop */
+        }
+        return position;
+    }
+
     // End utility methods
 
     // This method is responsible for finding a nice ordering of the nodes that favors run-time
@@ -733,7 +754,7 @@
     }
 
     /**
-     * Write a PtNodeArray to memory. The PtNodeArray is expected to have its final position cached.
+     * Write a PtNodeArray. The PtNodeArray is expected to have its final position cached.
      *
      * @param dict the dictionary the node array is a part of (for relative offsets).
      * @param dictEncoder the dictionary encoder.
@@ -741,7 +762,7 @@
      * @param formatOptions file format options.
      */
     @SuppressWarnings("unused")
-    /* package */ static void writePlacedNode(final FusionDictionary dict,
+    /* package */ static void writePlacedPtNodeArray(final FusionDictionary dict,
             final DictEncoder dictEncoder, final PtNodeArray ptNodeArray,
             final FormatOptions formatOptions) {
         // TODO: Make the code in common with BinaryDictIOUtils#writePtNode
@@ -767,13 +788,7 @@
                         + " : " + ptNode.mFrequency);
             }
 
-            dictEncoder.writePtNodeFlags(ptNode, parentPosition, formatOptions);
-            dictEncoder.writeParentPosition(parentPosition, ptNode, formatOptions);
-            dictEncoder.writeCharacters(ptNode.mChars, ptNode.hasSeveralChars());
-            dictEncoder.writeFrequency(ptNode.mFrequency);
-            dictEncoder.writeChildrenPosition(ptNode, formatOptions);
-            dictEncoder.writeShortcuts(ptNode.mShortcutTargets);
-            dictEncoder.writeBigrams(ptNode.mBigrams, dict);
+            dictEncoder.writePtNode(ptNode, parentPosition, formatOptions, dict);
         }
         if (formatOptions.mSupportsDynamicUpdate) {
             dictEncoder.writeForwardLinkAddress(FormatSpec.NO_FORWARD_LINK_ADDRESS);
diff --git a/java/src/com/android/inputmethod/latin/makedict/DictDecoder.java b/java/src/com/android/inputmethod/latin/makedict/DictDecoder.java
index 11a3f0b..64638fd 100644
--- a/java/src/com/android/inputmethod/latin/makedict/DictDecoder.java
+++ b/java/src/com/android/inputmethod/latin/makedict/DictDecoder.java
@@ -54,10 +54,13 @@
      * which words from the buffer should be added. If it is null, a new dictionary is created.
      *
      * @param dict an optional dictionary to add words to, or null.
+     * @param deleteDictIfBroken a flag indicating whether this method should remove the broken
+     * dictionary or not.
      * @return the created (or merged) dictionary.
      */
     @UsedForTesting
-    public FusionDictionary readDictionaryBinary(final FusionDictionary dict)
+    public FusionDictionary readDictionaryBinary(final FusionDictionary dict,
+            final boolean deleteDictIfBroken)
             throws FileNotFoundException, IOException, UnsupportedFormatException;
 
     /**
diff --git a/java/src/com/android/inputmethod/latin/makedict/DictEncoder.java b/java/src/com/android/inputmethod/latin/makedict/DictEncoder.java
index d1589a3..ea5d492 100644
--- a/java/src/com/android/inputmethod/latin/makedict/DictEncoder.java
+++ b/java/src/com/android/inputmethod/latin/makedict/DictEncoder.java
@@ -18,10 +18,8 @@
 
 import com.android.inputmethod.latin.makedict.FormatSpec.FormatOptions;
 import com.android.inputmethod.latin.makedict.FusionDictionary.PtNode;
-import com.android.inputmethod.latin.makedict.FusionDictionary.WeightedString;
 
 import java.io.IOException;
-import java.util.ArrayList;
 
 /**
  * An interface of binary dictionary encoder.
@@ -33,28 +31,8 @@
     public void setPosition(final int position);
     public int getPosition();
     public void writePtNodeCount(final int ptNodeCount);
-    public void writePtNodeFlags(final PtNode ptNode, final int parentAddress,
-           final FormatOptions formatOptions);
-    public void writeParentPosition(final int parentPosition, final PtNode ptNode,
-            final FormatOptions formatOptions);
-    public void writeCharacters(final int[] characters, final boolean hasSeveralChars);
-    public void writeFrequency(final int frequency);
-    public void writeChildrenPosition(final PtNode ptNode, final FormatOptions formatOptions);
-
-    /**
-     * Write a shortcut attributes list to memory.
-     *
-     * @param shortcuts the shortcut attributes list.
-     */
-    public void writeShortcuts(final ArrayList<WeightedString> shortcuts);
-
-    /**
-     * Write a bigram attributes list to memory.
-     *
-     * @param bigrams the bigram attributes list.
-     * @param dict the dictionary the node array is a part of (for relative offsets).
-     */
-    public void writeBigrams(final ArrayList<WeightedString> bigrams, final FusionDictionary dict);
-
     public void writeForwardLinkAddress(final int forwardLinkAddress);
+
+    public void writePtNode(final PtNode ptNode, final int parentPosition,
+            final FormatOptions formatOptions, final FusionDictionary dict);
 }
diff --git a/java/src/com/android/inputmethod/latin/makedict/Ver3DictDecoder.java b/java/src/com/android/inputmethod/latin/makedict/Ver3DictDecoder.java
index 1a5023e..b98aa0f 100644
--- a/java/src/com/android/inputmethod/latin/makedict/Ver3DictDecoder.java
+++ b/java/src/com/android/inputmethod/latin/makedict/Ver3DictDecoder.java
@@ -306,7 +306,8 @@
     }
 
     @Override
-    public FusionDictionary readDictionaryBinary(final FusionDictionary dict)
+    public FusionDictionary readDictionaryBinary(final FusionDictionary dict,
+            final boolean deleteDictIfBroken)
             throws FileNotFoundException, IOException, UnsupportedFormatException {
         if (mDictBuffer == null) {
             openDictBuffer();
@@ -315,13 +316,13 @@
             return BinaryDictDecoderUtils.readDictionaryBinary(this, dict);
         } catch (IOException e) {
             Log.e(TAG, "The dictionary " + mDictionaryBinaryFile.getName() + " is broken.", e);
-            if (!mDictionaryBinaryFile.delete()) {
+            if (deleteDictIfBroken && !mDictionaryBinaryFile.delete()) {
                 Log.e(TAG, "Failed to delete the broken dictionary.");
             }
             throw e;
         } catch (UnsupportedFormatException e) {
             Log.e(TAG, "The dictionary " + mDictionaryBinaryFile.getName() + " is broken.", e);
-            if (!mDictionaryBinaryFile.delete()) {
+            if (deleteDictIfBroken && !mDictionaryBinaryFile.delete()) {
                 Log.e(TAG, "Failed to delete the broken dictionary.");
             }
             throw e;
diff --git a/java/src/com/android/inputmethod/latin/makedict/Ver3DictEncoder.java b/java/src/com/android/inputmethod/latin/makedict/Ver3DictEncoder.java
index 3f26ff3..48a823d 100644
--- a/java/src/com/android/inputmethod/latin/makedict/Ver3DictEncoder.java
+++ b/java/src/com/android/inputmethod/latin/makedict/Ver3DictEncoder.java
@@ -103,7 +103,7 @@
         MakedictLog.i("Writing file...");
 
         for (PtNodeArray nodeArray : flatNodes) {
-            BinaryDictEncoderUtils.writePlacedNode(dict, this, nodeArray, formatOptions);
+            BinaryDictEncoderUtils.writePlacedPtNodeArray(dict, this, nodeArray, formatOptions);
         }
         if (MakedictLog.DBG) BinaryDictEncoderUtils.showStatistics(flatNodes);
         mOutStream.write(mBuffer, 0, mPosition);
@@ -126,26 +126,23 @@
     @Override
     public void writePtNodeCount(final int ptNodeCount) {
         final int countSize = BinaryDictIOUtils.getPtNodeCountSize(ptNodeCount);
-        if (1 == countSize) {
-            mBuffer[mPosition++] = (byte) ptNodeCount;
-        } else if (2 == countSize) {
-            mBuffer[mPosition++] = (byte) ((ptNodeCount >> 8) & 0xFF);
-            mBuffer[mPosition++] = (byte) (ptNodeCount & 0xFF);
-        } else {
+        if (countSize != 1 && countSize != 2) {
             throw new RuntimeException("Strange size from getGroupCountSize : " + countSize);
         }
+        mPosition = BinaryDictEncoderUtils.writeUIntToBuffer(mBuffer, mPosition, ptNodeCount,
+                countSize);
     }
 
-    @Override
-    public void writePtNodeFlags(final PtNode ptNode, final int parentAddress,
+    private void writePtNodeFlags(final PtNode ptNode, final int parentAddress,
             final FormatOptions formatOptions) {
         final int childrenPos = BinaryDictEncoderUtils.getChildrenPosition(ptNode, formatOptions);
-        mBuffer[mPosition++] = BinaryDictEncoderUtils.makePtNodeFlags(ptNode, mPosition,
-                childrenPos, formatOptions);
+        mPosition = BinaryDictEncoderUtils.writeUIntToBuffer(mBuffer, mPosition,
+                BinaryDictEncoderUtils.makePtNodeFlags(ptNode, mPosition, childrenPos,
+                        formatOptions),
+                FormatSpec.PTNODE_FLAGS_SIZE);
     }
 
-    @Override
-    public void writeParentPosition(final int parentPosition, final PtNode ptNode,
+    private void writeParentPosition(final int parentPosition, final PtNode ptNode,
             final FormatOptions formatOptions) {
         if (parentPosition == FormatSpec.NO_PARENT_ADDRESS) {
             mPosition = BinaryDictEncoderUtils.writeParentAddress(mBuffer, mPosition,
@@ -156,22 +153,20 @@
         }
     }
 
-    @Override
-    public void writeCharacters(final int[] codePoints, final boolean hasSeveralChars) {
+    private void writeCharacters(final int[] codePoints, final boolean hasSeveralChars) {
         mPosition = CharEncoding.writeCharArray(codePoints, mBuffer, mPosition);
         if (hasSeveralChars) {
             mBuffer[mPosition++] = FormatSpec.PTNODE_CHARACTERS_TERMINATOR;
         }
     }
 
-    @Override
-    public void writeFrequency(final int frequency) {
+    private void writeFrequency(final int frequency) {
         if (frequency >= 0) {
-            mBuffer[mPosition++] = (byte) frequency;
+            mPosition = BinaryDictEncoderUtils.writeUIntToBuffer(mBuffer, mPosition, frequency,
+                    FormatSpec.PTNODE_FREQUENCY_SIZE);
         }
     }
 
-    @Override
     public void writeChildrenPosition(final PtNode ptNode, final FormatOptions formatOptions) {
         final int childrenPos = BinaryDictEncoderUtils.getChildrenPosition(ptNode, formatOptions);
         if (formatOptions.mSupportsDynamicUpdate) {
@@ -183,8 +178,12 @@
         }
     }
 
-    @Override
-    public void writeShortcuts(final ArrayList<WeightedString> shortcuts) {
+    /**
+     * Write a shortcut attributes list to mBuffer.
+     *
+     * @param shortcuts the shortcut attributes list.
+     */
+    private void writeShortcuts(final ArrayList<WeightedString> shortcuts) {
         if (null == shortcuts || shortcuts.isEmpty()) return;
 
         final int indexOfShortcutByteSize = mPosition;
@@ -195,7 +194,8 @@
             final int shortcutFlags = BinaryDictEncoderUtils.makeShortcutFlags(
                     shortcutIterator.hasNext(),
                     target.mFrequency);
-            mBuffer[mPosition++] = (byte)shortcutFlags;
+            mPosition = BinaryDictEncoderUtils.writeUIntToBuffer(mBuffer, mPosition, shortcutFlags,
+                    FormatSpec.PTNODE_ATTRIBUTE_FLAGS_SIZE);
             final int shortcutShift = CharEncoding.writeString(mBuffer, mPosition, target.mWord);
             mPosition += shortcutShift;
         }
@@ -203,12 +203,18 @@
         if (shortcutByteSize > 0xFFFF) {
             throw new RuntimeException("Shortcut list too large");
         }
-        mBuffer[indexOfShortcutByteSize] = (byte)((shortcutByteSize >> 8) & 0xFF);
-        mBuffer[indexOfShortcutByteSize + 1] = (byte)(shortcutByteSize & 0xFF);
+        BinaryDictEncoderUtils.writeUIntToBuffer(mBuffer, indexOfShortcutByteSize, shortcutByteSize,
+                FormatSpec.PTNODE_SHORTCUT_LIST_SIZE_SIZE);
     }
 
-    @Override
-    public void writeBigrams(final ArrayList<WeightedString> bigrams, final FusionDictionary dict) {
+    /**
+     * Write a bigram attributes list to mBuffer.
+     *
+     * @param bigrams the bigram attributes list.
+     * @param dict the dictionary the node array is a part of (for relative offsets).
+     */
+    private void writeBigrams(final ArrayList<WeightedString> bigrams,
+            final FusionDictionary dict) {
         if (bigrams == null) return;
 
         final Iterator<WeightedString> bigramIterator = bigrams.iterator();
@@ -220,9 +226,10 @@
             final int unigramFrequencyForThisWord = target.mFrequency;
             final int offset = addressOfBigram
                     - (mPosition + FormatSpec.PTNODE_ATTRIBUTE_FLAGS_SIZE);
-            int bigramFlags = BinaryDictEncoderUtils.makeBigramFlags(bigramIterator.hasNext(),
+            final int bigramFlags = BinaryDictEncoderUtils.makeBigramFlags(bigramIterator.hasNext(),
                     offset, bigram.mFrequency, unigramFrequencyForThisWord, bigram.mWord);
-            mBuffer[mPosition++] = (byte) bigramFlags;
+            mPosition = BinaryDictEncoderUtils.writeUIntToBuffer(mBuffer, mPosition, bigramFlags,
+                    FormatSpec.PTNODE_ATTRIBUTE_FLAGS_SIZE);
             mPosition += BinaryDictEncoderUtils.writeChildrenPosition(mBuffer, mPosition,
                     Math.abs(offset));
         }
@@ -230,8 +237,19 @@
 
     @Override
     public void writeForwardLinkAddress(final int forwardLinkAddress) {
-        mBuffer[mPosition++] = (byte) ((forwardLinkAddress >> 16) & 0xFF);
-        mBuffer[mPosition++] = (byte) ((forwardLinkAddress >> 8) & 0xFF);
-        mBuffer[mPosition++] = (byte) (forwardLinkAddress & 0xFF);
+        mPosition = BinaryDictEncoderUtils.writeUIntToBuffer(mBuffer, mPosition, forwardLinkAddress,
+                FormatSpec.FORWARD_LINK_ADDRESS_SIZE);
+    }
+
+    @Override
+    public void writePtNode(final PtNode ptNode, final int parentPosition,
+            final FormatOptions formatOptions, final FusionDictionary dict) {
+        writePtNodeFlags(ptNode, parentPosition, formatOptions);
+        writeParentPosition(parentPosition, ptNode, formatOptions);
+        writeCharacters(ptNode.mChars, ptNode.hasSeveralChars());
+        writeFrequency(ptNode.mFrequency);
+        writeChildrenPosition(ptNode, formatOptions);
+        writeShortcuts(ptNode.mShortcutTargets);
+        writeBigrams(ptNode.mBigrams, dict);
     }
 }
diff --git a/tests/src/com/android/inputmethod/latin/makedict/BinaryDictDecoderEncoderTests.java b/tests/src/com/android/inputmethod/latin/makedict/BinaryDictDecoderEncoderTests.java
index 72ec5a3..1864845 100644
--- a/tests/src/com/android/inputmethod/latin/makedict/BinaryDictDecoderEncoderTests.java
+++ b/tests/src/com/android/inputmethod/latin/makedict/BinaryDictDecoderEncoderTests.java
@@ -289,7 +289,7 @@
             dictDecoder.openDictBuffer();
             assertNotNull(dictDecoder.getDictBuffer());
             now = System.currentTimeMillis();
-            dict = dictDecoder.readDictionaryBinary(null);
+            dict = dictDecoder.readDictionaryBinary(null, false /* deleteDictIfBroken */);
             diff  = System.currentTimeMillis() - now;
         } catch (IOException e) {
             Log.e(TAG, "IOException while reading dictionary", e);
diff --git a/tools/dicttool/src/com/android/inputmethod/latin/dicttool/BinaryDictOffdeviceUtils.java b/tools/dicttool/src/com/android/inputmethod/latin/dicttool/BinaryDictOffdeviceUtils.java
index 465b177..1417ca4 100644
--- a/tools/dicttool/src/com/android/inputmethod/latin/dicttool/BinaryDictOffdeviceUtils.java
+++ b/tools/dicttool/src/com/android/inputmethod/latin/dicttool/BinaryDictOffdeviceUtils.java
@@ -192,7 +192,7 @@
                         System.out.println("Packaging : " + decodedSpec.describeChain());
                         System.out.println("Uncompressed size : " + decodedSpec.mFile.length());
                     }
-                    return dictDecoder.readDictionaryBinary(null);
+                    return dictDecoder.readDictionaryBinary(null, false /* deleteDictIfBroken */);
                 }
             }
         } catch (IOException e) {
diff --git a/tools/dicttool/src/com/android/inputmethod/latin/dicttool/DictionaryMaker.java b/tools/dicttool/src/com/android/inputmethod/latin/dicttool/DictionaryMaker.java
index 709b819..767c147 100644
--- a/tools/dicttool/src/com/android/inputmethod/latin/dicttool/DictionaryMaker.java
+++ b/tools/dicttool/src/com/android/inputmethod/latin/dicttool/DictionaryMaker.java
@@ -268,7 +268,7 @@
             throws FileNotFoundException, IOException, UnsupportedFormatException {
         final File file = new File(binaryFilename);
         final DictDecoder dictDecoder = new Ver3DictDecoder(file);
-        return dictDecoder.readDictionaryBinary(null);
+        return dictDecoder.readDictionaryBinary(null, false /* deleteDictIfBroken */);
     }
 
     /**
diff --git a/tools/dicttool/tests/com/android/inputmethod/latin/dicttool/BinaryDictOffdeviceUtilsTests.java b/tools/dicttool/tests/com/android/inputmethod/latin/dicttool/BinaryDictOffdeviceUtilsTests.java
index 47e2206..6e82e37 100644
--- a/tools/dicttool/tests/com/android/inputmethod/latin/dicttool/BinaryDictOffdeviceUtilsTests.java
+++ b/tools/dicttool/tests/com/android/inputmethod/latin/dicttool/BinaryDictOffdeviceUtilsTests.java
@@ -71,7 +71,8 @@
         assertEquals("Wrong decode spec", 3, decodeSpec.mDecoderSpec.size());
         final DictDecoder dictDecoder = new Ver3DictDecoder(decodeSpec.mFile);
         final FusionDictionary resultDict = dictDecoder.readDictionaryBinary(
-                null /* dict : an optional dictionary to add words to, or null */);
+                null /* dict : an optional dictionary to add words to, or null */,
+                false /* deleteDictIfBroken */);
         assertEquals("Dictionary can't be read back correctly",
                 FusionDictionary.findWordInTree(resultDict.mRootNodeArray, "foo").getFrequency(),
                 TEST_FREQ);