summaryrefslogtreecommitdiffstats
path: root/src/com/android/camera/CameraSettings.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/com/android/camera/CameraSettings.java')
-rw-r--r--src/com/android/camera/CameraSettings.java226
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()]));
+ }
}