diff options
Diffstat (limited to 'src/com/android/camera/CameraSettings.java')
-rw-r--r-- | src/com/android/camera/CameraSettings.java | 227 |
1 files changed, 208 insertions, 19 deletions
diff --git a/src/com/android/camera/CameraSettings.java b/src/com/android/camera/CameraSettings.java index 68ea125d2..a2cb896ed 100644 --- a/src/com/android/camera/CameraSettings.java +++ b/src/com/android/camera/CameraSettings.java @@ -40,11 +40,14 @@ import com.android.camera.util.ApiHelper; import com.android.camera.util.CameraUtil; import com.android.camera.util.GcamHelper; import com.android.camera.util.PersistUtil; +import com.android.camera.util.MultiMap; + import org.codeaurora.snapcam.R; import org.codeaurora.snapcam.wrapper.CamcorderProfileWrapper; import org.codeaurora.snapcam.wrapper.ParametersWrapper; import java.util.ArrayList; +import java.util.Collections; import java.util.List; import java.util.Locale; import android.os.Build; @@ -488,26 +491,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 = sizes.get(0); + int maxSize = max.width * max.height; + + 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); @@ -1097,10 +1115,12 @@ public class CameraSettings { } if (pictureSize != null) { - filterUnsupportedOptions(group, pictureSize, sizeListToStringList( - mParameters.getSupportedPictureSizes())); - filterSimilarPictureSize(group, pictureSize); + formatPictureSizes(pictureSize, + fromLegacySizes(mParameters.getSupportedPictureSizes()), mContext); + resetIfInvalid(pictureSize); + } + if (whiteBalance != null) { filterUnsupportedOptions(group, whiteBalance, mParameters.getSupportedWhiteBalance()); @@ -1311,7 +1331,7 @@ public class CameraSettings { return false; } - private static void resetIfInvalid(ListPreference pref) { + static void resetIfInvalid(ListPreference pref) { // Set the value to the first entry if it is invalid. String value = pref.getValue(); if (pref.findIndexOfValue(value) == NOT_FOUND) { @@ -1623,4 +1643,173 @@ public class CameraSettings { Log.d(TAG,"getSupportedDegreesOfBlur str =" +str); return split(str); } + + // 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; + android.util.Size size; + int pixels; + + SizeEntry(android.util.Size size) { + this.ratio = AspectRatio.of(size.getWidth(), size.getHeight()); + this.size = size; + this.pixels = size.getWidth() * size.getHeight(); + } + + @Override + public int compareTo(SizeEntry another) { + return another.pixels - pixels; + } + + String resolution() { return size.getWidth()+"x"+size.getHeight(); } + + String formatted(Context ctx) { + 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() : ctx.getString(ratio.resourceId); + return ctx.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(); + if (locale == null) { return megapixels; } + String language = locale.getLanguage(); + // 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; + } + } + + static List<android.util.Size> fromLegacySizes(List<Size> oldSizes) { + final List<android.util.Size> sizes = new ArrayList<>(); + if (oldSizes == null || oldSizes.size() == 0) { + return sizes; + } + for (Size oldSize : oldSizes) { + sizes.add(new android.util.Size(oldSize.width, oldSize.height)); + } + return sizes; + } + + static void formatPictureSizes( + ListPreference pictureSize, List<android.util.Size> supported, Context ctx) { + if (supported == null || supported.isEmpty()) { return; } + + // convert list of sizes to list of "size entries" + List<SizeEntry> sizes = new ArrayList<SizeEntry>(supported.size()); + for (android.util.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 = ctx.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<AspectRatio,SizeEntry>(); + 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(ctx)); + } + } + + pictureSize.setEntries(entries.toArray(new String[entries.size()])); + pictureSize.setEntryValues(entryValues.toArray(new String[entryValues.size()])); + } } |