Skip to content
This repository has been archived by the owner on Jan 14, 2024. It is now read-only.

Commit

Permalink
Updated
Browse files Browse the repository at this point in the history
* Updated Gradle version from 2.3.0 to 2.3.1
* Added dp to px converter on Utils class
* GraphicOverlay can now be initialized from any other class, not only
XML.
* CameraSourcePreview can now be initialized from any other class, not
XML only.
* Tap to Focus added to Camera2Source. Now you can focus with both
Camera APIs.
  • Loading branch information
EzequielAdrianM committed May 7, 2017
1 parent 9da4702 commit 8fd769f
Show file tree
Hide file tree
Showing 10 changed files with 209 additions and 9 deletions.
2 changes: 1 addition & 1 deletion Camera2/Camera2.iml
Expand Up @@ -13,7 +13,7 @@
<content url="file://$MODULE_DIR$">
<excludeFolder url="file://$MODULE_DIR$/.gradle" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="jdk" jdkName="1.8" jdkType="JavaSDK" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>
10 changes: 9 additions & 1 deletion Camera2/app/app.iml
Expand Up @@ -78,15 +78,23 @@
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/shaders" isTestSource="true" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/assets" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/blame" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/builds" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/classes" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/incremental" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/incremental-classes" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/incremental-runtime-classes" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/incremental-safeguard" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/incremental-verifier" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/instant-run-resources" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/instant-run-support" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/jniLibs" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/manifests" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/pre-dexed" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/reload-dex" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/res" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/restart-dex" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/rs" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/shaders" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/split-apk" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/symbols" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/transforms" />
<excludeFolder url="file://$MODULE_DIR$/build/outputs" />
Expand Down
Expand Up @@ -15,14 +15,17 @@
import android.support.v4.content.ContextCompat;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.WindowManager;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;

import com.example.ezequiel.camera2.others.Camera2Source;
import com.example.ezequiel.camera2.others.FaceGraphic;
import com.example.ezequiel.camera2.utils.Utils;
import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.GoogleApiAvailability;
import com.google.android.gms.vision.MultiProcessor;
Expand All @@ -45,6 +48,7 @@ public class MainActivity extends AppCompatActivity {
private static final int REQUEST_CAMERA_PERMISSION = 200;
private static final int REQUEST_STORAGE_PERMISSION = 201;
private TextView cameraVersion;
private ImageView ivAutoFocus;

// CAMERA VERSION ONE DECLARATIONS
private CameraSource mCameraSource = null;
Expand Down Expand Up @@ -78,6 +82,7 @@ protected void onCreate(Bundle savedInstanceState) {
mPreview = (CameraSourcePreview) findViewById(R.id.preview);
mGraphicOverlay = (GraphicOverlay) findViewById(R.id.faceOverlay);
cameraVersion = (TextView) findViewById(R.id.cameraVersion);
ivAutoFocus = (ImageView) findViewById(R.id.ivAutoFocus);

if(checkGooglePlayAvailability()) {
requestPermissionThenOpenCamera();
Expand Down Expand Up @@ -107,6 +112,8 @@ public void onClick(View v) {
}
}
});

mPreview.setOnTouchListener(CameraPreviewTouchListener);
}
}

Expand Down Expand Up @@ -354,6 +361,49 @@ public void onDone() {
}
}

private final CameraSourcePreview.OnTouchListener CameraPreviewTouchListener = new CameraSourcePreview.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent pEvent) {
v.onTouchEvent(pEvent);
if (pEvent.getAction() == MotionEvent.ACTION_DOWN) {
int autoFocusX = (int) (pEvent.getX() - Utils.dpToPx(60)/2);
int autoFocusY = (int) (pEvent.getY() - Utils.dpToPx(60)/2);
ivAutoFocus.setTranslationX(autoFocusX);
ivAutoFocus.setTranslationY(autoFocusY);
ivAutoFocus.setVisibility(View.VISIBLE);
ivAutoFocus.bringToFront();
if(useCamera2) {
if(mCamera2Source != null) {
mCamera2Source.autoFocus(new Camera2Source.AutoFocusCallback() {
@Override
public void onAutoFocus(boolean success) {
runOnUiThread(new Runnable() {
@Override public void run() {ivAutoFocus.setVisibility(View.GONE);}
});
}
}, pEvent, v.getWidth(), v.getHeight());
} else {
ivAutoFocus.setVisibility(View.GONE);
}
} else {
if(mCameraSource != null) {
mCameraSource.autoFocus(new CameraSource.AutoFocusCallback() {
@Override
public void onAutoFocus(boolean success) {
runOnUiThread(new Runnable() {
@Override public void run() {ivAutoFocus.setVisibility(View.GONE);}
});
}
});
} else {
ivAutoFocus.setVisibility(View.GONE);
}
}
}
return false;
}
};

@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
if (requestCode == REQUEST_CAMERA_PERMISSION) {
Expand All @@ -377,7 +427,16 @@ public void onRequestPermissionsResult(int requestCode, @NonNull String[] permis
protected void onResume() {
super.onResume();
if(wasActivityResumed)
startCameraSource();
//If the CAMERA2 is paused then resumed, it won't start again unless creating the whole camera again.
if(useCamera2) {
if(usingFrontCamera) {
createCameraSourceFront();
} else {
createCameraSourceBack();
}
} else {
startCameraSource();
}
}

@Override
Expand Down
Expand Up @@ -9,6 +9,7 @@
import android.graphics.ImageFormat;
import android.graphics.Matrix;
import android.graphics.Point;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.SurfaceTexture;
import android.hardware.camera2.CameraAccessException;
Expand All @@ -17,9 +18,11 @@
import android.hardware.camera2.CameraDevice;
import android.hardware.camera2.CameraManager;
import android.hardware.camera2.CameraMetadata;
import android.hardware.camera2.CaptureFailure;
import android.hardware.camera2.CaptureRequest;
import android.hardware.camera2.CaptureResult;
import android.hardware.camera2.TotalCaptureResult;
import android.hardware.camera2.params.MeteringRectangle;
import android.hardware.camera2.params.StreamConfigurationMap;
import android.media.Image;
import android.media.ImageReader;
Expand All @@ -29,10 +32,12 @@
import android.os.SystemClock;
import android.support.annotation.IntDef;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.annotation.RequiresPermission;
import android.support.v4.content.ContextCompat;
import android.util.Log;
import android.util.SparseIntArray;
import android.view.MotionEvent;
import android.view.Surface;

import com.example.ezequiel.camera2.utils.Utils;
Expand Down Expand Up @@ -178,6 +183,11 @@ public class Camera2Source {

private ShutterCallback mShutterCallback;

private AutoFocusCallback mAutoFocusCallback;

private Rect sensorArraySize;
private boolean isMeteringAreaAFSupported = false;

private CameraManager manager = null;

static {
Expand Down Expand Up @@ -274,7 +284,29 @@ public void onCaptureProgressed(@NonNull CameraCaptureSession session, @NonNull

@Override
public void onCaptureCompleted(@NonNull CameraCaptureSession session, @NonNull CaptureRequest request, @NonNull TotalCaptureResult result) {
process(result);
if(request.getTag() == ("FOCUS_TAG")) {
//The focus trigger is complete!
//Resume repeating request, clear AF trigger.
mAutoFocusCallback.onAutoFocus(true);
mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AF_TRIGGER, null);
mPreviewRequestBuilder.setTag("");
mPreviewRequest = mPreviewRequestBuilder.build();
try {
mCaptureSession.setRepeatingRequest(mPreviewRequest, mCaptureCallback, mBackgroundHandler);
} catch(CameraAccessException ex) {
Log.d("ASD", "AUTO FOCUS FAILURE: "+ex);
}
} else {
process(result);
}
}

@Override
public void onCaptureFailed(@NonNull CameraCaptureSession session, @NonNull CaptureRequest request, @NonNull CaptureFailure failure) {
if(request.getTag() == "FOCUS_TAG") {
Log.d("ASD", "Manual AF failure: "+failure);
mAutoFocusCallback.onAutoFocus(false);
}
}

};
Expand Down Expand Up @@ -306,19 +338,19 @@ public void onImageAvailable(ImageReader reader) {
*/
private CameraDevice.StateCallback mStateCallback = new CameraDevice.StateCallback() {
@Override
public void onOpened(CameraDevice cameraDevice) {
public void onOpened(@NonNull CameraDevice cameraDevice) {
mCameraOpenCloseLock.release();
mCameraDevice = cameraDevice;
createCameraPreviewSession();
}
@Override
public void onDisconnected(CameraDevice cameraDevice) {
public void onDisconnected(@NonNull CameraDevice cameraDevice) {
mCameraOpenCloseLock.release();
cameraDevice.close();
mCameraDevice = null;
}
@Override
public void onError(CameraDevice cameraDevice, int error) {
public void onError(@NonNull CameraDevice cameraDevice, int error) {
mCameraOpenCloseLock.release();
cameraDevice.close();
mCameraDevice = null;
Expand Down Expand Up @@ -414,7 +446,23 @@ public interface PictureCallback {
void onPictureTaken(Image image);
}

// AUTO FOCUS PART HAS BEEN OMITTED FOR SIMPLICITY.
/**
* Callback interface used to notify on completion of camera auto focus.
*/
public interface AutoFocusCallback {
/**
* Called when the camera auto focus completes. If the camera
* does not support auto-focus and autoFocus is called,
* onAutoFocus will be called immediately with a fake value of
* <code>success</code> set to <code>true</code>.
* <p/>
* The auto-focus routine does not lock auto-exposure and auto-white
* balance after it completes.
*
* @param success true if focus was successful, false if otherwise
*/
void onAutoFocus(boolean success);
}

//==============================================================================================
// Public
Expand Down Expand Up @@ -558,6 +606,45 @@ public int getCameraFacing() {
return mFacing;
}

public void autoFocus(@Nullable AutoFocusCallback cb, MotionEvent pEvent, int screenW, int screenH) {
if(cb != null) {
mAutoFocusCallback = cb;
}
if(sensorArraySize != null) {
final int y = (int)pEvent.getX() / screenW * sensorArraySize.height();
final int x = (int)pEvent.getY() / screenH * sensorArraySize.width();
final int halfTouchWidth = 150;
final int halfTouchHeight = 150;
MeteringRectangle focusAreaTouch = new MeteringRectangle(
Math.max(x-halfTouchWidth, 0),
Math.max(y-halfTouchHeight, 0),
halfTouchWidth*2,
halfTouchHeight*2,
MeteringRectangle.METERING_WEIGHT_MAX - 1);

try {
mCaptureSession.stopRepeating();
//Cancel any existing AF trigger (repeated touches, etc.)
mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AF_TRIGGER, CameraMetadata.CONTROL_AF_TRIGGER_CANCEL);
mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_OFF);
mCaptureSession.capture(mPreviewRequestBuilder.build(), mCaptureCallback, mBackgroundHandler);

//Now add a new AF trigger with focus region
if(isMeteringAreaAFSupported) {
mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AF_REGIONS, new MeteringRectangle[]{focusAreaTouch});
}
mPreviewRequestBuilder.set(CaptureRequest.CONTROL_MODE, CameraMetadata.CONTROL_MODE_AUTO);
mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_AUTO);
mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AF_TRIGGER, CameraMetadata.CONTROL_AF_TRIGGER_START);
mPreviewRequestBuilder.setTag("FOCUS_TAG"); //we'll capture this later for resuming the preview!
//Then we ask for a single request (not repeating!)
mCaptureSession.capture(mPreviewRequestBuilder.build(), mCaptureCallback, mBackgroundHandler);
} catch(CameraAccessException ex) {
Log.d("ASD", "AUTO FOCUS EXCEPTION: "+ex);
}
}
}

/**
* Initiate a still image capture. The camera preview is suspended
* while the picture is being taken, but will resume once picture taking is done.
Expand Down Expand Up @@ -724,6 +811,11 @@ private void setUpCameraOutputs(int width, int height) {
mImageReaderStill = ImageReader.newInstance(largest.getWidth(), largest.getHeight(), ImageFormat.JPEG, /*maxImages*/2);
mImageReaderStill.setOnImageAvailableListener(mOnImageAvailableListener, mBackgroundHandler);

sensorArraySize = characteristics.get(CameraCharacteristics.SENSOR_INFO_ACTIVE_ARRAY_SIZE);
Integer maxAFRegions = characteristics.get(CameraCharacteristics.CONTROL_MAX_REGIONS_AF);
if(maxAFRegions != null) {
isMeteringAreaAFSupported = maxAFRegions >= 1;
}
// Find out if we need to swap dimension to get the preview size relative to sensor
// coordinate.
int displayRotation = mDisplayOrientation;
Expand Down
Expand Up @@ -39,6 +39,19 @@ public class CameraSourcePreview extends ViewGroup {
private int screenHeight;
private int screenRotation;

public CameraSourcePreview(Context context) {
super(context);
screenHeight = Utils.getScreenHeight(context);
screenWidth = Utils.getScreenWidth(context);
screenRotation = Utils.getScreenRotation(context);
mStartRequested = false;
mSurfaceAvailable = false;
mSurfaceView = new SurfaceView(context);
mSurfaceView.getHolder().addCallback(mSurfaceViewListener);
mAutoFitTextureView = new AutoFitTextureView(context);
mAutoFitTextureView.setSurfaceTextureListener(mSurfaceTextureListener);
}

public CameraSourcePreview(Context context, AttributeSet attrs) {
super(context, attrs);
screenHeight = Utils.getScreenHeight(context);
Expand Down
Expand Up @@ -107,6 +107,10 @@ public void postInvalidate() {
}
}

public GraphicOverlay(Context context) {
super(context);
}

public GraphicOverlay(Context context, AttributeSet attrs) {
super(context, attrs);
}
Expand Down
Expand Up @@ -5,6 +5,7 @@
*/

import android.content.Context;
import android.content.res.Resources;
import android.graphics.Point;
import android.graphics.PointF;
import android.util.DisplayMetrics;
Expand All @@ -17,6 +18,10 @@

public class Utils {

public static int dpToPx(int dp) {
return (int) (dp * Resources.getSystem().getDisplayMetrics().density);
}

public static int getScreenHeight(Context c) {
WindowManager wm = (WindowManager) c.getSystemService(Context.WINDOW_SERVICE);
Display display = wm.getDefaultDisplay();
Expand Down
11 changes: 11 additions & 0 deletions Camera2/app/src/main/res/drawable/btn_autofocus.xml
@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:innerRadius="0dp"
android:shape="ring"
android:thicknessRatio="2"
android:useLevel="false" >
<solid android:color="@android:color/transparent" />
<stroke
android:width="2dp"
android:color="@android:color/white" />
</shape>

0 comments on commit 8fd769f

Please sign in to comment.