diff --git a/.gitignore b/.gitignore index 9bee2ac..0b49617 100644 --- a/.gitignore +++ b/.gitignore @@ -34,13 +34,7 @@ captures/ # IntelliJ *.iml -.idea/workspace.xml -.idea/tasks.xml -.idea/gradle.xml -.idea/assetWizardSettings.xml -.idea/dictionaries -.idea/libraries -.idea/caches +.idea/ # Keystore files # Uncomment the following line if you do not want to check your keystore files in. diff --git a/.idea/compiler.xml b/.idea/compiler.xml new file mode 100644 index 0000000..fb7f4a8 --- /dev/null +++ b/.idea/compiler.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/jarRepositories.xml b/.idea/jarRepositories.xml new file mode 100644 index 0000000..dbc0164 --- /dev/null +++ b/.idea/jarRepositories.xml @@ -0,0 +1,40 @@ + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml index 23cea1a..0b76189 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -5,7 +5,7 @@ - + diff --git a/.idea/modules.xml b/.idea/modules.xml deleted file mode 100644 index a472893..0000000 --- a/.idea/modules.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - - \ No newline at end of file diff --git a/.idea/runConfigurations.xml b/.idea/runConfigurations.xml deleted file mode 100644 index 7f68460..0000000 --- a/.idea/runConfigurations.xml +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/app/build.gradle b/app/build.gradle index 871f5ce..84c9085 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -1,15 +1,16 @@ apply plugin: 'com.android.application' -apply plugin: 'io.fabric' +apply plugin: 'com.google.gms.google-services' +apply plugin: 'com.google.firebase.crashlytics' android { - compileSdkVersion 28 + compileSdkVersion 30 defaultConfig { applicationId "com.backyardbrains" minSdkVersion 19 - targetSdkVersion 28 - versionCode 89 - versionName '1.8.3.1' + targetSdkVersion 30 + versionCode 90 + versionName '1.8.3.5' externalNativeBuild { cmake { @@ -45,7 +46,7 @@ android { debug { debuggable true minifyEnabled false - ext.enableCrashlytics = false +// ext.enableCrashlytics = false } } @@ -111,6 +112,11 @@ dependencies { implementation "androidx.room:room-runtime:$roomVersion" annotationProcessor "androidx.room:room-compiler:$roomVersion" + implementation platform('com.google.firebase:firebase-bom:28.0.0') + implementation 'com.google.firebase:firebase-crashlytics' + implementation 'com.google.firebase:firebase-analytics' + implementation 'com.google.firebase:firebase-core' + // material design implementation "com.google.android.material:material:$materialDesignVersion" @@ -147,15 +153,6 @@ dependencies { // signal filtering implementation "org.apache.commons:commons-math3:$commonsMathVersion" - - // firebase & crashlytics - implementation "com.google.firebase:firebase-core:$firebaseVersion" - implementation("com.crashlytics.sdk.android:crashlytics:$crashlyticsVersion") { - transitive = true - } - // benchmark implementation "com.github.T-Spoon:Benchit:$benchitVersion" -} - -apply plugin: 'com.google.gms.google-services' \ No newline at end of file +} \ No newline at end of file diff --git a/app/src/main/cpp/byb/SampleStreamProcessor.cpp b/app/src/main/cpp/byb/SampleStreamProcessor.cpp index 26449de..9059d83 100644 --- a/app/src/main/cpp/byb/SampleStreamProcessor.cpp +++ b/app/src/main/cpp/byb/SampleStreamProcessor.cpp @@ -111,7 +111,13 @@ namespace backyardbrains { msb = msb & REMOVER; msb = msb << 7u; lsb = lsb & REMOVER; - sample = (short) (((msb | lsb) - 512) * 30); + sample = (short) (((msb | lsb) + - + backyardbrains::utils::SampleStreamUtils::getResolution( + hardwareType)) + * + backyardbrains::utils::SampleStreamUtils::getResolutionMultiplier( + hardwareType)); // calculate average sample average = 0.0001 * sample + 0.9999 * average; @@ -196,10 +202,19 @@ namespace backyardbrains { // inDataPrevLength = length; bool avoidFilteringOfChannels = stopFilteringAfterChannelIndex >= 0; + for (int i = 0; i < channelCount; i++) { // apply additional filtering if necessary - if (avoidFilteringOfChannels && i <= stopFilteringAfterChannelIndex) + //TODO: Check is stopFilteringAfterChannelIndex variable properly updated after insert extension board + if (avoidFilteringOfChannels && i <= stopFilteringAfterChannelIndex) { + + applyFilters(i, channels[i], sampleCounters[i]); + } + else if (!avoidFilteringOfChannels) + { applyFilters(i, channels[i], sampleCounters[i]); + + } outSamples[i] = new short[sampleCounters[i]]; std::copy(channels[i], channels[i] + sampleCounters[i], outSamples[i]); outSampleCounts[i] = sampleCounters[i]; @@ -217,8 +232,8 @@ namespace backyardbrains { __android_log_print(ANDROID_LOG_DEBUG, TAG, "ESCAPE SEQUENCE MESSAGE %s AT %d", message.c_str(), sampleIndex); if (backyardbrains::utils::SampleStreamUtils::isHardwareTypeMsg(message)) { - listener->onSpikerBoxHardwareTypeDetected( - backyardbrains::utils::SampleStreamUtils::getHardwareType(message)); + hardwareType = backyardbrains::utils::SampleStreamUtils::getHardwareType(message); + listener->onSpikerBoxHardwareTypeDetected(hardwareType); } else if (backyardbrains::utils::SampleStreamUtils::isSampleRateAndNumOfChannelsMsg(message)) { const int sampleRate = backyardbrains::utils::SampleStreamUtils::getMaxSampleRate(message); const int channelCount = backyardbrains::utils::SampleStreamUtils::getChannelCount(message); @@ -235,6 +250,8 @@ namespace backyardbrains { } void SampleStreamProcessor::updateProcessingParameters(int expansionBoardType) { + __android_log_print(ANDROID_LOG_DEBUG, typeid(*this).name(),"expansionBoardType %d", expansionBoardType); + switch (expansionBoardType) { default: case backyardbrains::utils::SampleStreamUtils::NONE_BOARD_DETACHED: diff --git a/app/src/main/cpp/byb/SampleStreamUtils.cpp b/app/src/main/cpp/byb/SampleStreamUtils.cpp index ee90bb2..d45c8a1 100644 --- a/app/src/main/cpp/byb/SampleStreamUtils.cpp +++ b/app/src/main/cpp/byb/SampleStreamUtils.cpp @@ -9,7 +9,8 @@ namespace backyardbrains { namespace utils { const std::string SampleStreamUtils::HARDWARE_TYPE_PREFIX = "HWT:"; - const std::string SampleStreamUtils::HARDWARE_TYPE_PLANT = SampleStreamUtils::HARDWARE_TYPE_PREFIX + "PLANTSS;"; + const std::string SampleStreamUtils::HARDWARE_TYPE_PLANT = + SampleStreamUtils::HARDWARE_TYPE_PREFIX + "PLANTSS;"; const std::string SampleStreamUtils::HARDWARE_TYPE_MUSCLE = SampleStreamUtils::HARDWARE_TYPE_PREFIX + "MUSCLESS;"; const std::string SampleStreamUtils::HARDWARE_TYPE_HEART_AND_BRAIN_6CH = @@ -20,6 +21,8 @@ namespace backyardbrains { SampleStreamUtils::HARDWARE_TYPE_PREFIX + "NEURONSB;"; const std::string SampleStreamUtils::HARDWARE_TYPE_MUSCLE_PRO = SampleStreamUtils::HARDWARE_TYPE_PREFIX + "MUSCLESB;"; + const std::string SampleStreamUtils::HARDWARE_TYPE_HUMANS = + SampleStreamUtils::HARDWARE_TYPE_PREFIX + "HUMANSB;"; const std::string SampleStreamUtils::SAMPLE_RATE_PREFIX = "MSF:"; const std::string SampleStreamUtils::NUM_OF_CHANNELS_PREFIX = "MNC:"; const std::string SampleStreamUtils::EVENT_PREFIX = "EVNT:"; @@ -30,12 +33,20 @@ namespace backyardbrains { } int SampleStreamUtils::getHardwareType(std::string message) { - if (std::strcmp(HARDWARE_TYPE_PLANT.c_str(), message.c_str()) == 0) return PLANT_HARDWARE; - if (std::strcmp(HARDWARE_TYPE_MUSCLE.c_str(), message.c_str()) == 0) return MUSCLE_HARDWARE; - if (std::strcmp(HARDWARE_TYPE_HEART_AND_BRAIN_6CH.c_str(), message.c_str()) == 0) return HEART_HARDWARE; - if (std::strcmp(HARDWARE_TYPE_HEART_AND_BRAIN.c_str(), message.c_str()) == 0) return HEART_HARDWARE; - if (message.find(HARDWARE_TYPE_NEURON_PRO) != std::string::npos) return NEURON_PRO_HARDWARE; - if (message.find(HARDWARE_TYPE_MUSCLE_PRO) != std::string::npos) return MUSCLE_PRO_HARDWARE; + if (std::strcmp(HARDWARE_TYPE_PLANT.c_str(), message.c_str()) == 0) + return PLANT_HARDWARE; + if (std::strcmp(HARDWARE_TYPE_MUSCLE.c_str(), message.c_str()) == 0) + return MUSCLE_HARDWARE; + if (std::strcmp(HARDWARE_TYPE_HEART_AND_BRAIN_6CH.c_str(), message.c_str()) == 0) + return HEART_HARDWARE; + if (std::strcmp(HARDWARE_TYPE_HEART_AND_BRAIN.c_str(), message.c_str()) == 0) + return HEART_HARDWARE; + if (std::strcmp(HARDWARE_TYPE_HUMANS.c_str(), message.c_str()) == 0) + return HUMANS_HARDWARE; + if (message.find(HARDWARE_TYPE_NEURON_PRO) != std::string::npos) + return NEURON_PRO_HARDWARE; + if (message.find(HARDWARE_TYPE_MUSCLE_PRO) != std::string::npos) + return MUSCLE_PRO_HARDWARE; return UNKNOWN_HARDWARE; } @@ -72,7 +83,8 @@ namespace backyardbrains { } bool SampleStreamUtils::isExpansionBoardTypeMsg(std::string message) { - return message.compare(0, EXPANSION_BOARD_TYPE_PREFIX.length(), EXPANSION_BOARD_TYPE_PREFIX) == 0; + return message.compare(0, EXPANSION_BOARD_TYPE_PREFIX.length(), + EXPANSION_BOARD_TYPE_PREFIX) == 0; } int SampleStreamUtils::getExpansionBoardType(std::string message) { @@ -82,5 +94,19 @@ namespace backyardbrains { message = message.replace(found, message.length() - found, ""); return std::stoi(message); } + + int SampleStreamUtils::getResolution(int hardwareType) { + if (hardwareType == HUMANS_HARDWARE) { + return 8192; //(2^14)/2 + } + return 512; //(2^10)/2 + } + + int SampleStreamUtils::getResolutionMultiplier(int hardwareType) { + if (hardwareType == HUMANS_HARDWARE) { + return 1; + } + return 30; + } } } \ No newline at end of file diff --git a/app/src/main/cpp/byb/includes/SampleStreamProcessor.h b/app/src/main/cpp/byb/includes/SampleStreamProcessor.h index 28c69d8..f5f58a2 100644 --- a/app/src/main/cpp/byb/includes/SampleStreamProcessor.h +++ b/app/src/main/cpp/byb/includes/SampleStreamProcessor.h @@ -115,6 +115,8 @@ namespace backyardbrains { byte msb; // Average signal which we use to avoid signal offset double average; + + int hardwareType = -1; }; } } diff --git a/app/src/main/cpp/byb/includes/SampleStreamUtils.h b/app/src/main/cpp/byb/includes/SampleStreamUtils.h index 1c44262..9e73b7b 100644 --- a/app/src/main/cpp/byb/includes/SampleStreamUtils.h +++ b/app/src/main/cpp/byb/includes/SampleStreamUtils.h @@ -87,6 +87,10 @@ namespace backyardbrains { */ static int getExpansionBoardType(std::string message); + static int getResolution(int hardwareType); + + static int getResolutionMultiplier(int hardwareType); + private: // Hardware type SpikerBox reply message prefix. static const std::string HARDWARE_TYPE_PREFIX; @@ -102,6 +106,8 @@ namespace backyardbrains { static const std::string HARDWARE_TYPE_NEURON_PRO; // Muscle PRO SpikerBox reply message for hardware type inquiry. static const std::string HARDWARE_TYPE_MUSCLE_PRO; + // Humans SpikerBox reply message for hardware type inquiry. + static const std::string HARDWARE_TYPE_HUMANS; // Sample rate SpikerBox reply message prefix static const std::string SAMPLE_RATE_PREFIX; // Number of channels SpikerBox reply message prefix @@ -123,9 +129,11 @@ namespace backyardbrains { static const int MUSCLE_PRO_HARDWARE = 3; // SpikerBox Neuron PRO hardware type. static const int NEURON_PRO_HARDWARE = 4; + // SpikerBox Humans hardware type. + static const int HUMANS_HARDWARE = 5; // Sample rate used throughout the app. - static const int SAMPLE_RATE = 10000; + static const int SAMPLE_RATE = 10000; //TODo sad je fizno proveri dal se negde cacka }; } } diff --git a/app/src/main/java/com/backyardbrains/BybApplication.java b/app/src/main/java/com/backyardbrains/BybApplication.java index 68997da..b6cf558 100644 --- a/app/src/main/java/com/backyardbrains/BybApplication.java +++ b/app/src/main/java/com/backyardbrains/BybApplication.java @@ -20,22 +20,12 @@ package com.backyardbrains; import android.app.Application; -import com.crashlytics.android.Crashlytics; -import com.crashlytics.android.core.CrashlyticsCore; -import io.fabric.sdk.android.Fabric; import org.greenrobot.eventbus.EventBus; public class BybApplication extends Application { @Override public void onCreate() { super.onCreate(); - - // Set up Crashlytics, disabled for debug builds - Crashlytics crashlyticsKit = - new Crashlytics.Builder().core(new CrashlyticsCore.Builder().disabled(BuildConfig.DEBUG).build()).build(); - // Initialize Fabric with the debug-disabled crashlytics. - Fabric.with(this, crashlyticsKit); - // initialize event bus EventBus.builder() .logNoSubscriberMessages(false) diff --git a/app/src/main/java/com/backyardbrains/analysis/AnalysisManager.java b/app/src/main/java/com/backyardbrains/analysis/AnalysisManager.java index f06f1a5..d09aa09 100644 --- a/app/src/main/java/com/backyardbrains/analysis/AnalysisManager.java +++ b/app/src/main/java/com/backyardbrains/analysis/AnalysisManager.java @@ -11,7 +11,6 @@ import com.backyardbrains.db.entity.Train; import com.backyardbrains.dsp.audio.AudioFile; import com.backyardbrains.dsp.audio.BaseAudioFile; -import com.backyardbrains.dsp.audio.WavAudioFile; import com.backyardbrains.events.AnalysisDoneEvent; import com.backyardbrains.utils.ObjectUtils; import com.backyardbrains.utils.ThresholdOrientation; @@ -19,7 +18,7 @@ import com.backyardbrains.vo.EventTriggeredAverages; import com.backyardbrains.vo.SpikeIndexValue; import com.backyardbrains.vo.Threshold; -import com.crashlytics.android.Crashlytics; +import com.google.firebase.crashlytics.FirebaseCrashlytics; import java.io.File; import java.io.IOException; import java.util.ArrayList; @@ -73,7 +72,9 @@ public void findSpikes(@NonNull String filePath) { // post event that audio file analysis failed EventBus.getDefault().post(new AnalysisDoneEvent(false, AnalysisType.FIND_SPIKES)); - Crashlytics.logException(new Throwable("Error while loading file during Find Spikes analysis")); + FirebaseCrashlytics.getInstance() + .recordException( + new Throwable("Error while loading file during Find Spikes analysis")); } } else { spikesAnalysisExists(filePath, false, spikeAnalysisCheckCallback); @@ -86,7 +87,9 @@ public void findSpikes(@NonNull String filePath) { // post event that audio file analysis failed EventBus.getDefault().post(new AnalysisDoneEvent(false, AnalysisType.FIND_SPIKES)); - Crashlytics.logException(new Throwable("Error while loading file during Find Spikes analysis")); + FirebaseCrashlytics.getInstance() + .recordException( + new Throwable("Error while loading file during Find Spikes analysis")); } } } @@ -144,7 +147,7 @@ private boolean load(@NonNull String filePath) { return load(new File(filePath)); } catch (IOException e) { LOGE(TAG, "Error while loading " + filePath); - Crashlytics.logException(e); + FirebaseCrashlytics.getInstance().recordException(e); return false; } } @@ -190,7 +193,7 @@ private void reset() { LOGD(TAG, "RandomAccessFile closed"); } catch (IOException e) { LOGE(TAG, "IOException while stopping random access file: " + e.toString()); - Crashlytics.logException(e); + FirebaseCrashlytics.getInstance().recordException(e); } finally { audioFile = null; } diff --git a/app/src/main/java/com/backyardbrains/drawing/DrawBuffer.java b/app/src/main/java/com/backyardbrains/drawing/DrawBuffer.java index 9593960..72cd782 100644 --- a/app/src/main/java/com/backyardbrains/drawing/DrawBuffer.java +++ b/app/src/main/java/com/backyardbrains/drawing/DrawBuffer.java @@ -19,7 +19,7 @@ package com.backyardbrains.drawing; -import com.crashlytics.android.Crashlytics; +import com.google.firebase.crashlytics.FirebaseCrashlytics; import static com.backyardbrains.utils.LogUtils.LOGD; import static com.backyardbrains.utils.LogUtils.makeLogTag; @@ -50,10 +50,10 @@ public void put(byte[] src, int len) { System.arraycopy(buffer, len, buffer, 0, buffer.length - len); System.arraycopy(src, 0, buffer, buffer.length - len, len); } catch (Exception e) { - LOGD(TAG, - "Can't add incoming to buffer, it's larger then buffer - src.length=" + buffer.length + " srcPos=" + len - + " dst.length=" + buffer.length + " dstPos=" + 0 + " length=" + (buffer.length - len)); - Crashlytics.logException(e); + LOGD(TAG, "Can't add incoming to buffer, it's larger then buffer - src.length=" + + buffer.length + " srcPos=" + len + " dst.length=" + buffer.length + " dstPos=" + 0 + + " length=" + (buffer.length - len)); + FirebaseCrashlytics.getInstance().recordException(e); } } @@ -62,9 +62,10 @@ public int get(byte[] dst, int off, int len) { System.arraycopy(buffer, off, dst, 0, len); return len; } catch (Exception e) { - LOGD(TAG, "Can't copy from buffer to destination - src.length=" + buffer.length + " srcPos=" + off - + " dst.length=" + dst.length + " dstPos=" + 0 + " length=" + len); - Crashlytics.logException(e); + LOGD(TAG, + "Can't copy from buffer to destination - src.length=" + buffer.length + " srcPos=" + + off + " dst.length=" + dst.length + " dstPos=" + 0 + " length=" + len); + FirebaseCrashlytics.getInstance().recordException(e); } return 0; diff --git a/app/src/main/java/com/backyardbrains/drawing/FftDrawBuffer.java b/app/src/main/java/com/backyardbrains/drawing/FftDrawBuffer.java index cafa891..9c1573a 100644 --- a/app/src/main/java/com/backyardbrains/drawing/FftDrawBuffer.java +++ b/app/src/main/java/com/backyardbrains/drawing/FftDrawBuffer.java @@ -19,7 +19,7 @@ package com.backyardbrains.drawing; -import com.crashlytics.android.Crashlytics; +import com.google.firebase.crashlytics.FirebaseCrashlytics; import java.util.Arrays; import static com.backyardbrains.utils.LogUtils.LOGD; @@ -93,9 +93,11 @@ public void add(float[][] incoming, int length) { } } } catch (Exception e) { - LOGD(TAG, "Can't add incoming to buffer, it's larger then buffer - src.length=" + windowCount + " srcPos=" - + length + " dst.length=" + windowCount + " dstPos=" + 0 + " length=" + (windowCount - length)); - Crashlytics.logException(e); + LOGD(TAG, + "Can't add incoming to buffer, it's larger then buffer - src.length=" + windowCount + + " srcPos=" + length + " dst.length=" + windowCount + " dstPos=" + 0 + + " length=" + (windowCount - length)); + FirebaseCrashlytics.getInstance().recordException(e); } } diff --git a/app/src/main/java/com/backyardbrains/drawing/FindSpikesRenderer.java b/app/src/main/java/com/backyardbrains/drawing/FindSpikesRenderer.java index 78bf135..9990171 100644 --- a/app/src/main/java/com/backyardbrains/drawing/FindSpikesRenderer.java +++ b/app/src/main/java/com/backyardbrains/drawing/FindSpikesRenderer.java @@ -1,8 +1,8 @@ package com.backyardbrains.drawing; +import android.view.MotionEvent; import androidx.annotation.NonNull; import androidx.annotation.Size; -import android.view.MotionEvent; import com.backyardbrains.drawing.gl.GlHLine; import com.backyardbrains.drawing.gl.GlHandle; import com.backyardbrains.drawing.gl.GlHandleDragHelper; @@ -14,7 +14,7 @@ import com.backyardbrains.utils.ViewUtils; import com.backyardbrains.vo.SpikeIndexValue; import com.backyardbrains.vo.Threshold; -import com.crashlytics.android.Crashlytics; +import com.google.firebase.crashlytics.FirebaseCrashlytics; import javax.microedition.khronos.opengles.GL10; import static com.backyardbrains.utils.LogUtils.LOGE; @@ -172,7 +172,7 @@ public void setSelectedSpikeTrain(int selectedSpikeTrain) { fromSample, toSample, drawStartIndex, drawEndIndex, samplesToDraw, surfaceWidth); } catch (Exception e) { LOGE(TAG, e.getMessage()); - Crashlytics.logException(e); + FirebaseCrashlytics.getInstance().recordException(e); } // draw spikes if (spikesDrawData.vertexCount > 0) { diff --git a/app/src/main/java/com/backyardbrains/drawing/MultichannelSignalDrawBuffer.java b/app/src/main/java/com/backyardbrains/drawing/MultichannelSignalDrawBuffer.java index bf44bc1..19531ba 100644 --- a/app/src/main/java/com/backyardbrains/drawing/MultichannelSignalDrawBuffer.java +++ b/app/src/main/java/com/backyardbrains/drawing/MultichannelSignalDrawBuffer.java @@ -21,7 +21,7 @@ import androidx.annotation.NonNull; import com.backyardbrains.dsp.SignalConfiguration; -import com.crashlytics.android.Crashlytics; +import com.google.firebase.crashlytics.FirebaseCrashlytics; import static com.backyardbrains.utils.LogUtils.LOGD; import static com.backyardbrains.utils.LogUtils.makeLogTag; @@ -87,10 +87,10 @@ public void add(int channel, short[] incoming, int length) { System.arraycopy(incoming, length - tmpBuffer.length, tmpBuffer, 0, tmpBuffer.length); } } catch (Exception e) { - LOGD(TAG, "Can't add incoming to buffer, it's larger then buffer - channel=" + channel + " src.length=" - + tmpBuffer.length + " srcPos=" + length + " dst.length=" + tmpBuffer.length + " dstPos=" + 0 - + " length=" + (tmpBuffer.length - length)); - Crashlytics.logException(e); + LOGD(TAG, "Can't add incoming to buffer, it's larger then buffer - channel=" + channel + + " src.length=" + tmpBuffer.length + " srcPos=" + length + " dst.length=" + + tmpBuffer.length + " dstPos=" + 0 + " length=" + (tmpBuffer.length - length)); + FirebaseCrashlytics.getInstance().recordException(e); } } diff --git a/app/src/main/java/com/backyardbrains/drawing/ScaleListener.java b/app/src/main/java/com/backyardbrains/drawing/ScaleListener.java index 2c69a05..3377dc7 100644 --- a/app/src/main/java/com/backyardbrains/drawing/ScaleListener.java +++ b/app/src/main/java/com/backyardbrains/drawing/ScaleListener.java @@ -19,9 +19,9 @@ package com.backyardbrains.drawing; -import androidx.annotation.Nullable; import android.view.ScaleGestureDetector; -import com.crashlytics.android.Crashlytics; +import androidx.annotation.Nullable; +import com.google.firebase.crashlytics.FirebaseCrashlytics; import static com.backyardbrains.utils.LogUtils.LOGE; import static com.backyardbrains.utils.LogUtils.makeLogTag; @@ -81,12 +81,12 @@ public class ScaleListener extends ScaleGestureDetector.SimpleOnScaleGestureList return true; } catch (IllegalStateException e) { LOGE(TAG, "Got invalid values back from Scale listener!"); - Crashlytics.logException(e); + FirebaseCrashlytics.getInstance().recordException(e); return false; } catch (NullPointerException e) { LOGE(TAG, "NPE while monitoring scale."); - Crashlytics.logException(e); + FirebaseCrashlytics.getInstance().recordException(e); return false; } diff --git a/app/src/main/java/com/backyardbrains/drawing/SeekableWaveformRenderer.java b/app/src/main/java/com/backyardbrains/drawing/SeekableWaveformRenderer.java index 0b61e60..1123a13 100644 --- a/app/src/main/java/com/backyardbrains/drawing/SeekableWaveformRenderer.java +++ b/app/src/main/java/com/backyardbrains/drawing/SeekableWaveformRenderer.java @@ -16,7 +16,7 @@ import com.backyardbrains.utils.JniUtils; import com.backyardbrains.utils.ViewUtils; import com.backyardbrains.vo.SpikeIndexValue; -import com.crashlytics.android.Crashlytics; +import com.google.firebase.crashlytics.FirebaseCrashlytics; import java.util.Arrays; import javax.microedition.khronos.egl.EGLConfig; import javax.microedition.khronos.opengles.GL10; @@ -275,7 +275,7 @@ public SeekableWaveformRenderer(@NonNull String filePath, @NonNull BaseFragment drawStartIndex, drawEndIndex, samplesToDraw, surfaceWidth); } catch (Exception e) { LOGE(TAG, e.getMessage()); - Crashlytics.logException(e); + FirebaseCrashlytics.getInstance().recordException(e); } if (spikesDrawData[j].vertexCount > 0) { gl.glPushMatrix(); diff --git a/app/src/main/java/com/backyardbrains/drawing/WaveformRenderer.java b/app/src/main/java/com/backyardbrains/drawing/WaveformRenderer.java index 5697a63..cec7456 100644 --- a/app/src/main/java/com/backyardbrains/drawing/WaveformRenderer.java +++ b/app/src/main/java/com/backyardbrains/drawing/WaveformRenderer.java @@ -20,10 +20,10 @@ package com.backyardbrains.drawing; import android.content.Context; +import android.view.MotionEvent; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.annotation.Size; -import android.view.MotionEvent; import com.backyardbrains.drawing.gl.GlAveragingTriggerLine; import com.backyardbrains.drawing.gl.GlDashedHLine; import com.backyardbrains.drawing.gl.GlEventMarker; @@ -40,7 +40,7 @@ import com.backyardbrains.utils.JniUtils; import com.backyardbrains.utils.PrefUtils; import com.backyardbrains.utils.ViewUtils; -import com.crashlytics.android.Crashlytics; +import com.google.firebase.crashlytics.FirebaseCrashlytics; import javax.microedition.khronos.egl.EGLConfig; import javax.microedition.khronos.opengles.GL10; @@ -362,7 +362,7 @@ protected void setThreshold(float threshold) { } } catch (Exception e) { LOGE(TAG, e.getMessage()); - Crashlytics.logException(e); + FirebaseCrashlytics.getInstance().recordException(e); } // only process events if threshold is off @@ -390,7 +390,7 @@ protected void setThreshold(float threshold) { drawSurfaceWidth, (int) fftSurfaceHeight, fftScaleFactor); } catch (Exception e) { LOGE(TAG, e.getMessage()); - Crashlytics.logException(e); + FirebaseCrashlytics.getInstance().recordException(e); } //benchmark.end(); } diff --git a/app/src/main/java/com/backyardbrains/dsp/Filters.java b/app/src/main/java/com/backyardbrains/dsp/Filters.java index e5c103b..bd8b7e0 100644 --- a/app/src/main/java/com/backyardbrains/dsp/Filters.java +++ b/app/src/main/java/com/backyardbrains/dsp/Filters.java @@ -30,6 +30,10 @@ public class Filters { private static final double FREQ_CUTOFF_50HZ = 50d; // 60Hz cut-off frequency private static final double FREQ_CUTOFF_60HZ = 60d; + // Low cut-off frequency for Human PRO + private static final double FREQ_LOW_CUTOFF_HUMAN_PRO = 1d; + // High cut-off frequency for Human PRO + private static final double FREQ_HIGH_CUTOFF_HUMAN_PRO = 2500d; /** * Predefined filter configured for EKG. @@ -49,12 +53,18 @@ public class Filters { /** * Predefined filter configured for EMG. */ - public static final BandFilter FILTER_BAND_MUSCLE = new BandFilter(FREQ_LOW_CUTOFF_MUSCLE, FREQ_HIGH_CUTOFF_MUSCLE); + public static final BandFilter FILTER_BAND_MUSCLE = + new BandFilter(FREQ_LOW_CUTOFF_MUSCLE, FREQ_HIGH_CUTOFF_MUSCLE); /** * Predefined filter configured for Neuron Pro. */ public static final BandFilter FILTER_BAND_NEURON_PRO = new BandFilter(FREQ_LOW_CUTOFF_NEURON_PRO, FREQ_HIGH_CUTOFF_NEURON_PRO); + /** + * Predefined filter configured for Human Pro. + */ + public static final BandFilter FILTER_BAND_HUMAN_PRO = + new BandFilter(FREQ_LOW_CUTOFF_HUMAN_PRO, FREQ_HIGH_CUTOFF_HUMAN_PRO); /** * Predefined notch filter that cuts-off 50Hz frequency */ diff --git a/app/src/main/java/com/backyardbrains/dsp/ProcessingService.java b/app/src/main/java/com/backyardbrains/dsp/ProcessingService.java index 5d8c7f4..9242e7e 100644 --- a/app/src/main/java/com/backyardbrains/dsp/ProcessingService.java +++ b/app/src/main/java/com/backyardbrains/dsp/ProcessingService.java @@ -56,7 +56,7 @@ import com.backyardbrains.utils.SignalAveragingTriggerType; import com.backyardbrains.utils.SpikerBoxHardwareType; import com.backyardbrains.utils.ViewUtils; -import com.crashlytics.android.Crashlytics; +import com.google.firebase.crashlytics.FirebaseCrashlytics; import java.io.IOException; import org.greenrobot.eventbus.EventBus; @@ -778,11 +778,12 @@ public void startRecording() { // post that recording of audio has started EventBus.getDefault().post(new AudioRecordingStartedEvent()); } catch (IllegalStateException e) { - Crashlytics.logException(e); - ViewUtils.toast(getApplicationContext(), "No SD Card is available. Recording is disabled"); + FirebaseCrashlytics.getInstance().recordException(e); + ViewUtils.toast(getApplicationContext(), + "No SD Card is available. Recording is disabled"); stopRecording(); } catch (IOException e) { - Crashlytics.logException(e); + FirebaseCrashlytics.getInstance().recordException(e); ViewUtils.toast(getApplicationContext(), "Error occurred while trying to initiate recording. Please try again."); stopRecording(); @@ -856,7 +857,7 @@ private void record(@NonNull SignalData signalData) { signalProcessor.getBitsPerSample())); } } catch (Exception e) { - Crashlytics.logException(e); + FirebaseCrashlytics.getInstance().recordException(e); LOGW(TAG, "Ignoring bytes received while not synced: " + e.getMessage()); } } diff --git a/app/src/main/java/com/backyardbrains/dsp/audio/MicrophoneSignalSource.java b/app/src/main/java/com/backyardbrains/dsp/audio/MicrophoneSignalSource.java index 9e20a8d..6fbd726 100644 --- a/app/src/main/java/com/backyardbrains/dsp/audio/MicrophoneSignalSource.java +++ b/app/src/main/java/com/backyardbrains/dsp/audio/MicrophoneSignalSource.java @@ -9,7 +9,7 @@ import com.backyardbrains.dsp.SignalData; import com.backyardbrains.utils.AudioUtils; import com.backyardbrains.utils.JniUtils; -import com.crashlytics.android.Crashlytics; +import com.google.firebase.crashlytics.FirebaseCrashlytics; import java.util.concurrent.atomic.AtomicBoolean; import static com.backyardbrains.utils.LogUtils.LOGD; @@ -57,7 +57,7 @@ private class ReadThread extends Thread { } } catch (Throwable e) { LOGE(TAG, "Could not open audio source", e); - Crashlytics.logException(e); + FirebaseCrashlytics.getInstance().recordException(e); } } } @@ -162,7 +162,7 @@ private void stopRecorder() { LOGD(TAG, "Recorder resources released"); } catch (IllegalStateException e) { LOGE(TAG, "Caught Illegal State Exception: " + e.toString()); - Crashlytics.logException(e); + FirebaseCrashlytics.getInstance().recordException(e); } recorder = null; } diff --git a/app/src/main/java/com/backyardbrains/dsp/audio/PlaybackSignalSource.java b/app/src/main/java/com/backyardbrains/dsp/audio/PlaybackSignalSource.java index ce89872..1885fa8 100644 --- a/app/src/main/java/com/backyardbrains/dsp/audio/PlaybackSignalSource.java +++ b/app/src/main/java/com/backyardbrains/dsp/audio/PlaybackSignalSource.java @@ -13,7 +13,7 @@ import com.backyardbrains.utils.BufferUtils; import com.backyardbrains.utils.EventUtils; import com.backyardbrains.utils.JniUtils; -import com.crashlytics.android.Crashlytics; +import com.google.firebase.crashlytics.FirebaseCrashlytics; import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; @@ -207,7 +207,7 @@ protected class ReadThread extends Thread { } catch (IOException e) { LOGE(TAG, e instanceof FileNotFoundException ? "Error loading file" : "Error reading random access file stream", e); - Crashlytics.logException(e); + FirebaseCrashlytics.getInstance().recordException(e); PlaybackSignalSource.this.stop(); } @@ -291,7 +291,7 @@ synchronized void rewind() { if (raf != null) raf.seek(0); } catch (IOException e) { LOGE(TAG, "IOException while rewinding: " + e.toString()); - Crashlytics.logException(e); + FirebaseCrashlytics.getInstance().recordException(e); } // update progress to 0 and trigger listener progress.set(0); @@ -313,7 +313,7 @@ private void closeRaf() { raf.close(); } catch (IOException e) { LOGE(TAG, "IOException while stopping random access file: " + e.toString()); - Crashlytics.logException(e); + FirebaseCrashlytics.getInstance().recordException(e); } finally { raf = null; } @@ -490,7 +490,7 @@ public void seek(int position) { try { playbackThread.seekToPosition(); } catch (IOException e) { - Crashlytics.logException(e); + FirebaseCrashlytics.getInstance().recordException(e); LOGE(TAG, "Error reading random access file stream", e); } } @@ -516,7 +516,7 @@ public void readLast(byte[] buffer, int len) { try { playbackThread.readLast(buffer, len); } catch (IOException e) { - Crashlytics.logException(e); + FirebaseCrashlytics.getInstance().recordException(e); LOGE(TAG, "Error reading random access file stream", e); } } diff --git a/app/src/main/java/com/backyardbrains/dsp/audio/Recorder.java b/app/src/main/java/com/backyardbrains/dsp/audio/Recorder.java index 3ba0262..9b502dd 100644 --- a/app/src/main/java/com/backyardbrains/dsp/audio/Recorder.java +++ b/app/src/main/java/com/backyardbrains/dsp/audio/Recorder.java @@ -26,7 +26,7 @@ import com.backyardbrains.utils.AudioUtils; import com.backyardbrains.utils.JniUtils; import com.backyardbrains.utils.RecordingUtils; -import com.crashlytics.android.Crashlytics; +import com.google.firebase.crashlytics.FirebaseCrashlytics; import java.io.File; import java.io.FileNotFoundException; import java.io.FileOutputStream; @@ -96,7 +96,7 @@ private class WriteThread extends Thread { } } } catch (IllegalStateException e) { - Crashlytics.logException(e); + FirebaseCrashlytics.getInstance().recordException(e); } } @@ -110,7 +110,7 @@ void startRecording(int sampleRate, int visibleChannelCount) throws IOException try { outputStream = new FileOutputStream(audioFile); } catch (FileNotFoundException e) { - Crashlytics.logException(e); + FirebaseCrashlytics.getInstance().recordException(e); throw new IOException( "Could not build OutputStream from audio file: " + audioFile.getAbsolutePath(), e); @@ -213,7 +213,7 @@ private void saveFiles() { if (events.size() > 0) saveEventFile(); } catch (IOException e) { - Crashlytics.logException(e); + FirebaseCrashlytics.getInstance().recordException(e); } } @@ -242,7 +242,7 @@ private void saveEventFile() throws IOException { outputStream.flush(); outputStream.close(); } catch (IOException e) { - Crashlytics.logException(e); + FirebaseCrashlytics.getInstance().recordException(e); throw new IOException( "could not build OutputStream from events file: " + audioFile.getAbsolutePath(), e); diff --git a/app/src/main/java/com/backyardbrains/dsp/audio/WavAudioFile.java b/app/src/main/java/com/backyardbrains/dsp/audio/WavAudioFile.java index 1449761..5abe0e2 100644 --- a/app/src/main/java/com/backyardbrains/dsp/audio/WavAudioFile.java +++ b/app/src/main/java/com/backyardbrains/dsp/audio/WavAudioFile.java @@ -3,7 +3,7 @@ import android.media.MediaExtractor; import androidx.annotation.NonNull; import com.backyardbrains.utils.WavUtils; -import com.crashlytics.android.Crashlytics; +import com.google.firebase.crashlytics.FirebaseCrashlytics; import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; @@ -35,7 +35,7 @@ public static boolean save(@NonNull File file, int channelCount, int sampleRate, try { raf = new RandomAccessFile(file, "rw"); } catch (FileNotFoundException e) { - Crashlytics.logException(e); + FirebaseCrashlytics.getInstance().recordException(e); return false; } @@ -44,7 +44,7 @@ public static boolean save(@NonNull File file, int channelCount, int sampleRate, raf.write(WavUtils.writeHeader(file.length(), sampleRate, channelCount, encoding)); raf.close(); } catch (IOException e) { - Crashlytics.logException(e); + FirebaseCrashlytics.getInstance().recordException(e); return false; } finally { raf.close(); diff --git a/app/src/main/java/com/backyardbrains/dsp/usb/AbstractUsbSignalSource.java b/app/src/main/java/com/backyardbrains/dsp/usb/AbstractUsbSignalSource.java index 2df3bbc..bc3dc22 100644 --- a/app/src/main/java/com/backyardbrains/dsp/usb/AbstractUsbSignalSource.java +++ b/app/src/main/java/com/backyardbrains/dsp/usb/AbstractUsbSignalSource.java @@ -120,7 +120,11 @@ public boolean isDisconnecting() { if (vid == BYB_VENDOR_ID) { if (pid == BYB_PID_MUSCLE_SB_PRO) { return SpikerBoxHardwareType.MUSCLE_PRO; - } else if (pid == BYB_PID_NEURON_SB_PRO) return SpikerBoxHardwareType.NEURON_PRO; + } else if (pid == BYB_PID_NEURON_SB_PRO) { + return SpikerBoxHardwareType.NEURON_PRO; + } else if (pid == BYB_PID_HUMAN_SB_PRO) { + return SpikerBoxHardwareType.HUMAN_PRO; + } } return SpikerBoxHardwareType.UNKNOWN; diff --git a/app/src/main/java/com/backyardbrains/dsp/usb/SerialSignalSource.java b/app/src/main/java/com/backyardbrains/dsp/usb/SerialSignalSource.java index 788b2bc..cbc937e 100644 --- a/app/src/main/java/com/backyardbrains/dsp/usb/SerialSignalSource.java +++ b/app/src/main/java/com/backyardbrains/dsp/usb/SerialSignalSource.java @@ -4,11 +4,14 @@ import android.hardware.usb.UsbDeviceConnection; import androidx.annotation.NonNull; import com.backyardbrains.utils.SampleStreamUtils; +import com.backyardbrains.utils.SpikerBoxHardwareType; import com.felhr.usbserial.UsbSerialDevice; import com.felhr.usbserial.UsbSerialInterface; import java.util.Locale; import static com.backyardbrains.utils.LogUtils.makeLogTag; +import static com.backyardbrains.utils.SampleStreamUtils.SAMPLE_RATE_5000; +import static com.backyardbrains.utils.SampleStreamUtils.SPIKER_BOX_PRO_CHANNEL_COUNT; /** * Implementation of {@link AbstractUsbSignalSource} capable of USB serial communication with BYB hardware. @@ -132,6 +135,11 @@ private SerialSignalSource(@NonNull UsbDevice device, @NonNull UsbDeviceConnecti usbBuffer = new SerialBuffer(); serialDevice = UsbSerialDevice.createUsbSerialDevice(device, connection); + + if (getHardwareType() == SpikerBoxHardwareType.HUMAN_PRO) { + setSampleRate(SAMPLE_RATE_5000); + setChannelCount(SPIKER_BOX_PRO_CHANNEL_COUNT); + } } /** diff --git a/app/src/main/java/com/backyardbrains/dsp/usb/SpikerBoxDetector.java b/app/src/main/java/com/backyardbrains/dsp/usb/SpikerBoxDetector.java index 27626ae..e531413 100644 --- a/app/src/main/java/com/backyardbrains/dsp/usb/SpikerBoxDetector.java +++ b/app/src/main/java/com/backyardbrains/dsp/usb/SpikerBoxDetector.java @@ -11,7 +11,7 @@ import com.backyardbrains.utils.AudioUtils; import com.backyardbrains.utils.JniUtils; import com.backyardbrains.utils.SpikerBoxHardwareType; -import com.crashlytics.android.Crashlytics; +import com.google.firebase.crashlytics.FirebaseCrashlytics; import java.util.Map; import static com.backyardbrains.utils.LogUtils.LOGD; @@ -116,21 +116,25 @@ void startDetection(@NonNull UsbDevice device) { "Failed to open USB communication port!"); } LOGD(TAG, "PORT NOT OPEN"); - Crashlytics.logException(new RuntimeException("Failed to open USB communication port!")); + FirebaseCrashlytics.getInstance() + .recordException( + new RuntimeException("Failed to open USB communication port!")); } } else { if (listener != null) { listener.onSpikerBoxDetectionError(device.getDeviceName(), "Failed to connect to USB device!"); } LOGD(TAG, "PORT IS NULL"); - Crashlytics.logException(new RuntimeException("Failed to connect to USB device!")); + FirebaseCrashlytics.getInstance() + .recordException(new RuntimeException("Failed to connect to USB device!")); } } else { if (listener != null) { listener.onSpikerBoxDetectionError(device.getDeviceName(), "Connected USB device is not supported!"); } LOGD(TAG, "DEVICE NOT SUPPORTED"); - Crashlytics.logException(new RuntimeException("Connected USB device is not supported!")); + FirebaseCrashlytics.getInstance() + .recordException(new RuntimeException("Connected USB device is not supported!")); } } diff --git a/app/src/main/java/com/backyardbrains/dsp/usb/UsbHelper.java b/app/src/main/java/com/backyardbrains/dsp/usb/UsbHelper.java index 30aa335..290ad8d 100644 --- a/app/src/main/java/com/backyardbrains/dsp/usb/UsbHelper.java +++ b/app/src/main/java/com/backyardbrains/dsp/usb/UsbHelper.java @@ -12,7 +12,7 @@ import androidx.annotation.Nullable; import androidx.collection.ArraySet; import com.backyardbrains.utils.SpikerBoxHardwareType; -import com.crashlytics.android.Crashlytics; +import com.google.firebase.crashlytics.FirebaseCrashlytics; import java.util.ArrayList; import java.util.HashMap; import java.util.List; @@ -145,19 +145,25 @@ private class CommunicationThread extends Thread { if (usbDevice != null) usbDevice.checkHardwareType(); } else { LOGD(TAG, "PORT NOT OPEN"); - Crashlytics.logException(new RuntimeException("Failed to open USB communication port!")); + FirebaseCrashlytics.getInstance() + .recordException( + new RuntimeException("Failed to open USB communication port!")); } } else { LOGD(TAG, "PORT IS NULL"); - Crashlytics.logException(new RuntimeException("Failed to create USB device!")); + FirebaseCrashlytics.getInstance() + .recordException(new RuntimeException("Failed to create USB device!")); } } else { LOGD(TAG, "USB DEVICE OPEN FAILED"); - Crashlytics.logException(new RuntimeException("USB device open connection failed!")); + FirebaseCrashlytics.getInstance() + .recordException( + new RuntimeException("USB device open connection failed!")); } } else { LOGD(TAG, "USB MANAGER NOT AVAILABLE"); - Crashlytics.logException(new RuntimeException("USB Manager is not available!")); + FirebaseCrashlytics.getInstance() + .recordException(new RuntimeException("USB Manager is not available!")); } } } diff --git a/app/src/main/java/com/backyardbrains/dsp/usb/UsbSignalSource.java b/app/src/main/java/com/backyardbrains/dsp/usb/UsbSignalSource.java index 7a65f15..85d6072 100644 --- a/app/src/main/java/com/backyardbrains/dsp/usb/UsbSignalSource.java +++ b/app/src/main/java/com/backyardbrains/dsp/usb/UsbSignalSource.java @@ -17,6 +17,8 @@ public interface UsbSignalSource extends SignalSource { int BYB_PID_MUSCLE_SB_PRO = 0x1; // BYB Neuron SpikerBox Pro Product ID int BYB_PID_NEURON_SB_PRO = 0x2; + // BYB Human SpikerBox Pro Product ID + int BYB_PID_HUMAN_SB_PRO = 0x4; /** * Opens usb communication port. diff --git a/app/src/main/java/com/backyardbrains/ui/MainActivity.java b/app/src/main/java/com/backyardbrains/ui/MainActivity.java index 1f12a99..ce82d56 100644 --- a/app/src/main/java/com/backyardbrains/ui/MainActivity.java +++ b/app/src/main/java/com/backyardbrains/ui/MainActivity.java @@ -9,18 +9,17 @@ import android.os.Bundle; import android.os.IBinder; import android.os.Parcelable; +import android.view.View; +import android.widget.Toast; import androidx.annotation.IdRes; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.annotation.StringRes; -import com.google.android.material.bottomnavigation.BottomNavigationView; +import androidx.appcompat.app.AppCompatActivity; +import androidx.appcompat.app.AppCompatDelegate; import androidx.fragment.app.Fragment; import androidx.fragment.app.FragmentManager; import androidx.fragment.app.FragmentTransaction; -import androidx.appcompat.app.AppCompatActivity; -import androidx.appcompat.app.AppCompatDelegate; -import android.view.View; -import android.widget.Toast; import butterknife.BindView; import butterknife.ButterKnife; import com.backyardbrains.R; @@ -43,8 +42,8 @@ import com.backyardbrains.utils.ImportUtils; import com.backyardbrains.utils.ImportUtils.ImportResultCode; import com.backyardbrains.utils.ViewUtils; -import com.crashlytics.android.answers.Answers; -import com.crashlytics.android.answers.ContentViewEvent; +import com.google.android.material.bottomnavigation.BottomNavigationView; +import com.google.firebase.analytics.FirebaseAnalytics; import java.util.List; import org.greenrobot.eventbus.EventBus; import org.greenrobot.eventbus.NoSubscriberEvent; @@ -87,6 +86,8 @@ public class MainActivity extends AppCompatActivity private static final int BYB_WRITE_STORAGE_PERM = 124; private static final int BYB_SETTINGS_SCREEN = 125; + private FirebaseAnalytics mFirebaseAnalytics; + static { AppCompatDelegate.setCompatVectorFromResourcesEnabled(true); } @@ -113,6 +114,8 @@ public class MainActivity extends AppCompatActivity super.onCreate(savedInstanceState); LOGD(TAG, "onCreate()"); + mFirebaseAnalytics = FirebaseAnalytics.getInstance(this); + setContentView(R.layout.activity_main); ButterKnife.bind(this); @@ -226,21 +229,25 @@ public void loadFragment(int fragType, boolean popExisting, Object... args) { fragName = RECORDING_OPTIONS_FRAGMENT; break; case RECORDING_DETAILS_VIEW: - frag = RecordingDetailsFragment.newInstance(args.length > 0 ? String.valueOf(args[0]) : null); + frag = RecordingDetailsFragment.newInstance( + args.length > 0 ? String.valueOf(args[0]) : null); fragName = RECORDING_DETAILS_FRAGMENT; break; case RECORDING_ANALYSIS_VIEW: - frag = RecordingAnalysisFragment.newInstance(args.length > 0 ? String.valueOf(args[0]) : null); + frag = RecordingAnalysisFragment.newInstance( + args.length > 0 ? String.valueOf(args[0]) : null); fragName = RECORDING_ANALYSIS_FRAGMENT; break; } // Log with Fabric Answers what view did the user opened - Answers.getInstance() - .logContentView(new ContentViewEvent().putContentName(fragName).putContentType("Screen View")); + Bundle bundle = new Bundle(); + bundle.putString(FirebaseAnalytics.Param.SCREEN_NAME, fragName); + mFirebaseAnalytics.logEvent(FirebaseAnalytics.Event.SCREEN_VIEW, bundle); setSelectedButton(fragType); - showFragment(frag, fragName, R.id.fragment_container, popExisting, false, R.anim.slide_in_right, - R.anim.slide_out_left, R.anim.slide_in_left, R.anim.slide_out_right); + showFragment(frag, fragName, R.id.fragment_container, popExisting, false, + R.anim.slide_in_right, R.anim.slide_out_left, R.anim.slide_in_left, + R.anim.slide_out_right); } } diff --git a/app/src/main/java/com/backyardbrains/ui/RecordScopeFragment.java b/app/src/main/java/com/backyardbrains/ui/RecordScopeFragment.java index 30317bf..945a8e2 100644 --- a/app/src/main/java/com/backyardbrains/ui/RecordScopeFragment.java +++ b/app/src/main/java/com/backyardbrains/ui/RecordScopeFragment.java @@ -4,10 +4,6 @@ import android.hardware.usb.UsbDevice; import android.os.Build; import android.os.Bundle; -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import androidx.annotation.Size; -import androidx.core.content.ContextCompat; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; @@ -17,6 +13,10 @@ import android.widget.SeekBar; import android.widget.TextView; import android.widget.ToggleButton; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.annotation.Size; +import androidx.core.content.ContextCompat; import butterknife.BindView; import butterknife.ButterKnife; import butterknife.Unbinder; @@ -53,7 +53,7 @@ import com.backyardbrains.view.HeartbeatView; import com.backyardbrains.view.SettingsView; import com.backyardbrains.view.SlidingView; -import com.crashlytics.android.Crashlytics; +import com.google.firebase.crashlytics.FirebaseCrashlytics; import java.util.ArrayList; import java.util.List; import org.greenrobot.eventbus.Subscribe; @@ -432,6 +432,10 @@ public void onSpikerBoxBoardTypeDetectionEvent(SpikerBoxHardwareTypeDetectionEve spikerBoxBoard = getString(R.string.board_type_neuron_pro); filter = Filters.FILTER_BAND_NEURON_PRO; break; + case SpikerBoxHardwareType.HUMAN_PRO: + spikerBoxBoard = getString(R.string.board_type_human_pro); + filter = Filters.FILTER_BAND_HUMAN_PRO; + break; default: case SpikerBoxHardwareType.UNKNOWN: case SpikerBoxHardwareType.NONE: @@ -831,7 +835,7 @@ void connectWithDevice() { try { startUsb(getProcessingService(), deviceName); } catch (IllegalArgumentException e) { - Crashlytics.logException(e); + FirebaseCrashlytics.getInstance().recordException(e); if (getContext() != null) { ViewUtils.toast(getContext(), "Error while connecting with device " + deviceName + "!"); } @@ -851,7 +855,7 @@ void disconnectFromDevice() { try { getProcessingService().stopUsb(); } catch (IllegalArgumentException e) { - Crashlytics.logException(e); + FirebaseCrashlytics.getInstance().recordException(e); if (getContext() != null) { ViewUtils.toast(getContext(), "Error while disconnecting from currently connected device!"); } diff --git a/app/src/main/java/com/backyardbrains/ui/RecordingDetailsFragment.java b/app/src/main/java/com/backyardbrains/ui/RecordingDetailsFragment.java index af87434..1a36031 100644 --- a/app/src/main/java/com/backyardbrains/ui/RecordingDetailsFragment.java +++ b/app/src/main/java/com/backyardbrains/ui/RecordingDetailsFragment.java @@ -25,7 +25,7 @@ import com.backyardbrains.utils.ObjectUtils; import com.backyardbrains.utils.RecordingUtils; import com.backyardbrains.utils.ViewUtils; -import com.crashlytics.android.Crashlytics; +import com.google.firebase.crashlytics.FirebaseCrashlytics; import java.io.File; import java.util.Date; import org.greenrobot.eventbus.EventBus; @@ -229,9 +229,10 @@ private void stopEditFilename() { if (!ef.renameTo(newEventsFile)) { BYBUtils.showAlert(getActivity(), getString(R.string.title_error), getString(R.string.error_message_files_events_rename)); - Crashlytics.logException(new Throwable( - "Renaming events file for the given recording " - + oldFile.getPath() + " failed")); + FirebaseCrashlytics.getInstance() + .recordException(new Throwable( + "Renaming events file for the given recording " + + oldFile.getPath() + " failed")); } } } @@ -240,8 +241,9 @@ private void stopEditFilename() { ViewUtils.toast(getContext(), getString(R.string.error_message_files_rename)); } - Crashlytics.logException( - new Throwable("Renaming file " + oldFile.getPath() + " failed")); + FirebaseCrashlytics.getInstance() + .recordException( + new Throwable("Renaming file " + oldFile.getPath() + " failed")); } } else { if (getContext() != null) { @@ -252,7 +254,8 @@ private void stopEditFilename() { if (getContext() != null) { ViewUtils.toast(getContext(), getString(R.string.error_message_files_no_file)); } - Crashlytics.logException(new Throwable("File " + oldFile.getPath() + " doesn't exist")); + FirebaseCrashlytics.getInstance() + .recordException(new Throwable("File " + oldFile.getPath() + " doesn't exist")); } return true; diff --git a/app/src/main/java/com/backyardbrains/ui/RecordingOptionsFragment.java b/app/src/main/java/com/backyardbrains/ui/RecordingOptionsFragment.java index 4c15373..f89a335 100644 --- a/app/src/main/java/com/backyardbrains/ui/RecordingOptionsFragment.java +++ b/app/src/main/java/com/backyardbrains/ui/RecordingOptionsFragment.java @@ -32,7 +32,7 @@ import com.backyardbrains.utils.BYBUtils; import com.backyardbrains.utils.RecordingUtils; import com.backyardbrains.utils.ViewUtils; -import com.crashlytics.android.Crashlytics; +import com.google.firebase.crashlytics.FirebaseCrashlytics; import java.io.File; import java.io.IOException; import java.util.ArrayList; @@ -253,9 +253,10 @@ private void delete() { if (!ef.delete()) { BYBUtils.showAlert(getActivity(), getString(R.string.title_error), getString(R.string.error_message_files_events_delete)); - Crashlytics.logException(new Throwable( - "Deleting events file for the given recording " + f.getPath() - + " failed")); + FirebaseCrashlytics.getInstance() + .recordException(new Throwable( + "Deleting events file for the given recording " + + f.getPath() + " failed")); } } // delete db analysis data for the deleted audio file @@ -267,16 +268,17 @@ private void delete() { ViewUtils.toast(getContext(), getString(R.string.error_message_files_delete)); } - Crashlytics.logException( - new Throwable("Deleting file " + f.getPath() + " failed")); + FirebaseCrashlytics.getInstance() + .recordException( + new Throwable("Deleting file " + f.getPath() + " failed")); } } else { if (getContext() != null) { ViewUtils.toast(getContext(), getString(R.string.error_message_files_no_file)); } - Crashlytics.logException( - new Throwable("File " + f.getPath() + " doesn't exist")); + FirebaseCrashlytics.getInstance() + .recordException(new Throwable("File " + f.getPath() + " doesn't exist")); } openRecordingsList(); @@ -350,36 +352,40 @@ private void convert() { ViewUtils.toast(getContext(), getString( R.string.error_message_files_convert_delete)); } - Crashlytics.logException(new Throwable( - "Deleting file " + f.getPath() - + " after conversion failed")); + FirebaseCrashlytics.getInstance() + .recordException(new Throwable( + "Deleting file " + f.getPath() + + " after conversion failed")); } openRecordingsList(); } else { handler.post(() -> showInfo(null)); handler.post(runnable); - Crashlytics.logException(new Throwable( - "Converting " + f.getPath() + " to WAV failed")); + FirebaseCrashlytics.getInstance() + .recordException(new Throwable( + "Converting " + f.getPath() + " to WAV failed")); } } catch (IOException e) { handler.post(() -> showInfo(null)); handler.post(runnable); - Crashlytics.logException( - new Throwable("Converting " + f.getPath() + " to WAV failed")); + FirebaseCrashlytics.getInstance() + .recordException(new Throwable( + "Converting " + f.getPath() + " to WAV failed")); } }).start(); // starts the thread by calling the run() method in its Runnable } else { - Crashlytics.logException( - new Throwable("Converting " + f.getPath() + " to WAV failed")); + FirebaseCrashlytics.getInstance() + .recordException( + new Throwable("Converting " + f.getPath() + " to WAV failed")); } } else { if (getContext() != null) { ViewUtils.toast(getContext(), getString(R.string.error_message_files_no_file)); } - Crashlytics.logException( - new Throwable("File " + f.getPath() + " doesn't exist")); + FirebaseCrashlytics.getInstance() + .recordException(new Throwable("File " + f.getPath() + " doesn't exist")); } }) .setNegativeButton(R.string.action_cancel, null) diff --git a/app/src/main/java/com/backyardbrains/utils/ImportUtils.java b/app/src/main/java/com/backyardbrains/utils/ImportUtils.java index 5ff8709..1583da5 100644 --- a/app/src/main/java/com/backyardbrains/utils/ImportUtils.java +++ b/app/src/main/java/com/backyardbrains/utils/ImportUtils.java @@ -9,7 +9,7 @@ import androidx.annotation.IntDef; import androidx.annotation.NonNull; import androidx.annotation.Nullable; -import com.crashlytics.android.Crashlytics; +import com.google.firebase.crashlytics.FirebaseCrashlytics; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; @@ -113,7 +113,7 @@ public static ImportResult importRecording(@NonNull Context context, String sche return ImportResult.createResult(file); } catch (IOException e) { - Crashlytics.logException(e); + FirebaseCrashlytics.getInstance().recordException(e); return ImportResult.createError(ImportResultCode.ERROR_SAVE); } diff --git a/app/src/main/java/com/backyardbrains/utils/SampleStreamUtils.java b/app/src/main/java/com/backyardbrains/utils/SampleStreamUtils.java index 7fe8cb0..dbbc705 100644 --- a/app/src/main/java/com/backyardbrains/utils/SampleStreamUtils.java +++ b/app/src/main/java/com/backyardbrains/utils/SampleStreamUtils.java @@ -43,6 +43,8 @@ public static String getSpikerBoxHardwareName(@SpikerBoxHardwareType int hardwar return "Neuron PRO SpikerBox"; case SpikerBoxHardwareType.PLANT: return "Plant SpikerBox"; + case SpikerBoxHardwareType.HUMAN_PRO: + return "Human PRO SpikerBox"; default: case SpikerBoxHardwareType.UNKNOWN: return "UNKNOWN"; diff --git a/app/src/main/java/com/backyardbrains/utils/SpikerBoxHardwareType.java b/app/src/main/java/com/backyardbrains/utils/SpikerBoxHardwareType.java index 34c60d8..351a6cf 100644 --- a/app/src/main/java/com/backyardbrains/utils/SpikerBoxHardwareType.java +++ b/app/src/main/java/com/backyardbrains/utils/SpikerBoxHardwareType.java @@ -9,8 +9,9 @@ */ @Retention(RetentionPolicy.SOURCE) @IntDef({ SpikerBoxHardwareType.NONE, SpikerBoxHardwareType.UNKNOWN, SpikerBoxHardwareType.PLANT, - SpikerBoxHardwareType.MUSCLE, SpikerBoxHardwareType.HEART_AND_BRAIN, SpikerBoxHardwareType.MUSCLE_PRO, - SpikerBoxHardwareType.NEURON_PRO + SpikerBoxHardwareType.MUSCLE, SpikerBoxHardwareType.HEART_AND_BRAIN, + SpikerBoxHardwareType.MUSCLE_PRO, SpikerBoxHardwareType.NEURON_PRO, + SpikerBoxHardwareType.HUMAN_PRO }) public @interface SpikerBoxHardwareType { /** @@ -47,4 +48,9 @@ * SpikerBox Neuron PRO hardware type. */ int NEURON_PRO = 4; + + /** + * SpikerBox Human PRO hardware type. + */ + int HUMAN_PRO = 5; } diff --git a/app/src/main/java/com/backyardbrains/view/FilterSettingsView.java b/app/src/main/java/com/backyardbrains/view/FilterSettingsView.java index 0d632ed..a067b51 100644 --- a/app/src/main/java/com/backyardbrains/view/FilterSettingsView.java +++ b/app/src/main/java/com/backyardbrains/view/FilterSettingsView.java @@ -38,8 +38,8 @@ public class FilterSettingsView extends ConstraintLayout { private static final String TAG = makeLogTag(FilterSettingsView.class); static final BandFilter[] FILTERS = new BandFilter[] { - Filters.FILTER_BAND_HEART, Filters.FILTER_BAND_BRAIN, Filters.FILTER_BAND_MUSCLE, Filters.FILTER_BAND_PLANT, - Filters.FILTER_BAND_NEURON_PRO + Filters.FILTER_BAND_HEART, Filters.FILTER_BAND_BRAIN, Filters.FILTER_BAND_MUSCLE, + Filters.FILTER_BAND_PLANT, Filters.FILTER_BAND_NEURON_PRO, Filters.FILTER_BAND_HUMAN_PRO }; private static final BandFilter NO_FILTER = new BandFilter(Filters.FREQ_NO_CUT_OFF, Filters.FREQ_NO_CUT_OFF); @@ -58,7 +58,7 @@ public class FilterSettingsView extends ConstraintLayout { @BindViews({ R.id.btn_filter_heart, R.id.btn_filter_brain, R.id.btn_filter_muscle, R.id.btn_filter_plant, - R.id.btn_filter_neuro + R.id.btn_filter_neuro, R.id.btn_filter_human }) List