Heavy refactoring, setParameters bug fixed

pull/1/head
Mattia Iavarone 7 years ago
parent 474d26e0c4
commit 3dbd7fa945
  1. 384
      camerakit/src/main/api16/com/flurgle/camerakit/Camera1.java
  2. 13
      camerakit/src/main/api21/com/flurgle/camerakit/Camera2.java
  3. 3
      camerakit/src/main/base/com/flurgle/camerakit/CameraImpl.java
  4. 38
      camerakit/src/main/base/com/flurgle/camerakit/PreviewImpl.java
  5. 11
      camerakit/src/main/base/com/flurgle/camerakit/SurfaceViewPreview.java
  6. 9
      camerakit/src/main/base/com/flurgle/camerakit/TextureViewPreview.java
  7. 13
      camerakit/src/main/java/com/flurgle/camerakit/CameraView.java
  8. 5
      demo/src/main/AndroidManifest.xml
  9. 31
      demo/src/main/java/com/flurgle/camerakit/demo/MainActivity.java
  10. 14
      demo/src/main/java/com/flurgle/camerakit/demo/PicturePreviewActivity.java
  11. 21
      demo/src/main/java/com/flurgle/camerakit/demo/ResultHolder.java
  12. 63
      demo/src/main/java/com/flurgle/camerakit/demo/VideoPreviewActivity.java
  13. 16
      demo/src/main/res/layout/activity_main.xml
  14. 0
      demo/src/main/res/layout/activity_picture_preview.xml
  15. 39
      demo/src/main/res/layout/activity_video_preview.xml

@ -8,11 +8,10 @@ import android.media.MediaRecorder;
import android.os.Build; import android.os.Build;
import android.os.Handler; import android.os.Handler;
import android.support.annotation.NonNull; import android.support.annotation.NonNull;
import android.util.Log;
import android.support.annotation.Nullable; import android.support.annotation.Nullable;
import android.util.Log;
import android.view.MotionEvent; import android.view.MotionEvent;
import android.view.SurfaceHolder; import android.view.SurfaceHolder;
import android.view.View;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
@ -38,9 +37,7 @@ class Camera1 extends CameraImpl {
private int mCameraId; private int mCameraId;
private Camera mCamera; private Camera mCamera;
private Camera.Parameters mCameraParameters;
private ExtraProperties mExtraProperties; private ExtraProperties mExtraProperties;
private Camera.CameraInfo mCameraInfo;
private Size mPreviewSize; private Size mPreviewSize;
private Size mCaptureSize; private Size mCaptureSize;
private MediaRecorder mMediaRecorder; private MediaRecorder mMediaRecorder;
@ -63,48 +60,60 @@ class Camera1 extends CameraImpl {
private double mLongitude; private double mLongitude;
private boolean mFocusOnTap; private boolean mFocusOnTap;
private Handler mHandler = new Handler(); private Handler mFocusHandler = new Handler();
private ConstantMapper.MapperImpl mMapper = new ConstantMapper.Mapper1(); private ConstantMapper.MapperImpl mMapper = new ConstantMapper.Mapper1();
private boolean mIsSetup = false;
private final Object mLock = new Object();
Camera1(CameraView.CameraListenerWrapper callback, PreviewImpl preview) {
Camera1(CameraView.CameraListenerWrapper callback, final PreviewImpl preview) {
super(callback, preview); super(callback, preview);
preview.setCallback(new PreviewImpl.OnPreviewSurfaceChangedCallback() {
@Override
public void onPreviewSurfaceChanged() {
if (mCamera != null) {
setupPreview();
computeCameraSizes();
adjustCameraParameters();
} }
}
});
mCameraInfo = new Camera.CameraInfo();
/**
* Preview surface is now available. If camera is open, set up.
*/
@Override
public void onSurfaceAvailable() {
Log.e(TAG, "onSurfaceAvailable, size is "+mPreview.getSurfaceSize());
if (shouldSetup()) setup();
} }
// CameraImpl: /**
* Preview surface did change its size. Compute a new preview size.
* This requires stopping and restarting the preview.
*/
@Override @Override
void start() { public void onSurfaceChanged() {
setFacing(mFacing); Log.e(TAG, "onSurfaceChanged, size is "+mPreview.getSurfaceSize());
openCamera(); if (mIsSetup) {
if (mPreview.isReady()) setupPreview(); // Compute a new camera preview size.
Size newSize = computePreviewSize();
if (!newSize.equals(mPreviewSize)) {
mPreviewSize = newSize;
synchronized (mLock) {
mCamera.stopPreview();
Camera.Parameters params = mCamera.getParameters();
params.setPreviewSize(mPreviewSize.getWidth(), mPreviewSize.getHeight());
mCamera.setParameters(params);
}
boolean invertPreviewSizes = shouldFlipSizes();
mPreview.setDesiredSize(
invertPreviewSizes ? mPreviewSize.getHeight() : mPreviewSize.getWidth(),
invertPreviewSizes ? mPreviewSize.getWidth() : mPreviewSize.getHeight()
);
mCamera.startPreview(); mCamera.startPreview();
} }
}
}
@Override private boolean shouldSetup() {
void stop() { return isCameraOpened() && mPreview.isReady() && !mIsSetup;
if (mCamera != null) mCamera.stopPreview();
mHandler.removeCallbacksAndMessages(null);
releaseCamera();
} }
/** // The act of binding an "open" camera to a "ready" preview.
* Sets the output stream for our preview. // These can happen at different times but we want to end up here.
* To be called when preview is ready. private void setup() {
*/
private void setupPreview() {
try { try {
if (mPreview.getOutputClass() == SurfaceHolder.class) { if (mPreview.getOutputClass() == SurfaceHolder.class) {
mCamera.setPreviewDisplay(mPreview.getSurfaceHolder()); mCamera.setPreviewDisplay(mPreview.getSurfaceHolder());
@ -114,9 +123,79 @@ class Camera1 extends CameraImpl {
} catch (IOException e) { } catch (IOException e) {
throw new RuntimeException(e); throw new RuntimeException(e);
} }
boolean invertPreviewSizes = shouldFlipSizes(); // mDisplayOffset % 180 != 0;
mCaptureSize = computeCaptureSize();
mPreviewSize = computePreviewSize();
mPreview.setDesiredSize(
invertPreviewSizes ? mPreviewSize.getHeight() : mPreviewSize.getWidth(),
invertPreviewSizes ? mPreviewSize.getWidth() : mPreviewSize.getHeight()
);
synchronized (mLock) {
Camera.Parameters params = mCamera.getParameters();
params.setPreviewSize(mPreviewSize.getWidth(), mPreviewSize.getHeight());
params.setPictureSize(mCaptureSize.getWidth(), mCaptureSize.getHeight()); // <- not allowed during preview
mCamera.setParameters(params);
}
mCamera.startPreview();
mIsSetup = true;
} }
@Override
void start() {
if (isCameraOpened()) stop();
if (collectCameraId()) {
mCamera = Camera.open(mCameraId);
mCameraListener.onCameraOpened();
// Set parameters that might have been set before the camera was opened.
synchronized (mLock) {
Camera.Parameters params = mCamera.getParameters();
mergeFocus(params, mFocus);
mergeFlash(params, mFlash);
mergeLocation(params, mLatitude, mLongitude);
mergeWhiteBalance(params, mWhiteBalance);
params.setRecordingHint(mSessionType == SESSION_TYPE_VIDEO);
mCamera.setParameters(params);
}
// Try starting preview.
mCamera.setDisplayOrientation(computeCameraToDisplayOffset()); // <- not allowed during preview
if (shouldSetup()) setup();
collectExtraProperties();
}
}
@Override
void stop() {
mFocusHandler.removeCallbacksAndMessages(null);
if (isCameraOpened()) {
mCamera.stopPreview();
mCamera.release();
mCameraListener.onCameraClosed();
}
mCamera = null;
mPreviewSize = null;
mCaptureSize = null;
mIsSetup = false;
}
private boolean collectCameraId() {
int internalFacing = mMapper.mapFacing(mFacing);
Camera.CameraInfo cameraInfo = new Camera.CameraInfo();
for (int i = 0, count = Camera.getNumberOfCameras(); i < count; i++) {
Camera.getCameraInfo(i, cameraInfo);
if (cameraInfo.facing == internalFacing) {
mSensorOffset = cameraInfo.orientation;
mCameraId = i;
return true;
}
}
return false;
}
@Override @Override
void onDisplayOffset(int displayOrientation) { void onDisplayOffset(int displayOrientation) {
// I doubt this will ever change. // I doubt this will ever change.
@ -134,7 +213,6 @@ class Camera1 extends CameraImpl {
if (sessionType != mSessionType) { if (sessionType != mSessionType) {
mSessionType = sessionType; mSessionType = sessionType;
if (isCameraOpened()) { if (isCameraOpened()) {
stop();
start(); start();
} }
} }
@ -142,75 +220,83 @@ class Camera1 extends CameraImpl {
@Override @Override
void setLocation(double latitude, double longitude) { void setLocation(double latitude, double longitude) {
double oldLat = mLatitude;
double oldLong = mLongitude;
mLatitude = latitude; mLatitude = latitude;
mLongitude = longitude; mLongitude = longitude;
if (mCameraParameters != null) { if (isCameraOpened()) {
// Sometimes this will fail... I have no idea why. synchronized (mLock) {
// Since native_setParameters is quite a black box, there's nothing we can do about it. Camera.Parameters params = mCamera.getParameters();
try { if (mergeLocation(params, oldLat, oldLong)) mCamera.setParameters(params);
mCameraParameters.setGpsLatitude(latitude);
mCameraParameters.setGpsLongitude(longitude);
// mCameraParameters.setGpsAltitude(0);
// mCameraParameters.setGpsTimestamp(System.currentTimeMillis());
// mCameraParameters.setGpsProcessingMethod("GPS");
mCamera.setParameters(mCameraParameters);
} catch (Exception e) {
// Reset or everything after will throw as well.
e.printStackTrace();
mCameraParameters = mCamera.getParameters();
} }
} }
} }
@Override private boolean mergeLocation(Camera.Parameters params, double oldLatitude, double oldLongitude) {
void setFacing(@Facing int facing) { if (mLatitude != 0 && mLongitude != 0) {
int internalFacing = mMapper.mapFacing(facing); params.setGpsLatitude(mLatitude);
for (int i = 0, count = Camera.getNumberOfCameras(); i < count; i++) { params.setGpsLongitude(mLongitude);
Camera.getCameraInfo(i, mCameraInfo); params.setGpsTimestamp(System.currentTimeMillis());
if (mCameraInfo.facing == internalFacing) { params.setGpsProcessingMethod("Unknown");
mSensorOffset = mCameraInfo.orientation;
mCameraId = i;
mFacing = facing;
break;
} }
return true;
} }
if (mFacing == facing && isCameraOpened()) { @Override
stop(); void setFacing(@Facing int facing) {
if (facing != mFacing) {
mFacing = facing;
if (collectCameraId() && isCameraOpened()) {
start(); start();
} }
} }
}
@Override @Override
void setWhiteBalance(@WhiteBalance int whiteBalance) { void setWhiteBalance(@WhiteBalance int whiteBalance) {
int old = mWhiteBalance; int old = mWhiteBalance;
mWhiteBalance = whiteBalance; mWhiteBalance = whiteBalance;
if (mCameraParameters != null) { if (isCameraOpened()) {
List<String> supported = mCameraParameters.getSupportedWhiteBalance(); synchronized (mLock) {
String internal = mMapper.mapWhiteBalance(whiteBalance); Camera.Parameters params = mCamera.getParameters();
if (supported != null && supported.contains(internal)) { if (mergeWhiteBalance(params, old)) mCamera.setParameters(params);
mCameraParameters.setWhiteBalance(internal); }
mCamera.setParameters(mCameraParameters); }
} else {
mWhiteBalance = old;
} }
private boolean mergeWhiteBalance(Camera.Parameters params, @WhiteBalance int oldWhiteBalance) {
List<String> supported = params.getSupportedWhiteBalance();
String internal = mMapper.mapWhiteBalance(mWhiteBalance);
if (supported != null && supported.contains(internal)) {
params.setWhiteBalance(internal);
return true;
} }
mWhiteBalance = oldWhiteBalance;
return false;
} }
@Override @Override
void setFlash(@Flash int flash) { void setFlash(@Flash int flash) {
int old = mFlash; int old = mFlash;
mFlash = flash; mFlash = flash;
if (mCameraParameters != null) { if (isCameraOpened()) {
List<String> flashes = mCameraParameters.getSupportedFlashModes(); synchronized (mLock) {
String internalFlash = mMapper.mapFlash(flash); Camera.Parameters params = mCamera.getParameters();
if (flashes != null && flashes.contains(internalFlash)) { if (mergeFlash(params, old)) mCamera.setParameters(params);
mCameraParameters.setFlashMode(internalFlash); }
mCamera.setParameters(mCameraParameters);
} else {
mFlash = old;
} }
} }
private boolean mergeFlash(Camera.Parameters params, @Flash int oldFlash) {
List<String> flashes = params.getSupportedFlashModes();
String internalFlash = mMapper.mapFlash(mFlash);
if (flashes != null && flashes.contains(internalFlash)) {
params.setFlashMode(internalFlash);
return true;
}
mFlash = oldFlash;
return false;
} }
@ -218,43 +304,45 @@ class Camera1 extends CameraImpl {
void setFocus(@Focus int focus) { void setFocus(@Focus int focus) {
int old = mFocus; int old = mFocus;
mFocus = focus; mFocus = focus;
if (mCameraParameters == null) return; if (isCameraOpened()) {
switch (focus) { synchronized (mLock) {
case FOCUS_CONTINUOUS: Camera.Parameters params = mCamera.getParameters();
mFocusOnTap = false; if (mergeFocus(params, old)) mCamera.setParameters(params);
final List<String> modes = mCameraParameters.getSupportedFocusModes();
if (modes.contains(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE)) {
mCameraParameters.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE);
} else {
mFocus = old;
} }
break; }
mFocusOnTap = mFocus == FOCUS_TAP || mFocus == FOCUS_TAP_WITH_MARKER;
}
private boolean mergeFocus(Camera.Parameters params, @Focus int oldFocus) {
final List<String> modes = params.getSupportedFocusModes();
switch (mFocus) {
case FOCUS_CONTINUOUS:
case FOCUS_TAP: case FOCUS_TAP:
case FOCUS_TAP_WITH_MARKER: case FOCUS_TAP_WITH_MARKER:
mFocusOnTap = true; if (modes.contains(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE)) {
final List<String> modes1 = mCameraParameters.getSupportedFocusModes(); params.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE);
if (modes1.contains(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE)) { return true;
mCameraParameters.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE);
} else {
mFocus = old;
} }
break; mFocus = oldFocus;
return false;
case FOCUS_OFF: case FOCUS_OFF:
mFocusOnTap = false; if (modes.contains(Camera.Parameters.FOCUS_MODE_FIXED)) {
final List<String> modes2 = mCameraParameters.getSupportedFocusModes(); params.setFocusMode(Camera.Parameters.FOCUS_MODE_FIXED);
if (modes2.contains(Camera.Parameters.FOCUS_MODE_FIXED)) { return true;
mCameraParameters.setFocusMode(Camera.Parameters.FOCUS_MODE_FIXED); } else if (modes.contains(Camera.Parameters.FOCUS_MODE_INFINITY)) {
} else if (modes2.contains(Camera.Parameters.FOCUS_MODE_INFINITY)) { params.setFocusMode(Camera.Parameters.FOCUS_MODE_INFINITY);
mCameraParameters.setFocusMode(Camera.Parameters.FOCUS_MODE_INFINITY); return true;
} else { } else if (modes.contains(Camera.Parameters.FOCUS_MODE_AUTO)) {
mCameraParameters.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO); params.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO);
return true;
} }
break;
} }
return false;
} }
@Override @Override
void setZoom(@ZoomMode int zoom) { void setZoom(@ZoomMode int zoom) {
this.mZoom = zoom; this.mZoom = zoom;
@ -263,26 +351,29 @@ class Camera1 extends CameraImpl {
@Override @Override
void setVideoQuality(int videoQuality) { void setVideoQuality(int videoQuality) {
this.mVideoQuality = videoQuality; this.mVideoQuality = videoQuality;
// TODO: restore preview size if needed.
} }
@Override @Override
void captureImage() { void captureImage() {
if (isCapturingImage) return; if (isCapturingImage) return;
if (mCamera == null) return; if (!isCameraOpened()) return;
switch (mSessionType) { switch (mSessionType) {
case SESSION_TYPE_PICTURE: case SESSION_TYPE_PICTURE:
// Set boolean to wait for image callback // Set boolean to wait for image callback
isCapturingImage = true; isCapturingImage = true;
synchronized (mLock) {
Camera.Parameters parameters = mCamera.getParameters(); Camera.Parameters parameters = mCamera.getParameters();
parameters.setRotation(computeExifOrientation()); parameters.setRotation(computeExifOrientation());
mCamera.setParameters(parameters); mCamera.setParameters(parameters);
}
mCamera.takePicture(null, null, null, mCamera.takePicture(null, null, null,
new Camera.PictureCallback() { new Camera.PictureCallback() {
@Override @Override
public void onPictureTaken(byte[] data, Camera camera) { public void onPictureTaken(byte[] data, Camera camera) {
mCameraListener.onPictureTaken(data); mCameraListener.onPictureTaken(data);
isCapturingImage = false; isCapturingImage = false;
camera.startPreview(); // TODO: is this needed? why? camera.startPreview(); // This is needed, read somewhere in the docs.
} }
}); });
break; break;
@ -297,13 +388,14 @@ class Camera1 extends CameraImpl {
public void onPreviewFrame(final byte[] data, Camera camera) { public void onPreviewFrame(final byte[] data, Camera camera) {
// Got to rotate the preview frame, since byte[] data here does not include // Got to rotate the preview frame, since byte[] data here does not include
// EXIF tags automatically set by camera. So either we add EXIF, or we rotate. // EXIF tags automatically set by camera. So either we add EXIF, or we rotate.
Camera.Parameters params = mCamera.getParameters();
final int rotation = computeExifOrientation(); final int rotation = computeExifOrientation();
final boolean flip = rotation % 180 != 0; final boolean flip = rotation % 180 != 0;
final int preWidth = mPreviewSize.getWidth(); final int preWidth = mPreviewSize.getWidth();
final int preHeight = mPreviewSize.getHeight(); final int preHeight = mPreviewSize.getHeight();
final int postWidth = flip ? preHeight : preWidth; final int postWidth = flip ? preHeight : preWidth;
final int postHeight = flip ? preWidth : preHeight; final int postHeight = flip ? preWidth : preHeight;
final int format = mCameraParameters.getPreviewFormat(); final int format = params.getPreviewFormat();
new Thread(new Runnable() { new Thread(new Runnable() {
@Override @Override
public void run() { public void run() {
@ -347,38 +439,13 @@ class Camera1 extends CameraImpl {
// Internal: // Internal:
private void openCamera() {
if (mCamera != null) {
releaseCamera();
}
mCamera = Camera.open(mCameraId);
mCameraParameters = mCamera.getParameters();
collectCameraProperties();
computeCameraSizes();
adjustCameraParameters();
mCamera.setDisplayOrientation(computeCameraToDisplayOffset());
mCameraListener.onCameraOpened();
}
private void releaseCamera() {
if (mCamera != null) {
mCamera.release();
mCamera = null;
mCameraParameters = null;
mPreviewSize = null;
mCaptureSize = null;
mCameraListener.onCameraClosed();
}
}
/** /**
* Returns how much should the sensor image be rotated before being shown. * Returns how much should the sensor image be rotated before being shown.
* It is meant to be fed to Camera.setDisplayOrientation(). * It is meant to be fed to Camera.setDisplayOrientation().
*/ */
private int computeCameraToDisplayOffset() { private int computeCameraToDisplayOffset() {
if (mCameraInfo.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) { if (mFacing == CameraKit.Constants.FACING_FRONT) {
// or: (360 - ((info.orientation + displayOrientation) % 360)) % 360; // or: (360 - ((info.orientation + displayOrientation) % 360)) % 360;
return ((mSensorOffset - mDisplayOffset) + 360 + 180) % 360; return ((mSensorOffset - mDisplayOffset) + 360 + 180) % 360;
} else { } else {
@ -399,45 +466,35 @@ class Camera1 extends CameraImpl {
* This is called either on cameraView.start(), or when the underlying surface changes. * This is called either on cameraView.start(), or when the underlying surface changes.
* It is possible that in the first call the preview surface has not already computed its * It is possible that in the first call the preview surface has not already computed its
* dimensions. * dimensions.
* But when it does, the {@link PreviewImpl.OnPreviewSurfaceChangedCallback} should be called, * But when it does, the {@link PreviewImpl.SurfaceCallback} should be called,
* and this should be refreshed. * and this should be refreshed.
*/ */
private void computeCameraSizes() { private Size computeCaptureSize() {
mCameraParameters.setRecordingHint(mSessionType == SESSION_TYPE_VIDEO); Camera.Parameters params = mCamera.getParameters();
List<Size> previewSizes = sizesFromList(mCameraParameters.getSupportedPreviewSizes());
if (mSessionType == SESSION_TYPE_PICTURE) { if (mSessionType == SESSION_TYPE_PICTURE) {
// Choose the max size. // Choose the max size.
List<Size> captureSizes = sizesFromList(mCameraParameters.getSupportedPictureSizes()); List<Size> captureSizes = sizesFromList(params.getSupportedPictureSizes());
mCaptureSize = Collections.max(captureSizes); return Collections.max(captureSizes);
} else { } else {
// Choose according to developer choice in setVideoQuality. // Choose according to developer choice in setVideoQuality.
// The Camcorder internally checks for cameraParameters.getSupportedVideoSizes() etc. // The Camcorder internally checks for cameraParameters.getSupportedVideoSizes() etc.
// So its output is our output. // So its output is our output.
CamcorderProfile camcorderProfile = getCamcorderProfile(mVideoQuality); CamcorderProfile camcorderProfile = getCamcorderProfile(mVideoQuality);
mCaptureSize = new Size(camcorderProfile.videoFrameWidth, camcorderProfile.videoFrameHeight); return new Size(camcorderProfile.videoFrameWidth, camcorderProfile.videoFrameHeight);
} }
mPreviewSize = computePreviewSize(previewSizes, mCaptureSize, mPreview.getSurfaceSize());
// Log.e("Camera1", "CaptureSize is "+mCaptureSize.toString());
// Log.e("Camera1", "PreviewSize is "+mPreviewSize.toString());
} }
private void adjustCameraParameters() { private Size computePreviewSize() {
boolean invertPreviewSizes = shouldFlipSizes(); // mDisplayOffset % 180 != 0; Camera.Parameters params = mCamera.getParameters();
mPreview.setDesiredSize( List<Size> previewSizes = sizesFromList(params.getSupportedPreviewSizes());
invertPreviewSizes ? getPreviewSize().getHeight() : getPreviewSize().getWidth(), return computePreviewSize(previewSizes, mCaptureSize, mPreview.getSurfaceSize());
invertPreviewSizes ? getPreviewSize().getWidth() : getPreviewSize().getHeight()
);
mCameraParameters.setPreviewSize(getPreviewSize().getWidth(), getPreviewSize().getHeight());
mCameraParameters.setPictureSize(getCaptureSize().getWidth(), getCaptureSize().getHeight());
setFocus(mFocus);
setFlash(mFlash);
setLocation(mLatitude, mLongitude);
mCamera.setParameters(mCameraParameters);
} }
private void collectCameraProperties() {
mExtraProperties = new ExtraProperties(mCameraParameters.getVerticalViewAngle(), private void collectExtraProperties() {
mCameraParameters.getHorizontalViewAngle()); Camera.Parameters params = mCamera.getParameters();
mExtraProperties = new ExtraProperties(params.getVerticalViewAngle(),
params.getHorizontalViewAngle());
} }
@ -546,15 +603,17 @@ class Camera1 extends CameraImpl {
if (!mFocusOnTap) return; if (!mFocusOnTap) return;
if (mCamera == null) return; if (mCamera == null) return;
if (event.getAction() != MotionEvent.ACTION_UP) return; if (event.getAction() != MotionEvent.ACTION_UP) return;
Camera.Parameters parameters = mCamera.getParameters();
Rect rect = calculateFocusArea(event.getX(), event.getY()); Rect rect = calculateFocusArea(event.getX(), event.getY());
List<Camera.Area> meteringAreas = new ArrayList<>(); List<Camera.Area> meteringAreas = new ArrayList<>();
meteringAreas.add(new Camera.Area(rect, getFocusMeteringAreaWeight())); meteringAreas.add(new Camera.Area(rect, getFocusMeteringAreaWeight()));
synchronized (mLock) {
Camera.Parameters parameters = mCamera.getParameters();
boolean autofocusSupported = parameters.getSupportedFocusModes().contains(Camera.Parameters.FOCUS_MODE_AUTO); boolean autofocusSupported = parameters.getSupportedFocusModes().contains(Camera.Parameters.FOCUS_MODE_AUTO);
if (autofocusSupported) { if (autofocusSupported) {
if (parameters.getMaxNumFocusAreas() > 0) parameters.setFocusAreas(meteringAreas); if (parameters.getMaxNumFocusAreas() > 0) parameters.setFocusAreas(meteringAreas);
if (parameters.getMaxNumMeteringAreas() > 0) parameters.setMeteringAreas(meteringAreas); if (parameters.getMaxNumMeteringAreas() > 0)
parameters.setMeteringAreas(meteringAreas);
parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO); parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO);
mCamera.setParameters(parameters); mCamera.setParameters(parameters);
mCamera.autoFocus(new Camera.AutoFocusCallback() { mCamera.autoFocus(new Camera.AutoFocusCallback() {
@ -565,6 +624,7 @@ class Camera1 extends CameraImpl {
}); });
} }
} }
}
private int getFocusAreaSize() { private int getFocusAreaSize() {
@ -578,18 +638,20 @@ class Camera1 extends CameraImpl {
private void resetFocus(final boolean success, final Camera camera) { private void resetFocus(final boolean success, final Camera camera) {
mHandler.removeCallbacksAndMessages(null); mFocusHandler.removeCallbacksAndMessages(null);
mHandler.postDelayed(new Runnable() { mFocusHandler.postDelayed(new Runnable() {
@Override @Override
public void run() { public void run() {
if (camera != null) { if (camera != null) {
camera.cancelAutoFocus(); camera.cancelAutoFocus();
synchronized (mLock) {
Camera.Parameters params = camera.getParameters(); Camera.Parameters params = camera.getParameters();
if (!params.getFocusMode().equals(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE)) { if (!params.getFocusMode().equals(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE)) {
params.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE); params.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE);
params.setFocusAreas(null); params.setFocusAreas(null);
params.setMeteringAreas(null); params.setMeteringAreas(null);
camera.setParameters(params); mCamera.setParameters(params);
}
} }
if (mAutofocusCallback != null) mAutofocusCallback.onAutoFocus(success, camera); if (mAutofocusCallback != null) mAutofocusCallback.onAutoFocus(success, camera);

@ -37,15 +37,18 @@ class Camera2 extends CameraImpl {
private ConstantMapper.MapperImpl mMapper = new ConstantMapper.Mapper2(); private ConstantMapper.MapperImpl mMapper = new ConstantMapper.Mapper2();
private final HashMap<String, ExtraProperties> mExtraPropertiesMap = new HashMap<>(); private final HashMap<String, ExtraProperties> mExtraPropertiesMap = new HashMap<>();
Camera2(CameraView.CameraListenerWrapper callback, PreviewImpl preview, Context context) {
super(callback, preview);
preview.setCallback(new PreviewImpl.OnPreviewSurfaceChangedCallback() {
@Override @Override
public void onPreviewSurfaceChanged() { public void onSurfaceChanged() {
}
@Override
public void onSurfaceAvailable() {
} }
});
Camera2(CameraView.CameraListenerWrapper callback, PreviewImpl preview, Context context) {
super(callback, preview);
mCameraManager = (CameraManager) context.getSystemService(Context.CAMERA_SERVICE); mCameraManager = (CameraManager) context.getSystemService(Context.CAMERA_SERVICE);
// Get all view angles // Get all view angles

@ -6,7 +6,7 @@ import android.view.MotionEvent;
import java.io.File; import java.io.File;
abstract class CameraImpl { abstract class CameraImpl implements PreviewImpl.SurfaceCallback {
protected final CameraView.CameraListenerWrapper mCameraListener; protected final CameraView.CameraListenerWrapper mCameraListener;
protected final PreviewImpl mPreview; protected final PreviewImpl mPreview;
@ -14,6 +14,7 @@ abstract class CameraImpl {
CameraImpl(CameraView.CameraListenerWrapper callback, PreviewImpl preview) { CameraImpl(CameraView.CameraListenerWrapper callback, PreviewImpl preview) {
mCameraListener = callback; mCameraListener = callback;
mPreview = preview; mPreview = preview;
mPreview.setSurfaceCallback(this);
} }
abstract void start(); abstract void start();

@ -7,11 +7,12 @@ import android.view.View;
abstract class PreviewImpl { abstract class PreviewImpl {
interface OnPreviewSurfaceChangedCallback { interface SurfaceCallback {
void onPreviewSurfaceChanged(); void onSurfaceAvailable();
void onSurfaceChanged();
} }
private OnPreviewSurfaceChangedCallback mOnPreviewSurfaceChangedCallback; private SurfaceCallback mSurfaceCallback;
// As far as I can see, these are the view/surface dimensions. // As far as I can see, these are the view/surface dimensions.
// This live in the 'View' orientation. // This live in the 'View' orientation.
@ -22,8 +23,8 @@ abstract class PreviewImpl {
private int mDesiredWidth; private int mDesiredWidth;
private int mDesiredHeight; private int mDesiredHeight;
void setCallback(OnPreviewSurfaceChangedCallback callback) { void setSurfaceCallback(SurfaceCallback callback) {
mOnPreviewSurfaceChangedCallback = callback; mSurfaceCallback = callback;
} }
abstract Surface getSurface(); abstract Surface getSurface();
@ -37,10 +38,6 @@ abstract class PreviewImpl {
abstract boolean isReady(); abstract boolean isReady();
protected void dispatchSurfaceChanged() {
mOnPreviewSurfaceChangedCallback.onPreviewSurfaceChanged();
}
SurfaceHolder getSurfaceHolder() { SurfaceHolder getSurfaceHolder() {
return null; return null;
} }
@ -49,12 +46,27 @@ abstract class PreviewImpl {
return null; return null;
} }
protected final void onSurfaceAvailable(int width, int height) {
mSurfaceWidth = width;
mSurfaceHeight = height;
refreshScale();
mSurfaceCallback.onSurfaceAvailable();
}
// As far as I can see, these are the view/surface dimensions. // As far as I can see, these are the view/surface dimensions.
// This is called by subclasses. // This is called by subclasses.
protected void setSurfaceSize(int width, int height) { protected final void onSurfaceSizeChanged(int width, int height) {
this.mSurfaceWidth = width; if (width != mSurfaceWidth || height != mSurfaceHeight) {
this.mSurfaceHeight = height; mSurfaceWidth = width;
refreshScale(); // Refresh true preview size to adjust scaling mSurfaceHeight = height;
refreshScale();
mSurfaceCallback.onSurfaceChanged();
}
}
protected final void onSurfaceDestroyed() {
mSurfaceWidth = 0;
mSurfaceHeight = 0;
refreshScale();
} }
// As far as I can see, these are the actual preview dimensions, as set in CameraParameters. // As far as I can see, these are the actual preview dimensions, as set in CameraParameters.

@ -1,12 +1,9 @@
package com.flurgle.camerakit; package com.flurgle.camerakit;
import android.annotation.TargetApi;
import android.content.Context; import android.content.Context;
import android.graphics.SurfaceTexture;
import android.view.Surface; import android.view.Surface;
import android.view.SurfaceHolder; import android.view.SurfaceHolder;
import android.view.SurfaceView; import android.view.SurfaceView;
import android.view.TextureView;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
@ -23,19 +20,17 @@ class SurfaceViewPreview extends PreviewImpl {
holder.addCallback(new SurfaceHolder.Callback() { holder.addCallback(new SurfaceHolder.Callback() {
@Override @Override
public void surfaceCreated(SurfaceHolder holder) { public void surfaceCreated(SurfaceHolder holder) {
setSurfaceSize(mSurfaceView.getWidth(), mSurfaceView.getHeight()); onSurfaceAvailable(mSurfaceView.getWidth(), mSurfaceView.getHeight());
dispatchSurfaceChanged();
} }
@Override @Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
setSurfaceSize(width, height); onSurfaceSizeChanged(width, height);
dispatchSurfaceChanged();
} }
@Override @Override
public void surfaceDestroyed(SurfaceHolder holder) { public void surfaceDestroyed(SurfaceHolder holder) {
setSurfaceSize(0, 0); onSurfaceDestroyed();
} }
}); });
} }

@ -21,20 +21,17 @@ class TextureViewPreview extends PreviewImpl {
@Override @Override
public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) { public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
setSurfaceSize(width, height); onSurfaceAvailable(width, height);
dispatchSurfaceChanged();
} }
@Override @Override
public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) { public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {
setSurfaceSize(width, height); onSurfaceSizeChanged(width, height);
dispatchSurfaceChanged();
// refreshScale();
} }
@Override @Override
public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) { public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
setSurfaceSize(0, 0); onSurfaceDestroyed();
return true; return true;
} }

@ -203,12 +203,14 @@ public class CameraView extends FrameLayout implements LifecycleObserver {
@Override @Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
if (!mAdjustViewBounds) { if (!mAdjustViewBounds) {
Log.e(TAG, "onMeasure, adjustViewBounds=false");
super.onMeasure(widthMeasureSpec, heightMeasureSpec); super.onMeasure(widthMeasureSpec, heightMeasureSpec);
return; return;
} }
Size previewSize = getPreviewSize(); Size previewSize = getPreviewSize();
if (previewSize == null) { // Early measure. if (previewSize == null) { // Early measure.
Log.e(TAG, "onMeasure, early measure");
super.onMeasure(widthMeasureSpec, heightMeasureSpec); super.onMeasure(widthMeasureSpec, heightMeasureSpec);
return; return;
} }
@ -218,21 +220,18 @@ public class CameraView extends FrameLayout implements LifecycleObserver {
boolean flip = mCameraImpl.shouldFlipSizes(); boolean flip = mCameraImpl.shouldFlipSizes();
float previewWidth = flip ? previewSize.getHeight() : previewSize.getWidth(); float previewWidth = flip ? previewSize.getHeight() : previewSize.getWidth();
float previewHeight = flip ? previewSize.getWidth() : previewSize.getHeight(); float previewHeight = flip ? previewSize.getWidth() : previewSize.getHeight();
float parentHeight = MeasureSpec.getSize(heightMeasureSpec);
float parentWidth = MeasureSpec.getSize(widthMeasureSpec); // mode = AT_MOST
Log.e(TAG, "onMeasure, parent size is "+new Size((int)parentWidth, (int)parentHeight)); // 1080x1794
Log.e(TAG, "onMeasure, surface size is "+new Size((int)previewWidth, (int)previewHeight)); // 1600x1200
if (wwc && hwc) { if (wwc && hwc) {
// If both dimensions are WRAP_CONTENT, let's try to fit the preview size perfectly // If both dimensions are WRAP_CONTENT, let's try to fit the preview size perfectly
// without cropping. // without cropping.
// TODO: This should actually be a flag, like scaleMode, that replaces cropOutput and adjustViewBounds. // TODO: This should actually be a flag, like scaleMode, that replaces cropOutput and adjustViewBounds.
// This is like a fitCenter. // This is like a fitCenter.
// preview: 1600x1200
// parent: 1080x1794
float parentHeight = MeasureSpec.getSize(heightMeasureSpec);
float parentWidth = MeasureSpec.getSize(widthMeasureSpec); // mode = AT_MOST
float targetRatio = previewHeight / previewWidth; float targetRatio = previewHeight / previewWidth;
float currentRatio = parentHeight / parentWidth; float currentRatio = parentHeight / parentWidth;
Log.e(TAG, "parentHeight="+parentHeight+", parentWidth="+parentWidth);
Log.e(TAG, "previewHeight="+previewHeight+", previewWidth="+previewWidth);
if (currentRatio > targetRatio) { if (currentRatio > targetRatio) {
// View is too tall. Must reduce height. // View is too tall. Must reduce height.
int newHeight = (int) (parentWidth * targetRatio); int newHeight = (int) (parentWidth * targetRatio);

@ -22,8 +22,9 @@
</activity> </activity>
<activity <activity
android:name=".PreviewActivity" android:name=".PicturePreviewActivity" />
android:screenOrientation="portrait" />
<activity android:name=".VideoPreviewActivity"/>
</application> </application>

@ -3,6 +3,7 @@ package com.flurgle.camerakit.demo;
import android.content.Intent; import android.content.Intent;
import android.graphics.Bitmap; import android.graphics.Bitmap;
import android.graphics.BitmapFactory; import android.graphics.BitmapFactory;
import android.net.Uri;
import android.os.Bundle; import android.os.Bundle;
import android.support.v7.app.AppCompatActivity; import android.support.v7.app.AppCompatActivity;
import android.view.View; import android.view.View;
@ -34,8 +35,8 @@ public class MainActivity extends AppCompatActivity implements View.OnLayoutChan
// Capture Mode: // Capture Mode:
@BindView(R.id.captureModeRadioGroup) @BindView(R.id.sessionTypeRadioGroup)
RadioGroup captureModeRadioGroup; RadioGroup sessionTypeRadioGroup;
// Crop Mode: // Crop Mode:
@ -84,7 +85,7 @@ public class MainActivity extends AppCompatActivity implements View.OnLayoutChan
camera.addOnLayoutChangeListener(this); camera.addOnLayoutChangeListener(this);
captureModeRadioGroup.setOnCheckedChangeListener(captureModeChangedListener); sessionTypeRadioGroup.setOnCheckedChangeListener(sessionTypeChangedListener);
cropModeRadioGroup.setOnCheckedChangeListener(cropModeChangedListener); cropModeRadioGroup.setOnCheckedChangeListener(cropModeChangedListener);
widthModeRadioGroup.setOnCheckedChangeListener(widthModeChangedListener); widthModeRadioGroup.setOnCheckedChangeListener(widthModeChangedListener);
heightModeRadioGroup.setOnCheckedChangeListener(heightModeChangedListener); heightModeRadioGroup.setOnCheckedChangeListener(heightModeChangedListener);
@ -122,12 +123,8 @@ public class MainActivity extends AppCompatActivity implements View.OnLayoutChan
Bitmap bitmap = BitmapFactory.decodeByteArray(jpeg, 0, jpeg.length); Bitmap bitmap = BitmapFactory.decodeByteArray(jpeg, 0, jpeg.length);
ResultHolder.dispose(); ResultHolder.dispose();
ResultHolder.setImage(bitmap); ResultHolder.setImage(bitmap);
ResultHolder.setNativeCaptureSize(
captureModeRadioGroup.getCheckedRadioButtonId() == R.id.modeCaptureStandard ?
camera.getCaptureSize() : camera.getPreviewSize()
);
ResultHolder.setTimeToCallback(callbackTime - startTime); ResultHolder.setTimeToCallback(callbackTime - startTime);
Intent intent = new Intent(MainActivity.this, PreviewActivity.class); Intent intent = new Intent(MainActivity.this, PicturePreviewActivity.class);
startActivity(intent); startActivity(intent);
} }
}); });
@ -136,6 +133,10 @@ public class MainActivity extends AppCompatActivity implements View.OnLayoutChan
@OnClick(R.id.captureVideo) @OnClick(R.id.captureVideo)
void captureVideo() { void captureVideo() {
if (camera.getSessionType() != CameraKit.Constants.SESSION_TYPE_VIDEO) {
Toast.makeText(this, "Can't record video while session type is 'picture'.", Toast.LENGTH_SHORT).show();
return;
}
if (mCapturing) return; if (mCapturing) return;
mCapturing = true; mCapturing = true;
camera.setCameraListener(new CameraListener() { camera.setCameraListener(new CameraListener() {
@ -143,16 +144,20 @@ public class MainActivity extends AppCompatActivity implements View.OnLayoutChan
public void onVideoTaken(File video) { public void onVideoTaken(File video) {
super.onVideoTaken(video); super.onVideoTaken(video);
mCapturing = false; mCapturing = false;
ResultHolder.dispose();
ResultHolder.setVideo(Uri.fromFile(video));
Intent intent = new Intent(MainActivity.this, VideoPreviewActivity.class);
startActivity(intent);
} }
}); });
Toast.makeText(this, "Recording for 3 seconds...", Toast.LENGTH_LONG).show(); Toast.makeText(this, "Recording for 8 seconds...", Toast.LENGTH_LONG).show();
camera.startCapturingVideo(null); camera.startCapturingVideo(null);
camera.postDelayed(new Runnable() { camera.postDelayed(new Runnable() {
@Override @Override
public void run() { public void run() {
camera.stopCapturingVideo(); camera.stopCapturingVideo();
} }
}, 3000); }, 8000);
} }
@OnClick(R.id.toggleCamera) @OnClick(R.id.toggleCamera)
@ -188,16 +193,16 @@ public class MainActivity extends AppCompatActivity implements View.OnLayoutChan
} }
} }
RadioGroup.OnCheckedChangeListener captureModeChangedListener = new RadioGroup.OnCheckedChangeListener() { RadioGroup.OnCheckedChangeListener sessionTypeChangedListener = new RadioGroup.OnCheckedChangeListener() {
@Override @Override
public void onCheckedChanged(RadioGroup group, int checkedId) { public void onCheckedChanged(RadioGroup group, int checkedId) {
if (mCapturing) return; if (mCapturing) return;
camera.setSessionType( camera.setSessionType(
checkedId == R.id.modeCaptureStandard ? checkedId == R.id.sessionTypePicture ?
CameraKit.Constants.SESSION_TYPE_PICTURE : CameraKit.Constants.SESSION_TYPE_PICTURE :
CameraKit.Constants.SESSION_TYPE_VIDEO CameraKit.Constants.SESSION_TYPE_VIDEO
); );
Toast.makeText(MainActivity.this, "Session type set to" + (checkedId == R.id.modeCaptureStandard ? " picture!" : " video!"), Toast.LENGTH_SHORT).show(); Toast.makeText(MainActivity.this, "Session type set to" + (checkedId == R.id.sessionTypePicture ? " picture!" : " video!"), Toast.LENGTH_SHORT).show();
} }
}; };

@ -13,7 +13,7 @@ import com.flurgle.camerakit.Size;
import butterknife.BindView; import butterknife.BindView;
import butterknife.ButterKnife; import butterknife.ButterKnife;
public class PreviewActivity extends Activity { public class PicturePreviewActivity extends Activity {
@BindView(R.id.image) @BindView(R.id.image)
ImageView imageView; ImageView imageView;
@ -33,7 +33,7 @@ public class PreviewActivity extends Activity {
@Override @Override
protected void onCreate(@Nullable Bundle savedInstanceState) { protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
setContentView(R.layout.activity_preview); setContentView(R.layout.activity_picture_preview);
ButterKnife.bind(this); ButterKnife.bind(this);
Bitmap bitmap = ResultHolder.getImage(); Bitmap bitmap = ResultHolder.getImage();
@ -44,12 +44,10 @@ public class PreviewActivity extends Activity {
imageView.setImageBitmap(bitmap); imageView.setImageBitmap(bitmap);
Size captureSize = ResultHolder.getNativeCaptureSize(); // Native sizes are landscape, activity might now. <- not clear what this means but OK
if (captureSize != null) { // TODO: ncr and ar might be different when cropOutput is true.
// Native sizes are landscape, hardcode flip because demo app forced to portrait. AspectRatio aspectRatio = AspectRatio.of(bitmap.getHeight(), bitmap.getWidth());
AspectRatio aspectRatio = AspectRatio.of(captureSize.getHeight(), captureSize.getWidth()); nativeCaptureResolution.setText(bitmap.getHeight() + " x " + bitmap.getWidth() + " (" + aspectRatio.toString() + ")");
nativeCaptureResolution.setText(captureSize.getHeight() + " x " + captureSize.getWidth() + " (" + aspectRatio.toString() + ")");
}
actualResolution.setText(bitmap.getWidth() + " x " + bitmap.getHeight()); actualResolution.setText(bitmap.getWidth() + " x " + bitmap.getHeight());
approxUncompressedSize.setText(getApproximateFileMegabytes(bitmap) + "MB"); approxUncompressedSize.setText(getApproximateFileMegabytes(bitmap) + "MB");

@ -1,6 +1,7 @@
package com.flurgle.camerakit.demo; package com.flurgle.camerakit.demo;
import android.graphics.Bitmap; import android.graphics.Bitmap;
import android.net.Uri;
import android.support.annotation.Nullable; import android.support.annotation.Nullable;
import com.flurgle.camerakit.Size; import com.flurgle.camerakit.Size;
@ -12,24 +13,24 @@ public class ResultHolder {
private static WeakReference<Bitmap> image; private static WeakReference<Bitmap> image;
private static Size nativeCaptureSize; private static Size nativeCaptureSize;
private static long timeToCallback; private static long timeToCallback;
private static Uri video;
public static void setImage(@Nullable Bitmap image) { public static Uri getVideo() {
ResultHolder.image = image != null ? new WeakReference<>(image) : null; return video;
} }
@Nullable public static void setVideo(Uri video) {
public static Bitmap getImage() { ResultHolder.video = video;
return image != null ? image.get() : null;
} }
public static void setNativeCaptureSize(@Nullable Size nativeCaptureSize) { public static void setImage(@Nullable Bitmap image) {
ResultHolder.nativeCaptureSize = nativeCaptureSize; ResultHolder.image = image != null ? new WeakReference<>(image) : null;
} }
@Nullable @Nullable
public static Size getNativeCaptureSize() { public static Bitmap getImage() {
return nativeCaptureSize; return image != null ? image.get() : null;
} }
public static void setTimeToCallback(long timeToCallback) { public static void setTimeToCallback(long timeToCallback) {
@ -42,7 +43,7 @@ public class ResultHolder {
public static void dispose() { public static void dispose() {
setImage(null); setImage(null);
setNativeCaptureSize(null); setVideo(null);
setTimeToCallback(0); setTimeToCallback(0);
} }

@ -0,0 +1,63 @@
package com.flurgle.camerakit.demo;
import android.app.Activity;
import android.graphics.Bitmap;
import android.media.MediaPlayer;
import android.net.Uri;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.view.View;
import android.widget.ImageView;
import android.widget.MediaController;
import android.widget.TextView;
import android.widget.VideoView;
import com.flurgle.camerakit.AspectRatio;
import com.flurgle.camerakit.Size;
import butterknife.BindView;
import butterknife.ButterKnife;
import butterknife.OnClick;
public class VideoPreviewActivity extends Activity {
@BindView(R.id.video)
VideoView videoView;
@BindView(R.id.actualResolution)
TextView actualResolution;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_video_preview);
ButterKnife.bind(this);
Uri videoUri = ResultHolder.getVideo();
if (videoUri == null) {
finish();
return;
}
MediaController controller = new MediaController(this);
controller.setAnchorView(videoView);
controller.setMediaPlayer(videoView);
videoView.setMediaController(controller);
videoView.setVideoURI(videoUri);
videoView.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
@Override
public void onPrepared(MediaPlayer mp) {
actualResolution.setText(mp.getVideoWidth() + " x " + mp.getVideoHeight());
}
});
playVideo();
}
@OnClick(R.id.video)
void playVideo() {
if (videoView.isPlaying()) return;
videoView.start();
}
}

@ -43,7 +43,7 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:orientation="horizontal" android:orientation="horizontal"
android:weightSum="3"> android:weightSum="4">
<ImageButton <ImageButton
android:id="@+id/capturePhoto" android:id="@+id/capturePhoto"
@ -113,31 +113,31 @@
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginLeft="3dp" android:layout_marginLeft="3dp"
android:text="CAPTURE METHOD" android:text="SESSION TYPE"
android:textColor="@android:color/black" android:textColor="@android:color/black"
android:textSize="14sp" android:textSize="14sp"
android:textStyle="bold" /> android:textStyle="bold" />
<RadioGroup <RadioGroup
android:id="@+id/captureModeRadioGroup" android:id="@+id/sessionTypeRadioGroup"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginTop="4dp" android:layout_marginTop="4dp"
android:checkedButton="@+id/modeCaptureStandard" android:checkedButton="@+id/sessionTypePicture"
android:orientation="horizontal"> android:orientation="horizontal">
<RadioButton <RadioButton
android:id="@+id/modeCaptureStandard" android:id="@+id/sessionTypePicture"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:text="Standard" /> android:text="Picture" />
<RadioButton <RadioButton
android:id="@+id/modeCaptureStill" android:id="@+id/sessionTypeVideo"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginLeft="10dp" android:layout_marginLeft="10dp"
android:text="Still" /> android:text="Video" />
</RadioGroup> </RadioGroup>

@ -0,0 +1,39 @@
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<VideoView
android:id="@+id/video"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="100dp"
android:layout_gravity="bottom"
android:gravity="center_vertical"
android:background="@android:color/white"
android:orientation="horizontal">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="8dp"
android:text="ACTUAL RESOLUTION"
android:textColor="@android:color/black"
android:textSize="18sp"
android:textStyle="bold" />
<TextView
android:id="@+id/actualResolution"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="8dp"
android:textColor="@android:color/black"
android:textSize="14.5sp" />
</LinearLayout>
</FrameLayout>
Loading…
Cancel
Save