Use Android KTX

This commit is contained in:
Mygod
2018-07-15 20:58:39 +08:00
parent d0e92b2505
commit af20a084cb
12 changed files with 43 additions and 59 deletions

View File

@@ -45,6 +45,7 @@ dependencies {
implementation 'com.android.billingclient:billing:1.1' implementation 'com.android.billingclient:billing:1.1'
implementation "androidx.browser:browser:$androidxVersion" implementation "androidx.browser:browser:$androidxVersion"
implementation 'androidx.constraintlayout:constraintlayout:2.0.0-alpha1' implementation 'androidx.constraintlayout:constraintlayout:2.0.0-alpha1'
implementation "androidx.core:core-ktx:$androidxVersion"
implementation "androidx.preference:preference:$androidxVersion" implementation "androidx.preference:preference:$androidxVersion"
implementation 'com.crashlytics.sdk.android:crashlytics:2.9.4' implementation 'com.crashlytics.sdk.android:crashlytics:2.9.4'
implementation 'com.github.luongvo:BadgeView:1.1.5' implementation 'com.github.luongvo:BadgeView:1.1.5'

View File

@@ -12,13 +12,12 @@ import android.os.Handler
import android.preference.PreferenceManager import android.preference.PreferenceManager
import androidx.annotation.StringRes import androidx.annotation.StringRes
import android.widget.Toast import android.widget.Toast
import androidx.core.content.getSystemService
import be.mygod.vpnhotspot.util.Event0 import be.mygod.vpnhotspot.util.Event0
import be.mygod.vpnhotspot.util.systemService
class App : Application() { class App : Application() {
companion object { companion object {
const val KEY_OPERATING_CHANNEL = "service.repeater.oc" const val KEY_OPERATING_CHANNEL = "service.repeater.oc"
private const val KEY_DNS = "service.dns"
private const val KEY_MASQUERADE = "service.masquerade" private const val KEY_MASQUERADE = "service.masquerade"
@SuppressLint("StaticFieldLeak") @SuppressLint("StaticFieldLeak")
@@ -32,9 +31,6 @@ class App : Application() {
deviceContext = createDeviceProtectedStorageContext() deviceContext = createDeviceProtectedStorageContext()
deviceContext.moveSharedPreferencesFrom(this, PreferenceManager.getDefaultSharedPreferencesName(this)) deviceContext.moveSharedPreferencesFrom(this, PreferenceManager.getDefaultSharedPreferencesName(this))
} else deviceContext = this } else deviceContext = this
// workaround for support lib PreferenceDataStore bug
dns = dns
masquerade = masquerade
ServiceNotification.updateNotificationChannels() ServiceNotification.updateNotificationChannels()
} }
@@ -46,19 +42,14 @@ class App : Application() {
lateinit var deviceContext: Context lateinit var deviceContext: Context
val handler = Handler() val handler = Handler()
val pref: SharedPreferences by lazy { PreferenceManager.getDefaultSharedPreferences(deviceContext) } val pref: SharedPreferences by lazy { PreferenceManager.getDefaultSharedPreferences(deviceContext) }
val connectivity by lazy { systemService<ConnectivityManager>() } val connectivity by lazy { getSystemService<ConnectivityManager>()!! }
val wifi by lazy { systemService<WifiManager>() } val wifi by lazy { getSystemService<WifiManager>()!! }
val operatingChannel: Int get() { val operatingChannel: Int get() {
val result = pref.getString(KEY_OPERATING_CHANNEL, null)?.toIntOrNull() ?: 0 val result = pref.getString(KEY_OPERATING_CHANNEL, null)?.toIntOrNull() ?: 0
return if (result in 1..165) result else 0 return if (result in 1..165) result else 0
} }
var dns: String val masquerade: Boolean get() = pref.getBoolean(KEY_MASQUERADE, true)
get() = pref.getString(KEY_DNS, "8.8.8.8")
set(value) = pref.edit().putString(KEY_DNS, value).apply()
var masquerade: Boolean
get() = pref.getBoolean(KEY_MASQUERADE, true)
set(value) = pref.edit().putBoolean(KEY_MASQUERADE, value).apply()
val cleanRoutings = Event0() val cleanRoutings = Event0()

View File

@@ -1,9 +1,7 @@
package be.mygod.vpnhotspot package be.mygod.vpnhotspot
import android.app.AlertDialog import android.app.AlertDialog
import android.net.Uri
import android.os.Bundle import android.os.Bundle
import androidx.fragment.app.DialogFragment
import android.util.Log import android.util.Log
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
@@ -12,6 +10,8 @@ import android.view.ViewStub
import android.widget.ArrayAdapter import android.widget.ArrayAdapter
import android.widget.Button import android.widget.Button
import android.widget.Spinner import android.widget.Spinner
import androidx.core.net.toUri
import androidx.fragment.app.DialogFragment
import com.android.billingclient.api.* import com.android.billingclient.api.*
import com.crashlytics.android.Crashlytics import com.crashlytics.android.Crashlytics
@@ -55,7 +55,7 @@ class EBegFragment : DialogFragment(), PurchasesUpdatedListener, BillingClientSt
@Suppress("ConstantConditionIf") @Suppress("ConstantConditionIf")
if (BuildConfig.DONATIONS) (view.findViewById<ViewStub>(R.id.donations__more_stub).inflate() as Button) if (BuildConfig.DONATIONS) (view.findViewById<ViewStub>(R.id.donations__more_stub).inflate() as Button)
.setOnClickListener { .setOnClickListener {
(activity as MainActivity).launchUrl(Uri.parse("https://mygod.be/donate/")) (activity as MainActivity).launchUrl("https://mygod.be/donate/".toUri())
} }
} }

View File

@@ -13,6 +13,7 @@ import android.os.Looper
import androidx.annotation.StringRes import androidx.annotation.StringRes
import android.util.Log import android.util.Log
import android.widget.Toast import android.widget.Toast
import androidx.core.content.getSystemService
import be.mygod.vpnhotspot.App.Companion.app import be.mygod.vpnhotspot.App.Companion.app
import be.mygod.vpnhotspot.net.wifi.WifiP2pManagerHelper import be.mygod.vpnhotspot.net.wifi.WifiP2pManagerHelper
import be.mygod.vpnhotspot.net.wifi.WifiP2pManagerHelper.deletePersistentGroup import be.mygod.vpnhotspot.net.wifi.WifiP2pManagerHelper.deletePersistentGroup
@@ -130,7 +131,7 @@ class RepeaterService : Service(), WifiP2pManager.ChannelListener, SharedPrefere
override fun onCreate() { override fun onCreate() {
super.onCreate() super.onCreate()
try { try {
p2pManager = systemService() p2pManager = getSystemService()!!
onChannelDisconnected() onChannelDisconnected()
app.pref.registerOnSharedPreferenceChangeListener(this) app.pref.registerOnSharedPreferenceChangeListener(this)
} catch (exc: KotlinNullPointerException) { } catch (exc: KotlinNullPointerException) {

View File

@@ -7,15 +7,15 @@ import android.content.Intent
import android.os.Build import android.os.Build
import androidx.core.app.NotificationCompat import androidx.core.app.NotificationCompat
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
import androidx.core.content.getSystemService
import be.mygod.vpnhotspot.App.Companion.app import be.mygod.vpnhotspot.App.Companion.app
import be.mygod.vpnhotspot.util.systemService
object ServiceNotification { object ServiceNotification {
private const val CHANNEL = "tethering" private const val CHANNEL = "tethering"
private const val CHANNEL_ID = 1 private const val CHANNEL_ID = 1
private val deviceCountsMap = HashMap<Service, Map<String, Int>>() private val deviceCountsMap = HashMap<Service, Map<String, Int>>()
private val manager = app.systemService<NotificationManager>() private val manager = app.getSystemService<NotificationManager>()!!
private fun buildNotification(context: Context): Notification { private fun buildNotification(context: Context): Notification {
val builder = NotificationCompat.Builder(context, CHANNEL) val builder = NotificationCompat.Builder(context, CHANNEL)

View File

@@ -2,10 +2,11 @@ package be.mygod.vpnhotspot
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import android.net.Uri
import android.os.Build import android.os.Build
import android.os.Bundle import android.os.Bundle
import androidx.core.content.FileProvider import androidx.core.content.FileProvider
import androidx.core.net.toUri
import androidx.core.os.bundleOf
import androidx.preference.Preference import androidx.preference.Preference
import be.mygod.vpnhotspot.App.Companion.app import be.mygod.vpnhotspot.App.Companion.app
import be.mygod.vpnhotspot.net.Routing import be.mygod.vpnhotspot.net.Routing
@@ -13,7 +14,6 @@ import be.mygod.vpnhotspot.net.UpstreamMonitor
import be.mygod.vpnhotspot.preference.AlwaysAutoCompleteEditTextPreferenceDialogFragmentCompat import be.mygod.vpnhotspot.preference.AlwaysAutoCompleteEditTextPreferenceDialogFragmentCompat
import be.mygod.vpnhotspot.preference.SharedPreferenceDataStore import be.mygod.vpnhotspot.preference.SharedPreferenceDataStore
import be.mygod.vpnhotspot.util.loggerSuStream import be.mygod.vpnhotspot.util.loggerSuStream
import be.mygod.vpnhotspot.util.put
import com.crashlytics.android.Crashlytics import com.crashlytics.android.Crashlytics
import com.takisoft.preferencex.PreferenceFragmentCompat import com.takisoft.preferencex.PreferenceFragmentCompat
import java.io.File import java.io.File
@@ -89,7 +89,7 @@ class SettingsPreferenceFragment : PreferenceFragmentCompat() {
true true
} }
findPreference("misc.source").setOnPreferenceClickListener { findPreference("misc.source").setOnPreferenceClickListener {
mainActivity.launchUrl(Uri.parse("https://github.com/Mygod/VPNHotspot")) mainActivity.launchUrl("https://github.com/Mygod/VPNHotspot".toUri())
true true
} }
findPreference("misc.donate").setOnPreferenceClickListener { findPreference("misc.donate").setOnPreferenceClickListener {
@@ -101,7 +101,7 @@ class SettingsPreferenceFragment : PreferenceFragmentCompat() {
override fun onDisplayPreferenceDialog(preference: Preference) = when (preference.key) { override fun onDisplayPreferenceDialog(preference: Preference) = when (preference.key) {
UpstreamMonitor.KEY -> displayPreferenceDialog( UpstreamMonitor.KEY -> displayPreferenceDialog(
AlwaysAutoCompleteEditTextPreferenceDialogFragmentCompat(), UpstreamMonitor.KEY, AlwaysAutoCompleteEditTextPreferenceDialogFragmentCompat(), UpstreamMonitor.KEY,
Bundle().put(AlwaysAutoCompleteEditTextPreferenceDialogFragmentCompat.KEY_SUGGESTIONS, bundleOf(Pair(AlwaysAutoCompleteEditTextPreferenceDialogFragmentCompat.KEY_SUGGESTIONS,
try { try {
NetworkInterface.getNetworkInterfaces().asSequence() NetworkInterface.getNetworkInterfaces().asSequence()
.filter { it.isUp && !it.isLoopback && it.interfaceAddresses.isNotEmpty() } .filter { it.isUp && !it.isLoopback && it.interfaceAddresses.isNotEmpty() }
@@ -110,7 +110,7 @@ class SettingsPreferenceFragment : PreferenceFragmentCompat() {
e.printStackTrace() e.printStackTrace()
Crashlytics.logException(e) Crashlytics.logException(e)
emptyArray<String>() emptyArray<String>()
})) })))
else -> super.onDisplayPreferenceDialog(preference) else -> super.onDisplayPreferenceDialog(preference)
} }
} }

View File

@@ -14,13 +14,13 @@ import android.provider.Settings
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import android.view.View import android.view.View
import android.widget.Toast import android.widget.Toast
import androidx.core.content.getSystemService
import be.mygod.vpnhotspot.LocalOnlyHotspotService import be.mygod.vpnhotspot.LocalOnlyHotspotService
import be.mygod.vpnhotspot.R import be.mygod.vpnhotspot.R
import be.mygod.vpnhotspot.databinding.ListitemInterfaceBinding import be.mygod.vpnhotspot.databinding.ListitemInterfaceBinding
import be.mygod.vpnhotspot.net.TetherType import be.mygod.vpnhotspot.net.TetherType
import be.mygod.vpnhotspot.util.ServiceForegroundConnector import be.mygod.vpnhotspot.util.ServiceForegroundConnector
import be.mygod.vpnhotspot.util.formatAddresses import be.mygod.vpnhotspot.util.formatAddresses
import be.mygod.vpnhotspot.util.systemService
import com.crashlytics.android.Crashlytics import com.crashlytics.android.Crashlytics
import java.net.NetworkInterface import java.net.NetworkInterface
@@ -52,7 +52,7 @@ class LocalOnlyHotspotManager(private val parent: TetheringFragment) : Manager()
if (if (Build.VERSION.SDK_INT < 28) @Suppress("DEPRECATION") { if (if (Build.VERSION.SDK_INT < 28) @Suppress("DEPRECATION") {
Settings.Secure.getInt(view.context.contentResolver, Settings.Secure.LOCATION_MODE, Settings.Secure.getInt(view.context.contentResolver, Settings.Secure.LOCATION_MODE,
Settings.Secure.LOCATION_MODE_OFF) == Settings.Secure.LOCATION_MODE_OFF Settings.Secure.LOCATION_MODE_OFF) == Settings.Secure.LOCATION_MODE_OFF
} else !context.systemService<LocationManager>().isLocationEnabled) { } else context.getSystemService<LocationManager>()?.isLocationEnabled != true) {
Toast.makeText(view.context, R.string.tethering_temp_hotspot_location, Toast.LENGTH_LONG).show() Toast.makeText(view.context, R.string.tethering_temp_hotspot_location, Toast.LENGTH_LONG).show()
try { try {
view.context.startActivity(Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS)) view.context.startActivity(Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS))

View File

@@ -1,19 +1,20 @@
package be.mygod.vpnhotspot.manage package be.mygod.vpnhotspot.manage
import android.annotation.SuppressLint import android.annotation.SuppressLint
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleObserver
import androidx.lifecycle.OnLifecycleEvent
import android.bluetooth.BluetoothAdapter import android.bluetooth.BluetoothAdapter
import android.bluetooth.BluetoothProfile import android.bluetooth.BluetoothProfile
import android.content.ActivityNotFoundException import android.content.ActivityNotFoundException
import android.content.Intent import android.content.Intent
import android.net.Uri
import android.os.Build import android.os.Build
import android.provider.Settings import android.provider.Settings
import androidx.annotation.RequiresApi
import androidx.recyclerview.widget.RecyclerView
import android.view.View import android.view.View
import androidx.annotation.RequiresApi
import androidx.core.net.toUri
import androidx.core.view.updatePaddingRelative
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleObserver
import androidx.lifecycle.OnLifecycleEvent
import androidx.recyclerview.widget.RecyclerView
import be.mygod.vpnhotspot.App.Companion.app import be.mygod.vpnhotspot.App.Companion.app
import be.mygod.vpnhotspot.MainActivity import be.mygod.vpnhotspot.MainActivity
import be.mygod.vpnhotspot.R import be.mygod.vpnhotspot.R
@@ -21,7 +22,6 @@ import be.mygod.vpnhotspot.databinding.ListitemInterfaceBinding
import be.mygod.vpnhotspot.net.TetherType import be.mygod.vpnhotspot.net.TetherType
import be.mygod.vpnhotspot.net.TetheringManager import be.mygod.vpnhotspot.net.TetheringManager
import be.mygod.vpnhotspot.net.wifi.WifiApManager import be.mygod.vpnhotspot.net.wifi.WifiApManager
import be.mygod.vpnhotspot.util.setPaddingStart
import com.crashlytics.android.Crashlytics import com.crashlytics.android.Crashlytics
import java.lang.reflect.InvocationTargetException import java.lang.reflect.InvocationTargetException
@@ -30,7 +30,7 @@ sealed class TetherManager(protected val parent: TetheringFragment) : Manager(),
class ViewHolder(val binding: ListitemInterfaceBinding) : RecyclerView.ViewHolder(binding.root), class ViewHolder(val binding: ListitemInterfaceBinding) : RecyclerView.ViewHolder(binding.root),
View.OnClickListener { View.OnClickListener {
init { init {
itemView.setPaddingStart(itemView.resources.getDimensionPixelOffset( itemView.updatePaddingRelative(start = itemView.resources.getDimensionPixelOffset(
R.dimen.listitem_manage_tether_padding_start)) R.dimen.listitem_manage_tether_padding_start))
itemView.setOnClickListener(this) itemView.setOnClickListener(this)
} }
@@ -46,7 +46,7 @@ sealed class TetherManager(protected val parent: TetheringFragment) : Manager(),
val mainActivity = manager.parent.activity as MainActivity val mainActivity = manager.parent.activity as MainActivity
if (Build.VERSION.SDK_INT >= 23 && !Settings.System.canWrite(mainActivity)) try { if (Build.VERSION.SDK_INT >= 23 && !Settings.System.canWrite(mainActivity)) try {
manager.parent.startActivity(Intent(Settings.ACTION_MANAGE_WRITE_SETTINGS, manager.parent.startActivity(Intent(Settings.ACTION_MANAGE_WRITE_SETTINGS,
Uri.parse("package:${mainActivity.packageName}"))) "package:${mainActivity.packageName}".toUri()))
return return
} catch (exc: ActivityNotFoundException) { } catch (exc: ActivityNotFoundException) {
exc.printStackTrace() exc.printStackTrace()

View File

@@ -106,7 +106,7 @@ class Routing(val upstream: String?, private val downstream: String, ownerAddres
fun dnsRedirect(dnses: List<InetAddress>): Routing { fun dnsRedirect(dnses: List<InetAddress>): Routing {
val hostAddress = hostAddress.address.hostAddress val hostAddress = hostAddress.address.hostAddress
val dns = dnses.firstOrNull { it is Inet4Address }?.hostAddress ?: app.dns val dns = dnses.firstOrNull { it is Inet4Address }?.hostAddress ?: app.pref.getString("service.dns", "8.8.8.8")
debugLog("Routing", "Using $dns from ($dnses)") debugLog("Routing", "Using $dns from ($dnses)")
startScript.add("$IPTABLES -t nat -A PREROUTING -i $downstream -p tcp -d $hostAddress --dport 53 -j DNAT --to-destination $dns") startScript.add("$IPTABLES -t nat -A PREROUTING -i $downstream -p tcp -d $hostAddress --dport 53 -j DNAT --to-destination $dns")
startScript.add("$IPTABLES -t nat -A PREROUTING -i $downstream -p udp -d $hostAddress --dport 53 -j DNAT --to-destination $dns") startScript.add("$IPTABLES -t nat -A PREROUTING -i $downstream -p udp -d $hostAddress --dport 53 -j DNAT --to-destination $dns")

View File

@@ -1,6 +1,7 @@
package be.mygod.vpnhotspot.preference package be.mygod.vpnhotspot.preference
import android.content.SharedPreferences import android.content.SharedPreferences
import androidx.core.content.edit
import androidx.preference.PreferenceDataStore import androidx.preference.PreferenceDataStore
class SharedPreferenceDataStore(private val pref: SharedPreferences) : PreferenceDataStore() { class SharedPreferenceDataStore(private val pref: SharedPreferences) : PreferenceDataStore() {
@@ -11,10 +12,10 @@ class SharedPreferenceDataStore(private val pref: SharedPreferences) : Preferenc
override fun getString(key: String?, defValue: String?): String? = pref.getString(key, defValue) override fun getString(key: String?, defValue: String?): String? = pref.getString(key, defValue)
override fun getStringSet(key: String?, defValue: MutableSet<String>?): MutableSet<String>? = override fun getStringSet(key: String?, defValue: MutableSet<String>?): MutableSet<String>? =
pref.getStringSet(key, defValue) pref.getStringSet(key, defValue)
override fun putBoolean(key: String?, value: Boolean) = pref.edit().putBoolean(key, value).apply() override fun putBoolean(key: String?, value: Boolean) = pref.edit { putBoolean(key, value) }
override fun putFloat(key: String?, value: Float) = pref.edit().putFloat(key, value).apply() override fun putFloat(key: String?, value: Float) = pref.edit { putFloat(key, value) }
override fun putInt(key: String?, value: Int) = pref.edit().putInt(key, value).apply() override fun putInt(key: String?, value: Int) = pref.edit { putInt(key, value) }
override fun putLong(key: String?, value: Long) = pref.edit().putLong(key, value).apply() override fun putLong(key: String?, value: Long) = pref.edit { putLong(key, value) }
override fun putString(key: String?, value: String?) = pref.edit().putString(key, value).apply() override fun putString(key: String?, value: String?) = pref.edit { putString(key, value) }
override fun putStringSet(key: String?, value: MutableSet<String>?) = pref.edit().putStringSet(key, value).apply() override fun putStringSet(key: String?, value: MutableSet<String>?) = pref.edit { putStringSet(key, value) }
} }

View File

@@ -1,13 +1,12 @@
package be.mygod.vpnhotspot.util package be.mygod.vpnhotspot.util
import android.content.* import android.content.*
import androidx.databinding.BindingAdapter
import android.os.Bundle
import androidx.annotation.DrawableRes
import androidx.core.content.ContextCompat
import android.util.Log import android.util.Log
import android.view.View import android.view.View
import android.widget.ImageView import android.widget.ImageView
import androidx.annotation.DrawableRes
import androidx.core.view.isVisible
import androidx.databinding.BindingAdapter
import be.mygod.vpnhotspot.App.Companion.app import be.mygod.vpnhotspot.App.Companion.app
import be.mygod.vpnhotspot.BuildConfig import be.mygod.vpnhotspot.BuildConfig
import be.mygod.vpnhotspot.R import be.mygod.vpnhotspot.R
@@ -30,21 +29,12 @@ fun intentFilter(vararg actions: String): IntentFilter {
return result return result
} }
inline fun <reified T> Context.systemService() = ContextCompat.getSystemService(this, T::class.java)!!
fun Bundle.put(key: String, map: Array<String>): Bundle {
putStringArray(key, map)
return this
}
fun View.setPaddingStart(value: Int) = setPaddingRelative(value, paddingTop, paddingEnd, paddingBottom)
@BindingAdapter("android:src") @BindingAdapter("android:src")
fun setImageResource(imageView: ImageView, @DrawableRes resource: Int) = imageView.setImageResource(resource) fun setImageResource(imageView: ImageView, @DrawableRes resource: Int) = imageView.setImageResource(resource)
@BindingAdapter("android:visibility") @BindingAdapter("android:visibility")
fun setVisibility(view: View, value: Boolean) { fun setVisibility(view: View, value: Boolean) {
view.visibility = if (value) View.VISIBLE else View.GONE view.isVisible = value
} }
fun NetworkInterface.formatAddresses() = fun NetworkInterface.formatAddresses() =

View File

@@ -1,15 +1,15 @@
package be.mygod.vpnhotspot.widget package be.mygod.vpnhotspot.widget
import android.content.Context import android.content.Context
import androidx.appcompat.widget.AppCompatTextView
import android.util.AttributeSet import android.util.AttributeSet
import android.view.View import androidx.appcompat.widget.AppCompatTextView
import androidx.core.view.isVisible
class AutoCollapseTextView @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null, class AutoCollapseTextView @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null,
defStyleAttr: Int = android.R.attr.textViewStyle) : defStyleAttr: Int = android.R.attr.textViewStyle) :
AppCompatTextView(context, attrs, defStyleAttr) { AppCompatTextView(context, attrs, defStyleAttr) {
override fun onTextChanged(text: CharSequence?, start: Int, lengthBefore: Int, lengthAfter: Int) { override fun onTextChanged(text: CharSequence?, start: Int, lengthBefore: Int, lengthAfter: Int) {
super.onTextChanged(text, start, lengthBefore, lengthAfter) super.onTextChanged(text, start, lengthBefore, lengthAfter)
visibility = if (text.isNullOrEmpty()) View.GONE else View.VISIBLE isVisible = !text.isNullOrEmpty()
} }
} }