1 /* 2 * Copyright (C) 2010 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.inputmethod.keyboard.internal; 18 19 import android.util.Log; 20 21 import java.util.ArrayList; 22 23 public final class PointerTrackerQueue { 24 private static final String TAG = PointerTrackerQueue.class.getSimpleName(); 25 private static final boolean DEBUG = false; 26 27 public interface Element { isModifier()28 public boolean isModifier(); isInDraggingFinger()29 public boolean isInDraggingFinger(); onPhantomUpEvent(long eventTime)30 public void onPhantomUpEvent(long eventTime); cancelTrackingForAction()31 public void cancelTrackingForAction(); 32 } 33 34 private static final int INITIAL_CAPACITY = 10; 35 // Note: {@link #mExpandableArrayOfActivePointers} and {@link #mArraySize} are synchronized by 36 // {@link #mExpandableArrayOfActivePointers} 37 private final ArrayList<Element> mExpandableArrayOfActivePointers = 38 new ArrayList<>(INITIAL_CAPACITY); 39 private int mArraySize = 0; 40 size()41 public int size() { 42 synchronized (mExpandableArrayOfActivePointers) { 43 return mArraySize; 44 } 45 } 46 add(final Element pointer)47 public void add(final Element pointer) { 48 synchronized (mExpandableArrayOfActivePointers) { 49 if (DEBUG) { 50 Log.d(TAG, "add: " + pointer + " " + this); 51 } 52 final ArrayList<Element> expandableArray = mExpandableArrayOfActivePointers; 53 final int arraySize = mArraySize; 54 if (arraySize < expandableArray.size()) { 55 expandableArray.set(arraySize, pointer); 56 } else { 57 expandableArray.add(pointer); 58 } 59 mArraySize = arraySize + 1; 60 } 61 } 62 remove(final Element pointer)63 public void remove(final Element pointer) { 64 synchronized (mExpandableArrayOfActivePointers) { 65 if (DEBUG) { 66 Log.d(TAG, "remove: " + pointer + " " + this); 67 } 68 final ArrayList<Element> expandableArray = mExpandableArrayOfActivePointers; 69 final int arraySize = mArraySize; 70 int newIndex = 0; 71 for (int index = 0; index < arraySize; index++) { 72 final Element element = expandableArray.get(index); 73 if (element == pointer) { 74 if (newIndex != index) { 75 Log.w(TAG, "Found duplicated element in remove: " + pointer); 76 } 77 continue; // Remove this element from the expandableArray. 78 } 79 if (newIndex != index) { 80 // Shift this element toward the beginning of the expandableArray. 81 expandableArray.set(newIndex, element); 82 } 83 newIndex++; 84 } 85 mArraySize = newIndex; 86 } 87 } 88 getOldestElement()89 public Element getOldestElement() { 90 synchronized (mExpandableArrayOfActivePointers) { 91 return (mArraySize == 0) ? null : mExpandableArrayOfActivePointers.get(0); 92 } 93 } 94 releaseAllPointersOlderThan(final Element pointer, final long eventTime)95 public void releaseAllPointersOlderThan(final Element pointer, final long eventTime) { 96 synchronized (mExpandableArrayOfActivePointers) { 97 if (DEBUG) { 98 Log.d(TAG, "releaseAllPointerOlderThan: " + pointer + " " + this); 99 } 100 final ArrayList<Element> expandableArray = mExpandableArrayOfActivePointers; 101 final int arraySize = mArraySize; 102 int newIndex, index; 103 for (newIndex = index = 0; index < arraySize; index++) { 104 final Element element = expandableArray.get(index); 105 if (element == pointer) { 106 break; // Stop releasing elements. 107 } 108 if (!element.isModifier()) { 109 element.onPhantomUpEvent(eventTime); 110 continue; // Remove this element from the expandableArray. 111 } 112 if (newIndex != index) { 113 // Shift this element toward the beginning of the expandableArray. 114 expandableArray.set(newIndex, element); 115 } 116 newIndex++; 117 } 118 // Shift rest of the expandableArray. 119 int count = 0; 120 for (; index < arraySize; index++) { 121 final Element element = expandableArray.get(index); 122 if (element == pointer) { 123 count++; 124 if (count > 1) { 125 Log.w(TAG, "Found duplicated element in releaseAllPointersOlderThan: " 126 + pointer); 127 } 128 } 129 if (newIndex != index) { 130 // Shift this element toward the beginning of the expandableArray. 131 expandableArray.set(newIndex, expandableArray.get(index)); 132 } 133 newIndex++; 134 } 135 mArraySize = newIndex; 136 } 137 } 138 releaseAllPointers(final long eventTime)139 public void releaseAllPointers(final long eventTime) { 140 releaseAllPointersExcept(null, eventTime); 141 } 142 releaseAllPointersExcept(final Element pointer, final long eventTime)143 public void releaseAllPointersExcept(final Element pointer, final long eventTime) { 144 synchronized (mExpandableArrayOfActivePointers) { 145 if (DEBUG) { 146 if (pointer == null) { 147 Log.d(TAG, "releaseAllPointers: " + this); 148 } else { 149 Log.d(TAG, "releaseAllPointerExcept: " + pointer + " " + this); 150 } 151 } 152 final ArrayList<Element> expandableArray = mExpandableArrayOfActivePointers; 153 final int arraySize = mArraySize; 154 int newIndex = 0, count = 0; 155 for (int index = 0; index < arraySize; index++) { 156 final Element element = expandableArray.get(index); 157 if (element == pointer) { 158 count++; 159 if (count > 1) { 160 Log.w(TAG, "Found duplicated element in releaseAllPointersExcept: " 161 + pointer); 162 } 163 } else { 164 element.onPhantomUpEvent(eventTime); 165 continue; // Remove this element from the expandableArray. 166 } 167 if (newIndex != index) { 168 // Shift this element toward the beginning of the expandableArray. 169 expandableArray.set(newIndex, element); 170 } 171 newIndex++; 172 } 173 mArraySize = newIndex; 174 } 175 } 176 hasModifierKeyOlderThan(final Element pointer)177 public boolean hasModifierKeyOlderThan(final Element pointer) { 178 synchronized (mExpandableArrayOfActivePointers) { 179 final ArrayList<Element> expandableArray = mExpandableArrayOfActivePointers; 180 final int arraySize = mArraySize; 181 for (int index = 0; index < arraySize; index++) { 182 final Element element = expandableArray.get(index); 183 if (element == pointer) { 184 return false; // Stop searching modifier key. 185 } 186 if (element.isModifier()) { 187 return true; 188 } 189 } 190 return false; 191 } 192 } 193 isAnyInDraggingFinger()194 public boolean isAnyInDraggingFinger() { 195 synchronized (mExpandableArrayOfActivePointers) { 196 final ArrayList<Element> expandableArray = mExpandableArrayOfActivePointers; 197 final int arraySize = mArraySize; 198 for (int index = 0; index < arraySize; index++) { 199 final Element element = expandableArray.get(index); 200 if (element.isInDraggingFinger()) { 201 return true; 202 } 203 } 204 return false; 205 } 206 } 207 cancelAllPointerTrackers()208 public void cancelAllPointerTrackers() { 209 synchronized (mExpandableArrayOfActivePointers) { 210 if (DEBUG) { 211 Log.d(TAG, "cancelAllPointerTracker: " + this); 212 } 213 final ArrayList<Element> expandableArray = mExpandableArrayOfActivePointers; 214 final int arraySize = mArraySize; 215 for (int index = 0; index < arraySize; index++) { 216 final Element element = expandableArray.get(index); 217 element.cancelTrackingForAction(); 218 } 219 } 220 } 221 222 @Override toString()223 public String toString() { 224 synchronized (mExpandableArrayOfActivePointers) { 225 final StringBuilder sb = new StringBuilder(); 226 final ArrayList<Element> expandableArray = mExpandableArrayOfActivePointers; 227 final int arraySize = mArraySize; 228 for (int index = 0; index < arraySize; index++) { 229 final Element element = expandableArray.get(index); 230 if (sb.length() > 0) { 231 sb.append(" "); 232 } 233 sb.append(element.toString()); 234 } 235 return "[" + sb.toString() + "]"; 236 } 237 } 238 } 239