2 * Copyright (C) 2009 The Android Open Source Project
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 package com.android.camera;
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;
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;
37 import java.util.ArrayList;
38 import java.util.List;
39 import java.util.Locale;
42 * Provides utilities and keys for Camera settings.
43 * TODO: deprecate once all modules are using SettingsManager.
46 public class CameraSettings {
47 private static final int NOT_FOUND = -1;
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";
73 public static final String EXPOSURE_DEFAULT_VALUE = "0";
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.
80 public static final int CURRENT_VERSION = 1;
82 private static final String TAG = "CameraSettings";
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;
91 public CameraSettings(AppController app, Parameters parameters,
92 int cameraId, CameraInfo[] cameraInfo) {
93 mActivityController = app;
94 mContext = app.getAndroidContext();
95 mParameters = parameters;
97 mCameraInfo = cameraInfo;
98 mSettingsManager = mActivityController.getSettingsManager();
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;
110 return supported.get(0);
113 public static void removePreferenceFromScreen(
114 PreferenceGroup group, String key) {
115 removePreference(group, key);
118 public static int getMaxVideoDuration(Context context) {
119 int duration = 0; // in milliseconds, 0 means unlimited.
121 duration = context.getResources().getInteger(R.integer.max_video_recording_length);
122 } catch (Resources.NotFoundException ex) {
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);
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));
151 if (pictureSize != null) {
152 filterUnsupportedOptions(group, pictureSize, sizeListToStringList(
153 mParameters.getSupportedPictureSizes()));
154 filterSimilarPictureSize(group, pictureSize);
156 if (whiteBalance != null) {
157 filterUnsupportedOptions(group,
158 whiteBalance, mParameters.getSupportedWhiteBalance());
160 if (sceneMode != null) {
161 filterUnsupportedOptions(group,
162 sceneMode, mParameters.getSupportedSceneModes());
164 if (flashMode != null) {
165 filterUnsupportedOptions(group,
166 flashMode, mParameters.getSupportedFlashModes());
168 if (focusMode != null) {
169 if (!CameraUtil.isFocusAreaSupported(mParameters)) {
170 filterUnsupportedOptions(group,
171 focusMode, mParameters.getSupportedFocusModes());
173 // Remove the focus mode if we can use tap-to-focus.
174 removePreference(group, focusMode.getKey());
177 if (videoFlashMode != null) {
178 filterUnsupportedOptions(group,
179 videoFlashMode, mParameters.getSupportedFlashModes());
181 if (exposure != null) {
182 buildExposureCompensation(group, exposure);
184 if (cameraIdPref != null) {
185 buildCameraId(group, cameraIdPref);
188 if (timeLapseInterval != null) {
189 resetIfInvalid(timeLapseInterval);
191 if (videoEffect != null) {
192 filterUnsupportedOptions(group, videoEffect, null);
194 if (cameraHdr != null && (!ApiHelper.HAS_CAMERA_HDR
195 || !CameraUtil.isCameraHdrSupported(mParameters))) {
196 removePreference(group, cameraHdr.getKey());
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());
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());
215 float step = mParameters.getExposureCompensationStep();
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();
233 entries[i - minValue] = builder.append(i).toString();
234 labels[i - minValue] = explabel + " " + builder.toString();
235 icons[i - minValue] = iconIds.getResourceId(3 + i, 0);
237 exposure.setUseSingleIcon(true);
238 exposure.setEntries(entries);
239 exposure.setLabels(labels);
240 exposure.setEntryValues(entryValues);
241 exposure.setLargeIconIds(icons);
244 private void buildCameraId(
245 PreferenceGroup group, IconListPreference preference) {
246 int numOfCameras = mCameraInfo.length;
247 if (numOfCameras < 2) {
248 removePreference(group, preference.getKey());
252 CharSequence[] entryValues = new CharSequence[numOfCameras];
253 for (int i = 0; i < numOfCameras; ++i) {
254 entryValues[i] = "" + i;
256 preference.setEntryValues(entryValues);
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)) {
267 if (child instanceof ListPreference &&
268 ((ListPreference) child).getKey().equals(key)) {
269 group.removePreference(i);
276 private void filterUnsupportedOptions(PreferenceGroup group,
277 ListPreference pref, List<String> supported) {
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());
289 pref.filterUnsupported(supported);
290 if (pref.getEntries().length <= 1) {
291 removePreference(group, pref.getKey());
295 resetIfInvalid(pref);
298 private void filterSimilarPictureSize(PreferenceGroup group,
299 ListPreference pref) {
300 pref.filterDuplicated();
301 if (pref.getEntries().length <= 1) {
302 removePreference(group, pref.getKey());
305 resetIfInvalid(pref);
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);
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));
325 * Upgrade the preferences file from previous older versions to the one we
326 * are using. No-op if the versions match.
328 * @param pref The preferences file.
329 * @param numberOfCameras The number of cameras available on this device.
331 public static void upgradeGlobalPreferences(SharedPreferences pref, int numberOfCameras) {
332 upgradeOldVersion(pref);
333 upgradeCameraId(pref, numberOfCameras);
336 private static void upgradeOldVersion(SharedPreferences pref) {
339 version = pref.getInt(KEY_VERSION, 0);
340 } catch (Exception ex) {
343 if (version == CURRENT_VERSION) {
347 SharedPreferences.Editor editor = pref.edit();
348 editor.putInt(KEY_VERSION, CURRENT_VERSION);
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.
357 * @param pref The preferences file.
358 * @param numberOfCameras The number of cameras available on this device.
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);
370 if (cameraId < 0 || cameraId >= numberOfCameras) {
371 writePreferredCameraId(pref, 0);
375 public static int readPreferredCameraId(SharedPreferences pref) {
376 return Integer.parseInt(pref.getString(KEY_CAMERA_ID, "0"));
379 public static void writePreferredCameraId(SharedPreferences pref,
381 Editor editor = pref.edit();
382 editor.putString(KEY_CAMERA_ID, Integer.toString(cameraId));
386 public static int readExposure(ComboPreferences preferences) {
387 String exposure = preferences.getString(
388 CameraSettings.KEY_EXPOSURE,
389 EXPOSURE_DEFAULT_VALUE);
391 return Integer.parseInt(exposure);
392 } catch (Exception ex) {
393 Log.e(TAG, "Invalid exposure: " + exposure);
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));
404 if (CamcorderProfile.hasProfile(cameraId, CamcorderProfile.QUALITY_720P)) {
405 supported.add(Integer.toString(CamcorderProfile.QUALITY_720P));
407 if (CamcorderProfile.hasProfile(cameraId, CamcorderProfile.QUALITY_480P)) {
408 supported.add(Integer.toString(CamcorderProfile.QUALITY_480P));