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.annotation.TargetApi;
20 import android.app.Activity;
21 import android.content.Context;
22 import android.content.SharedPreferences;
23 import android.content.SharedPreferences.Editor;
24 import android.content.res.Resources;
25 import android.content.res.TypedArray;
26 import android.hardware.Camera.CameraInfo;
27 import android.hardware.Camera.Parameters;
28 import android.hardware.Camera.Size;
29 import android.media.CamcorderProfile;
30 import android.util.FloatMath;
31 import android.util.Log;
32 
33 import com.android.gallery3d.common.ApiHelper;
34 
35 import java.util.ArrayList;
36 import java.util.List;
37 import java.util.Locale;
38 
39 /**
40  *  Provides utilities and keys for Camera settings.
41  */
42 public class CameraSettings {
43     private static final int NOT_FOUND = -1;
44 
45     public static final String KEY_VERSION = "pref_version_key";
46     public static final String KEY_LOCAL_VERSION = "pref_local_version_key";
47     public static final String KEY_RECORD_LOCATION = "pref_camera_recordlocation_key";
48     public static final String KEY_VIDEO_QUALITY = "pref_video_quality_key";
49     public static final String KEY_VIDEO_TIME_LAPSE_FRAME_INTERVAL = "pref_video_time_lapse_frame_interval_key";
50     public static final String KEY_PICTURE_SIZE = "pref_camera_picturesize_key";
51     public static final String KEY_JPEG_QUALITY = "pref_camera_jpegquality_key";
52     public static final String KEY_FOCUS_MODE = "pref_camera_focusmode_key";
53     public static final String KEY_FLASH_MODE = "pref_camera_flashmode_key";
54     public static final String KEY_VIDEOCAMERA_FLASH_MODE = "pref_camera_video_flashmode_key";
55     public static final String KEY_WHITE_BALANCE = "pref_camera_whitebalance_key";
56     public static final String KEY_SCENE_MODE = "pref_camera_scenemode_key";
57     public static final String KEY_EXPOSURE = "pref_camera_exposure_key";
58     public static final String KEY_TIMER = "pref_camera_timer_key";
59     public static final String KEY_TIMER_SOUND_EFFECTS = "pref_camera_timer_sound_key";
60     public static final String KEY_VIDEO_EFFECT = "pref_video_effect_key";
61     public static final String KEY_CAMERA_ID = "pref_camera_id_key";
62     public static final String KEY_CAMERA_HDR = "pref_camera_hdr_key";
63     public static final String KEY_CAMERA_FIRST_USE_HINT_SHOWN = "pref_camera_first_use_hint_shown_key";
64     public static final String KEY_VIDEO_FIRST_USE_HINT_SHOWN = "pref_video_first_use_hint_shown_key";
65 
66     public static final String EXPOSURE_DEFAULT_VALUE = "0";
67 
68     public static final int CURRENT_VERSION = 5;
69     public static final int CURRENT_LOCAL_VERSION = 2;
70 
71     private static final String TAG = "CameraSettings";
72 
73     private final Context mContext;
74     private final Parameters mParameters;
75     private final CameraInfo[] mCameraInfo;
76     private final int mCameraId;
77 
CameraSettings(Activity activity, Parameters parameters, int cameraId, CameraInfo[] cameraInfo)78     public CameraSettings(Activity activity, Parameters parameters,
79                           int cameraId, CameraInfo[] cameraInfo) {
80         mContext = activity;
81         mParameters = parameters;
82         mCameraId = cameraId;
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         if (mParameters != null) initPreference(group);
91         return group;
92     }
93 
94     @TargetApi(ApiHelper.VERSION_CODES.HONEYCOMB)
getDefaultVideoQuality(int cameraId, String defaultQuality)95     public static String getDefaultVideoQuality(int cameraId,
96             String defaultQuality) {
97         if (ApiHelper.HAS_FINE_RESOLUTION_QUALITY_LEVELS) {
98             if (CamcorderProfile.hasProfile(
99                     cameraId, Integer.valueOf(defaultQuality))) {
100                 return defaultQuality;
101             }
102         }
103         return Integer.toString(CamcorderProfile.QUALITY_HIGH);
104     }
105 
initialCameraPictureSize( Context context, Parameters parameters)106     public static void initialCameraPictureSize(
107             Context context, Parameters parameters) {
108         // When launching the camera app first time, we will set the picture
109         // size to the first one in the list defined in "arrays.xml" and is also
110         // supported by the driver.
111         List<Size> supported = parameters.getSupportedPictureSizes();
112         if (supported == null) return;
113         for (String candidate : context.getResources().getStringArray(
114                 R.array.pref_camera_picturesize_entryvalues)) {
115             if (setCameraPictureSize(candidate, supported, parameters)) {
116                 SharedPreferences.Editor editor = ComboPreferences
117                         .get(context).edit();
118                 editor.putString(KEY_PICTURE_SIZE, candidate);
119                 editor.apply();
120                 return;
121             }
122         }
123         Log.e(TAG, "No supported picture size found");
124     }
125 
removePreferenceFromScreen( PreferenceGroup group, String key)126     public static void removePreferenceFromScreen(
127             PreferenceGroup group, String key) {
128         removePreference(group, key);
129     }
130 
setCameraPictureSize( String candidate, List<Size> supported, Parameters parameters)131     public static boolean setCameraPictureSize(
132             String candidate, List<Size> supported, Parameters parameters) {
133         int index = candidate.indexOf('x');
134         if (index == NOT_FOUND) return false;
135         int width = Integer.parseInt(candidate.substring(0, index));
136         int height = Integer.parseInt(candidate.substring(index + 1));
137         for (Size size : supported) {
138             if (size.width == width && size.height == height) {
139                 parameters.setPictureSize(width, height);
140                 return true;
141             }
142         }
143         return false;
144     }
145 
getMaxVideoDuration(Context context)146     public static int getMaxVideoDuration(Context context) {
147         int duration = 0;  // in milliseconds, 0 means unlimited.
148         try {
149             duration = context.getResources().getInteger(R.integer.max_video_recording_length);
150         } catch (Resources.NotFoundException ex) {
151         }
152         return duration;
153     }
154 
initPreference(PreferenceGroup group)155     private void initPreference(PreferenceGroup group) {
156         ListPreference videoQuality = group.findPreference(KEY_VIDEO_QUALITY);
157         ListPreference timeLapseInterval = group.findPreference(KEY_VIDEO_TIME_LAPSE_FRAME_INTERVAL);
158         ListPreference pictureSize = group.findPreference(KEY_PICTURE_SIZE);
159         ListPreference whiteBalance =  group.findPreference(KEY_WHITE_BALANCE);
160         ListPreference sceneMode = group.findPreference(KEY_SCENE_MODE);
161         ListPreference flashMode = group.findPreference(KEY_FLASH_MODE);
162         ListPreference focusMode = group.findPreference(KEY_FOCUS_MODE);
163         IconListPreference exposure =
164                 (IconListPreference) group.findPreference(KEY_EXPOSURE);
165         CountDownTimerPreference timer =
166                 (CountDownTimerPreference) group.findPreference(KEY_TIMER);
167         ListPreference countDownSoundEffects = group.findPreference(KEY_TIMER_SOUND_EFFECTS);
168         IconListPreference cameraIdPref =
169                 (IconListPreference) group.findPreference(KEY_CAMERA_ID);
170         ListPreference videoFlashMode =
171                 group.findPreference(KEY_VIDEOCAMERA_FLASH_MODE);
172         ListPreference videoEffect = group.findPreference(KEY_VIDEO_EFFECT);
173         ListPreference cameraHdr = group.findPreference(KEY_CAMERA_HDR);
174 
175         // Since the screen could be loaded from different resources, we need
176         // to check if the preference is available here
177         if (videoQuality != null) {
178             filterUnsupportedOptions(group, videoQuality, getSupportedVideoQuality());
179         }
180 
181         if (pictureSize != null) {
182             filterUnsupportedOptions(group, pictureSize, sizeListToStringList(
183                     mParameters.getSupportedPictureSizes()));
184             filterSimilarPictureSize(group, pictureSize);
185         }
186         if (whiteBalance != null) {
187             filterUnsupportedOptions(group,
188                     whiteBalance, mParameters.getSupportedWhiteBalance());
189         }
190         if (sceneMode != null) {
191             filterUnsupportedOptions(group,
192                     sceneMode, mParameters.getSupportedSceneModes());
193         }
194         if (flashMode != null) {
195             filterUnsupportedOptions(group,
196                     flashMode, mParameters.getSupportedFlashModes());
197         }
198         if (focusMode != null) {
199             if (!Util.isFocusAreaSupported(mParameters)) {
200                 filterUnsupportedOptions(group,
201                         focusMode, mParameters.getSupportedFocusModes());
202             } else {
203                 // Remove the focus mode if we can use tap-to-focus.
204                 removePreference(group, focusMode.getKey());
205             }
206         }
207         if (videoFlashMode != null) {
208             filterUnsupportedOptions(group,
209                     videoFlashMode, mParameters.getSupportedFlashModes());
210         }
211         if (exposure != null) buildExposureCompensation(group, exposure);
212         if (cameraIdPref != null) buildCameraId(group, cameraIdPref);
213 
214         if (timeLapseInterval != null) {
215             if (ApiHelper.HAS_TIME_LAPSE_RECORDING) {
216                 resetIfInvalid(timeLapseInterval);
217             } else {
218                 removePreference(group, timeLapseInterval.getKey());
219             }
220         }
221         if (videoEffect != null) {
222             if (ApiHelper.HAS_EFFECTS_RECORDING) {
223                 initVideoEffect(group, videoEffect);
224                 resetIfInvalid(videoEffect);
225             } else {
226                 filterUnsupportedOptions(group, videoEffect, null);
227             }
228         }
229         if (cameraHdr != null && (!ApiHelper.HAS_CAMERA_HDR
230                     || !Util.isCameraHdrSupported(mParameters))) {
231             removePreference(group, cameraHdr.getKey());
232         }
233     }
234 
buildExposureCompensation( PreferenceGroup group, IconListPreference exposure)235     private void buildExposureCompensation(
236             PreferenceGroup group, IconListPreference exposure) {
237         int max = mParameters.getMaxExposureCompensation();
238         int min = mParameters.getMinExposureCompensation();
239         if (max == 0 && min == 0) {
240             removePreference(group, exposure.getKey());
241             return;
242         }
243         float step = mParameters.getExposureCompensationStep();
244 
245         // show only integer values for exposure compensation
246         int maxValue = (int) FloatMath.floor(max * step);
247         int minValue = (int) FloatMath.ceil(min * step);
248         CharSequence entries[] = new CharSequence[maxValue - minValue + 1];
249         CharSequence entryValues[] = new CharSequence[maxValue - minValue + 1];
250         int[] icons = new int[maxValue - minValue + 1];
251         TypedArray iconIds = mContext.getResources().obtainTypedArray(
252                 R.array.pref_camera_exposure_icons);
253         for (int i = minValue; i <= maxValue; ++i) {
254             entryValues[maxValue - i] = Integer.toString(Math.round(i / step));
255             StringBuilder builder = new StringBuilder();
256             if (i > 0) builder.append('+');
257             entries[maxValue - i] = builder.append(i).toString();
258             icons[maxValue - i] = iconIds.getResourceId(3 + i, 0);
259         }
260         exposure.setUseSingleIcon(true);
261         exposure.setEntries(entries);
262         exposure.setEntryValues(entryValues);
263         exposure.setLargeIconIds(icons);
264     }
265 
buildCameraId( PreferenceGroup group, IconListPreference preference)266     private void buildCameraId(
267             PreferenceGroup group, IconListPreference preference) {
268         int numOfCameras = mCameraInfo.length;
269         if (numOfCameras < 2) {
270             removePreference(group, preference.getKey());
271             return;
272         }
273 
274         CharSequence[] entryValues = new CharSequence[numOfCameras];
275         for (int i = 0; i < numOfCameras; ++i) {
276             entryValues[i] = "" + i;
277         }
278         preference.setEntryValues(entryValues);
279     }
280 
removePreference(PreferenceGroup group, String key)281     private static boolean removePreference(PreferenceGroup group, String key) {
282         for (int i = 0, n = group.size(); i < n; i++) {
283             CameraPreference child = group.get(i);
284             if (child instanceof PreferenceGroup) {
285                 if (removePreference((PreferenceGroup) child, key)) {
286                     return true;
287                 }
288             }
289             if (child instanceof ListPreference &&
290                     ((ListPreference) child).getKey().equals(key)) {
291                 group.removePreference(i);
292                 return true;
293             }
294         }
295         return false;
296     }
297 
filterUnsupportedOptions(PreferenceGroup group, ListPreference pref, List<String> supported)298     private void filterUnsupportedOptions(PreferenceGroup group,
299             ListPreference pref, List<String> supported) {
300 
301         // Remove the preference if the parameter is not supported or there is
302         // only one options for the settings.
303         if (supported == null || supported.size() <= 1) {
304             removePreference(group, pref.getKey());
305             return;
306         }
307 
308         pref.filterUnsupported(supported);
309         if (pref.getEntries().length <= 1) {
310             removePreference(group, pref.getKey());
311             return;
312         }
313 
314         resetIfInvalid(pref);
315     }
316 
filterSimilarPictureSize(PreferenceGroup group, ListPreference pref)317     private void filterSimilarPictureSize(PreferenceGroup group,
318             ListPreference pref) {
319         pref.filterDuplicated();
320         if (pref.getEntries().length <= 1) {
321             removePreference(group, pref.getKey());
322             return;
323         }
324         resetIfInvalid(pref);
325     }
326 
resetIfInvalid(ListPreference pref)327     private void resetIfInvalid(ListPreference pref) {
328         // Set the value to the first entry if it is invalid.
329         String value = pref.getValue();
330         if (pref.findIndexOfValue(value) == NOT_FOUND) {
331             pref.setValueIndex(0);
332         }
333     }
334 
sizeListToStringList(List<Size> sizes)335     private static List<String> sizeListToStringList(List<Size> sizes) {
336         ArrayList<String> list = new ArrayList<String>();
337         for (Size size : sizes) {
338             list.add(String.format(Locale.ENGLISH, "%dx%d", size.width, size.height));
339         }
340         return list;
341     }
342 
upgradeLocalPreferences(SharedPreferences pref)343     public static void upgradeLocalPreferences(SharedPreferences pref) {
344         int version;
345         try {
346             version = pref.getInt(KEY_LOCAL_VERSION, 0);
347         } catch (Exception ex) {
348             version = 0;
349         }
350         if (version == CURRENT_LOCAL_VERSION) return;
351 
352         SharedPreferences.Editor editor = pref.edit();
353         if (version == 1) {
354             // We use numbers to represent the quality now. The quality definition is identical to
355             // that of CamcorderProfile.java.
356             editor.remove("pref_video_quality_key");
357         }
358         editor.putInt(KEY_LOCAL_VERSION, CURRENT_LOCAL_VERSION);
359         editor.apply();
360     }
361 
upgradeGlobalPreferences(SharedPreferences pref)362     public static void upgradeGlobalPreferences(SharedPreferences pref) {
363         upgradeOldVersion(pref);
364         upgradeCameraId(pref);
365     }
366 
upgradeOldVersion(SharedPreferences pref)367     private static void upgradeOldVersion(SharedPreferences pref) {
368         int version;
369         try {
370             version = pref.getInt(KEY_VERSION, 0);
371         } catch (Exception ex) {
372             version = 0;
373         }
374         if (version == CURRENT_VERSION) return;
375 
376         SharedPreferences.Editor editor = pref.edit();
377         if (version == 0) {
378             // We won't use the preference which change in version 1.
379             // So, just upgrade to version 1 directly
380             version = 1;
381         }
382         if (version == 1) {
383             // Change jpeg quality {65,75,85} to {normal,fine,superfine}
384             String quality = pref.getString(KEY_JPEG_QUALITY, "85");
385             if (quality.equals("65")) {
386                 quality = "normal";
387             } else if (quality.equals("75")) {
388                 quality = "fine";
389             } else {
390                 quality = "superfine";
391             }
392             editor.putString(KEY_JPEG_QUALITY, quality);
393             version = 2;
394         }
395         if (version == 2) {
396             editor.putString(KEY_RECORD_LOCATION,
397                     pref.getBoolean(KEY_RECORD_LOCATION, false)
398                     ? RecordLocationPreference.VALUE_ON
399                     : RecordLocationPreference.VALUE_NONE);
400             version = 3;
401         }
402         if (version == 3) {
403             // Just use video quality to replace it and
404             // ignore the current settings.
405             editor.remove("pref_camera_videoquality_key");
406             editor.remove("pref_camera_video_duration_key");
407         }
408 
409         editor.putInt(KEY_VERSION, CURRENT_VERSION);
410         editor.apply();
411     }
412 
upgradeCameraId(SharedPreferences pref)413     private static void upgradeCameraId(SharedPreferences pref) {
414         // The id stored in the preference may be out of range if we are running
415         // inside the emulator and a webcam is removed.
416         // Note: This method accesses the global preferences directly, not the
417         // combo preferences.
418         int cameraId = readPreferredCameraId(pref);
419         if (cameraId == 0) return;  // fast path
420 
421         int n = CameraHolder.instance().getNumberOfCameras();
422         if (cameraId < 0 || cameraId >= n) {
423             writePreferredCameraId(pref, 0);
424         }
425     }
426 
readPreferredCameraId(SharedPreferences pref)427     public static int readPreferredCameraId(SharedPreferences pref) {
428         return Integer.parseInt(pref.getString(KEY_CAMERA_ID, "0"));
429     }
430 
writePreferredCameraId(SharedPreferences pref, int cameraId)431     public static void writePreferredCameraId(SharedPreferences pref,
432             int cameraId) {
433         Editor editor = pref.edit();
434         editor.putString(KEY_CAMERA_ID, Integer.toString(cameraId));
435         editor.apply();
436     }
437 
readExposure(ComboPreferences preferences)438     public static int readExposure(ComboPreferences preferences) {
439         String exposure = preferences.getString(
440                 CameraSettings.KEY_EXPOSURE,
441                 EXPOSURE_DEFAULT_VALUE);
442         try {
443             return Integer.parseInt(exposure);
444         } catch (Exception ex) {
445             Log.e(TAG, "Invalid exposure: " + exposure);
446         }
447         return 0;
448     }
449 
readEffectType(SharedPreferences pref)450     public static int readEffectType(SharedPreferences pref) {
451         String effectSelection = pref.getString(KEY_VIDEO_EFFECT, "none");
452         if (effectSelection.equals("none")) {
453             return EffectsRecorder.EFFECT_NONE;
454         } else if (effectSelection.startsWith("goofy_face")) {
455             return EffectsRecorder.EFFECT_GOOFY_FACE;
456         } else if (effectSelection.startsWith("backdropper")) {
457             return EffectsRecorder.EFFECT_BACKDROPPER;
458         }
459         Log.e(TAG, "Invalid effect selection: " + effectSelection);
460         return EffectsRecorder.EFFECT_NONE;
461     }
462 
readEffectParameter(SharedPreferences pref)463     public static Object readEffectParameter(SharedPreferences pref) {
464         String effectSelection = pref.getString(KEY_VIDEO_EFFECT, "none");
465         if (effectSelection.equals("none")) {
466             return null;
467         }
468         int separatorIndex = effectSelection.indexOf('/');
469         String effectParameter =
470                 effectSelection.substring(separatorIndex + 1);
471         if (effectSelection.startsWith("goofy_face")) {
472             if (effectParameter.equals("squeeze")) {
473                 return EffectsRecorder.EFFECT_GF_SQUEEZE;
474             } else if (effectParameter.equals("big_eyes")) {
475                 return EffectsRecorder.EFFECT_GF_BIG_EYES;
476             } else if (effectParameter.equals("big_mouth")) {
477                 return EffectsRecorder.EFFECT_GF_BIG_MOUTH;
478             } else if (effectParameter.equals("small_mouth")) {
479                 return EffectsRecorder.EFFECT_GF_SMALL_MOUTH;
480             } else if (effectParameter.equals("big_nose")) {
481                 return EffectsRecorder.EFFECT_GF_BIG_NOSE;
482             } else if (effectParameter.equals("small_eyes")) {
483                 return EffectsRecorder.EFFECT_GF_SMALL_EYES;
484             }
485         } else if (effectSelection.startsWith("backdropper")) {
486             // Parameter is a string that either encodes the URI to use,
487             // or specifies 'gallery'.
488             return effectParameter;
489         }
490 
491         Log.e(TAG, "Invalid effect selection: " + effectSelection);
492         return null;
493     }
494 
restorePreferences(Context context, ComboPreferences preferences, Parameters parameters)495     public static void restorePreferences(Context context,
496             ComboPreferences preferences, Parameters parameters) {
497         int currentCameraId = readPreferredCameraId(preferences);
498 
499         // Clear the preferences of both cameras.
500         int backCameraId = CameraHolder.instance().getBackCameraId();
501         if (backCameraId != -1) {
502             preferences.setLocalId(context, backCameraId);
503             Editor editor = preferences.edit();
504             editor.clear();
505             editor.apply();
506         }
507         int frontCameraId = CameraHolder.instance().getFrontCameraId();
508         if (frontCameraId != -1) {
509             preferences.setLocalId(context, frontCameraId);
510             Editor editor = preferences.edit();
511             editor.clear();
512             editor.apply();
513         }
514 
515         // Switch back to the preferences of the current camera. Otherwise,
516         // we may write the preference to wrong camera later.
517         preferences.setLocalId(context, currentCameraId);
518 
519         upgradeGlobalPreferences(preferences.getGlobal());
520         upgradeLocalPreferences(preferences.getLocal());
521 
522         // Write back the current camera id because parameters are related to
523         // the camera. Otherwise, we may switch to the front camera but the
524         // initial picture size is that of the back camera.
525         initialCameraPictureSize(context, parameters);
526         writePreferredCameraId(preferences, currentCameraId);
527     }
528 
getSupportedVideoQuality()529     private ArrayList<String> getSupportedVideoQuality() {
530         ArrayList<String> supported = new ArrayList<String>();
531         // Check for supported quality
532         if (ApiHelper.HAS_FINE_RESOLUTION_QUALITY_LEVELS) {
533             getFineResolutionQuality(supported);
534         } else {
535             supported.add(Integer.toString(CamcorderProfile.QUALITY_HIGH));
536             CamcorderProfile high = CamcorderProfile.get(
537                     mCameraId, CamcorderProfile.QUALITY_HIGH);
538             CamcorderProfile low = CamcorderProfile.get(
539                     mCameraId, CamcorderProfile.QUALITY_LOW);
540             if (high.videoFrameHeight * high.videoFrameWidth >
541                     low.videoFrameHeight * low.videoFrameWidth) {
542                 supported.add(Integer.toString(CamcorderProfile.QUALITY_LOW));
543             }
544         }
545 
546         return supported;
547     }
548 
549     @TargetApi(ApiHelper.VERSION_CODES.HONEYCOMB)
getFineResolutionQuality(ArrayList<String> supported)550     private void getFineResolutionQuality(ArrayList<String> supported) {
551         if (CamcorderProfile.hasProfile(mCameraId, CamcorderProfile.QUALITY_1080P)) {
552             supported.add(Integer.toString(CamcorderProfile.QUALITY_1080P));
553         }
554         if (CamcorderProfile.hasProfile(mCameraId, CamcorderProfile.QUALITY_720P)) {
555             supported.add(Integer.toString(CamcorderProfile.QUALITY_720P));
556         }
557         if (CamcorderProfile.hasProfile(mCameraId, CamcorderProfile.QUALITY_480P)) {
558             supported.add(Integer.toString(CamcorderProfile.QUALITY_480P));
559         }
560     }
561 
initVideoEffect(PreferenceGroup group, ListPreference videoEffect)562     private void initVideoEffect(PreferenceGroup group, ListPreference videoEffect) {
563         CharSequence[] values = videoEffect.getEntryValues();
564 
565         boolean goofyFaceSupported =
566                 EffectsRecorder.isEffectSupported(EffectsRecorder.EFFECT_GOOFY_FACE);
567         boolean backdropperSupported =
568                 EffectsRecorder.isEffectSupported(EffectsRecorder.EFFECT_BACKDROPPER) &&
569                 Util.isAutoExposureLockSupported(mParameters) &&
570                 Util.isAutoWhiteBalanceLockSupported(mParameters);
571 
572         ArrayList<String> supported = new ArrayList<String>();
573         for (CharSequence value : values) {
574             String effectSelection = value.toString();
575             if (!goofyFaceSupported && effectSelection.startsWith("goofy_face")) continue;
576             if (!backdropperSupported && effectSelection.startsWith("backdropper")) continue;
577             supported.add(effectSelection);
578         }
579 
580         filterUnsupportedOptions(group, videoEffect, supported);
581     }
582 }
583