My app turn on camera LED using FLASH_MODE_TORCH, but now some people say that FLASH_MODE_TORCH will not work on some Samsung devices correctly.
So should I use FLASH_MODE_ON for all devices to work?(especially for Samsung devices)
may be this will help you
Parameters params = null;
if(mCamera != null) {
params = mCamera.getParameters();
if(params != null) {
List<String> supportedFlashModes = params.getSupportedFlashModes();
if(supportedFlashModes != null) {
if(supportedFlashModes.contains(Parameters.FLASH_MODE_TORCH)) {
params.setFlashMode( Parameters.FLASH_MODE_TORCH );
} else if(supportedFlashModes.contains(Parameters.FLASH_MODE_ON)) {
params.setFlashMode( Parameters.FLASH_MODE_ON );
} else mCamera = null;
} else Log.d(TAG, "Camera is null.");
if(mCamera != null) {
Log.d(TAG, "Flash disponibile (" + params.getFlashMode() + ")");
mCamera.setParameters( params );
mCamera.startPreview();
mCamera.autoFocus(null);
} else Log.d(TAG, "Camera is null.");
There is no single way to make sure the flash works on every device. You have to add a lot of code that is specific of the manufacturer and the device.
Dwhanik's answer is how I would handle the specific problem you are talking about. Check for FLASH_MODE_TORCH first and then try FLASH_MODE_ON. But this does not mean that you will get a flash on every device.
public void Initialize(){
if (this.getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA_FLASH)) {
camManager = (CameraManager) getSystemService(this.CAMERA_SERVICE);
try {
if (camManager.getCameraIdList().length > 0) {
strCameraID=camManager.getCameraIdList()[0];
}
} catch (Exception EX_CAMLIST) {
}
}
}
public void switchLED(String strCemeraID,boolean status){
if(camManager==null || strCemeraID==null)return;
try {
if (strCemeraID.length() > 0) {
camManager.setTorchMode(strCemeraID, status);
}
} catch (Exception EX_CAMERA_TORCH) {
}
}
Related
I use this code for Camera X binding. When I run app for the first time everything works fine. But when I close app and start it again I get "ViewPort is NULL". Why viewPort is NULL I do not understand. What is wrong with my code?
#OptIn(markerClass = androidx.camera.lifecycle.ExperimentalUseCaseGroupLifecycle.class)
private void bindAllCameraUseCases() {
if (cameraProvider != null) {
// As required by CameraX API, unbinds all use cases before trying to re-bind any of them.
cameraProvider.unbindAll();
createPreviewUseCase();
createImageCaptureUseCase();
createAnalysisUseCase();
if (previewUseCase != null && analysisUseCase != null && imageCaptureUseCase != null) {
ViewPort viewPort = ((PreviewView)findViewById(R.id.preview_view)).getViewPort();
if (viewPort != null) {
#OptIn(markerClass = androidx.camera.core.ExperimentalUseCaseGroup.class)
UseCaseGroup useCaseGroup = new UseCaseGroup.Builder()
.addUseCase(previewUseCase)
.addUseCase(analysisUseCase)
.addUseCase(imageCaptureUseCase)
.setViewPort(viewPort)
.build();
camera = cameraProvider.bindToLifecycle(/* lifecycleOwner= */ this, cameraSelector, useCaseGroup);
LiveData<Integer> torchStateObserver = camera.getCameraInfo().getTorchState();
torchStateObserver.observe(this, new Observer<Integer>() {
#Override
public void onChanged(Integer state) {
torchState = state;
}
});
} else {
Toast.makeText(this, "VIEWPORT is NULL", Toast.LENGTH_SHORT).show();
}
}
}
}
I'm trying to switch from old Android camera API to new CameraX API. I'm using preview mode for an Augmented Reality App and I need to get some info like angle of view and size on my camera used by the Preview.
This is my code so far:
PreviewConfig config = new PreviewConfig.Builder()
.setLensFacing(CameraX.LensFacing.BACK)
.setTargetResolution(new Size(dsiWidth, dsiHeight))
.build();
Preview preview = new Preview(config);
preview.setOnPreviewOutputUpdateListener(new Preview.OnPreviewOutputUpdateListener() {
#Override
public void onUpdated(Preview.PreviewOutput output) {
tvCameraView.setSurfaceTexture(output.getSurfaceTexture());
}
});
CameraX.bindToLifecycle(this, preview);
This works so far. But how do I get information on the camera used by the Preview? Thanks a lot in advance!
When you use the "androidx.camera:camera-camera2:1.0.0-alpha02" dependency you can have a look at the class Camera2CameraFactory. There you can see how the front and back facing camera is determined.
#Override
public Set<String> getAvailableCameraIds() throws CameraInfoUnavailableException {
List<String> camerasList = null;
try {
camerasList = Arrays.asList(mCameraManager.getCameraIdList());
} catch (CameraAccessException e) {
throw new CameraInfoUnavailableException(
"Unable to retrieve list of cameras on device.", e);
}
// Use a LinkedHashSet to preserve order
return new LinkedHashSet<>(camerasList);
}
#Nullable
#Override
public String cameraIdForLensFacing(LensFacing lensFacing)
throws CameraInfoUnavailableException {
Set<String> cameraIds = getAvailableCameraIds();
// Convert to from CameraX enum to Camera2 CameraMetadata
Integer lensFacingInteger = -1;
switch (lensFacing) {
case BACK:
lensFacingInteger = CameraMetadata.LENS_FACING_BACK;
break;
case FRONT:
lensFacingInteger = CameraMetadata.LENS_FACING_FRONT;
break;
}
for (String cameraId : cameraIds) {
CameraCharacteristics characteristics = null;
try {
characteristics = mCameraManager.getCameraCharacteristics(cameraId);
} catch (CameraAccessException e) {
throw new CameraInfoUnavailableException(
"Unable to retrieve info for camera with id " + cameraId + ".", e);
}
Integer cameraLensFacing = characteristics.get(CameraCharacteristics.LENS_FACING);
if (cameraLensFacing == null) {
continue;
}
if (cameraLensFacing.equals(lensFacingInteger)) {
return cameraId;
}
}
return null;
}
It boils down to picking the first camera that matches the orientation from the camera service. I would assume that they will expand those apis in the future camerax release.
Problem: When i set scene mode to SCENE_MODE_NIGHT, flash cannot be set to Off when i call takePicture() method.
Pseudo:
Camera mCamera = Camera.open(Camera.CameraInfo.CAMERA_FACING_BACK)
Camera.Parameters params = camera.getParameters();
//AUTO-FOCUS
List<String> focus = params.getSupportedFocusModes();
if (focus != null && focus.contains(Camera.Parameters.FOCUS_MODE_CONTINUOUS_VIDEO)
params.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_VIDEO);
//AUTO NIGHT SCENE
List<String> scene = params.getSupportedSceneModes();
if (scene != null && scene.contains(Camera.Parameters.SCENE_MODE_NIGHT)){
params.setSceneMode(Camera.Parameters.SCENE_MODE_NIGHT);
}
//FLASH
List<String> flash = params.getSupportedFlashModes();
if(flash != null && flash.contains(Camera.Parameters.FLASH_MODE_OFF)) {
params.setFlashMode(Camera.Parameters.FLASH_MODE_OFF);
}
mCamera.setParameters(params);
mPreview = new CameraPreview(this, mCamera, params); //surfaceView (CameraPreview extends SurfaceView implements SurfaceHolder.Callback)
Call take a picture:
if(params.isVideoSnapshotSupported()){//Some device not supported this mode
mCamera.takePicture(null, null, new Camera.PictureCallback(){
...
}
Permissions:
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.FLASHLIGHT" /> <!--somewhere i find this strange permission, but still not working-->
Logcat shows correctly: params.getFlashMode(): off, but flash is fired.
Logcat (Nexus 5) shows: I/mm-jpeg-intf: process_sensor_data: Flash value 1 flash mode 4 flash state 3 after call mCamera.takePicture.
When i comment line: params.setSceneMode(Camera.Parameters.SCENE_MODE_NIGHT); (or change to Camera.Parameters.SCENE_MODE_AUTO) flash is not fired.
Logcat (Nexus 5) shows: I/mm-jpeg-intf: process_sensor_data: Flash value 0 flash mode 0 flash state 2 after call mCamera.takePicture.
Goal: Use these parameters: SCENE_MODE_NIGHT, FLASH_MODE_OFF together.
Use: Android Camera 1 API. Back camera.
Ocurrence: Android 6,7, maybe Android 5 too.
Tested:
Nexus 5: NOT OK.
Huawei Honor 4C: OK
Probably it's Nexus 5 "bug" because i tried Open Camera application from Google Play, set scene to night, disable flash, but flash is still active while take a picture.
use the below code on onClick of flash on and flash off Button
/**
* Action to be performed when image is capture is clicked
*/
private OnClickListener OnFlashClick = new OnClickListener()
{
#Override
public void onClick(View v)
{
if(btn_cameraFlashOn.isSelected())
{
btn_cameraFlashOn.setSelected(false);
mCamUtils.setFlashParams(Parameters.FLASH_MODE_OFF);
}
else
{
btn_cameraFlashOn.setSelected(true);
mCamUtils.setFlashParams(Parameters.FLASH_MODE_TORCH);
}
}
};
private OnClickListener OffFlashClick = new OnClickListener()
{
#Override
public void onClick(View v)
{
mCamUtils.toggleFlashSettings();
}
};
private String mFlashSetting = null;
/**
* Set the flash mode for camera
*/
public void toggleFlashSettings()
{
if (null == mCamera)
{
return;
}
Camera.Parameters params = mCamera.getParameters();
List<String> flashModes = params.getSupportedFlashModes();
if (flashModes == null)
{
mCallback.enableFlashButton(false);
return;
}
else
{
mCallback.enableFlashButton(true);
}
// Log.d(LOGTAG, " mFlashSetting mode = " + mFlashSetting);
if ((Camera.Parameters.FLASH_MODE_AUTO.equals(mFlashSetting))
&& (flashModes.contains(Camera.Parameters.FLASH_MODE_ON)))
{
setFlashParams(Camera.Parameters.FLASH_MODE_ON);
} else if ((Camera.Parameters.FLASH_MODE_ON.equals(mFlashSetting))
&& (flashModes.contains(Camera.Parameters.FLASH_MODE_OFF)))
{
setFlashParams(Camera.Parameters.FLASH_MODE_OFF);
}
else if (flashModes.contains(Camera.Parameters.FLASH_MODE_AUTO))
{
setFlashParams(Camera.Parameters.FLASH_MODE_AUTO);
}
}
/**
* Returns the current flash setting of the device
*
* #return
*/
public String getFlashMode()
{
if (null == mCamera)
{
return null;
}
mFlashSetting = mCamera.getParameters().getFlashMode();
return mFlashSetting;
}
/**
* Sets the flash mode of the camera. this is a internal method only
*
* #return
*/
public void setFlashParams(String flash)
{
if (null == mCamera)
{
return;
}
Camera.Parameters params = mCamera.getParameters();
List<String> flashModes = params.getSupportedFlashModes();
if (flashModes == null)
{
mCallback.enableFlashButton(false);
return;
}
else
{
mCallback.enableFlashButton(true);
}
if (flashModes.contains(flash))
{
mFlashSetting = flash;
params.setFlashMode(flash);
mCallback.flashSet(flash);
mCamera.setParameters(params);
// Log.d(LOGTAG, " new flash mode = " + flash);
}
else
{
// Log.e(LOGTAG, " INVALID FLASH MODE");
}
}
I'm experiencing a bad behavior when capturing a photo on a Samsung Galaxy S7 edge device.
I wait simultaneously for focus and exposure before taking the picture but at the end I have a kind of blurred image compared to the native camera app output.
The problem is especially visible on zoomed images but is present also when not zoomed. I've also tried to enable the optical image stabilization but the problem isn't fixed.
Below are linked sample images explaining the problem.
Native camera image
My camera image
Here is the code:
Method for picture capture step 1:
public void capturePicture() {
CameraState state = getState();
if (state != IDLE && state != CLOSING && state != TAKE_PICTURE) {
boolean af = false;
boolean ae = false;
if (isAFEnabled()) {
af = true;
} else if (isAEEnabled()) {
ae = true;
}
if (!af && !ae) {
takePicture();
} else {
triggerFocusAndExposure(true);
}
}
return;
}
Method for triggering focus and exposure:
private void triggerFocusAndExposure(boolean picture) {
setState(WAIT_PRECAPTURE_PICTURE);
if (isAFEnabled()) {
previewBuilder.set(CONTROL_AF_TRIGGER, CONTROL_AF_TRIGGER_START);
}
if (isAEEnabled()) {
previewBuilder.set(CONTROL_AE_PRECAPTURE_TRIGGER, CONTROL_AE_PRECAPTURE_TRIGGER_START);
}
try {
cameraSession.capture(previewBuilder.build(), new SCameraCaptureSession.CaptureCallback() {
#Override public void onCaptureCompleted(SCameraCaptureSession session, SCaptureRequest request, STotalCaptureResult result) {
setState(PRECAPTURE_TRIGGERED_PICTURE);
}
}, backgroundHandler);
} catch (CameraAccessException e) {
return;
}
try {
previewBuilder.set(CONTROL_AF_TRIGGER, CONTROL_AF_TRIGGER_IDLE);
previewBuilder.set(CONTROL_AE_PRECAPTURE_TRIGGER, CONTROL_AE_PRECAPTURE_TRIGGER_IDLE);
cameraSession.setRepeatingRequest(previewBuilder.build(), mSessionCaptureCallback, backgroundHandler);
} catch (CameraAccessException e) {
}
}
Methods for waiting focus and exposure:
private void waitPrecapture(STotalCaptureResult result, boolean picture) {
// Check if AF/AE triggered and/or finished
if ((!isAFTriggered(result) || isAfFinished(result)) && (!isAETriggered(result) || isAEFinished(result))) {
takePicture();
}
}
private boolean isAFTriggered(STotalCaptureResult result) {
Integer afMode = result.get(SCaptureResult.CONTROL_AF_MODE);
return afMode != CONTROL_AF_MODE_OFF &&
afMode != CONTROL_AF_MODE_EDOF;
}
private boolean isAfFinished(STotalCaptureResult result) {
int afState = result.get(SCaptureResult.CONTROL_AF_STATE);
return afState == CONTROL_AF_STATE_FOCUSED_LOCKED || afState == CONTROL_AF_STATE_NOT_FOCUSED_LOCKED
|| afState == CONTROL_AF_STATE_PASSIVE_FOCUSED || afState == CONTROL_AF_STATE_PASSIVE_UNFOCUSED;
}
private boolean isAETriggered(STotalCaptureResult result) {
boolean aeMode = result.get(SCaptureResult.CONTROL_AE_MODE) != SCaptureResult.CONTROL_AE_MODE_OFF;
return aeMode && cameraCharacteristics.get(SCameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL)
!= SCameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_LEGACY;
}
private boolean isAEFinished(STotalCaptureResult result) {
Integer aeState = result.get(SCaptureResult.CONTROL_AE_STATE);
return aeState == null || aeState == SCaptureResult.CONTROL_AE_STATE_CONVERGED || aeState == SCaptureResult.CONTROL_AE_STATE_FLASH_REQUIRED
|| aeState == SCaptureResult.CONTROL_AE_STATE_LOCKED;
}
Method for picture capture step 2:
public void takePicture(){
imageReader.setOnImageAvailableListener(reader -> {
Image image = reader.acquireLatestImage();
ByteBuffer buffer = image.getPlanes()[0].getBuffer();
byte[] bytes = new byte[buffer.remaining()];
buffer.get(bytes);
image.close();
singleSubscriber.onSuccess(bytes);
}, imageSavingHandler);
try {
cameraSession.capture(captureBuilder.build(), new SCameraCaptureSession.CaptureCallback() {
#Override
public void onCaptureCompleted(SCameraCaptureSession session, SCaptureRequest request, STotalCaptureResult result) {
if (getState() == CameraState.CLOSING) {
return;
}
cancelAF();
}
#Override
public void onCaptureStarted(SCameraCaptureSession session, SCaptureRequest request, long timestamp, long frameNumber) {
super.onCaptureStarted(session, request, timestamp, frameNumber);
shutterCallback.call();
}
#Override public void onCaptureFailed(SCameraCaptureSession session, SCaptureRequest request, SCaptureFailure failure) {
singleSubscriber.onError(new RuntimeException("Error taking picture, onCaptureFailed"));
if (getState() == CameraState.CLOSING) {
return;
}
cancelAF();
}
}, backgroundHandler);
setState(CameraState.TAKE_PICTURE);
} catch (CameraAccessException e) {
singleSubscriber.onError(new RuntimeException("Error capturing image", e));
}
}
I've found the fix.
captureBuilder automatically sets CaptureRequest.NOISE_REDUCTION_MODE_HIGH_QUALITY and CaptureRequest.EDGE_MODE_HIGH_QUALITY but in my case the device has some problem handling these options. Setting CaptureRequest.NOISE_REDUCTION_MODE_FAST and CaptureRequest.EDGE_MODE_FAST fixes the problem.
So Android M recently came out and it now has a built in cameralight function called setTorchMode. I was curious as to how this worked as the parameters are (String cameraID, Boolean true/false). The Boolean obviously dictates whether the light is on or off, but how do you get the cameraID? I know there's a method called getCameraIDList, but that returns an array of IDs, not just one. How do you know which one in that list to use?
You should use CameraManager "getCameraIdList" function which will retrieve you a list of strings where each represent an active camera.
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
mCameraManager = (CameraManager) context.getSystemService(Context.CAMERA_SERVICE);
try {
for (String camID : mCameraManager.getCameraIdList()) {
CameraCharacteristics cameraCharacteristics = mCameraManager.getCameraCharacteristics(camID);
int lensFacing = cameraCharacteristics.get(CameraCharacteristics.LENS_FACING);
if (lensFacing == CameraCharacteristics.LENS_FACING_FRONT && cameraCharacteristics.get(CameraCharacteristics.FLASH_INFO_AVAILABLE)) {
mCameraId = camID;
break;
} else if (lensFacing == CameraCharacteristics.LENS_FACING_BACK && cameraCharacteristics.get(CameraCharacteristics.FLASH_INFO_AVAILABLE)) {
mCameraId = camID;
}
}
if (mCameraId != null) {
mCameraManager.setTorchMode(mCameraId, true);
}
} catch (CameraAccessException e) {
e.printStackTrace();
}
}
mCameraId will turn on front camera flash if available or else back camera flash if available. If no flash is available then mCameraId will be null and setTorchMode will not be called.