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
1736799b2aa2982ec17341cd2c5ed81e608bcee8c6Jean Chalardpackage com.android.inputmethod.latin.common;
18e7dc5302afdaedc379e3725f2a5822b630b43276Tadashi G. Takaoka
1915f6d4ae34664ea3d92827a2c3003198c0bac70bTadashi G. Takaokaimport com.android.inputmethod.annotations.UsedForTesting;
2015f6d4ae34664ea3d92827a2c3003198c0bac70bTadashi G. Takaoka
21519df535996427c87242f8dbdd5993c6ab5a87d0Tadashi G. Takaokaimport javax.annotation.Nonnull;
22519df535996427c87242f8dbdd5993c6ab5a87d0Tadashi G. Takaoka
237247bff6d6d488640ac752127148e7746c43469dTadashi G. Takaoka// TODO: This class is not thread-safe.
24a28a05e971cc242b338331a3b78276fa95188d19Tadashi G. Takaokapublic final class InputPointers {
25e7dc5302afdaedc379e3725f2a5822b630b43276Tadashi G. Takaoka    private static final boolean DEBUG_TIME = false;
26e7dc5302afdaedc379e3725f2a5822b630b43276Tadashi G. Takaoka
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
33519df535996427c87242f8dbdd5993c6ab5a87d0Tadashi G. Takaoka    public InputPointers(final 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
41e7dc5302afdaedc379e3725f2a5822b630b43276Tadashi G. Takaoka    private void fillWithLastTimeUntil(final int index) {
42e7dc5302afdaedc379e3725f2a5822b630b43276Tadashi G. Takaoka        final int fromIndex = mTimes.getLength();
43e7dc5302afdaedc379e3725f2a5822b630b43276Tadashi G. Takaoka        // Fill the gap with the latest time.
44e7dc5302afdaedc379e3725f2a5822b630b43276Tadashi G. Takaoka        // See {@link #getTime(int)} and {@link #isValidTimeStamps()}.
45e7dc5302afdaedc379e3725f2a5822b630b43276Tadashi G. Takaoka        if (fromIndex <= 0) {
46e7dc5302afdaedc379e3725f2a5822b630b43276Tadashi G. Takaoka            return;
47e7dc5302afdaedc379e3725f2a5822b630b43276Tadashi G. Takaoka        }
48e7dc5302afdaedc379e3725f2a5822b630b43276Tadashi G. Takaoka        final int fillLength = index - fromIndex + 1;
49e7dc5302afdaedc379e3725f2a5822b630b43276Tadashi G. Takaoka        if (fillLength <= 0) {
50e7dc5302afdaedc379e3725f2a5822b630b43276Tadashi G. Takaoka            return;
51e7dc5302afdaedc379e3725f2a5822b630b43276Tadashi G. Takaoka        }
52e7dc5302afdaedc379e3725f2a5822b630b43276Tadashi G. Takaoka        final int lastTime = mTimes.get(fromIndex - 1);
53e7dc5302afdaedc379e3725f2a5822b630b43276Tadashi G. Takaoka        mTimes.fill(lastTime, fromIndex, fillLength);
54e7dc5302afdaedc379e3725f2a5822b630b43276Tadashi G. Takaoka    }
55e7dc5302afdaedc379e3725f2a5822b630b43276Tadashi G. Takaoka
56519df535996427c87242f8dbdd5993c6ab5a87d0Tadashi G. Takaoka    public void addPointerAt(final int index, final int x, final int y, final int pointerId,
57519df535996427c87242f8dbdd5993c6ab5a87d0Tadashi G. Takaoka            final int time) {
58ad78058a93492d4f114c6a6eb56177be9231a9ebTadashi G. Takaoka        mXCoordinates.addAt(index, x);
59ad78058a93492d4f114c6a6eb56177be9231a9ebTadashi G. Takaoka        mYCoordinates.addAt(index, y);
60ad78058a93492d4f114c6a6eb56177be9231a9ebTadashi G. Takaoka        mPointerIds.addAt(index, pointerId);
6136799b2aa2982ec17341cd2c5ed81e608bcee8c6Jean Chalard        if (DEBUG_TIME) {
62e7dc5302afdaedc379e3725f2a5822b630b43276Tadashi G. Takaoka            fillWithLastTimeUntil(index);
63e7dc5302afdaedc379e3725f2a5822b630b43276Tadashi G. Takaoka        }
64ad78058a93492d4f114c6a6eb56177be9231a9ebTadashi G. Takaoka        mTimes.addAt(index, time);
6571538b08e4e08d556f700ad344562ca2c7b74d82Satoshi Kataoka    }
6671538b08e4e08d556f700ad344562ca2c7b74d82Satoshi Kataoka
6715f6d4ae34664ea3d92827a2c3003198c0bac70bTadashi G. Takaoka    @UsedForTesting
68519df535996427c87242f8dbdd5993c6ab5a87d0Tadashi G. Takaoka    public void addPointer(final int x, final int y, final int pointerId, final int time) {
6971538b08e4e08d556f700ad344562ca2c7b74d82Satoshi Kataoka        mXCoordinates.add(x);
7071538b08e4e08d556f700ad344562ca2c7b74d82Satoshi Kataoka        mYCoordinates.add(y);
7171538b08e4e08d556f700ad344562ca2c7b74d82Satoshi Kataoka        mPointerIds.add(pointerId);
7271538b08e4e08d556f700ad344562ca2c7b74d82Satoshi Kataoka        mTimes.add(time);
7371538b08e4e08d556f700ad344562ca2c7b74d82Satoshi Kataoka    }
7471538b08e4e08d556f700ad344562ca2c7b74d82Satoshi Kataoka
75519df535996427c87242f8dbdd5993c6ab5a87d0Tadashi G. Takaoka    public void set(@Nonnull final InputPointers ip) {
7671538b08e4e08d556f700ad344562ca2c7b74d82Satoshi Kataoka        mXCoordinates.set(ip.mXCoordinates);
7771538b08e4e08d556f700ad344562ca2c7b74d82Satoshi Kataoka        mYCoordinates.set(ip.mYCoordinates);
7871538b08e4e08d556f700ad344562ca2c7b74d82Satoshi Kataoka        mPointerIds.set(ip.mPointerIds);
7971538b08e4e08d556f700ad344562ca2c7b74d82Satoshi Kataoka        mTimes.set(ip.mTimes);
8071538b08e4e08d556f700ad344562ca2c7b74d82Satoshi Kataoka    }
8171538b08e4e08d556f700ad344562ca2c7b74d82Satoshi Kataoka
82519df535996427c87242f8dbdd5993c6ab5a87d0Tadashi G. Takaoka    public void copy(@Nonnull final InputPointers ip) {
8371538b08e4e08d556f700ad344562ca2c7b74d82Satoshi Kataoka        mXCoordinates.copy(ip.mXCoordinates);
8471538b08e4e08d556f700ad344562ca2c7b74d82Satoshi Kataoka        mYCoordinates.copy(ip.mYCoordinates);
8571538b08e4e08d556f700ad344562ca2c7b74d82Satoshi Kataoka        mPointerIds.copy(ip.mPointerIds);
8671538b08e4e08d556f700ad344562ca2c7b74d82Satoshi Kataoka        mTimes.copy(ip.mTimes);
8771538b08e4e08d556f700ad344562ca2c7b74d82Satoshi Kataoka    }
8871538b08e4e08d556f700ad344562ca2c7b74d82Satoshi Kataoka
891087c53f5a6ced093eb4e71f88cff19e89819d73Tadashi G. Takaoka    /**
907519091f7c15c50a9a1e50d82fa92400335852ecTadashi G. Takaoka     * Append the times, x-coordinates and y-coordinates in the specified {@link ResizableIntArray}
917519091f7c15c50a9a1e50d82fa92400335852ecTadashi G. Takaoka     * to the end of this.
927519091f7c15c50a9a1e50d82fa92400335852ecTadashi G. Takaoka     * @param pointerId the pointer id of the source.
937519091f7c15c50a9a1e50d82fa92400335852ecTadashi G. Takaoka     * @param times the source {@link ResizableIntArray} to read the event times from.
947519091f7c15c50a9a1e50d82fa92400335852ecTadashi G. Takaoka     * @param xCoordinates the source {@link ResizableIntArray} to read the x-coordinates from.
957519091f7c15c50a9a1e50d82fa92400335852ecTadashi G. Takaoka     * @param yCoordinates the source {@link ResizableIntArray} to read the y-coordinates from.
967519091f7c15c50a9a1e50d82fa92400335852ecTadashi G. Takaoka     * @param startPos the starting index of the data in {@code times} and etc.
977519091f7c15c50a9a1e50d82fa92400335852ecTadashi G. Takaoka     * @param length the number of data to be appended.
987519091f7c15c50a9a1e50d82fa92400335852ecTadashi G. Takaoka     */
99519df535996427c87242f8dbdd5993c6ab5a87d0Tadashi G. Takaoka    public void append(final int pointerId, @Nonnull final ResizableIntArray times,
100519df535996427c87242f8dbdd5993c6ab5a87d0Tadashi G. Takaoka            @Nonnull final ResizableIntArray xCoordinates,
101519df535996427c87242f8dbdd5993c6ab5a87d0Tadashi G. Takaoka            @Nonnull final ResizableIntArray yCoordinates, final int startPos, final int length) {
1027519091f7c15c50a9a1e50d82fa92400335852ecTadashi G. Takaoka        if (length == 0) {
1037519091f7c15c50a9a1e50d82fa92400335852ecTadashi G. Takaoka            return;
1047519091f7c15c50a9a1e50d82fa92400335852ecTadashi G. Takaoka        }
1057519091f7c15c50a9a1e50d82fa92400335852ecTadashi G. Takaoka        mXCoordinates.append(xCoordinates, startPos, length);
1067519091f7c15c50a9a1e50d82fa92400335852ecTadashi G. Takaoka        mYCoordinates.append(yCoordinates, startPos, length);
10764a26b4389abb273afff7699a8c86596defd85bfTadashi G. Takaoka        mPointerIds.fill(pointerId, mPointerIds.getLength(), length);
1087519091f7c15c50a9a1e50d82fa92400335852ecTadashi G. Takaoka        mTimes.append(times, startPos, length);
1097519091f7c15c50a9a1e50d82fa92400335852ecTadashi G. Takaoka    }
1107519091f7c15c50a9a1e50d82fa92400335852ecTadashi G. Takaoka
111e8754aba1c8f217e7ca828de25e0506ac58daa99Keisuke Kuroyanagi    /**
112e8754aba1c8f217e7ca828de25e0506ac58daa99Keisuke Kuroyanagi     * Shift to the left by elementCount, discarding elementCount pointers at the start.
113e8754aba1c8f217e7ca828de25e0506ac58daa99Keisuke Kuroyanagi     * @param elementCount how many elements to shift.
114e8754aba1c8f217e7ca828de25e0506ac58daa99Keisuke Kuroyanagi     */
11554bf24f64b9bbd4c5e4b6d4c3c6144c047d6ddc6Mohammadinamul Sheik    @UsedForTesting
116e8754aba1c8f217e7ca828de25e0506ac58daa99Keisuke Kuroyanagi    public void shift(final int elementCount) {
117e8754aba1c8f217e7ca828de25e0506ac58daa99Keisuke Kuroyanagi        mXCoordinates.shift(elementCount);
118e8754aba1c8f217e7ca828de25e0506ac58daa99Keisuke Kuroyanagi        mYCoordinates.shift(elementCount);
119e8754aba1c8f217e7ca828de25e0506ac58daa99Keisuke Kuroyanagi        mPointerIds.shift(elementCount);
120e8754aba1c8f217e7ca828de25e0506ac58daa99Keisuke Kuroyanagi        mTimes.shift(elementCount);
121e8754aba1c8f217e7ca828de25e0506ac58daa99Keisuke Kuroyanagi    }
122e8754aba1c8f217e7ca828de25e0506ac58daa99Keisuke Kuroyanagi
12371538b08e4e08d556f700ad344562ca2c7b74d82Satoshi Kataoka    public void reset() {
12457f7de0ba664187e13bcea5adff7f5f65eddd823Tadashi G. Takaoka        final int defaultCapacity = mDefaultCapacity;
12557f7de0ba664187e13bcea5adff7f5f65eddd823Tadashi G. Takaoka        mXCoordinates.reset(defaultCapacity);
12657f7de0ba664187e13bcea5adff7f5f65eddd823Tadashi G. Takaoka        mYCoordinates.reset(defaultCapacity);
12757f7de0ba664187e13bcea5adff7f5f65eddd823Tadashi G. Takaoka        mPointerIds.reset(defaultCapacity);
12857f7de0ba664187e13bcea5adff7f5f65eddd823Tadashi G. Takaoka        mTimes.reset(defaultCapacity);
12971538b08e4e08d556f700ad344562ca2c7b74d82Satoshi Kataoka    }
13071538b08e4e08d556f700ad344562ca2c7b74d82Satoshi Kataoka
13171538b08e4e08d556f700ad344562ca2c7b74d82Satoshi Kataoka    public int getPointerSize() {
13271538b08e4e08d556f700ad344562ca2c7b74d82Satoshi Kataoka        return mXCoordinates.getLength();
13371538b08e4e08d556f700ad344562ca2c7b74d82Satoshi Kataoka    }
13471538b08e4e08d556f700ad344562ca2c7b74d82Satoshi Kataoka
135519df535996427c87242f8dbdd5993c6ab5a87d0Tadashi G. Takaoka    @Nonnull
13671538b08e4e08d556f700ad344562ca2c7b74d82Satoshi Kataoka    public int[] getXCoordinates() {
1371087c53f5a6ced093eb4e71f88cff19e89819d73Tadashi G. Takaoka        return mXCoordinates.getPrimitiveArray();
13871538b08e4e08d556f700ad344562ca2c7b74d82Satoshi Kataoka    }
13971538b08e4e08d556f700ad344562ca2c7b74d82Satoshi Kataoka
140519df535996427c87242f8dbdd5993c6ab5a87d0Tadashi G. Takaoka    @Nonnull
14171538b08e4e08d556f700ad344562ca2c7b74d82Satoshi Kataoka    public int[] getYCoordinates() {
1421087c53f5a6ced093eb4e71f88cff19e89819d73Tadashi G. Takaoka        return mYCoordinates.getPrimitiveArray();
14371538b08e4e08d556f700ad344562ca2c7b74d82Satoshi Kataoka    }
14471538b08e4e08d556f700ad344562ca2c7b74d82Satoshi Kataoka
145519df535996427c87242f8dbdd5993c6ab5a87d0Tadashi G. Takaoka    @Nonnull
14671538b08e4e08d556f700ad344562ca2c7b74d82Satoshi Kataoka    public int[] getPointerIds() {
1471087c53f5a6ced093eb4e71f88cff19e89819d73Tadashi G. Takaoka        return mPointerIds.getPrimitiveArray();
14871538b08e4e08d556f700ad344562ca2c7b74d82Satoshi Kataoka    }
14971538b08e4e08d556f700ad344562ca2c7b74d82Satoshi Kataoka
1509cf69a45b24646bdd4bf365afe4e8e9fb30f9a22David Faden    /**
1519cf69a45b24646bdd4bf365afe4e8e9fb30f9a22David Faden     * Gets the time each point was registered, in milliseconds, relative to the first event in the
1529cf69a45b24646bdd4bf365afe4e8e9fb30f9a22David Faden     * sequence.
1539cf69a45b24646bdd4bf365afe4e8e9fb30f9a22David Faden     * @return The time each point was registered, in milliseconds, relative to the first event in
1549cf69a45b24646bdd4bf365afe4e8e9fb30f9a22David Faden     * the sequence.
1559cf69a45b24646bdd4bf365afe4e8e9fb30f9a22David Faden     */
156519df535996427c87242f8dbdd5993c6ab5a87d0Tadashi G. Takaoka    @Nonnull
15771538b08e4e08d556f700ad344562ca2c7b74d82Satoshi Kataoka    public int[] getTimes() {
1581087c53f5a6ced093eb4e71f88cff19e89819d73Tadashi G. Takaoka        return mTimes.getPrimitiveArray();
15971538b08e4e08d556f700ad344562ca2c7b74d82Satoshi Kataoka    }
16064ee09610024eb1436c51f9c9ef9fc3f77239d73Tadashi G. Takaoka
16164ee09610024eb1436c51f9c9ef9fc3f77239d73Tadashi G. Takaoka    @Override
16264ee09610024eb1436c51f9c9ef9fc3f77239d73Tadashi G. Takaoka    public String toString() {
16364ee09610024eb1436c51f9c9ef9fc3f77239d73Tadashi G. Takaoka        return "size=" + getPointerSize() + " id=" + mPointerIds + " time=" + mTimes
16464ee09610024eb1436c51f9c9ef9fc3f77239d73Tadashi G. Takaoka                + " x=" + mXCoordinates + " y=" + mYCoordinates;
16564ee09610024eb1436c51f9c9ef9fc3f77239d73Tadashi G. Takaoka    }
16671538b08e4e08d556f700ad344562ca2c7b74d82Satoshi Kataoka}
167