Android Q beta 4 support
This commit is contained in:
@@ -12,7 +12,7 @@ buildscript {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
dependencies {
|
dependencies {
|
||||||
classpath 'com.android.tools.build:gradle:3.5.0-beta02'
|
classpath 'com.android.tools.build:gradle:3.5.0-beta04'
|
||||||
classpath 'com.github.ben-manes:gradle-versions-plugin:0.21.0'
|
classpath 'com.github.ben-manes:gradle-versions-plugin:0.21.0'
|
||||||
classpath 'com.google.gms:google-services:4.2.0'
|
classpath 'com.google.gms:google-services:4.2.0'
|
||||||
classpath 'io.fabric.tools:gradle:1.29.0'
|
classpath 'io.fabric.tools:gradle:1.29.0'
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ if (!getGradle().getStartParameter().getTaskRequests().toString().contains("Fdro
|
|||||||
}
|
}
|
||||||
|
|
||||||
android {
|
android {
|
||||||
compileSdkVersion 'android-Q'
|
compileSdkVersion 29
|
||||||
compileOptions {
|
compileOptions {
|
||||||
sourceCompatibility 1.8
|
sourceCompatibility 1.8
|
||||||
targetCompatibility 1.8
|
targetCompatibility 1.8
|
||||||
@@ -17,7 +17,7 @@ android {
|
|||||||
defaultConfig {
|
defaultConfig {
|
||||||
applicationId "be.mygod.vpnhotspot"
|
applicationId "be.mygod.vpnhotspot"
|
||||||
minSdkVersion 21
|
minSdkVersion 21
|
||||||
targetSdkVersion 28
|
targetSdkVersion 29
|
||||||
resConfigs "ru", "zh-rCN"
|
resConfigs "ru", "zh-rCN"
|
||||||
versionCode 204
|
versionCode 204
|
||||||
versionName '2.4.4'
|
versionName '2.4.4'
|
||||||
@@ -73,15 +73,15 @@ dependencies {
|
|||||||
kapt "androidx.room:room-compiler:$roomVersion"
|
kapt "androidx.room:room-compiler:$roomVersion"
|
||||||
implementation fileTree(dir: 'libs', include: ['*.jar'])
|
implementation fileTree(dir: 'libs', include: ['*.jar'])
|
||||||
implementation 'androidx.browser:browser:1.0.0'
|
implementation 'androidx.browser:browser:1.0.0'
|
||||||
implementation 'androidx.core:core-ktx:1.1.0-beta01'
|
implementation 'androidx.core:core-ktx:1.1.0-rc01'
|
||||||
implementation 'androidx.emoji:emoji:1.0.0'
|
implementation 'androidx.emoji:emoji:1.0.0'
|
||||||
implementation "androidx.lifecycle:lifecycle-common-java8:$lifecycleVersion"
|
implementation "androidx.lifecycle:lifecycle-common-java8:$lifecycleVersion"
|
||||||
implementation "androidx.lifecycle:lifecycle-extensions:$lifecycleVersion"
|
implementation "androidx.lifecycle:lifecycle-extensions:$lifecycleVersion"
|
||||||
implementation "androidx.lifecycle:lifecycle-livedata-ktx:$lifecycleVersion"
|
implementation "androidx.lifecycle:lifecycle-livedata-ktx:$lifecycleVersion"
|
||||||
implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:$lifecycleVersion"
|
implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:$lifecycleVersion"
|
||||||
implementation 'androidx.preference:preference:1.1.0-alpha05'
|
implementation 'androidx.preference:preference:1.1.0-beta01'
|
||||||
implementation "androidx.room:room-ktx:$roomVersion"
|
implementation "androidx.room:room-ktx:$roomVersion"
|
||||||
implementation 'com.android.billingclient:billing:2.0.0'
|
implementation 'com.android.billingclient:billing:2.0.1'
|
||||||
implementation 'com.github.topjohnwu.libsu:core:2.5.0'
|
implementation 'com.github.topjohnwu.libsu:core:2.5.0'
|
||||||
implementation 'com.google.android.material:material:1.1.0-alpha07'
|
implementation 'com.google.android.material:material:1.1.0-alpha07'
|
||||||
implementation 'com.jakewharton.timber:timber:4.7.1'
|
implementation 'com.jakewharton.timber:timber:4.7.1'
|
||||||
|
|||||||
@@ -13,7 +13,6 @@ import android.os.Looper
|
|||||||
import androidx.annotation.StringRes
|
import androidx.annotation.StringRes
|
||||||
import androidx.core.content.edit
|
import androidx.core.content.edit
|
||||||
import androidx.core.content.getSystemService
|
import androidx.core.content.getSystemService
|
||||||
import androidx.core.os.BuildCompat
|
|
||||||
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
|
||||||
@@ -161,7 +160,7 @@ class RepeaterService : Service(), WifiP2pManager.ChannelListener, SharedPrefere
|
|||||||
override fun onCreate() {
|
override fun onCreate() {
|
||||||
super.onCreate()
|
super.onCreate()
|
||||||
onChannelDisconnected()
|
onChannelDisconnected()
|
||||||
if (!BuildCompat.isAtLeastQ()) @Suppress("DEPRECATION") {
|
if (Build.VERSION.SDK_INT < 29) @Suppress("DEPRECATION") {
|
||||||
registerReceiver(deviceListener, intentFilter(WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION,
|
registerReceiver(deviceListener, intentFilter(WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION,
|
||||||
WifiP2pManagerHelper.WIFI_P2P_PERSISTENT_GROUPS_CHANGED_ACTION))
|
WifiP2pManagerHelper.WIFI_P2P_PERSISTENT_GROUPS_CHANGED_ACTION))
|
||||||
app.pref.registerOnSharedPreferenceChangeListener(this)
|
app.pref.registerOnSharedPreferenceChangeListener(this)
|
||||||
@@ -194,7 +193,7 @@ class RepeaterService : Service(), WifiP2pManager.ChannelListener, SharedPrefere
|
|||||||
channel = null
|
channel = null
|
||||||
if (status != Status.DESTROYED) try {
|
if (status != Status.DESTROYED) try {
|
||||||
channel = p2pManager.initialize(this, Looper.getMainLooper(), this)
|
channel = p2pManager.initialize(this, Looper.getMainLooper(), this)
|
||||||
if (!BuildCompat.isAtLeastQ()) @Suppress("DEPRECATION") setOperatingChannel()
|
if (Build.VERSION.SDK_INT < 29) @Suppress("DEPRECATION") setOperatingChannel()
|
||||||
} catch (e: RuntimeException) {
|
} catch (e: RuntimeException) {
|
||||||
Timber.w(e)
|
Timber.w(e)
|
||||||
handler.postDelayed(this::onChannelDisconnected, 1000)
|
handler.postDelayed(this::onChannelDisconnected, 1000)
|
||||||
@@ -282,7 +281,7 @@ class RepeaterService : Service(), WifiP2pManager.ChannelListener, SharedPrefere
|
|||||||
val networkName = networkName
|
val networkName = networkName
|
||||||
val passphrase = passphrase
|
val passphrase = passphrase
|
||||||
try {
|
try {
|
||||||
if (!BuildCompat.isAtLeastQ() || networkName == null || passphrase == null) {
|
if (Build.VERSION.SDK_INT < 29 || networkName == null || passphrase == null) {
|
||||||
persistNextGroup = true
|
persistNextGroup = true
|
||||||
p2pManager.createGroup(channel, listener)
|
p2pManager.createGroup(channel, listener)
|
||||||
} else p2pManager.createGroup(channel, WifiP2pConfig.Builder().apply {
|
} else p2pManager.createGroup(channel, WifiP2pConfig.Builder().apply {
|
||||||
@@ -392,7 +391,7 @@ class RepeaterService : Service(), WifiP2pManager.ChannelListener, SharedPrefere
|
|||||||
handler.removeCallbacksAndMessages(null)
|
handler.removeCallbacksAndMessages(null)
|
||||||
if (status != Status.IDLE) binder.shutdown()
|
if (status != Status.IDLE) binder.shutdown()
|
||||||
clean() // force clean to prevent leakage
|
clean() // force clean to prevent leakage
|
||||||
if (!BuildCompat.isAtLeastQ()) @Suppress("DEPRECATION") {
|
if (Build.VERSION.SDK_INT < 29) @Suppress("DEPRECATION") {
|
||||||
app.pref.unregisterOnSharedPreferenceChangeListener(this)
|
app.pref.unregisterOnSharedPreferenceChangeListener(this)
|
||||||
unregisterReceiver(deviceListener)
|
unregisterReceiver(deviceListener)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,7 +14,6 @@ import android.provider.Settings
|
|||||||
import android.view.View
|
import android.view.View
|
||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
import androidx.core.content.getSystemService
|
import androidx.core.content.getSystemService
|
||||||
import androidx.core.os.BuildCompat
|
|
||||||
import androidx.core.os.bundleOf
|
import androidx.core.os.bundleOf
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import be.mygod.vpnhotspot.DebugHelper
|
import be.mygod.vpnhotspot.DebugHelper
|
||||||
@@ -29,7 +28,7 @@ import java.net.NetworkInterface
|
|||||||
@TargetApi(26)
|
@TargetApi(26)
|
||||||
class LocalOnlyHotspotManager(private val parent: TetheringFragment) : Manager(), ServiceConnection {
|
class LocalOnlyHotspotManager(private val parent: TetheringFragment) : Manager(), ServiceConnection {
|
||||||
companion object {
|
companion object {
|
||||||
val permission = if (BuildCompat.isAtLeastQ())
|
val permission = if (Build.VERSION.SDK_INT >= 29)
|
||||||
Manifest.permission.ACCESS_FINE_LOCATION else Manifest.permission.ACCESS_COARSE_LOCATION
|
Manifest.permission.ACCESS_FINE_LOCATION else Manifest.permission.ACCESS_COARSE_LOCATION
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -18,7 +18,6 @@ import android.view.WindowManager
|
|||||||
import android.widget.EditText
|
import android.widget.EditText
|
||||||
import androidx.appcompat.app.AlertDialog
|
import androidx.appcompat.app.AlertDialog
|
||||||
import androidx.core.content.ContextCompat
|
import androidx.core.content.ContextCompat
|
||||||
import androidx.core.os.BuildCompat
|
|
||||||
import androidx.databinding.BaseObservable
|
import androidx.databinding.BaseObservable
|
||||||
import androidx.databinding.Bindable
|
import androidx.databinding.Bindable
|
||||||
import androidx.lifecycle.ViewModel
|
import androidx.lifecycle.ViewModel
|
||||||
@@ -33,7 +32,6 @@ import be.mygod.vpnhotspot.util.formatAddresses
|
|||||||
import be.mygod.vpnhotspot.widget.SmartSnackbar
|
import be.mygod.vpnhotspot.widget.SmartSnackbar
|
||||||
import kotlinx.android.parcel.Parcelize
|
import kotlinx.android.parcel.Parcelize
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
import java.lang.IllegalArgumentException
|
|
||||||
import java.net.NetworkInterface
|
import java.net.NetworkInterface
|
||||||
import java.net.SocketException
|
import java.net.SocketException
|
||||||
|
|
||||||
@@ -56,7 +54,7 @@ class RepeaterManager(private val parent: TetheringFragment) : Manager(), Servic
|
|||||||
}
|
}
|
||||||
|
|
||||||
val title: CharSequence @Bindable get() {
|
val title: CharSequence @Bindable get() {
|
||||||
if (BuildCompat.isAtLeastQ()) binder?.group?.frequency?.let {
|
if (Build.VERSION.SDK_INT >= 29) binder?.group?.frequency?.let {
|
||||||
return parent.getString(R.string.repeater_channel, it, frequencyToChannel(it))
|
return parent.getString(R.string.repeater_channel, it, frequencyToChannel(it))
|
||||||
}
|
}
|
||||||
return parent.getString(R.string.title_repeater)
|
return parent.getString(R.string.title_repeater)
|
||||||
@@ -76,7 +74,7 @@ class RepeaterManager(private val parent: TetheringFragment) : Manager(), Servic
|
|||||||
}
|
}
|
||||||
fun onGroupChanged(group: WifiP2pGroup? = null) {
|
fun onGroupChanged(group: WifiP2pGroup? = null) {
|
||||||
p2pInterface = group?.`interface`
|
p2pInterface = group?.`interface`
|
||||||
if (BuildCompat.isAtLeastQ()) notifyPropertyChanged(BR.title)
|
if (Build.VERSION.SDK_INT >= 29) notifyPropertyChanged(BR.title)
|
||||||
notifyPropertyChanged(BR.addresses)
|
notifyPropertyChanged(BR.addresses)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -85,7 +83,7 @@ class RepeaterManager(private val parent: TetheringFragment) : Manager(), Servic
|
|||||||
when (binder?.service?.status) {
|
when (binder?.service?.status) {
|
||||||
RepeaterService.Status.IDLE -> {
|
RepeaterService.Status.IDLE -> {
|
||||||
val context = parent.requireContext()
|
val context = parent.requireContext()
|
||||||
if (BuildCompat.isAtLeastQ() && context.checkSelfPermission(
|
if (Build.VERSION.SDK_INT >= 29 && context.checkSelfPermission(
|
||||||
Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
|
Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
|
||||||
parent.requestPermissions(arrayOf(Manifest.permission.ACCESS_FINE_LOCATION),
|
parent.requestPermissions(arrayOf(Manifest.permission.ACCESS_FINE_LOCATION),
|
||||||
TetheringFragment.START_REPEATER)
|
TetheringFragment.START_REPEATER)
|
||||||
@@ -165,7 +163,7 @@ class RepeaterManager(private val parent: TetheringFragment) : Manager(), Servic
|
|||||||
}
|
}
|
||||||
|
|
||||||
val configuration: WifiConfiguration? get() {
|
val configuration: WifiConfiguration? get() {
|
||||||
if (BuildCompat.isAtLeastQ()) {
|
if (Build.VERSION.SDK_INT >= 29) {
|
||||||
val networkName = RepeaterService.networkName
|
val networkName = RepeaterService.networkName
|
||||||
val passphrase = RepeaterService.passphrase
|
val passphrase = RepeaterService.passphrase
|
||||||
if (networkName != null && passphrase != null) {
|
if (networkName != null && passphrase != null) {
|
||||||
@@ -200,7 +198,7 @@ class RepeaterManager(private val parent: TetheringFragment) : Manager(), Servic
|
|||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
fun updateConfiguration(config: WifiConfiguration) {
|
fun updateConfiguration(config: WifiConfiguration) {
|
||||||
if (BuildCompat.isAtLeastQ()) {
|
if (Build.VERSION.SDK_INT >= 29) {
|
||||||
RepeaterService.networkName = config.SSID
|
RepeaterService.networkName = config.SSID
|
||||||
RepeaterService.passphrase = config.preSharedKey
|
RepeaterService.passphrase = config.preSharedKey
|
||||||
RepeaterService.operatingBand = when (config.apBand) {
|
RepeaterService.operatingBand = when (config.apBand) {
|
||||||
|
|||||||
@@ -1,15 +1,14 @@
|
|||||||
package be.mygod.vpnhotspot.net
|
package be.mygod.vpnhotspot.net
|
||||||
|
|
||||||
|
import android.os.Build
|
||||||
import android.system.ErrnoException
|
import android.system.ErrnoException
|
||||||
import android.system.OsConstants
|
import android.system.OsConstants
|
||||||
import androidx.core.os.BuildCompat
|
|
||||||
import be.mygod.vpnhotspot.room.macToLong
|
import be.mygod.vpnhotspot.room.macToLong
|
||||||
import be.mygod.vpnhotspot.util.parseNumericAddress
|
import be.mygod.vpnhotspot.util.parseNumericAddress
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.io.FileNotFoundException
|
import java.io.FileNotFoundException
|
||||||
import java.io.IOException
|
import java.io.IOException
|
||||||
import java.lang.NumberFormatException
|
|
||||||
import java.net.InetAddress
|
import java.net.InetAddress
|
||||||
import java.net.NetworkInterface
|
import java.net.NetworkInterface
|
||||||
import java.net.SocketException
|
import java.net.SocketException
|
||||||
@@ -98,7 +97,7 @@ data class IpNeighbour(val ip: InetAddress, val dev: String, val lladdr: Long, v
|
|||||||
.filter { it.size >= 6 && mac.matcher(it[ARP_HW_ADDRESS]).matches() }
|
.filter { it.size >= 6 && mac.matcher(it[ARP_HW_ADDRESS]).matches() }
|
||||||
.toList()
|
.toList()
|
||||||
} catch (e: IOException) {
|
} catch (e: IOException) {
|
||||||
if (e !is FileNotFoundException || !BuildCompat.isAtLeastQ() ||
|
if (e !is FileNotFoundException || Build.VERSION.SDK_INT < 29 ||
|
||||||
(e.cause as? ErrnoException)?.errno != OsConstants.EACCES) Timber.w(e)
|
(e.cause as? ErrnoException)?.errno != OsConstants.EACCES) Timber.w(e)
|
||||||
}
|
}
|
||||||
return arpCache
|
return arpCache
|
||||||
|
|||||||
@@ -3,13 +3,13 @@ package be.mygod.vpnhotspot.net.wifi
|
|||||||
import android.annotation.SuppressLint
|
import android.annotation.SuppressLint
|
||||||
import android.content.SharedPreferences
|
import android.content.SharedPreferences
|
||||||
import android.net.wifi.WifiManager
|
import android.net.wifi.WifiManager
|
||||||
|
import android.os.Build
|
||||||
import android.os.PowerManager
|
import android.os.PowerManager
|
||||||
import android.view.WindowManager
|
import android.view.WindowManager
|
||||||
import androidx.activity.ComponentActivity
|
import androidx.activity.ComponentActivity
|
||||||
import androidx.annotation.RequiresApi
|
import androidx.annotation.RequiresApi
|
||||||
import androidx.core.content.edit
|
import androidx.core.content.edit
|
||||||
import androidx.core.content.getSystemService
|
import androidx.core.content.getSystemService
|
||||||
import androidx.core.os.BuildCompat
|
|
||||||
import androidx.lifecycle.DefaultLifecycleObserver
|
import androidx.lifecycle.DefaultLifecycleObserver
|
||||||
import androidx.lifecycle.LifecycleOwner
|
import androidx.lifecycle.LifecycleOwner
|
||||||
import be.mygod.vpnhotspot.App.Companion.app
|
import be.mygod.vpnhotspot.App.Companion.app
|
||||||
@@ -23,7 +23,7 @@ class WifiDoubleLock(lockType: Int) : AutoCloseable {
|
|||||||
var mode: Mode
|
var mode: Mode
|
||||||
@Suppress("DEPRECATION")
|
@Suppress("DEPRECATION")
|
||||||
get() = Mode.valueOf(app.pref.getString(KEY, Mode.Full.toString()) ?: "").let {
|
get() = Mode.valueOf(app.pref.getString(KEY, Mode.Full.toString()) ?: "").let {
|
||||||
if (it == Mode.Full && BuildCompat.isAtLeastQ()) Mode.None else it
|
if (it == Mode.Full && Build.VERSION.SDK_INT >= 29) Mode.None else it
|
||||||
}
|
}
|
||||||
set(value) = app.pref.edit { putString(KEY, value.toString()) }
|
set(value) = app.pref.edit { putString(KEY, value.toString()) }
|
||||||
private val service by lazy { app.getSystemService<PowerManager>()!! }
|
private val service by lazy { app.getSystemService<PowerManager>()!! }
|
||||||
|
|||||||
@@ -15,7 +15,6 @@ import android.widget.AdapterView
|
|||||||
import android.widget.ArrayAdapter
|
import android.widget.ArrayAdapter
|
||||||
import androidx.appcompat.app.AlertDialog
|
import androidx.appcompat.app.AlertDialog
|
||||||
import androidx.appcompat.widget.Toolbar
|
import androidx.appcompat.widget.Toolbar
|
||||||
import androidx.core.os.BuildCompat
|
|
||||||
import androidx.core.view.isGone
|
import androidx.core.view.isGone
|
||||||
import be.mygod.vpnhotspot.AlertDialogFragment
|
import be.mygod.vpnhotspot.AlertDialogFragment
|
||||||
import be.mygod.vpnhotspot.App.Companion.app
|
import be.mygod.vpnhotspot.App.Companion.app
|
||||||
@@ -27,7 +26,6 @@ import be.mygod.vpnhotspot.util.toParcelable
|
|||||||
import be.mygod.vpnhotspot.widget.SmartSnackbar
|
import be.mygod.vpnhotspot.widget.SmartSnackbar
|
||||||
import kotlinx.android.parcel.Parcelize
|
import kotlinx.android.parcel.Parcelize
|
||||||
import kotlinx.android.synthetic.main.dialog_wifi_ap.view.*
|
import kotlinx.android.synthetic.main.dialog_wifi_ap.view.*
|
||||||
import java.lang.IllegalStateException
|
|
||||||
import java.nio.charset.Charset
|
import java.nio.charset.Charset
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -117,7 +115,7 @@ class WifiApDialogFragment : AlertDialogFragment<WifiApDialogFragment.Arg, WifiA
|
|||||||
bandOptions = mutableListOf<BandOption>().apply {
|
bandOptions = mutableListOf<BandOption>().apply {
|
||||||
if (arg.p2pMode) {
|
if (arg.p2pMode) {
|
||||||
add(BandOption.BandAny)
|
add(BandOption.BandAny)
|
||||||
if (BuildCompat.isAtLeastQ()) {
|
if (Build.VERSION.SDK_INT >= 29) {
|
||||||
add(BandOption.Band2GHz)
|
add(BandOption.Band2GHz)
|
||||||
add(BandOption.Band5GHz)
|
add(BandOption.Band5GHz)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,7 +14,6 @@ import android.view.View
|
|||||||
import android.widget.ImageView
|
import android.widget.ImageView
|
||||||
import androidx.annotation.DrawableRes
|
import androidx.annotation.DrawableRes
|
||||||
import androidx.core.net.toUri
|
import androidx.core.net.toUri
|
||||||
import androidx.core.os.BuildCompat
|
|
||||||
import androidx.core.view.isVisible
|
import androidx.core.view.isVisible
|
||||||
import androidx.databinding.BindingAdapter
|
import androidx.databinding.BindingAdapter
|
||||||
import be.mygod.vpnhotspot.App.Companion.app
|
import be.mygod.vpnhotspot.App.Companion.app
|
||||||
@@ -95,12 +94,12 @@ fun NetworkInterface.formatAddresses(macOnly: Boolean = false) = SpannableString
|
|||||||
}
|
}
|
||||||
}.trimEnd()
|
}.trimEnd()
|
||||||
|
|
||||||
private val parseNumericAddress by lazy {
|
private val parseNumericAddress by lazy @SuppressLint("SoonBlockedPrivateApi") {
|
||||||
InetAddress::class.java.getDeclaredMethod("parseNumericAddress", String::class.java).apply {
|
InetAddress::class.java.getDeclaredMethod("parseNumericAddress", String::class.java).apply {
|
||||||
isAccessible = true
|
isAccessible = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fun parseNumericAddress(address: String) = if (BuildCompat.isAtLeastQ())
|
fun parseNumericAddress(address: String) = if (Build.VERSION.SDK_INT >= 29)
|
||||||
InetAddresses.parseNumericAddress(address) else parseNumericAddress.invoke(null, address) as InetAddress
|
InetAddresses.parseNumericAddress(address) else parseNumericAddress.invoke(null, address) as InetAddress
|
||||||
|
|
||||||
fun Context.launchUrl(url: String) {
|
fun Context.launchUrl(url: String) {
|
||||||
|
|||||||
Reference in New Issue
Block a user