am 724db044: Deallocate gesture trail bitmap when unneeded further

* commit '724db044957eb3544323c9814cbb4f20e81b8594':
  Deallocate gesture trail bitmap when unneeded further
diff --git a/java/res/layout/input_view.xml b/java/res/layout/input_view.xml
index 1ffb8a3..78217b0 100644
--- a/java/res/layout/input_view.xml
+++ b/java/res/layout/input_view.xml
@@ -23,13 +23,8 @@
     android:orientation="vertical"
     android:layout_width="match_parent"
     android:layout_height="wrap_content"
+    android:gravity="bottom|center_horizontal"
 >
-    <!-- The height of key_preview_backing view will automatically be determined by code. -->
-    <View
-        android:id="@+id/key_preview_backing"
-        android:layout_width="match_parent"
-        android:layout_height="0dp" />
-
     <!-- To ensure that key preview popup is correctly placed when the current system locale is
          one of RTL locales, layoutDirection="ltr" is needed in the SDK version 17+. -->
     <com.android.inputmethod.latin.suggestions.SuggestionStripView
@@ -37,17 +32,14 @@
         android:layoutDirection="ltr"
         android:layout_width="match_parent"
         android:layout_height="@dimen/suggestions_strip_height"
-        android:gravity="center_vertical"
         android:paddingRight="@dimen/suggestions_strip_padding"
         android:paddingLeft="@dimen/suggestions_strip_padding"
         style="?attr/suggestionStripViewStyle" />
-
     <!-- To ensure that key preview popup is correctly placed when the current system locale is
          one of RTL locales, layoutDirection="ltr" is needed in the SDK version 17+. -->
     <com.android.inputmethod.keyboard.MainKeyboardView
         android:id="@+id/keyboard_view"
         android:layoutDirection="ltr"
-        android:layout_alignParentBottom="true"
-        android:layout_width="match_parent"
+        android:layout_width="wrap_content"
         android:layout_height="wrap_content" />
 </com.android.inputmethod.latin.InputView>
diff --git a/java/res/values-ka/strings-appname.xml b/java/res/values-ka/strings-appname.xml
deleted file mode 100644
index 703c66a..0000000
--- a/java/res/values-ka/strings-appname.xml
+++ /dev/null
@@ -1,27 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- 
-/*
-**
-** Copyright 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.
-*/
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="english_ime_name" msgid="5940510615957428904">"Android-ის კლავიატურა (AOSP)"</string>
-    <string name="spell_checker_service_name" msgid="1254221805440242662">"Android-ის მართლწერის შემმოწმებელი (AOSP)"</string>
-    <string name="english_ime_settings" msgid="5760361067176802794">"Android-ის კლავიატურის პარამეტრები (AOSP)"</string>
-    <string name="android_spell_checker_settings" msgid="6123949487832861885">"Android-ის მართლწერის შემმოწმებლის პარამეტრები (AOSP)"</string>
-</resources>
diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardView.java b/java/src/com/android/inputmethod/keyboard/KeyboardView.java
index 054c503..28eb585 100644
--- a/java/src/com/android/inputmethod/keyboard/KeyboardView.java
+++ b/java/src/com/android/inputmethod/keyboard/KeyboardView.java
@@ -196,13 +196,14 @@
 
     @Override
     protected void onMeasure(final int widthMeasureSpec, final int heightMeasureSpec) {
-        if (mKeyboard != null) {
-            // The main keyboard expands to the display width.
-            final int height = mKeyboard.mOccupiedHeight + getPaddingTop() + getPaddingBottom();
-            setMeasuredDimension(widthMeasureSpec, height);
-        } else {
+        if (mKeyboard == null) {
             super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+            return;
         }
+        // The main keyboard expands to the entire this {@link KeyboardView}.
+        final int width = mKeyboard.mOccupiedWidth + getPaddingLeft() + getPaddingRight();
+        final int height = mKeyboard.mOccupiedHeight + getPaddingTop() + getPaddingBottom();
+        setMeasuredDimension(width, height);
     }
 
     @Override
diff --git a/java/src/com/android/inputmethod/latin/BinaryDictionaryGetter.java b/java/src/com/android/inputmethod/latin/BinaryDictionaryGetter.java
index fa301b5..d0a4afd 100644
--- a/java/src/com/android/inputmethod/latin/BinaryDictionaryGetter.java
+++ b/java/src/com/android/inputmethod/latin/BinaryDictionaryGetter.java
@@ -235,7 +235,7 @@
                     new BinaryDictInputOutput.ByteBufferWrapper(inStream.getChannel().map(
                             FileChannel.MapMode.READ_ONLY, 0, f.length()));
             final int magic = buffer.readInt();
-            if (magic != FormatSpec.VERSION_2_MAGIC_NUMBER) {
+            if (magic != FormatSpec.MAGIC_NUMBER) {
                 return false;
             }
             final int formatVersion = buffer.readInt();
diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java
index 5c5b7b7..08a5429 100644
--- a/java/src/com/android/inputmethod/latin/LatinIME.java
+++ b/java/src/com/android/inputmethod/latin/LatinIME.java
@@ -31,7 +31,6 @@
 import android.content.pm.PackageInfo;
 import android.content.res.Configuration;
 import android.content.res.Resources;
-import android.graphics.Rect;
 import android.inputmethodservice.InputMethodService;
 import android.media.AudioManager;
 import android.net.ConnectivityManager;
@@ -51,7 +50,6 @@
 import android.view.KeyCharacterMap;
 import android.view.KeyEvent;
 import android.view.View;
-import android.view.ViewGroup.LayoutParams;
 import android.view.Window;
 import android.view.WindowManager;
 import android.view.inputmethod.CompletionInfo;
@@ -150,8 +148,8 @@
 
     private final Settings mSettings;
 
-    private View mExtractArea;
-    private View mKeyPreviewBackingView;
+    private View mInputView;
+    private int mInputViewMinHeight;
     private SuggestionStripView mSuggestionStripView;
     // Never null
     private SuggestedWords mSuggestedWords = SuggestedWords.EMPTY;
@@ -660,17 +658,25 @@
         return mKeyboardSwitcher.onCreateInputView(mIsHardwareAcceleratedDrawingEnabled);
     }
 
+    private void setInputViewMinHeight(final int minHeight) {
+        if (mInputView != null && mInputViewMinHeight != minHeight) {
+            mInputView.setMinimumHeight(minHeight);
+            mInputViewMinHeight = minHeight;
+        }
+    }
+
     @Override
-    public void setInputView(final View view) {
-        super.setInputView(view);
-        mExtractArea = getWindow().getWindow().getDecorView()
-                .findViewById(android.R.id.extractArea);
-        mKeyPreviewBackingView = view.findViewById(R.id.key_preview_backing);
-        mSuggestionStripView = (SuggestionStripView)view.findViewById(R.id.suggestion_strip_view);
-        if (mSuggestionStripView != null)
-            mSuggestionStripView.setListener(this, view);
+    public void setInputView(final View inputView) {
+        super.setInputView(inputView);
+        mInputView = inputView;
+        setInputViewMinHeight(0);
+        mSuggestionStripView = (SuggestionStripView)inputView.findViewById(
+                R.id.suggestion_strip_view);
+        if (mSuggestionStripView != null) {
+            mSuggestionStripView.setListener(this, inputView);
+        }
         if (LatinImeLogger.sVISUALDEBUG) {
-            mKeyPreviewBackingView.setBackgroundColor(0x10FF0000);
+            inputView.setBackgroundColor(0x10FF0000);
         }
     }
 
@@ -1122,6 +1128,11 @@
                 mSuggestionStripView.setVisibility(
                         shouldShowSuggestions ? View.VISIBLE : View.INVISIBLE);
             }
+            if (shouldShowSuggestions && mainKeyboardView != null) {
+                final int remainingHeight = getWindow().getWindow().getDecorView().getHeight()
+                        - mainKeyboardView.getHeight() - mSuggestionStripView.getHeight();
+                mSuggestionStripView.setMoreSuggestionsHeight(remainingHeight);
+            }
         }
     }
 
@@ -1129,31 +1140,6 @@
         setSuggestionStripShownInternal(shown, /* needsInputViewShown */true);
     }
 
-    private int getAdjustedBackingViewHeight() {
-        final int currentHeight = mKeyPreviewBackingView.getHeight();
-        if (currentHeight > 0) {
-            return currentHeight;
-        }
-
-        final MainKeyboardView mainKeyboardView = mKeyboardSwitcher.getMainKeyboardView();
-        if (mainKeyboardView == null) {
-            return 0;
-        }
-        final int keyboardHeight = mainKeyboardView.getHeight();
-        final int suggestionsHeight = mSuggestionStripView.getHeight();
-        final int displayHeight = getResources().getDisplayMetrics().heightPixels;
-        final Rect rect = new Rect();
-        mKeyPreviewBackingView.getWindowVisibleDisplayFrame(rect);
-        final int notificationBarHeight = rect.top;
-        final int remainingHeight = displayHeight - notificationBarHeight - suggestionsHeight
-                - keyboardHeight;
-
-        final LayoutParams params = mKeyPreviewBackingView.getLayoutParams();
-        params.height = mSuggestionStripView.setMoreSuggestionsHeight(remainingHeight);
-        mKeyPreviewBackingView.setLayoutParams(params);
-        return params.height;
-    }
-
     @Override
     public void onComputeInsets(final InputMethodService.Insets outInsets) {
         super.onComputeInsets(outInsets);
@@ -1161,32 +1147,30 @@
         if (mainKeyboardView == null || mSuggestionStripView == null) {
             return;
         }
-        final int adjustedBackingHeight = getAdjustedBackingViewHeight();
-        final boolean backingGone = (mKeyPreviewBackingView.getVisibility() == View.GONE);
-        final int backingHeight = backingGone ? 0 : adjustedBackingHeight;
-        // In fullscreen mode, the height of the extract area managed by InputMethodService should
-        // be considered.
-        // See {@link android.inputmethodservice.InputMethodService#onComputeInsets}.
-        final int extractHeight = isFullscreenMode() ? mExtractArea.getHeight() : 0;
-        final int suggestionsHeight = (mSuggestionStripView.getVisibility() == View.GONE) ? 0
-                : mSuggestionStripView.getHeight();
-        final int extraHeight = extractHeight + backingHeight + suggestionsHeight;
-        int visibleTopY = extraHeight;
+        // This method is never called when in fullscreen mode.
+        // The contentTop is the top coordinate of the keyboard. The application behind will be
+        // resized/panned above this coordibnate to be able to show an input field.
+        final int contentTop = mInputView.getHeight() - mainKeyboardView.getHeight();
+        final int suggestionsHeight = (mSuggestionStripView.getVisibility() == View.VISIBLE)
+                ? mSuggestionStripView.getHeight() : 0;
+        // The visibleTop is the top coordinates of the visible part of this IME. The application
+        // behind will never be resized, but may be panned or scrolled.
+        final int visibleTop = mainKeyboardView.isShowingMoreKeysPanel() ? 0
+                : contentTop - suggestionsHeight;
+        outInsets.contentTopInsets = contentTop;
+        outInsets.visibleTopInsets = visibleTop;
         // Need to set touchable region only if input view is being shown
         if (mainKeyboardView.isShown()) {
-            if (mSuggestionStripView.getVisibility() == View.VISIBLE) {
-                visibleTopY -= suggestionsHeight;
-            }
-            final int touchY = mainKeyboardView.isShowingMoreKeysPanel() ? 0 : visibleTopY;
-            final int touchWidth = mainKeyboardView.getWidth();
-            final int touchHeight = mainKeyboardView.getHeight() + extraHeight
+            final int touchLeft = 0;
+            final int touchTop = visibleTop;
+            final int touchRight = touchLeft + mainKeyboardView.getWidth();
+            final int touchBottom = contentTop + mainKeyboardView.getHeight()
                     // Extend touchable region below the keyboard.
                     + EXTENDED_TOUCHABLE_REGION_HEIGHT;
+            // The touch event on touchableRegion will be delivered to this IME.
+            outInsets.touchableRegion.set(touchLeft, touchTop, touchRight, touchBottom);
             outInsets.touchableInsets = InputMethodService.Insets.TOUCHABLE_INSETS_REGION;
-            outInsets.touchableRegion.set(0, touchY, touchWidth, touchHeight);
         }
-        outInsets.contentTopInsets = visibleTopY;
-        outInsets.visibleTopInsets = visibleTopY;
     }
 
     @Override
@@ -1209,11 +1193,11 @@
     @Override
     public void updateFullscreenMode() {
         super.updateFullscreenMode();
-
-        if (mKeyPreviewBackingView == null) return;
-        // In fullscreen mode, no need to have extra space to show the key preview.
-        // If not, we should have extra space above the keyboard to show the key preview.
-        mKeyPreviewBackingView.setVisibility(isFullscreenMode() ? View.GONE : View.VISIBLE);
+        if (!isFullscreenMode()) {
+            // Expand the input view to cover entire display to be able to show key previews and
+            // more suggestions view that may be displayed above the keyboard.
+            setInputViewMinHeight(getResources().getDisplayMetrics().heightPixels);
+        }
     }
 
     // This will reset the whole input state to the starting state. It will clear
diff --git a/java/src/com/android/inputmethod/latin/makedict/BinaryDictInputOutput.java b/java/src/com/android/inputmethod/latin/makedict/BinaryDictInputOutput.java
index 1b187d8..e2fa023 100644
--- a/java/src/com/android/inputmethod/latin/makedict/BinaryDictInputOutput.java
+++ b/java/src/com/android/inputmethod/latin/makedict/BinaryDictInputOutput.java
@@ -1210,49 +1210,38 @@
         ByteArrayOutputStream headerBuffer = new ByteArrayOutputStream(256);
 
         // The magic number in big-endian order.
-        if (version >= FormatSpec.FIRST_VERSION_WITH_HEADER_SIZE) {
-            // Magic number for version 2+.
-            headerBuffer.write((byte) (0xFF & (FormatSpec.VERSION_2_MAGIC_NUMBER >> 24)));
-            headerBuffer.write((byte) (0xFF & (FormatSpec.VERSION_2_MAGIC_NUMBER >> 16)));
-            headerBuffer.write((byte) (0xFF & (FormatSpec.VERSION_2_MAGIC_NUMBER >> 8)));
-            headerBuffer.write((byte) (0xFF & FormatSpec.VERSION_2_MAGIC_NUMBER));
-            // Dictionary version.
-            headerBuffer.write((byte) (0xFF & (version >> 8)));
-            headerBuffer.write((byte) (0xFF & version));
-        } else {
-            // Magic number for version 1.
-            headerBuffer.write((byte) (0xFF & (FormatSpec.VERSION_1_MAGIC_NUMBER >> 8)));
-            headerBuffer.write((byte) (0xFF & FormatSpec.VERSION_1_MAGIC_NUMBER));
-            // Dictionary version.
-            headerBuffer.write((byte) (0xFF & version));
-        }
+        // Magic number for all versions.
+        headerBuffer.write((byte) (0xFF & (FormatSpec.MAGIC_NUMBER >> 24)));
+        headerBuffer.write((byte) (0xFF & (FormatSpec.MAGIC_NUMBER >> 16)));
+        headerBuffer.write((byte) (0xFF & (FormatSpec.MAGIC_NUMBER >> 8)));
+        headerBuffer.write((byte) (0xFF & FormatSpec.MAGIC_NUMBER));
+        // Dictionary version.
+        headerBuffer.write((byte) (0xFF & (version >> 8)));
+        headerBuffer.write((byte) (0xFF & version));
+
         // Options flags
         final int options = makeOptionsValue(dict, formatOptions);
         headerBuffer.write((byte) (0xFF & (options >> 8)));
         headerBuffer.write((byte) (0xFF & options));
-        if (version >= FormatSpec.FIRST_VERSION_WITH_HEADER_SIZE) {
-            final int headerSizeOffset = headerBuffer.size();
-            // Placeholder to be written later with header size.
-            for (int i = 0; i < 4; ++i) {
-                headerBuffer.write(0);
-            }
-            // Write out the options.
-            for (final String key : dict.mOptions.mAttributes.keySet()) {
-                final String value = dict.mOptions.mAttributes.get(key);
-                CharEncoding.writeString(headerBuffer, key);
-                CharEncoding.writeString(headerBuffer, value);
-            }
-            final int size = headerBuffer.size();
-            final byte[] bytes = headerBuffer.toByteArray();
-            // Write out the header size.
-            bytes[headerSizeOffset] = (byte) (0xFF & (size >> 24));
-            bytes[headerSizeOffset + 1] = (byte) (0xFF & (size >> 16));
-            bytes[headerSizeOffset + 2] = (byte) (0xFF & (size >> 8));
-            bytes[headerSizeOffset + 3] = (byte) (0xFF & (size >> 0));
-            destination.write(bytes);
-        } else {
-            headerBuffer.writeTo(destination);
+        final int headerSizeOffset = headerBuffer.size();
+        // Placeholder to be written later with header size.
+        for (int i = 0; i < 4; ++i) {
+            headerBuffer.write(0);
         }
+        // Write out the options.
+        for (final String key : dict.mOptions.mAttributes.keySet()) {
+            final String value = dict.mOptions.mAttributes.get(key);
+            CharEncoding.writeString(headerBuffer, key);
+            CharEncoding.writeString(headerBuffer, value);
+        }
+        final int size = headerBuffer.size();
+        final byte[] bytes = headerBuffer.toByteArray();
+        // Write out the header size.
+        bytes[headerSizeOffset] = (byte) (0xFF & (size >> 24));
+        bytes[headerSizeOffset + 1] = (byte) (0xFF & (size >> 16));
+        bytes[headerSizeOffset + 2] = (byte) (0xFF & (size >> 8));
+        bytes[headerSizeOffset + 3] = (byte) (0xFF & (size >> 0));
+        destination.write(bytes);
 
         headerBuffer.close();
 
@@ -1658,10 +1647,8 @@
      */
     private static int getFormatVersion(final FusionDictionaryBufferInterface buffer)
             throws IOException {
-        final int magic_v1 = buffer.readUnsignedShort();
-        if (FormatSpec.VERSION_1_MAGIC_NUMBER == magic_v1) return buffer.readUnsignedByte();
-        final int magic_v2 = (magic_v1 << 16) + buffer.readUnsignedShort();
-        if (FormatSpec.VERSION_2_MAGIC_NUMBER == magic_v2) return buffer.readUnsignedShort();
+        final int magic = buffer.readInt();
+        if (FormatSpec.MAGIC_NUMBER == magic) return buffer.readUnsignedShort();
         return FormatSpec.NOT_A_VERSION_NUMBER;
     }
 
@@ -1695,13 +1682,9 @@
 
         final HashMap<String, String> attributes = new HashMap<String, String>();
         final int headerSize;
-        if (version < FormatSpec.FIRST_VERSION_WITH_HEADER_SIZE) {
-            headerSize = buffer.position();
-        } else {
-            headerSize = buffer.readInt();
-            populateOptions(buffer, headerSize, attributes);
-            buffer.position(headerSize);
-        }
+        headerSize = buffer.readInt();
+        populateOptions(buffer, headerSize, attributes);
+        buffer.position(headerSize);
 
         if (headerSize < 0) {
             throw new UnsupportedFormatException("header size can't be negative.");
diff --git a/java/src/com/android/inputmethod/latin/makedict/FormatSpec.java b/java/src/com/android/inputmethod/latin/makedict/FormatSpec.java
index 46266aa..2bb5d8b 100644
--- a/java/src/com/android/inputmethod/latin/makedict/FormatSpec.java
+++ b/java/src/com/android/inputmethod/latin/makedict/FormatSpec.java
@@ -26,6 +26,40 @@
 public final class FormatSpec {
 
     /*
+     * File header layout is as follows:
+     *
+     * v |
+     * e | MAGIC_NUMBER + version of the file format, 2 bytes.
+     * r |
+     * sion
+     *
+     * o |
+     * p | not used                                4 bits
+     * t | has bigrams ?                           1 bit, 1 = yes, 0 = no : CONTAINS_BIGRAMS_FLAG
+     * i | FRENCH_LIGATURE_PROCESSING_FLAG
+     * o | supports dynamic updates ?              1 bit, 1 = yes, 0 = no : SUPPORTS_DYNAMIC_UPDATE
+     * n | GERMAN_UMLAUT_PROCESSING_FLAG
+     * f |
+     * lags
+     *
+     * h |
+     * e | size of the file header, 4bytes
+     * a |   including the size of the magic number, the option flags and the header size
+     * d |
+     * ersize
+     *
+     *   | attributes list
+     *
+     * attributes list is:
+     * <key>   = | string of characters at the char format described below, with the terminator used
+     *           | to signal the end of the string.
+     * <value> = | string of characters at the char format described below, with the terminator used
+     *           | to signal the end of the string.
+     * if the size of already read < headersize, goto key.
+     *
+     */
+
+    /*
      * Array of Node(FusionDictionary.Node) layout is as follows:
      *
      * g |
@@ -151,12 +185,10 @@
      * if (FLAG_ATTRIBUTE_HAS_NEXT goto flags
      */
 
-    static final int VERSION_1_MAGIC_NUMBER = 0x78B1;
-    public static final int VERSION_2_MAGIC_NUMBER = 0x9BC13AFE;
-    static final int MINIMUM_SUPPORTED_VERSION = 1;
+    public static final int MAGIC_NUMBER = 0x9BC13AFE;
+    static final int MINIMUM_SUPPORTED_VERSION = 2;
     static final int MAXIMUM_SUPPORTED_VERSION = 3;
     static final int NOT_A_VERSION_NUMBER = -1;
-    static final int FIRST_VERSION_WITH_HEADER_SIZE = 2;
     static final int FIRST_VERSION_WITH_DYNAMIC_UPDATE = 3;
 
     // These options need to be the same numeric values as the one in the native reading code.
diff --git a/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripLayoutHelper.java b/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripLayoutHelper.java
index 1dd04fc..bcf64a8 100644
--- a/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripLayoutHelper.java
+++ b/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripLayoutHelper.java
@@ -177,20 +177,9 @@
         return mMaxMoreSuggestionsRow;
     }
 
-    private int getMoreSuggestionsHeight() {
-        return mMaxMoreSuggestionsRow * mMoreSuggestionsRowHeight + mMoreSuggestionsBottomGap;
-    }
-
-    public int setMoreSuggestionsHeight(final int remainingHeight) {
-        final int currentHeight = getMoreSuggestionsHeight();
-        if (currentHeight <= remainingHeight) {
-            return currentHeight;
-        }
-
+    public void setMoreSuggestionsHeight(final int remainingHeight) {
         mMaxMoreSuggestionsRow = (remainingHeight - mMoreSuggestionsBottomGap)
                 / mMoreSuggestionsRowHeight;
-        final int newHeight = getMoreSuggestionsHeight();
-        return newHeight;
     }
 
     private static Drawable getMoreSuggestionsHint(final Resources res, final float textSize,
diff --git a/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripView.java b/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripView.java
index a8a14a8..2644f3c 100644
--- a/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripView.java
+++ b/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripView.java
@@ -135,8 +135,8 @@
         }
     }
 
-    public int setMoreSuggestionsHeight(final int remainingHeight) {
-        return mLayoutHelper.setMoreSuggestionsHeight(remainingHeight);
+    public void setMoreSuggestionsHeight(final int remainingHeight) {
+        mLayoutHelper.setMoreSuggestionsHeight(remainingHeight);
     }
 
     public boolean isShowingAddToDictionaryHint() {
diff --git a/java/src/com/android/inputmethod/latin/utils/UserLogRingCharBuffer.java b/java/src/com/android/inputmethod/latin/utils/UserLogRingCharBuffer.java
index 161386e..a75d353 100644
--- a/java/src/com/android/inputmethod/latin/utils/UserLogRingCharBuffer.java
+++ b/java/src/com/android/inputmethod/latin/utils/UserLogRingCharBuffer.java
@@ -19,6 +19,7 @@
 import android.inputmethodservice.InputMethodService;
 
 import com.android.inputmethod.annotations.UsedForTesting;
+import com.android.inputmethod.latin.LatinImeLogger;
 import com.android.inputmethod.latin.settings.Settings;
 
 public final class UserLogRingCharBuffer {
@@ -64,6 +65,9 @@
         if (!mEnabled) {
             return;
         }
+        if (LatinImeLogger.sUsabilityStudy) {
+            UsabilityStudyLogUtils.getInstance().writeChar(c, x, y);
+        }
         mCharBuf[mEnd] = c;
         mXBuf[mEnd] = x;
         mYBuf[mEnd] = y;
diff --git a/native/jni/Android.mk b/native/jni/Android.mk
index e14cf5a..4786ef6 100644
--- a/native/jni/Android.mk
+++ b/native/jni/Android.mk
@@ -71,6 +71,7 @@
     suggest/core/policy/weighting.cpp \
     suggest/core/session/dic_traverse_session.cpp \
     $(addprefix suggest/policyimpl/dictionary/, \
+        dictionary_structure_with_buffer_policy_factory.cpp \
         dynamic_patricia_trie_node_reader.cpp \
         dynamic_patricia_trie_policy.cpp \
         dynamic_patricia_trie_reading_utils.cpp \
diff --git a/native/jni/src/suggest/core/dicnode/dic_node_proximity_filter.h b/native/jni/src/suggest/core/dicnode/dic_node_proximity_filter.h
index 1a39f2e..c7ab571 100644
--- a/native/jni/src/suggest/core/dicnode/dic_node_proximity_filter.h
+++ b/native/jni/src/suggest/core/dicnode/dic_node_proximity_filter.h
@@ -20,11 +20,11 @@
 #include "defines.h"
 #include "suggest/core/layout/proximity_info_state.h"
 #include "suggest/core/layout/proximity_info_utils.h"
-#include "suggest/core/policy/dictionary_structure_policy.h"
+#include "suggest/core/policy/dictionary_structure_with_buffer_policy.h"
 
 namespace latinime {
 
-class DicNodeProximityFilter : public DictionaryStructurePolicy::NodeFilter {
+class DicNodeProximityFilter : public DictionaryStructureWithBufferPolicy::NodeFilter {
  public:
     DicNodeProximityFilter(const ProximityInfoState *const pInfoState,
             const int pointIndex, const bool exactOnly)
diff --git a/native/jni/src/suggest/core/dicnode/dic_node_utils.cpp b/native/jni/src/suggest/core/dicnode/dic_node_utils.cpp
index 6b4ef2f..4ff4bc2 100644
--- a/native/jni/src/suggest/core/dicnode/dic_node_utils.cpp
+++ b/native/jni/src/suggest/core/dicnode/dic_node_utils.cpp
@@ -24,7 +24,7 @@
 #include "suggest/core/dictionary/binary_dictionary_info.h"
 #include "suggest/core/dictionary/multi_bigram_map.h"
 #include "suggest/core/dictionary/probability_utils.h"
-#include "suggest/core/policy/dictionary_structure_policy.h"
+#include "suggest/core/policy/dictionary_structure_with_buffer_policy.h"
 #include "utils/char_utils.h"
 
 namespace latinime {
@@ -83,7 +83,7 @@
         DicNodeUtils::createAndGetPassingChildNode(dicNode, &childrenFilter, childDicNodes);
     } else {
         binaryDictionaryInfo->getStructurePolicy()->createAndGetAllChildNodes(dicNode,
-                binaryDictionaryInfo, &childrenFilter, childDicNodes);
+                &childrenFilter, childDicNodes);
     }
 }
 
@@ -118,8 +118,8 @@
         return ProbabilityUtils::backoff(unigramProbability);
     }
     if (multiBigramMap) {
-        return multiBigramMap->getBigramProbability(
-                binaryDictionaryInfo, prevWordPos, wordPos, unigramProbability);
+        return multiBigramMap->getBigramProbability(binaryDictionaryInfo->getStructurePolicy(),
+                prevWordPos, wordPos, unigramProbability);
     }
     return ProbabilityUtils::backoff(unigramProbability);
 }
diff --git a/native/jni/src/suggest/core/dictionary/bigram_dictionary.cpp b/native/jni/src/suggest/core/dictionary/bigram_dictionary.cpp
index 3751ae5..fdaa562 100644
--- a/native/jni/src/suggest/core/dictionary/bigram_dictionary.cpp
+++ b/native/jni/src/suggest/core/dictionary/bigram_dictionary.cpp
@@ -112,13 +112,14 @@
     int bigramCount = 0;
     int unigramProbability = 0;
     int bigramBuffer[MAX_WORD_LENGTH];
-    BinaryDictionaryBigramsIterator bigramsIt(mBinaryDictionaryInfo, pos);
+    const DictionaryStructureWithBufferPolicy *const structurePolicy =
+            mBinaryDictionaryInfo->getStructurePolicy();
+    BinaryDictionaryBigramsIterator bigramsIt(structurePolicy->getBigramsStructurePolicy(), pos);
     while (bigramsIt.hasNext()) {
         bigramsIt.next();
-        const int length = mBinaryDictionaryInfo->getStructurePolicy()->
-                getCodePointsAndProbabilityAndReturnCodePointCount(
-                        mBinaryDictionaryInfo, bigramsIt.getBigramPos(), MAX_WORD_LENGTH,
-                        bigramBuffer, &unigramProbability);
+        const int length = structurePolicy->
+                getCodePointsAndProbabilityAndReturnCodePointCount(bigramsIt.getBigramPos(),
+                        MAX_WORD_LENGTH, bigramBuffer, &unigramProbability);
         // Due to space constraints, the probability for bigrams is approximate - the lower the
         // unigram probability, the worse the precision. The theoritical maximum error in
         // resulting probability is 8 - although in the practice it's never bigger than 3 or 4
@@ -138,11 +139,12 @@
 int BigramDictionary::getBigramListPositionForWord(const int *prevWord, const int prevWordLength,
         const bool forceLowerCaseSearch) const {
     if (0 >= prevWordLength) return NOT_A_DICT_POS;
-    int pos = mBinaryDictionaryInfo->getStructurePolicy()->getTerminalNodePositionOfWord(
-            mBinaryDictionaryInfo, prevWord, prevWordLength, forceLowerCaseSearch);
+    const DictionaryStructureWithBufferPolicy *const structurePolicy =
+            mBinaryDictionaryInfo->getStructurePolicy();
+    int pos = structurePolicy->getTerminalNodePositionOfWord(prevWord, prevWordLength,
+            forceLowerCaseSearch);
     if (NOT_A_VALID_WORD_POS == pos) return NOT_A_DICT_POS;
-    return mBinaryDictionaryInfo->getStructurePolicy()->getBigramsPositionOfNode(
-            mBinaryDictionaryInfo, pos);
+    return structurePolicy->getBigramsPositionOfNode(pos);
 }
 
 bool BigramDictionary::isValidBigram(const int *word0, int length0, const int *word1,
@@ -150,11 +152,13 @@
     int pos = getBigramListPositionForWord(word0, length0, false /* forceLowerCaseSearch */);
     // getBigramListPositionForWord returns 0 if this word isn't in the dictionary or has no bigrams
     if (NOT_A_DICT_POS == pos) return false;
-    int nextWordPos = mBinaryDictionaryInfo->getStructurePolicy()->getTerminalNodePositionOfWord(
-            mBinaryDictionaryInfo, word1, length1, false /* forceLowerCaseSearch */);
+    const DictionaryStructureWithBufferPolicy *const structurePolicy =
+            mBinaryDictionaryInfo->getStructurePolicy();
+    int nextWordPos = structurePolicy->getTerminalNodePositionOfWord(word1, length1,
+            false /* forceLowerCaseSearch */);
     if (NOT_A_VALID_WORD_POS == nextWordPos) return false;
 
-    BinaryDictionaryBigramsIterator bigramsIt(mBinaryDictionaryInfo, pos);
+    BinaryDictionaryBigramsIterator bigramsIt(structurePolicy->getBigramsStructurePolicy(), pos);
     while (bigramsIt.hasNext()) {
         bigramsIt.next();
         if (bigramsIt.getBigramPos() == nextWordPos) {
diff --git a/native/jni/src/suggest/core/dictionary/binary_dictionary_bigrams_iterator.h b/native/jni/src/suggest/core/dictionary/binary_dictionary_bigrams_iterator.h
index 8cbb129..d16ac47 100644
--- a/native/jni/src/suggest/core/dictionary/binary_dictionary_bigrams_iterator.h
+++ b/native/jni/src/suggest/core/dictionary/binary_dictionary_bigrams_iterator.h
@@ -18,51 +18,41 @@
 #define LATINIME_BINARY_DICTIONARY_BIGRAMS_ITERATOR_H
 
 #include "defines.h"
-#include "suggest/core/dictionary/binary_dictionary_info.h"
-#include "suggest/core/dictionary/binary_dictionary_terminal_attributes_reading_utils.h"
+#include "suggest/core/policy/dictionary_bigrams_structure_policy.h"
 
 namespace latinime {
 
 class BinaryDictionaryBigramsIterator {
  public:
     BinaryDictionaryBigramsIterator(
-            const BinaryDictionaryInfo *const binaryDictionaryInfo, const int pos)
-            : mBinaryDictionaryInfo(binaryDictionaryInfo), mPos(pos), mBigramFlags(0),
-              mBigramPos(NOT_A_DICT_POS), mHasNext(pos != NOT_A_DICT_POS) {}
+            const DictionaryBigramsStructurePolicy *const bigramsStructurePolicy, const int pos)
+            : mBigramsStructurePolicy(bigramsStructurePolicy), mPos(pos),
+              mBigramPos(NOT_A_DICT_POS), mProbability(NOT_A_PROBABILITY),
+              mHasNext(pos != NOT_A_DICT_POS) {}
 
     AK_FORCE_INLINE bool hasNext() const {
         return mHasNext;
     }
 
     AK_FORCE_INLINE void next() {
-        mBigramFlags = BinaryDictionaryTerminalAttributesReadingUtils::getFlagsAndForwardPointer(
-                mBinaryDictionaryInfo, &mPos);
-        mBigramPos =
-                BinaryDictionaryTerminalAttributesReadingUtils::getBigramAddressAndForwardPointer(
-                        mBinaryDictionaryInfo, mBigramFlags, &mPos);
-        mHasNext = BinaryDictionaryTerminalAttributesReadingUtils::hasNext(mBigramFlags);
+        mBigramsStructurePolicy->getNextBigram(&mBigramPos, &mProbability, &mHasNext, &mPos);
     }
 
     AK_FORCE_INLINE int getProbability() const {
-        return BinaryDictionaryTerminalAttributesReadingUtils::getProbabilityFromFlags(
-                mBigramFlags);
+        return mProbability;
     }
 
     AK_FORCE_INLINE int getBigramPos() const {
         return mBigramPos;
     }
 
-    AK_FORCE_INLINE int getFlags() const {
-        return mBigramFlags;
-    }
-
  private:
     DISALLOW_COPY_AND_ASSIGN(BinaryDictionaryBigramsIterator);
 
-    const BinaryDictionaryInfo *const mBinaryDictionaryInfo;
+    const DictionaryBigramsStructurePolicy *const mBigramsStructurePolicy;
     int mPos;
-    BinaryDictionaryTerminalAttributesReadingUtils::BigramFlags mBigramFlags;
     int mBigramPos;
+    int mProbability;
     bool mHasNext;
 };
 } // namespace latinime
diff --git a/native/jni/src/suggest/core/dictionary/binary_dictionary_info.h b/native/jni/src/suggest/core/dictionary/binary_dictionary_info.h
index cbea18f..c694c6a 100644
--- a/native/jni/src/suggest/core/dictionary/binary_dictionary_info.h
+++ b/native/jni/src/suggest/core/dictionary/binary_dictionary_info.h
@@ -23,7 +23,7 @@
 #include "jni.h"
 #include "suggest/core/dictionary/binary_dictionary_format_utils.h"
 #include "suggest/core/dictionary/binary_dictionary_header.h"
-#include "suggest/policyimpl/dictionary/dictionary_structure_policy_factory.h"
+#include "suggest/policyimpl/dictionary/dictionary_structure_with_buffer_policy_factory.h"
 #include "utils/log_utils.h"
 
 namespace latinime {
@@ -37,11 +37,16 @@
               mDictionaryFormat(BinaryDictionaryFormatUtils::detectFormatVersion(
                       mDictBuf, mDictSize)),
               mDictionaryHeader(this), mDictRoot(mDictBuf + mDictionaryHeader.getSize()),
-              mStructurePolicy(DictionaryStructurePolicyFactory::getDictionaryStructurePolicy(
-                      mDictionaryFormat)) {
+              // TODO: Remove.
+              mStructurePolicy(DictionaryStructureWithBufferPolicyFactory
+                      ::newDictionaryStructurePolicy(this)) {
         logDictionaryInfo(env);
     }
 
+    ~BinaryDictionaryInfo() {
+        delete mStructurePolicy;
+    }
+
     AK_FORCE_INLINE const uint8_t *getDictBuf() const {
         return mDictBuf;
     }
@@ -66,6 +71,7 @@
         return mDictionaryFormat;
     }
 
+    // TODO: Move to DictionaryStructurePolicy.
     AK_FORCE_INLINE const BinaryDictionaryHeader *getHeader() const {
         return &mDictionaryHeader;
     }
@@ -76,7 +82,8 @@
         return mIsUpdatable && isUpdatableDictionaryFormat;
     }
 
-    AK_FORCE_INLINE const DictionaryStructurePolicy *getStructurePolicy() const {
+    // TODO: remove
+    AK_FORCE_INLINE const DictionaryStructureWithBufferPolicy *getStructurePolicy() const {
         return mStructurePolicy;
     }
 
@@ -89,9 +96,12 @@
     const int mDictBufOffset;
     const bool mIsUpdatable;
     const BinaryDictionaryFormatUtils::FORMAT_VERSION mDictionaryFormat;
+    // TODO: Move BinaryDictionaryHeader to policyimpl and introduce dedicated API to the
+    // DictionaryStructurePolicy.
     const BinaryDictionaryHeader mDictionaryHeader;
     const uint8_t *const mDictRoot;
-    const DictionaryStructurePolicy *const mStructurePolicy;
+    // TODO: remove
+    const DictionaryStructureWithBufferPolicy *const mStructurePolicy;
 
     AK_FORCE_INLINE void logDictionaryInfo(JNIEnv *const env) const {
         const int BUFFER_SIZE = 16;
diff --git a/native/jni/src/suggest/core/dictionary/binary_dictionary_terminal_attributes_reading_utils.cpp b/native/jni/src/suggest/core/dictionary/binary_dictionary_terminal_attributes_reading_utils.cpp
index 20b77b3..9e7d7a3 100644
--- a/native/jni/src/suggest/core/dictionary/binary_dictionary_terminal_attributes_reading_utils.cpp
+++ b/native/jni/src/suggest/core/dictionary/binary_dictionary_terminal_attributes_reading_utils.cpp
@@ -16,7 +16,6 @@
 
 #include "suggest/core/dictionary/binary_dictionary_terminal_attributes_reading_utils.h"
 
-#include "suggest/core/dictionary/binary_dictionary_info.h"
 #include "suggest/core/dictionary/byte_array_utils.h"
 
 namespace latinime {
@@ -38,22 +37,19 @@
 const int TaUtils::WHITELIST_SHORTCUT_PROBABILITY = 15;
 
 /* static */ int TaUtils::getBigramAddressAndForwardPointer(
-        const BinaryDictionaryInfo *const binaryDictionaryInfo, const TerminalAttributeFlags flags,
+        const uint8_t *const dictRoot, const TerminalAttributeFlags flags,
         int *const pos) {
     int offset = 0;
     const int origin = *pos;
     switch (MASK_ATTRIBUTE_ADDRESS_TYPE & flags) {
         case FLAG_ATTRIBUTE_ADDRESS_TYPE_ONEBYTE:
-            offset = ByteArrayUtils::readUint8AndAdvancePosition(
-                    binaryDictionaryInfo->getDictRoot(), pos);
+            offset = ByteArrayUtils::readUint8AndAdvancePosition(dictRoot, pos);
             break;
         case FLAG_ATTRIBUTE_ADDRESS_TYPE_TWOBYTES:
-            offset = ByteArrayUtils::readUint16AndAdvancePosition(
-                    binaryDictionaryInfo->getDictRoot(), pos);
+            offset = ByteArrayUtils::readUint16AndAdvancePosition(dictRoot, pos);
             break;
         case FLAG_ATTRIBUTE_ADDRESS_TYPE_THREEBYTES:
-            offset = ByteArrayUtils::readUint24AndAdvancePosition(
-                    binaryDictionaryInfo->getDictRoot(), pos);
+            offset = ByteArrayUtils::readUint24AndAdvancePosition(dictRoot, pos);
             break;
     }
     if (isOffsetNegative(flags)) {
diff --git a/native/jni/src/suggest/core/dictionary/binary_dictionary_terminal_attributes_reading_utils.h b/native/jni/src/suggest/core/dictionary/binary_dictionary_terminal_attributes_reading_utils.h
index 375fc7d..e1e3e16 100644
--- a/native/jni/src/suggest/core/dictionary/binary_dictionary_terminal_attributes_reading_utils.h
+++ b/native/jni/src/suggest/core/dictionary/binary_dictionary_terminal_attributes_reading_utils.h
@@ -32,9 +32,8 @@
     typedef TerminalAttributeFlags ShortcutFlags;
 
     static AK_FORCE_INLINE TerminalAttributeFlags getFlagsAndForwardPointer(
-            const BinaryDictionaryInfo *const binaryDictionaryInfo, int *const pos) {
-        return ByteArrayUtils::readUint8AndAdvancePosition(
-                binaryDictionaryInfo->getDictRoot(), pos);
+            const uint8_t *const dictRoot, int *const pos) {
+        return ByteArrayUtils::readUint8AndAdvancePosition(dictRoot, pos);
     }
 
     static AK_FORCE_INLINE int getProbabilityFromFlags(const TerminalAttributeFlags flags) {
@@ -47,18 +46,17 @@
 
     // Bigrams reading methods
     static AK_FORCE_INLINE void skipExistingBigrams(
-            const BinaryDictionaryInfo *const binaryDictionaryInfo, int *const pos) {
-        BigramFlags flags = getFlagsAndForwardPointer(binaryDictionaryInfo, pos);
+            const uint8_t *const dictRoot, int *const pos) {
+        BigramFlags flags = getFlagsAndForwardPointer(dictRoot, pos);
         while (hasNext(flags)) {
             *pos += attributeAddressSize(flags);
-            flags = getFlagsAndForwardPointer(binaryDictionaryInfo, pos);
+            flags = getFlagsAndForwardPointer(dictRoot, pos);
         }
         *pos += attributeAddressSize(flags);
     }
 
     static int getBigramAddressAndForwardPointer(
-            const BinaryDictionaryInfo *const binaryDictionaryInfo, const BigramFlags flags,
-                    int *const pos);
+            const uint8_t *const dictRoot, const BigramFlags flags, int *const pos);
 
     // Shortcuts reading methods
     // This method returns the size of the shortcut list region excluding the shortcut list size
diff --git a/native/jni/src/suggest/core/dictionary/dictionary.cpp b/native/jni/src/suggest/core/dictionary/dictionary.cpp
index 4a9e38f..891b803 100644
--- a/native/jni/src/suggest/core/dictionary/dictionary.cpp
+++ b/native/jni/src/suggest/core/dictionary/dictionary.cpp
@@ -83,14 +83,14 @@
 }
 
 int Dictionary::getProbability(const int *word, int length) const {
-    const DictionaryStructurePolicy *const structurePolicy =
+    const DictionaryStructureWithBufferPolicy *const structurePolicy =
             mBinaryDictionaryInfo.getStructurePolicy();
-    int pos = structurePolicy->getTerminalNodePositionOfWord(&mBinaryDictionaryInfo, word, length,
+    int pos = structurePolicy->getTerminalNodePositionOfWord(word, length,
             false /* forceLowerCaseSearch */);
     if (NOT_A_VALID_WORD_POS == pos) {
         return NOT_A_PROBABILITY;
     }
-    return structurePolicy->getUnigramProbability(&mBinaryDictionaryInfo, pos);
+    return structurePolicy->getUnigramProbability(pos);
 }
 
 bool Dictionary::isValidBigram(const int *word0, int length0, const int *word1, int length1) const {
diff --git a/native/jni/src/suggest/core/dictionary/multi_bigram_map.h b/native/jni/src/suggest/core/dictionary/multi_bigram_map.h
index d5eafe1..97d4cd1 100644
--- a/native/jni/src/suggest/core/dictionary/multi_bigram_map.h
+++ b/native/jni/src/suggest/core/dictionary/multi_bigram_map.h
@@ -21,9 +21,9 @@
 
 #include "defines.h"
 #include "suggest/core/dictionary/binary_dictionary_bigrams_iterator.h"
-#include "suggest/core/dictionary/binary_dictionary_info.h"
 #include "suggest/core/dictionary/bloom_filter.h"
 #include "suggest/core/dictionary/probability_utils.h"
+#include "suggest/core/policy/dictionary_structure_with_buffer_policy.h"
 #include "utils/hash_map_compat.h"
 
 namespace latinime {
@@ -38,7 +38,7 @@
 
     // Look up the bigram probability for the given word pair from the cached bigram maps.
     // Also caches the bigrams if there is space remaining and they have not been cached already.
-    int getBigramProbability(const BinaryDictionaryInfo *const binaryDictionaryInfo,
+    int getBigramProbability(const DictionaryStructureWithBufferPolicy *const structurePolicy,
             const int wordPosition, const int nextWordPosition, const int unigramProbability) {
         hash_map_compat<int, BigramMap>::const_iterator mapPosition =
                 mBigramMaps.find(wordPosition);
@@ -46,12 +46,12 @@
             return mapPosition->second.getBigramProbability(nextWordPosition, unigramProbability);
         }
         if (mBigramMaps.size() < MAX_CACHED_PREV_WORDS_IN_BIGRAM_MAP) {
-            addBigramsForWordPosition(binaryDictionaryInfo, wordPosition);
+            addBigramsForWordPosition(structurePolicy, wordPosition);
             return mBigramMaps[wordPosition].getBigramProbability(
                     nextWordPosition, unigramProbability);
         }
-        return readBigramProbabilityFromBinaryDictionary(binaryDictionaryInfo,
-                wordPosition, nextWordPosition, unigramProbability);
+        return readBigramProbabilityFromBinaryDictionary(structurePolicy, wordPosition,
+                nextWordPosition, unigramProbability);
     }
 
     void clear() {
@@ -66,10 +66,11 @@
         BigramMap() : mBigramMap(DEFAULT_HASH_MAP_SIZE_FOR_EACH_BIGRAM_MAP), mBloomFilter() {}
         ~BigramMap() {}
 
-        void init(const BinaryDictionaryInfo *const binaryDictionaryInfo, const int nodePos) {
-            const int bigramsListPos = binaryDictionaryInfo->getStructurePolicy()->
-                    getBigramsPositionOfNode(binaryDictionaryInfo, nodePos);
-            BinaryDictionaryBigramsIterator bigramsIt(binaryDictionaryInfo, bigramsListPos);
+        void init(const DictionaryStructureWithBufferPolicy *const structurePolicy,
+                const int nodePos) {
+            const int bigramsListPos = structurePolicy->getBigramsPositionOfNode(nodePos);
+            BinaryDictionaryBigramsIterator bigramsIt(structurePolicy->getBigramsStructurePolicy(),
+                    bigramsListPos);
             while (bigramsIt.hasNext()) {
                 bigramsIt.next();
                 mBigramMap[bigramsIt.getBigramPos()] = bigramsIt.getProbability();
@@ -100,16 +101,16 @@
     };
 
     AK_FORCE_INLINE void addBigramsForWordPosition(
-            const BinaryDictionaryInfo *const binaryDictionaryInfo, const int position) {
-        mBigramMaps[position].init(binaryDictionaryInfo, position);
+            const DictionaryStructureWithBufferPolicy *const structurePolicy, const int position) {
+        mBigramMaps[position].init(structurePolicy, position);
     }
 
     AK_FORCE_INLINE int readBigramProbabilityFromBinaryDictionary(
-            const BinaryDictionaryInfo *const binaryDictionaryInfo, const int nodePos,
+            const DictionaryStructureWithBufferPolicy *const structurePolicy, const int nodePos,
             const int nextWordPosition, const int unigramProbability) {
-        const int bigramsListPos = binaryDictionaryInfo->getStructurePolicy()->
-                getBigramsPositionOfNode(binaryDictionaryInfo, nodePos);
-        BinaryDictionaryBigramsIterator bigramsIt(binaryDictionaryInfo, bigramsListPos);
+        const int bigramsListPos = structurePolicy->getBigramsPositionOfNode(nodePos);
+        BinaryDictionaryBigramsIterator bigramsIt(structurePolicy->getBigramsStructurePolicy(),
+                bigramsListPos);
         while (bigramsIt.hasNext()) {
             bigramsIt.next();
             if (bigramsIt.getBigramPos() == nextWordPosition) {
diff --git a/native/jni/src/suggest/core/dictionary/terminal_attributes.h b/native/jni/src/suggest/core/dictionary/terminal_attributes.h
index 0da6504..c40a3bb 100644
--- a/native/jni/src/suggest/core/dictionary/terminal_attributes.h
+++ b/native/jni/src/suggest/core/dictionary/terminal_attributes.h
@@ -49,7 +49,7 @@
                 bool *const outIsWhitelist) {
             const BinaryDictionaryTerminalAttributesReadingUtils::ShortcutFlags flags =
                     BinaryDictionaryTerminalAttributesReadingUtils::getFlagsAndForwardPointer(
-                            mBinaryDictionaryInfo, &mPos);
+                            mBinaryDictionaryInfo->getDictRoot(), &mPos);
             mHasNextShortcutTarget =
                     BinaryDictionaryTerminalAttributesReadingUtils::hasNext(flags);
             if (outIsWhitelist) {
diff --git a/native/jni/src/suggest/core/policy/dictionary_bigrams_structure_policy.h b/native/jni/src/suggest/core/policy/dictionary_bigrams_structure_policy.h
new file mode 100644
index 0000000..661ef1b
--- /dev/null
+++ b/native/jni/src/suggest/core/policy/dictionary_bigrams_structure_policy.h
@@ -0,0 +1,42 @@
+/*
+ * 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_DICTIONARY_BIGRAMS_STRUCTURE_POLICY_H
+#define LATINIME_DICTIONARY_BIGRAMS_STRUCTURE_POLICY_H
+
+#include "defines.h"
+
+namespace latinime {
+
+/*
+ * This class abstracts structure of bigrams.
+ */
+class DictionaryBigramsStructurePolicy {
+ public:
+    virtual ~DictionaryBigramsStructurePolicy() {}
+
+    virtual void getNextBigram(int *const outBigramPos, int *const outProbability,
+            bool *const outHasNext, int *const pos) const = 0;
+    virtual void skipAllBigrams(int *const pos) const = 0;
+
+ protected:
+    DictionaryBigramsStructurePolicy() {}
+
+ private:
+    DISALLOW_COPY_AND_ASSIGN(DictionaryBigramsStructurePolicy);
+};
+} // namespace latinime
+#endif /* LATINIME_DICTIONARY_BIGRAMS_STRUCTURE_POLICY_H */
diff --git a/native/jni/src/suggest/core/policy/dictionary_structure_policy.h b/native/jni/src/suggest/core/policy/dictionary_structure_with_buffer_policy.h
similarity index 67%
rename from native/jni/src/suggest/core/policy/dictionary_structure_policy.h
rename to native/jni/src/suggest/core/policy/dictionary_structure_with_buffer_policy.h
index cc14c98..d83d1e3 100644
--- a/native/jni/src/suggest/core/policy/dictionary_structure_policy.h
+++ b/native/jni/src/suggest/core/policy/dictionary_structure_with_buffer_policy.h
@@ -21,15 +21,15 @@
 
 namespace latinime {
 
-class BinaryDictionaryInfo;
 class DicNode;
 class DicNodeVector;
+class DictionaryBigramsStructurePolicy;
 
 /*
  * This class abstracts structure of dictionaries.
  * Implement this policy to support additional dictionaries.
  */
-class DictionaryStructurePolicy {
+class DictionaryStructureWithBufferPolicy {
  public:
     // This provides a filtering method for filtering new node.
     class NodeFilter {
@@ -44,36 +44,33 @@
         DISALLOW_COPY_AND_ASSIGN(NodeFilter);
     };
 
+    virtual ~DictionaryStructureWithBufferPolicy() {}
+
     virtual int getRootPosition() const = 0;
 
     virtual void createAndGetAllChildNodes(const DicNode *const dicNode,
-            const BinaryDictionaryInfo *const binaryDictionaryInfo,
             const NodeFilter *const nodeFilter, DicNodeVector *const childDicNodes) const = 0;
 
     virtual int getCodePointsAndProbabilityAndReturnCodePointCount(
-            const BinaryDictionaryInfo *const binaryDictionaryInfo,
             const int nodePos, const int maxCodePointCount, int *const outCodePoints,
             int *const outUnigramProbability) const = 0;
 
-    virtual int getTerminalNodePositionOfWord(
-            const BinaryDictionaryInfo *const binaryDictionaryInfo, const int *const inWord,
+    virtual int getTerminalNodePositionOfWord(const int *const inWord,
             const int length, const bool forceLowerCaseSearch) const = 0;
 
-    virtual int getUnigramProbability(const BinaryDictionaryInfo *const binaryDictionaryInfo,
-            const int nodePos) const = 0;
+    virtual int getUnigramProbability(const int nodePos) const = 0;
 
-    virtual int getShortcutPositionOfNode(const BinaryDictionaryInfo *const binaryDictionaryInfo,
-            const int nodePos) const = 0;
+    virtual int getShortcutPositionOfNode(const int nodePos) const = 0;
 
-    virtual int getBigramsPositionOfNode(const BinaryDictionaryInfo *const binaryDictionaryInfo,
-            const int nodePos) const = 0;
+    virtual int getBigramsPositionOfNode(const int nodePos) const = 0;
+
+    virtual const DictionaryBigramsStructurePolicy *getBigramsStructurePolicy() const = 0;
 
  protected:
-    DictionaryStructurePolicy() {}
-    virtual ~DictionaryStructurePolicy() {}
+    DictionaryStructureWithBufferPolicy() {}
 
  private:
-    DISALLOW_COPY_AND_ASSIGN(DictionaryStructurePolicy);
+    DISALLOW_COPY_AND_ASSIGN(DictionaryStructureWithBufferPolicy);
 };
 } // namespace latinime
 #endif /* LATINIME_DICTIONARY_STRUCTURE_POLICY_H */
diff --git a/native/jni/src/suggest/core/session/dic_traverse_session.cpp b/native/jni/src/suggest/core/session/dic_traverse_session.cpp
index 7651b19..11a147b 100644
--- a/native/jni/src/suggest/core/session/dic_traverse_session.cpp
+++ b/native/jni/src/suggest/core/session/dic_traverse_session.cpp
@@ -37,12 +37,12 @@
     }
     // TODO: merge following similar calls to getTerminalPosition into one case-insensitive call.
     mPrevWordPos = binaryDictionaryInfo->getStructurePolicy()->getTerminalNodePositionOfWord(
-            binaryDictionaryInfo, prevWord, prevWordLength, false /* forceLowerCaseSearch */);
+            prevWord, prevWordLength, false /* forceLowerCaseSearch */);
     if (mPrevWordPos == NOT_A_VALID_WORD_POS) {
         // Check bigrams for lower-cased previous word if original was not found. Useful for
         // auto-capitalized words like "The [current_word]".
         mPrevWordPos = binaryDictionaryInfo->getStructurePolicy()->getTerminalNodePositionOfWord(
-                binaryDictionaryInfo, prevWord, prevWordLength, true /* forceLowerCaseSearch */);
+                prevWord, prevWordLength, true /* forceLowerCaseSearch */);
     }
 }
 
diff --git a/native/jni/src/suggest/core/session/dic_traverse_session.h b/native/jni/src/suggest/core/session/dic_traverse_session.h
index de57e04..5c4cef0 100644
--- a/native/jni/src/suggest/core/session/dic_traverse_session.h
+++ b/native/jni/src/suggest/core/session/dic_traverse_session.h
@@ -75,7 +75,7 @@
             const int maxPointerCount);
     void resetCache(const int nextActiveCacheSize, const int maxWords);
 
-    // TODO: Remove
+    // TODO: Use DictionaryStructurePolicy instead of BinaryDictionaryInfo.
     const BinaryDictionaryInfo *getBinaryDictionaryInfo() const;
 
     //--------------------
diff --git a/native/jni/src/suggest/core/suggest.cpp b/native/jni/src/suggest/core/suggest.cpp
index 9376d7b..f28efd5 100644
--- a/native/jni/src/suggest/core/suggest.cpp
+++ b/native/jni/src/suggest/core/suggest.cpp
@@ -215,7 +215,7 @@
                     traverseSession->getBinaryDictionaryInfo();
             const TerminalAttributes terminalAttributes(traverseSession->getBinaryDictionaryInfo(),
                     binaryDictionaryInfo->getStructurePolicy()->getShortcutPositionOfNode(
-                            binaryDictionaryInfo, terminalDicNode->getPos()));
+                            terminalDicNode->getPos()));
             // Shortcut is not supported for multiple words suggestions.
             // TODO: Check shortcuts during traversal for multiple words suggestions.
             const bool sameAsTyped = TRAVERSAL->sameAsTyped(traverseSession, terminalDicNode);
diff --git a/native/jni/src/suggest/policyimpl/dictionary/bigrams/bigram_list_policy.h b/native/jni/src/suggest/policyimpl/dictionary/bigrams/bigram_list_policy.h
new file mode 100644
index 0000000..a9e5da3
--- /dev/null
+++ b/native/jni/src/suggest/policyimpl/dictionary/bigrams/bigram_list_policy.h
@@ -0,0 +1,58 @@
+/*
+ * 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_BIGRAM_LIST_POLICY_H
+#define LATINIME_BIGRAM_LIST_POLICY_H
+
+#include <stdint.h>
+
+#include "defines.h"
+#include "suggest/core/policy/dictionary_bigrams_structure_policy.h"
+// TODO: Move bigrams reading methods to policyimpl.
+#include "suggest/core/dictionary/binary_dictionary_terminal_attributes_reading_utils.h"
+
+namespace latinime {
+
+class BigramListPolicy : public DictionaryBigramsStructurePolicy {
+ public:
+    explicit BigramListPolicy(const uint8_t *const bigramsBuf) : mBigramsBuf(bigramsBuf) {}
+
+    ~BigramListPolicy() {}
+
+    void getNextBigram(int *const outBigramPos, int *const outProbability, bool *const outHasNext,
+            int *const pos) const {
+        const BinaryDictionaryTerminalAttributesReadingUtils::BigramFlags flags =
+                BinaryDictionaryTerminalAttributesReadingUtils::getFlagsAndForwardPointer(
+                        mBigramsBuf, pos);
+        *outBigramPos =
+                BinaryDictionaryTerminalAttributesReadingUtils::getBigramAddressAndForwardPointer(
+                        mBigramsBuf, flags, pos);
+        *outProbability =
+                BinaryDictionaryTerminalAttributesReadingUtils::getProbabilityFromFlags(flags);
+        *outHasNext = BinaryDictionaryTerminalAttributesReadingUtils::hasNext(flags);
+    }
+
+    void skipAllBigrams(int *const pos) const {
+        BinaryDictionaryTerminalAttributesReadingUtils::skipExistingBigrams(mBigramsBuf, pos);
+    }
+
+ private:
+    DISALLOW_IMPLICIT_CONSTRUCTORS(BigramListPolicy);
+
+    const uint8_t *const mBigramsBuf;
+};
+} // namespace latinime
+#endif // LATINIME_BIGRAM_LIST_POLICY_H
diff --git a/native/jni/src/suggest/policyimpl/dictionary/dictionary_structure_policy_factory.h b/native/jni/src/suggest/policyimpl/dictionary/dictionary_structure_policy_factory.h
deleted file mode 100644
index c0df89f..0000000
--- a/native/jni/src/suggest/policyimpl/dictionary/dictionary_structure_policy_factory.h
+++ /dev/null
@@ -1,48 +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_DICTIONARY_STRUCTURE_POLICY_FACTORY_H
-#define LATINIME_DICTIONARY_STRUCTURE_POLICY_FACTORY_H
-
-#include "defines.h"
-#include "suggest/core/dictionary/binary_dictionary_format_utils.h"
-#include "suggest/policyimpl/dictionary/dynamic_patricia_trie_policy.h"
-#include "suggest/policyimpl/dictionary/patricia_trie_policy.h"
-
-namespace latinime {
-
-class DictionaryStructurePolicy;
-
-class DictionaryStructurePolicyFactory {
- public:
-    static const DictionaryStructurePolicy *getDictionaryStructurePolicy(
-            const BinaryDictionaryFormatUtils::FORMAT_VERSION dictionaryFormat) {
-        switch (dictionaryFormat) {
-            case BinaryDictionaryFormatUtils::VERSION_2:
-                return PatriciaTriePolicy::getInstance();
-            case BinaryDictionaryFormatUtils::VERSION_3:
-                return DynamicPatriciaTriePolicy::getInstance();
-            default:
-                ASSERT(false);
-                return 0;
-        }
-    }
-
- private:
-    DISALLOW_IMPLICIT_CONSTRUCTORS(DictionaryStructurePolicyFactory);
-};
-} // namespace latinime
-#endif // LATINIME_DICTIONARY_STRUCTURE_POLICY_FACTORY_H
diff --git a/native/jni/src/suggest/policyimpl/dictionary/dictionary_structure_with_buffer_policy_factory.cpp b/native/jni/src/suggest/policyimpl/dictionary/dictionary_structure_with_buffer_policy_factory.cpp
new file mode 100644
index 0000000..f2c5862
--- /dev/null
+++ b/native/jni/src/suggest/policyimpl/dictionary/dictionary_structure_with_buffer_policy_factory.cpp
@@ -0,0 +1,42 @@
+/*
+ * 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.
+ */
+
+#include "suggest/policyimpl/dictionary/dictionary_structure_with_buffer_policy_factory.h"
+
+#include "defines.h"
+#include "suggest/core/dictionary/binary_dictionary_info.h"
+#include "suggest/policyimpl/dictionary/dynamic_patricia_trie_policy.h"
+#include "suggest/policyimpl/dictionary/patricia_trie_policy.h"
+
+namespace latinime {
+
+/* static */ DictionaryStructureWithBufferPolicy *DictionaryStructureWithBufferPolicyFactory
+        ::newDictionaryStructurePolicy(
+        const BinaryDictionaryInfo *const binaryDictionaryInfo) {
+    switch (binaryDictionaryInfo->getFormat()) {
+        case BinaryDictionaryFormatUtils::VERSION_2:
+            return new PatriciaTriePolicy(binaryDictionaryInfo->getDictRoot(),
+                    binaryDictionaryInfo);
+        case BinaryDictionaryFormatUtils::VERSION_3:
+            return new DynamicPatriciaTriePolicy(binaryDictionaryInfo->getDictRoot(),
+                    binaryDictionaryInfo);
+        default:
+            ASSERT(false);
+            return 0;
+    }
+}
+
+} // namespace latinime
diff --git a/native/jni/src/suggest/policyimpl/dictionary/dictionary_structure_with_buffer_policy_factory.h b/native/jni/src/suggest/policyimpl/dictionary/dictionary_structure_with_buffer_policy_factory.h
new file mode 100644
index 0000000..95f82aa
--- /dev/null
+++ b/native/jni/src/suggest/policyimpl/dictionary/dictionary_structure_with_buffer_policy_factory.h
@@ -0,0 +1,37 @@
+/*
+ * 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_DICTIONARY_STRUCTURE_WITH_BUFFER_POLICY_FACTORY_H
+#define LATINIME_DICTIONARY_STRUCTURE_WITH_BUFFER_POLICY_FACTORY_H
+
+#include "defines.h"
+
+#include "suggest/core/policy/dictionary_structure_with_buffer_policy.h"
+
+namespace latinime {
+
+class BinaryDictionaryInfo;
+
+class DictionaryStructureWithBufferPolicyFactory {
+ public:
+    static DictionaryStructureWithBufferPolicy *newDictionaryStructurePolicy(
+            const BinaryDictionaryInfo *const binaryDictionaryInfo);
+
+ private:
+    DISALLOW_IMPLICIT_CONSTRUCTORS(DictionaryStructureWithBufferPolicyFactory);
+};
+} // namespace latinime
+#endif // LATINIME_DICTIONARY_STRUCTURE_WITH_BUFFER_POLICY_FACTORY_H
diff --git a/native/jni/src/suggest/policyimpl/dictionary/dynamic_patricia_trie_node_reader.cpp b/native/jni/src/suggest/policyimpl/dictionary/dynamic_patricia_trie_node_reader.cpp
index 7ac635a..e8799e5 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/dynamic_patricia_trie_node_reader.cpp
+++ b/native/jni/src/suggest/policyimpl/dictionary/dynamic_patricia_trie_node_reader.cpp
@@ -18,6 +18,7 @@
 
 #include "suggest/core/dictionary/binary_dictionary_info.h"
 #include "suggest/core/dictionary/binary_dictionary_terminal_attributes_reading_utils.h"
+#include "suggest/policyimpl/dictionary/bigrams/bigram_list_policy.h"
 #include "suggest/policyimpl/dictionary/dynamic_patricia_trie_reading_utils.h"
 
 namespace latinime {
@@ -56,8 +57,7 @@
     }
     if (PatriciaTrieReadingUtils::hasBigrams(mFlags)) {
         mBigramPos = pos;
-        BinaryDictionaryTerminalAttributesReadingUtils::skipExistingBigrams(
-                mBinaryDictionaryInfo, &pos);
+        mBigramsPolicy->skipAllBigrams(&pos);
     } else {
         mBigramPos = NOT_A_DICT_POS;
     }
diff --git a/native/jni/src/suggest/policyimpl/dictionary/dynamic_patricia_trie_node_reader.h b/native/jni/src/suggest/policyimpl/dictionary/dynamic_patricia_trie_node_reader.h
index 71558ed..641ac9b 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/dynamic_patricia_trie_node_reader.h
+++ b/native/jni/src/suggest/policyimpl/dictionary/dynamic_patricia_trie_node_reader.h
@@ -17,13 +17,17 @@
 #ifndef LATINIME_DYNAMIC_PATRICIA_TRIE_NODE_READER_H
 #define LATINIME_DYNAMIC_PATRICIA_TRIE_NODE_READER_H
 
+#include <stdint.h>
+
 #include "defines.h"
+#include "suggest/policyimpl/dictionary/bigrams/bigram_list_policy.h"
 #include "suggest/policyimpl/dictionary/dynamic_patricia_trie_reading_utils.h"
 #include "suggest/policyimpl/dictionary/patricia_trie_reading_utils.h"
 
 namespace latinime {
 
 class BinaryDictionaryInfo;
+class DictionaryBigramsStructurePolicy;
 
 /*
  * This class is used for helping to read nodes of dynamic patricia trie. This class handles moved
@@ -31,10 +35,11 @@
  */
 class DynamicPatriciaTrieNodeReader {
  public:
-    explicit DynamicPatriciaTrieNodeReader(const BinaryDictionaryInfo *const binaryDictionaryInfo)
-            : mBinaryDictionaryInfo(binaryDictionaryInfo), mNodePos(NOT_A_VALID_WORD_POS),
-              mFlags(0), mParentPos(NOT_A_DICT_POS), mCodePointCount(0),
-              mProbability(NOT_A_PROBABILITY), mChildrenPos(NOT_A_DICT_POS),
+    DynamicPatriciaTrieNodeReader(const BinaryDictionaryInfo *const binaryDictionaryInfo,
+            const DictionaryBigramsStructurePolicy *const bigramsPolicy)
+            : mBinaryDictionaryInfo(binaryDictionaryInfo), mBigramsPolicy(bigramsPolicy),
+              mNodePos(NOT_A_VALID_WORD_POS), mFlags(0), mParentPos(NOT_A_DICT_POS),
+              mCodePointCount(0), mProbability(NOT_A_PROBABILITY), mChildrenPos(NOT_A_DICT_POS),
               mShortcutPos(NOT_A_DICT_POS), mBigramPos(NOT_A_DICT_POS),
               mSiblingPos(NOT_A_VALID_WORD_POS) {}
 
@@ -117,6 +122,7 @@
     DISALLOW_COPY_AND_ASSIGN(DynamicPatriciaTrieNodeReader);
 
     const BinaryDictionaryInfo *const mBinaryDictionaryInfo;
+    const DictionaryBigramsStructurePolicy *const mBigramsPolicy;
     int mNodePos;
     DynamicPatriciaTrieReadingUtils::NodeFlags mFlags;
     int mParentPos;
diff --git a/native/jni/src/suggest/policyimpl/dictionary/dynamic_patricia_trie_policy.cpp b/native/jni/src/suggest/policyimpl/dictionary/dynamic_patricia_trie_policy.cpp
index 3df5056..9b38415 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/dynamic_patricia_trie_policy.cpp
+++ b/native/jni/src/suggest/policyimpl/dictionary/dynamic_patricia_trie_policy.cpp
@@ -26,23 +26,21 @@
 
 namespace latinime {
 
-const DynamicPatriciaTriePolicy DynamicPatriciaTriePolicy::sInstance;
 // To avoid infinite loop caused by invalid or malicious forward links.
 const int DynamicPatriciaTriePolicy::MAX_CHILD_COUNT_TO_AVOID_INFINITE_LOOP = 100000;
 
 void DynamicPatriciaTriePolicy::createAndGetAllChildNodes(const DicNode *const dicNode,
-        const BinaryDictionaryInfo *const binaryDictionaryInfo,
         const NodeFilter *const nodeFilter, DicNodeVector *const childDicNodes) const {
     if (!dicNode->hasChildren()) {
         return;
     }
-    DynamicPatriciaTrieNodeReader nodeReader(binaryDictionaryInfo);
+    DynamicPatriciaTrieNodeReader nodeReader(mBinaryDictionaryInfo, getBigramsStructurePolicy());
     int mergedNodeCodePoints[MAX_WORD_LENGTH];
     int nextPos = dicNode->getChildrenPos();
     int totalChildCount = 0;
     do {
         const int childCount = PatriciaTrieReadingUtils::getGroupCountAndAdvancePosition(
-                binaryDictionaryInfo->getDictRoot(), &nextPos);
+                mDictRoot, &nextPos);
         totalChildCount += childCount;
         if (childCount <= 0 || totalChildCount > MAX_CHILD_COUNT_TO_AVOID_INFINITE_LOOP) {
             // Invalid dictionary.
@@ -64,13 +62,11 @@
             }
             nextPos = nodeReader.getSiblingNodePos();
         }
-        nextPos = DynamicPatriciaTrieReadingUtils::getForwardLinkPosition(
-                binaryDictionaryInfo->getDictRoot(), nextPos);
+        nextPos = DynamicPatriciaTrieReadingUtils::getForwardLinkPosition(mDictRoot, nextPos);
     } while (DynamicPatriciaTrieReadingUtils::isValidForwardLinkPosition(nextPos));
 }
 
 int DynamicPatriciaTriePolicy::getCodePointsAndProbabilityAndReturnCodePointCount(
-        const BinaryDictionaryInfo *const binaryDictionaryInfo,
         const int nodePos, const int maxCodePointCount, int *const outCodePoints,
         int *const outUnigramProbability) const {
     if (nodePos == NOT_A_VALID_WORD_POS) {
@@ -83,7 +79,7 @@
     int mergedNodeCodePoints[maxCodePointCount];
     int codePointCount = 0;
 
-    DynamicPatriciaTrieNodeReader nodeReader(binaryDictionaryInfo);
+    DynamicPatriciaTrieNodeReader nodeReader(mBinaryDictionaryInfo, getBigramsStructurePolicy());
     // First, read terminal node and get its probability.
     nodeReader.fetchNodeInfoFromBufferAndGetNodeCodePoints(nodePos, maxCodePointCount,
             mergedNodeCodePoints);
@@ -118,8 +114,7 @@
     return codePointCount;
 }
 
-int DynamicPatriciaTriePolicy::getTerminalNodePositionOfWord(
-        const BinaryDictionaryInfo *const binaryDictionaryInfo, const int *const inWord,
+int DynamicPatriciaTriePolicy::getTerminalNodePositionOfWord(const int *const inWord,
         const int length, const bool forceLowerCaseSearch) const {
     int searchCodePoints[length];
     for (int i = 0; i < length; ++i) {
@@ -128,14 +123,14 @@
     int mergedNodeCodePoints[MAX_WORD_LENGTH];
     int currentLength = 0;
     int pos = getRootPosition();
-    DynamicPatriciaTrieNodeReader nodeReader(binaryDictionaryInfo);
+    DynamicPatriciaTrieNodeReader nodeReader(mBinaryDictionaryInfo, getBigramsStructurePolicy());
     while (currentLength <= length) {
         // When foundMatchedNode becomes true, currentLength is increased at least once.
         bool foundMatchedNode = false;
         int totalChildCount = 0;
         do {
             const int childCount = PatriciaTrieReadingUtils::getGroupCountAndAdvancePosition(
-                    binaryDictionaryInfo->getDictRoot(), &pos);
+                    mDictRoot, &pos);
             totalChildCount += childCount;
             if (childCount <= 0 || totalChildCount > MAX_CHILD_COUNT_TO_AVOID_INFINITE_LOOP) {
                 // Invalid dictionary.
@@ -183,7 +178,7 @@
             // If the matched node is not found in the current node group, try to follow the
             // forward link.
             pos = DynamicPatriciaTrieReadingUtils::getForwardLinkPosition(
-                    binaryDictionaryInfo->getDictRoot(), pos);
+                    mDictRoot, pos);
         } while (DynamicPatriciaTrieReadingUtils::isValidForwardLinkPosition(pos));
         if (!foundMatchedNode) {
             // Matched node is not found.
@@ -195,12 +190,11 @@
     return NOT_A_VALID_WORD_POS;
 }
 
-int DynamicPatriciaTriePolicy::getUnigramProbability(
-        const BinaryDictionaryInfo *const binaryDictionaryInfo, const int nodePos) const {
+int DynamicPatriciaTriePolicy::getUnigramProbability(const int nodePos) const {
     if (nodePos == NOT_A_VALID_WORD_POS) {
         return NOT_A_PROBABILITY;
     }
-    DynamicPatriciaTrieNodeReader nodeReader(binaryDictionaryInfo);
+    DynamicPatriciaTrieNodeReader nodeReader(mBinaryDictionaryInfo, getBigramsStructurePolicy());
     nodeReader.fetchNodeInfoFromBuffer(nodePos);
     if (nodeReader.isDeleted() || nodeReader.isBlacklisted() || nodeReader.isNotAWord()) {
         return NOT_A_PROBABILITY;
@@ -208,13 +202,11 @@
     return nodeReader.getProbability();
 }
 
-int DynamicPatriciaTriePolicy::getShortcutPositionOfNode(
-        const BinaryDictionaryInfo *const binaryDictionaryInfo,
-        const int nodePos) const {
+int DynamicPatriciaTriePolicy::getShortcutPositionOfNode(const int nodePos) const {
     if (nodePos == NOT_A_VALID_WORD_POS) {
         return NOT_A_DICT_POS;
     }
-    DynamicPatriciaTrieNodeReader nodeReader(binaryDictionaryInfo);
+    DynamicPatriciaTrieNodeReader nodeReader(mBinaryDictionaryInfo, getBigramsStructurePolicy());
     nodeReader.fetchNodeInfoFromBuffer(nodePos);
     if (nodeReader.isDeleted()) {
         return NOT_A_DICT_POS;
@@ -222,13 +214,11 @@
     return nodeReader.getShortcutPos();
 }
 
-int DynamicPatriciaTriePolicy::getBigramsPositionOfNode(
-        const BinaryDictionaryInfo *const binaryDictionaryInfo,
-        const int nodePos) const {
+int DynamicPatriciaTriePolicy::getBigramsPositionOfNode(const int nodePos) const {
     if (nodePos == NOT_A_VALID_WORD_POS) {
         return NOT_A_DICT_POS;
     }
-    DynamicPatriciaTrieNodeReader nodeReader(binaryDictionaryInfo);
+    DynamicPatriciaTrieNodeReader nodeReader(mBinaryDictionaryInfo, getBigramsStructurePolicy());
     nodeReader.fetchNodeInfoFromBuffer(nodePos);
     if (nodeReader.isDeleted()) {
         return NOT_A_DICT_POS;
diff --git a/native/jni/src/suggest/policyimpl/dictionary/dynamic_patricia_trie_policy.h b/native/jni/src/suggest/policyimpl/dictionary/dynamic_patricia_trie_policy.h
index 6a79771..2386d93 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/dynamic_patricia_trie_policy.h
+++ b/native/jni/src/suggest/policyimpl/dictionary/dynamic_patricia_trie_policy.h
@@ -17,8 +17,11 @@
 #ifndef LATINIME_DYNAMIC_PATRICIA_TRIE_POLICY_H
 #define LATINIME_DYNAMIC_PATRICIA_TRIE_POLICY_H
 
+#include <stdint.h>
+
 #include "defines.h"
-#include "suggest/core/policy/dictionary_structure_policy.h"
+#include "suggest/core/policy/dictionary_structure_with_buffer_policy.h"
+#include "suggest/policyimpl/dictionary/bigrams/bigram_list_policy.h"
 
 namespace latinime {
 
@@ -26,45 +29,47 @@
 class DicNode;
 class DicNodeVector;
 
-class DynamicPatriciaTriePolicy : public DictionaryStructurePolicy {
+class DynamicPatriciaTriePolicy : public DictionaryStructureWithBufferPolicy {
  public:
-    static AK_FORCE_INLINE const DynamicPatriciaTriePolicy *getInstance() {
-        return &sInstance;
-    }
+    DynamicPatriciaTriePolicy(const uint8_t *const dictRoot,
+            const BinaryDictionaryInfo *const binaryDictionaryInfo)
+            : mDictRoot(dictRoot), mBinaryDictionaryInfo(binaryDictionaryInfo),
+              mBigramListPolicy(dictRoot) {}
+
+    ~DynamicPatriciaTriePolicy() {}
 
     AK_FORCE_INLINE int getRootPosition() const {
         return 0;
     }
 
     void createAndGetAllChildNodes(const DicNode *const dicNode,
-            const BinaryDictionaryInfo *const binaryDictionaryInfo,
             const NodeFilter *const nodeFilter, DicNodeVector *const childDicNodes) const;
 
     int getCodePointsAndProbabilityAndReturnCodePointCount(
-            const BinaryDictionaryInfo *const binaryDictionaryInfo,
             const int terminalNodePos, const int maxCodePointCount, int *const outCodePoints,
             int *const outUnigramProbability) const;
 
-    int getTerminalNodePositionOfWord(
-            const BinaryDictionaryInfo *const binaryDictionaryInfo, const int *const inWord,
+    int getTerminalNodePositionOfWord(const int *const inWord,
             const int length, const bool forceLowerCaseSearch) const;
 
-    int getUnigramProbability(const BinaryDictionaryInfo *const binaryDictionaryInfo,
-            const int nodePos) const;
+    int getUnigramProbability(const int nodePos) const;
 
-    int getShortcutPositionOfNode(const BinaryDictionaryInfo *const binaryDictionaryInfo,
-            const int nodePos) const;
+    int getShortcutPositionOfNode(const int nodePos) const;
 
-    int getBigramsPositionOfNode(const BinaryDictionaryInfo *const binaryDictionaryInfo,
-            const int nodePos) const;
+    int getBigramsPositionOfNode(const int nodePos) const;
+
+    const DictionaryBigramsStructurePolicy *getBigramsStructurePolicy() const {
+        return &mBigramListPolicy;
+    }
 
  private:
-    DISALLOW_COPY_AND_ASSIGN(DynamicPatriciaTriePolicy);
-    static const DynamicPatriciaTriePolicy sInstance;
+    DISALLOW_IMPLICIT_CONSTRUCTORS(DynamicPatriciaTriePolicy);
     static const int MAX_CHILD_COUNT_TO_AVOID_INFINITE_LOOP;
 
-    DynamicPatriciaTriePolicy() {}
-    ~DynamicPatriciaTriePolicy() {}
+    const uint8_t *const mDictRoot;
+    // TODO: remove
+    const BinaryDictionaryInfo *const mBinaryDictionaryInfo;
+    const BigramListPolicy mBigramListPolicy;
 };
 } // namespace latinime
 #endif // LATINIME_DYNAMIC_PATRICIA_TRIE_POLICY_H
diff --git a/native/jni/src/suggest/policyimpl/dictionary/patricia_trie_policy.cpp b/native/jni/src/suggest/policyimpl/dictionary/patricia_trie_policy.cpp
index 097f7c8..7001509 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/patricia_trie_policy.cpp
+++ b/native/jni/src/suggest/policyimpl/dictionary/patricia_trie_policy.cpp
@@ -27,48 +27,39 @@
 
 namespace latinime {
 
-const PatriciaTriePolicy PatriciaTriePolicy::sInstance;
-
 void PatriciaTriePolicy::createAndGetAllChildNodes(const DicNode *const dicNode,
-        const BinaryDictionaryInfo *const binaryDictionaryInfo,
         const NodeFilter *const nodeFilter, DicNodeVector *const childDicNodes) const {
     if (!dicNode->hasChildren()) {
         return;
     }
     int nextPos = dicNode->getChildrenPos();
     const int childCount = PatriciaTrieReadingUtils::getGroupCountAndAdvancePosition(
-            binaryDictionaryInfo->getDictRoot(), &nextPos);
+            mDictRoot, &nextPos);
     for (int i = 0; i < childCount; i++) {
-        nextPos = createAndGetLeavingChildNode(dicNode, nextPos, binaryDictionaryInfo,
-                nodeFilter, childDicNodes);
+        nextPos = createAndGetLeavingChildNode(dicNode, nextPos, nodeFilter, childDicNodes);
     }
 }
 
 int PatriciaTriePolicy::getCodePointsAndProbabilityAndReturnCodePointCount(
-        const BinaryDictionaryInfo *const binaryDictionaryInfo,
         const int nodePos, const int maxCodePointCount, int *const outCodePoints,
         int *const outUnigramProbability) const {
-    return BinaryFormat::getCodePointsAndProbabilityAndReturnCodePointCount(
-            binaryDictionaryInfo->getDictRoot(), nodePos,
+    return BinaryFormat::getCodePointsAndProbabilityAndReturnCodePointCount(mDictRoot, nodePos,
             maxCodePointCount, outCodePoints, outUnigramProbability);
 }
 
-int PatriciaTriePolicy::getTerminalNodePositionOfWord(
-        const BinaryDictionaryInfo *const binaryDictionaryInfo, const int *const inWord,
+int PatriciaTriePolicy::getTerminalNodePositionOfWord(const int *const inWord,
         const int length, const bool forceLowerCaseSearch) const {
-    return BinaryFormat::getTerminalPosition(binaryDictionaryInfo->getDictRoot(), inWord,
+    return BinaryFormat::getTerminalPosition(mDictRoot, inWord,
             length, forceLowerCaseSearch);
 }
 
-int PatriciaTriePolicy::getUnigramProbability(
-        const BinaryDictionaryInfo *const binaryDictionaryInfo, const int nodePos) const {
+int PatriciaTriePolicy::getUnigramProbability(const int nodePos) const {
     if (nodePos == NOT_A_VALID_WORD_POS) {
         return NOT_A_PROBABILITY;
     }
-    const uint8_t *const dictRoot = binaryDictionaryInfo->getDictRoot();
     int pos = nodePos;
     const PatriciaTrieReadingUtils::NodeFlags flags =
-            PatriciaTrieReadingUtils::getFlagsAndAdvancePosition(dictRoot, &pos);
+            PatriciaTrieReadingUtils::getFlagsAndAdvancePosition(mDictRoot, &pos);
     if (!PatriciaTrieReadingUtils::isTerminal(flags)) {
         return NOT_A_PROBABILITY;
     }
@@ -79,81 +70,73 @@
         // for shortcuts).
         return NOT_A_PROBABILITY;
     }
-    PatriciaTrieReadingUtils::skipCharacters(dictRoot, flags, MAX_WORD_LENGTH, &pos);
-    return PatriciaTrieReadingUtils::readProbabilityAndAdvancePosition(dictRoot, &pos);
+    PatriciaTrieReadingUtils::skipCharacters(mDictRoot, flags, MAX_WORD_LENGTH, &pos);
+    return PatriciaTrieReadingUtils::readProbabilityAndAdvancePosition(mDictRoot, &pos);
 }
 
-int PatriciaTriePolicy::getShortcutPositionOfNode(
-        const BinaryDictionaryInfo *const binaryDictionaryInfo,
-        const int nodePos) const {
+int PatriciaTriePolicy::getShortcutPositionOfNode(const int nodePos) const {
     if (nodePos == NOT_A_VALID_WORD_POS) {
         return NOT_A_DICT_POS;
     }
-    const uint8_t *const dictRoot = binaryDictionaryInfo->getDictRoot();
     int pos = nodePos;
     const PatriciaTrieReadingUtils::NodeFlags flags =
-            PatriciaTrieReadingUtils::getFlagsAndAdvancePosition(dictRoot, &pos);
+            PatriciaTrieReadingUtils::getFlagsAndAdvancePosition(mDictRoot, &pos);
     if (!PatriciaTrieReadingUtils::hasShortcutTargets(flags)) {
         return NOT_A_DICT_POS;
     }
-    PatriciaTrieReadingUtils::skipCharacters(dictRoot, flags, MAX_WORD_LENGTH, &pos);
+    PatriciaTrieReadingUtils::skipCharacters(mDictRoot, flags, MAX_WORD_LENGTH, &pos);
     if (PatriciaTrieReadingUtils::isTerminal(flags)) {
-        PatriciaTrieReadingUtils::readProbabilityAndAdvancePosition(dictRoot, &pos);
+        PatriciaTrieReadingUtils::readProbabilityAndAdvancePosition(mDictRoot, &pos);
     }
     if (PatriciaTrieReadingUtils::hasChildrenInFlags(flags)) {
-        PatriciaTrieReadingUtils::readChildrenPositionAndAdvancePosition(dictRoot, flags, &pos);
+        PatriciaTrieReadingUtils::readChildrenPositionAndAdvancePosition(mDictRoot, flags, &pos);
     }
     return pos;
 }
 
-int PatriciaTriePolicy::getBigramsPositionOfNode(
-        const BinaryDictionaryInfo *const binaryDictionaryInfo,
-        const int nodePos) const {
+int PatriciaTriePolicy::getBigramsPositionOfNode(const int nodePos) const {
     if (nodePos == NOT_A_VALID_WORD_POS) {
         return NOT_A_DICT_POS;
     }
-    const uint8_t *const dictRoot = binaryDictionaryInfo->getDictRoot();
     int pos = nodePos;
     const PatriciaTrieReadingUtils::NodeFlags flags =
-            PatriciaTrieReadingUtils::getFlagsAndAdvancePosition(dictRoot, &pos);
+            PatriciaTrieReadingUtils::getFlagsAndAdvancePosition(mDictRoot, &pos);
     if (!PatriciaTrieReadingUtils::hasBigrams(flags)) {
         return NOT_A_DICT_POS;
     }
-    PatriciaTrieReadingUtils::skipCharacters(dictRoot, flags, MAX_WORD_LENGTH, &pos);
+    PatriciaTrieReadingUtils::skipCharacters(mDictRoot, flags, MAX_WORD_LENGTH, &pos);
     if (PatriciaTrieReadingUtils::isTerminal(flags)) {
-        PatriciaTrieReadingUtils::readProbabilityAndAdvancePosition(dictRoot, &pos);
+        PatriciaTrieReadingUtils::readProbabilityAndAdvancePosition(mDictRoot, &pos);
     }
     if (PatriciaTrieReadingUtils::hasChildrenInFlags(flags)) {
-        PatriciaTrieReadingUtils::readChildrenPositionAndAdvancePosition(dictRoot, flags, &pos);
+        PatriciaTrieReadingUtils::readChildrenPositionAndAdvancePosition(mDictRoot, flags, &pos);
     }
     if (PatriciaTrieReadingUtils::hasShortcutTargets(flags)) {
-        BinaryDictionaryTerminalAttributesReadingUtils::skipShortcuts(binaryDictionaryInfo, &pos);
+        BinaryDictionaryTerminalAttributesReadingUtils::skipShortcuts(mBinaryDictionaryInfo, &pos);
     }
     return pos;
 }
 
 int PatriciaTriePolicy::createAndGetLeavingChildNode(const DicNode *const dicNode,
-        const int nodePos, const BinaryDictionaryInfo *const binaryDictionaryInfo,
-        const NodeFilter *const childrenFilter, DicNodeVector *childDicNodes) const {
-    const uint8_t *const dictRoot = binaryDictionaryInfo->getDictRoot();
+        const int nodePos,  const NodeFilter *const childrenFilter,
+        DicNodeVector *childDicNodes) const {
     int pos = nodePos;
     const PatriciaTrieReadingUtils::NodeFlags flags =
-            PatriciaTrieReadingUtils::getFlagsAndAdvancePosition(dictRoot, &pos);
+            PatriciaTrieReadingUtils::getFlagsAndAdvancePosition(mDictRoot, &pos);
     int mergedNodeCodePoints[MAX_WORD_LENGTH];
     const int mergedNodeCodePointCount = PatriciaTrieReadingUtils::getCharsAndAdvancePosition(
-            dictRoot, flags, MAX_WORD_LENGTH, mergedNodeCodePoints, &pos);
+            mDictRoot, flags, MAX_WORD_LENGTH, mergedNodeCodePoints, &pos);
     const int probability = (PatriciaTrieReadingUtils::isTerminal(flags))?
-            PatriciaTrieReadingUtils::readProbabilityAndAdvancePosition(dictRoot, &pos)
+            PatriciaTrieReadingUtils::readProbabilityAndAdvancePosition(mDictRoot, &pos)
                     : NOT_A_PROBABILITY;
     const int childrenPos = PatriciaTrieReadingUtils::hasChildrenInFlags(flags) ?
             PatriciaTrieReadingUtils::readChildrenPositionAndAdvancePosition(
-                    dictRoot, flags, &pos) : NOT_A_DICT_POS;
+                    mDictRoot, flags, &pos) : NOT_A_DICT_POS;
     if (PatriciaTrieReadingUtils::hasShortcutTargets(flags)) {
-        BinaryDictionaryTerminalAttributesReadingUtils::skipShortcuts(binaryDictionaryInfo, &pos);
+        BinaryDictionaryTerminalAttributesReadingUtils::skipShortcuts(mBinaryDictionaryInfo, &pos);
     }
     if (PatriciaTrieReadingUtils::hasBigrams(flags)) {
-        BinaryDictionaryTerminalAttributesReadingUtils::skipExistingBigrams(
-                binaryDictionaryInfo, &pos);
+        getBigramsStructurePolicy()->skipAllBigrams(&pos);
     }
     if (!childrenFilter->isFilteredOut(mergedNodeCodePoints[0])) {
         childDicNodes->pushLeavingChild(dicNode, nodePos, childrenPos, probability,
diff --git a/native/jni/src/suggest/policyimpl/dictionary/patricia_trie_policy.h b/native/jni/src/suggest/policyimpl/dictionary/patricia_trie_policy.h
index 71f256e..bebee39 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/patricia_trie_policy.h
+++ b/native/jni/src/suggest/policyimpl/dictionary/patricia_trie_policy.h
@@ -17,52 +17,60 @@
 #ifndef LATINIME_PATRICIA_TRIE_POLICY_H
 #define LATINIME_PATRICIA_TRIE_POLICY_H
 
+#include <stdint.h>
+
 #include "defines.h"
-#include "suggest/core/policy/dictionary_structure_policy.h"
+#include "suggest/core/policy/dictionary_structure_with_buffer_policy.h"
+#include "suggest/policyimpl/dictionary/bigrams/bigram_list_policy.h"
 
 namespace latinime {
 
-class PatriciaTriePolicy : public DictionaryStructurePolicy {
+class BinaryDictionaryInfo;
+class DicNode;
+class DicNodeVector;
+
+class PatriciaTriePolicy : public DictionaryStructureWithBufferPolicy {
  public:
-    static AK_FORCE_INLINE const PatriciaTriePolicy *getInstance() {
-        return &sInstance;
-    }
+    PatriciaTriePolicy(const uint8_t *const dictRoot,
+            const BinaryDictionaryInfo *const binaryDictionaryInfo)
+            : mDictRoot(dictRoot), mBinaryDictionaryInfo(binaryDictionaryInfo),
+              mBigramListPolicy(dictRoot) {}
+
+    ~PatriciaTriePolicy() {}
 
     AK_FORCE_INLINE int getRootPosition() const {
         return 0;
     }
 
     void createAndGetAllChildNodes(const DicNode *const dicNode,
-            const BinaryDictionaryInfo *const binaryDictionaryInfo,
             const NodeFilter *const nodeFilter, DicNodeVector *const childDicNodes) const;
 
     int getCodePointsAndProbabilityAndReturnCodePointCount(
-            const BinaryDictionaryInfo *const binaryDictionaryInfo,
             const int terminalNodePos, const int maxCodePointCount, int *const outCodePoints,
             int *const outUnigramProbability) const;
 
-    int getTerminalNodePositionOfWord(
-            const BinaryDictionaryInfo *const binaryDictionaryInfo, const int *const inWord,
+    int getTerminalNodePositionOfWord(const int *const inWord,
             const int length, const bool forceLowerCaseSearch) const;
 
-    int getUnigramProbability(const BinaryDictionaryInfo *const binaryDictionaryInfo,
-            const int nodePos) const;
+    int getUnigramProbability(const int nodePos) const;
 
-    int getShortcutPositionOfNode(const BinaryDictionaryInfo *const binaryDictionaryInfo,
-            const int nodePos) const;
+    int getShortcutPositionOfNode(const int nodePos) const;
 
-    int getBigramsPositionOfNode(const BinaryDictionaryInfo *const binaryDictionaryInfo,
-            const int nodePos) const;
+    int getBigramsPositionOfNode(const int nodePos) const;
+
+    const DictionaryBigramsStructurePolicy *getBigramsStructurePolicy() const {
+        return &mBigramListPolicy;
+    }
 
  private:
-    DISALLOW_COPY_AND_ASSIGN(PatriciaTriePolicy);
-    static const PatriciaTriePolicy sInstance;
+    DISALLOW_IMPLICIT_CONSTRUCTORS(PatriciaTriePolicy);
 
-    PatriciaTriePolicy() {}
-    ~PatriciaTriePolicy() {}
+    const uint8_t *const mDictRoot;
+    // TODO: remove
+    const BinaryDictionaryInfo *const mBinaryDictionaryInfo;
+    const BigramListPolicy mBigramListPolicy;
 
     int createAndGetLeavingChildNode(const DicNode *const dicNode, const int nodePos,
-            const BinaryDictionaryInfo *const binaryDictionaryInfo,
             const NodeFilter *const nodeFilter, DicNodeVector *const childDicNodes) const;
 };
 } // namespace latinime