diff options
Diffstat (limited to 'src/com/android/camera/CameraSettings.java')
-rw-r--r-- | src/com/android/camera/CameraSettings.java | 226 |
1 files changed, 208 insertions, 18 deletions
diff --git a/src/com/android/camera/CameraSettings.java b/src/com/android/camera/CameraSettings.java index 86d84ac6c..85faf0758 100644 --- a/src/com/android/camera/CameraSettings.java +++ b/src/com/android/camera/CameraSettings.java @@ -34,9 +34,12 @@ import android.util.Log; import com.android.camera.util.ApiHelper; import com.android.camera.util.CameraUtil; import com.android.camera.util.GcamHelper; +import com.android.camera.util.MultiMap; + import org.codeaurora.snapcam.R; import java.util.ArrayList; +import java.util.Collections; import java.util.List; import java.util.Locale; import java.util.HashMap; @@ -403,26 +406,41 @@ public class CameraSettings { return supported.get(0); } - public static void initialCameraPictureSize( - Context context, Parameters parameters) { - // When launching the camera app first time, we will set the picture - // size to the first one in the list defined in "arrays.xml" and is also - // supported by the driver. + public static void initialCameraPictureSize(Context context, Parameters parameters) { + // set the picture size to the largest supported size List<Size> supported = parameters.getSupportedPictureSizes(); - if (supported == null) return; - for (String candidate : context.getResources().getStringArray( - R.array.pref_camera_picturesize_entryvalues)) { - if (setCameraPictureSize(candidate, supported, parameters)) { - SharedPreferences.Editor editor = ComboPreferences - .get(context).edit(); - editor.putString(KEY_PICTURE_SIZE, candidate); - editor.apply(); - return; - } + if (supported == null || supported.isEmpty()) { return; } + Size largest = getLargestSize(supported); + String candidate = largest.width + "x" + largest.height; + if (setCameraPictureSize(candidate, supported, parameters)) { + SharedPreferences.Editor editor = + ComboPreferences.get(context).edit(); + editor.putString(KEY_PICTURE_SIZE, candidate); + editor.apply(); + return; } Log.e(TAG, "No supported picture size found"); } + private static Size getLargestSize(List<Size> sizes) { + if (sizes == null || sizes.isEmpty()) { + return null; + } + + Size max = null; + int maxSize = -1; + + for (Size candidate : sizes) { + int candidateSize = candidate.width * candidate.height; + if (candidateSize > maxSize) { + maxSize = candidateSize; + max = candidate; + } + } + + return max; + } + public static void removePreferenceFromScreen( PreferenceGroup group, String key) { removePreference(group, key); @@ -922,9 +940,9 @@ public class CameraSettings { } if (pictureSize != null) { - filterUnsupportedOptions(group, pictureSize, sizeListToStringList( - mParameters.getSupportedPictureSizes())); - filterSimilarPictureSize(group, pictureSize); + formatPictureSizes(mContext, pictureSize, mParameters); + resetIfInvalid(pictureSize); + } if (whiteBalance != null) { filterUnsupportedOptions(group, @@ -1438,4 +1456,176 @@ public class CameraSettings { } return false; } + + // common aspect ratios used for bucketing camera picture sizes + private enum AspectRatio { + FourThree(1.27, 1.42, R.string.pref_camera_aspectratio_43), + ThreeTwo(1.42, 1.55, R.string.pref_camera_aspectratio_32), + SixteenTen(1.55, 1.63, R.string.pref_camera_aspectratio_1610), + FiveThree(1.63, 1.73, R.string.pref_camera_aspectratio_53), + SixteenNine(1.73, 1.81, R.string.pref_camera_aspectratio_169), + OneOne(0.95, 1.05, R.string.pref_camera_aspectratio_11), + Wide(1.81, Float.MAX_VALUE, R.string.pref_camera_aspectratio_wide), + Other(Float.MIN_VALUE, 1.27, 0); + + public double min; + public double max; + public int resourceId; + + AspectRatio(double min, double max, int rid) { + this.min = min; + this.max = max; + this.resourceId = rid; + } + + boolean contains(double ratio) { + return ratio >= min && ratio < max; + } + + static AspectRatio of(int width, int height) { + double ratio = (double) width / height; + for (AspectRatio aspect : values()) { + if (aspect.contains(ratio)) { + return aspect; + } + } + return null; + } + } + + // track a camera picture size along with some derived info + private static class SizeEntry implements Comparable<SizeEntry> { + AspectRatio ratio; + Size size; + int pixels; + + SizeEntry(Size size) { + this.ratio = AspectRatio.of(size.width, size.height); + this.size = size; + this.pixels = size.width * size.height; + } + + @Override + public int compareTo(SizeEntry another) { + return another.pixels - pixels; + } + + String resolution() { + return size.width + "x" + size.height; + } + + String formatted(Context context) { + double pixelCount = pixels / 1000000d; // compute megapixels + + if (pixelCount > 1.9 && pixelCount < 2.0) { //conventional rounding + pixelCount = 2.0; + } + + pixelCount = adjustForLocale(pixelCount); // some locales group differently + if (pixelCount > 0.1) { + String ratioString = ratio.resourceId == 0 + ? resolution() : context.getString(ratio.resourceId); + return context.getString(R.string.pref_camera_megapixel_format, + ratioString, pixelCount); + } else { + // for super tiny stuff, just give the raw resolution + return resolution(); + } + } + + private static final String KOREAN = Locale.KOREAN.getLanguage(); + private static final String CHINESE = Locale.CHINESE.getLanguage(); + + private double adjustForLocale(double megapixels) { + Locale locale = Locale.getDefault(); + String language = locale != null ? locale.getLanguage() : null; + + // Chinese and Korean locales prefer to count by ten thousands + // instead of by millions - so we multiply the megapixels by 100 + // (with a little rounding on the way) + if (KOREAN.equals(language) || CHINESE.equals(language)) { + megapixels = Math.round(megapixels * 10); + return megapixels * 10; // wàn + } + return megapixels; + } + } + + private static void formatPictureSizes(Context context, + ListPreference pictureSize, Parameters parameters) { + List<Size> supported = parameters.getSupportedPictureSizes(); + if (supported == null || supported.isEmpty()) { + return; + } + + // convert list of sizes to list of "size entries" + List<SizeEntry> sizes = new ArrayList<SizeEntry>(supported.size()); + for (Size candidate : supported) { + sizes.add(new SizeEntry(candidate)); + } + + // sort descending by pixel size + Collections.sort(sizes); + + // trim really small sizes but never leave less than six choices + int minimum = context.getResources().getInteger(R.integer.minimum_picture_size); + while (sizes.size() > 6) { + int lastIndex = sizes.size() - 1; + SizeEntry last = sizes.get(lastIndex); + if (last.pixels < minimum) { + sizes.remove(lastIndex); + } else { + break; + } + } + + // re-sort into aspect ratio buckets + MultiMap<AspectRatio,SizeEntry> buckets = new MultiMap<>(); + for (SizeEntry size : sizes) { + buckets.put(size.ratio, size); + } + + // build the final lists - group by aspect ratio, with those + // buckets having the largest image sizes positioned first + List<String> entries = new ArrayList<String>(buckets.size()); + List<String> entryValues = new ArrayList<String>(buckets.size()); + while (!buckets.isEmpty()) { + // find the bucket with the largest first element + int maxSize = 0; + AspectRatio chosenKey = null; + for (AspectRatio ratio : buckets.keySet()) { + int size = buckets.get(ratio).get(0).pixels; + if (size > maxSize) { + maxSize = size; + chosenKey = ratio; + } + } + + List<SizeEntry> bucket = buckets.remove(chosenKey); + + // trim chosen bucket of similarly sized entries, but + // never leave less that three + int index = 0; + while (bucket.size() > 3 && bucket.size() > index + 1) { + SizeEntry current = bucket.get(index); + SizeEntry next = bucket.get(index + 1); + // if the two buckets differ in size by less than 30% + // remove the smaller one, otherwise advance through the list + if ((double) current.pixels / next.pixels < 1.3) { + bucket.remove(index + 1); + } else { + index++; + } + } + + // transfer chosen, trimmed bucket to final list + for (SizeEntry size : bucket) { + entryValues.add(size.resolution()); + entries.add(size.formatted(context)); + } + } + + pictureSize.setEntries(entries.toArray(new String[entries.size()])); + pictureSize.setEntryValues(entryValues.toArray(new String[entryValues.size()])); + } } |