am 639837f8: Merge "Postponing memory deallocation after onFinishInputView"

* commit '639837f85d648443359ac1883aa6f9c11e287c33':
  Postponing memory deallocation after onFinishInputView
diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java
index 8e93761..64e65ef 100644
--- a/java/src/com/android/inputmethod/latin/LatinIME.java
+++ b/java/src/com/android/inputmethod/latin/LatinIME.java
@@ -119,12 +119,10 @@
     private static boolean DEBUG = false;
 
     private static final int EXTENDED_TOUCHABLE_REGION_HEIGHT = 100;
-
-    private static final int PENDING_IMS_CALLBACK_DURATION = 800;
-
-    private static final int DELAY_WAIT_FOR_DICTIONARY_LOAD = 2000; // 2s
-
     private static final int PERIOD_FOR_AUDIO_AND_HAPTIC_FEEDBACK_IN_KEY_REPEAT = 2;
+    private static final int PENDING_IMS_CALLBACK_DURATION_MILLIS = 800;
+    private static final long DELAY_WAIT_FOR_DICTIONARY_LOAD_MILLIS = TimeUnit.SECONDS.toMillis(2);
+    private static final long DELAY_DEALLOCATE_MEMORY_MILLIS = TimeUnit.SECONDS.toMillis(10);
 
     /**
      * The name of the scheme used by the Package Manager to warn of a new package installation,
@@ -192,8 +190,9 @@
         private static final int MSG_UPDATE_TAIL_BATCH_INPUT_COMPLETED = 6;
         private static final int MSG_RESET_CACHES = 7;
         private static final int MSG_WAIT_FOR_DICTIONARY_LOAD = 8;
+        private static final int MSG_DEALLOCATE_MEMORY = 9;
         // Update this when adding new messages
-        private static final int MSG_LAST = MSG_WAIT_FOR_DICTIONARY_LOAD;
+        private static final int MSG_LAST = MSG_DEALLOCATE_MEMORY;
 
         private static final int ARG1_NOT_GESTURE_INPUT = 0;
         private static final int ARG1_DISMISS_GESTURE_FLOATING_PREVIEW_TEXT = 1;
@@ -280,6 +279,9 @@
             case MSG_WAIT_FOR_DICTIONARY_LOAD:
                 Log.i(TAG, "Timeout waiting for dictionary load");
                 break;
+            case MSG_DEALLOCATE_MEMORY:
+                latinIme.deallocateMemory();
+                break;
             }
         }
 
@@ -317,7 +319,7 @@
 
         public void postWaitForDictionaryLoad() {
             sendMessageDelayed(obtainMessage(MSG_WAIT_FOR_DICTIONARY_LOAD),
-                    DELAY_WAIT_FOR_DICTIONARY_LOAD);
+                    DELAY_WAIT_FOR_DICTIONARY_LOAD_MILLIS);
         }
 
         public void cancelWaitForDictionaryLoad() {
@@ -346,6 +348,19 @@
                     mDelayInMillisecondsToUpdateShiftState);
         }
 
+        public void postDeallocateMemory() {
+            sendMessageDelayed(obtainMessage(MSG_DEALLOCATE_MEMORY),
+                    DELAY_DEALLOCATE_MEMORY_MILLIS);
+        }
+
+        public void cancelDeallocateMemory() {
+            removeMessages(MSG_DEALLOCATE_MEMORY);
+        }
+
+        public boolean hasPendingDeallocateMemory() {
+            return hasMessages(MSG_DEALLOCATE_MEMORY);
+        }
+
         @UsedForTesting
         public void removeAllMessages() {
             for (int i = 0; i <= MSG_LAST; ++i) {
@@ -443,7 +458,7 @@
                     mPendingSuccessiveImsCallback = false;
                     resetPendingImsCallback();
                     sendMessageDelayed(obtainMessage(MSG_PENDING_IMS_CALLBACK),
-                            PENDING_IMS_CALLBACK_DURATION);
+                            PENDING_IMS_CALLBACK_DURATION_MILLIS);
                 }
                 final LatinIME latinIme = getOwnerInstance();
                 if (latinIme != null) {
@@ -451,6 +466,7 @@
                     latinIme.onStartInputViewInternal(editorInfo, restarting);
                     mAppliedEditorInfo = editorInfo;
                 }
+                cancelDeallocateMemory();
             }
         }
 
@@ -464,6 +480,9 @@
                     latinIme.onFinishInputViewInternal(finishingInput);
                     mAppliedEditorInfo = null;
                 }
+                if (!hasPendingDeallocateMemory()) {
+                    postDeallocateMemory();
+                }
             }
         }
 
@@ -1026,13 +1045,16 @@
     }
 
     private void cleanupInternalStateForFinishInput() {
-        mKeyboardSwitcher.deallocateMemory();
         // Remove pending messages related to update suggestions
         mHandler.cancelUpdateSuggestionStrip();
         // Should do the following in onFinishInputInternal but until JB MR2 it's not called :(
         mInputLogic.finishInput();
     }
 
+    protected void deallocateMemory() {
+        mKeyboardSwitcher.deallocateMemory();
+    }
+
     @Override
     public void onUpdateSelection(final int oldSelStart, final int oldSelEnd,
             final int newSelStart, final int newSelEnd,
diff --git a/tests/src/com/android/inputmethod/latin/LatinIMEForTests.java b/tests/src/com/android/inputmethod/latin/LatinIMEForTests.java
index e47c557..035c8d7 100644
--- a/tests/src/com/android/inputmethod/latin/LatinIMEForTests.java
+++ b/tests/src/com/android/inputmethod/latin/LatinIMEForTests.java
@@ -21,4 +21,16 @@
     public boolean isInputViewShown() {
         return true;
     }
+
+    private boolean deallocateMemoryWasPerformed = false;
+
+    @Override
+    protected void deallocateMemory() {
+        super.deallocateMemory();
+        deallocateMemoryWasPerformed = true;
+    }
+
+    public boolean getDeallocateMemoryWasPerformed() {
+        return deallocateMemoryWasPerformed;
+    }
 }
diff --git a/tests/src/com/android/inputmethod/latin/LatinImeTests.java b/tests/src/com/android/inputmethod/latin/LatinImeTests.java
new file mode 100644
index 0000000..c6f6313
--- /dev/null
+++ b/tests/src/com/android/inputmethod/latin/LatinImeTests.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.inputmethod.latin;
+
+import android.test.suitebuilder.annotation.LargeTest;
+
+@LargeTest
+public class LatinImeTests extends InputTestsBase {
+    public void testDeferredDeallocation_doesntHappenBeforeTimeout() {
+        mLatinIME.mHandler.onFinishInputView(true);
+        runMessages();
+        sleep(1000); // 1s
+        runMessages();
+        assertFalse("memory deallocation performed before timeout passed",
+                ((LatinIMEForTests)mLatinIME).getDeallocateMemoryWasPerformed());
+    }
+
+    public void testDeferredDeallocation_doesHappenAfterTimeout() {
+        mLatinIME.mHandler.onFinishInputView(true);
+        runMessages();
+        sleep(11000); // 11s (timeout is at 10s)
+        runMessages();
+        assertTrue("memory deallocation not performed although timeout passed",
+                ((LatinIMEForTests)mLatinIME).getDeallocateMemoryWasPerformed());
+    }
+}