Flashlight control in Marshmallow - android

I have a problem regarding the camera in the most recent Marshmallow build, more specifically the flashlight.
On any pre-Marshmallow version all I need to do to turn the flash on/off was the following:
private void turnFlashOn(final Camera camera, int flashLightDurationMs) {
if (!isFlashOn()) {
final List<String> supportedFlashModes = camera.getParameters().getSupportedFlashModes();
if (supportedFlashModes != null && supportedFlashModes.contains(Camera.Parameters.FLASH_MODE_TORCH)) {
mParams.setFlashMode(Camera.Parameters.FLASH_MODE_TORCH);
camera.setParameters(mParams);
}
}
}
and
private void turnFlashOff(Camera camera) {
if (camera != null) {
final List<String> supportedFlashModes = camera.getParameters().getSupportedFlashModes();
if (supportedFlashModes != null && supportedFlashModes.contains(Camera.Parameters.FLASH_MODE_OFF)) {
mParams.setFlashMode(Camera.Parameters.FLASH_MODE_OFF);
camera.setParameters(mParams);
}
}
}
Unfortunately, Marshmallow devices began to crash in the wild. Somehow camera.getParameters() and camera.setParameters() began to fail with messages such as:
RuntimeException: getParameters failed (empty parameters)
RuntimeException: setParameters failed
I tried starting and stopping the preview before getting the parameters, which no longer throws errors. However the preview is not resumed when I call camera.startPreview().
I fear releasing the camera and reopening it is out of the question as this takes some seconds and would produce a bad experience.
Any suggestions on how to turn the flashlight on/off in Marshmallow reliably?

Google has introduced torchmode in OS 6 (Android M).
if your purpose is only to turn on/off the flash, below code can help you with that:
private static void handleActionTurnOnFlashLight(Context context){
try{
CameraManager manager = (CameraManager) context.getSystemService(Context.CAMERA_SERVICE);
String[] list = manager.getCameraIdList();
manager.setTorchMode(list[0], true);
}
catch (CameraAccessException cae){
Log.e(TAG, cae.getMessage());
cae.printStackTrace();
}
}
private static void handleActionTurnOffFlashLight(Context context){
try{
CameraManager manager = (CameraManager) context.getSystemService(Context.CAMERA_SERVICE);
manager.setTorchMode(manager.getCameraIdList()[0], false);
}
catch (CameraAccessException cae){
Log.e(TAG, cae.getMessage());
cae.printStackTrace();
}
}
All you have to do is: Get cameraid's list out of which camera ID zero(0) is your primary camera for which you want to turn flash on/off. Simply pass the cameraID to setTochMode API with boolean value for turning it on or off.
Do note that this piece of code will work only with OS 6, so you need to check for device OS and based upon that you need to select which API's to call for pre-marshmallow devices.
Kindly mark this as solution if it solves your problem.

As Saurabh7474 has responded, to check the version of Android and use setTorchMode API it's very correct.
Although you can also use params.setFlashMode (...) in marshmallow using
mCamera.setPreviewTexture (new SurfaceTexture (100))
after Camera.open (...) and before calling mCamera.startPreview();
try {
Log.i(TAG, "getCamera");
int requestedCameraId = getIdForRequestedCamera(mFacing);
if (requestedCameraId == -1) {
throw new RuntimeException("Could not find requested camera.");
}
mCamera = Camera.open(requestedCameraId);
mCamera.setPreviewTexture(new SurfaceTexture(DUMMY_TEXTURE_NAME));
params = mCamera.getParameters();
} catch (RuntimeException e) {
Log.e("Failed to Open. Error:", e.getMessage());
} catch (IOException e) {
Log.e("Failed to Open. can't setPreviewTexture:", e.getMessage());
}
then when you want, you can use
mParams.setFlashMode(Camera.Parameters.FLASH_MODE_TORCH);
camera.setParameters(mParams);
My answer is based on CameraSource examples of Vision API that uses params.setFlashMode (...) and works in Api 23 and above.
If you decide to inspect CameraSource, the key method that has solved the same problem is "start ()", in the line 312 ...
https://github.com/googlesamples/android-vision/blob/master/visionSamples/barcode-reader/app/src/main/java/com/google/android/gms/samples/vision/barcodereader/ui/camera/CameraSource.java
The reason you can find here
https://stackoverflow.com/a/33333046/4114846

Update your app to check for permissions at runtime. You have to have android.permission.CAMERA granted. Including it in the manifest of your app is not going to grant it to you on Marshmallow. You'll need to detect whether or not it has been granted and request it.

Building off of Saurabh7474's answer, you can toggle Marshmallow's torchMode by registering a torchCallback:
final CameraManager mCameraManager = (CameraManager) getSystemService(Context.CAMERA_SERVICE);
CameraManager.TorchCallback torchCallback = new CameraManager.TorchCallback() {
#Override
public void onTorchModeUnavailable(String cameraId) {
super.onTorchModeUnavailable(cameraId);
}
#Override
public void onTorchModeChanged(String cameraId, boolean enabled) {
super.onTorchModeChanged(cameraId, enabled);
boolean currentTorchState = enabled;
try {
mCameraManager.setTorchMode(cameraId, !currentTorchState);
} catch (CameraAccessException e){}
}
};
mCameraManager.registerTorchCallback(torchCallback, null);//fires onTorchModeChanged upon register
mCameraManager.unregisterTorchCallback(torchCallback);

Related

ImageReader.OnImageAvailableListener() not being called when taking a picture

I have a Camera App developed for Android 26 SDK. I have been using it happily with a Motorola G5 and G6 but when I move to a Motorola G7 the app crashes when I press the button to take a picture in my app.
The G7 is running Android 9. I have another Android 9 phone a Samsung S10 plus. The S10 plus does not crash when I press the button for taking a picture.
While debugging I noticed that the G7 doesn't call ImageReader.OnImageAvailableListener while the S10 does. Looking at the code this is where the image is saved for use later on in CameraCaptureSession.CaptureCallback. The callback expects bytes to be populated and crashes when it isn't (I haven't included the stack trace because it's not a little unhelpful but I can if you think you would like to see it).
I can get the G7 to save the image if I run it slowly through debug on 'some' occasions.
So I have a button that calls the function onImageCaptureClick() inside it does a bunch of stuff but one of the things it does is create an ImageReader.OnImageAvailableListener. The OnImageAvailableListener saves the image and populates a variable bytes from the image buffer. This onImageAvailableListener is attached to my reader by using reader.setOnImageAvailableListener(readerListener, null), and this listener is never used. When I get in to the CaptureCallBack the class variable bytes is not populated and the app crashes.
Do you have any idea where I would look to solve this?
protected void onImageCaptureClick() {
if (null == mCameraDevice) {
logger.debug("null == mCameraDevice");
Log.e(TAG, "cameraDevice is null");
return;
}
CameraManager manager = (CameraManager) getSystemService(Context.CAMERA_SERVICE);
try {
CameraCharacteristics characteristics = manager.getCameraCharacteristics(mCameraDevice.getId());
Size[] jpegSizes = null;
if (characteristics != null) {
jpegSizes = characteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP).getOutputSizes(ImageFormat.JPEG);
}
int width = 640;
int height = 480;
if (jpegSizes != null && 0 < jpegSizes.length) {
width = jpegSizes[0].getWidth();
height = jpegSizes[0].getHeight();
}
ImageReader reader = ImageReader.newInstance(width, height, ImageFormat.JPEG, 1);
List < Surface > outputSurfaces = new ArrayList < > (2);
outputSurfaces.add(reader.getSurface());
outputSurfaces.add(new Surface(mTextureView.getSurfaceTexture()));
final CaptureRequest.Builder captureBuilder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE);
captureBuilder.addTarget(reader.getSurface());
if (mFlashMode == FLASH_MODE_OFF) {
captureBuilder.set(CaptureRequest.FLASH_MODE, CaptureRequest.FLASH_MODE_OFF);
logger.debug("FLASH OFF");
}
if (mFlashMode == CONTROL_AE_MODE_ON) {
captureBuilder.set(CaptureRequest.CONTROL_AE_MODE,
CaptureRequest.CONTROL_AE_MODE_ON);
captureBuilder.set(CaptureRequest.FLASH_MODE,
CaptureRequest.FLASH_MODE_TORCH);
logger.debug("FLASH ON");
}
if (mFlashMode == CONTROL_AE_MODE_ON_AUTO_FLASH) {
captureBuilder.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON_AUTO_FLASH);
captureBuilder.set(CaptureRequest.FLASH_MODE,
CaptureRequest.FLASH_MODE_OFF);
logger.debug("FLASH AUTO");
}
captureBuilder.set(CaptureRequest.SCALER_CROP_REGION, zoom);
int rotation = getWindowManager().getDefaultDisplay().getRotation();
captureBuilder.set(CaptureRequest.JPEG_ORIENTATION, ORIENTATIONS.get(rotation));
final File file = new File(_pictureUri.getPath());
logger.debug("OnImageCaptureClick: _pictureUri is: " + _pictureUri.getPath());
// ************************************
// this listener is not used on the G7,
// and so the image isn't saved.
// ************************************
ImageReader.OnImageAvailableListener readerListener = new ImageReader.OnImageAvailableListener() {
#Override
public void onImageAvailable(ImageReader reader) {
Image image = null;
try {
image = reader.acquireLatestImage();
ByteBuffer buffer = image.getPlanes()[0].getBuffer();
bytes = new byte[buffer.capacity()];
buffer.get(bytes);
logger.debug("onImageCaptureClick, the filesize to save is: " + bytes.toString());
save();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (image != null) {
image.close();
}
}
}
private void save() throws IOException {
OutputStream output = null;
try {
output = new FileOutputStream(file);
output.write(bytes);
} finally {
if (null != output) {
output.close();
}
}
}
};
// ********************************************************
// the reader sets the listener here but it is never called
// and when I get in to the CaptureCallback the BitmapUtils
// expects bytes to be populated and crashes the app
// ********************************************************
reader.setOnImageAvailableListener(readerListener, null);
final CameraCaptureSession.CaptureCallback captureListener = new CameraCaptureSession.CaptureCallback() {
#Override
public void onCaptureCompleted(#NonNull CameraCaptureSession session, #NonNull CaptureRequest request, #NonNull TotalCaptureResult result) {
super.onCaptureCompleted(session, request, result);
try {
BitmapUtils.addTimeStampAndRotate(_pictureUri, bytes);
Intent intent = new Intent(CameraActivity.this, CameraReviewPhotoActivity.class);
intent.putExtra(MediaStore.EXTRA_OUTPUT, _pictureUri);
startActivityForResult(intent, CameraActivity.kRequest_Code_Approve_Image);
} catch (IOException e) {
e.printStackTrace();
} catch (ImageReadException e) {
e.printStackTrace();
} catch (ImageWriteException e) {
e.printStackTrace();
}
}
};
mCameraDevice.createCaptureSession(outputSurfaces, new CameraCaptureSession.StateCallback() {
#Override
public void onConfigured(CameraCaptureSession session) {
try {
session.capture(captureBuilder.build(), captureListener, null);
} catch (CameraAccessException e) {
e.printStackTrace();
}
}
#Override
public void onConfigureFailed(CameraCaptureSession session) {
Log.w(TAG, "Failed to configure camera");
}
}, null);
} catch (CameraAccessException e) {
e.printStackTrace();
} finally {
takePictureButton.setEnabled(false);
mTextureView.setEnabled(false);
}
The API makes no guarantee about the order of onCaptureCompleted and OnImageAvailableListener. They may arrive in arbitrary order, depending on the device, capture settings, the load on the device, or even the particular OS build you have.
Please don't make any assumptions about it.
Instead, if you need both callbacks to fire before you process something, then wait for both to happen before you move forward. For example, check if the other callback has fired in each callback, and if so, call the method to do the processing.
I think I have found the solution to this.
I have the following phones:
Samsung S10 Plus
Motorola G7
Motorola G6
My app works on the S10 and the G6.
The S10 and G6 both call the OnImageAvailableListener function before the onCaptureCompleted callback. The G7 however calls them both the other way around onCaptureCompleted then OnImageAvailableListener.
According to https://proandroiddev.com/understanding-camera2-api-from-callbacks-part-1-5d348de65950 the correct way is onCaptureCompleted then OnImageAvailableListener.
In my code I am assuming that OnImageAvailableListener has saved the image and then OnCaptureCompleted tries to manipulate it, which causes the crash.
Looking at the INFO_SUPPORTED_HARDWARE_LEVEL of each device I have the following levels of support from none level 0 to uber level 3.
Samsung S10 Plus reports device level support level 1
Motorola G7 reports device level support level 3
Motorola G6 reports device level support level 2
My assumption at this point is that the events fire in a different order when you support the android-camera2 API at Level 3 compared to other levels.
Hope this helps

Size not in valid set when recording without preview

I am trying to record video using a Vivo X20 (7.1.1) and the camera2 api without using a preview and without recording sound (Strictly recording HD Video only).
I'm currently stuck because I cannot figure out how to successfully call MediaRecorder.setVideoSize() and record a video in HD. Currently when I run the app the log shows the error: Surface with size (w=1920, h=1080) and format 0x1 is not valid, size not in valid set: [1440x1080, 1280x960, 1280x720, 960x540, 800x480, 720x480, 768x432, 640x480, 384x288, 352x288, 320x240, 176x144]
The phone's stock camera app can record video up to 4K so I'm definitely missing something here. There are a total of two camera devices identified by CameraManager. When I use getOutPutFormats() from CameraCharacteristics it shows the same valid set of resolutions for both cameras and it is the same range as the above error message.
The below is the code I am using to initialize MediaRecorder and initiate a capture session:
public void StartRecordingVideo() {
Initialize();
recordingVideo = true;
cameraManager = (CameraManager) this.getSystemService(Context.CAMERA_SERVICE);
try {
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.CAMERA) == PackageManager.PERMISSION_GRANTED) {
String[] cameraIDs = cameraManager.getCameraIdList();
//LogAllCameraInfo();
if (cameraIDs != null)
{
for(int x = 0; x < cameraIDs.length; x++)
{
Log.d(LOG_ID, "ID: " + cameraIDs[x]);
}
}
cameraManager.openCamera(deviceCameraID, cameraStateCallback, handler);
Log.d(LOG_ID, "Successfully opened camera");
}
else
{
throw new IllegalAccessException();
}
}
catch (Exception e)
{
recordingVideo = false;
Log.e(LOG_ID, "Error during record video start: " + e.getMessage());
}
}
private void Initialize()
{
videoRecordThread = new HandlerThread("video_capture");
videoRecordThread.start();
handler = new Handler((videoRecordThread.getLooper()));
try
{
vidRecorder = new MediaRecorder();
vidRecorder.setVideoSource(MediaRecorder.VideoSource.SURFACE);
vidRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
vidRecorder.setVideoFrameRate(30);
vidRecorder.setCaptureRate(30);
vidRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.DEFAULT);
vidRecorder.setVideoEncodingBitRate(10000000);
vidRecorder.setVideoSize(1920, 1080);
String videoFilename = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS)+ File.separator + System.currentTimeMillis() + ".mp4";
vidRecorder.setOutputFile(videoFilename);
Log.d(LOG_ID, "Starting video: " + videoFilename);
vidRecorder.prepare();
}
catch (Exception e)
{
Log.e(LOG_ID, "Error during Initialize: " + e.getMessage());
}
}
And the onReady/onSurfacePrepared/Camera onOpened callbacks:
#Override
public void onReady(CameraCaptureSession session) {
Log.d(LOG_ID, "onReady: ");
super.onReady(session);
try {
CaptureRequest.Builder builder = deviceCamera.createCaptureRequest(CameraDevice.TEMPLATE_RECORD);
builder.addTarget(vidRecorder.getSurface());
CaptureRequest request = builder.build();
session.setRepeatingRequest(request, null, handler);
vidRecorder.start();
} catch (CameraAccessException e) {
Log.d(LOG_ID, "Error on Ready: " + e.getMessage());
}
}
#Override
public void onSurfacePrepared(CameraCaptureSession session, Surface surface) {
Log.d(LOG_ID, "onSurfacePrepared: ");
super.onSurfacePrepared(session, surface);
}
#Override
public void onOpened(CameraDevice camera) {
Log.d(LOG_ID, "onOpened: ");
deviceCamera = camera;
try {
camera.createCaptureSession(Arrays.asList(vidRecorder.getSurface()), recordSessionStateCallback, handler);
} catch (CameraAccessException e) {
Log.d(LOG_ID, "onOpened: " + e.getMessage());
}
}
I've tried messing with the order of calls and the output format/encoder with no luck. I am sure that I have all the required permissions. Thanks in advance for your time!
This device most likely supports camera2 at the LEGACY level; check what the output of INFO_SUPPORTED_HARDWARE_LEVEL is.
LEGACY devices are effectively running camera2 on top of the legacy android.hardware.Camera API (more complex than that, but roughly true); as a result, their capabilities via camera2 are restricted.
The maximum recording resolution is one significant problem; android.hardware.Camera records videos via a magic path that the LEGACY mapping layer cannot directly use (there's no Surface involved). As a result, camera2 LEGACY can only record at the maximum preview resolution supported by android.hardware.Camera, not at the maximum recording resolution.
Sounds like this device has no support for 1:1 1080p preview, which is pretty unusual for a device launched so recently.
You can verify if the set of supported preview sizes in the deprecated Camera API matches the list you get in your error; if it doesn't then there may be a OS bug in generating the list so it'd be good to know.
But in general, you can't request sizes that aren't enumerated in the CameraCharacteristics StreamConfiguraitonMap for the camera, no matter what the feature list on the side of the box says. Sometimes the OEM camera app has magic hooks to enable features that normal apps can't get to; often because the feature only works in some very very specific set of circumstances, which normal apps wouldn't know how to replicate.

Android Camera.open sometimes fails

I am using parts of the android vision barcode-reader sample to read QR-codes. Occasionally (like 2 in 500 Users) I'm getting a Firebase Crash report, which happens at Camera.open.
java.lang.RuntimeException:
at android.hardware.Camera.<init>(Camera.java:678)
at android.hardware.Camera.open(Camera.java:520)
at mobilevision.CameraSource.createCamera(CameraSource.java:0)
at <OR>.access$2200(CameraSource.java:0)
at mobilevision.CameraSource.release(CameraSource.java:0)
at <OR>.start(CameraSource.java:0)
at <OR>.getIdForRequestedCamera(CameraSource.java:0)
at <OR>.selectSizePair(CameraSource.java:0)
at <OR>.generateValidPreviewSizeList(CameraSource.java:0)
at <OR>.selectPreviewFpsRange(CameraSource.java:0)
at <OR>.setRotation(CameraSource.java:0)
at <OR>.createPreviewBuffer(CameraSource.java:0)
at <OR>.access$102(CameraSource.java:0)
at <OR>.access$202(CameraSource.java:0)
at <OR>.access$302(CameraSource.java:0)
at <OR>.access$502(CameraSource.java:0)
at <OR>.access$802(CameraSource.java:0)
at <OR>.access$1800(CameraSource.java:0)
at mobilevision.CameraSourcePreview.startIfReady(CameraSourcePreview.java:0)
at mobilevision.CameraSourcePreview.start(CameraSourcePreview.java:0)
at <OR>.start(CameraSourcePreview.java:0)
at <OR>.stop(CameraSourcePreview.java:0)
at <OR>.access$102(CameraSourcePreview.java:0)
at <OR>.access$200(CameraSourcePreview.java:0)
at mobilevision.CameraSourcePreview$SurfaceCallback.surfaceCreated(CameraSourcePreview.java:0)
at android.view.SurfaceView.updateWindow(SurfaceView.java:679)
at android.view.SurfaceView$3.onPreDraw(SurfaceView.java:206)
at android.view.ViewTreeObserver.dispatchOnPreDraw(ViewTreeObserver.java:944)
at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:2432)
at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1328)
at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:6730)
at android.view.Choreographer$CallbackRecord.run(Choreographer.java:894)
at android.view.Choreographer.doCallbacks(Choreographer.java:696)
at android.view.Choreographer.doFrame(Choreographer.java:631)
at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:880)
at android.os.Handler.handleCallback(Handler.java:815)
at android.os.Handler.dispatchMessage(Handler.java:104)
at android.os.Looper.loop(Looper.java:207)
at android.app.ActivityThread.main(ActivityThread.java:5765)
at java.lang.reflect.Method.invoke(Method.java:0)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:789)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:679)
Code part where exception is thrown:
int requestedCameraId = getIdForRequestedCamera(mFacing);
if (requestedCameraId == -1) {
throw new Exception("Could not find requested camera.");
}
Camera camera = Camera.open(requestedCameraId);
I'm asking for the camera permission similarly as it is implemented in the barcode-reader sample. Unfortunately I am not able to reproduce this exact exception.
But I was able to reproduce a similar exception when running the app in an emulator without camera (both cameras set to none). But since this exception happens in real devices, I'm wondering what might be the cause.
Phones in the crash report are e.g. Galaxy J1(2016) (j1x3g) with A5.1, Plume P6 Pro LTE (PGN528) with A6.0, 3600i (CP3600I) with A6.0.
Can anybody give me a hint on how to reproduce this exception or even better, does anybody know the reason why it is not possible to start a camera even though the permission is granted?
Thanks a lot!
It's my pleasure to answer your question.
There are corresponding checkPermission () methods, but these methods only determine whether the permissions have been registered in the manifest file. The user's actions are not accessible.
PackageManager packageManager = this.getPackageManager();
int permission = packageManager.checkPermission("android.permission.CAMERA", "your packageName");
if (PackageManager.PERMISSION_GRANTED == permission) {
// you can do something
} else {
// request permission
}
So how do we detect permissions in the system below 6.0?
The present method is the use of try{} catch){} way:
public boolean isCameraCanUse() {
boolean isCanUse = true;
Camera mCamera = null;
try {
mCamera = Camera.open();
Camera.Parameters mParameters = mCamera.getParameters(); //针对魅族手机
mCamera.setParameters(mParameters);
} catch (Exception e) {
isCanUse = false;
}
if (mCamera != null) {
try {
mCamera.release();
} catch (Exception e) {
e.printStackTrace();
return isCanUse;
}
}
return isCanUse;
}
I hope this helps.

Android CameraAccessException with older Apis generating lint error

I'm trying to create an Android app which supports both Camera and Camera2, and I have done that by using if statements which check the API level for appropriate sections of code. However, I'm having trouble coping with the CameraAccessException in that I'm getting a lint error, but I'm not sure how to get rid of it. If I surround the try/catch with an if statement which checks the API level, the lint error doesn't go away. Is there any other way of getting rid of the lint error? I'd rather not suppress inspections. Here is an example of what I'm talking about:
private String getFrontCamera2() {
if (Build.VERSION.SDK_INT >= 21) {
CameraManager cameraManager = (CameraManager) getSystemService(Context.CAMERA_SERVICE);
String[] cameraIdList;
try {
cameraIdList = cameraManager.getCameraIdList();
} catch (CameraAccessException e) {
return null;
}
for (String cameraId : cameraIdList) {
CameraCharacteristics cameraCharacteristics = null;
try {
cameraCharacteristics = cameraManager.getCameraCharacteristics(cameraId);
} catch (CameraAccessException e) {
return null;
}
Integer lensFacing = cameraCharacteristics.get(CameraCharacteristics.LENS_FACING);
if (lensFacing != null && lensFacing == CameraCharacteristics.LENS_FACING_FRONT) {
return cameraId;
}
}
}
return null;
}
Both catch statements in that piece of code are generating the lint error "Class requires API level 21".
I just learned about the #TargetApi annotation, which solves my problem.

When Setting Flash Mode for Camera Paramters in zxing set Parameters failed exception in android

I am integrating barcode scanning functionality using zxing in android, my app includes turn on/off flash light functionality by button press.
When the flash button is pressed it sets the flash to mode torch and that parameter is set to be a camera parameter. I got an exception: Set Paramters failed exception.
Here is my code.
Parameters p = camera.getParameters();
List<String> supportedFlashModes =p.getSupportedFlashModes();
if (active)
{
if(supportedFlashModes!= null)
{
if(supportedFlashModes.contains(Parameters.FLASH_MODE_TORCH))
{
p.setFlashMode(Parameters.FLASH_MODE_TORCH);
}
}
CaptureActivity.flashLightON=true;
}
else
{
p.setFlashMode(Parameters.FLASH_MODE_OFF);
}
camera.setParameters(p);
I got the following exception:
06-07 12:15:26.107: E/AndroidRuntime(24642): FATAL EXCEPTION: main
06-07 12:15:26.107: E/AndroidRuntime(24642): java.lang.RuntimeException:
setParameters failed
06-07 12:15:26.107: E/AndroidRuntime(24642): at
android.hardware.Camera.native_setParameters(Native Method)
Please advice me how to resolve this issue?
I had the same problem with my Google Nexus One.
The problem was solved for me by canceling autofocus, set parameters and then reset autofocus
camera.cancelAutoFocus();
camera.setParameters(parameters);
camera.autoFocus(autoFocusCallback);
Unfortunately its not an universal workaround since it does not work for S3 or Galaxy Nexus who totally loses it...
S-G starts to flashes and S3 stop autofocus.
I solved the issue for S3 by stoping preview and then restarting after the parameters were set
I had the same problem, turning the flaslight with the camera on causes some autofocus collision, when setting the parameters at the same time (especially when your autofocus interval is low).
Paste this right before enabling/disabling the flashlight, it will slow down the enabling event, but hey, no crash (not 100% crash proof though).
//sleep time should be long, 3000ms should be enough to prevent crash on some devices, 2000 may by to little (still crashes on Sony Xperia devices) - I have no idea wy this works that way :D
try {
Thread.currentThread().sleep(3000);
}
catch (InterruptedException e) {
e.printStackTrace();
}
Edit:
Better way to solve this problem, is to put your setParameters method in a loop, and catch runtime exception everytime. Exit the loop when there is no exception, or when your (optional) loop counter reaches max value.
final int MAX_TRIES = 100;
boolean success = false;
int triesCounter = 0;
while (!success) {
try {
triesCounter++;
if (triesCounter > MAX_TRIES) {
success = true;
}
parameters = camera.getParameters();
if (parameters != null) {
parameters.setFlashMode(Parameters.FLASH_MODE_OFF);
camera.setParameters(parameters);
}
success = true;
} catch (Exception exception) {
}
}
Some of the devices do not support and gives such problems. You can refer the link bellow, so that you can get a clear idea about it.
How to turn on camera flash light programmatically in Android?
One solution that works is to create a queue of camera parameters. Setting the torch would add a torch parameter to the queue.
Inside the onAutoFocus callback, call a function that iterates through all of the queue items and commits them. This way you are guaranteed that you are not autofocusing.
turning the flaslight with the camera on/trouch (FLASH_MODE_TORCH)
causes some autofocus collision, when setting the parameters at the
same time (especially when your autofocus interval is low).
I don't like the thread workaround. So I fixed it like this
...
private Boolean _flashOn = null;
...
private Runnable doAutoFocus = new Runnable() {
public void run() {
if (previewing) {
if (_flashOn != null) {
Parameters p = mCamera.getParameters();
if (_flashOn) {
p.setFlashMode(Parameters.FLASH_MODE_TORCH);
}else{
p.setFlashMode(Parameters.FLASH_MODE_OFF);
}
mCamera.setParameters(p);
_flashOn = null;
}
mCamera.autoFocus(autoFocusCB);
}
}
};
No RuntimeException now.
But still has FLASH_MODE_TORCH + autoFocus bug on some adroid devices, e.g. Motorala Milestone/Samsun I9100G/Blahblah...
See also a declined issue for Android: https://code.google.com/p/android/issues/detail?id=14360
BTW. ZBar is faster than ZXing :)
I wanted to start the flash light at the start of scanning and solve it with this.
I have changed in com.google.zxing.client.android.camera method openDriver
Camera theCamera = camera;
if (theCamera == null) {
theCamera = Camera.open();
if (theCamera == null) {
throw new IOException();
}
final Parameters p = theCamera.getParameters();
p.setFlashMode(Parameters.FLASH_MODE_TORCH);
theCamera.setParameters(p);
camera = theCamera;
}
than I have removed from com.google.zxing.client.android.camera.CameraConfigurationManager
initializeTorch(parameters, prefs);
finaly I have changed AndroidManifest.xml
<uses-feature android:name="android.hardware.camera.flash" android:required="true"/>
Try out this code. It worked fine with me.
private void turnOnFlashLight(){
if (!pm.hasSystemFeature(PackageManager.FEATURE_CAMERA))
{
//Check for Device Camera
Toast.makeText(this, getString(R.string.no_device_camera_msg), Toast.LENGTH_SHORT).show();
flashLightControl.setChecked(false);
return;
}else if (!pm.hasSystemFeature(PackageManager.FEATURE_CAMERA_FLASH))
{
//Check for Camera flash
Toast.makeText(this, getString(R.string.no_camera_flash), Toast.LENGTH_SHORT).show();
flashLightControl.setChecked(false);
return;
}else
{
//BIG ISSUE Fash mode is device specific
//Turn On Flash
String _model = android.os.Build.MODEL;
String _manufaturer = android.os.Build.MANUFACTURER;
if((_model.contains("GT-S5830") && _manufaturer.contains("samsung"))) //|| (_manufaturer.contains("lge")))
{
new Thread(new Runnable()
{
#Override
public void run()
{
// TODO Auto-generated method stub
Log.d(TAG, "From TimerTask..!!!");
cameraParams = CameraManager.camera.getParameters();
//cameraParams.setFlashMode(Parameters.FLASH_MODE_TORCH);
cameraParams.set("flash-mode", "on");
CameraManager.camera.setParameters(cameraParams);
CameraManager.camera.startPreview();
isFlash_On_Mode_Device = true;
isLightOn = true;
try{
Thread.sleep(2000);
Log.d(TAG, "From TimerTask After sleep!!!");
cameraParams = CameraManager.camera.getParameters();
cameraParams.setFlashMode(Parameters.FLASH_MODE_OFF);
CameraManager.camera.setParameters(cameraParams);
CameraManager.camera.startPreview();
isLightOn = true;
}
catch(Exception e){}
}
}).start();
}else if(_manufaturer.contains("lge"))
{
//Log.d(TAG, "From LG");
cameraParams = CameraManager.camera.getParameters();
cameraParams.setFlashMode(Parameters.FLASH_MODE_ON);
CameraManager.camera.setParameters(cameraParams);
CameraManager.camera.startPreview();
isLightOn = true;
}
else if(CameraManager.camera != null)
{
cameraParams = CameraManager.camera.getParameters();
//cameraParams.setFlashMode(Parameters.FLASH_MODE_TORCH);
cameraParams.set("flash-mode", "torch");
CameraManager.camera.setParameters(cameraParams);
CameraManager.camera.startPreview();
isLightOn = true;
}
}
private void turnOffFlashLight()
{
if (isLightOn)
{
if(CameraManager.camera != null)
{
if(isFlash_On_Mode_Device)
{
CameraManager.get().closeDriver();
SurfaceHolder surfaceHolder = surfaceView.getHolder();
if (hasSurface)
{
initCamera(surfaceHolder);
if(CameraManager.camera != null)
CameraManager.camera.startPreview();
}
//Log.d(TAG, "Stopping camera..!!!");
}else
{
cameraParams = CameraManager.camera.getParameters();
cameraParams.setFlashMode(Parameters.FLASH_MODE_OFF);
CameraManager.camera.setParameters(cameraParams);
CameraManager.camera.startPreview();
}
isLightOn = false;
isFlash_On_Mode_Device = false;
}
}
}

Categories

Resources