diff --git a/Neues Textdokument.txt b/Neues Textdokument.txt
deleted file mode 100644
index e69de29..0000000
diff --git a/app/build.gradle b/app/build.gradle
index 1c98d76..4d7dcc8 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -3,11 +3,11 @@ plugins {
}
android {
- namespace 'de.oklein.android.ueberwachungssystem'
+ namespace 'com.example.ueberwachungssystem'
compileSdk 33
defaultConfig {
- applicationId "de.oklein.android.ueberwachungssystem"
+ applicationId "com.example.ueberwachungssystem"
minSdk 28
targetSdk 33
versionCode 1
@@ -31,10 +31,18 @@ android {
dependencies {
implementation 'androidx.appcompat:appcompat:1.6.1'
- implementation 'com.google.android.material:material:1.9.0'
+ implementation 'com.google.android.material:material:1.8.0'
implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
testImplementation 'junit:junit:4.13.2'
androidTestImplementation 'androidx.test.ext:junit:1.1.5'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1'
- implementation "androidx.startup:startup-runtime:1.1.1"
+
+ // Required for CameraX
+ def camerax_version = "1.2.2"
+ implementation "androidx.camera:camera-core:${camerax_version}"
+ implementation "androidx.camera:camera-camera2:${camerax_version}"
+ implementation "androidx.camera:camera-lifecycle:${camerax_version}"
+ implementation "androidx.camera:camera-video:${camerax_version}"
+ implementation "androidx.camera:camera-view:${camerax_version}"
+ implementation "androidx.camera:camera-extensions:${camerax_version}"
}
\ No newline at end of file
diff --git a/app/src/androidTest/java/com/example/ueberwachungssystem/ExampleInstrumentedTest.java b/app/src/androidTest/java/com/example/ueberwachungssystem/ExampleInstrumentedTest.java
new file mode 100644
index 0000000..9b83717
--- /dev/null
+++ b/app/src/androidTest/java/com/example/ueberwachungssystem/ExampleInstrumentedTest.java
@@ -0,0 +1,26 @@
+package com.example.ueberwachungssystem;
+
+import android.content.Context;
+
+import androidx.test.platform.app.InstrumentationRegistry;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import static org.junit.Assert.*;
+
+/**
+ * Instrumented test, which will execute on an Android device.
+ *
+ * @see Testing documentation
+ */
+@RunWith(AndroidJUnit4.class)
+public class ExampleInstrumentedTest {
+ @Test
+ public void useAppContext() {
+ // Context of the app under test.
+ Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
+ assertEquals("com.example.ueberwachungssystem", appContext.getPackageName());
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/ueberwachungssystem/Detection/DetectionReport.java b/app/src/main/java/com/example/ueberwachungssystem/Detection/DetectionReport.java
new file mode 100644
index 0000000..2dc8cba
--- /dev/null
+++ b/app/src/main/java/com/example/ueberwachungssystem/Detection/DetectionReport.java
@@ -0,0 +1,36 @@
+package com.example.ueberwachungssystem.Detection;
+
+import android.util.Log;
+
+import java.util.Calendar;
+
+/** Detection Report Class */
+public class DetectionReport {
+ public String timeStamp;
+ public String detectionType;
+ public float detectedValue;
+ public String detectorID;
+
+ public DetectionReport(String detectorID, String detectionType, float detectedAmplitude) {
+ this.timeStamp = String.valueOf(Calendar.getInstance().getTime());
+ this.detectionType = detectionType;
+ this.detectedValue = detectedAmplitude;
+ this.detectorID = detectorID;
+ }
+
+
+ /** Get Detection Report in String format */
+ public String toString() {
+ String time = "Time: " + "[" + this.timeStamp + "]";
+ String type = "Type: " + "[" + this.detectionType + "]";
+ String value = "Value: " + "[" + this.detectedValue + "]";
+ String id = "ID: " + "[" + this.detectorID + "]";
+
+ return String.join("\t", time, type, value, id);
+ }
+
+ /** Debug Report */
+ public void log(String tag) {
+ Log.d(tag, this.toString());
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/ueberwachungssystem/Detection/Detector.java b/app/src/main/java/com/example/ueberwachungssystem/Detection/Detector.java
new file mode 100644
index 0000000..0b726a7
--- /dev/null
+++ b/app/src/main/java/com/example/ueberwachungssystem/Detection/Detector.java
@@ -0,0 +1,38 @@
+package com.example.ueberwachungssystem.Detection;
+
+import androidx.annotation.NonNull;
+
+
+abstract public class Detector {
+ private OnDetectionListener listener;
+
+ /** Constructor - takes context of current activity */
+ public Detector() {}
+
+
+ /** On Detection Listener - runs when violation is reported */
+ public interface OnDetectionListener {
+ void onDetection(@NonNull DetectionReport detectionReport);
+ }
+ public void setOnDetectionListener(@NonNull OnDetectionListener listener) {
+ this.listener = listener;
+ }
+
+
+ /** Triggers onDetectionListener - call this to trigger violation/alarm */
+ public void reportViolation(String detectorID, String detectionType, float amplitude) {
+ if (listener != null) {
+ DetectionReport detectionReport = new DetectionReport(detectorID, detectionType, amplitude);
+ listener.onDetection(detectionReport);
+ } else {
+ throw new IllegalStateException("No listener set for violation reporting");
+ }
+ }
+
+
+ /** Starts Detection (abstract method: needs to be overridden in child class) */
+ public abstract void startDetection();
+
+ /** Stops Detection (abstract method: needs to be overridden in child class) */
+ public abstract void stopDetection();
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/ueberwachungssystem/Detection/VideoDetector.java b/app/src/main/java/com/example/ueberwachungssystem/Detection/VideoDetector.java
new file mode 100644
index 0000000..bfec02c
--- /dev/null
+++ b/app/src/main/java/com/example/ueberwachungssystem/Detection/VideoDetector.java
@@ -0,0 +1,196 @@
+package com.example.ueberwachungssystem.Detection;
+
+import android.content.Context;
+import android.graphics.ImageFormat;
+import android.media.Image;
+import android.util.Size;
+
+import androidx.annotation.NonNull;
+import androidx.camera.core.CameraSelector;
+import androidx.camera.core.ExperimentalGetImage;
+import androidx.camera.core.ImageAnalysis;
+import androidx.camera.core.Preview;
+import androidx.camera.lifecycle.ProcessCameraProvider;
+import androidx.camera.view.PreviewView;
+import androidx.core.content.ContextCompat;
+import androidx.lifecycle.LifecycleOwner;
+
+import com.google.common.util.concurrent.ListenableFuture;
+
+import java.nio.ByteBuffer;
+import java.util.concurrent.ExecutionException;
+
+
+/**
+ * Video Detector inherits some methods from abstract Detector class (more info there)
+ *
+ *
+ * USE FROM MAIN ACTIVITY:
+ *
+ * VideoDetector vd = new VideoDetector(this);
+ * vd.setPreview(previewView); //THIS IS OPTIONAL!
+ * vd.setOnDetectionListener(new Detector.OnDetectionListener{...});
+ * vd.startDetection();
+ * vd.stopDetection
+ *
+ * */
+
+
+@ExperimentalGetImage
+public class VideoDetector extends Detector {
+
+ // Calling Activity
+ private final Context context;
+ // Camera Provider
+ private ProcessCameraProvider cameraProvider;
+ private Boolean isDetectionRunning = false;
+ // Preview Camera Image
+ private PreviewView previewView = null;
+ // Detect Violation
+ private static final float PIXEL_THRESHOLD = 30f; // Luminosity (brightness channel of YUV_420_888)
+ private static final float ALARM_THRESHOLD = 0.2f; // Percent of pixels changed
+ private ByteBuffer previousBuffer = null;
+
+
+
+ /**
+ * Constructor
+ * @param context: the context of calling activity (usually "this")
+ * */
+ public VideoDetector(Context context) {
+ super();
+ this.context = context;
+ }
+
+
+ /**
+ * Starts the Video Detection
+ * */
+ @Override
+ public void startDetection() {
+ if (isDetectionRunning)
+ return;
+ // Request Camera Provider
+ final ListenableFuture cameraProviderFuture = ProcessCameraProvider.getInstance(context);
+ //Check for Camera availability
+ cameraProviderFuture.addListener(() -> {
+ try {
+ cameraProvider = cameraProviderFuture.get();
+ bindAnalysis(cameraProvider);
+ isDetectionRunning = true;
+ previousBuffer = null;
+ } catch (ExecutionException | InterruptedException e) {
+ // No errors need to be handled for this Future. This should never be reached.
+ }
+ },ContextCompat.getMainExecutor(context));
+ }
+
+
+ /**
+ * Stops the Video Detection
+ * */
+ @Override
+ public void stopDetection() {
+ if (!isDetectionRunning)
+ return;
+ cameraProvider.unbindAll();
+ isDetectionRunning = false;
+ }
+
+
+ /**
+ * Set PreviewView to show video feed while detecting
+ * this is optional and does not need to be called
+ * */
+ public void setPreviewView(PreviewView previewView) {
+ this.previewView = previewView;
+ }
+
+
+ /**
+ * Binds the Luminosity Analyzer (configure and run Analysis)
+ * @param cameraProvider: CameraProvider of Context passed by Constructor
+ * */
+ private void bindAnalysis(@NonNull ProcessCameraProvider cameraProvider) {
+ // Configure and create Image Analysis
+ ImageAnalysis.Builder builder = new ImageAnalysis.Builder();
+ builder.setTargetResolution(new Size(640, 480));
+ builder.setBackpressureStrategy(ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST);
+ builder.setOutputImageFormat(ImageAnalysis.OUTPUT_IMAGE_FORMAT_YUV_420_888);
+ ImageAnalysis imageAnalysis = builder.build();
+
+ // Set Analyzer
+ imageAnalysis.setAnalyzer(ContextCompat.getMainExecutor(context), imageProxy -> {
+ if (imageProxy.getFormat() == ImageFormat.YUV_420_888) {
+ Image image = imageProxy.getImage();
+ assert image != null;
+
+ // Changed Pixel Detection
+ int pixelChanged = getChangedPixelCount(image);
+ int width = image.getWidth();
+ int height = image.getHeight();
+
+ float percentPixelChanged = (float) 100f * pixelChanged / (width * height);
+
+ if (percentPixelChanged > ALARM_THRESHOLD)
+ reportViolation("0", "Video", percentPixelChanged);
+ }
+ imageProxy.close();
+ });
+ // Create Preview
+ Preview preview = new Preview.Builder().build();
+ // Specify which Camera to use
+ CameraSelector cameraSelector = new CameraSelector.Builder().requireLensFacing(CameraSelector.LENS_FACING_BACK).build();
+ // Update PreviewView if set
+ if (previewView != null)
+ preview.setSurfaceProvider(previewView.getSurfaceProvider());
+
+ cameraProvider.bindToLifecycle((LifecycleOwner) context, cameraSelector, imageAnalysis, preview);
+ }
+
+
+
+ /**
+ * Calculate Amount of Pixels changed using a threshold
+ * @param image
+ * */
+ private int getChangedPixelCount(Image image) {
+ Image.Plane[] planes = image.getPlanes();
+ ByteBuffer buffer = planes[0].getBuffer();
+
+ if (previousBuffer == null) {
+ previousBuffer = ByteBuffer.allocate(buffer.capacity());
+ buffer.rewind();
+ previousBuffer.put(buffer);
+ previousBuffer.rewind();
+ return 0;
+ }
+
+ int width = image.getWidth();
+ int height = image.getHeight();
+
+ int yRowStride = image.getPlanes()[0].getRowStride();
+ int yPixelStride = image.getPlanes()[0].getPixelStride();
+
+ int changedPixelCount = 0;
+
+ // Count changed pixels
+ for (int y = 0; y < height; ++y) {
+ for (int x = 0; x < width; x++) {
+ int index = (y * yRowStride) + (x * yPixelStride);
+ int luminosity = (buffer.get(index) & 0xff);
+ int previousLuminosity = (previousBuffer.get(index) & 0xff);
+ int diff = Math.abs(luminosity - previousLuminosity);
+ if (diff > PIXEL_THRESHOLD)
+ changedPixelCount++;
+ }
+ }
+
+ // Reset and copy Byte Buffer
+ buffer.rewind();
+ previousBuffer.rewind();
+ previousBuffer.put(buffer);
+
+ return changedPixelCount;
+ }
+}
diff --git a/app/src/main/java/com/example/ueberwachungssystem/MainActivity.java b/app/src/main/java/com/example/ueberwachungssystem/MainActivity.java
new file mode 100644
index 0000000..f4fdae7
--- /dev/null
+++ b/app/src/main/java/com/example/ueberwachungssystem/MainActivity.java
@@ -0,0 +1,14 @@
+package com.example.ueberwachungssystem;
+
+import androidx.appcompat.app.AppCompatActivity;
+
+import android.os.Bundle;
+
+public class MainActivity extends AppCompatActivity {
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_main);
+ }
+}
\ No newline at end of file
diff --git a/app/src/test/java/com/example/ueberwachungssystem/ExampleUnitTest.java b/app/src/test/java/com/example/ueberwachungssystem/ExampleUnitTest.java
new file mode 100644
index 0000000..fb36b56
--- /dev/null
+++ b/app/src/test/java/com/example/ueberwachungssystem/ExampleUnitTest.java
@@ -0,0 +1,17 @@
+package com.example.ueberwachungssystem;
+
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+
+/**
+ * Example local unit test, which will execute on the development machine (host).
+ *
+ * @see Testing documentation
+ */
+public class ExampleUnitTest {
+ @Test
+ public void addition_isCorrect() {
+ assertEquals(4, 2 + 2);
+ }
+}
\ No newline at end of file