Compare commits
1
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8dd4c6d56a |
No files matched your search
@@ -35,4 +35,10 @@ dependencies {
|
|||||||
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'
|
||||||
|
|
||||||
|
def camerax_version = "1.2.3"
|
||||||
|
implementation "androidx.camera:camera-camera2:${camerax_version}"
|
||||||
|
implementation "androidx.camera:camera-lifecycle:${camerax_version}"
|
||||||
|
implementation "androidx.camera:camera-view:${camerax_version}"
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -3,11 +3,9 @@
|
|||||||
package="com.example.greenwatch">
|
package="com.example.greenwatch">
|
||||||
|
|
||||||
<uses-permission android:name="android.permission.INTERNET" />
|
<uses-permission android:name="android.permission.INTERNET" />
|
||||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
|
<uses-permission android:name="android.permission.CAMERA"/>
|
||||||
<uses-permission android:name="android.permission.READ_MEDIA_AUDIO" />
|
|
||||||
<uses-permission android:name="android.permission.READ_MEDIA_VIDEO" />
|
<uses-feature android:name="android.hardware.camera"/>
|
||||||
<uses-permission android:name="android.permission.RECORD_AUDIO" />
|
|
||||||
<uses-permission android:name="android.permission.CAMERA" />
|
|
||||||
|
|
||||||
<application
|
<application
|
||||||
android:allowBackup="true"
|
android:allowBackup="true"
|
||||||
|
|||||||
@@ -57,6 +57,7 @@ public class MainActivity extends AppCompatActivity {
|
|||||||
|
|
||||||
mMainActivityViewModel = new ViewModelProvider(this).get(MainActivityViewModel.class);
|
mMainActivityViewModel = new ViewModelProvider(this).get(MainActivityViewModel.class);
|
||||||
mMainActivityViewModel.init();
|
mMainActivityViewModel.init();
|
||||||
|
mMainActivityViewModel.accessRequestCamera(this);
|
||||||
mMainActivityViewModel.getConnectedDeviceList().observe(this, new Observer<List<Device>>() {
|
mMainActivityViewModel.getConnectedDeviceList().observe(this, new Observer<List<Device>>() {
|
||||||
@Override
|
@Override
|
||||||
public void onChanged(List<Device> devices) {
|
public void onChanged(List<Device> devices) {
|
||||||
@@ -82,10 +83,13 @@ public class MainActivity extends AppCompatActivity {
|
|||||||
videodetectionButton.setOnClickListener(new View.OnClickListener() {
|
videodetectionButton.setOnClickListener(new View.OnClickListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onClick(View v) {
|
public void onClick(View v) {
|
||||||
//openVideodetectionActivity();
|
if (mMainActivityViewModel.isCameraAccessAllowed(MainActivity.this)) {
|
||||||
mMainActivityViewModel.setSensorType(mMainActivityViewModel.getLocalDeviceUUID(), "Video");
|
openVideodetectionActivity();
|
||||||
mMainActivityViewModel.setTimeStamp(mMainActivityViewModel.getLocalDeviceUUID(), "12:50");
|
}
|
||||||
mMainActivityViewModel.setDeviceID(mMainActivityViewModel.getLocalDeviceUUID(), "12345");
|
else {
|
||||||
|
mMainActivityViewModel.accessRequestCamera(MainActivity.this);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
accelerometerButton.setOnClickListener(new View.OnClickListener() {
|
accelerometerButton.setOnClickListener(new View.OnClickListener() {
|
||||||
|
|||||||
@@ -1,14 +1,32 @@
|
|||||||
package com.example.greenwatch;
|
package com.example.greenwatch;
|
||||||
|
|
||||||
import androidx.appcompat.app.AppCompatActivity;
|
import androidx.appcompat.app.AppCompatActivity;
|
||||||
|
import androidx.camera.lifecycle.ProcessCameraProvider;
|
||||||
|
import androidx.core.content.ContextCompat;
|
||||||
|
import androidx.lifecycle.Observer;
|
||||||
|
import androidx.lifecycle.ViewModelProvider;
|
||||||
|
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||||
|
import androidx.recyclerview.widget.RecyclerView;
|
||||||
|
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.widget.Button;
|
import android.widget.Button;
|
||||||
|
import android.widget.Toast;
|
||||||
|
|
||||||
|
import com.example.greenwatch.adapters.AlarmHistoryListAdapter;
|
||||||
|
import com.example.greenwatch.adapters.DeviceListAdapter;
|
||||||
|
import com.example.greenwatch.models.Device;
|
||||||
|
import com.example.greenwatch.viewmodels.AccelerometerViewModel;
|
||||||
|
import com.example.greenwatch.viewmodels.VideodetectionViewModel;
|
||||||
|
import com.google.common.util.concurrent.ListenableFuture;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.concurrent.ExecutionException;
|
||||||
|
|
||||||
public class VideodetectionActivity extends AppCompatActivity {
|
public class VideodetectionActivity extends AppCompatActivity {
|
||||||
|
|
||||||
private Button backToMainActivity;
|
private Button backToMainActivity;
|
||||||
|
private VideodetectionViewModel mVideoDetectionViewModel;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onCreate(Bundle savedInstanceState) {
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
@@ -17,11 +35,64 @@ public class VideodetectionActivity extends AppCompatActivity {
|
|||||||
|
|
||||||
backToMainActivity = (Button) findViewById(R.id.videodetectorBackToMainActivity);
|
backToMainActivity = (Button) findViewById(R.id.videodetectorBackToMainActivity);
|
||||||
|
|
||||||
|
RecyclerView recyclerView = findViewById(R.id.deviceListRecyclerView);
|
||||||
|
recyclerView.setLayoutManager(new LinearLayoutManager(this));
|
||||||
|
recyclerView.setHasFixedSize(true);
|
||||||
|
|
||||||
|
final DeviceListAdapter deviceListAdapter = new DeviceListAdapter();
|
||||||
|
recyclerView.setAdapter(deviceListAdapter);
|
||||||
|
|
||||||
|
RecyclerView alarmHistoryListRecyclerView = findViewById(R.id.alarmHistoryListRecyclerView);
|
||||||
|
alarmHistoryListRecyclerView.setLayoutManager(new LinearLayoutManager(this));
|
||||||
|
alarmHistoryListRecyclerView.setHasFixedSize(true);
|
||||||
|
|
||||||
|
final AlarmHistoryListAdapter alarmHistoryListAdapter = new AlarmHistoryListAdapter();
|
||||||
|
alarmHistoryListRecyclerView.setAdapter(alarmHistoryListAdapter);
|
||||||
|
|
||||||
backToMainActivity.setOnClickListener(new View.OnClickListener() {
|
backToMainActivity.setOnClickListener(new View.OnClickListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onClick(View v) {
|
public void onClick(View v) {
|
||||||
finish();
|
finish();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
mVideoDetectionViewModel = new ViewModelProvider(this).get(VideodetectionViewModel.class);
|
||||||
|
mVideoDetectionViewModel.init();
|
||||||
|
mVideoDetectionViewModel.getConnectedDeviceList().observe(this, new Observer<List<Device>>() {
|
||||||
|
@Override
|
||||||
|
public void onChanged(List<Device> devices) {
|
||||||
|
deviceListAdapter.setDevices(devices);
|
||||||
|
Toast.makeText(VideodetectionActivity.this, "onChanged", Toast.LENGTH_LONG).show();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
mVideoDetectionViewModel.getAlarmHistoryList().observe(this, new Observer<List<Device>>() {
|
||||||
|
@Override
|
||||||
|
public void onChanged(List<Device> devices) {
|
||||||
|
alarmHistoryListAdapter.setAlarmHistoryList(devices);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
mVideoDetectionViewModel.getVideoAlarmDetectedValue().observe(this, new Observer<Boolean>() {
|
||||||
|
@Override
|
||||||
|
public void onChanged(Boolean aBoolean) {
|
||||||
|
if (aBoolean) {
|
||||||
|
mVideoDetectionViewModel.updateDevice(mVideoDetectionViewModel.getLocalDeviceUUID(), mVideoDetectionViewModel.getSystemTimeStamp(), true, "Video", 10);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
mVideoDetectionViewModel.updateDevice(mVideoDetectionViewModel.getLocalDeviceUUID(), mVideoDetectionViewModel.getSystemTimeStamp(), false, "Video", 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
final ListenableFuture<ProcessCameraProvider> cameraProviderFuture = ProcessCameraProvider.getInstance(this);
|
||||||
|
cameraProviderFuture.addListener(() -> {
|
||||||
|
try {
|
||||||
|
mVideoDetectionViewModel.bindImageAnalysis(cameraProviderFuture.get(), this, this);
|
||||||
|
} catch (ExecutionException | InterruptedException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}, ContextCompat.getMainExecutor(this));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,246 +0,0 @@
|
|||||||
package com.example.greenwatch.alarmrecorder;
|
|
||||||
|
|
||||||
import android.media.MediaCodec;
|
|
||||||
import android.media.MediaExtractor;
|
|
||||||
import android.media.MediaFormat;
|
|
||||||
import android.media.MediaMuxer;
|
|
||||||
import android.media.MediaRecorder;
|
|
||||||
import android.os.Environment;
|
|
||||||
import android.widget.Toast;
|
|
||||||
|
|
||||||
import com.example.greenwatch.MainActivity;
|
|
||||||
import com.example.greenwatch.alarmrecorder.runnables.AudioRecorder;
|
|
||||||
import com.example.greenwatch.alarmrecorder.runnables.VideoRecorder;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.nio.ByteBuffer;
|
|
||||||
|
|
||||||
public class AlarmRecorder {
|
|
||||||
|
|
||||||
private boolean isRecording;
|
|
||||||
private String videoPath;
|
|
||||||
private String audioPath;
|
|
||||||
private MediaFormat videoFormat;
|
|
||||||
private MediaFormat audioFormat;
|
|
||||||
private MediaExtractor videoExtractor;
|
|
||||||
private MediaExtractor audioExtractor;
|
|
||||||
private Runnable audioRecorderRunnable;
|
|
||||||
private Runnable videoRecorderRunnable;
|
|
||||||
private MediaRecorder videoRecorder;
|
|
||||||
private MediaRecorder audioRecorder;
|
|
||||||
private Thread videoThread; // Video-Thread als Instanzvariable
|
|
||||||
private Thread audioThread; // Audio-Thread als Instanzvariable
|
|
||||||
|
|
||||||
public AlarmRecorder() {
|
|
||||||
audioRecorder = new MediaRecorder();
|
|
||||||
videoRecorder = new MediaRecorder();
|
|
||||||
videoExtractor = new MediaExtractor();
|
|
||||||
audioExtractor = new MediaExtractor();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private void startRecording() {
|
|
||||||
createStoragePaths(); //Speicherort und -namen für Audio- und Video-Datei
|
|
||||||
|
|
||||||
audioRecorderRunnable = new AudioRecorder(audioRecorder, audioPath);
|
|
||||||
videoRecorderRunnable = new VideoRecorder(videoRecorder, videoPath);
|
|
||||||
audioThread = new Thread(audioRecorderRunnable);
|
|
||||||
videoThread = new Thread(videoRecorderRunnable);
|
|
||||||
|
|
||||||
//Threads starten
|
|
||||||
videoThread.start();
|
|
||||||
audioThread.start();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void stopRecording() {
|
|
||||||
isRecording = false;
|
|
||||||
try {
|
|
||||||
stopVideoRecording();
|
|
||||||
stopAudioRecording();
|
|
||||||
|
|
||||||
runOnUiThread(new Runnable() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
Toast.makeText(MainActivity.this, "Video- und Audioaufzeichnung beendet", Toast.LENGTH_SHORT).show();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
waitTillThreadsStopped();
|
|
||||||
File videoFile = new File(videoPath); //Speichere das aufgenommene Video
|
|
||||||
File audioFile = new File(audioPath); //Speichere die aufgenommene Audio
|
|
||||||
|
|
||||||
if (videoFile.exists() && audioFile.exists()) {
|
|
||||||
//Wenn Video- und Audioaufzeichnung gestoppt und abgespeichert sind, beginne mit dem Mergeprozess der beiden
|
|
||||||
mergeVideoWithAudio();
|
|
||||||
} else {
|
|
||||||
Toast.makeText(MainActivity.this, "Dateien wurden nicht gefunden!", Toast.LENGTH_SHORT).show();
|
|
||||||
}
|
|
||||||
} catch (RuntimeException stopException) {
|
|
||||||
stopException.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void createStoragePaths(){
|
|
||||||
//Pfade zum Zwischenspeichern der aufgenommenen Audio und Video-Datei
|
|
||||||
isRecording = true;
|
|
||||||
String externalStorageDirectory = Environment.getExternalStorageDirectory().getAbsolutePath();
|
|
||||||
String dcimDirectory = externalStorageDirectory + "/DCIM";
|
|
||||||
videoPath = dcimDirectory + "/video.mp4";
|
|
||||||
audioPath = dcimDirectory + "/audio.mp3";
|
|
||||||
}
|
|
||||||
|
|
||||||
private void stopVideoRecording(){
|
|
||||||
if (videoRecorder != null) {
|
|
||||||
videoRecorder.stop();
|
|
||||||
videoRecorder.release();
|
|
||||||
videoRecorder = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void stopAudioRecording(){
|
|
||||||
if (audioRecorder != null) {
|
|
||||||
audioRecorder.stop();
|
|
||||||
audioRecorder.release();
|
|
||||||
audioRecorder = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void waitTillThreadsStopped(){
|
|
||||||
try {
|
|
||||||
videoThread.join();
|
|
||||||
audioThread.join();
|
|
||||||
} catch (InterruptedException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void mergeVideoWithAudio() {
|
|
||||||
try {
|
|
||||||
setVideoExtractorDataSource(); //extrahieren der Video Datei, die zuvor zwischengespeichert wurde
|
|
||||||
setAudioExtractorDataSource(); //extrahieren der Audio Datei, die zuvor zwischengespeichert wurde
|
|
||||||
|
|
||||||
//Speicherort der später zusammengeführten Datei
|
|
||||||
String outputFilePath = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_MOVIES).getAbsolutePath() + "/merged_video.mp4";
|
|
||||||
//MediaMuxer zum Zusammenführen einer Audio- und einer Videodatei
|
|
||||||
MediaMuxer muxer = new MediaMuxer(outputFilePath, MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4);
|
|
||||||
int videoTrack = muxer.addTrack(videoFormat);
|
|
||||||
int audioTrack = muxer.addTrack(audioFormat);
|
|
||||||
muxer.start();
|
|
||||||
|
|
||||||
ByteBuffer buffer = ByteBuffer.allocate(1024 * 1024);
|
|
||||||
MediaCodec.BufferInfo bufferInfo = new MediaCodec.BufferInfo();
|
|
||||||
|
|
||||||
videoExtraction(buffer, videoTrack, bufferInfo, muxer);
|
|
||||||
audioExtraction(buffer, audioTrack, bufferInfo, muxer);
|
|
||||||
|
|
||||||
muxer.stop();
|
|
||||||
muxer.release();
|
|
||||||
|
|
||||||
runOnUiThread(new Runnable() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
Toast.makeText(MainActivity.this, "Video und Audio erfolgreich zusammengeführt", Toast.LENGTH_SHORT).show();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// Löschen der separaten Video- und Audio-Dateien
|
|
||||||
deleteVideoFile();
|
|
||||||
deleteAudioFile();
|
|
||||||
} catch (IOException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void setVideoExtractorDataSource() {
|
|
||||||
try {
|
|
||||||
videoExtractor.setDataSource(videoPath);
|
|
||||||
int videoTrackIndex = getTrackIndex(videoExtractor, "video/");
|
|
||||||
if (videoTrackIndex < 0) {
|
|
||||||
// Video-Track nicht gefunden
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
videoExtractor.selectTrack(videoTrackIndex);
|
|
||||||
videoFormat = videoExtractor.getTrackFormat(videoTrackIndex);
|
|
||||||
} catch (IOException e) {
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void setAudioExtractorDataSource() {
|
|
||||||
try {
|
|
||||||
audioExtractor.setDataSource(audioPath);
|
|
||||||
int audioTrackIndex = getTrackIndex(audioExtractor, "audio/");
|
|
||||||
if (audioTrackIndex < 0) {
|
|
||||||
// Audio-Track nicht gefunden
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
audioExtractor.selectTrack(audioTrackIndex);
|
|
||||||
audioFormat = audioExtractor.getTrackFormat(audioTrackIndex);
|
|
||||||
|
|
||||||
} catch (IOException e) {
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private int getTrackIndex(MediaExtractor extractor, String mimeType) {
|
|
||||||
int trackCount = extractor.getTrackCount();
|
|
||||||
for (int i = 0; i < trackCount; i++) {
|
|
||||||
MediaFormat format = extractor.getTrackFormat(i);
|
|
||||||
String trackMimeType = format.getString(MediaFormat.KEY_MIME);
|
|
||||||
if (trackMimeType.startsWith(mimeType)) {
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void videoExtraction(ByteBuffer buffer, int videoTrack, MediaCodec.BufferInfo bufferInfo, MediaMuxer muxer) {
|
|
||||||
videoExtractor.seekTo(0, MediaExtractor.SEEK_TO_CLOSEST_SYNC);
|
|
||||||
while (true) {
|
|
||||||
int sampleSize = videoExtractor.readSampleData(buffer, 0);
|
|
||||||
if (sampleSize < 0) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
long presentationTimeUs = videoExtractor.getSampleTime();
|
|
||||||
bufferInfo.offset = 0;
|
|
||||||
bufferInfo.size = sampleSize;
|
|
||||||
bufferInfo.flags = MediaCodec.BUFFER_FLAG_KEY_FRAME;
|
|
||||||
bufferInfo.presentationTimeUs = presentationTimeUs;
|
|
||||||
muxer.writeSampleData(videoTrack, buffer, bufferInfo);
|
|
||||||
videoExtractor.advance();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void audioExtraction(ByteBuffer buffer, int audioTrack, MediaCodec.BufferInfo bufferInfo, MediaMuxer muxer) {
|
|
||||||
audioExtractor.seekTo(0, MediaExtractor.SEEK_TO_CLOSEST_SYNC);
|
|
||||||
while (true) {
|
|
||||||
int sampleSize = audioExtractor.readSampleData(buffer, 0);
|
|
||||||
if (sampleSize < 0) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
long presentationTimeUs = audioExtractor.getSampleTime();
|
|
||||||
bufferInfo.offset = 0;
|
|
||||||
bufferInfo.size = sampleSize;
|
|
||||||
bufferInfo.flags = 0; // or MediaCodec.BUFFER_FLAG_KEY_FRAME
|
|
||||||
bufferInfo.presentationTimeUs = presentationTimeUs;
|
|
||||||
muxer.writeSampleData(audioTrack, buffer, bufferInfo);
|
|
||||||
audioExtractor.advance();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private void deleteVideoFile(){
|
|
||||||
File videoFile = new File(videoPath);
|
|
||||||
if (videoFile.exists()) {
|
|
||||||
videoFile.delete();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void deleteAudioFile(){
|
|
||||||
File audioFile = new File(audioPath);
|
|
||||||
if (audioFile.exists()) {
|
|
||||||
audioFile.delete();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,33 +0,0 @@
|
|||||||
package com.example.greenwatch.alarmrecorder.runnables;
|
|
||||||
|
|
||||||
import android.media.MediaRecorder;
|
|
||||||
import android.widget.Toast;
|
|
||||||
|
|
||||||
import com.example.greenwatch.MainActivity;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
public class AudioRecorder implements Runnable {
|
|
||||||
|
|
||||||
private final MediaRecorder audioRecorder;
|
|
||||||
private final String audioPath;
|
|
||||||
public AudioRecorder(MediaRecorder audioRecorder, String audioPath) {
|
|
||||||
this.audioRecorder = audioRecorder;
|
|
||||||
this.audioPath = audioPath;
|
|
||||||
}
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
audioRecorder.setAudioSource(MediaRecorder.AudioSource.DEFAULT);
|
|
||||||
audioRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
|
|
||||||
audioRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AAC);
|
|
||||||
audioRecorder.setOutputFile(audioPath);
|
|
||||||
|
|
||||||
try {
|
|
||||||
audioRecorder.prepare();
|
|
||||||
audioRecorder.start();
|
|
||||||
} catch (IOException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,35 +0,0 @@
|
|||||||
package com.example.greenwatch.alarmrecorder.runnables;
|
|
||||||
|
|
||||||
import android.media.MediaRecorder;
|
|
||||||
|
|
||||||
import com.example.greenwatch.viewmodels.ViewModelInterface;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
public class VideoRecorder implements Runnable{
|
|
||||||
private final MediaRecorder videoRecorder;
|
|
||||||
private final String videoPath;
|
|
||||||
|
|
||||||
public VideoRecorder(MediaRecorder videoRecorder, String videoPath) {
|
|
||||||
this.videoRecorder = videoRecorder;
|
|
||||||
this.videoPath = videoPath;
|
|
||||||
}
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
videoRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);
|
|
||||||
videoRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
|
|
||||||
videoRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.DEFAULT);
|
|
||||||
videoRecorder.setOutputFile(videoPath);
|
|
||||||
videoRecorder.setOrientationHint(90);
|
|
||||||
//todo find solution for videoView
|
|
||||||
videoRecorder.setPreviewDisplay(videoView.getHolder().getSurface());
|
|
||||||
|
|
||||||
try {
|
|
||||||
videoRecorder.prepare();
|
|
||||||
videoRecorder.start();
|
|
||||||
|
|
||||||
} catch (IOException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,126 @@
|
|||||||
|
package com.example.greenwatch.sensors;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.graphics.ImageFormat;
|
||||||
|
import android.media.Image;
|
||||||
|
import android.util.Size;
|
||||||
|
|
||||||
|
import androidx.camera.core.CameraSelector;
|
||||||
|
import androidx.camera.core.ImageAnalysis;
|
||||||
|
import androidx.camera.lifecycle.ProcessCameraProvider;
|
||||||
|
import androidx.core.content.ContextCompat;
|
||||||
|
import androidx.lifecycle.LifecycleOwner;
|
||||||
|
import androidx.lifecycle.MutableLiveData;
|
||||||
|
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
|
||||||
|
public class CameraSensor {
|
||||||
|
private final MutableLiveData<Boolean> mVideoAlarmDetected = new MutableLiveData<>();
|
||||||
|
private static CameraSensor cameraSensorInstance;
|
||||||
|
private boolean videoAlarmDetected;
|
||||||
|
private ByteBuffer previousBuffer;
|
||||||
|
private int previousWidth;
|
||||||
|
private int previousHeight;
|
||||||
|
|
||||||
|
private CameraSensor() {
|
||||||
|
videoAlarmDetected = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static synchronized CameraSensor getInstance() {
|
||||||
|
if (cameraSensorInstance == null){
|
||||||
|
cameraSensorInstance = new CameraSensor();
|
||||||
|
}
|
||||||
|
return cameraSensorInstance;
|
||||||
|
}
|
||||||
|
|
||||||
|
public MutableLiveData<Boolean> getVideoAlarmDetectedValue() {
|
||||||
|
setMutableLiveDataVideoMovementDetected();
|
||||||
|
return mVideoAlarmDetected;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setMutableLiveDataVideoMovementDetected() {
|
||||||
|
mVideoAlarmDetected.setValue(videoAlarmDetected);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void bindImageAnalysis(ProcessCameraProvider cameraProvider, LifecycleOwner lifecycleOwner, Context context) {
|
||||||
|
ImageAnalysis.Builder builder = new ImageAnalysis.Builder();
|
||||||
|
builder.setTargetResolution(new Size(640, 480));
|
||||||
|
builder.setBackpressureStrategy(ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST);
|
||||||
|
ImageAnalysis imageAnalysis = builder.build();
|
||||||
|
imageAnalysis.setAnalyzer(
|
||||||
|
ContextCompat.getMainExecutor(context),
|
||||||
|
imageProxy -> {
|
||||||
|
|
||||||
|
int imageFormat = imageProxy.getFormat();
|
||||||
|
|
||||||
|
if (imageFormat == ImageFormat.YUV_420_888) {
|
||||||
|
|
||||||
|
Image currentImage = imageProxy.getImage();
|
||||||
|
|
||||||
|
if (previousHeight != 0) {
|
||||||
|
assert currentImage != null;
|
||||||
|
videoAlarmDetected = compareFrames(currentImage);
|
||||||
|
}
|
||||||
|
|
||||||
|
assert currentImage != null;
|
||||||
|
Image.Plane[] planes = currentImage.getPlanes();
|
||||||
|
ByteBuffer buffer = planes[0].getBuffer().duplicate();
|
||||||
|
previousBuffer = ByteBuffer.allocateDirect(buffer.remaining());
|
||||||
|
previousBuffer.put(buffer);
|
||||||
|
previousWidth = currentImage.getWidth();
|
||||||
|
previousHeight = currentImage.getHeight();
|
||||||
|
|
||||||
|
currentImage.close();
|
||||||
|
|
||||||
|
checkAlarmCondition();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
imageProxy.close();
|
||||||
|
});
|
||||||
|
|
||||||
|
CameraSelector cameraSelector = new CameraSelector.Builder().requireLensFacing(CameraSelector.LENS_FACING_BACK).build();
|
||||||
|
|
||||||
|
cameraProvider.bindToLifecycle(lifecycleOwner, cameraSelector, imageAnalysis);
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean compareFrames(Image currentImage) {
|
||||||
|
|
||||||
|
ByteBuffer currentBuffer = currentImage.getPlanes()[0].getBuffer();
|
||||||
|
|
||||||
|
int currentWidth = currentImage.getWidth();
|
||||||
|
int currentHeight = currentImage.getHeight();
|
||||||
|
|
||||||
|
if (previousWidth != currentWidth || previousHeight != currentHeight) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int row = 0; row < previousHeight; row++) {
|
||||||
|
for (int col = 0; col < previousWidth; col++) {
|
||||||
|
|
||||||
|
int previousIndex = row * previousWidth + col;
|
||||||
|
int currentIndex = row * currentWidth + col;
|
||||||
|
|
||||||
|
int previousPixel = previousBuffer.get(previousIndex) & 0xFF;
|
||||||
|
int currentPixel = currentBuffer.get(currentIndex) & 0xFF;
|
||||||
|
|
||||||
|
int pixelDifference = Math.abs(previousPixel - currentPixel);
|
||||||
|
int threshold = 120;
|
||||||
|
|
||||||
|
if (pixelDifference > threshold) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void checkAlarmCondition() {
|
||||||
|
if (videoAlarmDetected && !mVideoAlarmDetected.getValue()) {
|
||||||
|
setMutableLiveDataVideoMovementDetected();
|
||||||
|
}
|
||||||
|
else if (!videoAlarmDetected && mVideoAlarmDetected.getValue()){
|
||||||
|
setMutableLiveDataVideoMovementDetected();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -82,10 +82,6 @@ public class AccelerometerViewModel extends ViewModel implements ViewModelInterf
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getSystemTimeStamp() {
|
|
||||||
return mDeviceRepository.getSystemTimeStamp();
|
|
||||||
}
|
|
||||||
|
|
||||||
public LiveData<Boolean> getMovementDetectedValue() {
|
public LiveData<Boolean> getMovementDetectedValue() {
|
||||||
return mMovementDetected;
|
return mMovementDetected;
|
||||||
}
|
}
|
||||||
@@ -159,4 +155,9 @@ public class AccelerometerViewModel extends ViewModel implements ViewModelInterf
|
|||||||
public String getLocalDeviceUUID() {
|
public String getLocalDeviceUUID() {
|
||||||
return mDeviceRepository.getLocalDeviceUUID();
|
return mDeviceRepository.getLocalDeviceUUID();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getSystemTimeStamp() {
|
||||||
|
return mDeviceRepository.getSystemTimeStamp();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -1,5 +1,11 @@
|
|||||||
package com.example.greenwatch.viewmodels;
|
package com.example.greenwatch.viewmodels;
|
||||||
|
|
||||||
|
import android.app.Activity;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.pm.PackageManager;
|
||||||
|
|
||||||
|
import androidx.core.app.ActivityCompat;
|
||||||
|
import androidx.core.content.ContextCompat;
|
||||||
import androidx.lifecycle.LiveData;
|
import androidx.lifecycle.LiveData;
|
||||||
import androidx.lifecycle.MutableLiveData;
|
import androidx.lifecycle.MutableLiveData;
|
||||||
import androidx.lifecycle.ViewModel;
|
import androidx.lifecycle.ViewModel;
|
||||||
@@ -15,6 +21,7 @@ public class MainActivityViewModel extends ViewModel implements ViewModelInterfa
|
|||||||
private MutableLiveData<List<Device>> mDeviceList;
|
private MutableLiveData<List<Device>> mDeviceList;
|
||||||
private MutableLiveData<List<Device>> mAlarmHistoryList;
|
private MutableLiveData<List<Device>> mAlarmHistoryList;
|
||||||
private DeviceRepository mDeviceRepository;
|
private DeviceRepository mDeviceRepository;
|
||||||
|
private static final int RECHTEANFORDERUNG_KAMERA = 10;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void init() {
|
public void init() {
|
||||||
@@ -28,11 +35,18 @@ public class MainActivityViewModel extends ViewModel implements ViewModelInterfa
|
|||||||
mDeviceRepository.setWiFiCommunication(mWiFiCommunication);
|
mDeviceRepository.setWiFiCommunication(mWiFiCommunication);
|
||||||
mWiFiCommunication.setDeviceRepository(mDeviceRepository);
|
mWiFiCommunication.setDeviceRepository(mDeviceRepository);
|
||||||
mDeviceRepository.createNewDevice(mDeviceRepository.getSystemTimeStamp(), mDeviceRepository.getLocalDeviceUUID(), false, "No Sensor selected", 0);
|
mDeviceRepository.createNewDevice(mDeviceRepository.getSystemTimeStamp(), mDeviceRepository.getLocalDeviceUUID(), false, "No Sensor selected", 0);
|
||||||
mDeviceRepository.createNewDevice("00:00", "1234", true, "Test", 21);
|
|
||||||
mDeviceList = mDeviceRepository.getConnectedDeviceList();
|
mDeviceList = mDeviceRepository.getConnectedDeviceList();
|
||||||
mAlarmHistoryList = mDeviceRepository.getAlarmHistoryDeviceList();
|
mAlarmHistoryList = mDeviceRepository.getAlarmHistoryDeviceList();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isCameraAccessAllowed(Context context) {
|
||||||
|
return ContextCompat.checkSelfPermission(context, android.Manifest.permission.CAMERA) == PackageManager.PERMISSION_GRANTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void accessRequestCamera(Activity activity) {
|
||||||
|
ActivityCompat.requestPermissions(activity, new String[]{android.Manifest.permission.CAMERA}, RECHTEANFORDERUNG_KAMERA);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public LiveData<List<Device>> getConnectedDeviceList() {
|
public LiveData<List<Device>> getConnectedDeviceList() {
|
||||||
return mDeviceList;
|
return mDeviceList;
|
||||||
@@ -102,4 +116,9 @@ public class MainActivityViewModel extends ViewModel implements ViewModelInterfa
|
|||||||
public String getLocalDeviceUUID() {
|
public String getLocalDeviceUUID() {
|
||||||
return mDeviceRepository.getLocalDeviceUUID();
|
return mDeviceRepository.getLocalDeviceUUID();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getSystemTimeStamp() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,131 @@
|
|||||||
|
package com.example.greenwatch.viewmodels;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
|
||||||
|
import androidx.camera.lifecycle.ProcessCameraProvider;
|
||||||
|
import androidx.lifecycle.LifecycleOwner;
|
||||||
|
import androidx.lifecycle.LiveData;
|
||||||
|
import androidx.lifecycle.MutableLiveData;
|
||||||
|
import androidx.lifecycle.ViewModel;
|
||||||
|
|
||||||
|
import com.example.greenwatch.models.Device;
|
||||||
|
import com.example.greenwatch.repositories.DeviceRepository;
|
||||||
|
import com.example.greenwatch.sensors.CameraSensor;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class VideodetectionViewModel extends ViewModel implements ViewModelInterface {
|
||||||
|
|
||||||
|
private MutableLiveData<List<Device>> mDeviceList;
|
||||||
|
private MutableLiveData<Boolean> mVideoAlarmDetected;
|
||||||
|
private MutableLiveData<List<Device>> mAlarmHistoryList;
|
||||||
|
private DeviceRepository mDeviceRepository;
|
||||||
|
private CameraSensor mCameraSensor;
|
||||||
|
|
||||||
|
|
||||||
|
public LiveData<Boolean> getVideoMovementDetectedValue() {
|
||||||
|
return mVideoAlarmDetected;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void init() {
|
||||||
|
if (mDeviceRepository == null) {
|
||||||
|
mDeviceRepository = DeviceRepository.getInstance();
|
||||||
|
}
|
||||||
|
if (mCameraSensor == null) {
|
||||||
|
mCameraSensor = CameraSensor.getInstance();
|
||||||
|
}
|
||||||
|
if (mDeviceList == null) {
|
||||||
|
mDeviceList = mDeviceRepository.getConnectedDeviceList();
|
||||||
|
}
|
||||||
|
if (mAlarmHistoryList == null) {
|
||||||
|
mAlarmHistoryList = mDeviceRepository.getAlarmHistoryDeviceList();
|
||||||
|
}
|
||||||
|
if (mVideoAlarmDetected == null) {
|
||||||
|
mVideoAlarmDetected = mCameraSensor.getVideoAlarmDetectedValue();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void bindImageAnalysis(ProcessCameraProvider cameraProvider, LifecycleOwner lifecycleOwner, Context context) {
|
||||||
|
mCameraSensor.bindImageAnalysis(cameraProvider, lifecycleOwner, context);
|
||||||
|
}
|
||||||
|
|
||||||
|
public LiveData<Boolean> getVideoAlarmDetectedValue() {
|
||||||
|
return mVideoAlarmDetected;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public LiveData<List<Device>> getConnectedDeviceList() {
|
||||||
|
return mDeviceList;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public LiveData<List<Device>> getAlarmHistoryList() {
|
||||||
|
return mAlarmHistoryList;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void updateDevice(String deviceID, String timeStamp, boolean sensorStatus, String sensorType, int sensorMassage) {
|
||||||
|
mDeviceRepository.updateDevice(deviceID, timeStamp, sensorStatus, sensorType, sensorMassage);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setTimeStamp(String deviceID, String timeStamp) {
|
||||||
|
mDeviceRepository.setTimeStamp(deviceID, timeStamp);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getTimeStamp(String deviceID) {
|
||||||
|
return mDeviceRepository.getTimeStamp(deviceID);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setDeviceID(String deviceID, String newDeviceID) {
|
||||||
|
mDeviceRepository.setDeviceID(deviceID, newDeviceID);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getDeviceID(String deviceID) {
|
||||||
|
return mDeviceRepository.getDeviceID(deviceID);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setSensorStatus(String deviceID, boolean sensorStatus) {
|
||||||
|
mDeviceRepository.setSensorStatus(deviceID, sensorStatus);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean getSensorStatus(String deviceID) {
|
||||||
|
return mDeviceRepository.getSensorStatus(deviceID);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setSensorType(String deviceID, String sensorType) {
|
||||||
|
mDeviceRepository.setSensorType(deviceID, sensorType);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getSensorType(String deviceID) {
|
||||||
|
return mDeviceRepository.getSensorType(deviceID);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setSensorMassage(String deviceID, int sensorMessage) {
|
||||||
|
mDeviceRepository.setSensorMassage(deviceID, sensorMessage);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getSensorMassage(String deviceID) {
|
||||||
|
return mDeviceRepository.getSensorMassage(deviceID);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getLocalDeviceUUID() {
|
||||||
|
return mDeviceRepository.getLocalDeviceUUID();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getSystemTimeStamp() {
|
||||||
|
return mDeviceRepository.getSystemTimeStamp();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -22,4 +22,5 @@ public interface ViewModelInterface {
|
|||||||
void setSensorMassage(String deviceID, int sensorMessage);
|
void setSensorMassage(String deviceID, int sensorMessage);
|
||||||
int getSensorMassage(String deviceID);
|
int getSensorMassage(String deviceID);
|
||||||
String getLocalDeviceUUID();
|
String getLocalDeviceUUID();
|
||||||
|
String getSystemTimeStamp();
|
||||||
}
|
}
|
||||||
@@ -22,4 +22,27 @@
|
|||||||
android:text="Back to MainActivity">
|
android:text="Back to MainActivity">
|
||||||
</Button>
|
</Button>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<androidx.recyclerview.widget.RecyclerView
|
||||||
|
android:id="@+id/deviceListRecyclerView"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
tools:listitem="@layout/device_item"
|
||||||
|
android:layout_weight="1">
|
||||||
|
</androidx.recyclerview.widget.RecyclerView>
|
||||||
|
|
||||||
|
<androidx.recyclerview.widget.RecyclerView
|
||||||
|
android:id="@+id/alarmHistoryListRecyclerView"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
tools:listitem="@layout/alarm_history_item"
|
||||||
|
android:layout_weight="1">
|
||||||
|
</androidx.recyclerview.widget.RecyclerView>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
Reference in new issue
Block a user