Merge "[HD02] Make the date header attribute mandatory."
diff --git a/java/res/layout/suggestions_strip.xml b/java/res/layout/suggestions_strip.xml
index d8a65f6..9c83542 100644
--- a/java/res/layout/suggestions_strip.xml
+++ b/java/res/layout/suggestions_strip.xml
@@ -42,6 +42,7 @@
             android:id="@+id/hint_add_to_dictionary"
             android:layout_width="match_parent"
             android:layout_height="match_parent"
+            android:textAlignment="viewStart"
             style="?attr/suggestionWordStyle" />
     </LinearLayout>
 </merge>
diff --git a/java/res/xml/keys_comma_period_symbols.xml b/java/res/xml/keys_comma_period_symbols.xml
index cbdbe2e..880fe40 100644
--- a/java/res/xml/keys_comma_period_symbols.xml
+++ b/java/res/xml/keys_comma_period_symbols.xml
@@ -22,7 +22,8 @@
     xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
 >
     <Key
-        latin:keyLabel="," />
+        latin:keyLabel="!text/keylabel_for_comma"
+        latin:moreKeys="!text/more_keys_for_comma" />
     <!-- U+2026: "…" HORIZONTAL ELLIPSIS -->
     <Key
         latin:keyLabel="."
diff --git a/java/src/com/android/inputmethod/keyboard/internal/KeyboardTextsSet.java b/java/src/com/android/inputmethod/keyboard/internal/KeyboardTextsSet.java
index 9f33fcc..4e8eb3e 100644
--- a/java/src/com/android/inputmethod/keyboard/internal/KeyboardTextsSet.java
+++ b/java/src/com/android/inputmethod/keyboard/internal/KeyboardTextsSet.java
@@ -1512,7 +1512,8 @@
         /* 104 */ "\u061F",
         /* 105 */ "!fixedColumnOrder!4,:,!,\u061F,\u061B,-,/,\u00AB|\u00BB,\u00BB|\u00AB",
         /* 106 */ null,
-        /* 107 */ "\u061F",
+        // U+064B: "ً" ARABIC FATHATAN
+        /* 107 */ "\u064B",
         /* 108 */ "!text/more_keys_for_arabic_diacritics",
         /* 109 */ null,
         /* 110 */ "\u064B",
diff --git a/java/src/com/android/inputmethod/latin/BinaryDictionary.java b/java/src/com/android/inputmethod/latin/BinaryDictionary.java
index e66cfca..95823da 100644
--- a/java/src/com/android/inputmethod/latin/BinaryDictionary.java
+++ b/java/src/com/android/inputmethod/latin/BinaryDictionary.java
@@ -27,7 +27,7 @@
 import com.android.inputmethod.latin.utils.JniUtils;
 import com.android.inputmethod.latin.utils.LanguageModelParam;
 import com.android.inputmethod.latin.utils.StringUtils;
-import com.android.inputmethod.latin.utils.UnigramProperty;
+import com.android.inputmethod.latin.utils.WordProperty;
 
 import java.io.File;
 import java.util.ArrayList;
@@ -61,18 +61,18 @@
 
     public static final int NOT_A_VALID_TIMESTAMP = -1;
 
-    // Format to get unigram flags from native side via getUnigramPropertyNative().
-    private static final int FORMAT_UNIGRAM_PROPERTY_OUTPUT_FLAG_COUNT = 4;
-    private static final int FORMAT_UNIGRAM_PROPERTY_IS_NOT_A_WORD_INDEX = 0;
-    private static final int FORMAT_UNIGRAM_PROPERTY_IS_BLACKLISTED_INDEX = 1;
-    private static final int FORMAT_UNIGRAM_PROPERTY_HAS_BIGRAMS_INDEX = 2;
-    private static final int FORMAT_UNIGRAM_PROPERTY_HAS_SHORTCUTS_INDEX = 3;
+    // Format to get unigram flags from native side via getWordPropertyNative().
+    private static final int FORMAT_WORD_PROPERTY_OUTPUT_FLAG_COUNT = 4;
+    private static final int FORMAT_WORD_PROPERTY_IS_NOT_A_WORD_INDEX = 0;
+    private static final int FORMAT_WORD_PROPERTY_IS_BLACKLISTED_INDEX = 1;
+    private static final int FORMAT_WORD_PROPERTY_HAS_BIGRAMS_INDEX = 2;
+    private static final int FORMAT_WORD_PROPERTY_HAS_SHORTCUTS_INDEX = 3;
 
-    // Format to get unigram historical info from native side via getUnigramPropertyNative().
-    private static final int FORMAT_UNIGRAM_PROPERTY_OUTPUT_HISTORICAL_INFO_COUNT = 3;
-    private static final int FORMAT_UNIGRAM_PROPERTY_TIMESTAMP_INDEX = 0;
-    private static final int FORMAT_UNIGRAM_PROPERTY_LEVEL_INDEX = 1;
-    private static final int FORMAT_UNIGRAM_PROPERTY_COUNT_INDEX = 2;
+    // Format to get unigram historical info from native side via getWordPropertyNative().
+    private static final int FORMAT_WORD_PROPERTY_OUTPUT_HISTORICAL_INFO_COUNT = 3;
+    private static final int FORMAT_WORD_PROPERTY_TIMESTAMP_INDEX = 0;
+    private static final int FORMAT_WORD_PROPERTY_LEVEL_INDEX = 1;
+    private static final int FORMAT_WORD_PROPERTY_COUNT_INDEX = 2;
 
     private long mNativeDict;
     private final Locale mLocale;
@@ -143,7 +143,7 @@
     private static native int getFormatVersionNative(long dict);
     private static native int getProbabilityNative(long dict, int[] word);
     private static native int getBigramProbabilityNative(long dict, int[] word0, int[] word1);
-    private static native void getUnigramPropertyNative(long dict, int[] word,
+    private static native void getWordPropertyNative(long dict, int[] word,
             int[] outCodePoints, boolean[] outFlags, int[] outProbability,
             int[] outHistoricalInfo, ArrayList<int[]> outShortcutTargets,
             ArrayList<Integer> outShortcutProbabilities);
@@ -306,28 +306,28 @@
     }
 
     @UsedForTesting
-    public UnigramProperty getUnigramProperty(final String word) {
+    public WordProperty getWordProperty(final String word) {
         if (TextUtils.isEmpty(word)) {
             return null;
         }
         final int[] codePoints = StringUtils.toCodePointArray(word);
         final int[] outCodePoints = new int[MAX_WORD_LENGTH];
-        final boolean[] outFlags = new boolean[FORMAT_UNIGRAM_PROPERTY_OUTPUT_FLAG_COUNT];
+        final boolean[] outFlags = new boolean[FORMAT_WORD_PROPERTY_OUTPUT_FLAG_COUNT];
         final int[] outProbability = new int[1];
         final int[] outHistoricalInfo =
-                new int[FORMAT_UNIGRAM_PROPERTY_OUTPUT_HISTORICAL_INFO_COUNT];
+                new int[FORMAT_WORD_PROPERTY_OUTPUT_HISTORICAL_INFO_COUNT];
         final ArrayList<int[]> outShortcutTargets = CollectionUtils.newArrayList();
         final ArrayList<Integer> outShortcutProbabilities = CollectionUtils.newArrayList();
-        getUnigramPropertyNative(mNativeDict, codePoints, outCodePoints, outFlags, outProbability,
+        getWordPropertyNative(mNativeDict, codePoints, outCodePoints, outFlags, outProbability,
                 outHistoricalInfo, outShortcutTargets, outShortcutProbabilities);
-        return new UnigramProperty(codePoints,
-                outFlags[FORMAT_UNIGRAM_PROPERTY_IS_NOT_A_WORD_INDEX],
-                outFlags[FORMAT_UNIGRAM_PROPERTY_IS_BLACKLISTED_INDEX],
-                outFlags[FORMAT_UNIGRAM_PROPERTY_HAS_BIGRAMS_INDEX],
-                outFlags[FORMAT_UNIGRAM_PROPERTY_HAS_SHORTCUTS_INDEX], outProbability[0],
-                outHistoricalInfo[FORMAT_UNIGRAM_PROPERTY_TIMESTAMP_INDEX],
-                outHistoricalInfo[FORMAT_UNIGRAM_PROPERTY_LEVEL_INDEX],
-                outHistoricalInfo[FORMAT_UNIGRAM_PROPERTY_COUNT_INDEX],
+        return new WordProperty(codePoints,
+                outFlags[FORMAT_WORD_PROPERTY_IS_NOT_A_WORD_INDEX],
+                outFlags[FORMAT_WORD_PROPERTY_IS_BLACKLISTED_INDEX],
+                outFlags[FORMAT_WORD_PROPERTY_HAS_BIGRAMS_INDEX],
+                outFlags[FORMAT_WORD_PROPERTY_HAS_SHORTCUTS_INDEX], outProbability[0],
+                outHistoricalInfo[FORMAT_WORD_PROPERTY_TIMESTAMP_INDEX],
+                outHistoricalInfo[FORMAT_WORD_PROPERTY_LEVEL_INDEX],
+                outHistoricalInfo[FORMAT_WORD_PROPERTY_COUNT_INDEX],
                 outShortcutTargets, outShortcutProbabilities);
     }
 
diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java
index 1de965e..8f4b2d6 100644
--- a/java/src/com/android/inputmethod/latin/LatinIME.java
+++ b/java/src/com/android/inputmethod/latin/LatinIME.java
@@ -1498,8 +1498,7 @@
         }
         if (showingAddToDictionaryHint
                 && suggest.mDictionaryFacilitator.isUserDictionaryEnabled()) {
-            mSuggestionStripView.showAddToDictionaryHint(
-                    suggestion, currentSettings.mHintToSaveText);
+            mSuggestionStripView.showAddToDictionaryHint(suggestion);
         } else {
             // If we're not showing the "Touch again to save", then update the suggestion strip.
             mHandler.postUpdateSuggestionStrip();
diff --git a/java/src/com/android/inputmethod/latin/makedict/Ver4DictDecoder.java b/java/src/com/android/inputmethod/latin/makedict/Ver4DictDecoder.java
index f230229..e459e48 100644
--- a/java/src/com/android/inputmethod/latin/makedict/Ver4DictDecoder.java
+++ b/java/src/com/android/inputmethod/latin/makedict/Ver4DictDecoder.java
@@ -215,11 +215,12 @@
 
                                 if (options.mHasTimestamp) {
                                     probability = buffer.readUnsignedByte();
-                                    final int pos = buffer.position();
-                                    // Skip historical info.
-                                    buffer.position(pos + FormatSpec.BIGRAM_TIMESTAMP_SIZE
-                                            + FormatSpec.BIGRAM_LEVEL_SIZE
-                                            + FormatSpec.BIGRAM_COUNTER_SIZE);
+                                    // Skip timestamp
+                                    buffer.readInt();
+                                    // Skip level
+                                    buffer.readUnsignedByte();
+                                    // Skip count
+                                    buffer.readUnsignedByte();
                                 } else {
                                     probability = bigramFlags
                                             & FormatSpec.FLAG_BIGRAM_SHORTCUT_ATTR_FREQUENCY;
diff --git a/java/src/com/android/inputmethod/latin/settings/SettingsValues.java b/java/src/com/android/inputmethod/latin/settings/SettingsValues.java
index e4ae64f..2979544 100644
--- a/java/src/com/android/inputmethod/latin/settings/SettingsValues.java
+++ b/java/src/com/android/inputmethod/latin/settings/SettingsValues.java
@@ -49,7 +49,6 @@
     // From resources:
     public final SpacingAndPunctuations mSpacingAndPunctuations;
     public final int mDelayUpdateOldSuggestions;
-    public final CharSequence mHintToSaveText;
 
     // From preferences, in the same order as xml/prefs.xml:
     public final boolean mAutoCap;
@@ -101,7 +100,6 @@
         // Get the resources
         mDelayUpdateOldSuggestions = res.getInteger(R.integer.config_delay_update_old_suggestions);
         mSpacingAndPunctuations = new SpacingAndPunctuations(res);
-        mHintToSaveText = res.getText(R.string.hint_add_to_dictionary);
 
         // Store the input attributes
         if (null == inputAttributes) {
diff --git a/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripLayoutHelper.java b/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripLayoutHelper.java
index 3cd9d95..5ed42ab 100644
--- a/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripLayoutHelper.java
+++ b/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripLayoutHelper.java
@@ -50,6 +50,7 @@
 import com.android.inputmethod.latin.SuggestedWords;
 import com.android.inputmethod.latin.utils.AutoCorrectionUtils;
 import com.android.inputmethod.latin.utils.ResourceUtils;
+import com.android.inputmethod.latin.utils.SubtypeLocaleUtils;
 import com.android.inputmethod.latin.utils.ViewLayoutUtils;
 
 import java.util.ArrayList;
@@ -459,7 +460,7 @@
     }
 
     public void layoutAddToDictionaryHint(final String word, final ViewGroup addToDictionaryStrip,
-            final int stripWidth, final CharSequence hintText) {
+            final int stripWidth) {
         final int width = stripWidth - mDividerWidth - mPadding * 2;
 
         final TextView wordView = (TextView)addToDictionaryStrip.findViewById(R.id.word_to_save);
@@ -473,13 +474,17 @@
 
         final TextView hintView = (TextView)addToDictionaryStrip.findViewById(
                 R.id.hint_add_to_dictionary);
-        hintView.setGravity(Gravity.LEFT | Gravity.CENTER_VERTICAL | GravityCompat.START);
         hintView.setTextColor(mColorAutoCorrect);
         final boolean isRtlLanguage = (ViewCompat.getLayoutDirection(addToDictionaryStrip)
                 == ViewCompat.LAYOUT_DIRECTION_RTL);
-        final String hintWithArrow = (isRtlLanguage ? RIGHTWARDS_ARROW : LEFTWARDS_ARROW)
-                + hintText;
+        final String arrow = isRtlLanguage ? RIGHTWARDS_ARROW : LEFTWARDS_ARROW;
+        final Resources res = addToDictionaryStrip.getResources();
+        final boolean isRtlSystem = SubtypeLocaleUtils.isRtlLanguage(res.getConfiguration().locale);
+        final CharSequence hintText = res.getText(R.string.hint_add_to_dictionary);
+        final String hintWithArrow = (isRtlLanguage == isRtlSystem)
+                ? (arrow + hintText) : (hintText + arrow);
         final int hintWidth = width - wordWidth;
+        hintView.setTextScaleX(1.0f); // Reset textScaleX.
         final float hintScaleX = getTextScaleX(hintWithArrow, hintWidth, hintView.getPaint());
         hintView.setText(hintWithArrow);
         hintView.setTextScaleX(hintScaleX);
diff --git a/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripView.java b/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripView.java
index 5469ced..22804fc 100644
--- a/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripView.java
+++ b/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripView.java
@@ -186,8 +186,8 @@
         return mStripVisibilityGroup.isShowingAddToDictionaryStrip();
     }
 
-    public void showAddToDictionaryHint(final String word, final CharSequence hintText) {
-        mLayoutHelper.layoutAddToDictionaryHint(word, mAddToDictionaryStrip, getWidth(), hintText);
+    public void showAddToDictionaryHint(final String word) {
+        mLayoutHelper.layoutAddToDictionaryHint(word, mAddToDictionaryStrip, getWidth());
         // {@link TextView#setTag()} is used to hold the word to be added to dictionary. The word
         // will be extracted at {@link #onClick(View)}.
         mAddToDictionaryStrip.setTag(word);
diff --git a/java/src/com/android/inputmethod/latin/utils/ImportantNoticeUtils.java b/java/src/com/android/inputmethod/latin/utils/ImportantNoticeUtils.java
new file mode 100644
index 0000000..8eff2e6
--- /dev/null
+++ b/java/src/com/android/inputmethod/latin/utils/ImportantNoticeUtils.java
@@ -0,0 +1,75 @@
+/*
+ * 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.latin.utils;
+
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.provider.Settings;
+import android.provider.Settings.SettingNotFoundException;
+import android.util.Log;
+
+public final class ImportantNoticeUtils {
+    private static final String TAG = ImportantNoticeUtils.class.getSimpleName();
+
+    // The current version number of an important notice.
+    // This number must be incremented whenever users should see a new important notice.
+    private static final int CURRENT_IMPORTANT_NOTICE_VERSION = 0;
+
+    // {@link SharedPreferences} name to save the last important notice version that has been
+    // displayed to users.
+    private static final String PREFERENCE_NAME = "important_notice";
+    private static final String KEY_IMPORTANT_NOTICE_VERSION = "important_notice_version";
+
+    // Copy of the hidden {@link Settings.Secure#USER_SETUP_COMPLETE} settings key.
+    // The value is zero until each multiuser completes system setup wizard.
+    // Caveat: This is a hidden API.
+    private static final String Settings_Secure_USER_SETUP_COMPLETE = "user_setup_complete";
+    private static final int USER_SETUP_IS_NOT_COMPLETE = 0;
+
+    private ImportantNoticeUtils() {
+        // This utility class is not publicly instantiable.
+    }
+
+    public static boolean isInSystemSetupWizard(final Context context) {
+        try {
+            final int userSetupComplete = Settings.Secure.getInt(
+                    context.getContentResolver(), Settings_Secure_USER_SETUP_COMPLETE);
+            return userSetupComplete == USER_SETUP_IS_NOT_COMPLETE;
+        } catch (final SettingNotFoundException e) {
+            Log.w(TAG, "Can't find settings in Settings.Secure: key="
+                    + Settings_Secure_USER_SETUP_COMPLETE);
+            return false;
+        }
+    }
+
+    private static SharedPreferences getImportantNoticePreferences(final Context context) {
+        return context.getSharedPreferences(PREFERENCE_NAME, Context.MODE_PRIVATE);
+    }
+
+    public static boolean hasNewImportantNotice(final Context context) {
+        final SharedPreferences prefs = getImportantNoticePreferences(context);
+        final int lastVersion = prefs.getInt(KEY_IMPORTANT_NOTICE_VERSION, 0);
+        return CURRENT_IMPORTANT_NOTICE_VERSION > lastVersion;
+    }
+
+    public static void updateLastImportantNoticeVersion(final Context context) {
+        final SharedPreferences prefs = getImportantNoticePreferences(context);
+        prefs.edit()
+                .putInt(KEY_IMPORTANT_NOTICE_VERSION, CURRENT_IMPORTANT_NOTICE_VERSION)
+                .apply();
+    }
+}
diff --git a/java/src/com/android/inputmethod/latin/utils/SubtypeLocaleUtils.java b/java/src/com/android/inputmethod/latin/utils/SubtypeLocaleUtils.java
index 0d02889..b3871bf 100644
--- a/java/src/com/android/inputmethod/latin/utils/SubtypeLocaleUtils.java
+++ b/java/src/com/android/inputmethod/latin/utils/SubtypeLocaleUtils.java
@@ -347,9 +347,12 @@
         Arrays.sort(SORTED_RTL_LANGUAGES);
     }
 
-    public static boolean isRtlLanguage(final InputMethodSubtype subtype) {
-        final Locale locale = getSubtypeLocale(subtype);
+    public static boolean isRtlLanguage(final Locale locale) {
         final String language = locale.getLanguage();
         return Arrays.binarySearch(SORTED_RTL_LANGUAGES, language) >= 0;
     }
+
+    public static boolean isRtlLanguage(final InputMethodSubtype subtype) {
+        return isRtlLanguage(getSubtypeLocale(subtype));
+    }
 }
diff --git a/java/src/com/android/inputmethod/latin/utils/UnigramProperty.java b/java/src/com/android/inputmethod/latin/utils/WordProperty.java
similarity index 93%
rename from java/src/com/android/inputmethod/latin/utils/UnigramProperty.java
rename to java/src/com/android/inputmethod/latin/utils/WordProperty.java
index 4feee43..d6c0f90 100644
--- a/java/src/com/android/inputmethod/latin/utils/UnigramProperty.java
+++ b/java/src/com/android/inputmethod/latin/utils/WordProperty.java
@@ -26,7 +26,7 @@
 // This has information that belong to a unigram. This class has some detailed attributes such as
 // historical information but they have to be checked only for testing purpose.
 @UsedForTesting
-public class UnigramProperty {
+public class WordProperty {
     public final String mCodePoints;
     public final boolean mIsNotAWord;
     public final boolean mIsBlacklisted;
@@ -50,8 +50,8 @@
         return codePoints.length;
     }
 
-    // This represents invalid unigram when the probability is BinaryDictionary.NOT_A_PROBABILITY.
-    public UnigramProperty(final int[] codePoints, final boolean isNotAWord,
+    // This represents invalid word when the probability is BinaryDictionary.NOT_A_PROBABILITY.
+    public WordProperty(final int[] codePoints, final boolean isNotAWord,
             final boolean isBlacklisted, final boolean hasBigram,
             final boolean hasShortcuts, final int probability, final int timestamp,
             final int level, final int count, final ArrayList<int[]> shortcutTargets,
diff --git a/native/jni/NativeFileList.mk b/native/jni/NativeFileList.mk
index d2f2259..c7061c8 100644
--- a/native/jni/NativeFileList.mk
+++ b/native/jni/NativeFileList.mk
@@ -32,7 +32,7 @@
         error_type_utils.cpp \
         multi_bigram_map.cpp \
         suggestions_output_utils.cpp \
-        unigram_property.cpp) \
+        word_property.cpp) \
     $(addprefix suggest/core/layout/, \
         additional_proximity_chars.cpp \
         proximity_info.cpp \
diff --git a/native/jni/com_android_inputmethod_latin_BinaryDictionary.cpp b/native/jni/com_android_inputmethod_latin_BinaryDictionary.cpp
index 586a306..16a3fe8 100644
--- a/native/jni/com_android_inputmethod_latin_BinaryDictionary.cpp
+++ b/native/jni/com_android_inputmethod_latin_BinaryDictionary.cpp
@@ -24,7 +24,7 @@
 #include "jni.h"
 #include "jni_common.h"
 #include "suggest/core/dictionary/dictionary.h"
-#include "suggest/core/dictionary/unigram_property.h"
+#include "suggest/core/dictionary/word_property.h"
 #include "suggest/core/suggest_options.h"
 #include "suggest/policyimpl/dictionary/structure/dictionary_structure_with_buffer_policy_factory.h"
 #include "suggest/policyimpl/dictionary/utils/dict_file_writing_utils.h"
@@ -260,7 +260,7 @@
             word1Length);
 }
 
-static void latinime_BinaryDictionary_getUnigramProperty(JNIEnv *env, jclass clazz,
+static void latinime_BinaryDictionary_getWordProperty(JNIEnv *env, jclass clazz,
         jlong dict, jintArray word, jintArray outCodePoints, jbooleanArray outFlags,
         jintArray outProbability, jintArray outHistoricalInfo, jobject outShortcutTargets,
         jobject outShortcutProbabilities) {
@@ -269,9 +269,8 @@
     const jsize wordLength = env->GetArrayLength(word);
     int wordCodePoints[wordLength];
     env->GetIntArrayRegion(word, 0, wordLength, wordCodePoints);
-    const UnigramProperty unigramProperty = dictionary->getUnigramProperty(
-            wordCodePoints, wordLength);
-    unigramProperty.outputProperties(env, outCodePoints, outFlags, outProbability,
+    const WordProperty wordProperty = dictionary->getWordProperty(wordCodePoints, wordLength);
+    wordProperty.outputProperties(env, outCodePoints, outFlags, outProbability,
             outHistoricalInfo, outShortcutTargets, outShortcutProbabilities);
 }
 
@@ -521,9 +520,9 @@
         reinterpret_cast<void *>(latinime_BinaryDictionary_getBigramProbability)
     },
     {
-        const_cast<char *>("getUnigramPropertyNative"),
+        const_cast<char *>("getWordPropertyNative"),
         const_cast<char *>("(J[I[I[Z[I[ILjava/util/ArrayList;Ljava/util/ArrayList;)V"),
-        reinterpret_cast<void *>(latinime_BinaryDictionary_getUnigramProperty)
+        reinterpret_cast<void *>(latinime_BinaryDictionary_getWordProperty)
     },
     {
         const_cast<char *>("calcNormalizedScoreNative"),
diff --git a/native/jni/src/suggest/core/dictionary/dictionary.cpp b/native/jni/src/suggest/core/dictionary/dictionary.cpp
index e68c0a6..16b1a56 100644
--- a/native/jni/src/suggest/core/dictionary/dictionary.cpp
+++ b/native/jni/src/suggest/core/dictionary/dictionary.cpp
@@ -143,10 +143,10 @@
             maxResultLength);
 }
 
-const UnigramProperty Dictionary::getUnigramProperty(const int *const codePoints,
+const WordProperty Dictionary::getWordProperty(const int *const codePoints,
         const int codePointCount) {
     TimeKeeper::setCurrentTime();
-    return mDictionaryStructureWithBufferPolicy.get()->getUnigramProperty(
+    return mDictionaryStructureWithBufferPolicy.get()->getWordProperty(
             codePoints, codePointCount);
 }
 
diff --git a/native/jni/src/suggest/core/dictionary/dictionary.h b/native/jni/src/suggest/core/dictionary/dictionary.h
index b37b4aa..4a468f3 100644
--- a/native/jni/src/suggest/core/dictionary/dictionary.h
+++ b/native/jni/src/suggest/core/dictionary/dictionary.h
@@ -22,7 +22,7 @@
 #include "defines.h"
 #include "jni.h"
 #include "suggest/core/dictionary/bigram_dictionary.h"
-#include "suggest/core/dictionary/unigram_property.h"
+#include "suggest/core/dictionary/word_property.h"
 #include "suggest/core/policy/dictionary_header_structure_policy.h"
 #include "suggest/core/policy/dictionary_structure_with_buffer_policy.h"
 #include "suggest/core/suggest_interface.h"
@@ -34,7 +34,7 @@
 class DicTraverseSession;
 class ProximityInfo;
 class SuggestOptions;
-class UnigramProperty;
+class WordProperty;
 
 class Dictionary {
  public:
@@ -94,7 +94,7 @@
     void getProperty(const char *const query, const int queryLength, char *const outResult,
             const int maxResultLength);
 
-    const UnigramProperty getUnigramProperty(const int *const codePoints, const int codePointCount);
+    const WordProperty getWordProperty(const int *const codePoints, const int codePointCount);
 
     const DictionaryStructureWithBufferPolicy *getDictionaryStructurePolicy() const {
         return mDictionaryStructureWithBufferPolicy.get();
diff --git a/native/jni/src/suggest/core/dictionary/unigram_property.h b/native/jni/src/suggest/core/dictionary/unigram_property.h
deleted file mode 100644
index c4ebb86..0000000
--- a/native/jni/src/suggest/core/dictionary/unigram_property.h
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- * Copyright (C) 2013 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.
- */
-
-#ifndef LATINIME_UNIGRAM_PROPERTY_H
-#define LATINIME_UNIGRAM_PROPERTY_H
-
-#include <cstring>
-#include <vector>
-
-#include "defines.h"
-#include "jni.h"
-
-namespace latinime {
-
-// This class is used for returning information belonging to a unigram to java side.
-class UnigramProperty {
- public:
-    // Invalid unigram.
-    UnigramProperty()
-            : mCodePoints(), mCodePointCount(0), mIsNotAWord(false), mIsBlacklisted(false),
-              mHasBigrams(false), mHasShortcuts(false), mProbability(NOT_A_PROBABILITY),
-              mTimestamp(0), mLevel(0), mCount(0), mShortcutTargets(), mShortcutProbabilities() {}
-
-    UnigramProperty(const UnigramProperty &unigramProperty)
-            : mCodePoints(), mCodePointCount(unigramProperty.mCodePointCount),
-              mIsNotAWord(unigramProperty.mIsNotAWord),
-              mIsBlacklisted(unigramProperty.mIsBlacklisted),
-              mHasBigrams(unigramProperty.mHasBigrams),
-              mHasShortcuts(unigramProperty.mHasShortcuts),
-              mProbability(unigramProperty.mProbability),
-              mTimestamp(unigramProperty.mTimestamp), mLevel(unigramProperty.mLevel),
-              mCount(unigramProperty.mCount), mShortcutTargets(unigramProperty.mShortcutTargets),
-              mShortcutProbabilities(unigramProperty.mShortcutProbabilities) {
-        memcpy(mCodePoints, unigramProperty.mCodePoints, sizeof(mCodePoints));
-    }
-
-    UnigramProperty(const int *const codePoints, const int codePointCount,
-            const bool isNotAWord, const bool isBlacklisted, const bool hasBigrams,
-            const bool hasShortcuts, const int probability, const int timestamp,
-            const int level, const int count,
-            const std::vector<std::vector<int> > *const shortcutTargets,
-            const std::vector<int> *const shortcutProbabilities)
-            : mCodePoints(), mCodePointCount(codePointCount),
-              mIsNotAWord(isNotAWord), mIsBlacklisted(isBlacklisted), mHasBigrams(hasBigrams),
-              mHasShortcuts(hasShortcuts), mProbability(probability), mTimestamp(timestamp),
-              mLevel(level), mCount(count), mShortcutTargets(*shortcutTargets),
-              mShortcutProbabilities(*shortcutProbabilities) {
-        memcpy(mCodePoints, codePoints, sizeof(mCodePoints));
-    }
-
-    void outputProperties(JNIEnv *const env, jintArray outCodePoints, jbooleanArray outFlags,
-            jintArray outProbability, jintArray outHistoricalInfo, jobject outShortcutTargets,
-            jobject outShortcutProbabilities) const;
-
- private:
-    DISALLOW_ASSIGNMENT_OPERATOR(UnigramProperty);
-
-    int mCodePoints[MAX_WORD_LENGTH];
-    int mCodePointCount;
-    bool mIsNotAWord;
-    bool mIsBlacklisted;
-    bool mHasBigrams;
-    bool mHasShortcuts;
-    int mProbability;
-    // Historical information
-    int mTimestamp;
-    int mLevel;
-    int mCount;
-    // Shortcut
-    std::vector<std::vector<int> > mShortcutTargets;
-    std::vector<int> mShortcutProbabilities;
-};
-} // namespace latinime
-#endif // LATINIME_UNIGRAM_PROPERTY_H
diff --git a/native/jni/src/suggest/core/dictionary/unigram_property.cpp b/native/jni/src/suggest/core/dictionary/word_property.cpp
similarity index 93%
rename from native/jni/src/suggest/core/dictionary/unigram_property.cpp
rename to native/jni/src/suggest/core/dictionary/word_property.cpp
index 16bbb69..ed32bde 100644
--- a/native/jni/src/suggest/core/dictionary/unigram_property.cpp
+++ b/native/jni/src/suggest/core/dictionary/word_property.cpp
@@ -14,14 +14,14 @@
  * limitations under the License.
  */
 
-#include "suggest/core/dictionary/unigram_property.h"
+#include "suggest/core/dictionary/word_property.h"
 
 namespace latinime {
 
-void UnigramProperty::outputProperties(JNIEnv *const env, jintArray outCodePoints,
+void WordProperty::outputProperties(JNIEnv *const env, jintArray outCodePoints,
         jbooleanArray outFlags, jintArray outProbability, jintArray outHistoricalInfo,
         jobject outShortcutTargets, jobject outShortcutProbabilities) const {
-    env->SetIntArrayRegion(outCodePoints, 0 /* start */, mCodePointCount, mCodePoints);
+    env->SetIntArrayRegion(outCodePoints, 0 /* start */, mCodePoints.size(), &mCodePoints[0]);
     jboolean flags[] = {mIsNotAWord, mIsBlacklisted, mHasBigrams, mHasShortcuts};
     env->SetBooleanArrayRegion(outFlags, 0 /* start */, NELEMS(flags), flags);
     env->SetIntArrayRegion(outProbability, 0 /* start */, 1 /* len */, &mProbability);
diff --git a/native/jni/src/suggest/core/dictionary/word_property.h b/native/jni/src/suggest/core/dictionary/word_property.h
new file mode 100644
index 0000000..dcac853
--- /dev/null
+++ b/native/jni/src/suggest/core/dictionary/word_property.h
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2013 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.
+ */
+
+#ifndef LATINIME_WORD_PROPERTY_H
+#define LATINIME_WORD_PROPERTY_H
+
+#include <cstring>
+#include <vector>
+
+#include "defines.h"
+#include "jni.h"
+
+namespace latinime {
+
+// This class is used for returning information belonging to a word to java side.
+class WordProperty {
+ public:
+    // TODO: Add bigram information.
+    // Invalid word.
+    WordProperty()
+            : mCodePoints(), mIsNotAWord(false), mIsBlacklisted(false),
+              mHasBigrams(false), mHasShortcuts(false), mProbability(NOT_A_PROBABILITY),
+              mTimestamp(0), mLevel(0), mCount(0), mShortcutTargets(), mShortcutProbabilities() {}
+
+    WordProperty(const std::vector<int> *const codePoints,
+            const bool isNotAWord, const bool isBlacklisted, const bool hasBigrams,
+            const bool hasShortcuts, const int probability, const int timestamp,
+            const int level, const int count,
+            const std::vector<std::vector<int> > *const shortcutTargets,
+            const std::vector<int> *const shortcutProbabilities)
+            : mCodePoints(*codePoints), mIsNotAWord(isNotAWord), mIsBlacklisted(isBlacklisted),
+              mHasBigrams(hasBigrams), mHasShortcuts(hasShortcuts), mProbability(probability),
+              mTimestamp(timestamp), mLevel(level), mCount(count),
+              mShortcutTargets(*shortcutTargets), mShortcutProbabilities(*shortcutProbabilities) {}
+
+    void outputProperties(JNIEnv *const env, jintArray outCodePoints, jbooleanArray outFlags,
+            jintArray outProbability, jintArray outHistoricalInfo, jobject outShortcutTargets,
+            jobject outShortcutProbabilities) const;
+
+ private:
+    DISALLOW_ASSIGNMENT_OPERATOR(WordProperty);
+
+    std::vector<int> mCodePoints;
+    bool mIsNotAWord;
+    bool mIsBlacklisted;
+    bool mHasBigrams;
+    bool mHasShortcuts;
+    int mProbability;
+    // Historical information
+    int mTimestamp;
+    int mLevel;
+    int mCount;
+    // Shortcut
+    std::vector<std::vector<int> > mShortcutTargets;
+    std::vector<int> mShortcutProbabilities;
+};
+} // namespace latinime
+#endif // LATINIME_WORD_PROPERTY_H
diff --git a/native/jni/src/suggest/core/policy/dictionary_structure_with_buffer_policy.h b/native/jni/src/suggest/core/policy/dictionary_structure_with_buffer_policy.h
index c74a4eb..b878984 100644
--- a/native/jni/src/suggest/core/policy/dictionary_structure_with_buffer_policy.h
+++ b/native/jni/src/suggest/core/policy/dictionary_structure_with_buffer_policy.h
@@ -18,7 +18,7 @@
 #define LATINIME_DICTIONARY_STRUCTURE_POLICY_H
 
 #include "defines.h"
-#include "suggest/core/dictionary/unigram_property.h"
+#include "suggest/core/dictionary/word_property.h"
 #include "utils/exclusive_ownership_pointer.h"
 
 namespace latinime {
@@ -92,7 +92,7 @@
             const int maxResultLength) = 0;
 
     // Used for testing.
-    virtual const UnigramProperty getUnigramProperty(const int *const codePonts,
+    virtual const WordProperty getWordProperty(const int *const codePonts,
             const int codePointCount) const = 0;
 
  protected:
diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/v2/patricia_trie_policy.h b/native/jni/src/suggest/policyimpl/dictionary/structure/v2/patricia_trie_policy.h
index 2adafd2..67d615e 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/structure/v2/patricia_trie_policy.h
+++ b/native/jni/src/suggest/policyimpl/dictionary/structure/v2/patricia_trie_policy.h
@@ -123,10 +123,10 @@
         }
     }
 
-    const UnigramProperty getUnigramProperty(const int *const codePoints,
+    const WordProperty getWordProperty(const int *const codePoints,
             const int codePointCount) const {
-        // getUnigramProperty is not supported.
-        return UnigramProperty();
+        // getWordProperty is not supported.
+        return WordProperty();
     }
 
  private:
diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_policy.cpp b/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_policy.cpp
index b4730fe..0b067e1 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_policy.cpp
+++ b/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_policy.cpp
@@ -20,7 +20,7 @@
 
 #include "suggest/core/dicnode/dic_node.h"
 #include "suggest/core/dicnode/dic_node_vector.h"
-#include "suggest/core/dictionary/unigram_property.h"
+#include "suggest/core/dictionary/word_property.h"
 #include "suggest/policyimpl/dictionary/structure/pt_common/dynamic_pt_reading_helper.h"
 #include "suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_node_reader.h"
 #include "suggest/policyimpl/dictionary/utils/forgetting_curve_utils.h"
@@ -317,15 +317,17 @@
     }
 }
 
-const UnigramProperty Ver4PatriciaTriePolicy::getUnigramProperty(const int *const codePoints,
+const WordProperty Ver4PatriciaTriePolicy::getWordProperty(const int *const codePoints,
         const int codePointCount) const {
     const int ptNodePos = getTerminalPtNodePositionOfWord(codePoints, codePointCount,
             false /* forceLowerCaseSearch */);
     if (ptNodePos == NOT_A_DICT_POS) {
-        AKLOGE("fetchUnigramProperty is called for invalid word.");
-        return UnigramProperty();
+        AKLOGE("getWordProperty is called for invalid word.");
+        return WordProperty();
     }
     const PtNodeParams ptNodeParams = mNodeReader.fetchNodeInfoInBufferFromPtNodePos(ptNodePos);
+    std::vector<int> codePointVector(ptNodeParams.getCodePoints(),
+            ptNodeParams.getCodePoints() + ptNodeParams.getCodePointCount());
     const ProbabilityEntry probabilityEntry =
             mBuffers.get()->getProbabilityDictContent()->getProbabilityEntry(
                     ptNodeParams.getTerminalId());
@@ -349,8 +351,8 @@
             shortcutProbabilities.push_back(shortcutProbability);
         }
     }
-    return UnigramProperty(ptNodeParams.getCodePoints(), ptNodeParams.getCodePointCount(),
-            ptNodeParams.isNotAWord(), ptNodeParams.isBlacklisted(), ptNodeParams.hasBigrams(),
+    return WordProperty(&codePointVector, ptNodeParams.isNotAWord(),
+            ptNodeParams.isBlacklisted(), ptNodeParams.hasBigrams(),
             ptNodeParams.hasShortcutTargets(), ptNodeParams.getProbability(),
             historicalInfo->getTimeStamp(), historicalInfo->getLevel(),
             historicalInfo->getCount(), &shortcutTargets, &shortcutProbabilities);
diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_policy.h b/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_policy.h
index 81aed20..a43bd0e 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_policy.h
+++ b/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_policy.h
@@ -106,7 +106,7 @@
     void getProperty(const char *const query, const int queryLength, char *const outResult,
             const int maxResultLength);
 
-    const UnigramProperty getUnigramProperty(const int *const codePoints,
+    const WordProperty getWordProperty(const int *const codePoints,
             const int codePointCount) const;
 
  private:
diff --git a/tests/src/com/android/inputmethod/latin/BinaryDictionaryTests.java b/tests/src/com/android/inputmethod/latin/BinaryDictionaryTests.java
index 73b6fdc..844fcbb 100644
--- a/tests/src/com/android/inputmethod/latin/BinaryDictionaryTests.java
+++ b/tests/src/com/android/inputmethod/latin/BinaryDictionaryTests.java
@@ -26,7 +26,7 @@
 import com.android.inputmethod.latin.makedict.FusionDictionary.WeightedString;
 import com.android.inputmethod.latin.utils.FileUtils;
 import com.android.inputmethod.latin.utils.LanguageModelParam;
-import com.android.inputmethod.latin.utils.UnigramProperty;
+import com.android.inputmethod.latin.utils.WordProperty;
 
 import java.io.File;
 import java.io.IOException;
@@ -892,8 +892,7 @@
                 0 /* offset */, dictFile.length(), true /* useFullEditDistance */,
                 Locale.getDefault(), TEST_LOCALE, true /* isUpdatable */);
 
-        final UnigramProperty invalidUnigramProperty =
-                binaryDictionary.getUnigramProperty("dummyWord");
+        final WordProperty invalidUnigramProperty = binaryDictionary.getWordProperty("dummyWord");
         assertFalse(invalidUnigramProperty.isValid());
 
         for (int i = 0; i < ITERATION_COUNT; i++) {
@@ -905,8 +904,7 @@
             binaryDictionary.addUnigramWord(word, unigramProbability,
                     null /* shortcutTarget */, BinaryDictionary.NOT_A_PROBABILITY,
                     isNotAWord, isBlacklisted, BinaryDictionary.NOT_A_VALID_TIMESTAMP);
-            final UnigramProperty unigramProperty =
-                    binaryDictionary.getUnigramProperty(word);
+            final WordProperty unigramProperty = binaryDictionary.getWordProperty(word);
             assertEquals(word, unigramProperty.mCodePoints);
             assertTrue(unigramProperty.isValid());
             assertEquals(isNotAWord, unigramProperty.mIsNotAWord);
@@ -938,7 +936,7 @@
         binaryDictionary.addUnigramWord("aaa", unigramProbability, "zzz",
                 shortcutProbability, false /* isNotAWord */, false /* isBlacklisted */,
                 0 /* timestamp */);
-        UnigramProperty unigramProperty = binaryDictionary.getUnigramProperty("aaa");
+        WordProperty unigramProperty = binaryDictionary.getWordProperty("aaa");
         assertEquals(1, unigramProperty.mShortcutTargets.size());
         assertEquals("zzz", unigramProperty.mShortcutTargets.get(0).mWord);
         assertEquals(shortcutProbability, unigramProperty.mShortcutTargets.get(0).mFrequency);
@@ -946,7 +944,7 @@
         binaryDictionary.addUnigramWord("aaa", unigramProbability, "zzz",
                 updatedShortcutProbability, false /* isNotAWord */, false /* isBlacklisted */,
                 0 /* timestamp */);
-        unigramProperty = binaryDictionary.getUnigramProperty("aaa");
+        unigramProperty = binaryDictionary.getWordProperty("aaa");
         assertEquals(1, unigramProperty.mShortcutTargets.size());
         assertEquals("zzz", unigramProperty.mShortcutTargets.get(0).mWord);
         assertEquals(updatedShortcutProbability,
@@ -957,7 +955,7 @@
         final HashMap<String, Integer> shortcutTargets = new HashMap<String, Integer>();
         shortcutTargets.put("zzz", updatedShortcutProbability);
         shortcutTargets.put("yyy", shortcutProbability);
-        unigramProperty = binaryDictionary.getUnigramProperty("aaa");
+        unigramProperty = binaryDictionary.getWordProperty("aaa");
         assertEquals(2, unigramProperty.mShortcutTargets.size());
         for (WeightedString shortcutTarget : unigramProperty.mShortcutTargets) {
             assertTrue(shortcutTargets.containsKey(shortcutTarget.mWord));
@@ -967,7 +965,7 @@
         shortcutTargets.put("zzz", updatedShortcutProbability);
         shortcutTargets.put("yyy", shortcutProbability);
         binaryDictionary.flushWithGC();
-        unigramProperty = binaryDictionary.getUnigramProperty("aaa");
+        unigramProperty = binaryDictionary.getWordProperty("aaa");
         assertEquals(2, unigramProperty.mShortcutTargets.size());
         for (WeightedString shortcutTarget : unigramProperty.mShortcutTargets) {
             assertTrue(shortcutTargets.containsKey(shortcutTarget.mWord));
@@ -1036,7 +1034,7 @@
         }
 
         for (final String word : words) {
-            final UnigramProperty unigramProperty = binaryDictionary.getUnigramProperty(word);
+            final WordProperty unigramProperty = binaryDictionary.getWordProperty(word);
             assertEquals((int)unigramProbabilities.get(word), unigramProperty.mProbability);
             if (!shortcutTargets.containsKey(word)) {
                 // The word does not have shortcut targets.
diff --git a/tools/make-keyboard-text/res/values-fa/donottranslate-more-keys.xml b/tools/make-keyboard-text/res/values-fa/donottranslate-more-keys.xml
index 5bcfe7f..a053a88 100644
--- a/tools/make-keyboard-text/res/values-fa/donottranslate-more-keys.xml
+++ b/tools/make-keyboard-text/res/values-fa/donottranslate-more-keys.xml
@@ -87,7 +87,6 @@
     <string name="keylabel_for_tablet_comma">"&#x060C;"</string>
     <string name="keyhintlabel_for_tablet_comma">"&#x061F;"</string>
     <string name="more_keys_for_tablet_comma">"!fixedColumnOrder!4,:,!,&#x061F;,&#x061B;,-,/,&#x00AB;|&#x00BB;,&#x00BB;|&#x00AB;"</string>
-    <string name="keyhintlabel_for_period">"&#x061F;"</string>
     <!-- U+FDFC: "﷼" RIAL SIGN -->
     <string name="keylabel_for_currency">&#xFDFC;</string>
     <!-- U+061F: "؟" ARABIC QUESTION MARK