From f239591d4e4997629cdd29ab61ec87ee5d76fb59 Mon Sep 17 00:00:00 2001 From: Andrewerr Date: Wed, 25 Oct 2023 17:54:20 +0200 Subject: [PATCH] Keep screen awake,WIP: freeze stream --- app/build.gradle | 2 +- .../com/polar/mirror/FreezeController.java | 124 ++++++++++++++++++ .../java/com/polar/mirror/MainActivity.java | 20 +-- app/src/main/res/layout/activity_main.xml | 8 ++ app/src/main/res/values/strings.xml | 1 + 5 files changed, 146 insertions(+), 9 deletions(-) create mode 100644 app/src/main/java/com/polar/mirror/FreezeController.java 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