Reputation: 579
I am trying to create a flashlight using Camera2. I am getting errors. When I am trying to turn on or off flashlight I get the error message:
android.hardware.camera2.CameraAccessExeption: The camera device has encountered a serious error.
MainActivity
package com.nettport.lommelykt;
import android.Manifest;
import android.content.pm.PackageManager;
import android.support.v4.app.ActivityCompat;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;
import android.widget.ToggleButton;
import android.content.Context;
import android.graphics.SurfaceTexture;
import android.hardware.camera2.CameraAccessException;
import android.hardware.camera2.CameraCaptureSession;
import android.hardware.camera2.CameraCharacteristics;
import android.hardware.camera2.CameraDevice;
import android.hardware.camera2.CameraManager;
import android.hardware.camera2.CameraMetadata;
import android.hardware.camera2.CaptureRequest;
import android.util.Size;
import android.view.Surface;
import java.util.ArrayList;
import java.util.List;
public class MainActivity extends AppCompatActivity {
CameraManager cameraManager;
CameraCharacteristics cameraCharacteristics;
CameraDevice mCameraDevice;
CameraCaptureSession mSession;
CaptureRequest.Builder mBuilder;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// Initialize camera
initCamera();
// Click button on or off
ToggleButton onOffButton = (ToggleButton) findViewById(R.id.toggleButton);
onOffButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// your click actions go here
if (((ToggleButton) v).isChecked()) {
changeTextAndIcon(1);
turnOnFlashLight();
} else {
changeTextAndIcon(0);
turnOffFlashLight();
}
}
});
}
/*- Change text and icon ------------------------------------- */
// modus = 1 -> turn on
// modus = 0 -> turn off
void changeTextAndIcon(int modus) {
// Change text
TextView statusText = (TextView) findViewById(R.id.textView);
if (modus == 1) {
statusText.setText("Lommelykten er på"); // Flash is on
} else {
statusText.setText("Lommelykten er av"); // Flash is off
}
// Change icon to off
ImageView flashlightIcon = (ImageView) findViewById(R.id.imageView);
if (modus == 1) {
flashlightIcon.setImageResource(R.drawable.flashlight_on);
} else {
flashlightIcon.setImageResource(R.drawable.flashlight_off);
}
}
private void initCamera() {
cameraManager = (CameraManager) getSystemService(Context.CAMERA_SERVICE);
try {
String[] id = cameraManager.getCameraIdList();
if (id != null && id.length > 0) {
cameraCharacteristics = cameraManager.getCameraCharacteristics(id[0]);
boolean isFlash = cameraCharacteristics.get(CameraCharacteristics.FLASH_INFO_AVAILABLE);
if (isFlash) {
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
// TODO: Consider calling
// ActivityCompat#requestPermissions
// here to request the missing permissions, and then overriding
// public void onRequestPermissionsResult(int requestCode, String[] permissions,
// int[] grantResults)
// to handle the case where the user grants the permission. See the documentation
// for ActivityCompat#requestPermissions for more details.
return;
}
cameraManager.openCamera(id[0], new MyCameraDeviceStateCallback(), null);
Toast.makeText(this, "Camera initialized", Toast.LENGTH_LONG).show();
}
}
}
catch (CameraAccessException e)
{
e.printStackTrace();
Toast.makeText(this, "Camera initialization error:\n" + e.toString(), Toast.LENGTH_LONG).show();
}
}
class MyCameraDeviceStateCallback extends CameraDevice.StateCallback
{
@Override
public void onOpened(CameraDevice camera)
{
mCameraDevice = camera;
// get builder
try
{
mBuilder = camera.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
List<Surface> list = new ArrayList<Surface>();
SurfaceTexture mSurfaceTexture = new SurfaceTexture(1);
Size size = getSmallestSize(mCameraDevice.getId());
mSurfaceTexture.setDefaultBufferSize(size.getWidth(), size.getHeight());
Surface mSurface = new Surface(mSurfaceTexture);
list.add(mSurface);
mBuilder.addTarget(mSurface);
camera.createCaptureSession(list, new MyCameraCaptureSessionStateCallback(), null);
}
catch (CameraAccessException e)
{
e.printStackTrace();
}
}
@Override
public void onDisconnected(CameraDevice camera)
{
}
@Override
public void onError(CameraDevice camera, int error)
{
}
}
private Size getSmallestSize(String cameraId) throws CameraAccessException
{
Size[] outputSizes = cameraManager.getCameraCharacteristics(cameraId).get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP).getOutputSizes(SurfaceTexture.class);
if (outputSizes == null || outputSizes.length == 0)
{
throw new IllegalStateException("Camera " + cameraId + "doesn't support any outputSize.");
}
Size chosen = outputSizes[0];
for (Size s : outputSizes)
{
if (chosen.getWidth() >= s.getWidth() && chosen.getHeight() >= s.getHeight())
{
chosen = s;
}
}
return chosen;
}
class MyCameraCaptureSessionStateCallback extends CameraCaptureSession.StateCallback
{
@Override
public void onConfigured(CameraCaptureSession session)
{
mSession = session;
try
{
mSession.setRepeatingRequest(mBuilder.build(), null, null);
}
catch (CameraAccessException e)
{
e.printStackTrace();
}
}
@Override
public void onConfigureFailed(CameraCaptureSession session)
{
}
}
public void turnOnFlashLight()
{
try
{
mBuilder.set(CaptureRequest.FLASH_MODE, CameraMetadata.FLASH_MODE_TORCH);
mSession.setRepeatingRequest(mBuilder.build(), null, null);
Toast.makeText(this, "Flash activated", Toast.LENGTH_LONG).show();
}
catch (Exception e)
{
e.printStackTrace();
Toast.makeText(this, "Flash failed:\n" + e.toString(), Toast.LENGTH_LONG).show();
}
}
public void turnOffFlashLight()
{
try
{
mBuilder.set(CaptureRequest.FLASH_MODE, CameraMetadata.FLASH_MODE_OFF);
mSession.setRepeatingRequest(mBuilder.build(), null, null);
Toast.makeText(this, "Flash disabled", Toast.LENGTH_LONG).show();
}
catch (Exception e)
{
e.printStackTrace();
Toast.makeText(this, "Flash failed:\n" + e.toString(), Toast.LENGTH_LONG).show();
}
}
private void close()
{
Toast.makeText(this, "Camera closed", Toast.LENGTH_LONG).show();
if (mCameraDevice == null || mSession == null)
{
return;
}
mSession.close();
mCameraDevice.close();
mCameraDevice = null;
mSession = null;
}
}
AndroidManifest
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.nettport.lommelykt">
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/AppTheme"
>
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
<!-- Allows access to the flashlight -->
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.FLASHLIGHT" />
<uses-feature android:name="android.hardware.camera" />
<uses-feature android:name="android.hardware.camera.autofocus" />
<uses-feature android:name="android.hardware.camera.flash" />
</manifest>
Upvotes: 3
Views: 2025
Reputation: 18107
You're not holding on to your SurfaceTexture; the Surface created from it is roughly equal to a weak pointer, and won't keep the SurfaceTexture from being garbage-collected.
See if storing the SurfaceTexture in your MainActivity fixes your problem. If not, you'll need to provide logcat of the crash (not just app logging, the whole system) to see what the camera service is complaining about in more detail.
Upvotes: 6