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