I'm working on a flashlight app using the camera flash. It seems to work fine but on occasion calling camera.release() causes a hang for about a minute or so. I've included the code below. I've looked at a bunch of examples and I don't see anything that could cause such a thing. Any ideas?
//latest
public void setOn(boolean on, Context context) {
if (lock) {
Log.i(TAG, "lock: true");
return;
}
if (on) {
if (mCamera == null) {
mCamera = Camera.open();
}
Parameters params = mCamera.getParameters();
params.setFlashMode(MODE_TORCH);
mCamera.setParameters(params);
mCamera.startPreview();
} else {
if (mCamera != null) {
try {
Parameters params = mCamera.getParameters();
params.setFlashMode(MODE_OFF);
mCamera.setParameters(params);
} finally {
new Thread(new Runnable() {
public void run() {
Log.i(TAG, "new Thread - start");
lock = true;
mCamera.setPreviewCallback(null);
mCamera.stopPreview();
mCamera.release();
mCamera = null;
lock = false;
Log.i(TAG, "new Thread - end");
}
}).start();
}
}
}
}
//original
public void setOn(boolean on, Context context) {
Camera camera = mCamera;
if (on) {
if (camera == null) {
mCamera = camera = Camera.open();
}
Parameters params = camera.getParameters();
params.setFlashMode(MODE_TORCH);
camera.setParameters(params);
camera.startPreview();
} else {
if (camera != null) {
try {
Parameters params = camera.getParameters();
params.setFlashMode(MODE_OFF);
camera.setParameters(params);
} finally {
camera.stopPreview();
camera.release();
mCamera = camera = null;
}
}
}
}
Try putting it in a thread to run in the background so it wont hang up the UI.
new Thread(new Runnable(){
public void run(){
camera.setPreviewCallback(null); // PreviewCallback de_init.
camera.stopPreview(); // stop Preview
camera.release();
}
}).start();
For me, the solution that works is:
Try{
camera.stopPreview();
camera.setPreviewCallback(null);
camera.release();
camera = null;
} catch (Exception e){
//...
}
I`ve solved this isuue adding camera.unlock() before release()
camera.stopPreview();
camera.setPreviewCallback(null);
camera.unlock();
camera.release();
camera = null;
test on more devices needed...
just call your methods like
mCamera.stopPreview();
mCamera.setPreviewCallback(null);
mCamera.release();
you have to call setPreviewCallback(null) betweeen stopPreview and camera.releass
Related
I want to make the camera light flash. My code will make it flash just fine of a single button press but if I hit the button again before it has finished flashing it will crash my app. I believe I need to somehow check to see if it is still flashing before I try to start the flash again.
public class BlinkBack {
public static void blink(MainActivity ma){
if (ma.getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA_FLASH)){
final Camera mCamera = Camera.open();
new CountDownTimer(5000, 100) {
int counter = 0;
public void onTick(long millisUntilFinished) {
if (counter % 2 == 0) {
Camera.Parameters params = mCamera.getParameters();
params.setFlashMode(Camera.Parameters.FLASH_MODE_TORCH);
mCamera.setParameters(params);
mCamera.startPreview();
}
else {
Camera.Parameters params = mCamera.getParameters();
params.setFlashMode(Camera.Parameters.FLASH_MODE_OFF);
mCamera.setParameters(params);
mCamera.stopPreview();
}
counter++;
}
public void onFinish() {
Camera.Parameters params = mCamera.getParameters();
params.setFlashMode(Camera.Parameters.FLASH_MODE_OFF);
mCamera.setParameters(params);
mCamera.stopPreview();
mCamera.release();
}
}.start();
}
}
}
I found my own answer. final Camera mCamera = Camera.open(); has an unchecked RunTimeException so I just ate that exception with a try catch and it fixed it
public class BlinkBack {
public static void blink(MainActivity ma){
if (ma.getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA_FLASH)){
try {
final Camera mCamera = Camera.open();
new CountDownTimer(5000, 100) {
int counter = 0;
public void onTick(long millisUntilFinished) {
if (counter % 2 == 0) {
Camera.Parameters params = mCamera.getParameters();
params.setFlashMode(Camera.Parameters.FLASH_MODE_TORCH);
mCamera.setParameters(params);
mCamera.startPreview();
}
else {
Camera.Parameters params = mCamera.getParameters();
params.setFlashMode(Camera.Parameters.FLASH_MODE_OFF);
mCamera.setParameters(params);
mCamera.stopPreview();
}
counter++;
}
public void onFinish() {
Camera.Parameters params = mCamera.getParameters();
params.setFlashMode(Camera.Parameters.FLASH_MODE_OFF);
mCamera.setParameters(params);
mCamera.stopPreview();
mCamera.release();
}
}.start();
}
catch (Exception e) {
e.printStackTrace();
}
}
}
}
I am using AsyncTask to open camera in background thread. It works fine but at times(10 % chance) it will not release the camera and I will have blank preview screen if I open my app again and native camera shouts at me saying you haven't released camera resource.
Below is my AsyncTask code.
private class AsyncCamera extends AsyncTask<Void, Void, Camera> {
int _id = 0;
public AsyncCamera(int id) {
_id = id;
}
protected void onPreExecute() {
progressBar.setVisibility(View.VISIBLE);
releaseCameraAndPreview();
}
protected Camera doInBackground(Void... params) {
Camera camera;
camera = getCamera(_id);
return camera;
}
protected void onPostExecute(Camera camera) {
mCamera = camera;
setCamera(camera);
safeToTakePicture = true;
progressBar.setVisibility(View.GONE);
}
}
And releaseCameraAndPreview() method
private void releaseCameraAndPreview() {
setCamera(null);//to stop preview and clear frame layout
if (mCamera != null) {
mCamera.release();
mCamera = null;
}
}
here getCamera() method
private Camera getCamera(int id) {
try {
releaseCameraAndPreview();
mCamera = Camera.open(id);
} catch (Exception e) {
Log.e(getString(R.string.app_name), "failed to open Camera");
e.printStackTrace();
}
return mCamera;
}
And last setCamera() method.
public void setCamera(Camera camera) {
if (camera == null) {
if (mCamera != null) {
mCamera.stopPreview();
}
return;
} else {
//set parameters.clear frame layout and add view to it and start preview
mCamera = camera;
params = mCamera.getParameters();
setPictureAndPreviewSize();
if (mCamera != null) {
mPreview = new Preview(getApplicationContext(), mCamera);
mPreviewLayout.removeAllViews();
mPreviewLayout.addView(mPreview);
}
}
}
onPause() method
#Override
protected void onPause() {
super.onPause();
if (mCamera != null) {
mCamera.setPreviewCallback(null);
mPreview.getHolder().removeCallback(mPreview);
mCamera.release();
mCamera = null;
}
}
I can produce the same error by pressing lock screen button while my app is open.
Update
Check out my answer
Original
I'm trying to turn on the camera flashlight on the LG Revolution within my program. I use the torch mode method which works on most phones but not on LG phone. Does anyone know how to get it to work on LG's or specifically the Revolution?
Here's my manifest:
<uses-permission android:name="android.permission.CAMERA" />
<uses-feature android:name="android.hardware.camera" />
<uses-permission android:name="android.permission.FLASHLIGHT"/>
Here's my current code:
public Camera camera = Camera.open();
public Camera.Parameters Flash = camera.getParameters();
With my on create:
Flash.setFlashMode("torch");
Parameters p = camera.getParameters();
camera.setParameters(Flash);
camera.startPreview();
I've seen people use an auto focus but i don't know if that would work.
I thought I would update this with some bullet prof code that works on almost all 4.0+ devices.
public void turnOn() {
camera = Camera.open();
try {
Parameters parameters = camera.getParameters();
parameters.setFlashMode(getFlashOnParameter());
camera.setParameters(parameters);
camera.setPreviewTexture(new SurfaceTexture(0));
camera.startPreview();
camera.autoFocus(this);
} catch (Exception e) {
// We are expecting this to happen on devices that don't support autofocus.
}
}
private String getFlashOnParameter() {
List<String> flashModes = camera.getParameters().getSupportedFlashModes();
if (flashModes.contains(FLASH_MODE_TORCH)) {
return FLASH_MODE_TORCH;
} else if (flashModes.contains(FLASH_MODE_ON)) {
return FLASH_MODE_ON;
} else if (flashModes.contains(FLASH_MODE_AUTO)) {
return FLASH_MODE_AUTO;
}
throw new RuntimeException();
}
The real key is setting that fake SurfaceTexture so that the preview will actually start. Turning it off is very easy as well
public void turnOff() {
try {
camera.stopPreview();
camera.release();
camera = null;
} catch (Exception e) {
// This will happen if the camera fails to turn on.
}
}
It seems like the developer of the Tiny Flashlight + LED app on the Android Market figured out how to make the flashlight work on LG Revolution.
Maybe you can contact him and ask?
You can also check the permissions he is using in his app to try to make your app work!
Good luck!
Test this :
if(camera == null){
camera = Camera.open();
parameters = camera.getParameters();
List<String> flashModes = parameters.getSupportedFlashModes();
if(flashModes != null && flashModes.contains(Parameters.FLASH_MODE_TORCH)){
//appareil supportant le mode torch
parameters.setFlashMode(Parameters.FLASH_MODE_TORCH);
camera.setParameters(parameters);
} else if (flashModes != null && flashModes.contains(Parameters.FLASH_MODE_ON)){
//spécial samsung
parameters.setFlashMode(Parameters.FLASH_MODE_ON);
camera.setParameters(parameters);
camera.startPreview();
camera.autoFocus(new AutoFocusCallback() {
public void onAutoFocus(boolean success, Camera camera) { }
});
} else {
parameters.setFlashMode(Parameters.FLASH_MODE_OFF);
camera.setParameters(parameters);
}
parameters.setFlashMode( Parameters.FLASH_MODE_OFF );
camera.setParameters(parameters);
camera.release();
camera = null;
} catch (RuntimeException e) {}
}//if
This worked well for LG Nexus:
camera = Camera.open();
camera.setPreviewTexture(new SurfaceTexture(0));
camera.setParameters(p);
camera.startPreview();
/*TESTED LG G4 */
public void flashOnOff(){
List<String> flashModes = parameter001.getSupportedFlashModes();
if(flashModes != null && flashModes.contains(Parameters.FLASH_MODE_TORCH)){
//appareil supportant le mode torch
parameter001.setFlashMode(Parameters.FLASH_MODE_TORCH);
mCamera.setParameters(parameter001);
} else if (flashModes != null && flashModes.contains(Parameters.FLASH_MODE_ON)){
//spécial samsung
parameter001.setFlashMode(Parameters.FLASH_MODE_ON);
mCamera.setParameters(parameter001);
mCamera.autoFocus(new AutoFocusCallback() {
public void onAutoFocus(boolean success, Camera camera) { }
});
} else {
parameter001.setFlashMode(Parameters.FLASH_MODE_OFF);
mCamera.setParameters(parameter001);
}
if (!isFlashOn) {
if (mCamera == null || parameter001 == null) {
return;
}
parameter001 = mCamera.getParameters();
parameter001.setFlashMode(Parameters.FLASH_MODE_TORCH);
mCamera.setParameters(parameter001);
try {
mCamera.setPreviewTexture(new SurfaceTexture(0));
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
mCamera.startPreview();
isFlashOn = true;
// changing button/switch image
}else if (isFlashOn) {
if (mCamera == null || parameter001 == null) {
return;
}
parameter001 = mCamera.getParameters();
parameter001.setFlashMode(Parameters.FLASH_MODE_OFF);
mCamera.setParameters(parameter001);
mCamera.stopPreview();
isFlashOn = false;
}
}
I've run into such a problem. The problem is that when I use onPictureTaken function the light is automatically go down. What should I do with it? I want the light not to turn off.
Photo :
if (v == shot)
{
camera.takePicture (null, null, null, this);
}
flashlight:
if (prefs.getBoolean (getString (R.string.torch), false))
{
Parameters params = camera.getParameters ();
params.setFlashMode (Parameters.FLASH_MODE_TORCH);
camera.setParameters (params);
}
#Override
public void surfaceCreated(SurfaceHolder holder)
{
try
{
camera.setPreviewCallback(this);
camera.setPreviewDisplay(holder);
Camera.Parameters p = camera.getParameters();
p.setPictureSize(1024, 768);
p.setPictureFormat (PixelFormat.RGB_565);
camera.setParameters(p);
}
catch (IOException e)
{
e.printStackTrace();
}
LayoutParams lp = preview.getLayoutParams();
if (this.getResources().getConfiguration().orientation != Configuration.UI_MODE_TYPE_CAR)
{
camera.setDisplayOrientation(90);
}
else
{
camera.setDisplayOrientation(0);
}
preview.setLayoutParams(lp);
camera.startPreview();
return;
}
#Override
protected void onPause()
{
if (camera != null)
{
camera.setPreviewCallback(null);
camera.stopPreview();
camera.release();
camera = null;
}
super.onPause();
return ;
}
protected void onResume()
{
super.onResume();
camera = Camera.open();
}
If I use only CAMERA_FACING_BACK or CAMERA_FACING_FRONT all works fine.
I have trouble with switch from CAMERA_FACING_BACK to CAMERA_FACING_FRONT.
My code snippet:
public class PhotoCameraActivity extends Activity implements OnClickListener {
private SurfaceView cameraView;
private Button turnButton;
private Camera camera = null;
private Callback listener;
private static int camId = Camera.CameraInfo.CAMERA_FACING_BACK;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.photo_camera_main);
prepareActivity();
}
private void prepareActivity() {
cameraView = (SurfaceView) findViewById(R.id.photo_camera_surface_view);
turnButton = (ImageButton) findViewById(R.id.turn_button);
turnButton.setOnClickListener(this);
}
#Override
public void onClick(View v) {
if (v.equals(turnButton)) {
if (Camera.getNumberOfCameras() > 1 && camId < Camera.getNumberOfCameras() - 1) {
startCamera(camId + 1);
} else {
startCamera(Camera.CameraInfo.CAMERA_FACING_BACK);
}
}
}
#Override
protected void onResume() {
startCamera(camId);
super.onResume();
}
#Override
protected void onPause() {
stopCamera();
super.onPause();
}
private void startCamera(int cameraId) {
if (camera != null) {
stopCamera();
}
holder = cameraView.getHolder();
listener = new Callback() {
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
}
#Override
public void surfaceCreated(SurfaceHolder holder) {
try {
camera.setPreviewDisplay(holder);
camera.startPreview();
} catch (IOException e) {
e.printStackTrace();
}
}
#Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {}
};
holder.addCallback(listener);
camId = cameraId;
camera = Camera.open(cameraId);
Camera.Parameters params = camera.getParameters();
if (cameraId == Camera.CameraInfo.CAMERA_FACING_BACK) {
params.setPreviewSize(1280, 800);
} else {
params.setPreviewSize(640, 480);
}
camera.setParameters(params);
}
private void stopCamera(){
System.out.println("stopCamera method");
if (camera != null){
camera.stopPreview();
camera.setPreviewCallback(null);
camera.release();
camera = null;
holder.removeCallback(listener);
holder = null;
}
}
}
In onCreate() of my activity I add the following onClick listener to a button overlayed on my Preview SurfaceView (there are numerous example on the web for previewing):
ImageButton useOtherCamera = (ImageButton) findViewById(R.id.useOtherCamera);
//if phone has only one camera, hide "switch camera" button
if(Camera.getNumberOfCameras() == 1){
useOtherCamera.setVisibility(View.INVISIBLE);
}
else {
useOtherCamera.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (inPreview) {
camera.stopPreview();
}
//NB: if you don't release the current camera before switching, you app will crash
camera.release();
//swap the id of the camera to be used
if(currentCameraId == Camera.CameraInfo.CAMERA_FACING_BACK){
currentCameraId = Camera.CameraInfo.CAMERA_FACING_FRONT;
}
else {
currentCameraId = Camera.CameraInfo.CAMERA_FACING_BACK;
}
camera = Camera.open(currentCameraId);
//Code snippet for this method from somewhere on android developers, i forget where
setCameraDisplayOrientation(CameraActivity.this, currentCameraId, camera);
try {
//this step is critical or preview on new camera will no know where to render to
camera.setPreviewDisplay(previewHolder);
} catch (IOException e) {
e.printStackTrace();
}
camera.startPreview();
}
On my test device the back camera has an ID of 0 and the front has an id of 1. I suggest using Camera.CameraInfo static variables for your camera id's rather than hard-coding values. I am sure that will only cause issues on other devices.
I restart Activity with cameraId = 2 and this is working.
I removed and re-added SurfaceView in my layout and so it worked.
public void switchCamera(int cameraType)
{
if(context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA_FRONT))
{
if(Camera.getNumberOfCameras() > cameraType)
{
// Set selected camera
this.cameraType = cameraType;
}
else
{
// Set default camera (Rear)
this.cameraType = Camera.CameraInfo.CAMERA_FACING_BACK;
}
if(mCamera != null)
{
// Destroy previuos Holder
surfaceDestroyed(holder);
holder.removeCallback(this);
// Remove and re-Add SurfaceView
ViewGroup rootLayout = (ViewGroup) surface.getParent();
rootLayout.removeView(surface);
surface = new SurfaceView(context);
holder = surface.getHolder();
holder.addCallback(this);
rootLayout.addView(surface, new ViewGroup.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT));
}
}
}
I have to remove the surface preview before adding a new one:
if (mPreview != null) {
mPreview.surfaceDestroyed(mPreview.getHolder());
mPreview.getHolder().removeCallback(mPreview);
mPreview.destroyDrawingCache();
FrameLayout preview = (FrameLayout) view.findViewById(R.id.camera_frame);
preview.removeView(mPreview);
mPreview.mCamera = null;
mPreview = null;
}
//then add your preview
Use this code:
if (mCamera != null) {
mCamera.stopPreview();
mCamera.release();
mCamera = null;
}
//swap the id of the camera to be used
if (currentCameraId == Camera.CameraInfo.CAMERA_FACING_BACK)
currentCameraId = Camera.CameraInfo.CAMERA_FACING_FRONT;
else
currentCameraId = Camera.CameraInfo.CAMERA_FACING_BACK;
try {
mCamera = Camera.open(currentCameraId);
mCamera.setDisplayOrientation(90);
mCamera.setPreviewDisplay(surfaceHolder);
mCamera.startPreview();
}
catch (Exception e) { e.printStackTrace(); }
try using this:
camera.stopPreview();
if(camera != null)
camera.release();
try {
camera = Camera.open(/*new id*/);
camera.setPreviewDisplay(holder);
camera.startPreview();
} catch (Exception ex) { ex.printStackTrace(); }