Added public CameraOptions to understand what is supported and what's not

pull/1/head
Mattia Iavarone 7 years ago
parent ec3ffcbf4a
commit 033872d0a6
  1. 6
      README.md
  2. 107
      camerakit/src/main/api16/com/flurgle/camerakit/Camera1.java
  3. 74
      camerakit/src/main/api16/com/flurgle/camerakit/MapperImpl.java
  4. 29
      camerakit/src/main/api21/com/flurgle/camerakit/Camera2.java
  5. 4
      camerakit/src/main/base/com/flurgle/camerakit/CameraImpl.java
  6. 91
      camerakit/src/main/base/com/flurgle/camerakit/CameraOptions.java
  7. 34
      camerakit/src/main/base/com/flurgle/camerakit/ExtraProperties.java
  8. 2
      camerakit/src/main/java/com/flurgle/camerakit/CameraKit.java
  9. 11
      camerakit/src/main/java/com/flurgle/camerakit/CameraListener.java
  10. 20
      camerakit/src/main/java/com/flurgle/camerakit/CameraUtils.java
  11. 22
      camerakit/src/main/java/com/flurgle/camerakit/CameraView.java
  12. 2
      camerakit/src/main/res/values/attrs.xml
  13. 4
      camerakit/src/main/types/com/flurgle/camerakit/Focus.java

@ -165,7 +165,7 @@ Make sure you can react to different camera events by setting up a `CameraListen
camera.setCameraListener(new CameraListener() { camera.setCameraListener(new CameraListener() {
@Override @Override
public void onCameraOpened() {} public void onCameraOpened(CameraOptions options) {}
@Override @Override
public void onCameraClosed() {} public void onCameraClosed() {}
@ -250,7 +250,7 @@ This means that part of the preview is hidden, and the image output will contain
|[`cameraSessionType`](#camerasessiontype)|`setSessionType()`|`picture` `video`|`picture`| |[`cameraSessionType`](#camerasessiontype)|`setSessionType()`|`picture` `video`|`picture`|
|[`cameraFacing`](#camerafacing)|`setFacing()`|`back` `front`|`back`| |[`cameraFacing`](#camerafacing)|`setFacing()`|`back` `front`|`back`|
|[`cameraFlash`](#cameraflash)|`setFlash()`|`off` `on` `auto` `torch`|`off`| |[`cameraFlash`](#cameraflash)|`setFlash()`|`off` `on` `auto` `torch`|`off`|
|[`cameraFocus`](#camerafocus)|`setFocus()`|`off` `continuous` `tap` `tapWithMarker`|`continuous`| |[`cameraFocus`](#camerafocus)|`setFocus()`|`fixed` `continuous` `tap` `tapWithMarker`|`continuous`|
|[`cameraZoomMode`](#camerazoommode)|`setZoom()`|`off` `pinch`|`off`| |[`cameraZoomMode`](#camerazoommode)|`setZoom()`|`off` `pinch`|`off`|
|[`cameraGrid`](#cameragrid)|`setGrid()`|`off` `grid3x3` `grid4x4` `phi`|`off`| |[`cameraGrid`](#cameragrid)|`setGrid()`|`off` `grid3x3` `grid4x4` `phi`|`off`|
|[`cameraCropOutput`](#cameracropoutput)|`setCropOutput()`|`true` `false`|`false`| |[`cameraCropOutput`](#cameracropoutput)|`setCropOutput()`|`true` `false`|`false`|
@ -297,7 +297,7 @@ cameraView.setFlash(CameraKit.Constants.FLASH_TORCH);
Focus behavior. Can be off, continuous (camera continuously tries to adapt its focus), tap (focus is driven by the user tap) and tapWithMarker (a marker is drawn on screen to indicate focusing). Focus behavior. Can be off, continuous (camera continuously tries to adapt its focus), tap (focus is driven by the user tap) and tapWithMarker (a marker is drawn on screen to indicate focusing).
```java ```java
cameraView.setFocus(CameraKit.Constants.FOCUS_OFF); cameraView.setFocus(CameraKit.Constants.FOCUS_FIXED);
cameraView.setFocus(CameraKit.Constants.FOCUS_CONTINUOUS); cameraView.setFocus(CameraKit.Constants.FOCUS_CONTINUOUS);
cameraView.setFocus(CameraKit.Constants.FOCUS_TAP); cameraView.setFocus(CameraKit.Constants.FOCUS_TAP);
cameraView.setFocus(CameraKit.Constants.FOCUS_TAP_WITH_MARKER); cameraView.setFocus(CameraKit.Constants.FOCUS_TAP_WITH_MARKER);

@ -10,7 +10,6 @@ import android.os.Handler;
import android.support.annotation.NonNull; import android.support.annotation.NonNull;
import android.support.annotation.Nullable; import android.support.annotation.Nullable;
import android.util.Log; import android.util.Log;
import android.view.MotionEvent;
import android.view.SurfaceHolder; import android.view.SurfaceHolder;
import java.io.File; import java.io.File;
@ -20,7 +19,7 @@ import java.util.Collections;
import java.util.List; import java.util.List;
import static com.flurgle.camerakit.CameraKit.Constants.FOCUS_CONTINUOUS; import static com.flurgle.camerakit.CameraKit.Constants.FOCUS_CONTINUOUS;
import static com.flurgle.camerakit.CameraKit.Constants.FOCUS_OFF; import static com.flurgle.camerakit.CameraKit.Constants.FOCUS_FIXED;
import static com.flurgle.camerakit.CameraKit.Constants.FOCUS_TAP; import static com.flurgle.camerakit.CameraKit.Constants.FOCUS_TAP;
import static com.flurgle.camerakit.CameraKit.Constants.FOCUS_TAP_WITH_MARKER; import static com.flurgle.camerakit.CameraKit.Constants.FOCUS_TAP_WITH_MARKER;
import static com.flurgle.camerakit.CameraKit.Constants.SESSION_TYPE_PICTURE; import static com.flurgle.camerakit.CameraKit.Constants.SESSION_TYPE_PICTURE;
@ -36,6 +35,7 @@ class Camera1 extends CameraImpl {
private int mCameraId; private int mCameraId;
private Camera mCamera; private Camera mCamera;
private ExtraProperties mExtraProperties; private ExtraProperties mExtraProperties;
private CameraOptions mOptions;
private Size mPreviewSize; private Size mPreviewSize;
private Size mCaptureSize; private Size mCaptureSize;
private MediaRecorder mMediaRecorder; private MediaRecorder mMediaRecorder;
@ -49,7 +49,7 @@ class Camera1 extends CameraImpl {
private double mLongitude; private double mLongitude;
private Handler mFocusHandler = new Handler(); private Handler mFocusHandler = new Handler();
private ConstantMapper.MapperImpl mMapper = new ConstantMapper.Mapper1(); private MapperImpl mMapper = new MapperImpl.Mapper1();
private boolean mIsSetup = false; private boolean mIsSetup = false;
private boolean mIsCapturingImage = false; private boolean mIsCapturingImage = false;
private boolean mIsCapturingVideo = false; private boolean mIsCapturingVideo = false;
@ -143,6 +143,8 @@ class Camera1 extends CameraImpl {
// Set parameters that might have been set before the camera was opened. // Set parameters that might have been set before the camera was opened.
synchronized (mLock) { synchronized (mLock) {
Camera.Parameters params = mCamera.getParameters(); Camera.Parameters params = mCamera.getParameters();
mExtraProperties = new ExtraProperties(params);
mOptions = new CameraOptions(params);
mergeFocus(params, CameraKit.Defaults.DEFAULT_FOCUS); mergeFocus(params, CameraKit.Defaults.DEFAULT_FOCUS);
mergeFlash(params, CameraKit.Defaults.DEFAULT_FLASH); mergeFlash(params, CameraKit.Defaults.DEFAULT_FLASH);
mergeLocation(params, 0d, 0d); mergeLocation(params, 0d, 0d);
@ -154,8 +156,7 @@ class Camera1 extends CameraImpl {
// Try starting preview. // Try starting preview.
mCamera.setDisplayOrientation(computeSensorToDisplayOffset()); // <- not allowed during preview mCamera.setDisplayOrientation(computeSensorToDisplayOffset()); // <- not allowed during preview
if (shouldSetup()) setup(); if (shouldSetup()) setup();
collectExtraProperties(); mCameraCallbacks.dispatchOnCameraOpened(mOptions);
mCameraCallbacks.dispatchOnCameraOpened();
} }
} }
@ -169,6 +170,8 @@ class Camera1 extends CameraImpl {
mCamera.release(); mCamera.release();
mCameraCallbacks.dispatchOnCameraClosed(); mCameraCallbacks.dispatchOnCameraClosed();
} }
mExtraProperties = null;
mOptions = null;
mCamera = null; mCamera = null;
mPreviewSize = null; mPreviewSize = null;
mCaptureSize = null; mCaptureSize = null;
@ -262,10 +265,8 @@ class Camera1 extends CameraImpl {
} }
private boolean mergeWhiteBalance(Camera.Parameters params, @WhiteBalance int oldWhiteBalance) { private boolean mergeWhiteBalance(Camera.Parameters params, @WhiteBalance int oldWhiteBalance) {
List<String> supported = params.getSupportedWhiteBalance(); if (mOptions.getSupportedWhiteBalance().contains(mWhiteBalance)) {
String internal = mMapper.mapWhiteBalance(mWhiteBalance); params.setWhiteBalance((String) mMapper.mapWhiteBalance(mWhiteBalance));
if (supported != null && supported.contains(internal)) {
params.setWhiteBalance(internal);
return true; return true;
} }
mWhiteBalance = oldWhiteBalance; mWhiteBalance = oldWhiteBalance;
@ -286,10 +287,8 @@ class Camera1 extends CameraImpl {
private boolean mergeFlash(Camera.Parameters params, @Flash int oldFlash) { private boolean mergeFlash(Camera.Parameters params, @Flash int oldFlash) {
List<String> flashes = params.getSupportedFlashModes(); if (mOptions.getSupportedFlash().contains(mFlash)) {
String internalFlash = mMapper.mapFlash(mFlash); params.setFlashMode((String) mMapper.mapFlash(mFlash));
if (flashes != null && flashes.contains(internalFlash)) {
params.setFlashMode(internalFlash);
return true; return true;
} }
mFlash = oldFlash; mFlash = oldFlash;
@ -311,30 +310,34 @@ class Camera1 extends CameraImpl {
private boolean mergeFocus(Camera.Parameters params, @Focus int oldFocus) { private boolean mergeFocus(Camera.Parameters params, @Focus int oldFocus) {
final List<String> modes = params.getSupportedFocusModes(); if (!mOptions.getSupportedFocus().contains(mFocus)) {
mFocus = oldFocus;
return false;
}
switch (mFocus) { switch (mFocus) {
case FOCUS_CONTINUOUS: case FOCUS_CONTINUOUS:
params.setFocusMode((String) mMapper.mapFocus(FOCUS_CONTINUOUS));
return true;
case FOCUS_TAP: case FOCUS_TAP:
case FOCUS_TAP_WITH_MARKER: case FOCUS_TAP_WITH_MARKER:
if (modes.contains(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE)) { // We are sure camera supports auto focus.
params.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE); // Now we must just find a fallback, because FOCUS_AUTO is used only on tap.
if (mOptions.getSupportedFocus().contains(FOCUS_CONTINUOUS)) {
params.setFocusMode((String) mMapper.mapFocus(FOCUS_CONTINUOUS));
return true; return true;
} }
mFocus = oldFocus; // Don't break.
return false;
case FOCUS_OFF: case FOCUS_FIXED:
if (modes.contains(Camera.Parameters.FOCUS_MODE_FIXED)) { if (mOptions.getSupportedFocus().contains(FOCUS_FIXED)) {
params.setFocusMode(Camera.Parameters.FOCUS_MODE_FIXED); params.setFocusMode((String) mMapper.mapFocus(FOCUS_FIXED));
return true;
} else if (modes.contains(Camera.Parameters.FOCUS_MODE_INFINITY)) {
params.setFocusMode(Camera.Parameters.FOCUS_MODE_INFINITY);
return true;
} else if (modes.contains(Camera.Parameters.FOCUS_MODE_AUTO)) {
params.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO);
return true; return true;
} }
} }
mFocus = oldFocus;
return false; return false;
} }
@ -370,8 +373,7 @@ class Camera1 extends CameraImpl {
if (mIsCapturingImage) return; if (mIsCapturingImage) return;
if (!isCameraOpened()) return; if (!isCameraOpened()) return;
if (mSessionType == SESSION_TYPE_VIDEO && mIsCapturingVideo) { if (mSessionType == SESSION_TYPE_VIDEO && mIsCapturingVideo) {
Camera.Parameters parameters = mCamera.getParameters(); if (!mOptions.isVideoSnapshotSupported()) return;
if (!parameters.isVideoSnapshotSupported()) return;
} }
// Set boolean to wait for image callback // Set boolean to wait for image callback
@ -380,10 +382,10 @@ class Camera1 extends CameraImpl {
final boolean exifFlip = computeExifFlip(); final boolean exifFlip = computeExifFlip();
final int sensorToDisplay = computeSensorToDisplayOffset(); final int sensorToDisplay = computeSensorToDisplayOffset();
synchronized (mLock) { synchronized (mLock) {
Camera.Parameters parameters = mCamera.getParameters(); Camera.Parameters params = mCamera.getParameters();
Log.e(TAG, "Setting exif rotation to "+exifRotation); Log.e(TAG, "Setting exif rotation to "+exifRotation);
parameters.setRotation(exifRotation); params.setRotation(exifRotation);
mCamera.setParameters(parameters); mCamera.setParameters(params);
} }
// Is the final picture (decoded respecting EXIF) consistent with CameraView orientation? // Is the final picture (decoded respecting EXIF) consistent with CameraView orientation?
// We must consider exifOrientation to bring back the picture in the sensor world. // We must consider exifOrientation to bring back the picture in the sensor world.
@ -469,6 +471,12 @@ class Camera1 extends CameraImpl {
return mExtraProperties; return mExtraProperties;
} }
@Nullable
@Override
CameraOptions getCameraOptions() {
return mOptions;
}
// Internal: // Internal:
@ -539,13 +547,6 @@ class Camera1 extends CameraImpl {
} }
private void collectExtraProperties() {
Camera.Parameters params = mCamera.getParameters();
mExtraProperties = new ExtraProperties(params.getVerticalViewAngle(),
params.getHorizontalViewAngle());
}
// ----------------- // -----------------
// Video recording stuff. // Video recording stuff.
@ -661,7 +662,7 @@ class Camera1 extends CameraImpl {
if (!isCameraOpened()) return false; if (!isCameraOpened()) return false;
synchronized (mLock) { synchronized (mLock) {
Camera.Parameters params = mCamera.getParameters(); Camera.Parameters params = mCamera.getParameters();
if (!params.isZoomSupported()) return false; if (!mOptions.isZoomSupported()) return false;
float max = params.getMaxZoom(); float max = params.getMaxZoom();
params.setZoom((int) (zoom * max)); params.setZoom((int) (zoom * max));
mCamera.setParameters(params); mCamera.setParameters(params);
@ -680,15 +681,15 @@ class Camera1 extends CameraImpl {
List<Camera.Area> meteringAreas2 = computeMeteringAreas(x, y); List<Camera.Area> meteringAreas2 = computeMeteringAreas(x, y);
List<Camera.Area> meteringAreas1 = meteringAreas2.subList(0, 1); List<Camera.Area> meteringAreas1 = meteringAreas2.subList(0, 1);
synchronized (mLock) { synchronized (mLock) {
Camera.Parameters parameters = mCamera.getParameters(); Camera.Parameters params = mCamera.getParameters();
boolean autofocusSupported = parameters.getSupportedFocusModes().contains(Camera.Parameters.FOCUS_MODE_AUTO); boolean autofocusSupported = params.getSupportedFocusModes().contains(Camera.Parameters.FOCUS_MODE_AUTO);
if (autofocusSupported) { if (autofocusSupported) {
int maxAF = parameters.getMaxNumFocusAreas(); int maxAF = params.getMaxNumFocusAreas();
int maxAE = parameters.getMaxNumMeteringAreas(); int maxAE = params.getMaxNumMeteringAreas();
if (maxAF > 0) parameters.setFocusAreas(maxAF > 1 ? meteringAreas2 : meteringAreas1); if (maxAF > 0) params.setFocusAreas(maxAF > 1 ? meteringAreas2 : meteringAreas1);
if (maxAE > 0) parameters.setMeteringAreas(maxAE > 1 ? meteringAreas2 : meteringAreas1); if (maxAE > 0) params.setMeteringAreas(maxAE > 1 ? meteringAreas2 : meteringAreas1);
parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO); params.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO);
mCamera.setParameters(parameters); mCamera.setParameters(params);
mCameraCallbacks.dispatchOnFocusStart(x, y); mCameraCallbacks.dispatchOnFocusStart(x, y);
mCamera.autoFocus(new Camera.AutoFocusCallback() { mCamera.autoFocus(new Camera.AutoFocusCallback() {
@Override @Override
@ -711,12 +712,10 @@ class Camera1 extends CameraImpl {
mCamera.cancelAutoFocus(); mCamera.cancelAutoFocus();
synchronized (mLock) { synchronized (mLock) {
Camera.Parameters params = mCamera.getParameters(); Camera.Parameters params = mCamera.getParameters();
if (!params.getFocusMode().equals(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE)) { params.setFocusAreas(null);
params.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE); params.setMeteringAreas(null);
params.setFocusAreas(null); mergeFocus(params, mFocus); // Revert to internal focus (CONTINUOUS_PICTURE if present).
params.setMeteringAreas(null); mCamera.setParameters(params);
mCamera.setParameters(params);
}
} }
} }
}, DELAY_MILLIS_BEFORE_RESETTING_FOCUS); }, DELAY_MILLIS_BEFORE_RESETTING_FOCUS);

@ -8,21 +8,22 @@ import android.util.SparseIntArray;
import java.util.Map; import java.util.Map;
public class ConstantMapper { abstract class MapperImpl {
static abstract class MapperImpl { abstract <T> T mapFlash(@Flash int internalConstant);
abstract <T> T mapFacing(@Facing int internalConstant);
MapperImpl() {} abstract <T> T mapWhiteBalance(@WhiteBalance int internalConstant);
abstract <T> T mapFocus(@Focus int internalConstant);
abstract <T> T mapFlash(@Flash int internalConstant); @Flash abstract <T> int unmapFlash(T cameraConstant);
abstract <T> T mapFacing(@Facing int internalConstant); @Facing abstract <T> int unmapFacing(T cameraConstant);
abstract <T> T mapWhiteBalance(@WhiteBalance int internalConstant); @WhiteBalance abstract <T> int unmapWhiteBalance(T cameraConstant);
} @Focus abstract <T> int unmapFocus(T cameraConstant);
static class Mapper1 extends MapperImpl { static class Mapper1 extends MapperImpl {
private static final SparseArrayCompat<String> FLASH = new SparseArrayCompat<>(); private static final SparseArrayCompat<String> FLASH = new SparseArrayCompat<>();
private static final SparseArrayCompat<String> WB = new SparseArrayCompat<>(); private static final SparseArrayCompat<String> WB = new SparseArrayCompat<>();
private static final SparseArrayCompat<Integer> FACING = new SparseArrayCompat<>(); private static final SparseArrayCompat<Integer> FACING = new SparseArrayCompat<>();
private static final SparseArrayCompat<String> FOCUS = new SparseArrayCompat<>();
static { static {
FLASH.put(CameraKit.Constants.FLASH_OFF, Camera.Parameters.FLASH_MODE_OFF); FLASH.put(CameraKit.Constants.FLASH_OFF, Camera.Parameters.FLASH_MODE_OFF);
@ -36,6 +37,10 @@ public class ConstantMapper {
WB.put(CameraKit.Constants.WHITE_BALANCE_FLUORESCENT, Camera.Parameters.WHITE_BALANCE_FLUORESCENT); WB.put(CameraKit.Constants.WHITE_BALANCE_FLUORESCENT, Camera.Parameters.WHITE_BALANCE_FLUORESCENT);
WB.put(CameraKit.Constants.WHITE_BALANCE_DAYLIGHT, Camera.Parameters.WHITE_BALANCE_DAYLIGHT); WB.put(CameraKit.Constants.WHITE_BALANCE_DAYLIGHT, Camera.Parameters.WHITE_BALANCE_DAYLIGHT);
WB.put(CameraKit.Constants.WHITE_BALANCE_CLOUDY, Camera.Parameters.WHITE_BALANCE_CLOUDY_DAYLIGHT); WB.put(CameraKit.Constants.WHITE_BALANCE_CLOUDY, Camera.Parameters.WHITE_BALANCE_CLOUDY_DAYLIGHT);
FOCUS.put(CameraKit.Constants.FOCUS_FIXED, Camera.Parameters.FOCUS_MODE_FIXED);
FOCUS.put(CameraKit.Constants.FOCUS_CONTINUOUS, Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE);
FOCUS.put(CameraKit.Constants.FOCUS_TAP, Camera.Parameters.FOCUS_MODE_AUTO);
FOCUS.put(CameraKit.Constants.FOCUS_TAP_WITH_MARKER, Camera.Parameters.FOCUS_MODE_AUTO);
} }
@Override @Override
@ -52,6 +57,32 @@ public class ConstantMapper {
<T> T mapWhiteBalance(int internalConstant) { <T> T mapWhiteBalance(int internalConstant) {
return (T) WB.get(internalConstant, null); return (T) WB.get(internalConstant, null);
} }
@Override
<T> T mapFocus(@Focus int internalConstant) {
return (T) FOCUS.get(internalConstant, null);
}
@Override
<T> int unmapFlash(T cameraConstant) {
return FLASH.keyAt(FLASH.indexOfValue((String) cameraConstant));
}
@Override
<T> int unmapFacing(T cameraConstant) {
return FACING.keyAt(FACING.indexOfValue((Integer) cameraConstant));
}
@Override
<T> int unmapWhiteBalance(T cameraConstant) {
return WB.keyAt(WB.indexOfValue((String) cameraConstant));
}
// This will ignore FOCUS_TAP_WITH_MARKER but it's fine
@Override
<T> int unmapFocus(T cameraConstant) {
return FOCUS.keyAt(FOCUS.indexOfValue((String) cameraConstant));
}
} }
static class Mapper2 extends MapperImpl { static class Mapper2 extends MapperImpl {
@ -70,6 +101,31 @@ public class ConstantMapper {
<T> T mapFlash(@Flash int internalConstant) { <T> T mapFlash(@Flash int internalConstant) {
return null; return null;
} }
@Override
<T> int unmapFlash(T cameraConstant) {
return 0;
}
@Override
<T> int unmapFacing(T cameraConstant) {
return 0;
}
@Override
<T> int unmapWhiteBalance(T cameraConstant) {
return 0;
}
@Override
<T> T mapFocus(@Focus int internalConstant) {
return null;
}
@Override
<T> int unmapFocus(T cameraConstant) {
return 0;
}
} }
} }

@ -11,8 +11,6 @@ import android.hardware.camera2.params.StreamConfigurationMap;
import android.support.annotation.NonNull; import android.support.annotation.NonNull;
import android.support.annotation.Nullable; import android.support.annotation.Nullable;
import android.util.Log; import android.util.Log;
import android.util.SizeF;
import android.view.MotionEvent;
import java.io.File; import java.io.File;
import java.util.ArrayList; import java.util.ArrayList;
@ -33,7 +31,7 @@ class Camera2 extends CameraImpl {
private Size mCaptureSize; private Size mCaptureSize;
private Size mPreviewSize; private Size mPreviewSize;
private ConstantMapper.MapperImpl mMapper = new ConstantMapper.Mapper2(); private MapperImpl mMapper = new MapperImpl.Mapper2();
private final HashMap<String, ExtraProperties> mExtraPropertiesMap = new HashMap<>(); private final HashMap<String, ExtraProperties> mExtraPropertiesMap = new HashMap<>();
@ -64,22 +62,8 @@ class Camera2 extends CameraImpl {
@SuppressWarnings("ConstantConditions") @SuppressWarnings("ConstantConditions")
int orientation = characteristics.get(CameraCharacteristics.LENS_FACING); int orientation = characteristics.get(CameraCharacteristics.LENS_FACING);
if (orientation == CameraCharacteristics.LENS_FACING_BACK) { if (orientation == CameraCharacteristics.LENS_FACING_BACK) {
float[] maxFocus = characteristics.get( ExtraProperties props = new ExtraProperties(characteristics);
CameraCharacteristics.LENS_INFO_AVAILABLE_FOCAL_LENGTHS); mExtraPropertiesMap.put(cameraId, props);
if (maxFocus == null) {
continue;
}
SizeF size = characteristics.get(
CameraCharacteristics.SENSOR_INFO_PHYSICAL_SIZE);
if (size == null) {
continue;
}
float w = size.getWidth();
float h = size.getHeight();
mExtraPropertiesMap.put(cameraId, new ExtraProperties(
(float) Math.toDegrees(2*Math.atan(w/(maxFocus[0]*2))),
(float) Math.toDegrees(2*Math.atan(h/(maxFocus[0]*2)))
));
} }
} }
} catch (CameraAccessException e) { } catch (CameraAccessException e) {
@ -274,6 +258,13 @@ class Camera2 extends CameraImpl {
} }
// Internal // Internal
@Nullable
@Override
CameraOptions getCameraOptions() {
return null;
}
private List<Size> getAvailableCaptureResolutions() { private List<Size> getAvailableCaptureResolutions() {
List<Size> output = new ArrayList<>(); List<Size> output = new ArrayList<>();

@ -51,8 +51,8 @@ abstract class CameraImpl implements PreviewImpl.SurfaceCallback {
abstract void startFocus(float x, float y); abstract void startFocus(float x, float y);
@Nullable @Nullable abstract ExtraProperties getExtraProperties();
abstract ExtraProperties getExtraProperties(); @Nullable abstract CameraOptions getCameraOptions();
@Facing @Facing
final int getFacing() { final int getFacing() {

@ -0,0 +1,91 @@
package com.flurgle.camerakit;
import android.annotation.TargetApi;
import android.hardware.Camera;
import android.hardware.camera2.CameraCharacteristics;
import java.util.ArrayList;
import java.util.List;
/**
* Options telling you what is available and what is not.
*/
@SuppressWarnings("deprecation")
public class CameraOptions {
private List<Integer> supportedWhiteBalance = new ArrayList<>(5);
private List<Integer> supportedFacing = new ArrayList<>(2);
private List<Integer> supportedFlash = new ArrayList<>(3);
private List<Integer> supportedFocus = new ArrayList<>(3);
private boolean zoomSupported;
private boolean videoSnapshotSupported;
CameraOptions(Camera.Parameters params) {
List<String> strings;
MapperImpl mapper = new MapperImpl.Mapper1();
// Facing
Camera.CameraInfo cameraInfo = new Camera.CameraInfo();
for (int i = 0, count = Camera.getNumberOfCameras(); i < count; i++) {
Camera.getCameraInfo(i, cameraInfo);
supportedFacing.add(mapper.unmapFacing(cameraInfo.facing));
}
// WB
strings = params.getSupportedWhiteBalance();
if (strings != null) {
for (String string : strings) {
supportedWhiteBalance.add(mapper.unmapWhiteBalance(string));
}
}
// Flash
strings = params.getSupportedFlashModes();
if (strings != null) {
for (String string : strings) {
supportedFlash.add(mapper.unmapFlash(string));
}
}
// Focus
strings = params.getSupportedFocusModes(); // Never null.
for (String string : strings) {
supportedFocus.add(mapper.unmapFocus(string));
}
zoomSupported = params.isZoomSupported();
videoSnapshotSupported = params.isVideoSnapshotSupported();
}
@TargetApi(21)
CameraOptions(CameraCharacteristics params) {}
public List<Integer> getSupportedFacing() {
return supportedFacing;
}
public List<Integer> getSupportedFlash() {
return supportedFlash;
}
public List<Integer> getSupportedWhiteBalance() {
return supportedWhiteBalance;
}
public List<Integer> getSupportedFocus() {
return supportedFocus;
}
public boolean isZoomSupported() {
return zoomSupported;
}
public boolean isVideoSnapshotSupported() {
return videoSnapshotSupported;
}
}

@ -1,14 +1,38 @@
package com.flurgle.camerakit; package com.flurgle.camerakit;
import android.annotation.TargetApi;
import android.hardware.Camera;
import android.hardware.camera2.CameraCharacteristics;
import android.util.SizeF;
/** /**
* Simple pojo containing various camera properties. * Simple pojo containing various camera properties.
*/ */
@SuppressWarnings("deprecation")
public class ExtraProperties { public class ExtraProperties {
public final float verticalViewingAngle;
public final float horizontalViewingAngle;
public ExtraProperties(float verticalViewingAngle, float horizontalViewingAngle) { float verticalViewingAngle;
this.verticalViewingAngle = verticalViewingAngle; float horizontalViewingAngle;
this.horizontalViewingAngle = horizontalViewingAngle;
ExtraProperties(Camera.Parameters params) {
verticalViewingAngle = params.getVerticalViewAngle();
horizontalViewingAngle = params.getHorizontalViewAngle();
}
@TargetApi(21)
ExtraProperties(CameraCharacteristics chars) {
float[] maxFocus = chars.get(CameraCharacteristics.LENS_INFO_AVAILABLE_FOCAL_LENGTHS);
SizeF size = chars.get(CameraCharacteristics.SENSOR_INFO_PHYSICAL_SIZE);
verticalViewingAngle = (float) Math.toDegrees(2 * Math.atan(size.getWidth() / (maxFocus[0] * 2)));
horizontalViewingAngle = (float) Math.toDegrees(2 * Math.atan(size.getHeight() / (maxFocus[0] * 2)));
}
public float getHorizontalViewingAngle() {
return horizontalViewingAngle;
}
public float getVerticalViewingAngle() {
return verticalViewingAngle;
} }
} }

@ -18,7 +18,7 @@ public class CameraKit {
public static final int FLASH_AUTO = 2; public static final int FLASH_AUTO = 2;
public static final int FLASH_TORCH = 3; public static final int FLASH_TORCH = 3;
public static final int FOCUS_OFF = 0; public static final int FOCUS_FIXED = 0;
public static final int FOCUS_CONTINUOUS = 1; public static final int FOCUS_CONTINUOUS = 1;
public static final int FOCUS_TAP = 2; public static final int FOCUS_TAP = 2;
public static final int FOCUS_TAP_WITH_MARKER = 3; public static final int FOCUS_TAP_WITH_MARKER = 3;

@ -7,18 +7,27 @@ import java.io.File;
public abstract class CameraListener { public abstract class CameraListener {
public void onCameraOpened() { /**
* Notifies that the camera was opened.
* The {@link CameraOptions} object collects all supported options by the current camera.
*
* @param options camera supported options
*/
public void onCameraOpened(CameraOptions options) {
} }
public void onCameraClosed() { public void onCameraClosed() {
} }
public void onPictureTaken(byte[] jpeg) { public void onPictureTaken(byte[] jpeg) {
} }
public void onVideoTaken(File video) { public void onVideoTaken(File video) {
} }

@ -5,6 +5,7 @@ import android.content.pm.PackageManager;
import android.graphics.Bitmap; import android.graphics.Bitmap;
import android.graphics.BitmapFactory; import android.graphics.BitmapFactory;
import android.graphics.Matrix; import android.graphics.Matrix;
import android.hardware.Camera;
import android.os.Handler; import android.os.Handler;
import android.support.annotation.UiThread; import android.support.annotation.UiThread;
import android.support.media.ExifInterface; import android.support.media.ExifInterface;
@ -34,6 +35,25 @@ public class CameraUtils {
} }
/**
* Determines whether the device has a valid camera sensor with the given
* Facing value, so that a session can be started.
*
* @param context a valid context
* @param facing either {@link CameraKit.Constants#FACING_BACK} or {@link CameraKit.Constants#FACING_FRONT}
* @return true if such sensor exists
*/
public static boolean hasCameraFacing(Context context, @Facing int facing) {
int internal = new MapperImpl.Mapper1().mapFacing(facing);
Camera.CameraInfo cameraInfo = new Camera.CameraInfo();
for (int i = 0, count = Camera.getNumberOfCameras(); i < count; i++) {
Camera.getCameraInfo(i, cameraInfo);
if (cameraInfo.facing == internal) return true;
}
return false;
}
/** /**
* Decodes an input byte array and outputs a Bitmap that is ready to be displayed. * Decodes an input byte array and outputs a Bitmap that is ready to be displayed.
* The difference with {@link android.graphics.BitmapFactory#decodeByteArray(byte[], int, int)} * The difference with {@link android.graphics.BitmapFactory#decodeByteArray(byte[], int, int)}

@ -477,6 +477,19 @@ public class CameraView extends FrameLayout implements LifecycleObserver {
} }
/**
* Returns a {@link CameraOptions} instance holding supported options for this camera
* session. This might change over time. It's better to hold a reference from
* {@link CameraListener#onCameraOpened(CameraOptions)}.
*
* @return an options map, or null if camera was not opened
*/
@Nullable
public CameraOptions getCameraOptions() {
return mCameraImpl.getCameraOptions();
}
/** /**
* If present, returns a collection of extra properties from the current camera * If present, returns a collection of extra properties from the current camera
* session. * session.
@ -648,7 +661,7 @@ public class CameraView extends FrameLayout implements LifecycleObserver {
/** /**
* Toggles the flash mode between {@link CameraKit.Constants#FLASH_OFF}, * Toggles the flash mode between {@link CameraKit.Constants#FLASH_OFF},
* {@link CameraKit.Constants#FLASH_ON}, {@link CameraKit.Constants#FLASH_AUTO} and * {@link CameraKit.Constants#FLASH_ON}, {@link CameraKit.Constants#FLASH_AUTO} and
* {@link CameraKit.Constants#FOCUS_OFF}, in this order. * {@link CameraKit.Constants#FOCUS_FIXED}, in this order.
* *
* @return the new flash value * @return the new flash value
*/ */
@ -692,13 +705,14 @@ public class CameraView extends FrameLayout implements LifecycleObserver {
* Sets the current focus behavior. * Sets the current focus behavior.
* *
* @see CameraKit.Constants#FOCUS_CONTINUOUS * @see CameraKit.Constants#FOCUS_CONTINUOUS
* @see CameraKit.Constants#FOCUS_OFF * @see CameraKit.Constants#FOCUS_FIXED
* @see CameraKit.Constants#FOCUS_TAP * @see CameraKit.Constants#FOCUS_TAP
* @see CameraKit.Constants#FOCUS_TAP_WITH_MARKER * @see CameraKit.Constants#FOCUS_TAP_WITH_MARKER
* @param focus a Focus value. * @param focus a Focus value.
*/ */
public void setFocus(@Focus int focus) { public void setFocus(@Focus int focus) {
// TODO we are not sure this focus is supported at this point, yet we enable the layout!
mFocusMarkerLayout.setEnabled(focus == CameraKit.Constants.FOCUS_TAP_WITH_MARKER); mFocusMarkerLayout.setEnabled(focus == CameraKit.Constants.FOCUS_TAP_WITH_MARKER);
if (focus == CameraKit.Constants.FOCUS_TAP_WITH_MARKER) { if (focus == CameraKit.Constants.FOCUS_TAP_WITH_MARKER) {
focus = CameraKit.Constants.FOCUS_TAP; focus = CameraKit.Constants.FOCUS_TAP;
@ -1067,12 +1081,12 @@ public class CameraView extends FrameLayout implements LifecycleObserver {
} }
public void dispatchOnCameraOpened() { public void dispatchOnCameraOpened(final CameraOptions options) {
uiHandler.post(new Runnable() { uiHandler.post(new Runnable() {
@Override @Override
public void run() { public void run() {
for (CameraListener listener : mListeners) { for (CameraListener listener : mListeners) {
listener.onCameraOpened(); listener.onCameraOpened(options);
} }
} }
}); });

@ -16,7 +16,7 @@
</attr> </attr>
<attr name="cameraFocus" format="enum"> <attr name="cameraFocus" format="enum">
<enum name="off" value="0" /> <enum name="fixed" value="0" />
<enum name="continuous" value="1" /> <enum name="continuous" value="1" />
<enum name="tap" value="2" /> <enum name="tap" value="2" />
<enum name="tapWithMarker" value="3" /> <enum name="tapWithMarker" value="3" />

@ -6,11 +6,11 @@ import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy; import java.lang.annotation.RetentionPolicy;
import static com.flurgle.camerakit.CameraKit.Constants.FOCUS_TAP; import static com.flurgle.camerakit.CameraKit.Constants.FOCUS_TAP;
import static com.flurgle.camerakit.CameraKit.Constants.FOCUS_OFF; import static com.flurgle.camerakit.CameraKit.Constants.FOCUS_FIXED;
import static com.flurgle.camerakit.CameraKit.Constants.FOCUS_CONTINUOUS; import static com.flurgle.camerakit.CameraKit.Constants.FOCUS_CONTINUOUS;
import static com.flurgle.camerakit.CameraKit.Constants.FOCUS_TAP_WITH_MARKER; import static com.flurgle.camerakit.CameraKit.Constants.FOCUS_TAP_WITH_MARKER;
@Retention(RetentionPolicy.SOURCE) @Retention(RetentionPolicy.SOURCE)
@IntDef({FOCUS_CONTINUOUS, FOCUS_TAP, FOCUS_OFF, FOCUS_TAP_WITH_MARKER}) @IntDef({FOCUS_CONTINUOUS, FOCUS_TAP, FOCUS_FIXED, FOCUS_TAP_WITH_MARKER})
public @interface Focus { public @interface Focus {
} }
Loading…
Cancel
Save