Home | History | Annotate | Download | only in utils
      1 /*
      2  * Copyright (C) 2014 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package com.android.inputmethod.latin.utils;
     18 
     19 import android.util.Log;
     20 
     21 import com.android.inputmethod.annotations.UsedForTesting;
     22 
     23 import java.lang.Thread.UncaughtExceptionHandler;
     24 import java.util.concurrent.Executors;
     25 import java.util.concurrent.ScheduledExecutorService;
     26 import java.util.concurrent.ThreadFactory;
     27 import java.util.concurrent.TimeUnit;
     28 
     29 /**
     30  * Utilities to manage executors.
     31  */
     32 public class ExecutorUtils {
     33 
     34     private static final String TAG = "ExecutorUtils";
     35 
     36     public static final String KEYBOARD = "Keyboard";
     37     public static final String SPELLING = "Spelling";
     38 
     39     private static ScheduledExecutorService sKeyboardExecutorService = newExecutorService(KEYBOARD);
     40     private static ScheduledExecutorService sSpellingExecutorService = newExecutorService(SPELLING);
     41 
     42     private static ScheduledExecutorService newExecutorService(final String name) {
     43         return Executors.newSingleThreadScheduledExecutor(new ExecutorFactory(name));
     44     }
     45 
     46     private static class ExecutorFactory implements ThreadFactory {
     47         private final String mName;
     48 
     49         private ExecutorFactory(final String name) {
     50             mName = name;
     51         }
     52 
     53         @Override
     54         public Thread newThread(final Runnable runnable) {
     55             Thread thread = new Thread(runnable, TAG);
     56             thread.setUncaughtExceptionHandler(new UncaughtExceptionHandler() {
     57                 @Override
     58                 public void uncaughtException(Thread thread, Throwable ex) {
     59                     Log.w(mName + "-" + runnable.getClass().getSimpleName(), ex);
     60                 }
     61             });
     62             return thread;
     63         }
     64     }
     65 
     66     @UsedForTesting
     67     private static ScheduledExecutorService sExecutorServiceForTests;
     68 
     69     @UsedForTesting
     70     public static void setExecutorServiceForTests(
     71             final ScheduledExecutorService executorServiceForTests) {
     72         sExecutorServiceForTests = executorServiceForTests;
     73     }
     74 
     75     //
     76     // Public methods used to schedule a runnable for execution.
     77     //
     78 
     79     /**
     80      * @param name Executor's name.
     81      * @return scheduled executor service used to run background tasks
     82      */
     83     public static ScheduledExecutorService getBackgroundExecutor(final String name) {
     84         if (sExecutorServiceForTests != null) {
     85             return sExecutorServiceForTests;
     86         }
     87         switch (name) {
     88             case KEYBOARD:
     89                 return sKeyboardExecutorService;
     90             case SPELLING:
     91                 return sSpellingExecutorService;
     92             default:
     93                 throw new IllegalArgumentException("Invalid executor: " + name);
     94         }
     95     }
     96 
     97     public static void killTasks(final String name) {
     98         final ScheduledExecutorService executorService = getBackgroundExecutor(name);
     99         executorService.shutdownNow();
    100         try {
    101             executorService.awaitTermination(5, TimeUnit.SECONDS);
    102         } catch (InterruptedException e) {
    103             Log.wtf(TAG, "Failed to shut down: " + name);
    104         }
    105         if (executorService == sExecutorServiceForTests) {
    106             // Don't do anything to the test service.
    107             return;
    108         }
    109         switch (name) {
    110             case KEYBOARD:
    111                 sKeyboardExecutorService = newExecutorService(KEYBOARD);
    112                 break;
    113             case SPELLING:
    114                 sSpellingExecutorService = newExecutorService(SPELLING);
    115                 break;
    116             default:
    117                 throw new IllegalArgumentException("Invalid executor: " + name);
    118         }
    119     }
    120 
    121     @UsedForTesting
    122     public static Runnable chain(final Runnable... runnables) {
    123         return new RunnableChain(runnables);
    124     }
    125 
    126     @UsedForTesting
    127     public static class RunnableChain implements Runnable {
    128         private final Runnable[] mRunnables;
    129 
    130         private RunnableChain(final Runnable... runnables) {
    131             if (runnables == null || runnables.length == 0) {
    132                 throw new IllegalArgumentException("Attempting to construct an empty chain");
    133             }
    134             mRunnables = runnables;
    135         }
    136 
    137         @UsedForTesting
    138         public Runnable[] getRunnables() {
    139             return mRunnables;
    140         }
    141 
    142         @Override
    143         public void run() {
    144             for (Runnable runnable : mRunnables) {
    145                 if (Thread.interrupted()) {
    146                     return;
    147                 }
    148                 runnable.run();
    149             }
    150         }
    151     }
    152 }
    153