1 /*
2  * Copyright (C) 2011 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.dialer.util;
18 
19 import android.os.AsyncTask;
20 import android.os.Looper;
21 
22 import com.android.contacts.common.testing.NeededForTesting;
23 import com.google.common.base.Preconditions;
24 
25 import java.util.concurrent.Executor;
26 
27 /**
28  * Factory methods for creating AsyncTaskExecutors.
29  * <p>
30  * All of the factory methods on this class check first to see if you have set a static
31  * {@link AsyncTaskExecutorFactory} set through the
32  * {@link #setFactoryForTest(AsyncTaskExecutorFactory)} method, and if so delegate to that instead,
33  * which is one way of injecting dependencies for testing classes whose construction cannot be
34  * controlled such as {@link android.app.Activity}.
35  */
36 public final class AsyncTaskExecutors {
37     /**
38      * A single instance of the {@link AsyncTaskExecutorFactory}, to which we delegate if it is
39      * non-null, for injecting when testing.
40      */
41     private static AsyncTaskExecutorFactory mInjectedAsyncTaskExecutorFactory = null;
42 
43     /**
44      * Creates an AsyncTaskExecutor that submits tasks to run with
45      * {@link AsyncTask#SERIAL_EXECUTOR}.
46      */
createAsyncTaskExecutor()47     public static AsyncTaskExecutor createAsyncTaskExecutor() {
48         synchronized (AsyncTaskExecutors.class) {
49             if (mInjectedAsyncTaskExecutorFactory != null) {
50                 return mInjectedAsyncTaskExecutorFactory.createAsyncTaskExeuctor();
51             }
52             return new SimpleAsyncTaskExecutor(AsyncTask.SERIAL_EXECUTOR);
53         }
54     }
55 
56     /**
57      * Creates an AsyncTaskExecutor that submits tasks to run with
58      * {@link AsyncTask#THREAD_POOL_EXECUTOR}.
59      */
createThreadPoolExecutor()60     public static AsyncTaskExecutor createThreadPoolExecutor() {
61         synchronized (AsyncTaskExecutors.class) {
62             if (mInjectedAsyncTaskExecutorFactory != null) {
63                 return mInjectedAsyncTaskExecutorFactory.createAsyncTaskExeuctor();
64             }
65             return new SimpleAsyncTaskExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
66         }
67     }
68 
69     /** Interface for creating AsyncTaskExecutor objects. */
70     public interface AsyncTaskExecutorFactory {
createAsyncTaskExeuctor()71         AsyncTaskExecutor createAsyncTaskExeuctor();
72     }
73 
74     @NeededForTesting
setFactoryForTest(AsyncTaskExecutorFactory factory)75     public static void setFactoryForTest(AsyncTaskExecutorFactory factory) {
76         synchronized (AsyncTaskExecutors.class) {
77             mInjectedAsyncTaskExecutorFactory = factory;
78         }
79     }
80 
checkCalledFromUiThread()81     public static void checkCalledFromUiThread() {
82         Preconditions.checkState(Thread.currentThread() == Looper.getMainLooper().getThread(),
83                 "submit method must be called from ui thread, was: " + Thread.currentThread());
84     }
85 
86     private static class SimpleAsyncTaskExecutor implements AsyncTaskExecutor {
87         private final Executor mExecutor;
88 
SimpleAsyncTaskExecutor(Executor executor)89         public SimpleAsyncTaskExecutor(Executor executor) {
90             mExecutor = executor;
91         }
92 
93         @Override
submit(Object identifer, AsyncTask<T, ?, ?> task, T... params)94         public <T> AsyncTask<T, ?, ?> submit(Object identifer, AsyncTask<T, ?, ?> task,
95                 T... params) {
96             checkCalledFromUiThread();
97             return task.executeOnExecutor(mExecutor, params);
98         }
99     }
100 }
101