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.app.Activity; 20 import android.content.Context; 21 import android.content.SharedPreferences; 22 import android.content.SharedPreferences.Editor; 23 import android.hardware.Camera.CameraInfo; 24 import android.hardware.Camera.Parameters; 25 import android.hardware.Camera.Size; 26 import android.media.CamcorderProfile; 27 import android.util.Log; 28 29 import java.util.ArrayList; 30 import java.util.List; 31 32 /** 33 * Provides utilities and keys for Camera settings. 34 */ 35 public class CameraSettings { 36 private static final int NOT_FOUND = -1; 37 38 public static final String KEY_VERSION = "pref_version_key"; 39 public static final String KEY_LOCAL_VERSION = "pref_local_version_key"; 40 public static final String KEY_RECORD_LOCATION = RecordLocationPreference.KEY; 41 public static final String KEY_VIDEO_QUALITY = "pref_video_quality_key"; 42 public static final String KEY_PICTURE_SIZE = "pref_camera_picturesize_key"; 43 public static final String KEY_JPEG_QUALITY = "pref_camera_jpegquality_key"; 44 public static final String KEY_FOCUS_MODE = "pref_camera_focusmode_key"; 45 public static final String KEY_FLASH_MODE = "pref_camera_flashmode_key"; 46 public static final String KEY_VIDEOCAMERA_FLASH_MODE = "pref_camera_video_flashmode_key"; 47 public static final String KEY_COLOR_EFFECT = "pref_camera_coloreffect_key"; 48 public static final String KEY_WHITE_BALANCE = "pref_camera_whitebalance_key"; 49 public static final String KEY_SCENE_MODE = "pref_camera_scenemode_key"; 50 public static final String KEY_EXPOSURE = "pref_camera_exposure_key"; 51 public static final String KEY_CAMERA_ID = "pref_camera_id_key"; 52 53 private static final String VIDEO_QUALITY_HIGH = "high"; 54 private static final String VIDEO_QUALITY_MMS = "mms"; 55 private static final String VIDEO_QUALITY_YOUTUBE = "youtube"; 56 57 public static final String EXPOSURE_DEFAULT_VALUE = "0"; 58 59 public static final int CURRENT_VERSION = 4; 60 public static final int CURRENT_LOCAL_VERSION = 1; 61 62 // max video duration in seconds for mms and youtube. 63 private static final int MMS_VIDEO_DURATION = CamcorderProfile.get(CamcorderProfile.QUALITY_LOW).duration; 64 private static final int YOUTUBE_VIDEO_DURATION = 10 * 60; // 10 mins 65 private static final int DEFAULT_VIDEO_DURATION = 30 * 60; // 10 mins 66 67 public static final String DEFAULT_VIDEO_QUALITY_VALUE = "high"; 68 69 // MMS video length 70 public static final int DEFAULT_VIDEO_DURATION_VALUE = -1; 71 72 @SuppressWarnings("unused") 73 private static final String TAG = "CameraSettings"; 74 75 private final Context mContext; 76 private final Parameters mParameters; 77 private final CameraInfo[] mCameraInfo; 78 CameraSettings(Activity activity, Parameters parameters, CameraInfo[] cameraInfo)79 public CameraSettings(Activity activity, Parameters parameters, 80 CameraInfo[] cameraInfo) { 81 mContext = activity; 82 mParameters = parameters; 83 mCameraInfo = cameraInfo; 84 } 85 getPreferenceGroup(int preferenceRes)86 public PreferenceGroup getPreferenceGroup(int preferenceRes) { 87 PreferenceInflater inflater = new PreferenceInflater(mContext); 88 PreferenceGroup group = 89 (PreferenceGroup) inflater.inflate(preferenceRes); 90 initPreference(group); 91 return group; 92 } 93 initialCameraPictureSize( Context context, Parameters parameters)94 public static void initialCameraPictureSize( 95 Context context, Parameters parameters) { 96 // When launching the camera app first time, we will set the picture 97 // size to the first one in the list defined in "arrays.xml" and is also 98 // supported by the driver. 99 List<Size> supported = parameters.getSupportedPictureSizes(); 100 if (supported == null) return; 101 for (String candidate : context.getResources().getStringArray( 102 R.array.pref_camera_picturesize_entryvalues)) { 103 if (setCameraPictureSize(candidate, supported, parameters)) { 104 SharedPreferences.Editor editor = ComboPreferences 105 .get(context).edit(); 106 editor.putString(KEY_PICTURE_SIZE, candidate); 107 editor.apply(); 108 return; 109 } 110 } 111 Log.e(TAG, "No supported picture size found"); 112 } 113 removePreferenceFromScreen( PreferenceGroup group, String key)114 public static void removePreferenceFromScreen( 115 PreferenceGroup group, String key) { 116 removePreference(group, key); 117 } 118 setCameraPictureSize( String candidate, List<Size> supported, Parameters parameters)119 public static boolean setCameraPictureSize( 120 String candidate, List<Size> supported, Parameters parameters) { 121 int index = candidate.indexOf('x'); 122 if (index == NOT_FOUND) return false; 123 int width = Integer.parseInt(candidate.substring(0, index)); 124 int height = Integer.parseInt(candidate.substring(index + 1)); 125 for (Size size: supported) { 126 if (size.width == width && size.height == height) { 127 parameters.setPictureSize(width, height); 128 return true; 129 } 130 } 131 return false; 132 } 133 initPreference(PreferenceGroup group)134 private void initPreference(PreferenceGroup group) { 135 ListPreference videoQuality = group.findPreference(KEY_VIDEO_QUALITY); 136 ListPreference pictureSize = group.findPreference(KEY_PICTURE_SIZE); 137 ListPreference whiteBalance = group.findPreference(KEY_WHITE_BALANCE); 138 ListPreference colorEffect = group.findPreference(KEY_COLOR_EFFECT); 139 ListPreference sceneMode = group.findPreference(KEY_SCENE_MODE); 140 ListPreference flashMode = group.findPreference(KEY_FLASH_MODE); 141 ListPreference focusMode = group.findPreference(KEY_FOCUS_MODE); 142 ListPreference exposure = group.findPreference(KEY_EXPOSURE); 143 IconListPreference cameraId = 144 (IconListPreference)group.findPreference(KEY_CAMERA_ID); 145 ListPreference videoFlashMode = 146 group.findPreference(KEY_VIDEOCAMERA_FLASH_MODE); 147 148 // Since the screen could be loaded from different resources, we need 149 // to check if the preference is available here 150 if (videoQuality != null) { 151 // Modify video duration settings. 152 // The first entry is for MMS video duration, and we need to fill 153 // in the device-dependent value (in seconds). 154 CharSequence[] entries = videoQuality.getEntries(); 155 CharSequence[] values = videoQuality.getEntryValues(); 156 for (int i = 0; i < entries.length; ++i) { 157 if (VIDEO_QUALITY_MMS.equals(values[i])) { 158 entries[i] = entries[i].toString().replace( 159 "30", Integer.toString(MMS_VIDEO_DURATION)); 160 break; 161 } 162 } 163 } 164 165 // Filter out unsupported settings / options 166 if (pictureSize != null) { 167 filterUnsupportedOptions(group, pictureSize, sizeListToStringList( 168 mParameters.getSupportedPictureSizes())); 169 } 170 if (whiteBalance != null) { 171 filterUnsupportedOptions(group, 172 whiteBalance, mParameters.getSupportedWhiteBalance()); 173 } 174 if (colorEffect != null) { 175 filterUnsupportedOptions(group, 176 colorEffect, mParameters.getSupportedColorEffects()); 177 } 178 if (sceneMode != null) { 179 filterUnsupportedOptions(group, 180 sceneMode, mParameters.getSupportedSceneModes()); 181 } 182 if (flashMode != null) { 183 filterUnsupportedOptions(group, 184 flashMode, mParameters.getSupportedFlashModes()); 185 } 186 if (focusMode != null) { 187 filterUnsupportedOptions(group, 188 focusMode, mParameters.getSupportedFocusModes()); 189 } 190 if (videoFlashMode != null) { 191 filterUnsupportedOptions(group, 192 videoFlashMode, mParameters.getSupportedFlashModes()); 193 } 194 if (exposure != null) buildExposureCompensation(group, exposure); 195 if (cameraId != null) buildCameraId(group, cameraId); 196 } 197 buildExposureCompensation( PreferenceGroup group, ListPreference exposure)198 private void buildExposureCompensation( 199 PreferenceGroup group, ListPreference exposure) { 200 int max = mParameters.getMaxExposureCompensation(); 201 int min = mParameters.getMinExposureCompensation(); 202 if (max == 0 && min == 0) { 203 removePreference(group, exposure.getKey()); 204 return; 205 } 206 float step = mParameters.getExposureCompensationStep(); 207 208 // show only integer values for exposure compensation 209 int maxValue = (int) Math.floor(max * step); 210 int minValue = (int) Math.ceil(min * step); 211 CharSequence entries[] = new CharSequence[maxValue - minValue + 1]; 212 CharSequence entryValues[] = new CharSequence[maxValue - minValue + 1]; 213 for (int i = minValue; i <= maxValue; ++i) { 214 entryValues[maxValue - i] = Integer.toString(Math.round(i / step)); 215 StringBuilder builder = new StringBuilder(); 216 if (i > 0) builder.append('+'); 217 entries[maxValue - i] = builder.append(i).toString(); 218 } 219 exposure.setEntries(entries); 220 exposure.setEntryValues(entryValues); 221 } 222 buildCameraId( PreferenceGroup group, IconListPreference cameraId)223 private void buildCameraId( 224 PreferenceGroup group, IconListPreference cameraId) { 225 int numOfCameras = mCameraInfo.length; 226 if (numOfCameras < 2) { 227 removePreference(group, cameraId.getKey()); 228 return; 229 } 230 231 CharSequence entries[] = new CharSequence[numOfCameras]; 232 CharSequence entryValues[] = new CharSequence[numOfCameras]; 233 int[] iconIds = new int[numOfCameras]; 234 int[] largeIconIds = new int[numOfCameras]; 235 for (int i = 0; i < numOfCameras; i++) { 236 entryValues[i] = Integer.toString(i); 237 if (mCameraInfo[i].facing == CameraInfo.CAMERA_FACING_FRONT) { 238 entries[i] = mContext.getString( 239 R.string.pref_camera_id_entry_front); 240 iconIds[i] = R.drawable.ic_menuselect_camera_facing_front; 241 largeIconIds[i] = R.drawable.ic_viewfinder_camera_facing_front; 242 } else { 243 entries[i] = mContext.getString( 244 R.string.pref_camera_id_entry_back); 245 iconIds[i] = R.drawable.ic_menuselect_camera_facing_back; 246 largeIconIds[i] = R.drawable.ic_viewfinder_camera_facing_back; 247 } 248 } 249 cameraId.setEntries(entries); 250 cameraId.setEntryValues(entryValues); 251 cameraId.setIconIds(iconIds); 252 cameraId.setLargeIconIds(largeIconIds); 253 } 254 removePreference(PreferenceGroup group, String key)255 private static boolean removePreference(PreferenceGroup group, String key) { 256 for (int i = 0, n = group.size(); i < n; i++) { 257 CameraPreference child = group.get(i); 258 if (child instanceof PreferenceGroup) { 259 if (removePreference((PreferenceGroup) child, key)) { 260 return true; 261 } 262 } 263 if (child instanceof ListPreference && 264 ((ListPreference) child).getKey().equals(key)) { 265 group.removePreference(i); 266 return true; 267 } 268 } 269 return false; 270 } 271 filterUnsupportedOptions(PreferenceGroup group, ListPreference pref, List<String> supported)272 private void filterUnsupportedOptions(PreferenceGroup group, 273 ListPreference pref, List<String> supported) { 274 275 CharSequence[] allEntries = pref.getEntries(); 276 277 // Remove the preference if the parameter is not supported or there is 278 // only one options for the settings. 279 if (supported == null || supported.size() <= 1) { 280 removePreference(group, pref.getKey()); 281 return; 282 } 283 284 pref.filterUnsupported(supported); 285 if (pref.getEntries().length <= 1) { 286 removePreference(group, pref.getKey()); 287 return; 288 } 289 290 // Set the value to the first entry if it is invalid. 291 String value = pref.getValue(); 292 if (pref.findIndexOfValue(value) == NOT_FOUND) { 293 pref.setValueIndex(0); 294 } 295 } 296 sizeListToStringList(List<Size> sizes)297 private static List<String> sizeListToStringList(List<Size> sizes) { 298 ArrayList<String> list = new ArrayList<String>(); 299 for (Size size : sizes) { 300 list.add(String.format("%dx%d", size.width, size.height)); 301 } 302 return list; 303 } 304 upgradeLocalPreferences(SharedPreferences pref)305 public static void upgradeLocalPreferences(SharedPreferences pref) { 306 int version; 307 try { 308 version = pref.getInt(KEY_LOCAL_VERSION, 0); 309 } catch (Exception ex) { 310 version = 0; 311 } 312 if (version == CURRENT_LOCAL_VERSION) return; 313 SharedPreferences.Editor editor = pref.edit(); 314 editor.putInt(KEY_LOCAL_VERSION, CURRENT_LOCAL_VERSION); 315 editor.apply(); 316 } 317 upgradeGlobalPreferences(SharedPreferences pref)318 public static void upgradeGlobalPreferences(SharedPreferences pref) { 319 int version; 320 try { 321 version = pref.getInt(KEY_VERSION, 0); 322 } catch (Exception ex) { 323 version = 0; 324 } 325 if (version == CURRENT_VERSION) return; 326 327 SharedPreferences.Editor editor = pref.edit(); 328 if (version == 0) { 329 // We won't use the preference which change in version 1. 330 // So, just upgrade to version 1 directly 331 version = 1; 332 } 333 if (version == 1) { 334 // Change jpeg quality {65,75,85} to {normal,fine,superfine} 335 String quality = pref.getString(KEY_JPEG_QUALITY, "85"); 336 if (quality.equals("65")) { 337 quality = "normal"; 338 } else if (quality.equals("75")) { 339 quality = "fine"; 340 } else { 341 quality = "superfine"; 342 } 343 editor.putString(KEY_JPEG_QUALITY, quality); 344 version = 2; 345 } 346 if (version == 2) { 347 editor.putString(KEY_RECORD_LOCATION, 348 pref.getBoolean(KEY_RECORD_LOCATION, false) 349 ? RecordLocationPreference.VALUE_ON 350 : RecordLocationPreference.VALUE_NONE); 351 version = 3; 352 } 353 if (version == 3) { 354 // Just use video quality to replace it and 355 // ignore the current settings. 356 editor.remove("pref_camera_videoquality_key"); 357 editor.remove("pref_camera_video_duration_key"); 358 } 359 editor.putInt(KEY_VERSION, CURRENT_VERSION); 360 editor.apply(); 361 } 362 upgradeAllPreferences(ComboPreferences pref)363 public static void upgradeAllPreferences(ComboPreferences pref) { 364 upgradeGlobalPreferences(pref.getGlobal()); 365 upgradeLocalPreferences(pref.getLocal()); 366 } 367 getVideoQuality(String quality)368 public static boolean getVideoQuality(String quality) { 369 return VIDEO_QUALITY_YOUTUBE.equals( 370 quality) || VIDEO_QUALITY_HIGH.equals(quality); 371 } 372 getVidoeDurationInMillis(String quality)373 public static int getVidoeDurationInMillis(String quality) { 374 if (VIDEO_QUALITY_MMS.equals(quality)) { 375 return MMS_VIDEO_DURATION * 1000; 376 } else if (VIDEO_QUALITY_YOUTUBE.equals(quality)) { 377 return YOUTUBE_VIDEO_DURATION * 1000; 378 } 379 return DEFAULT_VIDEO_DURATION * 1000; 380 } 381 readPreferredCameraId(SharedPreferences pref)382 public static int readPreferredCameraId(SharedPreferences pref) { 383 return Integer.parseInt(pref.getString(KEY_CAMERA_ID, "0")); 384 } 385 writePreferredCameraId(SharedPreferences pref, int cameraId)386 public static void writePreferredCameraId(SharedPreferences pref, 387 int cameraId) { 388 Editor editor = pref.edit(); 389 editor.putString(KEY_CAMERA_ID, Integer.toString(cameraId)); 390 editor.apply(); 391 } 392 } 393