aboutsummaryrefslogtreecommitdiff
path: root/app/src/main/java/org/pacien
diff options
context:
space:
mode:
Diffstat (limited to 'app/src/main/java/org/pacien')
-rw-r--r--app/src/main/java/org/pacien/tincapp/activities/StartActivity.kt204
-rw-r--r--app/src/main/java/org/pacien/tincapp/activities/start/ConnectionStarter.kt69
-rw-r--r--app/src/main/java/org/pacien/tincapp/activities/start/NetworkListFragment.kt84
-rw-r--r--app/src/main/java/org/pacien/tincapp/activities/start/NetworkListLiveData.kt46
-rw-r--r--app/src/main/java/org/pacien/tincapp/activities/start/NetworkListViewModel.kt28
-rw-r--r--app/src/main/java/org/pacien/tincapp/activities/start/StartActivity.kt117
-rw-r--r--app/src/main/java/org/pacien/tincapp/activities/status/StatusActivity.kt2
-rw-r--r--app/src/main/java/org/pacien/tincapp/activities/status/nodes/NodeListFragment.kt2
-rw-r--r--app/src/main/java/org/pacien/tincapp/service/TincVpnService.kt2
9 files changed, 347 insertions, 207 deletions
diff --git a/app/src/main/java/org/pacien/tincapp/activities/StartActivity.kt b/app/src/main/java/org/pacien/tincapp/activities/StartActivity.kt
deleted file mode 100644
index 7023316..0000000
--- a/app/src/main/java/org/pacien/tincapp/activities/StartActivity.kt
+++ /dev/null
@@ -1,204 +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
19package org.pacien.tincapp.activities
20
21import android.app.Activity
22import android.content.Intent
23import android.net.VpnService
24import android.os.Bundle
25import android.support.v4.widget.SwipeRefreshLayout
26import android.support.v7.app.AlertDialog
27import android.view.Menu
28import android.view.MenuItem
29import android.view.View
30import android.widget.AdapterView
31import android.widget.ArrayAdapter
32import android.widget.TextView
33import kotlinx.android.synthetic.main.base.*
34import kotlinx.android.synthetic.main.dialog_decrypt_keys.view.*
35import kotlinx.android.synthetic.main.fragment_list_view.*
36import kotlinx.android.synthetic.main.fragment_network_list_header.*
37import org.pacien.tincapp.R
38import org.pacien.tincapp.activities.common.ProgressModal
39import org.pacien.tincapp.activities.configure.ConfigureActivity
40import org.pacien.tincapp.activities.status.StatusActivity
41import org.pacien.tincapp.context.AppPaths
42import org.pacien.tincapp.extensions.setElements
43import org.pacien.tincapp.intent.Actions
44import org.pacien.tincapp.intent.BroadcastMapper
45import org.pacien.tincapp.service.TincVpnService
46import org.pacien.tincapp.utils.TincKeyring
47
48/**
49 * @author pacien
50 */
51class StartActivity : BaseActivity() {
52 companion object {
53 private const val PERMISSION_REQUEST = 0
54 }
55
56 private val networkList = object : AdapterView.OnItemClickListener, SwipeRefreshLayout.OnRefreshListener {
57 private var networkListAdapter: ArrayAdapter<String>? = null
58
59 fun init() {
60 networkListAdapter = ArrayAdapter(this@StartActivity, R.layout.fragment_list_item)
61 layoutInflater.inflate(R.layout.fragment_list_view, main_content)
62 list_wrapper.setOnRefreshListener(this)
63 list.addHeaderView(layoutInflater.inflate(R.layout.fragment_network_list_header, list, false), null, false)
64 list.addFooterView(View(this@StartActivity), null, false)
65 list.adapter = networkListAdapter
66 list.onItemClickListener = this
67 }
68
69 fun destroy() {
70 networkListAdapter = null
71 }
72
73 override fun onRefresh() {
74 val networks = AppPaths.confDir().list()?.sorted() ?: emptyList()
75 runOnUiThread {
76 networkListAdapter?.setElements(networks)
77 setPlaceholderVisibility()
78 list_wrapper.isRefreshing = false
79 }
80 }
81
82 override fun onItemClick(parent: AdapterView<*>?, view: View?, position: Int, id: Long) {
83 connectionStarter.tryStart(netName = (view as TextView).text.toString(), displayStatus = true)
84 }
85
86 private fun setPlaceholderVisibility() = if (networkListAdapter?.isEmpty != false) {
87 network_list_placeholder.text = getListPlaceholderText()
88 network_list_placeholder.visibility = View.VISIBLE
89 } else {
90 network_list_placeholder.visibility = View.GONE
91 }
92
93 private fun getListPlaceholderText() = if (!AppPaths.storageAvailable()) {
94 getText(R.string.message_storage_unavailable)
95 } else {
96 getText(R.string.message_no_network_configuration_found)
97 }
98 }
99
100 private val connectionStarter = object {
101 private var netName: String? = null
102 private var passphrase: String? = null
103 private var displayStatus = false
104
105 fun displayStatus() = displayStatus
106
107 fun tryStart(netName: String? = null, passphrase: String? = null, displayStatus: Boolean? = null) {
108 if (netName != null) this.netName = netName
109 this.passphrase = passphrase
110 if (displayStatus != null) this.displayStatus = displayStatus
111
112 val permissionRequestIntent = VpnService.prepare(this@StartActivity)
113 if (permissionRequestIntent != null)
114 return startActivityForResult(permissionRequestIntent, PERMISSION_REQUEST)
115
116 if (TincKeyring.needsPassphrase(this.netName!!) && this.passphrase == null)
117 return askForPassphrase()
118
119 startVpn(this.netName!!, this.passphrase)
120 }
121
122 private fun askForPassphrase() {
123 layoutInflater.inflate(R.layout.dialog_decrypt_keys, main_content, false).let { dialog ->
124 AlertDialog.Builder(this@StartActivity)
125 .setTitle(R.string.title_unlock_private_keys).setView(dialog)
126 .setPositiveButton(R.string.action_unlock) { _, _ -> tryStart(passphrase = dialog.passphrase.text.toString()) }
127 .setNegativeButton(R.string.action_cancel) { _, _ -> Unit }
128 .show()
129 }
130 }
131
132 private fun startVpn(netName: String, passphrase: String? = null) {
133 connectDialog = ProgressModal.show(this@StartActivity, getString(R.string.message_starting_vpn))
134 TincVpnService.connect(netName, passphrase)
135 }
136 }
137
138 private val broadcastMapper = BroadcastMapper(mapOf(
139 Actions.EVENT_CONNECTED to this::onVpnStart,
140 Actions.EVENT_ABORTED to this::onVpnStartError))
141
142 private var connectDialog: AlertDialog? = null
143
144 override fun onCreate(savedInstanceState: Bundle?) {
145 super.onCreate(savedInstanceState)
146 networkList.init()
147
148 if (intent.action == Actions.ACTION_CONNECT && intent.data?.schemeSpecificPart != null)
149 connectionStarter.tryStart(intent.data.schemeSpecificPart, intent.data.fragment, false)
150 }
151
152 override fun onCreateOptionsMenu(m: Menu): Boolean {
153 menuInflater.inflate(R.menu.menu_start, m)
154 return super.onCreateOptionsMenu(m)
155 }
156
157 override fun onDestroy() {
158 networkList.destroy()
159 connectDialog?.dismiss()
160 super.onDestroy()
161 }
162
163 override fun onStart() {
164 super.onStart()
165 networkList.onRefresh()
166 }
167
168 override fun onResume() {
169 super.onResume()
170 if (TincVpnService.isConnected()) openStatusActivity(false)
171 broadcastMapper.register()
172 handleRecentCrash()
173 }
174
175 override fun onPause() {
176 broadcastMapper.unregister()
177 super.onPause()
178 }
179
180 override fun onActivityResult(request: Int, result: Int, data: Intent?): Unit = when (request) {
181 PERMISSION_REQUEST -> if (result == Activity.RESULT_OK) connectionStarter.tryStart() else Unit
182 else -> throw IllegalArgumentException("Result for unknown request received.")
183 }
184
185 fun openConfigureActivity(@Suppress("UNUSED_PARAMETER") i: MenuItem) =
186 startActivity(Intent(this, ConfigureActivity::class.java))
187
188 private fun onVpnStart() {
189 connectDialog?.dismiss()
190 if (connectionStarter.displayStatus()) openStatusActivity()
191 finish()
192 }
193
194 private