# 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.xmlKommunikationcopie
testImplementation 'junit:junit:4.13.2' | testImplementation 'junit:junit:4.13.2' | ||||
androidTestImplementation 'androidx.test.ext:junit:1.1.5' | androidTestImplementation 'androidx.test.ext:junit:1.1.5' | ||||
androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1' | 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}" | |||||
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}" | |||||
} | } |
<manifest xmlns:android="http://schemas.android.com/apk/res/android" | <manifest xmlns:android="http://schemas.android.com/apk/res/android" | ||||
xmlns:tools="http://schemas.android.com/tools"> | xmlns:tools="http://schemas.android.com/tools"> | ||||
<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_WIFI_STATE" /> | ||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> | <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> | ||||
<uses-permission android:name="android.permission.INTERNET" /> | <uses-permission android:name="android.permission.INTERNET" /> | ||||
<uses-permission android:name="android.permission.CAMERA" /> <!-- §permissionCamera§ --> | |||||
<uses-permission android:name="android.permission.RECORD_AUDIO" /> | |||||
<application | <application | ||||
android:allowBackup="true" | android:allowBackup="true" | ||||
android:fullBackupContent="@xml/backup_rules" | android:fullBackupContent="@xml/backup_rules" | ||||
android:icon="@mipmap/ic_launcher" | android:icon="@mipmap/ic_launcher" | ||||
android:label="@string/app_name" | android:label="@string/app_name" | ||||
android:roundIcon="@mipmap/ic_launcher_round" | |||||
android:supportsRtl="true" | android:supportsRtl="true" | ||||
android:theme="@style/Theme.Ueberwachungssystem" | android:theme="@style/Theme.Ueberwachungssystem" | ||||
tools:targetApi="31"> | tools:targetApi="31"> | ||||
<activity | <activity | ||||
android:name=".MainActivity" | android:name=".MainActivity" | ||||
android:exported="true" | |||||
android:label="Ueberwachungsapp"> | |||||
android:exported="true"> | |||||
<intent-filter> | <intent-filter> | ||||
<action android:name="android.intent.action.MAIN" /> | <action android:name="android.intent.action.MAIN" /> | ||||
<category android:name="android.intent.category.LAUNCHER" /> | <category android:name="android.intent.category.LAUNCHER" /> | ||||
</intent-filter> | </intent-filter> | ||||
</activity> | </activity> | ||||
<service android:name=".Detection.DetectorService"/> | |||||
</application> | </application> | ||||
</manifest> | </manifest> |
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); | |||||
} | |||||
} |
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 boolean detectionState; | |||||
public DetectionReport(boolean detectionState, String detectionType, float detectedAmplitude) { | |||||
this.timeStamp = String.valueOf(Calendar.getInstance().getTime()); | |||||
this.detectionType = detectionType; | |||||
this.detectedValue = detectedAmplitude; | |||||
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 + "]"; | |||||
return String.join("\t", state, time, type, value); | |||||
} | |||||
/** Debug Report */ | |||||
public void log(String tag) { | |||||
Log.d(tag, this.toString()); | |||||
} | |||||
} |
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() {} | |||||
/** 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 detectionType, float amplitude) { | |||||
if (listener != null) { | |||||
if (!isDetecting) { | |||||
isDetecting = true; | |||||
DetectionReport detectionReport = new DetectionReport(true, detectionType, amplitude); | |||||
listener.onDetection(detectionReport); | |||||
startDetectionTimer(detectionType, amplitude); | |||||
} else { | |||||
extendViolation = true; | |||||
} | |||||
} else { | |||||
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(); | |||||
/** Stops Detection (abstract method: needs to be overridden in child class) */ | |||||
public abstract void stopDetection(); | |||||
} |
package com.example.ueberwachungssystem.Detection; | |||||
import android.content.Intent; | |||||
import android.os.Binder; | |||||
import android.os.IBinder; | |||||
import android.widget.ImageView; | |||||
import androidx.annotation.NonNull; | |||||
import androidx.annotation.Nullable; | |||||
import androidx.camera.core.ExperimentalGetImage; | |||||
import androidx.lifecycle.LifecycleService; | |||||
import java.io.File; | |||||
@ExperimentalGetImage | |||||
public class DetectorService extends LifecycleService { | |||||
public ServiceBinder serviceBinder = new ServiceBinder(); | |||||
private DetectorService.OnDetectionListener listener; | |||||
private boolean isServiceRunning = false; | |||||
VideoDetector videoDetector = null; | |||||
AudioRecorder audioRecorder = null; | |||||
@Override | |||||
public int onStartCommand(Intent intent, int flags, int startId) { | |||||
if (isServiceRunning) | |||||
return START_NOT_STICKY; | |||||
// Setup Service classes: | |||||
videoDetector = new VideoDetector(this); | |||||
videoDetector.setOnDetectionListener(new Detector.OnDetectionListener() { | |||||
@Override | |||||
public void onDetection(@NonNull DetectionReport detectionReport) { | |||||
passToServiceListener(detectionReport); | |||||
} | |||||
}); | |||||
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; | |||||
} | |||||
/** Video Detection */ | |||||
public void startVideoDetection() { | |||||
if(videoDetector != null) | |||||
videoDetector.startDetection(); | |||||
} | |||||
public void stopVideoDetection() { | |||||
if(videoDetector != null) | |||||
videoDetector.stopDetection(); | |||||
} | |||||
public boolean isVideoDetectionRunning() { | |||||
if(videoDetector != null) | |||||
return videoDetector.isDetecting(); | |||||
return false; | |||||
} | |||||
public void debugVideoProcessing(ImageView input, ImageView output) { | |||||
if(videoDetector != null) | |||||
videoDetector.debugProcessing(input, output); | |||||
} | |||||
/** Audio Detection */ | |||||
public void startAudioDetection() { | |||||
} | |||||
public void stopAudioDetection() { | |||||
} | |||||
/** Motion Detection */ | |||||
public void startMotionDetection() { | |||||
} | |||||
public void stopMotionDetection() { | |||||
} | |||||
/** Video Recording */ | |||||
public void startVideoRecording() { | |||||
if(videoDetector != null) | |||||
videoDetector.startRecording(); | |||||
} | |||||
public void stopVideoRecording() { | |||||
if(videoDetector != null) | |||||
videoDetector.stopRecording(); | |||||
} | |||||
public boolean isVideoRecordingRunning() { | |||||
if(videoDetector != null) | |||||
return videoDetector.isRecording(); | |||||
return false; | |||||
} | |||||
public void setVideoRecordingDir(File outputDir) { | |||||
if (videoDetector != null) | |||||
videoDetector.setOutputDir(outputDir); | |||||
} | |||||
/** Audio Recording */ | |||||
public void startAudioRecording() { | |||||
if(audioRecorder != null) | |||||
audioRecorder.startRecording(); | |||||
} | |||||
public void stopAudioRecording() { | |||||
if(audioRecorder != null) | |||||
audioRecorder.stopRecording(); | |||||
} | |||||
public boolean isAudioRecordingRunning() { | |||||
if(videoDetector != null) | |||||
return audioRecorder.isRecording(); | |||||
return false; | |||||
} | |||||
public void setAudioRecordingDir(File outputDir) { | |||||
if (audioRecorder != null) | |||||
audioRecorder.setOutputDir(outputDir); | |||||
} | |||||
/** pass Detection Report to Service Detection Listener and trigger it */ | |||||
public void passToServiceListener(DetectionReport detectionReport) { | |||||
if (listener != null) { | |||||
listener.onDetection(detectionReport); | |||||
} | |||||
} | |||||
/** On Detection Listener - runs when violation is reported */ | |||||
public interface OnDetectionListener { | |||||
void onDetection(@NonNull DetectionReport detectionReport); | |||||
} | |||||
public void setOnDetectionListener(@NonNull DetectorService.OnDetectionListener listener) { | |||||
this.listener = listener; | |||||
} | |||||
} |
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); | |||||
} | |||||
} |
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.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 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); | |||||
* */ | |||||
@ExperimentalGetImage | |||||
public class VideoDetector extends Detector { | |||||
// Calling Activity | |||||
private final Context context; | |||||
// Camera Provider | |||||
private ProcessCameraProvider cameraProvider; | |||||
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 */ | |||||
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 */ | |||||
@Override | |||||
public void startDetection() { | |||||
// Check States | |||||
if (isDetecting) | |||||
return; | |||||
// 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); | |||||
cameraProviderFuture.addListener(() -> { | |||||
try { | |||||
cameraProvider = cameraProviderFuture.get(); | |||||
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; | |||||
} | |||||
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 (!isDetecting || imageAnalysis == null) | |||||
return; | |||||
cameraProvider.unbind(imageAnalysis); | |||||
isDetecting = false; | |||||
allowReportViolation = false; | |||||
} | |||||
/** Stops the Recording */ | |||||
@SuppressLint("RestrictedApi") | |||||
public void stopRecording(){ | |||||
if(!isRecording) | |||||
return; | |||||
videoCapture.stopRecording(); | |||||
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(); | |||||
cameraProvider.bindToLifecycle((LifecycleOwner) context, cameraSelector, imageAnalysis, videoCapture); | |||||
} | |||||
/** Setup Use Cases */ | |||||
private ImageAnalysis setupImageAnalysis() { | |||||
// Configure and create Image Analysis | |||||
ImageAnalysis.Builder builder = new ImageAnalysis.Builder(); | |||||
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; | |||||
// Violation Handling | |||||
Mat processed = processImage(imageProxy); | |||||
int n = OpenCVHelper.countNonZeroPixels(processed); | |||||
int pixelCount = image.getWidth() * image.getHeight(); | |||||
float percentChanged = (float) n / pixelCount; | |||||
// Violation Condition | |||||
if (percentChanged * 100 > ALARM_THRESHOLD) { | |||||
if (allowReportViolation) | |||||
reportViolation("Video", percentChanged); | |||||
} | |||||
} | |||||
imageProxy.close(); | |||||
}); | |||||
return imageAnalysis; | |||||
} | |||||
@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; | |||||
} | |||||
/** | |||||
private void setPreviewView(@NonNull PreviewView previewView) { | |||||
// Create Preview | |||||
if (this.preview != null) | |||||
this.preview.setSurfaceProvider(previewView.getSurfaceProvider()); | |||||
} | |||||
*/ | |||||
/** 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); | |||||
} | |||||
/** Get current Display Rotation */ | |||||
private int getDisplayRotation() { | |||||
WindowManager windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); | |||||
Display display = windowManager.getDefaultDisplay(); | |||||
return display.getRotation(); | |||||
} | |||||
/** Start delay until Violation Report is allowed */ | |||||
private void startViolationTimer(float setupTime) { | |||||
new CountDownTimer((long) (START_DELAY), 100) { | |||||
@Override | |||||
public void onTick(long millisUntilFinished) { | |||||
} | |||||
@Override | |||||
public void onFinish() { | |||||
allowReportViolation = true; | |||||
} | |||||
}.start(); | |||||
} | |||||
public void setOutputDir(File outputDir) { | |||||
this.outputDir = outputDir; | |||||
} | |||||
} |
import android.annotation.SuppressLint; | import android.annotation.SuppressLint; | ||||
import android.net.wifi.WifiInfo; | import android.net.wifi.WifiInfo; | ||||
import android.net.wifi.WifiManager; | import android.net.wifi.WifiManager; | ||||
import android.net.wifi.WifiInfo; | |||||
import android.net.wifi.WifiManager; | |||||
import android.os.Bundle; | import android.os.Bundle; | ||||
import android.view.MenuItem; | |||||
import android.widget.Toast; | |||||
import android.view.Menu; | import android.view.Menu; | ||||
import android.view.MenuItem; | import android.view.MenuItem; | ||||
import android.view.View; | import android.view.View; | ||||
@SuppressLint("SetTextI18n") | @SuppressLint("SetTextI18n") | ||||
public class MainActivity extends AppCompatActivity { | public class MainActivity extends AppCompatActivity { | ||||
TextView tvMessages; | |||||
TextView tvConnectionInfos; | |||||
WifiCommunication communication; | WifiCommunication communication; | ||||
PermissionRequest permission; | PermissionRequest permission; | ||||
public static String SERVER_IP = ""; | |||||
public static final int SERVER_PORT = 1234; | |||||
//private static final int PERMISSION_REQUEST_CODE = 123; | |||||
float i=0; | |||||
boolean communicationRunning = false; | boolean communicationRunning = false; | ||||
@Override | |||||
protected void onCreate(Bundle savedInstanceState) { | |||||
super.onCreate(savedInstanceState); | |||||
setContentView(R.layout.activity_main); | |||||
} | |||||
@Override | @Override | ||||
protected void onCreate(Bundle savedInstanceState) { | |||||
super.onCreate(savedInstanceState); | |||||
setContentView(R.layout.activity_main); | |||||
tvMessages = findViewById(R.id.tvMessages); | |||||
tvConnectionInfos = findViewById(R.id.tvConnectionInfos); | |||||
try { | |||||
SERVER_IP = getLocalIpAddress(); | |||||
tvConnectionInfos.setText("Connection Infos: \n Own IP-Adress: " + SERVER_IP+ " Port: " + SERVER_PORT); | |||||
} catch (UnknownHostException e) { | |||||
e.printStackTrace(); | |||||
protected void onResume() { | |||||
super.onResume(); | |||||
if (!communicationRunning){ | |||||
communication = new WifiCommunication(MainActivity.this, SERVER_PORT); | |||||
communicationRunning = true; | |||||
} | } | ||||
Button btnSend = findViewById(R.id.btnSend); | |||||
btnSend.setOnClickListener(new View.OnClickListener() { | |||||
@Override | |||||
public void onClick(View v) { | |||||
i++; | |||||
communication.sendTrue(String.valueOf(i)); | |||||
} | |||||
}); | |||||
permission = new PermissionRequest(MainActivity.this); | |||||
permission.rechtePruefen(); | |||||
} | |||||
@Override | |||||
protected void onPause() { | |||||
super.onPause(); | |||||
//communication.stopCommunication(); | |||||
} | } | ||||
public boolean onCreateOptionsMenu(Menu menu) { | public boolean onCreateOptionsMenu(Menu menu) { | ||||
getMenuInflater().inflate(R.menu.options_menu, menu); | getMenuInflater().inflate(R.menu.options_menu, menu); | ||||
return true; | return true; | ||||
} | } | ||||
public boolean onOptionsItemSelected(MenuItem item) { | public boolean onOptionsItemSelected(MenuItem item) { | ||||
Toast.makeText(this, "Selected Item: " +item.getTitle(), Toast.LENGTH_SHORT).show(); | |||||
Toast.makeText(this, "Selected Item: " + item.getTitle(), Toast.LENGTH_SHORT).show(); | |||||
PopUpClass popUpClass; | PopUpClass popUpClass; | ||||
switch (item.getItemId()) { | switch (item.getItemId()) { | ||||
case R.id.Rechteverwaltung: | case R.id.Rechteverwaltung: | ||||
return super.onOptionsItemSelected(item); | return super.onOptionsItemSelected(item); | ||||
} | } | ||||
} | } | ||||
protected void onResume() { | |||||
super.onResume(); | |||||
if (!communicationRunning){ | |||||
communication = new WifiCommunication(MainActivity.this, SERVER_PORT); | |||||
communicationRunning = true; | |||||
} | |||||
permission = new PermissionRequest(MainActivity.this); | |||||
permission.rechtePruefen(); | |||||
} | |||||
@Override | |||||
protected void onPause() { | |||||
super.onPause(); | |||||
//communication.stopCommunication(); | |||||
} | |||||
private String getLocalIpAddress() throws UnknownHostException { | private String getLocalIpAddress() throws UnknownHostException { | ||||
WifiManager wifiManager = (WifiManager) getApplicationContext().getSystemService(WIFI_SERVICE); | WifiManager wifiManager = (WifiManager) getApplicationContext().getSystemService(WIFI_SERVICE); | ||||
assert wifiManager != null; | assert wifiManager != null; | ||||
return InetAddress.getByAddress(ByteBuffer.allocate(4).order(ByteOrder.LITTLE_ENDIAN).putInt(ipInt).array()).getHostAddress(); | return InetAddress.getByAddress(ByteBuffer.allocate(4).order(ByteOrder.LITTLE_ENDIAN).putInt(ipInt).array()).getHostAddress(); | ||||
} | } | ||||
} | } | ||||
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(); | |||||
} | |||||
} |
<?xml version = "1.0" encoding = "utf-8"?> | |||||
<RelativeLayout xmlns:android = "http://schemas.android.com/apk/res/android" | |||||
xmlns:tools = "http://schemas.android.com/tools" | |||||
android:layout_width = "match_parent" | |||||
android:layout_height = "match_parent" | |||||
android:layout_margin = "16dp" | |||||
tools:context = ".MainActivity"> | |||||
<TextView | |||||
android:id = "@+id/tvConnectionInfos" | |||||
android:layout_width = "match_parent" | |||||
android:layout_height = "wrap_content" | |||||
android:inputType = "textMultiLine" | |||||
android:hint="ConnectionInfos" | |||||
android:textAppearance = "@style/Base.TextAppearance.AppCompat.Medium" /> | |||||
<?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" | |||||
xmlns:tools="http://schemas.android.com/tools" | |||||
android:layout_width="match_parent" | |||||
android:layout_height="match_parent" | |||||
android:layout_gravity="center" | |||||
android:gravity="top" | |||||
android:orientation="vertical" | |||||
tools:context=".MainActivity"> | |||||
<Button | |||||
android:id="@+id/btnSend" | |||||
android:layout_width="wrap_content" | |||||
<androidx.camera.view.PreviewView | |||||
android:id="@+id/previewView" | |||||
android:layout_width="match_parent" | |||||
android:layout_height="wrap_content" | android:layout_height="wrap_content" | ||||
android:layout_below="@id/scrollView" | |||||
android:layout_centerHorizontal="true" | |||||
android:text="SEND" /> | |||||
android:backgroundTint="@android:color/black"/> | |||||
<ScrollView | |||||
android:id="@+id/scrollView" | |||||
<ToggleButton | |||||
android:id="@+id/toggleButton" | |||||
android:layout_width="match_parent" | android:layout_width="match_parent" | ||||
android:layout_below="@id/tvConnectionInfos" | |||||
android:layout_height="300dp"> | |||||
<TextView | |||||
android:id = "@+id/tvMessages" | |||||
android:layout_width = "match_parent" | |||||
android:layout_height = "wrap_content" | |||||
android:hint="Messages" | |||||
android:inputType = "textMultiLine" | |||||
android:textAppearance = "@style/Base.TextAppearance.AppCompat.Medium" /> | |||||
</ScrollView> | |||||
</RelativeLayout> | |||||
android:layout_height="wrap_content" | |||||
android:text="ToggleButton" /> | |||||
<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> |