OSDN Git Service

Merge "Add camera state in CameraManager implementation" into gb-ub-photos-denali
[android-x86/packages-apps-Camera2.git] / src / com / android / camera / CameraSettings.java
1 /*
2  * Copyright (C) 2009 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.camera;
18
19 import android.content.Context;
20 import android.content.SharedPreferences;
21 import android.content.SharedPreferences.Editor;
22 import android.content.res.Resources;
23 import android.content.res.TypedArray;
24 import android.hardware.Camera.CameraInfo;
25 import android.hardware.Camera.Parameters;
26 import android.hardware.Camera.Size;
27 import android.media.CamcorderProfile;
28 import android.util.Log;
29
30 import com.android.camera.app.AppController;
31 import com.android.camera.settings.SettingsManager;
32 import com.android.camera.util.ApiHelper;
33 import com.android.camera.util.CameraUtil;
34 import com.android.camera.util.GcamHelper;
35 import com.android.camera2.R;
36
37 import java.util.ArrayList;
38 import java.util.List;
39 import java.util.Locale;
40
41 /**
42  *  Provides utilities and keys for Camera settings.
43  *  TODO: deprecate once all modules are using SettingsManager.
44  */
45 @Deprecated
46 public class CameraSettings {
47     private static final int NOT_FOUND = -1;
48
49     public static final String KEY_VERSION = "pref_version_key";
50     public static final String KEY_LOCAL_VERSION = "pref_local_version_key";
51     public static final String KEY_RECORD_LOCATION = "pref_camera_recordlocation_key";
52     public static final String KEY_VIDEO_QUALITY = "pref_video_quality_key";
53     public static final String KEY_VIDEO_TIME_LAPSE_FRAME_INTERVAL = "pref_video_time_lapse_frame_interval_key";
54     public static final String KEY_PICTURE_SIZE = "pref_camera_picturesize_key";
55     public static final String KEY_JPEG_QUALITY = "pref_camera_jpegquality_key";
56     public static final String KEY_FOCUS_MODE = "pref_camera_focusmode_key";
57     public static final String KEY_FLASH_MODE = "pref_camera_flashmode_key";
58     public static final String KEY_VIDEOCAMERA_FLASH_MODE = "pref_camera_video_flashmode_key";
59     public static final String KEY_WHITE_BALANCE = "pref_camera_whitebalance_key";
60     public static final String KEY_SCENE_MODE = "pref_camera_scenemode_key";
61     public static final String KEY_EXPOSURE = "pref_camera_exposure_key";
62     public static final String KEY_TIMER = "pref_camera_timer_key";
63     public static final String KEY_TIMER_SOUND_EFFECTS = "pref_camera_timer_sound_key";
64     public static final String KEY_VIDEO_EFFECT = "pref_video_effect_key";
65     public static final String KEY_CAMERA_ID = "pref_camera_id_key";
66     public static final String KEY_CAMERA_HDR = "pref_camera_hdr_key";
67     public static final String KEY_CAMERA_HDR_PLUS = "pref_camera_hdr_plus_key";
68     public static final String KEY_CAMERA_FIRST_USE_HINT_SHOWN = "pref_camera_first_use_hint_shown_key";
69     public static final String KEY_VIDEO_FIRST_USE_HINT_SHOWN = "pref_video_first_use_hint_shown_key";
70     public static final String KEY_PHOTOSPHERE_PICTURESIZE = "pref_photosphere_picturesize_key";
71     public static final String KEY_STARTUP_MODULE_INDEX = "camera.startup_module";
72
73     public static final String EXPOSURE_DEFAULT_VALUE = "0";
74
75     /**
76      * This is used to indicate the current version of the preferences file.
77      * We should track this number to decide if we should change the file
78      * content once we move on to a new preferences file format.
79      */
80     public static final int CURRENT_VERSION = 1;
81
82     private static final String TAG = "CameraSettings";
83
84     private final AppController mActivityController;
85     private final Context mContext;
86     private final Parameters mParameters;
87     private final CameraInfo[] mCameraInfo;
88     private final int mCameraId;
89     private final SettingsManager mSettingsManager;
90
91     public CameraSettings(AppController app, Parameters parameters,
92                           int cameraId, CameraInfo[] cameraInfo) {
93         mActivityController = app;
94         mContext = app.getAndroidContext();
95         mParameters = parameters;
96         mCameraId = cameraId;
97         mCameraInfo = cameraInfo;
98         mSettingsManager = mActivityController.getSettingsManager();
99     }
100
101     public static String getSupportedHighestVideoQuality(int cameraId,
102             String defaultQuality) {
103         // When launching the camera app first time, we will set the video quality
104         // to the first one (i.e. highest quality) in the supported list
105         List<String> supported = getSupportedVideoQuality(cameraId);
106         if (supported == null) {
107             Log.e(TAG, "No supported video quality is found");
108             return defaultQuality;
109         }
110         return supported.get(0);
111     }
112
113     public static void removePreferenceFromScreen(
114             PreferenceGroup group, String key) {
115         removePreference(group, key);
116     }
117
118     public static int getMaxVideoDuration(Context context) {
119         int duration = 0;  // in milliseconds, 0 means unlimited.
120         try {
121             duration = context.getResources().getInteger(R.integer.max_video_recording_length);
122         } catch (Resources.NotFoundException ex) {
123         }
124         return duration;
125     }
126
127     private void initPreference(PreferenceGroup group) {
128         ListPreference videoQuality = group.findPreference(KEY_VIDEO_QUALITY);
129         ListPreference timeLapseInterval = group.findPreference(KEY_VIDEO_TIME_LAPSE_FRAME_INTERVAL);
130         ListPreference pictureSize = group.findPreference(KEY_PICTURE_SIZE);
131         ListPreference whiteBalance =  group.findPreference(KEY_WHITE_BALANCE);
132         ListPreference sceneMode = group.findPreference(KEY_SCENE_MODE);
133         ListPreference flashMode = group.findPreference(KEY_FLASH_MODE);
134         ListPreference focusMode = group.findPreference(KEY_FOCUS_MODE);
135         IconListPreference exposure =
136                 (IconListPreference) group.findPreference(KEY_EXPOSURE);
137         IconListPreference cameraIdPref =
138                 (IconListPreference) group.findPreference(KEY_CAMERA_ID);
139         ListPreference videoFlashMode =
140                 group.findPreference(KEY_VIDEOCAMERA_FLASH_MODE);
141         ListPreference videoEffect = group.findPreference(KEY_VIDEO_EFFECT);
142         ListPreference cameraHdr = group.findPreference(KEY_CAMERA_HDR);
143         ListPreference cameraHdrPlus = group.findPreference(KEY_CAMERA_HDR_PLUS);
144
145         // Since the screen could be loaded from different resources, we need
146         // to check if the preference is available here
147         if (videoQuality != null) {
148             filterUnsupportedOptions(group, videoQuality, getSupportedVideoQuality(mCameraId));
149         }
150
151         if (pictureSize != null) {
152             filterUnsupportedOptions(group, pictureSize, sizeListToStringList(
153                     mParameters.getSupportedPictureSizes()));
154             filterSimilarPictureSize(group, pictureSize);
155         }
156         if (whiteBalance != null) {
157             filterUnsupportedOptions(group,
158                     whiteBalance, mParameters.getSupportedWhiteBalance());
159         }
160         if (sceneMode != null) {
161             filterUnsupportedOptions(group,
162                     sceneMode, mParameters.getSupportedSceneModes());
163         }
164         if (flashMode != null) {
165             filterUnsupportedOptions(group,
166                     flashMode, mParameters.getSupportedFlashModes());
167         }
168         if (focusMode != null) {
169             if (!CameraUtil.isFocusAreaSupported(mParameters)) {
170                 filterUnsupportedOptions(group,
171                         focusMode, mParameters.getSupportedFocusModes());
172             } else {
173                 // Remove the focus mode if we can use tap-to-focus.
174                 removePreference(group, focusMode.getKey());
175             }
176         }
177         if (videoFlashMode != null) {
178             filterUnsupportedOptions(group,
179                     videoFlashMode, mParameters.getSupportedFlashModes());
180         }
181         if (exposure != null) {
182             buildExposureCompensation(group, exposure);
183         }
184         if (cameraIdPref != null) {
185             buildCameraId(group, cameraIdPref);
186         }
187
188         if (timeLapseInterval != null) {
189             resetIfInvalid(timeLapseInterval);
190         }
191         if (videoEffect != null) {
192             filterUnsupportedOptions(group, videoEffect, null);
193         }
194         if (cameraHdr != null && (!ApiHelper.HAS_CAMERA_HDR
195                 || !CameraUtil.isCameraHdrSupported(mParameters))) {
196             removePreference(group, cameraHdr.getKey());
197         }
198
199         int frontCameraId = mActivityController.getCameraProvider().getFirstFrontCameraId();
200         boolean isFrontCamera = (frontCameraId == mCameraId);
201         if (cameraHdrPlus != null && (!ApiHelper.HAS_CAMERA_HDR_PLUS ||
202                 !GcamHelper.hasGcamCapture() || isFrontCamera)) {
203             removePreference(group, cameraHdrPlus.getKey());
204         }
205     }
206
207     private void buildExposureCompensation(
208             PreferenceGroup group, IconListPreference exposure) {
209         int max = mParameters.getMaxExposureCompensation();
210         int min = mParameters.getMinExposureCompensation();
211         if (max == 0 && min == 0) {
212             removePreference(group, exposure.getKey());
213             return;
214         }
215         float step = mParameters.getExposureCompensationStep();
216
217         // show only integer values for exposure compensation
218         int maxValue = Math.min(3, (int) Math.floor(max * step));
219         int minValue = Math.max(-3, (int) Math.ceil(min * step));
220         String explabel = mContext.getResources().getString(R.string.pref_exposure_label);
221         CharSequence entries[] = new CharSequence[maxValue - minValue + 1];
222         CharSequence entryValues[] = new CharSequence[maxValue - minValue + 1];
223         CharSequence labels[] = new CharSequence[maxValue - minValue + 1];
224         int[] icons = new int[maxValue - minValue + 1];
225         TypedArray iconIds = mContext.getResources().obtainTypedArray(
226                 R.array.pref_camera_exposure_icons);
227         for (int i = minValue; i <= maxValue; ++i) {
228             entryValues[i - minValue] = Integer.toString(Math.round(i / step));
229             StringBuilder builder = new StringBuilder();
230             if (i > 0) {
231                 builder.append('+');
232             }
233             entries[i - minValue] = builder.append(i).toString();
234             labels[i - minValue] = explabel + " " + builder.toString();
235             icons[i - minValue] = iconIds.getResourceId(3 + i, 0);
236         }
237         exposure.setUseSingleIcon(true);
238         exposure.setEntries(entries);
239         exposure.setLabels(labels);
240         exposure.setEntryValues(entryValues);
241         exposure.setLargeIconIds(icons);
242     }
243
244     private void buildCameraId(
245             PreferenceGroup group, IconListPreference preference) {
246         int numOfCameras = mCameraInfo.length;
247         if (numOfCameras < 2) {
248             removePreference(group, preference.getKey());
249             return;
250         }
251
252         CharSequence[] entryValues = new CharSequence[numOfCameras];
253         for (int i = 0; i < numOfCameras; ++i) {
254             entryValues[i] = "" + i;
255         }
256         preference.setEntryValues(entryValues);
257     }
258
259     private static boolean removePreference(PreferenceGroup group, String key) {
260         for (int i = 0, n = group.size(); i < n; i++) {
261             CameraPreference child = group.get(i);
262             if (child instanceof PreferenceGroup) {
263                 if (removePreference((PreferenceGroup) child, key)) {
264                     return true;
265                 }
266             }
267             if (child instanceof ListPreference &&
268                     ((ListPreference) child).getKey().equals(key)) {
269                 group.removePreference(i);
270                 return true;
271             }
272         }
273         return false;
274     }
275
276     private void filterUnsupportedOptions(PreferenceGroup group,
277             ListPreference pref, List<String> supported) {
278         if (pref == null) {
279             return;
280         }
281
282         // Remove the preference if the parameter is not supported or there is
283         // only one options for the settings.
284         if (supported == null || supported.size() <= 1) {
285             removePreference(group, pref.getKey());
286             return;
287         }
288
289         pref.filterUnsupported(supported);
290         if (pref.getEntries().length <= 1) {
291             removePreference(group, pref.getKey());
292             return;
293         }
294
295         resetIfInvalid(pref);
296     }
297
298     private void filterSimilarPictureSize(PreferenceGroup group,
299             ListPreference pref) {
300         pref.filterDuplicated();
301         if (pref.getEntries().length <= 1) {
302             removePreference(group, pref.getKey());
303             return;
304         }
305         resetIfInvalid(pref);
306     }
307
308     private void resetIfInvalid(ListPreference pref) {
309         // Set the value to the first entry if it is invalid.
310         String value = mSettingsManager.getValueFromPreference(pref);
311         if (pref.findIndexOfValue(value) == NOT_FOUND) {
312             mSettingsManager.setValueIndexFromPreference(pref, 0);
313         }
314     }
315
316     private static List<String> sizeListToStringList(List<Size> sizes) {
317         ArrayList<String> list = new ArrayList<String>();
318         for (Size size : sizes) {
319             list.add(String.format(Locale.ENGLISH, "%dx%d", size.width, size.height));
320         }
321         return list;
322     }
323
324     /**
325      * Upgrade the preferences file from previous older versions to the one we
326      * are using. No-op if the versions match.
327      *
328      * @param pref The preferences file.
329      * @param numberOfCameras The number of cameras available on this device.
330      */
331     public static void upgradeGlobalPreferences(SharedPreferences pref, int numberOfCameras) {
332         upgradeOldVersion(pref);
333         upgradeCameraId(pref, numberOfCameras);
334     }
335
336     private static void upgradeOldVersion(SharedPreferences pref) {
337         int version;
338         try {
339             version = pref.getInt(KEY_VERSION, 0);
340         } catch (Exception ex) {
341             version = 0;
342         }
343         if (version == CURRENT_VERSION) {
344             return;
345         }
346
347         SharedPreferences.Editor editor = pref.edit();
348         editor.putInt(KEY_VERSION, CURRENT_VERSION);
349         editor.apply();
350     }
351
352     /**
353      * Updates the preferred camera ID to make sure it's a valid one on the
354      * current device. This solves the situation when the user backup all the
355      * data and moved to a new device.
356      *
357      * @param pref The preferences file.
358      * @param numberOfCameras The number of cameras available on this device.
359      */
360     private static void upgradeCameraId(SharedPreferences pref, int numberOfCameras) {
361         // The id stored in the preference may be out of range if we are running
362         // inside the emulator and a webcam is removed.
363         // Note: This method accesses the global preferences directly, not the
364         // combo preferences.
365         int cameraId = readPreferredCameraId(pref);
366         if (cameraId == 0) {
367             return; // fast path
368         }
369
370         if (cameraId < 0 || cameraId >= numberOfCameras) {
371             writePreferredCameraId(pref, 0);
372         }
373     }
374
375     public static int readPreferredCameraId(SharedPreferences pref) {
376         return Integer.parseInt(pref.getString(KEY_CAMERA_ID, "0"));
377     }
378
379     public static void writePreferredCameraId(SharedPreferences pref,
380             int cameraId) {
381         Editor editor = pref.edit();
382         editor.putString(KEY_CAMERA_ID, Integer.toString(cameraId));
383         editor.apply();
384     }
385
386     public static int readExposure(ComboPreferences preferences) {
387         String exposure = preferences.getString(
388                 CameraSettings.KEY_EXPOSURE,
389                 EXPOSURE_DEFAULT_VALUE);
390         try {
391             return Integer.parseInt(exposure);
392         } catch (Exception ex) {
393             Log.e(TAG, "Invalid exposure: " + exposure);
394         }
395         return 0;
396     }
397
398     private static ArrayList<String> getSupportedVideoQuality(int cameraId) {
399         ArrayList<String> supported = new ArrayList<String>();
400         // Check for supported quality
401         if (CamcorderProfile.hasProfile(cameraId, CamcorderProfile.QUALITY_1080P)) {
402             supported.add(Integer.toString(CamcorderProfile.QUALITY_1080P));
403         }
404         if (CamcorderProfile.hasProfile(cameraId, CamcorderProfile.QUALITY_720P)) {
405             supported.add(Integer.toString(CamcorderProfile.QUALITY_720P));
406         }
407         if (CamcorderProfile.hasProfile(cameraId, CamcorderProfile.QUALITY_480P)) {
408             supported.add(Integer.toString(CamcorderProfile.QUALITY_480P));
409         }
410         return supported;
411     }
412 }