Произошла ошибка при подключении к камере: 0, когда я делаю второй снимок - PullRequest
0 голосов
/ 08 ноября 2019

У меня есть задача внедрить фото-функцию в приложение-опрос, потому что в нем есть опросы, в которых респондент должен что-то нарисовать. Все работает хорошо, за исключением случаев, когда он заполняет анкеты, которые оба требуют картинупервый работает без ошибок, а второй дает сбой и сразу переходит к onError () - Method. но когда я заполняю опрос без фото между ними работает

Вот PictureActivity

@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
public class PictureActivity extends AppCompatActivity {

    private Camera2Pic model;
    private Button takePic;
    private TextureView textureView;
    private Fragebogen fragebogen;
    private ErhebungsSet set;

    /**
     * Initialisiert View-Komponenten und das Model
     * @param savedInstanceState
     */
    @RequiresApi(api = Build.VERSION_CODES.M)
    @SuppressLint({"ClickableViewAccessibility", "ResourceType", "WrongViewCast"})
    @Override
    protected void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_picture);
        textureView = findViewById(R.id.texture);
        takePic = findViewById(R.id.takePic);
        takePic.setText("\uD83D\uDCF7");
        takePic.setTextSize(40);
        textureView.setSurfaceTextureListener(textureListener);
        set = Persister.getErhebungsSet();
        model = new Camera2Pic(PictureActivity.this,textureView, set.getErhebungenListe().get(getIntent().getIntExtra("key",0)).getSurvey());
        takePic.setOnClickListener(new View.OnClickListener() {
            @RequiresApi(api = Build.VERSION_CODES.O)
            @Override
            public void onClick(View view) {
                try {
                    model.first = true;
                    model.takePic();

                } catch (CameraAccessException e) {
                    e.printStackTrace();
                }
            }
        });
        textureView.setOnTouchListener((view, motionEvent) -> model.focusTouch(view, motionEvent));
    }
    /**
     * Stellt die Texture zur verfügung
     */

    TextureView.SurfaceTextureListener textureListener = new TextureView.SurfaceTextureListener() {
        @Override
        public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
            try {
                model.openCamera();
            } catch (CameraAccessException e) {
                e.printStackTrace();
            }
        }

        @Override
        public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {

        }

        @Override
        public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
            return false;
        }

        @Override
        public void onSurfaceTextureUpdated(SurfaceTexture surface) {

        }
    };

    /**
     * Überprüft on die Rechte für die Kamera gegeben sind
     * @param requestCode
     * @param permissions
     * @param grantReesults
     */
    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantReesults){
        if(requestCode == 101){
            if(grantReesults[0]== PackageManager.PERMISSION_DENIED){
                Toast.makeText(getApplicationContext(),"Sorry, camera permission is neccesary", Toast.LENGTH_LONG).show();
            }
        }

    }

    @Override
    protected void onResume() {
        super.onResume();
        model.startBackgroundThread();

        if (textureView.isAvailable()){
            try {
                model.openCamera();
            }catch (CameraAccessException e){
                e.printStackTrace();
            }
        }else{
            textureView.setSurfaceTextureListener(textureListener);
        }

    }
    /**
     * Stoppt die übertragung
     */

    @Override
    protected void onPause(){
        super.onPause();
    }

}

А вот модель

@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
public class Camera2Pic {


    private static final int statePreview = 0;
    private static final int waitLock = 1;
    private int mState;
    private Bitmap bitmap;
    private Context context;
    private ImageView imageView;
    private CameraDevice cameraDevice;
    private String cameraID;
    private Size dimension;
    private CameraCaptureSession cameraCaptureSession;
    private CaptureRequest.Builder captureRequestBuilder;
    private Handler mBackgroundHandler;
    private HandlerThread handlerThread;
    private TextureView textureView;
    public Boolean first;
    private Fragebogen fragebogen;
    private ImageReader reader;
    private ImageReader.OnImageAvailableListener readerListenenr;

    @RequiresApi(api = Build.VERSION_CODES.M)
    public Camera2Pic(Context context, TextureView textureView, Fragebogen fragebogen) {
        this.context = context;
        this.textureView = textureView;
        this.fragebogen = fragebogen;
        readerListenenr = reader -> photo();

        first = true;

    }
    /**
     *Diese Methode lässt die Kamera den Bereich fokussieren auf den man Clickt
     *und bleibt bei dem Fokus
     *
     * @param view
     * @param motionEvent
     * @return boolean
     *
     *
     */
    @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
    public Boolean focusTouch(View view, MotionEvent motionEvent) {

        int pointerId = motionEvent.getPointerId(0);
        int pointerIndex = motionEvent.findPointerIndex(pointerId);
        float x = motionEvent.getX(pointerIndex);
        float y = motionEvent.getY(pointerIndex);
        Rect touchRect = new Rect((int) (x - 100), (int) (y - 100), (int) (x + 100), (int) (y + 100));
        if (cameraID == null) return false;

        MeteringRectangle focusArea = null;
        try {
            focusArea = new MeteringRectangle(touchRect, MeteringRectangle.METERING_WEIGHT_DONT_CARE);
            cameraCaptureSession.setRepeatingRequest(captureRequestBuilder.build(),null,mBackgroundHandler);
            mState = statePreview;
        } catch (CameraAccessException e) {
            e.printStackTrace();
        }catch (IllegalStateException e){
            Toast.makeText(context,"Bitte einen Moment Geduld", Toast.LENGTH_SHORT).show();
        }catch (IllegalArgumentException e){
            DisplayMetrics metrics = new DisplayMetrics();
            ((Activity)context).getWindowManager().getDefaultDisplay().getMetrics(metrics);
            touchRect = new Rect((int) (metrics.heightPixels/2 - 100), (int) (metrics.widthPixels/2 - 100), metrics.heightPixels/2 + 100, metrics.widthPixels/2 + 100);
            focusArea = new MeteringRectangle(touchRect, MeteringRectangle.METERING_WEIGHT_DONT_CARE);
        }

        try {
            captureRequestBuilder.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_AUTO);
            captureRequestBuilder.set(CaptureRequest.CONTROL_AF_REGIONS, new MeteringRectangle[]{focusArea});
            cameraCaptureSession.setRepeatingRequest(captureRequestBuilder.build(),null,mBackgroundHandler);
            captureRequestBuilder.set(CaptureRequest.CONTROL_AF_TRIGGER, CaptureRequest.CONTROL_AF_TRIGGER_START);
            cameraCaptureSession.capture(captureRequestBuilder.build(),null,mBackgroundHandler);
            captureRequestBuilder.set(CaptureRequest.CONTROL_AF_TRIGGER, CaptureRequest.CONTROL_AF_TRIGGER_IDLE);
            cameraCaptureSession.capture(captureRequestBuilder.build(),null,mBackgroundHandler);

        } catch (CameraAccessException e) {
            e.printStackTrace();
        }catch (IllegalStateException e){
            Toast.makeText(context,"Bitte einen Moment Geduld", Toast.LENGTH_LONG).show();

        }

        return false;

    }

    /**
     * Ruft die openCamera() Funktion auf wenn die Bedingungen erfüllt sind
     */

    TextureView.SurfaceTextureListener textureListener = new TextureView.SurfaceTextureListener() {
        @Override
        public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
            try {
                openCamera();
            } catch (CameraAccessException e) {
                e.printStackTrace();
            }
        }

        @Override
        public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {

        }

        @Override
        public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
            return false;
        }

        @Override
        public void onSurfaceTextureUpdated(SurfaceTexture surface) {

        }
    };

    CameraDevice.StateCallback stateCallback = new CameraDevice.StateCallback() {
        @Override
        public void onOpened(@NonNull CameraDevice camera) {

            cameraDevice = camera;
            try {
                createCamerPreview();
            }catch (CameraAccessException e){
                e.printStackTrace();
            }
            showMessage("Für den Fragebogen "+fragebogen.getName()+" muss ein Foto aufgenommen werden<p><b>Bitte Foto aufnehmen</b></p>");

        }

        @Override
        public void onDisconnected(@NonNull CameraDevice camera) {
            cameraDevice.close();
        }

        @Override
        public void onError(@NonNull CameraDevice camera, int error) {

            cameraDevice.close();
            cameraDevice = null;
        }

    };

    /**
     * Erstellt die klassische Kamera perspektive
     * @throws CameraAccessException
     */
    @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
    private void createCamerPreview() throws CameraAccessException {

        SurfaceTexture texture = textureView.getSurfaceTexture();
        texture.setDefaultBufferSize(dimension.getWidth(),dimension.getHeight());
        Surface surface = new Surface(texture);
        captureRequestBuilder = cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
        captureRequestBuilder.addTarget(surface);
        cameraDevice.createCaptureSession(Arrays.asList(surface), new CameraCaptureSession.StateCallback() {
            @Override

            public void onConfigured(CameraCaptureSession session) {
                if (cameraDevice == null) {
                    return;
                }
                cameraCaptureSession = session;
                try {
                    updatePreview();
                }catch (CameraAccessException e){
                    e.printStackTrace();
                }

            }

            @Override
            public void onConfigureFailed(@NonNull CameraCaptureSession session) {

                Toast.makeText(context, "Configuration Changed", Toast.LENGTH_LONG).show();

            }
        },null);

    }

    /**
     * erneuert die Kamera perspektive
     * @throws CameraAccessException
     */
    @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
    private void updatePreview() throws CameraAccessException {
        if(cameraDevice==null){
            return;
        } try {
            cameraCaptureSession.setRepeatingRequest(captureRequestBuilder.build(), null, mBackgroundHandler);
        }catch (IllegalStateException e){
            e.printStackTrace();
        }
    }

    /**
     * Öffnet die Kamera
     * @throws CameraAccessException
     */
    @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
    public void openCamera() throws CameraAccessException {

        CameraManager manager = (CameraManager) context.getSystemService(Context.CAMERA_SERVICE);
        cameraID = manager.getCameraIdList()[0];
        CameraCharacteristics cc = manager.getCameraCharacteristics(cameraID);
        StreamConfigurationMap map = cc.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
        dimension = map.getOutputSizes(SurfaceTexture.class)[0];


        if (ActivityCompat.checkSelfPermission(context, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED
                && ActivityCompat.checkSelfPermission(context, Manifest.permission.WRITE_EXTERNAL_STORAGE)!= PackageManager.PERMISSION_GRANTED)

        {
            ActivityCompat.requestPermissions(((Activity)context),new String[]{Manifest.permission.CAMERA, Manifest.permission.WRITE_EXTERNAL_STORAGE},101);

            return;
        }
        manager.openCamera(cameraID, stateCallback, null);


    }

    /**
     * Nimmt ein Foto auf und ruft die Überprüfung auf
     * @throws CameraAccessException
     */
    @RequiresApi(api = Build.VERSION_CODES.O)
    public void takePic() throws CameraAccessException {
        initReader();
        List<Surface> outputSurface = new ArrayList<>(2);
        outputSurface.add(reader.getSurface());
        Surface surface = new Surface(textureView.getSurfaceTexture());
        outputSurface.add(surface);
        final CaptureRequest.Builder captureBuilder = cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE);
        captureBuilder.addTarget(reader.getSurface());
        captureBuilder.addTarget(surface);
        captureBuilder.set(CaptureRequest.CONTROL_AF_MODE, CameraMetadata.CONTROL_AF_MODE_CONTINUOUS_PICTURE);
        photo();

        final  CameraCaptureSession.CaptureCallback captureListener = new CameraCaptureSession.CaptureCallback() {

            private void process(CaptureResult result){

                switch (mState){
                    case statePreview:
                        break;
                    case waitLock:
                        Integer afState = result.get(CaptureResult.CONTROL_AF_STATE);
                        break;
                }
            }

            @Override
            public void onCaptureStarted(CameraCaptureSession session, CaptureRequest request, long timestamp, long frameNumber) {
                super.onCaptureStarted(session, request, timestamp, frameNumber);
            }

            @Override
            public void onCaptureCompleted(CameraCaptureSession session, CaptureRequest request, TotalCaptureResult result) {
                super.onCaptureCompleted(session, request, result);

                process(result);

                try {
                    createCamerPreview();

                }catch (CameraAccessException e){
                    e.printStackTrace();
                }
            }

            @Override
            public void onCaptureFailed(CameraCaptureSession session, CaptureRequest request, CaptureFailure failure) {
                super.onCaptureFailed(session, request, failure);
                Toast.makeText(context, "Focus don't Locked", Toast.LENGTH_LONG).show();
            }
        };

        cameraDevice.createCaptureSession(outputSurface, new CameraCaptureSession.StateCallback() {
            @Override
            public void onConfigured(CameraCaptureSession cameraCaptureSession) {

                try {

                    cameraCaptureSession.setRepeatingRequest(captureBuilder.build(), captureListener, mBackgroundHandler);

                } catch (CameraAccessException e) {
                    e.printStackTrace();
                } catch (IllegalStateException e){
                    Toast.makeText(context,"Bitte einen Moment Geduld",Toast.LENGTH_LONG).show();
                }
            }

            @Override
            public void onConfigureFailed(@NonNull CameraCaptureSession cameraCaptureSession) {

            }
        },mBackgroundHandler);

    }
    /**
     * Fragt den Benutzer ob er das geschossen Foto behalten will.
     * Falls Ja wird das Bild gespeichert ansonsten kann er noch ein Bild machen
     */
    @SuppressLint("NewApi")
    @RequiresApi(api = Build.VERSION_CODES.M)
    public void show(){

        AlertDialog.Builder adb = new AlertDialog.Builder(context);
        imageView = new ImageView(context);
        imageView.setImageBitmap(bitmap);
        imageView.setPadding(10,10,10,10);

        adb.setPositiveButton("OK", (dialogInterface, i) -> {
            dialogInterface.cancel();
            try {
                save(toBase64());
            } catch (IOException e) {
                e.printStackTrace();
            }
            ((Activity)context).finish();
        });
        adb.setNegativeButton("Nochmal", (dialogInterface, i) -> dialogInterface.cancel());
        adb.setView(imageView);
        try {
            adb.create().show();
        }catch(WindowManager.BadTokenException e){

        }
    }

    /**
     * Speicher das Bild auf dem Gerät und wandelt es in eine String um.
     * Mit dem String wird das Bild im JSON-String gespeichert
     * @param meta
     * @throws IOException
     */
    public void save(String meta) throws IOException {
        Toast.makeText(context,"Gespeichert",Toast.LENGTH_LONG).show();
        if(meta.isEmpty()){
            meta = "{}";
        }
        Persister.addPic(meta);

    }


    @RequiresApi(api = Build.VERSION_CODES.M)
    public void photo(){

        Image image = reader.acquireLatestImage();
        if(image!=null) {
            ByteBuffer buffer = image.getPlanes()[0].getBuffer();
            byte[] bytes = new byte[buffer.capacity()];
            buffer.get(bytes);
            Matrix matrix = new Matrix();
            matrix.postRotate(90);
            bitmap = BitmapFactory.decodeByteArray(bytes, 0, bytes.length, null);
            bitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);

            if(first) {
                first = false;
                show();
            }
            if (image != null) {
                image.close();
            }
        }
        reader.setOnImageAvailableListener(readerListenenr, mBackgroundHandler);
    }

    /**
     * Konventiert ein Bild in einen String mit Hilfe von Base64
     *
     * @return String der das Bild representier
     *
     */
    @RequiresApi(api = Build.VERSION_CODES.O)
    public String toBase64(){

        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
        bitmap.compress(Bitmap.CompressFormat.JPEG, 40, byteArrayOutputStream);
        byte[] bytes = byteArrayOutputStream.toByteArray();
        return Base64.encodeToString(bytes, Base64.DEFAULT);
    }


    /**
     * Startet den Kamerahintergrund-Thread
     */
    public void startBackgroundThread(){

        handlerThread = new HandlerThread("Camera Background");
        handlerThread.start();
        mBackgroundHandler = new Handler(handlerThread.getLooper());

    }

    /**
     * Stoppt den Kamerahintergrund-Thread
     */
    @SuppressLint("NewApi")
    @RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR2)
    public void stopBackgroundThread() throws InterruptedException {

        handlerThread.quitSafely();
        handlerThread.join();
        handlerThread = null;
        mBackgroundHandler = null;

    }

    public void initReader(){
        CameraManager manager = (CameraManager)context.getSystemService(Context.CAMERA_SERVICE);
        CameraCharacteristics characteristics = null;
        try {
            characteristics = manager.getCameraCharacteristics(cameraDevice.getId());
        } catch (CameraAccessException e) {
            e.printStackTrace();
        }
        Size[] jpegSize = characteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP).getOutputSizes(ImageFormat.JPEG);
        int width = 0;
        int height = 0;
        if(jpegSize!=null && jpegSize.length>0){
            width = jpegSize[0].getWidth()/2;
            height = jpegSize[0].getHeight()/2;
        }
        reader = ImageReader.newInstance(width , height, ImageFormat.JPEG,2);

    }
    public void showMessage(String s){
        AlertDialog.Builder adb = new AlertDialog.Builder(context);
        TextView textView = new TextView(context);
        String content = s;
        textView.setText(Html.fromHtml(content));
        textView.setTextSize(23);
        adb.setPositiveButton("Ok", (dialog, which) -> {});
        adb.setView(textView);
        adb.create().show();
    }
}

И эти функциигде я запускаю PictureActivity

private void displaySurveyItem() {
    Button buttonNext = findViewById(R.id.button_erhebung_next);
    showSkipText(false);
    buttonNext.setOnClickListener(v -> nextPage(erhebung));

    if ((erhebung.getSurvey().getPage(erhebung.getAktPageNr()).isItem())
            && (!erhebung.aktPageAnswered())) {
        buttonNext.setEnabled(false);
        delayWorker.schedule(() -> buttonNext.setEnabled(true), 1, TimeUnit.SECONDS);
    }

    if (fragebogen != null) {
        if (erhebung.showTHX()) {
            if(fragebogen.getHasPic()) {
                PictureActivity activity = new PictureActivity();
                startActivityForResult(new Intent(SurveyFillOutActivity.this, activity.getClass()), 0);
            }else{
                showFragebodenEnd();
            }

        } else {
            FragebogenPage fragebogenPage = fragebogen.getPage(erhebung.getAktPageNr());
            fillTextView(fragebogenPage.getTitel(), R.id.erhebung_title, R.id.erhebung_title_space, true);
            fillTextView(fragebogenPage.getText1(), R.id.erhebung_text1, R.id.erhebung_text1_space, false);
            fillTextView(fragebogenPage.getText2(), R.id.erhebung_text2, R.id.erhebung_text2_space, false);
            fillTextView(fragebogenPage.getFutter(), R.id.erhebung_footer, R.id.erhebung_footer_space, true);
            toggleQuestionsVisibility(View.VISIBLE);
            buildAnswerPanel();

            int backButtonVisibility = erhebung.aktPageIsFirst() ? View.INVISIBLE : View.VISIBLE;
            findViewById(R.id.button_erhebung_back).setVisibility(backButtonVisibility);
        }
    }
}

А вот и сообщение об ошибке

    W/Camera: An error occurred while connecting to camera: 0
    D/AndroidRuntime: Shutting down VM
    E/AndroidRuntime: FATAL EXCEPTION: main
        Process: ch.zh.ipw.quest, PID: 25694
        java.lang.NullPointerException: Attempt to invoke virtual method 'void android.hardware.camera2.CameraDevice.close()' on a null object reference
            at ch.zh.ipw.quest.camera2scanner.Camera2Pic$2.onError(Camera2Pic.java:202)
            at android.hardware.camera2.impl.CameraDeviceImpl$8.run(CameraDeviceImpl.java:301)
            at android.os.Handler.handleCallback(Handler.java:739)
            at android.os.Handler.dispatchMessage(Handler.java:95)
            at android.os.Looper.loop(Looper.java:145)
            at android.app.ActivityThread.main(ActivityThread.java:6939)
            at java.lang.reflect.Method.invoke(Native Method)
            at java.lang.reflect.Method.invoke(Method.java:372)
            at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1404)
            at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1199)

Я думаю, что эта ошибка возникает, потому что камера используется все, но как я могу предотвратить это. Пожалуйста, спросите, если у вас есть вопросы о коде или приложении и заранее благодарим вас

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...