Home | History | Annotate | Download | only in params
      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 
     17 package android.hardware.camera2.params;
     18 
     19 import android.util.Size;
     20 import static com.android.internal.util.Preconditions.*;
     21 
     22 import android.graphics.Point;
     23 import android.graphics.Rect;
     24 import android.hardware.camera2.CameraCharacteristics;
     25 import android.hardware.camera2.CaptureRequest;
     26 import 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  */
     56 public 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      * <p>The point {@code xy}'s data is copied; the reference is not retained.</p>
    104      *
    105      * @param xy a non-{@code null} {@link Point} with both x,y >= 0
    106      * @param dimensions a non-{@code null} {@link android.util.Size Size} with width, height >= 0
    107      * @param meteringWeight weight >= 0
    108      *
    109      * @throws IllegalArgumentException if any of the parameters were negative
    110      * @throws NullPointerException if any of the arguments were null
    111      */
    112     public MeteringRectangle(Point xy, Size dimensions, int meteringWeight) {
    113         checkNotNull(xy, "xy must not be null");
    114         checkNotNull(dimensions, "dimensions must not be null");
    115 
    116         mX = checkArgumentNonnegative(xy.x, "x must be nonnegative");
    117         mY = checkArgumentNonnegative(xy.y, "y must be nonnegative");
    118         mWidth = checkArgumentNonnegative(dimensions.getWidth(), "width must be nonnegative");
    119         mHeight = checkArgumentNonnegative(dimensions.getHeight(), "height must be nonnegative");
    120         mWeight = checkArgumentNonnegative(meteringWeight, "meteringWeight must be nonnegative");
    121     }
    122 
    123     /**
    124      * Create a new metering rectangle.
    125      *
    126      * <p>The rectangle data is copied; the reference is not retained.</p>
    127      *
    128      * @param rect a non-{@code null} rectangle with all x,y,w,h dimensions >= 0
    129      * @param meteringWeight weight >= 0
    130      *
    131      * @throws IllegalArgumentException if any of the parameters were negative
    132      * @throws NullPointerException if any of the arguments were null
    133      */
    134     public MeteringRectangle(Rect rect, int meteringWeight) {
    135         checkNotNull(rect, "rect must not be null");
    136 
    137         mX = checkArgumentNonnegative(rect.left, "rect.left must be nonnegative");
    138         mY = checkArgumentNonnegative(rect.top, "rect.top must be nonnegative");
    139         mWidth = checkArgumentNonnegative(rect.width(), "rect.width must be nonnegative");
    140         mHeight = checkArgumentNonnegative(rect.height(), "rect.height must be nonnegative");
    141         mWeight = checkArgumentNonnegative(meteringWeight, "meteringWeight must be nonnegative");
    142     }
    143 
    144     /**
    145      * Return the X coordinate of the left side of the rectangle.
    146      *
    147      * @return x coordinate >= 0
    148      */
    149     public int getX() {
    150         return mX;
    151     }
    152 
    153     /**
    154      * Return the Y coordinate of the upper side of the rectangle.
    155      *
    156      * @return y coordinate >= 0
    157      */
    158     public int getY() {
    159         return mY;
    160     }
    161 
    162     /**
    163      * Return the width of the rectangle.
    164      *
    165      * @return width >= 0
    166      */
    167     public int getWidth() {
    168         return mWidth;
    169     }
    170 
    171     /**
    172      * Return the height of the rectangle.
    173      *
    174      * @return height >= 0
    175      */
    176     public int getHeight() {
    177         return mHeight;
    178     }
    179 
    180     /**
    181      * Return the metering weight of the rectangle.
    182      *
    183      * @return weight >= 0
    184      */
    185     public int getMeteringWeight() {
    186         return mWeight;
    187     }
    188 
    189     /**
    190      * Convenience method to create the upper-left (X,Y) coordinate as a {@link Point}.
    191      *
    192      * @return a new {@code (x,y)} {@link Point} with both x,y >= 0
    193      */
    194     public Point getUpperLeftPoint() {
    195         return new Point(mX, mY);
    196     }
    197 
    198     /**
    199      * Convenience method to create the size from this metering rectangle.
    200      *
    201      * <p>This strips away the X,Y,weight from the rectangle.</p>
    202      *
    203      * @return a new {@link Size} with non-negative width and height
    204      */
    205     public Size getSize() {
    206         return new Size(mWidth, mHeight);
    207     }
    208 
    209     /**
    210      * Convenience method to create a {@link Rect} from this metering rectangle.
    211      *
    212      * <p>This strips away the weight from the rectangle.</p>
    213      *
    214      * @return a new {@link Rect} with non-negative x1, y1, x2, y2
    215      */
    216     public Rect getRect() {
    217         return new Rect(mX, mY, mX + mWidth, mY + mHeight);
    218     }
    219 
    220     /**
    221      * {@inheritDoc}
    222      */
    223     @Override
    224     public boolean equals(final Object other) {
    225         return other instanceof MeteringRectangle && equals((MeteringRectangle)other);
    226     }
    227 
    228     /**
    229      * Compare two metering rectangles to see if they are equal.
    230      *
    231      * Two weighted rectangles are only considered equal if each of their components
    232      * (x, y, width, height, weight) is respectively equal.
    233      *
    234      * @param other Another MeteringRectangle
    235      *
    236      * @return {@code true} if the metering rectangles are equal, {@code false} otherwise
    237      */
    238     public boolean equals(final MeteringRectangle other) {
    239         if (other == null) {
    240             return false;
    241         }
    242 
    243         return (mX == other.mX
    244                 && mY == other.mY
    245                 && mWidth == other.mWidth
    246                 && mHeight == other.mHeight
    247                 && mWeight == other.mWeight);
    248     }
    249 
    250     /**
    251      * {@inheritDoc}
    252      */
    253     @Override
    254     public int hashCode() {
    255         return HashCodeHelpers.hashCode(mX, mY, mWidth, mHeight, mWeight);
    256     }
    257 
    258     /**
    259      * Return the metering rectangle as a string representation
    260      * {@code "(x:%d, y:%d, w:%d, h:%d, wt:%d)"} where each {@code %d} respectively represents
    261      * the x, y, width, height, and weight points.
    262      *
    263      * @return string representation of the metering rectangle
    264      */
    265     @Override
    266     public String toString() {
    267         return String.format("(x:%d, y:%d, w:%d, h:%d, wt:%d)", mX, mY, mWidth, mHeight, mWeight);
    268     }
    269 }
    270