I'm creating barcode reading application using google vision and it consists a flash on/off function also. i was able to implement flash using "CameraManager" like in the following code due to the "Camera" is now deprecated.but when camera screen is on, flash light is not working.when camera is freeze(when barcode is detected i'm stoping the camerasource), flash light is working. but i want to flash light on/off with out regarding the camera view is on or stop.i need this get done without using the deprecated APIs.can some one tell me how i can get solved this problem. thanks in advance.
private void setupBarcode(){
cameraPreview = (SurfaceView) findViewById(R.id.cameraPreview);
txtResult = findViewById(R.id.txtResult);
barcodeDetector = new BarcodeDetector.Builder(this)
.setBarcodeFormats(Barcode.ALL_FORMATS)
.build();
cameraSource = new CameraSource
.Builder(this, barcodeDetector)
.setAutoFocusEnabled(true)
.build();
//Add Event
cameraPreview.getHolder().addCallback(new SurfaceHolder.Callback() {
#Override
public void surfaceCreated(SurfaceHolder surfaceHolder) {
if (ActivityCompat.checkSelfPermission(getApplicationContext(), android.Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
//Request permission
ActivityCompat.requestPermissions(ScanActivity.this,
new String[]{Manifest.permission.CAMERA}, RequestCameraPermissionID);
return;
}
try {
cameraSource.start(cameraPreview.getHolder());
txtResult.setText("");
} catch (IOException e) {
e.printStackTrace();
}
}
#Override
public void surfaceChanged(SurfaceHolder surfaceHolder, int i, int i1, int i2) {
}
#Override
public void surfaceDestroyed(SurfaceHolder surfaceHolder) {
cameraSource.stop();
}
});
barcodeDetector.setProcessor(new Detector.Processor<Barcode>() {
#Override
public void release() {
}
#Override
public void receiveDetections(Detector.Detections<Barcode> detections) {
final SparseArray<Barcode> qrcodes = detections.getDetectedItems();
if (qrcodes.size() != 0) {
txtResult.post(new Runnable() {
#Override
public void run() {
okButton.setEnabled(true);
txtResult.setText(qrcodes.valueAt(0).displayValue);
cameraSource.stop();
}
});
}
}
});
}
private void flashLightOn() {
CameraManager cameraManager = (CameraManager) getSystemService(Context.CAMERA_SERVICE);
try {
String cameraId = cameraManager.getCameraIdList()[0];
cameraManager.setTorchMode(cameraId, true);
} catch (CameraAccessException e) {
}
}
Use the open source 'CameraSource.java' file from goole vision library in your project.
Get file from here
And then use the following code:
public void switchFlashLight(boolean status) {
cameraSource.setFlashMode(status ? Camera.Parameters.FLASH_MODE_TORCH : Camera.Parameters.FLASH_MODE_OFF);
}
Related
How to crop the SurfaceView for OCR, that OCR would be doing recognition only on the part of the photo, which is in the frame.
I used this tutorial! And for now the whole surface is recognizable. While I want to recognize only part of the whole SurfaceView, as for example in barcodes.
But still, User should have the picture of full surface.
I tried to use TextureView, but it's not compatible with CameraSouce.
private void startCameraSource() {
//Create the TextRecognizer
final TextRecognizer textRecognizer = new TextRecognizer.Builder(getApplicationContext()).build();
if (!textRecognizer.isOperational()) {
Log.w(TAG, "Detector dependencies not loaded yet");
} else {
//Initialize camerasource to use high resolution and set Autofocus on.
mCameraSource = new CameraSource.Builder(getApplicationContext(), textRecognizer)
.setFacing(CameraSource.CAMERA_FACING_BACK)
.setRequestedPreviewSize(1280, 1024)
.setAutoFocusEnabled(true)
.setRequestedFps(2.0f)
.build();
/*
Add call back to SurfaceView and check if camera permission is granted.
If permission is granted we can start our cameraSource and pass it to surfaceView
*/
surfaceView.getHolder().addCallback(new SurfaceHolder.Callback() {
#Override
public void surfaceCreated(SurfaceHolder holder) {
try {
if (ActivityCompat.checkSelfPermission(getApplicationContext(),
Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
return;
}
mCameraSource.start(surfaceView.getHolder());
} catch (IOException e) {
e.printStackTrace();
}
}
#Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
}
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
mCameraSource.stop();
}
});
//Set the TextRecognizer's Processor.
textRecognizer.setProcessor(new Detector.Processor<TextBlock>() {
#Override
public void release() {
}
/**
* Detect all the text from camera using TextBlock and the values into a stringBuilder
* which will then be set to the textView.
* */
#Override
public void receiveDetections(Detector.Detections<TextBlock> detections) {
final SparseArray<TextBlock> items = detections.getDetectedItems();
if (items.size() != 0) {
mTextView.post(new Runnable() {
#Override
public void run() {
StringBuilder stringBuilder = new StringBuilder();
for (int i = 0; i < items.size(); i++) {
TextBlock item = items.valueAt(i);
stringBuilder.append(item.getValue());
stringBuilder.append("\n");
}
String detectedext = stringBuilder.toString().replace("\n", "").replace("\r", "");
detectedext = detectedext.replaceAll("\\D+", "");
String comparisonResult = queryEquiNoDatabase(detectedext);
System.out.println(detectedext);
if (comparisonResult == null) {
textViewRectangle.setBackgroundResource(R.drawable.textview_border_detecting);
} else {
textViewRectangle.setBackgroundResource(R.drawable.textview_border_end);
Intent intentAfterCameraScan = new Intent(getApplicationContext(), TransformerBoxActivity.class);
intentAfterCameraScan.putExtra("equino", comparisonResult);
intentAfterCameraScan.putExtra("isOcrLast", true);
createEffect(intentAfterCameraScan, 1500);
textRecognizer.release();
}
}
});
}
}
});
}
}
The picture of the activity:
https://imgur.com/a/wc5Yjjb
What is actually recognized:
https://imgur.com/5LkmFzH
And I expect to recognize only thing which are inside the borders
For now the whole surface is applied for recognition.
I was trying to scan barcode using goggle vision api but am unable my app is scanning qr-codes correctly but when focusing on barcode it can't detect these is my snipe of code suggest me please:
camerapreview = (SurfaceView) findViewById(R.id.camerapreview);
barcodeDetector = new BarcodeDetector.Builder(this)
.setBarcodeFormats(Barcode.DATA_MATRIX | Barcode.QR_CODE)
.build();
if (!barcodeDetector.isOperational()) {
Toast.makeText(Scanner.this, "Could not set up the detector! Update google play services", Toast.LENGTH_LONG).show();
return;
}
cameraSource = new CameraSource
.Builder(this, barcodeDetector)
.setRequestedPreviewSize(640, 480)
.build();
//add event
camerapreview.getHolder().addCallback(new SurfaceHolder.Callback() {
#Override
public void surfaceCreated(SurfaceHolder holder) {
try {
cameraSource.start(camerapreview.getHolder());
} catch (IOException e) {
e.printStackTrace();
}
}
#Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
}
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
cameraSource.stop();
}
});
barcodeDetector.setProcessor(new Detector.Processor<Barcode>() {
#Override
public void release() {
try {
cameraSource.start(camerapreview.getHolder());
} catch (IOException e) {
e.printStackTrace();
}
}
....................
the app is scanning qr-codes perfectly but it can't detect barcodes i can't get it working please help
You need to set the accepted formats to include "Barcode".
Specific codes to change are:
barcodeDetector = new BarcodeDetector.Builder(this)
.setBarcodeFormats(Barcode.ALL_FORMATS)
.build();
Replace Barcode.DATA_MATRIX | Barcode.QR_CODE with Barcode.ALL_FORMATS
I am designing an app where i scan the text using the camera and use that text to fetch more details. To do that i am using Google's vision API. But by default the API reads all the text that is available on the image as shown below.
As you can see from the above image the app is recognizing all the text that is available in front of the camera. But i would like to just scan "Hello World" from the camera. Is it possible to use some kind of touch event just to focus on the desired text
Please find the code used for text recognition
private void startCameraSource() {
//Create the TextRecognizer
final TextRecognizer textRecognizer = new TextRecognizer.Builder(getApplicationContext()).build();
if (!textRecognizer.isOperational()) {
Log.w(TAG, "Detector dependencies not loaded yet");
} else {
//Initialize camerasource to use high resolution and set Autofocus on.
mCameraSource = new CameraSource.Builder(getApplicationContext(), textRecognizer)
.setFacing(CameraSource.CAMERA_FACING_BACK)
.setRequestedPreviewSize(1280, 1024)
.setAutoFocusEnabled(true)
.setRequestedFps(2.0f)
.build();
/**
* Add call back to SurfaceView and check if camera permission is granted.
* If permission is granted we can start our cameraSource and pass it to surfaceView
*/
mCameraView.getHolder().addCallback(new SurfaceHolder.Callback() {
#Override
public void surfaceCreated(SurfaceHolder holder) {
try {
if (ActivityCompat.checkSelfPermission(getApplicationContext(),
Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(MainActivity.this,
new String[]{Manifest.permission.CAMERA},
requestPermissionID);
return;
}
mCameraSource.start(mCameraView.getHolder());
} catch (IOException e) {
e.printStackTrace();
}
}
#Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
}
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
mCameraSource.stop();
}
});
//Set the TextRecognizer's Processor.
textRecognizer.setProcessor(new Detector.Processor<TextBlock>() {
#Override
public void release() {
}
/**
* Detect all the text from camera using TextBlock and the values into a stringBuilder
* which will then be set to the textView.
* */
#Override
public void receiveDetections(Detector.Detections<TextBlock> detections) {
final SparseArray<TextBlock> items = detections.getDetectedItems();
if (items.size() != 0 ){
mTextView.post(new Runnable() {
#Override
public void run() {
StringBuilder stringBuilder = new StringBuilder();
for(int i=0;i<items.size();i++){
TextBlock item = items.valueAt(i);
stringBuilder.append(item.getValue());
stringBuilder.append("\n");
}
mTextView.setText(stringBuilder.toString());
}
});
}
}
});
}
}
I have used the Camera2 API to implement a background video recorder running as a service and recording from the front cam. For this I have created a new SurfaceView, set its size to 1x1 and moved it to the top left corner. My code is shown below. I'm using Android 5.1.
With the Camera API it worked very well but unfortunately the frame rate is only at 20 fps (and when I increase the exposure compensation it drops even more), although with the Open Camera app I have 30 fps also with increased exposure compensation. That is why I want to try Camera2 API (hoping to get higher fps). Unfortunately, I'm getting the following error:
MediaRecoder: setOutputFile called in an invalid state(2)
MediaRecorder: start called in an invalid state: 2
Here is my code:
public class RecorderServiceCamera2 extends Service implements SurfaceHolder.Callback {
private WindowManager windowManager;
private SurfaceView surfaceView;
private CameraDevice mCamera;
private MediaRecorder mediaRecorder = null;
private CaptureRequest mCaptureRequest;
private CameraCaptureSession mSession;
#Override
public void onCreate() {
// Create new SurfaceView, set its size to 1x1, move it to the top left corner and set this service as a callback
windowManager = (WindowManager) this.getSystemService(Context.WINDOW_SERVICE);
surfaceView = new SurfaceView(this);
WindowManager.LayoutParams layoutParams = new WindowManager.LayoutParams(
1, 1,
WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY,
WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH,
PixelFormat.TRANSLUCENT
);
layoutParams.gravity = Gravity.LEFT | Gravity.TOP;
windowManager.addView(surfaceView, layoutParams);
surfaceView.getHolder().addCallback(this);
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Intent notificationIntent = new Intent(this, MainActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0,
notificationIntent, 0);
Notification notification = new NotificationCompat.Builder(this)
//.setSmallIcon(R.mipmap.app_icon)
.setContentTitle("Background Video Recorder")
.setContentText("")
.setContentIntent(pendingIntent).build();
startForeground(MainActivity.NOTIFICATION_ID_RECORDER_SERVICE, notification);
return Service.START_NOT_STICKY;
}
#Override
public void surfaceCreated(final SurfaceHolder surfaceHolder) {
mediaRecorder = new MediaRecorder();
try {
CameraManager manager = (CameraManager) getSystemService(CAMERA_SERVICE);
String[] cameras = manager.getCameraIdList();
CameraCharacteristics characteristics = manager.getCameraCharacteristics(cameras[1]);
StreamConfigurationMap configs = characteristics.get(
CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
Size[] sizes = configs.getOutputSizes(MediaCodec.class);
final Size sizeHigh = sizes[0];
manager.openCamera(cameras[1], new CameraDevice.StateCallback() {
#Override
public void onOpened(#NonNull CameraDevice camera) {
mCamera = camera;
mediaRecorder.setPreviewDisplay(surfaceHolder.getSurface());
mediaRecorder.setVideoSource(MediaRecorder.VideoSource.SURFACE);
mediaRecorder.setMaxFileSize(0);
mediaRecorder.setOrientationHint(0);
mediaRecorder.setOutputFile("test.mp4");
try { mediaRecorder.prepare(); } catch (Exception ignored) {}
List<Surface> list = new ArrayList<>();
list.add(surfaceHolder.getSurface());
try {
CaptureRequest.Builder captureRequest = mCamera.createCaptureRequest(CameraDevice.TEMPLATE_RECORD);
captureRequest.addTarget(surfaceHolder.getSurface());
mCaptureRequest = captureRequest.build();
} catch (CameraAccessException e) {
e.printStackTrace();
}
try {
mCamera.createCaptureSession(list, new CameraCaptureSession.StateCallback() {
#Override
public void onConfigured(#NonNull CameraCaptureSession session) {
mSession = session;
}
#Override
public void onConfigureFailed(#NonNull CameraCaptureSession session) {
mSession = session;
}
}, null);
} catch (CameraAccessException e) {
e.printStackTrace();
}
mediaRecorder.start();
try {
mSession.setRepeatingRequest(mCaptureRequest,
new CameraCaptureSession.CaptureCallback() {
#Override
public void onCaptureStarted(#NonNull CameraCaptureSession session, #NonNull CaptureRequest request, long timestamp, long frameNumber) {
super.onCaptureStarted(session, request, timestamp, frameNumber);
}
#Override
public void onCaptureCompleted(#NonNull CameraCaptureSession session, #NonNull CaptureRequest request, #NonNull TotalCaptureResult result) {
super.onCaptureCompleted(session, request, result);
}
#Override
public void onCaptureFailed(#NonNull CameraCaptureSession session, #NonNull CaptureRequest request, #NonNull CaptureFailure failure) {
}
}, null);
} catch (CameraAccessException e) {
e.printStackTrace();
}
}
#Override
public void onDisconnected(#NonNull CameraDevice camera) {
}
#Override
public void onError(#NonNull CameraDevice camera, int error) {
}
}, null);
} catch (CameraAccessException e) {
e.printStackTrace();
}
}
// Stop recording and remove SurfaceView
#Override
public void onDestroy() {
mediaRecorder.stop();
mediaRecorder.reset();
mediaRecorder.release();
mCamera.close();
mediaRecorder= null;
windowManager.removeView(surfaceView);
}
#Override
public void surfaceChanged(SurfaceHolder surfaceHolder, int format, int width, int height) {}
#Override
public void surfaceDestroyed(SurfaceHolder surfaceHolder) {}
#Override
public IBinder onBind(Intent intent) { return null; }
}
You don't need to put up a SurfaceView with Camera2, or even with Camera1 (with the latter, just create a SurfaceTexture to get a Surface from, and never call updateTexImage; with the former, just don't include a preview Surface at all, it's not needed).
That said, you're trying to use the same Surface in both Camera2 and the MediaRecorder; that doesn't work. MediaRecorder doesn't need to draw to a Surface at all to record, you can just leave that part off. It's only there to allow MediaRecorder to be used independently of the camera API, where it manages a camera behind the scenes.
I suspect the call to MediaRecorder.prepare() is throwing an error that you're ignoring, about the preview Surface already being in use, which is why start doesn't later work.
And yes, as CommonsWare says, you likely will need a foreground service in Android P.
I am trying to open the camera hardware on a SurfaceView. In the layout, I created a SurfaceView and I open the camera as shown in the code below. When I run the code, the toast in the CameraAvailableCB shows up and says "onCameraAvailable" but nothing appears on the SurfaceView.
How do I show the camera display on the SurfaceView?
Code
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
this.mBtnCapture = (Button) findViewById(R.id.actMain_btn_capture);
this.mSurfaceView = (SurfaceView) findViewById(R.id.actMain_surfaceView);
this.mSurfaceHolder = this.mSurfaceView.getHolder();
this.mSurfaceHolder.addCallback(this);
this.mCameraManager = (CameraManager) this.getSystemService(Context.CAMERA_SERVICE);
try {
cameraIDsList = this.mCameraManager.getCameraIdList();
for (String id : cameraIDsList) {
Log.v(TAG, "CameraID: " + id);
}
} catch (CameraAccessException e) {
e.printStackTrace();
}
cameraStateCB = new CameraDevice.StateCallback() {
#Override
public void onOpened(CameraDevice camera) {
Toast.makeText(getApplicationContext(), "onOpened", Toast.LENGTH_SHORT).show();
//requesting permission
int permissionCheck = ContextCompat.checkSelfPermission(activity, Manifest.permission.CAMERA);
if (permissionCheck != PackageManager.PERMISSION_GRANTED) {
if (ActivityCompat.shouldShowRequestPermissionRationale(activity, Manifest.permission.CAMERA)) {
} else {
ActivityCompat.requestPermissions(activity, new String[]{Manifest.permission.CAMERA}, MY_PERMISSIONS_REQUEST_CAMERA);
Toast.makeText(getApplicationContext(), "request permission", Toast.LENGTH_SHORT).show();
}
} else {
Toast.makeText(getApplicationContext(), "PERMISSION_ALREADY_GRANTED", Toast.LENGTH_SHORT).show();
}
//opening the camera
try {
mCameraManager.openCamera(cameraIDsList[1], cameraStateCB, new Handler());
} catch (CameraAccessException e) {
e.printStackTrace();
}
}
#Override
public void onDisconnected(CameraDevice camera) {
Toast.makeText(getApplicationContext(), "onDisconnected", Toast.LENGTH_SHORT).show();
}
#Override
public void onError(CameraDevice camera, int error) {
Toast.makeText(getApplicationContext(), "onError", Toast.LENGTH_SHORT).show();
}
};
CameraManager.AvailabilityCallback cameraAvailableCB = new CameraManager.AvailabilityCallback() {
#Override
public void onCameraAvailable(String cameraId) {
super.onCameraAvailable(cameraId);
Toast.makeText(getApplicationContext(), "onCameraAvailable", Toast.LENGTH_SHORT).show();
}
#Override
public void onCameraUnavailable(String cameraId) {
super.onCameraUnavailable(cameraId);
Toast.makeText(getApplicationContext(), "onCameraUnavailable", Toast.LENGTH_SHORT).show();
}
};
this.mCameraManager.registerAvailabilityCallback(cameraAvailableCB, new Handler());
}
#Override
public void onRequestPermissionsResult(int requestCode, #NonNull String[] permissions, #NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
switch (requestCode) {
case MY_PERMISSIONS_REQUEST_CAMERA:
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED)
// Open Camera
break;
}
}
#Override
public void surfaceCreated(SurfaceHolder holder) {
Log.w(TAG, "surfaceCreated");
}
#Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
Log.w(TAG, "surfaceChanged");
}
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
Log.w(TAG, "surfaceDestroyed");
}
To show preview from camera using Camera2 API you should do the following steps:
Get permission to use camera device
Using CameraManager open connection to a camera
Have prepared Surface for preview
Using opened camera device and desired surfaces (it can include not only preview surface) create CaptureSession
After CaptureSession created you need to create and configure CaptureRequest and submit it to CaptureSession
Need to notice that preparing surfaces and openning connection to camera are independent processes, so you need to be sure, that they are both completed before creating CaptureSession.
Here is the example of activity to display camera preview on the screen:
public class MainActivity extends AppCompatActivity implements SurfaceHolder.Callback, Handler.Callback {
static final String TAG = "CamTest";
static final int MY_PERMISSIONS_REQUEST_CAMERA = 1242;
private static final int MSG_CAMERA_OPENED = 1;
private static final int MSG_SURFACE_READY = 2;
private final Handler mHandler = new Handler(this);
SurfaceView mSurfaceView;
SurfaceHolder mSurfaceHolder;
CameraManager mCameraManager;
String[] mCameraIDsList;
CameraDevice.StateCallback mCameraStateCB;
CameraDevice mCameraDevice;
CameraCaptureSession mCaptureSession;
boolean mSurfaceCreated = true;
boolean mIsCameraConfigured = false;
private Surface mCameraSurface = null;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
this.mSurfaceView = (SurfaceView) findViewById(R.id.SurfaceViewPreview);
this.mSurfaceHolder = this.mSurfaceView.getHolder();
this.mSurfaceHolder.addCallback(this);
this.mCameraManager = (CameraManager) this.getSystemService(Context.CAMERA_SERVICE);
try {
mCameraIDsList = this.mCameraManager.getCameraIdList();
for (String id : mCameraIDsList) {
Log.v(TAG, "CameraID: " + id);
}
} catch (CameraAccessException e) {
e.printStackTrace();
}
mCameraStateCB = new CameraDevice.StateCallback() {
#Override
public void onOpened(CameraDevice camera) {
Toast.makeText(getApplicationContext(), "onOpened", Toast.LENGTH_SHORT).show();
mCameraDevice = camera;
mHandler.sendEmptyMessage(MSG_CAMERA_OPENED);
}
#Override
public void onDisconnected(CameraDevice camera) {
Toast.makeText(getApplicationContext(), "onDisconnected", Toast.LENGTH_SHORT).show();
}
#Override
public void onError(CameraDevice camera, int error) {
Toast.makeText(getApplicationContext(), "onError", Toast.LENGTH_SHORT).show();
}
};
}
#Override
protected void onStart() {
super.onStart();
//requesting permission
int permissionCheck = ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA);
if (permissionCheck != PackageManager.PERMISSION_GRANTED) {
if (ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.CAMERA)) {
} else {
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.CAMERA}, MY_PERMISSIONS_REQUEST_CAMERA);
Toast.makeText(getApplicationContext(), "request permission", Toast.LENGTH_SHORT).show();
}
} else {
Toast.makeText(getApplicationContext(), "PERMISSION_ALREADY_GRANTED", Toast.LENGTH_SHORT).show();
try {
mCameraManager.openCamera(mCameraIDsList[1], mCameraStateCB, new Handler());
} catch (CameraAccessException e) {
e.printStackTrace();
}
}
}
#Override
protected void onStop() {
super.onStop();
try {
if (mCaptureSession != null) {
mCaptureSession.stopRepeating();
mCaptureSession.close();
mCaptureSession = null;
}
mIsCameraConfigured = false;
} catch (final CameraAccessException e) {
// Doesn't matter, cloising device anyway
e.printStackTrace();
} catch (final IllegalStateException e2) {
// Doesn't matter, cloising device anyway
e2.printStackTrace();
} finally {
if (mCameraDevice != null) {
mCameraDevice.close();
mCameraDevice = null;
mCaptureSession = null;
}
}
}
#Override
public boolean handleMessage(Message msg) {
switch (msg.what) {
case MSG_CAMERA_OPENED:
case MSG_SURFACE_READY:
// if both surface is created and camera device is opened
// - ready to set up preview and other things
if (mSurfaceCreated && (mCameraDevice != null)
&& !mIsCameraConfigured) {
configureCamera();
}
break;
}
return true;
}
private void configureCamera() {
// prepare list of surfaces to be used in capture requests
List<Surface> sfl = new ArrayList<Surface>();
sfl.add(mCameraSurface); // surface for viewfinder preview
// configure camera with all the surfaces to be ever used
try {
mCameraDevice.createCaptureSession(sfl,
new CaptureSessionListener(), null);
} catch (CameraAccessException e) {
e.printStackTrace();
}
mIsCameraConfigured = true;
}
#Override
public void onRequestPermissionsResult(int requestCode, #NonNull String[] permissions, #NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
switch (requestCode) {
case MY_PERMISSIONS_REQUEST_CAMERA:
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.CAMERA) == PackageManager.PERMISSION_GRANTED)
try {
mCameraManager.openCamera(mCameraIDsList[1], mCameraStateCB, new Handler());
} catch (CameraAccessException e) {
e.printStackTrace();
}
break;
}
}
#Override
public void surfaceCreated(SurfaceHolder holder) {
mCameraSurface = holder.getSurface();
}
#Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
mCameraSurface = holder.getSurface();
mSurfaceCreated = true;
mHandler.sendEmptyMessage(MSG_SURFACE_READY);
}
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
mSurfaceCreated = false;
}
private class CaptureSessionListener extends
CameraCaptureSession.StateCallback {
#Override
public void onConfigureFailed(final CameraCaptureSession session) {
Log.d(TAG, "CaptureSessionConfigure failed");
}
#Override
public void onConfigured(final CameraCaptureSession session) {
Log.d(TAG, "CaptureSessionConfigure onConfigured");
mCaptureSession = session;
try {
CaptureRequest.Builder previewRequestBuilder = mCameraDevice
.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
previewRequestBuilder.addTarget(mCameraSurface);
mCaptureSession.setRepeatingRequest(previewRequestBuilder.build(),
null, null);
} catch (CameraAccessException e) {
Log.d(TAG, "setting up preview failed");
e.printStackTrace();
}
}
}
}
With CameraX it's easy now.
// Create a preview use case instance
val preview = Preview.Builder().build()
// Bind the preview use case and other needed user cases to a lifecycle
val camera = cameraProvider.bindToLifecycle(lifecycleOwner, cameraSelector, preview, imageAnalysis, imageCapture)
// Create a surfaceProvider using the bound camera's cameraInfo
val surfaceProvider = previewView.createSurfaceProvider(camera.cameraInfo)
// Attach the surfaceProvider to the preview use case to start preview
preview.setSurfaceProvider(surfaceProvider)
<androidx.camera.view.PreviewView
android:layout_width="match_parent"
android:layout_height="match_parent"
app:scaleType="fitEnd" />
https://medium.com/androiddevelopers/display-a-camera-preview-with-previewview-86562433d86c