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