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 com.android.ex.camera2.portability;
  
  import android.hardware.Camera;
  
  import com.android.ex.camera2.portability.debug.Log;
  
  import java.util.ArrayList;
  import java.util.List;
  import java.util.Map;
  import java.util.TreeMap;
  
  /**
   * A class which stores the camera settings.
   */
  public abstract class CameraSettings {
      private static final Log.Tag TAG = new Log.Tag("CamSet");
  
      // Attempts to provide a value outside this range will be ignored.
      private static final int MIN_JPEG_COMPRESSION_QUALITY = 1;
      private static final int MAX_JPEG_COMPRESSION_QUALITY = 100;
  
      protected final Map<String, String> mGeneralSetting = new TreeMap<>();
      protected final List<Camera.Area> mMeteringAreas = new ArrayList<>();
      protected final List<Camera.Area> mFocusAreas = new ArrayList<>();
      protected boolean mSizesLocked;
      protected int mPreviewFpsRangeMin;
      protected int mPreviewFpsRangeMax;
      protected int mPreviewFrameRate;
      protected Size mCurrentPreviewSize;
      private int mCurrentPreviewFormat;
      protected Size mCurrentPhotoSize;
      protected byte mJpegCompressQuality;
      protected int mCurrentPhotoFormat;
      protected float mCurrentZoomRatio;
      protected int mExposureCompensationIndex;
      protected CameraCapabilities.FlashMode mCurrentFlashMode;
      protected CameraCapabilities.FocusMode mCurrentFocusMode;
      protected CameraCapabilities.SceneMode mCurrentSceneMode;
      protected CameraCapabilities.WhiteBalance mWhiteBalance;
      protected boolean mVideoStabilizationEnabled;
      protected boolean mAutoExposureLocked;
      protected boolean mAutoWhiteBalanceLocked;
      protected boolean mRecordingHintEnabled;
      protected GpsData mGpsData;
      protected Size mExifThumbnailSize;
  
      /**
       * An immutable class storing GPS related information.
       * <p>It's a hack since we always use GPS time stamp but does not use other
       * fields sometimes. Setting processing method to null means the other
       * fields should not be used.</p>
       */
      public static class GpsData {
          public final double latitude;
          public final double longitude;
          public final double altitude;
          public final long timeStamp;
          public final String processingMethod;
  
          /**
           * Construct what may or may not actually represent a location,
           * depending on the value of {@code processingMethod}.
           *
           * <p>Setting {@code processingMethod} to {@code null} means that
           * {@code latitude}, {@code longitude}, and {@code altitude} will be
           * completely ignored.</p>
           */
          public GpsData(double latitude, double longitude, double altitude, long timeStamp,
                  String processingMethod) {
              if (processingMethod == null &&
                      (latitude != 0.0 || longitude != 0.0 || altitude != 0.0)) {
                  Log.w(TAG, "GpsData's nonzero data will be ignored due to null processingMethod");
              }
              this.latitude = latitude;
              this.longitude = longitude;
              this.altitude = altitude;
              this.timeStamp = timeStamp;
              this.processingMethod = processingMethod;
          }
  
          /** Copy constructor. */
          public GpsData(GpsData src) {
              this.latitude = src.latitude;
              this.longitude = src.longitude;
              this.altitude = src.altitude;
              this.timeStamp = src.timeStamp;
              this.processingMethod = src.processingMethod;
          }
      }
  
      protected CameraSettings() {
      }
  
      /**
       * Copy constructor.
       *
       * @param src The source settings.
       * @return The copy of the source.
       */
      protected CameraSettings(CameraSettings src) {
          mGeneralSetting.putAll(src.mGeneralSetting);
          mMeteringAreas.addAll(src.mMeteringAreas);
          mFocusAreas.addAll(src.mFocusAreas);
          mSizesLocked = src.mSizesLocked;
          mPreviewFpsRangeMin = src.mPreviewFpsRangeMin;
          mPreviewFpsRangeMax = src.mPreviewFpsRangeMax;
          mPreviewFrameRate = src.mPreviewFrameRate;
          mCurrentPreviewSize =
                  (src.mCurrentPreviewSize == null ? null : new Size(src.mCurrentPreviewSize));
          mCurrentPreviewFormat = src.mCurrentPreviewFormat;
          mCurrentPhotoSize =
                  (src.mCurrentPhotoSize == null ? null : new Size(src.mCurrentPhotoSize));
          mJpegCompressQuality = src.mJpegCompressQuality;
          mCurrentPhotoFormat = src.mCurrentPhotoFormat;
          mCurrentZoomRatio = src.mCurrentZoomRatio;
          mExposureCompensationIndex = src.mExposureCompensationIndex;
          mCurrentFlashMode = src.mCurrentFlashMode;
          mCurrentFocusMode = src.mCurrentFocusMode;
          mCurrentSceneMode = src.mCurrentSceneMode;
          mWhiteBalance = src.mWhiteBalance;
          mVideoStabilizationEnabled = src.mVideoStabilizationEnabled;
          mAutoExposureLocked = src.mAutoExposureLocked;
          mAutoWhiteBalanceLocked = src.mAutoWhiteBalanceLocked;
          mRecordingHintEnabled = src.mRecordingHintEnabled;
          mGpsData = src.mGpsData;
          mExifThumbnailSize = src.mExifThumbnailSize;
      }
  
      /**
       * @return A copy of this object, as an instance of the implementing class.
       */
      public abstract CameraSettings copy();
  
      /** General setting **/
      @Deprecated
      public void setSetting(String key, String value) {
          mGeneralSetting.put(key, value);
      }
  
      /**
       * Changes whether classes outside this class are allowed to set the preview
       * and photo capture sizes.
       *
       * @param locked Whether to prevent changes to these fields.
       *
       * @see #setPhotoSize
       * @see #setPreviewSize
       */
      /*package*/ void setSizesLocked(boolean locked) {
          mSizesLocked = locked;
      }
  
      /**  Preview **/
  
      /**
       * Sets the preview FPS range. This call will invalidate prior calls to
       * {@link #setPreviewFrameRate(int)}.
       *
       * @param min The min FPS.
       * @param max The max FPS.
       */
      public void setPreviewFpsRange(int min, int max) {
          if (min > max) {
              int temp = max;
              max = min;
              min = temp;
          }
          mPreviewFpsRangeMax = max;
          mPreviewFpsRangeMin = min;
          mPreviewFrameRate = -1;
      }
  
      /**
       * @return The min of the preview FPS range.
       */
      public int getPreviewFpsRangeMin() {
          return mPreviewFpsRangeMin;
      }
  
      /**
       * @return The max of the preview FPS range.
       */
      public int getPreviewFpsRangeMax() {
          return mPreviewFpsRangeMax;
      }
  
      /**
       * Sets the preview FPS. This call will invalidate prior calls to
       * {@link #setPreviewFpsRange(int, int)}.
       *
       * @param frameRate The target frame rate.
       */
      public void setPreviewFrameRate(int frameRate) {
          if (frameRate > 0) {
              mPreviewFrameRate = frameRate;
              mPreviewFpsRangeMax = frameRate;
              mPreviewFpsRangeMin = frameRate;
          }
      }
  
      public int getPreviewFrameRate() {
          return mPreviewFrameRate;
      }
  
      /**
       * @return The current preview size.
       */
      public Size getCurrentPreviewSize() {
          return new Size(mCurrentPreviewSize);
      }
  
      /**
       * @param previewSize The size to use for preview.
       * @return Whether the operation was allowed (i.e. the sizes are unlocked).
       */
      public boolean setPreviewSize(Size previewSize) {
          if (mSizesLocked) {
              Log.w(TAG, "Attempt to change preview size while locked");
              return false;
          }
  
          mCurrentPreviewSize = new Size(previewSize);
          return true;
      }
  
      /**
       * Sets the preview format.
       *
       * @param format
       * @see {@link android.graphics.ImageFormat}.
       */
      public void setPreviewFormat(int format) {
          mCurrentPreviewFormat = format;
      }
  
      /**
       * @return The preview format.
       * @see {@link android.graphics.ImageFormat}.
       */
      public int getCurrentPreviewFormat() {
          return mCurrentPreviewFormat;
      }
  
      /** Picture **/
  
      /**
       * @return The current photo size.
       */
      public Size getCurrentPhotoSize() {
          return new Size(mCurrentPhotoSize);
      }
  
      /**
       * @param photoSize The size to use for preview.
       * @return Whether the operation was allowed (i.e. the sizes are unlocked).
       */
      public boolean setPhotoSize(Size photoSize) {
          if (mSizesLocked) {
              Log.w(TAG, "Attempt to change photo size while locked");
              return false;
          }
  
          mCurrentPhotoSize = new Size(photoSize);
          return true;
      }
  
      /**
       * Sets the format for the photo.
       *
       * @param format The format for the photos taken.
       * @see {@link android.graphics.ImageFormat}.
       */
      public void setPhotoFormat(int format) {
          mCurrentPhotoFormat = format;
      }
  
      /**
       * @return The format for the photos taken.
       * @see {@link android.graphics.ImageFormat}.
       */
      public int getCurrentPhotoFormat() {
          return mCurrentPhotoFormat;
      }
  
      /**
       * Sets the JPEG compression quality.
       *
       * @param quality The quality for JPEG.
       */
      public void setPhotoJpegCompressionQuality(int quality) {
          if (quality < MIN_JPEG_COMPRESSION_QUALITY || quality > MAX_JPEG_COMPRESSION_QUALITY) {
              Log.w(TAG, "Ignoring JPEG quality that falls outside the expected range");
              return;
          }
          // This is safe because the positive numbers go up to 127.
          mJpegCompressQuality = (byte) quality;
      }
  
      public int getPhotoJpegCompressionQuality() {
          return mJpegCompressQuality;
      }
  
      /** Zoom **/
  
      /**
       * @return The current zoom ratio. The min is 1.0f.
       */
      public float getCurrentZoomRatio() {
          return mCurrentZoomRatio;
      }
  
      /**
       * Sets the zoom ratio.
       * @param ratio The new zoom ratio. Should be in the range between 1.0 to
       *              the value returned from {@link
       *              com.android.camera.cameradevice.CameraCapabilities#getMaxZoomRatio()}.
       * @throws java.lang.UnsupportedOperationException if the ratio is not
       *         supported.
       */
      public void setZoomRatio(float ratio) {
          mCurrentZoomRatio = ratio;
      }
  
      /** Exposure **/
  
      public void setExposureCompensationIndex(int index) {
          mExposureCompensationIndex = index;
      }
  
      /**
       * @return The exposure compensation, with 0 meaning unadjusted.
       */
      public int getExposureCompensationIndex() {
          return mExposureCompensationIndex;
      }
  
      public void setAutoExposureLock(boolean locked) {
          mAutoExposureLocked = locked;
      }
  
      public boolean isAutoExposureLocked() {
          return mAutoExposureLocked;
      }
  
      /**
       * @param areas The areas for autoexposure. The coordinate system has domain
       *              and range [-1000,1000], measured relative to the visible
       *              preview image, with orientation matching that of the sensor.
       *              This means the coordinates must be transformed to account
       *              for the devices rotation---but not the zoom level---before
       *              being passed into this method.
       */
      public void setMeteringAreas(List<Camera.Area> areas) {
          mMeteringAreas.clear();
          if (areas != null) {
              mMeteringAreas.addAll(areas);
          }
      }
  
      public List<Camera.Area> getMeteringAreas() {
          return new ArrayList<Camera.Area>(mMeteringAreas);
      }
  
      /** Flash **/
  
      public CameraCapabilities.FlashMode getCurrentFlashMode() {
          return mCurrentFlashMode;
      }
  
      public void setFlashMode(CameraCapabilities.FlashMode flashMode) {
          mCurrentFlashMode = flashMode;
      }
  
      /** Focus **/
  
      /**
       * Sets the focus mode.
       * @param focusMode The focus mode to use.
       */
      public void setFocusMode(CameraCapabilities.FocusMode focusMode) {
          mCurrentFocusMode = focusMode;
      }
  
      /**
       * @return The current focus mode.
       */
      public CameraCapabilities.FocusMode getCurrentFocusMode() {
          return mCurrentFocusMode;
      }
  
      /**
       * @param areas The areas to focus. The coordinate system has domain and
       *              range [-1000,1000], measured relative to the visible preview
       *              image, with orientation matching that of the sensor. This
       *              means the coordinates must be transformed to account for
       *              the devices rotation---but not the zoom level---before being
       *              passed into this method.
       */
      public void setFocusAreas(List<Camera.Area> areas) {
          mFocusAreas.clear();
          if (areas != null) {
              mFocusAreas.addAll(areas);
          }
      }
  
      public List<Camera.Area> getFocusAreas() {
          return new ArrayList<Camera.Area>(mFocusAreas);
      }
  
      /** White balance **/
  
      public void setWhiteBalance(CameraCapabilities.WhiteBalance whiteBalance) {
          mWhiteBalance = whiteBalance;
      }
  
      public CameraCapabilities.WhiteBalance getWhiteBalance() {
          return mWhiteBalance;
      }
  
      public void setAutoWhiteBalanceLock(boolean locked) {
          mAutoWhiteBalanceLocked = locked;
      }
  
      public boolean isAutoWhiteBalanceLocked() {
          return mAutoWhiteBalanceLocked;
      }
  
      /** Scene mode **/
  
      /**
       * @return The current scene mode.
       */
      public CameraCapabilities.SceneMode getCurrentSceneMode() {
          return mCurrentSceneMode;
      }
  
      /**
       * Sets the scene mode for capturing.
       *
       * @param sceneMode The scene mode to use.
       * @throws java.lang.UnsupportedOperationException if it's not supported.
       */
      public void setSceneMode(CameraCapabilities.SceneMode sceneMode) {
          mCurrentSceneMode = sceneMode;
      }
  
      /** Other Features **/
  
      public void setVideoStabilization(boolean enabled) {
          mVideoStabilizationEnabled = enabled;
      }
  
      public boolean isVideoStabilizationEnabled() {
          return mVideoStabilizationEnabled;
      }
  
      public void setRecordingHintEnabled(boolean hintEnabled) {
          mRecordingHintEnabled = hintEnabled;
      }
  
      public boolean isRecordingHintEnabled() {
          return mRecordingHintEnabled;
      }
  
      public void setGpsData(GpsData data) {
          mGpsData = new GpsData(data);
      }
  
      public GpsData getGpsData() {
          return (mGpsData == null ? null : new GpsData(mGpsData));
      }
  
      public void clearGpsData() {
          mGpsData = null;
      }
  
      /**
       * Sets the size of the thumbnail in EXIF header. To suppress thumbnail
       * generation, set a size of (0,0).
       *
       * @param s The size for the thumbnail. If {@code null}, agent will not
       *          set a thumbnail size.
       */
      public void setExifThumbnailSize(Size s) {
          mExifThumbnailSize = s;
      }
  
      /**
       * Gets the size of the thumbnail in EXIF header.
       *
       * @return desired thumbnail size, or null if no size was set
       */
      public Size getExifThumbnailSize() {
          return (mExifThumbnailSize == null) ? null : new Size(mExifThumbnailSize);
      }
  }
  