1 /* 2 * Copyright (C) 2015 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.ContentResolver; 20 import android.graphics.ImageFormat; 21 22 import com.android.camera.debug.Log; 23 import com.android.camera.device.CameraId; 24 import com.android.camera.exif.Rational; 25 import com.android.camera.one.OneCamera; 26 import com.android.camera.one.OneCamera.Facing; 27 import com.android.camera.one.OneCameraAccessException; 28 import com.android.camera.one.OneCameraCharacteristics; 29 import com.android.camera.one.OneCameraManager; 30 import com.android.camera.util.GservicesHelper; 31 import com.android.camera.util.Size; 32 33 import com.google.common.base.Preconditions; 34 35 import java.util.List; 36 37 /** 38 * Handles the picture resolution setting stored in SharedPreferences keyed by 39 * Keys.KEY_PICTURE_SIZE_BACK and Keys.KEY_PICTURE_SIZE_FRONT. 40 */ 41 public class ResolutionSetting { 42 private static final Log.Tag TAG = new Log.Tag("ResolutionSettings"); 43 44 private final SettingsManager mSettingsManager; 45 private final OneCameraManager mOneCameraManager; 46 private final String mResolutionDisallowedListBack; 47 private final String mResolutionDisallowedListFront; 48 ResolutionSetting(SettingsManager settingsManager, OneCameraManager oneCameraManager, ContentResolver contentResolver)49 public ResolutionSetting(SettingsManager settingsManager, 50 OneCameraManager oneCameraManager, 51 ContentResolver contentResolver) { 52 mSettingsManager = settingsManager; 53 mOneCameraManager = oneCameraManager; 54 55 mResolutionDisallowedListBack = GservicesHelper.getDisallowedlistedResolutionsBack( 56 contentResolver); 57 mResolutionDisallowedListFront = GservicesHelper.getDisallowedlistedResolutionsFront( 58 contentResolver); 59 } 60 61 /** 62 * Changes the picture size settings for the cameras with specified facing. 63 * Pick the largest picture size with the specified aspect ratio. 64 * 65 * @param cameraId The specific camera device. 66 * @param aspectRatio The chosen aspect ratio. 67 */ setPictureAspectRatio(CameraId cameraId, Rational aspectRatio)68 public void setPictureAspectRatio(CameraId cameraId, Rational aspectRatio) 69 throws OneCameraAccessException { 70 OneCameraCharacteristics cameraCharacteristics = 71 mOneCameraManager.getOneCameraCharacteristics(cameraId); 72 73 Facing cameraFacing = cameraCharacteristics.getCameraDirection(); 74 75 // Pick the largest picture size with the selected aspect ratio and save 76 // the choice for front camera. 77 final String pictureSizeSettingKey = cameraFacing == OneCamera.Facing.FRONT ? 78 Keys.KEY_PICTURE_SIZE_FRONT : Keys.KEY_PICTURE_SIZE_BACK; 79 final String disallowedlist = cameraFacing == OneCamera.Facing.FRONT ? 80 mResolutionDisallowedListFront : mResolutionDisallowedListBack; 81 82 // All resolutions supported by the camera. 83 List<Size> supportedPictureSizes = cameraCharacteristics 84 .getSupportedPictureSizes(ImageFormat.JPEG); 85 86 // Filter sizes which we are showing to the user in settings. 87 // This might also add some new resolution we support on some devices 88 // non-natively. 89 supportedPictureSizes = ResolutionUtil.getDisplayableSizesFromSupported( 90 supportedPictureSizes, cameraFacing == OneCamera.Facing.BACK); 91 92 // Filter the remaining sizes through our backlist. 93 supportedPictureSizes = ResolutionUtil.filterDisallowedListedSizes(supportedPictureSizes, 94 disallowedlist); 95 96 final Size chosenPictureSize = 97 ResolutionUtil.getLargestPictureSize(aspectRatio, supportedPictureSizes); 98 mSettingsManager.set( 99 SettingsManager.SCOPE_GLOBAL, 100 pictureSizeSettingKey, 101 SettingsUtil.sizeToSettingString(chosenPictureSize)); 102 } 103 104 /** 105 * Reads the picture size setting for the cameras with specified facing. 106 * This specifically avoids reading camera characteristics unless the size 107 * is disallowedlisted or is not cached to prevent a crash. 108 */ getPictureSize(CameraId cameraId, Facing cameraFacing)109 public Size getPictureSize(CameraId cameraId, Facing cameraFacing) 110 throws OneCameraAccessException { 111 final String pictureSizeSettingKey = cameraFacing == OneCamera.Facing.FRONT ? 112 Keys.KEY_PICTURE_SIZE_FRONT : Keys.KEY_PICTURE_SIZE_BACK; 113 114 Size pictureSize = null; 115 116 String disallowedlist = ""; 117 if (cameraFacing == OneCamera.Facing.BACK) { 118 disallowedlist = mResolutionDisallowedListBack; 119 } else if (cameraFacing == OneCamera.Facing.FRONT) { 120 disallowedlist = mResolutionDisallowedListFront; 121 } 122 123 // If there is no saved picture size preference or the saved on is 124 // disallowedlisted., pick a largest size with 4:3 aspect 125 boolean isPictureSizeSettingSet = 126 mSettingsManager.isSet(SettingsManager.SCOPE_GLOBAL, pictureSizeSettingKey); 127 boolean isPictureSizeDisallowedlisted = false; 128 129 // If a picture size is set, check whether it's disallowedlisted. 130 if (isPictureSizeSettingSet) { 131 pictureSize = SettingsUtil.sizeFromSettingString( 132 mSettingsManager.getString(SettingsManager.SCOPE_GLOBAL, 133 pictureSizeSettingKey)); 134 isPictureSizeDisallowedlisted = pictureSize == null || 135 ResolutionUtil.isDisallowedListed(pictureSize, disallowedlist); 136 } 137 138 // Due to b/21758681, it is possible that an invalid picture size has 139 // been saved to the settings. Therefore, picture size is set AND is not 140 // disallowedlisted, but completely invalid. In these cases, need to take the 141 // fallback, instead of the saved value. This logic should now save a 142 // valid picture size to the settings and self-correct the state of the 143 // settings. 144 final boolean isPictureSizeFromSettingsValid = pictureSize != null && 145 pictureSize.width() > 0 && pictureSize.height() > 0; 146 147 if (!isPictureSizeSettingSet || isPictureSizeDisallowedlisted || 148 !isPictureSizeFromSettingsValid) { 149 final Rational aspectRatio = ResolutionUtil.ASPECT_RATIO_4x3; 150 151 OneCameraCharacteristics cameraCharacteristics = 152 mOneCameraManager.getOneCameraCharacteristics(cameraId); 153 154 final List<Size> supportedPictureSizes = 155 ResolutionUtil.filterDisallowedListedSizes( 156 cameraCharacteristics.getSupportedPictureSizes(ImageFormat.JPEG), 157 disallowedlist); 158 final Size fallbackPictureSize = 159 ResolutionUtil.getLargestPictureSize(aspectRatio, supportedPictureSizes); 160 mSettingsManager.set( 161 SettingsManager.SCOPE_GLOBAL, 162 pictureSizeSettingKey, 163 SettingsUtil.sizeToSettingString(fallbackPictureSize)); 164 pictureSize = fallbackPictureSize; 165 Log.e(TAG, "Picture size setting is not set. Choose " + fallbackPictureSize); 166 // Crash here if invariants are violated 167 Preconditions.checkNotNull(fallbackPictureSize); 168 Preconditions.checkState(fallbackPictureSize.width() > 0 169 && fallbackPictureSize.height() > 0); 170 } 171 return pictureSize; 172 } 173 174 /** 175 * Obtains the preferred picture aspect ratio in terms of the picture size 176 * setting. 177 * 178 * @param cameraId The specific camera device. 179 * @return The preferred picture aspect ratio. 180 * @throws OneCameraAccessException 181 */ getPictureAspectRatio(CameraId cameraId, Facing facing)182 public Rational getPictureAspectRatio(CameraId cameraId, Facing facing) 183 throws OneCameraAccessException { 184 Size pictureSize = getPictureSize(cameraId, facing); 185 return new Rational(pictureSize.getWidth(), pictureSize.getHeight()); 186 } 187 } 188