diff --git a/app/build.gradle b/app/build.gradle
index f8d81e8..876447d 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -11,7 +11,7 @@ android {
minSdk 26
targetSdk 33
versionCode 1
- versionName "1.0"
+ versionName "1.0.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
diff --git a/app/src/main/java/com/polar/mirror/FreezeController.java b/app/src/main/java/com/polar/mirror/FreezeController.java
new file mode 100644
index 0000000..36457b7
--- /dev/null
+++ b/app/src/main/java/com/polar/mirror/FreezeController.java
@@ -0,0 +1,124 @@
+package com.polar.mirror;
+
+import static androidx.core.content.ContextCompat.getMainExecutor;
+
+import android.annotation.SuppressLint;
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.graphics.Camera;
+import android.graphics.ImageFormat;
+import android.graphics.Matrix;
+import android.media.Image;
+import android.util.Log;
+import android.view.View;
+import android.widget.ImageView;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.OptIn;
+import androidx.camera.core.CameraSelector;
+import androidx.camera.core.ExperimentalGetImage;
+import androidx.camera.core.ImageCapture;
+import androidx.camera.core.ImageCaptureException;
+import androidx.camera.core.ImageProxy;
+import androidx.camera.lifecycle.ProcessCameraProvider;
+import androidx.camera.view.PreviewView;
+import androidx.lifecycle.LifecycleOwner;
+
+import com.google.android.material.floatingactionbutton.FloatingActionButton;
+
+import java.io.File;
+import java.nio.ByteBuffer;
+
+/**
+ * Controls freezing camera view
+ */
+public class FreezeController {
+ private static final String TAG = "FreezeController";
+ private final FloatingActionButton mFreezeButton;
+ private final PreviewView mCameraView;
+ private final ImageView mFreezeView;
+ private final ImageCapture mImageCapture;
+ private final Context mContext;
+ private boolean mCameraFrozen = false;
+
+ FreezeController(Context context, FloatingActionButton freezeButton, PreviewView cameraView,
+ ImageView freezeView){
+ mFreezeButton = freezeButton;
+ mCameraView = cameraView;
+ mFreezeView = freezeView;
+ mContext = context;
+ mImageCapture = new ImageCapture.Builder()
+ .setCaptureMode(ImageCapture.CAPTURE_MODE_MINIMIZE_LATENCY)
+ .build();
+ }
+
+ /**
+ * Should be called when camera is ready
+ * @param provider camera provider
+ * @param lcOwner lifecycle owner used for binding camera usecases
+ */
+ public void onCameraInitialized(ProcessCameraProvider provider, LifecycleOwner lcOwner){
+ CameraSelector cameraSelector = new CameraSelector.Builder()
+ .requireLensFacing(CameraSelector.LENS_FACING_FRONT)
+ .build();
+ provider.bindToLifecycle(lcOwner, cameraSelector, mImageCapture);
+ Log.d(TAG, "completed onCameraInitialized");
+ }
+
+
+ private void setFrozenImage(){
+ mImageCapture.takePicture(getMainExecutor(mContext),
+ new ImageCapture.OnImageCapturedCallback() {
+
+ @Override
+ @SuppressLint("UnsafeOptInUsageError")
+ public void onCaptureSuccess(@NonNull ImageProxy imageProxy){
+ Log.i(TAG, "Capture success");
+ Image image = imageProxy.getImage();
+ if(image == null){
+ Log.e(TAG, "Image is null");
+ return;
+ }
+ int format = image.getFormat();
+ if(format != ImageFormat.JPEG){
+ Log.e(TAG, "Expected JPEG format, got format " + format);
+ return;
+ }
+ ByteBuffer buffer = image.getPlanes()[0].getBuffer();
+ byte[] bytes = new byte[buffer.remaining()];
+ buffer.get(bytes);
+ Bitmap bitmap = BitmapFactory.decodeByteArray(bytes, 0, bytes.length);
+ Matrix matrix = new Matrix();
+ matrix.postRotate(270);
+ bitmap = Bitmap.createBitmap(
+ bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true
+ );
+ mFreezeView.setImageBitmap(bitmap);
+ imageProxy.close();
+ }
+
+ @Override
+ public void onError(@NonNull ImageCaptureException exception) {
+ Log.e(TAG, "Can not capture image");
+ exception.printStackTrace();
+ }
+ });
+ }
+
+ /**
+ * Toggles camera freeze
+ */
+ public void toggleFreeze(){
+ if(mCameraFrozen){
+ mFreezeView.setVisibility(View.GONE);
+ mCameraView.setVisibility(View.VISIBLE);
+ mCameraFrozen = false;
+ } else {
+ setFrozenImage();
+ mCameraView.setVisibility(View.GONE);
+ mFreezeView.setVisibility(View.VISIBLE);
+ mCameraFrozen = true;
+ }
+ }
+}
diff --git a/app/src/main/java/com/polar/mirror/MainActivity.java b/app/src/main/java/com/polar/mirror/MainActivity.java
index deefb7c..753a8ca 100644
--- a/app/src/main/java/com/polar/mirror/MainActivity.java
+++ b/app/src/main/java/com/polar/mirror/MainActivity.java
@@ -12,6 +12,7 @@
import android.os.Bundle;
import android.util.Log;
import android.view.View;
+import android.widget.ImageView;
import com.google.android.material.floatingactionbutton.FloatingActionButton;
@@ -19,7 +20,7 @@
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
private PreviewView mCameraView;
- private boolean mCameraFrozen = false;
+ private FreezeController mFreezeController;
private final static String TAG = "MainActivity";
@Override
@@ -30,6 +31,14 @@ protected void onCreate(Bundle savedInstanceState) {
setupView();
mCameraView = findViewById(R.id.preview_view);
+
+ //Initialize freeze controller
+ FloatingActionButton freezeButton = findViewById(R.id.freeze_button);
+ ImageView freezeView = findViewById(R.id.stop_view);
+ mFreezeController = new FreezeController(this, freezeButton, mCameraView,
+ freezeView);
+
+ //Start camera
try {
startCamera();
} catch (ExecutionException | InterruptedException e) {
@@ -94,6 +103,7 @@ private void startCamera() throws ExecutionException, InterruptedException {
.build();
cameraProvider.unbindAll();
cameraProvider.bindToLifecycle((LifecycleOwner)this, cameraSelector, preview);
+ mFreezeController.onCameraInitialized(cameraProvider, (LifecycleOwner)this);
} catch (Exception e) {
e.printStackTrace();
}
@@ -103,13 +113,7 @@ private void startCamera() throws ExecutionException, InterruptedException {
* Toggles camera freeze mode
*/
private void toggleCameraFreeze(){
- if(!mCameraFrozen) {
- mCameraView.setVisibility(View.GONE);
- mCameraFrozen = true;
- } else {
- mCameraView.setVisibility(View.VISIBLE);
- mCameraFrozen = false;
- }
+ mFreezeController.toggleFreeze();
}
@Override
diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml
index 89b852a..ad4c076 100644
--- a/app/src/main/res/layout/activity_main.xml
+++ b/app/src/main/res/layout/activity_main.xml
@@ -4,6 +4,7 @@
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
+ android:keepScreenOn="true"
tools:context=".MainActivity">
+
+
\ No newline at end of file
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 7fe75d2..cb0e2f5 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -2,4 +2,5 @@
Mirror
Exit app
Freeze
+ Image displaying stop-frame
\ No newline at end of file