Solo
Solo

Reputation: 579

Trying to create flashlight with Android Camera2

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

Answers (1)

Eddy Talvala
Eddy Talvala

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

Related Questions