content: /*
   * 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.utils;
  
  import android.graphics.Matrix;
  import android.graphics.Rect;
  import android.graphics.RectF;
  import android.hardware.camera2.CaptureRequest;
  import android.util.Rational;
  import android.util.Size;
  
  import static com.android.internal.util.Preconditions.*;
  
  /**
   * Various assortment of params utilities.
   */
  public class ParamsUtils {
  
      /** Arbitrary denominator used to estimate floats as rationals */
      private static final int RATIONAL_DENOMINATOR = 1000000; // 1million
  
      /**
       * Create a {@link Rect} from a {@code Size} by creating a new rectangle with
       * left, top = {@code (0, 0)} and right, bottom = {@code (width, height)}
       *
       * @param size a non-{@code null} size
       *
       * @return a {@code non-null} rectangle
       *
       * @throws NullPointerException if {@code size} was {@code null}
       */
      public static Rect createRect(Size size) {
          checkNotNull(size, "size must not be null");
  
          return new Rect(/*left*/0, /*top*/0, size.getWidth(), size.getHeight());
      }
  
      /**
       * Create a {@link Rect} from a {@code RectF} by creating a new rectangle with
       * each corner (left, top, right, bottom) rounded towards the nearest integer bounding box.
       *
       * <p>In particular (left, top) is floored, and (right, bottom) is ceiled.</p>
       *
       * @param size a non-{@code null} rect
       *
       * @return a {@code non-null} rectangle
       *
       * @throws NullPointerException if {@code rect} was {@code null}
       */
      public static Rect createRect(RectF rect) {
          checkNotNull(rect, "rect must not be null");
  
          Rect r = new Rect();
          rect.roundOut(r);
  
          return r;
      }
  
      /**
       * Map the rectangle in {@code rect} with the transform in {@code transform} into
       * a new rectangle, with each corner (left, top, right, bottom) rounded towards the nearest
       * integer bounding box.
       *
       * <p>None of the arguments are mutated.</p>
       *
       * @param transform a non-{@code null} transformation matrix
       * @param rect a non-{@code null} rectangle
       * @return a new rectangle that was transformed by {@code transform}
       *
       * @throws NullPointerException if any of the args were {@code null}
       */
      public static Rect mapRect(Matrix transform, Rect rect) {
          checkNotNull(transform, "transform must not be null");
          checkNotNull(rect, "rect must not be null");
  
          RectF rectF = new RectF(rect);
          transform.mapRect(rectF);
          return createRect(rectF);
      }
  
      /**
       * Create a {@link Size} from a {@code Rect} by creating a new size whose width
       * and height are the same as the rectangle's width and heights.
       *
       * @param rect a non-{@code null} rectangle
       *
       * @return a {@code non-null} size
       *
       * @throws NullPointerException if {@code rect} was {@code null}
       */
      public static Size createSize(Rect rect) {
          checkNotNull(rect, "rect must not be null");
  
          return new Size(rect.width(), rect.height());
      }
  
      /**
       * Create a {@link Rational} value by approximating the float value as a rational.
       *
       * <p>Floating points too large to be represented as an integer will be converted to
       * to {@link Integer#MAX_VALUE}; floating points too small to be represented as an integer
       * will be converted to {@link Integer#MIN_VALUE}.</p>
       *
       * @param value a floating point value
       * @return the rational representation of the float
       */
      public static Rational createRational(float value) {
          if (Float.isNaN(value)) {
              return Rational.NaN;
          } else if (value == Float.POSITIVE_INFINITY) {
              return Rational.POSITIVE_INFINITY;
          } else if (value == Float.NEGATIVE_INFINITY) {
              return Rational.NEGATIVE_INFINITY;
          } else if (value == 0.0f) {
              return Rational.ZERO;
          }
  
          // normal finite value: approximate it
  
          /*
           * Start out trying to approximate with denominator = 1million,
           * but if the numerator doesn't fit into an Int then keep making the denominator
           * smaller until it does.
           */
          int den = RATIONAL_DENOMINATOR;
          float numF;
          do {
              numF = value * den;
  
              if ((numF > Integer.MIN_VALUE && numF < Integer.MAX_VALUE) || (den == 1)) {
                  break;
              }
  
              den /= 10;
          } while (true);
  
          /*
           *  By float -> int narrowing conversion in JLS 5.1.3, this will automatically become
           *  MIN_VALUE or MAX_VALUE if numF is too small/large to be represented by an integer
           */
          int num = (int) numF;
  
          return new Rational(num, den);
       }
  
      /**
       * Convert an integral rectangle ({@code source}) to a floating point rectangle
       * ({@code destination}) in-place.
       *
       * @param source the originating integer rectangle will be read from here
       * @param destination the resulting floating point rectangle will be written out to here
       *
       * @throws NullPointerException if {@code rect} was {@code null}
       */
      public static void convertRectF(Rect source, RectF destination) {
          checkNotNull(source, "source must not be null");
          checkNotNull(destination, "destination must not be null");
  
          destination.left = source.left;
          destination.right = source.right;
          destination.bottom = source.bottom;
          destination.top = source.top;
      }
  
      /**
       * Return the value set by the key, or the {@code defaultValue} if no value was set.
       *
       * @throws NullPointerException if any of the args were {@code null}
       */
      public static <T> T getOrDefault(CaptureRequest r, CaptureRequest.Key<T> key, T defaultValue) {
          checkNotNull(r, "r must not be null");
          checkNotNull(key, "key must not be null");
          checkNotNull(defaultValue, "defaultValue must not be null");
  
          T value = r.get(key);
          if (value == null) {
              return defaultValue;
          } else {
              return value;
          }
      }
  
      private ParamsUtils() {
          throw new AssertionError();
      }
  }
  