Preliminary support for Ethernet and NCM tethering
This commit is contained in:
@@ -17,6 +17,8 @@ abstract class Manager {
|
||||
const val VIEW_TYPE_WIFI = 2
|
||||
const val VIEW_TYPE_USB = 3
|
||||
const val VIEW_TYPE_BLUETOOTH = 4
|
||||
const val VIEW_TYPE_ETHERNET = 8
|
||||
const val VIEW_TYPE_NCM = 9
|
||||
const val VIEW_TYPE_WIFI_LEGACY = 5
|
||||
const val VIEW_TYPE_LOCAL_ONLY_HOTSPOT = 6
|
||||
const val VIEW_TYPE_REPEATER = 7
|
||||
@@ -29,8 +31,14 @@ abstract class Manager {
|
||||
VIEW_TYPE_INTERFACE ->
|
||||
InterfaceManager.ViewHolder(ListitemInterfaceBinding.inflate(inflater, parent, false))
|
||||
VIEW_TYPE_MANAGE -> ManageBar.ViewHolder(ListitemManageBinding.inflate(inflater, parent, false))
|
||||
VIEW_TYPE_WIFI, VIEW_TYPE_USB, VIEW_TYPE_BLUETOOTH, VIEW_TYPE_WIFI_LEGACY ->
|
||||
VIEW_TYPE_WIFI,
|
||||
VIEW_TYPE_USB,
|
||||
VIEW_TYPE_BLUETOOTH,
|
||||
VIEW_TYPE_ETHERNET,
|
||||
VIEW_TYPE_NCM,
|
||||
VIEW_TYPE_WIFI_LEGACY -> {
|
||||
TetherManager.ViewHolder(ListitemInterfaceBinding.inflate(inflater, parent, false))
|
||||
}
|
||||
VIEW_TYPE_LOCAL_ONLY_HOTSPOT -> @TargetApi(26) {
|
||||
LocalOnlyHotspotManager.ViewHolder(ListitemInterfaceBinding.inflate(inflater, parent, false))
|
||||
}
|
||||
|
||||
@@ -157,6 +157,24 @@ sealed class TetherManager(protected val parent: TetheringFragment) : Manager(),
|
||||
onTetheringStarted() // force flush state
|
||||
}
|
||||
}
|
||||
@RequiresApi(30)
|
||||
class Ethernet(parent: TetheringFragment) : TetherManager(parent) {
|
||||
override val title get() = parent.getString(R.string.tethering_manage_ethernet)
|
||||
override val tetherType get() = TetherType.ETHERNET
|
||||
override val type get() = VIEW_TYPE_ETHERNET
|
||||
|
||||
override fun start() = TetheringManager.startTethering(TetheringManager.TETHERING_ETHERNET, true, this)
|
||||
override fun stop() = TetheringManager.stopTethering(TetheringManager.TETHERING_ETHERNET)
|
||||
}
|
||||
@RequiresApi(30)
|
||||
class Ncm(parent: TetheringFragment) : TetherManager(parent) {
|
||||
override val title get() = parent.getString(R.string.tethering_manage_ncm)
|
||||
override val tetherType get() = TetherType.NCM
|
||||
override val type get() = VIEW_TYPE_NCM
|
||||
|
||||
override fun start() = TetheringManager.startTethering(TetheringManager.TETHERING_NCM, true, this)
|
||||
override fun stop() = TetheringManager.stopTethering(TetheringManager.TETHERING_NCM)
|
||||
}
|
||||
|
||||
@Suppress("DEPRECATION")
|
||||
@Deprecated("Not usable since API 26, malfunctioning on API 25")
|
||||
|
||||
@@ -10,8 +10,10 @@ import android.view.LayoutInflater
|
||||
import android.view.MenuItem
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.annotation.RequiresApi
|
||||
import androidx.appcompat.widget.Toolbar
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.core.os.BuildCompat
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.recyclerview.widget.DefaultItemAnimator
|
||||
@@ -46,12 +48,18 @@ class TetheringFragment : Fragment(), ServiceConnection, Toolbar.OnMenuItemClick
|
||||
|
||||
inner class ManagerAdapter : ListAdapter<Manager, RecyclerView.ViewHolder>(Manager) {
|
||||
internal val repeaterManager by lazy { RepeaterManager(this@TetheringFragment) }
|
||||
@get:RequiresApi(26)
|
||||
internal val localOnlyHotspotManager by lazy @TargetApi(26) { LocalOnlyHotspotManager(this@TetheringFragment) }
|
||||
@get:RequiresApi(24)
|
||||
private val tetherManagers by lazy @TargetApi(24) {
|
||||
listOf(TetherManager.Wifi(this@TetheringFragment),
|
||||
TetherManager.Usb(this@TetheringFragment),
|
||||
TetherManager.Bluetooth(this@TetheringFragment))
|
||||
}
|
||||
@get:RequiresApi(30)
|
||||
private val tetherManagers30 by lazy @TargetApi(30) {
|
||||
listOf(TetherManager.Ethernet(this@TetheringFragment), TetherManager.Ncm(this@TetheringFragment))
|
||||
}
|
||||
private val wifiManagerLegacy by lazy @Suppress("Deprecation") {
|
||||
TetherManager.WifiLegacy(this@TetheringFragment)
|
||||
}
|
||||
@@ -78,6 +86,10 @@ class TetheringFragment : Fragment(), ServiceConnection, Toolbar.OnMenuItemClick
|
||||
list.addAll(tetherManagers)
|
||||
tetherManagers.forEach { it.updateErrorMessage(erroredIfaces) }
|
||||
}
|
||||
if (BuildCompat.isAtLeastR()) {
|
||||
list.addAll(tetherManagers30)
|
||||
tetherManagers30.forEach { it.updateErrorMessage(erroredIfaces) }
|
||||
}
|
||||
if (Build.VERSION.SDK_INT < 26) {
|
||||
list.add(wifiManagerLegacy)
|
||||
wifiManagerLegacy.onTetheringStarted()
|
||||
|
||||
@@ -191,6 +191,22 @@ sealed class TetheringTileService : TetherListeningTileService(), TetheringManag
|
||||
}
|
||||
}
|
||||
}
|
||||
@RequiresApi(30)
|
||||
class Ethernet : TetheringTileService() {
|
||||
override val labelString get() = R.string.tethering_manage_ethernet
|
||||
override val tetherType get() = TetherType.ETHERNET
|
||||
|
||||
override fun start() = TetheringManager.startTethering(TetheringManager.TETHERING_ETHERNET, true, this)
|
||||
override fun stop() = TetheringManager.stopTethering(TetheringManager.TETHERING_ETHERNET)
|
||||
}
|
||||
@RequiresApi(30)
|
||||
class Ncm : TetheringTileService() {
|
||||
override val labelString get() = R.string.tethering_manage_ncm
|
||||
override val tetherType get() = TetherType.NCM
|
||||
|
||||
override fun start() = TetheringManager.startTethering(TetheringManager.TETHERING_NCM, true, this)
|
||||
override fun stop() = TetheringManager.stopTethering(TetheringManager.TETHERING_NCM)
|
||||
}
|
||||
|
||||
@Suppress("DEPRECATION")
|
||||
@Deprecated("Not usable since API 25")
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
package be.mygod.vpnhotspot.net
|
||||
|
||||
import android.content.res.Resources
|
||||
import androidx.core.os.BuildCompat
|
||||
import be.mygod.vpnhotspot.App.Companion.app
|
||||
import be.mygod.vpnhotspot.R
|
||||
import java.util.regex.Pattern
|
||||
|
||||
enum class TetherType {
|
||||
NONE, WIFI_P2P, USB, WIFI, WIMAX, BLUETOOTH;
|
||||
NONE, WIFI_P2P, USB, WIFI, WIMAX, BLUETOOTH, NCM, ETHERNET;
|
||||
|
||||
val icon get() = when (this) {
|
||||
USB -> R.drawable.ic_device_usb
|
||||
@@ -14,6 +15,9 @@ enum class TetherType {
|
||||
WIFI -> R.drawable.ic_device_network_wifi
|
||||
WIMAX -> R.drawable.ic_action_contactless
|
||||
BLUETOOTH -> R.drawable.ic_device_bluetooth
|
||||
// if you have an issue with these Ethernet icon namings, blame Google
|
||||
NCM -> R.drawable.ic_action_settings_ethernet
|
||||
ETHERNET -> R.drawable.ic_content_inbox
|
||||
else -> R.drawable.ic_device_wifi_tethering
|
||||
}
|
||||
val isWifi get() = when (this) {
|
||||
@@ -24,43 +28,48 @@ enum class TetherType {
|
||||
companion object {
|
||||
private val usbRegexs: List<Pattern>
|
||||
private val wifiRegexs: List<Pattern>
|
||||
private val wifiP2pRegexs: List<Pattern>
|
||||
private val wimaxRegexs: List<Pattern>
|
||||
private val bluetoothRegexs: List<Pattern>
|
||||
private val ncmRegexs: List<Pattern>
|
||||
private val ethernetRegex: Pattern?
|
||||
|
||||
/**
|
||||
* Source: https://android.googlesource.com/platform/frameworks/base/+/61fa313/core/res/res/values/config.xml#328
|
||||
* Source: https://android.googlesource.com/platform/frameworks/base/+/32e772f/packages/Tethering/src/com/android/networkstack/tethering/TetheringConfiguration.java#93
|
||||
*/
|
||||
init {
|
||||
val appRes = app.resources
|
||||
val sysRes = Resources.getSystem()
|
||||
usbRegexs = appRes.getStringArray(sysRes
|
||||
.getIdentifier("config_tether_usb_regexs", "array", "android"))
|
||||
.filterNotNull()
|
||||
.map { it.toPattern() }
|
||||
wifiRegexs = appRes.getStringArray(sysRes
|
||||
.getIdentifier("config_tether_wifi_regexs", "array", "android"))
|
||||
.filterNotNull()
|
||||
.map { it.toPattern() }
|
||||
wimaxRegexs = appRes.getStringArray(sysRes
|
||||
.getIdentifier("config_tether_wimax_regexs", "array", "android"))
|
||||
.filterNotNull()
|
||||
.map { it.toPattern() }
|
||||
bluetoothRegexs = appRes.getStringArray(sysRes
|
||||
.getIdentifier("config_tether_bluetooth_regexs", "array", "android"))
|
||||
fun getRegexs(name: String) = appRes.getStringArray(sysRes
|
||||
.getIdentifier(name, "array", "android"))
|
||||
.filterNotNull()
|
||||
.map { it.toPattern() }
|
||||
usbRegexs = getRegexs("config_tether_usb_regexs")
|
||||
wifiRegexs = getRegexs("config_tether_wifi_regexs")
|
||||
wifiP2pRegexs = if (BuildCompat.isAtLeastR()) getRegexs("config_tether_wifi_p2p_regexs") else emptyList()
|
||||
wimaxRegexs = getRegexs("config_tether_wimax_regexs")
|
||||
bluetoothRegexs = getRegexs("config_tether_bluetooth_regexs")
|
||||
ncmRegexs = if (BuildCompat.isAtLeastR()) getRegexs("config_tether_ncm_regexs") else emptyList()
|
||||
ethernetRegex = if (BuildCompat.isAtLeastR()) {
|
||||
appRes.getString(sysRes.getIdentifier("config_ethernet_iface_regex", "string", "android")).run {
|
||||
if (isEmpty()) null else toPattern()
|
||||
}
|
||||
} else null
|
||||
}
|
||||
|
||||
/**
|
||||
* Based on: https://android.googlesource.com/platform/frameworks/base/+/0e3d092/services/core/java/com/android/server/connectivity/Tethering.java#311
|
||||
* Based on: https://android.googlesource.com/platform/frameworks/base/+/5d36f01/packages/Tethering/src/com/android/networkstack/tethering/Tethering.java#479
|
||||
*/
|
||||
fun ofInterface(iface: String?, p2pDev: String? = null) = when {
|
||||
iface == null -> NONE
|
||||
iface == p2pDev -> WIFI_P2P
|
||||
wifiRegexs.any { it.matcher(iface).matches() } -> WIFI
|
||||
wifiP2pRegexs.any { it.matcher(iface).matches() } -> WIFI_P2P
|
||||
usbRegexs.any { it.matcher(iface).matches() } -> USB
|
||||
bluetoothRegexs.any { it.matcher(iface).matches() } -> BLUETOOTH
|
||||
ncmRegexs.any { it.matcher(iface).matches() } -> NCM
|
||||
wimaxRegexs.any { it.matcher(iface).matches() } -> WIMAX
|
||||
ethernetRegex?.matcher(iface)?.matches() == true -> ETHERNET
|
||||
else -> NONE
|
||||
}
|
||||
}
|
||||
|
||||
@@ -79,6 +79,7 @@ object TetheringManager {
|
||||
*/
|
||||
const val EXTRA_ERRORED_TETHER = "erroredArray"
|
||||
|
||||
// tethering types supported by enableTetheringInternal: https://android.googlesource.com/platform/frameworks/base/+/5d36f01/packages/Tethering/src/com/android/networkstack/tethering/Tethering.java#549
|
||||
/**
|
||||
* Wifi tethering type.
|
||||
* @see [startTethering].
|
||||
@@ -103,6 +104,22 @@ object TetheringManager {
|
||||
*/
|
||||
@RequiresApi(24)
|
||||
const val TETHERING_BLUETOOTH = 2
|
||||
/**
|
||||
* Ncm local tethering type.
|
||||
*
|
||||
* Requires NETWORK_SETTINGS permission, which is sadly not obtainable.
|
||||
* @see [startTethering]
|
||||
*/
|
||||
@RequiresApi(30)
|
||||
const val TETHERING_NCM = 4
|
||||
/**
|
||||
* Ethernet tethering type.
|
||||
*
|
||||
* Requires MANAGE_USB permission, also.
|
||||
* @see [startTethering]
|
||||
*/
|
||||
@RequiresApi(30)
|
||||
const val TETHERING_ETHERNET = 5
|
||||
|
||||
@get:RequiresApi(30)
|
||||
private val clazz by lazy { Class.forName("android.net.TetheringManager") }
|
||||
|
||||
Reference in New Issue
Block a user