diff --git a/cameraview/src/main/java/com/otaliastudios/cameraview/AspectRatio.java b/cameraview/src/main/java/com/otaliastudios/cameraview/AspectRatio.java index 3d94e376..cf054d04 100644 --- a/cameraview/src/main/java/com/otaliastudios/cameraview/AspectRatio.java +++ b/cameraview/src/main/java/com/otaliastudios/cameraview/AspectRatio.java @@ -7,10 +7,50 @@ import android.util.SparseArray; import java.util.HashMap; + +/** + * A simple class representing an aspect ratio. + */ public class AspectRatio implements Comparable { final static HashMap sCache = new HashMap<>(16); + /** + * Creates an aspect ratio with the given values. + * @param x the width + * @param y the height + * @return a (possibly cached) aspect ratio + */ + public static AspectRatio of(int x, int y) { + int gcd = gcd(x, y); + x /= gcd; + y /= gcd; + String key = x + ":" + y; + AspectRatio cached = sCache.get(key); + if (cached == null) { + cached = new AspectRatio(x, y); + sCache.put(key, cached); + } + return cached; + } + + /** + * Parses an aspect ratio string, for example those previously obtained + * with {@link #toString()}. + * + * @param string a string of the format x:y where x and y are integers + * @return a (possibly cached) aspect ratio + */ + public static AspectRatio parse(@NonNull String string) { + String[] parts = string.split(":"); + if (parts.length != 2) { + throw new NumberFormatException("Illegal AspectRatio string. Must be x:y"); + } + int x = Integer.valueOf(parts[0]); + int y = Integer.valueOf(parts[1]); + return of(x, y); + } + private final int mX; private final int mY; @@ -78,19 +118,6 @@ public class AspectRatio implements Comparable { return AspectRatio.of(mY, mX); } - public static AspectRatio of(int x, int y) { - int gcd = gcd(x, y); - x /= gcd; - y /= gcd; - String key = x + ":" + y; - AspectRatio cached = sCache.get(key); - if (cached == null) { - cached = new AspectRatio(x, y); - sCache.put(key, cached); - } - return cached; - } - private static int gcd(int a, int b) { while (b != 0) { int c = b; diff --git a/cameraview/src/main/java/com/otaliastudios/cameraview/CameraView.java b/cameraview/src/main/java/com/otaliastudios/cameraview/CameraView.java index d13c2355..6e611d80 100644 --- a/cameraview/src/main/java/com/otaliastudios/cameraview/CameraView.java +++ b/cameraview/src/main/java/com/otaliastudios/cameraview/CameraView.java @@ -92,6 +92,7 @@ public class CameraView extends FrameLayout { private void init(@NonNull Context context, @Nullable AttributeSet attrs) { setWillNotDraw(false); TypedArray a = context.getTheme().obtainStyledAttributes(attrs, R.styleable.CameraView, 0, 0); + // Self managed int jpegQuality = a.getInteger(R.styleable.CameraView_cameraJpegQuality, DEFAULT_JPEG_QUALITY); boolean cropOutput = a.getBoolean(R.styleable.CameraView_cameraCropOutput, DEFAULT_CROP_OUTPUT); @@ -107,6 +108,36 @@ public class CameraView extends FrameLayout { Hdr hdr = Hdr.fromValue(a.getInteger(R.styleable.CameraView_cameraHdr, Hdr.DEFAULT.value())); Audio audio = Audio.fromValue(a.getInteger(R.styleable.CameraView_cameraAudio, Audio.DEFAULT.value())); + // Size selectors + List constraints = new ArrayList<>(3); + if (a.hasValue(R.styleable.CameraView_cameraPictureSizeMinWidth)) { + constraints.add(SizeSelectors.minWidth(a.getInteger(R.styleable.CameraView_cameraPictureSizeMinWidth, 0))); + } + if (a.hasValue(R.styleable.CameraView_cameraPictureSizeMaxWidth)) { + constraints.add(SizeSelectors.maxWidth(a.getInteger(R.styleable.CameraView_cameraPictureSizeMaxWidth, 0))); + } + if (a.hasValue(R.styleable.CameraView_cameraPictureSizeMinHeight)) { + constraints.add(SizeSelectors.minHeight(a.getInteger(R.styleable.CameraView_cameraPictureSizeMinHeight, 0))); + } + if (a.hasValue(R.styleable.CameraView_cameraPictureSizeMaxHeight)) { + constraints.add(SizeSelectors.maxHeight(a.getInteger(R.styleable.CameraView_cameraPictureSizeMaxHeight, 0))); + } + if (a.hasValue(R.styleable.CameraView_cameraPictureSizeMinArea)) { + constraints.add(SizeSelectors.minArea(a.getInteger(R.styleable.CameraView_cameraPictureSizeMinArea, 0))); + } + if (a.hasValue(R.styleable.CameraView_cameraPictureSizeMaxArea)) { + constraints.add(SizeSelectors.maxArea(a.getInteger(R.styleable.CameraView_cameraPictureSizeMaxArea, 0))); + } + if (a.hasValue(R.styleable.CameraView_cameraPictureSizeAspectRatio)) { + //noinspection ConstantConditions + constraints.add(SizeSelectors.aspectRatio(AspectRatio.parse(a.getString(R.styleable.CameraView_cameraPictureSizeAspectRatio)), 0)); + } + if (a.getBoolean(R.styleable.CameraView_cameraPictureSizeMin, false)) constraints.add(SizeSelectors.min()); + if (a.getBoolean(R.styleable.CameraView_cameraPictureSizeMax, false)) constraints.add(SizeSelectors.max()); + SizeSelector selector = !constraints.isEmpty() ? + SizeSelectors.and(constraints.toArray(new SizeSelector[constraints.size()])) : + SizeSelectors.max(); + // Gestures GestureAction tapGesture = GestureAction.fromValue(a.getInteger(R.styleable.CameraView_cameraGestureTap, GestureAction.DEFAULT_TAP.value())); GestureAction longTapGesture = GestureAction.fromValue(a.getInteger(R.styleable.CameraView_cameraGestureLongTap, GestureAction.DEFAULT_LONG_TAP.value())); @@ -146,8 +177,7 @@ public class CameraView extends FrameLayout { setGrid(grid); setHdr(hdr); setAudio(audio); - // TODO: add from XML - setPictureSize(SizeSelectors.max()); + setPictureSize(selector); // Apply gestures mapGesture(Gesture.TAP, tapGesture); @@ -516,8 +546,8 @@ public class CameraView extends FrameLayout { /** * Checks that we have appropriate permissions for this session type. * Throws if session = audio and manifest did not add the microphone permissions. - * @param sessionType - * @param audio + * @param sessionType the sessionType to be checked + * @param audio the audio setting to be checked * @return true if we can go on, false otherwise. */ @SuppressLint("NewApi") @@ -849,33 +879,6 @@ public class CameraView extends FrameLayout { } - /** - * Toggles the flash mode between {@link Flash#OFF}, - * {@link Flash#ON} and {@link Flash#AUTO}, in this order. - * - * @return the new flash value - */ - public Flash toggleFlash() { - Flash flash = mCameraController.getFlash(); - switch (flash) { - case OFF: - setFlash(Flash.ON); - break; - - case ON: - setFlash(Flash.AUTO); - break; - - case AUTO: - case TORCH: - setFlash(Flash.OFF); - break; - } - - return mCameraController.getFlash(); - } - - /** * Controls the audio mode. * @@ -1638,6 +1641,10 @@ public class CameraView extends FrameLayout { } } + //endregion + + //region deprecated APIs + /** * @deprecated use {@link #getPictureSize()} instead. */ @@ -1647,5 +1654,25 @@ public class CameraView extends FrameLayout { return getPictureSize(); } + /** + * Toggles the flash mode between {@link Flash#OFF}, + * {@link Flash#ON} and {@link Flash#AUTO}, in this order. + * + * @deprecated Don't use this. Flash values might not be supported, + * and the return value is unreliable. + * + * @return the new flash value + */ + @Deprecated + public Flash toggleFlash() { + Flash flash = mCameraController.getFlash(); + switch (flash) { + case OFF: setFlash(Flash.ON); break; + case ON: setFlash(Flash.AUTO); break; + case AUTO: case TORCH: setFlash(Flash.OFF); break; + } + return mCameraController.getFlash(); + } + //endregion } diff --git a/cameraview/src/main/res/values/attrs.xml b/cameraview/src/main/res/values/attrs.xml index e75d0fa1..f486f234 100644 --- a/cameraview/src/main/res/values/attrs.xml +++ b/cameraview/src/main/res/values/attrs.xml @@ -1,12 +1,24 @@ - + + + + + + + + + + + + + + + + + +