Fix crash on Android 7-
This commit is contained in:
@@ -1,19 +1,31 @@
|
||||
package be.mygod.vpnhotspot
|
||||
|
||||
import android.net.ConnectivityManager
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.support.annotation.RequiresApi
|
||||
import java.io.File
|
||||
|
||||
object NetUtils {
|
||||
// hidden constants from ConnectivityManager
|
||||
/**
|
||||
* This is a sticky broadcast since almost forever.
|
||||
*
|
||||
* https://android.googlesource.com/platform/frameworks/base.git/+/2a091d7aa0c174986387e5d56bf97a87fe075bdb%5E%21/services/java/com/android/server/connectivity/Tethering.java
|
||||
*/
|
||||
const val ACTION_TETHER_STATE_CHANGED = "android.net.conn.TETHER_STATE_CHANGED"
|
||||
const val EXTRA_ACTIVE_TETHER = "tetherArray"
|
||||
@Deprecated("No longer used on Android 8+ (API 26+)")
|
||||
private const val EXTRA_ACTIVE_TETHER_LEGACY = "activeArray"
|
||||
@RequiresApi(26)
|
||||
private const val EXTRA_ACTIVE_LOCAL_ONLY = "localOnlyArray"
|
||||
@RequiresApi(26)
|
||||
private const val EXTRA_ACTIVE_TETHER = "tetherArray"
|
||||
|
||||
private val spaces = " +".toPattern()
|
||||
private val mac = "^([0-9a-f]{2}:){5}[0-9a-f]{2}$".toPattern()
|
||||
|
||||
private val getTetheredIfaces = ConnectivityManager::class.java.getDeclaredMethod("getTetheredIfaces")
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
val ConnectivityManager.tetheredIfaces get() = getTetheredIfaces.invoke(this) as Array<String>
|
||||
fun getTetheredIfaces(extras: Bundle) = if (Build.VERSION.SDK_INT >= 26)
|
||||
extras.getStringArrayList(EXTRA_ACTIVE_TETHER).toSet() + extras.getStringArrayList(EXTRA_ACTIVE_LOCAL_ONLY)
|
||||
else extras.getStringArrayList(EXTRA_ACTIVE_TETHER_LEGACY).toSet()
|
||||
|
||||
fun arp(iface: String? = null) = File("/proc/net/arp").bufferedReader().useLines {
|
||||
// IP address HW type Flags HW address Mask Device
|
||||
|
||||
@@ -18,7 +18,6 @@ import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import be.mygod.vpnhotspot.App.Companion.app
|
||||
import be.mygod.vpnhotspot.NetUtils.tetheredIfaces
|
||||
import be.mygod.vpnhotspot.databinding.FragmentTetheringBinding
|
||||
import be.mygod.vpnhotspot.databinding.ListitemInterfaceBinding
|
||||
import be.mygod.vpnhotspot.widget.TextViewLinkHandler
|
||||
@@ -86,7 +85,7 @@ class TetheringFragment : Fragment() {
|
||||
inner class InterfaceAdapter : RecyclerView.Adapter<InterfaceViewHolder>() {
|
||||
private val tethered = SortedList(String::class.java, StringSorter)
|
||||
|
||||
fun update(data: Set<String> = VpnListener.connectivityManager.tetheredIfaces.toSet()) {
|
||||
fun update(data: Set<String>) {
|
||||
val oldEmpty = tethered.size() == 0
|
||||
tethered.clear()
|
||||
tethered.addAll(data)
|
||||
@@ -109,8 +108,7 @@ class TetheringFragment : Fragment() {
|
||||
private val receiver = broadcastReceiver { _, intent ->
|
||||
when (intent.action) {
|
||||
TetheringService.ACTION_ACTIVE_INTERFACES_CHANGED -> adapter.notifyDataSetChanged()
|
||||
NetUtils.ACTION_TETHER_STATE_CHANGED ->
|
||||
adapter.update(intent.extras.getStringArrayList(NetUtils.EXTRA_ACTIVE_TETHER).toSet())
|
||||
NetUtils.ACTION_TETHER_STATE_CHANGED -> adapter.update(NetUtils.getTetheredIfaces(intent.extras).toSet())
|
||||
}
|
||||
}
|
||||
private var receiverRegistered = false
|
||||
@@ -133,7 +131,6 @@ class TetheringFragment : Fragment() {
|
||||
override fun onStart() {
|
||||
super.onStart()
|
||||
if (!receiverRegistered) {
|
||||
adapter.update()
|
||||
val context = context!!
|
||||
context.registerReceiver(receiver, intentFilter(NetUtils.ACTION_TETHER_STATE_CHANGED))
|
||||
LocalBroadcastManager.getInstance(context)
|
||||
|
||||
@@ -4,7 +4,6 @@ import android.app.Service
|
||||
import android.content.Intent
|
||||
import android.support.v4.content.LocalBroadcastManager
|
||||
import be.mygod.vpnhotspot.App.Companion.app
|
||||
import be.mygod.vpnhotspot.NetUtils.tetheredIfaces
|
||||
|
||||
class TetheringService : Service(), VpnListener.Callback {
|
||||
companion object {
|
||||
@@ -25,7 +24,7 @@ class TetheringService : Service(), VpnListener.Callback {
|
||||
private var upstream: String? = null
|
||||
private var receiverRegistered = false
|
||||
private val receiver = broadcastReceiver { _, intent ->
|
||||
val remove = routings.keys - intent.extras.getStringArrayList(NetUtils.EXTRA_ACTIVE_TETHER).toSet()
|
||||
val remove = routings.keys - NetUtils.getTetheredIfaces(intent.extras)
|
||||
if (remove.isEmpty()) return@broadcastReceiver
|
||||
for (iface in remove) routings.remove(iface)?.stop()
|
||||
updateRoutings()
|
||||
@@ -34,12 +33,7 @@ class TetheringService : Service(), VpnListener.Callback {
|
||||
private fun updateRoutings() {
|
||||
active = routings.keys
|
||||
if (routings.isEmpty()) {
|
||||
if (receiverRegistered) {
|
||||
unregisterReceiver(receiver)
|
||||
VpnListener.unregisterCallback(this)
|
||||
upstream = null
|
||||
receiverRegistered = false
|
||||
}
|
||||
unregisterReceiver()
|
||||
stopSelf()
|
||||
} else {
|
||||
val upstream = upstream
|
||||
@@ -61,14 +55,9 @@ class TetheringService : Service(), VpnListener.Callback {
|
||||
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
|
||||
if (intent != null) { // otw service is recreated after being killed
|
||||
val iface = intent.getStringExtra(EXTRA_ADD_INTERFACE)
|
||||
if (iface != null && VpnListener.connectivityManager.tetheredIfaces.contains(iface))
|
||||
routings.put(iface, null)
|
||||
if (iface != null) routings.put(iface, null)
|
||||
routings.remove(intent.getStringExtra(EXTRA_REMOVE_INTERFACE))?.stop()
|
||||
} else {
|
||||
val active = active
|
||||
if (active.isNotEmpty()) active.intersect(VpnListener.connectivityManager.tetheredIfaces.asIterable())
|
||||
.forEach { routings.put(it, null) }
|
||||
}
|
||||
} else active.forEach { routings.put(it, null) }
|
||||
updateRoutings()
|
||||
return START_STICKY
|
||||
}
|
||||
@@ -87,4 +76,18 @@ class TetheringService : Service(), VpnListener.Callback {
|
||||
routings[iface] = null
|
||||
}
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
unregisterReceiver()
|
||||
super.onDestroy()
|
||||
}
|
||||
|
||||
fun unregisterReceiver() {
|
||||
if (receiverRegistered) {
|
||||
unregisterReceiver(receiver)
|
||||
VpnListener.unregisterCallback(this)
|
||||
upstream = null
|
||||
receiverRegistered = false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user