Support vendor elements for p2p
This commit is contained in:
@@ -3,8 +3,6 @@
|
|||||||
<!-- Required since API 31, when targeting API 31 -->
|
<!-- Required since API 31, when targeting API 31 -->
|
||||||
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT"/>
|
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT"/>
|
||||||
<!-- Required since API 33, when targeting API 33 -->
|
<!-- Required since API 33, when targeting API 33 -->
|
||||||
<uses-permission android:name="android.permission.NEARBY_WIFI_DEVICES"
|
|
||||||
android:usesPermissionFlags="neverForLocation"/>
|
|
||||||
<uses-permission android:name="android.permission.POST_NOTIFICATIONS"/>
|
<uses-permission android:name="android.permission.POST_NOTIFICATIONS"/>
|
||||||
<uses-permission-sdk-23 android:name="android.permission.ACCESS_COARSE_LOCATION"
|
<uses-permission-sdk-23 android:name="android.permission.ACCESS_COARSE_LOCATION"
|
||||||
android:maxSdkVersion="32"/>
|
android:maxSdkVersion="32"/>
|
||||||
|
|||||||
@@ -36,6 +36,8 @@
|
|||||||
tools:ignore="ProtectedPermissions" />
|
tools:ignore="ProtectedPermissions" />
|
||||||
<uses-permission android:name="android.permission.MANAGE_USB"
|
<uses-permission android:name="android.permission.MANAGE_USB"
|
||||||
tools:ignore="ProtectedPermissions"/>
|
tools:ignore="ProtectedPermissions"/>
|
||||||
|
<uses-permission android:name="android.permission.NEARBY_WIFI_DEVICES"
|
||||||
|
android:usesPermissionFlags="neverForLocation"/>
|
||||||
<uses-permission android:name="android.permission.OVERRIDE_WIFI_CONFIG"
|
<uses-permission android:name="android.permission.OVERRIDE_WIFI_CONFIG"
|
||||||
tools:ignore="ProtectedPermissions"/>
|
tools:ignore="ProtectedPermissions"/>
|
||||||
<uses-permission android:name="android.permission.READ_WIFI_CREDENTIAL"
|
<uses-permission android:name="android.permission.READ_WIFI_CREDENTIAL"
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import android.content.Intent
|
|||||||
import android.content.SharedPreferences
|
import android.content.SharedPreferences
|
||||||
import android.content.pm.PackageManager
|
import android.content.pm.PackageManager
|
||||||
import android.location.LocationManager
|
import android.location.LocationManager
|
||||||
|
import android.net.wifi.ScanResult
|
||||||
import android.net.wifi.WpsInfo
|
import android.net.wifi.WpsInfo
|
||||||
import android.net.wifi.p2p.*
|
import android.net.wifi.p2p.*
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
@@ -21,6 +22,7 @@ import be.mygod.vpnhotspot.App.Companion.app
|
|||||||
import be.mygod.vpnhotspot.net.MacAddressCompat
|
import be.mygod.vpnhotspot.net.MacAddressCompat
|
||||||
import be.mygod.vpnhotspot.net.monitor.TetherTimeoutMonitor
|
import be.mygod.vpnhotspot.net.monitor.TetherTimeoutMonitor
|
||||||
import be.mygod.vpnhotspot.net.wifi.SoftApConfigurationCompat
|
import be.mygod.vpnhotspot.net.wifi.SoftApConfigurationCompat
|
||||||
|
import be.mygod.vpnhotspot.net.wifi.VendorElements
|
||||||
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
|
||||||
import be.mygod.vpnhotspot.net.wifi.WifiP2pManagerHelper.requestConnectionInfo
|
import be.mygod.vpnhotspot.net.wifi.WifiP2pManagerHelper.requestConnectionInfo
|
||||||
@@ -28,6 +30,7 @@ import be.mygod.vpnhotspot.net.wifi.WifiP2pManagerHelper.requestDeviceAddress
|
|||||||
import be.mygod.vpnhotspot.net.wifi.WifiP2pManagerHelper.requestGroupInfo
|
import be.mygod.vpnhotspot.net.wifi.WifiP2pManagerHelper.requestGroupInfo
|
||||||
import be.mygod.vpnhotspot.net.wifi.WifiP2pManagerHelper.requestP2pState
|
import be.mygod.vpnhotspot.net.wifi.WifiP2pManagerHelper.requestP2pState
|
||||||
import be.mygod.vpnhotspot.net.wifi.WifiP2pManagerHelper.requestPersistentGroupInfo
|
import be.mygod.vpnhotspot.net.wifi.WifiP2pManagerHelper.requestPersistentGroupInfo
|
||||||
|
import be.mygod.vpnhotspot.net.wifi.WifiP2pManagerHelper.setVendorElements
|
||||||
import be.mygod.vpnhotspot.net.wifi.WifiP2pManagerHelper.setWifiP2pChannels
|
import be.mygod.vpnhotspot.net.wifi.WifiP2pManagerHelper.setWifiP2pChannels
|
||||||
import be.mygod.vpnhotspot.net.wifi.WifiP2pManagerHelper.startWps
|
import be.mygod.vpnhotspot.net.wifi.WifiP2pManagerHelper.startWps
|
||||||
import be.mygod.vpnhotspot.root.RepeaterCommands
|
import be.mygod.vpnhotspot.root.RepeaterCommands
|
||||||
@@ -55,6 +58,7 @@ class RepeaterService : Service(), CoroutineScope, WifiP2pManager.ChannelListene
|
|||||||
private const val KEY_AUTO_SHUTDOWN = "service.repeater.autoShutdown"
|
private const val KEY_AUTO_SHUTDOWN = "service.repeater.autoShutdown"
|
||||||
private const val KEY_SHUTDOWN_TIMEOUT = "service.repeater.shutdownTimeout"
|
private const val KEY_SHUTDOWN_TIMEOUT = "service.repeater.shutdownTimeout"
|
||||||
private const val KEY_DEVICE_ADDRESS = "service.repeater.mac"
|
private const val KEY_DEVICE_ADDRESS = "service.repeater.mac"
|
||||||
|
private const val KEY_VENDOR_ELEMENTS = "service.repeater.vendorElements"
|
||||||
|
|
||||||
var persistentSupported = false
|
var persistentSupported = false
|
||||||
|
|
||||||
@@ -105,6 +109,11 @@ class RepeaterService : Service(), CoroutineScope, WifiP2pManager.ChannelListene
|
|||||||
null
|
null
|
||||||
}
|
}
|
||||||
set(value) = app.pref.edit { putLong(KEY_DEVICE_ADDRESS, (value ?: MacAddressCompat.ANY_ADDRESS).addr) }
|
set(value) = app.pref.edit { putLong(KEY_DEVICE_ADDRESS, (value ?: MacAddressCompat.ANY_ADDRESS).addr) }
|
||||||
|
@get:RequiresApi(33)
|
||||||
|
@set:RequiresApi(33)
|
||||||
|
var vendorElements: List<ScanResult.InformationElement>
|
||||||
|
get() = VendorElements.deserialize(app.pref.getString(KEY_VENDOR_ELEMENTS, null))
|
||||||
|
set(value) = app.pref.edit { putString(KEY_VENDOR_ELEMENTS, VendorElements.serialize(value)) }
|
||||||
}
|
}
|
||||||
|
|
||||||
enum class Status {
|
enum class Status {
|
||||||
@@ -305,6 +314,31 @@ class RepeaterService : Service(), CoroutineScope, WifiP2pManager.ChannelListene
|
|||||||
} else SmartSnackbar.make(formatReason(R.string.repeater_set_oc_failure, reason)).show()
|
} else SmartSnackbar.make(formatReason(R.string.repeater_set_oc_failure, reason)).show()
|
||||||
} else SmartSnackbar.make(R.string.repeater_failure_disconnected).show()
|
} else SmartSnackbar.make(R.string.repeater_failure_disconnected).show()
|
||||||
}
|
}
|
||||||
|
@RequiresApi(33)
|
||||||
|
private suspend fun setVendorElements(ve: List<ScanResult.InformationElement> = vendorElements) {
|
||||||
|
val channel = channel
|
||||||
|
if (channel != null) {
|
||||||
|
val reason = try {
|
||||||
|
p2pManager.setVendorElements(channel, ve) ?: return
|
||||||
|
} catch (e: IllegalArgumentException) {
|
||||||
|
SmartSnackbar.make(getString(R.string.repeater_set_vendor_elements_failure, e.message)).show()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (reason == WifiP2pManager.ERROR) {
|
||||||
|
val rootReason = try {
|
||||||
|
RootManager.use {
|
||||||
|
if (deinitPending.getAndSet(false)) it.execute(RepeaterCommands.Deinit())
|
||||||
|
it.execute(RepeaterCommands.SetVendorElements(ve))
|
||||||
|
} ?: return
|
||||||
|
} catch (e: Exception) {
|
||||||
|
Timber.w(e)
|
||||||
|
SmartSnackbar.make(e).show()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
SmartSnackbar.make(formatReason(R.string.repeater_set_vendor_elements_failure, rootReason.value)).show()
|
||||||
|
} else SmartSnackbar.make(formatReason(R.string.repeater_set_vendor_elements_failure, reason)).show()
|
||||||
|
} else SmartSnackbar.make(R.string.repeater_failure_disconnected).show()
|
||||||
|
}
|
||||||
|
|
||||||
override fun onChannelDisconnected() {
|
override fun onChannelDisconnected() {
|
||||||
channel = null
|
channel = null
|
||||||
@@ -321,9 +355,10 @@ class RepeaterService : Service(), CoroutineScope, WifiP2pManager.ChannelListene
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences?, key: String?) {
|
override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences?, key: String?) {
|
||||||
if (!safeMode) when (key) {
|
when (key) {
|
||||||
KEY_OPERATING_CHANNEL -> launch { setOperatingChannel() }
|
KEY_OPERATING_CHANNEL -> if (!safeMode) launch { setOperatingChannel() }
|
||||||
KEY_SAFE_MODE -> deinitPending.set(true)
|
KEY_VENDOR_ELEMENTS -> if (Build.VERSION.SDK_INT >= 33) launch { setVendorElements() }
|
||||||
|
KEY_SAFE_MODE -> if (!safeMode) deinitPending.set(true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -405,6 +440,7 @@ class RepeaterService : Service(), CoroutineScope, WifiP2pManager.ChannelListene
|
|||||||
binder.fetchPersistentGroup()
|
binder.fetchPersistentGroup()
|
||||||
setOperatingChannel()
|
setOperatingChannel()
|
||||||
}
|
}
|
||||||
|
if (Build.VERSION.SDK_INT >= 33) setVendorElements()
|
||||||
val networkName = networkName
|
val networkName = networkName
|
||||||
val passphrase = passphrase
|
val passphrase = passphrase
|
||||||
@SuppressLint("MissingPermission") // missing permission will simply leading to returning ERROR
|
@SuppressLint("MissingPermission") // missing permission will simply leading to returning ERROR
|
||||||
|
|||||||
@@ -199,6 +199,7 @@ class RepeaterManager(private val parent: TetheringFragment) : Manager(), Servic
|
|||||||
macRandomizationSetting = if (WifiApManager.p2pMacRandomizationSupported) {
|
macRandomizationSetting = if (WifiApManager.p2pMacRandomizationSupported) {
|
||||||
SoftApConfigurationCompat.RANDOMIZATION_NON_PERSISTENT
|
SoftApConfigurationCompat.RANDOMIZATION_NON_PERSISTENT
|
||||||
} else SoftApConfigurationCompat.RANDOMIZATION_NONE,
|
} else SoftApConfigurationCompat.RANDOMIZATION_NONE,
|
||||||
|
vendorElements = RepeaterService.vendorElements,
|
||||||
).apply {
|
).apply {
|
||||||
bssid = RepeaterService.deviceAddress
|
bssid = RepeaterService.deviceAddress
|
||||||
setChannel(RepeaterService.operatingChannel, RepeaterService.operatingBand)
|
setChannel(RepeaterService.operatingChannel, RepeaterService.operatingBand)
|
||||||
@@ -214,6 +215,7 @@ class RepeaterManager(private val parent: TetheringFragment) : Manager(), Servic
|
|||||||
macRandomizationSetting = if (WifiApManager.p2pMacRandomizationSupported) {
|
macRandomizationSetting = if (WifiApManager.p2pMacRandomizationSupported) {
|
||||||
SoftApConfigurationCompat.RANDOMIZATION_NON_PERSISTENT
|
SoftApConfigurationCompat.RANDOMIZATION_NON_PERSISTENT
|
||||||
} else SoftApConfigurationCompat.RANDOMIZATION_NONE,
|
} else SoftApConfigurationCompat.RANDOMIZATION_NONE,
|
||||||
|
vendorElements = RepeaterService.vendorElements,
|
||||||
).run {
|
).run {
|
||||||
setChannel(RepeaterService.operatingChannel)
|
setChannel(RepeaterService.operatingChannel)
|
||||||
try {
|
try {
|
||||||
@@ -258,5 +260,6 @@ class RepeaterManager(private val parent: TetheringFragment) : Manager(), Servic
|
|||||||
RepeaterService.operatingChannel = channel
|
RepeaterService.operatingChannel = channel
|
||||||
RepeaterService.isAutoShutdownEnabled = config.isAutoShutdownEnabled
|
RepeaterService.isAutoShutdownEnabled = config.isAutoShutdownEnabled
|
||||||
RepeaterService.shutdownTimeoutMillis = config.shutdownTimeoutMillis
|
RepeaterService.shutdownTimeoutMillis = config.shutdownTimeoutMillis
|
||||||
|
RepeaterService.vendorElements = config.vendorElements
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,27 @@
|
|||||||
|
package be.mygod.vpnhotspot.net.wifi
|
||||||
|
|
||||||
|
import android.net.wifi.ScanResult
|
||||||
|
import androidx.annotation.RequiresApi
|
||||||
|
import timber.log.Timber
|
||||||
|
|
||||||
|
@RequiresApi(33)
|
||||||
|
object VendorElements {
|
||||||
|
fun serialize(input: List<ScanResult.InformationElement>) = input.joinToString("\n") { element ->
|
||||||
|
element.bytes.let { buffer ->
|
||||||
|
StringBuilder().apply {
|
||||||
|
while (buffer.hasRemaining()) append("%02x".format(buffer.get()))
|
||||||
|
}.toString()
|
||||||
|
}.also {
|
||||||
|
if (element.id != 221 || element.idExt != 0 || it.isEmpty()) Timber.w(Exception(
|
||||||
|
"Unexpected InformationElement ${element.id}, ${element.idExt}, $it"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun deserialize(input: CharSequence?) = (input ?: "").split("\n").map { line ->
|
||||||
|
if (line.isBlank()) return@map null
|
||||||
|
require(line.length % 2 == 0) { "Input should be hex: $line" }
|
||||||
|
(0 until line.length / 2).map {
|
||||||
|
Integer.parseInt(line.substring(it * 2, it * 2 + 2), 16).toByte()
|
||||||
|
}.toByteArray()
|
||||||
|
}.filterNotNull().map { ScanResult.InformationElement(221, 0, it) }
|
||||||
|
}
|
||||||
@@ -5,7 +5,6 @@ import android.annotation.TargetApi
|
|||||||
import android.content.ClipData
|
import android.content.ClipData
|
||||||
import android.content.ClipDescription
|
import android.content.ClipDescription
|
||||||
import android.content.DialogInterface
|
import android.content.DialogInterface
|
||||||
import android.net.wifi.ScanResult
|
|
||||||
import android.net.wifi.SoftApConfiguration
|
import android.net.wifi.SoftApConfiguration
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
import android.os.Parcelable
|
import android.os.Parcelable
|
||||||
@@ -143,13 +142,6 @@ class WifiApDialogFragment : AlertDialogFragment<WifiApDialogFragment.Arg, WifiA
|
|||||||
}
|
}
|
||||||
(dialogView.bandPrimary.selectedItem as ChannelOption).apply { put(band, channel) }
|
(dialogView.bandPrimary.selectedItem as ChannelOption).apply { put(band, channel) }
|
||||||
}
|
}
|
||||||
private fun generateVendorElements() = (dialogView.vendorElements.text ?: "").split("\n").map { line ->
|
|
||||||
if (line.isBlank()) return@map null
|
|
||||||
require(line.length % 2 == 0) { "Input should be hex: $line" }
|
|
||||||
(0 until line.length / 2).map {
|
|
||||||
Integer.parseInt(line.substring(it * 2, it * 2 + 2), 16).toByte()
|
|
||||||
}.toByteArray()
|
|
||||||
}.filterNotNull().map { ScanResult.InformationElement(221, 0, it) }
|
|
||||||
private fun generateConfig(full: Boolean = true) = base.copy(
|
private fun generateConfig(full: Boolean = true) = base.copy(
|
||||||
ssid = dialogView.ssid.text.toString(),
|
ssid = dialogView.ssid.text.toString(),
|
||||||
passphrase = if (dialogView.password.length() != 0) dialogView.password.text.toString() else null).apply {
|
passphrase = if (dialogView.password.length() != 0) dialogView.password.text.toString() else null).apply {
|
||||||
@@ -182,14 +174,16 @@ class WifiApDialogFragment : AlertDialogFragment<WifiApDialogFragment.Arg, WifiA
|
|||||||
bridgedModeOpportunisticShutdownTimeoutMillis = dialogView.bridgedTimeout.text.let { text ->
|
bridgedModeOpportunisticShutdownTimeoutMillis = dialogView.bridgedTimeout.text.let { text ->
|
||||||
if (text.isNullOrEmpty()) -1L else text.toString().toLong()
|
if (text.isNullOrEmpty()) -1L else text.toString().toLong()
|
||||||
}
|
}
|
||||||
vendorElements = generateVendorElements()
|
vendorElements = VendorElements.deserialize(dialogView.vendorElements.text)
|
||||||
persistentRandomizedMacAddress = if (dialogView.persistentRandomizedMac.length() != 0) {
|
persistentRandomizedMacAddress = if (dialogView.persistentRandomizedMac.length() != 0) {
|
||||||
MacAddressCompat.fromString(dialogView.persistentRandomizedMac.text.toString()).toPlatform()
|
MacAddressCompat.fromString(dialogView.persistentRandomizedMac.text.toString()).toPlatform()
|
||||||
} else null
|
} else null
|
||||||
allowedAcsChannels = acsList.associate { (band, text, _) -> band to RangeInput.fromString(text.text) }
|
allowedAcsChannels = acsList.associate { (band, text, _) -> band to RangeInput.fromString(text.text) }
|
||||||
|
if (!arg.p2pMode && Build.VERSION.SDK_INT >= 33) {
|
||||||
maxChannelBandwidth = (dialogView.maxChannelBandwidth.selectedItem as BandWidth).width
|
maxChannelBandwidth = (dialogView.maxChannelBandwidth.selectedItem as BandWidth).width
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override fun AlertDialog.Builder.prepare(listener: DialogInterface.OnClickListener) {
|
override fun AlertDialog.Builder.prepare(listener: DialogInterface.OnClickListener) {
|
||||||
val activity = requireActivity()
|
val activity = requireActivity()
|
||||||
@@ -332,16 +326,7 @@ class WifiApDialogFragment : AlertDialogFragment<WifiApDialogFragment.Arg, WifiA
|
|||||||
dialogView.bridgedTimeout.setText(base.bridgedModeOpportunisticShutdownTimeoutMillis.let {
|
dialogView.bridgedTimeout.setText(base.bridgedModeOpportunisticShutdownTimeoutMillis.let {
|
||||||
if (it == -1L) "" else it.toString()
|
if (it == -1L) "" else it.toString()
|
||||||
})
|
})
|
||||||
dialogView.vendorElements.setText(base.vendorElements.joinToString("\n") { element ->
|
dialogView.vendorElements.setText(VendorElements.serialize(base.vendorElements))
|
||||||
element.bytes.let { buffer ->
|
|
||||||
StringBuilder().apply {
|
|
||||||
while (buffer.hasRemaining()) append("%02x".format(buffer.get()))
|
|
||||||
}.toString()
|
|
||||||
}.also {
|
|
||||||
if (element.id != 221 || element.idExt != 0 || it.isEmpty()) Timber.w(Exception(
|
|
||||||
"Unexpected InformationElement ${element.id}, ${element.idExt}, $it"))
|
|
||||||
}
|
|
||||||
})
|
|
||||||
dialogView.persistentRandomizedMac.setText(base.persistentRandomizedMacAddress?.toString())
|
dialogView.persistentRandomizedMac.setText(base.persistentRandomizedMacAddress?.toString())
|
||||||
for ((band, text, _) in acsList) text.setText(RangeInput.toString(base.allowedAcsChannels[band]))
|
for ((band, text, _) in acsList) text.setText(RangeInput.toString(base.allowedAcsChannels[band]))
|
||||||
if (Build.VERSION.SDK_INT >= 33) bandWidthOptions.binarySearch(BandWidth(base.maxChannelBandwidth)).let {
|
if (Build.VERSION.SDK_INT >= 33) bandWidthOptions.binarySearch(BandWidth(base.maxChannelBandwidth)).let {
|
||||||
@@ -448,7 +433,7 @@ class WifiApDialogFragment : AlertDialogFragment<WifiApDialogFragment.Arg, WifiA
|
|||||||
dialogView.bridgedTimeoutWrapper.error = bridgedTimeoutError
|
dialogView.bridgedTimeoutWrapper.error = bridgedTimeoutError
|
||||||
val vendorElementsError = if (Build.VERSION.SDK_INT >= 33) {
|
val vendorElementsError = if (Build.VERSION.SDK_INT >= 33) {
|
||||||
try {
|
try {
|
||||||
generateVendorElements().also {
|
VendorElements.deserialize(dialogView.vendorElements.text).also {
|
||||||
if (!arg.p2pMode) SoftApConfigurationCompat.testPlatformValidity(it)
|
if (!arg.p2pMode) SoftApConfigurationCompat.testPlatformValidity(it)
|
||||||
}
|
}
|
||||||
null
|
null
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package be.mygod.vpnhotspot.net.wifi
|
package be.mygod.vpnhotspot.net.wifi
|
||||||
|
|
||||||
import android.annotation.SuppressLint
|
import android.annotation.SuppressLint
|
||||||
|
import android.net.wifi.ScanResult
|
||||||
import android.net.wifi.WpsInfo
|
import android.net.wifi.WpsInfo
|
||||||
import android.net.wifi.p2p.WifiP2pGroup
|
import android.net.wifi.p2p.WifiP2pGroup
|
||||||
import android.net.wifi.p2p.WifiP2pInfo
|
import android.net.wifi.p2p.WifiP2pInfo
|
||||||
@@ -8,6 +9,7 @@ import android.net.wifi.p2p.WifiP2pManager
|
|||||||
import androidx.annotation.RequiresApi
|
import androidx.annotation.RequiresApi
|
||||||
import be.mygod.vpnhotspot.App.Companion.app
|
import be.mygod.vpnhotspot.App.Companion.app
|
||||||
import be.mygod.vpnhotspot.net.MacAddressCompat
|
import be.mygod.vpnhotspot.net.MacAddressCompat
|
||||||
|
import be.mygod.vpnhotspot.net.wifi.WifiP2pManagerHelper.setWifiP2pChannels
|
||||||
import be.mygod.vpnhotspot.util.callSuper
|
import be.mygod.vpnhotspot.util.callSuper
|
||||||
import be.mygod.vpnhotspot.util.matchesCompat
|
import be.mygod.vpnhotspot.util.matchesCompat
|
||||||
import kotlinx.coroutines.CompletableDeferred
|
import kotlinx.coroutines.CompletableDeferred
|
||||||
@@ -54,6 +56,14 @@ object WifiP2pManagerHelper {
|
|||||||
return result.future.await()
|
return result.future.await()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@RequiresApi(33)
|
||||||
|
suspend fun WifiP2pManager.setVendorElements(c: WifiP2pManager.Channel,
|
||||||
|
ve: List<ScanResult.InformationElement>): Int? {
|
||||||
|
val result = ResultListener()
|
||||||
|
setVendorElements(c, ve, result)
|
||||||
|
return result.future.await()
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Available since Android 4.3.
|
* Available since Android 4.3.
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package be.mygod.vpnhotspot.root
|
package be.mygod.vpnhotspot.root
|
||||||
|
|
||||||
|
import android.net.wifi.ScanResult
|
||||||
import android.net.wifi.p2p.WifiP2pManager
|
import android.net.wifi.p2p.WifiP2pManager
|
||||||
import android.os.Looper
|
import android.os.Looper
|
||||||
import android.os.Parcelable
|
import android.os.Parcelable
|
||||||
@@ -11,6 +12,7 @@ import be.mygod.librootkotlinx.*
|
|||||||
import be.mygod.vpnhotspot.net.wifi.WifiP2pManagerHelper.deletePersistentGroup
|
import be.mygod.vpnhotspot.net.wifi.WifiP2pManagerHelper.deletePersistentGroup
|
||||||
import be.mygod.vpnhotspot.net.wifi.WifiP2pManagerHelper.requestDeviceAddress
|
import be.mygod.vpnhotspot.net.wifi.WifiP2pManagerHelper.requestDeviceAddress
|
||||||
import be.mygod.vpnhotspot.net.wifi.WifiP2pManagerHelper.requestPersistentGroupInfo
|
import be.mygod.vpnhotspot.net.wifi.WifiP2pManagerHelper.requestPersistentGroupInfo
|
||||||
|
import be.mygod.vpnhotspot.net.wifi.WifiP2pManagerHelper.setVendorElements
|
||||||
import be.mygod.vpnhotspot.net.wifi.WifiP2pManagerHelper.setWifiP2pChannels
|
import be.mygod.vpnhotspot.net.wifi.WifiP2pManagerHelper.setWifiP2pChannels
|
||||||
import be.mygod.vpnhotspot.util.Services
|
import be.mygod.vpnhotspot.util.Services
|
||||||
import kotlinx.parcelize.Parcelize
|
import kotlinx.parcelize.Parcelize
|
||||||
@@ -55,6 +57,14 @@ object RepeaterCommands {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Parcelize
|
||||||
|
@RequiresApi(33)
|
||||||
|
data class SetVendorElements(private val ve: List<ScanResult.InformationElement>) : RootCommand<ParcelableInt?> {
|
||||||
|
override suspend fun execute() = Services.p2p!!.run {
|
||||||
|
setVendorElements(obtainChannel(), ve)?.let { ParcelableInt(it) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Parcelize
|
@Parcelize
|
||||||
data class WriteP2pConfig(val data: String, val legacy: Boolean) : RootCommandNoResult {
|
data class WriteP2pConfig(val data: String, val legacy: Boolean) : RootCommandNoResult {
|
||||||
override suspend fun execute(): Parcelable? {
|
override suspend fun execute(): Parcelable? {
|
||||||
|
|||||||
@@ -23,6 +23,7 @@
|
|||||||
<string name="repeater_remove_group_failure">关闭已有 P2P 群组失败(原因:%s)</string>
|
<string name="repeater_remove_group_failure">关闭已有 P2P 群组失败(原因:%s)</string>
|
||||||
<string name="repeater_remove_old_group_failure">关闭 P2P 群组失败(原因:%s)</string>
|
<string name="repeater_remove_old_group_failure">关闭 P2P 群组失败(原因:%s)</string>
|
||||||
<string name="repeater_set_oc_failure">设置运行频段失败(原因:%s)</string>
|
<string name="repeater_set_oc_failure">设置运行频段失败(原因:%s)</string>
|
||||||
|
<string name="repeater_set_vendor_elements_failure">设置供应商特定元素失败(原因:%s)</string>
|
||||||
|
|
||||||
<string name="repeater_failure_reason_error">内部异常</string>
|
<string name="repeater_failure_reason_error">内部异常</string>
|
||||||
<string name="repeater_failure_reason_p2p_unsupported">设备不支持 Wi\u2011Fi 直连</string>
|
<string name="repeater_failure_reason_p2p_unsupported">设备不支持 Wi\u2011Fi 直连</string>
|
||||||
|
|||||||
@@ -40,6 +40,7 @@
|
|||||||
<string name="repeater_remove_group_failure">Failed to remove P2P group (reason: %s)</string>
|
<string name="repeater_remove_group_failure">Failed to remove P2P group (reason: %s)</string>
|
||||||
<string name="repeater_remove_old_group_failure">Failed to remove old P2P group (reason: %s)</string>
|
<string name="repeater_remove_old_group_failure">Failed to remove old P2P group (reason: %s)</string>
|
||||||
<string name="repeater_set_oc_failure">Failed to set operating channel (reason: %s)</string>
|
<string name="repeater_set_oc_failure">Failed to set operating channel (reason: %s)</string>
|
||||||
|
<string name="repeater_set_vendor_elements_failure">Failed to set vendor elements (reason: %s)</string>
|
||||||
|
|
||||||
<string name="repeater_failure_reason_error">internal error</string>
|
<string name="repeater_failure_reason_error">internal error</string>
|
||||||
<string name="repeater_failure_reason_p2p_unsupported">Wi\u2011Fi direct unsupported</string>
|
<string name="repeater_failure_reason_p2p_unsupported">Wi\u2011Fi direct unsupported</string>
|
||||||
|
|||||||
Reference in New Issue
Block a user