diff --git a/catroid/src/androidTest/java/org/catrobat/catroid/test/formulaeditor/SensorHandlerTest.kt b/catroid/src/androidTest/java/org/catrobat/catroid/test/formulaeditor/SensorHandlerTest.kt index b8a085fa95f..2a699f85a27 100644 --- a/catroid/src/androidTest/java/org/catrobat/catroid/test/formulaeditor/SensorHandlerTest.kt +++ b/catroid/src/androidTest/java/org/catrobat/catroid/test/formulaeditor/SensorHandlerTest.kt @@ -1,6 +1,6 @@ /* * Catroid: An on-device visual programming system for Android devices - * Copyright (C) 2010-2022 The Catrobat Team + * Copyright (C) 2010-2024 The Catrobat Team * () * * This program is free software: you can redistribute it and/or modify @@ -34,6 +34,8 @@ import org.catrobat.catroid.camera.VisualDetectionHandler.updateFaceDetectionSta import org.catrobat.catroid.camera.VisualDetectionHandler.updateFaceSensorValues import org.catrobat.catroid.camera.VisualDetectionHandlerFace import org.catrobat.catroid.content.Project +import org.catrobat.catroid.formulaeditor.SensorCustomEvent +import org.catrobat.catroid.formulaeditor.SensorCustomEventListener import org.catrobat.catroid.formulaeditor.SensorHandler import org.catrobat.catroid.formulaeditor.SensorLoudness import org.catrobat.catroid.formulaeditor.Sensors @@ -41,6 +43,8 @@ import org.catrobat.catroid.soundrecorder.SoundRecorder import org.catrobat.catroid.test.utils.TestUtils import org.junit.After import org.junit.Assert.assertEquals +import org.junit.Assert.assertTrue +import org.junit.Assert.fail import org.junit.Before import org.junit.Rule import org.junit.Test @@ -117,9 +121,8 @@ class SensorHandlerTest { @Test @UiThreadTest fun testMicRelease() { - val loudnessSensor = SensorLoudness() val soundRecorder = Mockito.mock(SoundRecorder::class.java) - loudnessSensor.soundRecorder = soundRecorder + val loudnessSensor = SensorLoudness(soundRecorder) Mockito.`when`(soundRecorder.isRecording).thenReturn(false) SensorHandler.getInstance(ApplicationProvider.getApplicationContext()).setSensorLoudness(loudnessSensor) @@ -132,6 +135,25 @@ class SensorHandlerTest { Mockito.verify(soundRecorder).stop() } + @Test + @UiThreadTest + fun testSensorLoudnessStatusChecker() { + val soundRecorder = Mockito.mock(SoundRecorder::class.java) + val loudnessSensor = SensorLoudness(soundRecorder) + + Mockito.`when`(soundRecorder.maxAmplitude).thenReturn(10) + Mockito.`when`(soundRecorder.isRecording).thenReturn(true) + val listener = SensorCustomEventListener {event: SensorCustomEvent? -> + event?.let { + assertTrue(event.sensor == Sensors.LOUDNESS) + assertEquals((10 / 32767).toFloat(), event.value as Float, 0.05f) + } ?: fail() + } + loudnessSensor.registerListener(listener) + loudnessSensor.unregisterListener(listener) + Mockito.verify(soundRecorder).stop() + } + @After fun tearDown() { SensorHandler.destroy() @@ -144,4 +166,4 @@ class SensorHandlerTest { companion object { private const val DELTA = 0.01 } -} +} \ No newline at end of file diff --git a/catroid/src/androidTest/java/org/catrobat/catroid/uiespresso/ui/activity/ProjectUploadDialogTest.kt b/catroid/src/androidTest/java/org/catrobat/catroid/uiespresso/ui/activity/ProjectUploadDialogTest.kt index 1397f3afb2a..7214a6aee28 100644 --- a/catroid/src/androidTest/java/org/catrobat/catroid/uiespresso/ui/activity/ProjectUploadDialogTest.kt +++ b/catroid/src/androidTest/java/org/catrobat/catroid/uiespresso/ui/activity/ProjectUploadDialogTest.kt @@ -1,6 +1,6 @@ /* * Catroid: An on-device visual programming system for Android devices - * Copyright (C) 2010-2023 The Catrobat Team + * Copyright (C) 2010-2024 The Catrobat Team * () * * This program is free software: you can redistribute it and/or modify diff --git a/catroid/src/main/java/org/catrobat/catroid/formulaeditor/SensorLoudness.java b/catroid/src/main/java/org/catrobat/catroid/formulaeditor/SensorLoudness.java deleted file mode 100644 index 6ba762803bf..00000000000 --- a/catroid/src/main/java/org/catrobat/catroid/formulaeditor/SensorLoudness.java +++ /dev/null @@ -1,120 +0,0 @@ -/* - * Catroid: An on-device visual programming system for Android devices - * Copyright (C) 2010-2022 The Catrobat Team - * () - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * An additional term exception under section 7 of the GNU Affero - * General Public License, version 3, is available at - * http://developer.catrobat.org/license_additional_term - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ -package org.catrobat.catroid.formulaeditor; - -import android.os.Handler; -import android.util.Log; - -import org.catrobat.catroid.soundrecorder.SoundRecorder; - -import java.io.IOException; -import java.util.ArrayList; -import java.util.List; - -import androidx.annotation.VisibleForTesting; - -public class SensorLoudness { - private static final int UPDATE_INTERVAL = 50; - private static final double SCALE_RANGE = 100d; - private static final double MAX_AMP_VALUE = 32767d; - private static final String TAG = SensorLoudness.class.getSimpleName(); - private List listenerList = new ArrayList<>(); - - private SoundRecorder recorder; - private final Handler handler; - private Double lastValue = 0.0; - - public SensorLoudness() { - handler = new Handler(); - recorder = new SoundRecorder("/dev/null"); - } - - Runnable statusChecker = new Runnable() { - @Override - public void run() { - Double loudness = ((SCALE_RANGE / MAX_AMP_VALUE) * recorder.getMaxAmplitude()); - if (!loudness.equals(lastValue) && !loudness.equals(0.0)) { - lastValue = loudness; - SensorCustomEvent event = new SensorCustomEvent(Sensors.LOUDNESS, loudness); - - for (SensorCustomEventListener listener : listenerList) { - listener.onCustomSensorChanged(event); - } - } - handler.postDelayed(statusChecker, UPDATE_INTERVAL); - } - }; - - public synchronized boolean registerListener(SensorCustomEventListener listener) { - if (listenerList.contains(listener)) { - return true; - } - listenerList.add(listener); - if (!recorder.isRecording()) { - try { - recorder.start(); - statusChecker.run(); - } catch (IOException ioException) { - Log.d(TAG, "Could not start recorder", ioException); - listenerList.remove(listener); - recorder = new SoundRecorder("/dev/null"); - return false; - } catch (RuntimeException runtimeException) { - Log.d(TAG, "Could not start recorder", runtimeException); - listenerList.remove(listener); - recorder = new SoundRecorder("/dev/null"); - return false; - } - } - return true; - } - - public synchronized void unregisterListener(SensorCustomEventListener listener) { - if (listenerList.contains(listener)) { - listenerList.remove(listener); - if (listenerList.size() == 0) { - handler.removeCallbacks(statusChecker); - if (recorder.isRecording()) { - try { - recorder.stop(); - } catch (IOException ioException) { - // ignored, nothing we can do - Log.d(TAG, "Could not stop recorder", ioException); - } - recorder = new SoundRecorder("/dev/null"); - } - lastValue = 0.0; - } - } - } - - @VisibleForTesting - public void setSoundRecorder(SoundRecorder soundRecorder) { - recorder = soundRecorder; - } - - @VisibleForTesting - public SoundRecorder getSoundRecorder() { - return recorder; - } -} diff --git a/catroid/src/main/java/org/catrobat/catroid/formulaeditor/SensorLoudness.kt b/catroid/src/main/java/org/catrobat/catroid/formulaeditor/SensorLoudness.kt new file mode 100644 index 00000000000..3672bbe5e63 --- /dev/null +++ b/catroid/src/main/java/org/catrobat/catroid/formulaeditor/SensorLoudness.kt @@ -0,0 +1,97 @@ +/* + * Catroid: An on-device visual programming system for Android devices + * Copyright (C) 2010-2024 The Catrobat Team + * () + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * An additional term exception under section 7 of the GNU Affero + * General Public License, version 3, is available at + * http://developer.catrobat.org/license_additional_term + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ +package org.catrobat.catroid.formulaeditor + +import android.os.Handler +import android.util.Log +import androidx.annotation.VisibleForTesting +import org.catrobat.catroid.soundrecorder.SoundRecorder +import java.io.IOException + +class SensorLoudness(soundRecorderVar: SoundRecorder) { + private val listenerList: MutableList = ArrayList() + private val handler = Handler() + private var lastValue = 0.0 + var soundRecorder = soundRecorderVar + + var statusChecker: Runnable = object : Runnable { + override fun run() { + val loudness = ((SCALE_RANGE / MAX_AMP_VALUE) * soundRecorder.maxAmplitude) + if (!loudness.equals(lastValue) && !loudness.equals(0.0)) { + lastValue = loudness + val event = SensorCustomEvent(Sensors.LOUDNESS, loudness) + + for (listener in listenerList) { + listener.onCustomSensorChanged(event) + } + } + handler.postDelayed(this, UPDATE_INTERVAL.toLong()) + } + } + + @Synchronized + fun registerListener(listener: SensorCustomEventListener) { + listenerList.add(listener) + if (!soundRecorder.isRecording) { + try { + soundRecorder.start() + statusChecker.run() + } catch (ioException: IOException) { + Log.d(TAG, "Could not start recorder", ioException) + listenerList.remove(listener) + soundRecorder = SoundRecorder("/dev/null") + } catch (runtimeException: RuntimeException) { + Log.d(TAG, "Could not start recorder", runtimeException) + listenerList.remove(listener) + soundRecorder = SoundRecorder("/dev/null") + } + } + } + + @Synchronized + fun unregisterListener(listener: SensorCustomEventListener) { + if (listenerList.contains(listener)) { + listenerList.remove(listener) + if (listenerList.size == 0) { + handler.removeCallbacks(statusChecker) + if (soundRecorder.isRecording) { + try { + soundRecorder.stop() + } catch (ioException: IOException) { + // ignored, nothing we can do + Log.d(TAG, "Could not stop recorder", ioException) + } + soundRecorder = SoundRecorder("/dev/null") + } + lastValue = 0.0 + } + } + } + + companion object { + private const val UPDATE_INTERVAL = 50 + private const val SCALE_RANGE = 100.0 + private const val MAX_AMP_VALUE = 32767.0 + private val TAG: String = SensorLoudness::class.java.simpleName + } +} \ No newline at end of file diff --git a/catroid/src/main/java/org/catrobat/catroid/stage/StageResourceHolder.java b/catroid/src/main/java/org/catrobat/catroid/stage/StageResourceHolder.java index 373ce05c37d..22ff28fc1ce 100644 --- a/catroid/src/main/java/org/catrobat/catroid/stage/StageResourceHolder.java +++ b/catroid/src/main/java/org/catrobat/catroid/stage/StageResourceHolder.java @@ -53,6 +53,7 @@ import org.catrobat.catroid.formulaeditor.SensorHandler; import org.catrobat.catroid.formulaeditor.SensorLoudness; import org.catrobat.catroid.sensing.GatherCollisionInformationTask; +import org.catrobat.catroid.soundrecorder.SoundRecorder; import org.catrobat.catroid.ui.runtimepermissions.BrickResourcesToRuntimePermissions; import org.catrobat.catroid.ui.settingsfragments.SettingsFragment; import org.catrobat.catroid.utils.MobileServiceAvailability; @@ -130,7 +131,7 @@ public void initResources() { } if (requiredResourcesSet.contains(Brick.MICROPHONE)) { - sensorHandler.setSensorLoudness(new SensorLoudness()); + sensorHandler.setSensorLoudness(new SensorLoudness(new SoundRecorder("/dev/null"))); resourceInitialized(); } @@ -289,18 +290,18 @@ public void onClick(DialogInterface dialog, int id) { if (requiredResourcesSet.contains(Brick.NETWORK_CONNECTION)) { if (!Utils.isNetworkAvailable(stageActivity)) { new AlertDialog.Builder(new ContextThemeWrapper(stageActivity, R.style.Theme_AppCompat_Dialog)) - .setTitle(R.string.error_no_network_title) - .setPositiveButton(R.string.preference_title, (dialog, whichButton) -> { - stageActivity.startActivity(new Intent(Settings.ACTION_SETTINGS)); - }) - .setNegativeButton(R.string.cancel, (dialog, whichButton) -> { - endStageActivity(); - }) - .setOnDismissListener(dialog -> { - endStageActivity(); - }) - .create() - .show(); + .setTitle(R.string.error_no_network_title) + .setPositiveButton(R.string.preference_title, (dialog, whichButton) -> { + stageActivity.startActivity(new Intent(Settings.ACTION_SETTINGS)); + }) + .setNegativeButton(R.string.cancel, (dialog, whichButton) -> { + endStageActivity(); + }) + .setOnDismissListener(dialog -> { + endStageActivity(); + }) + .create() + .show(); } else { resourceInitialized(); } @@ -549,4 +550,4 @@ private void nfcInitialize() { public void onFinished() { resourceInitialized(); } -} +} \ No newline at end of file diff --git a/catroid/src/main/java/org/catrobat/catroid/ui/dialogs/FormulaEditorComputeDialog.java b/catroid/src/main/java/org/catrobat/catroid/ui/dialogs/FormulaEditorComputeDialog.java index 3dd0220f633..b88bd2edce5 100644 --- a/catroid/src/main/java/org/catrobat/catroid/ui/dialogs/FormulaEditorComputeDialog.java +++ b/catroid/src/main/java/org/catrobat/catroid/ui/dialogs/FormulaEditorComputeDialog.java @@ -1,6 +1,6 @@ /* * Catroid: An on-device visual programming system for Android devices - * Copyright (C) 2010-2022 The Catrobat Team + * Copyright (C) 2010-2024 The Catrobat Team * () * * This program is free software: you can redistribute it and/or modify @@ -43,6 +43,7 @@ import org.catrobat.catroid.formulaeditor.FormulaElement.ElementType; import org.catrobat.catroid.formulaeditor.SensorHandler; import org.catrobat.catroid.formulaeditor.SensorLoudness; +import org.catrobat.catroid.soundrecorder.SoundRecorder; import org.catrobat.catroid.utils.ShowTextUtils.AndroidStringProvider; import androidx.appcompat.app.AlertDialog; @@ -84,7 +85,7 @@ public void setFormula(Formula formula) { formula.addRequiredResources(resourcesSet); if (resourcesSet.contains(Brick.MICROPHONE)) { - SensorHandler.getInstance(getContext()).setSensorLoudness(new SensorLoudness()); + SensorHandler.getInstance(getContext()).setSensorLoudness(new SensorLoudness(new SoundRecorder("/dev/null"))); } if (resourcesSet.contains(Brick.BLUETOOTH_LEGO_NXT)) {