1d01571e6d4e1c403534e19142720530d324eac9bJeff Sharkey/*
2d01571e6d4e1c403534e19142720530d324eac9bJeff Sharkey * Copyright (C) 2013 The Android Open Source Project
3d01571e6d4e1c403534e19142720530d324eac9bJeff Sharkey *
4d01571e6d4e1c403534e19142720530d324eac9bJeff Sharkey * Licensed under the Apache License, Version 2.0 (the "License");
5d01571e6d4e1c403534e19142720530d324eac9bJeff Sharkey * you may not use this file except in compliance with the License.
6d01571e6d4e1c403534e19142720530d324eac9bJeff Sharkey * You may obtain a copy of the License at
7d01571e6d4e1c403534e19142720530d324eac9bJeff Sharkey *
8d01571e6d4e1c403534e19142720530d324eac9bJeff Sharkey *      http://www.apache.org/licenses/LICENSE-2.0
9d01571e6d4e1c403534e19142720530d324eac9bJeff Sharkey *
10d01571e6d4e1c403534e19142720530d324eac9bJeff Sharkey * Unless required by applicable law or agreed to in writing, software
11d01571e6d4e1c403534e19142720530d324eac9bJeff Sharkey * distributed under the License is distributed on an "AS IS" BASIS,
12d01571e6d4e1c403534e19142720530d324eac9bJeff Sharkey * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13d01571e6d4e1c403534e19142720530d324eac9bJeff Sharkey * See the License for the specific language governing permissions and
14d01571e6d4e1c403534e19142720530d324eac9bJeff Sharkey * limitations under the License.
15d01571e6d4e1c403534e19142720530d324eac9bJeff Sharkey */
16d01571e6d4e1c403534e19142720530d324eac9bJeff Sharkey
17d01571e6d4e1c403534e19142720530d324eac9bJeff Sharkeypackage com.android.documentsui;
18d01571e6d4e1c403534e19142720530d324eac9bJeff Sharkey
19b3d42635aafacd80b1e1d257338ea6abb93d22c3Jeff Sharkeyimport android.os.AsyncTask;
20b3d42635aafacd80b1e1d257338ea6abb93d22c3Jeff Sharkey
21d01571e6d4e1c403534e19142720530d324eac9bJeff Sharkeyimport com.android.internal.annotations.GuardedBy;
22d01571e6d4e1c403534e19142720530d324eac9bJeff Sharkeyimport com.android.internal.util.Preconditions;
23b3d42635aafacd80b1e1d257338ea6abb93d22c3Jeff Sharkeyimport com.google.android.collect.Lists;
24d01571e6d4e1c403534e19142720530d324eac9bJeff Sharkeyimport com.google.android.collect.Maps;
25d01571e6d4e1c403534e19142720530d324eac9bJeff Sharkey
26b3d42635aafacd80b1e1d257338ea6abb93d22c3Jeff Sharkeyimport java.lang.ref.WeakReference;
27b3d42635aafacd80b1e1d257338ea6abb93d22c3Jeff Sharkeyimport java.util.ArrayList;
28d01571e6d4e1c403534e19142720530d324eac9bJeff Sharkeyimport java.util.HashMap;
29d01571e6d4e1c403534e19142720530d324eac9bJeff Sharkeyimport java.util.concurrent.Executor;
30d01571e6d4e1c403534e19142720530d324eac9bJeff Sharkeyimport java.util.concurrent.LinkedBlockingQueue;
31d01571e6d4e1c403534e19142720530d324eac9bJeff Sharkey
32d01571e6d4e1c403534e19142720530d324eac9bJeff Sharkeypublic class ProviderExecutor extends Thread implements Executor {
33d01571e6d4e1c403534e19142720530d324eac9bJeff Sharkey
34d01571e6d4e1c403534e19142720530d324eac9bJeff Sharkey    @GuardedBy("sExecutors")
35d01571e6d4e1c403534e19142720530d324eac9bJeff Sharkey    private static HashMap<String, ProviderExecutor> sExecutors = Maps.newHashMap();
36d01571e6d4e1c403534e19142720530d324eac9bJeff Sharkey
37b3d42635aafacd80b1e1d257338ea6abb93d22c3Jeff Sharkey    public static ProviderExecutor forAuthority(String authority) {
38d01571e6d4e1c403534e19142720530d324eac9bJeff Sharkey        synchronized (sExecutors) {
39d01571e6d4e1c403534e19142720530d324eac9bJeff Sharkey            ProviderExecutor executor = sExecutors.get(authority);
40d01571e6d4e1c403534e19142720530d324eac9bJeff Sharkey            if (executor == null) {
41d01571e6d4e1c403534e19142720530d324eac9bJeff Sharkey                executor = new ProviderExecutor();
42d01571e6d4e1c403534e19142720530d324eac9bJeff Sharkey                executor.setName("ProviderExecutor: " + authority);
43d01571e6d4e1c403534e19142720530d324eac9bJeff Sharkey                executor.start();
44d01571e6d4e1c403534e19142720530d324eac9bJeff Sharkey                sExecutors.put(authority, executor);
45d01571e6d4e1c403534e19142720530d324eac9bJeff Sharkey            }
46d01571e6d4e1c403534e19142720530d324eac9bJeff Sharkey            return executor;
47d01571e6d4e1c403534e19142720530d324eac9bJeff Sharkey        }
48d01571e6d4e1c403534e19142720530d324eac9bJeff Sharkey    }
49d01571e6d4e1c403534e19142720530d324eac9bJeff Sharkey
50b3d42635aafacd80b1e1d257338ea6abb93d22c3Jeff Sharkey    public interface Preemptable {
51b3d42635aafacd80b1e1d257338ea6abb93d22c3Jeff Sharkey        void preempt();
52b3d42635aafacd80b1e1d257338ea6abb93d22c3Jeff Sharkey    }
53b3d42635aafacd80b1e1d257338ea6abb93d22c3Jeff Sharkey
54d01571e6d4e1c403534e19142720530d324eac9bJeff Sharkey    private final LinkedBlockingQueue<Runnable> mQueue = new LinkedBlockingQueue<Runnable>();
55d01571e6d4e1c403534e19142720530d324eac9bJeff Sharkey
56b3d42635aafacd80b1e1d257338ea6abb93d22c3Jeff Sharkey    private final ArrayList<WeakReference<Preemptable>> mPreemptable = Lists.newArrayList();
57b3d42635aafacd80b1e1d257338ea6abb93d22c3Jeff Sharkey
58b3d42635aafacd80b1e1d257338ea6abb93d22c3Jeff Sharkey    private void preempt() {
59b3d42635aafacd80b1e1d257338ea6abb93d22c3Jeff Sharkey        synchronized (mPreemptable) {
60b3d42635aafacd80b1e1d257338ea6abb93d22c3Jeff Sharkey            int count = 0;
61b3d42635aafacd80b1e1d257338ea6abb93d22c3Jeff Sharkey            for (WeakReference<Preemptable> ref : mPreemptable) {
62b3d42635aafacd80b1e1d257338ea6abb93d22c3Jeff Sharkey                final Preemptable p = ref.get();
63b3d42635aafacd80b1e1d257338ea6abb93d22c3Jeff Sharkey                if (p != null) {
64b3d42635aafacd80b1e1d257338ea6abb93d22c3Jeff Sharkey                    count++;
65b3d42635aafacd80b1e1d257338ea6abb93d22c3Jeff Sharkey                    p.preempt();
66b3d42635aafacd80b1e1d257338ea6abb93d22c3Jeff Sharkey                }
67b3d42635aafacd80b1e1d257338ea6abb93d22c3Jeff Sharkey            }
68b3d42635aafacd80b1e1d257338ea6abb93d22c3Jeff Sharkey            mPreemptable.clear();
69b3d42635aafacd80b1e1d257338ea6abb93d22c3Jeff Sharkey        }
70b3d42635aafacd80b1e1d257338ea6abb93d22c3Jeff Sharkey    }
71b3d42635aafacd80b1e1d257338ea6abb93d22c3Jeff Sharkey
72b3d42635aafacd80b1e1d257338ea6abb93d22c3Jeff Sharkey    /**
73b3d42635aafacd80b1e1d257338ea6abb93d22c3Jeff Sharkey     * Execute the given task. If given task is not {@link Preemptable}, it will
74b3d42635aafacd80b1e1d257338ea6abb93d22c3Jeff Sharkey     * preempt all outstanding preemptable tasks.
75b3d42635aafacd80b1e1d257338ea6abb93d22c3Jeff Sharkey     */
76b3d42635aafacd80b1e1d257338ea6abb93d22c3Jeff Sharkey    public <P> void execute(AsyncTask<P, ?, ?> task, P... params) {
77b3d42635aafacd80b1e1d257338ea6abb93d22c3Jeff Sharkey        if (task instanceof Preemptable) {
78b3d42635aafacd80b1e1d257338ea6abb93d22c3Jeff Sharkey            synchronized (mPreemptable) {
79b3d42635aafacd80b1e1d257338ea6abb93d22c3Jeff Sharkey                mPreemptable.add(new WeakReference<Preemptable>((Preemptable) task));
80b3d42635aafacd80b1e1d257338ea6abb93d22c3Jeff Sharkey            }
81b3d42635aafacd80b1e1d257338ea6abb93d22c3Jeff Sharkey            task.executeOnExecutor(mNonPreemptingExecutor, params);
82b3d42635aafacd80b1e1d257338ea6abb93d22c3Jeff Sharkey        } else {
83b3d42635aafacd80b1e1d257338ea6abb93d22c3Jeff Sharkey            task.executeOnExecutor(this, params);
84b3d42635aafacd80b1e1d257338ea6abb93d22c3Jeff Sharkey        }
85b3d42635aafacd80b1e1d257338ea6abb93d22c3Jeff Sharkey    }
86b3d42635aafacd80b1e1d257338ea6abb93d22c3Jeff Sharkey
87b3d42635aafacd80b1e1d257338ea6abb93d22c3Jeff Sharkey    private Executor mNonPreemptingExecutor = new Executor() {
88b3d42635aafacd80b1e1d257338ea6abb93d22c3Jeff Sharkey        @Override
89b3d42635aafacd80b1e1d257338ea6abb93d22c3Jeff Sharkey        public void execute(Runnable command) {
90b3d42635aafacd80b1e1d257338ea6abb93d22c3Jeff Sharkey            Preconditions.checkNotNull(command);
91b3d42635aafacd80b1e1d257338ea6abb93d22c3Jeff Sharkey            mQueue.add(command);
92b3d42635aafacd80b1e1d257338ea6abb93d22c3Jeff Sharkey        }
93b3d42635aafacd80b1e1d257338ea6abb93d22c3Jeff Sharkey    };
94b3d42635aafacd80b1e1d257338ea6abb93d22c3Jeff Sharkey
95d01571e6d4e1c403534e19142720530d324eac9bJeff Sharkey    @Override
96d01571e6d4e1c403534e19142720530d324eac9bJeff Sharkey    public void execute(Runnable command) {
97b3d42635aafacd80b1e1d257338ea6abb93d22c3Jeff Sharkey        preempt();
98d01571e6d4e1c403534e19142720530d324eac9bJeff Sharkey        Preconditions.checkNotNull(command);
99d01571e6d4e1c403534e19142720530d324eac9bJeff Sharkey        mQueue.add(command);
100d01571e6d4e1c403534e19142720530d324eac9bJeff Sharkey    }
101d01571e6d4e1c403534e19142720530d324eac9bJeff Sharkey
102d01571e6d4e1c403534e19142720530d324eac9bJeff Sharkey    @Override
103d01571e6d4e1c403534e19142720530d324eac9bJeff Sharkey    public void run() {
104d01571e6d4e1c403534e19142720530d324eac9bJeff Sharkey        while (true) {
105d01571e6d4e1c403534e19142720530d324eac9bJeff Sharkey            try {
106d01571e6d4e1c403534e19142720530d324eac9bJeff Sharkey                final Runnable command = mQueue.take();
107d01571e6d4e1c403534e19142720530d324eac9bJeff Sharkey                command.run();
108d01571e6d4e1c403534e19142720530d324eac9bJeff Sharkey            } catch (InterruptedException e) {
109d01571e6d4e1c403534e19142720530d324eac9bJeff Sharkey                // That was weird; let's go look for more tasks.
110d01571e6d4e1c403534e19142720530d324eac9bJeff Sharkey            }
111d01571e6d4e1c403534e19142720530d324eac9bJeff Sharkey        }
112d01571e6d4e1c403534e19142720530d324eac9bJeff Sharkey    }
113d01571e6d4e1c403534e19142720530d324eac9bJeff Sharkey}
114