I am practicing building Android apps and figured starting with a flashlight would be a great beginner step. After having my code blow up several times, I have the app stable where it no longer force closes.
However, the LED camera flash doesn't turn on like I was hoping it should.
Any insight as to what I'm doing wrong would be most helpful.
public class PMATorch extends Activity {
private Camera camera;
private Button button;
private Camera.Parameters param;
private boolean torchStat = false;
public Camera getCameraInstance() {
Camera c = null;
try {
c = camera.open();
} catch (Exception e) {
}
return c;
}
private void torchOn(){
if (camera != null){
Parameters param = camera.getParameters();
param.setFlashMode(Parameters.FLASH_MODE_TORCH);
camera.setParameters(param);
camera.startPreview();
torchStat = true;
}
}
private void torchOff(){
if (camera != null){
Parameters param = camera.getParameters();
param.setFlashMode(Parameters.FLASH_MODE_OFF);
camera.setParameters(param);
camera.stopPreview();
torchStat = false;
}
}
#Override
protected void onDestroy() {
if (camera != null) {
camera.release();
camera = null;
}
super.onDestroy();
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_pmatorch);
camera = getCameraInstance();
button = (Button) findViewById(R.id.torchOnOff);
button.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
if (torchStat = false) {
torchOn();
} else {
torchOff();
}
}
});
}
}
Edit: I have the permissions and features set in AndroidManifest.xml.
Edit 2: Updated the code to what I just tried running.
private Camera camera;
is never assigned anything. So if (camera != null){ in torchOn won't do anything. You probably wanted to do something like:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
camera = getCameraInstance(); // <<
public Camera getCameraInstance() {
Camera c = null;
try {
c = camera.open();
} catch (Exception e) {
}
return c;
}
has furthermore 2 minor problems:
* catch (Exception e) {} hides anything that might go wrong here. I would add at least a logging statement like Log.e("PMATorch", "getCameraInstance", e).
* Cosmetical issue: camera.open() screams NullPointerException at first glance. Change to Camera.open() - the method is static and belongs to the class.
E.g. (IMO nicer to read if you get rid of the local variable so I removed that as well)
public Camera getCameraInstance() {
try {
return Camera.open();
} catch (Exception e) {
Log.e("PMATorch", "getCameraInstance", e);
return null;
}
}
To further help with debugging such a problem. Add Log to the place that actually causes the action that doesn't seem to work.
private void torchOn(){
if (camera != null){
Log.d("PMATorch", "now actually turning on");
...
You will find that In many cases code you think is not working is actually not executed. When that happen, trace back the path that leads there, either with more log or by using the debugger and stepping though the code.
Instead of using Parameters.FLASH_MODE_ON, try using Parameters.FLASH_MODE_TORCH on your torchOn() method.
According to the documentation on Camera Parameters
Parameters.FLASH_MODE_ON: Flash will always be fired during snapshot.
Parameters.FLASH_MODE_TORCH: Constant emission of light during preview, auto-focus and snapshot.
In my understanding using Parameters.FLASH_MODE_ON will only turn on the light once and instantly or only if a picture is being taken. Parameters.FLASH_MODE_TORCH will constantly emit light so this option fits your requirement of having a light turned on when a button is pressed.
A nice tutorial on creating a flashlight application can be found here.
Related
Problem background
I am developing a VR Project on Unreal Engine 4, and the project requires the usage of Android's native camera. Since there are no built-in functions in UE4 to iteract with Android's native methods, I customized this plugin under my need.
The original plugin uses the JNI interface to iteract with C++ code. It calls camera.open() and camera.startPreview() on UE4's EventBeginPlay, and calls camera.stopPreview() and camera.Release() on UE4's EventEndPlay. Since it is a known issue that EventEndPlay never fires up on Android platform, I decided to manipulate the camera in onResume() and onPause() methods. Here is the code:
<gameActivityClassAdditions>
<insert>
/* Unrelevant code goes here */
...
...
/* End of unrelevant code */
public void AndroidThunkJava_startCamera()
{
surfaceTexture = new SurfaceTexture(10);
surfaceTexture.setDefaultBufferSize(preferredWidth, preferredHeight);
if (camera == null){
try {
camera = Camera.open();
} catch (RuntimeException exc) {
return;
}
}
try {
camera.setPreviewTexture(surfaceTexture);
} catch (IOException t) {
return;
}
Parameters cameraParam = camera.getParameters();
cameraParam.setPreviewFormat(ImageFormat.NV21);
cameraParam.setPreviewSize(preferredWidth, preferredHeight);
cameraParam.setPreviewFpsRange(preferredFPS, preferredFPS);
cameraParam.setFocusMode(Camera.Parameters.FOCUS_MODE_MACRO);
if (cameraParam.isVideoStabilizationSupported()) {
cameraParam.setVideoStabilization(false);
}
if (cameraParam.isAutoWhiteBalanceLockSupported()) {
cameraParam.setAutoWhiteBalanceLock(false);
}
camera.setParameters(cameraParam);
camera.setPreviewCallback(new PreviewCallback() {
#Override
public void onPreviewFrame(byte[] data, Camera camera) {
int Height = camera.getParameters().getPreviewSize().height;
int Width = camera.getParameters().getPreviewSize().width;
// calling C++ function via JNI interface
processFrameData(Width, Height, data);
}
});
camera.startPreview();
}
public void AndroidThunkJava_stopCamera()
{
if (camera != null)
{
camera.stopPreview();
camera.release();
camera = null;
}
}
</insert>
</gameActivityClassAdditions>
<gameActivityOnPauseAdditions>
<insert>
AndroidThunkJava_stopCamera();
</insert>
</gameActivityOnPauseAdditions>
<gameActivityOnResumeAdditions>
<insert>
AndroidThunkJava_startCamera();
</insert>
</gameActivityOnResumeAdditions>
The problem
The camera works fine every second time. That means:
I open the app, camera is working. I pushed the home button (which triggers onPause() method), then switch back to the app (triggers onResume() method). Pushed the home button again, and then switched back - camera works. And so on, the camera works every second time.
Anybody have any idea about this issue? Is that connected to the fact that android.hardware.Camera is deprecated? I'm using API version 19, so it is not possible to use newer android.hardware.camera2.
Here is my onStop and onResume methods. I'm not using onPause. And it works perfectly:
#Override
protected void onResume() {
super.onResume();
if (mCamera == null) {
restartPreview();
}
}
#Override
public void onStop() {
// stop the preview
if (mCamera != null) {
stopCameraPreview();
mCamera.release();
mCamera = null;
}
super.onStop();
}
private void restartPreview() {
if (mCamera != null) {
stopCameraPreview();
mCamera.release();
mCamera = null;
}
getCamera(mCameraID);
startCameraPreview();
}
private void startCameraPreview() {
try {
mCamera.setPreviewDisplay(mSurfaceHolder);
mCamera.startPreview();
setSafeToTakePhoto(true);
setCameraFocusReady(true);
} catch (IOException e) {
Log.d("st", "Can't start camera preview due to IOException " + e);
e.printStackTrace();
}
}
private void stopCameraPreview() {
setSafeToTakePhoto(false);
setCameraFocusReady(false);
// Nulls out callbacks, stops face detection
mCamera.stopPreview();
mPreviewView.setCamera(null);
}
maybe some implementations not equals yours but i think it is help you.
In a previous way, flashlight feature could be used by using Camera class. But now that the entire Camera and Camera-related classes in android.hardware packages are deprecated, I should alternatively use some other classes in the android.hardware.camera2 package.
Traditionally, I coded the flashlight part like this.
// getting camera parameters
private void getCamera() {
if (camera == null) {
try {
camera = Camera.open();
params = camera.getParameters();
} catch (RuntimeException e) {
Log.e("Camera Error. Failed to Open. Error: ", e.getMessage());
}
}
}
/*
* Turning On flash
*/
private void turnOnFlash() {
if (!isFlashOn) {
if (camera == null || params == null) {
return;
}
// play sound
playSound();
params = camera.getParameters();
params.setFlashMode(Parameters.FLASH_MODE_TORCH);
camera.setParameters(params);
camera.startPreview();
isFlashOn = true;
// changing button/switch image
toggleButtonImage();
}
}
But now with the new API I'm getting so confused how to use the new one. Can anybody explain?
for flashlight I advise using the Camera2 API only from Android 6 (api 23), my function for toggling the flashlight looks like
#TargetApi(Build.VERSION_CODES.M)
public void toggleMarshmallowFlashlight(boolean enable) {
try {
final CameraManager manager = (CameraManager) mContext.getSystemService(Context.CAMERA_SERVICE);
final String[] list = manager.getCameraIdList();
manager.setTorchMode(list[0], enable);
} catch (CameraAccessException e) {
}
}
i stuck here with a Problem. Trying to build a torch app. Works fine, but when i switch fragment or go to homescreen and come back the flash light wont work. Error is failed to connect to camera service.
I think the Problem is, that I create a new Camera instance then, and the new cant connect to the camera anymore. But how should i solve it?
public class FlashCameraManager {
private boolean isFlashOn;
private Camera camera;
public Camera.Parameters params;
// getting camera parameters
public void getCamera() {
if (camera == null) {
try {
camera = Camera.open();
params = camera.getParameters();
} catch (RuntimeException e) {
camera = null;
Log.e("Camera Error. Failed to Open. Error: ", e.getMessage());
}
} else {
camera.release();
camera = null;
}
}
public void FlashOnOff()
{
//Flash Aktivieren oder deaktivieren
if (isFlashOn)
{
//Turn Flash off
if (camera == null || params == null) {
return;
}
params = camera.getParameters();
params.setFlashMode(Camera.Parameters.FLASH_MODE_OFF);
camera.setParameters(params);
camera.stopPreview();
isFlashOn = false;
Log.d("FlashCameraManager", "Turning Flash off");
}
else
{
// Turn Flash on
if (camera == null || params == null) {
return;
}
params = camera.getParameters();
params.setFlashMode(Camera.Parameters.FLASH_MODE_TORCH);
camera.setParameters(params);
camera.startPreview();
isFlashOn = true;
Log.d("FlashCameraManager", "Turning Flash on");
}
}
public boolean isFlashActive()
{
//Prüfen ob Flash an oder aus ist
return isFlashOn;
}}
This is from the MainActivity
final ImageButton flash = (ImageButton) rootView.findViewById(R.id.none_flash);
if(camera == null) {
camera = new FlashCameraManager();
}
camera.getCamera();
flash.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
//Content
if (camera.isFlashActive())
{
//Turn Flash off
camera.FlashOnOff();
Log.d("NoneFragment", "Turning Flash off");
flash.setActivated(false);
}
else
{
//Turn Flash on
camera.FlashOnOff();
Log.d("NoneFragment", "Turning Flash on");
flash.setActivated(true);
}
}} );
After you are done with the camera (i.e. before exiting the application or launching another activity) make sure that you release the camera resources by calling the method release(), which, per the API Guide, "Disconnects and releases the Camera object resources". The API guide also provides some valueable insight into properly utilizing the class and performing simple operations, such as tasking a picture. The API Guide may be found here:
http://developer.android.com/reference/android/hardware/Camera.html
You might also want to consider taking a glance at the new camera API (android.hardware.camera2), as the current API that you are using is deprecated as of API level 21. The guide for the new API is found here:
http://developer.android.com/reference/android/hardware/camera2/package-summary.html
I want to detect the numbers of faces in the front camera frame. I can detect the face once I get the image using this :http://www.developer.com/ws/android/programming/face-detection-with-android-apis.html.
But I don't know how to capture an image using the front camera every 30 seconds without an user interaction.Can someone please help me?
Following code will capture photo from your camera after every 5 secs.
if (TIMER_STARTED) {
multishotTimer.cancel();
multishotTimer.purge();
TIMER_STARTED = false;
} else {
multishotTimer = new Timer();
multishotTimer.schedule(new TimerTask() {
#Override
public void run() {
TIMER_STARTED = true;
Camera camera = surfaceView.getCamera();
camera.takePicture(null, null,
new HandlePictureStorage());
}
}, 1000, 5000L);
}
Here, TIMER_STARTED is boolean which indicate whether timer is running or not.
Following is code for HandlePictureStorage
private class HandlePictureStorage implements PictureCallback {
#Override
public void onPictureTaken(byte[] picture, final Camera camera) {
//do something when picture is captured...
}
}
You can create manually a SurfaceView and preview camera on it as follows:
//First get a reference to the SurfaceView displaying the camera preview
cameraSurface = (SurfaceView) findViewById(R.id.cameraSurface);
cameraSurfaceHolder = cameraSurface.getHolder();
cameraSurfaceHolder.addCallback(cameraSurfaceHolderCallbacks);
.
.
.
private SurfaceHolder.Callback cameraSurfaceHolderCallbacks = new SurfaceHolder.Callback() {
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
if(mCamera == null)return;
mCamera.stopPreview();
mCamera.release();
mCamera = null;
}
#Override
public void surfaceCreated(SurfaceHolder holder) {
try {
mCamera = Camera.open();
mCamera.setPreviewDisplay(holder);
} catch (Exception exception) {
if(mCamera == null)return;
mCamera.release();
mCamera = null;
}
}
#Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
Parameters cameraParameters = mCamera.getParameters();
cameraParameters.setPreviewSize(320, 240);
cameraParameters.setPictureSize(320, 240);
int avrgExposure = (cameraParameters.getMinExposureCompensation() + cameraParameters.getMaxExposureCompensation())/2;
cameraParameters.setExposureCompensation(avrgExposure);
mCamera.setParameters(cameraParameters);
mCamera.startPreview();
mCamera.takePicture(null, null, mPictureCallback);
}
};
Do not forget to add the proper camera permission in your manifest:
<uses-permission android:name="android.permission.CAMERA"/>
And finally if you are using an Android 4.0 device or above you can use the method:
mCamera.startFaceDetection();
.
.
.
private FaceDetectionListener faceDetectionListener = new FaceDetectionListener() {
#Override
public void onFaceDetection(Face[] faces, Camera camera) {
//Faces have been detected...
}
};
.
.
.
mCamera.setFaceDetectionListener(faceDetectionListener);
You can go to this post which explains everything related to that specific functionality and even provides a functional Android Source Code that you can download to do it yourself.
Regards!
You should be scheduling an RTC_WAKEUP Alarm using the AlarmManager, at every 30 seconds, set a PendingIntent to the Alarm to launch a Service and inside the Service you should access the Camera to capture the image.
You should probably look at this post : Open/Run camera from a background Service.
I have built an application which takes photos when you touch the preview.
I can take many photos, but sometimes when i touch the preview to take a photo, there is no shutter sound and the whole application freezes. Moreover, after that, if i try to launch launch the built-in camera application, i get a message that the camera can't be used.
I don't know the reason for that behavior, it happens randomly and when it happens i must restart the device (Samsung Galaxy S) to be able to use the camera again.
In the DDM, after the crash i can see the following line: keyDispatchingTimedOut
Here is the relevant code:
CameraActivity Class:
public class CameraActivity extends Activity {
private static final String TAG = "CameraDemo";
Preview preview;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
preview = new Preview(this);
((FrameLayout) findViewById(R.id.preview)).addView(preview);
((FrameLayout) findViewById(R.id.preview)).setOnTouchListener(preview);
Log.d(TAG, "Camera Activity Created.");
}
}
Preview Class:
class Preview extends SurfaceView implements SurfaceHolder.Callback, OnTouchListener {
private static final String TAG = "Preview";
SurfaceHolder mHolder;
public Camera camera;
Context ctx;
boolean previewing = false;
Preview(Context context) {
super(context);
ctx = context;
// Install a SurfaceHolder.Callback so we get notified when the
// underlying surface is created and destroyed.
mHolder = getHolder();
mHolder.addCallback(this);
mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
}
// Called once the holder is ready
public void surfaceCreated(SurfaceHolder holder) {
// The Surface has been created, acquire the camera and tell it where
// to draw.
camera = Camera.open();
}
// Called when the holder is destroyed
public void surfaceDestroyed(SurfaceHolder holder) {
if (camera != null) {
camera.setPreviewCallback(null);
camera.stopPreview();
camera.release();
camera = null;
}
previewing = false;
}
// Called when holder has changed
public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
if(previewing){
camera.stopPreview();
previewing = false;
}
if (camera != null){
try {
camera.setDisplayOrientation(90);
camera.setPreviewDisplay(holder);
camera.setPreviewCallback(new PreviewCallback() {
// Called for each frame previewed
public void onPreviewFrame(byte[] data, Camera camera) {
Log.d(TAG, "onPreviewFrame called at: " + System.currentTimeMillis());
Preview.this.invalidate();
}
});
camera.startPreview();
previewing = true;
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
public boolean onTouch(View v, MotionEvent event) {
camera.takePicture(shutterCallback, rawCallback, jpegCallback);
return false;
}
// Called when shutter is opened
ShutterCallback shutterCallback = new ShutterCallback() {
public void onShutter() {
Log.d(TAG, "onShutter'd");
}
};
// Handles data for raw picture
PictureCallback rawCallback = new PictureCallback() {
public void onPictureTaken(byte[] data, Camera camera) {
Log.d(TAG, "onPictureTaken - raw");
}
};
// Handles data for jpeg picture
PictureCallback jpegCallback = new PictureCallback() {
public void onPictureTaken(byte[] data, Camera camera) {
FileOutputStream outStream = null;
try {
// Write to SD Card
outStream = new FileOutputStream(String.format("/sdcard/TVguide/Detection/detected.jpg", System.currentTimeMillis())); // <9>
outStream.write(data);
outStream.close();
Log.d(TAG, "onPictureTaken - wrote bytes: " + data.length);
} catch (FileNotFoundException e) { // <10>
//Toast.makeText(ctx, "Exception #2", Toast.LENGTH_LONG).show();
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {}
Log.d(TAG, "onPictureTaken - jpeg");
Toast.makeText(ctx, "SAVED", Toast.LENGTH_SHORT).show();
camera.startPreview();
}
};
}
Please help, i am trying a few days to understand where the problem is with no success
Eyal
I just run into this issue when testing my application on a Samsung Galaxy SII. You just have to remove the preview callback before taking the picture:
mCamera.setPreviewCallback(null);
mCamera.takePicture(null, null, mPictureCallback);
I don't know what causes that bug, it would really help if you posted the loggcat output from the time from when this error happened.
But, I can make some gusesses. It looks like camera is locked (built-in camera does not work). If your app force closed, the camera lock might be caused by erroneus error handling in Samsung camera HAL. Especially in older phones, like Galaxy S, they did not do the best job at handling wrong, or not standard API calls.
Here are some suggestions of what may have caused this behaviour:
You should add a guard for picture taking. Right now, if you touch the screen and take picture, you can touch the screen again, before the picture finishes taking. So, camera.takePicture() will be called twice. The second one will fail. This is my best guess.
Add some boolean isTakingPicture = false variable and then:
public boolean onTouch(View v, MotionEvent event) {
if (!isTakingPicture) {
camera.takePicture(shutterCallback, rawCallback, jpegCallback);
isTakingPicture = true;
}
return false;
}
...
public void onPictureTaken(byte[] data, Camera camera) {
isTakingPicture = false;
...
What do you use previewCallback for? I doesn't do anything useful here. Preview callbacks sometimes can sometimes cause some pain, although your code looks fine to me. You can alwys try to remove it and check if that helps.
I experienced a similar issue reported here. On LG p705 and Samsung Galaxy Trend, after taking a photo, the preview is frozen and camera was no longer usable until the phone was restarted. On Galaxy S3 however, the preview continues to display properly even after multiple photo snaps.
While debugging, I noticed that the relevant listener class was receiving more than one call when the camera button was pressed to take picture. I am unsure why it is being invoked twice, even though the button was only click once. In any case, thanks to Tomasz's suggestion to use of a boolean variable, the second call skips taking photo while the first attempt is in progress. And thanks Eyal for the question too. :)