314 lines
11 KiB
Java
314 lines
11 KiB
Java
/*
|
|
* Copyright (C) 2014 The Android Open Source Project
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
|
* use this file except in compliance with the License. You may obtain a copy of
|
|
* the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
* License for the specific language governing permissions and limitations under
|
|
* the License.
|
|
*/
|
|
|
|
package android.view.inputmethod;
|
|
|
|
import android.annotation.Nullable;
|
|
import android.graphics.RectF;
|
|
import android.os.Parcel;
|
|
import android.os.Parcelable;
|
|
|
|
import java.util.Arrays;
|
|
|
|
/**
|
|
* An implementation of SparseArray specialized for {@link android.graphics.RectF}.
|
|
* <p>
|
|
* As this is a sparse array, it represents an array of {@link RectF} most of which are null. This
|
|
* class could be in some other packages like android.graphics or android.util but currently
|
|
* belong to android.view.inputmethod because this class is hidden and used only in input method
|
|
* framework.
|
|
* </p>
|
|
* @hide
|
|
*/
|
|
public final class SparseRectFArray implements Parcelable {
|
|
/**
|
|
* The keys, in ascending order, of those {@link RectF} that are not null. For example,
|
|
* {@code [null, null, null, Rect1, null, Rect2]} would be represented by {@code [3,5]}.
|
|
* @see #mCoordinates
|
|
*/
|
|
private final int[] mKeys;
|
|
|
|
/**
|
|
* Stores coordinates of the rectangles, in the order of
|
|
* {@code rects[mKeys[0]].left}, {@code rects[mKeys[0]].top},
|
|
* {@code rects[mKeys[0]].right}, {@code rects[mKeys[0]].bottom},
|
|
* {@code rects[mKeys[1]].left}, {@code rects[mKeys[1]].top},
|
|
* {@code rects[mKeys[1]].right}, {@code rects[mKeys[1]].bottom},
|
|
* {@code rects[mKeys[2]].left}, {@code rects[mKeys[2]].top}, ....
|
|
*/
|
|
private final float[] mCoordinates;
|
|
|
|
/**
|
|
* Stores visibility information.
|
|
*/
|
|
private final int[] mFlagsArray;
|
|
|
|
public SparseRectFArray(final Parcel source) {
|
|
mKeys = source.createIntArray();
|
|
mCoordinates = source.createFloatArray();
|
|
mFlagsArray = source.createIntArray();
|
|
}
|
|
|
|
/**
|
|
* Used to package this object into a {@link Parcel}.
|
|
*
|
|
* @param dest The {@link Parcel} to be written.
|
|
* @param flags The flags used for parceling.
|
|
*/
|
|
@Override
|
|
public void writeToParcel(Parcel dest, int flags) {
|
|
dest.writeIntArray(mKeys);
|
|
dest.writeFloatArray(mCoordinates);
|
|
dest.writeIntArray(mFlagsArray);
|
|
}
|
|
|
|
@Override
|
|
public int hashCode() {
|
|
// TODO: Improve the hash function.
|
|
if (mKeys == null || mKeys.length == 0) {
|
|
return 0;
|
|
}
|
|
int hash = mKeys.length;
|
|
// For performance reasons, only the first rectangle is used for the hash code now.
|
|
for (int i = 0; i < 4; i++) {
|
|
hash *= 31;
|
|
hash += mCoordinates[i];
|
|
}
|
|
hash *= 31;
|
|
hash += mFlagsArray[0];
|
|
return hash;
|
|
}
|
|
|
|
@Override
|
|
public boolean equals(@Nullable Object obj){
|
|
if (obj == null) {
|
|
return false;
|
|
}
|
|
if (this == obj) {
|
|
return true;
|
|
}
|
|
if (!(obj instanceof SparseRectFArray)) {
|
|
return false;
|
|
}
|
|
final SparseRectFArray that = (SparseRectFArray) obj;
|
|
|
|
return Arrays.equals(mKeys, that.mKeys) && Arrays.equals(mCoordinates, that.mCoordinates)
|
|
&& Arrays.equals(mFlagsArray, that.mFlagsArray);
|
|
}
|
|
|
|
@Override
|
|
public String toString() {
|
|
if (mKeys == null || mCoordinates == null || mFlagsArray == null) {
|
|
return "SparseRectFArray{}";
|
|
}
|
|
final StringBuilder sb = new StringBuilder();
|
|
sb.append("SparseRectFArray{");
|
|
for (int i = 0; i < mKeys.length; i++) {
|
|
if (i != 0) {
|
|
sb.append(", ");
|
|
}
|
|
final int baseIndex = i * 4;
|
|
sb.append(mKeys[i]);
|
|
sb.append(":[");
|
|
sb.append(mCoordinates[baseIndex + 0]);
|
|
sb.append(",");
|
|
sb.append(mCoordinates[baseIndex + 1]);
|
|
sb.append("],[");
|
|
sb.append(mCoordinates[baseIndex + 2]);
|
|
sb.append(",");
|
|
sb.append(mCoordinates[baseIndex + 3]);
|
|
sb.append("]:flagsArray=");
|
|
sb.append(mFlagsArray[i]);
|
|
}
|
|
sb.append("}");
|
|
return sb.toString();
|
|
}
|
|
|
|
/**
|
|
* Builder for {@link SparseRectFArray}. This class is not designed to be thread-safe.
|
|
* @hide
|
|
*/
|
|
public static final class SparseRectFArrayBuilder {
|
|
/**
|
|
* Throws {@link IllegalArgumentException} to make sure that this class is correctly used.
|
|
* @param key key to be checked.
|
|
*/
|
|
private void checkIndex(final int key) {
|
|
if (mCount == 0) {
|
|
return;
|
|
}
|
|
if (mKeys[mCount - 1] >= key) {
|
|
throw new IllegalArgumentException("key must be greater than all existing keys.");
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Extends the internal array if necessary.
|
|
*/
|
|
private void ensureBufferSize() {
|
|
if (mKeys == null) {
|
|
mKeys = new int[INITIAL_SIZE];
|
|
}
|
|
if (mCoordinates == null) {
|
|
mCoordinates = new float[INITIAL_SIZE * 4];
|
|
}
|
|
if (mFlagsArray == null) {
|
|
mFlagsArray = new int[INITIAL_SIZE];
|
|
}
|
|
final int requiredIndexArraySize = mCount + 1;
|
|
if (mKeys.length <= requiredIndexArraySize) {
|
|
final int[] newArray = new int[requiredIndexArraySize * 2];
|
|
System.arraycopy(mKeys, 0, newArray, 0, mCount);
|
|
mKeys = newArray;
|
|
}
|
|
final int requiredCoordinatesArraySize = (mCount + 1) * 4;
|
|
if (mCoordinates.length <= requiredCoordinatesArraySize) {
|
|
final float[] newArray = new float[requiredCoordinatesArraySize * 2];
|
|
System.arraycopy(mCoordinates, 0, newArray, 0, mCount * 4);
|
|
mCoordinates = newArray;
|
|
}
|
|
final int requiredFlagsArraySize = requiredIndexArraySize;
|
|
if (mFlagsArray.length <= requiredFlagsArraySize) {
|
|
final int[] newArray = new int[requiredFlagsArraySize * 2];
|
|
System.arraycopy(mFlagsArray, 0, newArray, 0, mCount);
|
|
mFlagsArray = newArray;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Puts the rectangle with an integer key.
|
|
* @param key the key to be associated with the rectangle. It must be greater than all
|
|
* existing keys that have been previously specified.
|
|
* @param left left of the rectangle.
|
|
* @param top top of the rectangle.
|
|
* @param right right of the rectangle.
|
|
* @param bottom bottom of the rectangle.
|
|
* @param flags an arbitrary integer value to be associated with this rectangle.
|
|
* @return the receiver object itself for chaining method calls.
|
|
* @throws IllegalArgumentException If the index is not greater than all of existing keys.
|
|
*/
|
|
public SparseRectFArrayBuilder append(final int key,
|
|
final float left, final float top, final float right, final float bottom,
|
|
final int flags) {
|
|
checkIndex(key);
|
|
ensureBufferSize();
|
|
final int baseCoordinatesIndex = mCount * 4;
|
|
mCoordinates[baseCoordinatesIndex + 0] = left;
|
|
mCoordinates[baseCoordinatesIndex + 1] = top;
|
|
mCoordinates[baseCoordinatesIndex + 2] = right;
|
|
mCoordinates[baseCoordinatesIndex + 3] = bottom;
|
|
final int flagsIndex = mCount;
|
|
mFlagsArray[flagsIndex] = flags;
|
|
mKeys[mCount] = key;
|
|
++mCount;
|
|
return this;
|
|
}
|
|
private int mCount = 0;
|
|
private int[] mKeys = null;
|
|
private float[] mCoordinates = null;
|
|
private int[] mFlagsArray = null;
|
|
private static int INITIAL_SIZE = 16;
|
|
|
|
public boolean isEmpty() {
|
|
return mCount <= 0;
|
|
}
|
|
|
|
/**
|
|
* @return {@link SparseRectFArray} using parameters in this {@link SparseRectFArray}.
|
|
*/
|
|
public SparseRectFArray build() {
|
|
return new SparseRectFArray(this);
|
|
}
|
|
|
|
public void reset() {
|
|
if (mCount == 0) {
|
|
mKeys = null;
|
|
mCoordinates = null;
|
|
mFlagsArray = null;
|
|
}
|
|
mCount = 0;
|
|
}
|
|
}
|
|
|
|
private SparseRectFArray(final SparseRectFArrayBuilder builder) {
|
|
if (builder.mCount == 0) {
|
|
mKeys = null;
|
|
mCoordinates = null;
|
|
mFlagsArray = null;
|
|
} else {
|
|
mKeys = new int[builder.mCount];
|
|
mCoordinates = new float[builder.mCount * 4];
|
|
mFlagsArray = new int[builder.mCount];
|
|
System.arraycopy(builder.mKeys, 0, mKeys, 0, builder.mCount);
|
|
System.arraycopy(builder.mCoordinates, 0, mCoordinates, 0, builder.mCount * 4);
|
|
System.arraycopy(builder.mFlagsArray, 0, mFlagsArray, 0, builder.mCount);
|
|
}
|
|
}
|
|
|
|
public RectF get(final int index) {
|
|
if (mKeys == null) {
|
|
return null;
|
|
}
|
|
if (index < 0) {
|
|
return null;
|
|
}
|
|
final int arrayIndex = Arrays.binarySearch(mKeys, index);
|
|
if (arrayIndex < 0) {
|
|
return null;
|
|
}
|
|
final int baseCoordIndex = arrayIndex * 4;
|
|
return new RectF(mCoordinates[baseCoordIndex],
|
|
mCoordinates[baseCoordIndex + 1],
|
|
mCoordinates[baseCoordIndex + 2],
|
|
mCoordinates[baseCoordIndex + 3]);
|
|
}
|
|
|
|
public int getFlags(final int index, final int valueIfKeyNotFound) {
|
|
if (mKeys == null) {
|
|
return valueIfKeyNotFound;
|
|
}
|
|
if (index < 0) {
|
|
return valueIfKeyNotFound;
|
|
}
|
|
final int arrayIndex = Arrays.binarySearch(mKeys, index);
|
|
if (arrayIndex < 0) {
|
|
return valueIfKeyNotFound;
|
|
}
|
|
return mFlagsArray[arrayIndex];
|
|
}
|
|
|
|
/**
|
|
* Used to make this class parcelable.
|
|
*/
|
|
public static final @android.annotation.NonNull Parcelable.Creator<SparseRectFArray> CREATOR =
|
|
new Parcelable.Creator<SparseRectFArray>() {
|
|
@Override
|
|
public SparseRectFArray createFromParcel(Parcel source) {
|
|
return new SparseRectFArray(source);
|
|
}
|
|
@Override
|
|
public SparseRectFArray[] newArray(int size) {
|
|
return new SparseRectFArray[size];
|
|
}
|
|
};
|
|
|
|
@Override
|
|
public int describeContents() {
|
|
return 0;
|
|
}
|
|
}
|
|
|