MeteringRectangle.java revision 97f1c854993a65b2c700426a1e3a83b23ea65337
1/*
2 * Copyright (C) 2014 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 android.hardware.camera2.params;
18
19import android.util.Size;
20import static com.android.internal.util.Preconditions.*;
21
22import android.graphics.Point;
23import android.graphics.Rect;
24import android.hardware.camera2.CameraCharacteristics;
25import android.hardware.camera2.CaptureRequest;
26import android.hardware.camera2.utils.HashCodeHelpers;
27
28/**
29 * An immutable class to represent a rectangle {@code (x, y, width, height)} with an additional
30 * weight component.
31 * <p>
32 * The rectangle is defined to be inclusive of the specified coordinates.
33 * </p>
34 * <p>
35 * When used with a {@link CaptureRequest}, the coordinate system is based on the active pixel
36 * array, with {@code (0,0)} being the top-left pixel in the
37 * {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE active pixel array}, and
38 * {@code (android.sensor.info.activeArraySize.width - 1,
39 * android.sensor.info.activeArraySize.height - 1)} being the bottom-right pixel in the active pixel
40 * array.
41 * </p>
42 * <p>
43 * The weight must range from {@value #METERING_WEIGHT_MIN} to {@value #METERING_WEIGHT_MAX}
44 * inclusively, and represents a weight for every pixel in the area. This means that a large
45 * metering area with the same weight as a smaller area will have more effect in the metering
46 * result. Metering areas can partially overlap and the camera device will add the weights in the
47 * overlap rectangle.
48 * </p>
49 * <p>
50 * If all rectangles have 0 weight, then no specific metering area needs to be used by the camera
51 * device. If the metering rectangle is outside the used android.scaler.cropRegion returned in
52 * capture result metadata, the camera device will ignore the sections outside the rectangle and
53 * output the used sections in the result metadata.
54 * </p>
55 */
56public final class MeteringRectangle {
57    /**
58     * The minimum value of valid metering weight.
59     */
60    public static final int METERING_WEIGHT_MIN = 0;
61
62    /**
63     * The maximum value of valid metering weight.
64     */
65    public static final int METERING_WEIGHT_MAX = 1000;
66
67    /**
68     * Weights set to this value will cause the camera device to ignore this rectangle.
69     * If all metering rectangles are weighed with 0, the camera device will choose its own metering
70     * rectangles.
71     */
72    public static final int METERING_WEIGHT_DONT_CARE = 0;
73
74    private final int mX;
75    private final int mY;
76    private final int mWidth;
77    private final int mHeight;
78    private final int mWeight;
79
80    /**
81     * Create a new metering rectangle.
82     *
83     * @param x coordinate >= 0
84     * @param y coordinate >= 0
85     * @param width width >= 0
86     * @param height height >= 0
87     * @param meteringWeight weight between {@value #METERING_WEIGHT_MIN} and
88     *        {@value #METERING_WEIGHT_MAX} inclusively
89     * @throws IllegalArgumentException if any of the parameters were negative
90     */
91    public MeteringRectangle(int x, int y, int width, int height, int meteringWeight) {
92        mX = checkArgumentNonnegative(x, "x must be nonnegative");
93        mY = checkArgumentNonnegative(y, "y must be nonnegative");
94        mWidth = checkArgumentNonnegative(width, "width must be nonnegative");
95        mHeight = checkArgumentNonnegative(height, "height must be nonnegative");
96        mWeight = checkArgumentInRange(
97                meteringWeight, METERING_WEIGHT_MIN, METERING_WEIGHT_MAX, "meteringWeight");
98    }
99
100    /**
101     * Create a new metering rectangle.
102     *
103     * @param xy a non-{@code null} {@link Point} with both x,y >= 0
104     * @param dimensions a non-{@code null} {@link android.util.Size Size} with width, height >= 0
105     * @param meteringWeight weight >= 0
106     *
107     * @throws IllegalArgumentException if any of the parameters were negative
108     * @throws NullPointerException if any of the arguments were null
109     */
110    public MeteringRectangle(Point xy, Size dimensions, int meteringWeight) {
111        checkNotNull(xy, "xy must not be null");
112        checkNotNull(dimensions, "dimensions must not be null");
113
114        mX = checkArgumentNonnegative(xy.x, "x must be nonnegative");
115        mY = checkArgumentNonnegative(xy.y, "y must be nonnegative");
116        mWidth = checkArgumentNonnegative(dimensions.getWidth(), "width must be nonnegative");
117        mHeight = checkArgumentNonnegative(dimensions.getHeight(), "height must be nonnegative");
118        mWeight = checkArgumentNonnegative(meteringWeight, "meteringWeight must be nonnegative");
119    }
120
121    /**
122     * Create a new metering rectangle.
123     *
124     * @param rect a non-{@code null} rectangle with all x,y,w,h dimensions >= 0
125     * @param meteringWeight weight >= 0
126     *
127     * @throws IllegalArgumentException if any of the parameters were negative
128     * @throws NullPointerException if any of the arguments were null
129     */
130    public MeteringRectangle(Rect rect, int meteringWeight) {
131        checkNotNull(rect, "rect must not be null");
132
133        mX = checkArgumentNonnegative(rect.left, "rect.left must be nonnegative");
134        mY = checkArgumentNonnegative(rect.top, "rect.top must be nonnegative");
135        mWidth = checkArgumentNonnegative(rect.width(), "rect.width must be nonnegative");
136        mHeight = checkArgumentNonnegative(rect.height(), "rect.height must be nonnegative");
137        mWeight = checkArgumentNonnegative(meteringWeight, "meteringWeight must be nonnegative");
138    }
139
140    /**
141     * Return the X coordinate of the left side of the rectangle.
142     *
143     * @return x coordinate >= 0
144     */
145    public int getX() {
146        return mX;
147    }
148
149    /**
150     * Return the Y coordinate of the upper side of the rectangle.
151     *
152     * @return y coordinate >= 0
153     */
154    public int getY() {
155        return mY;
156    }
157
158    /**
159     * Return the width of the rectangle.
160     *
161     * @return width >= 0
162     */
163    public int getWidth() {
164        return mWidth;
165    }
166
167    /**
168     * Return the height of the rectangle.
169     *
170     * @return height >= 0
171     */
172    public int getHeight() {
173        return mHeight;
174    }
175
176    /**
177     * Return the metering weight of the rectangle.
178     *
179     * @return weight >= 0
180     */
181    public int getMeteringWeight() {
182        return mWeight;
183    }
184
185    /**
186     * Convenience method to create the upper-left (X,Y) coordinate as a {@link Point}.
187     *
188     * @return {@code (x,y)} point with both x,y >= 0
189     */
190    public Point getUpperLeftPoint() {
191        return new Point(mX, mY);
192    }
193
194    /**
195     * Convenience method to create the size from this metering rectangle.
196     *
197     * <p>This strips away the X,Y,weight from the rectangle.</p>
198     *
199     * @return a Size with non-negative width and height
200     */
201    public Size getSize() {
202        return new Size(mWidth, mHeight);
203    }
204
205    /**
206     * Convenience method to create a {@link Rect} from this metering rectangle.
207     *
208     * <p>This strips away the weight from the rectangle.</p>
209     *
210     * @return a {@link Rect} with non-negative x1, y1, x2, y2
211     */
212    public Rect getRect() {
213        return new Rect(mX, mY, mX + mWidth, mY + mHeight);
214    }
215
216    /**
217     * {@inheritDoc}
218     */
219    @Override
220    public boolean equals(final Object other) {
221        return other instanceof MeteringRectangle && equals((MeteringRectangle)other);
222    }
223
224    /**
225     * Compare two metering rectangles to see if they are equal.
226     *
227     * Two weighted rectangles are only considered equal if each of their components
228     * (x, y, width, height, weight) is respectively equal.
229     *
230     * @param other Another MeteringRectangle
231     *
232     * @return {@code true} if the metering rectangles are equal, {@code false} otherwise
233     */
234    public boolean equals(final MeteringRectangle other) {
235        if (other == null) {
236            return false;
237        }
238
239        return (mX == other.mX
240                && mY == other.mY
241                && mWidth == other.mWidth
242                && mHeight == other.mHeight
243                && mWeight == other.mWeight);
244    }
245
246    /**
247     * {@inheritDoc}
248     */
249    @Override
250    public int hashCode() {
251        return HashCodeHelpers.hashCode(mX, mY, mWidth, mHeight, mWeight);
252    }
253}
254