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