1 /*
2  * Copyright (C) 2020 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 com.android.systemui.classifier;
18 
19 import android.view.InputEvent;
20 
21 import java.util.ArrayList;
22 import java.util.Collection;
23 import java.util.Iterator;
24 import java.util.List;
25 import java.util.ListIterator;
26 
27 /**
28  * Maintains an ordered list of the last N milliseconds of InputEvents.
29  *
30  * This class is simply a convenience class designed to look like a simple list, but that
31  * automatically discards old InputEvents. It functions much like a queue - first in first out -
32  * but does not have a fixed size like a circular buffer.
33  */
34 public class TimeLimitedInputEventBuffer<T extends InputEvent> implements List<T> {
35 
36     private final List<T> mInputEvents;
37     private final long mMaxAgeMs;
38 
TimeLimitedInputEventBuffer(long maxAgeMs)39     public TimeLimitedInputEventBuffer(long maxAgeMs) {
40         super();
41         mMaxAgeMs = maxAgeMs;
42         mInputEvents = new ArrayList<>();
43     }
44 
ejectOldEvents()45     private void ejectOldEvents() {
46         if (mInputEvents.isEmpty()) {
47             return;
48         }
49         Iterator<T> iter = listIterator();
50         long mostRecentMs = mInputEvents.get(mInputEvents.size() - 1).getEventTime();
51         while (iter.hasNext()) {
52             T ev = iter.next();
53             if (mostRecentMs - ev.getEventTime() > mMaxAgeMs) {
54                 iter.remove();
55                 ev.recycle();
56             }
57         }
58     }
59 
60     @Override
add(int index, T element)61     public void add(int index, T element) {
62         throw new UnsupportedOperationException();
63     }
64 
65     @Override
remove(int index)66     public T remove(int index) {
67         return mInputEvents.remove(index);
68     }
69 
70     @Override
indexOf(Object o)71     public int indexOf(Object o) {
72         return mInputEvents.indexOf(o);
73     }
74 
75     @Override
lastIndexOf(Object o)76     public int lastIndexOf(Object o) {
77         return mInputEvents.lastIndexOf(o);
78     }
79 
80     @Override
size()81     public int size() {
82         return mInputEvents.size();
83     }
84 
85     @Override
isEmpty()86     public boolean isEmpty() {
87         return mInputEvents.isEmpty();
88     }
89 
90     @Override
contains(Object o)91     public boolean contains(Object o) {
92         return mInputEvents.contains(o);
93     }
94 
95     @Override
iterator()96     public Iterator<T> iterator() {
97         return mInputEvents.iterator();
98     }
99 
100     @Override
toArray()101     public Object[] toArray() {
102         return mInputEvents.toArray();
103     }
104 
105     @Override
toArray(T2[] a)106     public <T2> T2[] toArray(T2[] a) {
107         return mInputEvents.toArray(a);
108     }
109 
110     @Override
add(T element)111     public boolean add(T element) {
112         boolean result = mInputEvents.add(element);
113         ejectOldEvents();
114         return result;
115     }
116 
117     @Override
remove(Object o)118     public boolean remove(Object o) {
119         return mInputEvents.remove(o);
120     }
121 
122     @Override
containsAll(Collection<?> c)123     public boolean containsAll(Collection<?> c) {
124         return mInputEvents.containsAll(c);
125     }
126 
127     @Override
addAll(Collection<? extends T> collection)128     public boolean addAll(Collection<? extends T> collection) {
129         boolean result = mInputEvents.addAll(collection);
130         ejectOldEvents();
131         return result;
132     }
133 
134     @Override
addAll(int index, Collection<? extends T> elements)135     public boolean addAll(int index, Collection<? extends T> elements) {
136         throw new UnsupportedOperationException();
137     }
138 
139     @Override
removeAll(Collection<?> c)140     public boolean removeAll(Collection<?> c) {
141         return mInputEvents.removeAll(c);
142     }
143 
144     @Override
retainAll(Collection<?> c)145     public boolean retainAll(Collection<?> c) {
146         return mInputEvents.retainAll(c);
147     }
148 
149     @Override
clear()150     public void clear() {
151         mInputEvents.clear();
152     }
153 
154     @Override
equals(Object o)155     public boolean equals(Object o) {
156         return mInputEvents.equals(o);
157     }
158 
159     @Override
hashCode()160     public int hashCode() {
161         return mInputEvents.hashCode();
162     }
163 
164     @Override
get(int index)165     public T get(int index) {
166         return mInputEvents.get(index);
167     }
168 
169     @Override
set(int index, T element)170     public T set(int index, T element) {
171         throw new UnsupportedOperationException();
172     }
173 
174     @Override
listIterator()175     public ListIterator<T> listIterator() {
176         return new Iter(0);
177     }
178 
179     @Override
listIterator(int index)180     public ListIterator<T> listIterator(int index) {
181         return new Iter(index);
182     }
183 
184     @Override
subList(int fromIndex, int toIndex)185     public List<T> subList(int fromIndex, int toIndex) {
186         return mInputEvents.subList(fromIndex, toIndex);
187     }
188 
189     class Iter implements ListIterator<T> {
190 
191         private final ListIterator<T> mIterator;
192 
Iter(int index)193         Iter(int index) {
194             this.mIterator = mInputEvents.listIterator(index);
195         }
196 
197         @Override
hasNext()198         public boolean hasNext() {
199             return mIterator.hasNext();
200         }
201 
202         @Override
next()203         public T next() {
204             return mIterator.next();
205         }
206 
207         @Override
hasPrevious()208         public boolean hasPrevious() {
209             return mIterator.hasPrevious();
210         }
211 
212         @Override
previous()213         public T previous() {
214             return mIterator.previous();
215         }
216 
217         @Override
nextIndex()218         public int nextIndex() {
219             return mIterator.nextIndex();
220         }
221 
222         @Override
previousIndex()223         public int previousIndex() {
224             return mIterator.previousIndex();
225         }
226 
227         @Override
remove()228         public void remove() {
229             mIterator.remove();
230         }
231 
232         @Override
set(T inputEvent)233         public void set(T inputEvent) {
234             throw new UnsupportedOperationException();
235         }
236 
237         @Override
add(T element)238         public void add(T element) {
239             throw new UnsupportedOperationException();
240         }
241     }
242 }
243