diff options
author | pacien | 2018-08-19 18:04:58 +0200 |
---|---|---|
committer | pacien | 2018-08-19 18:04:58 +0200 |
commit | 483e6634e0621d2100ae11cbcd8cba6d21a76c4e (patch) | |
tree | 0d2fda7f5e6026c5f091df2188f2e8396de42091 /app/src/main/java/org/pacien | |
parent | 3b353c4037f3c52710287777a17110dad6b9d720 (diff) | |
download | tincapp-483e6634e0621d2100ae11cbcd8cba6d21a76c4e.tar.gz |
Refactor log viewer activity
Diffstat (limited to 'app/src/main/java/org/pacien')
7 files changed, 242 insertions, 166 deletions
diff --git a/app/src/main/java/org/pacien/tincapp/activities/BaseActivity.kt b/app/src/main/java/org/pacien/tincapp/activities/BaseActivity.kt index af71544..a51d401 100644 --- a/app/src/main/java/org/pacien/tincapp/activities/BaseActivity.kt +++ b/app/src/main/java/org/pacien/tincapp/activities/BaseActivity.kt | |||
@@ -18,6 +18,7 @@ | |||
18 | 18 | ||
19 | package org.pacien.tincapp.activities | 19 | package org.pacien.tincapp.activities |
20 | 20 | ||
21 | import android.content.Intent | ||
21 | import android.os.Bundle | 22 | import android.os.Bundle |
22 | import android.support.annotation.LayoutRes | 23 | import android.support.annotation.LayoutRes |
23 | import android.support.annotation.StringRes | 24 | import android.support.annotation.StringRes |
@@ -68,6 +69,13 @@ abstract class BaseActivity : AppCompatActivity() { | |||
68 | super.onStop() | 69 | super.onStop() |
69 | } | 70 | } |
70 | 71 | ||
72 | override fun getSupportActionBar() = super.getSupportActionBar()!! | ||
73 | |||
74 | fun startActivityChooser(target: Intent, title: String) { | ||
75 | val intentChooser = Intent.createChooser(target, title) | ||
76 | startActivity(intentChooser) | ||
77 | } | ||
78 | |||
71 | fun aboutDialog(@Suppress("UNUSED_PARAMETER") i: MenuItem) { | 79 | fun aboutDialog(@Suppress("UNUSED_PARAMETER") i: MenuItem) { |
72 | AlertDialog.Builder(this) | 80 | AlertDialog.Builder(this) |
73 | .setTitle(resources.getString(R.string.app_name)) | 81 | .setTitle(resources.getString(R.string.app_name)) |
diff --git a/app/src/main/java/org/pacien/tincapp/activities/ViewLogActivity.kt b/app/src/main/java/org/pacien/tincapp/activities/ViewLogActivity.kt deleted file mode 100644 index f3f7e24..0000000 --- a/app/src/main/java/org/pacien/tincapp/activities/ViewLogActivity.kt +++ /dev/null | |||
@@ -1,164 +0,0 @@ | |||
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 | |||
19 | package org.pacien.tincapp.activities | ||
20 | |||
21 | import android.content.Intent | ||
22 | import android.os.Bundle | ||
23 | import android.view.Menu | ||
24 | import android.view.MenuItem | ||
25 | import android.view.View | ||
26 | import android.widget.ScrollView | ||
27 | import kotlinx.android.synthetic.main.base.* | ||
28 | import kotlinx.android.synthetic.main.page_viewlog.* | ||
29 | import org.pacien.tincapp.R | ||
30 | import org.pacien.tincapp.commands.Executor | ||
31 | import org.pacien.tincapp.commands.Tinc | ||
32 | import org.pacien.tincapp.service.TincVpnService | ||
33 | import java.util.* | ||
34 | import kotlin.concurrent.timer | ||
35 | |||
36 | /** | ||
37 | * @author pacien | ||
38 | */ | ||
39 | class ViewLogActivity : BaseActivity() { | ||
40 | companion object { | ||
41 | private const val LOG_LINES = 250 | ||
42 | private const val LOG_LEVEL = 5 | ||
43 | private const val NEW_LINE = "\n" | ||
44 | private const val SPACED_NEW_LINE = "\n\n" | ||
45 | private const val UPDATE_INTERVAL = 250L // ms | ||
46 | private const val MIME_TYPE = "text/plain" | ||
47 | } | ||
48 | |||
49 | private val log = LinkedList<String>() | ||
50 | private var logUpdateTimer: Timer? = null | ||
51 | private var logger: Process? = null | ||
52 | private var toggleButton: MenuItem? = null | ||
53 | |||
54 | override fun onCreate(savedInstanceState: Bundle?) { | ||
55 | super.onCreate(savedInstanceState) | ||
56 | supportActionBar!!.setDisplayHomeAsUpEnabled(true) | ||
57 | layoutInflater.inflate(R.layout.page_viewlog, main_content) | ||
58 | toggleLogging(true) | ||
59 | } | ||
60 | |||
61 | override fun onCreateOptionsMenu(m: Menu): Boolean { | ||
62 | menuInflater.inflate(R.menu.menu_viewlog, m) | ||
63 | toggleButton = m.findItem(R.id.log_viewer_action_toggle) | ||
64 | return super.onCreateOptionsMenu(m) | ||
65 | } | ||
66 | |||
67 | override fun onSupportNavigateUp(): Boolean { | ||
68 | finish() | ||
69 | return true | ||
70 | } | ||
71 | |||
72 | override fun onDestroy() { | ||
73 | toggleLogging(false) | ||
74 | super.onDestroy() | ||
75 | } | ||
76 | |||
77 | fun share(@Suppress("UNUSED_PARAMETER") menuItem: MenuItem) { | ||
78 | synchronized(this) { | ||
79 | val logFragment = log.joinToString(NEW_LINE) | ||
80 | val shareIntent = Intent(Intent.ACTION_SEND) | ||
81 | .setType(MIME_TYPE) | ||
82 | .putExtra(Intent.EXTRA_TEXT, logFragment) | ||
83 | |||
84 | startActivity(Intent.createChooser(shareIntent, resources.getString(R.string.menu_share_log))) | ||
85 | } | ||
86 | } | ||
87 | |||
88 | fun toggleLogging(@Suppress("UNUSED_PARAMETER") menuItem: MenuItem) = toggleLogging(logger == null) | ||
89 | |||
90 | private fun toggleLogging(enable: Boolean) { | ||
91 | if (enable) { | ||
92 | disableUserScroll() | ||
93 | toggleButton?.setIcon(R.drawable.ic_pause_circle_outline_primary_24dp) | ||
94 | startLogging() | ||
95 | } else { | ||
96 | enableUserScroll() | ||
97 | toggleButton?.setIcon(R.drawable.ic_pause_circle_filled_primary_24dp) | ||
98 | stopLogging() | ||
99 | } | ||
100 | } | ||
101 | |||
102 | private fun startLogging(level: Int = LOG_LEVEL) { | ||
103 | appendLog(resources.getString(R.string.message_log_level_set, level)) | ||
104 | |||
105 | TincVpnService.getCurrentNetName()?.let { netName -> | ||
106 | Tinc.log(netName, level).let { process -> | ||
107 | logger = process | ||
108 | Executor.runAsyncTask { captureLog(process) } | ||
109 | } | ||
110 | logUpdateTimer = timer(period = UPDATE_INTERVAL, action = { printLog() }) | ||
111 | } ?: run { | ||
112 | appendLog(resources.getString(R.string.message_no_daemon)) | ||
113 | toggleLogging(false) | ||
114 | } | ||
115 | } | ||
116 | |||
117 | private fun stopLogging() { | ||
118 | logger?.destroy() | ||
119 | logger = null | ||
120 | logUpdateTimer?.cancel() | ||
121 | logUpdateTimer?.purge() | ||
122 | logUpdateTimer = null | ||
123 | appendLog(resources.getString(R.string.message_log_paused)) | ||
124 | printLog() | ||
125 | } | ||
126 | |||
127 | private fun captureLog(logger: Process) { | ||
128 | logger.inputStream?.use { inputStream -> | ||
129 | inputStream.bufferedReader().useLines { lines -> | ||
130 | lines.forEach { appendLog(it) } | ||
131 | } | ||
132 | } | ||
133 | } | ||
134 | |||
135 | private fun appendLog(line: String) = synchronized(this) { | ||
136 | if (log.size >= LOG_LINES) log.removeFirst() | ||
137 | log.addLast(line) | ||
138 | } | ||
139 | |||
140 | private fun printLog() = synchronized(this) { | ||
141 | log.joinToString(SPACED_NEW_LINE).let { | ||
142 | logview_text.post { | ||
143 | logview_text.text = it | ||
144 | logview_frame.post { logview_frame.fullScroll(View.FOCUS_DOWN) } | ||
145 | } | ||
146 | } | ||
147 | } | ||
148 | |||
149 | private fun enableUserScroll() { | ||
150 | logview_text.setTextIsSelectable(true) | ||
151 | logview_frame.setState(true) | ||
152 | } | ||
153 | |||
154 | private fun disableUserScroll() { | ||
155 | logview_text.setTextIsSelectable(false) | ||
156 | logview_frame.setState(false) | ||
157 | } | ||
158 | |||
159 | private fun ScrollView.setState(enabled: Boolean) { | ||
160 | if (enabled) setOnTouchListener(null) else setOnTouchListener { _, _ -> true } | ||
161 | logview_frame.isSmoothScrollingEnabled = enabled | ||
162 | logview_frame.isVerticalScrollBarEnabled = enabled | ||
163 | } | ||
164 | } | ||