aboutsummaryrefslogtreecommitdiff
path: root/app/src/main/java/org/pacien/tincapp/activities/status/StatusActivity.kt
diff options
context:
space:
mode:
Diffstat (limited to 'app/src/main/java/org/pacien/tincapp/activities/status/StatusActivity.kt')
-rw-r--r--app/src/main/java/org/pacien/tincapp/activities/status/StatusActivity.kt184
1 files changed, 184 insertions, 0 deletions
diff --git a/app/src/main/java/org/pacien/tincapp/activities/status/StatusActivity.kt b/app/src/main/java/org/pacien/tincapp/activities/status/StatusActivity.kt
new file mode 100644
index 0000000..2bf42ce
--- /dev/null
+++ b/app/src/main/java/org/pacien/tincapp/activities/status/StatusActivity.kt
@@ -0,0 +1,184 @@
1/*
2 * Tinc App, an Android binding and user interface for the tinc mesh VPN daemon
3 * Copyright (C) 2017-2018 Pacien TRAN-GIRARD
4 *
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <https://www.gnu.org/licenses/>.
17 */
18
19package org.pacien.tincapp.activities.status
20
21import android.content.Intent
22import android.os.Bundle
23import android.support.v4.widget.SwipeRefreshLayout
24import android.support.v7.app.AlertDialog
25import android.view.Menu
26import android.view.MenuItem
27import android.view.View
28import android.widget.AdapterView
29import android.widget.ArrayAdapter
30import android.widget.TextView
31import java8.util.concurrent.CompletableFuture
32import kotlinx.android.synthetic.main.base.*
33import kotlinx.android.synthetic.main.fragment_list_view.*
34import kotlinx.android.synthetic.main.status_activity_list_header.*
35import kotlinx.android.synthetic.main.status_node_info_dialog.view.*
36import org.pacien.tincapp.R
37import org.pacien.tincapp.activities.BaseActivity
38import org.pacien.tincapp.activities.StartActivity
39import org.pacien.tincapp.activities.ViewLogActivity
40import org.pacien.tincapp.activities.common.ProgressModal
41import org.pacien.tincapp.commands.Executor
42import org.pacien.tincapp.commands.Tinc
43import org.pacien.tincapp.extensions.Android.setElements
44import org.pacien.tincapp.intent.Actions
45import org.pacien.tincapp.intent.BroadcastMapper
46import org.pacien.tincapp.service.TincVpnService
47import java.util.*
48import kotlin.concurrent.timerTask
49
50/**
51 * @author pacien
52 */
53class StatusActivity : BaseActivity(), AdapterView.OnItemClickListener, SwipeRefreshLayout.OnRefreshListener {
54 private val broadcastMapper = BroadcastMapper(mapOf(Actions.EVENT_DISCONNECTED to this::onVpnShutdown))
55 private var shutdownDialog: AlertDialog? = null
56 private var nodeListAdapter: ArrayAdapter<String>? = null
57 private var refreshTimer: Timer? = null
58 private var listNetworksAfterExit = true
59
60 override fun onCreate(savedInstanceState: Bundle?) {
61 super.onCreate(savedInstanceState)
62 nodeListAdapter = ArrayAdapter(this, R.layout.fragment_list_item)
63
64 layoutInflater.inflate(R.layout.fragment_list_view, main_content)
65 list_wrapper.setOnRefreshListener(this)
66 list.addHeaderView(layoutInflater.inflate(R.layout.status_activity_list_header, list, false), null, false)
67 list.addFooterView(View(this), null, false)
68 list.onItemClickListener = this
69 list.adapter = nodeListAdapter
70
71 if (intent.action == Actions.ACTION_DISCONNECT) {
72 listNetworksAfterExit = false
73 stopVpn()
74 } else {
75 listNetworksAfterExit = true
76 }
77 }
78
79 override fun onCreateOptionsMenu(m: Menu): Boolean {
80 menuInflater.inflate(R.menu.menu_status, m)
81 return super.onCreateOptionsMenu(m)
82 }
83
84 override fun onDestroy() {
85 super.onDestroy()
86 nodeListAdapter = null
87 refreshTimer = null
88 }
89
90 override fun onStart() {
91 super.onStart()
92 refreshTimer = Timer(true)
93 refreshTimer?.schedule(timerTask { updateView() }, NOW, REFRESH_RATE)
94 }
95
96 override fun onStop() {
97 refreshTimer?.cancel()
98 super.onStop()
99 }
100
101 override fun onResume() {
102 super.onResume()
103 broadcastMapper.register()
104 updateView()
105 handleRecentCrash()
106 }
107
108 override fun onPause() {
109 broadcastMapper.unregister()
110 super.onPause()
111 }
112
113 override fun onRefresh() {
114 refreshTimer?.schedule(timerTask { updateView() }, NOW)
115 }
116
117 override fun onItemClick(parent: AdapterView<*>?, view: View?, position: Int, id: Long) = when (view) {
118 is TextView -> showNodeInfo(view.text.toString())
119 else -> Unit
120 }
121
122 private fun onVpnShutdown() {
123 shutdownDialog?.dismiss()
124 if (listNetworksAfterExit) openStartActivity()
125 finish()
126 }
127
128 fun stopVpn(@Suppress("UNUSED_PARAMETER") i: MenuItem? = null) {
129 refreshTimer?.cancel()
130 list_wrapper.isRefreshing = false
131 shutdownDialog = ProgressModal.show(this, getString(R.string.message_disconnecting_vpn))
132 TincVpnService.disconnect()
133 }
134
135 fun openLogViewer(@Suppress("UNUSED_PARAMETER") i: MenuItem) =
136 startActivity(Intent(this, ViewLogActivity::class.java))
137
138 private fun writeNodeList(nodeList: List<String>) {
139 nodeListAdapter?.setElements(nodeList)
140 status_activity_node_list_placeholder.visibility = View.GONE
141 list_wrapper.isRefreshing = false
142 }
143
144 private fun updateNodeList() {
145 getNodeNames().thenAccept { nodeList -> runOnUiThread { writeNodeList(nodeList) } }
146 }
147
148 private fun showNodeInfo(nodeName: String) {
149 val dialogTextView = layoutInflater.inflate(R.layout.status_node_info_dialog, main_content, false)
150
151 runOnUiThread {
152 AlertDialog.Builder(this)
153 .setTitle(R.string.status_node_info_dialog_title)
154 .setView(dialogTextView)
155 .setPositiveButton(R.string.status_node_info_dialog_close_action) { _, _ -> Unit }
156 .show()
157 }
158
159 TincVpnService.getCurrentNetName()?.let { netName ->
160 Tinc.info(netName, nodeName).thenAccept { nodeInfo ->
161 runOnUiThread { dialogTextView.dialog_node_details.text = nodeInfo }
162 }
163 }
164 }
165
166 private fun updateView() = when {
167 TincVpnService.isConnected() -> updateNodeList()
168 else -> openStartActivity()
169 }
170
171 private fun openStartActivity() {
172 startActivity(Intent(this, StartActivity::class.java).addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP))
173 finish()
174 }
175
176 companion object {
177 private const val REFRESH_RATE = 5000L
178 private const val NOW = 0L
179
180 fun getNodeNames(): CompletableFuture<List<String>> = TincVpnService.getCurrentNetName()?.let { netName ->
181 Tinc.dumpNodes(netName).thenApply<List<String>> { list -> list.map { it.substringBefore(' ') } }
182 } ?: Executor.supplyAsyncTask<List<String>> { emptyList() }
183 }
184}