From bd1bc4067ff87ce1a21d12a48b1695fe58c8dd4d Mon Sep 17 00:00:00 2001
From: Dan Zivkovic <zivkovic@google.com>
Date: Mon, 9 Mar 2015 14:48:51 -0700
Subject: [PATCH] ExecutorUtils lets use schedule a runnable chain.

Bug 19625976.

Change-Id: Iebbef7fed57a381498301dcf26fefa27d06802f7
---
 .../latin/ContactsContentObserver.java        |  4 +-
 .../latin/utils/ExecutorUtils.java            | 60 +++++++++++--------
 2 files changed, 37 insertions(+), 27 deletions(-)

diff --git a/java/src/com/android/inputmethod/latin/ContactsContentObserver.java b/java/src/com/android/inputmethod/latin/ContactsContentObserver.java
index 04c1cf3339..4a8d1133b2 100644
--- a/java/src/com/android/inputmethod/latin/ContactsContentObserver.java
+++ b/java/src/com/android/inputmethod/latin/ContactsContentObserver.java
@@ -56,8 +56,8 @@ public class ContactsContentObserver implements Runnable {
         mContentObserver = new ContentObserver(null /* handler */) {
             @Override
             public void onChange(boolean self) {
-                ExecutorUtils.getBackgroundExecutor()
-                        .execute(ContactsContentObserver.this);
+                // TODO(zivkovic): Schedule a separate task to reset the decoder.
+                ExecutorUtils.getBackgroundExecutor().execute(ContactsContentObserver.this);
             }
         };
         final ContentResolver contentResolver = mContext.getContentResolver();
diff --git a/java/src/com/android/inputmethod/latin/utils/ExecutorUtils.java b/java/src/com/android/inputmethod/latin/utils/ExecutorUtils.java
index b21538caa0..b04a820aad 100644
--- a/java/src/com/android/inputmethod/latin/utils/ExecutorUtils.java
+++ b/java/src/com/android/inputmethod/latin/utils/ExecutorUtils.java
@@ -23,7 +23,9 @@ import com.android.inputmethod.annotations.UsedForTesting;
 import java.lang.Thread.UncaughtExceptionHandler;
 import java.util.concurrent.Executors;
 import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.ScheduledFuture;
 import java.util.concurrent.ThreadFactory;
+import java.util.concurrent.TimeUnit;
 
 /**
  * Utilities to manage executors.
@@ -35,6 +37,20 @@ public class ExecutorUtils {
     private static final ScheduledExecutorService sExecutorService =
             Executors.newSingleThreadScheduledExecutor(new ExecutorFactory());
 
+    private static class ExecutorFactory implements ThreadFactory {
+        @Override
+        public Thread newThread(final Runnable runnable) {
+            Thread thread = new Thread(runnable, TAG);
+            thread.setUncaughtExceptionHandler(new UncaughtExceptionHandler() {
+                @Override
+                public void uncaughtException(Thread thread, Throwable ex) {
+                    Log.w(TAG + "-" + runnable.getClass().getSimpleName(), ex);
+                }
+            });
+            return thread;
+        }
+    }
+
     @UsedForTesting
     private static ScheduledExecutorService sExecutorServiceForTests;
 
@@ -44,6 +60,10 @@ public class ExecutorUtils {
         sExecutorServiceForTests = executorServiceForTests;
     }
 
+    //
+    // Public methods used to schedule a runnable for execution.
+    //
+
     /**
      * @return scheduled executor service used to run background tasks
      */
@@ -54,38 +74,28 @@ public class ExecutorUtils {
         return sExecutorService;
     }
 
-    /**
-     * Shutdowns all executors and removes all executors from the executor map for testing.
-     */
-    @UsedForTesting
-    public static void shutdownAllExecutors() {
-        sExecutorService.execute(new ExecutorShutdown(sExecutorService));
-    }
-
-    private static class ExecutorFactory implements ThreadFactory {
-        @Override
-        public Thread newThread(final Runnable runnable) {
-            Thread thread = new Thread(runnable, TAG);
-            thread.setUncaughtExceptionHandler(new UncaughtExceptionHandler() {
-                @Override
-                public void uncaughtException(Thread thread, Throwable ex) {
-                    Log.w(TAG + "-" + runnable.getClass().getSimpleName(), ex);
-                }
-            });
-            return thread;
-        }
+    public static Runnable chain(final Runnable... runnables) {
+        return new RunnableChain(runnables);
     }
 
-    private static class ExecutorShutdown implements Runnable {
-        private final ScheduledExecutorService mExecutor;
+    private static class RunnableChain implements Runnable {
+        private final Runnable[] mRunnables;
 
-        public ExecutorShutdown(final ScheduledExecutorService executor) {
-            mExecutor = executor;
+        private RunnableChain(final Runnable... runnables) {
+            if (runnables == null || runnables.length == 0) {
+                throw new IllegalArgumentException("Attempting to construct an empty chain");
+            }
+            mRunnables = runnables;
         }
 
         @Override
         public void run() {
-            mExecutor.shutdown();
+            for (Runnable runnable : mRunnables) {
+                if (Thread.interrupted()) {
+                    return;
+                }
+                runnable.run();
+            }
         }
     }
 }
-- 
GitLab