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 "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'

View File

@@ -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()

View File

@@ -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())
}
}

View File

@@ -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) {

View File

@@ -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)

View File

@@ -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)
}
}

View File

@@ -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))

View File

@@ -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()

View File

@@ -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")

View File

@@ -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) }
}

View File

@@ -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() =

View File

@@ -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()
}
}