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