From a099a3e341d8de0512c8bb8f4dbe352456f2a4a4 Mon Sep 17 00:00:00 2001
From: Yuichiro Hanada <yhanada@google.com>
Date: Fri, 13 Sep 2013 17:32:51 +0900
Subject: [PATCH] Add shutdown and isTerminated to PrioritizedSerialExecutor.

Change-Id: Id185224d135c8571a39efe8a41a66ce769142903
---
 .../latin/ExpandableBinaryDictionary.java     | 10 ++++++
 .../utils/PrioritizedSerialExecutor.java      | 33 +++++++++++++++----
 .../UserHistoryDictionaryTests.java           | 21 ++++++++++--
 3 files changed, 55 insertions(+), 9 deletions(-)

diff --git a/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java b/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java
index c884e7b1f9..2a90764362 100644
--- a/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java
+++ b/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java
@@ -617,4 +617,14 @@ abstract public class ExpandableBinaryDictionary extends Dictionary {
         });
         return holder.get(false, TIMEOUT_FOR_READ_OPS_IN_MILLISECONDS);
     }
+
+    @UsedForTesting
+    public void shutdownExecutorForTests() {
+        getExecutor(mFilename).shutdown();
+    }
+
+    @UsedForTesting
+    public boolean isTerminatedForTests() {
+        return getExecutor(mFilename).isTerminated();
+    }
 }
diff --git a/java/src/com/android/inputmethod/latin/utils/PrioritizedSerialExecutor.java b/java/src/com/android/inputmethod/latin/utils/PrioritizedSerialExecutor.java
index 3c1db65296..5dc0b58938 100644
--- a/java/src/com/android/inputmethod/latin/utils/PrioritizedSerialExecutor.java
+++ b/java/src/com/android/inputmethod/latin/utils/PrioritizedSerialExecutor.java
@@ -31,6 +31,7 @@ public class PrioritizedSerialExecutor {
     private static final int TASK_QUEUE_CAPACITY = 1000;
     private final Queue<Runnable> mTasks;
     private final Queue<Runnable> mPrioritizedTasks;
+    private boolean mIsShutdown;
 
     // The task which is running now.
     private Runnable mActive;
@@ -38,6 +39,7 @@ public class PrioritizedSerialExecutor {
     public PrioritizedSerialExecutor() {
         mTasks = new ArrayDeque<Runnable>(TASK_QUEUE_CAPACITY);
         mPrioritizedTasks = new ArrayDeque<Runnable>(TASK_QUEUE_CAPACITY);
+        mIsShutdown = false;
     }
 
     /**
@@ -56,9 +58,11 @@ public class PrioritizedSerialExecutor {
      */
     public void execute(final Runnable r) {
         synchronized(mLock) {
-            mTasks.offer(r);
-            if (mActive == null) {
-                scheduleNext();
+            if (!mIsShutdown) {
+                mTasks.offer(r);
+                if (mActive == null) {
+                    scheduleNext();
+                }
             }
         }
     }
@@ -69,9 +73,11 @@ public class PrioritizedSerialExecutor {
      */
     public void executePrioritized(final Runnable r) {
         synchronized(mLock) {
-            mPrioritizedTasks.offer(r);
-            if (mActive ==  null) {
-                scheduleNext();
+            if (!mIsShutdown) {
+                mPrioritizedTasks.offer(r);
+                if (mActive ==  null) {
+                    scheduleNext();
+                }
             }
         }
     }
@@ -123,4 +129,19 @@ public class PrioritizedSerialExecutor {
             execute(newTask);
         }
     }
+
+    public void shutdown() {
+        synchronized(mLock) {
+            mIsShutdown = true;
+        }
+    }
+
+    public boolean isTerminated() {
+        synchronized(mLock) {
+            if (!mIsShutdown) {
+                return false;
+            }
+            return mPrioritizedTasks.isEmpty() && mTasks.isEmpty() && mActive == null;
+        }
+    }
 }
diff --git a/tests/src/com/android/inputmethod/latin/personalization/UserHistoryDictionaryTests.java b/tests/src/com/android/inputmethod/latin/personalization/UserHistoryDictionaryTests.java
index d15e88bdb5..bf44a14244 100644
--- a/tests/src/com/android/inputmethod/latin/personalization/UserHistoryDictionaryTests.java
+++ b/tests/src/com/android/inputmethod/latin/personalization/UserHistoryDictionaryTests.java
@@ -46,6 +46,7 @@ public class UserHistoryDictionaryTests extends AndroidTestCase {
     };
 
     private static final int MIN_USER_HISTORY_DICTIONARY_FILE_SIZE = 1000;
+    private static final int WAIT_TERMINATING_IN_MILLISECONDS = 100;
 
     @Override
     public void setUp() {
@@ -122,8 +123,14 @@ public class UserHistoryDictionaryTests extends AndroidTestCase {
                     true /* checksContents */);
         } finally {
             try {
+                final UserHistoryPredictionDictionary dict =
+                        PersonalizationHelper.getUserHistoryPredictionDictionary(getContext(),
+                                testFilenameSuffix, mPrefs);
                 Log.d(TAG, "waiting for writing ...");
-                Thread.sleep(TimeUnit.MILLISECONDS.convert(5L, TimeUnit.SECONDS));
+                dict.shutdownExecutorForTests();
+                while (!dict.isTerminatedForTests()) {
+                    Thread.sleep(WAIT_TERMINATING_IN_MILLISECONDS);
+                }
             } catch (InterruptedException e) {
                 Log.d(TAG, "InterruptedException: " + e);
             }
@@ -146,11 +153,11 @@ public class UserHistoryDictionaryTests extends AndroidTestCase {
         final int numberOfWordsInsertedForEachLanguageSwitch = 100;
 
         final File dictFiles[] = new File[numberOfLanguages];
+        final String testFilenameSuffixes[] = new String[numberOfLanguages];
         try {
             final Random random = new Random(123456);
 
             // Create filename suffixes for this test.
-            String testFilenameSuffixes[] = new String[numberOfLanguages];
             for (int i = 0; i < numberOfLanguages; i++) {
                 testFilenameSuffixes[i] = "testSwitchingLanguages" + i;
                 final String fileName = UserHistoryPredictionDictionary.NAME + "." +
@@ -174,7 +181,15 @@ public class UserHistoryDictionaryTests extends AndroidTestCase {
         } finally {
             try {
                 Log.d(TAG, "waiting for writing ...");
-                Thread.sleep(TimeUnit.MILLISECONDS.convert(5L, TimeUnit.SECONDS));
+                for (int i = 0; i < numberOfLanguages; i++) {
+                    final UserHistoryPredictionDictionary dict =
+                            PersonalizationHelper.getUserHistoryPredictionDictionary(getContext(),
+                                    testFilenameSuffixes[i], mPrefs);
+                    dict.shutdownExecutorForTests();
+                    while (!dict.isTerminatedForTests()) {
+                        Thread.sleep(WAIT_TERMINATING_IN_MILLISECONDS);
+                    }
+                }
             } catch (InterruptedException e) {
                 Log.d(TAG, "InterruptedException: " + e);
             }
-- 
GitLab