diff --git a/app/build.gradle b/app/build.gradle index 2ac908a..2bed0ba 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -51,22 +51,21 @@ android { version '3.18.1+' } } - buildToolsVersion '30.0.3' ndkVersion '24.0.8215888' namespace 'com.jvdegithub.aiscatcher' } dependencies { - implementation 'androidx.appcompat:appcompat:1.5.0' - implementation 'com.google.android.material:material:1.6.1' - implementation 'androidx.constraintlayout:constraintlayout:2.1.4' - implementation 'androidx.lifecycle:lifecycle-livedata-ktx:2.5.1' - implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.5.1' + implementation 'androidx.appcompat:appcompat:1.7.0' + implementation 'com.google.android.material:material:1.12.0' + implementation 'androidx.constraintlayout:constraintlayout:2.2.0' + implementation 'androidx.lifecycle:lifecycle-livedata-ktx:2.8.7' + implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.8.7' implementation 'androidx.legacy:legacy-support-v4:1.0.0' - implementation 'androidx.preference:preference:1.2.0' - implementation 'androidx.webkit:webkit:1.4.0' + implementation 'androidx.preference:preference:1.2.1' + implementation 'androidx.webkit:webkit:1.12.1' testImplementation 'junit:junit:4.13.2' - androidTestImplementation 'androidx.test.ext:junit:1.1.3' - androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0' + androidTestImplementation 'androidx.test.ext:junit:1.2.1' + androidTestImplementation 'androidx.test.espresso:espresso-core:3.6.1' } diff --git a/app/src/main/assets/webassets b/app/src/main/assets/webassets index 3a17cbb..8ef6243 160000 --- a/app/src/main/assets/webassets +++ b/app/src/main/assets/webassets @@ -1 +1 @@ -Subproject commit 3a17cbb1c5eb3132300bd2f1d713c404455dbd1d +Subproject commit 8ef6243cb32f83b96e5ca3da9d1445a8648748a0 diff --git a/app/src/main/java/com/jvdegithub/aiscatcher/AisCatcherJava.java b/app/src/main/java/com/jvdegithub/aiscatcher/AisCatcherJava.java index 245848e..a86ea89 100644 --- a/app/src/main/java/com/jvdegithub/aiscatcher/AisCatcherJava.java +++ b/app/src/main/java/com/jvdegithub/aiscatcher/AisCatcherJava.java @@ -55,6 +55,8 @@ public interface AisCallback { static native int createUDP(String h, String p); + static native int createWebViewer(String p); + static native int createSharing(boolean b, String key); diff --git a/app/src/main/java/com/jvdegithub/aiscatcher/Settings.java b/app/src/main/java/com/jvdegithub/aiscatcher/Settings.java index d2f2ecf..9beafc2 100644 --- a/app/src/main/java/com/jvdegithub/aiscatcher/Settings.java +++ b/app/src/main/java/com/jvdegithub/aiscatcher/Settings.java @@ -60,6 +60,10 @@ static void setDefault(Context context) { preferences.edit().putString("sSHARINGKEY", "").commit(); preferences.edit().putBoolean("sSHARING", false).commit(); + preferences.edit().putBoolean("w1SWITCH", false).commit(); + preferences.edit().putInt("w1PORT", 8100).commit(); + + preferences.edit().putString("oCGF_WIDE", "Default").commit(); preferences.edit().putString("oMODEL_TYPE", "Default").commit(); preferences.edit().putBoolean("oFP_DS", false).commit(); @@ -123,6 +127,7 @@ public void onCreatePreferences(Bundle savedInstanceState, String rootKey) { ((EditTextPreference) getPreferenceManager().findPreference("sHOST")).setOnBindEditTextListener(validateIP); ((EditTextPreference) getPreferenceManager().findPreference("sPORT")).setOnBindEditTextListener(validatePort); + ((EditTextPreference) getPreferenceManager().findPreference("w1PORT")).setOnBindEditTextListener(validatePort);; ((SeekBarPreference) getPreferenceManager().findPreference("sGAIN")).setUpdatesContinuously(true); ((EditTextPreference) getPreferenceManager().findPreference("tPORT")).setOnBindEditTextListener(validatePort); ((EditTextPreference) getPreferenceManager().findPreference("rFREQOFFSET")).setOnBindEditTextListener(validatePPM); @@ -147,7 +152,7 @@ static public int getModelType(Context context) } private void setSummaries() { - setSummaryText(new String[]{"tPORT","tHOST","sPORT","sHOST","u1HOST","u1PORT","u2HOST","u2PORT", "u3HOST","u3PORT", "u4HOST","u4PORT", "rFREQOFFSET", "sSHARINGKEY"}); + setSummaryText(new String[]{"w1PORT","tPORT","tHOST","sPORT","sHOST","u1HOST","u1PORT","u2HOST","u2PORT", "u3HOST","u3PORT", "u4HOST","u4PORT", "rFREQOFFSET", "sSHARINGKEY"}); setSummaryList(new String[]{"rTUNER","rRATE","sRATE","tRATE","tPROTOCOL","tTUNER","mRATE","hRATE","oMODEL_TYPE","oCGF_WIDE"}); setSummarySeekbar(new String[]{"mLINEARITY", "sGAIN"}); } @@ -269,6 +274,8 @@ static public boolean Apply(Context context) { if (!SetUDPoutput("u3", context)) return false; if (!SetUDPoutput("u4", context)) return false; + if (!SetWebViewerOutput( context)) return false; + if(!SetSharing(context)) return false; return true; @@ -360,6 +367,19 @@ static private boolean SetUDPoutput(String s, Context context) { } return true; } + + static private boolean SetWebViewerOutput(Context context) { + SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(context); + + boolean b = preferences.getBoolean("w1SWITCH", false); + if (b) { + String port = preferences.getString("w1PORT", ""); + return AisCatcherJava.createWebViewer(port) == 0; + + } + return true; + } + static private boolean SetSharing(Context context) { String defaultKey = "a6392e08-c57e-4e7a-a4fb-d73bfc7619ae"; diff --git a/app/src/main/jni/AIS-catcher b/app/src/main/jni/AIS-catcher index 398bb7b..a536c06 160000 --- a/app/src/main/jni/AIS-catcher +++ b/app/src/main/jni/AIS-catcher @@ -1 +1 @@ -Subproject commit 398bb7b28676a39a5d2ea5c50c1ed56590fddd72 +Subproject commit a536c061d57efb9c0e1d31b530d39cc74422ee3f diff --git a/app/src/main/jni/CMakeLists.txt b/app/src/main/jni/CMakeLists.txt index 72cd235..1fe3bf3 100644 --- a/app/src/main/jni/CMakeLists.txt +++ b/app/src/main/jni/CMakeLists.txt @@ -7,8 +7,8 @@ cmake_minimum_required(VERSION 3.10.2) project("AIScatcherNDK") -set(OPTIMIZATION_FLAGS "-Ofast") -#set(OPTIMIZATION_FLAGS "-g") +#set(OPTIMIZATION_FLAGS "-Ofast") +set(OPTIMIZATION_FLAGS "-g") set(CMAKE_CXX_FLAGS "${OPTIMIZATION_FLAGS}") set(CMAKE_C_FLAGS "${OPTIMIZATION_FLAGS}") @@ -52,7 +52,7 @@ add_library( # Sets the name of the library. ./AIS-catcher/Device/ZMQ.cpp ./AIS-catcher/Device/SoapySDR.cpp ./AIS-catcher/Device/SpyServer.cpp ./AIS-catcher/Library/Message.cpp ./AIS-catcher/Library/NMEA.cpp ./AIS-catcher/Library/Utilities.cpp ./AIS-catcher/Library/TCP.cpp ./AIS-catcher/JSON/JSON.cpp ./AIS-catcher/IO/Network.cpp ./AIS-catcher/IO/HTTPServer.cpp ./AIS-catcher/JSON/StringBuilder.cpp ./AIS-catcher/JSON/Parser.cpp ./AIS-catcher/Device/AIRSPY.cpp ./AIS-catcher/Device/Serial.cpp - ./AIS-catcher/DSP/DSP.cpp ./AIS-catcher/IO/IO.cpp ./AIS-catcher/Application/WebViewer.cpp ./AIS-catcher/Application/Prometheus.cpp + ./AIS-catcher/DSP/DSP.cpp ./AIS-catcher/Application/WebViewer.cpp ./AIS-catcher/Application/Prometheus.cpp ./AIS-catcher/Protocol/Protocol.cpp ./AIS-catcher/Library/Logger.cpp JNI/AIScatcherNDK.cpp) @@ -61,7 +61,7 @@ include_directories( ./rtl-sdr/include ./airspyone_host/libairspy/src ./airspyhf/libairspyhf/src - ./AIS-catcher ./AIS-catcher/Application ./AIS-catcher/IO ./AIS-catcher/Library ./AIS-catcher/Ships ./AIS-catcher/DBMS ./AIS-catcher/DSP ./AIS-catcher/Device) + ./AIS-catcher ./AIS-catcher/Application ./AIS-catcher/IO ./AIS-catcher/Library ./AIS-catcher/Ships ./AIS-catcher/DBMS ./AIS-catcher/DSP ./AIS-catcher/Device ./AIS-catcher/Protocol) add_definitions(-DHASRTLSDR -DHASRTLSDR_BIASTEE -DHASRTL_ANDROID -DHASAIRSPY -DHASAIRSPY_ANDROID -D HASAIRSPYHF -DHASAIRSPYHF_ANDROID -DHASRTLSDR_TUNERBW) diff --git a/app/src/main/jni/JNI/AIScatcherNDK.cpp b/app/src/main/jni/JNI/AIScatcherNDK.cpp index ff932c9..a76f500 100644 --- a/app/src/main/jni/JNI/AIScatcherNDK.cpp +++ b/app/src/main/jni/JNI/AIScatcherNDK.cpp @@ -32,12 +32,12 @@ const int TIME_CONSTRAINT = 120; G_ERROR, LOG_TAG, __VA_ARGS__) #include "AIS-catcher.h" +#include "Application/version.h" #include "Receiver.h" #include "JSONAIS.h" #include "Signals.h" #include "Common.h" #include "Model.h" -#include "IO.h" #include "Network.h" #include "WebViewer.h" @@ -65,6 +65,8 @@ struct Statistics { } statistics; WebViewer server; +static std::unique_ptr webviewer = nullptr; +int webviewer_port = -1; std::string nmea_msg; std::string json_queue; @@ -88,6 +90,20 @@ void DetachThread() // JAVA interaction and callbacks +std::string toString(JNIEnv* env, jstring jStr) { + + if (!jStr) { + return std::string(); + } + + const char* chars = env->GetStringUTFChars(jStr, nullptr); + if (!chars) return std::string(); + + std::string result(chars); + env->ReleaseStringUTFChars(jStr, chars); + return result; +} + void pushStatistics(JNIEnv *env) { const int GB = 1000000000; @@ -224,10 +240,8 @@ struct Drivers { Device::SpyServer SPYSERVER; Device::AIRSPY AIRSPY; Device::AIRSPYHF AIRSPYHF; - //Device::SerialPort Serial; } drivers; -//Device::Type type = Device::Type::NONE; std::vector UDP_connections; std::vector TCP_connections; std::vector UDPhost; @@ -239,7 +253,7 @@ NMEAcounter NMEAcounter; RAWcounter rawcounter; Device::Device *device = nullptr; -AIS::Model *model = nullptr; +static std::unique_ptr model = nullptr; AIS::JSONAIS json2ais; bool stop = false; @@ -283,10 +297,9 @@ JNIEXPORT jint JNICALL Java_com_jvdegithub_aiscatcher_AisCatcherJava_applySetting(JNIEnv *env, jclass, jstring dev, jstring setting, jstring param) { try { - jboolean isCopy; - std::string d = (env)->GetStringUTFChars(dev, &isCopy); - std::string s = (env)->GetStringUTFChars(setting, &isCopy); - std::string p = (env)->GetStringUTFChars(param, &isCopy); + std::string d = toString(env,dev); + std::string s = toString(env, setting); + std::string p = toString(env, param); switch (d[0]) { case 't': @@ -333,6 +346,7 @@ Java_com_jvdegithub_aiscatcher_AisCatcherJava_Run(JNIEnv *env, jclass) { try { callbackConsole(env, "Creating UDP output channels\n"); UDP_connections.resize(UDPhost.size()); + for (int i = 0; i < UDPhost.size(); i++) { UDP_connections[i].Set("host",UDPhost[i]).Set("port",UDPport[i]); UDP_connections[i].Start(); @@ -348,6 +362,12 @@ Java_com_jvdegithub_aiscatcher_AisCatcherJava_Run(JNIEnv *env, jclass) { TCP_connections[0].Start(); model->Output() >> TCP_connections[0]; } + + if(webviewer) { + callbackConsole(env, "Starting Web Viewer\n"); + webviewer->start(); + } + callbackConsole(env, "Starting device\n"); device->setTag(tag); @@ -389,6 +409,13 @@ Java_com_jvdegithub_aiscatcher_AisCatcherJava_Run(JNIEnv *env, jclass) { UDPport.clear(); UDPhost.clear(); + + if(webviewer) { + webviewer->close(); + webviewer.reset(); + } + webviewer_port = -1; + } catch (std::exception& e) { callbackError(env, e.what()); } @@ -408,11 +435,7 @@ Java_com_jvdegithub_aiscatcher_AisCatcherJava_Close(JNIEnv *env, jclass) { try { if (device) device->Close(); device = nullptr; - - if(model) { - delete model; - model = nullptr; - } + model.reset(); } catch (std::exception& e) { callbackError(env, e.what()); @@ -480,22 +503,19 @@ Java_com_jvdegithub_aiscatcher_AisCatcherJava_createReceiver(JNIEnv *env, jclass callbackConsoleFormat(env, "Building model with sampling rate: %dK\n", device->getSampleRate() / 1000); - if(model != nullptr) { - delete model; - model = nullptr; - } + model.reset(); if(device && device->getFormat() == Format::TXT) { callbackConsole(env, "Model: NMEA\n"); - model = new AIS::ModelNMEA(); + model = std::make_unique(); model->buildModel('A','B',device->getSampleRate(), false, device); } else { if(model_type == 0) { callbackConsole(env, "Model: default\n"); - model = new AIS::ModelDefault(); + model = std::make_unique(); std::string s = (CGF_wide == 0)?"OFF":"ON"; model->Set("AFC_WIDE",s); @@ -503,7 +523,7 @@ Java_com_jvdegithub_aiscatcher_AisCatcherJava_createReceiver(JNIEnv *env, jclass } else { callbackConsole(env, "Model: base (FM)\n"); - model = new AIS::ModelBase(); + model = std::make_unique(); } std::string s = (FPDS == 0)?"OFF":"ON"; @@ -525,6 +545,27 @@ Java_com_jvdegithub_aiscatcher_AisCatcherJava_createReceiver(JNIEnv *env, jclass model->Output() >> json2ais; server.connect(*model, json2ais.out, *device); + callbackConsole(env, "Creating additional Web Viewer\n"); + + if(webviewer) webviewer.reset(); + + if(webviewer_port != -1) { + webviewer = std::make_unique(); + + if(!webviewer) + throw std::runtime_error("Cannot create Web Viewer)"); + + webviewer->Set("PORT", std::to_string(webviewer_port)); + webviewer->Set("STATION", "Android"); + webviewer->Set("SHARE_LOC","ON"); + webviewer->Set("REALTIME","ON"); + //webviewer->Set("LAT","42"); + //webviewer->Set("LON","4"); + } + + if(webviewer && webviewer_port != -1) + webviewer->connect(*model, json2ais.out, *device); + return 0; } @@ -537,8 +578,8 @@ Java_com_jvdegithub_aiscatcher_AisCatcherJava_createUDP(JNIEnv *env, jclass claz UDPhost.resize(UDPhost.size() + 1); jboolean b; - std::string host = (env)->GetStringUTFChars(h, &b); - std::string port = (env)->GetStringUTFChars(p, &b); + std::string host = toString(env,h); //(env)->GetStringUTFChars(h, &b); + std::string port = toString(env, p); //(env)->GetStringUTFChars(p, &b); UDPport[UDPport.size() - 1] = port; UDPhost[UDPhost.size() - 1] = host; @@ -553,13 +594,31 @@ Java_com_jvdegithub_aiscatcher_AisCatcherJava_createUDP(JNIEnv *env, jclass claz return 0; } +extern "C" +JNIEXPORT jint JNICALL +Java_com_jvdegithub_aiscatcher_AisCatcherJava_createWebViewer(JNIEnv *env, jclass clazz, + jstring p) { + try { + jboolean b; + std::string port = toString(env,p); //(env)->GetStringUTFChars(p, &b); + webviewer_port = std::stoi(port); + + callbackConsoleFormat(env, "WebViewer active on Port: %s\n", port.c_str()); + + } catch (std::exception& e) { + callbackError(env, e.what()); + device = nullptr; + return -1; + } + return 0;} + extern "C" JNIEXPORT jint JNICALL Java_com_jvdegithub_aiscatcher_AisCatcherJava_createSharing(JNIEnv *env, jclass clazz, jboolean b, jstring k) { if(b) { jboolean isCopy; - std::string key = (env)->GetStringUTFChars(k, &isCopy); + std::string key = toString(env,k); //(env)->GetStringUTFChars(k, &isCopy); sharing = communityFeed = true; sharingKey = key; @@ -607,6 +666,11 @@ Java_com_jvdegithub_aiscatcher_AisCatcherJava_setLatLon(JNIEnv *env, jclass claz jfloat lon) { server.Set("LAT",std::to_string(lat)); server.Set("LON",std::to_string(lon)); + + if(webviewer) { + webviewer->Set("LAT",std::to_string(lat)); + webviewer->Set("LON",std::to_string(lon)); + } } extern "C" @@ -621,28 +685,12 @@ JNIEXPORT void JNICALL Java_com_jvdegithub_aiscatcher_AisCatcherJava_setDeviceDescription(JNIEnv *env, jclass clazz, jstring p, jstring v, jstring s) { - const char* pChar = env->GetStringUTFChars(p, NULL); - std::string pStr; - if (pChar != NULL) { - pStr = pChar; - env->ReleaseStringUTFChars(p, pChar); - } - const char* vChar = env->GetStringUTFChars(v, NULL); - std::string vStr; - if (vChar != NULL) { - vStr = vChar; - env->ReleaseStringUTFChars(v, vChar); - } + std::string product = toString(env,p); + std::string vendor = toString(env,v); + std::string serial = toString(env, s); - const char* sChar = env->GetStringUTFChars(s, NULL); - std::string sStr; - if (sChar != NULL) { - sStr = sChar; - env->ReleaseStringUTFChars(s, sChar); - } - - server.setDeviceDescription(pStr, vStr, sStr); + server.setDeviceDescription(product.c_str(), vendor.c_str(), serial.c_str()); } extern "C" @@ -650,3 +698,4 @@ JNIEXPORT jstring JNICALL Java_com_jvdegithub_aiscatcher_AisCatcherJava_getRateDescription(JNIEnv *env, jclass clazz) { return env->NewStringUTF(device->getRateDescription().c_str()); } + diff --git a/app/src/main/res/xml/preferences.xml b/app/src/main/res/xml/preferences.xml index 97a180a..50fdd86 100644 --- a/app/src/main/res/xml/preferences.xml +++ b/app/src/main/res/xml/preferences.xml @@ -27,6 +27,25 @@ + + + + + + + + diff --git a/build.gradle b/build.gradle index 8c91de5..70517a6 100644 --- a/build.gradle +++ b/build.gradle @@ -1,7 +1,7 @@ // Top-level build file where you can add configuration options common to all sub-projects/modules. plugins { - id 'com.android.application' version '8.0.2' apply false - id 'com.android.library' version '8.0.2' apply false + id 'com.android.application' version '8.7.3' apply false + id 'com.android.library' version '8.7.3' apply false } task clean(type: Delete) { diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 78b55a2..cc7b993 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ #Thu May 12 15:35:41 CEST 2022 distributionBase=GRADLE_USER_HOME -distributionUrl=https\://services.gradle.org/distributions/gradle-8.0-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.9-bin.zip distributionPath=wrapper/dists zipStorePath=wrapper/dists zipStoreBase=GRADLE_USER_HOME