1/*
2 * Copyright (C) 2012 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
17package com.android.inputmethod.latin.common;
18
19import com.android.inputmethod.annotations.UsedForTesting;
20
21import javax.annotation.Nonnull;
22
23// TODO: This class is not thread-safe.
24public final class InputPointers {
25    private static final boolean DEBUG_TIME = false;
26
27    private final int mDefaultCapacity;
28    private final ResizableIntArray mXCoordinates;
29    private final ResizableIntArray mYCoordinates;
30    private final ResizableIntArray mPointerIds;
31    private final ResizableIntArray mTimes;
32
33    public InputPointers(final int defaultCapacity) {
34        mDefaultCapacity = defaultCapacity;
35        mXCoordinates = new ResizableIntArray(defaultCapacity);
36        mYCoordinates = new ResizableIntArray(defaultCapacity);
37        mPointerIds = new ResizableIntArray(defaultCapacity);
38        mTimes = new ResizableIntArray(defaultCapacity);
39    }
40
41    private void fillWithLastTimeUntil(final int index) {
42        final int fromIndex = mTimes.getLength();
43        // Fill the gap with the latest time.
44        // See {@link #getTime(int)} and {@link #isValidTimeStamps()}.
45        if (fromIndex <= 0) {
46            return;
47        }
48        final int fillLength = index - fromIndex + 1;
49        if (fillLength <= 0) {
50            return;
51        }
52        final int lastTime = mTimes.get(fromIndex - 1);
53        mTimes.fill(lastTime, fromIndex, fillLength);
54    }
55
56    public void addPointerAt(final int index, final int x, final int y, final int pointerId,
57            final int time) {
58        mXCoordinates.addAt(index, x);
59        mYCoordinates.addAt(index, y);
60        mPointerIds.addAt(index, pointerId);
61        if (DEBUG_TIME) {
62            fillWithLastTimeUntil(index);
63        }
64        mTimes.addAt(index, time);
65    }
66
67    @UsedForTesting
68    public void addPointer(final int x, final int y, final int pointerId, final int time) {
69        mXCoordinates.add(x);
70        mYCoordinates.add(y);
71        mPointerIds.add(pointerId);
72        mTimes.add(time);
73    }
74
75    public void set(@Nonnull final InputPointers ip) {
76        mXCoordinates.set(ip.mXCoordinates);
77        mYCoordinates.set(ip.mYCoordinates);
78        mPointerIds.set(ip.mPointerIds);
79        mTimes.set(ip.mTimes);
80    }
81
82    public void copy(@Nonnull final InputPointers ip) {
83        mXCoordinates.copy(ip.mXCoordinates);
84        mYCoordinates.copy(ip.mYCoordinates);
85        mPointerIds.copy(ip.mPointerIds);
86        mTimes.copy(ip.mTimes);
87    }
88
89    /**
90     * Append the times, x-coordinates and y-coordinates in the specified {@link ResizableIntArray}
91     * to the end of this.
92     * @param pointerId the pointer id of the source.
93     * @param times the source {@link ResizableIntArray} to read the event times from.
94     * @param xCoordinates the source {@link ResizableIntArray} to read the x-coordinates from.
95     * @param yCoordinates the source {@link ResizableIntArray} to read the y-coordinates from.
96     * @param startPos the starting index of the data in {@code times} and etc.
97     * @param length the number of data to be appended.
98     */
99    public void append(final int pointerId, @Nonnull final ResizableIntArray times,
100            @Nonnull final ResizableIntArray xCoordinates,
101            @Nonnull final ResizableIntArray yCoordinates, final int startPos, final int length) {
102        if (length == 0) {
103            return;
104        }
105        mXCoordinates.append(xCoordinates, startPos, length);
106        mYCoordinates.append(yCoordinates, startPos, length);
107        mPointerIds.fill(pointerId, mPointerIds.getLength(), length);
108        mTimes.append(times, startPos, length);
109    }
110
111    /**
112     * Shift to the left by elementCount, discarding elementCount pointers at the start.
113     * @param elementCount how many elements to shift.
114     */
115    @UsedForTesting
116    public void shift(final int elementCount) {
117        mXCoordinates.shift(elementCount);
118        mYCoordinates.shift(elementCount);
119        mPointerIds.shift(elementCount);
120        mTimes.shift(elementCount);
121    }
122
123    public void reset() {
124        final int defaultCapacity = mDefaultCapacity;
125        mXCoordinates.reset(defaultCapacity);
126        mYCoordinates.reset(defaultCapacity);
127        mPointerIds.reset(defaultCapacity);
128        mTimes.reset(defaultCapacity);
129    }
130
131    public int getPointerSize() {
132        return mXCoordinates.getLength();
133    }
134
135    @Nonnull
136    public int[] getXCoordinates() {
137        return mXCoordinates.getPrimitiveArray();
138    }
139
140    @Nonnull
141    public int[] getYCoordinates() {
142        return mYCoordinates.getPrimitiveArray();
143    }
144
145    @Nonnull
146    public int[] getPointerIds() {
147        return mPointerIds.getPrimitiveArray();
148    }
149
150    /**
151     * Gets the time each point was registered, in milliseconds, relative to the first event in the
152     * sequence.
153     * @return The time each point was registered, in milliseconds, relative to the first event in
154     * the sequence.
155     */
156    @Nonnull
157    public int[] getTimes() {
158        return mTimes.getPrimitiveArray();
159    }
160
161    @Override
162    public String toString() {
163        return "size=" + getPointerSize() + " id=" + mPointerIds + " time=" + mTimes
164                + " x=" + mXCoordinates + " y=" + mYCoordinates;
165    }
166}
167