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