From e024953ebec2d9a581b00113f95d5b6f43fd0803 Mon Sep 17 00:00:00 2001 From: simon Date: Wed, 19 Aug 2020 17:00:08 +0300 Subject: [PATCH] simple web server added --- OsmAnd/AndroidManifest.xml | 1 + OsmAnd/assets/server/main.html | 238 +++++++ OsmAnd/res/layout/server_activity.xml | 51 ++ OsmAnd/res/values/strings.xml | 1 + OsmAnd/src/androidhttpweb/ServerActivity.java | 59 ++ OsmAnd/src/androidhttpweb/TinyWebServer.java | 614 ++++++++++++++++++ OsmAnd/src/appapis/queryfiles/AppApis.java | 134 ++++ .../plus/activities/MapActivityActions.java | 15 + 8 files changed, 1113 insertions(+) create mode 100644 OsmAnd/assets/server/main.html create mode 100644 OsmAnd/res/layout/server_activity.xml create mode 100644 OsmAnd/src/androidhttpweb/ServerActivity.java create mode 100644 OsmAnd/src/androidhttpweb/TinyWebServer.java create mode 100644 OsmAnd/src/appapis/queryfiles/AppApis.java diff --git a/OsmAnd/AndroidManifest.xml b/OsmAnd/AndroidManifest.xml index e1508f6ba2..764a3402d4 100644 --- a/OsmAnd/AndroidManifest.xml +++ b/OsmAnd/AndroidManifest.xml @@ -408,6 +408,7 @@ + diff --git a/OsmAnd/assets/server/main.html b/OsmAnd/assets/server/main.html new file mode 100644 index 0000000000..db48cfbe30 --- /dev/null +++ b/OsmAnd/assets/server/main.html @@ -0,0 +1,238 @@ + + + + + + + + + BootsApp | Home + + + + + + + + + +
+
+
+

Company Inc.

+

Lorem ipsum, dolor sit amet consectetur adipisicing elit. Ut unde quaerat consequatur?

+ Get Started +
+
+
+ +
+

Our Speciality

+
+
+ +

Device Compatible

+

Lorem ipsum dolor sit amet consectetur adipisicing elit. Illo, doloremque voluptatum. Ducimus.

+
+
+ +

Cloud Support

+

Lorem ipsum dolor sit amet consectetur adipisicing elit. Illo, doloremque voluptatum. Ducimus.

+
+
+ +

24/7 Call Support

+

Lorem ipsum dolor sit amet consectetur adipisicing elit. Illo, doloremque voluptatum. Ducimus.

+
+
+
+ +
+

Our Products

+ +
+
+ product-image +
+
+

Lorem ipsum dolor sit, amet consectetur adipisicing elit. Velit nobis officiis unde necessitatibus esse alias expedita quia doloremque assumenda. Cupiditate nam exercitationem voluptatem quidem ad dolore ullam aliquid culpa ducimus qui, ut dignissimos inventore veniam!

+
+
+
+
+

Lorem ipsum dolor sit, amet consectetur adipisicing elit. Velit nobis officiis unde necessitatibus esse alias expedita quia doloremque assumenda. Cupiditate nam exercitationem voluptatem !

+
+
+ product-image +
+
+
+
+ product-image +
+
+

Lorem ipsum dolor sit, amet consectetur adipisicing elit. Velit nobis officiis unde necessitatibus esse alias expedita quia doloremque assumenda. Cupiditate nam exercitationem voluptatem quidem ad dolore ullam aliquid culpa ducimus qui, ut dignissimos inventore veniam!

+
+
+ + +
+ +
+

Our Customers

+ +
+ +
+
+

Ready to get started

+ Try it for free
+
+
+ + + + + +
+
+
+ +
+
+ +
+
+ Follow us on + +
+ +
+ +
+   with   By Developers
+ 2018 © Developers.com
+ The images are taken from Unsplash.com to avoid copyright issues. +
+
+ + + + \ No newline at end of file diff --git a/OsmAnd/res/layout/server_activity.xml b/OsmAnd/res/layout/server_activity.xml new file mode 100644 index 0000000000..51aa730efc --- /dev/null +++ b/OsmAnd/res/layout/server_activity.xml @@ -0,0 +1,51 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/OsmAnd/res/values/strings.xml b/OsmAnd/res/values/strings.xml index 90990a2b78..bfe1b9cc85 100644 --- a/OsmAnd/res/values/strings.xml +++ b/OsmAnd/res/values/strings.xml @@ -11,6 +11,7 @@ Thx - Hardy --> + Web server In case of reverse direction Are you sure you want to close Plan route without saving? You will lose all changes. Street-level imagery diff --git a/OsmAnd/src/androidhttpweb/ServerActivity.java b/OsmAnd/src/androidhttpweb/ServerActivity.java new file mode 100644 index 0000000000..ee8a13223e --- /dev/null +++ b/OsmAnd/src/androidhttpweb/ServerActivity.java @@ -0,0 +1,59 @@ +package androidhttpweb; + +import android.net.TrafficStats; +import android.os.Bundle; +import android.view.View; +import android.widget.TextView; + +import androidx.annotation.Nullable; +import androidx.appcompat.app.AppCompatActivity; + +import net.osmand.plus.R; + +public class ServerActivity extends AppCompatActivity { + private boolean initialized = false; + + @Override + protected void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.server_activity); + findViewById(R.id.Button01).setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + if (!initialized) { + ((TextView) findViewById(R.id.TextView02)).setText("Click second button to deactivate server"); + initServer(); + } + } + }); + findViewById(R.id.Button03).setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + if (initialized) { + ((TextView) findViewById(R.id.TextView02)).setText("Click first button to activate server"); + deInitServer(); + } + } + }); + } + + private void initServer() { + final String ip = "localhost"; + final int port = 9000; + final int THREAD_ID = 10000; + TrafficStats.setThreadStatsTag(THREAD_ID); + TinyWebServer.startServer(ip, port, "/web/public_html"); + TinyWebServer.object = ServerActivity.this; + } + + private void deInitServer() { + TinyWebServer.stopServer(); + initialized = false; + } + + @Override + protected void onDestroy() { + deInitServer(); + super.onDestroy(); + } +} diff --git a/OsmAnd/src/androidhttpweb/TinyWebServer.java b/OsmAnd/src/androidhttpweb/TinyWebServer.java new file mode 100644 index 0000000000..b71de2630f --- /dev/null +++ b/OsmAnd/src/androidhttpweb/TinyWebServer.java @@ -0,0 +1,614 @@ +/* + * The MIT License + * + * Copyright 2018 Sonu Auti http://sonuauti.com twitter @SonuAuti + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package androidhttpweb; + +import android.net.TrafficStats; + +import java.io.BufferedWriter; +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.OutputStreamWriter; +import java.io.PrintWriter; +import java.lang.reflect.Method; +import java.net.InetAddress; +import java.net.ServerSocket; +import java.net.Socket; +import java.net.SocketTimeoutException; +import java.net.URL; +import java.net.URLDecoder; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.HashMap; +import java.util.Hashtable; +import java.util.Locale; +import java.util.Map; +import java.util.TimeZone; +import java.util.regex.Pattern; + +/** + * + * @author Sonu Auti @cis + */ +public class TinyWebServer extends Thread { + + /** + * @param args the command line arguments + */ + private static ServerSocket serverSocket; + private final Map lowerCaseHeader = new HashMap<>(); + + public static String CONTENT_TYPE = "text/html"; + private String CONTENT_DATE = ""; + private String CONN_TYPE = ""; + private String Content_Encoding = ""; + private String content_length = ""; + private String STATUS = "200"; + private boolean keepAlive = true; + private String SERVER_NAME = "Firefly http server v0.1"; + private static final String MULTIPART_FORM_DATA_HEADER = "multipart/form-data"; + private static final String ASCII_ENCODING = "US-ASCII"; + private String REQUEST_TYPE = "GET"; + private String HTTP_VER = "HTTP/1.1"; + + //all status + public static String PAGE_NOT_FOUND = "404"; + public static String OKAY = "200"; + public static String CREATED = "201"; + public static String ACCEPTED = "202"; + public static String NO_CONTENT = "204"; + public static String PARTIAL_NO_CONTENT = "206"; + public static String MULTI_STATUS = "207"; + public static String MOVED_PERMANENTLY = "301"; + public static String SEE_OTHER = "303"; + public static String NOT_MODIFIED = "304"; + public static String TEMP_REDIRECT = "307"; + public static String BAD_REQUEST = "400"; + public static String UNAUTHORIZED_REQUEST = "401"; + public static String FORBIDDEN = "403"; + public static String NOT_FOUND = "404"; + public static String METHOD_NOT_ALLOWED = "405"; + public static String NOT_ACCEPTABLE = "406"; + public static String REQUEST_TIMEOUT = "408"; + public static String CONFLICT = "409"; + public static String GONE = "410"; + public static String LENGTH_REQUIRED = "411"; + public static String PRECONDITION_FAILED = "412"; + + public static String PAYLOAD_TOO_LARGE = "413"; + public static String UNSUPPORTED_MEDIA_TYPE = "415"; + public static String RANGE_NOT_SATISFIABLE = "416"; + public static String EXPECTATION_FAILED = "417"; + public static String TOO_MANY_REQUESTS = "429"; + + public static String INTERNAL_ERROR = "500"; + public static String NOT_IMPLEMENTED = "501"; + public static String SERVICE_UNAVAILABLE = "503"; + public static String UNSUPPORTED_HTTP_VERSION = "505"; + + public static final String CONTENT_DISPOSITION_REGEX = "([ |\t]*Content-Disposition[ |\t]*:)(.*)"; + + public static final Pattern CONTENT_DISPOSITION_PATTERN = Pattern.compile(CONTENT_DISPOSITION_REGEX, Pattern.CASE_INSENSITIVE); + + public static final String CONTENT_TYPE_REGEX = "([ |\t]*content-type[ |\t]*:)(.*)"; + + public static final Pattern CONTENT_TYPE_PATTERN = Pattern.compile(CONTENT_TYPE_REGEX, Pattern.CASE_INSENSITIVE); + + public static final String CONTENT_DISPOSITION_ATTRIBUTE_REGEX = "[ |\t]*([a-zA-Z]*)[ |\t]*=[ |\t]*['|\"]([^\"^']*)['|\"]"; + + public static final Pattern CONTENT_DISPOSITION_ATTRIBUTE_PATTERN = Pattern.compile(CONTENT_DISPOSITION_ATTRIBUTE_REGEX); + + public static final String CONTENT_LENGTH_REGEX = "Content-Length:"; + public static final Pattern CONTENT_LENGTH_PATTERN = Pattern.compile(CONTENT_LENGTH_REGEX, Pattern.CASE_INSENSITIVE); + + public static final String USER_AGENT = "User-Agent:"; + public static final Pattern USER_AGENT_PATTERN = Pattern.compile(USER_AGENT, Pattern.CASE_INSENSITIVE); + + public static final String HOST_REGEX = "Host:"; + public static final Pattern CLIENT_HOST_PATTERN = Pattern.compile(HOST_REGEX, Pattern.CASE_INSENSITIVE); + + public static final String CONNECTION_TYPE_REGEX = "Connection:"; + public static final Pattern CONNECTION_TYPE_PATTERN = Pattern.compile(CONNECTION_TYPE_REGEX, Pattern.CASE_INSENSITIVE); + + public static final String ACCEPT_ENCODING_REGEX = "Accept-Encoding:"; + public static final Pattern ACCEPT_ENCODING_PATTERN = Pattern.compile(ACCEPT_ENCODING_REGEX, Pattern.CASE_INSENSITIVE); + + private static final String CONTENT_REGEX = "[ |\t]*([^/^ ^;^,]+/[^ ^;^,]+)"; + + private static final Pattern MIME_PATTERN = Pattern.compile(CONTENT_REGEX, Pattern.CASE_INSENSITIVE); + + private static final String CHARSET_REGEX = "[ |\t]*(charset)[ |\t]*=[ |\t]*['|\"]?([^\"^'^;^,]*)['|\"]?"; + + private static final Pattern CHARSET_PATTERN = Pattern.compile(CHARSET_REGEX, Pattern.CASE_INSENSITIVE); + + private static final String BOUNDARY_REGEX = "[ |\t]*(boundary)[ |\t]*=[ |\t]*['|\"]?([^\"^'^;^,]*)['|\"]?"; + + private static final Pattern BOUNDARY_PATTERN = Pattern.compile(BOUNDARY_REGEX, Pattern.CASE_INSENSITIVE); + + + public static String WEB_DIR_PATH="/"; + public static String SERVER_IP="localhost"; + public static int SERVER_PORT=9000; + public static boolean isStart=true; + public static String INDEX_FILE_NAME="index.html"; + public static Object object; + + public TinyWebServer(final String ip, final int port) throws IOException { + + InetAddress addr = InetAddress.getByName(ip); ////"172.31.0.186"); + serverSocket = new ServerSocket(port, 100, addr); + serverSocket.setSoTimeout(5000); //set timeout for listner + + } + + @Override + public void run() { + + while (isStart) { + try { + TrafficStats.setThreadStatsTag(1); + Socket newSocket = serverSocket.accept(); + Thread newClient = new EchoThread(newSocket); + newClient.start(); + } catch (SocketTimeoutException s) { + } catch (IOException e) { + } + + }//endof Never Ending while loop + + } + + public class EchoThread extends Thread { + + protected Socket socket; + protected boolean nb_open; + + public EchoThread(Socket clientSocket) { + this.socket = clientSocket; + this.nb_open = true; + } + + @Override + public void run() { + + try { + DataInputStream in = null; + DataOutputStream out = null; + + if (socket.isConnected()) { + in = new DataInputStream(socket.getInputStream()); + out = new DataOutputStream(socket.getOutputStream()); + } + + byte[] data = new byte[1500]; + //socket.setSoTimeout(60 * 1000 * 5); + + while (in.read(data) != -1) { + String recData = new String(data).trim(); + //System.out.println("received data: \n" + recData); + //System.out.println("------------------------------"); + String[] header = recData.split("\\r?\\n"); + + String contentLen = "0"; + String contentType = "text/html"; + String connectionType = "keep-alive"; + String hostname = ""; + String userAgent = ""; + String encoding = ""; + + String[] h1 = header[0].split(" "); + if (h1.length == 3) { + setRequestType(h1[0]); + setHttpVer(h1[2]); + } + + for (int h = 0; h < header.length; h++) { + String value = header[h].trim(); + + //System.out.println(header[h]+" -> "+CONTENT_LENGTH_PATTERN.matcher(header[h]).find()); + if (CONTENT_LENGTH_PATTERN.matcher(value).find()) { + contentLen = value.split(":")[1].trim(); + } else if (CONTENT_TYPE_PATTERN.matcher(value).find()) { + contentType = value.split(":")[1].trim(); + } else if (CONNECTION_TYPE_PATTERN.matcher(value).find()) { + connectionType = value.split(":")[1].trim(); + } else if (CLIENT_HOST_PATTERN.matcher(value).find()) { + hostname = value.split(":")[1].trim(); + } else if (USER_AGENT_PATTERN.matcher(value).find()) { + for (String ua : value.split(":")) { + if (!ua.equalsIgnoreCase("User-Agent:")) { + userAgent += ua.trim(); + } + } + } else if (ACCEPT_ENCODING_PATTERN.matcher(value).find()) { + encoding = value.split(":")[1].trim(); + } + + } + + if (!REQUEST_TYPE.equals("")) { + String postData = ""; + if (REQUEST_TYPE.equalsIgnoreCase("POST") && !contentLen.equals("0")) { + postData = header[header.length - 1]; + if (postData.length() > 0 && contentLen.length() > 0) { + int len = Integer.valueOf(contentLen); + postData = postData.substring(0, len); + // System.out.println("Post data -> " + contentLen + " ->" + postData); + } + } + + // System.out.println("contentLen ->" + contentLen + "\ncontentType ->" + contentType + "\nhostname ->" + hostname + "\nconnectionType-> " + connectionType + "\nhostname ->" + hostname + "\nuserAgent -> " + userAgent); + final String requestLocation = h1[1]; + if (requestLocation != null) { + processLocation(out, requestLocation, postData); + } + //System.out.println("requestLocation "+requestLocation); + } + + } + } catch (Exception er) { + er.printStackTrace(); + } + + } + + } + + public void processLocation(DataOutputStream out, String location, String postData) { + + String data = ""; + switch (location) { + case "/": + //root location, server index file + CONTENT_TYPE = "text/html"; + data=readFile(WEB_DIR_PATH+"/"+INDEX_FILE_NAME); + constructHeader(out, data.length() + "", data); + break; + default: + + System.out.println("url location -> " + location); + URL geturl = getDecodedUrl("http://localhost" + location); + String[] dirPath = geturl.getPath().split("/"); + String fullFilePath=geturl.getPath(); + if (dirPath.length > 1) { + String fileName = dirPath[dirPath.length - 1]; + HashMap qparms = (HashMap) splitQuery(geturl.getQuery()); + if(REQUEST_TYPE.equals("POST")){ + if (qparms==null){ qparms=new HashMap();} + qparms.put("_POST", postData); + } + //System.out.println("File name " + fileName); + //System.out.println("url parms " + qparms); + CONTENT_TYPE = getContentType(fileName); + if(!CONTENT_TYPE.equals("text/plain")){ + // System.out.println("Full file path - >"+fullFilePath +" "+CONTENT_TYPE); + + if(CONTENT_TYPE.equals("image/jpeg") || CONTENT_TYPE.equals("image/png") || CONTENT_TYPE.equals("video/mp4")){ + byte[] bytdata=readImageFiles(WEB_DIR_PATH+fullFilePath,CONTENT_TYPE); + //System.out.println(bytdata.length); + if(bytdata!=null){ + constructHeaderImage(out, bytdata.length+"", bytdata); + }else{ + pageNotFound(); + } + }else{ + data=readFile(WEB_DIR_PATH+fullFilePath); + if(!data.equals("")){ + constructHeader(out, data.length() + "", data); + }else{ + pageNotFound(); + } + } + }else{ + data = getResultByName(fileName, qparms); + constructHeader(out, data.length() + "", data); + } + + + } + + } + + } + + public URL getDecodedUrl(String parms) { + try { + //String decodedurl =URLDecoder.decode(parms,"UTF-8"); + URL aURL = new URL(parms); + return aURL; + } catch (Exception er) { + } + return null; + } + + public static HashMap splitQuery(String parms) { + try { + final HashMap query_pairs = new HashMap<>(); + final String[] pairs = parms.split("&"); + for (String pair : pairs) { + final int idx = pair.indexOf("="); + final String key = idx > 0 ? URLDecoder.decode(pair.substring(0, idx), "UTF-8") : pair; + if (!query_pairs.containsKey(key)) { + query_pairs.put(key, ""); + } + final String value = idx > 0 && pair.length() > idx + 1 ? URLDecoder.decode(pair.substring(idx + 1), "UTF-8") : null; + query_pairs.put(key, value); + } + return query_pairs; + } catch (Exception er) { + } + return null; + } + + public String getResultByName(String name, HashMap qparms) { + try { + String ClassName = "appapis.queryfiles.AppApis"; + Class rClass = Class.forName(ClassName); // convert string classname to class + Object obj = rClass.newInstance(); // invoke empty constructor + Method getNameMethod = obj.getClass().getMethod(name, HashMap.class); + STATUS = TinyWebServer.OKAY; + return getNameMethod.invoke(obj, qparms).toString(); + } catch (Exception er) { + // er.printStackTrace(); + return pageNotFound(); + } + } + + public void setRequestType(String type) { + // System.out.println("REQUEST TYPE " + type); + this.REQUEST_TYPE = type; + } + + public void setHttpVer(String httpver) { + // System.out.println("REQUEST ver " + httpver); + this.HTTP_VER = httpver; + } + + public String getRequestType() { + return this.REQUEST_TYPE; + } + + public String getHttpVer() { + return this.HTTP_VER; + } + + public String pageNotFound() { + STATUS = NOT_FOUND; + CONTENT_TYPE = "text/html"; + //customize your page here + return "" + + "Page not found | Firefly web server" + + "

Requested page not found

"; + } + + //hashtable initilization for content types + static Hashtable mContentTypes = new Hashtable(); + + { + mContentTypes.put("js", "application/javascript"); + mContentTypes.put("php", "text/html"); + mContentTypes.put("java", "text/html"); + mContentTypes.put("json", "application/json"); + mContentTypes.put("png", "image/png"); + mContentTypes.put("jpg", "image/jpeg"); + mContentTypes.put("html", "text/html"); + mContentTypes.put("css", "text/css"); + mContentTypes.put("mp4", "video/mp4"); + mContentTypes.put("mov", "video/quicktime"); + mContentTypes.put("wmv", "video/x-ms-wmv"); + + } + + //get request content type + public static String getContentType(String path) { + String type = tryGetContentType(path); + if (type != null) { + return type; + } + return "text/plain"; + } + + //get request content type from path + public static String tryGetContentType(String path) { + int index = path.lastIndexOf("."); + if (index != -1) { + String e = path.substring(index + 1); + String ct = mContentTypes.get(e); + // System.out.println("content type: " + ct); + if (ct != null) { + return ct; + } + } + return null; + } + + private void constructHeader(DataOutputStream output, String size, String data) { + SimpleDateFormat gmtFrmt = new SimpleDateFormat("E, d MMM yyyy HH:mm:ss 'GMT'", Locale.US); + gmtFrmt.setTimeZone(TimeZone.getTimeZone("GMT")); + PrintWriter pw = new PrintWriter(new BufferedWriter(new OutputStreamWriter(output)), false); + pw.append("HTTP/1.1 ").append(STATUS).append(" \r\n"); + if (this.CONTENT_TYPE != null) { + printHeader(pw, "Content-Type", this.CONTENT_TYPE); + } + printHeader(pw, "Date", gmtFrmt.format(new Date())); + printHeader(pw, "Connection", (this.keepAlive ? "keep-alive" : "close")); + printHeader(pw, "Content-Length", size); + printHeader(pw, "Server", SERVER_NAME); + pw.append("\r\n"); + pw.append(data); + pw.flush(); + //pw.close(); + } + + private void constructHeaderImage(DataOutputStream output, String size, byte[] data) { + try{ + + SimpleDateFormat gmtFrmt = new SimpleDateFormat("E, d MMM yyyy HH:mm:ss 'GMT'", Locale.US); + gmtFrmt.setTimeZone(TimeZone.getTimeZone("GMT")); + PrintWriter pw = new PrintWriter(new BufferedWriter(new OutputStreamWriter(output)), false); + pw.append("HTTP/1.1 ").append(STATUS).append(" \r\n"); + if (this.CONTENT_TYPE != null) { + printHeader(pw, "Content-Type", this.CONTENT_TYPE); + } + printHeader(pw, "Date", gmtFrmt.format(new Date())); + printHeader(pw, "Connection", (this.keepAlive ? "keep-alive" : "close")); + printHeader(pw, "Content-Length", size); + printHeader(pw, "Server", SERVER_NAME); + pw.append("\r\n"); + pw.flush(); + output.write(data); + output.flush(); + //System.out.println("data sent success"); + + //pw.close(); + }catch(Exception er){er.printStackTrace();} + + } + + + @SuppressWarnings("static-method") + protected void printHeader(PrintWriter pw, String key, String value) { + pw.append(key).append(": ").append(value).append("\r\n"); + } + + public byte[] readImageFiles(String fileName, String filetype){ + try{ + File ifile=new File(fileName); + if(ifile.exists()){ + if(filetype.equalsIgnoreCase("image/png") || filetype.equalsIgnoreCase("image/jpeg") || filetype.equalsIgnoreCase("image/gif") || filetype.equalsIgnoreCase("image/jpg")){ + FileInputStream fis = new FileInputStream(fileName); + byte[] buffer = new byte[fis.available()]; + while (fis.read(buffer) != -1) {} + fis.close(); + return buffer; + } + }else{ + + } + }catch(Exception er){} + return null; + } + public String readFile(String fileName){ + String content=""; + try{ + File ifile=new File(fileName); + if(ifile.exists()){ + FileInputStream fis = new FileInputStream(fileName); + byte[] buffer = new byte[10]; + StringBuilder sb = new StringBuilder(); + while (fis.read(buffer) != -1) { + sb.append(new String(buffer)); + buffer = new byte[10]; + } + fis.close(); + content = sb.toString(); + }else{ + pageNotFound(); + return content; + } + }catch(Exception er){ + pageNotFound(); + return ""; + } + return content; + } + + + public static void init(String ip, int port, String public_dir){ + + SERVER_IP=ip; + SERVER_PORT=port; + WEB_DIR_PATH=public_dir; + scanFileDirectory(); + + } + + public static void startServer(String ip, int port, String public_dir){ + try { + + isStart=true; + init(ip,port,public_dir); + Thread t = new TinyWebServer(SERVER_IP, SERVER_PORT); + t.start(); + System.out.println("Server Started !"); + + } catch (IOException e) { + e.printStackTrace(); + } catch (Exception e) { + } + } + + public static void stopServer(){ + if(isStart){ + try{ + isStart=false; + serverSocket.close(); + System.out.println("Server stopped running !"); + }catch(IOException er){ + er.printStackTrace(); + } + } + } + + + //scan for index file + public static void scanFileDirectory(){ + boolean isIndexFound=false; + try{ + File file=new File(WEB_DIR_PATH); + if(file.isDirectory()){ + File[] allFiles=file.listFiles(); + for (File allFile : allFiles) { + //System.out.println(allFile.getName().split("\\.")[0]); + if(allFile.getName().split("\\.")[0].equalsIgnoreCase("index")){ + TinyWebServer.INDEX_FILE_NAME=allFile.getName(); + isIndexFound=true; + } + } + } + + }catch(Exception er){} + + if(!isIndexFound){ + System.out.println("Index file not found !"); + } + } + + /* //use for testing + public static void main(String[] args) { + try { + + Thread t = new TinyWebServer(SERVER_IP, SERVER_PORT); + t.start(); + System.out.println("Server Started !"); + + } catch (IOException e) { + e.printStackTrace(); + } catch (Exception e) { + } + }*/ + +} diff --git a/OsmAnd/src/appapis/queryfiles/AppApis.java b/OsmAnd/src/appapis/queryfiles/AppApis.java new file mode 100644 index 0000000000..30143abfc2 --- /dev/null +++ b/OsmAnd/src/appapis/queryfiles/AppApis.java @@ -0,0 +1,134 @@ +/* + * The MIT License + * + * Copyright 2018 Sonu Auti http://sonuauti.com twitter @SonuAuti + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package appapis.queryfiles; + + +import android.widget.Toast; + +import org.apache.commons.compress.utils.IOUtils; + +import androidhttpweb.ServerActivity; +import androidhttpweb.TinyWebServer; + +import java.io.IOException; +import java.io.InputStream; +import java.util.HashMap; +import java.util.Scanner; + + +/** + * + * @author cis + */ +public class AppApis { + + public AppApis(){ + } + + public String helloworld(HashMap qparms){ + //demo of simple html webpage from controller method + TinyWebServer.CONTENT_TYPE="text/html"; + return "Simple HTML and Javascript Demo\n" + + " \n" + + " \n" + + " \n" + + "

Say Hello !

\n" + + "
\n" + + "
\n" + + "
\n" + + "
\n" + + "
\n" + + "
\n" + + " "; + } + + public String simplejson(HashMap qparms){ + //simple json output demo from controller method + String json = "{\"name\":\"sonu\",\"age\":29}"; + return json.toString(); + } + + public String simplegetparm(HashMap qparms){ + /* + qparms is hashmap of get and post parameter + + simply use qparms.get(key) to get parameter value + user _POST as key for post data + e.g to get post data use qparms.get("_POST"), return will be post method + data + */ + + System.out.println("output in simplehelloworld "+qparms); + String p=""; + if(qparms!=null){ + p=qparms.get("age")+""; + } + String json = "{\"name\":\"sonu\",\"age\":"+p+",\"isp\":yes}"; + return json.toString(); + } + + public String main(HashMap qparams){ + TinyWebServer.CONTENT_TYPE="text/html"; + final ServerActivity act = ((ServerActivity)(TinyWebServer.object)); + InputStream stream = null; + try { + stream = act.getAssets().open("server/main.html"); + } catch (IOException e) { + e.printStackTrace(); + } + Scanner s = new Scanner(stream).useDelimiter("\\A"); + String result = s.hasNext() ? s.next() : ""; + return result; + } + + public String button1Click(HashMap qparams){ + try { + final ServerActivity act = ((ServerActivity)(TinyWebServer.object)); + act.runOnUiThread(new Runnable() { + @Override + public void run() { + Toast.makeText(act,"Hello from btn1",Toast.LENGTH_LONG).show(); + } + }); + } + catch (Exception e){ + e.printStackTrace(); + } + TinyWebServer.CONTENT_TYPE="text/html"; + return ""; + } + + + public String button2Click(HashMap qparams){ + return "cancel"; + } + //implement web callback here and access them using method name +} diff --git a/OsmAnd/src/net/osmand/plus/activities/MapActivityActions.java b/OsmAnd/src/net/osmand/plus/activities/MapActivityActions.java index 57c499407f..d5d6470556 100644 --- a/OsmAnd/src/net/osmand/plus/activities/MapActivityActions.java +++ b/OsmAnd/src/net/osmand/plus/activities/MapActivityActions.java @@ -36,6 +36,7 @@ import net.osmand.data.QuadRect; import net.osmand.data.RotatedTileBox; import net.osmand.map.ITileSource; import net.osmand.plus.dialogs.SpeedCamerasBottomSheet; +import androidhttpweb.ServerActivity; import net.osmand.plus.settings.backend.ApplicationMode; import net.osmand.plus.ContextMenuAdapter; import net.osmand.plus.ContextMenuAdapter.ItemClickListener; @@ -1011,6 +1012,20 @@ public class MapActivityActions implements DialogProvider { }).createItem()); */ + optionsMenuHelper.addItem(new ItemBuilder().setTitleId(R.string.web_server, mapActivity) + .setId("SERVER_ID") + .setIcon(R.drawable.mm_shop_computer) + .setListener(new ItemClickListener() { + @Override + public boolean onContextMenuClick(ArrayAdapter adapter, int itemId, int pos, boolean isChecked, int[] viewCoordinates) { + app.logEvent("drawer_help_open"); + Intent intent = new Intent(mapActivity, ServerActivity.class); + intent.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT); + mapActivity.startActivity(intent); + return true; + } + }).createItem()); + optionsMenuHelper.addItem(new ItemBuilder().setTitleId(R.string.shared_string_help, mapActivity) .setId(DRAWER_HELP_ID) .setIcon(R.drawable.ic_action_help)