Flash Camera Crash - android

my app uses the camera flash but I do not understand why if I open another app and then resume my app the app crashes. I think because I have not inserted the pause and resume in the app.
This is MainActivity:
public class MainActivity extends ActionBarActivity {
//flag to detect flash is on or off
private boolean isLighOn = false;
private Camera camera;
private Button button;
private LinearLayout rl;
int i=0;
#Override
protected void onStop() {
super.onStop();
if (camera != null) {
camera.release();
}
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
button = (Button) findViewById(R.id.buttonFlashlight);
rl=(LinearLayout) findViewById(R.id.container);
rl.setBackgroundColor(getResources().getColor(R.color.Black));
Context context = this;
PackageManager pm = context.getPackageManager();
// if device support camera?
if (!pm.hasSystemFeature(PackageManager.FEATURE_CAMERA)) {
Log.e("err", "Device has no camera!");
return;
}
camera = Camera.open();
final Parameters p = camera.getParameters();
button.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View arg0) {
if (isLighOn) {
Log.i("info", "torch is turn off!");
p.setFlashMode(Parameters.FLASH_MODE_OFF);
camera.setParameters(p);
camera.stopPreview();
isLighOn = false;
button.setBackgroundResource(R.drawable.off);
rl.setBackgroundColor(getResources().getColor(R.color.Black));
} else {
Log.i("info", "torch is turn on!");
p.setFlashMode(Parameters.FLASH_MODE_TORCH);
camera.setParameters(p);
camera.startPreview();
isLighOn = true;
button.setBackgroundResource(R.drawable.on);
rl.setBackgroundResource(R.drawable.check);
}
}
});
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, 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();
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
}
Logcat:
03-29 21:24:51.048: D/AndroidRuntime(27113): Shutting down VM
03-29 21:24:51.048: W/dalvikvm(27113): threadid=1: thread exiting with uncaught exception (group=0x418eeda0)
03-29 21:24:51.058: E/AndroidRuntime(27113): FATAL EXCEPTION: main
03-29 21:24:51.058: E/AndroidRuntime(27113): Process: com.example.torcia, PID: 27113
03-29 21:24:51.058: E/AndroidRuntime(27113): java.lang.RuntimeException: Method called after release()

When you let your app go into the background, stop() is called. Then you release your camera. After this you cannot use it again- you need to call camera.open() and get a new camera object. I suggest not creating camera objects in onCreate, but only doing it in onStart (or onResume).

The problem is that you release the camera when the application is stopped, but you don't initialise the camera again when the application is resumed. Your camera initialisation code is in onCreate which won't get called again.
It's probably best to initialise the camera in onResume and release it in onPause.
E.g.
#Override
protected void onResume() {
super.onResume();
camera = Camera.open();
}
#Override
protected void onPause() {
super.onPause();
if (camera != null) {
camera.release();
}
}

Related

Running an android flashlight in background

How can I keep the flashlight on in the background even when I switch to next activity or next application. Also my flashlight turns off automatically when I my screen locks and I want to keep my flash glowing even the screen locks.
This is my current code:
private Camera camera;
private boolean isFlashOn;
private boolean hasFlash;
Camera.Parameters params;
MediaPlayer mp;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_savedform);
toolbar= (Toolbar) findViewById(R.id.app_bar);
setSupportActionBar(toolbar);
getSupportActionBar().setHomeButtonEnabled(true);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
btnSwitch = (ImageButton) findViewById(R.id.btnSwitch);
// First check if device is supporting flashlight or not
hasFlash = getApplicationContext().getPackageManager()
.hasSystemFeature(PackageManager.FEATURE_CAMERA_FLASH);
if (!hasFlash) {
// device doesn't support flash
// Show alert message and close the application
AlertDialog alert = new AlertDialog.Builder(SavedForm.this)
.create();
alert.setTitle("Error");
alert.setMessage("Sorry, your device doesn't support flash light!");
alert.setButton("OK", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
// closing the application
finish();
}
});
alert.show();
return;
}
// get the camera
getCamera();
// displaying button image
toggleButtonImage();
// Switch button click event to toggle flash on/off
btnSwitch.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (isFlashOn) {
// turn off flash
turnOffFlash();
} else {
// turn on flash
turnOnFlash();
}
}
});
}
// Get the camera
private void getCamera() {
if (camera == null) {
try {
camera = Camera.open();
params = camera.getParameters();
} catch (RuntimeException e) {
Log.e("Error. Failed to Open", e.getMessage());
}
}
}
// Turning On flash
private void turnOnFlash() {
if (!isFlashOn) {
if (camera == null || params == null) {
return;
}
// play sound
playSound();
params = camera.getParameters();
params.setFlashMode(Camera.Parameters.FLASH_MODE_TORCH);
camera.setParameters(params);
camera.startPreview();
isFlashOn = true;
// changing button/switch image
toggleButtonImage();
}
}
// Turning Off flash
private void turnOffFlash() {
if (isFlashOn) {
if (camera == null || params == null) {
return;
}
// play sound
playSound();
params = camera.getParameters();
params.setFlashMode(Camera.Parameters.FLASH_MODE_OFF);
camera.setParameters(params);
camera.stopPreview();
isFlashOn = false;
// changing button/switch image
toggleButtonImage();
}
}
// Playing sound
// will play button toggle sound on flash on / off
private void playSound(){
if(isFlashOn){
mp = MediaPlayer.create(SavedForm.this, R.raw.flashoff);
}else{
mp = MediaPlayer.create(SavedForm.this, R.raw.flashon);
}
mp.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
#Override
public void onCompletion(MediaPlayer mp) {
// TODO Auto-generated method stub
mp.release();
}
});
mp.start();
}
private void toggleButtonImage(){
if(isFlashOn){
btnSwitch.setImageResource(R.drawable.button_on);
}else{
btnSwitch.setImageResource(R.drawable.button_off);
}
}
#Override
protected void onDestroy() {
super.onDestroy();
}
#Override
protected void onPause() {
super.onPause();
// on pause turn off the flash
turnOnFlash();
}
#Override
protected void onRestart() {
super.onRestart();
}
#Override
protected void onResume() {
super.onResume();
// on resume turn on the flash
if(hasFlash)
turnOffFlash();
}
#Override
protected void onStart() {
super.onStart();
// on starting the app get the camera params
getCamera();
}
#Override
protected void onStop() {
super.onStop();
// on stop release the camera
if (camera != null) {
camera.release();
camera = null;
}
}
#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_savedform, 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;
}
if(id==android.R.id.home){
NavUtils.navigateUpFromSameTask(this);
}
return super.onOptionsItemSelected(item);
}
}
The best way to do is by Running a Background service that handles the Flashlight.
You need to put your FlashLight Start and Stop code inside the OnStart and onDestroy of the Service. That you need to do on your own
First of all create a class named FlashLightService that extends the Service
public class FlashLightService extends Service {
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public void onCreate() {
Toast.makeText(this, "Service Created", Toast.LENGTH_LONG).show();
}
#Override
public void onStart(Intent intent, int startid) {
// Put Your Code To Start the FlashLight Over Here
}
#Override
public void onDestroy() {
// Put Your Code To Stop the FlashLight Over Here
}
Now from any Activity you can start and stop the Flashlight according to your need
To start The FlashLight
startService(new Intent(this, FlashLightService.class));
To stop the FlashLight
stopService(new Intent(this, FlashLightService.class));
Do not forget to mention this in your AndroidManifest.xml
Let me know if this works! :)
Remove these code or line.
`
#Override
protected void onStop() {
super.onStop();
// on stop release the camera`enter code here`
if (camera != null) {
camera.release();
camera = null;
}
`
It worked for me.
I am not an android expert but I would recommend,
run it as service or run it as singleton thread.
The flash depends on the camera. Your onStop method contains: camera.release() which will release the camera hardware overriding any other acquisition methods implemented.
You could use background service to control the camera hardware. Start it from an activity and stop the service when your app is closed.

Why is my Flashlight Turning off when clicking a button with intent function?

I am new to android programming and I don't understand why my flashlight is turning off when clicking a button that starts another Activity with an Intent? I have searched for this but found nothing similar. I looked at others' ideas but the closest one is to use a Service instead of an Activity from my main activity. Is it okay to change my Activity to a Service or is another way to resolve this?
tbOnOff = (ToggleButton) findViewById(R.id.togglebutton);
tbOnOff.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
public void onCheckedChanged(CompoundButton buttonView,
boolean isChecked) {
if (isChecked) {
if (camera == null) {
camera = Camera.open();
parameters = camera.getParameters();
parameters.setFlashMode(Parameters.FLASH_MODE_TORCH);
camera.setParameters(parameters);
}
} else {
if (camera != null) {
parameters.setFlashMode(Parameters.FLASH_MODE_OFF);
camera.setParameters(parameters);
camera.release();
camera = null;
}
}
}
});
boolean checkFlash = context.getPackageManager().hasSystemFeature(
PackageManager.FEATURE_CAMERA_FLASH);
if (!checkFlash) {
tbOnOff.setEnabled(false);
Toast.makeText(context, "LED Not Available!", Toast.LENGTH_LONG)
.show();
}
}
// release camera when onPause called
#Override
protected void onPause() {
// TODO Auto-generated method stub
super.onPause();
if (camera != null) {
parameters.setFlashMode(Parameters.FLASH_MODE_OFF);
camera.setParameters(parameters);
camera.release();
camera = null;
}
}
public void send(View arg1) {
Intent i = new Intent(this, InformationActivity.class);
startActivity(i);
}
that's my code for LED light and the Intent.
When you start a new Activity it will be brought to the foreground straight away, which means that you're original Activity will be paused straight away too. Since you're turning off the flashlight in your onPause(), well that's what it does.
As to your other question, yes, if you want the flashlight to stay on independent of the Activity lifecycle, a Service would be a way to do this, as anything else you want to be independent of Activity lifecycles.

End SurfaceView and GameThread on exiting app

I've got a surfaceview and a gameThread class.
The gameThread keeps updating and painting on the SurfaceView class.
Now when I exit the app (By pressing the home or back button) I get a message that the app force closed. That's because the GameThread still tries to draw on the erased surfaceview...
So how do i properly end the app without getting this force close notification? I would like the GameThread class to stop when the back button is pressed. It should pause when pressing on home and running in the background. When re-entering the still running game it should resume....
Any ideas?
This is my GameThread class:
public class GameThread extends Thread{
private GameView view;
public boolean isRunning = false;
public GameThread(GameView view) {
this.view = view;
}
public void setRunning(boolean setRunning) {
isRunning = setRunning;
}
public void run() {
while(isRunning) {
Canvas c = null;
view.update();
try {
c = view.getHolder().lockCanvas();
synchronized (view.getHolder()) {
view.draw(c);
}
}finally {
if(c != null) {
view.getHolder().unlockCanvasAndPost(c);
}
}
}
}
It keeps updating my GameView class:
public class GameView extends SurfaceView{
private GameThread gameThread;
public GameView(Context context, Activity activity) {
super(context);
gameThread = new GameThread(this);
init();
holder = getHolder();
holder.addCallback(new SurfaceHolder.Callback() {
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
}
#Override
public void surfaceCreated(SurfaceHolder holder) {
gameThread.setRunning(true);
gameThread.start();
}
#Override
public void surfaceChanged(SurfaceHolder holder, int format, int width,
int height) {
}
});
}
public void init() {
}
public void update() {
}
public void draw(Canvas canvas) {
super.draw(canvas);
}
}
When pressing home my logcat shows this up:
02-24 18:24:59.336: E/SurfaceHolder(839): Exception locking surface
02-24 18:24:59.336: E/SurfaceHolder(839): java.lang.IllegalStateException: Surface has already been released.
02-24 18:24:59.336: E/SurfaceHolder(839): at android.view.Surface.checkNotReleasedLocked(Surface.java:437)
02-24 18:24:59.336: E/SurfaceHolder(839): at android.view.Surface.lockCanvas(Surface.java:245)
02-24 18:24:59.336: E/SurfaceHolder(839): at android.view.SurfaceView$4.internalLockCanvas(SurfaceView.java:872)
Main activity:
public class MainActivity extends Activity {
private RelativeLayout relativeLayout;
private GameView gameView;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
gameView = new GameView(this, this);
setContentView(R.layout.activity_main);
relativeLayout = (RelativeLayout)findViewById(R.id.mainView);
relativeLayout.addView(gameView);
}
#Override
public void onBackPressed() {
// TODO Auto-generated method stub
super.onBackPressed();
gameView.onBackPressed();
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
}
Well you can make changes to your code like this.
In GameView
#Override
public void surfaceCreated(SurfaceHolder holder) {
MainActivity obj=new MainActivity();
stop=obj.getBoolean(); //receive status of boolean from main activity
//stop is boolean set if backPressed in main activity
if(!stop){
gameThread.setRunning(true);
gameThread.start();
}
else
gameThread.setRunning(false);
}
In MainActivity
public Boolean getBoolean(){
return stop;
}
public void setBoolean(Boolean bools){
stop=bools;
}
#Override
public void onBackPressed() {
// TODO Auto-generated method stub
super.onBackPressed();
stop=true;
setBoolean(stop);
try{
Thread.sleep(200); // Be safeside and wait for Game thread to finish
}
catch(Exception e){
e.printStackTrace();
}
MainActivity.finish();
}
Call setBoolean once before backPress else it will give error. Make amendments to code as per your needs.
Hope it helps. Cheers. :)
The Surface underlying the SurfaceView gets destroyed between onPause() and onDestroy() in the app lifecycle. Send a message to your renderer thread in onPause(), and wait for the thread to shut down.
For an example, see the "Hardware scaler exerciser" activity in Grafika. It starts the render thread in the SurfaceHolder's surfaceCreated() callback.
Update: it felt weird to start the thread in surfaceCreated() and stop it in onPause(), so after a bit of reshuffling HardwareScalerActivity now stops the thread in surfaceDestroyed(). (The SurfaceView documentation is a bit ambiguous -- it says the Surface is valid "between surfaceCreated() and surfaceDestroyed()" -- but looking at the SurfaceView implementation this appears to be the expected usage.)
Update 2: I updated the code some more after finding cases it didn't handle well. There's now a 60-line megacomment in the sources, which can also been seen in my answer to a similar question.
Update 3: The mega-comment turned into an architecture doc appendix. Grafika's "hardware scaler exerciser" activity demonstrates approach #2, while "texture from camera" demonstrates approach #1.

Refresh Activity using onResume()

I have a Flashlight Activity. Normally it works fine but When I go to any other activity, it stop working!
So I want to refresh the code when I back to the Flashlight Activity.
I think refreshing using onResume() would help me best, But how to do it?
public class FlashLightActivity extends Activity {
//flag to detect flash is on or off
private boolean isLighOn = false;
private Camera camera;
private Button next1, next2;
#Override
protected void onStop() {
super.onStop();
if (camera != null) {
camera.release();
}
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
next1 = (Button) findViewById(R.id.ebtn28_answer);
next1.setOnClickListener(new View.OnClickListener() {
public void onClick(View view) {
Intent myIntent = new Intent(view.getContext(), FullScreen.class);
startActivityForResult(myIntent, 0);
}
});
next2 = (Button) findViewById(R.id.buttonFlashlight);
Context context = this;
PackageManager pm = context.getPackageManager();
// if device support camera?
if (!pm.hasSystemFeature(PackageManager.FEATURE_CAMERA)) {
Log.e("err", "Device has no camera!");
return;
}
camera = Camera.open();
final Parameters p = camera.getParameters();
next2.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View arg0) {
if (isLighOn) {
Log.i("info", "torch is turn off!");
p.setFlashMode(Parameters.FLASH_MODE_OFF);
camera.setParameters(p);
camera.stopPreview();
isLighOn = false;
} else {
Log.i("info", "torch is turn on!");
p.setFlashMode(Parameters.FLASH_MODE_TORCH);
camera.setParameters(p);
camera.startPreview();
isLighOn = true;
}
}
});
}
}
You need to override onPause and onResume. In onPause, you need to release the Camera. In onResume, you need to re-request it. Camera doesn't like it if you try to hold it when you aren't the active activity.
public void onPause(){
super.onPause();
if(camera != null){
camera.release();
camera = null;
}
}
public void onResume(){
super.onResume();
//Need to release if we already have one, or we won't get the camera
if(camera != null){
camera.release();
camera = null;
}
try {
camera = Camera.open();
}
catch (Exception e){
}
}

Android CameraPreview not working on return to activity

I am working on an application using the camera. I want my application to have a custom menu that launches when the user presses the menu button.
Right now the application launches properly and the CameraPreview works fine. The menu opens correctly when the menu button is pressed. It even returns to the first activity from the menu when you press the button like it is supposed to.
The problem is that the CameraPreview no longer appears in the first activity when returning from the menu activity. What do I need to do so the CameraPreview will appear properly when returning to the first activity from the menu?
public class CameraMenuTest extends Activity implements Callback {
private Camera camera;
private MediaRecorder mediaRecorder;
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
SurfaceView cameraPreview = (SurfaceView)findViewById(R.id.camera_preview);
SurfaceHolder holder = cameraPreview.getHolder();
holder.addCallback(this);
holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
}
public boolean onKeyDown(int keyCode, KeyEvent event) {
if ( keyCode == KeyEvent.KEYCODE_MENU ) {
Intent mIntent = new Intent(CameraMenuTest.this, CameraMenuTestMenu.class);
startActivityForResult(mIntent, 0);
return true;
}
return super.onKeyDown(keyCode, event);
}
public void onActivityResult(int requestCode, int resultCode, Intent data) {
}
#Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
mediaRecorder = new MediaRecorder();
mediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
mediaRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);
mediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.DEFAULT);
mediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.DEFAULT);
mediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.DEFAULT);
mediaRecorder.setOutputFile("/sdcard/myoutputfile.mp4");
try {
mediaRecorder.prepare();
} catch (IllegalStateException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
#Override
public void surfaceCreated(SurfaceHolder holder) {
if (mediaRecorder == null) {
try {
camera = Camera.open();
camera.setPreviewDisplay(holder);
camera.startPreview();
}
catch (IOException e){
Log.d("CAMERA", e.getMessage());
}
}
}
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
camera.stopPreview();
camera.release();
}
}
public class CameraMenuTestMenu extends Activity {
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.menu);
Button btn = (Button)findViewById(R.id.btn);
btn.setOnTouchListener(new OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
finish();
return false;
}
});
}
}
I am assuming I need to do something in the onActivityResult() of the first activity.
I have tried:
public void onActivityResult(int requestCode, int resultCode, Intent data) {
SurfaceView cameraPreview = (SurfaceView)findViewById(R.id.camera_preview);
SurfaceHolder holder = cameraPreview.getHolder();
holder.addCallback(this);
holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
}
and also:
public void onActivityResult(int requestCode, int resultCode, Intent data) {
camera = Camera.open();
camera.setPreviewDisplay(holder);
camera.startPreview();
}
Thank you for your help.
Move this part of your code from onCreate() to onResume():
SurfaceView cameraPreview = (SurfaceView)findViewById(R.id.camera_preview);
SurfaceHolder holder = cameraPreview.getHolder();
holder.addCallback(this);
holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
Also modify the above block to this:
SurfaceView surfaceView = (SurfaceView) findViewById(R.id.camera_preview);
SurfaceHolder holder = surfaceView.getHolder();
if ( mediaRecorder != null) {
// The activity was paused but not stopped, so the surface still exists. Therefore
// surfaceCreated() won't be called, so init the camera here.
initCamera(holder);
} else {
// Install the callback and wait for surfaceCreated() to init the camera.
holder.addCallback(this);
holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
}
the method initCamera(holder) should do the same things as the overridden method surfaceCreated().
Don't forget to release the camera in onPause():
#Override
protected void onPause() {
super.onPause();
if (camera != null) {
camera.stopPreview();
camera.release();
}
}
Good Luck!
Ok, sorry I missed the hasSurface flag - it's just set and cleared when surfaceCreated() and surfaceDestroyed() are called.
You have two options:
Option one
Since you are using an object, mediaRecorder, you can just check whether this is null to do the same thing, like this:
mediaRecorder != null. I've added it to the if statement above.
NOTE - if you are going to do this, you need to set mediaRecorder to null in surfaceDestroyed() so that the above if statement works.
Option two
If you wanted to use the boolean (member variable) (hasSurface), set it to
false in onCreate(),
false in surfaceDestroyed()
true in surfaceCreated() eg
if (!hasSurface) {
hasSurface = true;
initCamera(holder);
}
Let me know if this works for you.
Most likely reason is that when you return to your preview activity and surfaceCreated is called again, mediaRecorder is not null, thus the code that is supposed to start the preview is not executed.
That's probably because the SurfaceView breaks due to onPause/onResume being called. You need to reinitialize the camera preview during these times.
From the SDK docs:
Important: Call release() to release the camera for use by other applications. Applications should release the camera immediately in onPause() (and re-open() it in onResume()).

Categories

Resources