Home | History | Annotate | Download | only in camera
      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 
     79     public CameraSettings(Activity activity, Parameters parameters,
     80                           CameraInfo[] cameraInfo) {
     81         mContext = activity;
     82         mParameters = parameters;
     83         mCameraInfo = cameraInfo;
     84     }
     85 
     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 
     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 
    114     public static void removePreferenceFromScreen(
    115             PreferenceGroup group, String key) {
    116         removePreference(group, key);
    117     }
    118 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    363     public static void upgradeAllPreferences(ComboPreferences pref) {
    364         upgradeGlobalPreferences(pref.getGlobal());
    365         upgradeLocalPreferences(pref.getLocal());
    366     }
    367 
    368     public static boolean getVideoQuality(String quality) {
    369         return VIDEO_QUALITY_YOUTUBE.equals(
    370                 quality) || VIDEO_QUALITY_HIGH.equals(quality);
    371     }
    372 
    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 
    382     public static int readPreferredCameraId(SharedPreferences pref) {
    383         return Integer.parseInt(pref.getString(KEY_CAMERA_ID, "0"));
    384     }
    385 
    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