1 /*
2  * Copyright (C) 2014 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 android.hardware.camera2.legacy;
18 
19 import android.os.ConditionVariable;
20 import android.os.Handler;
21 import android.os.HandlerThread;
22 import android.os.Looper;
23 import android.os.MessageQueue;
24 
25 public class RequestHandlerThread extends HandlerThread {
26 
27     /**
28      * Ensure that the MessageQueue's idle handler gets run by poking the message queue;
29      * normally if the message queue is already idle, the idle handler won't get invoked.
30      *
31      * <p>Users of this handler thread should ignore this message.</p>
32      */
33     public final static int MSG_POKE_IDLE_HANDLER = -1;
34 
35     private final ConditionVariable mStarted = new ConditionVariable(false);
36     private final ConditionVariable mIdle = new ConditionVariable(true);
37     private Handler.Callback mCallback;
38     private volatile Handler mHandler;
39 
RequestHandlerThread(String name, Handler.Callback callback)40     public RequestHandlerThread(String name, Handler.Callback callback) {
41         super(name, Thread.MAX_PRIORITY);
42         mCallback = callback;
43     }
44 
45     @Override
onLooperPrepared()46     protected void onLooperPrepared() {
47         mHandler = new Handler(getLooper(), mCallback);
48         mStarted.open();
49     }
50 
51     // Blocks until thread has started
waitUntilStarted()52     public void waitUntilStarted() {
53         mStarted.block();
54     }
55 
56     // May return null if the handler is not set up yet.
getHandler()57     public Handler getHandler() {
58         return mHandler;
59     }
60 
61     // Blocks until thread has started
waitAndGetHandler()62     public Handler waitAndGetHandler() {
63         waitUntilStarted();
64         return getHandler();
65     }
66 
67     // Atomic multi-type message existence check
hasAnyMessages(int[] what)68     public boolean hasAnyMessages(int[] what) {
69         synchronized (mHandler.getLooper().getQueue()) {
70             for (int i : what) {
71                 if (mHandler.hasMessages(i)) {
72                     return true;
73                 }
74             }
75         }
76         return false;
77     }
78 
79     // Atomic multi-type message remove
removeMessages(int[] what)80     public void removeMessages(int[] what) {
81         synchronized (mHandler.getLooper().getQueue()) {
82             for (int i : what) {
83                 mHandler.removeMessages(i);
84             }
85         }
86     }
87 
88     private final MessageQueue.IdleHandler mIdleHandler = new MessageQueue.IdleHandler() {
89         @Override
90         public boolean queueIdle() {
91             mIdle.open();
92             return false;
93         }
94     };
95 
96     // Blocks until thread is idling
waitUntilIdle()97     public void waitUntilIdle() {
98         Handler handler = waitAndGetHandler();
99         MessageQueue queue = handler.getLooper().getQueue();
100         if (queue.isIdle()) {
101             return;
102         }
103         mIdle.close();
104         queue.addIdleHandler(mIdleHandler);
105         // Ensure that the idle handler gets run even if the looper already went idle
106         handler.sendEmptyMessage(MSG_POKE_IDLE_HANDLER);
107         if (queue.isIdle()) {
108             return;
109         }
110         mIdle.block();
111     }
112 
113 }
114