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
17package com.android.contacts.util;
18
19import android.os.AsyncTask;
20import android.os.Looper;
21
22import com.android.contacts.test.NeededForTesting;
23import com.google.common.base.Preconditions;
24
25import 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 */
36public 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     */
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     */
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 {
71        AsyncTaskExecutor createAsyncTaskExeuctor();
72    }
73
74    @NeededForTesting
75    public static void setFactoryForTest(AsyncTaskExecutorFactory factory) {
76        synchronized (AsyncTaskExecutors.class) {
77            mInjectedAsyncTaskExecutorFactory = factory;
78        }
79    }
80
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
89        public SimpleAsyncTaskExecutor(Executor executor) {
90            mExecutor = executor;
91        }
92
93        @Override
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