Added sessionType to switch between picture and video. Deprecated permissionsPolicy and captureMethod. Improved video sizing.

pull/1/head
Mattia Iavarone 7 years ago
parent c98ecf7e28
commit c429a99972
  1. 192
      camerakit/src/main/api16/com/flurgle/camerakit/Camera1.java
  2. 2
      camerakit/src/main/api21/com/flurgle/camerakit/Camera2.java
  3. 2
      camerakit/src/main/base/com/flurgle/camerakit/CameraImpl.java
  4. 6
      camerakit/src/main/base/com/flurgle/camerakit/TextureViewPreview.java
  5. 20
      camerakit/src/main/java/com/flurgle/camerakit/CameraKit.java
  6. 272
      camerakit/src/main/java/com/flurgle/camerakit/CameraView.java
  7. 5
      camerakit/src/main/res/values/attrs.xml
  8. 1
      camerakit/src/main/types/com/flurgle/camerakit/Method.java
  9. 1
      camerakit/src/main/types/com/flurgle/camerakit/Permissions.java

@ -5,7 +5,9 @@ import android.graphics.YuvImage;
import android.hardware.Camera;
import android.media.CamcorderProfile;
import android.media.MediaRecorder;
import android.os.Build;
import android.os.Handler;
import android.support.annotation.NonNull;
import android.util.Log;
import android.support.annotation.Nullable;
import android.view.MotionEvent;
@ -21,9 +23,9 @@ import java.util.List;
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_TAP;
import static com.flurgle.camerakit.CameraKit.Constants.CAPTURE_METHOD_STANDARD;
import static com.flurgle.camerakit.CameraKit.Constants.CAPTURE_METHOD_FRAME;
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_VIDEO;
@SuppressWarnings("deprecation")
class Camera1 extends CameraImpl {
@ -53,10 +55,10 @@ class Camera1 extends CameraImpl {
@Facing private int mFacing;
@Flash private int mFlash;
@Focus private int mFocus;
@Method private int mMethod;
@ZoomMode private int mZoom;
@VideoQuality private int mVideoQuality;
@WhiteBalance private int mWhiteBalance;
@SessionType private int mSessionType;
private double mLatitude;
private double mLongitude;
@ -70,7 +72,7 @@ class Camera1 extends CameraImpl {
public void onPreviewSurfaceChanged() {
if (mCamera != null) {
setupPreview();
collectCameraSizes();
computeCameraSizes();
adjustCameraParameters();
}
}
@ -125,6 +127,18 @@ class Camera1 extends CameraImpl {
this.mDeviceOrientation = deviceOrientation;
}
@Override
void setSessionType(@SessionType int sessionType) {
if (sessionType != mSessionType) {
mSessionType = sessionType;
if (isCameraOpened()) {
stop();
start();
}
}
}
@Override
void setLocation(double latitude, double longitude) {
mLatitude = latitude;
@ -234,11 +248,6 @@ class Camera1 extends CameraImpl {
}
}
@Override
void setMethod(@Method int method) {
this.mMethod = method;
}
@Override
void setZoom(@ZoomMode int zoom) {
this.mZoom = zoom;
@ -251,8 +260,8 @@ class Camera1 extends CameraImpl {
@Override
void captureImage() {
switch (mMethod) {
case CAPTURE_METHOD_STANDARD:
switch (mSessionType) {
case SESSION_TYPE_PICTURE:
// Null check required for camera here as is briefly null when View is detached
if (!capturingImage && mCamera != null) {
// Set boolean to wait for image callback
@ -270,13 +279,14 @@ class Camera1 extends CameraImpl {
camera.startPreview();
}
});
}
else {
} else {
Log.w(TAG, "Unable, waiting for picture to be taken");
}
break;
case CAPTURE_METHOD_FRAME:
case SESSION_TYPE_VIDEO:
// If we are in a video session, camera captures are fast captures coming
// from the preview stream.
// TODO: will calculateCaptureRotation work here? It's the only usage. Test...
mCamera.setOneShotPreviewCallback(new Camera.PreviewCallback() {
@Override
@ -293,22 +303,6 @@ class Camera1 extends CameraImpl {
}
}
@Override
void startVideo() {
initMediaRecorder();
prepareMediaRecorder();
mMediaRecorder.start();
}
@Override
void endVideo() {
mMediaRecorder.stop();
mMediaRecorder.release();
mMediaRecorder = null;
mCameraListener.onVideoTaken(mVideoFile);
}
@Override
Size getCaptureSize() {
return mCaptureSize;
@ -346,7 +340,7 @@ class Camera1 extends CameraImpl {
mCameraParameters = mCamera.getParameters();
collectCameraProperties();
collectCameraSizes();
computeCameraSizes();
adjustCameraParameters();
mCamera.setDisplayOrientation(computeCameraToDisplayOffset());
mCameraListener.onCameraOpened();
@ -401,22 +395,22 @@ class Camera1 extends CameraImpl {
* dimensions.
* But when it does, the {@link PreviewImpl.OnPreviewSurfaceChangedCallback} should be called,
* and this should be refreshed.
*
*
* TODO: either camera or video.
*/
private void collectCameraSizes() {
private void computeCameraSizes() {
mCameraParameters.setRecordingHint(mSessionType == SESSION_TYPE_VIDEO);
List<Size> previewSizes = sizesFromList(mCameraParameters.getSupportedPreviewSizes());
if (mSessionType == SESSION_TYPE_PICTURE) {
// Choose the max size.
List<Size> captureSizes = sizesFromList(mCameraParameters.getSupportedPictureSizes());
/* video stuff: CamcorderProfile camcorderProfile = getCamcorderProfile(mVideoQuality);
mCaptureSize = getSizeWithClosestRatio(
(videoSizes == null || videoSizes.isEmpty()) ? previewSizes : videoSizes,
camcorderProfile.videoFrameWidth, camcorderProfile.videoFrameHeight); */
Size surfaceSize = mPreview.getSurfaceSize();
mCaptureSize = Collections.max(captureSizes);
mPreviewSize = computePreviewSize(previewSizes, mCaptureSize, surfaceSize);
} else {
// Choose according to developer choice in setVideoQuality.
// The Camcorder internally checks for cameraParameters.getSupportedVideoSizes() etc.
// So its output is our output.
CamcorderProfile camcorderProfile = getCamcorderProfile(mVideoQuality);
mCaptureSize = new Size(camcorderProfile.videoFrameWidth, camcorderProfile.videoFrameHeight);
}
mPreviewSize = computePreviewSize(previewSizes, mCaptureSize, mPreview.getSurfaceSize());
}
@ -442,6 +436,37 @@ class Camera1 extends CameraImpl {
}
@Override
void startVideo() {
if (mSessionType == SESSION_TYPE_VIDEO) {
initMediaRecorder();
try {
mMediaRecorder.prepare();
} catch (Exception e) {
e.printStackTrace();
mVideoFile = null;
endVideo();
return;
}
mMediaRecorder.start();
} else {
throw new IllegalStateException("Can't record video while session type is picture");
}
}
@Override
void endVideo() {
mMediaRecorder.stop();
mMediaRecorder.release();
mMediaRecorder = null;
if (mVideoFile != null) {
mCameraListener.onVideoTaken(mVideoFile);
mVideoFile = null;
}
}
private void initMediaRecorder() {
mMediaRecorder = new MediaRecorder();
mCamera.unlock();
@ -455,75 +480,57 @@ class Camera1 extends CameraImpl {
mVideoFile = new File(mPreview.getView().getContext().getExternalFilesDir(null), "video.mp4");
mMediaRecorder.setOutputFile(mVideoFile.getAbsolutePath());
mMediaRecorder.setOrientationHint(computeCameraToDisplayOffset());
mMediaRecorder.setVideoSize(mCaptureSize.getWidth(), mCaptureSize.getHeight());
mMediaRecorder.setOrientationHint(computeCameraToDisplayOffset()); // TODO is this correct? Should we use exif orientation? Maybe not.
// Not needed. mMediaRecorder.setPreviewDisplay(mPreview.getSurface());
}
private void prepareMediaRecorder() {
try {
mMediaRecorder.prepare();
} catch (IllegalStateException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
@NonNull
private CamcorderProfile getCamcorderProfile(@VideoQuality int videoQuality) {
CamcorderProfile camcorderProfile = null;
switch (videoQuality) {
case CameraKit.Constants.VIDEO_QUALITY_QVGA:
if (CamcorderProfile.hasProfile(mCameraId, CamcorderProfile.QUALITY_QVGA)) {
camcorderProfile = CamcorderProfile.get(mCameraId, CamcorderProfile.QUALITY_QVGA);
} else {
return getCamcorderProfile(CameraKit.Constants.VIDEO_QUALITY_LOWEST);
case CameraKit.Constants.VIDEO_QUALITY_HIGHEST:
return CamcorderProfile.get(mCameraId, CamcorderProfile.QUALITY_HIGH);
case CameraKit.Constants.VIDEO_QUALITY_2160P:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP &&
CamcorderProfile.hasProfile(CamcorderProfile.QUALITY_2160P)) {
return CamcorderProfile.get(mCameraId, CamcorderProfile.QUALITY_2160P);
}
break;
// Don't break.
case CameraKit.Constants.VIDEO_QUALITY_480P:
if (CamcorderProfile.hasProfile(mCameraId, CamcorderProfile.QUALITY_480P)) {
camcorderProfile = CamcorderProfile.get(mCameraId, CamcorderProfile.QUALITY_480P);
} else {
return getCamcorderProfile(CameraKit.Constants.VIDEO_QUALITY_QVGA);
case CameraKit.Constants.VIDEO_QUALITY_1080P:
if (CamcorderProfile.hasProfile(mCameraId, CamcorderProfile.QUALITY_1080P)) {
return CamcorderProfile.get(mCameraId, CamcorderProfile.QUALITY_1080P);
}
break;
// Don't break.
case CameraKit.Constants.VIDEO_QUALITY_720P:
if (CamcorderProfile.hasProfile(mCameraId, CamcorderProfile.QUALITY_720P)) {
camcorderProfile = CamcorderProfile.get(mCameraId, CamcorderProfile.QUALITY_720P);
} else {
return getCamcorderProfile(CameraKit.Constants.VIDEO_QUALITY_480P);
return CamcorderProfile.get(mCameraId, CamcorderProfile.QUALITY_720P);
}
break;
// Don't break.
case CameraKit.Constants.VIDEO_QUALITY_1080P:
if (CamcorderProfile.hasProfile(mCameraId, CamcorderProfile.QUALITY_1080P)) {
camcorderProfile = CamcorderProfile.get(mCameraId, CamcorderProfile.QUALITY_1080P);
} else {
return getCamcorderProfile(CameraKit.Constants.VIDEO_QUALITY_720P);
case CameraKit.Constants.VIDEO_QUALITY_480P:
if (CamcorderProfile.hasProfile(mCameraId, CamcorderProfile.QUALITY_480P)) {
return CamcorderProfile.get(mCameraId, CamcorderProfile.QUALITY_480P);
}
break;
// Don't break.
case CameraKit.Constants.VIDEO_QUALITY_2160P:
try {
camcorderProfile = CamcorderProfile.get(mCameraId, CamcorderProfile.QUALITY_2160P);
} catch (Exception e) {
return getCamcorderProfile(CameraKit.Constants.VIDEO_QUALITY_HIGHEST);
case CameraKit.Constants.VIDEO_QUALITY_QVGA:
if (CamcorderProfile.hasProfile(mCameraId, CamcorderProfile.QUALITY_QVGA)) {
return CamcorderProfile.get(mCameraId, CamcorderProfile.QUALITY_QVGA);
}
break;
case CameraKit.Constants.VIDEO_QUALITY_HIGHEST:
camcorderProfile = CamcorderProfile.get(mCameraId, CamcorderProfile.QUALITY_HIGH);
break;
// Don't break.
case CameraKit.Constants.VIDEO_QUALITY_LOWEST:
camcorderProfile = CamcorderProfile.get(mCameraId, CamcorderProfile.QUALITY_LOW);
break;
default:
// Fallback to lowest.
return CamcorderProfile.get(mCameraId, CamcorderProfile.QUALITY_LOW);
}
return camcorderProfile;
}
void setTapToAutofocusListener(Camera.AutoFocusCallback callback) {
if (this.mFocus != FOCUS_TAP) {
throw new IllegalArgumentException("Please set the camera to FOCUS_TAP.");
@ -663,6 +670,7 @@ class Camera1 extends CameraImpl {
/**
* Returns a list of {@link Size} out of Camera.Sizes.
*/
@Nullable
private static List<Size> sizesFromList(List<Camera.Size> sizes) {
if (sizes == null) return null;
List<Size> result = new ArrayList<>(sizes.size());
@ -688,7 +696,7 @@ class Camera1 extends CameraImpl {
List<Size> bigEnoughAndConsistent = new ArrayList<>(5);
final AspectRatio targetRatio = AspectRatio.of(captureSize.getWidth(), captureSize.getHeight());
final Size targetSize = captureSize;
final Size targetSize = surfaceSize;
for (Size size : sizes) {
AspectRatio ratio = AspectRatio.of(size.getWidth(), size.getHeight());
if (ratio.equals(targetRatio)) {

@ -147,7 +147,7 @@ class Camera2 extends CameraImpl {
}
@Override
void setMethod(@Method int method) {
void setSessionType(@SessionType int sessionType) {
}

@ -21,10 +21,10 @@ abstract class CameraImpl {
abstract void setFacing(@Facing int facing);
abstract void setFlash(@Flash int flash);
abstract void setFocus(@Focus int focus);
abstract void setMethod(@Method int method);
abstract void setZoom(@ZoomMode int zoom);
abstract void setVideoQuality(@VideoQuality int videoQuality);
abstract void setWhiteBalance(@WhiteBalance int whiteBalance);
abstract void setSessionType(@SessionType int sessionType);
abstract void setLocation(double latitude, double longitude);
abstract void captureImage();

@ -12,6 +12,7 @@ import android.view.ViewGroup;
class TextureViewPreview extends PreviewImpl {
private final TextureView mTextureView;
private Surface mSurface;
TextureViewPreview(Context context, ViewGroup parent) {
final View view = View.inflate(context, R.layout.texture_view, parent); // MATCH_PARENT
@ -45,7 +46,10 @@ class TextureViewPreview extends PreviewImpl {
@Override
Surface getSurface() {
return new Surface(getSurfaceTexture());
if (mSurface == null) { // Check if valid?
mSurface = new Surface(getSurfaceTexture());
}
return mSurface;
}
@Override

@ -32,8 +32,11 @@ public class CameraKit {
public static final int ZOOM_OFF = 0;
public static final int ZOOM_PINCH = 1;
public static final int CAPTURE_METHOD_STANDARD = 0;
public static final int CAPTURE_METHOD_FRAME = 1;
public static final int SESSION_TYPE_PICTURE = 0;
public static final int SESSION_TYPE_VIDEO = 1;
@Deprecated public static final int CAPTURE_METHOD_STANDARD = 0;
@Deprecated public static final int CAPTURE_METHOD_FRAME = 1;
/**
@ -41,15 +44,19 @@ public class CameraKit {
* With this configuration, it is mandatory that the developer adds
* <uses-permission android:name="android.permission.RECORD_AUDIO" />
* to its manifest, or the app will crash.
*
* @deprecated this does nothing.
*/
public static final int PERMISSIONS_VIDEO = 0;
@Deprecated public static final int PERMISSIONS_VIDEO = 0;
/**
* This means the app will be requesting the Camera permissions on Marshmallow+.
* On older APIs, this is not important, since the Camera permission is already
* declared in the manifest by the library.
*
* @deprecated this does nothing.
*/
public static final int PERMISSIONS_PICTURE = 1;
@Deprecated public static final int PERMISSIONS_PICTURE = 1;
public static final int VIDEO_QUALITY_480P = 0;
public static final int VIDEO_QUALITY_720P = 1;
@ -72,10 +79,11 @@ public class CameraKit {
static final int DEFAULT_FLASH = Constants.FLASH_OFF;
static final int DEFAULT_FOCUS = Constants.FOCUS_CONTINUOUS;
static final int DEFAULT_ZOOM = Constants.ZOOM_OFF;
static final int DEFAULT_METHOD = Constants.CAPTURE_METHOD_STANDARD;
static final int DEFAULT_PERMISSIONS = Constants.PERMISSIONS_PICTURE;
@Deprecated static final int DEFAULT_METHOD = Constants.CAPTURE_METHOD_STANDARD;
@Deprecated static final int DEFAULT_PERMISSIONS = Constants.PERMISSIONS_PICTURE;
static final int DEFAULT_VIDEO_QUALITY = Constants.VIDEO_QUALITY_480P;
static final int DEFAULT_WHITE_BALANCE = Constants.WHITE_BALANCE_AUTO;
static final int DEFAULT_SESSION_TYPE = Constants.SESSION_TYPE_PICTURE;
static final int DEFAULT_JPEG_QUALITY = 100;
static final boolean DEFAULT_CROP_OUTPUT = false;
static final boolean DEFAULT_ADJUST_VIEW_BOUNDS = false;

@ -39,8 +39,8 @@ import static com.flurgle.camerakit.CameraKit.Constants.FLASH_AUTO;
import static com.flurgle.camerakit.CameraKit.Constants.FLASH_OFF;
import static com.flurgle.camerakit.CameraKit.Constants.FLASH_ON;
import static com.flurgle.camerakit.CameraKit.Constants.FLASH_TORCH;
import static com.flurgle.camerakit.CameraKit.Constants.PERMISSIONS_PICTURE;
import static com.flurgle.camerakit.CameraKit.Constants.PERMISSIONS_VIDEO;
import static com.flurgle.camerakit.CameraKit.Constants.SESSION_TYPE_PICTURE;
import static com.flurgle.camerakit.CameraKit.Constants.SESSION_TYPE_VIDEO;
/**
* The CameraView implements the LifecycleObserver interface for ease of use. To take advantage of
@ -79,15 +79,16 @@ public class CameraView extends FrameLayout implements LifecycleObserver {
@Facing private int mFacing;
@Flash private int mFlash;
@Focus private int mFocus;
@Method private int mMethod;
// @Method private int mMethod;
@ZoomMode private int mZoom;
@Permissions private int mPermissions;
// @Permissions private int mPermissions;
@SessionType private int mSessionType;
@VideoQuality private int mVideoQuality;
@WhiteBalance private int mWhiteBalance;
private int mJpegQuality;
private boolean mCropOutput;
private boolean mAdjustViewBounds;
private CameraListenerMiddleWare mCameraListener;
private CameraListenerWrapper mCameraListener;
private OrientationHelper mOrientationHelper;
private CameraImpl mCameraImpl;
private PreviewImpl mPreviewImpl;
@ -113,9 +114,10 @@ public class CameraView extends FrameLayout implements LifecycleObserver {
mFacing = a.getInteger(R.styleable.CameraView_cameraFacing, CameraKit.Defaults.DEFAULT_FACING);
mFlash = a.getInteger(R.styleable.CameraView_cameraFlash, CameraKit.Defaults.DEFAULT_FLASH);
mFocus = a.getInteger(R.styleable.CameraView_cameraFocus, CameraKit.Defaults.DEFAULT_FOCUS);
mMethod = a.getInteger(R.styleable.CameraView_cameraCaptureMethod, CameraKit.Defaults.DEFAULT_METHOD);
// mMethod = a.getInteger(R.styleable.CameraView_cameraCaptureMethod, CameraKit.Defaults.DEFAULT_METHOD);
// mPermissions = a.getInteger(R.styleable.CameraView_cameraPermissionPolicy, CameraKit.Defaults.DEFAULT_PERMISSIONS);
mSessionType = a.getInteger(R.styleable.CameraView_cameraSessionType, CameraKit.Defaults.DEFAULT_SESSION_TYPE);
mZoom = a.getInteger(R.styleable.CameraView_cameraZoomMode, CameraKit.Defaults.DEFAULT_ZOOM);
mPermissions = a.getInteger(R.styleable.CameraView_cameraPermissionPolicy, CameraKit.Defaults.DEFAULT_PERMISSIONS);
mWhiteBalance = a.getInteger(R.styleable.CameraView_cameraWhiteBalance, CameraKit.Defaults.DEFAULT_WHITE_BALANCE);
mVideoQuality = a.getInteger(R.styleable.CameraView_cameraVideoQuality, CameraKit.Defaults.DEFAULT_VIDEO_QUALITY);
mJpegQuality = a.getInteger(R.styleable.CameraView_cameraJpegQuality, CameraKit.Defaults.DEFAULT_JPEG_QUALITY);
@ -126,7 +128,7 @@ public class CameraView extends FrameLayout implements LifecycleObserver {
}
}
mCameraListener = new CameraListenerMiddleWare();
mCameraListener = new CameraListenerWrapper();
mPreviewImpl = new TextureViewPreview(context, this);
mCameraImpl = new Camera1(mCameraListener, mPreviewImpl);
@ -135,9 +137,10 @@ public class CameraView extends FrameLayout implements LifecycleObserver {
setFacing(mFacing);
setFlash(mFlash);
setFocus(mFocus);
setCaptureMethod(mMethod);
setSessionType(mSessionType);
// setCaptureMethod(mMethod);
// setPermissionPolicy(mPermissions);
setZoom(mZoom);
setPermissionPolicy(mPermissions);
setVideoQuality(mVideoQuality);
setWhiteBalance(mWhiteBalance);
@ -311,32 +314,70 @@ public class CameraView extends FrameLayout implements LifecycleObserver {
// Already started, do nothing.
return;
}
checkPermissionPolicyOrThrow();
if (checkPermissions()) {
mIsStarted = true;
run(new Runnable() {
@Override
public void run() {
mCameraImpl.start();
}
});
}
}
/**
* Checks that we have appropriate permissions for this session type.
* Throws if session = audio and manifest did not add the microphone permissions.
* @return true if we can go on, false otherwise.
*/
private boolean checkPermissions() {
checkPermissionsManifestOrThrow();
int cameraCheck = ContextCompat.checkSelfPermission(getContext(), Manifest.permission.CAMERA);
int audioCheck = ContextCompat.checkSelfPermission(getContext(), Manifest.permission.RECORD_AUDIO);
switch (mPermissions) {
case PERMISSIONS_VIDEO:
switch (mSessionType) {
case SESSION_TYPE_VIDEO:
if (cameraCheck != PackageManager.PERMISSION_GRANTED || audioCheck != PackageManager.PERMISSION_GRANTED) {
requestPermissions(true, true);
return;
return false;
}
break;
case PERMISSIONS_PICTURE:
case SESSION_TYPE_PICTURE:
if (cameraCheck != PackageManager.PERMISSION_GRANTED) {
requestPermissions(true, false);
return;
return false;
}
break;
}
return true;
}
mIsStarted = true;
run(new Runnable() {
@Override
public void run() {
mCameraImpl.start();
/**
* If mSessionType == SESSION_TYPE_VIDEO we will ask for RECORD_AUDIO permission.
* If the developer did not add this to its manifest, throw and fire warnings.
* (Hoping this is not cought elsewhere... we should test).
*/
private void checkPermissionsManifestOrThrow() {
if (mSessionType == SESSION_TYPE_VIDEO) {
try {
PackageManager manager = getContext().getPackageManager();
PackageInfo info = manager.getPackageInfo(getContext().getPackageName(), PackageManager.GET_PERMISSIONS);
for (String requestedPermission : info.requestedPermissions) {
if (requestedPermission.equals(Manifest.permission.RECORD_AUDIO)) {
return;
}
}
String message = "When the session type is set to video, the RECORD_AUDIO permission " +
"should be added to the application manifest file.";
Log.w(TAG, message);
throw new IllegalStateException(message);
} catch (PackageManager.NameNotFoundException e) {
// Not possible.
}
}
});
}
public void stop() {
@ -349,10 +390,17 @@ public class CameraView extends FrameLayout implements LifecycleObserver {
}
public void destroy() {
mCameraListener = new CameraListenerWrapper(); // Release inner listener.
// This might be useless, but no time to think about it now.
sWorkerHandler = null;
}
/**
* If present, returns a collection of extra properties from the current camera
* session.
* @return an ExtraProperties object.
*/
@Nullable
public ExtraProperties getExtraProperties() {
return mCameraImpl.getExtraProperties();
@ -386,11 +434,15 @@ public class CameraView extends FrameLayout implements LifecycleObserver {
return mWhiteBalance;
}
@Facing
public int getFacing() {
return mFacing;
}
/**
* Sets which camera sensor should be used.
*
* @see CameraKit.Constants#FACING_FRONT
* @see CameraKit.Constants#FACING_BACK
*
* @param facing a facing value.
*/
public void setFacing(@Facing final int facing) {
this.mFacing = facing;
run(new Runnable() {
@ -401,16 +453,53 @@ public class CameraView extends FrameLayout implements LifecycleObserver {
});
}
/**
* Gets the facing camera currently being used.
* @return a facing value.
*/
@Facing
public int getFacing() {
return mFacing;
}
/**
* Sets the flash mode.
*
* @see CameraKit.Constants#FLASH_OFF
* @see CameraKit.Constants#FLASH_ON
* @see CameraKit.Constants#FLASH_AUTO
* @see CameraKit.Constants#FLASH_TORCH
* @param flash desired flash mode.
*/
public void setFlash(@Flash int flash) {
this.mFlash = flash;
mCameraImpl.setFlash(flash);
}
/**
* Gets the current flash mode.
* @return a flash mode
*/
@Flash
public int getFlash() {
return mFlash;
}
/**
* Sets the current focus behavior.
*
* @see CameraKit.Constants#FOCUS_CONTINUOUS
* @see CameraKit.Constants#FOCUS_OFF
* @see CameraKit.Constants#FOCUS_TAP
* @see CameraKit.Constants#FOCUS_TAP_WITH_MARKER
* @param focus a Focus value.
*/
public void setFocus(@Focus int focus) {
this.mFocus = focus;
if (this.mFocus == CameraKit.Constants.FOCUS_TAP_WITH_MARKER) {
@ -421,23 +510,54 @@ public class CameraView extends FrameLayout implements LifecycleObserver {
mCameraImpl.setFocus(mFocus);
}
/**
* This does nothing.
* @param method no-op
* @deprecated
*/
@Deprecated
public void setCaptureMethod(@Method int method) {
this.mMethod = method;
mCameraImpl.setMethod(mMethod);
}
public void setZoom(@ZoomMode int zoom) {
this.mZoom = zoom;
mCameraImpl.setZoom(mZoom);
}
/**
* Sets permission policy.
* @param permissions desired policy, either picture or video.
* This does nothing.
* @param permissions no-op
* @deprecated
*/
@Deprecated
public void setPermissionPolicy(@Permissions int permissions) {
this.mPermissions = permissions;
checkPermissionPolicyOrThrow();
}
/**
* Set the current session type to either picture or video.
*
* @see CameraKit.Constants#SESSION_TYPE_PICTURE
* @see CameraKit.Constants#SESSION_TYPE_VIDEO
*
* @param sessionType desired session type.
*/
public void setSessionType(@SessionType int sessionType) {
if (sessionType == mSessionType || !mIsStarted) {
// Check did took place, or will happen on start().
mSessionType = sessionType;
mCameraImpl.setSessionType(sessionType);
} else if (checkPermissions()) {
// Camera is running. CameraImpl setSessionType will do the trick.
mSessionType = sessionType;
mCameraImpl.setSessionType(sessionType);
} else {
// This means that the audio permission is being asked.
// Stop the camera so it can be restarted by the developer onPermissionResult.
// Developer must also set the session type again...
// Not ideal but good for now.
stop();
}
}
public void setVideoQuality(@VideoQuality int videoQuality) {
@ -445,6 +565,13 @@ public class CameraView extends FrameLayout implements LifecycleObserver {
mCameraImpl.setVideoQuality(mVideoQuality);
}
public void setZoom(@ZoomMode int zoom) {
this.mZoom = zoom;
mCameraImpl.setZoom(mZoom);
}
public void setJpegQuality(int jpegQuality) {
this.mJpegQuality = jpegQuality;
}
@ -453,6 +580,13 @@ public class CameraView extends FrameLayout implements LifecycleObserver {
this.mCropOutput = cropOutput;
}
/**
* Toggles the facing value between {@link CameraKit.Constants#FACING_BACK}
* and {@link CameraKit.Constants#FACING_FRONT}.
*
* @return the new facing value
*/
@Facing
public int toggleFacing() {
switch (mFacing) {
@ -488,8 +622,15 @@ public class CameraView extends FrameLayout implements LifecycleObserver {
return mFlash;
}
/**
* Sets a {@link CameraListener} instance to be notified of all
* interesting events that will happen during the camera lifecycle.
*
* @param cameraListener a listener for events.
*/
public void setCameraListener(CameraListener cameraListener) {
this.mCameraListener.setCameraListener(cameraListener);
this.mCameraListener.wrapListener(cameraListener);
}
public void captureImage() {
@ -544,87 +685,60 @@ public class CameraView extends FrameLayout implements LifecycleObserver {
}
}
private class CameraListenerMiddleWare extends CameraListener {
private class CameraListenerWrapper extends CameraListener {
private CameraListener mCameraListener;
private CameraListener mWrappedListener;
@Override
public void onCameraOpened() {
super.onCameraOpened();
getCameraListener().onCameraOpened();
if (mWrappedListener == null) return;
mWrappedListener.onCameraOpened();
}
@Override
public void onCameraClosed() {
super.onCameraClosed();
getCameraListener().onCameraClosed();
if (mWrappedListener == null) return;
mWrappedListener.onCameraClosed();
}
@Override
public void onPictureTaken(byte[] jpeg) {
super.onPictureTaken(jpeg);
if (mWrappedListener == null) return;
if (mCropOutput) {
AspectRatio outputRatio = AspectRatio.of(getWidth(), getHeight());
getCameraListener().onPictureTaken(new CenterCrop(jpeg, outputRatio, mJpegQuality).getJpeg());
mWrappedListener.onPictureTaken(new CenterCrop(jpeg, outputRatio, mJpegQuality).getJpeg());
} else {
getCameraListener().onPictureTaken(jpeg);
mWrappedListener.onPictureTaken(jpeg);
}
}
@Override
public void onPictureTaken(YuvImage yuv) {
super.onPictureTaken(yuv);
if (mWrappedListener == null) return;
if (mCropOutput) {
AspectRatio outputRatio = AspectRatio.of(getWidth(), getHeight());
getCameraListener().onPictureTaken(new CenterCrop(yuv, outputRatio, mJpegQuality).getJpeg());
mWrappedListener.onPictureTaken(new CenterCrop(yuv, outputRatio, mJpegQuality).getJpeg());
} else {
ByteArrayOutputStream out = new ByteArrayOutputStream();
yuv.compressToJpeg(new Rect(0, 0, yuv.getWidth(), yuv.getHeight()), mJpegQuality, out);
getCameraListener().onPictureTaken(out.toByteArray());
mWrappedListener.onPictureTaken(out.toByteArray());
}
}
@Override
public void onVideoTaken(File video) {
super.onVideoTaken(video);
getCameraListener().onVideoTaken(video);
mWrappedListener.onVideoTaken(video);
}
public void setCameraListener(@Nullable CameraListener cameraListener) {
this.mCameraListener = cameraListener;
private void wrapListener(@Nullable CameraListener cameraListener) {
mWrappedListener = cameraListener;
}
@NonNull
public CameraListener getCameraListener() {
return mCameraListener != null ? mCameraListener : new CameraListener() {
};
}
}
/**
* If mPermissions == PERMISSIONS_VIDEO we will ask for RECORD_AUDIO permission.
* If the developer did not add this to its manifest, throw and fire warnings.
* (Hoping this is not cought elsewhere... we should test).
*/
private void checkPermissionPolicyOrThrow() {
if (mPermissions == PERMISSIONS_VIDEO) {
try {
PackageManager manager = getContext().getPackageManager();
PackageInfo info = manager.getPackageInfo(getContext().getPackageName(), PackageManager.GET_PERMISSIONS);
for (String requestedPermission : info.requestedPermissions) {
if (requestedPermission.equals(Manifest.permission.RECORD_AUDIO)) {
return;
}
}
String message = "When the permission policy is PERMISSION_VIDEO, the RECORD_AUDIO permission " +
"should be added to the application manifest file.";
Log.w(TAG, message);
throw new IllegalStateException(message);
} catch (PackageManager.NameNotFoundException e) {
// Not possible.
}
}
}
}

@ -43,6 +43,11 @@
<enum name="frame" value="1" />
</attr>
<attr name="cameraSessionType" format="enum">
<enum name="picture" value="0" />
<enum name="video" value="1" />
</attr>
<attr name="cameraPermissionPolicy" format="enum">
<enum name="video" value="0" />
<enum name="picture" value="1" />

@ -8,6 +8,7 @@ import java.lang.annotation.RetentionPolicy;
import static com.flurgle.camerakit.CameraKit.Constants.CAPTURE_METHOD_STANDARD;
import static com.flurgle.camerakit.CameraKit.Constants.CAPTURE_METHOD_FRAME;
@Deprecated
@Retention(RetentionPolicy.SOURCE)
@IntDef({CAPTURE_METHOD_STANDARD, CAPTURE_METHOD_FRAME})
public @interface Method {

@ -8,6 +8,7 @@ import java.lang.annotation.RetentionPolicy;
import static com.flurgle.camerakit.CameraKit.Constants.PERMISSIONS_PICTURE;
import static com.flurgle.camerakit.CameraKit.Constants.PERMISSIONS_VIDEO;
@Deprecated
@Retention(RetentionPolicy.SOURCE)
@IntDef({PERMISSIONS_VIDEO, PERMISSIONS_PICTURE})
public @interface Permissions {

Loading…
Cancel
Save