19c747ac625d212a10176082fba6b087035f5d144Hugo Hudson/* 29c747ac625d212a10176082fba6b087035f5d144Hugo Hudson * Copyright (C) 2011 The Android Open Source Project 39c747ac625d212a10176082fba6b087035f5d144Hugo Hudson * 49c747ac625d212a10176082fba6b087035f5d144Hugo Hudson * Licensed under the Apache License, Version 2.0 (the "License"); 59c747ac625d212a10176082fba6b087035f5d144Hugo Hudson * you may not use this file except in compliance with the License. 69c747ac625d212a10176082fba6b087035f5d144Hugo Hudson * You may obtain a copy of the License at 79c747ac625d212a10176082fba6b087035f5d144Hugo Hudson * 89c747ac625d212a10176082fba6b087035f5d144Hugo Hudson * http://www.apache.org/licenses/LICENSE-2.0 99c747ac625d212a10176082fba6b087035f5d144Hugo Hudson * 109c747ac625d212a10176082fba6b087035f5d144Hugo Hudson * Unless required by applicable law or agreed to in writing, software 119c747ac625d212a10176082fba6b087035f5d144Hugo Hudson * distributed under the License is distributed on an "AS IS" BASIS, 129c747ac625d212a10176082fba6b087035f5d144Hugo Hudson * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 139c747ac625d212a10176082fba6b087035f5d144Hugo Hudson * See the License for the specific language governing permissions and 149c747ac625d212a10176082fba6b087035f5d144Hugo Hudson * limitations under the License. 159c747ac625d212a10176082fba6b087035f5d144Hugo Hudson */ 169c747ac625d212a10176082fba6b087035f5d144Hugo Hudson 179c747ac625d212a10176082fba6b087035f5d144Hugo Hudsonpackage com.android.contacts.util; 189c747ac625d212a10176082fba6b087035f5d144Hugo Hudson 19c06f21bd72611b335f4d34586f656225fb02f0fbHugo Hudsonimport static com.google.common.base.Preconditions.checkNotNull; 20c06f21bd72611b335f4d34586f656225fb02f0fbHugo Hudsonimport static com.google.common.base.Preconditions.checkState; 21c06f21bd72611b335f4d34586f656225fb02f0fbHugo Hudson 229c747ac625d212a10176082fba6b087035f5d144Hugo Hudsonimport com.google.common.base.Preconditions; 239c747ac625d212a10176082fba6b087035f5d144Hugo Hudsonimport com.google.common.collect.Lists; 249c747ac625d212a10176082fba6b087035f5d144Hugo Hudson 259c747ac625d212a10176082fba6b087035f5d144Hugo Hudsonimport android.app.Instrumentation; 269c747ac625d212a10176082fba6b087035f5d144Hugo Hudsonimport android.os.AsyncTask; 279c747ac625d212a10176082fba6b087035f5d144Hugo Hudson 289c747ac625d212a10176082fba6b087035f5d144Hugo Hudsonimport junit.framework.Assert; 299c747ac625d212a10176082fba6b087035f5d144Hugo Hudson 309c747ac625d212a10176082fba6b087035f5d144Hugo Hudsonimport java.util.Iterator; 319c747ac625d212a10176082fba6b087035f5d144Hugo Hudsonimport java.util.List; 329c747ac625d212a10176082fba6b087035f5d144Hugo Hudsonimport java.util.concurrent.CountDownLatch; 339c747ac625d212a10176082fba6b087035f5d144Hugo Hudsonimport java.util.concurrent.Executor; 349c747ac625d212a10176082fba6b087035f5d144Hugo Hudsonimport java.util.concurrent.TimeUnit; 359c747ac625d212a10176082fba6b087035f5d144Hugo Hudson 369c747ac625d212a10176082fba6b087035f5d144Hugo Hudsonimport javax.annotation.concurrent.GuardedBy; 379c747ac625d212a10176082fba6b087035f5d144Hugo Hudsonimport javax.annotation.concurrent.ThreadSafe; 389c747ac625d212a10176082fba6b087035f5d144Hugo Hudson 399c747ac625d212a10176082fba6b087035f5d144Hugo Hudson/** 409c747ac625d212a10176082fba6b087035f5d144Hugo Hudson * Test implementation of AsyncTaskExecutor. 419c747ac625d212a10176082fba6b087035f5d144Hugo Hudson * <p> 429c747ac625d212a10176082fba6b087035f5d144Hugo Hudson * This class is thread-safe. As per the contract of the AsyncTaskExecutor, the submit methods must 439c747ac625d212a10176082fba6b087035f5d144Hugo Hudson * be called from the main ui thread, however the other public methods may be called from any thread 449c747ac625d212a10176082fba6b087035f5d144Hugo Hudson * (most commonly the test thread). 459c747ac625d212a10176082fba6b087035f5d144Hugo Hudson * <p> 469c747ac625d212a10176082fba6b087035f5d144Hugo Hudson * Tasks submitted to this executor will not be run immediately. Rather they will be stored in a 479c747ac625d212a10176082fba6b087035f5d144Hugo Hudson * list of submitted tasks, where they can be examined. They can also be run on-demand using the run 489c747ac625d212a10176082fba6b087035f5d144Hugo Hudson * methods, so that different ordering of AsyncTask execution can be simulated. 49c06f21bd72611b335f4d34586f656225fb02f0fbHugo Hudson * <p> 50c06f21bd72611b335f4d34586f656225fb02f0fbHugo Hudson * The onPreExecute method of the submitted AsyncTask will be called synchronously during the 51c06f21bd72611b335f4d34586f656225fb02f0fbHugo Hudson * call to {@link #submit(Object, AsyncTask, Object...)}. 529c747ac625d212a10176082fba6b087035f5d144Hugo Hudson */ 539c747ac625d212a10176082fba6b087035f5d144Hugo Hudson@ThreadSafe 549c747ac625d212a10176082fba6b087035f5d144Hugo Hudsonpublic class FakeAsyncTaskExecutor implements AsyncTaskExecutor { 559c747ac625d212a10176082fba6b087035f5d144Hugo Hudson private static final long DEFAULT_TIMEOUT_MS = 10000; 569c747ac625d212a10176082fba6b087035f5d144Hugo Hudson 579c747ac625d212a10176082fba6b087035f5d144Hugo Hudson /** The maximum length of time in ms to wait for tasks to execute during tests. */ 589c747ac625d212a10176082fba6b087035f5d144Hugo Hudson private final long mTimeoutMs = DEFAULT_TIMEOUT_MS; 599c747ac625d212a10176082fba6b087035f5d144Hugo Hudson 609c747ac625d212a10176082fba6b087035f5d144Hugo Hudson private final Object mLock = new Object(); 61c06f21bd72611b335f4d34586f656225fb02f0fbHugo Hudson @GuardedBy("mLock") private final List<SubmittedTask> mSubmittedTasks = Lists.newArrayList(); 629c747ac625d212a10176082fba6b087035f5d144Hugo Hudson 63c06f21bd72611b335f4d34586f656225fb02f0fbHugo Hudson private final DelayedExecutor mBlockingExecutor = new DelayedExecutor(); 649c747ac625d212a10176082fba6b087035f5d144Hugo Hudson private final Instrumentation mInstrumentation; 659c747ac625d212a10176082fba6b087035f5d144Hugo Hudson 669c747ac625d212a10176082fba6b087035f5d144Hugo Hudson /** Create a fake AsyncTaskExecutor for use in unit tests. */ 679c747ac625d212a10176082fba6b087035f5d144Hugo Hudson public FakeAsyncTaskExecutor(Instrumentation instrumentation) { 68c06f21bd72611b335f4d34586f656225fb02f0fbHugo Hudson mInstrumentation = checkNotNull(instrumentation); 699c747ac625d212a10176082fba6b087035f5d144Hugo Hudson } 709c747ac625d212a10176082fba6b087035f5d144Hugo Hudson 719c747ac625d212a10176082fba6b087035f5d144Hugo Hudson /** Encapsulates an async task with the params and identifier it was submitted with. */ 72c06f21bd72611b335f4d34586f656225fb02f0fbHugo Hudson public interface SubmittedTask { 73c06f21bd72611b335f4d34586f656225fb02f0fbHugo Hudson Runnable getRunnable(); 749c747ac625d212a10176082fba6b087035f5d144Hugo Hudson Object getIdentifier(); 75c06f21bd72611b335f4d34586f656225fb02f0fbHugo Hudson AsyncTask<?, ?, ?> getAsyncTask(); 769c747ac625d212a10176082fba6b087035f5d144Hugo Hudson } 779c747ac625d212a10176082fba6b087035f5d144Hugo Hudson 78c06f21bd72611b335f4d34586f656225fb02f0fbHugo Hudson private static final class SubmittedTaskImpl implements SubmittedTask { 799c747ac625d212a10176082fba6b087035f5d144Hugo Hudson private final Object mIdentifier; 80c06f21bd72611b335f4d34586f656225fb02f0fbHugo Hudson private final Runnable mRunnable; 81c06f21bd72611b335f4d34586f656225fb02f0fbHugo Hudson private final AsyncTask<?, ?, ?> mAsyncTask; 829c747ac625d212a10176082fba6b087035f5d144Hugo Hudson 83c06f21bd72611b335f4d34586f656225fb02f0fbHugo Hudson public SubmittedTaskImpl(Object identifier, Runnable runnable, 84c06f21bd72611b335f4d34586f656225fb02f0fbHugo Hudson AsyncTask<?, ?, ?> asyncTask) { 859c747ac625d212a10176082fba6b087035f5d144Hugo Hudson mIdentifier = identifier; 86c06f21bd72611b335f4d34586f656225fb02f0fbHugo Hudson mRunnable = runnable; 87c06f21bd72611b335f4d34586f656225fb02f0fbHugo Hudson mAsyncTask = asyncTask; 889c747ac625d212a10176082fba6b087035f5d144Hugo Hudson } 899c747ac625d212a10176082fba6b087035f5d144Hugo Hudson 909c747ac625d212a10176082fba6b087035f5d144Hugo Hudson @Override 919c747ac625d212a10176082fba6b087035f5d144Hugo Hudson public Object getIdentifier() { 929c747ac625d212a10176082fba6b087035f5d144Hugo Hudson return mIdentifier; 939c747ac625d212a10176082fba6b087035f5d144Hugo Hudson } 949c747ac625d212a10176082fba6b087035f5d144Hugo Hudson 959c747ac625d212a10176082fba6b087035f5d144Hugo Hudson @Override 96c06f21bd72611b335f4d34586f656225fb02f0fbHugo Hudson public Runnable getRunnable() { 97c06f21bd72611b335f4d34586f656225fb02f0fbHugo Hudson return mRunnable; 989c747ac625d212a10176082fba6b087035f5d144Hugo Hudson } 999c747ac625d212a10176082fba6b087035f5d144Hugo Hudson 1009c747ac625d212a10176082fba6b087035f5d144Hugo Hudson @Override 101c06f21bd72611b335f4d34586f656225fb02f0fbHugo Hudson public AsyncTask<?, ?, ?> getAsyncTask() { 102c06f21bd72611b335f4d34586f656225fb02f0fbHugo Hudson return mAsyncTask; 1039c747ac625d212a10176082fba6b087035f5d144Hugo Hudson } 1049c747ac625d212a10176082fba6b087035f5d144Hugo Hudson 1059c747ac625d212a10176082fba6b087035f5d144Hugo Hudson @Override 1069c747ac625d212a10176082fba6b087035f5d144Hugo Hudson public String toString() { 1079c747ac625d212a10176082fba6b087035f5d144Hugo Hudson return "SubmittedTaskImpl [mIdentifier=" + mIdentifier + "]"; 1089c747ac625d212a10176082fba6b087035f5d144Hugo Hudson } 1099c747ac625d212a10176082fba6b087035f5d144Hugo Hudson } 1109c747ac625d212a10176082fba6b087035f5d144Hugo Hudson 111c06f21bd72611b335f4d34586f656225fb02f0fbHugo Hudson private class DelayedExecutor implements Executor { 112c06f21bd72611b335f4d34586f656225fb02f0fbHugo Hudson private final Object mNextLock = new Object(); 113c06f21bd72611b335f4d34586f656225fb02f0fbHugo Hudson @GuardedBy("mNextLock") private Object mNextIdentifier; 114c06f21bd72611b335f4d34586f656225fb02f0fbHugo Hudson @GuardedBy("mNextLock") private AsyncTask<?, ?, ?> mNextTask; 115c06f21bd72611b335f4d34586f656225fb02f0fbHugo Hudson 116c06f21bd72611b335f4d34586f656225fb02f0fbHugo Hudson @Override 117c06f21bd72611b335f4d34586f656225fb02f0fbHugo Hudson public void execute(Runnable command) { 118c06f21bd72611b335f4d34586f656225fb02f0fbHugo Hudson synchronized (mNextLock) { 119c06f21bd72611b335f4d34586f656225fb02f0fbHugo Hudson mSubmittedTasks.add(new SubmittedTaskImpl(mNextIdentifier, 120c06f21bd72611b335f4d34586f656225fb02f0fbHugo Hudson command, checkNotNull(mNextTask))); 121c06f21bd72611b335f4d34586f656225fb02f0fbHugo Hudson mNextIdentifier = null; 122c06f21bd72611b335f4d34586f656225fb02f0fbHugo Hudson mNextTask = null; 123c06f21bd72611b335f4d34586f656225fb02f0fbHugo Hudson } 124c06f21bd72611b335f4d34586f656225fb02f0fbHugo Hudson } 125c06f21bd72611b335f4d34586f656225fb02f0fbHugo Hudson 126c06f21bd72611b335f4d34586f656225fb02f0fbHugo Hudson public <T> AsyncTask<T, ?, ?> submit(Object identifier, 127c06f21bd72611b335f4d34586f656225fb02f0fbHugo Hudson AsyncTask<T, ?, ?> task, T... params) { 128c06f21bd72611b335f4d34586f656225fb02f0fbHugo Hudson synchronized (mNextLock) { 129c06f21bd72611b335f4d34586f656225fb02f0fbHugo Hudson checkState(mNextIdentifier == null); 130c06f21bd72611b335f4d34586f656225fb02f0fbHugo Hudson checkState(mNextTask == null); 131c06f21bd72611b335f4d34586f656225fb02f0fbHugo Hudson mNextIdentifier = identifier; 132c06f21bd72611b335f4d34586f656225fb02f0fbHugo Hudson mNextTask = checkNotNull(task, "Already had a valid task.\n" 133c06f21bd72611b335f4d34586f656225fb02f0fbHugo Hudson + "Are you calling AsyncTaskExecutor.submit(...) from within the " 134c06f21bd72611b335f4d34586f656225fb02f0fbHugo Hudson + "onPreExecute() method of another task being submitted?\n" 135c06f21bd72611b335f4d34586f656225fb02f0fbHugo Hudson + "Sorry! Not that's not supported."); 136c06f21bd72611b335f4d34586f656225fb02f0fbHugo Hudson } 137c06f21bd72611b335f4d34586f656225fb02f0fbHugo Hudson return task.executeOnExecutor(this, params); 138c06f21bd72611b335f4d34586f656225fb02f0fbHugo Hudson } 139c06f21bd72611b335f4d34586f656225fb02f0fbHugo Hudson } 140c06f21bd72611b335f4d34586f656225fb02f0fbHugo Hudson 1419c747ac625d212a10176082fba6b087035f5d144Hugo Hudson @Override 1429c747ac625d212a10176082fba6b087035f5d144Hugo Hudson public <T> AsyncTask<T, ?, ?> submit(Object identifier, AsyncTask<T, ?, ?> task, T... params) { 1439c747ac625d212a10176082fba6b087035f5d144Hugo Hudson AsyncTaskExecutors.checkCalledFromUiThread(); 144c06f21bd72611b335f4d34586f656225fb02f0fbHugo Hudson return mBlockingExecutor.submit(identifier, task, params); 1459c747ac625d212a10176082fba6b087035f5d144Hugo Hudson } 1469c747ac625d212a10176082fba6b087035f5d144Hugo Hudson 1479c747ac625d212a10176082fba6b087035f5d144Hugo Hudson /** 1489c747ac625d212a10176082fba6b087035f5d144Hugo Hudson * Runs a single task matching the given identifier. 1499c747ac625d212a10176082fba6b087035f5d144Hugo Hudson * <p> 1509c747ac625d212a10176082fba6b087035f5d144Hugo Hudson * Removes the matching task from the list of submitted tasks, then runs it. The executor used 1519c747ac625d212a10176082fba6b087035f5d144Hugo Hudson * to execute this async task will be a same-thread executor. 1529c747ac625d212a10176082fba6b087035f5d144Hugo Hudson * <p> 1539c747ac625d212a10176082fba6b087035f5d144Hugo Hudson * Fails if there was not exactly one task matching the given identifier. 1549c747ac625d212a10176082fba6b087035f5d144Hugo Hudson * <p> 1559c747ac625d212a10176082fba6b087035f5d144Hugo Hudson * This method blocks until the AsyncTask has completely finished executing. 1569c747ac625d212a10176082fba6b087035f5d144Hugo Hudson */ 157c06f21bd72611b335f4d34586f656225fb02f0fbHugo Hudson public void runTask(Object identifier) throws InterruptedException { 158c06f21bd72611b335f4d34586f656225fb02f0fbHugo Hudson List<SubmittedTask> tasks = getSubmittedTasksByIdentifier(identifier, true); 1599c747ac625d212a10176082fba6b087035f5d144Hugo Hudson Assert.assertEquals("Expected one task " + identifier + ", got " + tasks, 1, tasks.size()); 1609c747ac625d212a10176082fba6b087035f5d144Hugo Hudson runTask(tasks.get(0)); 1619c747ac625d212a10176082fba6b087035f5d144Hugo Hudson } 1629c747ac625d212a10176082fba6b087035f5d144Hugo Hudson 1639c747ac625d212a10176082fba6b087035f5d144Hugo Hudson /** 1649c747ac625d212a10176082fba6b087035f5d144Hugo Hudson * Runs all tasks whose identifier matches the given identifier. 1659c747ac625d212a10176082fba6b087035f5d144Hugo Hudson * <p> 1669c747ac625d212a10176082fba6b087035f5d144Hugo Hudson * Removes all matching tasks from the list of submitted tasks, and runs them. The executor used 1679c747ac625d212a10176082fba6b087035f5d144Hugo Hudson * to execute these async tasks will be a same-thread executor. 1689c747ac625d212a10176082fba6b087035f5d144Hugo Hudson * <p> 1699c747ac625d212a10176082fba6b087035f5d144Hugo Hudson * Fails if there were no tasks matching the given identifier. 1709c747ac625d212a10176082fba6b087035f5d144Hugo Hudson * <p> 1719c747ac625d212a10176082fba6b087035f5d144Hugo Hudson * This method blocks until the AsyncTask objects have completely finished executing. 1729c747ac625d212a10176082fba6b087035f5d144Hugo Hudson */ 173c06f21bd72611b335f4d34586f656225fb02f0fbHugo Hudson public void runAllTasks(Object identifier) throws InterruptedException { 174c06f21bd72611b335f4d34586f656225fb02f0fbHugo Hudson List<SubmittedTask> tasks = getSubmittedTasksByIdentifier(identifier, true); 1759c747ac625d212a10176082fba6b087035f5d144Hugo Hudson Assert.assertTrue("There were no tasks with identifier " + identifier, tasks.size() > 0); 176c06f21bd72611b335f4d34586f656225fb02f0fbHugo Hudson for (SubmittedTask task : tasks) { 1779c747ac625d212a10176082fba6b087035f5d144Hugo Hudson runTask(task); 1789c747ac625d212a10176082fba6b087035f5d144Hugo Hudson } 1799c747ac625d212a10176082fba6b087035f5d144Hugo Hudson } 1809c747ac625d212a10176082fba6b087035f5d144Hugo Hudson 1819c747ac625d212a10176082fba6b087035f5d144Hugo Hudson /** 182c06f21bd72611b335f4d34586f656225fb02f0fbHugo Hudson * Executes a single {@link SubmittedTask}. 1839c747ac625d212a10176082fba6b087035f5d144Hugo Hudson * <p> 1849c747ac625d212a10176082fba6b087035f5d144Hugo Hudson * Blocks until the task has completed running. 1859c747ac625d212a10176082fba6b087035f5d144Hugo Hudson */ 186c06f21bd72611b335f4d34586f656225fb02f0fbHugo Hudson private <T> void runTask(final SubmittedTask submittedTask) throws InterruptedException { 187c06f21bd72611b335f4d34586f656225fb02f0fbHugo Hudson submittedTask.getRunnable().run(); 1889c747ac625d212a10176082fba6b087035f5d144Hugo Hudson // Block until the onPostExecute or onCancelled has finished. 1899c747ac625d212a10176082fba6b087035f5d144Hugo Hudson // Unfortunately we can't be sure when the AsyncTask will have posted its result handling 1909c747ac625d212a10176082fba6b087035f5d144Hugo Hudson // code to the main ui thread, the best we can do is wait for the Status to be FINISHED. 1919c747ac625d212a10176082fba6b087035f5d144Hugo Hudson final CountDownLatch latch = new CountDownLatch(1); 1929c747ac625d212a10176082fba6b087035f5d144Hugo Hudson class AsyncTaskHasFinishedRunnable implements Runnable { 1939c747ac625d212a10176082fba6b087035f5d144Hugo Hudson @Override 1949c747ac625d212a10176082fba6b087035f5d144Hugo Hudson public void run() { 195c06f21bd72611b335f4d34586f656225fb02f0fbHugo Hudson if (submittedTask.getAsyncTask().getStatus() == AsyncTask.Status.FINISHED) { 1969c747ac625d212a10176082fba6b087035f5d144Hugo Hudson latch.countDown(); 1979c747ac625d212a10176082fba6b087035f5d144Hugo Hudson } else { 1989c747ac625d212a10176082fba6b087035f5d144Hugo Hudson mInstrumentation.waitForIdle(this); 1999c747ac625d212a10176082fba6b087035f5d144Hugo Hudson } 2009c747ac625d212a10176082fba6b087035f5d144Hugo Hudson } 2019c747ac625d212a10176082fba6b087035f5d144Hugo Hudson } 2029c747ac625d212a10176082fba6b087035f5d144Hugo Hudson mInstrumentation.waitForIdle(new AsyncTaskHasFinishedRunnable()); 2039c747ac625d212a10176082fba6b087035f5d144Hugo Hudson Assert.assertTrue(latch.await(mTimeoutMs, TimeUnit.MILLISECONDS)); 2049c747ac625d212a10176082fba6b087035f5d144Hugo Hudson } 2059c747ac625d212a10176082fba6b087035f5d144Hugo Hudson 206c06f21bd72611b335f4d34586f656225fb02f0fbHugo Hudson private List<SubmittedTask> getSubmittedTasksByIdentifier( 207c06f21bd72611b335f4d34586f656225fb02f0fbHugo Hudson Object identifier, boolean remove) { 2089c747ac625d212a10176082fba6b087035f5d144Hugo Hudson Preconditions.checkNotNull(identifier, "can't lookup tasks by 'null' identifier"); 209c06f21bd72611b335f4d34586f656225fb02f0fbHugo Hudson List<SubmittedTask> results = Lists.newArrayList(); 2109c747ac625d212a10176082fba6b087035f5d144Hugo Hudson synchronized (mLock) { 211c06f21bd72611b335f4d34586f656225fb02f0fbHugo Hudson Iterator<SubmittedTask> iter = mSubmittedTasks.iterator(); 2129c747ac625d212a10176082fba6b087035f5d144Hugo Hudson while (iter.hasNext()) { 213c06f21bd72611b335f4d34586f656225fb02f0fbHugo Hudson SubmittedTask task = iter.next(); 2149c747ac625d212a10176082fba6b087035f5d144Hugo Hudson if (identifier.equals(task.getIdentifier())) { 2159c747ac625d212a10176082fba6b087035f5d144Hugo Hudson results.add(task); 2169c747ac625d212a10176082fba6b087035f5d144Hugo Hudson iter.remove(); 2179c747ac625d212a10176082fba6b087035f5d144Hugo Hudson } 2189c747ac625d212a10176082fba6b087035f5d144Hugo Hudson } 2199c747ac625d212a10176082fba6b087035f5d144Hugo Hudson } 2209c747ac625d212a10176082fba6b087035f5d144Hugo Hudson return results; 2219c747ac625d212a10176082fba6b087035f5d144Hugo Hudson } 2229c747ac625d212a10176082fba6b087035f5d144Hugo Hudson 2239c747ac625d212a10176082fba6b087035f5d144Hugo Hudson /** Get a factory that will return this instance - useful for testing. */ 2249c747ac625d212a10176082fba6b087035f5d144Hugo Hudson public AsyncTaskExecutors.AsyncTaskExecutorFactory getFactory() { 2259c747ac625d212a10176082fba6b087035f5d144Hugo Hudson return new AsyncTaskExecutors.AsyncTaskExecutorFactory() { 2269c747ac625d212a10176082fba6b087035f5d144Hugo Hudson @Override 2279c747ac625d212a10176082fba6b087035f5d144Hugo Hudson public AsyncTaskExecutor createAsyncTaskExeuctor() { 2289c747ac625d212a10176082fba6b087035f5d144Hugo Hudson return FakeAsyncTaskExecutor.this; 2299c747ac625d212a10176082fba6b087035f5d144Hugo Hudson } 2309c747ac625d212a10176082fba6b087035f5d144Hugo Hudson }; 2319c747ac625d212a10176082fba6b087035f5d144Hugo Hudson } 2329c747ac625d212a10176082fba6b087035f5d144Hugo Hudson} 233