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