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