1/*
2 * Copyright (C) 2015 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.view;
18
19import android.os.Looper;
20
21/**
22 * Similar to {@link InputEventReceiver}, but batches events to vsync boundaries when possible.
23 * @hide
24 */
25public class BatchedInputEventReceiver extends InputEventReceiver {
26    Choreographer mChoreographer;
27    private boolean mBatchedInputScheduled;
28
29    public BatchedInputEventReceiver(
30            InputChannel inputChannel, Looper looper, Choreographer choreographer) {
31        super(inputChannel, looper);
32        mChoreographer = choreographer;
33    }
34
35    @Override
36    public void onBatchedInputEventPending() {
37        scheduleBatchedInput();
38    }
39
40    @Override
41    public void dispose() {
42        unscheduleBatchedInput();
43        super.dispose();
44    }
45
46    void doConsumeBatchedInput(long frameTimeNanos) {
47        if (mBatchedInputScheduled) {
48            mBatchedInputScheduled = false;
49            if (consumeBatchedInputEvents(frameTimeNanos) && frameTimeNanos != -1) {
50                // If we consumed a batch here, we want to go ahead and schedule the
51                // consumption of batched input events on the next frame. Otherwise, we would
52                // wait until we have more input events pending and might get starved by other
53                // things occurring in the process. If the frame time is -1, however, then
54                // we're in a non-batching mode, so there's no need to schedule this.
55                scheduleBatchedInput();
56            }
57        }
58    }
59
60    private void scheduleBatchedInput() {
61        if (!mBatchedInputScheduled) {
62            mBatchedInputScheduled = true;
63            mChoreographer.postCallback(Choreographer.CALLBACK_INPUT, mBatchedInputRunnable, null);
64        }
65    }
66
67    private void unscheduleBatchedInput() {
68        if (mBatchedInputScheduled) {
69            mBatchedInputScheduled = false;
70            mChoreographer.removeCallbacks(
71                    Choreographer.CALLBACK_INPUT, mBatchedInputRunnable, null);
72        }
73    }
74
75    private final class BatchedInputRunnable implements Runnable {
76        @Override
77        public void run() {
78            doConsumeBatchedInput(mChoreographer.getFrameTimeNanos());
79        }
80    }
81    private final BatchedInputRunnable mBatchedInputRunnable = new BatchedInputRunnable();
82}
83