diff --git a/java-overridable/src/com/android/inputmethod/latin/define/ProductionFlags.java b/java-overridable/src/com/android/inputmethod/latin/define/ProductionFlags.java
index f80625644f39266ab402b4ff53f05661e2c8222d..43675682de6b23189f01483b039015fb7cca9062 100644
--- a/java-overridable/src/com/android/inputmethod/latin/define/ProductionFlags.java
+++ b/java-overridable/src/com/android/inputmethod/latin/define/ProductionFlags.java
@@ -48,4 +48,10 @@ public final class ProductionFlags {
      * When {@code true}, personal dictionary sync feature is ready to be enabled.
      */
     public static final boolean ENABLE_PERSONAL_DICTIONARY_SYNC = ENABLE_ACCOUNT_SIGN_IN && false;
+
+    /**
+     * When {@code true}, the IME maintains per account {@link UserHistoryDictionary}.
+     */
+    public static final boolean ENABLE_PER_ACCOUNT_USER_HISTORY_DICTIONARY =
+            ENABLE_ACCOUNT_SIGN_IN && false;
 }
diff --git a/java/src/com/android/inputmethod/latin/personalization/PersonalizationHelper.java b/java/src/com/android/inputmethod/latin/personalization/PersonalizationHelper.java
index ac2fc07c2524099fd77b579c0ba7c10da4b58352..8c5eb0aa73c7cd07ddcb6db779359a7c21d23831 100644
--- a/java/src/com/android/inputmethod/latin/personalization/PersonalizationHelper.java
+++ b/java/src/com/android/inputmethod/latin/personalization/PersonalizationHelper.java
@@ -28,32 +28,45 @@ import java.util.Locale;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.TimeUnit;
 
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
+/**
+ * Helps handle and manage personalized dictionaries such as {@link UserHistoryDictionary} and
+ * {@link PersonalizationDictionary}.
+ */
 public class PersonalizationHelper {
     private static final String TAG = PersonalizationHelper.class.getSimpleName();
     private static final boolean DEBUG = false;
+
     private static final ConcurrentHashMap<String, SoftReference<UserHistoryDictionary>>
             sLangUserHistoryDictCache = new ConcurrentHashMap<>();
     private static final ConcurrentHashMap<String, SoftReference<PersonalizationDictionary>>
             sLangPersonalizationDictCache = new ConcurrentHashMap<>();
 
+    @Nonnull
     public static UserHistoryDictionary getUserHistoryDictionary(
-            final Context context, final Locale locale) {
-        final String localeStr = locale.toString();
+            final Context context, final Locale locale, @Nullable final String accountName) {
+        String lookupStr = locale.toString();
+        if (accountName != null) {
+            lookupStr += "." + accountName;
+        }
         synchronized (sLangUserHistoryDictCache) {
-            if (sLangUserHistoryDictCache.containsKey(localeStr)) {
+            if (sLangUserHistoryDictCache.containsKey(lookupStr)) {
                 final SoftReference<UserHistoryDictionary> ref =
-                        sLangUserHistoryDictCache.get(localeStr);
+                        sLangUserHistoryDictCache.get(lookupStr);
                 final UserHistoryDictionary dict = ref == null ? null : ref.get();
                 if (dict != null) {
                     if (DEBUG) {
-                        Log.w(TAG, "Use cached UserHistoryDictionary for " + locale);
+                        Log.d(TAG, "Use cached UserHistoryDictionary for " + locale +
+                                " & account" + accountName);
                     }
                     dict.reloadDictionaryIfRequired();
                     return dict;
                 }
             }
             final UserHistoryDictionary dict = new UserHistoryDictionary(context, locale);
-            sLangUserHistoryDictCache.put(localeStr, new SoftReference<>(dict));
+            sLangUserHistoryDictCache.put(lookupStr, new SoftReference<>(dict));
             return dict;
         }
     }
diff --git a/java/src/com/android/inputmethod/latin/personalization/UserHistoryDictionary.java b/java/src/com/android/inputmethod/latin/personalization/UserHistoryDictionary.java
index 58782c646973567efdc531564e97f5979efc5a66..946835cbc8c00b550aab3453281a0b2098e3ebbf 100644
--- a/java/src/com/android/inputmethod/latin/personalization/UserHistoryDictionary.java
+++ b/java/src/com/android/inputmethod/latin/personalization/UserHistoryDictionary.java
@@ -17,30 +17,73 @@
 package com.android.inputmethod.latin.personalization;
 
 import android.content.Context;
+import android.content.SharedPreferences;
+import android.preference.PreferenceManager;
 
 import com.android.inputmethod.annotations.ExternallyReferenced;
+import com.android.inputmethod.annotations.UsedForTesting;
 import com.android.inputmethod.latin.Dictionary;
 import com.android.inputmethod.latin.ExpandableBinaryDictionary;
 import com.android.inputmethod.latin.NgramContext;
 import com.android.inputmethod.latin.common.Constants;
+import com.android.inputmethod.latin.define.ProductionFlags;
+import com.android.inputmethod.latin.settings.LocalSettingsConstants;
 import com.android.inputmethod.latin.utils.DistracterFilter;
 
 import java.io.File;
 import java.util.Locale;
 
 import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
 
 /**
  * Locally gathers stats about the words user types and various other signals like auto-correction
  * cancellation or manual picks. This allows the keyboard to adapt to the typist over time.
  */
 public class UserHistoryDictionary extends DecayingExpandableBinaryDictionaryBase {
-    /* package */ static final String NAME = UserHistoryDictionary.class.getSimpleName();
+    static final String NAME = UserHistoryDictionary.class.getSimpleName();
 
     // TODO: Make this constructor private
-    /* package */ UserHistoryDictionary(final Context context, final Locale locale) {
-        super(context, getDictName(NAME, locale, null /* dictFile */), locale,
-                Dictionary.TYPE_USER_HISTORY, null /* dictFile */);
+    UserHistoryDictionary(final Context context, final Locale locale) {
+        super(context,
+                getUserHistoryDictName(
+                        NAME,
+                        locale,
+                        null /* dictFile */,
+                        context),
+                locale,
+                Dictionary.TYPE_USER_HISTORY,
+                null /* dictFile */);
+    }
+
+    /**
+     * @returns the name of the {@link UserHistoryDictionary}.
+     */
+    @UsedForTesting
+    static String getUserHistoryDictName(final String name, final Locale locale,
+            @Nullable final File dictFile, final Context context) {
+        if (!ProductionFlags.ENABLE_PER_ACCOUNT_USER_HISTORY_DICTIONARY) {
+            return getDictName(name, locale, dictFile);
+        }
+        return getUserHistoryDictNamePerAccount(name, locale, dictFile, context);
+    }
+
+    /**
+     * Uses the currently signed in account to determine the dictionary name.
+     */
+    private static String getUserHistoryDictNamePerAccount(final String name, final Locale locale,
+            @Nullable final File dictFile, final Context context) {
+        if (dictFile != null) {
+            return dictFile.getName();
+        }
+        final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
+        final String account = prefs.getString(LocalSettingsConstants.PREF_ACCOUNT_NAME,
+                null /* default */);
+        String dictName = name + "." + locale.toString();
+        if (account != null) {
+            dictName += "." + account;
+        }
+        return dictName;
     }
 
     // Note: This method is called by {@link DictionaryFacilitator} using Java reflection.
@@ -48,7 +91,14 @@ public class UserHistoryDictionary extends DecayingExpandableBinaryDictionaryBas
     @ExternallyReferenced
     public static UserHistoryDictionary getDictionary(final Context context, final Locale locale,
             final File dictFile, final String dictNamePrefix) {
-        return PersonalizationHelper.getUserHistoryDictionary(context, locale);
+        final String account;
+        if (ProductionFlags.ENABLE_PER_ACCOUNT_USER_HISTORY_DICTIONARY) {
+            account = PreferenceManager.getDefaultSharedPreferences(context)
+                    .getString(LocalSettingsConstants.PREF_ACCOUNT_NAME, null /* default */);
+        } else {
+            account = null;
+        }
+        return PersonalizationHelper.getUserHistoryDictionary(context, locale, account);
     }
 
     /**
diff --git a/tests/src/com/android/inputmethod/latin/personalization/UserHistoryDictionaryTests.java b/tests/src/com/android/inputmethod/latin/personalization/UserHistoryDictionaryTests.java
index 813a712393bae903a707e7620cdd0fa32947956b..a84df28c944bc0b52e2bb4ec44f5577012289099 100644
--- a/tests/src/com/android/inputmethod/latin/personalization/UserHistoryDictionaryTests.java
+++ b/tests/src/com/android/inputmethod/latin/personalization/UserHistoryDictionaryTests.java
@@ -16,6 +16,8 @@
 
 package com.android.inputmethod.latin.personalization;
 
+import android.content.SharedPreferences;
+import android.preference.PreferenceManager;
 import android.test.AndroidTestCase;
 import android.test.suitebuilder.annotation.LargeTest;
 import android.util.Log;
@@ -24,6 +26,7 @@ import com.android.inputmethod.latin.ExpandableBinaryDictionary;
 import com.android.inputmethod.latin.NgramContext;
 import com.android.inputmethod.latin.NgramContext.WordInfo;
 import com.android.inputmethod.latin.common.FileUtils;
+import com.android.inputmethod.latin.settings.LocalSettingsConstants;
 import com.android.inputmethod.latin.utils.BinaryDictionaryUtils;
 import com.android.inputmethod.latin.utils.DistracterFilter;
 
@@ -36,6 +39,8 @@ import java.util.Locale;
 import java.util.Random;
 import java.util.concurrent.TimeUnit;
 
+import javax.annotation.Nullable;
+
 /**
  * Unit tests for UserHistoryDictionary
  */
@@ -44,6 +49,7 @@ public class UserHistoryDictionaryTests extends AndroidTestCase {
     private static final String TAG = UserHistoryDictionaryTests.class.getSimpleName();
     private static final int WAIT_FOR_WRITING_FILE_IN_MILLISECONDS = 3000;
     private static final String TEST_LOCALE_PREFIX = "test_";
+    private static final String TEST_ACCOUNT = "account@example.com";
 
     private static final String[] CHARACTERS = {
         "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m",
@@ -52,15 +58,18 @@ public class UserHistoryDictionaryTests extends AndroidTestCase {
 
     private int mCurrentTime = 0;
 
+    private SharedPreferences mPrefs;
+    private String mLastKnownAccount = null;
+
     private void removeAllTestDictFiles() {
         final Locale dummyLocale = new Locale(TEST_LOCALE_PREFIX);
-        final String dictName = ExpandableBinaryDictionary.getDictName(
-                UserHistoryDictionary.NAME, dummyLocale, null /* dictFile */);
+        final String dictName = UserHistoryDictionary.getUserHistoryDictName(
+                UserHistoryDictionary.NAME, dummyLocale, null /* dictFile */, getContext());
         final File dictFile = ExpandableBinaryDictionary.getDictFile(
                 mContext, dictName, null /* dictFile */);
         final FilenameFilter filenameFilter = new FilenameFilter() {
             @Override
-            public boolean accept(File dir, String filename) {
+            public boolean accept(final File dir, final String filename) {
                 return filename.startsWith(UserHistoryDictionary.NAME + "." + TEST_LOCALE_PREFIX);
             }
         };
@@ -99,6 +108,12 @@ public class UserHistoryDictionaryTests extends AndroidTestCase {
     @Override
     protected void setUp() throws Exception {
         super.setUp();
+
+        mPrefs = PreferenceManager.getDefaultSharedPreferences(getContext());
+        // Keep track of the current account so that we restore it when the test finishes.
+        mLastKnownAccount = mPrefs.getString(LocalSettingsConstants.PREF_ACCOUNT_NAME, null);
+        updateAccountName(TEST_ACCOUNT);
+
         resetCurrentTimeForTestMode();
         removeAllTestDictFiles();
     }
@@ -107,6 +122,10 @@ public class UserHistoryDictionaryTests extends AndroidTestCase {
     protected void tearDown() throws Exception {
         removeAllTestDictFiles();
         stopTestModeInNativeCode();
+
+        // Restore the account that was present before running the test.
+        updateAccountName(mLastKnownAccount);
+
         super.tearDown();
     }
 
@@ -115,6 +134,14 @@ public class UserHistoryDictionaryTests extends AndroidTestCase {
         setCurrentTimeForTestMode(mCurrentTime);
     }
 
+    private void updateAccountName(@Nullable final String accountName) {
+        if (accountName == null) {
+            mPrefs.edit().remove(LocalSettingsConstants.PREF_ACCOUNT_NAME).apply();
+        } else {
+            mPrefs.edit().putString(LocalSettingsConstants.PREF_ACCOUNT_NAME, accountName).apply();
+        }
+    }
+
     private void forcePassingShortTime() {
         // 3 days.
         final int timeToElapse = (int)TimeUnit.DAYS.toSeconds(3);
@@ -142,7 +169,7 @@ public class UserHistoryDictionaryTests extends AndroidTestCase {
      */
     private static String generateWord(final int value) {
         final int lengthOfChars = CHARACTERS.length;
-        StringBuilder builder = new StringBuilder();
+        final StringBuilder builder = new StringBuilder();
         long lvalue = Math.abs((long)value);
         while (lvalue > 0) {
             builder.append(CHARACTERS[(int)(lvalue % lengthOfChars)]);
@@ -162,7 +189,7 @@ public class UserHistoryDictionaryTests extends AndroidTestCase {
     private static void addToDict(final UserHistoryDictionary dict, final List<String> words,
             final int timestamp) {
         NgramContext ngramContext = NgramContext.EMPTY_PREV_WORDS_INFO;
-        for (String word : words) {
+        for (final String word : words) {
             UserHistoryDictionary.addToDictionary(dict, ngramContext, word, true, timestamp,
                     DistracterFilter.EMPTY_DISTRACTER_FILTER);
             ngramContext = ngramContext.getNextNgramContext(new WordInfo(word));
@@ -204,12 +231,12 @@ public class UserHistoryDictionaryTests extends AndroidTestCase {
         Log.d(TAG, "This test can be used for profiling.");
         Log.d(TAG, "Usage: please set UserHistoryDictionary.PROFILE_SAVE_RESTORE to true.");
         final Locale dummyLocale = getDummyLocale("random_words");
-        final String dictName = ExpandableBinaryDictionary.getDictName(
-                UserHistoryDictionary.NAME, dummyLocale, null /* dictFile */);
+        final String dictName = UserHistoryDictionary.getUserHistoryDictName(
+                UserHistoryDictionary.NAME, dummyLocale, null /* dictFile */, getContext());
         final File dictFile = ExpandableBinaryDictionary.getDictFile(
                 mContext, dictName, null /* dictFile */);
         final UserHistoryDictionary dict = PersonalizationHelper.getUserHistoryDictionary(
-                getContext(), dummyLocale);
+                getContext(), dummyLocale, TEST_ACCOUNT);
 
         final int numberOfWords = 1000;
         final Random random = new Random(123456);
@@ -232,12 +259,12 @@ public class UserHistoryDictionaryTests extends AndroidTestCase {
             // Create filename suffixes for this test.
             for (int i = 0; i < numberOfLanguages; i++) {
                 final Locale dummyLocale = getDummyLocale("switching_languages" + i);
-                final String dictName = ExpandableBinaryDictionary.getDictName(
-                        UserHistoryDictionary.NAME, dummyLocale, null /* dictFile */);
+                final String dictName = UserHistoryDictionary.getUserHistoryDictName(
+                        UserHistoryDictionary.NAME, dummyLocale, null /* dictFile */, getContext());
                 dictFiles[i] = ExpandableBinaryDictionary.getDictFile(
                         mContext, dictName, null /* dictFile */);
                 dicts[i] = PersonalizationHelper.getUserHistoryDictionary(getContext(),
-                        dummyLocale);
+                        dummyLocale, TEST_ACCOUNT);
                 clearHistory(dicts[i]);
             }
 
@@ -262,14 +289,14 @@ public class UserHistoryDictionaryTests extends AndroidTestCase {
 
     public void testAddManyWords() {
         final Locale dummyLocale = getDummyLocale("many_random_words");
-        final String dictName = ExpandableBinaryDictionary.getDictName(
-                UserHistoryDictionary.NAME, dummyLocale, null /* dictFile */);
+        final String dictName = UserHistoryDictionary.getUserHistoryDictName(
+                UserHistoryDictionary.NAME, dummyLocale, null /* dictFile */, getContext());
         final File dictFile = ExpandableBinaryDictionary.getDictFile(
                 mContext, dictName, null /* dictFile */);
         final int numberOfWords = 10000;
         final Random random = new Random(123456);
         final UserHistoryDictionary dict = PersonalizationHelper.getUserHistoryDictionary(
-                getContext(), dummyLocale);
+                getContext(), dummyLocale, TEST_ACCOUNT);
         clearHistory(dict);
         try {
             addAndWriteRandomWords(dict, numberOfWords, random, true /* checksContents */);
@@ -281,7 +308,7 @@ public class UserHistoryDictionaryTests extends AndroidTestCase {
     public void testDecaying() {
         final Locale dummyLocale = getDummyLocale("decaying");
         final UserHistoryDictionary dict = PersonalizationHelper.getUserHistoryDictionary(
-                getContext(), dummyLocale);
+                getContext(), dummyLocale, TEST_ACCOUNT);
         final int numberOfWords = 5000;
         final Random random = new Random(123456);
         resetCurrentTimeForTestMode();
@@ -309,4 +336,9 @@ public class UserHistoryDictionaryTests extends AndroidTestCase {
             assertFalse(dict.isInDictionary(word));
         }
     }
-}
+
+    public void testRandomWords_NullAccount() {
+        updateAccountName(null);
+        testRandomWords();
+    }
+}
\ No newline at end of file