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
17package com.android.ex.camera2.portability;
18
19import android.hardware.Camera;
20
21import com.android.ex.camera2.portability.debug.Log;
22
23import java.util.ArrayList;
24import java.util.List;
25import java.util.Map;
26import java.util.TreeMap;
27
28/**
29 * A class which stores the camera settings.
30 */
31public 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         */
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. */
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
107    protected CameraSettings() {
108    }
109
110    /**
111     * Copy constructor.
112     *
113     * @param src The source settings.
114     * @return The copy of the source.
115     */
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     */
148    public abstract CameraSettings copy();
149
150    /** General setting **/
151    @Deprecated
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     */
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     */
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     */
192    public int getPreviewFpsRangeMin() {
193        return mPreviewFpsRangeMin;
194    }
195
196    /**
197     * @return The max of the preview FPS range.
198     */
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     */
209    public void setPreviewFrameRate(int frameRate) {
210        if (frameRate > 0) {
211            mPreviewFrameRate = frameRate;
212            mPreviewFpsRangeMax = frameRate;
213            mPreviewFpsRangeMin = frameRate;
214        }
215    }
216
217    public int getPreviewFrameRate() {
218        return mPreviewFrameRate;
219    }
220
221    /**
222     * @return The current preview size.
223     */
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     */
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     */
248    public void setPreviewFormat(int format) {
249        mCurrentPreviewFormat = format;
250    }
251
252    /**
253     * @return The preview format.
254     * @see {@link android.graphics.ImageFormat}.
255     */
256    public int getCurrentPreviewFormat() {
257        return mCurrentPreviewFormat;
258    }
259
260    /** Picture **/
261
262    /**
263     * @return The current photo size.
264     */
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     */
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     */
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     */
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     */
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
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     */
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     */
336    public void setZoomRatio(float ratio) {
337        mCurrentZoomRatio = ratio;
338    }
339
340    /** Exposure **/
341
342    public void setExposureCompensationIndex(int index) {
343        mExposureCompensationIndex = index;
344    }
345
346    /**
347     * @return The exposure compensation, with 0 meaning unadjusted.
348     */
349    public int getExposureCompensationIndex() {
350        return mExposureCompensationIndex;
351    }
352
353    public void setAutoExposureLock(boolean locked) {
354        mAutoExposureLocked = locked;
355    }
356
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     */
369    public void setMeteringAreas(List<Camera.Area> areas) {
370        mMeteringAreas.clear();
371        if (areas != null) {
372            mMeteringAreas.addAll(areas);
373        }
374    }
375
376    public List<Camera.Area> getMeteringAreas() {
377        return new ArrayList<Camera.Area>(mMeteringAreas);
378    }
379
380    /** Flash **/
381
382    public CameraCapabilities.FlashMode getCurrentFlashMode() {
383        return mCurrentFlashMode;
384    }
385
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     */
396    public void setFocusMode(CameraCapabilities.FocusMode focusMode) {
397        mCurrentFocusMode = focusMode;
398    }
399
400    /**
401     * @return The current focus mode.
402     */
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     */
415    public void setFocusAreas(List<Camera.Area> areas) {
416        mFocusAreas.clear();
417        if (areas != null) {
418            mFocusAreas.addAll(areas);
419        }
420    }
421
422    public List<Camera.Area> getFocusAreas() {
423        return new ArrayList<Camera.Area>(mFocusAreas);
424    }
425
426    /** White balance **/
427
428    public void setWhiteBalance(CameraCapabilities.WhiteBalance whiteBalance) {
429        mWhiteBalance = whiteBalance;
430    }
431
432    public CameraCapabilities.WhiteBalance getWhiteBalance() {
433        return mWhiteBalance;
434    }
435
436    public void setAutoWhiteBalanceLock(boolean locked) {
437        mAutoWhiteBalanceLocked = locked;
438    }
439
440    public boolean isAutoWhiteBalanceLocked() {
441        return mAutoWhiteBalanceLocked;
442    }
443
444    /** Scene mode **/
445
446    /**
447     * @return The current scene mode.
448     */
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     */
459    public void setSceneMode(CameraCapabilities.SceneMode sceneMode) {
460        mCurrentSceneMode = sceneMode;
461    }
462
463    /** Other Features **/
464
465    public void setVideoStabilization(boolean enabled) {
466        mVideoStabilizationEnabled = enabled;
467    }
468
469    public boolean isVideoStabilizationEnabled() {
470        return mVideoStabilizationEnabled;
471    }
472
473    public void setRecordingHintEnabled(boolean hintEnabled) {
474        mRecordingHintEnabled = hintEnabled;
475    }
476
477    public boolean isRecordingHintEnabled() {
478        return mRecordingHintEnabled;
479    }
480
481    public void setGpsData(GpsData data) {
482        mGpsData = new GpsData(data);
483    }
484
485    public GpsData getGpsData() {
486        return (mGpsData == null ? null : new GpsData(mGpsData));
487    }
488
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     */
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     */
509    public Size getExifThumbnailSize() {
510        return (mExifThumbnailSize == null) ? null : new Size(mExifThumbnailSize);
511    }
512}
513