diff --git a/android/app/build.gradle b/android/app/build.gradle index a725c471..d2f10b2d 100755 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -23,8 +23,8 @@ android { applicationId "com.openipc.decoder" minSdk 21 targetSdk 36 - versionCode 35 - versionName "2.10" + versionCode 36 + versionName "2.11" buildConfigField "String", "GIT_HASH", "\"${getGitHash()}\"" } diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index 922a4fe1..bb26eb26 100755 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -14,6 +14,14 @@ + + + + + + + + stats, String log, Date now, long uptimeS) { + StringBuilder sb = new StringBuilder(64 * 1024); + sb.append(REPORT_TITLE).append('\n'); + sb.append("App: OpenIPC Decoder ").append(BuildConfig.VERSION_NAME) + .append(" (").append(BuildConfig.VERSION_CODE).append("), git ") + .append(BuildConfig.GIT_HASH).append('\n'); + sb.append("Device: ").append(android.os.Build.MANUFACTURER).append(' ') + .append(android.os.Build.MODEL).append('\n'); + sb.append("Android: ").append(android.os.Build.VERSION.RELEASE).append(" (SDK ") + .append(android.os.Build.VERSION.SDK_INT).append(")\n"); + sb.append("Time: ").append(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss Z", Locale.US) + .format(now)).append('\n'); + sb.append("Uptime: ").append(uptime(uptimeS)).append('\n'); + sb.append("\n== stats.json ==\n"); + sb.append(toJson(stats, true)); + sb.append("\n== log ==\n"); + sb.append(log != null ? log : ""); + return redact(sb.toString()); + } + + /** 1d 2h 3m 4s; the leading zero units left out. */ + static String uptime(long s) { + long d = s / 86400, h = s % 86400 / 3600, m = s % 3600 / 60; + StringBuilder sb = new StringBuilder(); + if (d > 0) sb.append(d).append("d "); + if (d > 0 || h > 0) sb.append(h).append("h "); + if (d > 0 || h > 0 || m > 0) sb.append(m).append("m "); + return sb.append(s % 60).append('s').toString(); + } + private Map snapshot() { Source s = source; Map m; @@ -270,11 +340,18 @@ private static void reply(OutputStream out, int code, String type, String body) private static void reply(OutputStream out, int code, String type, byte[] data) throws IOException { + reply(out, code, type, data, ""); + } + + /** {@code extra}: more header lines, each ending with \r\n. */ + private static void reply(OutputStream out, int code, String type, byte[] data, String extra) + throws IOException { String head = "HTTP/1.1 " + code + " " + reason(code) + "\r\n" + "Content-Type: " + type + "\r\n" + "Content-Length: " + data.length + "\r\n" + "Cache-Control: no-store\r\n" + (code == 405 ? "Allow: GET\r\n" : "") + + extra + "Connection: close\r\n\r\n"; out.write(head.getBytes(StandardCharsets.ISO_8859_1)); out.write(data); @@ -466,7 +543,8 @@ private static void closeQuietly(Socket s) { + "
" + "