From 2ea8b743388a16e7984b0977c2b57ac3ba4e43c4 Mon Sep 17 00:00:00 2001 From: YushraJewon Date: Mon, 18 Mar 2024 13:29:59 +0400 Subject: [PATCH 01/13] video capture test --- src/android/CameraPreviewFragment.java | 153 ++++++++++++++++++++++--- src/android/SimpleCameraPreview.java | 46 ++++++++ www/SimpleCameraPreview.js | 6 + 3 files changed, 190 insertions(+), 15 deletions(-) diff --git a/src/android/CameraPreviewFragment.java b/src/android/CameraPreviewFragment.java index a808b31..1290eea 100644 --- a/src/android/CameraPreviewFragment.java +++ b/src/android/CameraPreviewFragment.java @@ -7,6 +7,7 @@ import android.location.Location; import android.net.Uri; import android.os.Bundle; +import android.provider.MediaStore; import android.util.Log; import android.util.Size; import android.view.Display; @@ -15,6 +16,7 @@ import android.view.ViewGroup; import android.view.WindowManager; import android.widget.RelativeLayout; +import android.widget.Toast; import androidx.annotation.NonNull; import androidx.annotation.Nullable; @@ -24,8 +26,18 @@ import androidx.camera.core.ImageCaptureException; import androidx.camera.core.Preview; import androidx.camera.lifecycle.ProcessCameraProvider; +import androidx.camera.video.FileOutputOptions; +import androidx.camera.video.MediaStoreOutputOptions; +import androidx.camera.video.Quality; +import androidx.camera.video.QualitySelector; +import androidx.camera.video.Recorder; +import androidx.camera.video.Recording; +import androidx.camera.video.VideoCapture; +import androidx.camera.video.VideoRecordEvent; import androidx.camera.view.PreviewView; +import androidx.core.app.ActivityCompat; import androidx.core.content.ContextCompat; + import androidx.exifinterface.media.ExifInterface; import androidx.fragment.app.Fragment; @@ -43,6 +55,11 @@ interface CameraCallback { void onCompleted(Exception err, String nativePath); } +interface VideoCallback { + void onStart(Exception err,Boolean recording, String nativePath); + void onStop(Exception err, Boolean recording, String nativePath); +} + interface CameraStartedCallback { void onCameraStarted(Exception err); } @@ -60,6 +77,9 @@ public class CameraPreviewFragment extends Fragment { private PreviewView viewFinder; private Preview preview; private ImageCapture imageCapture; + private VideoCapture videoCapture; + Recording recording = null; + ProcessCameraProvider cameraProvider = null; private Camera camera; private CameraStartedCallback startCameraCallback; private Location location; @@ -102,9 +122,41 @@ public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup c return containerView; } + +// public void startCamera() { +// ListenableFuture cameraProviderFuture = ProcessCameraProvider.getInstance(getActivity()); +// cameraProviderFuture.addListener(() -> { +// try { +// // Used to bind the lifecycle of cameras to the lifecycle owner +// ProcessCameraProvider cameraProvider = cameraProviderFuture.get(); +// +// Recorder recorder = new Recorder.Builder() +// .setQualitySelector(QualitySelector.from(Quality.HIGHEST)) +// .build(); +// videoCapture = VideoCapture.withOutput(recorder); +// imageCapture = new ImageCapture.Builder().build(); +// +// // Select back camera as a default +// CameraSelector cameraSelector = CameraSelector.DEFAULT_BACK_CAMERA; +// try { +// // Unbind use cases before rebinding +// cameraProvider.unbindAll(); +// // Bind use cases to camera +// cameraProvider.bindToLifecycle( +// this, cameraSelector, preview, imageCapture, videoCapture); +// } catch (Exception exc) { +// Log.e(TAG, "Use case binding failed", exc); +// } +// } catch (Exception e) { +// e.printStackTrace(); +// } +// }, ContextCompat.getMainExecutor(this.getContext())); +// if (startCameraCallback != null) { +// startCameraCallback.onCameraStarted(null); +// } +// } public void startCamera() { ListenableFuture cameraProviderFuture = ProcessCameraProvider.getInstance(getActivity()); - ProcessCameraProvider cameraProvider = null; try { cameraProvider = cameraProviderFuture.get(); @@ -124,31 +176,41 @@ public void startCamera() { targetResolution = CameraPreviewFragment.calculateResolution(getContext(), targetSize); } + Recorder recorder = new Recorder.Builder() + .setQualitySelector(QualitySelector.from(Quality.HD)) + .build(); + videoCapture = VideoCapture.withOutput(recorder); + + preview = new Preview.Builder().build(); imageCapture = new ImageCapture.Builder() .setTargetResolution(targetResolution) .build(); - - cameraProvider.unbindAll(); - try { - camera = cameraProvider.bindToLifecycle( - this, - cameraSelector, - preview, - imageCapture - ); - } catch (IllegalArgumentException e) { - // Error with result in capturing image with default resolution - e.printStackTrace(); + this.getActivity().runOnUiThread(() -> { + try { + cameraProvider.unbindAll(); + camera = cameraProvider.bindToLifecycle( + this, + cameraSelector, + preview, + imageCapture, + videoCapture + ); + } catch (IllegalArgumentException e) { + // Error with result in capturing image with default resolution + e.printStackTrace(); imageCapture = new ImageCapture.Builder() .build(); camera = cameraProvider.bindToLifecycle( this, cameraSelector, preview, - imageCapture + imageCapture, + videoCapture ); - } + } + + }); preview.setSurfaceProvider(viewFinder.getSurfaceProvider()); @@ -232,6 +294,67 @@ public void hasFlash(HasFlashCallback hasFlashCallback) { hasFlashCallback.onResult(camera.getCameraInfo().hasFlashUnit()); } + public void captureVideo(boolean useFlash, VideoCallback videoCallback) { + if (torchActivated) { + useFlash = true; + } else { + camera.getCameraControl().enableTorch(useFlash); + } + if (recording != null) { + Toast.makeText(this.getContext(), "Video not null" , Toast.LENGTH_LONG).show(); + + recording.stop(); + return; + } + UUID uuid = UUID.randomUUID(); + + String filename = uuid.toString() + ".mp4"; + ContentValues contentValues = new ContentValues(); + contentValues.put(MediaStore.Video.Media.DISPLAY_NAME, filename); +// 2. Configure Recorder and Start recording to the mediaStoreOutput. + if (ActivityCompat.checkSelfPermission(this.getContext(), Manifest.permission.RECORD_AUDIO) != PackageManager.PERMISSION_GRANTED) { + ActivityCompat.requestPermissions(this.getActivity(), new String[]{Manifest.permission.RECORD_AUDIO}, 200); + } + File videoFile = new File( + getContext().getApplicationContext().getFilesDir(), + filename + ); + +// Configure the recorder to save the video to the specified file + FileOutputOptions outputOptions = new FileOutputOptions.Builder(videoFile).build(); + + recording = videoCapture.getOutput() + .prepareRecording(this.getContext().getApplicationContext(), outputOptions) + .withAudioEnabled() + .start(ContextCompat.getMainExecutor(this.getContext()), videoRecordEvent -> { + if (videoRecordEvent instanceof VideoRecordEvent.Start) { + videoCallback.onStart(null,true, null); + Toast.makeText(this.getContext(), "Video start" , Toast.LENGTH_LONG).show(); + + } else if (videoRecordEvent instanceof VideoRecordEvent.Finalize) { + Toast.makeText(this.getContext(), "Video fin" , Toast.LENGTH_LONG).show(); + VideoRecordEvent.Finalize finalizeEvent = (VideoRecordEvent.Finalize) videoRecordEvent; + if (finalizeEvent.hasError()) { + // Handle the error + int errorCode = finalizeEvent.getError(); + Throwable errorCause = finalizeEvent.getCause(); + Log.e(TAG, "Video recording error: " + errorCode, errorCause); + } else { + // Handle video saved + videoCallback.onStop(null, false, Uri.fromFile(videoFile).toString()); + Uri savedUri = finalizeEvent.getOutputResults().getOutputUri(); + Log.d(TAG, "Video saved to: " + savedUri); + Toast.makeText(this.getContext(), "Video stop" + savedUri, Toast.LENGTH_LONG).show(); + recording = null; + } + } + // Other event types can be handled if needed + }); + + } + + + public void takePicture(boolean useFlash, CameraCallback takePictureCallback) { if (torchActivated) { useFlash = true; diff --git a/src/android/SimpleCameraPreview.java b/src/android/SimpleCameraPreview.java index be44226..973bb4e 100644 --- a/src/android/SimpleCameraPreview.java +++ b/src/android/SimpleCameraPreview.java @@ -72,6 +72,9 @@ public boolean execute(String action, JSONArray args, CallbackContext callbackCo case "torchSwitch": return torchSwitch(args.getBoolean(0), callbackContext); + case "captureVideo": + return captureVideo(args.getBoolean(0), callbackContext); + case "deviceHasFlash": return deviceHasFlash(callbackContext); default: @@ -246,6 +249,49 @@ public void fetchLocation() { } } + private boolean captureVideo(boolean useFlash, CallbackContext callbackContext) { + if (fragment == null) { + callbackContext.error("Camera is closed"); + return true; + } + + fragment.captureVideo( useFlash, new VideoCallback() { + public void onStart(Exception err, Boolean recording, String nativePath) { + JSONObject data = new JSONObject(); + if (recording) { + try { + data.put("recording", true); + data.put("nativePath", null); + } catch (JSONException e) { + e.printStackTrace(); + callbackContext.error("Cannot send recording data"); + return; + } + + PluginResult pluginResult = new PluginResult(PluginResult.Status.OK, data); + pluginResult.setKeepCallback(true); + callbackContext.sendPluginResult(pluginResult); + } + } + + public void onStop(Exception err, Boolean started, String nativePath) { + JSONObject data = new JSONObject(); + try { + data.put("recording", false); + data.put("nativePath", nativePath); + } catch (JSONException e) { + e.printStackTrace(); + callbackContext.error("Cannot send recording data"); + return; + } + PluginResult pluginResult = new PluginResult(PluginResult.Status.OK, data); + pluginResult.setKeepCallback(true); + callbackContext.sendPluginResult(pluginResult); + } + }); + return true; + } + private boolean capture(boolean useFlash, CallbackContext callbackContext) { if (fragment == null) { callbackContext.error("Camera is closed"); diff --git a/www/SimpleCameraPreview.js b/www/SimpleCameraPreview.js index b1f4d96..9afca33 100755 --- a/www/SimpleCameraPreview.js +++ b/www/SimpleCameraPreview.js @@ -20,6 +20,12 @@ SimpleCameraPreview.capture = function (options, onSuccess, onError) { exec(onSuccess, onError, PLUGIN_NAME, "capture", [options.flash]); }; +SimpleCameraPreview.captureVideo = function (options, onSuccess, onError) { + options = options || {}; + options.flash = options.flash || false; + exec(onSuccess, onError, PLUGIN_NAME, "captureVideo", [options.flash]); +}; + SimpleCameraPreview.setSize = function (options, onSuccess, onError) { exec(onSuccess, onError, PLUGIN_NAME, "setSize", [options]); }; From fb341a5c836d1c715795aecae22522de7b1259ea Mon Sep 17 00:00:00 2001 From: YushraJewon Date: Fri, 22 Mar 2024 11:26:32 +0400 Subject: [PATCH 02/13] add missing imports --- src/android/CameraPreviewFragment.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/android/CameraPreviewFragment.java b/src/android/CameraPreviewFragment.java index 1290eea..d6b8464 100644 --- a/src/android/CameraPreviewFragment.java +++ b/src/android/CameraPreviewFragment.java @@ -1,7 +1,10 @@ package com.spoon.simplecamerapreview; +import android.Manifest; import android.annotation.SuppressLint; +import android.content.ContentValues; import android.content.Context; +import android.content.pm.PackageManager; import android.content.res.Configuration; import android.graphics.Point; import android.location.Location; From 8c139a517807c6268f0cd2968aadf5d49e01600c Mon Sep 17 00:00:00 2001 From: YushraJewon Date: Fri, 22 Mar 2024 11:49:50 +0400 Subject: [PATCH 03/13] add camera-video in plugin xml --- plugin.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/plugin.xml b/plugin.xml index 6d78762..b843342 100644 --- a/plugin.xml +++ b/plugin.xml @@ -19,6 +19,7 @@ + From 3aa4f2f5cf3e66831d36c21795c0befe64f7080b Mon Sep 17 00:00:00 2001 From: YushraJewon Date: Fri, 22 Mar 2024 11:58:00 +0400 Subject: [PATCH 04/13] remove space --- plugin.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugin.xml b/plugin.xml index b843342..9678fc6 100644 --- a/plugin.xml +++ b/plugin.xml @@ -19,7 +19,7 @@ - + From ddcce2159a6b7fde68926da5e69ef9e0f562a742 Mon Sep 17 00:00:00 2001 From: YushraJewon Date: Wed, 3 Apr 2024 11:45:20 +0400 Subject: [PATCH 05/13] setQuality lowest and remove toast --- src/android/CameraPreviewFragment.java | 41 +------------------------- 1 file changed, 1 insertion(+), 40 deletions(-) diff --git a/src/android/CameraPreviewFragment.java b/src/android/CameraPreviewFragment.java index d6b8464..aff5d0a 100644 --- a/src/android/CameraPreviewFragment.java +++ b/src/android/CameraPreviewFragment.java @@ -19,7 +19,6 @@ import android.view.ViewGroup; import android.view.WindowManager; import android.widget.RelativeLayout; -import android.widget.Toast; import androidx.annotation.NonNull; import androidx.annotation.Nullable; @@ -126,38 +125,6 @@ public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup c } -// public void startCamera() { -// ListenableFuture cameraProviderFuture = ProcessCameraProvider.getInstance(getActivity()); -// cameraProviderFuture.addListener(() -> { -// try { -// // Used to bind the lifecycle of cameras to the lifecycle owner -// ProcessCameraProvider cameraProvider = cameraProviderFuture.get(); -// -// Recorder recorder = new Recorder.Builder() -// .setQualitySelector(QualitySelector.from(Quality.HIGHEST)) -// .build(); -// videoCapture = VideoCapture.withOutput(recorder); -// imageCapture = new ImageCapture.Builder().build(); -// -// // Select back camera as a default -// CameraSelector cameraSelector = CameraSelector.DEFAULT_BACK_CAMERA; -// try { -// // Unbind use cases before rebinding -// cameraProvider.unbindAll(); -// // Bind use cases to camera -// cameraProvider.bindToLifecycle( -// this, cameraSelector, preview, imageCapture, videoCapture); -// } catch (Exception exc) { -// Log.e(TAG, "Use case binding failed", exc); -// } -// } catch (Exception e) { -// e.printStackTrace(); -// } -// }, ContextCompat.getMainExecutor(this.getContext())); -// if (startCameraCallback != null) { -// startCameraCallback.onCameraStarted(null); -// } -// } public void startCamera() { ListenableFuture cameraProviderFuture = ProcessCameraProvider.getInstance(getActivity()); @@ -180,7 +147,7 @@ public void startCamera() { } Recorder recorder = new Recorder.Builder() - .setQualitySelector(QualitySelector.from(Quality.HD)) + .setQualitySelector(QualitySelector.from(Quality.LOWEST)) .build(); videoCapture = VideoCapture.withOutput(recorder); @@ -304,8 +271,6 @@ public void captureVideo(boolean useFlash, VideoCallback videoCallback) { camera.getCameraControl().enableTorch(useFlash); } if (recording != null) { - Toast.makeText(this.getContext(), "Video not null" , Toast.LENGTH_LONG).show(); - recording.stop(); return; } @@ -332,10 +297,7 @@ public void captureVideo(boolean useFlash, VideoCallback videoCallback) { .start(ContextCompat.getMainExecutor(this.getContext()), videoRecordEvent -> { if (videoRecordEvent instanceof VideoRecordEvent.Start) { videoCallback.onStart(null,true, null); - Toast.makeText(this.getContext(), "Video start" , Toast.LENGTH_LONG).show(); - } else if (videoRecordEvent instanceof VideoRecordEvent.Finalize) { - Toast.makeText(this.getContext(), "Video fin" , Toast.LENGTH_LONG).show(); VideoRecordEvent.Finalize finalizeEvent = (VideoRecordEvent.Finalize) videoRecordEvent; if (finalizeEvent.hasError()) { // Handle the error @@ -347,7 +309,6 @@ public void captureVideo(boolean useFlash, VideoCallback videoCallback) { videoCallback.onStop(null, false, Uri.fromFile(videoFile).toString()); Uri savedUri = finalizeEvent.getOutputResults().getOutputUri(); Log.d(TAG, "Video saved to: " + savedUri); - Toast.makeText(this.getContext(), "Video stop" + savedUri, Toast.LENGTH_LONG).show(); recording = null; } } From 7ce1e7abf304f153713e6ae1d48773e0f23ae82b Mon Sep 17 00:00:00 2001 From: YushraJewon Date: Fri, 24 May 2024 09:12:11 +0400 Subject: [PATCH 06/13] indentation and suggestions --- src/android/CameraPreviewFragment.java | 17 ++++++----------- src/android/SimpleCameraPreview.java | 2 +- 2 files changed, 7 insertions(+), 12 deletions(-) diff --git a/src/android/CameraPreviewFragment.java b/src/android/CameraPreviewFragment.java index 8d6bc76..4ab8d70 100644 --- a/src/android/CameraPreviewFragment.java +++ b/src/android/CameraPreviewFragment.java @@ -34,7 +34,6 @@ import androidx.camera.core.Preview; import androidx.camera.lifecycle.ProcessCameraProvider; import androidx.camera.video.FileOutputOptions; -import androidx.camera.video.MediaStoreOutputOptions; import androidx.camera.video.Quality; import androidx.camera.video.QualitySelector; import androidx.camera.video.Recorder; @@ -142,7 +141,6 @@ public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup c viewFinder.setLayoutParams(new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT, RelativeLayout.LayoutParams.MATCH_PARENT)); containerView.addView(viewFinder); startCamera(); - return containerView; } @@ -204,7 +202,6 @@ public void startCamera() { }); setUpCamera(captureDevice,cameraProvider); - preview.setSurfaceProvider(viewFinder.getSurfaceProvider()); if (startCameraCallback != null) { @@ -326,11 +323,11 @@ public void hasFlash(HasFlashCallback hasFlashCallback) { } public void captureVideo(boolean useFlash, VideoCallback videoCallback) { - if (torchActivated) { - useFlash = true; - } else { - camera.getCameraControl().enableTorch(useFlash); - } + if (torchActivated) { + useFlash = true; + } else { + camera.getCameraControl().enableTorch(useFlash); + } if (recording != null) { recording.stop(); return; @@ -340,7 +337,6 @@ public void captureVideo(boolean useFlash, VideoCallback videoCallback) { String filename = uuid.toString() + ".mp4"; ContentValues contentValues = new ContentValues(); contentValues.put(MediaStore.Video.Media.DISPLAY_NAME, filename); -// 2. Configure Recorder and Start recording to the mediaStoreOutput. if (ActivityCompat.checkSelfPermission(this.getContext(), Manifest.permission.RECORD_AUDIO) != PackageManager.PERMISSION_GRANTED) { ActivityCompat.requestPermissions(this.getActivity(), new String[]{Manifest.permission.RECORD_AUDIO}, 200); } @@ -349,7 +345,6 @@ public void captureVideo(boolean useFlash, VideoCallback videoCallback) { filename ); -// Configure the recorder to save the video to the specified file FileOutputOptions outputOptions = new FileOutputOptions.Builder(videoFile).build(); recording = videoCapture.getOutput() @@ -357,7 +352,7 @@ public void captureVideo(boolean useFlash, VideoCallback videoCallback) { .withAudioEnabled() .start(ContextCompat.getMainExecutor(this.getContext()), videoRecordEvent -> { if (videoRecordEvent instanceof VideoRecordEvent.Start) { - videoCallback.onStart(null,true, null); + videoCallback.onStart(null, true, null); } else if (videoRecordEvent instanceof VideoRecordEvent.Finalize) { VideoRecordEvent.Finalize finalizeEvent = (VideoRecordEvent.Finalize) videoRecordEvent; if (finalizeEvent.hasError()) { diff --git a/src/android/SimpleCameraPreview.java b/src/android/SimpleCameraPreview.java index d522a84..222b3c2 100644 --- a/src/android/SimpleCameraPreview.java +++ b/src/android/SimpleCameraPreview.java @@ -276,7 +276,7 @@ private boolean captureVideo(boolean useFlash, CallbackContext callbackContext) return true; } - fragment.captureVideo( useFlash, new VideoCallback() { + fragment.captureVideo(useFlash, new VideoCallback() { public void onStart(Exception err, Boolean recording, String nativePath) { JSONObject data = new JSONObject(); if (recording) { From d87739f6341875544bb33c99437d23eca4a3a12f Mon Sep 17 00:00:00 2001 From: YushraJewon Date: Mon, 27 May 2024 15:57:25 +0400 Subject: [PATCH 07/13] resolve conflict move videoRecorder setup in setUp camera --- src/android/CameraPreviewFragment.java | 94 ++++++++------------------ 1 file changed, 28 insertions(+), 66 deletions(-) diff --git a/src/android/CameraPreviewFragment.java b/src/android/CameraPreviewFragment.java index 4ab8d70..55164e5 100644 --- a/src/android/CameraPreviewFragment.java +++ b/src/android/CameraPreviewFragment.java @@ -157,50 +157,6 @@ public void startCamera() { return; } - CameraSelector cameraSelector = new CameraSelector.Builder() - .requireLensFacing(direction) - .build(); - - Size targetResolution = null; - if (targetSize > 0) { - targetResolution = CameraPreviewFragment.calculateResolution(getContext(), targetSize); - } - - Recorder recorder = new Recorder.Builder() - .setQualitySelector(QualitySelector.from(Quality.LOWEST)) - .build(); - videoCapture = VideoCapture.withOutput(recorder); - - - preview = new Preview.Builder().build(); - imageCapture = new ImageCapture.Builder() - .setTargetResolution(targetResolution) - .build(); - this.getActivity().runOnUiThread(() -> { - try { - cameraProvider.unbindAll(); - camera = cameraProvider.bindToLifecycle( - this, - cameraSelector, - preview, - imageCapture, - videoCapture - ); - } catch (IllegalArgumentException e) { - // Error with result in capturing image with default resolution - e.printStackTrace(); - imageCapture = new ImageCapture.Builder() - .build(); - camera = cameraProvider.bindToLifecycle( - this, - cameraSelector, - preview, - imageCapture, - videoCapture - ); - } - - }); setUpCamera(captureDevice,cameraProvider); preview.setSurfaceProvider(viewFinder.getSurfaceProvider()); @@ -515,31 +471,37 @@ public void setUpCamera(String captureDevice, ProcessCameraProvider cameraProvid targetResolution = CameraPreviewFragment.calculateResolution(getContext(), targetSize); } + Recorder recorder = new Recorder.Builder() + .setQualitySelector(QualitySelector.from(Quality.LOWEST)) + .build(); + videoCapture = VideoCapture.withOutput(recorder); + + preview = new Preview.Builder().build(); imageCapture = new ImageCapture.Builder() .setTargetResolution(targetResolution) .build(); - - cameraProvider.unbindAll(); - try { - camera = cameraProvider.bindToLifecycle( - getActivity(), - cameraSelector, - preview, - imageCapture - ); - } catch (IllegalArgumentException e) { - // Error with result in capturing image with default resolution - e.printStackTrace(); - imageCapture = new ImageCapture.Builder() - .build(); - camera = cameraProvider.bindToLifecycle( - getActivity(), - cameraSelector, - preview, - imageCapture - ); - } - + cameraProvider.unbindAll(); + try { + camera = cameraProvider.bindToLifecycle( + getActivity(), + cameraSelector, + preview, + imageCapture, + videoCapture + ); + } catch (IllegalArgumentException e) { + // Error with result in capturing image with default resolution + e.printStackTrace(); + imageCapture = new ImageCapture.Builder() + .build(); + camera = cameraProvider.bindToLifecycle( + getActivity(), + cameraSelector, + preview, + imageCapture, + videoCapture + ); + } } } From 03d77e988ce2fbd3ab0a07b761c511aa398fdf77 Mon Sep 17 00:00:00 2001 From: YushraJewon Date: Mon, 27 May 2024 16:03:50 +0400 Subject: [PATCH 08/13] indent --- src/android/CameraPreviewFragment.java | 45 +++++++++++++------------- 1 file changed, 22 insertions(+), 23 deletions(-) diff --git a/src/android/CameraPreviewFragment.java b/src/android/CameraPreviewFragment.java index 55164e5..52bbdb2 100644 --- a/src/android/CameraPreviewFragment.java +++ b/src/android/CameraPreviewFragment.java @@ -144,7 +144,6 @@ public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup c return containerView; } - public void startCamera() { ListenableFuture cameraProviderFuture = ProcessCameraProvider.getInstance(getActivity()); @@ -481,27 +480,27 @@ public void setUpCamera(String captureDevice, ProcessCameraProvider cameraProvid imageCapture = new ImageCapture.Builder() .setTargetResolution(targetResolution) .build(); - cameraProvider.unbindAll(); - try { - camera = cameraProvider.bindToLifecycle( - getActivity(), - cameraSelector, - preview, - imageCapture, - videoCapture - ); - } catch (IllegalArgumentException e) { - // Error with result in capturing image with default resolution - e.printStackTrace(); - imageCapture = new ImageCapture.Builder() - .build(); - camera = cameraProvider.bindToLifecycle( - getActivity(), - cameraSelector, - preview, - imageCapture, - videoCapture - ); - } + cameraProvider.unbindAll(); + try { + camera = cameraProvider.bindToLifecycle( + getActivity(), + cameraSelector, + preview, + imageCapture, + videoCapture + ); + } catch (IllegalArgumentException e) { + // Error with result in capturing image with default resolution + e.printStackTrace(); + imageCapture = new ImageCapture.Builder() + .build(); + camera = cameraProvider.bindToLifecycle( + getActivity(), + cameraSelector, + preview, + imageCapture, + videoCapture + ); + } } } From b891b4ce63f59eed8ece82397a955723025b36ed Mon Sep 17 00:00:00 2001 From: YushraJewon Date: Tue, 28 May 2024 15:04:33 +0400 Subject: [PATCH 09/13] remove exception err from videoCallback and remove torch from videoCapture --- src/android/CameraPreviewFragment.java | 17 ++++++----------- src/android/SimpleCameraPreview.java | 10 +++++----- 2 files changed, 11 insertions(+), 16 deletions(-) diff --git a/src/android/CameraPreviewFragment.java b/src/android/CameraPreviewFragment.java index 52bbdb2..0ee6dea 100644 --- a/src/android/CameraPreviewFragment.java +++ b/src/android/CameraPreviewFragment.java @@ -65,8 +65,8 @@ interface CameraCallback { } interface VideoCallback { - void onStart(Exception err,Boolean recording, String nativePath); - void onStop(Exception err, Boolean recording, String nativePath); + void onStart(Boolean recording, String nativePath); + void onStop(Boolean recording, String nativePath); } interface CameraStartedCallback { @@ -277,12 +277,7 @@ public void hasFlash(HasFlashCallback hasFlashCallback) { hasFlashCallback.onResult(camera.getCameraInfo().hasFlashUnit()); } - public void captureVideo(boolean useFlash, VideoCallback videoCallback) { - if (torchActivated) { - useFlash = true; - } else { - camera.getCameraControl().enableTorch(useFlash); - } + public void captureVideo(VideoCallback videoCallback) { if (recording != null) { recording.stop(); return; @@ -307,7 +302,7 @@ public void captureVideo(boolean useFlash, VideoCallback videoCallback) { .withAudioEnabled() .start(ContextCompat.getMainExecutor(this.getContext()), videoRecordEvent -> { if (videoRecordEvent instanceof VideoRecordEvent.Start) { - videoCallback.onStart(null, true, null); + videoCallback.onStart(true, null); } else if (videoRecordEvent instanceof VideoRecordEvent.Finalize) { VideoRecordEvent.Finalize finalizeEvent = (VideoRecordEvent.Finalize) videoRecordEvent; if (finalizeEvent.hasError()) { @@ -317,9 +312,9 @@ public void captureVideo(boolean useFlash, VideoCallback videoCallback) { Log.e(TAG, "Video recording error: " + errorCode, errorCause); } else { // Handle video saved - videoCallback.onStop(null, false, Uri.fromFile(videoFile).toString()); + videoCallback.onStop(false, Uri.fromFile(videoFile).toString()); Uri savedUri = finalizeEvent.getOutputResults().getOutputUri(); - Log.d(TAG, "Video saved to: " + savedUri); + Log.i(TAG, "Video saved to: " + savedUri); recording = null; } } diff --git a/src/android/SimpleCameraPreview.java b/src/android/SimpleCameraPreview.java index 222b3c2..93fd242 100644 --- a/src/android/SimpleCameraPreview.java +++ b/src/android/SimpleCameraPreview.java @@ -73,7 +73,7 @@ public boolean execute(String action, JSONArray args, CallbackContext callbackCo return torchSwitch(args.getBoolean(0), callbackContext); case "captureVideo": - return captureVideo(args.getBoolean(0), callbackContext); + return captureVideo(callbackContext); case "deviceHasFlash": return deviceHasFlash(callbackContext); @@ -270,14 +270,14 @@ public void fetchLocation() { } } - private boolean captureVideo(boolean useFlash, CallbackContext callbackContext) { + private boolean captureVideo(CallbackContext callbackContext) { if (fragment == null) { callbackContext.error("Camera is closed"); return true; } - fragment.captureVideo(useFlash, new VideoCallback() { - public void onStart(Exception err, Boolean recording, String nativePath) { + fragment.captureVideo(new VideoCallback() { + public void onStart(Boolean recording, String nativePath) { JSONObject data = new JSONObject(); if (recording) { try { @@ -295,7 +295,7 @@ public void onStart(Exception err, Boolean recording, String nativePath) { } } - public void onStop(Exception err, Boolean started, String nativePath) { + public void onStop(Boolean recording, String nativePath) { JSONObject data = new JSONObject(); try { data.put("recording", false); From 029c815d9209f3432bb838ecacdf1e12f92452ce Mon Sep 17 00:00:00 2001 From: YushraJewon Date: Tue, 28 May 2024 15:41:55 +0400 Subject: [PATCH 10/13] remove flash from js options --- www/SimpleCameraPreview.js | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/www/SimpleCameraPreview.js b/www/SimpleCameraPreview.js index 47506fc..51bf38c 100755 --- a/www/SimpleCameraPreview.js +++ b/www/SimpleCameraPreview.js @@ -20,10 +20,8 @@ SimpleCameraPreview.capture = function (options, onSuccess, onError) { exec(onSuccess, onError, PLUGIN_NAME, "capture", [options.flash]); }; -SimpleCameraPreview.captureVideo = function (options, onSuccess, onError) { - options = options || {}; - options.flash = options.flash || false; - exec(onSuccess, onError, PLUGIN_NAME, "captureVideo", [options.flash]); +SimpleCameraPreview.captureVideo = function (onSuccess, onError) { + exec(onSuccess, onError, PLUGIN_NAME, "captureVideo"); }; SimpleCameraPreview.setSize = function (options, onSuccess, onError) { From 041a975487281735fac4b4596b4bc71d6f2bdf45 Mon Sep 17 00:00:00 2001 From: YushraJewon Date: Thu, 30 May 2024 14:01:50 +0400 Subject: [PATCH 11/13] remove unused codes and set recording null after recording --- src/android/CameraPreviewFragment.java | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/android/CameraPreviewFragment.java b/src/android/CameraPreviewFragment.java index 0ee6dea..f7a504e 100644 --- a/src/android/CameraPreviewFragment.java +++ b/src/android/CameraPreviewFragment.java @@ -280,18 +280,17 @@ public void hasFlash(HasFlashCallback hasFlashCallback) { public void captureVideo(VideoCallback videoCallback) { if (recording != null) { recording.stop(); + recording = null; return; } UUID uuid = UUID.randomUUID(); String filename = uuid.toString() + ".mp4"; - ContentValues contentValues = new ContentValues(); - contentValues.put(MediaStore.Video.Media.DISPLAY_NAME, filename); if (ActivityCompat.checkSelfPermission(this.getContext(), Manifest.permission.RECORD_AUDIO) != PackageManager.PERMISSION_GRANTED) { ActivityCompat.requestPermissions(this.getActivity(), new String[]{Manifest.permission.RECORD_AUDIO}, 200); } File videoFile = new File( - getContext().getApplicationContext().getFilesDir(), + getContext().getFilesDir(), filename ); @@ -315,8 +314,8 @@ public void captureVideo(VideoCallback videoCallback) { videoCallback.onStop(false, Uri.fromFile(videoFile).toString()); Uri savedUri = finalizeEvent.getOutputResults().getOutputUri(); Log.i(TAG, "Video saved to: " + savedUri); - recording = null; } + recording = null; } // Other event types can be handled if needed }); From dd388f1b1e4ecd9b76f85c35dd0c6593060bdaf2 Mon Sep 17 00:00:00 2001 From: dinitri Date: Tue, 4 Jun 2024 17:47:23 +0400 Subject: [PATCH 12/13] stop video method --- www/SimpleCameraPreview.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/www/SimpleCameraPreview.js b/www/SimpleCameraPreview.js index 51bf38c..9d4333f 100755 --- a/www/SimpleCameraPreview.js +++ b/www/SimpleCameraPreview.js @@ -24,6 +24,10 @@ SimpleCameraPreview.captureVideo = function (onSuccess, onError) { exec(onSuccess, onError, PLUGIN_NAME, "captureVideo"); }; +SimpleCameraPreview.stopCaptureVideo = function (onSuccess, onError) { + exec(onSuccess, onError, PLUGIN_NAME, "stopCaptureVideo"); +}; + SimpleCameraPreview.setSize = function (options, onSuccess, onError) { exec(onSuccess, onError, PLUGIN_NAME, "setSize", [options]); }; From 80f6d7d109d3094cc3ed5726f44e84183530f190 Mon Sep 17 00:00:00 2001 From: dinitri Date: Tue, 4 Jun 2024 18:45:25 +0400 Subject: [PATCH 13/13] start stop test --- src/android/CameraPreviewFragment.java | 7 +++++++ src/android/SimpleCameraPreview.java | 26 ++++++++++++++++++++++++-- 2 files changed, 31 insertions(+), 2 deletions(-) diff --git a/src/android/CameraPreviewFragment.java b/src/android/CameraPreviewFragment.java index f7a504e..bd34780 100644 --- a/src/android/CameraPreviewFragment.java +++ b/src/android/CameraPreviewFragment.java @@ -277,6 +277,13 @@ public void hasFlash(HasFlashCallback hasFlashCallback) { hasFlashCallback.onResult(camera.getCameraInfo().hasFlashUnit()); } + public void stopCaptureVideo() { + if (recording != null) { + recording.stop(); + recording = null; + } + } + public void captureVideo(VideoCallback videoCallback) { if (recording != null) { recording.stop(); diff --git a/src/android/SimpleCameraPreview.java b/src/android/SimpleCameraPreview.java index 93fd242..8d3c87c 100644 --- a/src/android/SimpleCameraPreview.java +++ b/src/android/SimpleCameraPreview.java @@ -43,12 +43,15 @@ public class SimpleCameraPreview extends CordovaPlugin { private LocationListener mLocationCallback; private ViewParent webViewParent; + private CallbackContext videoCallback; + private static final int containerViewId = 20; private static final int DIRECTION_FRONT = 0; private static final int DIRECTION_BACK = 1; private static final int REQUEST_CODE_PERMISSIONS = 4582679; private static final String[] REQUIRED_PERMISSIONS = {Manifest.permission.CAMERA, Manifest.permission.ACCESS_FINE_LOCATION}; + public SimpleCameraPreview() { super(); } @@ -75,6 +78,10 @@ public boolean execute(String action, JSONArray args, CallbackContext callbackCo case "captureVideo": return captureVideo(callbackContext); + case "stopCaptureVideo": + this.videoStopCallback = callbackContext; + return stopCaptureVideo(callbackContext); + case "deviceHasFlash": return deviceHasFlash(callbackContext); @@ -270,6 +277,16 @@ public void fetchLocation() { } } + CallbackContext videoStopCallback; + + private boolean stopCaptureVideo(CallbackContext callbackContext) { + if (fragment == null) { + callbackContext.error("Camera is closed"); + return true; + } + fragment.stopCaptureVideo(); + return true; + } private boolean captureVideo(CallbackContext callbackContext) { if (fragment == null) { callbackContext.error("Camera is closed"); @@ -290,7 +307,7 @@ public void onStart(Boolean recording, String nativePath) { } PluginResult pluginResult = new PluginResult(PluginResult.Status.OK, data); - pluginResult.setKeepCallback(true); +// pluginResult.setKeepCallback(true); callbackContext.sendPluginResult(pluginResult); } } @@ -306,7 +323,12 @@ public void onStop(Boolean recording, String nativePath) { return; } PluginResult pluginResult = new PluginResult(PluginResult.Status.OK, data); - pluginResult.setKeepCallback(true); +// pluginResult.setKeepCallback(true); + if (videoStopCallback != null) { + videoStopCallback.sendPluginResult(pluginResult); + videoStopCallback = null; + return; + } callbackContext.sendPluginResult(pluginResult); } });