diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index c2af3f9..a695d06 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -3,41 +3,53 @@ xmlns:tools="http://schemas.android.com/tools"> + + android:theme="@style/Theme.Transparent"> + - - - + + + + + + + - \ No newline at end of file diff --git a/app/src/main/java/ru/karasevm/privatednstoggle/DNSServerDialogFragment.kt b/app/src/main/java/ru/karasevm/privatednstoggle/DNSServerDialogFragment.kt new file mode 100644 index 0000000..7713217 --- /dev/null +++ b/app/src/main/java/ru/karasevm/privatednstoggle/DNSServerDialogFragment.kt @@ -0,0 +1,88 @@ +package ru.karasevm.privatednstoggle + +import android.app.Dialog +import android.content.SharedPreferences +import android.os.Bundle +import android.widget.Toast +import androidx.fragment.app.DialogFragment +import androidx.recyclerview.widget.LinearLayoutManager +import com.google.android.material.dialog.MaterialAlertDialogBuilder +import ru.karasevm.privatednstoggle.databinding.SheetDnsSelectorBinding +import ru.karasevm.privatednstoggle.utils.PreferenceHelper.defaultPreference +import ru.karasevm.privatednstoggle.utils.PreferenceHelper.dns_servers +import ru.karasevm.privatednstoggle.utils.PrivateDNSUtils + +class DNSServerDialogFragment: DialogFragment() { + + private var _binding: SheetDnsSelectorBinding? = null + private val binding get() = _binding!! + + private lateinit var linearLayoutManager: LinearLayoutManager + private lateinit var adapter: RecyclerAdapter + private var items = mutableListOf() + private lateinit var sharedPrefs: SharedPreferences + + override fun onCreateDialog( + savedInstanceState: Bundle? + ): Dialog { + return activity?.let { + val builder = MaterialAlertDialogBuilder(it) + val inflater = requireActivity().layoutInflater + _binding = SheetDnsSelectorBinding.inflate(inflater) + + linearLayoutManager = LinearLayoutManager(context) + binding.recyclerView.layoutManager = linearLayoutManager + + sharedPrefs = defaultPreference(requireContext()) + items = sharedPrefs.dns_servers + if(items[0] == "") { + items.removeAt(0) + items.add("dns.google") + } + + adapter = RecyclerAdapter(items) + binding.recyclerView.adapter = adapter + + builder.setTitle(R.string.select_server) + .setView(binding.root) + .setPositiveButton(R.string.done + ) { _, _ -> + dialog?.dismiss() + } + builder.create() + } ?: throw IllegalStateException("Activity cannot be null") + } + + override fun onStart() { + super.onStart() + val dnsMode = PrivateDNSUtils.getPrivateMode(requireActivity().contentResolver) + binding.autoSwitch.isChecked = dnsMode.lowercase() == "opportunistic" + + adapter.onItemClick = { position -> + binding.autoSwitch.isChecked = false + val server = items[position] + PrivateDNSUtils.setPrivateMode(requireActivity().contentResolver, PrivateDNSUtils.DNS_MODE_PRIVATE) + PrivateDNSUtils.setPrivateProvider(requireActivity().contentResolver, server) + Toast.makeText(context, "DNS Server Set", Toast.LENGTH_SHORT).show() + } + + binding.autoSwitch.setOnClickListener { + if(binding.autoSwitch.isChecked) { + PrivateDNSUtils.setPrivateMode(requireActivity().contentResolver, PrivateDNSUtils.DNS_MODE_AUTO) + Toast.makeText(context, "DNS Server Set to Auto", Toast.LENGTH_SHORT).show() + } else { + PrivateDNSUtils.setPrivateMode(requireActivity().contentResolver, PrivateDNSUtils.DNS_MODE_PRIVATE) + Toast.makeText(context, "DNS Server Set", Toast.LENGTH_SHORT).show() + } + } + } + + override fun onDestroy() { + super.onDestroy() + activity?.finish() + } + + companion object { + const val TAG = "DNSServerDialogFragment" + } +} \ No newline at end of file diff --git a/app/src/main/java/ru/karasevm/privatednstoggle/DnsTileService.kt b/app/src/main/java/ru/karasevm/privatednstoggle/DnsTileService.kt index 1e19dac..5a33aa9 100644 --- a/app/src/main/java/ru/karasevm/privatednstoggle/DnsTileService.kt +++ b/app/src/main/java/ru/karasevm/privatednstoggle/DnsTileService.kt @@ -1,34 +1,23 @@ package ru.karasevm.privatednstoggle -import android.Manifest -import android.content.pm.PackageManager import android.graphics.drawable.Icon import android.provider.Settings import android.service.quicksettings.Tile import android.service.quicksettings.TileService -import android.widget.Toast import ru.karasevm.privatednstoggle.utils.PreferenceHelper import ru.karasevm.privatednstoggle.utils.PreferenceHelper.autoMode import ru.karasevm.privatednstoggle.utils.PreferenceHelper.dns_servers - -const val DNS_MODE_OFF = "off" -const val DNS_MODE_AUTO = "opportunistic" -const val DNS_MODE_PRIVATE = "hostname" +import ru.karasevm.privatednstoggle.utils.PrivateDNSUtils +import ru.karasevm.privatednstoggle.utils.PrivateDNSUtils.DNS_MODE_AUTO +import ru.karasevm.privatednstoggle.utils.PrivateDNSUtils.DNS_MODE_OFF +import ru.karasevm.privatednstoggle.utils.PrivateDNSUtils.DNS_MODE_PRIVATE +import ru.karasevm.privatednstoggle.utils.PrivateDNSUtils.checkForPermission class DnsTileService : TileService() { - - private fun checkForPermission(): Boolean { - if (checkSelfPermission(Manifest.permission.WRITE_SECURE_SETTINGS) == PackageManager.PERMISSION_GRANTED) { - return true - } - Toast.makeText(this, R.string.permission_missing, Toast.LENGTH_SHORT).show() - return false - } - override fun onTileAdded() { super.onTileAdded() - checkForPermission() + checkForPermission(this) // Update state qsTile.state = Tile.STATE_INACTIVE @@ -38,7 +27,7 @@ class DnsTileService : TileService() { override fun onClick() { super.onClick() - if (!checkForPermission()) { + if (!checkForPermission(this)) { return } @@ -104,7 +93,7 @@ class DnsTileService : TileService() { override fun onStartListening() { super.onStartListening() - if (!checkForPermission()) { + if (!checkForPermission(this)) { return } val dnsMode = Settings.Global.getString(contentResolver, "private_dns_mode") @@ -137,16 +126,12 @@ class DnsTileService : TileService() { ) } else if (dnsMode.equals(DNS_MODE_PRIVATE, ignoreCase = true)) { val dnsProvider = Settings.Global.getString(contentResolver, "private_dns_specifier") - if (dnsProvider != null) { - refreshTile( - qsTile, - Tile.STATE_ACTIVE, - dnsProvider, - R.drawable.ic_private_black_24dp - ) - } else { - Toast.makeText(this, R.string.permission_missing, Toast.LENGTH_SHORT).show() - } + refreshTile( + qsTile, + Tile.STATE_ACTIVE, + dnsProvider, + R.drawable.ic_private_black_24dp + ) } } @@ -187,8 +172,8 @@ class DnsTileService : TileService() { tile.label = label tile.state = state tile.icon = Icon.createWithResource(this, icon) - Settings.Global.putString(contentResolver, "private_dns_mode", dnsMode) - Settings.Global.putString(contentResolver, "private_dns_specifier", dnsProvider) + PrivateDNSUtils.setPrivateMode(contentResolver, dnsMode) + PrivateDNSUtils.setPrivateProvider(contentResolver, dnsProvider) tile.updateTile() } diff --git a/app/src/main/java/ru/karasevm/privatednstoggle/SettingsDialogActivity.kt b/app/src/main/java/ru/karasevm/privatednstoggle/SettingsDialogActivity.kt new file mode 100644 index 0000000..c8a86b6 --- /dev/null +++ b/app/src/main/java/ru/karasevm/privatednstoggle/SettingsDialogActivity.kt @@ -0,0 +1,12 @@ +package ru.karasevm.privatednstoggle + +import android.os.Bundle +import androidx.appcompat.app.AppCompatActivity + +class SettingsDialogActivity : AppCompatActivity() { + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + val newFragment = DNSServerDialogFragment() + newFragment.show(supportFragmentManager, DNSServerDialogFragment.TAG) + } +} \ No newline at end of file diff --git a/app/src/main/java/ru/karasevm/privatednstoggle/utils/PrivateDNSUtils.kt b/app/src/main/java/ru/karasevm/privatednstoggle/utils/PrivateDNSUtils.kt new file mode 100644 index 0000000..521e53f --- /dev/null +++ b/app/src/main/java/ru/karasevm/privatednstoggle/utils/PrivateDNSUtils.kt @@ -0,0 +1,44 @@ +package ru.karasevm.privatednstoggle.utils + +import android.Manifest +import android.content.ContentResolver +import android.content.Context +import android.content.pm.PackageManager +import android.provider.Settings +import android.widget.Toast +import androidx.core.content.ContextCompat.checkSelfPermission +import ru.karasevm.privatednstoggle.R + +object PrivateDNSUtils { + const val DNS_MODE_OFF = "off" + const val DNS_MODE_AUTO = "opportunistic" + const val DNS_MODE_PRIVATE = "hostname" + + private const val PRIVATE_DNS_MODE = "private_dns_mode" + private const val PRIVATE_DNS_PROVIDER = "private_dns_specifier" + + fun getPrivateMode(contentResolver: ContentResolver): String { + return Settings.Global.getString(contentResolver, PRIVATE_DNS_MODE) + } + + fun getPrivateProvider(contentResolver: ContentResolver): String { + return Settings.Global.getString(contentResolver, PRIVATE_DNS_PROVIDER) + } + + fun setPrivateMode(contentResolver: ContentResolver, value: String) { + Settings.Global.putString(contentResolver, PRIVATE_DNS_MODE, value) + } + + fun setPrivateProvider(contentResolver: ContentResolver, value: String?) { + Settings.Global.putString(contentResolver, PRIVATE_DNS_PROVIDER, value) + } + + fun checkForPermission(context: Context): Boolean { + if (checkSelfPermission(context, Manifest.permission.WRITE_SECURE_SETTINGS) == PackageManager.PERMISSION_GRANTED) { + return true + } + Toast.makeText(context, R.string.permission_missing, Toast.LENGTH_SHORT).show() + return false + } + +} \ No newline at end of file diff --git a/app/src/main/res/layout/sheet_dns_selector.xml b/app/src/main/res/layout/sheet_dns_selector.xml new file mode 100644 index 0000000..6cf14cb --- /dev/null +++ b/app/src/main/res/layout/sheet_dns_selector.xml @@ -0,0 +1,44 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 2f37be2..c148b93 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -9,7 +9,9 @@ Add Privacy Policy Enable auto + Select Server Automatic (opportunistic) DNS mode will now be available in the tile + Done Cancel Delete Are you sure you want to delete server? diff --git a/app/src/main/res/values/themes.xml b/app/src/main/res/values/themes.xml index 7cf8d95..2f2bf2c 100644 --- a/app/src/main/res/values/themes.xml +++ b/app/src/main/res/values/themes.xml @@ -10,4 +10,17 @@ true @android:color/transparent + + \ No newline at end of file