From 9d8846e105904b31478ed19d3a34c0d62708abcf Mon Sep 17 00:00:00 2001
From: pacien
Date: Tue, 7 Aug 2018 01:08:22 +0200
Subject: Revert "Rename source directory"
This reverts commit dbba24e
---
.../main/java/org/pacien/tincapp/context/App.kt | 85 ++++++++++++++++++++++
.../java/org/pacien/tincapp/context/AppInfo.kt | 47 ++++++++++++
.../java/org/pacien/tincapp/context/AppLogger.kt | 63 ++++++++++++++++
.../tincapp/context/AppNotificationManager.kt | 84 +++++++++++++++++++++
.../java/org/pacien/tincapp/context/AppPaths.kt | 71 ++++++++++++++++++
.../org/pacien/tincapp/context/CrashRecorder.kt | 48 ++++++++++++
6 files changed, 398 insertions(+)
create mode 100644 app/src/main/java/org/pacien/tincapp/context/App.kt
create mode 100644 app/src/main/java/org/pacien/tincapp/context/AppInfo.kt
create mode 100644 app/src/main/java/org/pacien/tincapp/context/AppLogger.kt
create mode 100644 app/src/main/java/org/pacien/tincapp/context/AppNotificationManager.kt
create mode 100644 app/src/main/java/org/pacien/tincapp/context/AppPaths.kt
create mode 100644 app/src/main/java/org/pacien/tincapp/context/CrashRecorder.kt
(limited to 'app/src/main/java/org/pacien/tincapp/context')
diff --git a/app/src/main/java/org/pacien/tincapp/context/App.kt b/app/src/main/java/org/pacien/tincapp/context/App.kt
new file mode 100644
index 0000000..359cd23
--- /dev/null
+++ b/app/src/main/java/org/pacien/tincapp/context/App.kt
@@ -0,0 +1,85 @@
+/*
+ * Tinc App, an Android binding and user interface for the tinc mesh VPN daemon
+ * Copyright (C) 2017-2018 Pacien TRAN-GIRARD
+ *
+ * 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 org.pacien.tincapp.context
+
+import android.app.Application
+import android.content.Context
+import android.content.Intent
+import android.net.Uri
+import android.os.Build
+import android.os.Handler
+import android.support.annotation.StringRes
+import org.pacien.tincapp.BuildConfig
+import org.pacien.tincapp.R
+import org.slf4j.LoggerFactory
+import java.io.File
+
+/**
+ * @author pacien
+ */
+class App : Application() {
+ override fun onCreate() {
+ super.onCreate()
+ appContext = applicationContext
+ handler = Handler()
+ AppLogger.configure()
+ setupCrashHandler()
+
+ val logger = LoggerFactory.getLogger(this.javaClass)
+ logger.info("Starting tinc app {} ({} build), running on {} ({})",
+ BuildConfig.VERSION_NAME, BuildConfig.BUILD_TYPE, Build.VERSION.CODENAME, Build.VERSION.RELEASE)
+ }
+
+ private fun setupCrashHandler() {
+ val logger = LoggerFactory.getLogger(this.javaClass)
+ val systemCrashHandler = Thread.getDefaultUncaughtExceptionHandler()
+ val crashRecorder = CrashRecorder(logger, systemCrashHandler)
+ Thread.setDefaultUncaughtExceptionHandler(crashRecorder)
+ }
+
+ companion object {
+ private var appContext: Context? = null
+ private var handler: Handler? = null
+
+ val notificationManager: AppNotificationManager by lazy { AppNotificationManager(appContext!!) }
+
+ fun getContext() = appContext!!
+ fun getResources() = getContext().resources!!
+
+ fun alert(@StringRes title: Int, msg: String, manualLink: String? = null) =
+ notificationManager.notifyError(appContext!!.getString(title), msg, manualLink)
+
+ fun openURL(url: String) {
+ val intent = Intent(Intent.ACTION_VIEW, Uri.parse(url))
+ val chooser = Intent.createChooser(intent, getResources().getString(R.string.action_open_web_page))
+ appContext?.startActivity(chooser.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK))
+ }
+
+ fun sendMail(recipient: String, subject: String, body: String? = null, attachment: File? = null) {
+ val intent = Intent(Intent.ACTION_SENDTO, Uri.parse("mailto:"))
+ .putExtra(Intent.EXTRA_EMAIL, arrayOf(recipient))
+ .putExtra(Intent.EXTRA_SUBJECT, subject)
+ .apply { if (body != null) putExtra(Intent.EXTRA_TEXT, body) }
+ .apply { if (attachment != null) putExtra(Intent.EXTRA_STREAM, Uri.fromFile(attachment)) }
+
+ val chooser = Intent.createChooser(intent, getResources().getString(R.string.action_send_email))
+ appContext?.startActivity(chooser.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK))
+ }
+ }
+}
diff --git a/app/src/main/java/org/pacien/tincapp/context/AppInfo.kt b/app/src/main/java/org/pacien/tincapp/context/AppInfo.kt
new file mode 100644
index 0000000..e0d49f1
--- /dev/null
+++ b/app/src/main/java/org/pacien/tincapp/context/AppInfo.kt
@@ -0,0 +1,47 @@
+/*
+ * Tinc App, an Android binding and user interface for the tinc mesh VPN daemon
+ * Copyright (C) 2017-2018 Pacien TRAN-GIRARD
+ *
+ * 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 org.pacien.tincapp.context
+
+import android.os.Build
+import org.pacien.tincapp.BuildConfig
+import org.pacien.tincapp.R
+
+/**
+ * @author pacien
+ */
+object AppInfo {
+ private fun appVersion(): String = App.getResources().getString(
+ R.string.info_version_format,
+ BuildConfig.VERSION_NAME,
+ BuildConfig.BUILD_TYPE)
+
+ private fun androidVersion(): String = App.getResources().getString(
+ R.string.info_running_on_format,
+ Build.VERSION.CODENAME,
+ Build.VERSION.RELEASE)
+
+ private fun supportedABIs(): String = App.getResources().getString(
+ R.string.info_supported_abis_format,
+ Build.SUPPORTED_ABIS.joinToString(","))
+
+ fun all(): String = listOf(
+ appVersion(),
+ androidVersion(),
+ supportedABIs()).joinToString("\n")
+}
diff --git a/app/src/main/java/org/pacien/tincapp/context/AppLogger.kt b/app/src/main/java/org/pacien/tincapp/context/AppLogger.kt
new file mode 100644
index 0000000..3c1be44
--- /dev/null
+++ b/app/src/main/java/org/pacien/tincapp/context/AppLogger.kt
@@ -0,0 +1,63 @@
+/*
+ * Tinc App, an Android binding and user interface for the tinc mesh VPN daemon
+ * Copyright (C) 2017-2018 Pacien TRAN-GIRARD
+ *
+ * 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 org.pacien.tincapp.context
+
+import ch.qos.logback.classic.Logger
+import ch.qos.logback.classic.LoggerContext
+import ch.qos.logback.classic.android.LogcatAppender
+import ch.qos.logback.classic.encoder.PatternLayoutEncoder
+import ch.qos.logback.classic.spi.ILoggingEvent
+import ch.qos.logback.core.Context
+import ch.qos.logback.core.FileAppender
+import org.slf4j.LoggerFactory
+
+/**
+ * @author pacien
+ */
+object AppLogger {
+ private const val LOGCAT_PATTERN = "[%thread] %msg%n%rEx"
+ private const val LOGFILE_PATTERN = "%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n%rEx"
+
+ fun configure() {
+ (LoggerFactory.getILoggerFactory() as LoggerContext)
+ .apply { reset() }
+ .let { loggerContext ->
+ (LoggerFactory.getLogger(Logger.ROOT_LOGGER_NAME) as Logger)
+ .apply {
+ addAppender(LogcatAppender()
+ .apply { context = loggerContext }
+ .apply { encoder = patternEncoder(loggerContext, LOGCAT_PATTERN) }
+ .apply { start() })
+ }
+ .apply {
+ addAppender(FileAppender()
+ .apply { context = loggerContext }
+ .apply { encoder = patternEncoder(loggerContext, LOGFILE_PATTERN) }
+ .apply { file = AppPaths.appLogFile().absolutePath }
+ .apply { start() })
+ }
+ }
+ }
+
+ private fun patternEncoder(ctx: Context, pat: String) =
+ PatternLayoutEncoder()
+ .apply { context = ctx }
+ .apply { pattern = pat }
+ .apply { start() }
+}
diff --git a/app/src/main/java/org/pacien/tincapp/context/AppNotificationManager.kt b/app/src/main/java/org/pacien/tincapp/context/AppNotificationManager.kt
new file mode 100644
index 0000000..d543210
--- /dev/null
+++ b/app/src/main/java/org/pacien/tincapp/context/AppNotificationManager.kt
@@ -0,0 +1,84 @@
+/*
+ * Tinc App, an Android binding and user interface for the tinc mesh VPN daemon
+ * Copyright (C) 2017-2018 Pacien TRAN-GIRARD
+ *
+ * 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 org.pacien.tincapp.context
+
+import android.app.NotificationChannel
+import android.app.NotificationManager
+import android.app.PendingIntent
+import android.content.Context
+import android.content.Intent
+import android.net.Uri
+import android.os.Build
+import android.support.annotation.RequiresApi
+import android.support.v4.app.NotificationCompat
+import android.support.v4.app.NotificationManagerCompat
+import org.pacien.tincapp.R
+
+/**
+ * @author pacien
+ */
+class AppNotificationManager(private val context: Context) {
+ companion object {
+ private const val CHANNEL_ID = "org.pacien.tincapp.notification.channels.error"
+ private const val ERROR_NOTIFICATION_ID = 0
+ }
+
+ init {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) registerChannel()
+ }
+
+ fun notifyError(title: String, message: String, manualLink: String? = null) {
+ val notification = NotificationCompat.Builder(context, CHANNEL_ID)
+ .setSmallIcon(R.drawable.ic_warning_primary_24dp)
+ .setContentTitle(title)
+ .setContentText(message)
+ .setStyle(NotificationCompat.BigTextStyle().bigText(message))
+ .setHighPriority()
+ .setAutoCancel(true)
+ .apply { if (manualLink != null) setManualLink(manualLink) }
+ .build()
+
+ NotificationManagerCompat.from(context)
+ .notify(ERROR_NOTIFICATION_ID, notification)
+ }
+
+ fun dismissAll() {
+ NotificationManagerCompat.from(context).cancelAll()
+ }
+
+ @RequiresApi(Build.VERSION_CODES.O)
+ private fun registerChannel() {
+ val name = context.getString(R.string.notification_channel_error_name)
+ val importance = NotificationManager.IMPORTANCE_HIGH
+ val channel = NotificationChannel(CHANNEL_ID, name, importance)
+ val notificationManager = context.getSystemService(NotificationManager::class.java)
+ notificationManager.createNotificationChannel(channel)
+ }
+
+ private fun NotificationCompat.Builder.setHighPriority() = apply {
+ priority = NotificationCompat.PRIORITY_MAX
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) setDefaults(NotificationCompat.DEFAULT_SOUND) // force heads-up notification
+ }
+
+ private fun NotificationCompat.Builder.setManualLink(manualLink: String) = apply {
+ val intent = Intent(Intent.ACTION_VIEW, Uri.parse(manualLink))
+ val pendingIntent = PendingIntent.getActivity(context, 0, intent, 0)
+ addAction(R.drawable.ic_help_primary_24dp, context.getString(R.string.action_open_manual), pendingIntent)
+ }
+}
diff --git a/app/src/main/java/org/pacien/tincapp/context/AppPaths.kt b/app/src/main/java/org/pacien/tincapp/context/AppPaths.kt
new file mode 100644
index 0000000..0b85565
--- /dev/null
+++ b/app/src/main/java/org/pacien/tincapp/context/AppPaths.kt
@@ -0,0 +1,71 @@
+/*
+ * Tinc App, an Android binding and user interface for the tinc mesh VPN daemon
+ * Copyright (C) 2017-2018 Pacien TRAN-GIRARD
+ *
+ * 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 org.pacien.tincapp.context
+
+import android.os.Environment
+import java.io.File
+import java.io.FileNotFoundException
+
+/**
+ * @author pacien
+ *
+ * @implNote Logs and PID files are stored in the cache directory for easy clean up.
+ */
+object AppPaths {
+ private const val TINCD_BIN = "libtincd.so"
+ private const val TINC_BIN = "libtinc.so"
+
+ private const val APPLOG_FILE = "tincapp.log"
+ private const val CRASHFLAG_FILE = "crash.flag"
+ private const val LOGFILE_FORMAT = "tinc.%s.log"
+ private const val PIDFILE_FORMAT = "tinc.%s.pid"
+
+ private const val NET_CONF_FILE = "network.conf"
+ private const val NET_TINC_CONF_FILE = "tinc.conf"
+ private const val NET_HOSTS_DIR = "hosts"
+ private const val NET_INVITATION_FILE = "invitation-data"
+ private const val NET_DEFAULT_ED25519_PRIVATE_KEY_FILE = "ed25519_key.priv"
+ private const val NET_DEFAULT_RSA_PRIVATE_KEY_FILE = "rsa_key.priv"
+
+ fun storageAvailable() =
+ Environment.getExternalStorageState().let { it == Environment.MEDIA_MOUNTED && it != Environment.MEDIA_MOUNTED_READ_ONLY }
+
+ private fun internalCacheDir() = App.getContext().cacheDir!!
+ fun cacheDir() = App.getContext().externalCacheDir!!
+ fun confDir() = App.getContext().getExternalFilesDir(null)!!
+ private fun binDir() = File(App.getContext().applicationInfo.nativeLibraryDir)
+
+ fun confDir(netName: String) = File(confDir(), netName)
+ fun hostsDir(netName: String) = File(confDir(netName), NET_HOSTS_DIR)
+ fun netConfFile(netName: String) = File(confDir(netName), NET_CONF_FILE)
+ fun tincConfFile(netName: String) = File(confDir(netName), NET_TINC_CONF_FILE)
+ fun invitationFile(netName: String) = File(confDir(netName), NET_INVITATION_FILE)
+ fun logFile(netName: String) = File(cacheDir(), String.format(LOGFILE_FORMAT, netName))
+ fun pidFile(netName: String) = File(App.getContext().cacheDir, String.format(PIDFILE_FORMAT, netName))
+ fun appLogFile() = File(cacheDir(), APPLOG_FILE)
+ fun crashFlagFile() = File(internalCacheDir(), CRASHFLAG_FILE)
+
+ fun existing(f: File) = f.apply { if (!exists()) throw FileNotFoundException(f.absolutePath) }
+
+ fun defaultEd25519PrivateKeyFile(netName: String) = File(confDir(netName), NET_DEFAULT_ED25519_PRIVATE_KEY_FILE)
+ fun defaultRsaPrivateKeyFile(netName: String) = File(confDir(netName), NET_DEFAULT_RSA_PRIVATE_KEY_FILE)
+
+ fun tincd() = File(binDir(), TINCD_BIN)
+ fun tinc() = File(binDir(), TINC_BIN)
+}
diff --git a/app/src/main/java/org/pacien/tincapp/context/CrashRecorder.kt b/app/src/main/java/org/pacien/tincapp/context/CrashRecorder.kt
new file mode 100644
index 0000000..d0310c2
--- /dev/null
+++ b/app/src/main/java/org/pacien/tincapp/context/CrashRecorder.kt
@@ -0,0 +1,48 @@
+/*
+ * Tinc App, an Android binding and user interface for the tinc mesh VPN daemon
+ * Copyright (C) 2017-2018 Pacien TRAN-GIRARD
+ *
+ * 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 org.pacien.tincapp.context
+
+import org.slf4j.Logger
+
+/**
+ * @author pacien
+ */
+class CrashRecorder(private val logger: Logger,
+ private val upstreamCrashHandler: Thread.UncaughtExceptionHandler) : Thread.UncaughtExceptionHandler {
+
+ companion object {
+ private val flagFile = AppPaths.crashFlagFile()
+
+ fun hasPreviouslyCrashed() = flagFile.exists()
+
+ fun flagCrash() {
+ flagFile.apply { if (!exists()) createNewFile() }
+ }
+
+ fun dismissPreviousCrash() {
+ flagFile.delete()
+ }
+ }
+
+ override fun uncaughtException(thread: Thread, throwable: Throwable) {
+ logger.error("Fatal application error.", throwable)
+ flagCrash()
+ upstreamCrashHandler.uncaughtException(thread, throwable)
+ }
+}
--
cgit v1.2.3