am 9c31c106: camera2: Add re-usable data types for camera metadata key/values
* commit '9c31c106db115c8fba67f83a1b416839b99317ee': camera2: Add re-usable data types for camera metadata key/values
This commit is contained in:
239
core/java/android/hardware/camera2/ColorSpaceTransform.java
Normal file
239
core/java/android/hardware/camera2/ColorSpaceTransform.java
Normal file
@@ -0,0 +1,239 @@
|
||||
/*
|
||||
* 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.hardware.camera2;
|
||||
|
||||
import static com.android.internal.util.Preconditions.*;
|
||||
import android.hardware.camera2.impl.HashCodeHelpers;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* Immutable class for describing a 3x3 matrix of {@link Rational} values in row-major order.
|
||||
*
|
||||
* <p>This matrix maps a transform from one color space to another. For the particular color space
|
||||
* source and target, see the appropriate camera metadata documentation for the key that provides
|
||||
* this value.</p>
|
||||
*
|
||||
* @see CameraMetadata
|
||||
*/
|
||||
public final class ColorSpaceTransform {
|
||||
|
||||
/** The number of rows in this matrix. */
|
||||
private static final int ROWS = 3;
|
||||
|
||||
/** The number of columns in this matrix. */
|
||||
private static final int COLUMNS = 3;
|
||||
|
||||
/** The number of total Rational elements in this matrix. */
|
||||
private static final int COUNT = ROWS * COLUMNS;
|
||||
|
||||
/** Number of int elements in a rational. */
|
||||
private static final int RATIONAL_SIZE = 2;
|
||||
|
||||
/** Numerator offset inside a rational (pair). */
|
||||
private static final int OFFSET_NUMERATOR = 0;
|
||||
|
||||
/** Denominator offset inside a rational (pair). */
|
||||
private static final int OFFSET_DENOMINATOR = 1;
|
||||
|
||||
/** Number of int elements in this matrix. */
|
||||
private static final int COUNT_INT = ROWS * COLUMNS * RATIONAL_SIZE;
|
||||
|
||||
/**
|
||||
* Create a new immutable {@link ColorSpaceTransform} instance from a {@link Rational} array.
|
||||
*
|
||||
* <p>The elements must be stored in a row-major order.</p>
|
||||
*
|
||||
* @param elements An array of {@code 9} elements
|
||||
*
|
||||
* @throws IllegalArgumentException
|
||||
* if the count of {@code elements} is not {@code 9}
|
||||
* @throws NullPointerException
|
||||
* if {@code elements} or any sub-element is {@code null}
|
||||
*/
|
||||
public ColorSpaceTransform(Rational[] elements) {
|
||||
|
||||
checkNotNull(elements, "elements must not be null");
|
||||
if (elements.length != COUNT) {
|
||||
throw new IllegalArgumentException("elements must be " + COUNT + " length");
|
||||
}
|
||||
|
||||
mElements = new int[COUNT_INT];
|
||||
|
||||
for (int i = 0; i < elements.length; ++i) {
|
||||
checkNotNull(elements, "element[" + i + "] must not be null");
|
||||
mElements[i * RATIONAL_SIZE + OFFSET_NUMERATOR] = elements[i].getNumerator();
|
||||
mElements[i * RATIONAL_SIZE + OFFSET_DENOMINATOR] = elements[i].getDenominator();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new immutable {@link ColorSpaceTransform} instance from an {@code int} array.
|
||||
*
|
||||
* <p>The elements must be stored in a row-major order. Each rational is stored
|
||||
* contiguously as a {@code (numerator, denominator)} pair.</p>
|
||||
*
|
||||
* <p>In particular:<pre>{@code
|
||||
* int[] elements = new int[
|
||||
* N11, D11, N12, D12, N13, D13,
|
||||
* N21, D21, N22, D22, N23, D23,
|
||||
* N31, D31, N32, D32, N33, D33
|
||||
* ];
|
||||
*
|
||||
* new ColorSpaceTransform(elements)}</pre>
|
||||
*
|
||||
* where {@code Nij} and {@code Dij} is the numerator and denominator for row {@code i} and
|
||||
* column {@code j}.</p>
|
||||
*
|
||||
* @param elements An array of {@code 18} elements
|
||||
*
|
||||
* @throws IllegalArgumentException
|
||||
* if the count of {@code elements} is not {@code 18}
|
||||
* @throws NullPointerException
|
||||
* if {@code elements} is {@code null}
|
||||
*/
|
||||
public ColorSpaceTransform(int[] elements) {
|
||||
checkNotNull(elements, "elements must not be null");
|
||||
if (elements.length != COUNT_INT) {
|
||||
throw new IllegalArgumentException("elements must be " + COUNT_INT + " length");
|
||||
}
|
||||
|
||||
for (int i = 0; i < elements.length; ++i) {
|
||||
checkNotNull(elements, "element " + i + " must not be null");
|
||||
}
|
||||
|
||||
mElements = Arrays.copyOf(elements, elements.length);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an element of this matrix by its row and column.
|
||||
*
|
||||
* <p>The rows must be within the range [0, 3),
|
||||
* and the column must be within the range [0, 3).</p>
|
||||
*
|
||||
* @return element (non-{@code null})
|
||||
*
|
||||
* @throws IllegalArgumentException if column or row was out of range
|
||||
*/
|
||||
public Rational getElement(int column, int row) {
|
||||
if (column < 0 || column >= COLUMNS) {
|
||||
throw new IllegalArgumentException("column out of range");
|
||||
} else if (row < 0 || row >= ROWS) {
|
||||
throw new IllegalArgumentException("row out of range");
|
||||
}
|
||||
|
||||
int numerator = mElements[row * ROWS * RATIONAL_SIZE + column + OFFSET_NUMERATOR];
|
||||
int denominator = mElements[row * ROWS * RATIONAL_SIZE + column + OFFSET_DENOMINATOR];
|
||||
|
||||
return new Rational(numerator, denominator);
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy the {@link Rational} elements in row-major order from this matrix into the destination.
|
||||
*
|
||||
* @param destination
|
||||
* an array big enough to hold at least {@code 9} elements after the
|
||||
* {@code offset}
|
||||
* @param offset
|
||||
* a non-negative offset into the array
|
||||
* @throws NullPointerException
|
||||
* If {@code destination} was {@code null}
|
||||
* @throws ArrayIndexOutOfBoundsException
|
||||
* If there's not enough room to write the elements at the specified destination and
|
||||
* offset.
|
||||
*/
|
||||
public void copyElements(Rational[] destination, int offset) {
|
||||
checkArgumentNonnegative(offset, "offset must not be negative");
|
||||
checkNotNull(destination, "destination must not be null");
|
||||
if (destination.length + offset < COUNT) {
|
||||
throw new ArrayIndexOutOfBoundsException("destination too small to fit elements");
|
||||
}
|
||||
|
||||
for (int i = 0, j = 0; i < COUNT; ++i, j += RATIONAL_SIZE) {
|
||||
int numerator = mElements[j + OFFSET_NUMERATOR];
|
||||
int denominator = mElements[j + OFFSET_DENOMINATOR];
|
||||
|
||||
destination[i + offset] = new Rational(numerator, denominator);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy the {@link Rational} elements in row-major order from this matrix into the destination.
|
||||
*
|
||||
* <p>Each element is stored as a contiguous rational packed as a
|
||||
* {@code (numerator, denominator)} pair of ints, identical to the
|
||||
* {@link ColorSpaceTransform#ColorSpaceTransform(int[]) constructor}.</p>
|
||||
*
|
||||
* @param destination
|
||||
* an array big enough to hold at least {@code 18} elements after the
|
||||
* {@code offset}
|
||||
* @param offset
|
||||
* a non-negative offset into the array
|
||||
* @throws NullPointerException
|
||||
* If {@code destination} was {@code null}
|
||||
* @throws ArrayIndexOutOfBoundsException
|
||||
* If there's not enough room to write the elements at the specified destination and
|
||||
* offset.
|
||||
*
|
||||
* @see ColorSpaceTransform#ColorSpaceTransform(int[])
|
||||
*/
|
||||
public void copyElements(int[] destination, int offset) {
|
||||
checkArgumentNonnegative(offset, "offset must not be negative");
|
||||
checkNotNull(destination, "destination must not be null");
|
||||
if (destination.length + offset < COUNT_INT) {
|
||||
throw new ArrayIndexOutOfBoundsException("destination too small to fit elements");
|
||||
}
|
||||
|
||||
// Manual copy faster than System#arraycopy for very small loops
|
||||
for (int i = 0; i < COUNT_INT; ++i) {
|
||||
destination[i + offset] = mElements[i];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if this {@link ColorSpaceTransform} is equal to another {@link ColorSpaceTransform}.
|
||||
*
|
||||
* <p>Two color space transforms are equal if and only if all of their elements are
|
||||
* {@link Object#equals equal}.</p>
|
||||
*
|
||||
* @return {@code true} if the objects were equal, {@code false} otherwise
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(final Object obj) {
|
||||
if (obj == null) {
|
||||
return false;
|
||||
}
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if (obj instanceof ColorSpaceTransform) {
|
||||
final ColorSpaceTransform other = (ColorSpaceTransform) obj;
|
||||
return Arrays.equals(mElements, other.mElements);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return HashCodeHelpers.hashCode(mElements);
|
||||
}
|
||||
|
||||
private final int[] mElements;
|
||||
};
|
||||
224
core/java/android/hardware/camera2/MeteringRectangle.java
Normal file
224
core/java/android/hardware/camera2/MeteringRectangle.java
Normal file
@@ -0,0 +1,224 @@
|
||||
/*
|
||||
* 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.hardware.camera2;
|
||||
|
||||
import android.util.Size;
|
||||
import static com.android.internal.util.Preconditions.*;
|
||||
|
||||
import android.graphics.Point;
|
||||
import android.graphics.Rect;
|
||||
import android.hardware.camera2.impl.HashCodeHelpers;
|
||||
|
||||
/**
|
||||
* An immutable class to represent a rectangle {@code (x,y, width, height)} with an
|
||||
* additional weight component.
|
||||
*
|
||||
* </p>The rectangle is defined to be inclusive of the specified coordinates.</p>
|
||||
*
|
||||
* <p>When used with a {@link CaptureRequest}, the coordinate system is based on the active pixel
|
||||
* array, with {@code (0,0)} being the top-left pixel in the
|
||||
* {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE active pixel array}, and
|
||||
* {@code (android.sensor.info.activeArraySize.width - 1,
|
||||
* android.sensor.info.activeArraySize.height - 1)}
|
||||
* being the bottom-right pixel in the active pixel array.
|
||||
* </p>
|
||||
*
|
||||
* <p>The metering weight is nonnegative.</p>
|
||||
*/
|
||||
public final class MeteringRectangle {
|
||||
|
||||
private final int mX;
|
||||
private final int mY;
|
||||
private final int mWidth;
|
||||
private final int mHeight;
|
||||
private final int mWeight;
|
||||
|
||||
/**
|
||||
* Create a new metering rectangle.
|
||||
*
|
||||
* @param x coordinate >= 0
|
||||
* @param y coordinate >= 0
|
||||
* @param width width >= 0
|
||||
* @param height height >= 0
|
||||
* @param meteringWeight weight >= 0
|
||||
*
|
||||
* @throws IllegalArgumentException if any of the parameters were non-negative
|
||||
*/
|
||||
public MeteringRectangle(int x, int y, int width, int height, int meteringWeight) {
|
||||
mX = checkArgumentNonnegative(x, "x must be nonnegative");
|
||||
mY = checkArgumentNonnegative(y, "y must be nonnegative");
|
||||
mWidth = checkArgumentNonnegative(width, "width must be nonnegative");
|
||||
mHeight = checkArgumentNonnegative(height, "height must be nonnegative");
|
||||
mWeight = checkArgumentNonnegative(meteringWeight, "meteringWeight must be nonnegative");
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new metering rectangle.
|
||||
*
|
||||
* @param xy a non-{@code null} {@link Point} with both x,y >= 0
|
||||
* @param dimensions a non-{@code null} {@link android.util.Size Size} with width, height >= 0
|
||||
* @param meteringWeight weight >= 0
|
||||
*
|
||||
* @throws IllegalArgumentException if any of the parameters were non-negative
|
||||
* @throws NullPointerException if any of the arguments were null
|
||||
*/
|
||||
public MeteringRectangle(Point xy, Size dimensions, int meteringWeight) {
|
||||
checkNotNull(xy, "xy must not be null");
|
||||
checkNotNull(dimensions, "dimensions must not be null");
|
||||
|
||||
mX = checkArgumentNonnegative(xy.x, "x must be nonnegative");
|
||||
mY = checkArgumentNonnegative(xy.y, "y must be nonnegative");
|
||||
mWidth = checkArgumentNonnegative(dimensions.getWidth(), "width must be nonnegative");
|
||||
mHeight = checkArgumentNonnegative(dimensions.getHeight(), "height must be nonnegative");
|
||||
mWeight = checkArgumentNonnegative(meteringWeight, "meteringWeight must be nonnegative");
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new metering rectangle.
|
||||
*
|
||||
* @param rect a non-{@code null} rectangle with all x,y,w,h dimensions >= 0
|
||||
* @param meteringWeight weight >= 0
|
||||
*
|
||||
* @throws IllegalArgumentException if any of the parameters were non-negative
|
||||
* @throws NullPointerException if any of the arguments were null
|
||||
*/
|
||||
public MeteringRectangle(Rect rect, int meteringWeight) {
|
||||
checkNotNull(rect, "rect must not be null");
|
||||
|
||||
mX = checkArgumentNonnegative(rect.left, "rect.left must be nonnegative");
|
||||
mY = checkArgumentNonnegative(rect.top, "rect.top must be nonnegative");
|
||||
mWidth = checkArgumentNonnegative(rect.width(), "rect.width must be nonnegative");
|
||||
mHeight = checkArgumentNonnegative(rect.height(), "rect.height must be nonnegative");
|
||||
mWeight = checkArgumentNonnegative(meteringWeight, "meteringWeight must be nonnegative");
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the X coordinate of the left side of the rectangle.
|
||||
*
|
||||
* @return x coordinate >= 0
|
||||
*/
|
||||
public int getX() {
|
||||
return mX;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the Y coordinate of the upper side of the rectangle.
|
||||
*
|
||||
* @return y coordinate >= 0
|
||||
*/
|
||||
public int getY() {
|
||||
return mY;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the width of the rectangle.
|
||||
*
|
||||
* @return width >= 0
|
||||
*/
|
||||
public int getWidth() {
|
||||
return mWidth;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the height of the rectangle.
|
||||
*
|
||||
* @return height >= 0
|
||||
*/
|
||||
public int getHeight() {
|
||||
return mHeight;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the metering weight of the rectangle.
|
||||
*
|
||||
* @return weight >= 0
|
||||
*/
|
||||
public int getMeteringWeight() {
|
||||
return mWeight;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience method to create the upper-left (X,Y) coordinate as a {@link Point}.
|
||||
*
|
||||
* @return {@code (x,y)} point with both x,y >= 0
|
||||
*/
|
||||
public Point getUpperLeftPoint() {
|
||||
return new Point(mX, mY);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience method to create the size from this metering rectangle.
|
||||
*
|
||||
* <p>This strips away the X,Y,weight from the rectangle.</p>
|
||||
*
|
||||
* @return a Size with non-negative width and height
|
||||
*/
|
||||
public Size getSize() {
|
||||
return new Size(mWidth, mHeight);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience method to create a {@link Rect} from this metering rectangle.
|
||||
*
|
||||
* <p>This strips away the weight from the rectangle.</p>
|
||||
*
|
||||
* @return a {@link Rect} with non-negative x1, y1, x2, y2
|
||||
*/
|
||||
public Rect getRect() {
|
||||
return new Rect(mX, mY, mX + mWidth, mY + mHeight);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(final Object other) {
|
||||
if (other instanceof MeteringRectangle) {
|
||||
return equals(other);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compare two metering rectangles to see if they are equal.
|
||||
*
|
||||
* Two weighted rectangles are only considered equal if each of their components
|
||||
* (x, y, width, height, weight) is respectively equal.
|
||||
*
|
||||
* @param other Another MeteringRectangle
|
||||
*
|
||||
* @return {@code true} if the metering rectangles are equal, {@code false} otherwise
|
||||
*/
|
||||
public boolean equals(final MeteringRectangle other) {
|
||||
if (other == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return (mX == other.mX
|
||||
&& mY == other.mY
|
||||
&& mWidth == other.mWidth
|
||||
&& mHeight == other.mHeight
|
||||
&& mWidth == other.mWidth);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return HashCodeHelpers.hashCode(mX, mY, mWidth, mHeight, mWeight);
|
||||
}
|
||||
}
|
||||
@@ -16,32 +16,55 @@
|
||||
|
||||
package android.hardware.camera2;
|
||||
|
||||
// TODO: Delete this class, since it was moved to android.util as public API
|
||||
|
||||
/**
|
||||
* A simple immutable class for describing the dimensions of camera image
|
||||
* buffers.
|
||||
* Immutable class for describing width and height dimensions in pixels.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public final class Size {
|
||||
/**
|
||||
* Create a new immutable Size instance
|
||||
* Create a new immutable Size instance.
|
||||
*
|
||||
* @param width The width to store in the Size instance
|
||||
* @param height The height to store in the Size instance
|
||||
* @param width The width of the size, in pixels
|
||||
* @param height The height of the size, in pixels
|
||||
*/
|
||||
public Size(int width, int height) {
|
||||
public Size(final int width, final int height) {
|
||||
mWidth = width;
|
||||
mHeight = height;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the width of the size (in pixels).
|
||||
* @return width
|
||||
*/
|
||||
public final int getWidth() {
|
||||
return mWidth;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the height of the size (in pixels).
|
||||
* @return height
|
||||
*/
|
||||
public final int getHeight() {
|
||||
return mHeight;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if this size is equal to another size.
|
||||
* <p>
|
||||
* Two sizes are equal if and only if both their widths and heights are
|
||||
* equal.
|
||||
* </p>
|
||||
* <p>
|
||||
* A size object is never equal to any other type of object.
|
||||
* </p>
|
||||
*
|
||||
* @return {@code true} if the objects were equal, {@code false} otherwise
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
public boolean equals(final Object obj) {
|
||||
if (obj == null) {
|
||||
return false;
|
||||
}
|
||||
@@ -49,27 +72,29 @@ public final class Size {
|
||||
return true;
|
||||
}
|
||||
if (obj instanceof Size) {
|
||||
Size other = (Size) obj;
|
||||
final Size other = (Size) obj;
|
||||
return mWidth == other.mWidth && mHeight == other.mHeight;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the size represented as a string with the format {@code "WxH"}
|
||||
*
|
||||
* @return string representation of the size
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return mWidth + "x" + mHeight;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final long INT_MASK = 0xffffffffL;
|
||||
|
||||
long asLong = INT_MASK & mWidth;
|
||||
asLong <<= 32;
|
||||
|
||||
asLong |= (INT_MASK & mHeight);
|
||||
|
||||
return ((Long)asLong).hashCode();
|
||||
// assuming most sizes are <2^16, doing a rotate will give us perfect hashing
|
||||
return mHeight ^ ((mWidth << (Integer.SIZE / 2)) | (mWidth >>> (Integer.SIZE / 2)));
|
||||
}
|
||||
|
||||
private final int mWidth;
|
||||
|
||||
143
core/java/android/hardware/camera2/impl/HashCodeHelpers.java
Normal file
143
core/java/android/hardware/camera2/impl/HashCodeHelpers.java
Normal file
@@ -0,0 +1,143 @@
|
||||
/*
|
||||
* 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.hardware.camera2.impl;
|
||||
|
||||
/**
|
||||
* Provide hashing functions using the Modified Bernstein hash
|
||||
*/
|
||||
public final class HashCodeHelpers {
|
||||
|
||||
/**
|
||||
* Hash every element uniformly using the Modified Bernstein hash.
|
||||
*
|
||||
* <p>Useful to implement a {@link Object#hashCode} for uniformly distributed data.</p>
|
||||
*
|
||||
* @param array a non-{@code null} array of integers
|
||||
*
|
||||
* @return the numeric hash code
|
||||
*/
|
||||
public static int hashCode(int[] array) {
|
||||
if (array == null) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Note that we use 31 here instead of 33 since it's preferred in Effective Java
|
||||
* and used elsewhere in the runtime (e.g. Arrays#hashCode)
|
||||
*
|
||||
* That being said 33 and 31 are nearly identical in terms of their usefulness
|
||||
* according to http://svn.apache.org/repos/asf/apr/apr/trunk/tables/apr_hash.c
|
||||
*/
|
||||
int h = 1;
|
||||
for (int x : array) {
|
||||
// Strength reduction; in case the compiler has illusions about divisions being faster
|
||||
h = ((h << 5) - h) ^ x; // (h * 31) XOR x
|
||||
}
|
||||
|
||||
return h;
|
||||
}
|
||||
|
||||
/**
|
||||
* Hash every element uniformly using the Modified Bernstein hash.
|
||||
*
|
||||
* <p>Useful to implement a {@link Object#hashCode} for uniformly distributed data.</p>
|
||||
*
|
||||
* @param array a non-{@code null} array of floats
|
||||
*
|
||||
* @return the numeric hash code
|
||||
*/
|
||||
public static int hashCode(float[] array) {
|
||||
if (array == null) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int h = 1;
|
||||
for (float f : array) {
|
||||
int x = Float.floatToIntBits(f);
|
||||
h = ((h << 5) - h) ^ x; // (h * 31) XOR x
|
||||
}
|
||||
|
||||
return h;
|
||||
}
|
||||
|
||||
/**
|
||||
* Hash every element uniformly using the Modified Bernstein hash.
|
||||
*
|
||||
* <p>Useful to implement a {@link Object#hashCode} for uniformly distributed data.</p>
|
||||
*
|
||||
* @param array a non-{@code null} array of objects
|
||||
*
|
||||
* @return the numeric hash code
|
||||
*/
|
||||
public static <T> int hashCode(T[] array) {
|
||||
if (array == null) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int h = 1;
|
||||
for (T o : array) {
|
||||
int x = (o == null) ? 0 : o.hashCode();
|
||||
h = ((h << 5) - h) ^ x; // (h * 31) XOR x
|
||||
}
|
||||
|
||||
return h;
|
||||
}
|
||||
|
||||
public static <T> int hashCode(T a) {
|
||||
return (a == null) ? 0 : a.hashCode();
|
||||
}
|
||||
|
||||
public static <T> int hashCode(T a, T b) {
|
||||
int h = hashCode(a);
|
||||
|
||||
int x = (b == null) ? 0 : b.hashCode();
|
||||
h = ((h << 5) - h) ^ x; // (h * 31) XOR x
|
||||
|
||||
return h;
|
||||
}
|
||||
|
||||
public static <T> int hashCode(T a, T b, T c) {
|
||||
int h = hashCode(a, b);
|
||||
|
||||
int x = (a == null) ? 0 : a.hashCode();
|
||||
h = ((h << 5) - h) ^ x; // (h * 31) XOR x
|
||||
|
||||
return h;
|
||||
}
|
||||
|
||||
public static int hashCode(int x) {
|
||||
return hashCode(new int[] { x } );
|
||||
}
|
||||
|
||||
public static int hashCode(int x, int y) {
|
||||
return hashCode(new int[] { x, y } );
|
||||
}
|
||||
|
||||
public static int hashCode(int x, int y, int z) {
|
||||
return hashCode(new int[] { x, y, z } );
|
||||
}
|
||||
|
||||
public static int hashCode(int x, int y, int z, int w) {
|
||||
return hashCode(new int[] { x, y, z, w } );
|
||||
}
|
||||
|
||||
public static int hashCode(int x, int y, int z, int w, int t) {
|
||||
return hashCode(new int[] { x, y, z, w, t } );
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
144
core/java/android/util/Range.java
Normal file
144
core/java/android/util/Range.java
Normal file
@@ -0,0 +1,144 @@
|
||||
/*
|
||||
* 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.util;
|
||||
|
||||
import static com.android.internal.util.Preconditions.*;
|
||||
|
||||
import android.hardware.camera2.impl.HashCodeHelpers;
|
||||
|
||||
/**
|
||||
* Immutable class for describing the range of two numeric values.
|
||||
* <p>
|
||||
* A range (or "interval") defines the inclusive boundaries around a contiguous span of
|
||||
* values of some {@link Comparable} type; for example,
|
||||
* "integers from 1 to 100 inclusive."
|
||||
* </p>
|
||||
* <p>
|
||||
* All ranges are bounded, and the left side of the range is always {@code >=}
|
||||
* the right side of the range.
|
||||
* </p>
|
||||
*
|
||||
* <p>Although the implementation itself is immutable, there is no restriction that objects
|
||||
* stored must also be immutable. If mutable objects are stored here, then the range
|
||||
* effectively becomes mutable. </p>
|
||||
*/
|
||||
public final class Range<T extends Comparable<? super T>> {
|
||||
/**
|
||||
* Create a new immutable range.
|
||||
*
|
||||
* <p>
|
||||
* The endpoints are {@code [lower, upper]}; that
|
||||
* is the range is bounded. {@code lower} must be {@link Comparable#compareTo lesser or equal}
|
||||
* to {@code upper}.
|
||||
* </p>
|
||||
*
|
||||
* @param lower The lower endpoint (inclusive)
|
||||
* @param upper The upper endpoint (inclusive)
|
||||
*
|
||||
* @throws NullPointerException if {@code lower} or {@code upper} is {@code null}
|
||||
*/
|
||||
public Range(final T lower, final T upper) {
|
||||
mLower = checkNotNull(lower, "lower must not be null");
|
||||
mUpper = checkNotNull(upper, "upper must not be null");
|
||||
|
||||
if (lower.compareTo(upper) > 0) {
|
||||
throw new IllegalArgumentException("lower must be less than or equal to upper");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new immutable range, with the argument types inferred.
|
||||
*
|
||||
* <p>
|
||||
* The endpoints are {@code [lower, upper]}; that
|
||||
* is the range is bounded. {@code lower} must be {@link Comparable#compareTo lesser or equal}
|
||||
* to {@code upper}.
|
||||
* </p>
|
||||
*
|
||||
* @param lower The lower endpoint (inclusive)
|
||||
* @param upper The upper endpoint (inclusive)
|
||||
*
|
||||
* @throws NullPointerException if {@code lower} or {@code upper} is {@code null}
|
||||
*/
|
||||
public static <T extends Comparable<? super T>> Range<T> create(final T lower, final T upper) {
|
||||
return new Range<T>(lower, upper);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the lower endpoint.
|
||||
*
|
||||
* @return a non-{@code null} {@code T} reference
|
||||
*/
|
||||
public T getLower() {
|
||||
return mLower;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the upper endpoint.
|
||||
*
|
||||
* @return a non-{@code null} {@code T} reference
|
||||
*/
|
||||
public T getUpper() {
|
||||
return mUpper;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compare two ranges for equality.
|
||||
*
|
||||
* <p>A range is considered equal if and only if both the lower and upper endpoints
|
||||
* are also equal.</p>
|
||||
*
|
||||
* @return {@code true} if the ranges are equal, {@code false} otherwise
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(final Object obj) {
|
||||
if (obj == null) {
|
||||
return false;
|
||||
}
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if (obj instanceof Range) {
|
||||
@SuppressWarnings("rawtypes")
|
||||
final
|
||||
Range other = (Range) obj;
|
||||
return mLower.equals(other.mLower) && mUpper.equals(other.mUpper);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the range as a string representation {@code "[lower, upper]"}.
|
||||
*
|
||||
* @return string representation of the range
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format("[%s, %s]", mLower, mUpper);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return HashCodeHelpers.hashCode(mLower, mUpper);
|
||||
}
|
||||
|
||||
private final T mLower;
|
||||
private final T mUpper;
|
||||
};
|
||||
98
core/java/android/util/Size.java
Normal file
98
core/java/android/util/Size.java
Normal file
@@ -0,0 +1,98 @@
|
||||
/*
|
||||
* Copyright (C) 2013 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.util;
|
||||
|
||||
/**
|
||||
* Immutable class for describing width and height dimensions in pixels.
|
||||
*/
|
||||
public final class Size {
|
||||
/**
|
||||
* Create a new immutable Size instance.
|
||||
*
|
||||
* @param width The width of the size, in pixels
|
||||
* @param height The height of the size, in pixels
|
||||
*/
|
||||
public Size(int width, int height) {
|
||||
mWidth = width;
|
||||
mHeight = height;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the width of the size (in pixels).
|
||||
* @return width
|
||||
*/
|
||||
public int getWidth() {
|
||||
return mWidth;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the height of the size (in pixels).
|
||||
* @return height
|
||||
*/
|
||||
public int getHeight() {
|
||||
return mHeight;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if this size is equal to another size.
|
||||
* <p>
|
||||
* Two sizes are equal if and only if both their widths and heights are
|
||||
* equal.
|
||||
* </p>
|
||||
* <p>
|
||||
* A size object is never equal to any other type of object.
|
||||
* </p>
|
||||
*
|
||||
* @return {@code true} if the objects were equal, {@code false} otherwise
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(final Object obj) {
|
||||
if (obj == null) {
|
||||
return false;
|
||||
}
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if (obj instanceof Size) {
|
||||
Size other = (Size) obj;
|
||||
return mWidth == other.mWidth && mHeight == other.mHeight;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the size represented as a string with the format {@code "WxH"}
|
||||
*
|
||||
* @return string representation of the size
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return mWidth + "x" + mHeight;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public int hashCode() {
|
||||
// assuming most sizes are <2^16, doing a rotate will give us perfect hashing
|
||||
return mHeight ^ ((mWidth << (Integer.SIZE / 2)) | (mWidth >>> (Integer.SIZE / 2)));
|
||||
}
|
||||
|
||||
private final int mWidth;
|
||||
private final int mHeight;
|
||||
};
|
||||
108
core/java/android/util/SizeF.java
Normal file
108
core/java/android/util/SizeF.java
Normal file
@@ -0,0 +1,108 @@
|
||||
/*
|
||||
* 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.util;
|
||||
|
||||
import static com.android.internal.util.Preconditions.*;
|
||||
|
||||
/**
|
||||
* Immutable class for describing width and height dimensions in some arbitrary
|
||||
* unit.
|
||||
* <p>
|
||||
* Width and height are finite values stored as a floating point representation.
|
||||
* </p>
|
||||
*/
|
||||
public final class SizeF {
|
||||
/**
|
||||
* Create a new immutable SizeF instance.
|
||||
*
|
||||
* <p>Both the {@code width} and the {@code height} must be a finite number.
|
||||
* In particular, {@code NaN} and positive/negative infinity are illegal values.</p>
|
||||
*
|
||||
* @param width The width of the size
|
||||
* @param height The height of the size
|
||||
*
|
||||
* @throws IllegalArgumentException
|
||||
* if either {@code width} or {@code height} was not finite.
|
||||
*/
|
||||
public SizeF(final float width, final float height) {
|
||||
mWidth = checkArgumentFinite(width, "width");
|
||||
mHeight = checkArgumentFinite(height, "height");
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the width of the size (as an arbitrary unit).
|
||||
* @return width
|
||||
*/
|
||||
public float getWidth() {
|
||||
return mWidth;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the height of the size (as an arbitrary unit).
|
||||
* @return height
|
||||
*/
|
||||
public float getHeight() {
|
||||
return mHeight;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if this size is equal to another size.
|
||||
*
|
||||
* <p>Two sizes are equal if and only if both their widths and heights are the same.</p>
|
||||
*
|
||||
* <p>For this purpose, the width/height float values are considered to be the same if and only
|
||||
* if the method {@link Float#floatToIntBits(float)} returns the identical {@code int} value
|
||||
* when applied to each.</p>
|
||||
*
|
||||
* @return {@code true} if the objects were equal, {@code false} otherwise
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(final Object obj) {
|
||||
if (obj == null) {
|
||||
return false;
|
||||
}
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if (obj instanceof SizeF) {
|
||||
final SizeF other = (SizeF) obj;
|
||||
return mWidth == other.mWidth && mHeight == other.mHeight;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the size represented as a string with the format {@code "WxH"}
|
||||
*
|
||||
* @return string representation of the size
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return mWidth + "x" + mHeight;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Float.floatToIntBits(mWidth) ^ Float.floatToIntBits(mHeight);
|
||||
}
|
||||
|
||||
private final float mWidth;
|
||||
private final float mHeight;
|
||||
};
|
||||
Reference in New Issue
Block a user