1/*
2 * Copyright (C) 2010 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
5 * use this file except in compliance with the License. You may obtain a copy of
6 * 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, WITHOUT
12 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13 * License for the specific language governing permissions and limitations under
14 * the License.
15 */
16
17package com.android.inputmethod.keyboard.internal;
18
19import android.util.Log;
20
21import com.android.inputmethod.latin.CollectionUtils;
22
23import java.util.ArrayList;
24
25public 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    }
34
35    private static final int INITIAL_CAPACITY = 10;
36    private final ArrayList<Element> mExpandableArrayOfActivePointers =
37            CollectionUtils.newArrayList(INITIAL_CAPACITY);
38    private int mArraySize = 0;
39
40    public synchronized int size() {
41        return mArraySize;
42    }
43
44    public synchronized void add(final Element pointer) {
45        final ArrayList<Element> expandableArray = mExpandableArrayOfActivePointers;
46        final int arraySize = mArraySize;
47        if (arraySize < expandableArray.size()) {
48            expandableArray.set(arraySize, pointer);
49        } else {
50            expandableArray.add(pointer);
51        }
52        mArraySize = arraySize + 1;
53    }
54
55    public synchronized void remove(final Element pointer) {
56        final ArrayList<Element> expandableArray = mExpandableArrayOfActivePointers;
57        final int arraySize = mArraySize;
58        int newSize = 0;
59        for (int index = 0; index < arraySize; index++) {
60            final Element element = expandableArray.get(index);
61            if (element == pointer) {
62                if (newSize != index) {
63                    Log.w(TAG, "Found duplicated element in remove: " + pointer);
64                }
65                continue; // Remove this element from the expandableArray.
66            }
67            if (newSize != index) {
68                // Shift this element toward the beginning of the expandableArray.
69                expandableArray.set(newSize, element);
70            }
71            newSize++;
72        }
73        mArraySize = newSize;
74    }
75
76    public synchronized Element getOldestElement() {
77        return (mArraySize == 0) ? null : mExpandableArrayOfActivePointers.get(0);
78    }
79
80    public synchronized void releaseAllPointersOlderThan(final Element pointer,
81            final long eventTime) {
82        if (DEBUG) {
83            Log.d(TAG, "releaseAllPoniterOlderThan: " + pointer + " " + this);
84        }
85        final ArrayList<Element> expandableArray = mExpandableArrayOfActivePointers;
86        final int arraySize = mArraySize;
87        int newSize, index;
88        for (newSize = index = 0; index < arraySize; index++) {
89            final Element element = expandableArray.get(index);
90            if (element == pointer) {
91                break; // Stop releasing elements.
92            }
93            if (!element.isModifier()) {
94                element.onPhantomUpEvent(eventTime);
95                continue; // Remove this element from the expandableArray.
96            }
97            if (newSize != index) {
98                // Shift this element toward the beginning of the expandableArray.
99                expandableArray.set(newSize, element);
100            }
101            newSize++;
102        }
103        // Shift rest of the expandableArray.
104        int count = 0;
105        for (; index < arraySize; index++) {
106            final Element element = expandableArray.get(index);
107            if (element == pointer) {
108                if (count > 0) {
109                    Log.w(TAG, "Found duplicated element in releaseAllPointersOlderThan: "
110                            + pointer);
111                }
112                count++;
113            }
114            if (newSize != index) {
115                expandableArray.set(newSize, expandableArray.get(index));
116                newSize++;
117            }
118        }
119        mArraySize = newSize;
120    }
121
122    public void releaseAllPointers(final long eventTime) {
123        releaseAllPointersExcept(null, eventTime);
124    }
125
126    public synchronized void releaseAllPointersExcept(final Element pointer,
127            final long eventTime) {
128        if (DEBUG) {
129            if (pointer == null) {
130                Log.d(TAG, "releaseAllPoniters: " + this);
131            } else {
132                Log.d(TAG, "releaseAllPoniterExcept: " + pointer + " " + this);
133            }
134        }
135        final ArrayList<Element> expandableArray = mExpandableArrayOfActivePointers;
136        final int arraySize = mArraySize;
137        int newSize = 0, count = 0;
138        for (int index = 0; index < arraySize; index++) {
139            final Element element = expandableArray.get(index);
140            if (element == pointer) {
141                if (count > 0) {
142                    Log.w(TAG, "Found duplicated element in releaseAllPointersExcept: " + pointer);
143                }
144                count++;
145            } else {
146                element.onPhantomUpEvent(eventTime);
147                continue; // Remove this element from the expandableArray.
148            }
149            if (newSize != index) {
150                // Shift this element toward the beginning of the expandableArray.
151                expandableArray.set(newSize, element);
152            }
153            newSize++;
154        }
155        mArraySize = newSize;
156    }
157
158    public synchronized boolean hasModifierKeyOlderThan(final Element pointer) {
159        final ArrayList<Element> expandableArray = mExpandableArrayOfActivePointers;
160        final int arraySize = mArraySize;
161        for (int index = 0; index < arraySize; index++) {
162            final Element element = expandableArray.get(index);
163            if (element == pointer) {
164                return false; // Stop searching modifier key.
165            }
166            if (element.isModifier()) {
167                return true;
168            }
169        }
170        return false;
171    }
172
173    public synchronized boolean isAnyInSlidingKeyInput() {
174        final ArrayList<Element> expandableArray = mExpandableArrayOfActivePointers;
175        final int arraySize = mArraySize;
176        for (int index = 0; index < arraySize; index++) {
177            final Element element = expandableArray.get(index);
178            if (element.isInSlidingKeyInput()) {
179                return true;
180            }
181        }
182        return false;
183    }
184
185    @Override
186    public synchronized String toString() {
187        final StringBuilder sb = new StringBuilder();
188        final ArrayList<Element> expandableArray = mExpandableArrayOfActivePointers;
189        final int arraySize = mArraySize;
190        for (int index = 0; index < arraySize; index++) {
191            final Element element = expandableArray.get(index);
192            if (sb.length() > 0)
193                sb.append(" ");
194            sb.append(element.toString());
195        }
196        return "[" + sb.toString() + "]";
197    }
198}
199