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 com.android.ex.camera2.portability;
18 
19 import android.hardware.Camera;
20 
21 import com.android.ex.camera2.portability.debug.Log;
22 
23 import java.util.ArrayList;
24 import java.util.List;
25 import java.util.Map;
26 import java.util.TreeMap;
27 
28 /**
29  * A class which stores the camera settings.
30  */
31 public abstract class CameraSettings {
32     private static final Log.Tag TAG = new Log.Tag("CamSet");
33 
34     // Attempts to provide a value outside this range will be ignored.
35     private static final int MIN_JPEG_COMPRESSION_QUALITY = 1;
36     private static final int MAX_JPEG_COMPRESSION_QUALITY = 100;
37 
38     protected final Map<String, String> mGeneralSetting = new TreeMap<>();
39     protected final List<Camera.Area> mMeteringAreas = new ArrayList<>();
40     protected final List<Camera.Area> mFocusAreas = new ArrayList<>();
41     protected boolean mSizesLocked;
42     protected int mPreviewFpsRangeMin;
43     protected int mPreviewFpsRangeMax;
44     protected int mPreviewFrameRate;
45     protected Size mCurrentPreviewSize;
46     private int mCurrentPreviewFormat;
47     protected Size mCurrentPhotoSize;
48     protected byte mJpegCompressQuality;
49     protected int mCurrentPhotoFormat;
50     protected float mCurrentZoomRatio;
51     protected int mExposureCompensationIndex;
52     protected CameraCapabilities.FlashMode mCurrentFlashMode;
53     protected CameraCapabilities.FocusMode mCurrentFocusMode;
54     protected CameraCapabilities.SceneMode mCurrentSceneMode;
55     protected CameraCapabilities.WhiteBalance mWhiteBalance;
56     protected boolean mVideoStabilizationEnabled;
57     protected boolean mAutoExposureLocked;
58     protected boolean mAutoWhiteBalanceLocked;
59     protected boolean mRecordingHintEnabled;
60     protected GpsData mGpsData;
61     protected Size mExifThumbnailSize;
62 
63     /**
64      * An immutable class storing GPS related information.
65      * <p>It's a hack since we always use GPS time stamp but does not use other
66      * fields sometimes. Setting processing method to null means the other
67      * fields should not be used.</p>
68      */
69     public static class GpsData {
70         public final double latitude;
71         public final double longitude;
72         public final double altitude;
73         public final long timeStamp;
74         public final String processingMethod;
75 
76         /**
77          * Construct what may or may not actually represent a location,
78          * depending on the value of {@code processingMethod}.
79          *
80          * <p>Setting {@code processingMethod} to {@code null} means that
81          * {@code latitude}, {@code longitude}, and {@code altitude} will be
82          * completely ignored.</p>
83          */
GpsData(double latitude, double longitude, double altitude, long timeStamp, String processingMethod)84         public GpsData(double latitude, double longitude, double altitude, long timeStamp,
85                 String processingMethod) {
86             if (processingMethod == null &&
87                     (latitude != 0.0 || longitude != 0.0 || altitude != 0.0)) {
88                 Log.w(TAG, "GpsData's nonzero data will be ignored due to null processingMethod");
89             }
90             this.latitude = latitude;
91             this.longitude = longitude;
92             this.altitude = altitude;
93             this.timeStamp = timeStamp;
94             this.processingMethod = processingMethod;
95         }
96 
97         /** Copy constructor. */
GpsData(GpsData src)98         public GpsData(GpsData src) {
99             this.latitude = src.latitude;
100             this.longitude = src.longitude;
101             this.altitude = src.altitude;
102             this.timeStamp = src.timeStamp;
103             this.processingMethod = src.processingMethod;
104         }
105     }
106 
CameraSettings()107     protected CameraSettings() {
108     }
109 
110     /**
111      * Copy constructor.
112      *
113      * @param src The source settings.
114      * @return The copy of the source.
115      */
CameraSettings(CameraSettings src)116     protected CameraSettings(CameraSettings src) {
117         mGeneralSetting.putAll(src.mGeneralSetting);
118         mMeteringAreas.addAll(src.mMeteringAreas);
119         mFocusAreas.addAll(src.mFocusAreas);
120         mSizesLocked = src.mSizesLocked;
121         mPreviewFpsRangeMin = src.mPreviewFpsRangeMin;
122         mPreviewFpsRangeMax = src.mPreviewFpsRangeMax;
123         mPreviewFrameRate = src.mPreviewFrameRate;
124         mCurrentPreviewSize =
125                 (src.mCurrentPreviewSize == null ? null : new Size(src.mCurrentPreviewSize));
126         mCurrentPreviewFormat = src.mCurrentPreviewFormat;
127         mCurrentPhotoSize =
128                 (src.mCurrentPhotoSize == null ? null : new Size(src.mCurrentPhotoSize));
129         mJpegCompressQuality = src.mJpegCompressQuality;
130         mCurrentPhotoFormat = src.mCurrentPhotoFormat;
131         mCurrentZoomRatio = src.mCurrentZoomRatio;
132         mExposureCompensationIndex = src.mExposureCompensationIndex;
133         mCurrentFlashMode = src.mCurrentFlashMode;
134         mCurrentFocusMode = src.mCurrentFocusMode;
135         mCurrentSceneMode = src.mCurrentSceneMode;
136         mWhiteBalance = src.mWhiteBalance;
137         mVideoStabilizationEnabled = src.mVideoStabilizationEnabled;
138         mAutoExposureLocked = src.mAutoExposureLocked;
139         mAutoWhiteBalanceLocked = src.mAutoWhiteBalanceLocked;
140         mRecordingHintEnabled = src.mRecordingHintEnabled;
141         mGpsData = src.mGpsData;
142         mExifThumbnailSize = src.mExifThumbnailSize;
143     }
144 
145     /**
146      * @return A copy of this object, as an instance of the implementing class.
147      */
copy()148     public abstract CameraSettings copy();
149 
150     /** General setting **/
151     @Deprecated
setSetting(String key, String value)152     public void setSetting(String key, String value) {
153         mGeneralSetting.put(key, value);
154     }
155 
156     /**
157      * Changes whether classes outside this class are allowed to set the preview
158      * and photo capture sizes.
159      *
160      * @param locked Whether to prevent changes to these fields.
161      *
162      * @see #setPhotoSize
163      * @see #setPreviewSize
164      */
setSizesLocked(boolean locked)165     /*package*/ void setSizesLocked(boolean locked) {
166         mSizesLocked = locked;
167     }
168 
169     /**  Preview **/
170 
171     /**
172      * Sets the preview FPS range. This call will invalidate prior calls to
173      * {@link #setPreviewFrameRate(int)}.
174      *
175      * @param min The min FPS.
176      * @param max The max FPS.
177      */
setPreviewFpsRange(int min, int max)178     public void setPreviewFpsRange(int min, int max) {
179         if (min > max) {
180             int temp = max;
181             max = min;
182             min = temp;
183         }
184         mPreviewFpsRangeMax = max;
185         mPreviewFpsRangeMin = min;
186         mPreviewFrameRate = -1;
187     }
188 
189     /**
190      * @return The min of the preview FPS range.
191      */
getPreviewFpsRangeMin()192     public int getPreviewFpsRangeMin() {
193         return mPreviewFpsRangeMin;
194     }
195 
196     /**
197      * @return The max of the preview FPS range.
198      */
getPreviewFpsRangeMax()199     public int getPreviewFpsRangeMax() {
200         return mPreviewFpsRangeMax;
201     }
202 
203     /**
204      * Sets the preview FPS. This call will invalidate prior calls to
205      * {@link #setPreviewFpsRange(int, int)}.
206      *
207      * @param frameRate The target frame rate.
208      */
setPreviewFrameRate(int frameRate)209     public void setPreviewFrameRate(int frameRate) {
210         if (frameRate > 0) {
211             mPreviewFrameRate = frameRate;
212             mPreviewFpsRangeMax = frameRate;
213             mPreviewFpsRangeMin = frameRate;
214         }
215     }
216 
getPreviewFrameRate()217     public int getPreviewFrameRate() {
218         return mPreviewFrameRate;
219     }
220 
221     /**
222      * @return The current preview size.
223      */
getCurrentPreviewSize()224     public Size getCurrentPreviewSize() {
225         return new Size(mCurrentPreviewSize);
226     }
227 
228     /**
229      * @param previewSize The size to use for preview.
230      * @return Whether the operation was allowed (i.e. the sizes are unlocked).
231      */
setPreviewSize(Size previewSize)232     public boolean setPreviewSize(Size previewSize) {
233         if (mSizesLocked) {
234             Log.w(TAG, "Attempt to change preview size while locked");
235             return false;
236         }
237 
238         mCurrentPreviewSize = new Size(previewSize);
239         return true;
240     }
241 
242     /**
243      * Sets the preview format.
244      *
245      * @param format
246      * @see {@link android.graphics.ImageFormat}.
247      */
setPreviewFormat(int format)248     public void setPreviewFormat(int format) {
249         mCurrentPreviewFormat = format;
250     }
251 
252     /**
253      * @return The preview format.
254      * @see {@link android.graphics.ImageFormat}.
255      */
getCurrentPreviewFormat()256     public int getCurrentPreviewFormat() {
257         return mCurrentPreviewFormat;
258     }
259 
260     /** Picture **/
261 
262     /**
263      * @return The current photo size.
264      */
getCurrentPhotoSize()265     public Size getCurrentPhotoSize() {
266         return new Size(mCurrentPhotoSize);
267     }
268 
269     /**
270      * @param photoSize The size to use for preview.
271      * @return Whether the operation was allowed (i.e. the sizes are unlocked).
272      */
setPhotoSize(Size photoSize)273     public boolean setPhotoSize(Size photoSize) {
274         if (mSizesLocked) {
275             Log.w(TAG, "Attempt to change photo size while locked");
276             return false;
277         }
278 
279         mCurrentPhotoSize = new Size(photoSize);
280         return true;
281     }
282 
283     /**
284      * Sets the format for the photo.
285      *
286      * @param format The format for the photos taken.
287      * @see {@link android.graphics.ImageFormat}.
288      */
setPhotoFormat(int format)289     public void setPhotoFormat(int format) {
290         mCurrentPhotoFormat = format;
291     }
292 
293     /**
294      * @return The format for the photos taken.
295      * @see {@link android.graphics.ImageFormat}.
296      */
getCurrentPhotoFormat()297     public int getCurrentPhotoFormat() {
298         return mCurrentPhotoFormat;
299     }
300 
301     /**
302      * Sets the JPEG compression quality.
303      *
304      * @param quality The quality for JPEG.
305      */
setPhotoJpegCompressionQuality(int quality)306     public void setPhotoJpegCompressionQuality(int quality) {
307         if (quality < MIN_JPEG_COMPRESSION_QUALITY || quality > MAX_JPEG_COMPRESSION_QUALITY) {
308             Log.w(TAG, "Ignoring JPEG quality that falls outside the expected range");
309             return;
310         }
311         // This is safe because the positive numbers go up to 127.
312         mJpegCompressQuality = (byte) quality;
313     }
314 
getPhotoJpegCompressionQuality()315     public int getPhotoJpegCompressionQuality() {
316         return mJpegCompressQuality;
317     }
318 
319     /** Zoom **/
320 
321     /**
322      * @return The current zoom ratio. The min is 1.0f.
323      */
getCurrentZoomRatio()324     public float getCurrentZoomRatio() {
325         return mCurrentZoomRatio;
326     }
327 
328     /**
329      * Sets the zoom ratio.
330      * @param ratio The new zoom ratio. Should be in the range between 1.0 to
331      *              the value returned from {@link
332      *              com.android.camera.cameradevice.CameraCapabilities#getMaxZoomRatio()}.
333      * @throws java.lang.UnsupportedOperationException if the ratio is not
334      *         supported.
335      */
setZoomRatio(float ratio)336     public void setZoomRatio(float ratio) {
337         mCurrentZoomRatio = ratio;
338     }
339 
340     /** Exposure **/
341 
setExposureCompensationIndex(int index)342     public void setExposureCompensationIndex(int index) {
343         mExposureCompensationIndex = index;
344     }
345 
346     /**
347      * @return The exposure compensation, with 0 meaning unadjusted.
348      */
getExposureCompensationIndex()349     public int getExposureCompensationIndex() {
350         return mExposureCompensationIndex;
351     }
352 
setAutoExposureLock(boolean locked)353     public void setAutoExposureLock(boolean locked) {
354         mAutoExposureLocked = locked;
355     }
356 
isAutoExposureLocked()357     public boolean isAutoExposureLocked() {
358         return mAutoExposureLocked;
359     }
360 
361     /**
362      * @param areas The areas for autoexposure. The coordinate system has domain
363      *              and range [-1000,1000], measured relative to the visible
364      *              preview image, with orientation matching that of the sensor.
365      *              This means the coordinates must be transformed to account
366      *              for the devices rotation---but not the zoom level---before
367      *              being passed into this method.
368      */
setMeteringAreas(List<Camera.Area> areas)369     public void setMeteringAreas(List<Camera.Area> areas) {
370         mMeteringAreas.clear();
371         if (areas != null) {
372             mMeteringAreas.addAll(areas);
373         }
374     }
375 
getMeteringAreas()376     public List<Camera.Area> getMeteringAreas() {
377         return new ArrayList<Camera.Area>(mMeteringAreas);
378     }
379 
380     /** Flash **/
381 
getCurrentFlashMode()382     public CameraCapabilities.FlashMode getCurrentFlashMode() {
383         return mCurrentFlashMode;
384     }
385 
setFlashMode(CameraCapabilities.FlashMode flashMode)386     public void setFlashMode(CameraCapabilities.FlashMode flashMode) {
387         mCurrentFlashMode = flashMode;
388     }
389 
390     /** Focus **/
391 
392     /**
393      * Sets the focus mode.
394      * @param focusMode The focus mode to use.
395      */
setFocusMode(CameraCapabilities.FocusMode focusMode)396     public void setFocusMode(CameraCapabilities.FocusMode focusMode) {
397         mCurrentFocusMode = focusMode;
398     }
399 
400     /**
401      * @return The current focus mode.
402      */
getCurrentFocusMode()403     public CameraCapabilities.FocusMode getCurrentFocusMode() {
404         return mCurrentFocusMode;
405     }
406 
407     /**
408      * @param areas The areas to focus. The coordinate system has domain and
409      *              range [-1000,1000], measured relative to the visible preview
410      *              image, with orientation matching that of the sensor. This
411      *              means the coordinates must be transformed to account for
412      *              the devices rotation---but not the zoom level---before being
413      *              passed into this method.
414      */
setFocusAreas(List<Camera.Area> areas)415     public void setFocusAreas(List<Camera.Area> areas) {
416         mFocusAreas.clear();
417         if (areas != null) {
418             mFocusAreas.addAll(areas);
419         }
420     }
421 
getFocusAreas()422     public List<Camera.Area> getFocusAreas() {
423         return new ArrayList<Camera.Area>(mFocusAreas);
424     }
425 
426     /** White balance **/
427 
setWhiteBalance(CameraCapabilities.WhiteBalance whiteBalance)428     public void setWhiteBalance(CameraCapabilities.WhiteBalance whiteBalance) {
429         mWhiteBalance = whiteBalance;
430     }
431 
getWhiteBalance()432     public CameraCapabilities.WhiteBalance getWhiteBalance() {
433         return mWhiteBalance;
434     }
435 
setAutoWhiteBalanceLock(boolean locked)436     public void setAutoWhiteBalanceLock(boolean locked) {
437         mAutoWhiteBalanceLocked = locked;
438     }
439 
isAutoWhiteBalanceLocked()440     public boolean isAutoWhiteBalanceLocked() {
441         return mAutoWhiteBalanceLocked;
442     }
443 
444     /** Scene mode **/
445 
446     /**
447      * @return The current scene mode.
448      */
getCurrentSceneMode()449     public CameraCapabilities.SceneMode getCurrentSceneMode() {
450         return mCurrentSceneMode;
451     }
452 
453     /**
454      * Sets the scene mode for capturing.
455      *
456      * @param sceneMode The scene mode to use.
457      * @throws java.lang.UnsupportedOperationException if it's not supported.
458      */
setSceneMode(CameraCapabilities.SceneMode sceneMode)459     public void setSceneMode(CameraCapabilities.SceneMode sceneMode) {
460         mCurrentSceneMode = sceneMode;
461     }
462 
463     /** Other Features **/
464 
setVideoStabilization(boolean enabled)465     public void setVideoStabilization(boolean enabled) {
466         mVideoStabilizationEnabled = enabled;
467     }
468 
isVideoStabilizationEnabled()469     public boolean isVideoStabilizationEnabled() {
470         return mVideoStabilizationEnabled;
471     }
472 
setRecordingHintEnabled(boolean hintEnabled)473     public void setRecordingHintEnabled(boolean hintEnabled) {
474         mRecordingHintEnabled = hintEnabled;
475     }
476 
isRecordingHintEnabled()477     public boolean isRecordingHintEnabled() {
478         return mRecordingHintEnabled;
479     }
480 
setGpsData(GpsData data)481     public void setGpsData(GpsData data) {
482         mGpsData = new GpsData(data);
483     }
484 
getGpsData()485     public GpsData getGpsData() {
486         return (mGpsData == null ? null : new GpsData(mGpsData));
487     }
488 
clearGpsData()489     public void clearGpsData() {
490         mGpsData = null;
491     }
492 
493     /**
494      * Sets the size of the thumbnail in EXIF header. To suppress thumbnail
495      * generation, set a size of (0,0).
496      *
497      * @param s The size for the thumbnail. If {@code null}, agent will not
498      *          set a thumbnail size.
499      */
setExifThumbnailSize(Size s)500     public void setExifThumbnailSize(Size s) {
501         mExifThumbnailSize = s;
502     }
503 
504     /**
505      * Gets the size of the thumbnail in EXIF header.
506      *
507      * @return desired thumbnail size, or null if no size was set
508      */
getExifThumbnailSize()509     public Size getExifThumbnailSize() {
510         return (mExifThumbnailSize == null) ? null : new Size(mExifThumbnailSize);
511     }
512 }
513