From 08a36c6d25c862a312fe6f7386e1bb95fc3b1fbe Mon Sep 17 00:00:00 2001 From: Mikhail Basov Date: Fri, 17 Nov 2017 21:33:50 +0300 Subject: [PATCH 001/267] Rewrite notification code to compile SDK 23+ --- src/com/bolutions/webserver/ServerService.java | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/src/com/bolutions/webserver/ServerService.java b/src/com/bolutions/webserver/ServerService.java index 160dd7a..67ac2e6 100644 --- a/src/com/bolutions/webserver/ServerService.java +++ b/src/com/bolutions/webserver/ServerService.java @@ -112,15 +112,13 @@ public void updateNotifiction(String message) { CharSequence text = message; PendingIntent contentIntent = PendingIntent.getActivity(this, 0, new Intent(this, StartActivity.class), 0); - if (notification == null) { - notification = new Notification(R.drawable.ic_launcher, text, System.currentTimeMillis()); - notification.setLatestEventInfo(this, getString(R.string.app_name), text, contentIntent); - - mNM.notify(NOTIFICATION_ID, notification); - } else { - notification.setLatestEventInfo(this, getString(R.string.app_name), text, contentIntent); - mNM.notify(NOTIFICATION_ID, notification); - } + Notification.Builder builder = new Notification.Builder(this) + .setSmallIcon(R.drawable.ic_launcher) + .setContentTitle(getString(R.string.app_name)) + .setContentText(text) + .setContentIntent(contentIntent); + notification = builder.build(); + mNM.notify(NOTIFICATION_ID, notification); } @Override From fc260d602a10f708c6fbb4591a6627f2f4ded458 Mon Sep 17 00:00:00 2001 From: Mikhail Basov Date: Fri, 17 Nov 2017 22:30:12 +0300 Subject: [PATCH 002/267] Migrate to modern Android Studio (3.0) Progect converted to build using gradle. Min SDK is 17 now. --- .classpath | 9 - .gitignore | 38 +- .project | 33 - .settings/org.eclipse.jdt.core.prefs | 5 - app/build.gradle | 23 + .../src/main/AndroidManifest.xml | 0 .../java}/com/bolutions/webserver/Server.java | 0 .../bolutions/webserver/ServerHandler.java | 446 ++++----- .../bolutions/webserver/ServerService.java | 285 +++--- .../bolutions/webserver/StartActivity.java | 0 .../android/tasker/TaskerIntent.java | 898 +++++++++--------- .../main/res}/drawable-hdpi/ic_launcher.png | Bin .../main/res}/drawable-mdpi/ic_launcher.png | Bin .../main/res}/drawable-xhdpi/ic_launcher.png | Bin .../main/res}/drawable-xxhdpi/ic_launcher.png | Bin {res => app/src/main/res}/layout/main.xml | 0 {res => app/src/main/res}/values/strings.xml | 0 build.gradle | 15 + default.properties | 22 - import-summary.txt | 38 + project.properties | 15 - settings.gradle | 1 + 22 files changed, 921 insertions(+), 907 deletions(-) delete mode 100644 .classpath delete mode 100644 .project delete mode 100644 .settings/org.eclipse.jdt.core.prefs create mode 100644 app/build.gradle rename AndroidManifest.xml => app/src/main/AndroidManifest.xml (100%) rename {src => app/src/main/java}/com/bolutions/webserver/Server.java (100%) rename {src => app/src/main/java}/com/bolutions/webserver/ServerHandler.java (96%) rename {src => app/src/main/java}/com/bolutions/webserver/ServerService.java (90%) rename {src => app/src/main/java}/com/bolutions/webserver/StartActivity.java (100%) rename {src => app/src/main/java}/net/dinglisch/android/tasker/TaskerIntent.java (96%) rename {res => app/src/main/res}/drawable-hdpi/ic_launcher.png (100%) rename {res => app/src/main/res}/drawable-mdpi/ic_launcher.png (100%) rename {res => app/src/main/res}/drawable-xhdpi/ic_launcher.png (100%) rename {res => app/src/main/res}/drawable-xxhdpi/ic_launcher.png (100%) rename {res => app/src/main/res}/layout/main.xml (100%) rename {res => app/src/main/res}/values/strings.xml (100%) create mode 100644 build.gradle delete mode 100644 default.properties create mode 100644 import-summary.txt delete mode 100644 project.properties create mode 100644 settings.gradle diff --git a/.classpath b/.classpath deleted file mode 100644 index dec02b3..0000000 --- a/.classpath +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - - diff --git a/.gitignore b/.gitignore index 64d3c97..29bd24a 100644 --- a/.gitignore +++ b/.gitignore @@ -1,23 +1,39 @@ # Built application files +build/ + +# Crashlytics configuations +/*/com_crashlytics_export_strings.xml + +# Local configuration file (sdk path, etc) +local.properties +/*/local.properties + +# Gradle generated files +.gradle/ +gradle/ +gradlew +gradlew.bat + +# Signing files +/*/.signing/ + +.idea/ + +*.iml + +# built application files *.apk *.ap_ -# Files for the Dalvik VM +# files for the dex VM *.dex # Java class files *.class -# Generated files -bin/ -gen/ +# built native files +*.o +*.so -# Gradle files -.gradle/ -build/ -# Local configuration file (sdk path, etc) -local.properties -# Proguard folder generated by Eclipse -proguard/ diff --git a/.project b/.project deleted file mode 100644 index dd5d4a1..0000000 --- a/.project +++ /dev/null @@ -1,33 +0,0 @@ - - - andwebserver - - - - - - com.android.ide.eclipse.adt.ResourceManagerBuilder - - - - - com.android.ide.eclipse.adt.PreCompilerBuilder - - - - - org.eclipse.jdt.core.javabuilder - - - - - com.android.ide.eclipse.adt.ApkBuilder - - - - - - com.android.ide.eclipse.adt.AndroidNature - org.eclipse.jdt.core.javanature - - diff --git a/.settings/org.eclipse.jdt.core.prefs b/.settings/org.eclipse.jdt.core.prefs deleted file mode 100644 index 885a520..0000000 --- a/.settings/org.eclipse.jdt.core.prefs +++ /dev/null @@ -1,5 +0,0 @@ -#Sun Jul 19 12:56:49 CEST 2009 -eclipse.preferences.version=1 -org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.5 -org.eclipse.jdt.core.compiler.compliance=1.5 -org.eclipse.jdt.core.compiler.source=1.5 diff --git a/app/build.gradle b/app/build.gradle new file mode 100644 index 0000000..f126fc6 --- /dev/null +++ b/app/build.gradle @@ -0,0 +1,23 @@ +apply plugin: 'com.android.application' + +android { + compileSdkVersion 25 + buildToolsVersion "26.0.2" + + defaultConfig { + applicationId "com.bolutions.webserver" + minSdkVersion 17 + targetSdkVersion 21 + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_7 + targetCompatibility JavaVersion.VERSION_1_7 + } + } + + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt' + } + } +} diff --git a/AndroidManifest.xml b/app/src/main/AndroidManifest.xml similarity index 100% rename from AndroidManifest.xml rename to app/src/main/AndroidManifest.xml diff --git a/src/com/bolutions/webserver/Server.java b/app/src/main/java/com/bolutions/webserver/Server.java similarity index 100% rename from src/com/bolutions/webserver/Server.java rename to app/src/main/java/com/bolutions/webserver/Server.java diff --git a/src/com/bolutions/webserver/ServerHandler.java b/app/src/main/java/com/bolutions/webserver/ServerHandler.java similarity index 96% rename from src/com/bolutions/webserver/ServerHandler.java rename to app/src/main/java/com/bolutions/webserver/ServerHandler.java index fcd5838..279f657 100644 --- a/src/com/bolutions/webserver/ServerHandler.java +++ b/app/src/main/java/com/bolutions/webserver/ServerHandler.java @@ -1,223 +1,223 @@ -/* - * Copyright (C) 2009-2014 Markus Bode - * - * Licensed under the GNU General Public License v3 - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - */ -package com.bolutions.webserver; -import java.io.*; -import java.net.*; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -import net.dinglisch.android.tasker.TaskerIntent; -import android.content.Context; -import android.database.Cursor; -import android.net.Uri; -import android.util.Log; - -class ServerHandler extends Thread { - private BufferedReader in; - private PrintWriter out; - private Socket toClient; - private String documentRoot; - private Context context; - - public ServerHandler(String d, Context c, Socket s) { - toClient = s; - documentRoot = d; - context = c; - } - - public void run() { - String dokument = ""; - - try { - in = new BufferedReader(new InputStreamReader(toClient.getInputStream())); - - // Receive data - while (true) { - String s = in.readLine().trim(); - - if (s.equals("")) { - break; - } - - if (s.substring(0, 3).equals("GET")) { - int leerstelle = s.indexOf(" HTTP/"); - dokument = s.substring(5,leerstelle); - dokument = dokument.replaceAll("[/]+","/"); - } - } - } catch (Exception e) { - Server.remove(toClient); - try { - toClient.close(); - } - catch (Exception ex){} - } - - Pattern taskerPattern = Pattern.compile("tasker/(.+)"); - Matcher taskerMatcher = taskerPattern.matcher(dokument); - - if(taskerMatcher.matches()) { - try { - dokument = java.net.URLDecoder.decode(taskerMatcher.group(1), "UTF-8"); - sendTasker(dokument); - } catch (UnsupportedEncodingException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - showHtml("403.html"); - } - } else if(dokument.equals("tasker/")) { - listTaskerTasks(); - } else { - showHtml(dokument); - } - } - - private void sendTasker(String taskName) { - if(TaskerIntent.testStatus(context).equals(TaskerIntent.Status.OK)) { - TaskerIntent i = new TaskerIntent(taskName); - context.sendBroadcast(i); - - send("Sent intent \"" + taskName + "\" to tasker."); - } else { - send("Could not sent intent \"" + taskName + "\" to tasker (" + - TaskerIntent.testStatus(context) + ")."); - } - } - - private void listTaskerTasks() { - Cursor c = context.getContentResolver().query(Uri.parse("content://net.dinglisch.android.tasker/tasks"), null, null, null, null); - - String text = "Found tasks:
    "; - if(c != null) { - Log.d("Webserver", "Cursor is not null"); - int nameCol = c.getColumnIndex("name"); - int projNameCol = c.getColumnIndex("project_name"); - - while(c.moveToNext()) { - text = text + "
  • " + c.getString(projNameCol) + ": " + c.getString(nameCol) + "
  • "; - } - c.close(); - } else { - Log.d("Webserver", "Cursor is null"); - } - text = text + "
"; - send(text); - } - - private void send(String text) { - String header = getHeaderBase(); - header = header.replace("%code%", "200 ok"); - header = header.replace("%length%", "" + text.length()); - try { - out = new PrintWriter(toClient.getOutputStream(), true); - out.print(header); - out.print(text); - out.flush(); - Server.remove(toClient); - toClient.close(); - } catch (Exception e) { - - } - } - - private void showHtml(String dokument) { - // Standard-Doc - if (dokument.equals("")) { - dokument = "index.html"; - } - - // Don't allow directory traversal - if (dokument.indexOf("..") != -1) { - dokument = "403.html"; - } - - // Search for files in docroot - dokument = documentRoot + dokument; - Log.d("Webserver", "Got " + dokument); - dokument = dokument.replaceAll("[/]+","/"); - - if(dokument.charAt(dokument.length()-1) == '/') { - dokument = documentRoot + "404.html"; - } - - String header = getHeaderBase(); - header = header.replace("%code%", "403 Forbidden"); - - try { - File f = new File(dokument); - if (!f.exists()) { - header = getHeaderBase(); - header = header.replace("%code%", "404 File not found"); - dokument = "404.html"; - } - } - catch (Exception e) {} - - if (!dokument.equals(documentRoot + "403.html")) { - header = getHeaderBase().replace("%code%", "200 OK"); - } - - Log.d("Webserver", "Serving " + dokument); - - try { - File f = new File(dokument); - if (f.exists()) { - BufferedInputStream in = new BufferedInputStream(new FileInputStream(dokument)); - BufferedOutputStream out = new BufferedOutputStream(toClient.getOutputStream()); - ByteArrayOutputStream tempOut = new ByteArrayOutputStream(); - - byte[] buf = new byte[4096]; - int count = 0; - while ((count = in.read(buf)) != -1){ - tempOut.write(buf, 0, count); - } - - tempOut.flush(); - header = header.replace("%length%", ""+tempOut.size()); - - out.write(header.getBytes()); - out.write(tempOut.toByteArray()); - out.flush(); - } else { - // Send HTML-File (Ascii, not as a stream) - header = getHeaderBase(); - header = header.replace("%code%", "404 File not found"); - header = header.replace("%length%", ""+"404 - File not Found".length()); - out = new PrintWriter(toClient.getOutputStream(), true); - out.print(header); - out.print("404 - File not Found"); - out.flush(); - } - - Server.remove(toClient); - toClient.close(); - } catch (Exception e) { - - } - } - - private String getHeaderBase() { - return "HTTP/1.1 %code%\n"+ - "Server: AndroidWebserver/1.0\n"+ - "Content-Length: %length%\n"+ - "Connection: close\n"+ - "Content-Type: text/html; charset=iso-8859-1\n\n"; - } -} +/* + * Copyright (C) 2009-2014 Markus Bode + * + * Licensed under the GNU General Public License v3 + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ +package com.bolutions.webserver; +import java.io.*; +import java.net.*; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import net.dinglisch.android.tasker.TaskerIntent; +import android.content.Context; +import android.database.Cursor; +import android.net.Uri; +import android.util.Log; + +class ServerHandler extends Thread { + private BufferedReader in; + private PrintWriter out; + private Socket toClient; + private String documentRoot; + private Context context; + + public ServerHandler(String d, Context c, Socket s) { + toClient = s; + documentRoot = d; + context = c; + } + + public void run() { + String dokument = ""; + + try { + in = new BufferedReader(new InputStreamReader(toClient.getInputStream())); + + // Receive data + while (true) { + String s = in.readLine().trim(); + + if (s.equals("")) { + break; + } + + if (s.substring(0, 3).equals("GET")) { + int leerstelle = s.indexOf(" HTTP/"); + dokument = s.substring(5,leerstelle); + dokument = dokument.replaceAll("[/]+","/"); + } + } + } catch (Exception e) { + Server.remove(toClient); + try { + toClient.close(); + } + catch (Exception ex){} + } + + Pattern taskerPattern = Pattern.compile("tasker/(.+)"); + Matcher taskerMatcher = taskerPattern.matcher(dokument); + + if(taskerMatcher.matches()) { + try { + dokument = java.net.URLDecoder.decode(taskerMatcher.group(1), "UTF-8"); + sendTasker(dokument); + } catch (UnsupportedEncodingException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + showHtml("403.html"); + } + } else if(dokument.equals("tasker/")) { + listTaskerTasks(); + } else { + showHtml(dokument); + } + } + + private void sendTasker(String taskName) { + if(TaskerIntent.testStatus(context).equals(TaskerIntent.Status.OK)) { + TaskerIntent i = new TaskerIntent(taskName); + context.sendBroadcast(i); + + send("Sent intent \"" + taskName + "\" to tasker."); + } else { + send("Could not sent intent \"" + taskName + "\" to tasker (" + + TaskerIntent.testStatus(context) + ")."); + } + } + + private void listTaskerTasks() { + Cursor c = context.getContentResolver().query(Uri.parse("content://net.dinglisch.android.tasker/tasks"), null, null, null, null); + + String text = "Found tasks:
    "; + if(c != null) { + Log.d("Webserver", "Cursor is not null"); + int nameCol = c.getColumnIndex("name"); + int projNameCol = c.getColumnIndex("project_name"); + + while(c.moveToNext()) { + text = text + "
  • " + c.getString(projNameCol) + ": " + c.getString(nameCol) + "
  • "; + } + c.close(); + } else { + Log.d("Webserver", "Cursor is null"); + } + text = text + "
"; + send(text); + } + + private void send(String text) { + String header = getHeaderBase(); + header = header.replace("%code%", "200 ok"); + header = header.replace("%length%", "" + text.length()); + try { + out = new PrintWriter(toClient.getOutputStream(), true); + out.print(header); + out.print(text); + out.flush(); + Server.remove(toClient); + toClient.close(); + } catch (Exception e) { + + } + } + + private void showHtml(String dokument) { + // Standard-Doc + if (dokument.equals("")) { + dokument = "index.html"; + } + + // Don't allow directory traversal + if (dokument.indexOf("..") != -1) { + dokument = "403.html"; + } + + // Search for files in docroot + dokument = documentRoot + dokument; + Log.d("Webserver", "Got " + dokument); + dokument = dokument.replaceAll("[/]+","/"); + + if(dokument.charAt(dokument.length()-1) == '/') { + dokument = documentRoot + "404.html"; + } + + String header = getHeaderBase(); + header = header.replace("%code%", "403 Forbidden"); + + try { + File f = new File(dokument); + if (!f.exists()) { + header = getHeaderBase(); + header = header.replace("%code%", "404 File not found"); + dokument = "404.html"; + } + } + catch (Exception e) {} + + if (!dokument.equals(documentRoot + "403.html")) { + header = getHeaderBase().replace("%code%", "200 OK"); + } + + Log.d("Webserver", "Serving " + dokument); + + try { + File f = new File(dokument); + if (f.exists()) { + BufferedInputStream in = new BufferedInputStream(new FileInputStream(dokument)); + BufferedOutputStream out = new BufferedOutputStream(toClient.getOutputStream()); + ByteArrayOutputStream tempOut = new ByteArrayOutputStream(); + + byte[] buf = new byte[4096]; + int count = 0; + while ((count = in.read(buf)) != -1){ + tempOut.write(buf, 0, count); + } + + tempOut.flush(); + header = header.replace("%length%", ""+tempOut.size()); + + out.write(header.getBytes()); + out.write(tempOut.toByteArray()); + out.flush(); + } else { + // Send HTML-File (Ascii, not as a stream) + header = getHeaderBase(); + header = header.replace("%code%", "404 File not found"); + header = header.replace("%length%", ""+"404 - File not Found".length()); + out = new PrintWriter(toClient.getOutputStream(), true); + out.print(header); + out.print("404 - File not Found"); + out.flush(); + } + + Server.remove(toClient); + toClient.close(); + } catch (Exception e) { + + } + } + + private String getHeaderBase() { + return "HTTP/1.1 %code%\n"+ + "Server: AndroidWebserver/1.0\n"+ + "Content-Length: %length%\n"+ + "Connection: close\n"+ + "Content-Type: text/html; charset=iso-8859-1\n\n"; + } +} diff --git a/src/com/bolutions/webserver/ServerService.java b/app/src/main/java/com/bolutions/webserver/ServerService.java similarity index 90% rename from src/com/bolutions/webserver/ServerService.java rename to app/src/main/java/com/bolutions/webserver/ServerService.java index 67ac2e6..f8a9812 100644 --- a/src/com/bolutions/webserver/ServerService.java +++ b/app/src/main/java/com/bolutions/webserver/ServerService.java @@ -1,140 +1,145 @@ -/* - * Copyright (C) 2009-2014 Markus Bode - * - * Licensed under the GNU General Public License v3 - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - */ - -package com.bolutions.webserver; - - -import android.app.AlertDialog; -import android.app.IntentService; -import android.app.Notification; -import android.app.NotificationManager; -import android.app.PendingIntent; -import android.app.Service; -import android.content.Intent; -import android.net.wifi.SupplicantState; -import android.net.wifi.WifiInfo; -import android.net.wifi.WifiManager; -import android.os.Binder; -import android.os.Bundle; -import android.os.Handler; -import android.os.IBinder; -import android.os.Message; -import android.preference.PreferenceManager; -import android.util.Log; - -public class ServerService extends Service { - - private int NOTIFICATION_ID = 4711; - private NotificationManager mNM; - private String message; - private Notification notification; - private Server server; - private boolean isRunning = false; - - @Override - public void onCreate() { - mNM = (NotificationManager)getSystemService(NOTIFICATION_SERVICE); - showNotification(); - } - - private void showNotification() { - updateNotifiction(""); - startForeground(NOTIFICATION_ID, notification); - } - - public void startServer(Handler handler, String documentRoot, int port) { - try { - isRunning = true; - WifiManager wifiManager = (WifiManager) getSystemService(WIFI_SERVICE); - WifiInfo wifiInfo = wifiManager.getConnectionInfo(); - - String ipAddress = intToIp(wifiInfo.getIpAddress()); - - if( wifiInfo.getSupplicantState() != SupplicantState.COMPLETED) { - new AlertDialog.Builder(this).setTitle("Error").setMessage("Please connect to a WIFI-network for starting the webserver.").setPositiveButton("OK", null).show(); - throw new Exception("Please connect to a WIFI-network."); - } - - server = new Server(handler, documentRoot, ipAddress, port, getApplicationContext()); - server.start(); - - Intent i = new Intent(this, StartActivity.class); - PendingIntent contentIntent = PendingIntent.getActivity(this, 0, i, 0); - - updateNotifiction("Webserver is running on port " + ipAddress + ":" + port); - - Message msg = new Message(); - Bundle b = new Bundle(); - b.putString("msg", "Webserver is running on port " + ipAddress + ":" + port); - msg.setData(b); - handler.sendMessage(msg); - - } catch (Exception e) { - isRunning = false; - Log.e("Webserver", e.getMessage()); - updateNotifiction("Error: " + e.getMessage()); - } - } - - public static String intToIp(int i) { - return ((i ) & 0xFF) + "." + - ((i >> 8 ) & 0xFF) + "." + - ((i >> 16 ) & 0xFF) + "." + - ( i >> 24 & 0xFF); - } - - public void stopServer() { - if(null != server) { - server.stopServer(); - server.interrupt(); - isRunning = false; - } - } - - public void updateNotifiction(String message) { - CharSequence text = message; - - PendingIntent contentIntent = PendingIntent.getActivity(this, 0, new Intent(this, StartActivity.class), 0); - Notification.Builder builder = new Notification.Builder(this) - .setSmallIcon(R.drawable.ic_launcher) - .setContentTitle(getString(R.string.app_name)) - .setContentText(text) - .setContentIntent(contentIntent); - notification = builder.build(); - mNM.notify(NOTIFICATION_ID, notification); - } - - @Override - public IBinder onBind(Intent intent) { - return mBinder; - } - - private final IBinder mBinder = new LocalBinder(); - - public class LocalBinder extends Binder { - ServerService getService() { - return ServerService.this; - } - } - - public boolean isRunning() { - return isRunning; - } -} +/* + * Copyright (C) 2009-2014 Markus Bode + * Copyright (C) 2017 Mikhail Basov + * + * Licensed under the GNU General Public License v3 + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +package com.bolutions.webserver; + + +import android.app.AlertDialog; +import android.app.IntentService; +import android.app.Notification; +import android.app.NotificationManager; +import android.app.PendingIntent; +import android.app.Service; +import android.content.Intent; +import android.graphics.BitmapFactory; +import android.net.wifi.SupplicantState; +import android.net.wifi.WifiInfo; +import android.net.wifi.WifiManager; +import android.os.Binder; +import android.os.Bundle; +import android.os.Handler; +import android.os.IBinder; +import android.os.Message; +import android.preference.PreferenceManager; +import android.util.Log; + +public class ServerService extends Service { + + private int NOTIFICATION_ID = 4711; + private NotificationManager mNM; + private String message; + private Notification notification; + private Server server; + private boolean isRunning = false; + + @Override + public void onCreate() { + mNM = (NotificationManager)getSystemService(NOTIFICATION_SERVICE); + showNotification(); + } + + private void showNotification() { + updateNotifiction(""); + startForeground(NOTIFICATION_ID, notification); + } + + public void startServer(Handler handler, String documentRoot, int port) { + try { + isRunning = true; + WifiManager wifiManager = (WifiManager) getApplicationContext().getSystemService(WIFI_SERVICE); + WifiInfo wifiInfo = wifiManager.getConnectionInfo(); + + String ipAddress = intToIp(wifiInfo.getIpAddress()); + + if( wifiInfo.getSupplicantState() != SupplicantState.COMPLETED) { + new AlertDialog.Builder(this).setTitle("Error").setMessage("Please connect to a WIFI-network for starting the webserver.").setPositiveButton("OK", null).show(); + throw new Exception("Please connect to a WIFI-network."); + } + + server = new Server(handler, documentRoot, ipAddress, port, getApplicationContext()); + server.start(); + + Intent i = new Intent(this, StartActivity.class); + PendingIntent contentIntent = PendingIntent.getActivity(this, 0, i, 0); + + updateNotifiction("Webserver is running on port " + ipAddress + ":" + port); + + Message msg = new Message(); + Bundle b = new Bundle(); + b.putString("msg", "Webserver is running on port " + ipAddress + ":" + port); + msg.setData(b); + handler.sendMessage(msg); + + } catch (Exception e) { + isRunning = false; + Log.e("Webserver", e.getMessage()); + updateNotifiction("Error: " + e.getMessage()); + } + } + + public static String intToIp(int i) { + return ((i ) & 0xFF) + "." + + ((i >> 8 ) & 0xFF) + "." + + ((i >> 16 ) & 0xFF) + "." + + ( i >> 24 & 0xFF); + } + + public void stopServer() { + if(null != server) { + server.stopServer(); + server.interrupt(); + isRunning = false; + } + } + + public void updateNotifiction(String message) { + CharSequence text = message; + + PendingIntent contentIntent = PendingIntent.getActivity(this, 0, new Intent(this, StartActivity.class), 0); + notification = new Notification.Builder(this) + .setSmallIcon(R.drawable.ic_launcher) + .setLargeIcon(BitmapFactory.decodeResource(getResources(), R.drawable.ic_launcher)) + .setContentTitle(getString(R.string.app_name)) + .setContentText(text) + .setWhen(System.currentTimeMillis()) + .setContentIntent(contentIntent) + .build(); + mNM.notify(NOTIFICATION_ID, notification); + + } + + @Override + public IBinder onBind(Intent intent) { + return mBinder; + } + + private final IBinder mBinder = new LocalBinder(); + + public class LocalBinder extends Binder { + ServerService getService() { + return ServerService.this; + } + } + + public boolean isRunning() { + return isRunning; + } +} diff --git a/src/com/bolutions/webserver/StartActivity.java b/app/src/main/java/com/bolutions/webserver/StartActivity.java similarity index 100% rename from src/com/bolutions/webserver/StartActivity.java rename to app/src/main/java/com/bolutions/webserver/StartActivity.java diff --git a/src/net/dinglisch/android/tasker/TaskerIntent.java b/app/src/main/java/net/dinglisch/android/tasker/TaskerIntent.java similarity index 96% rename from src/net/dinglisch/android/tasker/TaskerIntent.java rename to app/src/main/java/net/dinglisch/android/tasker/TaskerIntent.java index 17f5b6e..09732fd 100644 --- a/src/net/dinglisch/android/tasker/TaskerIntent.java +++ b/app/src/main/java/net/dinglisch/android/tasker/TaskerIntent.java @@ -1,450 +1,450 @@ -package net.dinglisch.android.tasker; - -//Version 1.3.3 - -//Changelog - -//Version 1.3.3 -//- increased MAX_NO_ARGS to 10 - -//Version 1.3.2 -// - bug setting app arg -// - pulled provider column names out of function - -//For usage examples see http://tasker.dinglisch.net/invoketasks.html - - -import java.lang.reflect.Field; -import java.util.ArrayList; -import java.util.List; -import java.util.Random; - -import android.content.Context; -import android.content.Intent; -import android.content.IntentFilter; -import android.content.pm.PackageManager; -import android.content.pm.ResolveInfo; -import android.database.Cursor; -import android.net.Uri; -import android.os.Bundle; -import android.os.PatternMatcher; -import android.os.Process; -import android.util.Log; - -public class TaskerIntent extends Intent { - - // 3 Tasker versions - public final static String TASKER_PACKAGE = "net.dinglisch.android.tasker"; - public final static String TASKER_PACKAGE_MARKET = TASKER_PACKAGE + "m"; - public final static String TASKER_PACKAGE_CUPCAKE = TASKER_PACKAGE + "cupcake"; - - // Play Store download URLs - public final static String MARKET_DOWNLOAD_URL_PREFIX = "market://details?id="; - private final static String TASKER_MARKET_URL = MARKET_DOWNLOAD_URL_PREFIX + TASKER_PACKAGE_MARKET; - private final static String TASKER_MARKET_URL_CUPCAKE = MARKET_DOWNLOAD_URL_PREFIX + TASKER_PACKAGE_CUPCAKE; - - // Direct-purchase version - private final static String TASKER_DOWNLOAD_URL = "http://tasker.dinglisch.net/download.html"; - - // Intent actions - public final static String ACTION_TASK = TASKER_PACKAGE + ".ACTION_TASK"; - public final static String ACTION_TASK_COMPLETE = TASKER_PACKAGE + ".ACTION_TASK_COMPLETE"; - public final static String ACTION_TASK_SELECT = TASKER_PACKAGE + ".ACTION_TASK_SELECT"; - - // Intent parameters - public final static String EXTRA_ACTION_INDEX_PREFIX = "action"; - public final static String TASK_NAME_DATA_SCHEME = "task"; - public final static String EXTRA_TASK_NAME = "task_name"; - public final static String EXTRA_TASK_PRIORITY = "task_priority"; - public final static String EXTRA_SUCCESS_FLAG = "success"; - public final static String EXTRA_VAR_NAMES_LIST = "varNames"; - public final static String EXTRA_VAR_VALUES_LIST = "varValues"; - public final static String EXTRA_TASK_OUTPUT = "output"; - - // Content provider columns - public static final String PROVIDER_COL_NAME_EXTERNAL_ACCESS = "ext_access"; - public static final String PROVIDER_COL_NAME_ENABLED = "enabled"; - - // DEPRECATED, use EXTRA_VAR_NAMES_LIST, EXTRA_VAR_VALUES_LIST - public final static String EXTRA_PARAM_LIST = "params"; - - // Intent data - - public final static String TASK_ID_SCHEME = "id"; - - // For particular actions - - public final static String DEFAULT_ENCRYPTION_KEY= "default"; - public final static String ENCRYPTED_AFFIX = "tec"; - public final static int MAX_NO_ARGS = 10; - - // Bundle keys - // Only useful for Tasker - public final static String ACTION_CODE = "action"; - public final static String APP_ARG_PREFIX = "app:"; - public final static String ICON_ARG_PREFIX = "icn:"; - public final static String ARG_INDEX_PREFIX = "arg:"; - public static final String PARAM_VAR_NAME_PREFIX = "par"; - - // Misc - private final static String PERMISSION_RUN_TASKS = TASKER_PACKAGE + ".PERMISSION_RUN_TASKS"; - - private final static String ACTION_OPEN_PREFS = TASKER_PACKAGE + ".ACTION_OPEN_PREFS"; - public final static String EXTRA_OPEN_PREFS_TAB_NO = "tno"; - private final static int MISC_PREFS_TAB_NO = 3; // 0 based - - // To query whether Tasker is enabled and external access is enabled - private final static String TASKER_PREFS_URI = "content://" + TASKER_PACKAGE + "/prefs"; - - private final static int CUPCAKE_SDK_VERSION = 3; - - // result values for TestSend - - // NotInstalled: Tasker package not found on device - // NoPermission: calling app does not have permission PERMISSION_RUN_TASKS - // NotEnabled: Tasker is not enabled - // AccessBlocked: user prefs disallow external access - // NoReceiver: Tasker has not created a listener for external access (probably a Tasker bug) - // OK: you should be able to send a task to run. Still need to listen for result - // for e.g. task not found - - public static enum Status { NotInstalled, NoPermission, NotEnabled, AccessBlocked, NoReceiver, OK }; - - // -------------------------- PRIVATE VARS ---------------------------- // - - private final static String TAG = "TaskerIntent"; - - private final static String EXTRA_INTENT_VERSION_NUMBER = "version_number"; - private final static String INTENT_VERSION_NUMBER = "1.1"; - - // Inclusive values - private final static int MIN_PRIORITY = 0; - private final static int MAX_PRIORITY = 10; - - // For generating random names - private static Random rand = new Random(); - - // Tracking state - private int actionCount = 0; - private int argCount; - - // -------------------------- PUBLIC METHODS ---------------------------- // - - public static int getMaxPriority() { - return MAX_PRIORITY; - } - - public static boolean validatePriority( int pri ) { - return ( - ( pri >= MIN_PRIORITY ) || - ( pri <= MAX_PRIORITY ) - ); - } - - // Tasker has different package names for Play Store and non- versions - // for historical reasons - - public static String getInstalledTaskerPackage( Context context ) { - - String foundPackage = null; - - try { - context.getPackageManager().getPackageInfo( TASKER_PACKAGE, 0 ); - foundPackage = TASKER_PACKAGE; - } - catch ( PackageManager.NameNotFoundException e ) { - } - - try { - context.getPackageManager().getPackageInfo( TASKER_PACKAGE_MARKET, 0 ); - foundPackage = TASKER_PACKAGE_MARKET; - } - catch ( PackageManager.NameNotFoundException e ) { - } - - return foundPackage; - } - - // test we can send a TaskerIntent to Tasker - // use *before* sending an intent - // still need to test the *result after* sending intent - - public static Status testStatus( Context c ) { - - Status result; - - if ( ! taskerInstalled( c ) ) - result = Status.NotInstalled; - else if ( ! havePermission( c ) ) - result = Status.NoPermission; - else if ( ! TaskerIntent.prefSet( c, PROVIDER_COL_NAME_ENABLED ) ) - result = Status.NotEnabled; - else if ( ! TaskerIntent.prefSet( c, PROVIDER_COL_NAME_EXTERNAL_ACCESS ) ) - result = Status.AccessBlocked; - else if ( ! new TaskerIntent( "" ).receiverExists( c ) ) - result = Status.NoReceiver; - else - result = Status.OK; - - return result; - } - - // Check if Tasker installed - - public static boolean taskerInstalled( Context context ) { - return ( getInstalledTaskerPackage( context ) != null ); - } - - // Use with startActivity to retrieve Tasker from Android market - public static Intent getTaskerInstallIntent( boolean marketFlag ) { - - return new Intent( - Intent.ACTION_VIEW, - Uri.parse( - marketFlag ? - ( ( SDKVersion() == CUPCAKE_SDK_VERSION ) ? TASKER_MARKET_URL_CUPCAKE : TASKER_MARKET_URL ) : - TASKER_DOWNLOAD_URL - ) - ); - } - - public static int SDKVersion() { - try { - Field f = android.os.Build.VERSION.class.getField( "SDK_INT" ); - return f.getInt( null ); - } - catch ( Exception e ) { - return CUPCAKE_SDK_VERSION; - } - } - - public static IntentFilter getCompletionFilter( String taskName ) { - - IntentFilter filter = new IntentFilter( TaskerIntent.ACTION_TASK_COMPLETE ); - - filter.addDataScheme( TASK_NAME_DATA_SCHEME ); - filter.addDataPath( taskName, PatternMatcher.PATTERN_LITERAL ); - - return filter; - } - - public static Intent getTaskSelectIntent() { - return new Intent( ACTION_TASK_SELECT ). - setFlags( - Intent.FLAG_ACTIVITY_NO_USER_ACTION | - Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS | - Intent.FLAG_ACTIVITY_NO_HISTORY - ); - } - - // public access deprecated, use TaskerIntent.testSend() instead - - public static boolean havePermission( Context c ) { - return c.checkPermission( PERMISSION_RUN_TASKS, Process.myPid(), Process.myUid() ) == - PackageManager.PERMISSION_GRANTED; - } - - // Get an intent that will bring up the Tasker prefs screen with the External Access control(s) - // Probably you want to use startActivity or startActivityForResult with it - - public static Intent getExternalAccessPrefsIntent() { - return new Intent( ACTION_OPEN_PREFS ).putExtra( EXTRA_OPEN_PREFS_TAB_NO, MISC_PREFS_TAB_NO ); - } - - // ------------------------------------- INSTANCE METHODS ----------------------------- // - - public TaskerIntent() { - super( ACTION_TASK ); - setRandomData(); - putMetaExtras( getRandomString() ); - } - - public TaskerIntent( String taskName ) { - super( ACTION_TASK ); - setRandomData(); - putMetaExtras( taskName ); - } - - public TaskerIntent setTaskPriority( int priority ) { - - if ( validatePriority( priority ) ) - putExtra( EXTRA_TASK_PRIORITY, priority ); - else - Log.e( TAG, "priority out of range: " + MIN_PRIORITY + ":" + MAX_PRIORITY ); - - return this; - } - - // Sets subsequently %par1, %par2 etc - public TaskerIntent addParameter( String value ) { - - int index = 1; - - if ( getExtras().containsKey( EXTRA_VAR_NAMES_LIST ) ) - index = getExtras().getStringArrayList( EXTRA_VAR_NAMES_LIST ).size() + 1; - - Log.d(TAG, "index: " + index ); - - addLocalVariable( "%" + PARAM_VAR_NAME_PREFIX + index, value ); - - return this; - } - - // Arbitrary specification of (local) variable names and values - public TaskerIntent addLocalVariable( String name, String value ) { - - ArrayList names, values; - - if ( hasExtra( EXTRA_VAR_NAMES_LIST ) ) { - names = getStringArrayListExtra( EXTRA_VAR_NAMES_LIST ); - values = getStringArrayListExtra( EXTRA_VAR_VALUES_LIST ); - } - else { - names = new ArrayList(); - values = new ArrayList(); - - putStringArrayListExtra( EXTRA_VAR_NAMES_LIST, names ); - putStringArrayListExtra( EXTRA_VAR_VALUES_LIST, values ); - } - - names.add( name ); - values.add( value ); - - return this; - } - - public TaskerIntent addAction( int code ) { - - actionCount++; - argCount = 1; - - Bundle actionBundle = new Bundle(); - - actionBundle.putInt( ACTION_CODE, code ); - - // Add action bundle to intent - putExtra( EXTRA_ACTION_INDEX_PREFIX + Integer.toString( actionCount ), actionBundle ); - - return this; - } - - // string arg - public TaskerIntent addArg( String arg ) { - - Bundle b = getActionBundle(); - - if ( b != null ) - b.putString( ARG_INDEX_PREFIX + Integer.toString( argCount++ ), arg ); - - return this; - } - - // int arg - public TaskerIntent addArg( int arg ) { - Bundle b = getActionBundle(); - - if ( b != null ) - b.putInt( ARG_INDEX_PREFIX + Integer.toString( argCount++ ), arg ); - - return this; - } - - // boolean arg - public TaskerIntent addArg( boolean arg ) { - Bundle b = getActionBundle(); - - if ( b != null ) - b.putBoolean( ARG_INDEX_PREFIX + Integer.toString( argCount++ ), arg ); - - return this; - } - - // Application arg - public TaskerIntent addArg( String pkg, String cls ) { - Bundle b = getActionBundle(); - - if ( b != null ) { - StringBuilder builder = new StringBuilder(); - builder.append( APP_ARG_PREFIX ). - append( pkg ). append( "," ). append( cls ); - b.putString( ARG_INDEX_PREFIX + Integer.toString( argCount++ ), b.toString() ); - } - - return this; - } - - public IntentFilter getCompletionFilter() { - return getCompletionFilter( getTaskName() ); - } - - public String getTaskName() { - return getStringExtra( EXTRA_TASK_NAME ); - } - - public boolean receiverExists( Context context ) { - List recs = context.getPackageManager().queryBroadcastReceivers( this, 0 ); - return ( - ( recs != null ) && - ( recs.size() > 0 ) - ); - } - - // -------------------- PRIVATE METHODS -------------------- // - - private String getRandomString() { - return Long.toString( rand.nextLong() ); - } - - // so that if multiple TaskerIntents are used in PendingIntents there's virtually no - // clash chance - private void setRandomData() { - setData( Uri.parse( TASK_ID_SCHEME + ":" + getRandomString() ) ); - } - - private Bundle getActionBundle() { - - Bundle toReturn = null; - - if ( argCount > MAX_NO_ARGS ) - Log.e( TAG, "maximum number of arguments exceeded (" + MAX_NO_ARGS + ")" ); - else { - String key = EXTRA_ACTION_INDEX_PREFIX + Integer.toString( actionCount ); - - if ( this.hasExtra( key ) ) - toReturn = getBundleExtra( key ); - else - Log.e( TAG, "no actions added yet" ); - } - - return toReturn; - } - - private void putMetaExtras( String taskName ) { - putExtra( EXTRA_INTENT_VERSION_NUMBER, INTENT_VERSION_NUMBER ); - putExtra( EXTRA_TASK_NAME, taskName ); - } - - // for testing that Tasker is enabled and external access is allowed - - private static boolean prefSet( Context context, String col ) { - - String [] proj = new String [] { col }; - - Cursor c = context.getContentResolver().query( Uri.parse( TASKER_PREFS_URI ), proj, null, null, null ); - - boolean acceptingFlag = false; - - if ( c == null ) - Log.w( TAG, "no cursor for " + TASKER_PREFS_URI ); - else { - c.moveToFirst(); - - if ( Boolean.TRUE.toString().equals( c.getString( 0 ) ) ) - acceptingFlag = true; - - c.close(); - } - - return acceptingFlag; - } +package net.dinglisch.android.tasker; + +//Version 1.3.3 + +//Changelog + +//Version 1.3.3 +//- increased MAX_NO_ARGS to 10 + +//Version 1.3.2 +// - bug setting app arg +// - pulled provider column names out of function + +//For usage examples see http://tasker.dinglisch.net/invoketasks.html + + +import java.lang.reflect.Field; +import java.util.ArrayList; +import java.util.List; +import java.util.Random; + +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.content.pm.PackageManager; +import android.content.pm.ResolveInfo; +import android.database.Cursor; +import android.net.Uri; +import android.os.Bundle; +import android.os.PatternMatcher; +import android.os.Process; +import android.util.Log; + +public class TaskerIntent extends Intent { + + // 3 Tasker versions + public final static String TASKER_PACKAGE = "net.dinglisch.android.tasker"; + public final static String TASKER_PACKAGE_MARKET = TASKER_PACKAGE + "m"; + public final static String TASKER_PACKAGE_CUPCAKE = TASKER_PACKAGE + "cupcake"; + + // Play Store download URLs + public final static String MARKET_DOWNLOAD_URL_PREFIX = "market://details?id="; + private final static String TASKER_MARKET_URL = MARKET_DOWNLOAD_URL_PREFIX + TASKER_PACKAGE_MARKET; + private final static String TASKER_MARKET_URL_CUPCAKE = MARKET_DOWNLOAD_URL_PREFIX + TASKER_PACKAGE_CUPCAKE; + + // Direct-purchase version + private final static String TASKER_DOWNLOAD_URL = "http://tasker.dinglisch.net/download.html"; + + // Intent actions + public final static String ACTION_TASK = TASKER_PACKAGE + ".ACTION_TASK"; + public final static String ACTION_TASK_COMPLETE = TASKER_PACKAGE + ".ACTION_TASK_COMPLETE"; + public final static String ACTION_TASK_SELECT = TASKER_PACKAGE + ".ACTION_TASK_SELECT"; + + // Intent parameters + public final static String EXTRA_ACTION_INDEX_PREFIX = "action"; + public final static String TASK_NAME_DATA_SCHEME = "task"; + public final static String EXTRA_TASK_NAME = "task_name"; + public final static String EXTRA_TASK_PRIORITY = "task_priority"; + public final static String EXTRA_SUCCESS_FLAG = "success"; + public final static String EXTRA_VAR_NAMES_LIST = "varNames"; + public final static String EXTRA_VAR_VALUES_LIST = "varValues"; + public final static String EXTRA_TASK_OUTPUT = "output"; + + // Content provider columns + public static final String PROVIDER_COL_NAME_EXTERNAL_ACCESS = "ext_access"; + public static final String PROVIDER_COL_NAME_ENABLED = "enabled"; + + // DEPRECATED, use EXTRA_VAR_NAMES_LIST, EXTRA_VAR_VALUES_LIST + public final static String EXTRA_PARAM_LIST = "params"; + + // Intent data + + public final static String TASK_ID_SCHEME = "id"; + + // For particular actions + + public final static String DEFAULT_ENCRYPTION_KEY= "default"; + public final static String ENCRYPTED_AFFIX = "tec"; + public final static int MAX_NO_ARGS = 10; + + // Bundle keys + // Only useful for Tasker + public final static String ACTION_CODE = "action"; + public final static String APP_ARG_PREFIX = "app:"; + public final static String ICON_ARG_PREFIX = "icn:"; + public final static String ARG_INDEX_PREFIX = "arg:"; + public static final String PARAM_VAR_NAME_PREFIX = "par"; + + // Misc + private final static String PERMISSION_RUN_TASKS = TASKER_PACKAGE + ".PERMISSION_RUN_TASKS"; + + private final static String ACTION_OPEN_PREFS = TASKER_PACKAGE + ".ACTION_OPEN_PREFS"; + public final static String EXTRA_OPEN_PREFS_TAB_NO = "tno"; + private final static int MISC_PREFS_TAB_NO = 3; // 0 based + + // To query whether Tasker is enabled and external access is enabled + private final static String TASKER_PREFS_URI = "content://" + TASKER_PACKAGE + "/prefs"; + + private final static int CUPCAKE_SDK_VERSION = 3; + + // result values for TestSend + + // NotInstalled: Tasker package not found on device + // NoPermission: calling app does not have permission PERMISSION_RUN_TASKS + // NotEnabled: Tasker is not enabled + // AccessBlocked: user prefs disallow external access + // NoReceiver: Tasker has not created a listener for external access (probably a Tasker bug) + // OK: you should be able to send a task to run. Still need to listen for result + // for e.g. task not found + + public static enum Status { NotInstalled, NoPermission, NotEnabled, AccessBlocked, NoReceiver, OK }; + + // -------------------------- PRIVATE VARS ---------------------------- // + + private final static String TAG = "TaskerIntent"; + + private final static String EXTRA_INTENT_VERSION_NUMBER = "version_number"; + private final static String INTENT_VERSION_NUMBER = "1.1"; + + // Inclusive values + private final static int MIN_PRIORITY = 0; + private final static int MAX_PRIORITY = 10; + + // For generating random names + private static Random rand = new Random(); + + // Tracking state + private int actionCount = 0; + private int argCount; + + // -------------------------- PUBLIC METHODS ---------------------------- // + + public static int getMaxPriority() { + return MAX_PRIORITY; + } + + public static boolean validatePriority( int pri ) { + return ( + ( pri >= MIN_PRIORITY ) || + ( pri <= MAX_PRIORITY ) + ); + } + + // Tasker has different package names for Play Store and non- versions + // for historical reasons + + public static String getInstalledTaskerPackage( Context context ) { + + String foundPackage = null; + + try { + context.getPackageManager().getPackageInfo( TASKER_PACKAGE, 0 ); + foundPackage = TASKER_PACKAGE; + } + catch ( PackageManager.NameNotFoundException e ) { + } + + try { + context.getPackageManager().getPackageInfo( TASKER_PACKAGE_MARKET, 0 ); + foundPackage = TASKER_PACKAGE_MARKET; + } + catch ( PackageManager.NameNotFoundException e ) { + } + + return foundPackage; + } + + // test we can send a TaskerIntent to Tasker + // use *before* sending an intent + // still need to test the *result after* sending intent + + public static Status testStatus( Context c ) { + + Status result; + + if ( ! taskerInstalled( c ) ) + result = Status.NotInstalled; + else if ( ! havePermission( c ) ) + result = Status.NoPermission; + else if ( ! TaskerIntent.prefSet( c, PROVIDER_COL_NAME_ENABLED ) ) + result = Status.NotEnabled; + else if ( ! TaskerIntent.prefSet( c, PROVIDER_COL_NAME_EXTERNAL_ACCESS ) ) + result = Status.AccessBlocked; + else if ( ! new TaskerIntent( "" ).receiverExists( c ) ) + result = Status.NoReceiver; + else + result = Status.OK; + + return result; + } + + // Check if Tasker installed + + public static boolean taskerInstalled( Context context ) { + return ( getInstalledTaskerPackage( context ) != null ); + } + + // Use with startActivity to retrieve Tasker from Android market + public static Intent getTaskerInstallIntent( boolean marketFlag ) { + + return new Intent( + Intent.ACTION_VIEW, + Uri.parse( + marketFlag ? + ( ( SDKVersion() == CUPCAKE_SDK_VERSION ) ? TASKER_MARKET_URL_CUPCAKE : TASKER_MARKET_URL ) : + TASKER_DOWNLOAD_URL + ) + ); + } + + public static int SDKVersion() { + try { + Field f = android.os.Build.VERSION.class.getField( "SDK_INT" ); + return f.getInt( null ); + } + catch ( Exception e ) { + return CUPCAKE_SDK_VERSION; + } + } + + public static IntentFilter getCompletionFilter( String taskName ) { + + IntentFilter filter = new IntentFilter( TaskerIntent.ACTION_TASK_COMPLETE ); + + filter.addDataScheme( TASK_NAME_DATA_SCHEME ); + filter.addDataPath( taskName, PatternMatcher.PATTERN_LITERAL ); + + return filter; + } + + public static Intent getTaskSelectIntent() { + return new Intent( ACTION_TASK_SELECT ). + setFlags( + Intent.FLAG_ACTIVITY_NO_USER_ACTION | + Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS | + Intent.FLAG_ACTIVITY_NO_HISTORY + ); + } + + // public access deprecated, use TaskerIntent.testSend() instead + + public static boolean havePermission( Context c ) { + return c.checkPermission( PERMISSION_RUN_TASKS, Process.myPid(), Process.myUid() ) == + PackageManager.PERMISSION_GRANTED; + } + + // Get an intent that will bring up the Tasker prefs screen with the External Access control(s) + // Probably you want to use startActivity or startActivityForResult with it + + public static Intent getExternalAccessPrefsIntent() { + return new Intent( ACTION_OPEN_PREFS ).putExtra( EXTRA_OPEN_PREFS_TAB_NO, MISC_PREFS_TAB_NO ); + } + + // ------------------------------------- INSTANCE METHODS ----------------------------- // + + public TaskerIntent() { + super( ACTION_TASK ); + setRandomData(); + putMetaExtras( getRandomString() ); + } + + public TaskerIntent( String taskName ) { + super( ACTION_TASK ); + setRandomData(); + putMetaExtras( taskName ); + } + + public TaskerIntent setTaskPriority( int priority ) { + + if ( validatePriority( priority ) ) + putExtra( EXTRA_TASK_PRIORITY, priority ); + else + Log.e( TAG, "priority out of range: " + MIN_PRIORITY + ":" + MAX_PRIORITY ); + + return this; + } + + // Sets subsequently %par1, %par2 etc + public TaskerIntent addParameter( String value ) { + + int index = 1; + + if ( getExtras().containsKey( EXTRA_VAR_NAMES_LIST ) ) + index = getExtras().getStringArrayList( EXTRA_VAR_NAMES_LIST ).size() + 1; + + Log.d(TAG, "index: " + index ); + + addLocalVariable( "%" + PARAM_VAR_NAME_PREFIX + index, value ); + + return this; + } + + // Arbitrary specification of (local) variable names and values + public TaskerIntent addLocalVariable( String name, String value ) { + + ArrayList names, values; + + if ( hasExtra( EXTRA_VAR_NAMES_LIST ) ) { + names = getStringArrayListExtra( EXTRA_VAR_NAMES_LIST ); + values = getStringArrayListExtra( EXTRA_VAR_VALUES_LIST ); + } + else { + names = new ArrayList(); + values = new ArrayList(); + + putStringArrayListExtra( EXTRA_VAR_NAMES_LIST, names ); + putStringArrayListExtra( EXTRA_VAR_VALUES_LIST, values ); + } + + names.add( name ); + values.add( value ); + + return this; + } + + public TaskerIntent addAction( int code ) { + + actionCount++; + argCount = 1; + + Bundle actionBundle = new Bundle(); + + actionBundle.putInt( ACTION_CODE, code ); + + // Add action bundle to intent + putExtra( EXTRA_ACTION_INDEX_PREFIX + Integer.toString( actionCount ), actionBundle ); + + return this; + } + + // string arg + public TaskerIntent addArg( String arg ) { + + Bundle b = getActionBundle(); + + if ( b != null ) + b.putString( ARG_INDEX_PREFIX + Integer.toString( argCount++ ), arg ); + + return this; + } + + // int arg + public TaskerIntent addArg( int arg ) { + Bundle b = getActionBundle(); + + if ( b != null ) + b.putInt( ARG_INDEX_PREFIX + Integer.toString( argCount++ ), arg ); + + return this; + } + + // boolean arg + public TaskerIntent addArg( boolean arg ) { + Bundle b = getActionBundle(); + + if ( b != null ) + b.putBoolean( ARG_INDEX_PREFIX + Integer.toString( argCount++ ), arg ); + + return this; + } + + // Application arg + public TaskerIntent addArg( String pkg, String cls ) { + Bundle b = getActionBundle(); + + if ( b != null ) { + StringBuilder builder = new StringBuilder(); + builder.append( APP_ARG_PREFIX ). + append( pkg ). append( "," ). append( cls ); + b.putString( ARG_INDEX_PREFIX + Integer.toString( argCount++ ), b.toString() ); + } + + return this; + } + + public IntentFilter getCompletionFilter() { + return getCompletionFilter( getTaskName() ); + } + + public String getTaskName() { + return getStringExtra( EXTRA_TASK_NAME ); + } + + public boolean receiverExists( Context context ) { + List recs = context.getPackageManager().queryBroadcastReceivers( this, 0 ); + return ( + ( recs != null ) && + ( recs.size() > 0 ) + ); + } + + // -------------------- PRIVATE METHODS -------------------- // + + private String getRandomString() { + return Long.toString( rand.nextLong() ); + } + + // so that if multiple TaskerIntents are used in PendingIntents there's virtually no + // clash chance + private void setRandomData() { + setData( Uri.parse( TASK_ID_SCHEME + ":" + getRandomString() ) ); + } + + private Bundle getActionBundle() { + + Bundle toReturn = null; + + if ( argCount > MAX_NO_ARGS ) + Log.e( TAG, "maximum number of arguments exceeded (" + MAX_NO_ARGS + ")" ); + else { + String key = EXTRA_ACTION_INDEX_PREFIX + Integer.toString( actionCount ); + + if ( this.hasExtra( key ) ) + toReturn = getBundleExtra( key ); + else + Log.e( TAG, "no actions added yet" ); + } + + return toReturn; + } + + private void putMetaExtras( String taskName ) { + putExtra( EXTRA_INTENT_VERSION_NUMBER, INTENT_VERSION_NUMBER ); + putExtra( EXTRA_TASK_NAME, taskName ); + } + + // for testing that Tasker is enabled and external access is allowed + + private static boolean prefSet( Context context, String col ) { + + String [] proj = new String [] { col }; + + Cursor c = context.getContentResolver().query( Uri.parse( TASKER_PREFS_URI ), proj, null, null, null ); + + boolean acceptingFlag = false; + + if ( c == null ) + Log.w( TAG, "no cursor for " + TASKER_PREFS_URI ); + else { + c.moveToFirst(); + + if ( Boolean.TRUE.toString().equals( c.getString( 0 ) ) ) + acceptingFlag = true; + + c.close(); + } + + return acceptingFlag; + } } \ No newline at end of file diff --git a/res/drawable-hdpi/ic_launcher.png b/app/src/main/res/drawable-hdpi/ic_launcher.png similarity index 100% rename from res/drawable-hdpi/ic_launcher.png rename to app/src/main/res/drawable-hdpi/ic_launcher.png diff --git a/res/drawable-mdpi/ic_launcher.png b/app/src/main/res/drawable-mdpi/ic_launcher.png similarity index 100% rename from res/drawable-mdpi/ic_launcher.png rename to app/src/main/res/drawable-mdpi/ic_launcher.png diff --git a/res/drawable-xhdpi/ic_launcher.png b/app/src/main/res/drawable-xhdpi/ic_launcher.png similarity index 100% rename from res/drawable-xhdpi/ic_launcher.png rename to app/src/main/res/drawable-xhdpi/ic_launcher.png diff --git a/res/drawable-xxhdpi/ic_launcher.png b/app/src/main/res/drawable-xxhdpi/ic_launcher.png similarity index 100% rename from res/drawable-xxhdpi/ic_launcher.png rename to app/src/main/res/drawable-xxhdpi/ic_launcher.png diff --git a/res/layout/main.xml b/app/src/main/res/layout/main.xml similarity index 100% rename from res/layout/main.xml rename to app/src/main/res/layout/main.xml diff --git a/res/values/strings.xml b/app/src/main/res/values/strings.xml similarity index 100% rename from res/values/strings.xml rename to app/src/main/res/values/strings.xml diff --git a/build.gradle b/build.gradle new file mode 100644 index 0000000..8585242 --- /dev/null +++ b/build.gradle @@ -0,0 +1,15 @@ +// Top-level build file where you can add configuration options common to all sub-projects/modules. +buildscript { + repositories { + jcenter() + } + dependencies { + classpath 'com.android.tools.build:gradle:3.0.0' + } +} + +allprojects { + repositories { + jcenter() + } +} diff --git a/default.properties b/default.properties deleted file mode 100644 index 6b8ae52..0000000 --- a/default.properties +++ /dev/null @@ -1,22 +0,0 @@ -# This file is automatically generated by Android Tools. -# Do not modify this file -- YOUR CHANGES WILL BE ERASED! -# -# This file must be checked in Version Control Systems. -# -# To customize properties used by the Ant build system use, -# "build.properties", and override values to adapt the script to your -# project structure. - -# apk configurations. This property allows creation of APK files with limited -# resources. For example, if your application contains many locales and -# you wish to release multiple smaller apks instead of a large one, you can -# define configuration to create apks with limited language sets. -# Format is a comma separated list of configuration names. For each -# configuration, a property will declare the resource configurations to -# include. Example: -# apk-configurations=european,northamerica -# apk-config-european=en,fr,it,de,es -# apk-config-northamerica=en,es -apk-configurations= -# Project target. -target=android-3 diff --git a/import-summary.txt b/import-summary.txt new file mode 100644 index 0000000..385927f --- /dev/null +++ b/import-summary.txt @@ -0,0 +1,38 @@ +ECLIPSE ANDROID PROJECT IMPORT SUMMARY +====================================== + +Ignored Files: +-------------- +The following files were *not* copied into the new Gradle project; you +should evaluate whether these are still needed in your project and if +so manually move them: + +* .gitignore +* LICENSE +* README.md +* default.properties +* ic_launcher-web.png + +Moved Files: +------------ +Android Gradle projects use a different directory structure than ADT +Eclipse projects. Here's how the projects were restructured: + +* AndroidManifest.xml => app/src/main/AndroidManifest.xml +* res/ => app/src/main/res/ +* src/ => app/src/main/java/ + +Next Steps: +----------- +You can now build the project. The Gradle project needs network +connectivity to download dependencies. + +Bugs: +----- +If for some reason your project does not build, and you determine that +it is due to a bug or limitation of the Eclipse to Gradle importer, +please file a bug at http://b.android.com with category +Component-Tools. + +(This import summary is for your information only, and can be deleted +after import once you are satisfied with the results.) diff --git a/project.properties b/project.properties deleted file mode 100644 index ed2065f..0000000 --- a/project.properties +++ /dev/null @@ -1,15 +0,0 @@ -# This file is automatically generated by Android Tools. -# Do not modify this file -- YOUR CHANGES WILL BE ERASED! -# -# This file must be checked in Version Control Systems. -# -# To customize properties used by the Ant build system edit -# "ant.properties", and override values to adapt the script to your -# project structure. -# -# To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home): -#proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt - -apk-configurations= -# Project target. -target=android-8 diff --git a/settings.gradle b/settings.gradle new file mode 100644 index 0000000..e7b4def --- /dev/null +++ b/settings.gradle @@ -0,0 +1 @@ +include ':app' From 7aef7bca3f0afd4233e892bacf1bbeda3956a736 Mon Sep 17 00:00:00 2001 From: Mikhail Basov Date: Thu, 30 Nov 2017 20:53:38 +0300 Subject: [PATCH 003/267] Rename package. Remove Tasker functionality. --- app/build.gradle | 2 +- app/src/main/AndroidManifest.xml | 4 +- .../webserver => net/basov/web}/Server.java | 5 +- .../basov/web}/ServerHandler.java | 71 +-- .../basov/web}/ServerService.java | 6 +- .../basov/web}/StartActivity.java | 7 +- .../android/tasker/TaskerIntent.java | 450 ------------------ build.gradle | 2 +- 8 files changed, 24 insertions(+), 523 deletions(-) rename app/src/main/java/{com/bolutions/webserver => net/basov/web}/Server.java (97%) rename app/src/main/java/{com/bolutions/webserver => net/basov/web}/ServerHandler.java (70%) rename app/src/main/java/{com/bolutions/webserver => net/basov/web}/ServerService.java (97%) rename app/src/main/java/{com/bolutions/webserver => net/basov/web}/StartActivity.java (96%) delete mode 100644 app/src/main/java/net/dinglisch/android/tasker/TaskerIntent.java diff --git a/app/build.gradle b/app/build.gradle index f126fc6..5aebcf8 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -5,7 +5,7 @@ android { buildToolsVersion "26.0.2" defaultConfig { - applicationId "com.bolutions.webserver" + applicationId "net.basov.web" minSdkVersion 17 targetSdkVersion 21 compileOptions { diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 3cdc2c1..0c2b8e6 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -1,6 +1,6 @@ @@ -23,4 +23,4 @@ - \ No newline at end of file + diff --git a/app/src/main/java/com/bolutions/webserver/Server.java b/app/src/main/java/net/basov/web/Server.java similarity index 97% rename from app/src/main/java/com/bolutions/webserver/Server.java rename to app/src/main/java/net/basov/web/Server.java index 1535ae9..ceb1a69 100644 --- a/app/src/main/java/com/bolutions/webserver/Server.java +++ b/app/src/main/java/net/basov/web/Server.java @@ -1,6 +1,7 @@ /* + * Copyright (C) 2017 Mikhail Basov * Copyright (C) 2009-2014 Markus Bode - * + * * Licensed under the GNU General Public License v3 * * This program is free software: you can redistribute it and/or modify @@ -18,7 +19,7 @@ * */ -package com.bolutions.webserver; +package net.basov.web; import java.io.IOException; import java.net.InetAddress; diff --git a/app/src/main/java/com/bolutions/webserver/ServerHandler.java b/app/src/main/java/net/basov/web/ServerHandler.java similarity index 70% rename from app/src/main/java/com/bolutions/webserver/ServerHandler.java rename to app/src/main/java/net/basov/web/ServerHandler.java index 279f657..6630542 100644 --- a/app/src/main/java/com/bolutions/webserver/ServerHandler.java +++ b/app/src/main/java/net/basov/web/ServerHandler.java @@ -1,4 +1,5 @@ /* + * Copyright (C) 2017 Mikhail Basov * Copyright (C) 2009-2014 Markus Bode * * Licensed under the GNU General Public License v3 @@ -17,16 +18,18 @@ * along with this program. If not, see . * */ -package com.bolutions.webserver; -import java.io.*; -import java.net.*; -import java.util.regex.Matcher; -import java.util.regex.Pattern; +package net.basov.web; +import java.io.BufferedInputStream; +import java.io.BufferedOutputStream; +import java.io.BufferedReader; +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.InputStreamReader; +import java.io.PrintWriter; +import java.net.Socket; -import net.dinglisch.android.tasker.TaskerIntent; import android.content.Context; -import android.database.Cursor; -import android.net.Uri; import android.util.Log; class ServerHandler extends Thread { @@ -70,55 +73,7 @@ public void run() { catch (Exception ex){} } - Pattern taskerPattern = Pattern.compile("tasker/(.+)"); - Matcher taskerMatcher = taskerPattern.matcher(dokument); - - if(taskerMatcher.matches()) { - try { - dokument = java.net.URLDecoder.decode(taskerMatcher.group(1), "UTF-8"); - sendTasker(dokument); - } catch (UnsupportedEncodingException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - showHtml("403.html"); - } - } else if(dokument.equals("tasker/")) { - listTaskerTasks(); - } else { - showHtml(dokument); - } - } - - private void sendTasker(String taskName) { - if(TaskerIntent.testStatus(context).equals(TaskerIntent.Status.OK)) { - TaskerIntent i = new TaskerIntent(taskName); - context.sendBroadcast(i); - - send("Sent intent \"" + taskName + "\" to tasker."); - } else { - send("Could not sent intent \"" + taskName + "\" to tasker (" + - TaskerIntent.testStatus(context) + ")."); - } - } - - private void listTaskerTasks() { - Cursor c = context.getContentResolver().query(Uri.parse("content://net.dinglisch.android.tasker/tasks"), null, null, null, null); - - String text = "Found tasks:
    "; - if(c != null) { - Log.d("Webserver", "Cursor is not null"); - int nameCol = c.getColumnIndex("name"); - int projNameCol = c.getColumnIndex("project_name"); - - while(c.moveToNext()) { - text = text + "
  • " + c.getString(projNameCol) + ": " + c.getString(nameCol) + "
  • "; - } - c.close(); - } else { - Log.d("Webserver", "Cursor is null"); - } - text = text + "
"; - send(text); + showHtml(dokument); } private void send(String text) { @@ -218,6 +173,6 @@ private String getHeaderBase() { "Server: AndroidWebserver/1.0\n"+ "Content-Length: %length%\n"+ "Connection: close\n"+ - "Content-Type: text/html; charset=iso-8859-1\n\n"; + "Content-Type: text/html; charset=utf-8\n\n"; } } diff --git a/app/src/main/java/com/bolutions/webserver/ServerService.java b/app/src/main/java/net/basov/web/ServerService.java similarity index 97% rename from app/src/main/java/com/bolutions/webserver/ServerService.java rename to app/src/main/java/net/basov/web/ServerService.java index f8a9812..c221ccb 100644 --- a/app/src/main/java/com/bolutions/webserver/ServerService.java +++ b/app/src/main/java/net/basov/web/ServerService.java @@ -1,6 +1,6 @@ /* - * Copyright (C) 2009-2014 Markus Bode * Copyright (C) 2017 Mikhail Basov + * Copyright (C) 2009-2014 Markus Bode * * Licensed under the GNU General Public License v3 * @@ -19,11 +19,10 @@ * */ -package com.bolutions.webserver; +package net.basov.web; import android.app.AlertDialog; -import android.app.IntentService; import android.app.Notification; import android.app.NotificationManager; import android.app.PendingIntent; @@ -38,7 +37,6 @@ import android.os.Handler; import android.os.IBinder; import android.os.Message; -import android.preference.PreferenceManager; import android.util.Log; public class ServerService extends Service { diff --git a/app/src/main/java/com/bolutions/webserver/StartActivity.java b/app/src/main/java/net/basov/web/StartActivity.java similarity index 96% rename from app/src/main/java/com/bolutions/webserver/StartActivity.java rename to app/src/main/java/net/basov/web/StartActivity.java index c4a91b1..f37e871 100644 --- a/app/src/main/java/com/bolutions/webserver/StartActivity.java +++ b/app/src/main/java/net/basov/web/StartActivity.java @@ -1,4 +1,5 @@ /* + * Copyright (C) 2017 Mikhail Basov * Copyright (C) 2009-2014 Markus Bode * * Licensed under the GNU General Public License v3 @@ -18,21 +19,17 @@ * */ -package com.bolutions.webserver; +package net.basov.web; import java.io.BufferedWriter; import java.io.File; import java.io.FileWriter; import android.app.Activity; -import android.app.NotificationManager; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.ServiceConnection; -import android.content.pm.PackageInfo; -import android.content.pm.PackageManager; -import android.content.pm.PackageManager.NameNotFoundException; import android.os.Bundle; import android.os.Environment; import android.os.Handler; diff --git a/app/src/main/java/net/dinglisch/android/tasker/TaskerIntent.java b/app/src/main/java/net/dinglisch/android/tasker/TaskerIntent.java deleted file mode 100644 index 09732fd..0000000 --- a/app/src/main/java/net/dinglisch/android/tasker/TaskerIntent.java +++ /dev/null @@ -1,450 +0,0 @@ -package net.dinglisch.android.tasker; - -//Version 1.3.3 - -//Changelog - -//Version 1.3.3 -//- increased MAX_NO_ARGS to 10 - -//Version 1.3.2 -// - bug setting app arg -// - pulled provider column names out of function - -//For usage examples see http://tasker.dinglisch.net/invoketasks.html - - -import java.lang.reflect.Field; -import java.util.ArrayList; -import java.util.List; -import java.util.Random; - -import android.content.Context; -import android.content.Intent; -import android.content.IntentFilter; -import android.content.pm.PackageManager; -import android.content.pm.ResolveInfo; -import android.database.Cursor; -import android.net.Uri; -import android.os.Bundle; -import android.os.PatternMatcher; -import android.os.Process; -import android.util.Log; - -public class TaskerIntent extends Intent { - - // 3 Tasker versions - public final static String TASKER_PACKAGE = "net.dinglisch.android.tasker"; - public final static String TASKER_PACKAGE_MARKET = TASKER_PACKAGE + "m"; - public final static String TASKER_PACKAGE_CUPCAKE = TASKER_PACKAGE + "cupcake"; - - // Play Store download URLs - public final static String MARKET_DOWNLOAD_URL_PREFIX = "market://details?id="; - private final static String TASKER_MARKET_URL = MARKET_DOWNLOAD_URL_PREFIX + TASKER_PACKAGE_MARKET; - private final static String TASKER_MARKET_URL_CUPCAKE = MARKET_DOWNLOAD_URL_PREFIX + TASKER_PACKAGE_CUPCAKE; - - // Direct-purchase version - private final static String TASKER_DOWNLOAD_URL = "http://tasker.dinglisch.net/download.html"; - - // Intent actions - public final static String ACTION_TASK = TASKER_PACKAGE + ".ACTION_TASK"; - public final static String ACTION_TASK_COMPLETE = TASKER_PACKAGE + ".ACTION_TASK_COMPLETE"; - public final static String ACTION_TASK_SELECT = TASKER_PACKAGE + ".ACTION_TASK_SELECT"; - - // Intent parameters - public final static String EXTRA_ACTION_INDEX_PREFIX = "action"; - public final static String TASK_NAME_DATA_SCHEME = "task"; - public final static String EXTRA_TASK_NAME = "task_name"; - public final static String EXTRA_TASK_PRIORITY = "task_priority"; - public final static String EXTRA_SUCCESS_FLAG = "success"; - public final static String EXTRA_VAR_NAMES_LIST = "varNames"; - public final static String EXTRA_VAR_VALUES_LIST = "varValues"; - public final static String EXTRA_TASK_OUTPUT = "output"; - - // Content provider columns - public static final String PROVIDER_COL_NAME_EXTERNAL_ACCESS = "ext_access"; - public static final String PROVIDER_COL_NAME_ENABLED = "enabled"; - - // DEPRECATED, use EXTRA_VAR_NAMES_LIST, EXTRA_VAR_VALUES_LIST - public final static String EXTRA_PARAM_LIST = "params"; - - // Intent data - - public final static String TASK_ID_SCHEME = "id"; - - // For particular actions - - public final static String DEFAULT_ENCRYPTION_KEY= "default"; - public final static String ENCRYPTED_AFFIX = "tec"; - public final static int MAX_NO_ARGS = 10; - - // Bundle keys - // Only useful for Tasker - public final static String ACTION_CODE = "action"; - public final static String APP_ARG_PREFIX = "app:"; - public final static String ICON_ARG_PREFIX = "icn:"; - public final static String ARG_INDEX_PREFIX = "arg:"; - public static final String PARAM_VAR_NAME_PREFIX = "par"; - - // Misc - private final static String PERMISSION_RUN_TASKS = TASKER_PACKAGE + ".PERMISSION_RUN_TASKS"; - - private final static String ACTION_OPEN_PREFS = TASKER_PACKAGE + ".ACTION_OPEN_PREFS"; - public final static String EXTRA_OPEN_PREFS_TAB_NO = "tno"; - private final static int MISC_PREFS_TAB_NO = 3; // 0 based - - // To query whether Tasker is enabled and external access is enabled - private final static String TASKER_PREFS_URI = "content://" + TASKER_PACKAGE + "/prefs"; - - private final static int CUPCAKE_SDK_VERSION = 3; - - // result values for TestSend - - // NotInstalled: Tasker package not found on device - // NoPermission: calling app does not have permission PERMISSION_RUN_TASKS - // NotEnabled: Tasker is not enabled - // AccessBlocked: user prefs disallow external access - // NoReceiver: Tasker has not created a listener for external access (probably a Tasker bug) - // OK: you should be able to send a task to run. Still need to listen for result - // for e.g. task not found - - public static enum Status { NotInstalled, NoPermission, NotEnabled, AccessBlocked, NoReceiver, OK }; - - // -------------------------- PRIVATE VARS ---------------------------- // - - private final static String TAG = "TaskerIntent"; - - private final static String EXTRA_INTENT_VERSION_NUMBER = "version_number"; - private final static String INTENT_VERSION_NUMBER = "1.1"; - - // Inclusive values - private final static int MIN_PRIORITY = 0; - private final static int MAX_PRIORITY = 10; - - // For generating random names - private static Random rand = new Random(); - - // Tracking state - private int actionCount = 0; - private int argCount; - - // -------------------------- PUBLIC METHODS ---------------------------- // - - public static int getMaxPriority() { - return MAX_PRIORITY; - } - - public static boolean validatePriority( int pri ) { - return ( - ( pri >= MIN_PRIORITY ) || - ( pri <= MAX_PRIORITY ) - ); - } - - // Tasker has different package names for Play Store and non- versions - // for historical reasons - - public static String getInstalledTaskerPackage( Context context ) { - - String foundPackage = null; - - try { - context.getPackageManager().getPackageInfo( TASKER_PACKAGE, 0 ); - foundPackage = TASKER_PACKAGE; - } - catch ( PackageManager.NameNotFoundException e ) { - } - - try { - context.getPackageManager().getPackageInfo( TASKER_PACKAGE_MARKET, 0 ); - foundPackage = TASKER_PACKAGE_MARKET; - } - catch ( PackageManager.NameNotFoundException e ) { - } - - return foundPackage; - } - - // test we can send a TaskerIntent to Tasker - // use *before* sending an intent - // still need to test the *result after* sending intent - - public static Status testStatus( Context c ) { - - Status result; - - if ( ! taskerInstalled( c ) ) - result = Status.NotInstalled; - else if ( ! havePermission( c ) ) - result = Status.NoPermission; - else if ( ! TaskerIntent.prefSet( c, PROVIDER_COL_NAME_ENABLED ) ) - result = Status.NotEnabled; - else if ( ! TaskerIntent.prefSet( c, PROVIDER_COL_NAME_EXTERNAL_ACCESS ) ) - result = Status.AccessBlocked; - else if ( ! new TaskerIntent( "" ).receiverExists( c ) ) - result = Status.NoReceiver; - else - result = Status.OK; - - return result; - } - - // Check if Tasker installed - - public static boolean taskerInstalled( Context context ) { - return ( getInstalledTaskerPackage( context ) != null ); - } - - // Use with startActivity to retrieve Tasker from Android market - public static Intent getTaskerInstallIntent( boolean marketFlag ) { - - return new Intent( - Intent.ACTION_VIEW, - Uri.parse( - marketFlag ? - ( ( SDKVersion() == CUPCAKE_SDK_VERSION ) ? TASKER_MARKET_URL_CUPCAKE : TASKER_MARKET_URL ) : - TASKER_DOWNLOAD_URL - ) - ); - } - - public static int SDKVersion() { - try { - Field f = android.os.Build.VERSION.class.getField( "SDK_INT" ); - return f.getInt( null ); - } - catch ( Exception e ) { - return CUPCAKE_SDK_VERSION; - } - } - - public static IntentFilter getCompletionFilter( String taskName ) { - - IntentFilter filter = new IntentFilter( TaskerIntent.ACTION_TASK_COMPLETE ); - - filter.addDataScheme( TASK_NAME_DATA_SCHEME ); - filter.addDataPath( taskName, PatternMatcher.PATTERN_LITERAL ); - - return filter; - } - - public static Intent getTaskSelectIntent() { - return new Intent( ACTION_TASK_SELECT ). - setFlags( - Intent.FLAG_ACTIVITY_NO_USER_ACTION | - Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS | - Intent.FLAG_ACTIVITY_NO_HISTORY - ); - } - - // public access deprecated, use TaskerIntent.testSend() instead - - public static boolean havePermission( Context c ) { - return c.checkPermission( PERMISSION_RUN_TASKS, Process.myPid(), Process.myUid() ) == - PackageManager.PERMISSION_GRANTED; - } - - // Get an intent that will bring up the Tasker prefs screen with the External Access control(s) - // Probably you want to use startActivity or startActivityForResult with it - - public static Intent getExternalAccessPrefsIntent() { - return new Intent( ACTION_OPEN_PREFS ).putExtra( EXTRA_OPEN_PREFS_TAB_NO, MISC_PREFS_TAB_NO ); - } - - // ------------------------------------- INSTANCE METHODS ----------------------------- // - - public TaskerIntent() { - super( ACTION_TASK ); - setRandomData(); - putMetaExtras( getRandomString() ); - } - - public TaskerIntent( String taskName ) { - super( ACTION_TASK ); - setRandomData(); - putMetaExtras( taskName ); - } - - public TaskerIntent setTaskPriority( int priority ) { - - if ( validatePriority( priority ) ) - putExtra( EXTRA_TASK_PRIORITY, priority ); - else - Log.e( TAG, "priority out of range: " + MIN_PRIORITY + ":" + MAX_PRIORITY ); - - return this; - } - - // Sets subsequently %par1, %par2 etc - public TaskerIntent addParameter( String value ) { - - int index = 1; - - if ( getExtras().containsKey( EXTRA_VAR_NAMES_LIST ) ) - index = getExtras().getStringArrayList( EXTRA_VAR_NAMES_LIST ).size() + 1; - - Log.d(TAG, "index: " + index ); - - addLocalVariable( "%" + PARAM_VAR_NAME_PREFIX + index, value ); - - return this; - } - - // Arbitrary specification of (local) variable names and values - public TaskerIntent addLocalVariable( String name, String value ) { - - ArrayList names, values; - - if ( hasExtra( EXTRA_VAR_NAMES_LIST ) ) { - names = getStringArrayListExtra( EXTRA_VAR_NAMES_LIST ); - values = getStringArrayListExtra( EXTRA_VAR_VALUES_LIST ); - } - else { - names = new ArrayList(); - values = new ArrayList(); - - putStringArrayListExtra( EXTRA_VAR_NAMES_LIST, names ); - putStringArrayListExtra( EXTRA_VAR_VALUES_LIST, values ); - } - - names.add( name ); - values.add( value ); - - return this; - } - - public TaskerIntent addAction( int code ) { - - actionCount++; - argCount = 1; - - Bundle actionBundle = new Bundle(); - - actionBundle.putInt( ACTION_CODE, code ); - - // Add action bundle to intent - putExtra( EXTRA_ACTION_INDEX_PREFIX + Integer.toString( actionCount ), actionBundle ); - - return this; - } - - // string arg - public TaskerIntent addArg( String arg ) { - - Bundle b = getActionBundle(); - - if ( b != null ) - b.putString( ARG_INDEX_PREFIX + Integer.toString( argCount++ ), arg ); - - return this; - } - - // int arg - public TaskerIntent addArg( int arg ) { - Bundle b = getActionBundle(); - - if ( b != null ) - b.putInt( ARG_INDEX_PREFIX + Integer.toString( argCount++ ), arg ); - - return this; - } - - // boolean arg - public TaskerIntent addArg( boolean arg ) { - Bundle b = getActionBundle(); - - if ( b != null ) - b.putBoolean( ARG_INDEX_PREFIX + Integer.toString( argCount++ ), arg ); - - return this; - } - - // Application arg - public TaskerIntent addArg( String pkg, String cls ) { - Bundle b = getActionBundle(); - - if ( b != null ) { - StringBuilder builder = new StringBuilder(); - builder.append( APP_ARG_PREFIX ). - append( pkg ). append( "," ). append( cls ); - b.putString( ARG_INDEX_PREFIX + Integer.toString( argCount++ ), b.toString() ); - } - - return this; - } - - public IntentFilter getCompletionFilter() { - return getCompletionFilter( getTaskName() ); - } - - public String getTaskName() { - return getStringExtra( EXTRA_TASK_NAME ); - } - - public boolean receiverExists( Context context ) { - List recs = context.getPackageManager().queryBroadcastReceivers( this, 0 ); - return ( - ( recs != null ) && - ( recs.size() > 0 ) - ); - } - - // -------------------- PRIVATE METHODS -------------------- // - - private String getRandomString() { - return Long.toString( rand.nextLong() ); - } - - // so that if multiple TaskerIntents are used in PendingIntents there's virtually no - // clash chance - private void setRandomData() { - setData( Uri.parse( TASK_ID_SCHEME + ":" + getRandomString() ) ); - } - - private Bundle getActionBundle() { - - Bundle toReturn = null; - - if ( argCount > MAX_NO_ARGS ) - Log.e( TAG, "maximum number of arguments exceeded (" + MAX_NO_ARGS + ")" ); - else { - String key = EXTRA_ACTION_INDEX_PREFIX + Integer.toString( actionCount ); - - if ( this.hasExtra( key ) ) - toReturn = getBundleExtra( key ); - else - Log.e( TAG, "no actions added yet" ); - } - - return toReturn; - } - - private void putMetaExtras( String taskName ) { - putExtra( EXTRA_INTENT_VERSION_NUMBER, INTENT_VERSION_NUMBER ); - putExtra( EXTRA_TASK_NAME, taskName ); - } - - // for testing that Tasker is enabled and external access is allowed - - private static boolean prefSet( Context context, String col ) { - - String [] proj = new String [] { col }; - - Cursor c = context.getContentResolver().query( Uri.parse( TASKER_PREFS_URI ), proj, null, null, null ); - - boolean acceptingFlag = false; - - if ( c == null ) - Log.w( TAG, "no cursor for " + TASKER_PREFS_URI ); - else { - c.moveToFirst(); - - if ( Boolean.TRUE.toString().equals( c.getString( 0 ) ) ) - acceptingFlag = true; - - c.close(); - } - - return acceptingFlag; - } -} \ No newline at end of file diff --git a/build.gradle b/build.gradle index 8585242..e4467f8 100644 --- a/build.gradle +++ b/build.gradle @@ -4,7 +4,7 @@ buildscript { jcenter() } dependencies { - classpath 'com.android.tools.build:gradle:3.0.0' + classpath 'com.android.tools.build:gradle:3.0.1' } } From ea1c1278d3f40a46d8cad438c106ee79bb89e16b Mon Sep 17 00:00:00 2001 From: Mikhail Basov Date: Thu, 30 Nov 2017 21:00:59 +0300 Subject: [PATCH 004/267] Move build configuration from Manifest to Gradle --- app/build.gradle | 6 ++---- app/src/main/AndroidManifest.xml | 6 +----- 2 files changed, 3 insertions(+), 9 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index 5aebcf8..7af3284 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -8,10 +8,8 @@ android { applicationId "net.basov.web" minSdkVersion 17 targetSdkVersion 21 - compileOptions { - sourceCompatibility JavaVersion.VERSION_1_7 - targetCompatibility JavaVersion.VERSION_1_7 - } + versionCode 10 + versionName "00.00.10" } buildTypes { diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 0c2b8e6..1805211 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -1,7 +1,6 @@ + package="net.basov.web"> - - - From a7be7b53d7f4f523a22d5fb8bba44dfda269f8a2 Mon Sep 17 00:00:00 2001 From: Mikhail Basov Date: Thu, 30 Nov 2017 22:03:38 +0300 Subject: [PATCH 005/267] Actual README --- README.md | 19 ++++++------------- import-summary.txt | 38 -------------------------------------- 2 files changed, 6 insertions(+), 51 deletions(-) delete mode 100644 import-summary.txt diff --git a/README.md b/README.md index 2bd629e..4c0a905 100644 --- a/README.md +++ b/README.md @@ -1,17 +1,10 @@ -Webserver for Android -===================== +### Lightweight Web Serwer (lWS) -Smallest webserver for android. Works only when connected to a wifi-network. Use at your own risk and feel free to contribute :-) +Simple as possible. Lightweight as possible. Open source. +This project based on [another open source project](https://github.com/bodeme/androidwebserver) +Unfortunately, original project didn't maintened for 3 years. -Twitter: [@bodeme](https://twitter.com/bodeme) +### License +lWS is licensed under the [GPLv3 License](COPYING) because original project -License -======= -Android Webserver is licensed under the [GPLv3 License](COPYING). -Features -======== -* GET-Requests -* Handling of ASCII and BINARY Files -* Tasker: List all tasks (http://example.org/tasker/) -* Tasker: Execute task (http://example.org/tasker/taskname) diff --git a/import-summary.txt b/import-summary.txt deleted file mode 100644 index 385927f..0000000 --- a/import-summary.txt +++ /dev/null @@ -1,38 +0,0 @@ -ECLIPSE ANDROID PROJECT IMPORT SUMMARY -====================================== - -Ignored Files: --------------- -The following files were *not* copied into the new Gradle project; you -should evaluate whether these are still needed in your project and if -so manually move them: - -* .gitignore -* LICENSE -* README.md -* default.properties -* ic_launcher-web.png - -Moved Files: ------------- -Android Gradle projects use a different directory structure than ADT -Eclipse projects. Here's how the projects were restructured: - -* AndroidManifest.xml => app/src/main/AndroidManifest.xml -* res/ => app/src/main/res/ -* src/ => app/src/main/java/ - -Next Steps: ------------ -You can now build the project. The Gradle project needs network -connectivity to download dependencies. - -Bugs: ------ -If for some reason your project does not build, and you determine that -it is due to a bug or limitation of the Eclipse to Gradle importer, -please file a bug at http://b.android.com with category -Component-Tools. - -(This import summary is for your information only, and can be deleted -after import once you are satisfied with the results.) From 27228d1565665f035b76d97a0f0dd8500ce2cff0 Mon Sep 17 00:00:00 2001 From: Mikhail Basov Date: Thu, 30 Nov 2017 23:24:27 +0300 Subject: [PATCH 006/267] Move rc codes and header strings to resources --- .../java/net/basov/web/ServerHandler.java | 77 +++++++++++-------- app/src/main/res/values/strings.xml | 16 ++++ 2 files changed, 61 insertions(+), 32 deletions(-) diff --git a/app/src/main/java/net/basov/web/ServerHandler.java b/app/src/main/java/net/basov/web/ServerHandler.java index 6630542..6e7b0ca 100644 --- a/app/src/main/java/net/basov/web/ServerHandler.java +++ b/app/src/main/java/net/basov/web/ServerHandler.java @@ -77,9 +77,11 @@ public void run() { } private void send(String text) { - String header = getHeaderBase(); - header = header.replace("%code%", "200 ok"); - header = header.replace("%length%", "" + text.length()); + String header = context.getString(R.string.header, + context.getString(R.string.rc200), + text.length(), + "text/html" + ); try { out = new PrintWriter(toClient.getOutputStream(), true); out.print(header); @@ -88,11 +90,12 @@ private void send(String text) { Server.remove(toClient); toClient.close(); } catch (Exception e) { - + } } private void showHtml(String dokument) { + Integer rc = 200; // Standard-Doc if (dokument.equals("")) { dokument = "index.html"; @@ -100,6 +103,7 @@ private void showHtml(String dokument) { // Don't allow directory traversal if (dokument.indexOf("..") != -1) { + rc = 403; dokument = "403.html"; } @@ -110,31 +114,26 @@ private void showHtml(String dokument) { if(dokument.charAt(dokument.length()-1) == '/') { dokument = documentRoot + "404.html"; + rc = 404; } - String header = getHeaderBase(); - header = header.replace("%code%", "403 Forbidden"); - try { File f = new File(dokument); if (!f.exists()) { - header = getHeaderBase(); - header = header.replace("%code%", "404 File not found"); - dokument = "404.html"; + dokument = documentRoot + "404.html"; + rc = 404; } } catch (Exception e) {} - if (!dokument.equals(documentRoot + "403.html")) { - header = getHeaderBase().replace("%code%", "200 OK"); - } - Log.d("Webserver", "Serving " + dokument); try { File f = new File(dokument); if (f.exists()) { - BufferedInputStream in = new BufferedInputStream(new FileInputStream(dokument)); + Log.d("Webserver", "Send " + dokument + ", rc:" + rc); + + BufferedInputStream in = new BufferedInputStream(new FileInputStream(dokument)); BufferedOutputStream out = new BufferedOutputStream(toClient.getOutputStream()); ByteArrayOutputStream tempOut = new ByteArrayOutputStream(); @@ -145,20 +144,42 @@ private void showHtml(String dokument) { } tempOut.flush(); - header = header.replace("%length%", ""+tempOut.size()); + String rcStr; + switch (rc) { + case 404: + rcStr = context.getString(R.string.rc404); + break; + case 403: + rcStr = context.getString(R.string.rc403); + break; + case 200: + rcStr = context.getString(R.string.rc200); + break; + default: + rcStr = context.getString(R.string.rc500); + break; + } + + String header = context.getString(R.string.header, + rcStr, + tempOut.size(), + "text/html" + ); out.write(header.getBytes()); out.write(tempOut.toByteArray()); out.flush(); } else { - // Send HTML-File (Ascii, not as a stream) - header = getHeaderBase(); - header = header.replace("%code%", "404 File not found"); - header = header.replace("%length%", ""+"404 - File not Found".length()); - out = new PrintWriter(toClient.getOutputStream(), true); - out.print(header); - out.print("404 - File not Found"); - out.flush(); + String rc404 = context.getString(R.string.rc404); + String header = context.getString(R.string.header, + rc404, + rc404.length(), + "text/html" + ); + out = new PrintWriter(toClient.getOutputStream(), true); + out.print(header); + out.print(rc404); + out.flush(); } Server.remove(toClient); @@ -167,12 +188,4 @@ private void showHtml(String dokument) { } } - - private String getHeaderBase() { - return "HTTP/1.1 %code%\n"+ - "Server: AndroidWebserver/1.0\n"+ - "Content-Length: %length%\n"+ - "Connection: close\n"+ - "Content-Type: text/html; charset=utf-8\n\n"; - } } diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index ad79dd1..e629ee6 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -2,4 +2,20 @@ Smallest Webserver for Android Webserver for Android + + + 500 Internal server error + 404 File not found + 403 Forbidden + 200 OK From e849da835f9e8a81da00f9481240df43a46d371c Mon Sep 17 00:00:00 2001 From: Mikhail Basov Date: Fri, 1 Dec 2017 13:29:37 +0300 Subject: [PATCH 007/267] Correct misstype in README --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 4c0a905..3d5647a 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -### Lightweight Web Serwer (lWS) +### Lightweight Web Server (lWS) Simple as possible. Lightweight as possible. Open source. This project based on [another open source project](https://github.com/bodeme/androidwebserver) From 29b6b90a9db6508be8d3c9a72abb56cfa830c7c1 Mon Sep 17 00:00:00 2001 From: Mikhail Basov Date: Fri, 1 Dec 2017 14:21:53 +0300 Subject: [PATCH 008/267] Tweak notification message format --- README.md | 2 +- app/src/main/java/net/basov/web/ServerService.java | 4 ++-- .../res/drawable-anydpi-v21/ic_http_black_24dp.xml | 14 ++++++++++++++ app/src/main/res/values/strings.xml | 4 ++-- 4 files changed, 19 insertions(+), 5 deletions(-) create mode 100644 app/src/main/res/drawable-anydpi-v21/ic_http_black_24dp.xml diff --git a/README.md b/README.md index 3d5647a..7d02db3 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -### Lightweight Web Server (lWS) +### lightweight Web Server (lWS) Simple as possible. Lightweight as possible. Open source. This project based on [another open source project](https://github.com/bodeme/androidwebserver) diff --git a/app/src/main/java/net/basov/web/ServerService.java b/app/src/main/java/net/basov/web/ServerService.java index c221ccb..3002e7c 100644 --- a/app/src/main/java/net/basov/web/ServerService.java +++ b/app/src/main/java/net/basov/web/ServerService.java @@ -78,7 +78,7 @@ public void startServer(Handler handler, String documentRoot, int port) { Intent i = new Intent(this, StartActivity.class); PendingIntent contentIntent = PendingIntent.getActivity(this, 0, i, 0); - updateNotifiction("Webserver is running on port " + ipAddress + ":" + port); + updateNotifiction("Running on " + ipAddress + ":" + port); Message msg = new Message(); Bundle b = new Bundle(); @@ -113,7 +113,7 @@ public void updateNotifiction(String message) { PendingIntent contentIntent = PendingIntent.getActivity(this, 0, new Intent(this, StartActivity.class), 0); notification = new Notification.Builder(this) - .setSmallIcon(R.drawable.ic_launcher) + .setSmallIcon(R.drawable.ic_http_black_24dp) .setLargeIcon(BitmapFactory.decodeResource(getResources(), R.drawable.ic_launcher)) .setContentTitle(getString(R.string.app_name)) .setContentText(text) diff --git a/app/src/main/res/drawable-anydpi-v21/ic_http_black_24dp.xml b/app/src/main/res/drawable-anydpi-v21/ic_http_black_24dp.xml new file mode 100644 index 0000000..920170f --- /dev/null +++ b/app/src/main/res/drawable-anydpi-v21/ic_http_black_24dp.xml @@ -0,0 +1,14 @@ + + + + diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index e629ee6..2130cc4 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -1,7 +1,7 @@ - Smallest Webserver for Android - Webserver for Android + lightweight Web Server (lWG) for Android + lightweight Web Server (lWS) - diff --git a/app/src/main/res/layout/main.xml b/app/src/main/res/layout/main.xml index e65cf97..a573ae3 100644 --- a/app/src/main/res/layout/main.xml +++ b/app/src/main/res/layout/main.xml @@ -12,28 +12,27 @@ android:padding="10dp" android:text="@string/hello" /> - + - + + - - - - + + From ee2ab96a0d20548cc8491fe566650e7c93ddd520 Mon Sep 17 00:00:00 2001 From: Mikhail Basov Date: Fri, 1 Dec 2017 21:12:36 +0300 Subject: [PATCH 013/267] Auto generate apk name. Downgrade gradle to 2.3.3. --- app/build.gradle | 54 ++++++++++++++++++++++++++++++++++++++++++++++++ build.gradle | 2 +- 2 files changed, 55 insertions(+), 1 deletion(-) diff --git a/app/build.gradle b/app/build.gradle index 7af3284..c6cf73e 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -1,6 +1,21 @@ apply plugin: 'com.android.application' android { + def last_tag = getGitRevParseInfo("describe --tags --abbrev=0") + def commit_count = getGitRevParseInfo("rev-list --count ${last_tag}..") + def current_commit = getGitRevParseInfo("rev-parse --short") + + applicationVariants.all { variant -> + variant.outputs.each { output -> + def outputFile = output.outputFile + if (outputFile != null && outputFile.name.endsWith('.apk')) { + def fileName = "lWS." + versionName + ".apk" + output.outputFile = new File(outputFile.parent, fileName) + } + } + + } + compileSdkVersion 25 buildToolsVersion "26.0.2" @@ -12,10 +27,49 @@ android { versionName "00.00.10" } + signingConfigs { + release { + keyAlias 'mvb_key' + storeFile file('../../.keys/mvb-release.keystore') + v2SigningEnabled false + } + debug { + storeFile file('../../.keys/mvb-debug.keystore') + keyAlias 'androiddebugkey' + keyPassword 'android' + storePassword 'android' + } + } + buildTypes { release { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt' + zipAlignEnabled true + applicationIdSuffix '.r' + versionNameSuffix "r-g" + current_commit + resValue "string", "git_describe", getGitRevParseInfo("describe --tags --abbrev=1") + signingConfig signingConfigs.release + } + betta { + applicationIdSuffix '.b' + versionNameSuffix "b-g" + current_commit + debuggable true + resValue "string", "git_describe", getGitRevParseInfo("describe --tags --abbrev=1") + signingConfig signingConfigs.debug + } + debug { + debuggable true + versionNameSuffix 'a-' + commit_count + "-g" + current_commit + resValue "string", "git_describe", getGitRevParseInfo("describe --tags --abbrev=1") + signingConfig signingConfigs.debug } } } + +def getGitRevParseInfo (what) { + def cmd = "git " + what + " HEAD" + def proc = cmd.execute () + proc.text.trim () +} + diff --git a/build.gradle b/build.gradle index e4467f8..8674409 100644 --- a/build.gradle +++ b/build.gradle @@ -4,7 +4,7 @@ buildscript { jcenter() } dependencies { - classpath 'com.android.tools.build:gradle:3.0.1' + classpath 'com.android.tools.build:gradle:2.3.3' } } From eb4702e6b60c2c0957e97484d1ccda81952f6768 Mon Sep 17 00:00:00 2001 From: Mikhail Basov Date: Fri, 1 Dec 2017 21:26:08 +0300 Subject: [PATCH 014/267] Bump version to v00.01.00b --- app/build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index c6cf73e..f030b19 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -23,8 +23,8 @@ android { applicationId "net.basov.web" minSdkVersion 17 targetSdkVersion 21 - versionCode 10 - versionName "00.00.10" + versionCode 100 + versionName "00.01.00" } signingConfigs { From 844626f0c00ab0672e083c3d267e6a884ed525c5 Mon Sep 17 00:00:00 2001 From: Mikhail Basov Date: Fri, 1 Dec 2017 21:39:16 +0300 Subject: [PATCH 015/267] Fix 0 content length --- .../java/net/basov/web/ServerHandler.java | 21 +++++++++---------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/app/src/main/java/net/basov/web/ServerHandler.java b/app/src/main/java/net/basov/web/ServerHandler.java index 0b01198..da5bf74 100644 --- a/app/src/main/java/net/basov/web/ServerHandler.java +++ b/app/src/main/java/net/basov/web/ServerHandler.java @@ -132,6 +132,7 @@ private void showHtml(String dokument) { try { String rcStr; String header; + String contType; ByteArrayOutputStream tempOut = new ByteArrayOutputStream(); BufferedOutputStream outStream = new BufferedOutputStream(toClient.getOutputStream()); BufferedInputStream in; @@ -143,11 +144,7 @@ private void showHtml(String dokument) { rcStr = context.getString(R.string.rc200); - header = context.getString(R.string.header, - rcStr, - tempOut.size(), - getMIMETypeForDocument(dokument) - ); + contType = getMIMETypeForDocument(dokument); } else { String errAsset = ""; AssetManager am = context.getAssets(); @@ -166,14 +163,9 @@ private void showHtml(String dokument) { break; } + contType = "text/html"; in = new BufferedInputStream(am.open(errAsset)); - header = context.getString(R.string.header, - rcStr, - tempOut.size(), - "text/html" - ); - } byte[] buf = new byte[4096]; @@ -184,6 +176,13 @@ private void showHtml(String dokument) { tempOut.flush(); + header = context.getString(R.string.header, + rcStr, + tempOut.size(), + contType + ); + + outStream.write(header.getBytes()); outStream.write(tempOut.toByteArray()); outStream.flush(); From 9efcd5f20c469ee014d96d93a45be72ad1034a26 Mon Sep 17 00:00:00 2001 From: Mikhail Basov Date: Fri, 1 Dec 2017 21:41:42 +0300 Subject: [PATCH 016/267] Label fix commit as v00.01.01 --- app/build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index f030b19..c36ca7d 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -23,8 +23,8 @@ android { applicationId "net.basov.web" minSdkVersion 17 targetSdkVersion 21 - versionCode 100 - versionName "00.01.00" + versionCode 101 + versionName "00.01.01" } signingConfigs { From 020745a7203485c33c93a964d46e9f3a2428a804 Mon Sep 17 00:00:00 2001 From: "Mikhail Basov(xmi5s)" Date: Mon, 18 Dec 2017 00:40:36 +0300 Subject: [PATCH 017/267] Force notification to represent service state Issue when user swipe task not solved. --- app/src/main/AndroidManifest.xml | 7 ++- .../java/net/basov/web/ServerService.java | 28 ++++++--- .../java/net/basov/web/StartActivity.java | 57 +++++++++++-------- 3 files changed, 57 insertions(+), 35 deletions(-) diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 006d9e4..8c31a33 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -4,14 +4,17 @@ + android:label="@string/app_name" + android:launchMode="singleInstance"> - + diff --git a/app/src/main/java/net/basov/web/ServerService.java b/app/src/main/java/net/basov/web/ServerService.java index 9026e67..a6bdeb5 100644 --- a/app/src/main/java/net/basov/web/ServerService.java +++ b/app/src/main/java/net/basov/web/ServerService.java @@ -49,8 +49,7 @@ public class ServerService extends Service { @Override public void onCreate() { - mNM = (NotificationManager)getSystemService(NOTIFICATION_SERVICE); - showNotification(); + mNM = (NotificationManager)getSystemService(NOTIFICATION_SERVICE); } private void showNotification() { @@ -73,10 +72,6 @@ public void startServer(Handler handler, String documentRoot, int port) { server = new Server(handler, documentRoot, ipAddress, port, getApplicationContext()); server.start(); - - Intent i = new Intent(this, StartActivity.class); - PendingIntent contentIntent = PendingIntent.getActivity(this, 0, i, 0); - updateNotifiction("Running on " + ipAddress + ":" + port); Message msg = new Message(); @@ -100,14 +95,16 @@ public static String intToIp(int i) { } public void stopServer() { + isRunning = false; + mNM.cancel(NOTIFICATION_ID); if(null != server) { server.stopServer(); - server.interrupt(); - isRunning = false; + server.interrupt(); } } public void updateNotifiction(String message) { + if(null == message || message.length()==0) return; CharSequence text = message; PendingIntent contentIntent = PendingIntent.getActivity(this, 0, new Intent(this, StartActivity.class), 0); @@ -139,4 +136,19 @@ ServerService getService() { public boolean isRunning() { return isRunning; } + + @Override + public void onDestroy() { + stopServer(); + stopSelf(); + super.onDestroy(); + } + + @Override + public void onTaskRemoved(Intent rootIntent) { + stopServer(); + stopSelf(); + super.onTaskRemoved(rootIntent); + } + } diff --git a/app/src/main/java/net/basov/web/StartActivity.java b/app/src/main/java/net/basov/web/StartActivity.java index c127ab1..438487c 100644 --- a/app/src/main/java/net/basov/web/StartActivity.java +++ b/app/src/main/java/net/basov/web/StartActivity.java @@ -54,6 +54,8 @@ public class StartActivity extends Activity { private String lastMessage = ""; private ServerService mBoundService; + + private ServiceConnection mConnection; final Handler mHandler = new Handler() { @Override @@ -110,8 +112,33 @@ public void onClick(View arg0) { } } }); - - doBindService(); + + mConnection = new ServiceConnection() { + public void onServiceConnected(ComponentName className, IBinder service) { + mBoundService = ((ServerService.LocalBinder)service).getService(); + Toast.makeText(StartActivity.this, "Service connected", Toast.LENGTH_SHORT).show(); + mBoundService.updateNotifiction(lastMessage); + + mToggleButton.setChecked(mBoundService.isRunning()); + } + + public void onServiceDisconnected(ComponentName className) { + mBoundService = null; + Toast.makeText(StartActivity.this, "Service disconnected", Toast.LENGTH_SHORT).show(); + } + }; + + doBindService(); + + if(mBoundService != null) + mToggleButton.setChecked(mBoundService.isRunning()); + } + + private void doUnbindService() { + if (mBoundService != null) { + getApplicationContext().unbindService(mConnection); + } + } public static void log( String s ) { @@ -135,40 +162,20 @@ private void stopServer() { } } - private ServiceConnection mConnection = new ServiceConnection() { - public void onServiceConnected(ComponentName className, IBinder service) { - mBoundService = ((ServerService.LocalBinder)service).getService(); - Toast.makeText(StartActivity.this, "Service connected", Toast.LENGTH_SHORT).show(); - mBoundService.updateNotifiction(lastMessage); - - mToggleButton.setChecked(mBoundService.isRunning()); - } - - public void onServiceDisconnected(ComponentName className) { - mBoundService = null; - Toast.makeText(StartActivity.this, "Service disconnected", Toast.LENGTH_SHORT).show(); - } - }; - - private void doUnbindService() { - if (mBoundService != null) { - unbindService(mConnection); - } - } - private void doBindService() { - bindService(new Intent(StartActivity.this, ServerService.class), mConnection, Context.BIND_AUTO_CREATE); + getApplicationContext().bindService(new Intent(StartActivity.this, ServerService.class), mConnection, Context.BIND_AUTO_CREATE); } @Override protected void onDestroy() { + doUnbindService(); super.onDestroy(); - doUnbindService(); } @Override protected void onResume() { super.onResume(); + doBindService(); } private String getDocRoot() { From e2ffa0d446655ba08b985908497cef0b36161682 Mon Sep 17 00:00:00 2001 From: Mikhail Basov Date: Mon, 18 Dec 2017 00:54:35 +0300 Subject: [PATCH 018/267] Refirmat code after mobile development session --- app/src/main/AndroidManifest.xml | 6 +-- .../java/net/basov/web/ServerService.java | 32 ++++++------ .../java/net/basov/web/StartActivity.java | 52 +++++++++---------- 3 files changed, 45 insertions(+), 45 deletions(-) diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 8c31a33..4a4b41c 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -5,7 +5,7 @@ + android:launchMode="singleInstance"> @@ -13,8 +13,8 @@ + android:exported="false" + android:stopWithTask="false"/> diff --git a/app/src/main/java/net/basov/web/ServerService.java b/app/src/main/java/net/basov/web/ServerService.java index a6bdeb5..cb8a868 100644 --- a/app/src/main/java/net/basov/web/ServerService.java +++ b/app/src/main/java/net/basov/web/ServerService.java @@ -95,8 +95,8 @@ public static String intToIp(int i) { } public void stopServer() { - isRunning = false; - mNM.cancel(NOTIFICATION_ID); + isRunning = false; + mNM.cancel(NOTIFICATION_ID); if(null != server) { server.stopServer(); server.interrupt(); @@ -104,7 +104,7 @@ public void stopServer() { } public void updateNotifiction(String message) { - if(null == message || message.length()==0) return; + if(null == message || message.length()==0) return; CharSequence text = message; PendingIntent contentIntent = PendingIntent.getActivity(this, 0, new Intent(this, StartActivity.class), 0); @@ -137,18 +137,18 @@ public boolean isRunning() { return isRunning; } - @Override - public void onDestroy() { - stopServer(); - stopSelf(); - super.onDestroy(); - } - - @Override - public void onTaskRemoved(Intent rootIntent) { - stopServer(); - stopSelf(); - super.onTaskRemoved(rootIntent); - } + @Override + public void onDestroy() { + stopServer(); + stopSelf(); + super.onDestroy(); + } + + @Override + public void onTaskRemoved(Intent rootIntent) { + stopServer(); + stopSelf(); + super.onTaskRemoved(rootIntent); + } } diff --git a/app/src/main/java/net/basov/web/StartActivity.java b/app/src/main/java/net/basov/web/StartActivity.java index 438487c..28a7681 100644 --- a/app/src/main/java/net/basov/web/StartActivity.java +++ b/app/src/main/java/net/basov/web/StartActivity.java @@ -54,8 +54,8 @@ public class StartActivity extends Activity { private String lastMessage = ""; private ServerService mBoundService; - - private ServiceConnection mConnection; + + private ServiceConnection mConnection; final Handler mHandler = new Handler() { @Override @@ -112,33 +112,33 @@ public void onClick(View arg0) { } } }); - - mConnection = new ServiceConnection() { - public void onServiceConnected(ComponentName className, IBinder service) { - mBoundService = ((ServerService.LocalBinder)service).getService(); - Toast.makeText(StartActivity.this, "Service connected", Toast.LENGTH_SHORT).show(); - mBoundService.updateNotifiction(lastMessage); - - mToggleButton.setChecked(mBoundService.isRunning()); - } - - public void onServiceDisconnected(ComponentName className) { - mBoundService = null; - Toast.makeText(StartActivity.this, "Service disconnected", Toast.LENGTH_SHORT).show(); - } - }; - - doBindService(); - - if(mBoundService != null) - mToggleButton.setChecked(mBoundService.isRunning()); + + mConnection = new ServiceConnection() { + public void onServiceConnected(ComponentName className, IBinder service) { + mBoundService = ((ServerService.LocalBinder)service).getService(); + Toast.makeText(StartActivity.this, "Service connected", Toast.LENGTH_SHORT).show(); + mBoundService.updateNotifiction(lastMessage); + + mToggleButton.setChecked(mBoundService.isRunning()); + } + + public void onServiceDisconnected(ComponentName className) { + mBoundService = null; + Toast.makeText(StartActivity.this, "Service disconnected", Toast.LENGTH_SHORT).show(); + } + }; + + doBindService(); + + if(mBoundService != null) + mToggleButton.setChecked(mBoundService.isRunning()); } - + private void doUnbindService() { if (mBoundService != null) { getApplicationContext().unbindService(mConnection); } - + } public static void log( String s ) { @@ -168,14 +168,14 @@ private void doBindService() { @Override protected void onDestroy() { - doUnbindService(); + doUnbindService(); super.onDestroy(); } @Override protected void onResume() { super.onResume(); - doBindService(); + doBindService(); } private String getDocRoot() { From 3530089141afaafa9098d526f92ba5273ee4142a Mon Sep 17 00:00:00 2001 From: Mikhail Basov Date: Mon, 18 Dec 2017 15:28:12 +0300 Subject: [PATCH 019/267] Move app. global constants to separate class --- app/src/main/java/net/basov/web/Constants.java | 10 ++++++++++ app/src/main/java/net/basov/web/Server.java | 6 ++++-- app/src/main/java/net/basov/web/ServerHandler.java | 8 +++++--- app/src/main/java/net/basov/web/ServerService.java | 5 +++-- app/src/main/java/net/basov/web/StartActivity.java | 8 +++++--- 5 files changed, 27 insertions(+), 10 deletions(-) create mode 100644 app/src/main/java/net/basov/web/Constants.java diff --git a/app/src/main/java/net/basov/web/Constants.java b/app/src/main/java/net/basov/web/Constants.java new file mode 100644 index 0000000..01719a0 --- /dev/null +++ b/app/src/main/java/net/basov/web/Constants.java @@ -0,0 +1,10 @@ +package net.basov.web; + +/** + * Created by mvb on 12/18/17. + */ + +public final class Constants { + public static final String LOG_TAG = "lWS"; + public static final int NOTIFICATION_ID = 690927; +} diff --git a/app/src/main/java/net/basov/web/Server.java b/app/src/main/java/net/basov/web/Server.java index 264c1fb..bce160f 100644 --- a/app/src/main/java/net/basov/web/Server.java +++ b/app/src/main/java/net/basov/web/Server.java @@ -33,6 +33,8 @@ import android.os.Message; import android.util.Log; +import static net.basov.web.Constants.*; + public class Server extends Thread { private ServerSocket listener = null; private boolean running = true; @@ -63,7 +65,7 @@ public void run() { clientList.add(client); } catch (IOException e) { send(e.getMessage()); - Log.e("Webserver", e.getMessage()); + Log.e(LOG_TAG, e.getMessage()); } } } @@ -74,7 +76,7 @@ public void stopServer() { listener.close(); } catch (IOException e) { send(e.getMessage()); - Log.e("Webserver", e.getMessage()); + Log.e("lWS", e.getMessage()); } } diff --git a/app/src/main/java/net/basov/web/ServerHandler.java b/app/src/main/java/net/basov/web/ServerHandler.java index da5bf74..e28775e 100644 --- a/app/src/main/java/net/basov/web/ServerHandler.java +++ b/app/src/main/java/net/basov/web/ServerHandler.java @@ -36,6 +36,8 @@ import android.content.res.AssetManager; import android.util.Log; +import static net.basov.web.Constants.*; + class ServerHandler extends Thread { private BufferedReader in; private PrintWriter out; @@ -111,7 +113,7 @@ private void showHtml(String dokument) { // Search for files in docroot dokument = documentRoot + dokument; - Log.d("Webserver", "Got " + dokument); + Log.d(LOG_TAG, "Got " + dokument); dokument = dokument.replaceAll("[/]+","/"); // This is directory @@ -127,7 +129,7 @@ private void showHtml(String dokument) { } catch (Exception e) {} - Log.d("lWS", "Serving " + dokument); + Log.d(LOG_TAG, "Serving " + dokument); try { String rcStr; @@ -138,7 +140,7 @@ private void showHtml(String dokument) { BufferedInputStream in; if (rc == 200) { - Log.d("lWS", "Send " + dokument + ", rc:" + rc); + Log.d(LOG_TAG, "Send " + dokument + ", rc:" + rc); in = new BufferedInputStream(new FileInputStream(dokument)); diff --git a/app/src/main/java/net/basov/web/ServerService.java b/app/src/main/java/net/basov/web/ServerService.java index cb8a868..700a085 100644 --- a/app/src/main/java/net/basov/web/ServerService.java +++ b/app/src/main/java/net/basov/web/ServerService.java @@ -38,9 +38,10 @@ import android.os.Message; import android.util.Log; +import static net.basov.web.Constants.*; + public class ServerService extends Service { - private int NOTIFICATION_ID = 4711; private NotificationManager mNM; private String message; private Notification notification; @@ -82,7 +83,7 @@ public void startServer(Handler handler, String documentRoot, int port) { } catch (Exception e) { isRunning = false; - Log.e("Webserver", e.getMessage()); + Log.e(LOG_TAG, e.getMessage()); updateNotifiction("Error: " + e.getMessage()); } } diff --git a/app/src/main/java/net/basov/web/StartActivity.java b/app/src/main/java/net/basov/web/StartActivity.java index 28a7681..f580e3b 100644 --- a/app/src/main/java/net/basov/web/StartActivity.java +++ b/app/src/main/java/net/basov/web/StartActivity.java @@ -44,6 +44,8 @@ import android.widget.Toast; import android.widget.ToggleButton; +import static net.basov.web.Constants.*; + public class StartActivity extends Activity { private ToggleButton mToggleButton; private EditText port; @@ -81,7 +83,7 @@ public void onCreate(Bundle savedInstanceState) { try { if (!(new File(documentRoot)).exists()) { (new File(documentRoot)).mkdir(); - Log.d("Webserver", "Created " + documentRoot); + Log.d(LOG_TAG, "Created " + documentRoot); BufferedWriter bout = new BufferedWriter(new FileWriter(documentRoot + "index.html")); bout.write("lightweight WebServer"); bout.write(""); @@ -91,10 +93,10 @@ public void onCreate(Bundle savedInstanceState) { bout.write(""); bout.flush(); bout.close(); - Log.d("lWS", "Created html files"); + Log.d(LOG_TAG, "Created html files"); } } catch (Exception e) { - Log.v("ERROR",e.getMessage()); + Log.v(LOG_TAG,e.getMessage()); } log(""); From 9f22fece3d4b90821a93c6b357473508e7f90abc Mon Sep 17 00:00:00 2001 From: Mikhail Basov Date: Mon, 18 Dec 2017 20:17:40 +0300 Subject: [PATCH 020/267] Add preferences. --- app/src/main/AndroidManifest.xml | 10 ++ .../main/java/net/basov/web/Constants.java | 20 ++++ .../net/basov/web/PreferencesActivity.java | 89 +++++++++++++++++ .../java/net/basov/web/ServerService.java | 11 +-- .../java/net/basov/web/StartActivity.java | 99 ++++++++++++++++--- app/src/main/res/layout/main.xml | 40 +++++++- app/src/main/res/values/strings.xml | 5 +- app/src/main/res/xml/preferences.xml | 14 +++ 8 files changed, 265 insertions(+), 23 deletions(-) create mode 100644 app/src/main/java/net/basov/web/PreferencesActivity.java create mode 100644 app/src/main/res/xml/preferences.xml diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 4a4b41c..16b733a 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -12,6 +12,16 @@ + + + + + + + + diff --git a/app/src/main/java/net/basov/web/Constants.java b/app/src/main/java/net/basov/web/Constants.java index 01719a0..83fc936 100644 --- a/app/src/main/java/net/basov/web/Constants.java +++ b/app/src/main/java/net/basov/web/Constants.java @@ -1,3 +1,22 @@ +/* + * Copyright (C) 2017 Mikhail Basov + * + * Licensed under the GNU General Public License v3 + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ package net.basov.web; /** @@ -7,4 +26,5 @@ public final class Constants { public static final String LOG_TAG = "lWS"; public static final int NOTIFICATION_ID = 690927; + public static final int PREFERENCES_REQUEST = 653; } diff --git a/app/src/main/java/net/basov/web/PreferencesActivity.java b/app/src/main/java/net/basov/web/PreferencesActivity.java new file mode 100644 index 0000000..3cdcb5d --- /dev/null +++ b/app/src/main/java/net/basov/web/PreferencesActivity.java @@ -0,0 +1,89 @@ +/* + * Copyright (C) 2017 Mikhail Basov + * + * Licensed under the GNU General Public License v3 + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ +package net.basov.web; + +/** + * Created by mvb on 6/22/17. + */ + +import android.content.SharedPreferences; +import android.os.Bundle; +import android.preference.Preference; +import android.preference.PreferenceActivity; +import android.preference.PreferenceManager; + +public class PreferencesActivity extends PreferenceActivity implements + SharedPreferences.OnSharedPreferenceChangeListener { + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + addPreferencesFromResource(R.xml.preferences); + + SharedPreferences defSharedPref = PreferenceManager.getDefaultSharedPreferences(this); + + Preference prefDocumetRoot = findPreference(getString(R.string.pk_document_root)); + prefDocumetRoot.setSummary(defSharedPref.getString(getString(R.string.pk_document_root), "")); + + Preference prefPort = findPreference(getString(R.string.pk_port)); + prefPort.setSummary(defSharedPref.getString(getString(R.string.pk_port), "8080")); + + } + + @Override + protected void onResume() { + super.onResume(); + getPreferenceScreen().getSharedPreferences() + .registerOnSharedPreferenceChangeListener(this); + } + + @Override + protected void onPause() { + super.onPause(); + getPreferenceScreen().getSharedPreferences() + .unregisterOnSharedPreferenceChangeListener(this); + } + + @Override + public void onDestroy(){ + super.onDestroy(); + SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this); + sharedPreferences.edit().putBoolean(getString(R.string.pk_pref_changed), true).apply(); + } + + @Override + public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, + String key) { + Preference pref = findPreference(key); + + String pref_document_root = getString(R.string.pk_document_root); + if (pref_document_root.equals(key)) { + pref.setSummary(sharedPreferences.getString(pref_document_root,"")); + } + + String pref_port = getString(R.string.pk_port); + if (pref_port.equals(key)) { + pref.setSummary(sharedPreferences.getString(pref_port,"8081")); + } + } +} + + diff --git a/app/src/main/java/net/basov/web/ServerService.java b/app/src/main/java/net/basov/web/ServerService.java index 700a085..fdd01cc 100644 --- a/app/src/main/java/net/basov/web/ServerService.java +++ b/app/src/main/java/net/basov/web/ServerService.java @@ -43,28 +43,23 @@ public class ServerService extends Service { private NotificationManager mNM; - private String message; private Notification notification; private Server server; private boolean isRunning = false; + private String ipAddress; @Override public void onCreate() { mNM = (NotificationManager)getSystemService(NOTIFICATION_SERVICE); } - private void showNotification() { - updateNotifiction(""); - startForeground(NOTIFICATION_ID, notification); - } - public void startServer(Handler handler, String documentRoot, int port) { try { isRunning = true; WifiManager wifiManager = (WifiManager) getApplicationContext().getSystemService(WIFI_SERVICE); WifiInfo wifiInfo = wifiManager.getConnectionInfo(); - String ipAddress = intToIp(wifiInfo.getIpAddress()); + ipAddress = intToIp(wifiInfo.getIpAddress()); if( wifiInfo.getSupplicantState() != SupplicantState.COMPLETED) { new AlertDialog.Builder(this).setTitle("Error").setMessage("Please connect to a WIFI-network for starting the webserver.").setPositiveButton("OK", null).show(); @@ -152,4 +147,6 @@ public void onTaskRemoved(Intent rootIntent) { super.onTaskRemoved(rootIntent); } + public String getIpAddress() { return ipAddress; } + } diff --git a/app/src/main/java/net/basov/web/StartActivity.java b/app/src/main/java/net/basov/web/StartActivity.java index f580e3b..e9230c7 100644 --- a/app/src/main/java/net/basov/web/StartActivity.java +++ b/app/src/main/java/net/basov/web/StartActivity.java @@ -30,15 +30,18 @@ import android.content.Context; import android.content.Intent; import android.content.ServiceConnection; +import android.content.SharedPreferences; +import android.os.Build; import android.os.Bundle; import android.os.Environment; import android.os.Handler; import android.os.IBinder; import android.os.Message; +import android.preference.PreferenceManager; import android.util.Log; import android.view.View; import android.view.View.OnClickListener; -import android.widget.EditText; +import android.widget.Button; import android.widget.ScrollView; import android.widget.TextView; import android.widget.Toast; @@ -48,7 +51,6 @@ public class StartActivity extends Activity { private ToggleButton mToggleButton; - private EditText port; private static TextView mLog; private static ScrollView mScroll; private String documentRoot; @@ -73,11 +75,24 @@ public void onCreate(Bundle savedInstanceState) { setContentView(R.layout.main); mToggleButton = (ToggleButton) findViewById(R.id.toggle); - port = (EditText) findViewById(R.id.port); mLog = (TextView) findViewById(R.id.log); mScroll = (ScrollView) findViewById(R.id.ScrollView01); - documentRoot = getDocRoot(); + Button button = (Button) findViewById(R.id.buttonSettings); + button.setOnClickListener(new OnClickListener() { + @Override + public void onClick(View v) { + Intent i = new Intent(StartActivity.this, PreferencesActivity.class); + StartActivity.this.startActivityForResult(i, PREFERENCES_REQUEST); + } + }); + + final SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this); + documentRoot = sharedPreferences.getString( + getString(R.string.pk_document_root), + getFilesDir(this).getPath() + + "/html/" + ); if(null != documentRoot) { try { @@ -100,15 +115,24 @@ public void onCreate(Bundle savedInstanceState) { } log(""); - log("Document-Root: " + documentRoot); } else { log("Error: Document-Root could not be found."); } + final String port = sharedPreferences.getString( + getString(R.string.pk_port), + "8080" + ); + mToggleButton.setOnClickListener(new OnClickListener() { public void onClick(View arg0) { if(mToggleButton.isChecked()) { - startServer(mHandler, documentRoot, new Integer(port.getText().toString())); + startServer( + mHandler, + documentRoot, + Integer.valueOf(port) + ); + refreshMainScreen(); } else { stopServer(); } @@ -120,8 +144,7 @@ public void onServiceConnected(ComponentName className, IBinder service) { mBoundService = ((ServerService.LocalBinder)service).getService(); Toast.makeText(StartActivity.this, "Service connected", Toast.LENGTH_SHORT).show(); mBoundService.updateNotifiction(lastMessage); - - mToggleButton.setChecked(mBoundService.isRunning()); + refreshMainScreen(); } public void onServiceDisconnected(ComponentName className) { @@ -132,8 +155,7 @@ public void onServiceDisconnected(ComponentName className) { doBindService(); - if(mBoundService != null) - mToggleButton.setChecked(mBoundService.isRunning()); + refreshMainScreen(); } private void doUnbindService() { @@ -180,7 +202,60 @@ protected void onResume() { doBindService(); } - private String getDocRoot() { - return Environment.getExternalStorageDirectory().getAbsolutePath() + "/androidwebserver/"; + @Override + protected void onActivityResult(int requestCode, int resultCode, Intent data) { + if (requestCode == PREFERENCES_REQUEST) { + SharedPreferences defSharedPref = PreferenceManager.getDefaultSharedPreferences(this); + if (defSharedPref.getBoolean(getString(R.string.pk_pref_changed), false)) { + SharedPreferences.Editor editor = defSharedPref.edit(); + refreshMainScreen(); + editor.putBoolean(getString(R.string.pk_pref_changed), false); + editor.commit(); + } + } + } + + public void refreshMainScreen() { + final TextView viewDirectoryRoot = (TextView) findViewById(R.id.document_root); + final TextView viewAddress = (TextView) findViewById(R.id.address); + final TextView viewPort = (TextView) findViewById(R.id.port); + + final SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this); + + documentRoot = sharedPreferences.getString( + getString(R.string.pk_document_root), + getFilesDir(this).getPath() + + "/html/" + ); + viewDirectoryRoot.setText(documentRoot); + + final String port = sharedPreferences.getString( + getString(R.string.pk_port), + "8080" + ); + viewPort.setText(port); + + if(mBoundService != null) { + mToggleButton.setChecked(mBoundService.isRunning()); + viewAddress.setText(mBoundService.getIpAddress()); + } + } + + + public static File getFilesDir(Context c) { + File filesDir; + if (Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState())) { + if (Build.VERSION.SDK_INT <= 18) + filesDir = new File(Environment.getExternalStorageDirectory() + + "/Android/data/" + + c.getPackageName() + +"/files" + ); + else + filesDir = c.getExternalFilesDir(null); + } else { + filesDir = c.getFilesDir(); + } + return filesDir; } } diff --git a/app/src/main/res/layout/main.xml b/app/src/main/res/layout/main.xml index a573ae3..ddaa4d6 100644 --- a/app/src/main/res/layout/main.xml +++ b/app/src/main/res/layout/main.xml @@ -12,11 +12,45 @@ android:padding="10dp" android:text="@string/hello" /> - + + + + + + + + + +