summaryrefslogtreecommitdiffstats
path: root/core/java/android/hardware/camera2/params/MeteringRectangle.java
blob: b1cea575200a3795f70186de6719000196bbb6ff (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
/*
 * 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.params;

import android.util.Size;
import static com.android.internal.util.Preconditions.*;

import android.graphics.Point;
import android.graphics.Rect;
import android.hardware.camera2.CameraCharacteristics;
import android.hardware.camera2.CaptureRequest;
import android.hardware.camera2.utils.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 weight must range from {@value #METERING_WEIGHT_MIN} to {@value #METERING_WEIGHT_MAX}
 * inclusively, and represents a weight for every pixel in the area. This means that a large
 * metering area with the same weight as a smaller area will have more effect in the metering
 * result. Metering areas can partially overlap and the camera device will add the weights in the
 * overlap rectangle.
 * </p>
 * <p>
 * If all rectangles have 0 weight, then no specific metering area needs to be used by the camera
 * device. If the metering rectangle is outside the used android.scaler.cropRegion returned in
 * capture result metadata, the camera device will ignore the sections outside the rectangle and
 * output the used sections in the result metadata.
 * </p>
 */
public final class MeteringRectangle {
    /**
     * The minimum value of valid metering weight.
     */
    public static final int METERING_WEIGHT_MIN = 0;

    /**
     * The maximum value of valid metering weight.
     */
    public static final int METERING_WEIGHT_MAX = 1000;

    /**
     * Weights set to this value will cause the camera device to ignore this rectangle.
     * If all metering rectangles are weighed with 0, the camera device will choose its own metering
     * rectangles.
     */
    public static final int METERING_WEIGHT_DONT_CARE = 0;

    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 between {@value #METERING_WEIGHT_MIN} and
     *        {@value #METERING_WEIGHT_MAX} inclusively
     * @throws IllegalArgumentException if any of the parameters were 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 = checkArgumentInRange(
                meteringWeight, METERING_WEIGHT_MIN, METERING_WEIGHT_MAX, "meteringWeight");
    }

    /**
     * Create a new metering rectangle.
     *
     * <p>The point {@code xy}'s data is copied; the reference is not retained.</p>
     *
     * @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 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.
     *
     * <p>The rectangle data is copied; the reference is not retained.</p>
     *
     * @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 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 a new {@code (x,y)} {@link 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 new {@link 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 new {@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) {
        return other instanceof MeteringRectangle && equals((MeteringRectangle)other);
    }

    /**
     * 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
                && mWeight == other.mWeight);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public int hashCode() {
        return HashCodeHelpers.hashCode(mX, mY, mWidth, mHeight, mWeight);
    }

    /**
     * Return the metering rectangle as a string representation
     * {@code "(x:%d, y:%d, w:%d, h:%d, wt:%d)"} where each {@code %d} respectively represents
     * the x, y, width, height, and weight points.
     *
     * @return string representation of the metering rectangle
     */
    @Override
    public String toString() {
        return String.format("(x:%d, y:%d, w:%d, h:%d, wt:%d)", mX, mY, mWidth, mHeight, mWeight);
    }
}