Support setting Wi-Fi operating channel
This commit is contained in:
@@ -39,10 +39,6 @@ SSID is hardcoded to `DIRECT-<random 2 char>-<your device name>` so the only thi
|
||||
system Wi-Fi direct settings. Password is hardcoded to a random 8 char string. Changing anything else requires replacing
|
||||
driver `wpa_supplicant` which we are not considering implementing.
|
||||
|
||||
### Connect a 2.4GHz-only device to a 5GHz repeater?
|
||||
|
||||
You'll have to use WPS for now to make the repeater switch to 2.4GHz.
|
||||
|
||||
### [IPv6 tethering?](https://github.com/Mygod/VPNHotspot/issues/6)
|
||||
|
||||
### Missing `android.permission.MANAGE_USB` permission?
|
||||
|
||||
@@ -15,6 +15,7 @@ import android.widget.Toast
|
||||
class App : Application() {
|
||||
companion object {
|
||||
const val ACTION_CLEAN_ROUTINGS = "be.mygod.vpnhotspot.CLEAN_ROUTINGS"
|
||||
const val KEY_OPERATING_CHANNEL = "service.repeater.oc"
|
||||
private const val KEY_DNS = "service.dns"
|
||||
|
||||
@SuppressLint("StaticFieldLeak")
|
||||
@@ -29,6 +30,7 @@ class App : Application() {
|
||||
deviceContext.moveSharedPreferencesFrom(this, PreferenceManager.getDefaultSharedPreferencesName(this))
|
||||
} else deviceContext = this
|
||||
// workaround for support lib PreferenceDataStore bug
|
||||
operatingChannel = operatingChannel
|
||||
dns = dns
|
||||
ServiceNotification.updateNotificationChannels()
|
||||
}
|
||||
@@ -43,6 +45,12 @@ class App : Application() {
|
||||
val pref: SharedPreferences by lazy { PreferenceManager.getDefaultSharedPreferences(deviceContext) }
|
||||
val connectivity by lazy { getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager }
|
||||
|
||||
var operatingChannel: Int
|
||||
get() {
|
||||
val result = pref.getString(KEY_OPERATING_CHANNEL, null)?.toIntOrNull() ?: 0
|
||||
return if (result in 0..165) result else 0
|
||||
}
|
||||
set(value) = pref.edit().putString(KEY_OPERATING_CHANNEL, value.toString()).apply()
|
||||
var dns: String
|
||||
get() = pref.getString(KEY_DNS, "8.8.8.8")
|
||||
set(value) = pref.edit().putString(KEY_DNS, value).apply()
|
||||
|
||||
@@ -3,6 +3,7 @@ package be.mygod.vpnhotspot
|
||||
import android.app.Service
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.SharedPreferences
|
||||
import android.net.NetworkInfo
|
||||
import android.net.wifi.WpsInfo
|
||||
import android.net.wifi.p2p.WifiP2pGroup
|
||||
@@ -21,7 +22,8 @@ import java.net.InetAddress
|
||||
import java.net.SocketException
|
||||
import java.util.regex.Pattern
|
||||
|
||||
class RepeaterService : Service(), WifiP2pManager.ChannelListener, VpnMonitor.Callback {
|
||||
class RepeaterService : Service(), WifiP2pManager.ChannelListener, VpnMonitor.Callback,
|
||||
SharedPreferences.OnSharedPreferenceChangeListener {
|
||||
companion object {
|
||||
const val ACTION_STATUS_CHANGED = "be.mygod.vpnhotspot.RepeaterService.STATUS_CHANGED"
|
||||
const val KEY_NET_ID = "netId"
|
||||
@@ -40,6 +42,21 @@ class RepeaterService : Service(), WifiP2pManager.ChannelListener, VpnMonitor.Ca
|
||||
*/
|
||||
private val patternNetworkInfo = "^mNetworkInfo .* (isA|a)vailable: (true|false)".toPattern(Pattern.MULTILINE)
|
||||
|
||||
/**
|
||||
* Available since Android 4.4.
|
||||
*
|
||||
* Source: https://android.googlesource.com/platform/frameworks/base/+/android-4.4_r1/wifi/java/android/net/wifi/p2p/WifiP2pManager.java#994
|
||||
* Implementation: https://android.googlesource.com/platform/frameworks/opt/net/wifi/+/d72d2f4/service/java/com/android/server/wifi/p2p/SupplicantP2pIfaceHal.java#1159
|
||||
*/
|
||||
private val setWifiP2pChannels by lazy {
|
||||
WifiP2pManager::class.java.getDeclaredMethod("setWifiP2pChannels", WifiP2pManager.Channel::class.java,
|
||||
Int::class.java, Int::class.java, WifiP2pManager.ActionListener::class.java)
|
||||
}
|
||||
private fun WifiP2pManager.setWifiP2pChannels(c: WifiP2pManager.Channel, lc: Int, oc: Int,
|
||||
listener: WifiP2pManager.ActionListener) {
|
||||
setWifiP2pChannels.invoke(this, c, lc, oc, listener)
|
||||
}
|
||||
|
||||
/**
|
||||
* Available since Android 4.3.
|
||||
*
|
||||
@@ -171,6 +188,7 @@ class RepeaterService : Service(), WifiP2pManager.ChannelListener, VpnMonitor.Ca
|
||||
try {
|
||||
p2pManager = getSystemService(Context.WIFI_P2P_SERVICE) as WifiP2pManager
|
||||
onChannelDisconnected()
|
||||
app.pref.registerOnSharedPreferenceChangeListener(this)
|
||||
} catch (exc: TypeCastException) {
|
||||
exc.printStackTrace()
|
||||
}
|
||||
@@ -178,8 +196,28 @@ class RepeaterService : Service(), WifiP2pManager.ChannelListener, VpnMonitor.Ca
|
||||
|
||||
override fun onBind(intent: Intent) = binder
|
||||
|
||||
private fun setOperatingChannel(init: Boolean = false) {
|
||||
val oc = app.operatingChannel
|
||||
if (!init || oc > 0) {
|
||||
// we don't care about listening channel
|
||||
debugLog(TAG, "Setting OC to $oc")
|
||||
p2pManager.setWifiP2pChannels(channel, 0, oc, object : WifiP2pManager.ActionListener {
|
||||
override fun onSuccess() { }
|
||||
override fun onFailure(reason: Int) {
|
||||
Toast.makeText(this@RepeaterService, formatReason(R.string.repeater_set_oc_failure, reason),
|
||||
Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
override fun onChannelDisconnected() {
|
||||
channel = p2pManager.initialize(this, Looper.getMainLooper(), this)
|
||||
setOperatingChannel(true)
|
||||
}
|
||||
|
||||
override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences?, key: String?) {
|
||||
if (key == App.KEY_OPERATING_CHANNEL) setOperatingChannel()
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -339,6 +377,7 @@ class RepeaterService : Service(), WifiP2pManager.ChannelListener, VpnMonitor.Ca
|
||||
override fun onDestroy() {
|
||||
if (status != Status.IDLE) binder.shutdown()
|
||||
clean() // force clean to prevent leakage
|
||||
app.pref.unregisterOnSharedPreferenceChangeListener(this)
|
||||
super.onDestroy()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
<string name="repeater_create_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_set_oc_failure">设置运行频段失败(原因:%s)</string>
|
||||
|
||||
<string name="repeater_failure_reason_error">内部异常</string>
|
||||
<string name="repeater_failure_reason_p2p_unsupported">设备不支持 Wi\u2011Fi 直连</string>
|
||||
@@ -53,7 +54,9 @@
|
||||
<string name="connected_state_failed">%s (已断开)</string>
|
||||
|
||||
<string name="settings_service">服务</string>
|
||||
<string name="settings_service_repeater_strict">严格模式 (仅用于中继)</string>
|
||||
<string name="settings_service_repeater_oc">Wi\u2011Fi 运行频段</string>
|
||||
<string name="settings_service_repeater_oc_summary">"%s (0 = 自动, 1\u201114 = 2.4GHz, 15\u2011165 = 5GHz)"</string>
|
||||
<string name="settings_service_repeater_strict">严格模式</string>
|
||||
<string name="settings_service_repeater_strict_summary">只允许通过 VPN 隧道的包通过</string>
|
||||
<string name="settings_service_dns">备用 DNS 服务器[:端口]</string>
|
||||
<string name="settings_service_clean">清理/重新应用路由规则</string>
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
<string name="repeater_create_group_failure">Failed to create 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_set_oc_failure">Failed to set operating channel (reason: %s)</string>
|
||||
|
||||
<string name="repeater_failure_reason_error">internal error</string>
|
||||
<string name="repeater_failure_reason_p2p_unsupported">Wi\u2011Fi direct unsupported</string>
|
||||
@@ -55,7 +56,9 @@
|
||||
<string name="connected_state_failed">%s (lost)</string>
|
||||
|
||||
<string name="settings_service">Service</string>
|
||||
<string name="settings_service_repeater_strict">Strict mode (repeater only)</string>
|
||||
<string name="settings_service_repeater_oc">Operating Wi\u2011Fi channel</string>
|
||||
<string name="settings_service_repeater_oc_summary">%s (0 = auto, 1\u201114 = 2.4GHz, 15\u2011165 = 5GHz)</string>
|
||||
<string name="settings_service_repeater_strict">Strict mode</string>
|
||||
<string name="settings_service_repeater_strict_summary">Only allow packets that goes through VPN tunnel</string>
|
||||
<string name="settings_service_dns">Fallback DNS server[:port]</string>
|
||||
<string name="settings_service_clean">Clean/reapply routing rules</string>
|
||||
|
||||
@@ -1,15 +1,25 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||
<PreferenceCategory
|
||||
android:title="@string/settings_service">
|
||||
android:title="@string/title_repeater">
|
||||
<AutoSummaryEditTextPreference
|
||||
android:key="service.repeater.oc"
|
||||
android:title="@string/settings_service_repeater_oc"
|
||||
app:pref_summaryHasText="@string/settings_service_repeater_oc_summary"
|
||||
android:inputType="number"
|
||||
android:maxLength="3"
|
||||
android:defaultValue="0"/>
|
||||
<SwitchPreference
|
||||
android:key="service.repeater.strict"
|
||||
android:title="@string/settings_service_repeater_strict"
|
||||
android:summary="@string/settings_service_repeater_strict_summary"/>
|
||||
</PreferenceCategory>
|
||||
<PreferenceCategory
|
||||
android:title="@string/settings_service">
|
||||
<AutoSummaryEditTextPreference
|
||||
android:key="service.dns"
|
||||
android:title="@string/settings_service_dns"
|
||||
android:summary="%s"
|
||||
android:singleLine="true"
|
||||
android:defaultValue="8.8.8.8"/>
|
||||
<Preference
|
||||
|
||||
Reference in New Issue
Block a user