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