Merge "Do not throw NPE if the dictionary info is not available on db"
diff --git a/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java b/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java
index 37899d2..9070957 100644
--- a/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java
+++ b/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java
@@ -650,7 +650,8 @@
         reloadDictionaryIfRequired();
         final String dictName = mDictName;
         final File dictFile = mDictFile;
-        final AsyncResultHolder<DictionaryStats> result = new AsyncResultHolder<>();
+        final AsyncResultHolder<DictionaryStats> result =
+                new AsyncResultHolder<>("DictionaryStats");
         asyncExecuteTaskWithLock(mLock.readLock(), new Runnable() {
             @Override
             public void run() {
@@ -724,7 +725,8 @@
      */
     public WordProperty[] getWordPropertiesForSyncing() {
         reloadDictionaryIfRequired();
-        final AsyncResultHolder<WordProperty[]> result = new AsyncResultHolder<>();
+        final AsyncResultHolder<WordProperty[]> result =
+                new AsyncResultHolder<>("WordPropertiesForSync");
         asyncExecuteTaskWithLock(mLock.readLock(), new Runnable() {
             @Override
             public void run() {
diff --git a/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java b/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java
index 5f5f083..9ceb371 100644
--- a/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java
+++ b/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java
@@ -1436,7 +1436,7 @@
             return;
         }
 
-        final AsyncResultHolder<SuggestedWords> holder = new AsyncResultHolder<>();
+        final AsyncResultHolder<SuggestedWords> holder = new AsyncResultHolder<>("Suggest");
         mInputLogicHandler.getSuggestedWords(inputStyle, SuggestedWords.NOT_A_SEQUENCE_NUMBER,
                 new OnGetSuggestedWordsCallback() {
                     @Override
@@ -2104,24 +2104,60 @@
      */
     private void commitChosenWord(final SettingsValues settingsValues, final String chosenWord,
             final int commitType, final String separatorString) {
+        long startTimeMillis = 0;
+        if (DebugFlags.DEBUG_ENABLED) {
+            startTimeMillis = System.currentTimeMillis();
+            Log.d(TAG, "commitChosenWord() : [" + chosenWord + "]");
+        }
         final SuggestedWords suggestedWords = mSuggestedWords;
         final CharSequence chosenWordWithSuggestions =
                 SuggestionSpanUtils.getTextWithSuggestionSpan(mLatinIME, chosenWord,
                         suggestedWords);
+        if (DebugFlags.DEBUG_ENABLED) {
+            long runTimeMillis = System.currentTimeMillis() - startTimeMillis;
+            Log.d(TAG, "commitChosenWord() : " + runTimeMillis + " ms to run "
+                    + "SuggestionSpanUtils.getTextWithSuggestionSpan()");
+            startTimeMillis = System.currentTimeMillis();
+        }
         // When we are composing word, get n-gram context from the 2nd previous word because the
         // 1st previous word is the word to be committed. Otherwise get n-gram context from the 1st
         // previous word.
         final NgramContext ngramContext = mConnection.getNgramContextFromNthPreviousWord(
                 settingsValues.mSpacingAndPunctuations, mWordComposer.isComposingWord() ? 2 : 1);
+        if (DebugFlags.DEBUG_ENABLED) {
+            long runTimeMillis = System.currentTimeMillis() - startTimeMillis;
+            Log.d(TAG, "commitChosenWord() : " + runTimeMillis + " ms to run "
+                    + "Connection.getNgramContextFromNthPreviousWord()");
+            Log.d(TAG, "commitChosenWord() : NgramContext = " + ngramContext);
+            startTimeMillis = System.currentTimeMillis();
+        }
         mConnection.commitText(chosenWordWithSuggestions, 1);
+        if (DebugFlags.DEBUG_ENABLED) {
+            long runTimeMillis = System.currentTimeMillis() - startTimeMillis;
+            Log.d(TAG, "commitChosenWord() : " + runTimeMillis + " ms to run "
+                    + "Connection.commitText");
+            startTimeMillis = System.currentTimeMillis();
+        }
         // Add the word to the user history dictionary
         performAdditionToUserHistoryDictionary(settingsValues, chosenWord, ngramContext);
+        if (DebugFlags.DEBUG_ENABLED) {
+            long runTimeMillis = System.currentTimeMillis() - startTimeMillis;
+            Log.d(TAG, "commitChosenWord() : " + runTimeMillis + " ms to run "
+                    + "performAdditionToUserHistoryDictionary()");
+            startTimeMillis = System.currentTimeMillis();
+        }
         // TODO: figure out here if this is an auto-correct or if the best word is actually
         // what user typed. Note: currently this is done much later in
         // LastComposedWord#didCommitTypedWord by string equality of the remembered
         // strings.
         mLastComposedWord = mWordComposer.commitWord(commitType,
                 chosenWordWithSuggestions, separatorString, ngramContext);
+        if (DebugFlags.DEBUG_ENABLED) {
+            long runTimeMillis = System.currentTimeMillis() - startTimeMillis;
+            Log.d(TAG, "commitChosenWord() : " + runTimeMillis + " ms to run "
+                    + "WordComposer.commitWord()");
+            startTimeMillis = System.currentTimeMillis();
+        }
     }
 
     /**
diff --git a/java/src/com/android/inputmethod/latin/settings/SettingsValues.java b/java/src/com/android/inputmethod/latin/settings/SettingsValues.java
index d112e72..94573a6 100644
--- a/java/src/com/android/inputmethod/latin/settings/SettingsValues.java
+++ b/java/src/com/android/inputmethod/latin/settings/SettingsValues.java
@@ -209,7 +209,7 @@
                 prefs, DebugSettings.PREF_KEY_PREVIEW_DISMISS_END_Y_SCALE,
                 defaultKeyPreviewDismissEndScale);
         mDisplayOrientation = res.getConfiguration().orientation;
-        mAppWorkarounds = new AsyncResultHolder<>();
+        mAppWorkarounds = new AsyncResultHolder<>("AppWorkarounds");
         final PackageInfo packageInfo = TargetPackageInfoGetterTask.getCachedPackageInfo(
                 mInputAttributes.mTargetApplicationPackageName);
         if (null != packageInfo) {
diff --git a/java/src/com/android/inputmethod/latin/utils/AsyncResultHolder.java b/java/src/com/android/inputmethod/latin/utils/AsyncResultHolder.java
index 952ac2a..1525f2d 100644
--- a/java/src/com/android/inputmethod/latin/utils/AsyncResultHolder.java
+++ b/java/src/com/android/inputmethod/latin/utils/AsyncResultHolder.java
@@ -16,6 +16,8 @@
 
 package com.android.inputmethod.latin.utils;
 
+import android.util.Log;
+
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
 
@@ -29,9 +31,11 @@
     private final Object mLock = new Object();
 
     private E mResult;
+    private final String mTag;
     private final CountDownLatch mLatch;
 
-    public AsyncResultHolder() {
+    public AsyncResultHolder(final String tag) {
+        mTag = tag;
         mLatch = new CountDownLatch(1);
     }
 
@@ -61,6 +65,7 @@
         try {
             return mLatch.await(timeOut, TimeUnit.MILLISECONDS) ? mResult : defaultValue;
         } catch (InterruptedException e) {
+            Log.w(mTag, "get() : Interrupted after " + timeOut + " ms");
             return defaultValue;
         }
     }
diff --git a/tests/src/com/android/inputmethod/latin/utils/AsyncResultHolderTests.java b/tests/src/com/android/inputmethod/latin/utils/AsyncResultHolderTests.java
index 170d643..c214b5f 100644
--- a/tests/src/com/android/inputmethod/latin/utils/AsyncResultHolderTests.java
+++ b/tests/src/com/android/inputmethod/latin/utils/AsyncResultHolderTests.java
@@ -45,27 +45,27 @@
     }
 
     public void testGetWithoutSet() {
-        final AsyncResultHolder<Integer> holder = new AsyncResultHolder<>();
+        final AsyncResultHolder<Integer> holder = new AsyncResultHolder<>("Test");
         final int resultValue = holder.get(DEFAULT_VALUE, TIMEOUT_IN_MILLISECONDS);
         assertEquals(DEFAULT_VALUE, resultValue);
     }
 
     public void testGetBeforeSet() {
-        final AsyncResultHolder<Integer> holder = new AsyncResultHolder<>();
+        final AsyncResultHolder<Integer> holder = new AsyncResultHolder<>("Test");
         setAfterGivenTime(holder, SET_VALUE, TIMEOUT_IN_MILLISECONDS + MARGIN_IN_MILLISECONDS);
         final int resultValue = holder.get(DEFAULT_VALUE, TIMEOUT_IN_MILLISECONDS);
         assertEquals(DEFAULT_VALUE, resultValue);
     }
 
     public void testGetAfterSet() {
-        final AsyncResultHolder<Integer> holder = new AsyncResultHolder<>();
+        final AsyncResultHolder<Integer> holder = new AsyncResultHolder<>("Test");
         holder.set(SET_VALUE);
         final int resultValue = holder.get(DEFAULT_VALUE, TIMEOUT_IN_MILLISECONDS);
         assertEquals(SET_VALUE, resultValue);
     }
 
     public void testGetBeforeTimeout() {
-        final AsyncResultHolder<Integer> holder = new AsyncResultHolder<>();
+        final AsyncResultHolder<Integer> holder = new AsyncResultHolder<>("Test");
         setAfterGivenTime(holder, SET_VALUE, TIMEOUT_IN_MILLISECONDS - MARGIN_IN_MILLISECONDS);
         final int resultValue = holder.get(DEFAULT_VALUE, TIMEOUT_IN_MILLISECONDS);
         assertEquals(SET_VALUE, resultValue);