Compare commits

..
92 Commits
Author SHA1 Message Date
siebenhaarmi76624 be1e52a9b0 Kopie Master Version 1.3 UDP Socket merged with sensor, mit Fehler 2023-06-21 14:27:53 +02:00
siebenhaarmi76624 5b042611a5 Kopie Master Version 1.2 UDP Socket merged with sensor 2023-06-21 13:55:36 +02:00
siebenhaarmi76624 5a0aab0176 Merge branch 'master' into copie
# Conflicts:
#	app/src/main/java/com/example/ueberwachungssystem/Detection/DetectorService.java
#	app/src/main/java/com/example/ueberwachungssystem/MainActivity.java
2023-06-21 13:29:54 +02:00
siebenhaarmi76624 5f1f127e62 Kopie Master Version 1.2 UDP Socket merged with sensor 2023-06-21 13:17:47 +02:00
kohlerba68671 1eba8e0f7c Merge branch 'bk_service' 2023-06-21 13:12:43 +02:00
kohlerba68671 d17f455ae1 Added toMessage() to DetectionReport 2023-06-21 13:05:56 +02:00
wolzto94552 94970885cf Changed time to lay phone down to startDelay = 20000, threadSleeptime = 10 and Log.d Report in case of detection for readability ´reasons 2023-06-21 13:04:52 +02:00
kohlerba68671 3b88a140cc Removed DetectorService methods and added public classes 2023-06-21 10:49:18 +02:00
kohlerba68671 c730eec9f9 Working DetectorService with all Detectors and Recorders 2023-06-21 10:24:45 +02:00
kohlerba68671 1aea88d08f Fixed another bug with calculating pixels changed 2023-06-21 10:02:58 +02:00
kohlerba68671 43eac872ed Bug Fixes on VideoDetector 2023-06-21 09:50:14 +02:00
kohlerba68671 39295f9780 Changed Format in Detection Report 2023-06-21 09:49:45 +02:00
kohlerba68671 54ba3b4862 Sensors working together in main 2023-06-21 00:26:33 +02:00
kohlerba68671 2087edd3e6 Reset main 2023-06-20 23:29:43 +02:00
kohlerba68671 4222ebef83 Fixed error 2023-06-20 23:24:05 +02:00
siebenhaarmi76624 35708220f8 Kopie Master Version 1.1 UDP Socket merged with sensor 2023-06-20 23:16:20 +02:00
kleineckeol72024 061646a7d6 Merge remote-tracking branch 'origin/master'
# Conflicts:
#	app/src/main/AndroidManifest.xml
#	app/src/main/java/com/example/ueberwachungssystem/MainActivity.java
#	app/src/main/res/layout/activity_main.xml
2023-06-20 23:05:14 +02:00
siebenhaarmi76624 415af15cb7 Kopie Matser Version 1 UDP Socket 2023-06-20 23:02:05 +02:00
siebenhaarmi76624 6f78836c4d Merge remote-tracking branch 'origin/master' 2023-06-20 22:34:42 +02:00
siebenhaarmi76624 b667e70fef Kommunikationcopie Version 1.8 UDP Socket 2023-06-20 22:30:30 +02:00
wolzto94552 272daf9fae Adjustment to fit master 2023-06-20 22:25:20 +02:00
wolzto94552 55ae95e661 Merge of MicrophoneDetector 2023-06-20 21:58:09 +02:00
wolzto94552 8e47934beb Merge branch 'tw' into master
# Conflicts:
#	app/build.gradle
#	app/src/main/AndroidManifest.xml
#	app/src/main/java/com/example/ueberwachungssystem/MainActivity.java
#	app/src/main/res/layout/activity_main.xml
#	gradle.properties
2023-06-20 21:42:25 +02:00
wolzto94552 c60a14b6ac Clean project for merge 2023-06-20 21:37:17 +02:00
Leon Market b9c66f7533 Updated detection report constructor in Accelerometer 2023-06-20 21:23:57 +02:00
Leon Market 7e1143880e Merge branch 'lm'
# Conflicts:
#	app/src/main/java/com/example/ueberwachungssystem/Detection/DetectionReport.java
#	app/src/main/java/com/example/ueberwachungssystem/Detection/Detector.java
#	app/src/main/java/com/example/ueberwachungssystem/MainActivity.java
#	app/src/main/res/layout/activity_main.xml
2023-06-20 21:20:04 +02:00
wolzto94552 4381ae78f8 Commit before cleaning project for merge (minor changes) 2023-06-20 21:16:18 +02:00
siebenhaarmi76624 c198292fbf Merge remote-tracking branch 'origin/master' into Kommunikationcopie
# Conflicts:
#	app/src/main/AndroidManifest.xml
#	app/src/main/java/com/example/ueberwachungssystem/MainActivity.java
#	app/src/main/java/com/example/ueberwachungssystem/WifiCommunication.java
#	app/src/main/res/layout/activity_main.xml
2023-06-20 21:13:26 +02:00
Leon Market 81c3542654 Removed unnecessary packages 2023-06-20 21:13:08 +02:00
siebenhaarmi76624 35d52088aa merge Kommunikationcopie Version 1.7 UDP Socket 2023-06-20 21:06:51 +02:00
wolzto94552 81e04e370a Commit before cleaning project for merge 2023-06-20 21:04:33 +02:00
Leon Market d33ab299ab Added reportViolation() 2023-06-20 20:59:18 +02:00
siebenhaarmi76624 ee61f7042b Kommunikation Version 1.6 UDP Socket 2023-06-20 20:50:18 +02:00
siebenhaarmi76624 ab54b6d96a Kommunikation Version 1.5 UDP Socket 2023-06-20 20:47:53 +02:00
siebenhaarmi76624 a85fb1f5ca Kommunikation Version 1.5 UDP Socket 2023-06-20 20:33:46 +02:00
kohlerba68671 f8f1fd23fb Merge branch 'bk_video'
# Conflicts:
#	app/src/main/java/com/example/ueberwachungssystem/MainActivity.java
2023-06-20 15:34:24 +02:00
siebenhaarmi76624 e007ad1744 Kommunikation Version 1.4 UDP Socket 2023-06-20 15:22:27 +02:00
siebenhaarmi76624 292c3457fa Kommunikation Version 1.4 UDP Socket 2023-06-20 15:22:10 +02:00
siebenhaarmi76624 79c7c16d21 Kommunikation Version 1.4 UDP Socket 2023-06-20 15:19:29 +02:00
kohlerba68671 e01e23eccd Refactor 2023-06-20 14:29:10 +02:00
kohlerba68671 a493bafb79 Refactor 2023-06-20 11:16:26 +02:00
kohlerba68671 aed079377f Refactor 2023-06-20 11:07:57 +02:00
kohlerba68671 bff6abbd29 Removed Permission Handling from Video Detector, Added PermissionHandler.java class 2023-06-20 11:00:26 +02:00
kohlerba68671 5d31f0bb46 Adapted Parameters 2023-06-19 15:47:40 +02:00
kohlerba68671 ea0e88ed89 Refactor in DetectorService class 2023-06-19 14:51:04 +02:00
kohlerba68671 7dee124378 Refactor in DetectorService class 2023-06-19 14:41:41 +02:00
kohlerba68671 0ee1446cbc Merge branch 'bk_video_service' into bk_video
# Conflicts:
#	app/src/main/java/com/example/ueberwachungssystem/MainActivity.java
2023-06-19 14:40:06 +02:00
kohlerba68671 bc5227ba4f Refactor of DetectorService 2023-06-19 14:37:49 +02:00
kohlerba68671 4185cb5200 Proper display of Toasts in Audio Recorder 2023-06-19 14:34:07 +02:00
kohlerba68671 0a3600d0d6 Refactor 2023-06-19 14:27:04 +02:00
kohlerba68671 9b2d57ad37 Refactor 2023-06-19 13:35:02 +02:00
kohlerba68671 847e90f5ac Fixed Bug in VideoDetector 2023-06-19 13:17:17 +02:00
kohlerba68671 ab41217f0e Added DetectionService 2023-06-19 13:13:23 +02:00
siebenhaarmi76624 0782bbdd04 merge Kommunikation Version 1.3 UDP Socket 2023-06-19 13:00:22 +02:00
kohlerba68671 e088b0afa3 Working Recorder and Video Detector 2023-06-18 20:17:19 +02:00
kohlerba68671 493fa8ca83 Fixed Grey Stripes and Rotation Problems 2023-06-18 18:12:03 +02:00
kohlerba68671 6954d38143 Moved OpenCV Helper to its own Java File 2023-06-18 13:43:10 +02:00
Leon Market 8a5d720685 Changed to a (hopefully) working version of the Accelerometer 2023-06-18 13:13:30 +02:00
kohlerba68671 057c7fc139 Added Audio Recorder 2023-06-18 13:03:38 +02:00
kohlerba68671 29c193b716 Removed Preview Use Case, Audio still not working 2023-06-18 10:55:21 +02:00
Leon Market 90aea5b1bc Added LinkedBlockingQueue to collect data, added Thread to evaluate data from queue 2023-06-17 23:58:34 +02:00
kohlerba68671 76442888f7 Working Video Detector + Recorder WIP: Use Case logic 2023-06-17 19:44:08 +02:00
Leon Market 8a357e0d26 Fixed errors after merge with origin:lm 2023-06-17 19:20:32 +02:00
Leon Market 83268c763b Merge remote-tracking branch 'origin/lm' into lm
# Conflicts:
#	app/src/main/java/com/example/ueberwachungssystem/Beschleunigungssensor.java
2023-06-17 19:17:11 +02:00
Leon Market 3d02d8d4c0 Added 2023-06-17 19:16:48 +02:00
Leon Market cafe763c4a Removed unnecessary code parts 2023-06-17 19:14:34 +02:00
Leon Market 2cff334056 Added detection report 2023-06-17 19:00:44 +02:00
kohlerba68671 d32e0a11f5 Fixed bug in Detector and VideoDetector 2023-06-17 11:20:56 +02:00
wolzto94552 b94a1d98b7 Working detection with calibration and dB signals. FFT also implemented, but does not work properly at the moment. (Added Complex class, FFT class and imported jjoe64 Graphview (in gradle and gradle.properties) for visualising FFT results) 2023-06-16 16:49:20 +02:00
kleineckeol72024 746eec18ba removed Fragment classes from MainActivity 2023-06-15 17:19:35 +02:00
siebenhaarmi76624 e89a5d11a1 Kommunikation Version 1.2 UDP Socket 2023-06-15 16:38:49 +02:00
siebenhaarmi76624 b246ad8624 Kommunikation Version 1.1 UDP Socket 2023-06-15 15:09:19 +02:00
Leon Market 6c4905d0e7 Added constructors for activity and textView in ThreadDemo 2023-06-15 14:27:25 +02:00
kohlerba68671 fb8bdcd895 Fixed up Video detector 2023-06-15 12:40:54 +02:00
Leon Market 402b73e4bd Removed calibration code and added method checkAlarm 2023-06-14 22:28:05 +02:00
Leon Market 9e5b669986 Added Accelerometer as Runnable Class and ThreadDemo as example 2023-06-14 22:25:54 +02:00
Leon Market 8275d8bd5a Added 2023-06-14 22:11:17 +02:00
kohlerba68671 7ef0df48dd Refactored Detector 2023-06-14 20:14:06 +02:00
kohlerba68671 50b579705e Detector based on OpenCV working 2023-06-14 19:43:18 +02:00
kohlerba68671 8551abfc5d Changde Detector class 2023-06-14 16:38:33 +02:00
kohlerba68671 bbd333426d unfinished changes in Detector 2023-06-13 20:55:30 +02:00
kohlerba68671 e98ae10267 refactor 2023-06-12 19:03:52 +02:00
kohlerba68671 7d29ed1ca9 Rebuild to use openCV. Alarm not yet implemented 2023-06-09 20:56:14 +02:00
kohlerba68671 f98079d431 Readded main and main xml 2023-06-09 09:09:50 +02:00
siebenhaarmi76624 192f88ede5 Kommunikation Version 1 UDP Socket 2023-06-08 18:10:39 +02:00
siebenhaarmi76624 3c1366bd10 Kommunikation Version 1 UDP Socket 2023-06-08 17:59:47 +02:00
wolzto94552 7c8610facb Move from Mikrofon to MicrophoneDetector class and add of abstract Detector class 2023-05-25 16:58:08 +02:00
Leon Market 4999f1b998 added Detector, DetectorReport, Logger 2023-05-25 16:46:12 +02:00
Leon Market 620528302e added Beschleunigungssensor 2023-05-24 20:40:18 +02:00
unknown 90a2aad491 new class Mikrofon 2023-05-11 16:21:59 +02:00
siebenhaarmi76624 35583a4cdd Merge branch 'test' of siebenhaarmi76624/MDT5_1_Ueberwachungssystem_G1 into ms 2023-05-11 13:39:00 +00:00
siebenhaarmi76624 d22952d83b Initial commit Project Version 0 2023-05-11 15:38:14 +02:00
28 changed files with 2094 additions and 482 deletions
+3
View File
@@ -0,0 +1,3 @@
Sensor als Service einrichten, der aus Activity heraus gestartet werden kann.
Stichwort: Intent
Siehe Skript Teil 1
+12
View File
@@ -26,6 +26,9 @@ android {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
buildFeatures {
viewBinding true
}
}
dependencies {
@@ -33,10 +36,19 @@ dependencies {
implementation 'androidx.appcompat:appcompat:1.6.1'
implementation 'com.google.android.material:material:1.8.0'
implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
implementation 'com.google.android.gms:play-services-nearby:18.0.0'
testImplementation 'junit:junit:4.13.2'
androidTestImplementation 'androidx.test.ext:junit:1.1.5'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1'
// OpenCV (from: https://github.com/QuickBirdEng/opencv-android)
def opencv_version = "4.5.3.0"
implementation "com.quickbirdstudios:opencv:${opencv_version}"
implementation "androidx.lifecycle:lifecycle-extensions:2.0.0"
// Required for CameraX
def camerax_version = "1.2.2"
implementation "androidx.camera:camera-core:${camerax_version}"
+4 -21
View File
@@ -2,27 +2,9 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<!-- &lt;!&ndash; If your app targets Android 13 (API level 33)-->
<!-- or higher, you must declare the NEARBY_WIFI_DEVICES permission. &ndash;&gt;-->
<!-- <uses-permission android:name="android.permission.NEARBY_WIFI_DEVICES"-->
<!-- &lt;!&ndash; If your app derives location information from Wi-Fi APIs,-->
<!-- don't include the "usesPermissionFlags" attribute. &ndash;&gt;-->
<!-- android:usesPermissionFlags="neverForLocation" />-->
<uses-permission
android:required="true"
android:name="android.permission.ACCESS_FINE_LOCATION"/>
<!-- If any feature in your app relies on precise location information,
don't include the "maxSdkVersion" attribute. -->
<uses-permission
android:required="true"
android:name="android.permission.ACCESS_WIFI_STATE"/>
<uses-permission
android:required="true"
android:name="android.permission.CHANGE_WIFI_STATE"/>
<uses-permission
android:required="true"
android:name="android.permission.INTERNET"/>
<uses-feature android:name="android.hardware.camera"/>
<uses-permission android:name="android.permission.CAMERA"/>
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
@@ -46,6 +28,7 @@
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<service android:name=".Detection.DetectorService"/>
</application>
</manifest>
@@ -0,0 +1,108 @@
package com.example.ueberwachungssystem.Detection;
import static java.lang.Math.sqrt;
import android.content.Context;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
/**
* Accelerometer inherits some methods from abstract Detector class (more info there)
*
*
* USE FROM MAIN ACTIVITY:
*
* Accelerometer beschleunigungssensor = new Accelerometer(this);
* onCreate:
* //Accelerometer Setup
* beschleunigungssensor = new Accelerometer(this, logger, textViewLog); //logger and textview only for debugging necessary
* beschleunigungssensor.getSensor();
*
* //Starting Detection:
* beschleunigungssensor.startDetection();
* //Stopping Detection: also recommended at onPause to avoid unnecessary battery consumption
* beschleunigungssensor.stopDetection();
*
* */
public class Accelerometer extends Detector implements SensorEventListener {
public SensorManager sensorManager;
private static final int sensorType = Sensor.TYPE_LINEAR_ACCELERATION;
private Sensor accelerometer;
private Context context;
boolean alarm = false;
//Preallocate memory for the data of each axis of the acceleration sensor
float x;
float y;
float z;
float betrag; //Betrag aller drei Achsen sqrt(x*x + y*y + z*z)
private DetectionReport detectionReport;
// In constructor pass Activity, Context and TextView from MainActivity in Accelerometer class
public Accelerometer(Context context){
super(); //von Detektor
this.context = context;
}
public void getSensor(){
sensorManager = (SensorManager)context.getSystemService(Context.SENSOR_SERVICE);
if(sensorManager.getSensorList(sensorType).size()==0) {
accelerometer = null;
}
else {
accelerometer = sensorManager.getSensorList(sensorType).get(0);
}
}
@Override
public void onSensorChanged(SensorEvent event) {
try {
checkAlarm(event);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
public void checkAlarm (SensorEvent event) throws InterruptedException {
x = event.values[0];
y = event.values[1];
z = event.values[2];
betrag = (float) sqrt(x*x + y*y + z*z);
float threshold = 1.5F;
if (!alarm) {
if (betrag > threshold) {
alarm = true;
reportViolation("Bewegung", betrag);
}
} else {
if (betrag < threshold) {
alarm = false;
} else {
}
}
}
@Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {
}
@Override
public void startDetection() {
// entspricht void start()
//getSensor();
if (accelerometer != null) {
sensorManager.registerListener(this, accelerometer, SensorManager.SENSOR_DELAY_GAME);
}
}
@Override
public void stopDetection() {
// entspricht void stop()
sensorManager.unregisterListener(this, accelerometer);
}
}
@@ -0,0 +1,74 @@
package com.example.ueberwachungssystem.Detection;
import android.content.Context;
import android.media.MediaPlayer;
import android.media.MediaRecorder;
import android.widget.Toast;
import java.io.File;
import java.io.IOException;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
public class AudioRecorder {
private final Context context;
private MediaRecorder mediaRecorder = null;
private boolean isRecording = false;
private File outputDir; // Default: in app files directory
public AudioRecorder (Context context) {
this.context = context;
this.outputDir = context.getFilesDir();
}
public void startRecording() {
// Handle logic
if (outputDir == null)
return;
if (isRecording)
return;
isRecording = true;
// Setup Audio Recorder for output Format: 3GP
mediaRecorder = new MediaRecorder();
mediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
mediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
mediaRecorder.setOutputFile(outputDir + "/" + generateFileName() + ".3gp");
mediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
try {
mediaRecorder.prepare();
} catch (IOException e) {
e.printStackTrace();
}
mediaRecorder.start();
}
public void stopRecording() {
if (mediaRecorder != null) {
mediaRecorder.stop();
mediaRecorder.reset();
mediaRecorder.release();
mediaRecorder = null;
isRecording = false;
Toast.makeText(context, "audio recording saved", Toast.LENGTH_SHORT).show();
}
}
public boolean isRecording(){
return isRecording;
}
public void setOutputDir(File outputDir) {
this.outputDir = outputDir;
}
private String generateFileName(){
// Get the current timestamp
LocalDateTime currentTime = LocalDateTime.now();
// Define the format for the timestamp
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMMdd_HHmmss");
// Return the timestamp as a string
return currentTime.format(formatter);
}
}
@@ -1,32 +1,53 @@
package com.example.ueberwachungssystem.Detection;
import android.annotation.SuppressLint;
import android.util.Log;
import com.example.ueberwachungssystem.WifiCommunication;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
/** Detection Report Class */
public class DetectionReport {
public String timeStamp;
public String detectionType;
public float detectedValue;
public String detectorID;
public boolean detectionState;
public DetectionReport(String detectorID, String detectionType, float detectedAmplitude) {
this.timeStamp = String.valueOf(Calendar.getInstance().getTime());
public DetectionReport(boolean detectionState, String detectionType, float detectedAmplitude) {
// New Date Format
@SuppressLint("SimpleDateFormat") SimpleDateFormat formatter = new SimpleDateFormat("HH:mm:ss");
Date curDate = new Date(System.currentTimeMillis());
this.timeStamp = formatter.format(curDate);
//Old Date Format: this.timeStamp = String.valueOf(Calendar.getInstance().getTime());
this.detectionType = detectionType;
this.detectedValue = detectedAmplitude;
this.detectorID = detectorID;
this.detectionState = detectionState;
//this.detectorID = detectorID;
}
/** Get Detection Report in String format */
public String toString() {
String state = "State: " + "[" + this.detectionState + "]";
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);
return String.join("\t", state, time, type, value);
}
public String toMessage() {
String state;
if(detectionState)
state = "An";
else
state = "Aus";
return String.join(",", "1", timeStamp, "Gruppe2", WifiCommunication.getLocalIpAddress(), state, detectionType, String.valueOf(detectedValue));
}
/** Debug Report */
@@ -1,10 +1,19 @@
package com.example.ueberwachungssystem.Detection;
import android.os.CountDownTimer;
import androidx.annotation.NonNull;
import androidx.camera.core.ExperimentalGetImage;
abstract public class Detector {
private OnDetectionListener listener;
private boolean isDetecting = false;
private boolean extendViolation = false;
// Countdown parameters
private final int COUNTDOWN_TIME = 10000; // milliseconds
private final int COUNTDOWN_POLLING_TIME = 100; // milliseconds
/** Constructor - takes context of current activity */
public Detector() {}
@@ -18,17 +27,46 @@ abstract public class Detector {
this.listener = listener;
}
/** Triggers onDetectionListener - call this to trigger violation/alarm */
public void reportViolation(String detectorID, String detectionType, float amplitude) {
public void reportViolation(String detectionType, float amplitude) {
if (listener != null) {
DetectionReport detectionReport = new DetectionReport(detectorID, detectionType, amplitude);
listener.onDetection(detectionReport);
if (!isDetecting) {
isDetecting = true;
DetectionReport detectionReport = new DetectionReport(true, detectionType, amplitude);
listener.onDetection(detectionReport);
startDetectionTimer(detectionType, amplitude);
} else {
extendViolation = true;
}
} else {
throw new IllegalStateException("No listener set for violation reporting");
isDetecting = false;
extendViolation = false;
}
}
private void startDetectionTimer(String detectionType, float amplitude) {
isDetecting = true;
new CountDownTimer((long) COUNTDOWN_TIME, COUNTDOWN_POLLING_TIME) {
@Override
public void onTick(long millisUntilFinished) {
if (extendViolation) {
extendViolation = false;
startDetectionTimer(detectionType, amplitude);
this.cancel();
}
}
@Override
public void onFinish() {
isDetecting = false;
DetectionReport detectionReport = new DetectionReport(false, detectionType, amplitude);
listener.onDetection(detectionReport);
}
}.start();
}
public void extendViolation(){
this.extendViolation = true;
}
/** Starts Detection (abstract method: needs to be overridden in child class) */
public abstract void startDetection();
@@ -0,0 +1,140 @@
package com.example.ueberwachungssystem.Detection;
import android.content.Intent;
import android.os.Binder;
import android.os.IBinder;
import android.util.Log;
import android.widget.ImageView;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.camera.core.ExperimentalGetImage;
import androidx.lifecycle.LifecycleService;
import com.example.ueberwachungssystem.WifiCommunication;
import java.io.File;
@ExperimentalGetImage
public class DetectorService extends LifecycleService {
public ServiceBinder serviceBinder = new ServiceBinder();
private DetectorService.OnDetectionListener listener;
private boolean isServiceRunning = false;
// Used Objects:
public VideoDetector videoDetector = null;
public AudioRecorder audioRecorder = null;
public Accelerometer motionDetector = null;
public MicrophoneDetector audioDetector = null;
WifiCommunication wifiCommunication;
String dataFromWifi;
StringBuffer stringBufferFromWifi;
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
if (isServiceRunning)
return START_NOT_STICKY;
/** Wifi Instanz Starten und Listener **/
wifiCommunication = new WifiCommunication (1234);
wifiCommunication.setOnConnectionListener(new WifiCommunication.OnConnectionListener() {
@Override
public void onConnection(String data) {
dataFromWifi = data;
stringToStringbuffer(data);
}
});
/** Video Detection/Recorder **/
videoDetector = new VideoDetector(this);
videoDetector.setOnDetectionListener(new Detector.OnDetectionListener() {
@Override
public void onDetection(@NonNull DetectionReport detectionReport) {
//passToServiceListener(detectionReport);
Log.d("Video", detectionReport.toMessage());
wifiCommunication.sendTrue(detectionReport.toMessage());
}
});
/** Motion Detection**/
motionDetector = new Accelerometer(this);
motionDetector.getSensor();
motionDetector.setOnDetectionListener(new Detector.OnDetectionListener() {
@Override
public void onDetection(@NonNull DetectionReport detectionReport) {
//passToServiceListener(detectionReport);
Log.d("Motion", detectionReport.toMessage());
wifiCommunication.sendTrue(detectionReport.toMessage());
}
});
/** Audio Detection **/
audioDetector = new MicrophoneDetector(this);
audioDetector.setOnDetectionListener(new Detector.OnDetectionListener() {
@Override
public void onDetection(@NonNull DetectionReport detectionReport) {
//passToServiceListener(detectionReport);
Log.d("Audio", detectionReport.toMessage());
wifiCommunication.sendTrue(detectionReport.toMessage());
}
});
/** Audio Recorder**/
audioRecorder = new AudioRecorder(this);
isServiceRunning = true;
return super.onStartCommand(intent, flags, startId);
}
@Override
public void onDestroy() {
super.onDestroy();
isServiceRunning = false;
}
/** Service methods */
public class ServiceBinder extends Binder {
public DetectorService getBoundService() {
// Return an instance of the TestService
return DetectorService.this;
}
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
super.onBind(intent);
return serviceBinder;
}
/** Pass Detection Report to Service Detection Listener and trigger it */
public void passToServiceListener(StringBuffer stringBuffer) {
if (listener != null) {
listener.onDetection(stringBuffer);
}
}
/** On Detection Listener - runs when violation is reported */
public interface OnDetectionListener {
void onDetection(@NonNull StringBuffer stringBuffer);
}
public void setOnDetectionListener(@NonNull DetectorService.OnDetectionListener listener) {
this.listener = listener;
}
/** string to stringbuffer **/
public void stringToStringbuffer(String dataString){
stringBufferFromWifi.append(dataString).append("\n");
passToServiceListener(stringBufferFromWifi);
}
}
@@ -0,0 +1,365 @@
package com.example.ueberwachungssystem.Detection;
import static java.lang.Math.*;
import android.annotation.SuppressLint;
import android.content.Context;
import android.media.AudioFormat;
import android.media.AudioRecord;
import android.media.MediaRecorder;
import android.os.AsyncTask;
import android.util.Log;
import com.example.ueberwachungssystem.Detection.Signalverarbeitung.Complex;
import com.example.ueberwachungssystem.Detection.Signalverarbeitung.FFT;
public class MicrophoneDetector extends Detector {
/**
* Constructor - takes context of current activity
*
* @param context
*/
private AufnahmeTask aufnahmeTask;
public boolean armed = false;
public int schwellwertAlarm = 100;
private Context context;
public MicrophoneDetector(Context context) {
super();
this.context = context;
}
@Override
public void startDetection() {
aufnahmeTask = new AufnahmeTask();
aufnahmeTask.execute();
}
@Override
public void stopDetection() {
if (aufnahmeTask != null) {
aufnahmeTask.cancel(true);
}
}
class AufnahmeTask extends AsyncTask<Long, Verarbeitungsergebnis, Void> {
private AudioRecord recorder;
private final int sampleRateInHz = 44100;
private final int channelConfig = AudioFormat.CHANNEL_IN_MONO;
private final int audioFormat = AudioFormat.ENCODING_PCM_16BIT;
private final int startDelay = 20000;
private final int threadSleeptime = 10;
private int minPufferGroesseInBytes;
private int pufferGroesseInBytes;
private RingPuffer ringPuffer = new RingPuffer(10);
private float kalibierWert;
private com.example.ueberwachungssystem.Detection.DetectionReport detectionReport;
@SuppressLint("MissingPermission")
AufnahmeTask() {
minPufferGroesseInBytes = AudioRecord.getMinBufferSize(sampleRateInHz, channelConfig, audioFormat);
pufferGroesseInBytes = minPufferGroesseInBytes * 2;
try {
recorder = new AudioRecord(MediaRecorder.AudioSource.MIC, sampleRateInHz, channelConfig, audioFormat, pufferGroesseInBytes);
} catch (Exception e) {
e.printStackTrace();
}
Log.d("0","Puffergroeße: "+ minPufferGroesseInBytes + " " + pufferGroesseInBytes);
Log.d("0","Recorder (SR, CH): "+ recorder.getSampleRate() + " " + recorder.getChannelCount());
int anzahlBytesProAbtastwert;
String s;
switch (recorder.getAudioFormat()) {
case AudioFormat.ENCODING_PCM_8BIT:
s = "8 Bit PCM ";
anzahlBytesProAbtastwert = 1;
break;
case AudioFormat.ENCODING_PCM_16BIT:
s = "16 Bit PCM";
anzahlBytesProAbtastwert = 2;
break;
case AudioFormat.ENCODING_PCM_FLOAT:
s = "Float PCM";
anzahlBytesProAbtastwert = 4;
break;
default:
throw new IllegalArgumentException();
}
switch (recorder.getChannelConfiguration()) {
case AudioFormat.CHANNEL_IN_MONO:
s = "Mono";
break;
case AudioFormat.CHANNEL_IN_STEREO:
s = "Stereo";
anzahlBytesProAbtastwert *= 2;
break;
case AudioFormat.CHANNEL_INVALID:
s = "ungültig";
break;
default:
throw new IllegalArgumentException();
}
Log.d("0","Konfiguration: "+ s);
}
@Override
protected Void doInBackground(Long... params) {
recorder.startRecording();
short[] puffer = new short[pufferGroesseInBytes / 2];
long lastTime = System.currentTimeMillis();
float verarbeitungsrate = 0;
final int maxZaehlerZeitMessung = 10;
int zaehlerZeitMessung = 0;
int anzahlVerarbeitet = 0;
GleitenderMittelwert gleitenderMittelwert = new GleitenderMittelwert(0.3f);
//Kalibrierung
try {
Thread.sleep(startDelay); // Time to lay down the phone
} catch (InterruptedException e) {
e.printStackTrace();
}
int i = 0;
for (i = 0; i < 20; i++) {
int n = recorder.read(puffer, 0, puffer.length);
Verarbeitungsergebnis kalibrierErgebnis = verarbeiten(puffer, n);
kalibierWert += kalibrierErgebnis.maxAmp;
try {
Thread.sleep(threadSleeptime);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
kalibierWert = kalibierWert/i;
// __Part of FFT__
// Complex[] zeitSignal = new Complex[puffer.length];
// for (int j = 0; j < puffer.length; j++) {
// zeitSignal[j] = new Complex(puffer[j], 0);
// }
// Complex[] spektrum = FFT.fft(zeitSignal);
// double[] spektrum = calculateFFT(puffer);
// DataPoint AddPoint;
// LineGraphSeries<DataPoint> series = new LineGraphSeries<DataPoint>(new DataPoint[]{});
// for (i = 0; i < spektrum.length; i++) {
// AddPoint = new DataPoint(i, spektrum[i]);
// series.appendData(AddPoint, true, spektrum.length);
// }
// graph.addSeries(series);
for (; ; ) {
if (aufnahmeTask.isCancelled()) {
break;
} else {
int n = recorder.read(puffer, 0, puffer.length);
Verarbeitungsergebnis ergebnis = verarbeiten(puffer, n);
anzahlVerarbeitet += n;
// __Part of FFT__
// spektrum = calculateFFT(puffer);
// LineGraphSeries<DataPoint> newseries = new LineGraphSeries<DataPoint>(new DataPoint[]{});
// for (i = 0; i < spektrum.length; i++) {
// AddPoint = new DataPoint(i, spektrum[i]);
// newseries.appendData(AddPoint, true, spektrum.length);
// }
zaehlerZeitMessung++;
if (zaehlerZeitMessung == maxZaehlerZeitMessung) {
long time = System.currentTimeMillis();
long deltaTime = time - lastTime;
verarbeitungsrate = 1000.0f * anzahlVerarbeitet / deltaTime;
verarbeitungsrate = gleitenderMittelwert.mittel(verarbeitungsrate);
zaehlerZeitMessung = 0;
anzahlVerarbeitet = 0;
lastTime = time;
}
ergebnis.verarbeitungsrate = (int) verarbeitungsrate;
publishProgress(ergebnis);
try {
Thread.sleep(threadSleeptime);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
recorder.release();
return null;
}
private Verarbeitungsergebnis verarbeiten(short[] daten, int n) {
String status;
short maxAmp = -1;
if (n == AudioRecord.ERROR_INVALID_OPERATION) {
status = "ERROR_INVALID_OPERATION";
} else if (n == AudioRecord.ERROR_BAD_VALUE) {
status = "ERROR_BAD_VALUE";
} else {
status = "OK";
short max = 0;
for (int i = 0; i < n; i++) {
if (daten[i] > max) {
max = daten[i];
}
}
ringPuffer.hinzufuegen(max);
maxAmp = ringPuffer.maximum();
if (maxAmp <= schwellwertAlarm + kalibierWert) {
armed = true;
}
}
return new Verarbeitungsergebnis(status, maxAmp, 0);
}
@Override
protected void onProgressUpdate(Verarbeitungsergebnis... progress) {
super.onProgressUpdate(progress);
float maxAmpPrint = round(20*log10(abs(progress[0].maxAmp/1.0)));
float kalibierWertPrint = round(20*log10(abs(kalibierWert)));
Log.d("alarmAudio","VR: " + progress[0].verarbeitungsrate + ", Amp: " + maxAmpPrint
+ " dB, Kal: " + kalibierWertPrint + " dB");
if (progress[0].maxAmp >= schwellwertAlarm + kalibierWert && armed == true) {
armed = false;
detectionReport = new DetectionReport(true, "Audio", maxAmpPrint);
reportViolation("Audio", maxAmpPrint);
Log.d("1",detectionReport.toString());
}
}
}
private double[] calculateFFT(short[] zeitsignal)
{
byte signal[] = new byte[zeitsignal.length];
// loops through all the values of a Short
for (int i = 0; i < zeitsignal.length-1; i++) {
signal[i] = (byte) (zeitsignal[i]);
signal[i+1] = (byte) (zeitsignal[i] >> 8);
}
final int mNumberOfFFTPoints =1024;
double temp;
Complex[] y;
Complex[] complexSignal = new Complex[mNumberOfFFTPoints];
double[] absSignal = new double[mNumberOfFFTPoints/2];
for(int i = 0; i < mNumberOfFFTPoints; i++){
temp = (double)((signal[2*i] & 0xFF) | (signal[2*i+1] << 8)) / 32768.0F;
complexSignal[i] = new Complex(temp,0.0);
}
y = FFT.fft(complexSignal);
for(int i = 0; i < (mNumberOfFFTPoints/2); i++)
{
absSignal[i] = y[i].abs();
}
return absSignal;
}
class Verarbeitungsergebnis {
String status;
short maxAmp;
int verarbeitungsrate;
Verarbeitungsergebnis(String status, short maxAmp, int verarbeitungsrate) {
this.status = status;
this.maxAmp = maxAmp;
this.verarbeitungsrate = verarbeitungsrate;
}
}
class RingPuffer {
private short[] puffer;
private final int laenge;
private int anzahlEnthaltenerDaten;
private int position;
public RingPuffer(int n) {
laenge = n;
anzahlEnthaltenerDaten = 0;
position = 0;
puffer = new short[laenge];
}
public void hinzufuegen(short wert) {
puffer[position] = wert;
position++;
if (position >= laenge) {
position = 0;
}
if (anzahlEnthaltenerDaten < laenge) {
anzahlEnthaltenerDaten++;
}
}
public void hinzufuegen(short[] daten) {
for (short d : daten) {
puffer[position] = d;
position++;
if (position >= laenge) {
position = 0;
}
}
if (anzahlEnthaltenerDaten < laenge) {
anzahlEnthaltenerDaten += daten.length;
if (anzahlEnthaltenerDaten >= laenge) {
anzahlEnthaltenerDaten = laenge;
}
}
}
public short maximum() {
short max = 0;
for (int i = 0; i < anzahlEnthaltenerDaten; i++) {
if (puffer[i] > max) {
max = puffer[i];
}
}
return max;
}
public float mittelwert() {
float summe = 0;
for (int i = 0; i < anzahlEnthaltenerDaten; i++) {
summe += puffer[i];
}
return summe / anzahlEnthaltenerDaten;
}
}
class GleitenderMittelwert {
private final float wichtungNeuerWert;
private final float wichtungAlterWert;
private float mittelwert = 0;
private boolean istMittelwertGesetzt = false;
GleitenderMittelwert(float wichtungNeuerWert) {
this.wichtungNeuerWert = wichtungNeuerWert;
this.wichtungAlterWert = 1 - this.wichtungNeuerWert;
}
float mittel(float wert) {
if (istMittelwertGesetzt) {
mittelwert = wert * wichtungNeuerWert + mittelwert * wichtungAlterWert;
} else {
mittelwert = wert;
istMittelwertGesetzt = true;
}
return mittelwert;
}
}
}
@@ -0,0 +1,109 @@
package com.example.ueberwachungssystem.Detection;
import android.graphics.Bitmap;
import android.media.Image;
import android.widget.ImageView;
import androidx.annotation.NonNull;
import androidx.camera.core.ExperimentalGetImage;
import androidx.camera.core.ImageProxy;
import org.opencv.android.Utils;
import org.opencv.core.Core;
import org.opencv.core.CvType;
import org.opencv.core.Mat;
import org.opencv.core.MatOfPoint;
import org.opencv.core.Scalar;
import org.opencv.core.Size;
import org.opencv.imgproc.Imgproc;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
@ExperimentalGetImage
public class OpenCVHelper {
/** OpenCV helper methods **/
public static Mat addGaussianBlur(Mat inputMat, Size kernelSize){
Mat outputMat = new Mat();
Imgproc.GaussianBlur(inputMat, outputMat, kernelSize, 0);
return outputMat;
}
public static Mat addBlur(Mat inputMat, Size kernelSize){
Mat outputMat = new Mat();
Imgproc.blur(inputMat, outputMat, kernelSize);
return outputMat;
}
public static Mat extractYChannel(@NonNull ImageProxy imgProxy) {
Image img = imgProxy.getImage();
assert img != null;
ByteBuffer yBuffer = img.getPlanes()[0].getBuffer();
byte[] yData = new byte[yBuffer.remaining()];
yBuffer.get(yData);
Mat yMat = new Mat(img.getHeight(), img.getWidth(), CvType.CV_8UC1);
yMat.put(0, 0, yData);
return yMat;
}
public static Mat thresholdPixels(Mat inputMat, Mat previousImage, int threshold){
Mat diffImage = new Mat();
Core.absdiff(inputMat, previousImage, diffImage);
Mat binaryMat = new Mat();
Imgproc.threshold(diffImage, binaryMat, threshold, 255, Imgproc.THRESH_BINARY);
return binaryMat;
}
public static Mat thresholdContourArea(Mat inputMat, float areaThreshold){
List<MatOfPoint> contours = new ArrayList<>();
Mat hierarchy = new Mat();
Imgproc.findContours(inputMat, contours, hierarchy, Imgproc.RETR_EXTERNAL, Imgproc.CHAIN_APPROX_SIMPLE);
Mat outputMat = new Mat(inputMat.size(), inputMat.type(), new Scalar(0));
// Iterate over the contours and draw only the larger contours on the outputMat
for (MatOfPoint contour : contours) {
double contourArea = Imgproc.contourArea(contour);
if (contourArea > areaThreshold) {
Imgproc.drawContours(outputMat, Collections.singletonList(contour), 0, new Scalar(255), -1);
}
}
// Apply the outputMat as a mask to the dilatedImage
Mat maskedImage = new Mat();
inputMat.copyTo(maskedImage, outputMat);
return outputMat;
}
public static Mat dilateBinaryMat(Mat inputMat, Size kernelSize){
Mat dilatedMat = new Mat();
Mat kernel = Imgproc.getStructuringElement(Imgproc.MORPH_ELLIPSE, kernelSize);
Imgproc.dilate(inputMat, dilatedMat, kernel);
return dilatedMat;
}
public static int countNonZeroPixels(Mat inputImage) {
if (inputImage != null)
return Core.countNonZero(inputImage);
else
return 0;
}
public static void debugMat(Mat mat, ImageView imageView) {
if (imageView == null || mat == null)
return;
Bitmap bitmap = Bitmap.createBitmap(mat.cols(), mat.rows(), Bitmap.Config.ARGB_8888);
Utils.matToBitmap(mat, bitmap);
// Display the bitmap in an ImageView
imageView.setImageBitmap(bitmap);
}
}
@@ -0,0 +1,148 @@
package com.example.ueberwachungssystem.Detection.Signalverarbeitung;
import java.util.Objects;
public class Complex {
private final double re; // the real part
private final double im; // the imaginary part
// create a new object with the given real and imaginary parts
public Complex(double real, double imag) {
re = real;
im = imag;
}
// return a string representation of the invoking com.example.ueberwachungssystem.Detection.Signalverarbeitung.Complex object
public String toString() {
if (im == 0) return re + "";
if (re == 0) return im + "i";
if (im < 0) return re + " - " + (-im) + "i";
return re + " + " + im + "i";
}
// return abs/modulus/magnitude
public double abs() {
return Math.hypot(re, im);
}
// return angle/phase/argument, normalized to be between -pi and pi
public double phase() {
return Math.atan2(im, re);
}
// return a new com.example.ueberwachungssystem.Detection.Signalverarbeitung.Complex object whose value is (this + b)
public Complex plus(Complex b) {
Complex a = this; // invoking object
double real = a.re + b.re;
double imag = a.im + b.im;
return new Complex(real, imag);
}
// return a new com.example.ueberwachungssystem.Detection.Signalverarbeitung.Complex object whose value is (this - b)
public Complex minus(Complex b) {
Complex a = this;
double real = a.re - b.re;
double imag = a.im - b.im;
return new Complex(real, imag);
}
// return a new com.example.ueberwachungssystem.Detection.Signalverarbeitung.Complex object whose value is (this * b)
public Complex times(Complex b) {
Complex a = this;
double real = a.re * b.re - a.im * b.im;
double imag = a.re * b.im + a.im * b.re;
return new Complex(real, imag);
}
// return a new object whose value is (this * alpha)
public Complex scale(double alpha) {
return new Complex(alpha * re, alpha * im);
}
// return a new com.example.ueberwachungssystem.Detection.Signalverarbeitung.Complex object whose value is the conjugate of this
public Complex conjugate() {
return new Complex(re, -im);
}
// return a new com.example.ueberwachungssystem.Detection.Signalverarbeitung.Complex object whose value is the reciprocal of this
public Complex reciprocal() {
double scale = re * re + im * im;
return new Complex(re / scale, -im / scale);
}
// return the real or imaginary part
public double re() {
return re;
}
public double im() {
return im;
}
// return a / b
public Complex divides(Complex b) {
Complex a = this;
return a.times(b.reciprocal());
}
// return a new com.example.ueberwachungssystem.Detection.Signalverarbeitung.Complex object whose value is the complex exponential of this
public Complex exp() {
return new Complex(Math.exp(re) * Math.cos(im), Math.exp(re) * Math.sin(im));
}
// return a new com.example.ueberwachungssystem.Detection.Signalverarbeitung.Complex object whose value is the complex sine of this
public Complex sin() {
return new Complex(Math.sin(re) * Math.cosh(im), Math.cos(re) * Math.sinh(im));
}
// return a new com.example.ueberwachungssystem.Detection.Signalverarbeitung.Complex object whose value is the complex cosine of this
public Complex cos() {
return new Complex(Math.cos(re) * Math.cosh(im), -Math.sin(re) * Math.sinh(im));
}
// return a new com.example.ueberwachungssystem.Detection.Signalverarbeitung.Complex object whose value is the complex tangent of this
public Complex tan() {
return sin().divides(cos());
}
// a static version of plus
public static Complex plus(Complex a, Complex b) {
double real = a.re + b.re;
double imag = a.im + b.im;
Complex sum = new Complex(real, imag);
return sum;
}
// See Section 3.3.
public boolean equals(Object x) {
if (x == null) return false;
if (this.getClass() != x.getClass()) return false;
Complex that = (Complex) x;
return (this.re == that.re) && (this.im == that.im);
}
// See Section 3.3.
public int hashCode() {
return Objects.hash(re, im);
}
// sample client for testing
public static void main(String[] args) {
Complex a = new Complex(5.0, 6.0);
Complex b = new Complex(-3.0, 4.0);
System.out.println("a = " + a);
System.out.println("b = " + b);
System.out.println("Re(a) = " + a.re());
System.out.println("Im(a) = " + a.im());
System.out.println("b + a = " + b.plus(a));
System.out.println("a - b = " + a.minus(b));
System.out.println("a * b = " + a.times(b));
System.out.println("b * a = " + b.times(a));
System.out.println("a / b = " + a.divides(b));
System.out.println("(a / b) * b = " + a.divides(b).times(b));
System.out.println("conj(a) = " + a.conjugate());
System.out.println("|a| = " + a.abs());
System.out.println("tan(a) = " + a.tan());
}
}
@@ -0,0 +1,246 @@
package com.example.ueberwachungssystem.Detection.Signalverarbeitung;
// Source: https://introcs.cs.princeton.edu/java/97data/FFT.java.html
/******************************************************************************
* Compilation: javac FFT.java
* Execution: java FFT n
* Dependencies: com.example.ueberwachungssystem.Detection.Signalverarbeitung.Complex.java
*
* Compute the FFT and inverse FFT of a length n complex sequence
* using the radix 2 Cooley-Tukey algorithm.
* Bare bones implementation that runs in O(n log n) time and O(n)
* space. Our goal is to optimize the clarity of the code, rather
* than performance.
*
* This implementation uses the primitive root of unity w = e^(-2 pi i / n).
* Some resources use w = e^(2 pi i / n).
*
* Reference: https://www.cs.princeton.edu/~wayne/kleinberg-tardos/pdf/05DivideAndConquerII.pdf
*
* Limitations
* -----------
* - assumes n is a power of 2
*
* - not the most memory efficient algorithm (because it uses
* an object type for representing complex numbers and because
* it re-allocates memory for the subarray, instead of doing
* in-place or reusing a single temporary array)
*
* For an in-place radix 2 Cooley-Tukey FFT, see
* https://introcs.cs.princeton.edu/java/97data/InplaceFFT.java.html
*
******************************************************************************/
public class FFT {
// compute the FFT of x[], assuming its length n is a power of 2
public static Complex[] fft(Complex[] x) {
int n = x.length;
// base case
if (n == 1) return new Complex[]{x[0]};
// radix 2 Cooley-Tukey FFT
if (n % 2 != 0) {
throw new IllegalArgumentException("n is not a power of 2");
}
// compute FFT of even terms
Complex[] even = new Complex[n / 2];
for (int k = 0; k < n / 2; k++) {
even[k] = x[2 * k];
}
Complex[] evenFFT = fft(even);
// compute FFT of odd terms
Complex[] odd = even; // reuse the array (to avoid n log n space)
for (int k = 0; k < n / 2; k++) {
odd[k] = x[2 * k + 1];
}
Complex[] oddFFT = fft(odd);
// combine
Complex[] y = new Complex[n];
for (int k = 0; k < n / 2; k++) {
double kth = -2 * k * Math.PI / n;
Complex wk = new Complex(Math.cos(kth), Math.sin(kth));
y[k] = evenFFT[k].plus(wk.times(oddFFT[k]));
y[k + n / 2] = evenFFT[k].minus(wk.times(oddFFT[k]));
}
return y;
}
// compute the inverse FFT of x[], assuming its length n is a power of 2
public static Complex[] ifft(Complex[] x) {
int n = x.length;
Complex[] y = new Complex[n];
// take conjugate
for (int i = 0; i < n; i++) {
y[i] = x[i].conjugate();
}
// compute forward FFT
y = fft(y);
// take conjugate again
for (int i = 0; i < n; i++) {
y[i] = y[i].conjugate();
}
// divide by n
for (int i = 0; i < n; i++) {
y[i] = y[i].scale(1.0 / n);
}
return y;
}
// compute the circular convolution of x and y
public static Complex[] cconvolve(Complex[] x, Complex[] y) {
// should probably pad x and y with 0s so that they have same length
// and are powers of 2
if (x.length != y.length) {
throw new IllegalArgumentException("Dimensions don't agree");
}
int n = x.length;
// compute FFT of each sequence
Complex[] a = fft(x);
Complex[] b = fft(y);
// point-wise multiply
Complex[] c = new Complex[n];
for (int i = 0; i < n; i++) {
c[i] = a[i].times(b[i]);
}
// compute inverse FFT
return ifft(c);
}
// compute the linear convolution of x and y
public static Complex[] convolve(Complex[] x, Complex[] y) {
Complex ZERO = new Complex(0, 0);
Complex[] a = new Complex[2 * x.length];
for (int i = 0; i < x.length; i++) a[i] = x[i];
for (int i = x.length; i < 2 * x.length; i++) a[i] = ZERO;
Complex[] b = new Complex[2 * y.length];
for (int i = 0; i < y.length; i++) b[i] = y[i];
for (int i = y.length; i < 2 * y.length; i++) b[i] = ZERO;
return cconvolve(a, b);
}
// compute the DFT of x[] via brute force (n^2 time)
public static Complex[] dft(Complex[] x) {
int n = x.length;
Complex ZERO = new Complex(0, 0);
Complex[] y = new Complex[n];
for (int k = 0; k < n; k++) {
y[k] = ZERO;
for (int j = 0; j < n; j++) {
int power = (k * j) % n;
double kth = -2 * power * Math.PI / n;
Complex wkj = new Complex(Math.cos(kth), Math.sin(kth));
y[k] = y[k].plus(x[j].times(wkj));
}
}
return y;
}
// display an array of com.example.ueberwachungssystem.Detection.Signalverarbeitung.Complex numbers to standard output
public static void show(Complex[] x, String title) {
System.out.println(title);
System.out.println("-------------------");
for (int i = 0; i < x.length; i++) {
System.out.println(x[i]);
}
System.out.println();
}
/***************************************************************************
* Test client and sample execution
*
* % java FFT 4
* x
* -------------------
* -0.03480425839330703
* 0.07910192950176387
* 0.7233322451735928
* 0.1659819820667019
*
* y = fft(x)
* -------------------
* 0.9336118983487516
* -0.7581365035668999 + 0.08688005256493803i
* 0.44344407521182005
* -0.7581365035668999 - 0.08688005256493803i
*
* z = ifft(y)
* -------------------
* -0.03480425839330703
* 0.07910192950176387 + 2.6599344570851287E-18i
* 0.7233322451735928
* 0.1659819820667019 - 2.6599344570851287E-18i
*
* c = cconvolve(x, x)
* -------------------
* 0.5506798633981853
* 0.23461407150576394 - 4.033186818023279E-18i
* -0.016542951108772352
* 0.10288019294318276 + 4.033186818023279E-18i
*
* d = convolve(x, x)
* -------------------
* 0.001211336402308083 - 3.122502256758253E-17i
* -0.005506167987577068 - 5.058885073636224E-17i
* -0.044092969479563274 + 2.1934338938072244E-18i
* 0.10288019294318276 - 3.6147323062478115E-17i
* 0.5494685269958772 + 3.122502256758253E-17i
* 0.240120239493341 + 4.655566391833896E-17i
* 0.02755001837079092 - 2.1934338938072244E-18i
* 4.01805098805014E-17i
*
***************************************************************************/
public static void main(String[] args) {
int n = Integer.parseInt(args[0]);
Complex[] x = new Complex[n];
// original data
for (int i = 0; i < n; i++) {
x[i] = new Complex(i, 0);
}
show(x, "x");
// FFT of original data
Complex[] y = fft(x);
show(y, "y = fft(x)");
// FFT of original data
Complex[] y2 = dft(x);
show(y2, "y2 = dft(x)");
// take inverse FFT
Complex[] z = ifft(y);
show(z, "z = ifft(y)");
// circular convolution of x with itself
Complex[] c = cconvolve(x, x);
show(c, "c = cconvolve(x, x)");
// linear convolution of x with itself
Complex[] d = convolve(x, x);
show(d, "d = convolve(x, x)");
}
}
@@ -1,196 +1,332 @@
package com.example.ueberwachungssystem.Detection;
import android.Manifest;
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.pm.PackageManager;
import android.graphics.ImageFormat;
import android.media.Image;
import android.util.Size;
import android.os.CountDownTimer;
import android.util.Log;
import android.view.Display;
import android.view.Surface;
import android.view.WindowManager;
import android.widget.ImageView;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.camera.core.CameraSelector;
import androidx.camera.core.ExperimentalGetImage;
import androidx.camera.core.ImageAnalysis;
import androidx.camera.core.ImageProxy;
import androidx.camera.core.Preview;
import androidx.camera.core.VideoCapture;
import androidx.camera.lifecycle.ProcessCameraProvider;
import androidx.camera.view.PreviewView;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;
import androidx.lifecycle.LifecycleOwner;
import com.google.common.util.concurrent.ListenableFuture;
import java.nio.ByteBuffer;
import org.opencv.android.OpenCVLoader;
import org.opencv.core.Mat;
import org.opencv.core.Size;
import java.io.File;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
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;
private ImageAnalysis imageAnalysis;
private VideoCapture videoCapture;
//private Preview preview;
// Logic
private boolean isDetecting = false;
private boolean isRecording = false;
private boolean allowReportViolation = false;
// Image Processing
private Mat previousImage = null;
// Debugging
private ImageView inputImageView = null;
private ImageView outputImageView = null;
// Recorder
private File outputDir; // Default: in app files directory
// Parameters
private static final float ALARM_THRESHOLD = 0f; // Percent of pixels changed
private static final float AREA_THRESHOLD = 10f;
private static final int DILATE_ITERATIONS = 2;
private static final float START_DELAY = 20000; // milliseconds
private static final android.util.Size IMAGE_RES = new android.util.Size(640, 480);
/**
* Constructor
* @param context: the context of calling activity (usually "this")
* */
/** Constructor */
public VideoDetector(Context context) {
super();
this.context = context;
this.imageAnalysis = setupImageAnalysis();
this.videoCapture = setupVideoCapture();
this.outputDir = context.getFilesDir();
//this.preview = new Preview.Builder().build();
}
/** Get States */
public boolean isDetecting() {
return isDetecting;
}
public boolean isRecording(){
return isRecording;
}
/**
* Starts the Video Detection
* */
/** Starts the Video Detection */
@Override
public void startDetection() {
if (isDetectionRunning)
// Check States
if (isDetecting)
return;
// Request Camera Provider
// Configure Image Analysis
imageAnalysis = setupImageAnalysis();
// Open CV startup check
if (!OpenCVLoader.initDebug()) {
Log.e("OpenCV", "Unable to load OpenCV!");
return;
} else
Log.d("OpenCV", "OpenCV loaded Successfully!");
// Get Process Camera Provider and start
final ListenableFuture<ProcessCameraProvider> 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));
isDetecting = true;
bindCameraProvider();
} catch (ExecutionException | InterruptedException e) {}
}, ContextCompat.getMainExecutor(context));
// Disable Violation Calling for Setup Time
startViolationTimer(START_DELAY);
}
/** Starts the Recorder */
@SuppressLint("RestrictedApi")
public void startRecording() {
// Check States
if (isRecording){
return;
}
/**
* Stops the Video Detection
* */
videoCapture = setupVideoCapture();
final ListenableFuture<ProcessCameraProvider> cameraProviderFuture = ProcessCameraProvider.getInstance(context);
cameraProviderFuture.addListener(() -> {
try {
cameraProvider = cameraProviderFuture.get();
isRecording = true;
bindCameraProvider();
File vidFile = new File(context.getFilesDir() + "/" + generateFileName() + ".mp4");
if (ActivityCompat.checkSelfPermission(context, Manifest.permission.RECORD_AUDIO) != PackageManager.PERMISSION_GRANTED) {
return;
}
videoCapture.startRecording(
new VideoCapture.OutputFileOptions.Builder(vidFile).build(),
context.getMainExecutor(),
new VideoCapture.OnVideoSavedCallback() {
@Override
public void onVideoSaved(@NonNull VideoCapture.OutputFileResults outputFileResults) {
isRecording = false;
Toast.makeText(context, "video recording saved", Toast.LENGTH_SHORT).show();
}
@Override
public void onError(int videoCaptureError, @NonNull String message, @Nullable Throwable cause) {
isRecording = false;
Toast.makeText(context, "video recording failed", Toast.LENGTH_SHORT).show();
}
}
);
} catch (ExecutionException | InterruptedException ignored) {}
}, ContextCompat.getMainExecutor(context));
}
/** Stops the Video Detection */
@Override
public void stopDetection() {
if (!isDetectionRunning)
if (!isDetecting || imageAnalysis == null)
return;
if (!isRecording)
cameraProvider.unbindAll();
else
cameraProvider.unbind(imageAnalysis);
isDetecting = false;
allowReportViolation = false;
}
/** Stops the Recording */
@SuppressLint("RestrictedApi")
public void stopRecording(){
if(!isRecording)
return;
videoCapture.stopRecording();
if (!isDetecting())
cameraProvider.unbindAll();
else
cameraProvider.unbind(videoCapture);
isRecording = false;
}
/** Bind Camera Provider */
private void bindCameraProvider() {
// Specify which Camera to use
CameraSelector cameraSelector = new CameraSelector.Builder().requireLensFacing(CameraSelector.LENS_FACING_BACK).build();
cameraProvider.unbindAll();
isDetectionRunning = false;
cameraProvider.bindToLifecycle((LifecycleOwner) context, cameraSelector, imageAnalysis, videoCapture);
}
/**
* 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) {
/** Setup Use Cases */
private ImageAnalysis setupImageAnalysis() {
// Configure and create Image Analysis
ImageAnalysis.Builder builder = new ImageAnalysis.Builder();
builder.setTargetResolution(new Size(640, 480));
builder.setTargetResolution(IMAGE_RES);
builder.setBackpressureStrategy(ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST);
builder.setOutputImageFormat(ImageAnalysis.OUTPUT_IMAGE_FORMAT_YUV_420_888);
builder.setTargetRotation(Surface.ROTATION_90);
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();
// Violation Handling
Mat processed = processImage(imageProxy);
float percentPixelChanged = (float) 100f * pixelChanged / (width * height);
int n = OpenCVHelper.countNonZeroPixels(processed);
int pixelCount = image.getWidth() * image.getHeight();
float percentChanged = ((float) n / pixelCount) * 100;
if (percentPixelChanged > ALARM_THRESHOLD)
reportViolation("0", "Video", percentPixelChanged);
// Violation Condition
if (percentChanged> ALARM_THRESHOLD) {
if (allowReportViolation)
reportViolation("Video", percentChanged);
}
}
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());
return imageAnalysis;
}
cameraProvider.bindToLifecycle((LifecycleOwner) context, cameraSelector, imageAnalysis, preview);
@SuppressLint("RestrictedApi")
private VideoCapture setupVideoCapture() {
int rotation = getDisplayRotation();
return new VideoCapture.Builder()
.setTargetRotation(rotation)
.build();
}
/** Process Image to be used for Motion Detection */
private Mat processImage(ImageProxy imageProxy){
if (imageProxy == null)
return null;
// Image Transformation
Mat imageMat = OpenCVHelper.extractYChannel(imageProxy);
// Show Input Image
if (inputImageView != null)
OpenCVHelper.debugMat(imageMat, inputImageView);
// Preprocess Image
Mat preprocessed = imageMat;
preprocessed = OpenCVHelper.addGaussianBlur(preprocessed, new Size(21, 21));
preprocessed = OpenCVHelper.addBlur(preprocessed, new Size(3, 3));
// Set Previous Image
if (previousImage == null) {
previousImage = preprocessed;
return null;
}
// Process Image
Mat processed = preprocessed.clone();
processed = OpenCVHelper.thresholdPixels(processed, previousImage, 25);
for(int i = 0; i < DILATE_ITERATIONS; i++)
processed = OpenCVHelper.dilateBinaryMat(processed, new Size(3,3));
processed = OpenCVHelper.thresholdContourArea(processed, AREA_THRESHOLD);
// Output
previousImage = preprocessed.clone();
// Show Output Image
if (outputImageView != null)
OpenCVHelper.debugMat(processed, outputImageView);
return processed;
}
/** Debug input and result of processing */
public void debugProcessing(@NonNull ImageView inputImageView, @NonNull ImageView outputImageView){
this.inputImageView = inputImageView;
this.outputImageView = outputImageView;
}
/**
* 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();
private void setPreviewView(@NonNull PreviewView previewView) {
// Create Preview
if (this.preview != null)
this.preview.setSurfaceProvider(previewView.getSurfaceProvider());
}
*/
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();
/** Generate File Name */
private String generateFileName(){
// Get the current timestamp
LocalDateTime currentTime = LocalDateTime.now();
// Define the format for the timestamp
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMMdd_HHmmss");
// Return the timestamp as a string
return currentTime.format(formatter);
}
int yRowStride = image.getPlanes()[0].getRowStride();
int yPixelStride = image.getPlanes()[0].getPixelStride();
int changedPixelCount = 0;
/** Get current Display Rotation */
private int getDisplayRotation() {
WindowManager windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
Display display = windowManager.getDefaultDisplay();
return display.getRotation();
}
// 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++;
/** Start delay until Violation Report is allowed */
private void startViolationTimer(float setupTime) {
new CountDownTimer((long) (setupTime), 100) {
@Override
public void onTick(long millisUntilFinished) {
}
}
@Override
public void onFinish() {
allowReportViolation = true;
}
}.start();
}
// Reset and copy Byte Buffer
buffer.rewind();
previousBuffer.rewind();
previousBuffer.put(buffer);
return changedPixelCount;
public void setOutputDir(File outputDir) {
this.outputDir = outputDir;
}
}
@@ -0,0 +1,48 @@
package com.example.ueberwachungssystem.Fragments;
import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import androidx.fragment.app.Fragment;
import com.example.ueberwachungssystem.R;
public class Fragment1 extends Fragment {
private String text;
private final static String KEY_TEXT = "KEY_TEXT";
private void log(String nachricht) {
Log.d(this.getClass().getSimpleName(), nachricht);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle bundle) {
log("onCreateView");
View view = inflater.inflate(R.layout.fragment1, container, false);
TextView Sensor = (TextView) view.findViewById(R.id.Sensor);
Sensor.setText(text);
return view;
}
public static Fragment1 erstellen(String text) {
Fragment1 fragment = new Fragment1();
Bundle b = new Bundle();
b.putString(KEY_TEXT, text);
fragment.setArguments(b);
return fragment;
}
@Override
public void onCreate(Bundle bundle) {
super .onCreate(bundle);
Bundle args = getArguments();
if (args != null ) {
text = args.getString(KEY_TEXT);
log("onCreate: text=" + text);
} else {
log("onCreate");
}
}
}
@@ -0,0 +1,46 @@
package com.example.ueberwachungssystem.Fragments;
import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import androidx.fragment.app.Fragment;
import com.example.ueberwachungssystem.R;
public class Fragment2 extends Fragment {
private String text;
private final static String KEY_TEXT = "KEY_TEXT" ;
private void log(String nachricht) {
Log.d(this.getClass().getSimpleName(), nachricht);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle bundle) {
log( "onCreateView" );
View view = inflater.inflate(R.layout.fragment2, container, false );
TextView Sensor = (TextView) view.findViewById(R.id.Sensor);
Sensor.setText(text);
return view;
}
public static Fragment2 erstellen(String text) {
Fragment2 fragment = new Fragment2();
Bundle b = new Bundle();
b.putString(KEY_TEXT, text);
fragment.setArguments(b);
return fragment;
}
@Override
public void onCreate(Bundle bundle) {
super.onCreate(bundle);
Bundle args = getArguments();
if (args != null) {
text = args.getString(KEY_TEXT);
log("onCreate: text=" + text);
} else {
log("onCreate");
}
}
}
@@ -0,0 +1,46 @@
package com.example.ueberwachungssystem.Fragments;
import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import androidx.fragment.app.Fragment;
import com.example.ueberwachungssystem.R;
public class Fragment3 extends Fragment {
private String text;
private final static String KEY_TEXT = "KEY_TEXT" ;
private void log(String nachricht) {
Log.d(this.getClass().getSimpleName(), nachricht);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle bundle) {
log( "onCreateView" );
View view = inflater.inflate(R.layout.fragment2, container, false );
TextView Sensor = (TextView) view.findViewById(R.id.Sensor);
Sensor.setText(text);
return view;
}
public static Fragment3 erstellen(String text) {
Fragment3 fragment = new Fragment3();
Bundle b = new Bundle();
b.putString(KEY_TEXT, text);
fragment.setArguments(b);
return fragment;
}
@Override
public void onCreate(Bundle bundle) {
super.onCreate(bundle);
Bundle args = getArguments();
if (args != null) {
text = args.getString(KEY_TEXT);
log("onCreate: text=" + text);
} else {
log("onCreate");
}
}
}
@@ -1,220 +1,158 @@
package com.example.ueberwachungssystem;
import androidx.annotation.NonNull;
import androidx.camera.core.ExperimentalGetImage;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentTransaction;
import androidx.appcompat.app.AppCompatActivity;
import static android.content.ContentValues.TAG;
import android.annotation.SuppressLint;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.net.wifi.WifiInfo;
import android.net.wifi.WifiManager;
import android.net.wifi.WifiInfo;
import android.net.wifi.WifiManager;
import android.os.Bundle;
import android.os.IBinder;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.MenuItem;
import android.widget.Toast;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ScrollView;
import android.widget.TextView;
import android.widget.Toast;
import android.widget.ToggleButton;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.camera.core.ExperimentalGetImage;
import com.example.ueberwachungssystem.Detection.DetectionReport;
import com.example.ueberwachungssystem.Detection.Detector;
import com.example.ueberwachungssystem.Detection.VideoDetector;
import org.w3c.dom.Text;
import com.example.ueberwachungssystem.Detection.DetectorService;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
@ExperimentalGetImage
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
private Fragment aktuellesFragment;
WifiCommunication communication;
private TextView alarm;
private String text = "Das ist ein Alarm des Sensors";
//Buttons
private ToggleButton toggleKamera;
private ToggleButton btnAudio;
private ToggleButton btnBewegung;
//Detektoren
VideoDetector vd = new VideoDetector(this);
private void log(String nachricht) {
Log.d(this.getClass().getSimpleName(), nachricht);
}
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setTitle(this.getClass().getSimpleName());
setContentView(R.layout.activity_main);
alarm = findViewById(R.id.Alarm);
alarm.setText(text);
toggleKamera = findViewById(R.id.toggleKamera);
toggleKamera.setOnClickListener(this);
vd.setOnDetectionListener(new Detector.OnDetectionListener() {
@Override
public void onDetection(@NonNull DetectionReport detectionReport) {
DetectionReport dr = detectionReport;
String drString = dr.toString();
}
});
//WifiCommunication communication;
PermissionRequest permission;
boolean communicationRunning = true;
TextView textview1;
//boolean isRunning = vd.isRunning();
private DetectorService detectorService = new DetectorService();
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Intent serviceIntent = new Intent(this, DetectorService.class);
bindService(serviceIntent, serviceConnection, Context.BIND_AUTO_CREATE);
startService(serviceIntent);
ToggleButton button1 = findViewById(R.id.toggleButton);
button1.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if(button1.isChecked()){
if(detectorService != null){
detectorService.videoDetector.startDetection();
}
}else{
detectorService.videoDetector.stopDetection();
}
}
});
//textview1 = findViewById(R.id.textView1);
//Button button1 = findViewById(R.id.buttonSend);
/*button1.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
communication.sendTrue("Testmessage");
}
});*/
}
private ServiceConnection serviceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
DetectorService.ServiceBinder binder = (DetectorService.ServiceBinder) service;
detectorService = binder.getBoundService();
detectorService.setOnDetectionListener(new DetectorService.OnDetectionListener() {
@Override
public void onDetection(StringBuffer stringBuffer) {
//textview für oli
Log.d("Debugger", stringBuffer.toString());
}
});
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
};
@Override
public void onClick(View v) {
if (v == toggleKamera) {
if (toggleKamera.isChecked()) {
vd.startDetection();
} else {
vd.stopDetection();
}
protected void onResume() {
super.onResume();
/*if (communicationRunning){
communication = new WifiCommunication(1234);
communication.setOnConnectionListener(new WifiCommunication.OnConnectionListener() {
@Override
public void onConnection(String data) {
//Log.d("Test", data.toString());
runOnUiThread(new Runnable() {
@Override
public void run() {
textview1.setText(data);
}
});
}
});
communicationRunning = false;
}*/
permission = new PermissionRequest(MainActivity.this);
permission.rechtePruefen();
}
}
@Override
protected void onPause() {
super.onPause();
communication.stopCommunication();
//communication.stopCommunication();
}
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.options_menu, menu);
return true;
}
/*public boolean onOptionsItemSelected(MenuItem item) {
Toast.makeText(this, "Selected Item: " + item.getTitle(), Toast.LENGTH_SHORT).show();
PopUpClass popUpClass;
switch (item.getItemId()) {
case R.id.Rechteverwaltung:
popUpClass = new PopUpClass(MainActivity.this);
popUpClass.showPopupWindow(textview1);
popUpClass.RechtePrüfen();
return true;
case R.id.Sensoren:
popUpClass = new PopUpClass(MainActivity.this);
popUpClass.showPopupWindow(textview1);
popUpClass.Sensoren();
return true;
case R.id.Impressum:
popUpClass = new PopUpClass(MainActivity.this);
popUpClass.showPopupWindow(textview1);
popUpClass.Impressum();
return true;
default:
return super.onOptionsItemSelected(item);
}
}*/
@Override
protected void onResume() {
super.onResume();
communication = new WifiCommunication(MainActivity.this, 1234);
}
public void onClickZeigeFragment1(View view) {
Button button = (Button) view;
log(button.getText() + " ausgewählt");
zeigeFragment(Fragment1.erstellen("Fragment 1 wurde angeklickt"));
}
public void onClickZeigeFragment2(View view) {
Button button = (Button) view;
log(button.getText() + " ausgewählt");
zeigeFragment(Fragment2.erstellen("Fragment 2 wurde angeklickt"));
}
public void onClickZeigeFragment3(View view) {
Button button = (Button) view;
log(button.getText() + " ausgewählt");
zeigeFragment(Fragment3.erstellen("Fragment 3 wurde angeklickt"));
}
public void onClickEntferneFragment(View view) {
entferneFragment();
}
private void zeigeFragment(Fragment fragment) {
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
ft.replace(R.id.frame, fragment);
ft.commit();
aktuellesFragment = fragment;
}
private void entferneFragment() {
if (aktuellesFragment != null) {
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
ft.remove(aktuellesFragment);
ft.commit();
aktuellesFragment = null ;
}
}
public static class Fragment1 extends Fragment {
private String text;
private final static String KEY_TEXT = "KEY_TEXT";
private void log(String nachricht) {
Log.d(this.getClass().getSimpleName(), nachricht);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle bundle) {
log("onCreateView");
View view = inflater.inflate(R.layout.fragment1, container, false);
TextView Sensor = (TextView) view.findViewById(R.id.Sensor);
Sensor.setText(text);
return view;
}
public static Fragment1 erstellen(String text) {
Fragment1 fragment = new Fragment1();
Bundle b = new Bundle();
b.putString(KEY_TEXT, text);
fragment.setArguments(b);
return fragment;
}
@Override
public void onCreate(Bundle bundle) {
super .onCreate(bundle);
Bundle args = getArguments();
if (args != null ) {
text = args.getString(KEY_TEXT);
log("onCreate: text=" + text);
} else {
log("onCreate");
}
}
}
public static class Fragment2 extends Fragment {
private String text;
private final static String KEY_TEXT = "KEY_TEXT" ;
private void log(String nachricht) {
Log.d(this.getClass().getSimpleName(), nachricht);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle bundle) {
log( "onCreateView" );
View view = inflater.inflate(R.layout.fragment2, container, false );
TextView Sensor = (TextView) view.findViewById(R.id.Sensor);
Sensor.setText(text);
return view;
}
public static Fragment2 erstellen(String text) {
Fragment2 fragment = new Fragment2();
Bundle b = new Bundle();
b.putString(KEY_TEXT, text);
fragment.setArguments(b);
return fragment;
}
@Override
public void onCreate(Bundle bundle) {
super.onCreate(bundle);
Bundle args = getArguments();
if (args != null) {
text = args.getString(KEY_TEXT);
log("onCreate: text=" + text);
} else {
log("onCreate");
}
}
}
public static class Fragment3 extends Fragment {
private String text;
private final static String KEY_TEXT = "KEY_TEXT" ;
private void log(String nachricht) {
Log.d(this.getClass().getSimpleName(), nachricht);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle bundle) {
log( "onCreateView" );
View view = inflater.inflate(R.layout.fragment2, container, false );
TextView Sensor = (TextView) view.findViewById(R.id.Sensor);
Sensor.setText(text);
return view;
}
public static Fragment3 erstellen(String text) {
Fragment3 fragment = new Fragment3();
Bundle b = new Bundle();
b.putString(KEY_TEXT, text);
fragment.setArguments(b);
return fragment;
}
@Override
public void onCreate(Bundle bundle) {
super.onCreate(bundle);
Bundle args = getArguments();
if (args != null) {
text = args.getString(KEY_TEXT);
log("onCreate: text=" + text);
} else {
log("onCreate");
}
}
}
}
@@ -0,0 +1,43 @@
package com.example.ueberwachungssystem;
import android.app.Activity;
import android.content.Context;
import android.content.pm.PackageManager;
import android.widget.Toast;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;
public class PermissionHandler {
private final Context context;
private static final int PERMISSION_REQUEST_CODE = 23409;
private static final String[] permissions = new String[]{
android.Manifest.permission.CAMERA,
android.Manifest.permission.RECORD_AUDIO
};
public PermissionHandler(Context context) {
this.context = context;
}
public boolean hasPermissions() {
boolean permissionState = true;
for (String permission: permissions) {
permissionState = permissionState && ContextCompat.checkSelfPermission(context, permission) == PackageManager.PERMISSION_GRANTED;
}
return permissionState;
}
public void getPermissions() {
if (!hasPermissions())
ActivityCompat.requestPermissions((Activity) context, permissions, PERMISSION_REQUEST_CODE);
}
public void showPermissionToast() {
if (hasPermissions())
Toast.makeText(context, "permissions available", Toast.LENGTH_SHORT).show();
else
Toast.makeText(context, "permissions missing", Toast.LENGTH_SHORT).show();
}
}
@@ -0,0 +1,48 @@
package com.example.ueberwachungssystem;
import static android.Manifest.permission.INTERNET;
import static android.Manifest.permission.CAMERA;
import static android.Manifest.permission.RECORD_AUDIO;
import android.content.pm.PackageManager;
import android.os.Handler;
import android.widget.Toast;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.content.ContextCompat;
public class PermissionRequest extends AppCompatActivity{
private static final int PERMISSION_REQUEST_CODE = 123;
private final MainActivity mainActivity;
Handler handler = new Handler();
public PermissionRequest(MainActivity mainActivity) {
this.mainActivity = mainActivity;
}
public StringBuilder rechtePruefen() {
boolean rechtKamera = ContextCompat.checkSelfPermission(mainActivity, CAMERA) == PackageManager.PERMISSION_GRANTED;
boolean rechtMikrofon = ContextCompat.checkSelfPermission(mainActivity, RECORD_AUDIO) == PackageManager.PERMISSION_GRANTED;
boolean rechtInternet = ContextCompat.checkSelfPermission(mainActivity, INTERNET) == PackageManager.PERMISSION_GRANTED;
StringBuilder sb = new StringBuilder();
sb.append("Rechte prüfen:")
.append("\nKamera: ").append(rechtKamera)
.append("\nMikrofon: ").append(rechtMikrofon)
.append("\nInternet: ").append(rechtInternet);
//mainActivity.runOnUiThread(() -> mainActivity.tvMessages.setText(sb));
if (!(rechtKamera && rechtMikrofon && rechtInternet)){
handler.post(new Runnable() {
@Override
public void run() {
Toast.makeText(mainActivity.getApplicationContext(),"Es werden Rechte benötigt", Toast.LENGTH_LONG).show();
}
});
}
return sb;
}
public void rechteAnfordern() {
mainActivity.requestPermissions(new String[]{CAMERA, RECORD_AUDIO, INTERNET}, PERMISSION_REQUEST_CODE);
}
}
@@ -0,0 +1,85 @@
package com.example.ueberwachungssystem;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.widget.Button;
import android.widget.LinearLayout;
import android.widget.PopupWindow;
import android.widget.TextView;
public class PopUpClass {
private final MainActivity mainActivity;
PermissionRequest permission;
TextView PopUpText;
public PopUpClass(MainActivity mainActivity) {
this.mainActivity = mainActivity;
permission = new PermissionRequest(mainActivity);
}
//PopupWindow display method
public void showPopupWindow(final View view) {
//Create a View object yourself through inflater
LayoutInflater inflater = (LayoutInflater) view.getContext().getSystemService(view.getContext().LAYOUT_INFLATER_SERVICE);
View popupView = inflater.inflate(R.layout.popup_window, null);
//Specify the length and width through constants
int width = LinearLayout.LayoutParams.WRAP_CONTENT;
int height = LinearLayout.LayoutParams.WRAP_CONTENT;
//Make Inactive Items Outside Of PopupWindow
boolean focusable = true;
//Create a window with our parameters
final PopupWindow popupWindow = new PopupWindow(popupView,width*1, height*1, focusable);
//Set the location of the window on the screen
popupWindow.showAtLocation(view, Gravity.CENTER, 0, 0);
//Initialize the elements of our window, install the handler
PopUpText = popupView.findViewById(R.id.titleText);
Button buttonEdit = popupView.findViewById(R.id.RechteAnfordern);
buttonEdit.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {RechteAnfordern();
}
});
//Handler for clicking on the inactive zone of the window
popupView.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
//Close the window when clicked
popupWindow.dismiss();
return true;
}
});
}
public void RechtePrüfen(){
StringBuilder Text = permission.rechtePruefen();
PopUpText.setText(Text);
}
public void RechteAnfordern(){
permission.rechteAnfordern();
StringBuilder Text = permission.rechtePruefen();
PopUpText.setText(Text);
}
public void Sensoren(){
PopUpText.setText("Es können 3 verschiedene Sensoren verwendet werden \n -1. Beschleunigungssensor\n -2. Mikrofon\n -3. Kamera");
}
public void Impressum(){
PopUpText.setText("Die Ueberwachungsapp wurde im Rahmen eines Praktikums der TH-Nürnberg programmiert");
}
}
@@ -1,5 +1,13 @@
package com.example.ueberwachungssystem;
import android.annotation.SuppressLint;
import android.util.Log;
import android.widget.Toast;
import androidx.annotation.NonNull;
import com.example.ueberwachungssystem.Detection.DetectionReport;
import com.example.ueberwachungssystem.Detection.Detector;
import com.example.ueberwachungssystem.Detection.DetectorService;
import java.io.IOException;
import java.net.DatagramPacket;
@@ -14,7 +22,7 @@ import java.util.Date;
import java.util.Enumeration;
public class WifiCommunication {
private final MainActivity mainActivity;
//private final MainActivity mainActivity;
private final InetAddress address;
private final int port;
@@ -22,9 +30,11 @@ public class WifiCommunication {
volatile private boolean send;
private final DatagramSocket socket;
volatile private boolean running;
private OnConnectionListener listener;
@SuppressLint("SetTextI18n")
public WifiCommunication(MainActivity mainActivity, int port) {
this.mainActivity = mainActivity;
public WifiCommunication(int port) {
//this.mainActivity = mainActivity;
this.port = port;
try {
socket = new DatagramSocket(this.port);
@@ -37,8 +47,23 @@ public class WifiCommunication {
} catch (SocketException | UnknownHostException e) {
throw new RuntimeException(e);
}
//Toast.makeText(mainActivity.getApplicationContext(),"Communication running", Toast.LENGTH_SHORT).show();
//mainActivity.runOnUiThread(() -> mainActivity.tvMessages.setText("Communication running"));
}
public interface OnConnectionListener {
void onConnection(String data);
}
public void setOnConnectionListener(@NonNull OnConnectionListener listener) {
this.listener = listener;
}
public void sendWifiData(String wifiMessage) {
if (listener != null) {
listener.onConnection(wifiMessage);
}
}
private class ReceiveThread extends Thread {
private StringBuffer rxStringBuffer = new StringBuffer();
private String rxString="";
@@ -49,20 +74,18 @@ public class WifiCommunication {
try {
do {
byte[] receiveData = new byte[512];
InetAddress fromAdress;
int fromPort;
DatagramPacket rxPacket = new DatagramPacket(receiveData, receiveData.length);
socket.receive(rxPacket);
fromAdress = rxPacket.getAddress();
fromPort = rxPacket.getPort();
rxString = new String(rxPacket.getData());
if(!previousRxString.equals(rxString)) {
rxStringBuffer.append(rxString).append("\n");
rxString = new String(receiveData, 0, rxPacket.getLength());
String[] splitrxString = rxString.split(",");
Log.d("empfangen", rxString);
if(!previousRxString.equals(rxString) && splitrxString[0].equals("1") && splitrxString.length==7) {
//rxStringBuffer.append(rxString).append("\n");
sendWifiData(rxString);
//mainActivity.runOnUiThread(() -> mainActivity.tvMessages.setText(rxStringBuffer));
previousRxString = rxString;
}
} while (running);
}
catch (IOException e) {
@@ -79,22 +102,15 @@ public class WifiCommunication {
if(send)
{
send = false;
SimpleDateFormat formatter = new SimpleDateFormat("HH:mm:ss");
Date curDate = new Date(System.currentTimeMillis());
String str = formatter.format(curDate);
byte[] send_Data = new byte[512];
String txString = (str+ ",Gruppe2," + getLocalIpAddress() + ",An,Video," +messageToSend);
String txString = (messageToSend);
send_Data = txString.getBytes();
DatagramPacket txPacket = new DatagramPacket(send_Data, txString.length(), address, port);
for(int i = 0; i < 500; i++) {
socket.send(txPacket);
/*try{
sleep(10);
}catch (InterruptedException e){
e.printStackTrace();
}*/
Log.d("senden", txPacket.getData().toString());
}
}
} while (running);
+32 -114
View File
@@ -1,123 +1,41 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@android:color/holo_green_dark"
android:visibility="visible"
tools:context="com.example.ueberwachungssystem.MainActivity"
tools:visibility="visible">
android:layout_gravity="center"
android:gravity="top"
android:orientation="vertical"
tools:context=".MainActivity">
<ToggleButton
android:id="@+id/toggleKamera"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignBottom="@id/toggleAudio"
android:layout_marginRight="15dp"
android:layout_toStartOf="@+id/toggleAudio"
android:layout_toLeftOf="@id/toggleAudio"
android:text="Kamera" />
<ToggleButton
android:id="@+id/toggleAudio"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_centerHorizontal="true"
android:text="Audio" />
<ToggleButton
android:id="@+id/toggleBewegung"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignBottom="@id/toggleAudio"
android:layout_marginLeft="15dp"
android:layout_toEndOf="@+id/toggleAudio"
android:layout_toRightOf="@id/toggleAudio"
android:text="Bewegung" />
<Button
android:id="@+id/btnAudio"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignBottom="@id/btnKamera"
android:layout_marginRight="15dp"
android:layout_toStartOf="@+id/btnKamera"
android:onClick="onClickZeigeFragment1"
android:text="Audio" />
<Button
android:id="@+id/btnKamera"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/toggleAudio"
android:layout_centerHorizontal="true"
android:onClick="onClickZeigeFragment2"
android:text="Kamera" />
<!--
<Button
android:id="@+id/btnSensorWeg"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_below="@+id/btn1"
android:text="Entferne Sensordarstellung"
android:onClick="onClickEntferneFragment"/>
-->
<Button
android:id="@+id/btnBewegung"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignBottom="@id/btnKamera"
android:layout_marginLeft="15dp"
android:layout_toEndOf="@+id/btnKamera"
android:layout_toRightOf="@id/btnKamera"
android:onClick="onClickZeigeFragment3"
android:text="Bewegung" />
<Button
android:id="@+id/btnAufnahme"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@+id/btnKamera"
android:layout_toLeftOf="@id/btnKamera"
android:layout_marginRight="15dp"
android:onClick="onClickEntferneFragment"
android:text="Aufnahme" />
<Button
android:id="@+id/btnWiedergabe"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@+id/btnKamera"
android:layout_toRightOf="@id/btnKamera"
android:layout_marginLeft="15dp"
android:onClick="onClickEntferneFragment"
android:text="Wiedergabe" />
<FrameLayout
android:id="@+id/frame"
<androidx.camera.view.PreviewView
android:id="@+id/previewView"
android:layout_width="match_parent"
android:layout_height="200dp"
android:layout_below="@+id/btnAufnahme"
android:layout_alignParentStart="true">
</FrameLayout>
android:layout_height="wrap_content"
android:backgroundTint="@android:color/black"/>
<ScrollView
android:id= "@+id/scrollView1"
android:layout_width= "wrap_content"
android:layout_height= "wrap_content"
android:layout_below= "@id/frame">
<LinearLayout
android:layout_width= "match_parent"
android:layout_height= "match_parent"
android:orientation= "vertical" >
<TextView
android:id= "@+id/Alarm"
android:layout_width= "wrap_content"
android:layout_height= "wrap_content" />
</LinearLayout>
</ScrollView>
<ToggleButton
android:id="@+id/toggleButton"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="ToggleButton" />
</RelativeLayout>
<ImageView
android:id="@+id/inputImageView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
tools:srcCompat="@tools:sample/avatars" />
<ImageView
android:id="@+id/outputImageView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
tools:srcCompat="@tools:sample/avatars" />
<androidx.camera.view.PreviewView
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
+29
View File
@@ -0,0 +1,29 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingLeft="10dp"
android:paddingRight="10dp"
android:gravity="center"
android:background="#A5ACB2">
<TextView
android:id="@+id/titleText"
android:layout_gravity="center"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="20sp"
android:textStyle="italic"
android:padding="10dp"/>
<Button
android:id="@+id/RechteAnfordern"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="Rechte Anfordern" />
</LinearLayout>
+9
View File
@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android" >
<item android:id="@+id/Rechteverwaltung"
android:title="Rechteverwaltung" />
<item android:id="@+id/Sensoren"
android:title="Sensoren" />
<item android:id="@+id/Impressum"
android:title="Impressum" />
</menu>
+2 -2
View File
@@ -1,5 +1,5 @@
// Top-level build file where you can add configuration options common to all sub-projects/modules.
plugins {
id 'com.android.application' version '7.4.2' apply false
id 'com.android.library' version '7.4.2' apply false
id 'com.android.application' version '8.0.0' apply false
id 'com.android.library' version '8.0.0' apply false
}
+2
View File
@@ -19,3 +19,5 @@ android.useAndroidX=true
# resources declared in the library itself and none from the library's dependencies,
# thereby reducing the size of the R class for that library
android.nonTransitiveRClass=true
android.defaults.buildfeatures.buildconfig=true
android.nonFinalResIds=false
+1 -1
View File
@@ -1,6 +1,6 @@
#Thu May 11 15:19:24 CEST 2023
distributionBase=GRADLE_USER_HOME
distributionUrl=https\://services.gradle.org/distributions/gradle-7.5-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-8.0-bin.zip
distributionPath=wrapper/dists
zipStorePath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
+1
View File
@@ -14,3 +14,4 @@ dependencyResolutionManagement {
}
rootProject.name = "Ueberwachungssystem"
include ':app'
include ':app'