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;
18
19import com.android.inputmethod.annotations.UsedForTesting;
20import com.android.inputmethod.latin.utils.ResizableIntArray;
21
22import android.util.Log;
23
24// TODO: This class is not thread-safe.
25public final class InputPointers {
26    private static final String TAG = InputPointers.class.getSimpleName();
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(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    public void addPointer(int index, int x, int y, int pointerId, int time) {
42        mXCoordinates.add(index, x);
43        mYCoordinates.add(index, y);
44        mPointerIds.add(index, pointerId);
45        mTimes.add(index, time);
46    }
47
48    @UsedForTesting
49    void addPointer(int x, int y, int pointerId, int time) {
50        mXCoordinates.add(x);
51        mYCoordinates.add(y);
52        mPointerIds.add(pointerId);
53        mTimes.add(time);
54    }
55
56    public void set(InputPointers ip) {
57        mXCoordinates.set(ip.mXCoordinates);
58        mYCoordinates.set(ip.mYCoordinates);
59        mPointerIds.set(ip.mPointerIds);
60        mTimes.set(ip.mTimes);
61    }
62
63    public void copy(InputPointers ip) {
64        mXCoordinates.copy(ip.mXCoordinates);
65        mYCoordinates.copy(ip.mYCoordinates);
66        mPointerIds.copy(ip.mPointerIds);
67        mTimes.copy(ip.mTimes);
68    }
69
70    /**
71     * Append the pointers in the specified {@link InputPointers} to the end of this.
72     * @param src the source {@link InputPointers} to read the data from.
73     * @param startPos the starting index of the pointers in {@code src}.
74     * @param length the number of pointers to be appended.
75     */
76    @UsedForTesting
77    void append(InputPointers src, int startPos, int length) {
78        if (length == 0) {
79            return;
80        }
81        mXCoordinates.append(src.mXCoordinates, startPos, length);
82        mYCoordinates.append(src.mYCoordinates, startPos, length);
83        mPointerIds.append(src.mPointerIds, startPos, length);
84        mTimes.append(src.mTimes, startPos, length);
85    }
86
87    /**
88     * Append the times, x-coordinates and y-coordinates in the specified {@link ResizableIntArray}
89     * to the end of this.
90     * @param pointerId the pointer id of the source.
91     * @param times the source {@link ResizableIntArray} to read the event times from.
92     * @param xCoordinates the source {@link ResizableIntArray} to read the x-coordinates from.
93     * @param yCoordinates the source {@link ResizableIntArray} to read the y-coordinates from.
94     * @param startPos the starting index of the data in {@code times} and etc.
95     * @param length the number of data to be appended.
96     */
97    public void append(int pointerId, ResizableIntArray times, ResizableIntArray xCoordinates,
98            ResizableIntArray yCoordinates, int startPos, int length) {
99        if (length == 0) {
100            return;
101        }
102        mXCoordinates.append(xCoordinates, startPos, length);
103        mYCoordinates.append(yCoordinates, startPos, length);
104        mPointerIds.fill(pointerId, mPointerIds.getLength(), length);
105        mTimes.append(times, startPos, length);
106    }
107
108    /**
109     * Shift to the left by elementCount, discarding elementCount pointers at the start.
110     * @param elementCount how many elements to shift.
111     */
112    public void shift(final int elementCount) {
113        mXCoordinates.shift(elementCount);
114        mYCoordinates.shift(elementCount);
115        mPointerIds.shift(elementCount);
116        mTimes.shift(elementCount);
117    }
118
119    public void reset() {
120        final int defaultCapacity = mDefaultCapacity;
121        mXCoordinates.reset(defaultCapacity);
122        mYCoordinates.reset(defaultCapacity);
123        mPointerIds.reset(defaultCapacity);
124        mTimes.reset(defaultCapacity);
125    }
126
127    public int getPointerSize() {
128        return mXCoordinates.getLength();
129    }
130
131    public int[] getXCoordinates() {
132        return mXCoordinates.getPrimitiveArray();
133    }
134
135    public int[] getYCoordinates() {
136        return mYCoordinates.getPrimitiveArray();
137    }
138
139    public int[] getPointerIds() {
140        return mPointerIds.getPrimitiveArray();
141    }
142
143    public int[] getTimes() {
144        if (LatinImeLogger.sDBG) {
145            if (!isValidTimeStamps()) {
146                throw new RuntimeException("Time stamps are invalid.");
147            }
148        }
149        return mTimes.getPrimitiveArray();
150    }
151
152    @Override
153    public String toString() {
154        return "size=" + getPointerSize() + " id=" + mPointerIds + " time=" + mTimes
155                + " x=" + mXCoordinates + " y=" + mYCoordinates;
156    }
157
158    private boolean isValidTimeStamps() {
159        final int[] times = mTimes.getPrimitiveArray();
160        for (int i = 1; i < getPointerSize(); ++i) {
161            if (times[i] < times[i - 1]) {
162                // dump
163                for (int j = 0; j < times.length; ++j) {
164                    Log.d(TAG, "--- (" + j + ") " + times[j]);
165                }
166                return false;
167            }
168        }
169        return true;
170    }
171}
172