171538b08e4e08d556f700ad344562ca2c7b74d82Satoshi Kataoka/*
271538b08e4e08d556f700ad344562ca2c7b74d82Satoshi Kataoka * Copyright (C) 2012 The Android Open Source Project
371538b08e4e08d556f700ad344562ca2c7b74d82Satoshi Kataoka *
48aa9963a895f9dd5bb1bc92ab2e4f461e058f87aTadashi G. Takaoka * Licensed under the Apache License, Version 2.0 (the "License");
58aa9963a895f9dd5bb1bc92ab2e4f461e058f87aTadashi G. Takaoka * you may not use this file except in compliance with the License.
68aa9963a895f9dd5bb1bc92ab2e4f461e058f87aTadashi G. Takaoka * You may obtain a copy of the License at
771538b08e4e08d556f700ad344562ca2c7b74d82Satoshi Kataoka *
88aa9963a895f9dd5bb1bc92ab2e4f461e058f87aTadashi G. Takaoka *      http://www.apache.org/licenses/LICENSE-2.0
971538b08e4e08d556f700ad344562ca2c7b74d82Satoshi Kataoka *
1071538b08e4e08d556f700ad344562ca2c7b74d82Satoshi Kataoka * Unless required by applicable law or agreed to in writing, software
118aa9963a895f9dd5bb1bc92ab2e4f461e058f87aTadashi G. Takaoka * distributed under the License is distributed on an "AS IS" BASIS,
128aa9963a895f9dd5bb1bc92ab2e4f461e058f87aTadashi G. Takaoka * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
138aa9963a895f9dd5bb1bc92ab2e4f461e058f87aTadashi G. Takaoka * See the License for the specific language governing permissions and
148aa9963a895f9dd5bb1bc92ab2e4f461e058f87aTadashi G. Takaoka * limitations under the License.
1571538b08e4e08d556f700ad344562ca2c7b74d82Satoshi Kataoka */
1671538b08e4e08d556f700ad344562ca2c7b74d82Satoshi Kataoka
1771538b08e4e08d556f700ad344562ca2c7b74d82Satoshi Kataokapackage com.android.inputmethod.latin;
1871538b08e4e08d556f700ad344562ca2c7b74d82Satoshi Kataoka
1915f6d4ae34664ea3d92827a2c3003198c0bac70bTadashi G. Takaokaimport com.android.inputmethod.annotations.UsedForTesting;
20e28eba5074664d5716b8e58b8d0a235746b261ebKen Wakasaimport com.android.inputmethod.latin.utils.ResizableIntArray;
2115f6d4ae34664ea3d92827a2c3003198c0bac70bTadashi G. Takaoka
22f1074c508e70b3489dc85c036f7ed49d3196ba47Satoshi Kataokaimport android.util.Log;
23f1074c508e70b3489dc85c036f7ed49d3196ba47Satoshi Kataoka
247247bff6d6d488640ac752127148e7746c43469dTadashi G. Takaoka// TODO: This class is not thread-safe.
25a28a05e971cc242b338331a3b78276fa95188d19Tadashi G. Takaokapublic final class InputPointers {
26f1074c508e70b3489dc85c036f7ed49d3196ba47Satoshi Kataoka    private static final String TAG = InputPointers.class.getSimpleName();
2757f7de0ba664187e13bcea5adff7f5f65eddd823Tadashi G. Takaoka    private final int mDefaultCapacity;
289370ab9adad3b4bc3af8bde52b6422b8d2b873e7Tadashi G. Takaoka    private final ResizableIntArray mXCoordinates;
299370ab9adad3b4bc3af8bde52b6422b8d2b873e7Tadashi G. Takaoka    private final ResizableIntArray mYCoordinates;
309370ab9adad3b4bc3af8bde52b6422b8d2b873e7Tadashi G. Takaoka    private final ResizableIntArray mPointerIds;
319370ab9adad3b4bc3af8bde52b6422b8d2b873e7Tadashi G. Takaoka    private final ResizableIntArray mTimes;
3257f7de0ba664187e13bcea5adff7f5f65eddd823Tadashi G. Takaoka
3357f7de0ba664187e13bcea5adff7f5f65eddd823Tadashi G. Takaoka    public InputPointers(int defaultCapacity) {
3457f7de0ba664187e13bcea5adff7f5f65eddd823Tadashi G. Takaoka        mDefaultCapacity = defaultCapacity;
359370ab9adad3b4bc3af8bde52b6422b8d2b873e7Tadashi G. Takaoka        mXCoordinates = new ResizableIntArray(defaultCapacity);
369370ab9adad3b4bc3af8bde52b6422b8d2b873e7Tadashi G. Takaoka        mYCoordinates = new ResizableIntArray(defaultCapacity);
379370ab9adad3b4bc3af8bde52b6422b8d2b873e7Tadashi G. Takaoka        mPointerIds = new ResizableIntArray(defaultCapacity);
389370ab9adad3b4bc3af8bde52b6422b8d2b873e7Tadashi G. Takaoka        mTimes = new ResizableIntArray(defaultCapacity);
3957f7de0ba664187e13bcea5adff7f5f65eddd823Tadashi G. Takaoka    }
4071538b08e4e08d556f700ad344562ca2c7b74d82Satoshi Kataoka
4171538b08e4e08d556f700ad344562ca2c7b74d82Satoshi Kataoka    public void addPointer(int index, int x, int y, int pointerId, int time) {
4271538b08e4e08d556f700ad344562ca2c7b74d82Satoshi Kataoka        mXCoordinates.add(index, x);
4371538b08e4e08d556f700ad344562ca2c7b74d82Satoshi Kataoka        mYCoordinates.add(index, y);
4471538b08e4e08d556f700ad344562ca2c7b74d82Satoshi Kataoka        mPointerIds.add(index, pointerId);
4571538b08e4e08d556f700ad344562ca2c7b74d82Satoshi Kataoka        mTimes.add(index, time);
4671538b08e4e08d556f700ad344562ca2c7b74d82Satoshi Kataoka    }
4771538b08e4e08d556f700ad344562ca2c7b74d82Satoshi Kataoka
4815f6d4ae34664ea3d92827a2c3003198c0bac70bTadashi G. Takaoka    @UsedForTesting
4915f6d4ae34664ea3d92827a2c3003198c0bac70bTadashi G. Takaoka    void addPointer(int x, int y, int pointerId, int time) {
5071538b08e4e08d556f700ad344562ca2c7b74d82Satoshi Kataoka        mXCoordinates.add(x);
5171538b08e4e08d556f700ad344562ca2c7b74d82Satoshi Kataoka        mYCoordinates.add(y);
5271538b08e4e08d556f700ad344562ca2c7b74d82Satoshi Kataoka        mPointerIds.add(pointerId);
5371538b08e4e08d556f700ad344562ca2c7b74d82Satoshi Kataoka        mTimes.add(time);
5471538b08e4e08d556f700ad344562ca2c7b74d82Satoshi Kataoka    }
5571538b08e4e08d556f700ad344562ca2c7b74d82Satoshi Kataoka
5671538b08e4e08d556f700ad344562ca2c7b74d82Satoshi Kataoka    public void set(InputPointers ip) {
5771538b08e4e08d556f700ad344562ca2c7b74d82Satoshi Kataoka        mXCoordinates.set(ip.mXCoordinates);
5871538b08e4e08d556f700ad344562ca2c7b74d82Satoshi Kataoka        mYCoordinates.set(ip.mYCoordinates);
5971538b08e4e08d556f700ad344562ca2c7b74d82Satoshi Kataoka        mPointerIds.set(ip.mPointerIds);
6071538b08e4e08d556f700ad344562ca2c7b74d82Satoshi Kataoka        mTimes.set(ip.mTimes);
6171538b08e4e08d556f700ad344562ca2c7b74d82Satoshi Kataoka    }
6271538b08e4e08d556f700ad344562ca2c7b74d82Satoshi Kataoka
6371538b08e4e08d556f700ad344562ca2c7b74d82Satoshi Kataoka    public void copy(InputPointers ip) {
6471538b08e4e08d556f700ad344562ca2c7b74d82Satoshi Kataoka        mXCoordinates.copy(ip.mXCoordinates);
6571538b08e4e08d556f700ad344562ca2c7b74d82Satoshi Kataoka        mYCoordinates.copy(ip.mYCoordinates);
6671538b08e4e08d556f700ad344562ca2c7b74d82Satoshi Kataoka        mPointerIds.copy(ip.mPointerIds);
6771538b08e4e08d556f700ad344562ca2c7b74d82Satoshi Kataoka        mTimes.copy(ip.mTimes);
6871538b08e4e08d556f700ad344562ca2c7b74d82Satoshi Kataoka    }
6971538b08e4e08d556f700ad344562ca2c7b74d82Satoshi Kataoka
701087c53f5a6ced093eb4e71f88cff19e89819d73Tadashi G. Takaoka    /**
711087c53f5a6ced093eb4e71f88cff19e89819d73Tadashi G. Takaoka     * Append the pointers in the specified {@link InputPointers} to the end of this.
727247bff6d6d488640ac752127148e7746c43469dTadashi G. Takaoka     * @param src the source {@link InputPointers} to read the data from.
731087c53f5a6ced093eb4e71f88cff19e89819d73Tadashi G. Takaoka     * @param startPos the starting index of the pointers in {@code src}.
741087c53f5a6ced093eb4e71f88cff19e89819d73Tadashi G. Takaoka     * @param length the number of pointers to be appended.
751087c53f5a6ced093eb4e71f88cff19e89819d73Tadashi G. Takaoka     */
7615f6d4ae34664ea3d92827a2c3003198c0bac70bTadashi G. Takaoka    @UsedForTesting
7715f6d4ae34664ea3d92827a2c3003198c0bac70bTadashi G. Takaoka    void append(InputPointers src, int startPos, int length) {
789580c467f96c542c66af86a2c376612ba4d91434Tadashi G. Takaoka        if (length == 0) {
799580c467f96c542c66af86a2c376612ba4d91434Tadashi G. Takaoka            return;
809580c467f96c542c66af86a2c376612ba4d91434Tadashi G. Takaoka        }
817247bff6d6d488640ac752127148e7746c43469dTadashi G. Takaoka        mXCoordinates.append(src.mXCoordinates, startPos, length);
827247bff6d6d488640ac752127148e7746c43469dTadashi G. Takaoka        mYCoordinates.append(src.mYCoordinates, startPos, length);
837247bff6d6d488640ac752127148e7746c43469dTadashi G. Takaoka        mPointerIds.append(src.mPointerIds, startPos, length);
847247bff6d6d488640ac752127148e7746c43469dTadashi G. Takaoka        mTimes.append(src.mTimes, startPos, length);
851087c53f5a6ced093eb4e71f88cff19e89819d73Tadashi G. Takaoka    }
861087c53f5a6ced093eb4e71f88cff19e89819d73Tadashi G. Takaoka
877519091f7c15c50a9a1e50d82fa92400335852ecTadashi G. Takaoka    /**
887519091f7c15c50a9a1e50d82fa92400335852ecTadashi G. Takaoka     * Append the times, x-coordinates and y-coordinates in the specified {@link ResizableIntArray}
897519091f7c15c50a9a1e50d82fa92400335852ecTadashi G. Takaoka     * to the end of this.
907519091f7c15c50a9a1e50d82fa92400335852ecTadashi G. Takaoka     * @param pointerId the pointer id of the source.
917519091f7c15c50a9a1e50d82fa92400335852ecTadashi G. Takaoka     * @param times the source {@link ResizableIntArray} to read the event times from.
927519091f7c15c50a9a1e50d82fa92400335852ecTadashi G. Takaoka     * @param xCoordinates the source {@link ResizableIntArray} to read the x-coordinates from.
937519091f7c15c50a9a1e50d82fa92400335852ecTadashi G. Takaoka     * @param yCoordinates the source {@link ResizableIntArray} to read the y-coordinates from.
947519091f7c15c50a9a1e50d82fa92400335852ecTadashi G. Takaoka     * @param startPos the starting index of the data in {@code times} and etc.
957519091f7c15c50a9a1e50d82fa92400335852ecTadashi G. Takaoka     * @param length the number of data to be appended.
967519091f7c15c50a9a1e50d82fa92400335852ecTadashi G. Takaoka     */
977519091f7c15c50a9a1e50d82fa92400335852ecTadashi G. Takaoka    public void append(int pointerId, ResizableIntArray times, ResizableIntArray xCoordinates,
987519091f7c15c50a9a1e50d82fa92400335852ecTadashi G. Takaoka            ResizableIntArray yCoordinates, int startPos, int length) {
997519091f7c15c50a9a1e50d82fa92400335852ecTadashi G. Takaoka        if (length == 0) {
1007519091f7c15c50a9a1e50d82fa92400335852ecTadashi G. Takaoka            return;
1017519091f7c15c50a9a1e50d82fa92400335852ecTadashi G. Takaoka        }
1027519091f7c15c50a9a1e50d82fa92400335852ecTadashi G. Takaoka        mXCoordinates.append(xCoordinates, startPos, length);
1037519091f7c15c50a9a1e50d82fa92400335852ecTadashi G. Takaoka        mYCoordinates.append(yCoordinates, startPos, length);
10464a26b4389abb273afff7699a8c86596defd85bfTadashi G. Takaoka        mPointerIds.fill(pointerId, mPointerIds.getLength(), length);
1057519091f7c15c50a9a1e50d82fa92400335852ecTadashi G. Takaoka        mTimes.append(times, startPos, length);
1067519091f7c15c50a9a1e50d82fa92400335852ecTadashi G. Takaoka    }
1077519091f7c15c50a9a1e50d82fa92400335852ecTadashi G. Takaoka
108e8754aba1c8f217e7ca828de25e0506ac58daa99Keisuke Kuroyanagi    /**
109e8754aba1c8f217e7ca828de25e0506ac58daa99Keisuke Kuroyanagi     * Shift to the left by elementCount, discarding elementCount pointers at the start.
110e8754aba1c8f217e7ca828de25e0506ac58daa99Keisuke Kuroyanagi     * @param elementCount how many elements to shift.
111e8754aba1c8f217e7ca828de25e0506ac58daa99Keisuke Kuroyanagi     */
112e8754aba1c8f217e7ca828de25e0506ac58daa99Keisuke Kuroyanagi    public void shift(final int elementCount) {
113e8754aba1c8f217e7ca828de25e0506ac58daa99Keisuke Kuroyanagi        mXCoordinates.shift(elementCount);
114e8754aba1c8f217e7ca828de25e0506ac58daa99Keisuke Kuroyanagi        mYCoordinates.shift(elementCount);
115e8754aba1c8f217e7ca828de25e0506ac58daa99Keisuke Kuroyanagi        mPointerIds.shift(elementCount);
116e8754aba1c8f217e7ca828de25e0506ac58daa99Keisuke Kuroyanagi        mTimes.shift(elementCount);
117e8754aba1c8f217e7ca828de25e0506ac58daa99Keisuke Kuroyanagi    }
118e8754aba1c8f217e7ca828de25e0506ac58daa99Keisuke Kuroyanagi
11971538b08e4e08d556f700ad344562ca2c7b74d82Satoshi Kataoka    public void reset() {
12057f7de0ba664187e13bcea5adff7f5f65eddd823Tadashi G. Takaoka        final int defaultCapacity = mDefaultCapacity;
12157f7de0ba664187e13bcea5adff7f5f65eddd823Tadashi G. Takaoka        mXCoordinates.reset(defaultCapacity);
12257f7de0ba664187e13bcea5adff7f5f65eddd823Tadashi G. Takaoka        mYCoordinates.reset(defaultCapacity);
12357f7de0ba664187e13bcea5adff7f5f65eddd823Tadashi G. Takaoka        mPointerIds.reset(defaultCapacity);
12457f7de0ba664187e13bcea5adff7f5f65eddd823Tadashi G. Takaoka        mTimes.reset(defaultCapacity);
12571538b08e4e08d556f700ad344562ca2c7b74d82Satoshi Kataoka    }
12671538b08e4e08d556f700ad344562ca2c7b74d82Satoshi Kataoka
12771538b08e4e08d556f700ad344562ca2c7b74d82Satoshi Kataoka    public int getPointerSize() {
12871538b08e4e08d556f700ad344562ca2c7b74d82Satoshi Kataoka        return mXCoordinates.getLength();
12971538b08e4e08d556f700ad344562ca2c7b74d82Satoshi Kataoka    }
13071538b08e4e08d556f700ad344562ca2c7b74d82Satoshi Kataoka
13171538b08e4e08d556f700ad344562ca2c7b74d82Satoshi Kataoka    public int[] getXCoordinates() {
1321087c53f5a6ced093eb4e71f88cff19e89819d73Tadashi G. Takaoka        return mXCoordinates.getPrimitiveArray();
13371538b08e4e08d556f700ad344562ca2c7b74d82Satoshi Kataoka    }
13471538b08e4e08d556f700ad344562ca2c7b74d82Satoshi Kataoka
13571538b08e4e08d556f700ad344562ca2c7b74d82Satoshi Kataoka    public int[] getYCoordinates() {
1361087c53f5a6ced093eb4e71f88cff19e89819d73Tadashi G. Takaoka        return mYCoordinates.getPrimitiveArray();
13771538b08e4e08d556f700ad344562ca2c7b74d82Satoshi Kataoka    }
13871538b08e4e08d556f700ad344562ca2c7b74d82Satoshi Kataoka
13971538b08e4e08d556f700ad344562ca2c7b74d82Satoshi Kataoka    public int[] getPointerIds() {
1401087c53f5a6ced093eb4e71f88cff19e89819d73Tadashi G. Takaoka        return mPointerIds.getPrimitiveArray();
14171538b08e4e08d556f700ad344562ca2c7b74d82Satoshi Kataoka    }
14271538b08e4e08d556f700ad344562ca2c7b74d82Satoshi Kataoka
14371538b08e4e08d556f700ad344562ca2c7b74d82Satoshi Kataoka    public int[] getTimes() {
144f1074c508e70b3489dc85c036f7ed49d3196ba47Satoshi Kataoka        if (LatinImeLogger.sDBG) {
145f1074c508e70b3489dc85c036f7ed49d3196ba47Satoshi Kataoka            if (!isValidTimeStamps()) {
146f1074c508e70b3489dc85c036f7ed49d3196ba47Satoshi Kataoka                throw new RuntimeException("Time stamps are invalid.");
147f1074c508e70b3489dc85c036f7ed49d3196ba47Satoshi Kataoka            }
148f1074c508e70b3489dc85c036f7ed49d3196ba47Satoshi Kataoka        }
1491087c53f5a6ced093eb4e71f88cff19e89819d73Tadashi G. Takaoka        return mTimes.getPrimitiveArray();
15071538b08e4e08d556f700ad344562ca2c7b74d82Satoshi Kataoka    }
15164ee09610024eb1436c51f9c9ef9fc3f77239d73Tadashi G. Takaoka
15264ee09610024eb1436c51f9c9ef9fc3f77239d73Tadashi G. Takaoka    @Override
15364ee09610024eb1436c51f9c9ef9fc3f77239d73Tadashi G. Takaoka    public String toString() {
15464ee09610024eb1436c51f9c9ef9fc3f77239d73Tadashi G. Takaoka        return "size=" + getPointerSize() + " id=" + mPointerIds + " time=" + mTimes
15564ee09610024eb1436c51f9c9ef9fc3f77239d73Tadashi G. Takaoka                + " x=" + mXCoordinates + " y=" + mYCoordinates;
15664ee09610024eb1436c51f9c9ef9fc3f77239d73Tadashi G. Takaoka    }
157f1074c508e70b3489dc85c036f7ed49d3196ba47Satoshi Kataoka
158f1074c508e70b3489dc85c036f7ed49d3196ba47Satoshi Kataoka    private boolean isValidTimeStamps() {
159f1074c508e70b3489dc85c036f7ed49d3196ba47Satoshi Kataoka        final int[] times = mTimes.getPrimitiveArray();
160f1074c508e70b3489dc85c036f7ed49d3196ba47Satoshi Kataoka        for (int i = 1; i < getPointerSize(); ++i) {
161f1074c508e70b3489dc85c036f7ed49d3196ba47Satoshi Kataoka            if (times[i] < times[i - 1]) {
162f1074c508e70b3489dc85c036f7ed49d3196ba47Satoshi Kataoka                // dump
163f1074c508e70b3489dc85c036f7ed49d3196ba47Satoshi Kataoka                for (int j = 0; j < times.length; ++j) {
164f1074c508e70b3489dc85c036f7ed49d3196ba47Satoshi Kataoka                    Log.d(TAG, "--- (" + j + ") " + times[j]);
165f1074c508e70b3489dc85c036f7ed49d3196ba47Satoshi Kataoka                }
166f1074c508e70b3489dc85c036f7ed49d3196ba47Satoshi Kataoka                return false;
167f1074c508e70b3489dc85c036f7ed49d3196ba47Satoshi Kataoka            }
168f1074c508e70b3489dc85c036f7ed49d3196ba47Satoshi Kataoka        }
169f1074c508e70b3489dc85c036f7ed49d3196ba47Satoshi Kataoka        return true;
170f1074c508e70b3489dc85c036f7ed49d3196ba47Satoshi Kataoka    }
17171538b08e4e08d556f700ad344562ca2c7b74d82Satoshi Kataoka}
172