diff --git a/app/build.gradle b/app/build.gradle index b277167..9596aff 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -48,4 +48,5 @@ dependencies { testImplementation libs.junit androidTestImplementation libs.ext.junit androidTestImplementation libs.espresso.core + testImplementation libs.robolectric } \ No newline at end of file diff --git a/app/src/main/java/com/example/cameraxtestappjava/segpass/SegpassCamera.java b/app/src/main/java/com/example/cameraxtestappjava/segpass/SegpassCamera.java index d7afda0..9f8f8dd 100644 --- a/app/src/main/java/com/example/cameraxtestappjava/segpass/SegpassCamera.java +++ b/app/src/main/java/com/example/cameraxtestappjava/segpass/SegpassCamera.java @@ -3,7 +3,6 @@ package com.example.cameraxtestappjava.segpass; import android.Manifest; import android.app.Activity; import android.content.Context; -import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.content.res.Configuration; import android.graphics.ImageFormat; @@ -22,7 +21,6 @@ import android.hardware.camera2.TotalCaptureResult; import android.hardware.camera2.params.StreamConfigurationMap; import android.media.Image; import android.media.ImageReader; -import android.os.Environment; import android.os.Handler; import android.os.HandlerThread; import android.util.Log; @@ -45,7 +43,6 @@ import com.example.cameraxtestappjava.segpass.camera.utils.SegpassCameraCallback import com.example.cameraxtestappjava.segpass.camera.utils.SegpassPermissionListener; import com.example.cameraxtestappjava.segpass.camera.view.AutoFitTextureView; -import java.io.File; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; @@ -135,21 +132,18 @@ public class SegpassCamera { */ private ImageReader mImageReader; - /** - * This is the folder where the pictures will be saved. - */ - private File mFileFolder; + private ImageReader mCaptureImageReader; /** * This is the resulting image encoded to Base64 */ private String mBase64Value; - private final CaptureRequest.Key mCaptureAfModeKey = CaptureRequest.CONTROL_AF_MODE; - private final int mCaptureAfModeValue = CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE; + private static final CaptureRequest.Key mCaptureAfModeKey = CaptureRequest.CONTROL_AF_MODE; + private static final int mCaptureAfModeValue = CameraMetadata.CONTROL_AF_MODE_CONTINUOUS_PICTURE; - private final CaptureRequest.Key mCaptureAfTriggerKey = CaptureRequest.CONTROL_AF_TRIGGER; - private final int mCaptureAfTriggervalue = CaptureRequest.CONTROL_AF_TRIGGER_START; + private static final CaptureRequest.Key mCaptureAfTriggerKey = CaptureRequest.CONTROL_AF_TRIGGER; + private static final int mCaptureAfTriggerValue = CameraMetadata.CONTROL_AF_TRIGGER_START; /** * {@link CaptureRequest.Builder} for the camera preview @@ -454,7 +448,7 @@ public class SegpassCamera { // If facis is null, return if (facing == null) return null; - if (facing == CameraCharacteristics.LENS_FACING_BACK) return null; + if (facing == CameraMetadata.LENS_FACING_BACK) return null; return characteristics.get( CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP); @@ -598,7 +592,7 @@ public class SegpassCamera { // Auto focus should be continuous for camera preview. mPreviewRequestBuilder.set(mCaptureAfModeKey, mCaptureAfModeValue); // Trigger AF - mPreviewRequestBuilder.set(mCaptureAfTriggerKey, mCaptureAfTriggervalue); + mPreviewRequestBuilder.set(mCaptureAfTriggerKey, mCaptureAfTriggerValue); // Finally, we start displaying the camera preview. mPreviewRequest = mPreviewRequestBuilder.build(); @@ -648,7 +642,7 @@ public class SegpassCamera { (float) viewHeight / mPreviewSize.getHeight(), (float) viewWidth / mPreviewSize.getWidth()); matrix.postScale(scale, scale, centerX, centerY); - matrix.postRotate(90 * (rotation - 2L), centerX, centerY); + matrix.postRotate(90L * (rotation - 2), centerX, centerY); } else if (Surface.ROTATION_180 == rotation) { matrix.postRotate(180, centerX, centerY); } @@ -683,23 +677,23 @@ public class SegpassCamera { } // Set a new instance of ImageReader - ImageReader mReader = ImageReader.newInstance(width, height, ImageFormat.JPEG, 1); + mCaptureImageReader = getCaptureImageReader(width, height); // Set the output surfaces (from where the picture is taken) List outputSurfaces = new ArrayList<>(2); - outputSurfaces.add(mReader.getSurface()); + outputSurfaces.add(mCaptureImageReader.getSurface()); outputSurfaces.add(new Surface(mTextureView.getSurfaceTexture())); // Create the CaptiureBuilder final CaptureRequest.Builder captureBuilder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE); - captureBuilder.addTarget(mReader.getSurface()); + captureBuilder.addTarget(mCaptureImageReader.getSurface()); captureBuilder.set(CaptureRequest.CONTROL_MODE, CameraMetadata.CONTROL_MODE_AUTO); // Picture orientation int rotation = mActivity.getWindowManager().getDefaultDisplay().getRotation(); captureBuilder.set(CaptureRequest.JPEG_ORIENTATION, getOrientation(rotation)); - mReader.setOnImageAvailableListener(mOnImageAvailableListener, mBackgroundHandler); + mCaptureImageReader.setOnImageAvailableListener(mOnImageAvailableListener, mBackgroundHandler); final CameraCaptureSession.CaptureCallback captureListener = new CameraCaptureSession.CaptureCallback() { @Override public void onCaptureCompleted(@NonNull CameraCaptureSession session, @NonNull CaptureRequest request, @NonNull TotalCaptureResult result) { @@ -712,6 +706,7 @@ public class SegpassCamera { mCameraCallback.onPictureTakenFailError("Error saving picture..."); } Log.d(TAG, "Recreating camera preview..."); + mCaptureImageReader.close(); createCameraPreviewSession(); } }; @@ -729,6 +724,7 @@ public class SegpassCamera { @Override public void onConfigureFailed(@NonNull CameraCaptureSession session) { + // No implementation needed here. } }, mBackgroundHandler); } catch (CameraAccessException e) { @@ -738,6 +734,11 @@ public class SegpassCamera { } + @NonNull + private static ImageReader getCaptureImageReader(int width, int height) { + return ImageReader.newInstance(width, height, ImageFormat.JPEG, 1); + } + private int getOrientation(int rotation) { // Sensor orientation is 90 for most devices, or 270 for some devices (eg. Nexus 5X) // We have to take that into account and rotate JPEG properly. diff --git a/app/src/main/java/com/example/cameraxtestappjava/segpass/camera/exceptions/SegpassCameraException.java b/app/src/main/java/com/example/cameraxtestappjava/segpass/camera/exceptions/SegpassCameraException.java index d180274..5f86b40 100644 --- a/app/src/main/java/com/example/cameraxtestappjava/segpass/camera/exceptions/SegpassCameraException.java +++ b/app/src/main/java/com/example/cameraxtestappjava/segpass/camera/exceptions/SegpassCameraException.java @@ -2,19 +2,11 @@ package com.example.cameraxtestappjava.segpass.camera.exceptions; public class SegpassCameraException extends RuntimeException { - // Optional: You can define a constructor with a message argument public SegpassCameraException(String message) { super(message); } - // Optional: You can define a constructor with a message and a cause (throwable) public SegpassCameraException(String message, Throwable cause) { super(message, cause); } - - // Optional: You can define custom methods specific to your exception - public String getCustomDetails() { - // ... Add logic to return additional details related to the exception - return "This is a custom detail"; - } } diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 4fb91f0..e923289 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -8,6 +8,7 @@ material = "1.12.0" activity = "1.8.0" constraintlayout = "2.1.4" camerax = "1.3.3" +robolectric = "4.8.1" [libraries] junit = { group = "junit", name = "junit", version.ref = "junit" } @@ -22,6 +23,7 @@ camera-camera2 = { group = "androidx.camera", name = "camera-camera2", version.r camera-lifecycle = { group = "androidx.camera", name = "camera-lifecycle", version.ref = "camerax"} camera-view = { group = "androidx.camera", name = "camera-view", version.ref = "camerax"} camera-extensions = { group = "androidx.camera", name = "camera-extensions", version.ref = "camerax"} +robolectric = { module = "org.robolectric:robolectric", version.ref = "robolectric" } [plugins] android-application = { id = "com.android.application", version.ref = "agp" }