From 80394001852e8400fd2c3d30e441306957d32243 Mon Sep 17 00:00:00 2001
From: Pacien TRAN-GIRARD
Date: Tue, 4 Jul 2017 18:51:57 +0200
Subject: Add status activity
---
app/src/main/AndroidManifest.xml | 5 +
.../org/pacien/tincapp/activities/StartActivity.kt | 8 ++
.../pacien/tincapp/activities/StatusActivity.kt | 88 +++++++++++++++
.../java/org/pacien/tincapp/commands/Executor.kt | 11 +-
.../main/java/org/pacien/tincapp/commands/Tinc.kt | 2 +-
.../org/pacien/tincapp/service/TincVpnService.kt | 44 ++++++--
.../tincapp/service/VpnInterfaceConfiguraton.kt | 28 +++--
app/src/main/res/drawable/ic_build_black_24dp.xml | 9 --
.../main/res/drawable/ic_build_primary_24dp.xml | 9 ++
app/src/main/res/drawable/ic_stop_primary_24dp.xml | 9 ++
app/src/main/res/layout/dialog_frame.xml | 1 -
app/src/main/res/layout/dialog_text_monopsace.xml | 15 +++
.../res/layout/fragment_network_status_header.xml | 122 +++++++++++++++++++++
app/src/main/res/layout/page_status.xml | 22 ++++
app/src/main/res/menu/menu_start.xml | 2 +-
app/src/main/res/menu/menu_status.xml | 14 +++
app/src/main/res/values/strings.xml | 17 +++
17 files changed, 365 insertions(+), 41 deletions(-)
create mode 100644 app/src/main/java/org/pacien/tincapp/activities/StatusActivity.kt
delete mode 100644 app/src/main/res/drawable/ic_build_black_24dp.xml
create mode 100644 app/src/main/res/drawable/ic_build_primary_24dp.xml
create mode 100644 app/src/main/res/drawable/ic_stop_primary_24dp.xml
create mode 100644 app/src/main/res/layout/dialog_text_monopsace.xml
create mode 100644 app/src/main/res/layout/fragment_network_status_header.xml
create mode 100644 app/src/main/res/layout/page_status.xml
create mode 100644 app/src/main/res/menu/menu_status.xml
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 6558873..89e618c 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -31,6 +31,11 @@
android:theme="@style/AppTheme.NoActionBar">
+
+
+
diff --git a/app/src/main/java/org/pacien/tincapp/activities/StartActivity.kt b/app/src/main/java/org/pacien/tincapp/activities/StartActivity.kt
index c438be0..19d01e6 100644
--- a/app/src/main/java/org/pacien/tincapp/activities/StartActivity.kt
+++ b/app/src/main/java/org/pacien/tincapp/activities/StartActivity.kt
@@ -12,6 +12,7 @@ import kotlinx.android.synthetic.main.base.*
import kotlinx.android.synthetic.main.page_start.*
import org.pacien.tincapp.R
import org.pacien.tincapp.context.AppPaths
+import org.pacien.tincapp.service.TincVpnService
/**
* @author pacien
@@ -29,6 +30,13 @@ class StartActivity : BaseActivity(), AdapterView.OnItemClickListener {
return super.onCreateOptionsMenu(m)
}
+ override fun onResume() {
+ super.onResume()
+
+ if (TincVpnService.isConnected()) startActivity(Intent(this, StatusActivity::class.java)
+ .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK))
+ }
+
override fun onItemClick(parent: AdapterView<*>?, view: View?, position: Int, id: Long) {
PromptActivity.requestVpnPermission((view as TextView).text.toString())
}
diff --git a/app/src/main/java/org/pacien/tincapp/activities/StatusActivity.kt b/app/src/main/java/org/pacien/tincapp/activities/StatusActivity.kt
new file mode 100644
index 0000000..ca572ea
--- /dev/null
+++ b/app/src/main/java/org/pacien/tincapp/activities/StatusActivity.kt
@@ -0,0 +1,88 @@
+package org.pacien.tincapp.activities
+
+import android.content.Intent
+import android.os.Bundle
+import android.support.v7.app.AlertDialog
+import android.view.Menu
+import android.view.MenuItem
+import android.view.View
+import android.widget.AdapterView
+import android.widget.ArrayAdapter
+import android.widget.TextView
+import kotlinx.android.synthetic.main.base.*
+import kotlinx.android.synthetic.main.dialog_text_monopsace.view.*
+import kotlinx.android.synthetic.main.fragment_network_status_header.*
+import kotlinx.android.synthetic.main.page_status.*
+import org.pacien.tincapp.R
+import org.pacien.tincapp.commands.Tinc
+import org.pacien.tincapp.service.TincVpnService
+import org.pacien.tincapp.service.VpnInterfaceConfiguration
+
+/**
+ * @author pacien
+ */
+class StatusActivity : BaseActivity(), AdapterView.OnItemClickListener {
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ layoutInflater.inflate(R.layout.page_status, main_content)
+ writeContent()
+ }
+
+ override fun onCreateOptionsMenu(m: Menu): Boolean {
+ menuInflater.inflate(R.menu.menu_status, m)
+ return super.onCreateOptionsMenu(m)
+ }
+
+ override fun onItemClick(parent: AdapterView<*>?, view: View?, position: Int, id: Long) {
+ val nodeName = (view as TextView).text.toString()
+ val v = layoutInflater.inflate(R.layout.dialog_text_monopsace, main_content, false)
+ v.dialog_text_monospace.text = Tinc.info(TincVpnService.getCurrentNetName()!!, nodeName)
+
+ AlertDialog.Builder(this)
+ .setTitle(R.string.title_node_info)
+ .setView(v)
+ .setPositiveButton(R.string.action_close) { _, _ -> /* nop */ }
+ .show()
+ }
+
+ fun stopVpn(@Suppress("UNUSED_PARAMETER") i: MenuItem) {
+ TincVpnService.stopVpn()
+ startActivity(Intent(this, StartActivity::class.java).addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP))
+ finish()
+ }
+
+ private fun TextView.setText(list: List) {
+ if (list.isNotEmpty()) text = list.joinToString("\n")
+ else text = getString(R.string.value_none)
+ }
+
+ private fun getNodeNames() = Tinc.dumpNodes(TincVpnService.getCurrentNetName()!!).map { it.substringBefore(" ") }
+
+ private fun writeContent() {
+ node_list.addHeaderView(layoutInflater.inflate(R.layout.fragment_network_status_header, node_list, false), null, false)
+ node_list.addFooterView(View(this), null, false)
+ node_list.emptyView = node_list_empty
+ node_list.onItemClickListener = this
+ node_list.adapter = ArrayAdapter(this, R.layout.fragment_list_item, getNodeNames())
+
+ text_network_name.text = TincVpnService.getCurrentNetName() ?: getString(R.string.value_none)
+ writeNetworkInfo(TincVpnService.getCurrentInterfaceCfg() ?: VpnInterfaceConfiguration())
+ }
+
+
+ private fun writeNetworkInfo(cfg: VpnInterfaceConfiguration) {
+ text_network_ip_addresses.setText(cfg.addresses.map { it.toString() })
+ text_network_routes.setText(cfg.routes.map { it.toString() })
+ text_network_dns_servers.setText(cfg.dnsServers)
+ text_network_search_domains.setText(cfg.searchDomains)
+ text_network_allow_bypass.text = getString(if (cfg.allowBypass) R.string.value_yes else R.string.value_no)
+
+ block_network_allowed_applications.visibility = if (cfg.allowedApplications.isNotEmpty()) View.VISIBLE else View.GONE
+ text_network_allowed_applications.setText(cfg.allowedApplications)
+
+ block_network_disallowed_applications.visibility = if (cfg.disallowedApplications.isNotEmpty()) View.VISIBLE else View.GONE
+ text_network_disallowed_applications.setText(cfg.disallowedApplications)
+ }
+
+}
diff --git a/app/src/main/java/org/pacien/tincapp/commands/Executor.kt b/app/src/main/java/org/pacien/tincapp/commands/Executor.kt
index 160f0cd..c93de64 100644
--- a/app/src/main/java/org/pacien/tincapp/commands/Executor.kt
+++ b/app/src/main/java/org/pacien/tincapp/commands/Executor.kt
@@ -3,7 +3,6 @@ package org.pacien.tincapp.commands
import java.io.BufferedReader
import java.io.IOException
import java.io.InputStreamReader
-import java.util.*
/**
* @author pacien
@@ -29,15 +28,7 @@ internal object Executor {
fun call(cmd: Command): List {
val proc = ProcessBuilder(cmd.asList()).start()
val outputReader = BufferedReader(InputStreamReader(proc.inputStream))
-
- var line: String? = outputReader.readLine()
- val list = LinkedList()
- while (line != null) {
- line = outputReader.readLine()
- list.add(line)
- }
-
- return list
+ return outputReader.readLines()
}
}
diff --git a/app/src/main/java/org/pacien/tincapp/commands/Tinc.kt b/app/src/main/java/org/pacien/tincapp/commands/Tinc.kt
index 22cbe71..e8ebb21 100644
--- a/app/src/main/java/org/pacien/tincapp/commands/Tinc.kt
+++ b/app/src/main/java/org/pacien/tincapp/commands/Tinc.kt
@@ -30,7 +30,7 @@ object Tinc {
}
@Throws(IOException::class)
- fun dumpNodes(netName: String, reachable: Boolean): List =
+ fun dumpNodes(netName: String, reachable: Boolean = false): List =
Executor.call(
if (reachable) newCommand(netName).withArguments("dump", "reachable", "nodes")
else newCommand(netName).withArguments("dump", "nodes"))
diff --git a/app/src/main/java/org/pacien/tincapp/service/TincVpnService.kt b/app/src/main/java/org/pacien/tincapp/service/TincVpnService.kt
index 30e2956..7813601 100644
--- a/app/src/main/java/org/pacien/tincapp/service/TincVpnService.kt
+++ b/app/src/main/java/org/pacien/tincapp/service/TincVpnService.kt
@@ -3,6 +3,7 @@ package org.pacien.tincapp.service
import android.app.Service
import android.content.Intent
import android.net.VpnService
+import android.os.ParcelFileDescriptor
import org.pacien.tincapp.BuildConfig
import org.pacien.tincapp.commands.Tinc
import org.pacien.tincapp.commands.Tincd
@@ -11,48 +12,75 @@ import org.pacien.tincapp.context.AppPaths
import org.pacien.tincapp.utils.applyIgnoringException
import java.io.IOException
+
/**
* @author pacien
*/
class TincVpnService : VpnService() {
- private var netName: String? = null
-
override fun onStartCommand(intent: Intent, flags: Int, startId: Int): Int {
- startVpn(intent.getStringExtra(INTENT_EXTRA_NET_NAME)!!)
+ when (intent.getSerializableExtra(INTENT_EXTRA_ACTION)) {
+ Action.START -> startVpn(intent.getStringExtra(INTENT_EXTRA_NET_NAME)!!)
+ Action.STOP -> onDestroy()
+ }
+
return Service.START_STICKY
}
override fun onDestroy() = try {
Tinc.stop(netName!!)
+ fd!!.close()
} catch (e: IOException) {
e.printStackTrace()
} finally {
netName = null
+ interfaceCfg = null
+ fd = null
+ super.onDestroy()
}
private fun startVpn(netName: String) {
- if (netName == this.netName) onDestroy()
- this.netName = netName
+ if (netName == TincVpnService.netName) onDestroy()
+ TincVpnService.netName = netName
+ TincVpnService.interfaceCfg = VpnInterfaceConfiguration(AppPaths.netConfFile(netName))
- val net = Builder().setSession(netName)
- net.apply(VpnInterfaceConfiguration(AppPaths.netConfFile(netName)))
+ val net = Builder().setSession(netName).apply(TincVpnService.interfaceCfg!!)
applyIgnoringException(net::addDisallowedApplication, BuildConfig.APPLICATION_ID)
try {
- Tincd.start(netName, net.establish().detachFd())
+ fd = net.establish()
+ Tincd.start(netName, fd!!.fd)
} catch (e: IOException) {
e.printStackTrace()
}
}
companion object {
+
+ private val INTENT_EXTRA_ACTION = "action"
private val INTENT_EXTRA_NET_NAME = "netName"
+ private enum class Action { START, STOP }
+
+ private var netName: String? = null
+ private var interfaceCfg: VpnInterfaceConfiguration? = null
+ private var fd: ParcelFileDescriptor? = null
+
fun startVpn(netName: String) {
App.getContext().startService(Intent(App.getContext(), TincVpnService::class.java)
+ .putExtra(INTENT_EXTRA_ACTION, Action.START)
.putExtra(TincVpnService.INTENT_EXTRA_NET_NAME, netName))
}
+
+ fun stopVpn() {
+ App.getContext().startService(Intent(App.getContext(), TincVpnService::class.java)
+ .putExtra(INTENT_EXTRA_ACTION, Action.STOP))
+ }
+
+ fun getCurrentNetName() = netName
+ fun getCurrentInterfaceCfg() = interfaceCfg
+ fun isConnected() = netName != null
+
}
}
diff --git a/app/src/main/java/org/pacien/tincapp/service/VpnInterfaceConfiguraton.kt b/app/src/main/java/org/pacien/tincapp/service/VpnInterfaceConfiguraton.kt
index 520d68c..50ccb20 100644
--- a/app/src/main/java/org/pacien/tincapp/service/VpnInterfaceConfiguraton.kt
+++ b/app/src/main/java/org/pacien/tincapp/service/VpnInterfaceConfiguraton.kt
@@ -25,19 +25,25 @@ private fun Configuration.getIntList(key: String): List = getList(Int::clas
data class CidrAddress(val address: String, val prefix: Int) {
constructor(slashSeparated: String) :
- this(slashSeparated.substringBefore("/"), Integer.parseInt(slashSeparated.substringAfter("/")))
+ this(slashSeparated.substringBefore(SEPARATOR), Integer.parseInt(slashSeparated.substringAfter(SEPARATOR)))
+
+ override fun toString() = address + SEPARATOR + prefix
+
+ companion object {
+ private val SEPARATOR = "/"
+ }
}
-data class VpnInterfaceConfiguration(val addresses: List,
- val routes: List,
- val dnsServers: List,
- val searchDomains: List,
- val allowedApplications: List,
- val disallowedApplications: List,
- val allowedFamilies: List,
- val allowBypass: Boolean,
- val blocking: Boolean,
- val mtu: Int?) {
+data class VpnInterfaceConfiguration(val addresses: List = emptyList(),
+ val routes: List = emptyList(),
+ val dnsServers: List = emptyList(),
+ val searchDomains: List = emptyList(),
+ val allowedApplications: List = emptyList(),
+ val disallowedApplications: List = emptyList(),
+ val allowedFamilies: List = emptyList(),
+ val allowBypass: Boolean = false,
+ val blocking: Boolean = false,
+ val mtu: Int? = null) {
constructor(cfg: Configuration) : this(
cfg.getCidrList(KEY_ADDRESSES),
diff --git a/app/src/main/res/drawable/ic_build_black_24dp.xml b/app/src/main/res/drawable/ic_build_black_24dp.xml
deleted file mode 100644
index b099a5c..0000000
--- a/app/src/main/res/drawable/ic_build_black_24dp.xml
+++ /dev/null
@@ -1,9 +0,0 @@
-
-
-
diff --git a/app/src/main/res/drawable/ic_build_primary_24dp.xml b/app/src/main/res/drawable/ic_build_primary_24dp.xml
new file mode 100644
index 0000000..b099a5c
--- /dev/null
+++ b/app/src/main/res/drawable/ic_build_primary_24dp.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/app/src/main/res/drawable/ic_stop_primary_24dp.xml b/app/src/main/res/drawable/ic_stop_primary_24dp.xml
new file mode 100644
index 0000000..9d41e25
--- /dev/null
+++ b/app/src/main/res/drawable/ic_stop_primary_24dp.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/app/src/main/res/layout/dialog_frame.xml b/app/src/main/res/layout/dialog_frame.xml
index 82a130f..9b4a512 100644
--- a/app/src/main/res/layout/dialog_frame.xml
+++ b/app/src/main/res/layout/dialog_frame.xml
@@ -1,4 +1,3 @@
-
+
+
+
+
diff --git a/app/src/main/res/layout/fragment_network_status_header.xml b/app/src/main/res/layout/fragment_network_status_header.xml
new file mode 100644
index 0000000..947183b
--- /dev/null
+++ b/app/src/main/res/layout/fragment_network_status_header.xml
@@ -0,0 +1,122 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/layout/page_status.xml b/app/src/main/res/layout/page_status.xml
new file mode 100644
index 0000000..22faaf1
--- /dev/null
+++ b/app/src/main/res/layout/page_status.xml
@@ -0,0 +1,22 @@
+
+
+
+
+
+
+
diff --git a/app/src/main/res/menu/menu_start.xml b/app/src/main/res/menu/menu_start.xml
index 4f455d1..89ad0a2 100644
--- a/app/src/main/res/menu/menu_start.xml
+++ b/app/src/main/res/menu/menu_start.xml
@@ -5,7 +5,7 @@
-
+
+
+
+
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 750edbb..4b4be51 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -12,16 +12,28 @@
About this app
Configure
+ Disconnect
Tinc network name
Connect to network
Request VPN permissions
Path info
+ Node info
Tools
Configuration directory
Log directory
Tinc binary
+ Network info
+ Network name
+ IP addresses
+ Routes
+ DNS servers
+ Search domains
+ Allowed applications
+ Disallowed applications
+ Allow bypass
+ Nodes
Close
Project website
@@ -29,4 +41,9 @@
Join network via invitation URL
No network configuration has been found.
+ No known node
+
+ none
+ yes
+ no
--
cgit v1.2.3