Merge "Introduce DynamicPatriciaTrieReadingHelper."
diff --git a/java/res/layout/input_view.xml b/java/res/layout/input_view.xml
index 86bd1e6..0b682d1 100644
--- a/java/res/layout/input_view.xml
+++ b/java/res/layout/input_view.xml
@@ -24,13 +24,17 @@
     android:layout_height="wrap_content"
     android:gravity="bottom|center_horizontal"
     android:orientation="vertical" >
-    <include
-        layout="@layout/emoji_keyboard_view" />
+    <!-- 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" />
     <LinearLayout
         android:id="@+id/main_keyboard_frame"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
         android:orientation="vertical" >
+
         <!-- 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
@@ -38,15 +42,19 @@
             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_width="wrap_content"
+            android:layout_width="match_parent"
             android:layout_height="wrap_content" />
     </LinearLayout>
+    <include
+        layout="@layout/emoji_keyboard_view" />
 </com.android.inputmethod.latin.InputView>
diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java b/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java
index 0208249..c319c57 100644
--- a/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java
+++ b/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java
@@ -308,6 +308,20 @@
         mState.onCodeInput(code, mLatinIME.getCurrentAutoCapsState());
     }
 
+    public boolean isShowingMoreKeysPanel() {
+        if (mEmojiKeyboardView.getVisibility() == View.VISIBLE) {
+            return false;
+        }
+        return mKeyboardView.isShowingMoreKeysPanel();
+    }
+
+    public View getVisibleKeyboardView() {
+        if (mEmojiKeyboardView.getVisibility() == View.VISIBLE) {
+            return mEmojiKeyboardView;
+        }
+        return mKeyboardView;
+    }
+
     public MainKeyboardView getMainKeyboardView() {
         return mKeyboardView;
     }
diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java
index 27a1739..eee631e 100644
--- a/java/src/com/android/inputmethod/latin/LatinIME.java
+++ b/java/src/com/android/inputmethod/latin/LatinIME.java
@@ -31,6 +31,7 @@
 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;
@@ -50,6 +51,7 @@
 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;
@@ -153,8 +155,8 @@
 
     private final Settings mSettings;
 
-    private View mInputView;
-    private int mInputViewMinHeight;
+    private View mExtractArea;
+    private View mKeyPreviewBackingView;
     private SuggestionStripView mSuggestionStripView;
     // Never null
     private SuggestedWords mSuggestedWords = SuggestedWords.EMPTY;
@@ -673,25 +675,17 @@
         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 inputView) {
-        super.setInputView(inputView);
-        mInputView = inputView;
-        setInputViewMinHeight(0);
-        mSuggestionStripView = (SuggestionStripView)inputView.findViewById(
-                R.id.suggestion_strip_view);
-        if (mSuggestionStripView != null) {
-            mSuggestionStripView.setListener(this, inputView);
-        }
+    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);
         if (LatinImeLogger.sVISUALDEBUG) {
-            inputView.setBackgroundColor(0x10FF0000);
+            mKeyPreviewBackingView.setBackgroundColor(0x10FF0000);
         }
     }
 
@@ -1169,11 +1163,6 @@
                 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);
-            }
         }
     }
 
@@ -1181,37 +1170,66 @@
         setSuggestionStripShownInternal(shown, /* needsInputViewShown */true);
     }
 
+    private int getAdjustedBackingViewHeight() {
+        final int currentHeight = mKeyPreviewBackingView.getHeight();
+        if (currentHeight > 0) {
+            return currentHeight;
+        }
+
+        final View visibleKeyboardView = mKeyboardSwitcher.getVisibleKeyboardView();
+        if (visibleKeyboardView == null) {
+            return 0;
+        }
+        // TODO: !!!!!!!!!!!!!!!!!!!! Handle different backing view heights between the main   !!!
+        // keyboard and the emoji keyboard. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+        final int keyboardHeight = visibleKeyboardView.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);
-        final MainKeyboardView mainKeyboardView = mKeyboardSwitcher.getMainKeyboardView();
-        if (mainKeyboardView == null || mSuggestionStripView == null) {
+        final View visibleKeyboardView = mKeyboardSwitcher.getVisibleKeyboardView();
+        if (visibleKeyboardView == null || mSuggestionStripView == null) {
             return;
         }
-        // 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;
+        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;
         // Need to set touchable region only if input view is being shown
-        if (mainKeyboardView.isShown()) {
-            final int touchLeft = 0;
-            final int touchTop = visibleTop;
-            final int touchRight = touchLeft + mainKeyboardView.getWidth();
-            final int touchBottom = contentTop + mainKeyboardView.getHeight()
+        if (visibleKeyboardView.isShown()) {
+            if (mSuggestionStripView.getVisibility() == View.VISIBLE) {
+                visibleTopY -= suggestionsHeight;
+            }
+            final int touchY = mKeyboardSwitcher.isShowingMoreKeysPanel() ? 0 : visibleTopY;
+            final int touchWidth = visibleKeyboardView.getWidth();
+            final int touchHeight = visibleKeyboardView.getHeight() + extraHeight
                     // 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
@@ -1234,11 +1252,11 @@
     @Override
     public void updateFullscreenMode() {
         super.updateFullscreenMode();
-        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);
-        }
+
+        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);
     }
 
     // This will reset the whole input state to the starting state. It will clear
diff --git a/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripLayoutHelper.java b/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripLayoutHelper.java
index aca2492..8d2689a 100644
--- a/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripLayoutHelper.java
+++ b/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripLayoutHelper.java
@@ -165,9 +165,20 @@
         return mMaxMoreSuggestionsRow;
     }
 
-    public void setMoreSuggestionsHeight(final int remainingHeight) {
+    private int getMoreSuggestionsHeight() {
+        return mMaxMoreSuggestionsRow * mMoreSuggestionsRowHeight + mMoreSuggestionsBottomGap;
+    }
+
+    public int setMoreSuggestionsHeight(final int remainingHeight) {
+        final int currentHeight = getMoreSuggestionsHeight();
+        if (currentHeight <= remainingHeight) {
+            return currentHeight;
+        }
+
         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 badc942..75f17c5 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 void setMoreSuggestionsHeight(final int remainingHeight) {
-        mLayoutHelper.setMoreSuggestionsHeight(remainingHeight);
+    public int setMoreSuggestionsHeight(final int remainingHeight) {
+        return mLayoutHelper.setMoreSuggestionsHeight(remainingHeight);
     }
 
     public boolean isShowingAddToDictionaryHint() {