1 /*
2  *  Copyright 2015 The WebRTC Project Authors. All rights reserved.
3  *
4  *  Use of this source code is governed by a BSD-style license
5  *  that can be found in the LICENSE file in the root of the source
6  *  tree. An additional intellectual property rights grant can be found
7  *  in the file PATENTS.  All contributing project authors may
8  *  be found in the AUTHORS file in the root of the source tree.
9  */
10 
11 package org.appspot.apprtc.util;
12 
13 import android.os.Handler;
14 import android.os.Looper;
15 import android.util.Log;
16 
17 import java.util.concurrent.Executor;
18 
19 /**
20  * Looper based executor class.
21  */
22 public class LooperExecutor extends Thread implements Executor {
23   private static final String TAG = "LooperExecutor";
24   // Object used to signal that looper thread has started and Handler instance
25   // associated with looper thread has been allocated.
26   private final Object looperStartedEvent = new Object();
27   private Handler handler = null;
28   private boolean running = false;
29   private long threadId;
30 
31   @Override
run()32   public void run() {
33     Looper.prepare();
34     synchronized (looperStartedEvent) {
35       Log.d(TAG, "Looper thread started.");
36       handler = new Handler();
37       threadId = Thread.currentThread().getId();
38       looperStartedEvent.notify();
39     }
40     Looper.loop();
41   }
42 
requestStart()43   public synchronized void requestStart() {
44     if (running) {
45       return;
46     }
47     running = true;
48     handler = null;
49     start();
50     // Wait for Hander allocation.
51     synchronized (looperStartedEvent) {
52       while (handler == null) {
53         try {
54           looperStartedEvent.wait();
55         } catch (InterruptedException e) {
56           Log.e(TAG, "Can not start looper thread");
57           running = false;
58         }
59       }
60     }
61   }
62 
requestStop()63   public synchronized void requestStop() {
64     if (!running) {
65       return;
66     }
67     running = false;
68     handler.post(new Runnable() {
69       @Override
70       public void run() {
71         Looper.myLooper().quit();
72         Log.d(TAG, "Looper thread finished.");
73       }
74     });
75   }
76 
77   // Checks if current thread is a looper thread.
checkOnLooperThread()78   public boolean checkOnLooperThread() {
79     return (Thread.currentThread().getId() == threadId);
80   }
81 
82   @Override
execute(final Runnable runnable)83   public synchronized void execute(final Runnable runnable) {
84     if (!running) {
85       Log.w(TAG, "Running looper executor without calling requestStart()");
86       return;
87     }
88     if (Thread.currentThread().getId() == threadId) {
89       runnable.run();
90     } else {
91       handler.post(runnable);
92     }
93   }
94 
95 }
96