blob: 0699ffbc9c813dd03bf6f851d8d9343a54bae2a3 [file] [log] [blame]
Ruben Brunkfeb50af2014-05-09 19:58:49 -07001/*
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
17package android.hardware.camera2.legacy;
18
19import android.os.ConditionVariable;
20import android.os.Handler;
21import android.os.HandlerThread;
22import android.os.Looper;
23import android.os.MessageQueue;
24
25public class RequestHandlerThread extends HandlerThread {
Igor Murashkin51dcfd652014-09-25 16:55:01 -070026
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
Ruben Brunkfeb50af2014-05-09 19:58:49 -070035 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
40 public RequestHandlerThread(String name, Handler.Callback callback) {
41 super(name, Thread.MAX_PRIORITY);
42 mCallback = callback;
43 }
44
45 @Override
46 protected void onLooperPrepared() {
47 mHandler = new Handler(getLooper(), mCallback);
48 mStarted.open();
49 }
50
51 // Blocks until thread has started
52 public void waitUntilStarted() {
53 mStarted.block();
54 }
55
56 // May return null if the handler is not set up yet.
57 public Handler getHandler() {
58 return mHandler;
59 }
60
61 // Blocks until thread has started
62 public Handler waitAndGetHandler() {
63 waitUntilStarted();
64 return getHandler();
65 }
66
67 // Atomic multi-type message existence check
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
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
97 public void waitUntilIdle() {
Igor Murashkin51dcfd652014-09-25 16:55:01 -070098 Handler handler = waitAndGetHandler();
99 Looper looper = handler.getLooper();
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700100 if (looper.isIdling()) {
101 return;
102 }
103 mIdle.close();
104 looper.getQueue().addIdleHandler(mIdleHandler);
Igor Murashkin51dcfd652014-09-25 16:55:01 -0700105 // Ensure that the idle handler gets run even if the looper already went idle
106 handler.sendEmptyMessage(MSG_POKE_IDLE_HANDLER);
Ruben Brunkfeb50af2014-05-09 19:58:49 -0700107 if (looper.isIdling()) {
108 return;
109 }
110 mIdle.block();
111 }
112
113}