diff --git a/mobile/build.gradle b/mobile/build.gradle index 091264c5..4b161f76 100644 --- a/mobile/build.gradle +++ b/mobile/build.gradle @@ -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' diff --git a/mobile/src/main/java/be/mygod/vpnhotspot/App.kt b/mobile/src/main/java/be/mygod/vpnhotspot/App.kt index c545bfa1..f39b177a 100644 --- a/mobile/src/main/java/be/mygod/vpnhotspot/App.kt +++ b/mobile/src/main/java/be/mygod/vpnhotspot/App.kt @@ -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() } - val wifi by lazy { systemService() } + val connectivity by lazy { getSystemService()!! } + val wifi by lazy { getSystemService()!! } 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() diff --git a/mobile/src/main/java/be/mygod/vpnhotspot/EBegFragment.kt b/mobile/src/main/java/be/mygod/vpnhotspot/EBegFragment.kt index 2ac3342c..db1c2a97 100644 --- a/mobile/src/main/java/be/mygod/vpnhotspot/EBegFragment.kt +++ b/mobile/src/main/java/be/mygod/vpnhotspot/EBegFragment.kt @@ -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(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()) } } diff --git a/mobile/src/main/java/be/mygod/vpnhotspot/RepeaterService.kt b/mobile/src/main/java/be/mygod/vpnhotspot/RepeaterService.kt index cacc5bc1..c393965e 100644 --- a/mobile/src/main/java/be/mygod/vpnhotspot/RepeaterService.kt +++ b/mobile/src/main/java/be/mygod/vpnhotspot/RepeaterService.kt @@ -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) { diff --git a/mobile/src/main/java/be/mygod/vpnhotspot/ServiceNotification.kt b/mobile/src/main/java/be/mygod/vpnhotspot/ServiceNotification.kt index f77b025e..d7d06dbf 100644 --- a/mobile/src/main/java/be/mygod/vpnhotspot/ServiceNotification.kt +++ b/mobile/src/main/java/be/mygod/vpnhotspot/ServiceNotification.kt @@ -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>() - private val manager = app.systemService() + private val manager = app.getSystemService()!! private fun buildNotification(context: Context): Notification { val builder = NotificationCompat.Builder(context, CHANNEL) diff --git a/mobile/src/main/java/be/mygod/vpnhotspot/SettingsPreferenceFragment.kt b/mobile/src/main/java/be/mygod/vpnhotspot/SettingsPreferenceFragment.kt index 5bb28525..4824f918 100644 --- a/mobile/src/main/java/be/mygod/vpnhotspot/SettingsPreferenceFragment.kt +++ b/mobile/src/main/java/be/mygod/vpnhotspot/SettingsPreferenceFragment.kt @@ -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() - })) + }))) else -> super.onDisplayPreferenceDialog(preference) } } diff --git a/mobile/src/main/java/be/mygod/vpnhotspot/manage/LocalOnlyHotspotManager.kt b/mobile/src/main/java/be/mygod/vpnhotspot/manage/LocalOnlyHotspotManager.kt index b689053b..fd9d4ab0 100644 --- a/mobile/src/main/java/be/mygod/vpnhotspot/manage/LocalOnlyHotspotManager.kt +++ b/mobile/src/main/java/be/mygod/vpnhotspot/manage/LocalOnlyHotspotManager.kt @@ -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().isLocationEnabled) { + } else context.getSystemService()?.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)) diff --git a/mobile/src/main/java/be/mygod/vpnhotspot/manage/TetherManager.kt b/mobile/src/main/java/be/mygod/vpnhotspot/manage/TetherManager.kt index f2a348f2..1aa49040 100644 --- a/mobile/src/main/java/be/mygod/vpnhotspot/manage/TetherManager.kt +++ b/mobile/src/main/java/be/mygod/vpnhotspot/manage/TetherManager.kt @@ -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() diff --git a/mobile/src/main/java/be/mygod/vpnhotspot/net/Routing.kt b/mobile/src/main/java/be/mygod/vpnhotspot/net/Routing.kt index a1b60706..061909af 100644 --- a/mobile/src/main/java/be/mygod/vpnhotspot/net/Routing.kt +++ b/mobile/src/main/java/be/mygod/vpnhotspot/net/Routing.kt @@ -106,7 +106,7 @@ class Routing(val upstream: String?, private val downstream: String, ownerAddres fun dnsRedirect(dnses: List): 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") diff --git a/mobile/src/main/java/be/mygod/vpnhotspot/preference/SharedPreferenceDataStore.kt b/mobile/src/main/java/be/mygod/vpnhotspot/preference/SharedPreferenceDataStore.kt index cc2bdf2f..0dc3d240 100644 --- a/mobile/src/main/java/be/mygod/vpnhotspot/preference/SharedPreferenceDataStore.kt +++ b/mobile/src/main/java/be/mygod/vpnhotspot/preference/SharedPreferenceDataStore.kt @@ -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?): MutableSet? = 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?) = 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?) = pref.edit { putStringSet(key, value) } } diff --git a/mobile/src/main/java/be/mygod/vpnhotspot/util/Utils.kt b/mobile/src/main/java/be/mygod/vpnhotspot/util/Utils.kt index e86df668..6ff925da 100644 --- a/mobile/src/main/java/be/mygod/vpnhotspot/util/Utils.kt +++ b/mobile/src/main/java/be/mygod/vpnhotspot/util/Utils.kt @@ -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 Context.systemService() = ContextCompat.getSystemService(this, T::class.java)!! - -fun Bundle.put(key: String, map: Array): 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() = diff --git a/mobile/src/main/java/be/mygod/vpnhotspot/widget/AutoCollapseTextView.kt b/mobile/src/main/java/be/mygod/vpnhotspot/widget/AutoCollapseTextView.kt index edf48e40..08b95076 100644 --- a/mobile/src/main/java/be/mygod/vpnhotspot/widget/AutoCollapseTextView.kt +++ b/mobile/src/main/java/be/mygod/vpnhotspot/widget/AutoCollapseTextView.kt @@ -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() } }