I am quite new to Android, thus the code is not from me since I use it only to learn.
The application I want to make has to show a camera preview. I have the preview of the camera on the surface, but it's not focused. As a work-around I made a runnable that calls auto-focus every 750ms.
I would like to know how I can make this better since whenever I call auto-focus the preview will blur until it's focused again.
Thank you for any help.
import android.app.Activity;
import android.hardware.Camera;
import android.hardware.Camera.AutoFocusCallback;
import android.os.Bundle;
import android.os.Handler;
import android.util.Log;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.widget.Toast;
public class Draw extends Activity {
private SurfaceView preview = null;
private SurfaceHolder previewHolder = null;
private Camera camera = null;
private boolean inPreview = false;
private boolean cameraConfigured = false;
private Handler handler = new Handler();;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.draw);
preview = (SurfaceView) findViewById(R.id.preview);
previewHolder = preview.getHolder();
previewHolder.addCallback(surfaceCallback);
final Runnable r = new Runnable() {
#Override
public void run() {
camera.autoFocus(autoFocusCallback);
handler.postDelayed(this, 1000);
}
};
handler.postDelayed(r, 750);
}
private AutoFocusCallback autoFocusCallback = new AutoFocusCallback() {
#Override
public void onAutoFocus(boolean autoFocusSuccess, Camera arg1) {
}
};
#Override
public void onResume() {
super.onResume();
camera = Camera.open();
startPreview();
}
#Override
public void onPause() {
if (inPreview) {
camera.stopPreview();
}
camera.release();
camera = null;
inPreview = false;
super.onPause();
}
private Camera.Size getBestPreviewSize(int width, int height, Camera.Parameters parameters) {
Camera.Size result = null;
for (Camera.Size size : parameters.getSupportedPreviewSizes()) {
if (size.width <= width && size.height <= height) {
if (result == null) {
result = size;
} else {
int resultArea = result.width * result.height;
int newArea = size.width * size.height;
if (newArea > resultArea) {
result = size;
}
}
}
}
return (result);
}
private void initPreview(int width, int height) {
if (camera != null && previewHolder.getSurface() != null) {
try {
camera.setPreviewDisplay(previewHolder);
} catch (Throwable t) {
Log.e("KritzelKunst-surfaceCallback", "Exception in setPreviewDisplay()", t);
Toast.makeText(Draw.this, t.getMessage(), Toast.LENGTH_LONG).show();
}
if (!cameraConfigured) {
Camera.Parameters parameters = camera.getParameters();
Camera.Size size = getBestPreviewSize(width, height, parameters);
if (size != null) {
parameters.setPreviewSize(size.width, size.height);
camera.setParameters(parameters);
cameraConfigured = true;
}
}
}
}
private void startPreview() {
if (cameraConfigured && camera != null) {
camera.startPreview();
inPreview = true;
}
}
SurfaceHolder.Callback surfaceCallback = new SurfaceHolder.Callback() {
#Override
public void surfaceCreated(SurfaceHolder holder) {
// no-op -- wait until surfaceChanged()
}
#Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
initPreview(width, height);
startPreview();
}
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
// no-op
}
};
}
Try adding
<uses-feature android:name="android.hardware.camera.autofocus" />
in your manifest.
Related
I am trying to implement a barcode scanning function in my Libgdx project.
i have tried to follow : https://github.com/libgdx/libgdx/wiki/Integrating-libgdx-and-the-device-camera
but it seems to be outdated.
Does anyone have a clue on how to get the device camera working in libgdx?
I have a project that implemented the android camera. Heres the important code:
Manifest
<uses-permission android:name="android.permission.CAMERA"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-feature android:name="android.hardware.camera"/>
<uses-feature android:name="android.hardware.camera.autofocus" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
AndroidDeviceCameraController (New Class)
import android.graphics.Bitmap;
import android.hardware.Camera;
import android.view.ViewGroup;
import android.view.ViewGroup.LayoutParams;
import android.view.ViewParent;
import com.badlogic.gdx.files.FileHandle;
import com.badlogic.gdx.graphics.Pixmap;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.List;
public class AndroidDeviceCameraController implements DeviceCameraControl,
Camera.PictureCallback, Camera.AutoFocusCallback {
private static final int ONE_SECOND_IN_MILI = 1000;
private final MainActivity activity;
private CameraSurface cameraSurface;
private byte[] pictureData;
FileHandle jpgfile;
Pixmap pixmap;
FileHandle jpgfile2;
Pixmap pixmap2;
public AndroidDeviceCameraController(MainActivity activity) {
this.activity = activity;
}
#Override
public synchronized void prepareCamera() {
activity.setFixedSize(960,640);
if (cameraSurface == null) {
cameraSurface = new CameraSurface(activity);
}
activity.addContentView( cameraSurface, new LayoutParams(
LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT ) );
}
#Override
public synchronized void startPreview() {
setCameraParametersForPicture(cameraSurface.getCamera());
if (cameraSurface != null && cameraSurface.getCamera() != null) {
cameraSurface.getCamera().startPreview();
}
}
#Override
public synchronized void stopPreview() {
if (cameraSurface != null) {
ViewParent parentView = cameraSurface.getParent();
if (parentView instanceof ViewGroup) {
ViewGroup viewGroup = (ViewGroup) parentView;
viewGroup.removeView(cameraSurface);
}
if (cameraSurface.getCamera() != null) {
cameraSurface.getCamera().stopPreview();
}
}
activity.restoreFixedSize();
}
public void setCameraParametersForPicture(Camera camera) {
camera.setDisplayOrientation(90);
Camera.Parameters p = camera.getParameters();
List<Camera.Size> supportedSizes = p.getSupportedPictureSizes();
int maxSupportedWidth = -1;
int maxSupportedHeight = -1;
for (Camera.Size size : supportedSizes) {
if (size.width > maxSupportedWidth) {
maxSupportedWidth = size.width;
maxSupportedHeight = size.height;
}
}
p.setPictureSize(maxSupportedWidth, maxSupportedHeight);
p.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO);
camera.setParameters( p );
}
#Override
public synchronized void takePicture() {
setCameraParametersForPicture(cameraSurface.getCamera());
cameraSurface.getCamera().autoFocus(this);
}
#Override
public synchronized void onAutoFocus(boolean success, Camera camera) {
if (success) {
if (camera != null) {
camera.startPreview();
ShutterCallback shutterCallback = new ShutterCallback() {
#Override
public void onShutter() {
}
};
camera.takePicture(shutterCallback, null, null, this);
}
}
}
#Override
public synchronized void onPictureTaken(byte[] pictureData, Camera camera) {
main.makefoto = true;
this.pictureData = pictureData;
}
#Override
public synchronized byte[] getPictureData() {
return pictureData;
}
#Override
public void prepareCameraAsync() {
Runnable r = new Runnable() {
public void run() {
prepareCamera();
}
};
activity.post(r);
}
#Override
public synchronized void startPreviewAsync() {
Runnable r = new Runnable() {
public void run() {
startPreview();
}
};
activity.post(r);
}
#Override
public synchronized void stopPreviewAsync() {
Runnable r = new Runnable() {
public void run() {
stopPreview();
}
};
activity.post(r);
}
#Override
public synchronized byte[] takePictureAsync(long timeout) {
timeout *= ONE_SECOND_IN_MILI;
pictureData = null;
Runnable r = new Runnable() {
public void run() {
takePicture();
}
};
activity.post(r);
while (pictureData == null && timeout > 0) {
try {
Thread.sleep(ONE_SECOND_IN_MILI);
timeout -= ONE_SECOND_IN_MILI;
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
if (pictureData == null) {
cameraSurface.getCamera().cancelAutoFocus();
}
return pictureData;
}
public void convert() {
new Thread(new Runnable() {
#Override
public void run() {
FileOutputStream fos;
int x=0,y=0;
int xl=0,yl=0;
try {
Bitmap bmp = Bitmap.createBitmap(pixmap.getWidth(),
pixmap.getHeight(), Bitmap.Config.ARGB_8888);
for (x=0,xl=pixmap.getWidth(); x<xl;x++) {
for (y=0,yl=pixmap.getHeight(); y<yl;y++) {
int color = pixmap.getPixel(x, y);
// RGBA => ARGB
int RGB = color >> 8;
int A = (color & 0x000000ff) << 24;
int ARGB = A | RGB;
bmp.setPixel(x, y, ARGB);
}
}
fos = new FileOutputStream(jpgfile.file());
bmp.compress(Bitmap.CompressFormat.JPEG, 90, fos);
fos.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (IllegalArgumentException e) {
e.printStackTrace();
}
jpgfile = jpgfile2;
pixmap = pixmap2;
}
}).start();
}
#Override
public void saveAsJpeg(FileHandle jpgfile, Pixmap pixmap) {
convert();
this.jpgfile = jpgfile;
this.pixmap = pixmap;
jpgfile2 = this.jpgfile;
pixmap2 = this.pixmap;
}
#Override
public boolean isReady() {
if (cameraSurface!=null && cameraSurface.getCamera() != null) {
return true;
}
return false;
}
}
I want to implement zoom function while video recording in android.But, I am not able to access Camera parameters or Camera startSmoothZoom() method in neither main activity nor surface class. If you access camera parametera in media recorder method(prepareMediaRecorder()) it will throw null pointer exception.
this activity class- in prepareMediaRecorder() method not able to access camera parameters and also not able to set startSmoothZoom(). here camera object giving null pointer exception.
public class CustomCameraPreview extends BaseActivity implements
OnClickListener, AlertPositiveListener, OrientationListener,
ActivityCompat.OnRequestPermissionsResultCallback {
RelativeLayout mLayout;
MediaRecorder mediaRecorder;
private PictureCallback mPictureCallback = new PictureCallback() {
#Override
public void onPictureTaken(byte[] data, Camera camera) {
try {
cameraData = data;
captureAngle = getRotation();
mBitmap = BitmapFactory.decodeByteArray(data, 0, data.length);
}
catch (OutOfMemoryError e){
System.gc();
mBitmap = BitmapFactory.decodeByteArray(data, 0, data.length);
}
// int rotation=getRotation();
Matrix matrix = new Matrix();
matrix.postRotate(getRotation());
/*mBitmap = Bitmap.createBitmap(mBitmap, 0, 0, mBitmap.getWidth(),
mBitmap.getHeight(), matrix, true);*/
mBitmap = Bitmap.createBitmap(mBitmap, 0, 0, mBitmap.getWidth(),
mBitmap.getHeight(), matrix, false);
if (mBitmap != null) {
mButtonRetake.setEnabled(true);
} else {
Message.displayToast(CustomCameraPreview.this,
getString(R.string.picture_not_taken));
}
mCamera.release();
mButtonCapture.setEnabled(false);
}
};
protected void onCreate(){
initiCameraForVideo();
}
private void initiCameraForVideo() {
params = mCamera.getParameters();
mButtonCapture.setBackgroundResource(R.drawable.videostart);
mShowCamera = new CameraSurfaceHolder(CustomCameraPreview.this,
mCamera);
mLayout = (RelativeLayout) findViewById(R.id.relativeLayout);
mLayout.removeAllViews();
mLayout.addView(mShowCamera);
List<Camera.Size> mSizeList_Video = null;// params.getSupportedPreviewSizes();
if (params.getSupportedVideoSizes() != null) {
mSizeList_Video = params.getSupportedVideoSizes();
} else {
// Video sizes may be null, which indicates that all the
// supported preview sizes are supported for video
// recording.
mSizeList_Video = mCamera.getParameters()
.getSupportedPreviewSizes();
}
}
#Override
public void onClick(View v) {
int viewId = v.getId();
switch (viewId) {
case R.id.button_Capture:
releaseCamera();
if (!prepareMediaRecorder()) {
Message.displayToast(
CustomCameraPreview.this,
getString(R.string.somethign_went_wrong));
} else {
mediaRecorder.start();
recording = true;
}
}
private boolean prepareMediaRecorder() \*method to setup media player to record video
{
mCamera = isCameraAvailable();
mediaRecorder = new MediaRecorder();
mCamera.unlock();
mediaRecorder.setCamera(mCamera);
mediaRecorder.setAudioSource(MediaRecorder.AudioSource.CAMCORDER);
mediaRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);
if(CamcorderProfile.hasProfile(findCameraID(), CamcorderProfile.QUALITY_480P)) {
mediaRecorder.setProfile(CamcorderProfile
.get(CamcorderProfile.QUALITY_480P));
}else{
mediaRecorder.setProfile(CamcorderProfile
.get(CamcorderProfile.QUALITY_LOW));
}
mediaRecorder.setOutputFile(getOutputVideoFile());
mediaRecorder.setMaxDuration(60000);
// mediaRecorder.setMaxFileSize(100 * 1000 * 1000);
mediaRecorder.setPreviewDisplay(mShowCamera.getHolder().getSurface());
try {
mediaRecorder.prepare();
}
}
#Override
protected void onPause() {
super.onPause();
releaseMediaRecorder();
releaseCamera();
}
private void releaseCamera() {
if (mCamera != null) {
mCamera.release();
mCamera = null;
}
}
and this surface preview class-
public class CameraSurfaceHolder extends SurfaceView implements
SurfaceHolder.Callback {
private static final String TAG = "CameraSurfaceHolder";
Context mContext;
private String errorMessage = "";
private SurfaceHolder mSurfaceHolder;
private Camera mCamera;
public CameraSurfaceHolder(Context context, Camera camera) {
super(context);
mContext = context;
mCamera = camera;
mSurfaceHolder = getHolder();
mSurfaceHolder.addCallback(this);
}
#Override
public void surfaceChanged(SurfaceHolder holder, int format, int width,
int height) {
/*if (holder.getSurface() == null){
// preview surface does not exist
return;
}
// stop preview before making changes
try {
mCamera.stopPreview();
} catch (Exception e){
// ignore: tried to stop a non-existent preview
}
// set preview size and make any resize, rotate or
// reformatting changes here
setCameraDisplayOrientation((Activity)mContext, Camera.CameraInfo.CAMERA_FACING_BACK, mCamera);
// start preview with new settings
try {
mCamera.setPreviewDisplay(holder);
mCamera.startPreview();
}
*/
}
#Override
public void surfaceCreated(SurfaceHolder holder) {
try {
mCamera.setPreviewDisplay(mSurfaceHolder);
mCamera.startPreview();
} catch (Exception e) {
Logger.ex(e);
}
}
public void setCameraDisplayOrientation(Activity activity, int cameraId,
Camera camera) {
Camera.CameraInfo info = new Camera.CameraInfo();
Camera.getCameraInfo(cameraId, info);
/*Display mDisplay = ((WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay();
int rotation = mDisplay.getDisplayId();*/
int rotation = activity.getWindowManager().getDefaultDisplay()
.getRotation();
int degrees = 0;
switch (rotation) {
case Surface.ROTATION_0:
degrees = 0;
break;
case Surface.ROTATION_90:
degrees = 90;
break;
case Surface.ROTATION_180:
degrees = 180;
break;
case Surface.ROTATION_270:
degrees = 270;
break;
}
int result;
if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
result = (info.orientation + degrees) % 360;
result = (360 - result) % 360; // compensate the mirror
} else { // back-facing
result = (info.orientation - degrees + 360) % 360;
}
Camera.Parameters mParameters = camera.getParameters();
mParameters.setRotation(rotation);
camera.setDisplayOrientation(result);
camera.setParameters(mParameters);
}
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
}
}
in above class I added some code like below and when user touch on camera preview its throwing null pointer exception in onTouchEvent() on access of camera paramters. Also tried like I set again camera object to surface in activity after configure media recorder(prepareMediaRecorder()), but zoom function working but video is not recording.
#Override
public boolean onTouchEvent(MotionEvent event) {
// Get the pointer ID
Camera.Parameters params = mCamera.getParameters();
int action = event.getAction();
if (event.getPointerCount() > 1) {
// handle multi-touch events
if (action == MotionEvent.ACTION_POINTER_DOWN) {
mDist = getFingerSpacing(event);
} else if (action == MotionEvent.ACTION_MOVE && params.isZoomSupported()) {
mCamera.cancelAutoFocus();
handleZoom(event, params);
}
} else {
// handle single touch events
if (action == MotionEvent.ACTION_UP) {
handleFocus(event, params);
}
}
return true;
}
private void handleZoom(MotionEvent event, Camera.Parameters params) {
int maxZoom = params.getMaxZoom();
int zoom = params.getZoom();
float newDist = getFingerSpacing(event);
if (newDist > mDist) {
//zoom in
if (zoom < maxZoom)
zoom++;
} else if (newDist < mDist) {
//zoom out
if (zoom > 0)
zoom--;
}
mDist = newDist;
params.setZoom(zoom);
mCamera.setParameters(params);
}
public void handleFocus(MotionEvent event, Camera.Parameters params) {
int pointerId = event.getPointerId(0);
int pointerIndex = event.findPointerIndex(pointerId);
// Get the pointer's current position
float x = event.getX(pointerIndex);
float y = event.getY(pointerIndex);
List<String> supportedFocusModes = params.getSupportedFocusModes();
if (supportedFocusModes != null && supportedFocusModes.contains(Camera.Parameters.FOCUS_MODE_AUTO)) {
mCamera.autoFocus(new Camera.AutoFocusCallback() {
#Override
public void onAutoFocus(boolean b, Camera camera) {
// currently set to auto-focus on single touch
}
});
}
}
/** Determine the space between the first two fingers */
private float getFingerSpacing(MotionEvent event) {
// ...
float x = event.getX(0) - event.getX(1);
float y = event.getY(0) - event.getY(1);
return (float)Math.sqrt(x * x + y * y);
}
So I am new to coding and working with the camera. I don't understand why the cameraId was null. Would really appreciate if someone could help me out. Thanks
Code:
public class CameraFragment extends Fragment {
private TextureView textureView;
private HandlerThread mBackgroundHandlerThread;
private Handler mBackgroundHandler;
private String mCameraId;
private Size mPreviewSize;
public static CameraFragment newInstance() {
return new CameraFragment();
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout. fragment_camera, container, false);
textureView = (TextureView) rootView.findViewById(R.id.textureView);
return rootView;
}
private static final int REQUEST_CAMERA_PERMISSION_RESULT = 0;
private TextureView.SurfaceTextureListener surfaceTextureListener = new TextureView.SurfaceTextureListener() {
#Override
public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
setupCamera(width, height);
connectCamera();
}
#Override
public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {
}
#Override
public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
return false;
}
#Override
public void onSurfaceTextureUpdated(SurfaceTexture surface) {
}
};
private CameraDevice mCameraDevice;
private CameraDevice.StateCallback mCameraDeviceStateCallback = new CameraDevice.StateCallback() {
#Override
public void onOpened(#NonNull CameraDevice camera) {
mCameraDevice = camera;
startPreview();
//Toast.makeText(getApplicationContext(), "Camera connected!", Toast.LENGTH_LONG).show();
}
#Override
public void onDisconnected(#NonNull CameraDevice camera) {
camera.close();
mCameraDevice = null;
}
#Override
public void onError(#NonNull CameraDevice camera, int error) {
camera.close();
mCameraDevice = null;
}
};
#Override
public void onResume() {
super.onResume();
startBackgroundThread();
if (textureView.isAvailable()) {
//setupCamera(textureView.getWidth(), textureView.getHeight());
connectCamera();
} else {
textureView.setSurfaceTextureListener(surfaceTextureListener);
}
}
#Override
public void onPause() {
closeCamera();
stopBackgroundThread();
super.onPause();
}
private void closeCamera() {
if(mCameraDevice != null) {
mCameraDevice.close();
mCameraDevice = null;
}
}
private void stopBackgroundThread() {
mBackgroundHandlerThread.quitSafely();
try {
mBackgroundHandlerThread.join();
mBackgroundHandlerThread = null;
mBackgroundHandler = null;
} catch (InterruptedException e) {
e.printStackTrace();
}
}
private void setupCamera(int width, int height) {
if(mCameraDevice == null)
return;
CameraManager cameraManager = (CameraManager) getActivity().getSystemService(Context.CAMERA_SERVICE);
try {
if (cameraManager != null) {
mCameraId = cameraManager.getCameraIdList()[0];
}
assert cameraManager != null;
for (String cameraId : cameraManager.getCameraIdList()) {
CameraCharacteristics cameraCharacteristics = cameraManager.getCameraCharacteristics(cameraId);
if(cameraCharacteristics.get(CameraCharacteristics.LENS_FACING) ==
CameraCharacteristics.LENS_FACING_FRONT){
continue;
}
StreamConfigurationMap map = cameraCharacteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
int deviceOrientation = getActivity().getWindowManager().getDefaultDisplay().getRotation();
int totalRotation = sensorToDeviceRotation(cameraCharacteristics, deviceOrientation);
boolean swapRotation = totalRotation == 90 || totalRotation == 270;
int rotatedWidth = width;
int rotatedHeight = height;
if (swapRotation){
rotatedWidth = height;
rotatedHeight = width;
}
if (map != null) {
mPreviewSize = chooseOptimalSize(map.getOutputSizes(SurfaceTexture.class), rotatedWidth, rotatedHeight);
}
mCameraId = cameraId;
return;
}
} catch (CameraAccessException e) {
e.printStackTrace();
}
}
private void connectCamera() {
CameraManager cameraManager = (CameraManager) getActivity().getSystemService(Context.CAMERA_SERVICE);
try {
if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.M) {
if (ContextCompat.checkSelfPermission(getActivity(), Manifest.permission.CAMERA) ==
PackageManager.PERMISSION_GRANTED) {
assert cameraManager != null;
cameraManager.openCamera(mCameraId, mCameraDeviceStateCallback, mBackgroundHandler);
} else {
if (shouldShowRequestPermissionRationale(Manifest.permission.CAMERA)) {
Toast.makeText(getActivity(), "This app requires access to camera", Toast.LENGTH_LONG).show();
}
requestPermissions(new String[]{Manifest.permission.CAMERA}, REQUEST_CAMERA_PERMISSION_RESULT);
}
} else {
assert cameraManager != null;
cameraManager.openCamera(mCameraId, mCameraDeviceStateCallback, mBackgroundHandler);
}
}catch(CameraAccessException e){
e.printStackTrace();
}
}
private CaptureRequest.Builder mCaptureRequestBuilder;
private static SparseIntArray ORIENTATIONS = new SparseIntArray();
static {
ORIENTATIONS.append(Surface.ROTATION_0, 0);
ORIENTATIONS.append(Surface.ROTATION_90, 90);
ORIENTATIONS.append(Surface.ROTATION_180, 180);
ORIENTATIONS.append(Surface.ROTATION_270, 270);
}
private static class CompareSizeByArea implements Comparator<Size> {
#Override
public int compare(Size lhs, Size rhs){
return Long.signum((long) lhs.getWidth() * lhs.getHeight() /
(long) rhs.getWidth() * rhs.getHeight());
}
}
private static int sensorToDeviceRotation(CameraCharacteristics cameraCharacteristics, int deviceOrientation){
int sensorOrientation = cameraCharacteristics.get(CameraCharacteristics.SENSOR_ORIENTATION);
deviceOrientation = ORIENTATIONS.get(deviceOrientation);
return(sensorOrientation + deviceOrientation + 360) % 360;
}
public void onWindowFocusChanged (boolean hasFocus) {
super.getActivity().onWindowFocusChanged(hasFocus);
View decorView = getActivity().getWindow().getDecorView();
if(hasFocus){
decorView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE
| View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY
| View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
| View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
| View.SYSTEM_UI_FLAG_FULLSCREEN
| View.SYSTEM_UI_FLAG_HIDE_NAVIGATION);
}
}
private void startBackgroundThread() {
mBackgroundHandlerThread = new HandlerThread("Camera Background");
mBackgroundHandlerThread.start();
mBackgroundHandler = new Handler(mBackgroundHandlerThread.getLooper());
}
private void startPreview() {
SurfaceTexture surfaceTexture = textureView.getSurfaceTexture();
assert surfaceTexture != null;
surfaceTexture.setDefaultBufferSize(mPreviewSize.getWidth(), mPreviewSize.getHeight());
Surface previewSurface = new Surface(surfaceTexture);
try {
mCaptureRequestBuilder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
mCaptureRequestBuilder.addTarget(previewSurface);
mCameraDevice.createCaptureSession(Collections.singletonList(previewSurface),
new CameraCaptureSession.StateCallback() {
#Override
public void onConfigured(#NonNull CameraCaptureSession session) {
try {
session.setRepeatingRequest(mCaptureRequestBuilder.build(),
null, mBackgroundHandler);
} catch (CameraAccessException e){
e.printStackTrace();
}
}
#Override
public void onConfigureFailed(#NonNull CameraCaptureSession session) {
Toast.makeText(getActivity(), "Unable to connect to camera", Toast.LENGTH_LONG).show();
}
}, null);
} catch (CameraAccessException e){
e.printStackTrace();
}
}
private static Size chooseOptimalSize(Size[] choices, int width, int height) {
List<Size> bigEnough = new ArrayList<Size>();
for(Size option : choices){
if(option.getHeight() == option.getWidth() * height/width &&
option.getWidth() >= width && option.getHeight() >= height) {
bigEnough.add(option);
}
}
if(bigEnough.size() > 0){
return Collections.min(bigEnough, (Comparator<? super Size>) new CompareSizeByArea());
} else {
return choices[0];
}
}
}
Log:
> FATAL EXCEPTION: main
Process: com.example.patrick.wz, PID: 5246
java.lang.IllegalArgumentException: cameraId was null
at android.hardware.camera2.CameraManager.openCameraForUid(CameraManager.java:454)
at android.hardware.camera2.CameraManager.openCamera(CameraManager.java:430)
at com.example.patrick.wz.Fragments.CameraFragment.connectCamera(CameraFragment.java:214)
at com.example.patrick.wz.Fragments.CameraFragment.access$100(CameraFragment.java:40)
at com.example.patrick.wz.Fragments.CameraFragment$1.onSurfaceTextureAvailable(CameraFragment.java:74)
at android.view.TextureView.getHardwareLayer(TextureView.java:390)
at android.view.TextureView.draw(TextureView.java:339)
at android.view.View.updateDisplayListIfDirty(View.java:18069)
at android.view.View.draw(View.java:18847)
at android.view.ViewGroup.drawChild(ViewGroup.java:4214)
at android.view.ViewGroup.dispatchDraw(ViewGroup.java:4000)
at android.view.View.updateDisplayListIfDirty(View.java:18060)
at android.view.ViewGroup.recreateChildDisplayList(ViewGroup.java:4198)
at android.view.ViewGroup.dispatchGetDisplayList(ViewGroup.java:4178)
at android.view.View.updateDisplayListIfDirty(View.java:18028)
at android.view.ViewGroup.recreateChildDisplayList(ViewGroup.java:4198)
at android.view.ViewGroup.dispatchGetDisplayList(ViewGroup.java:4178)
at android.view.View.updateDisplayListIfDirty(View.java:18028)
at android.view.ViewGroup.recreateChildDisplayList(ViewGroup.java:4198)
at android.view.ViewGroup.dispatchGetDisplayList(ViewGroup.java:4178)
at android.view.View.updateDisplayListIfDirty(View.java:18028)
at android.view.ViewGroup.recreateChildDisplayList(ViewGroup.java:4198)
at android.view.ViewGroup.dispatchGetDisplayList(ViewGroup.java:4178)
at android.view.View.updateDisplayListIfDirty(View.java:18028)
at android.view.ViewGroup.recreateChildDisplayList(ViewGroup.java:4198)
at android.view.ViewGroup.dispatchGetDisplayList(ViewGroup.java:4178)
at android.view.View.updateDisplayListIfDirty(View.java:18028)
at android.view.ViewGroup.recreateChildDisplayList(ViewGroup.java:4198)
at android.view.ViewGroup.dispatchGetDisplayList(ViewGroup.java:4178)
at android.view.View.updateDisplayListIfDirty(View.java:18028)
at android.view.ViewGroup.recreateChildDisplayList(ViewGroup.java:4198)
at android.view.ViewGroup.dispatchGetDisplayList(ViewGroup.java:4178)
at android.view.View.updateDisplayListIfDirty(View.java:18028)
at android.view.ThreadedRenderer.updateRootDisplayList(ThreadedRenderer.java:659)
at android.view.ThreadedRenderer.draw(ThreadedRenderer.java:757)
at android.view.ViewRootImpl.draw(ViewRootImpl.java:2980)
at android.view.ViewRootImpl.performDraw(ViewRootImpl.java:2794)
at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:2347)
at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1386)
at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:6733)
at android.view.Choreographer$CallbackRecord.run(Choreographer.java:911)
at android.view.Choreographer.doCallbacks(Choreographer.java:723)
at android.view.Choreographer.doFrame(Choreographer.java:658)
at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:897)
at android.os.Handler.handleCallback(Handler.java:789)
at android.os.Handler.dispatchMessage(Handler.java:98)
In onResume, you've commented out the call to setupCamera, which is what sets mCameraId. So it's still null when you get to connectCamera.
I'm trying to make a motion detector app that captures images on the motion detection. Its working fine & saving the images. The problem is that the app crashes when I press back button from the camera activity to return to the home activity. How to fix it ?
Here is my code:
public class MotionDetectionActivity extends SensorsActivity {
private static final String TAG = "MotionDetectionActivity";
private static final String ENABLE_MOTION_DETECTION="switch_md";
private static SurfaceView preview = null;
private static SurfaceHolder previewHolder = null;
private static Camera camera = null;
private static boolean inPreview = false;
private static long mReferenceTime = 0;
private static IMotionDetection detector = null;
public static MediaPlayer song;
public static Vibrator mVibrator;
private static volatile AtomicBoolean processing = new AtomicBoolean(false);
public int MY_PERMISSIONS_REQUEST_CAMERA;
/**
* {#inheritDoc}
*/
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
setContentView(R.layout.main);
SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(this);
boolean enablemotionpref = sharedPref.getBoolean(ENABLE_MOTION_DETECTION, true);
song = MediaPlayer.create(this, R.raw.sound);
mVibrator = (Vibrator)this.getSystemService(VIBRATOR_SERVICE);
preview = (SurfaceView) findViewById(R.id.preview);
previewHolder = preview.getHolder();
previewHolder.addCallback(surfaceCallback);
previewHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
if (enablemotionpref) {
if (Preferences.USE_RGB) {
detector = new RgbMotionDetection();
} else if (Preferences.USE_LUMA) {
detector = new LumaMotionDetection();
} else {
// Using State based (aggregate map)
detector = new AggregateLumaMotionDetection();
}
}
}
/**
* {#inheritDoc}
*/
#Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
}
/**
* {#inheritDoc}
*/
#Override
public void onPause() {
super.onPause();
if(song!=null && song.isPlaying())
{
song.stop();}
camera.setPreviewCallback(null);
if (inPreview) camera.stopPreview();
inPreview = false;
camera.release();
camera = null;
}
/**
* {#inheritDoc}
*/
#Override
public void onResume() {
super.onResume();
camera = Camera.open();
}
private PreviewCallback previewCallback = new PreviewCallback() {
/**
* {#inheritDoc}
*/
#Override
public void onPreviewFrame(byte[] data, Camera cam) {
if (data == null) return;
Camera.Size size = cam.getParameters().getPreviewSize();
if (size == null) return;
if (!GlobalData.isPhoneInMotion()) {
DetectionThread thread = new DetectionThread(data, size.width, size.height);
thread.start();
}
}
};
private SurfaceHolder.Callback surfaceCallback = new SurfaceHolder.Callback() {
/**
* {#inheritDoc}
*/
#Override
public void surfaceCreated(SurfaceHolder holder) {
try {
camera.setPreviewDisplay(previewHolder);
camera.setPreviewCallback(previewCallback);
} catch (Throwable t) {
Log.e("Callback", "Exception in setPreviewDisplay()", t);
}
}
/**
* {#inheritDoc}
*/
#Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
Camera.Parameters parameters = camera.getParameters();
Camera.Size size = getBestPreviewSize(width, height, parameters);
if (size != null) {
parameters.setPreviewSize(size.width, size.height);
Log.d(TAG, "Using width=" + size.width + " height=" + size.height);
}
camera.setParameters(parameters);
camera.startPreview();
inPreview = true;
}
/**
* {#inheritDoc}
*/
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
// Ignore
}
};
private static Camera.Size getBestPreviewSize(int width, int height, Camera.Parameters parameters) {
Camera.Size result = null;
for (Camera.Size size : parameters.getSupportedPreviewSizes()) {
if (size.width <= width && size.height <= height) {
if (result == null) {
result = size;
} else {
int resultArea = result.width * result.height;
int newArea = size.width * size.height;
if (newArea > resultArea) result = size;
}
}
}
return result;
}
private static final class DetectionThread extends Thread {
private byte[] data;
private int width;
private int height;
public DetectionThread(byte[] data, int width, int height) {
this.data = data;
this.width = width;
this.height = height;
}
/**
* {#inheritDoc}
*/
#Override
public void run() {
if (!processing.compareAndSet(false, true)) return;
// Log.d(TAG, "BEGIN PROCESSING...");
try {
// Previous frame
int[] pre = null;
if (Preferences.SAVE_PREVIOUS) pre = detector.getPrevious();
// Current frame (with changes)
// long bConversion = System.currentTimeMillis();
int[] img = null;
if (Preferences.USE_RGB) {
img = ImageProcessing.decodeYUV420SPtoRGB(data, width, height);
if (img != null && detector.detect(img, width, height))
{
if(song!=null && !song.isPlaying())
{
song.start();
mVibrator.vibrate(50);
}
}
else
{
if(song!=null && song.isPlaying())
{
song.pause();
}
}
}
// Current frame (without changes)
int[] org = null;
if (Preferences.SAVE_ORIGINAL && img != null) org = img.clone();
if (img != null && detector.detect(img, width, height)) {
// The delay is necessary to avoid taking a picture while in
// the
// middle of taking another. This problem can causes some
// phones
// to reboot.
long now = System.currentTimeMillis();
if (now > (mReferenceTime + Preferences.PICTURE_DELAY)) {
mReferenceTime = now;
Bitmap previous = null;
if (Preferences.SAVE_PREVIOUS && pre != null) {
if (Preferences.USE_RGB) previous = ImageProcessing.rgbToBitmap(pre, width, height);
else previous = ImageProcessing.lumaToGreyscale(pre, width, height);
}
Bitmap original = null;
if (Preferences.SAVE_ORIGINAL && org != null) {
if (Preferences.USE_RGB) original = ImageProcessing.rgbToBitmap(org, width, height);
else original = ImageProcessing.lumaToGreyscale(org, width, height);
}
Bitmap bitmap = null;
if (Preferences.SAVE_CHANGES) {
if (Preferences.USE_RGB) bitmap = ImageProcessing.rgbToBitmap(img, width, height);
else bitmap = ImageProcessing.lumaToGreyscale(img, width, height);
}
Log.i(TAG, "Saving.. previous=" + previous + " original=" + original + " bitmap=" + bitmap);
Looper.prepare();
new SavePhotoTask().execute(previous, original, bitmap);
} else {
Log.i(TAG, "Not taking picture because not enough time has passed since the creation of the Surface");
}
}
} catch (Exception e) {
e.printStackTrace();
} finally {
processing.set(false);
}
// Log.d(TAG, "END PROCESSING...");
processing.set(false);
}
};
private static final class SavePhotoTask extends AsyncTask<Bitmap, Integer, Integer> {
/**
* {#inheritDoc}
*/
#Override
protected Integer doInBackground(Bitmap... data) {
for (int i = 0; i < data.length; i++) {
Bitmap bitmap = data[i];
String name = "MotDet_"+String.valueOf(System.currentTimeMillis());
if (bitmap != null) createDirectoryAndSaveFile(name, bitmap);
}
return 1;
}
private void createDirectoryAndSaveFile(String name, Bitmap bitmap) {
File folder = new File(Environment.getExternalStorageDirectory() +
File.separator + "MD");//here you have created different name
boolean success = true;
if (!folder.exists()) {
success = folder.mkdirs();
}
if (success) {
// Do something on success
} else {
// Do something else on failure
}
File photo = new File(folder.getAbsolutePath(), name+ ".jpg"); //use path of above created folder
if (photo.exists()) {
photo.delete();
}
try {
FileOutputStream out = new FileOutputStream(photo.getPath());
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, out);
out.flush();
out.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
HomeActivity
public class HomeActivity extends AppCompatActivity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
setContentView(R.layout.home_layout);
Button bt1 = (Button) findViewById(R.id.button);
Button bt2= (Button)findViewById(R.id.button1);
bt1.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Intent i = new Intent(view.getContext(), MotionDetectionActivity.class);
startActivity(i);
}
});
bt2.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View vew) {
Intent b=new Intent(vew.getContext(),SettingsActivity.class);
startActivity(b);
}
});
}
}
Stacktrace
handle like this an see if it still crashes
#Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
if(camera != null) {
Camera.Parameters parameters = camera.getParameters();
Camera.Size size = getBestPreviewSize(width, height, parameters);
if (size != null) {
parameters.setPreviewSize(size.width, size.height);
Log.d(TAG, "Using width=" + size.width + " height=" + size.height);
}
camera.setParameters(parameters);
camera.startPreview();
inPreview = true;
}
}
i am trying to make an app that detects faces. The code below has no errors and from what i can see should be working fine. However when I run it, i get the following:
FATAL EXCEPTION: main
Process: org.bytefish.videofacedetection, PID: 12075
java.lang.NullPointerException: Attempt to invoke virtual method 'void
android.hardware.Camera.setFaceDetectionListener(android.hardware.Camera$FaceDetectionListener)'
on a null object reference
at org.bytefish.videofacedetection.
CameraActivity.surfaceCreated(CameraActivity.java:100)
at android.view.SurfaceView.updateWindow(SurfaceView.java:582)
at android.view.SurfaceView$3.onPreDraw(SurfaceView.java:177)
at
android.view.ViewTreeObserver.dispatchOnPreDraw(ViewTreeObserver.java:944)
at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:2055)
at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1107)
at
android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:6013)
at
android.view.Choreographer$CallbackRecord.run(Choreographer.java:858)
at android.view.Choreographer.doCallbacks(Choreographer.java:670)
at android.view.Choreographer.doFrame(Choreographer.java:606)
at
android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:844)
at android.os.Handler.handleCallback(Handler.java:739)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:148)
at android.app.ActivityThread.main(ActivityThread.java:5417)
at java.lang.reflect.Method.invoke(Native Method)
at
com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)
The code is below, an all caps comment shows line 100 and the error
import android.app.Activity;
import android.content.Context;
import android.hardware.Camera;
import android.hardware.Camera.Face;
import android.hardware.Camera.FaceDetectionListener;
import android.hardware.SensorManager;
import android.os.Bundle;
import android.util.Log;
import android.view.OrientationEventListener;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.ViewGroup.LayoutParams;
import android.widget.Toast;
import java.util.List;
public class CameraActivity extends Activity
implements SurfaceHolder.Callback {
public static final String TAG = CameraActivity.class.getSimpleName();
private Camera mCamera;
// We need the phone orientation to correctly draw the overlay:
private int mOrientation;
private int mOrientationCompensation;
private OrientationEventListener mOrientationEventListener;
// Let's keep track of the display rotation and orientation also:
private int mDisplayRotation;
private int mDisplayOrientation;
// Holds the Face Detection result:
private Camera.Face[] mFaces;
// The surface view for the camera data
private SurfaceView mView;
// Draw rectangles and other fancy stuff:
private FaceOverlayView mFaceView;
// Log all errors:
private final CameraErrorCallback mErrorCallback = new CameraErrorCallback();
/**
* Sets the faces for the overlay view, so it can be updated
* and the face overlays will be drawn again.
*/
private FaceDetectionListener faceDetectionListener = new FaceDetectionListener() {
#Override
public void onFaceDetection(Face[] faces, Camera camera) {
Log.d("onFaceDetection", "Number of Faces:" + faces.length);
// Update the view now!
mFaceView.setFaces(faces);
}
};
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mView = new SurfaceView(this);
setContentView(mView);
// Now create the OverlayView:
mFaceView = new FaceOverlayView(this);
addContentView(mFaceView, new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
// Create and Start the OrientationListener:
mOrientationEventListener = new SimpleOrientationEventListener(this);
mOrientationEventListener.enable();
}
#Override
protected void onPostCreate(Bundle savedInstanceState) {
super.onPostCreate(savedInstanceState);
SurfaceHolder holder = mView.getHolder();
holder.addCallback(this);
}
#Override
protected void onPause() {
mOrientationEventListener.disable();
super.onPause();
}
#Override
protected void onResume() {
mOrientationEventListener.enable();
super.onResume();
}
#Override
public void surfaceCreated(SurfaceHolder surfaceHolder) {
mCamera = Camera.open();
mCamera.setFaceDetectionListener(faceDetectionListener);
mCamera.startFaceDetection();
try {
mCamera.setPreviewDisplay(surfaceHolder);
} catch (Exception e) {
Log.e(TAG, "Could not preview the image.", e);
}
}
#Override
public void surfaceChanged(SurfaceHolder surfaceHolder, int format, int width, int height) {
// We have no surface, return immediately:
if (surfaceHolder.getSurface() == null) {
return;
}
// Try to stop the current preview:
try {
mCamera.stopPreview();
} catch (Exception e) {
// Ignore...
}
configureCamera(width, height);
setDisplayOrientation();
setErrorCallback();
// Everything is configured! Finally start the camera preview again:
mCamera.startPreview();
}
private void setErrorCallback() {
mCamera.setErrorCallback(mErrorCallback);
}
private void setDisplayOrientation() {
// Now set the display orientation:
mDisplayRotation = Util.getDisplayRotation(CameraActivity.this);
mDisplayOrientation = Util.getDisplayOrientation(mDisplayRotation, 0);
mCamera.setDisplayOrientation(mDisplayOrientation);
if (mFaceView != null) {
mFaceView.setDisplayOrientation(mDisplayOrientation);
}
}
private void configureCamera(int width, int height) {
Camera.Parameters parameters = mCamera.getParameters();
// Set the PreviewSize and AutoFocus:
setOptimalPreviewSize(parameters, width, height);
setAutoFocus(parameters);
// And set the parameters:
mCamera.setParameters(parameters);
}
private void setOptimalPreviewSize(Camera.Parameters cameraParameters, int width, int height) {
List<Camera.Size> previewSizes = cameraParameters.getSupportedPreviewSizes();
float targetRatio = (float) width / height;
Camera.Size previewSize = Util.getOptimalPreviewSize(this, previewSizes, targetRatio);
cameraParameters.setPreviewSize(previewSize.width, previewSize.height);
}
private void setAutoFocus(Camera.Parameters cameraParameters) {
cameraParameters.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_VIDEO);
}
#Override
public void surfaceDestroyed(SurfaceHolder surfaceHolder) {
mCamera.setPreviewCallback(null);
mCamera.setFaceDetectionListener(null);
mCamera.setErrorCallback(null);
mCamera.release();
mCamera = null;
}
/**
* We need to react on OrientationEvents to rotate the screen and
* update the views.
*/
private class SimpleOrientationEventListener extends OrientationEventListener {
public SimpleOrientationEventListener(Context context) {
super(context, SensorManager.SENSOR_DELAY_NORMAL);
}
#Override
public void onOrientationChanged(int orientation) {
// We keep the last known orientation. So if the user first orient
// the camera then point the camera to floor or sky, we still have
// the correct orientation.
if (orientation == ORIENTATION_UNKNOWN) return;
mOrientation = Util.roundOrientation(orientation, mOrientation);
// When the screen is unlocked, display rotation may change. Always
// calculate the up-to-date orientationCompensation.
int orientationCompensation = mOrientation
+ Util.getDisplayRotation(CameraActivity.this);
if (mOrientationCompensation != orientationCompensation) {
mOrientationCompensation = orientationCompensation;
mFaceView.setOrientation(mOrientationCompensation);
}
}
}
}
When i try to open it in android studio it opens fine with no errors but dies when i try to run it.
I am new to android so any tips would be much appreciated. Thanks a ton for your help and time.
Ok, it looks like you are not getting the camera object right
this code will init the front camera properly
part1
cameraId = findFrontFacingCamera();
if (cameraId < 0) {
Toast.makeText(this, "No camera found.",
Toast.LENGTH_LONG).show();
} else {
mcamera = Camera.open(cameraId);
}
part2
private int findFrontFacingCamera() {
int cameraId = -1;
// Search for the front facing camera
int numberOfCameras = Camera.getNumberOfCameras();
for (int i = 0; i < numberOfCameras; i++) {
CameraInfo info = new CameraInfo();
Camera.getCameraInfo(i, info);
if (info.facing == CameraInfo.CAMERA_FACING_FRONT) {
Log.d(DEBUG_TAG, "Camera found");
cameraId = i;
break;
}
}
return cameraId;
}
please try and let me know.