MainFragment.kt 7.91 KB
Newer Older
Daniel Wolf's avatar
Daniel Wolf committed
1
2
3
package com.frostnerd.smokescreen.fragment

import android.app.Activity
4
import android.content.ActivityNotFoundException
Daniel Wolf's avatar
Daniel Wolf committed
5
6
import android.content.BroadcastReceiver
import android.content.Intent
7
import android.net.Uri
Daniel Wolf's avatar
Daniel Wolf committed
8
9
10
11
12
13
14
15
import android.net.VpnService
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.view.animation.Animation
import android.view.animation.LinearInterpolator
import android.view.animation.RotateAnimation
16
import android.widget.TextView
17
import android.widget.Toast
Daniel Wolf's avatar
Daniel Wolf committed
18
import androidx.appcompat.app.AppCompatActivity
Daniel Wolf's avatar
Daniel Wolf committed
19
import androidx.fragment.app.Fragment
Daniel Wolf's avatar
Daniel Wolf committed
20
import com.frostnerd.dnstunnelproxy.DnsServerInformation
Daniel Wolf's avatar
Daniel Wolf committed
21
import com.frostnerd.general.service.isServiceRunning
22
import com.frostnerd.smokescreen.*
23
import com.frostnerd.smokescreen.activity.SpeedTestActivity
24
import com.frostnerd.smokescreen.dialog.ServerChoosalDialog
Daniel Wolf's avatar
Daniel Wolf committed
25
26
import com.frostnerd.smokescreen.service.Command
import com.frostnerd.smokescreen.service.DnsVpnService
27
import com.frostnerd.smokescreen.service.RootDnsService
Daniel Wolf's avatar
Daniel Wolf committed
28
import kotlinx.android.synthetic.main.fragment_main.*
29
30
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
Daniel Wolf's avatar
Daniel Wolf committed
31
import java.net.URL
Daniel Wolf's avatar
Daniel Wolf committed
32
33


Daniel Wolf's avatar
Daniel Wolf committed
34
35
/*
 * Copyright (C) 2019 Daniel Wolf (Ch4t4r)
Daniel Wolf's avatar
Daniel Wolf committed
36
 *
Daniel Wolf's avatar
Daniel Wolf committed
37
38
39
40
41
42
43
44
45
46
47
48
49
50
 * 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 <http://www.gnu.org/licenses/>.
 *
 * You can contact the developer at daniel.wolf@frostnerd.com.
Daniel Wolf's avatar
Daniel Wolf committed
51
 */
52
53
class MainFragment : Fragment() {
    private val vpnRequestCode: Int = 1
Daniel Wolf's avatar
Daniel Wolf committed
54
    private var loadingAnimation: RotateAnimation? = null
55
    private var proxyRunning: Boolean = false
Daniel Wolf's avatar
Daniel Wolf committed
56
    private var proxyStarting = false
57
    private var vpnStateReceiver: BroadcastReceiver? = null
Daniel Wolf's avatar
Daniel Wolf committed
58
59
60
61
62
63
64

    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
        return inflater.inflate(R.layout.fragment_main, container, false)
    }

    override fun onResume() {
        super.onResume()
Daniel Wolf's avatar
Daniel Wolf committed
65
        proxyRunning = requireContext().isServiceRunning(DnsVpnService::class.java)
66
        updateVpnIndicators()
Daniel Wolf's avatar
Daniel Wolf committed
67
68
69
70
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        startButton.setOnClickListener {
71
            if (proxyRunning) {
Daniel Wolf's avatar
Daniel Wolf committed
72
73
74
75
76
77
78
                DnsVpnService.sendCommand(requireContext(), Command.STOP)
                proxyStarting = true
                proxyRunning = false
            } else {
                startVpn()
                proxyStarting = true
            }
79
            updateVpnIndicators()
Daniel Wolf's avatar
Daniel Wolf committed
80
        }
81
82
83
84
        startButton.setOnLongClickListener {
            context!!.startForegroundServiceCompat(Intent(context!!, RootDnsService::class.java))
            true
        }
85
86
87
        speedTest.setOnClickListener {
            startActivity(Intent(context!!, SpeedTestActivity::class.java))
        }
88
89
90
91
92
93
94
95
        vpnStateReceiver = requireContext().registerLocalReceiver(
            listOf(
                DnsVpnService.BROADCAST_VPN_ACTIVE,
                DnsVpnService.BROADCAST_VPN_INACTIVE
            )
        ) {
            if (it != null && it.action != null) {
                when (it.action) {
Daniel Wolf's avatar
Daniel Wolf committed
96
97
98
99
100
101
102
103
104
                    DnsVpnService.BROADCAST_VPN_ACTIVE -> {
                        proxyStarting = false
                        proxyRunning = true
                    }
                    DnsVpnService.BROADCAST_VPN_INACTIVE -> {
                        proxyRunning = false
                        proxyStarting = false
                    }
                }
105
                updateVpnIndicators()
Daniel Wolf's avatar
Daniel Wolf committed
106
107
108
            }
        }
        serverButton.setOnClickListener {
109
            ServerChoosalDialog(requireActivity() as AppCompatActivity) { config ->
Daniel Wolf's avatar
Daniel Wolf committed
110
                updatePrivacyPolicyLink(config)
111
                val prefs = requireContext().getPreferences()
112
                prefs.edit {
Daniel Wolf's avatar
Daniel Wolf committed
113
                    prefs.dnsServerConfig = config
114
                }
Daniel Wolf's avatar
Daniel Wolf committed
115
                println("Saved $config")
116
            }.show()
Daniel Wolf's avatar
Daniel Wolf committed
117
        }
118
        privacyStatementText.setOnClickListener {
119
            if (it.tag != null) {
120
121
122
                val i = Intent(Intent.ACTION_VIEW)
                val url = it.tag as URL
                i.data = Uri.parse(url.toURI().toString())
123
124
125
                try {
                    startActivity(i)
                } catch (e: ActivityNotFoundException) { Toast.makeText(context!!, R.string.error_no_webbrowser_installed, Toast.LENGTH_LONG).show() }
126
            }
127
        }
128
        GlobalScope.launch {
129
130
131
            val context = context
            if (isAdded && !isDetached && context != null) {
                val config = context.getPreferences().dnsServerConfig
132
                updatePrivacyPolicyLink(config)
133
134
            }
        }
135
        updateVpnIndicators()
Daniel Wolf's avatar
Daniel Wolf committed
136
137
138
139
    }

    override fun onDestroy() {
        super.onDestroy()
140
        if (vpnStateReceiver != null) requireContext().unregisterLocalReceiver(vpnStateReceiver!!)
Daniel Wolf's avatar
Daniel Wolf committed
141
142
143
144
145
    }

    fun startVpn() {
        val prepare = VpnService.prepare(requireContext())

146
        if (prepare == null) {
Daniel Wolf's avatar
Daniel Wolf committed
147
148
149
150
151
152
153
            requireContext().startService(Intent(requireContext(), DnsVpnService::class.java))
        } else {
            startActivityForResult(prepare, vpnRequestCode)
        }
    }

    override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
154
        if (requestCode == vpnRequestCode && resultCode == Activity.RESULT_OK) {
Daniel Wolf's avatar
Daniel Wolf committed
155
            startVpn()
156
        } else if (requestCode == vpnRequestCode) {
Daniel Wolf's avatar
Daniel Wolf committed
157
            proxyStarting = false
158
            updateVpnIndicators()
Daniel Wolf's avatar
Daniel Wolf committed
159
160
161
        }
    }

162
    private fun updateVpnIndicators() {
Daniel Wolf's avatar
Daniel Wolf committed
163
164
165
166
167
168
169
170
        when {
            proxyRunning -> {
                statusImage.setImageResource(R.drawable.ic_lock)
                statusImage.clearAnimation()
                startButton.setText(R.string.all_stop)
            }
            proxyStarting -> {
                startButton.setText(R.string.all_stop)
171
172
173
174
175
176
177
178
179
                if (loadingAnimation == null) {
                    loadingAnimation = RotateAnimation(
                        0f,
                        360f,
                        Animation.RELATIVE_TO_SELF,
                        0.5f,
                        Animation.RELATIVE_TO_SELF,
                        0.5f
                    )
Daniel Wolf's avatar
Daniel Wolf committed
180
181
182
183
                    loadingAnimation?.repeatCount = Animation.INFINITE
                    loadingAnimation?.duration = 2300
                    loadingAnimation?.interpolator = LinearInterpolator()
                    statusImage.startAnimation(loadingAnimation)
184
                } else if (!loadingAnimation!!.hasStarted() || loadingAnimation!!.hasEnded()) {
Daniel Wolf's avatar
Daniel Wolf committed
185
186
187
188
189
190
191
192
193
194
195
                    statusImage.startAnimation(loadingAnimation)
                }
                statusImage.setImageResource(R.drawable.ic_spinner)
            }
            else -> {
                startButton.setText(R.string.all_start)
                statusImage.setImageResource(R.drawable.ic_lock_open)
                statusImage.clearAnimation()
            }
        }
    }
196

197
    private fun updatePrivacyPolicyLink(serverInfo: DnsServerInformation<*>) {
198
        activity?.runOnUiThread {
199
            val url = serverInfo.specification.privacyPolicyURL
200
201
202
203
204
205
206
            val text = view?.findViewById<TextView>(R.id.privacyStatementText)
            if (url != null && text != null) {
                text.text = getString(R.string.main_dnssurveillance_privacystatement, serverInfo.name)
                text.tag = url
                text.visibility = View.VISIBLE
            } else if(text != null){
                text.visibility = View.GONE
207
            }
208
209
        }
    }
Daniel Wolf's avatar
Daniel Wolf committed
210
}