Use Android KTX
This commit is contained in:
@@ -45,6 +45,7 @@ dependencies {
|
||||
implementation 'com.android.billingclient:billing:1.1'
|
||||
implementation "androidx.browser:browser:$androidxVersion"
|
||||
implementation 'androidx.constraintlayout:constraintlayout:2.0.0-alpha1'
|
||||
implementation "androidx.core:core-ktx:$androidxVersion"
|
||||
implementation "androidx.preference:preference:$androidxVersion"
|
||||
implementation 'com.crashlytics.sdk.android:crashlytics:2.9.4'
|
||||
implementation 'com.github.luongvo:BadgeView:1.1.5'
|
||||
|
||||
@@ -12,13 +12,12 @@ import android.os.Handler
|
||||
import android.preference.PreferenceManager
|
||||
import androidx.annotation.StringRes
|
||||
import android.widget.Toast
|
||||
import androidx.core.content.getSystemService
|
||||
import be.mygod.vpnhotspot.util.Event0
|
||||
import be.mygod.vpnhotspot.util.systemService
|
||||
|
||||
class App : Application() {
|
||||
companion object {
|
||||
const val KEY_OPERATING_CHANNEL = "service.repeater.oc"
|
||||
private const val KEY_DNS = "service.dns"
|
||||
private const val KEY_MASQUERADE = "service.masquerade"
|
||||
|
||||
@SuppressLint("StaticFieldLeak")
|
||||
@@ -32,9 +31,6 @@ class App : Application() {
|
||||
deviceContext = createDeviceProtectedStorageContext()
|
||||
deviceContext.moveSharedPreferencesFrom(this, PreferenceManager.getDefaultSharedPreferencesName(this))
|
||||
} else deviceContext = this
|
||||
// workaround for support lib PreferenceDataStore bug
|
||||
dns = dns
|
||||
masquerade = masquerade
|
||||
ServiceNotification.updateNotificationChannels()
|
||||
}
|
||||
|
||||
@@ -46,19 +42,14 @@ class App : Application() {
|
||||
lateinit var deviceContext: Context
|
||||
val handler = Handler()
|
||||
val pref: SharedPreferences by lazy { PreferenceManager.getDefaultSharedPreferences(deviceContext) }
|
||||
val connectivity by lazy { systemService<ConnectivityManager>() }
|
||||
val wifi by lazy { systemService<WifiManager>() }
|
||||
val connectivity by lazy { getSystemService<ConnectivityManager>()!! }
|
||||
val wifi by lazy { getSystemService<WifiManager>()!! }
|
||||
|
||||
val operatingChannel: Int get() {
|
||||
val result = pref.getString(KEY_OPERATING_CHANNEL, null)?.toIntOrNull() ?: 0
|
||||
return if (result in 1..165) result else 0
|
||||
}
|
||||
var dns: String
|
||||
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 masquerade: Boolean get() = pref.getBoolean(KEY_MASQUERADE, true)
|
||||
|
||||
val cleanRoutings = Event0()
|
||||
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
package be.mygod.vpnhotspot
|
||||
|
||||
import android.app.AlertDialog
|
||||
import android.net.Uri
|
||||
import android.os.Bundle
|
||||
import androidx.fragment.app.DialogFragment
|
||||
import android.util.Log
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
@@ -12,6 +10,8 @@ import android.view.ViewStub
|
||||
import android.widget.ArrayAdapter
|
||||
import android.widget.Button
|
||||
import android.widget.Spinner
|
||||
import androidx.core.net.toUri
|
||||
import androidx.fragment.app.DialogFragment
|
||||
import com.android.billingclient.api.*
|
||||
import com.crashlytics.android.Crashlytics
|
||||
|
||||
@@ -55,7 +55,7 @@ class EBegFragment : DialogFragment(), PurchasesUpdatedListener, BillingClientSt
|
||||
@Suppress("ConstantConditionIf")
|
||||
if (BuildConfig.DONATIONS) (view.findViewById<ViewStub>(R.id.donations__more_stub).inflate() as Button)
|
||||
.setOnClickListener {
|
||||
(activity as MainActivity).launchUrl(Uri.parse("https://mygod.be/donate/"))
|
||||
(activity as MainActivity).launchUrl("https://mygod.be/donate/".toUri())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -13,6 +13,7 @@ import android.os.Looper
|
||||
import androidx.annotation.StringRes
|
||||
import android.util.Log
|
||||
import android.widget.Toast
|
||||
import androidx.core.content.getSystemService
|
||||
import be.mygod.vpnhotspot.App.Companion.app
|
||||
import be.mygod.vpnhotspot.net.wifi.WifiP2pManagerHelper
|
||||
import be.mygod.vpnhotspot.net.wifi.WifiP2pManagerHelper.deletePersistentGroup
|
||||
@@ -130,7 +131,7 @@ class RepeaterService : Service(), WifiP2pManager.ChannelListener, SharedPrefere
|
||||
override fun onCreate() {
|
||||
super.onCreate()
|
||||
try {
|
||||
p2pManager = systemService()
|
||||
p2pManager = getSystemService()!!
|
||||
onChannelDisconnected()
|
||||
app.pref.registerOnSharedPreferenceChangeListener(this)
|
||||
} catch (exc: KotlinNullPointerException) {
|
||||
|
||||
@@ -7,15 +7,15 @@ import android.content.Intent
|
||||
import android.os.Build
|
||||
import androidx.core.app.NotificationCompat
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.core.content.getSystemService
|
||||
import be.mygod.vpnhotspot.App.Companion.app
|
||||
import be.mygod.vpnhotspot.util.systemService
|
||||
|
||||
object ServiceNotification {
|
||||
private const val CHANNEL = "tethering"
|
||||
private const val CHANNEL_ID = 1
|
||||
|
||||
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 {
|
||||
val builder = NotificationCompat.Builder(context, CHANNEL)
|
||||
|
||||
@@ -2,10 +2,11 @@ package be.mygod.vpnhotspot
|
||||
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.net.Uri
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import androidx.core.content.FileProvider
|
||||
import androidx.core.net.toUri
|
||||
import androidx.core.os.bundleOf
|
||||
import androidx.preference.Preference
|
||||
import be.mygod.vpnhotspot.App.Companion.app
|
||||
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.SharedPreferenceDataStore
|
||||
import be.mygod.vpnhotspot.util.loggerSuStream
|
||||
import be.mygod.vpnhotspot.util.put
|
||||
import com.crashlytics.android.Crashlytics
|
||||
import com.takisoft.preferencex.PreferenceFragmentCompat
|
||||
import java.io.File
|
||||
@@ -89,7 +89,7 @@ class SettingsPreferenceFragment : PreferenceFragmentCompat() {
|
||||
true
|
||||
}
|
||||
findPreference("misc.source").setOnPreferenceClickListener {
|
||||
mainActivity.launchUrl(Uri.parse("https://github.com/Mygod/VPNHotspot"))
|
||||
mainActivity.launchUrl("https://github.com/Mygod/VPNHotspot".toUri())
|
||||
true
|
||||
}
|
||||
findPreference("misc.donate").setOnPreferenceClickListener {
|
||||
@@ -101,7 +101,7 @@ class SettingsPreferenceFragment : PreferenceFragmentCompat() {
|
||||
override fun onDisplayPreferenceDialog(preference: Preference) = when (preference.key) {
|
||||
UpstreamMonitor.KEY -> displayPreferenceDialog(
|
||||
AlwaysAutoCompleteEditTextPreferenceDialogFragmentCompat(), UpstreamMonitor.KEY,
|
||||
Bundle().put(AlwaysAutoCompleteEditTextPreferenceDialogFragmentCompat.KEY_SUGGESTIONS,
|
||||
bundleOf(Pair(AlwaysAutoCompleteEditTextPreferenceDialogFragmentCompat.KEY_SUGGESTIONS,
|
||||
try {
|
||||
NetworkInterface.getNetworkInterfaces().asSequence()
|
||||
.filter { it.isUp && !it.isLoopback && it.interfaceAddresses.isNotEmpty() }
|
||||
@@ -110,7 +110,7 @@ class SettingsPreferenceFragment : PreferenceFragmentCompat() {
|
||||
e.printStackTrace()
|
||||
Crashlytics.logException(e)
|
||||
emptyArray<String>()
|
||||
}))
|
||||
})))
|
||||
else -> super.onDisplayPreferenceDialog(preference)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,13 +14,13 @@ import android.provider.Settings
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import android.view.View
|
||||
import android.widget.Toast
|
||||
import androidx.core.content.getSystemService
|
||||
import be.mygod.vpnhotspot.LocalOnlyHotspotService
|
||||
import be.mygod.vpnhotspot.R
|
||||
import be.mygod.vpnhotspot.databinding.ListitemInterfaceBinding
|
||||
import be.mygod.vpnhotspot.net.TetherType
|
||||
import be.mygod.vpnhotspot.util.ServiceForegroundConnector
|
||||
import be.mygod.vpnhotspot.util.formatAddresses
|
||||
import be.mygod.vpnhotspot.util.systemService
|
||||
import com.crashlytics.android.Crashlytics
|
||||
import java.net.NetworkInterface
|
||||
|
||||
@@ -52,7 +52,7 @@ class LocalOnlyHotspotManager(private val parent: TetheringFragment) : Manager()
|
||||
if (if (Build.VERSION.SDK_INT < 28) @Suppress("DEPRECATION") {
|
||||
Settings.Secure.getInt(view.context.contentResolver, Settings.Secure.LOCATION_MODE,
|
||||
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()
|
||||
try {
|
||||
view.context.startActivity(Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS))
|
||||
|
||||
@@ -1,19 +1,20 @@
|
||||
package be.mygod.vpnhotspot.manage
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import androidx.lifecycle.Lifecycle
|
||||
import androidx.lifecycle.LifecycleObserver
|
||||
import androidx.lifecycle.OnLifecycleEvent
|
||||
import android.bluetooth.BluetoothAdapter
|
||||
import android.bluetooth.BluetoothProfile
|
||||
import android.content.ActivityNotFoundException
|
||||
import android.content.Intent
|
||||
import android.net.Uri
|
||||
import android.os.Build
|
||||
import android.provider.Settings
|
||||
import androidx.annotation.RequiresApi
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
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.MainActivity
|
||||
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.TetheringManager
|
||||
import be.mygod.vpnhotspot.net.wifi.WifiApManager
|
||||
import be.mygod.vpnhotspot.util.setPaddingStart
|
||||
import com.crashlytics.android.Crashlytics
|
||||
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),
|
||||
View.OnClickListener {
|
||||
init {
|
||||
itemView.setPaddingStart(itemView.resources.getDimensionPixelOffset(
|
||||
itemView.updatePaddingRelative(start = itemView.resources.getDimensionPixelOffset(
|
||||
R.dimen.listitem_manage_tether_padding_start))
|
||||
itemView.setOnClickListener(this)
|
||||
}
|
||||
@@ -46,7 +46,7 @@ sealed class TetherManager(protected val parent: TetheringFragment) : Manager(),
|
||||
val mainActivity = manager.parent.activity as MainActivity
|
||||
if (Build.VERSION.SDK_INT >= 23 && !Settings.System.canWrite(mainActivity)) try {
|
||||
manager.parent.startActivity(Intent(Settings.ACTION_MANAGE_WRITE_SETTINGS,
|
||||
Uri.parse("package:${mainActivity.packageName}")))
|
||||
"package:${mainActivity.packageName}".toUri()))
|
||||
return
|
||||
} catch (exc: ActivityNotFoundException) {
|
||||
exc.printStackTrace()
|
||||
|
||||
@@ -106,7 +106,7 @@ class Routing(val upstream: String?, private val downstream: String, ownerAddres
|
||||
|
||||
fun dnsRedirect(dnses: List<InetAddress>): Routing {
|
||||
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)")
|
||||
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")
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package be.mygod.vpnhotspot.preference
|
||||
|
||||
import android.content.SharedPreferences
|
||||
import androidx.core.content.edit
|
||||
import androidx.preference.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 getStringSet(key: String?, defValue: MutableSet<String>?): MutableSet<String>? =
|
||||
pref.getStringSet(key, defValue)
|
||||
override fun putBoolean(key: String?, value: Boolean) = pref.edit().putBoolean(key, value).apply()
|
||||
override fun putFloat(key: String?, value: Float) = pref.edit().putFloat(key, value).apply()
|
||||
override fun putInt(key: String?, value: Int) = pref.edit().putInt(key, value).apply()
|
||||
override fun putLong(key: String?, value: Long) = pref.edit().putLong(key, value).apply()
|
||||
override fun putString(key: String?, value: String?) = pref.edit().putString(key, value).apply()
|
||||
override fun putStringSet(key: String?, value: MutableSet<String>?) = pref.edit().putStringSet(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) }
|
||||
override fun putInt(key: String?, value: Int) = pref.edit { putInt(key, value) }
|
||||
override fun putLong(key: String?, value: Long) = pref.edit { putLong(key, value) }
|
||||
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) }
|
||||
}
|
||||
|
||||
@@ -1,13 +1,12 @@
|
||||
package be.mygod.vpnhotspot.util
|
||||
|
||||
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.view.View
|
||||
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.BuildConfig
|
||||
import be.mygod.vpnhotspot.R
|
||||
@@ -30,21 +29,12 @@ fun intentFilter(vararg actions: String): IntentFilter {
|
||||
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")
|
||||
fun setImageResource(imageView: ImageView, @DrawableRes resource: Int) = imageView.setImageResource(resource)
|
||||
|
||||
@BindingAdapter("android:visibility")
|
||||
fun setVisibility(view: View, value: Boolean) {
|
||||
view.visibility = if (value) View.VISIBLE else View.GONE
|
||||
view.isVisible = value
|
||||
}
|
||||
|
||||
fun NetworkInterface.formatAddresses() =
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
package be.mygod.vpnhotspot.widget
|
||||
|
||||
import android.content.Context
|
||||
import androidx.appcompat.widget.AppCompatTextView
|
||||
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,
|
||||
defStyleAttr: Int = android.R.attr.textViewStyle) :
|
||||
AppCompatTextView(context, attrs, defStyleAttr) {
|
||||
override fun onTextChanged(text: CharSequence?, start: Int, lengthBefore: Int, lengthAfter: Int) {
|
||||
super.onTextChanged(text, start, lengthBefore, lengthAfter)
|
||||
visibility = if (text.isNullOrEmpty()) View.GONE else View.VISIBLE
|
||||
isVisible = !text.isNullOrEmpty()
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user