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