0

I am making a custom camera that simply takes a picture and previews the image. I am not able to preview the image. Even if i call the stopPreview method after taking the picture, the picture is displayed but the camera gets reset when I press home and resume the app again.

public class CameraActivity extends ActionBarActivity {
Camera camera;
private static final String TAG = CameraActivity.class.getName();
private Button captureImageButton;
private Button retakeImageButton;
private Button nextImageButton;
private Button doneButton;
static final String IS_NEW_IMAGE = "isNewImage";
private CameraSurfaceView cameraPreview;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_camera);
    captureImageButton = (Button) findViewById(R.id.button_capture);
    retakeImageButton = (Button) findViewById(R.id.retakeImage);
    nextImageButton = (Button) findViewById(R.id.nextImage);
    doneButton = (Button) findViewById(R.id.done);
}

@Override
protected void onResume() {
    super.onResume();
    camera = getCameraInstance();
    if (camera != null) {
        cameraPreview = new CameraSurfaceView(this, camera);
        FrameLayout preview = (FrameLayout) findViewById(R.id.camera_preview);
        preview.addView(cameraPreview);
    }
    captureImageButton.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            if (camera != null) {
                camera.takePicture(null, null, mPicture);
            }
        }
    });
}

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    // Inflate the menu; this adds items to the action bar if it is present.
    getMenuInflater().inflate(R.menu.menu_camera, menu);
    return true;
}

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    // Handle action bar item clicks here. The action bar will
    // automatically handle clicks on the Home/Up button, so long
    // as you specify a parent activity in AndroidManifest.xml.
    int id = item.getItemId();

    //noinspection SimplifiableIfStatement
    if (id == R.id.action_settings) {
        return true;
    }

    return super.onOptionsItemSelected(item);
}

private Camera getCameraInstance() {
    Camera c = null;
    try {
        int backCameraId = findBackFacingCamera();
        if (backCameraId >= 0) {
            c = Camera.open(backCameraId); // attempt to get a Camera instance
        }
    } catch (Exception e) {
        final Snackbar snackBar = Snackbar.make(findViewById(android.R.id.content), "Please shut down all the background applications and try again", Snackbar.LENGTH_LONG);
        ViewGroup snackBarView = (ViewGroup) snackBar.getView();
        snackBarView.setBackgroundColor(getResources().getColor(R.color.PrimaryOrange));
        snackBar.setAction("Go Back", new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (getApplicationContext() != null) {
                    snackBar.dismiss();
                    finish();
                }
            }
        });
        snackBar.show();
    }
    return c; // returns null if camera is unavailable
}

private Camera.PictureCallback mPicture = new Camera.PictureCallback() {

    @Override
    public void onPictureTaken(byte[] data, Camera camera) {
        enablePreviewMode();
        camera.stopPreview();
        File pictureFile = getOutputMediaFile(MEDIA_TYPE_IMAGE);
        if (pictureFile == null) {
            Log.d(TAG, "Error creating media file, check storage permissions: ");
            return;
        }
        try {
            FileOutputStream fos = new FileOutputStream(pictureFile);
            fos.write(data);
            fos.close();
        } catch (FileNotFoundException e) {
            Log.d(TAG, "File not found: " + e.getMessage());
        } catch (IOException e) {
            Log.d(TAG, "Error accessing file: " + e.getMessage());
        }

    }
};
public static final int MEDIA_TYPE_IMAGE = 1;

/**
 * Create a file Uri for saving an image or video
 */
private static Uri getOutputMediaFileUri(int type) {
    return Uri.fromFile(getOutputMediaFile(type));
}

/**
 * Create a File for saving an image or video
 */
private static File getOutputMediaFile(int type) {
    // To be safe, you should check that the SDCard is mounted
    // using Environment.getExternalStorageState() before doing this.

    File mediaStorageDir = new File(Environment.getExternalStoragePublicDirectory(
            Environment.DIRECTORY_PICTURES), "MyCameraApp");
    // This location works best if you want the created images to be shared
    // between applications and persist after your app has been uninstalled.

    // Create the storage directory if it does not exist
    if (!mediaStorageDir.exists()) {
        if (!mediaStorageDir.mkdirs()) {
            Log.d("MyCameraApp", "failed to create directory");
            return null;
        }
    }

    // Create a media file name
    String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss", Locale.US).format(new Date());
    File mediaFile;
    mediaFile = new File(mediaStorageDir.getPath() + File.separator +
            "IMG_" + timeStamp + ".png");
    return mediaFile;
}

private void enablePreviewMode() {
    if (captureImageButton != null && retakeImageButton != null && doneButton != null & nextImageButton != null) {
        captureImageButton.setVisibility(View.GONE);
        retakeImageButton.setVisibility(View.VISIBLE);
        retakeImageButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent retakeIntent = getIntent();
                if (retakeIntent != null) {
                    finish();
                    retakeIntent.putExtra(IS_NEW_IMAGE, true);
                    startActivity(retakeIntent);
                }
            }
        });
        doneButton.setVisibility(View.VISIBLE);
        doneButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                finish();
            }
        });
        nextImageButton.setVisibility(View.VISIBLE);
        nextImageButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent retakeIntent = getIntent();
                if (retakeIntent != null) {
                    finish();
                    retakeIntent.putExtra(IS_NEW_IMAGE, false);
                    startActivity(retakeIntent);
                }
            }
        });
    }
}

private void releaseCamera() {
    if (camera != null) {
        camera.release();
    }
    if (cameraPreview != null) {
        cameraPreview.getHolder().removeCallback(cameraPreview);
    }
}

private int findBackFacingCamera() {
    int cameraId = -1;
    //Search for the back facing camera
    //get the number of cameras
    int numberOfCameras = Camera.getNumberOfCameras();
    //for every camera check
    for (int i = 0; i < numberOfCameras; i++) {
        Camera.CameraInfo info = new Camera.CameraInfo();
        Camera.getCameraInfo(i, info);
        if (info.facing == Camera.CameraInfo.CAMERA_FACING_BACK) {
            cameraId = i;
            break;
        }
    }
    return cameraId;
}

@Override
protected void onPause() {
    super.onPause();
    releaseCamera();
}

@Override
protected void onStop() {
    super.onStop();
    releaseCamera();

}

}

SurfaceView

public class CameraSurfaceView extends SurfaceView implements SurfaceHolder.Callback {
private SurfaceHolder mHolder;
private Camera mCamera;
private static final String TAG = CameraSurfaceView.class.getName();

public CameraSurfaceView(Context context, Camera camera) {
    super(context);
    mCamera = camera;

    // Install a SurfaceHolder.Callback so we get notified when the
    // underlying surface is created and destroyed.
    mHolder = getHolder();
    mHolder.addCallback(this);
    // deprecated setting, but required on Android versions prior to 3.0
    mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
}

public void surfaceCreated(SurfaceHolder holder) {
    // The Surface has been created, now tell the camera where to draw the preview.
    try {
        mCamera.setDisplayOrientation(90);
        mCamera.setPreviewDisplay(holder);
        Camera.Parameters params = mCamera.getParameters();
        params.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO);
        mCamera.setParameters(params);
        mCamera.startPreview();
    } catch (IOException e) {
        Log.d(TAG, "Error setting camera preview: " + e.getMessage());
    }
}

public void surfaceDestroyed(SurfaceHolder holder) {
    // empty. Take care of releasing the Camera preview in your activity.
    mCamera.release();
}

public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
    // If your preview can change or rotate, take care of those events here.
    // Make sure to stop the preview before resizing or reformatting it.

    if (mHolder.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

    // start preview with new settings
    try {
        mCamera.setPreviewDisplay(mHolder);
        mCamera.startPreview();

    } catch (Exception e) {
        Log.d(TAG, "Error starting camera preview: " + e.getMessage());
    }
}

}

Even the normal camera does not work like this. Another way was using 2 fragments and passing the image but I would like it if android had some provision for this.

android_eng
  • 1,370
  • 3
  • 17
  • 40

1 Answers1

0

Do you put your CameraSurfaceView in your activity_camera.xml ?
If the answer is true, I think I know how to fix your problem.
You just need extract your CameraSurfaceView xml definition into a standalone xml layout file, and inflate it at onResume() callback of Activity, and attach it to your layout root, say call top level Layout object's addChild method and pass your inflated CameraSurfaceView in, and detach it at onPause() callback of Activity, say remove the CameraSurfaceView from your top level Layout object.
In summary:
1. inflate (re-inflate every time) and add your CameraSurfaceView into your view hierarchy in onResume();
2. remove your CameraSurfaceView from your view hierarchy and nullify it.

Piasy
  • 989
  • 13
  • 35