1package eu.siacs.conversations.utils;
2
3import android.os.Looper;
4import android.util.Log;
5
6import java.util.ArrayDeque;
7import java.util.Queue;
8import java.util.concurrent.Executor;
9import java.util.concurrent.Executors;
10
11import eu.siacs.conversations.Config;
12import eu.siacs.conversations.services.AttachFileToConversationRunnable;
13
14public class SerialSingleThreadExecutor implements Executor {
15
16 private final Executor executor = Executors.newSingleThreadExecutor();
17 final ArrayDeque<Runnable> tasks = new ArrayDeque<>();
18 protected Runnable active;
19 private final String name;
20
21 public SerialSingleThreadExecutor(String name) {
22 this(name, false);
23 }
24
25 SerialSingleThreadExecutor(String name, boolean prepareLooper) {
26 if (prepareLooper) {
27 execute(Looper::prepare);
28 }
29 this.name = name;
30 }
31
32 public synchronized void execute(final Runnable r) {
33 tasks.offer(new Runner(r));
34 if (active == null) {
35 scheduleNext();
36 }
37 }
38
39 private synchronized void scheduleNext() {
40 if ((active = tasks.poll()) != null) {
41 executor.execute(active);
42 int remaining = tasks.size();
43 if (remaining > 0) {
44 Log.d(Config.LOGTAG,remaining+" remaining tasks on executor '"+name+"'");
45 }
46 }
47 }
48
49 private class Runner implements Runnable, Cancellable {
50
51 private final Runnable runnable;
52
53 private Runner(Runnable runnable) {
54 this.runnable = runnable;
55 }
56
57 @Override
58 public void cancel() {
59 if (runnable instanceof Cancellable) {
60 ((Cancellable) runnable).cancel();
61 }
62 }
63
64 @Override
65 public void run() {
66 try {
67 runnable.run();
68 } finally {
69 scheduleNext();
70 }
71 }
72 }
73}