Home | History | Annotate | Download | only in settings
      1 /*
      2  * Copyright (C) 2014 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.settings;
     18 
     19 import android.content.Context;
     20 import android.content.SharedPreferences;
     21 
     22 import com.android.camera.app.AppController;
     23 import com.android.camera.app.ModuleManagerImpl;
     24 import com.android.camera.debug.Log;
     25 import com.android.camera.util.ApiHelper;
     26 import com.android.camera.util.Size;
     27 import com.android.camera2.R;
     28 import com.android.ex.camera2.portability.CameraAgentFactory;
     29 import com.android.ex.camera2.portability.CameraDeviceInfo;
     30 
     31 import java.util.List;
     32 import java.util.Map;
     33 
     34 /**
     35  * Defines the general upgrade path for the app. Modules may define specific
     36  * upgrade logic, but upgrading for preferences across modules, CameraActivity
     37  * or application-wide can be added here.
     38  */
     39 public class AppUpgrader extends SettingsUpgrader {
     40     private static final Log.Tag TAG = new Log.Tag("AppUpgrader");
     41 
     42     private static final String OLD_CAMERA_PREFERENCES_PREFIX = "_preferences_";
     43     private static final String OLD_MODULE_PREFERENCES_PREFIX = "_preferences_module_";
     44     private static final String OLD_GLOBAL_PREFERENCES_FILENAME = "_preferences_camera";
     45     private static final String OLD_KEY_UPGRADE_VERSION = "pref_strict_upgrade_version";
     46 
     47     /**
     48      * With this version everyone was forced to choose their location settings
     49      * again.
     50      */
     51     private static final int FORCE_LOCATION_CHOICE_VERSION = 2;
     52 
     53     /**
     54      * With this version, the camera size setting changed from a "small",
     55      * "medium" and "default" to strings representing the actual resolutions,
     56      * i.e. "1080x1776".
     57      */
     58     private static final int CAMERA_SIZE_SETTING_UPGRADE_VERSION = 3;
     59 
     60     /**
     61      * With this version, the names of the files storing camera specific and
     62      * module specific settings changed.
     63      * <p>
     64      * NOTE: changed this from 4 to 6 to re-run on latest Glacier upgrade.
     65      * Initial upgraders to Glacier will run conversion once as of the change.
     66      * When re-run for early dogfooders, values will get overwritten but will
     67      * all work.
     68      */
     69     private static final int CAMERA_MODULE_SETTINGS_FILES_RENAMED_VERSION = 6;
     70 
     71     /**
     72      * With this version, timelapse mode was removed and mode indices need to be
     73      * resequenced.
     74      */
     75     private static final int CAMERA_SETTINGS_SELECTED_MODULE_INDEX = 5;
     76 
     77     /**
     78      * With this version internal storage is changed to use only Strings, and
     79      * a type conversion process should execute.
     80      */
     81     private static final int CAMERA_SETTINGS_STRINGS_UPGRADE = 5;
     82 
     83     /**
     84      * With this version we needed to convert the artificial 16:9 high
     85      * resolution size on the N5 since we stored it with a swapped width/height.
     86      */
     87     public static final int NEEDS_N5_16by9_RESOLUTION_SWAP = 7;
     88     /**
     89      * Increment this value whenever new AOSP UpgradeSteps need to be executed.
     90      */
     91     public static final int APP_UPGRADE_VERSION = 7;
     92 
     93     private final AppController mAppController;
     94 
     95     public AppUpgrader(final AppController appController) {
     96         super(Keys.KEY_UPGRADE_VERSION, APP_UPGRADE_VERSION);
     97         mAppController = appController;
     98     }
     99 
    100     @Override
    101     protected int getLastVersion(SettingsManager settingsManager) {
    102         // Prior upgrade versions were stored in the default preferences as int
    103         // and String. We create a new version location for migration to String.
    104         // If we don't have a version persisted in the new location, check for
    105         // the prior value from the old location. We expect the old value to be
    106         // processed during {@link #upgradeTypesToStrings}.
    107         SharedPreferences defaultPreferences = settingsManager.getDefaultPreferences();
    108         if (defaultPreferences.contains(OLD_KEY_UPGRADE_VERSION)) {
    109             Map<String, ?> allPrefs = defaultPreferences.getAll();
    110             Object oldVersion = allPrefs.get(OLD_KEY_UPGRADE_VERSION);
    111             defaultPreferences.edit().remove(OLD_KEY_UPGRADE_VERSION).apply();
    112             if (oldVersion instanceof Integer) {
    113                 return (Integer) oldVersion;
    114             } else if (oldVersion instanceof String) {
    115                 return SettingsManager.convertToInt((String) oldVersion);
    116             }
    117         }
    118         return super.getLastVersion(settingsManager);
    119     }
    120 
    121     @Override
    122     public void upgrade(SettingsManager settingsManager, int lastVersion, int currentVersion) {
    123         Context context = mAppController.getAndroidContext();
    124 
    125         // Do strings upgrade first before 'earlier' upgrades, since they assume
    126         // valid storage of values.
    127         if (lastVersion < CAMERA_SETTINGS_STRINGS_UPGRADE) {
    128             upgradeTypesToStrings(settingsManager);
    129         }
    130 
    131         if (lastVersion < FORCE_LOCATION_CHOICE_VERSION) {
    132             forceLocationChoice(settingsManager);
    133         }
    134 
    135         if (lastVersion < CAMERA_SIZE_SETTING_UPGRADE_VERSION) {
    136             CameraDeviceInfo infos = CameraAgentFactory
    137                     .getAndroidCameraAgent(context, CameraAgentFactory.CameraApi.API_1)
    138                     .getCameraDeviceInfo();
    139             upgradeCameraSizeSetting(settingsManager, context, infos,
    140                     SettingsUtil.CAMERA_FACING_FRONT);
    141             upgradeCameraSizeSetting(settingsManager, context, infos,
    142                     SettingsUtil.CAMERA_FACING_BACK);
    143             // We changed size handling and aspect ratio placement, put user
    144             // back into Camera mode this time to ensure they see the ratio
    145             // chooser if applicable.
    146             settingsManager.remove(SettingsManager.SCOPE_GLOBAL,
    147                     Keys.KEY_STARTUP_MODULE_INDEX);
    148         }
    149 
    150         if (lastVersion < CAMERA_MODULE_SETTINGS_FILES_RENAMED_VERSION) {
    151             upgradeCameraSettingsFiles(settingsManager, context);
    152             upgradeModuleSettingsFiles(settingsManager, context,
    153                     mAppController);
    154         }
    155 
    156         if (lastVersion < CAMERA_SETTINGS_SELECTED_MODULE_INDEX) {
    157             upgradeSelectedModeIndex(settingsManager, context);
    158         }
    159 
    160         if (lastVersion < NEEDS_N5_16by9_RESOLUTION_SWAP) {
    161             updateN516by9ResolutionIfNeeded(settingsManager);
    162         }
    163     }
    164 
    165     /**
    166      * Converts settings that were stored in SharedPreferences as non-Strings,
    167      * to Strings. This is necessary due to a SettingsManager API refactoring.
    168      * Should only be executed if we detected a change in
    169      * Keys.KEY_UPGRADE_VERSION type from int to string; rerunning this on
    170      * string values will result in ClassCastExceptions when trying to retrieve
    171      * an int or boolean as a String.
    172      */
    173     private void upgradeTypesToStrings(SettingsManager settingsManager) {
    174         SharedPreferences defaultPreferences = settingsManager.getDefaultPreferences();
    175         SharedPreferences oldGlobalPreferences =
    176                 settingsManager.openPreferences(OLD_GLOBAL_PREFERENCES_FILENAME);
    177 
    178         // Location: boolean -> String, from default.
    179         if (defaultPreferences.contains(Keys.KEY_RECORD_LOCATION)) {
    180             boolean location = removeBoolean(defaultPreferences, Keys.KEY_RECORD_LOCATION);
    181             settingsManager.set(SettingsManager.SCOPE_GLOBAL, Keys.KEY_RECORD_LOCATION, location);
    182         }
    183 
    184         // User selected aspect ratio: boolean -> String, from default.
    185         if (defaultPreferences.contains(Keys.KEY_USER_SELECTED_ASPECT_RATIO)) {
    186             boolean userSelectedAspectRatio = removeBoolean(defaultPreferences,
    187                     Keys.KEY_USER_SELECTED_ASPECT_RATIO);
    188             settingsManager.set(SettingsManager.SCOPE_GLOBAL, Keys.KEY_USER_SELECTED_ASPECT_RATIO,
    189                     userSelectedAspectRatio);
    190         }
    191 
    192         // Manual exposure compensation: boolean -> String, from default.
    193         if (defaultPreferences.contains(Keys.KEY_EXPOSURE_COMPENSATION_ENABLED)) {
    194             boolean manualExposureCompensationEnabled = removeBoolean(defaultPreferences,
    195                     Keys.KEY_EXPOSURE_COMPENSATION_ENABLED);
    196             settingsManager.set(SettingsManager.SCOPE_GLOBAL,
    197                     Keys.KEY_EXPOSURE_COMPENSATION_ENABLED, manualExposureCompensationEnabled);
    198         }
    199 
    200         // Hint: boolean -> String, from default.
    201         if (defaultPreferences.contains(Keys.KEY_CAMERA_FIRST_USE_HINT_SHOWN)) {
    202             boolean hint = removeBoolean(defaultPreferences, Keys.KEY_CAMERA_FIRST_USE_HINT_SHOWN);
    203             settingsManager.set(SettingsManager.SCOPE_GLOBAL, Keys.KEY_CAMERA_FIRST_USE_HINT_SHOWN,
    204                     hint);
    205         }
    206 
    207         // Startup module index: Integer -> String, from default.
    208         if (defaultPreferences.contains(Keys.KEY_STARTUP_MODULE_INDEX)) {
    209             int startupModuleIndex = removeInteger(defaultPreferences,
    210                     Keys.KEY_STARTUP_MODULE_INDEX);
    211             settingsManager.set(SettingsManager.SCOPE_GLOBAL, Keys.KEY_STARTUP_MODULE_INDEX,
    212                     startupModuleIndex);
    213         }
    214 
    215         // Last camera used module index: Integer -> String, from default.
    216         if (defaultPreferences.contains(Keys.KEY_CAMERA_MODULE_LAST_USED)) {
    217             int lastCameraUsedModuleIndex = removeInteger(defaultPreferences,
    218                     Keys.KEY_CAMERA_MODULE_LAST_USED);
    219             settingsManager.set(SettingsManager.SCOPE_GLOBAL, Keys.KEY_CAMERA_MODULE_LAST_USED,
    220                     lastCameraUsedModuleIndex);
    221         }
    222 
    223         // Flash supported back camera setting: boolean -> String, from old
    224         // global.
    225         if (oldGlobalPreferences.contains(Keys.KEY_FLASH_SUPPORTED_BACK_CAMERA)) {
    226             boolean flashSupportedBackCamera = removeBoolean(oldGlobalPreferences,
    227                     Keys.KEY_FLASH_SUPPORTED_BACK_CAMERA);
    228             if (flashSupportedBackCamera) {
    229                 settingsManager.set(SettingsManager.SCOPE_GLOBAL,
    230                         Keys.KEY_FLASH_SUPPORTED_BACK_CAMERA, flashSupportedBackCamera);
    231             }
    232         }
    233 
    234         // Should show refocus viewer cling: boolean -> String, from default.
    235         if (defaultPreferences.contains(Keys.KEY_SHOULD_SHOW_REFOCUS_VIEWER_CLING)) {
    236             boolean shouldShowRefocusViewer = removeBoolean(defaultPreferences,
    237                     Keys.KEY_SHOULD_SHOW_REFOCUS_VIEWER_CLING);
    238             settingsManager.set(SettingsManager.SCOPE_GLOBAL,
    239                     Keys.KEY_SHOULD_SHOW_REFOCUS_VIEWER_CLING, shouldShowRefocusViewer);
    240         }
    241 
    242         // Should show settings button cling: boolean -> String, from default.
    243         if (defaultPreferences.contains(Keys.KEY_SHOULD_SHOW_SETTINGS_BUTTON_CLING)) {
    244             boolean shouldShowSettingsButtonCling = removeBoolean(defaultPreferences,
    245                     Keys.KEY_SHOULD_SHOW_SETTINGS_BUTTON_CLING);
    246             settingsManager.set(SettingsManager.SCOPE_GLOBAL,
    247                     Keys.KEY_SHOULD_SHOW_SETTINGS_BUTTON_CLING, shouldShowSettingsButtonCling);
    248         }
    249 
    250         // HDR plus on setting: String on/off -> String, from old global.
    251         if (oldGlobalPreferences.contains(Keys.KEY_CAMERA_HDR_PLUS)) {
    252             String hdrPlus = removeString(oldGlobalPreferences, Keys.KEY_CAMERA_HDR_PLUS);
    253             if (OLD_SETTINGS_VALUE_ON.equals(hdrPlus)) {
    254                 settingsManager.set(SettingsManager.SCOPE_GLOBAL, Keys.KEY_CAMERA_HDR_PLUS, true);
    255             }
    256         }
    257 
    258         // HDR on setting: String on/off -> String, from old global.
    259         if (oldGlobalPreferences.contains(Keys.KEY_CAMERA_HDR)) {
    260             String hdrPlus = removeString(oldGlobalPreferences, Keys.KEY_CAMERA_HDR);
    261             if (OLD_SETTINGS_VALUE_ON.equals(hdrPlus)) {
    262                 settingsManager.set(SettingsManager.SCOPE_GLOBAL, Keys.KEY_CAMERA_HDR, true);
    263             }
    264         }
    265 
    266         // Grid on setting: String on/off -> String, from old global.
    267         if (oldGlobalPreferences.contains(Keys.KEY_CAMERA_GRID_LINES)) {
    268             String hdrPlus = removeString(oldGlobalPreferences, Keys.KEY_CAMERA_GRID_LINES);
    269             if (OLD_SETTINGS_VALUE_ON.equals(hdrPlus)) {
    270                 settingsManager.set(SettingsManager.SCOPE_GLOBAL, Keys.KEY_CAMERA_GRID_LINES,
    271                         true);
    272             }
    273         }
    274     }
    275 
    276     /**
    277      * Part of the AOSP upgrade path, forces the user to choose their location
    278      * again if it was originally set to false.
    279      */
    280     private void forceLocationChoice(SettingsManager settingsManager) {
    281         SharedPreferences oldGlobalPreferences =
    282                 settingsManager.openPreferences(OLD_GLOBAL_PREFERENCES_FILENAME);
    283        // Show the location dialog on upgrade if
    284         // (a) the user has never set this option (status quo).
    285         // (b) the user opt'ed out previously.
    286         if (settingsManager.isSet(SettingsManager.SCOPE_GLOBAL,
    287                 Keys.KEY_RECORD_LOCATION)) {
    288             // Location is set in the source file defined for this setting.
    289             // Remove the setting if the value is false to launch the dialog.
    290             if (!settingsManager.getBoolean(SettingsManager.SCOPE_GLOBAL,
    291                     Keys.KEY_RECORD_LOCATION)) {
    292                 settingsManager.remove(SettingsManager.SCOPE_GLOBAL, Keys.KEY_RECORD_LOCATION);
    293             }
    294         } else if (oldGlobalPreferences.contains(Keys.KEY_RECORD_LOCATION)) {
    295             // Location is not set, check to see if we're upgrading from
    296             // a different source file.
    297             String location = removeString(oldGlobalPreferences, Keys.KEY_RECORD_LOCATION);
    298             if (OLD_SETTINGS_VALUE_ON.equals(location)) {
    299                     settingsManager.set(SettingsManager.SCOPE_GLOBAL, Keys.KEY_RECORD_LOCATION,
    300                             true);
    301             }
    302         }
    303     }
    304 
    305     /**
    306      * Part of the AOSP upgrade path, sets front and back picture sizes.
    307      */
    308     private void upgradeCameraSizeSetting(SettingsManager settingsManager,
    309             Context context, CameraDeviceInfo infos,
    310             SettingsUtil.CameraDeviceSelector facing) {
    311         String key;
    312         if (facing == SettingsUtil.CAMERA_FACING_FRONT) {
    313             key = Keys.KEY_PICTURE_SIZE_FRONT;
    314         } else if (facing == SettingsUtil.CAMERA_FACING_BACK) {
    315             key = Keys.KEY_PICTURE_SIZE_BACK;
    316         } else {
    317             Log.w(TAG, "Ignoring attempt to upgrade size of unhandled camera facing direction");
    318             return;
    319         }
    320 
    321         // infos might be null if the underlying camera device is broken. In
    322         // that case, just delete the old settings and force the user to
    323         // reselect, it's the least evil solution given we want to only upgrade
    324         // settings once.
    325         if (infos == null) {
    326             settingsManager.remove(SettingsManager.SCOPE_GLOBAL, key);
    327             return;
    328         }
    329 
    330         String pictureSize = settingsManager.getString(SettingsManager.SCOPE_GLOBAL, key);
    331         int camera = SettingsUtil.getCameraId(infos, facing);
    332         if (camera != -1) {
    333             List<Size> supported = CameraPictureSizesCacher.getSizesForCamera(camera, context);
    334             if (supported != null) {
    335                 Size size = SettingsUtil.getPhotoSize(pictureSize, supported, camera);
    336                 settingsManager.set(SettingsManager.SCOPE_GLOBAL, key,
    337                         SettingsUtil.sizeToSettingString(size));
    338             }
    339         }
    340     }
    341 
    342     /**
    343      * Part of the AOSP upgrade path, copies all of the keys and values in a
    344      * SharedPreferences file to another SharedPreferences file, as Strings.
    345      * Settings that are not a known supported format (int/boolean/String)
    346      * are dropped with warning.
    347      *
    348      * This will normally be run only once but was used both for upgrade version
    349      * 4 and 6 -- in 6 we repair issues with previous runs of the upgrader. So
    350      * we make sure to remove entries from destination if the source isn't valid
    351      * like a null or unsupported type.
    352      */
    353     private void copyPreferences(SharedPreferences oldPrefs,
    354             SharedPreferences newPrefs) {
    355         Map<String, ?> entries = oldPrefs.getAll();
    356         for (Map.Entry<String, ?> entry : entries.entrySet()) {
    357             String key = entry.getKey();
    358             Object value = entry.getValue();
    359             if (value == null) {
    360                 Log.w(TAG, "skipped upgrade and removing entry for null key " + key);
    361                 newPrefs.edit().remove(key).apply();
    362             } else if (value instanceof Boolean) {
    363                 String boolValue = SettingsManager.convert((Boolean) value);
    364                 newPrefs.edit().putString(key, boolValue).apply();
    365             } else if (value instanceof Integer) {
    366                 String intValue = SettingsManager.convert((Integer) value);
    367                 newPrefs.edit().putString(key, intValue).apply();
    368             } else if (value instanceof Long){
    369                 // New SettingsManager only supports int values. Attempt to
    370                 // recover any longs which happen to be present if they are
    371                 // within int range.
    372                 long longValue = (Long) value;
    373                 if (longValue <= Integer.MAX_VALUE && longValue >= Integer.MIN_VALUE) {
    374                     String intValue = SettingsManager.convert((int) longValue);
    375                     newPrefs.edit().putString(key, intValue).apply();
    376                 } else {
    377                     Log.w(TAG, "skipped upgrade for out of bounds long key " +
    378                             key + " : " + longValue);
    379                 }
    380             } else if (value instanceof String){
    381                 newPrefs.edit().putString(key, (String) value).apply();
    382             } else {
    383                 Log.w(TAG,"skipped upgrade and removing entry for unrecognized "
    384                         + "key type " + key + " : " + value.getClass());
    385                 newPrefs.edit().remove(key).apply();
    386             }
    387         }
    388     }
    389 
    390     /**
    391      * Part of the AOSP upgrade path, copies all of the key and values in the
    392      * old camera SharedPreferences files to new files.
    393      */
    394     private void upgradeCameraSettingsFiles(SettingsManager settingsManager,
    395             Context context) {
    396         String[] cameraIds =
    397                 context.getResources().getStringArray(R.array.camera_id_entryvalues);
    398 
    399         for (int i = 0; i < cameraIds.length; i++) {
    400             SharedPreferences oldCameraPreferences =
    401                     settingsManager.openPreferences(
    402                             OLD_CAMERA_PREFERENCES_PREFIX + cameraIds[i]);
    403             SharedPreferences newCameraPreferences =
    404                     settingsManager.openPreferences(
    405                             SettingsManager.getCameraSettingScope(cameraIds[i]));
    406 
    407             copyPreferences(oldCameraPreferences, newCameraPreferences);
    408         }
    409     }
    410 
    411     private void upgradeModuleSettingsFiles(SettingsManager settingsManager,
    412             Context context, AppController app) {
    413         int[] moduleIds = context.getResources().getIntArray(R.array.camera_modes);
    414 
    415         for (int i = 0; i < moduleIds.length; i++) {
    416             String moduleId = Integer.toString(moduleIds[i]);
    417             SharedPreferences oldModulePreferences =
    418                     settingsManager.openPreferences(
    419                             OLD_MODULE_PREFERENCES_PREFIX + moduleId);
    420 
    421             if (oldModulePreferences != null && oldModulePreferences.getAll().size() > 0) {
    422                 ModuleManagerImpl.ModuleAgent agent =
    423                         app.getModuleManager().getModuleAgent(moduleIds[i]);
    424                 if (agent != null) {
    425                     SharedPreferences newModulePreferences = settingsManager.openPreferences(
    426                             SettingsManager.getModuleSettingScope(agent.getScopeNamespace()));
    427 
    428                     copyPreferences(oldModulePreferences, newModulePreferences);
    429                 }
    430             }
    431         }
    432     }
    433 
    434     /**
    435      * The R.integer.camera_mode_* indices were cleaned up, resulting in
    436      * removals and renaming of certain values. In particular camera_mode_gcam
    437      * is now 5, not 6. We modify any persisted user settings that may refer to
    438      * the old value.
    439      */
    440     private void upgradeSelectedModeIndex(SettingsManager settingsManager, Context context) {
    441         int oldGcamIndex = 6; // from hardcoded previous mode index resource
    442         int gcamIndex = context.getResources().getInteger(R.integer.camera_mode_gcam);
    443 
    444         int lastUsedCameraIndex = settingsManager.getInteger(SettingsManager.SCOPE_GLOBAL,
    445                 Keys.KEY_CAMERA_MODULE_LAST_USED);
    446         if (lastUsedCameraIndex == oldGcamIndex) {
    447             settingsManager.set(SettingsManager.SCOPE_GLOBAL, Keys.KEY_CAMERA_MODULE_LAST_USED,
    448                     gcamIndex);
    449         }
    450 
    451         int startupModuleIndex = settingsManager.getInteger(SettingsManager.SCOPE_GLOBAL,
    452                 Keys.KEY_STARTUP_MODULE_INDEX);
    453         if (startupModuleIndex == oldGcamIndex) {
    454             settingsManager.set(SettingsManager.SCOPE_GLOBAL, Keys.KEY_STARTUP_MODULE_INDEX,
    455                     gcamIndex);
    456         }
    457     }
    458 
    459     /**
    460      * A targeted fix for b/19693226.
    461      * <p>
    462      * Since the N5 doesn't natively support a high resolution 16:9 size we need
    463      * to artificially add it and then crop the result from the high-resolution
    464      * 4:3 size. In version 2.4 we unfortunately swapped the dimensions of
    465      * ResolutionUtil#NEXUS_5_LARGE_16_BY_9_SIZE, which now causes a few issues
    466      * in 2.5. If we detect this case, we will swap the dimensions here to make
    467      * sure they are the right way around going forward.
    468      */
    469     private void updateN516by9ResolutionIfNeeded(SettingsManager settingsManager) {
    470         if (!ApiHelper.IS_NEXUS_5) {
    471             return;
    472         }
    473 
    474         String pictureSize = settingsManager.getString(SettingsManager.SCOPE_GLOBAL,
    475                 Keys.KEY_PICTURE_SIZE_BACK);
    476         if ("1836x3264".equals(pictureSize)) {
    477             Log.i(TAG, "Swapped dimensions on N5 16:9 resolution.");
    478             settingsManager.set(SettingsManager.SCOPE_GLOBAL, Keys.KEY_PICTURE_SIZE_BACK,
    479                     "3264x1836");
    480         }
    481     }
    482 }
    483