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