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