diff --git a/camerakit/build.gradle b/camerakit/build.gradle index ee7ff74b..8133fe07 100644 --- a/camerakit/build.gradle +++ b/camerakit/build.gradle @@ -11,7 +11,7 @@ android { buildToolsVersion "25.0.2" defaultConfig { - minSdkVersion 19 + minSdkVersion 16 targetSdkVersion 25 versionCode 1 versionName "1.0" diff --git a/camerakit/src/main/api16/com/flurgle/camerakit/ConstantMapper.java b/camerakit/src/main/api16/com/flurgle/camerakit/ConstantMapper.java index 51dbcbb7..4e73e7c8 100644 --- a/camerakit/src/main/api16/com/flurgle/camerakit/ConstantMapper.java +++ b/camerakit/src/main/api16/com/flurgle/camerakit/ConstantMapper.java @@ -1,7 +1,10 @@ package com.flurgle.camerakit; +import android.annotation.TargetApi; import android.hardware.Camera; +import android.hardware.camera2.CameraCharacteristics; import android.support.v4.util.SparseArrayCompat; +import android.util.SparseIntArray; public class ConstantMapper { @@ -17,7 +20,7 @@ public class ConstantMapper { } - public static class Flash extends BaseMapper { + static class Flash extends BaseMapper { private static final SparseArrayCompat FLASH_MODES = new SparseArrayCompat<>(); @@ -38,7 +41,21 @@ public class ConstantMapper { } - public static class Facing extends BaseMapper { + @TargetApi(21) + static class Flash2 extends BaseMapper { + + protected Flash2(int cameraKitConstant) { + super(cameraKitConstant); + } + + @Override + String map() { + return null; + } + + } + + static class Facing extends BaseMapper { private static final SparseArrayCompat FACING_MODES = new SparseArrayCompat<>(); @@ -53,7 +70,28 @@ public class ConstantMapper { @Override Integer map() { - return FACING_MODES.get(mCameraKitConstant, FACING_MODES.get(Camera.CameraInfo.CAMERA_FACING_BACK)); + return FACING_MODES.get(mCameraKitConstant, FACING_MODES.get(CameraKit.Constants.FACING_BACK)); + } + + } + + @TargetApi(21) + static class Facing2 extends BaseMapper { + + private static final SparseIntArray FACING_MODES = new SparseIntArray(); + + static { + FACING_MODES.put(CameraKit.Constants.FACING_BACK, CameraCharacteristics.LENS_FACING_BACK); + FACING_MODES.put(CameraKit.Constants.FACING_FRONT, CameraCharacteristics.LENS_FACING_FRONT); + } + + protected Facing2(int cameraKitConstant) { + super(cameraKitConstant); + } + + @Override + Integer map() { + return FACING_MODES.get(mCameraKitConstant, FACING_MODES.get(CameraKit.Constants.FACING_BACK)); } } diff --git a/camerakit/src/main/api21/com/flurgle/camerakit/Camera2.java b/camerakit/src/main/api21/com/flurgle/camerakit/Camera2.java index 419852f4..34e3e4ea 100644 --- a/camerakit/src/main/api21/com/flurgle/camerakit/Camera2.java +++ b/camerakit/src/main/api21/com/flurgle/camerakit/Camera2.java @@ -1,11 +1,47 @@ package com.flurgle.camerakit; +import android.annotation.TargetApi; +import android.content.Context; +import android.graphics.ImageFormat; +import android.hardware.camera2.CameraAccessException; +import android.hardware.camera2.CameraCharacteristics; +import android.hardware.camera2.CameraDevice; +import android.hardware.camera2.CameraManager; +import android.hardware.camera2.params.StreamConfigurationMap; +import android.util.Log; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.TreeSet; + +@TargetApi(21) class Camera2 extends CameraImpl { - Camera2(CameraListener callback, PreviewImpl preview) { + private CameraDevice mCamera; + private CameraCharacteristics mCameraCharacteristics; + private CameraManager mCameraManager; + + private String mCameraId; + private int mFacing; + + private Size mCaptureSize; + private Size mPreviewSize; + + Camera2(CameraListener callback, PreviewImpl preview, Context context) { super(callback, preview); + preview.setCallback(new PreviewImpl.Callback() { + @Override + public void onSurfaceChanged() { + + } + }); + + mCameraManager = (CameraManager) context.getSystemService(Context.CAMERA_SERVICE); } + // CameraImpl: + @Override void start() { @@ -23,7 +59,44 @@ class Camera2 extends CameraImpl { @Override void setFacing(@Facing int facing) { - + int internalFacing = new ConstantMapper.Facing(facing).map(); + if (internalFacing == -1) { + return; + } + + final String[] ids; + try { + ids = mCameraManager.getCameraIdList(); + } catch (CameraAccessException e) { + Log.e("CameraKit", e.toString()); + return; + } + + if (ids.length == 0) { + throw new RuntimeException("No camera available."); + } +// +// for (String id : ids) { +// CameraCharacteristics cameraCharacteristics = mCameraManager.getCameraCharacteristics(id); +// Integer level = cameraCharacteristics.get(CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL); +// if (level == null || level == CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_LEGACY) { +// continue; +// } +// Integer internal = cameraCharacteristics.get(CameraCharacteristics.LENS_FACING); +// if (internal == null) { +// throw new NullPointerException("Unexpected state: LENS_FACING null"); +// } +// if (internal == internalFacing) { +// mCameraId = id; +// mCameraCharacteristics = cameraCharacteristics; +// return true; +// } +// } + + if (mFacing == facing && isCameraOpened()) { + stop(); + start(); + } } @Override @@ -63,17 +136,95 @@ class Camera2 extends CameraImpl { @Override Size getCaptureResolution() { - return null; + if (mCaptureSize == null && mCameraCharacteristics != null) { + TreeSet sizes = new TreeSet<>(); + sizes.addAll(getAvailableCaptureResolutions()); + + TreeSet aspectRatios = new CommonAspectRatioFilter( + getAvailablePreviewResolutions(), + getAvailableCaptureResolutions() + ).filter(); + AspectRatio targetRatio = aspectRatios.size() > 0 ? aspectRatios.last() : null; + + Iterator descendingSizes = sizes.descendingIterator(); + Size size; + while (descendingSizes.hasNext() && mCaptureSize == null) { + size = descendingSizes.next(); + if (targetRatio == null || targetRatio.matches(size)) { + mCaptureSize = size; + break; + } + } + } + + return mCaptureSize; } @Override Size getPreviewResolution() { - return null; + if (mPreviewSize == null && mCameraCharacteristics != null) { + TreeSet sizes = new TreeSet<>(); + sizes.addAll(getAvailablePreviewResolutions()); + + TreeSet aspectRatios = new CommonAspectRatioFilter( + getAvailablePreviewResolutions(), + getAvailableCaptureResolutions() + ).filter(); + AspectRatio targetRatio = aspectRatios.size() > 0 ? aspectRatios.last() : null; + + Iterator descendingSizes = sizes.descendingIterator(); + Size size; + while (descendingSizes.hasNext() && mPreviewSize == null) { + size = descendingSizes.next(); + if (targetRatio == null || targetRatio.matches(size)) { + mPreviewSize = size; + break; + } + } + } + + return mPreviewSize; } @Override boolean isCameraOpened() { - return false; + return mCamera != null; + } + + // Internal + + private List getAvailableCaptureResolutions() { + List output = new ArrayList<>(); + + if (mCameraCharacteristics != null) { + StreamConfigurationMap map = mCameraCharacteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP); + if (map == null) { + throw new IllegalStateException("Failed to get configuration map: " + mCameraId); + } + + for (android.util.Size size : map.getOutputSizes(ImageFormat.JPEG)) { + output.add(new Size(size.getWidth(), size.getHeight())); + } + } + + return output; + } + + private List getAvailablePreviewResolutions() { + List output = new ArrayList<>(); + + if (mCameraCharacteristics != null) { + StreamConfigurationMap map = mCameraCharacteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP); + if (map == null) { + throw new IllegalStateException("Failed to get configuration map: " + mCameraId); + } + + for (android.util.Size size : map.getOutputSizes(mPreview.getOutputClass())) { + output.add(new Size(size.getWidth(), size.getHeight())); + } + } + + return output; } } diff --git a/camerakit/src/main/utils/com/flurgle/camerakit/CommonAspectRatioFilter.java b/camerakit/src/main/utils/com/flurgle/camerakit/CommonAspectRatioFilter.java new file mode 100644 index 00000000..b0cc9d21 --- /dev/null +++ b/camerakit/src/main/utils/com/flurgle/camerakit/CommonAspectRatioFilter.java @@ -0,0 +1,41 @@ +package com.flurgle.camerakit; + +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.TreeSet; + +public class CommonAspectRatioFilter { + + private List mPreviewSizes; + private List mCaptureSizes; + + public CommonAspectRatioFilter(List previewSizes, List captureSizes) { + this.mPreviewSizes = previewSizes; + this.mCaptureSizes = captureSizes; + } + + public TreeSet filter() { + Set previewAspectRatios = new HashSet<>(); + for (Size size : mPreviewSizes) { + if (size.getWidth() >= CameraKit.Internal.screenHeight && size.getHeight() >= CameraKit.Internal.screenWidth) { + previewAspectRatios.add(AspectRatio.of(size.getWidth(), size.getHeight())); + } + } + + Set captureAspectRatios = new HashSet<>(); + for (Size size : mCaptureSizes) { + captureAspectRatios.add(AspectRatio.of(size.getWidth(), size.getHeight())); + } + + TreeSet output = new TreeSet<>(); + for (AspectRatio aspectRatio : previewAspectRatios) { + if (captureAspectRatios.contains(aspectRatio)) { + output.add(aspectRatio); + } + } + + return output; + } + +} diff --git a/demo/build.gradle b/demo/build.gradle index da4c5de3..dc9a7a0c 100644 --- a/demo/build.gradle +++ b/demo/build.gradle @@ -5,7 +5,7 @@ android { buildToolsVersion "25.0.2" defaultConfig { applicationId "com.flurgle.camerakit.demo" - minSdkVersion 19 + minSdkVersion 16 targetSdkVersion 25 versionCode 2 versionName "1.0.1"