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.MotionEvent; 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 MotionEvents. 29 * 30 * This class is simply a convenience class designed to look like a simple list, but that 31 * automatically discards old MotionEvents. 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 TimeLimitedMotionEventBuffer implements List<MotionEvent> { 35 36 private final List<MotionEvent> mMotionEvents; 37 private final long mMaxAgeMs; 38 TimeLimitedMotionEventBuffer(long maxAgeMs)39 public TimeLimitedMotionEventBuffer(long maxAgeMs) { 40 super(); 41 mMaxAgeMs = maxAgeMs; 42 mMotionEvents = new ArrayList<>(); 43 } 44 ejectOldEvents()45 private void ejectOldEvents() { 46 if (mMotionEvents.isEmpty()) { 47 return; 48 } 49 Iterator<MotionEvent> iter = listIterator(); 50 long mostRecentMs = mMotionEvents.get(mMotionEvents.size() - 1).getEventTime(); 51 while (iter.hasNext()) { 52 MotionEvent ev = iter.next(); 53 if (mostRecentMs - ev.getEventTime() > mMaxAgeMs) { 54 iter.remove(); 55 ev.recycle(); 56 } 57 } 58 } 59 60 @Override add(int index, MotionEvent element)61 public void add(int index, MotionEvent element) { 62 throw new UnsupportedOperationException(); 63 } 64 65 @Override remove(int index)66 public MotionEvent remove(int index) { 67 return mMotionEvents.remove(index); 68 } 69 70 @Override indexOf(Object o)71 public int indexOf(Object o) { 72 return mMotionEvents.indexOf(o); 73 } 74 75 @Override lastIndexOf(Object o)76 public int lastIndexOf(Object o) { 77 return mMotionEvents.lastIndexOf(o); 78 } 79 80 @Override size()81 public int size() { 82 return mMotionEvents.size(); 83 } 84 85 @Override isEmpty()86 public boolean isEmpty() { 87 return mMotionEvents.isEmpty(); 88 } 89 90 @Override contains(Object o)91 public boolean contains(Object o) { 92 return mMotionEvents.contains(o); 93 } 94 95 @Override iterator()96 public Iterator<MotionEvent> iterator() { 97 return mMotionEvents.iterator(); 98 } 99 100 @Override toArray()101 public Object[] toArray() { 102 return mMotionEvents.toArray(); 103 } 104 105 @Override toArray(T[] a)106 public <T> T[] toArray(T[] a) { 107 return mMotionEvents.toArray(a); 108 } 109 110 @Override add(MotionEvent element)111 public boolean add(MotionEvent element) { 112 boolean result = mMotionEvents.add(element); 113 ejectOldEvents(); 114 return result; 115 } 116 117 @Override remove(Object o)118 public boolean remove(Object o) { 119 return mMotionEvents.remove(o); 120 } 121 122 @Override containsAll(Collection<?> c)123 public boolean containsAll(Collection<?> c) { 124 return mMotionEvents.containsAll(c); 125 } 126 127 @Override addAll(Collection<? extends MotionEvent> collection)128 public boolean addAll(Collection<? extends MotionEvent> collection) { 129 boolean result = mMotionEvents.addAll(collection); 130 ejectOldEvents(); 131 return result; 132 } 133 134 @Override addAll(int index, Collection<? extends MotionEvent> elements)135 public boolean addAll(int index, Collection<? extends MotionEvent> elements) { 136 throw new UnsupportedOperationException(); 137 } 138 139 @Override removeAll(Collection<?> c)140 public boolean removeAll(Collection<?> c) { 141 return mMotionEvents.removeAll(c); 142 } 143 144 @Override retainAll(Collection<?> c)145 public boolean retainAll(Collection<?> c) { 146 return mMotionEvents.retainAll(c); 147 } 148 149 @Override clear()150 public void clear() { 151 mMotionEvents.clear(); 152 } 153 154 @Override equals(Object o)155 public boolean equals(Object o) { 156 return mMotionEvents.equals(o); 157 } 158 159 @Override hashCode()160 public int hashCode() { 161 return mMotionEvents.hashCode(); 162 } 163 164 @Override get(int index)165 public MotionEvent get(int index) { 166 return mMotionEvents.get(index); 167 } 168 169 @Override set(int index, MotionEvent element)170 public MotionEvent set(int index, MotionEvent element) { 171 throw new UnsupportedOperationException(); 172 } 173 174 @Override listIterator()175 public ListIterator<MotionEvent> listIterator() { 176 return new Iter(0); 177 } 178 179 @Override listIterator(int index)180 public ListIterator<MotionEvent> listIterator(int index) { 181 return new Iter(index); 182 } 183 184 @Override subList(int fromIndex, int toIndex)185 public List<MotionEvent> subList(int fromIndex, int toIndex) { 186 return mMotionEvents.subList(fromIndex, toIndex); 187 } 188 189 class Iter implements ListIterator<MotionEvent> { 190 191 private final ListIterator<MotionEvent> mIterator; 192 Iter(int index)193 Iter(int index) { 194 this.mIterator = mMotionEvents.listIterator(index); 195 } 196 197 @Override hasNext()198 public boolean hasNext() { 199 return mIterator.hasNext(); 200 } 201 202 @Override next()203 public MotionEvent 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 MotionEvent 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(MotionEvent motionEvent)233 public void set(MotionEvent motionEvent) { 234 throw new UnsupportedOperationException(); 235 } 236 237 @Override add(MotionEvent element)238 public void add(MotionEvent element) { 239 throw new UnsupportedOperationException(); 240 } 241 } 242 } 243