Home | History | Annotate | Download | only in base
      1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 package org.chromium.base;
      6 
      7 import android.os.Handler;
      8 import android.os.Looper;
      9 import android.os.Process;
     10 
     11 import java.util.concurrent.Callable;
     12 import java.util.concurrent.ExecutionException;
     13 import java.util.concurrent.FutureTask;
     14 
     15 /**
     16  * Helper methods to deal with threading related tasks.
     17  */
     18 public class ThreadUtils {
     19 
     20     private static boolean sWillOverride = false;
     21 
     22     private static Handler sUiThreadHandler = null;
     23 
     24     public static synchronized void setWillOverrideUiThread() {
     25         sWillOverride = true;
     26     }
     27 
     28     public static synchronized void setUiThread(Looper looper) {
     29         if (sUiThreadHandler != null && sUiThreadHandler.getLooper() != looper) {
     30             throw new RuntimeException("UI thread looper is already set to " +
     31                     sUiThreadHandler.getLooper() + " (Main thread looper is " +
     32                     Looper.getMainLooper() + "), cannot set to new looper " + looper);
     33         } else {
     34             sUiThreadHandler = new Handler(looper);
     35         }
     36     }
     37 
     38     private static synchronized Handler getUiThreadHandler() {
     39         if (sUiThreadHandler == null) {
     40             if (sWillOverride) {
     41                 throw new RuntimeException("Did not yet override the UI thread");
     42             }
     43             sUiThreadHandler = new Handler(Looper.getMainLooper());
     44         }
     45         return sUiThreadHandler;
     46     }
     47 
     48     /**
     49      * Run the supplied Runnable on the main thread. The method will block until the Runnable
     50      * completes.
     51      *
     52      * @param r The Runnable to run.
     53      */
     54     public static void runOnUiThreadBlocking(final Runnable r) {
     55         if (runningOnUiThread()) {
     56             r.run();
     57         } else {
     58             FutureTask<Void> task = new FutureTask<Void>(r, null);
     59             postOnUiThread(task);
     60             try {
     61                 task.get();
     62             } catch (Exception e) {
     63                 throw new RuntimeException("Exception occured while waiting for runnable", e);
     64             }
     65         }
     66     }
     67 
     68     /**
     69      * Run the supplied Callable on the main thread, wrapping any exceptions in a RuntimeException.
     70      * The method will block until the Callable completes.
     71      *
     72      * @param c The Callable to run
     73      * @return The result of the callable
     74      */
     75     public static <T> T runOnUiThreadBlockingNoException(Callable<T> c) {
     76         try {
     77             return runOnUiThreadBlocking(c);
     78         } catch (ExecutionException e) {
     79             throw new RuntimeException("Error occured waiting for callable", e);
     80         }
     81     }
     82 
     83     /**
     84      * Run the supplied Callable on the main thread, The method will block until the Callable
     85      * completes.
     86      *
     87      * @param c The Callable to run
     88      * @return The result of the callable
     89      * @throws ExecutionException c's exception
     90      */
     91     public static <T> T runOnUiThreadBlocking(Callable<T> c) throws ExecutionException {
     92         FutureTask<T> task = new FutureTask<T>(c);
     93         runOnUiThread(task);
     94         try {
     95             return task.get();
     96         } catch (InterruptedException e) {
     97             throw new RuntimeException("Interrupted waiting for callable", e);
     98         }
     99     }
    100 
    101     /**
    102      * Run the supplied FutureTask on the main thread. The method will block only if the current
    103      * thread is the main thread.
    104      *
    105      * @param task The FutureTask to run
    106      * @return The queried task (to aid inline construction)
    107      */
    108     public static <T> FutureTask<T> runOnUiThread(FutureTask<T> task) {
    109         if (runningOnUiThread()) {
    110             task.run();
    111         } else {
    112             postOnUiThread(task);
    113         }
    114         return task;
    115     }
    116 
    117     /**
    118      * Run the supplied Callable on the main thread. The method will block only if the current
    119      * thread is the main thread.
    120      *
    121      * @param c The Callable to run
    122      * @return A FutureTask wrapping the callable to retrieve results
    123      */
    124     public static <T> FutureTask<T> runOnUiThread(Callable<T> c) {
    125         return runOnUiThread(new FutureTask<T>(c));
    126     }
    127 
    128     /**
    129      * Run the supplied Runnable on the main thread. The method will block only if the current
    130      * thread is the main thread.
    131      *
    132      * @param r The Runnable to run
    133      */
    134     public static void runOnUiThread(Runnable r) {
    135         if (runningOnUiThread()) {
    136             r.run();
    137         } else {
    138             getUiThreadHandler().post(r);
    139         }
    140     }
    141 
    142     /**
    143      * Post the supplied FutureTask to run on the main thread. The method will not block, even if
    144      * called on the UI thread.
    145      *
    146      * @param task The FutureTask to run
    147      * @return The queried task (to aid inline construction)
    148      */
    149     public static <T> FutureTask<T> postOnUiThread(FutureTask<T> task) {
    150         getUiThreadHandler().post(task);
    151         return task;
    152     }
    153 
    154     /**
    155      * Post the supplied Runnable to run on the main thread. The method will not block, even if
    156      * called on the UI thread.
    157      *
    158      * @param task The Runnable to run
    159      */
    160     public static void postOnUiThread(Runnable r) {
    161         getUiThreadHandler().post(r);
    162     }
    163 
    164     /**
    165      * Post the supplied Runnable to run on the main thread after the given amount of time. The
    166      * method will not block, even if called on the UI thread.
    167      *
    168      * @param task The Runnable to run
    169      * @param delayMillis The delay in milliseconds until the Runnable will be run
    170      */
    171     public static void postOnUiThreadDelayed(Runnable r, long delayMillis) {
    172         getUiThreadHandler().postDelayed(r, delayMillis);
    173     }
    174 
    175     /**
    176      * Asserts that the current thread is running on the main thread.
    177      */
    178     public static void assertOnUiThread() {
    179         assert runningOnUiThread();
    180     }
    181 
    182     /**
    183      * @return true iff the current thread is the main (UI) thread.
    184      */
    185     public static boolean runningOnUiThread() {
    186         return getUiThreadHandler().getLooper() == Looper.myLooper();
    187     }
    188 
    189     public static Looper getUiThreadLooper() {
    190         return getUiThreadHandler().getLooper();
    191     }
    192 
    193     /**
    194      * Set thread priority to audio.
    195      */
    196     @CalledByNative
    197     public static void setThreadPriorityAudio(int tid) {
    198       Process.setThreadPriority(tid, Process.THREAD_PRIORITY_AUDIO);
    199     }
    200 }
    201