Skip to content

Commit

Permalink
Merge remote-tracking branch 'wellenvogel/master' into 347-missing-va…
Browse files Browse the repository at this point in the history
…lues

# Conflicts:
#	viewer/components/SKWidgets.jsx
  • Loading branch information
quantenschaum committed Dec 29, 2024
2 parents c064667 + 5ae38f6 commit ceff90d
Show file tree
Hide file tree
Showing 101 changed files with 5,237 additions and 3,667 deletions.
9 changes: 8 additions & 1 deletion android/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,14 @@ dependencies {
implementation "net.sf.marineapi:marineapi:0.11.0"
implementation 'androidx.core:core:1.10.1'
implementation 'androidx.appcompat:appcompat:1.6.1'
implementation 'com.github.felHR85:UsbSerial:6.1.0'
//see https://github.com/felHR85/UsbSerial/issues/375
implementation('com.github.felHR85:UsbSerial:7ad6c9f6'){
artifact {
name = 'UsbSerial'
classifier = 'release'
type = 'aar'
}
}
implementation group: 'net.straylightlabs', name: 'hola', version: '0.2.2'
implementation group: 'org.apache.httpcomponents', name: 'httpcore', version: '4.0'
implementation 'androidx.documentfile:documentfile:1.0.1'
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
package de.wellenvogel.avnav.appapi;

import android.content.Context;
import android.net.Uri;
import android.os.Build;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.nio.file.Files;
import java.nio.file.StandardCopyOption;
import java.util.ArrayList;
import java.util.Date;
import java.util.Enumeration;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;

import androidx.annotation.NonNull;
import de.wellenvogel.avnav.main.BuildConfig;
import de.wellenvogel.avnav.util.AvnLog;
import de.wellenvogel.avnav.util.AvnUtil;
import de.wellenvogel.avnav.worker.GpsService;
import de.wellenvogel.avnav.worker.Worker;

public class IconRequestHandler extends Worker implements INavRequestHandler{
protected String urlPrefix;
protected String type;
protected Context context;
JSONArray iconFiles;
static final String ICONBASE="viewer/images";
public IconRequestHandler(String type, GpsService ctx,String urlPrefrix) throws IOException {
super(type,ctx);
this.type=type;
this.urlPrefix=urlPrefrix;
this.context=ctx;
iconFiles=new JSONArray();
try {
for (String name : ctx.getAssets().list(ICONBASE)) {
JSONObject item = new JSONObject();
item.put("name", name);
item.put("url", "/"+urlPrefrix+"/"+name);
item.put("canDelete",false);
item.put("mtime", BuildConfig.TIMESTAMP/1000);
iconFiles.put(item);
}
}catch(Throwable t){
AvnLog.e("unable to read system icons");
}

}

private boolean isValidName(String name) throws JSONException {
for (int i=0;i<iconFiles.length();i++){
JSONObject item=iconFiles.getJSONObject(i);
if (item.getString("name").equals(name)){
return true;
}
}
return false;
}

@Override
public ExtendedWebResourceResponse handleDownload(String name, Uri uri) throws Exception {
if (isValidName(name)){
return new ExtendedWebResourceResponse(-1,"application/octet-stream", "",context.getAssets().open(ICONBASE+"/"+name));
}
throw new IOException("file not found "+name);
}

@Override
public boolean handleUpload(PostVars postData, String name, boolean ignoreExisting) throws Exception {
throw new IOException("upload not allowed");
}

protected String getUrlFromName(String name) throws UnsupportedEncodingException {
return "/"+urlPrefix+"/"+
URLEncoder.encode(name,"utf-8");
}
@Override
public JSONArray handleList(Uri uri, RequestHandler.ServerInfo serverInfo) throws Exception {
return iconFiles;
}

@Override
public boolean handleDelete(String name, Uri uri) throws Exception {
throw new IOException("delete not allowed");
}

@Override
public JSONObject handleApiRequest(Uri uri, PostVars postData, RequestHandler.ServerInfo serverInfo) throws Exception {
String command=AvnUtil.getMandatoryParameter(uri,"command");
if (command.equals("list")){
return RequestHandler.getReturn(new AvnUtil.KeyValue("items",handleList(uri, serverInfo)));
}
return handleSpecialApiRequest(command,uri,postData,serverInfo);
}

@Override
public ExtendedWebResourceResponse handleDirectRequest(Uri uri, RequestHandler handler, String method) throws Exception {
String path=uri.getPath();
if (path == null) return null;
if (path.startsWith("/")) path=path.substring(1);
if (!path.startsWith(urlPrefix)) return null;
path = path.substring((urlPrefix.length()+1));
if (! isValidName(path)) return null;
return new ExtendedWebResourceResponse(-1,RequestHandler.mimeType(path), "",context.getAssets().open(ICONBASE+"/"+path));
}

protected JSONObject handleSpecialApiRequest(String command,Uri uri,PostVars postData,RequestHandler.ServerInfo serverInfo) throws Exception {
return RequestHandler.getErrorReturn("unknonw api request "+command);
}


@Override
protected void run(int startSequence) throws JSONException, IOException {
}


@Override
public String getPrefix() {
return urlPrefix;
}


}
Original file line number Diff line number Diff line change
Expand Up @@ -447,4 +447,16 @@ public boolean isChannelOpen(int id){
return socket.isOpen();
}

@JavascriptInterface
public boolean dataDownload(String dataUrl, String fileName, String mimeType){
try {
mainActivity.startDataDownload(dataUrl,fileName,mimeType);
} catch (Exception e) {
AvnLog.e("dataDownload error ",e);
return false;
}
return true;

}

}
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ public class RequestHandler {
public static String TYPE_USER="user";
public static String TYPE_IMAGE="images";
public static String TYPE_OVERLAY="overlay";
public static String TYPE_ICONS="icons";
public static String TYPE_ADDON="addon";
public static String TYPE_CONFIG="config";
public static String TYPE_REMOTE="remotechannels";
Expand Down Expand Up @@ -259,6 +260,18 @@ public INavRequestHandler getHandler() {
}catch(Exception e){
AvnLog.e("unable to create images handler",e);
}
try {
final IconRequestHandler iconHandler=new IconRequestHandler(TYPE_ICONS,service,
"viewer/icons");
handlerMap.put(TYPE_ICONS, new LazyHandlerAccess() {
@Override
public INavRequestHandler getHandler() {
return iconHandler;
}
});
}catch(Exception e){
AvnLog.e("unable to create images handler",e);
}
handlerMap.put(TYPE_ADDON, new LazyHandlerAccess() {
@Override
public INavRequestHandler getHandler() {
Expand Down
37 changes: 27 additions & 10 deletions android/src/main/java/de/wellenvogel/avnav/main/MainActivity.java
Original file line number Diff line number Diff line change
Expand Up @@ -414,13 +414,39 @@ protected void onDestroy() {
gpsService=null;
}

private boolean startNextDownload(DownloadHandler.Download nextDownload,String mimeType){
if (download != null && download.isRunning()) return false;
nextDownload.progress=MainActivity.this.dlProgress;
nextDownload.dlText=MainActivity.this.dlText;
download=nextDownload;
Intent intent = new Intent(Intent.ACTION_CREATE_DOCUMENT);
intent.addCategory(Intent.CATEGORY_OPENABLE);
intent.setType(mimeType);
if (nextDownload.fileName != null) {
intent.putExtra(Intent.EXTRA_TITLE, nextDownload.fileName);
}
startActivityForResult(intent,Constants.FILE_OPEN_DOWNLOAD);
return true;
}

public void startDataDownload(String dataUrl,String fileName, String mimeType) throws Exception {
Uri uri=Uri.parse(dataUrl);
if (!"data".equals(uri.getScheme())){
throw new Exception("only data urls allowed for DataDownload");
}
DownloadHandler.DataDownload nextDownload=new DownloadHandler.DataDownload(dataUrl,this);
nextDownload.fileName=fileName;
startNextDownload(nextDownload,mimeType);
}

private void initializeWebView(){
if (webView != null) return;
sharedPrefs.edit().putBoolean(Constants.WAITSTART,true).commit();
jsInterface=new JavaScriptApi(this,getRequestHandler());
webView=(WebView)findViewById(R.id.webmain);
webView.getSettings().setJavaScriptEnabled(true);
webView.getSettings().setAllowFileAccess(true);
webView.getSettings().setAllowFileAccess(true);
if (Build.VERSION.SDK_INT >= 16){
try {
WebSettings settings = webView.getSettings();
Expand Down Expand Up @@ -563,16 +589,7 @@ public void onDownloadStart(String url, String userAgent, String contentDisposit
else {
nextDownload=DownloadHandler.createHandler(MainActivity.this,url,userAgent,contentDisposition,mimeType,l);
}
nextDownload.progress=MainActivity.this.dlProgress;
nextDownload.dlText=MainActivity.this.dlText;
download=nextDownload;
Intent intent = new Intent(Intent.ACTION_CREATE_DOCUMENT);
intent.addCategory(Intent.CATEGORY_OPENABLE);
intent.setType(mimeType);
if (nextDownload.fileName != null) {
intent.putExtra(Intent.EXTRA_TITLE, nextDownload.fileName);
}
startActivityForResult(intent,Constants.FILE_OPEN_DOWNLOAD);
startNextDownload(nextDownload,mimeType);
}catch (Throwable t){
Toast.makeText(MainActivity.this,"download error:"+t,Toast.LENGTH_LONG).show();
}
Expand Down
4 changes: 2 additions & 2 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -316,7 +316,7 @@ task release{
println "all release packages have been build"
}
dependsOn testGit, releaseRpm, releaseDeb,raspiDeb
dependsOn windowsBuild
dependsOn windowsBuild, buildZip
if (buildAndroid){
dependsOn assembleReleaseAndroid
}
Expand All @@ -328,7 +328,7 @@ task beta{
println "all beta packages have been build"
}
dependsOn releaseRpm, releaseDeb,raspiDeb
dependsOn windowsBuild
dependsOn windowsBuild, buildZip
if (buildAndroid){
dependsOn assembleBetaAndroid
}
Expand Down
2 changes: 1 addition & 1 deletion docs/en_install.html
Original file line number Diff line number Diff line change
Expand Up @@ -306,7 +306,7 @@ <h4><a name="connect-wifi"></a>Connection via the internal Wifi</h4>
<p>There is one restriction: Unfortunately xxx.local will not work on
Android devices. I recommend installing a tool that is able to resolve
mDNS-&nbsp;<a href="https://play.google.com/store/apps/details?id=de.wellenvogel.bonjourbrowser">
BonjourBrowser </a>. For IOS there is a <a href="https://play.google.com/store/apps/details?id=de.wellenvogel.bonjourbrowser">similar
BonjourBrowser </a>. For IOS there is a <a href="https://apps.apple.com/us/app/bonjour-search-for-http-web-in-wi-fi/id1097517829">similar
tool</a> - although xxx.local should work there in the browser. You will
find your Pi with the AvNav image with the name "avnav-server". Normally
there will be a second entry "avnav" - this is <a href="hints/CanboatAndSignalk.html">SignalK</a>.<br>
Expand Down
5 changes: 3 additions & 2 deletions docs/install.html
Original file line number Diff line number Diff line change
Expand Up @@ -324,7 +324,7 @@ <h4><a name="connect-wifi"></a>Verbindung über das eingebaute WLAN</h4>
<p>Eine Einschränkung bleibt: Leider funktioniert xxx.local nicht auf
Android-Geräten. Daher empfehle ich, dort ein Tool zu nutzen, das mDNS
nutzen kann - einen <a href="https://play.google.com/store/apps/details?id=de.wellenvogel.bonjourbrowser">
BonjourBrowser </a>. Für IOS gibt es ein&nbsp; <a href="https://play.google.com/store/apps/details?id=de.wellenvogel.bonjourbrowser">vergleichbares
BonjourBrowser </a>. Für IOS gibt es ein&nbsp; <a href="https://apps.apple.com/us/app/bonjour-search-for-http-web-in-wi-fi/id1097517829">vergleichbares
Tool</a> - auch wenn dort der Eintrag "xxx.local" im Browser
funktioniert. Man wird seinen Raspberry mit dem AvNav-Image in den
Browsern unter dem Namen "avnav-server" finden. Typischerweise wird man
Expand Down Expand Up @@ -588,7 +588,8 @@ <h3>Download</h3>
<p>Avnav als Systemdienst starten. Wenn man diese Datei nicht
anlegt/kopiert, wird AvNav nicht mit den Nutzer "pi", sondern mit dem
Nutzer "avnav" arbeiten.</p>
<a name="openplotter"></a><h2>OpenPlotter </h2>
<a name="openplotter"></a>
<h2>OpenPlotter </h2>
<p>Für <a href="https://openmarine.net/openplotter">OpenPlotter</a> gibt es
eine komplette Integration von AvNav (Dank an <a href="https://github.com/e-sailing">e-sailing</a>).
Im Repository <a href="https://www.free-x.de/deb4op/">https://www.free-x.de/deb4op/</a>
Expand Down
2 changes: 1 addition & 1 deletion server/avnav_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,7 @@ def addNMEA(self, nmea, addCheckSum=False,omitDecode=True,source=None):
"""
raise NotImplemented()

def addData(self, key, value, source=None,record=None):
def addData(self, key, value, source=None,record=None, sourcePriority=60):
"""
add a data item (potentially from a decoded NMEA record) to the internal data store
the data added here later on will be fetched from the GUI
Expand Down
3 changes: 2 additions & 1 deletion server/avnav_nmea.py
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ class NMEAParser(object):
K_DEPTHT=Key('depthBelowTransducer','depthBelowTransducer in m','m','environment.depth.belowTransducer')
K_DEPTHW=Key('depthBelowWaterline','depthBelowWaterlinein m','m','environment.depth.belowSurface')
K_DEPTHK=Key('depthBelowKeel','depthBelowKeel in m','m','environment.depth.belowKeel')
K_TIME=Key('time','the received GPS time',signalK='navigation.datetime')
#we will add the GPS base to all entries
GPS_DATA=[
K_LAT,
Expand All @@ -98,7 +99,7 @@ class NMEAParser(object):
K_DEPTHT,
K_DEPTHW,
K_DEPTHK,
Key('time','the received GPS time',signalK='navigation.datetime'),
K_TIME,
Key('satInview', 'number of Sats in view',signalK='navigation.gnss.satellitesInView.count'),
Key('satUsed', 'number of Sats in use',signalK='navigation.gnss.satellites'),
Key('transducers.*','transducer data from xdr'),
Expand Down
41 changes: 24 additions & 17 deletions server/avnav_store.py
Original file line number Diff line number Diff line change
Expand Up @@ -405,14 +405,29 @@ def isKeyRegistered(self,key,source=None):
@param source: if not None: only return True if registered by different source
@return:
'''
rt=self.__allowedKey(key)
if not rt:
return False
if source is None:
return rt
return self.__keySources[key] != source
try:
self.__checkAlreadyExists(key)
except:
#we come here if it already exists
if source is None:
return True
existingSource = self.__keySources.get(key)
return existingSource != source
return False

def registerKey(self,key,keyDescription,source=None):
def __checkAlreadyExists(self,key):
for existing in list(self.__registeredKeys.keys()):
if existing == key or key.startswith(existing):
raise Exception("key %s already registered from %s:%s" % (key,existing,self.__registeredKeys[existing]))
for existing in list(self.__wildcardKeys.keys()):
if self.wildCardMatch(key, existing):
raise Exception("key %s matches wildcard from %s:%s" % (key, existing, self.__wildcardKeys[existing]))
if self.__isWildCard(key):
for existing in list(self.__registeredKeys.keys()):
if self.wildCardMatch(existing, key):
raise Exception("wildcard key %s matches existing from %s:%s" % (key, existing, self.__registeredKeys[existing]))

def registerKey(self,key,keyDescription,source=None,allowOverwrite=False):
"""
register a new key description
raise an exception if there is already a key with the same name or a prefix of it
Expand All @@ -424,16 +439,8 @@ def registerKey(self,key,keyDescription,source=None):
if source is not None and self.__keySources.get(key) == source:
AVNLog.ld("key re-registration - ignore - for %s, source %s",key,source)
return
for existing in list(self.__registeredKeys.keys()):
if existing == key or key.startswith(existing):
raise Exception("key %s already registered from %s:%s" % (key,existing,self.__registeredKeys[existing]))
for existing in list(self.__wildcardKeys.keys()):
if self.wildCardMatch(key, existing):
raise Exception("key %s matches wildcard from %s:%s" % (key, existing, self.__wildcardKeys[existing]))
if self.__isWildCard(key):
for existing in list(self.__registeredKeys.keys()):
if self.wildCardMatch(existing, key):
raise Exception("wildcard key %s matches existing from %s:%s" % (key, existing, self.__registeredKeys[existing]))
if not allowOverwrite:
self.__checkAlreadyExists(key)
self.__keySources[key]=source
if self.__isWildCard(key):
self.__wildcardKeys[key]=keyDescription
Expand Down
Loading

0 comments on commit ceff90d

Please sign in to comment.