Skip to content

Commit 53f50b8

Browse files
Add WiFi toggle for Android via WifiManager with root fallback
Expose isWifiEnabled() and setWifiEnabled() to Lua via JNI. setWifiEnabled() tries WifiManager.setWifiEnabled() first; if blocked (OEM restriction or Android 10+), falls back to `su -c "svc wifi enable/disable"`. Requires ACCESS_WIFI_STATE and CHANGE_WIFI_STATE permissions. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent 23d04ce commit 53f50b8

5 files changed

Lines changed: 53 additions & 0 deletions

File tree

app/src/main/AndroidManifest.xml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@
1111
<!-- common android permissions -->
1212
<uses-permission android:name="android.permission.INTERNET" />
1313
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
14+
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
15+
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
1416
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"
1517
android:maxSdkVersion="29" />
1618
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"

app/src/main/java/org/koreader/launcher/LuaInterface.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,9 @@ interface LuaInterface {
6565
fun isWarmthDevice(): Boolean
6666
fun needsWakelocks(): Boolean
6767
fun openLink(url: String): Boolean
68+
fun isWifiEnabled(): Boolean
6869
fun openWifiSettings()
70+
fun setWifiEnabled(enable: Boolean): Boolean
6971
fun performHapticFeedback(constant: Int, force: Int)
7072
fun requestIgnoreBatteryOptimizations(rationale: String, okButton: String, cancelButton: String)
7173
fun requestWriteSystemSettings(rationale: String, okButton: String, cancelButton: String)

app/src/main/java/org/koreader/launcher/MainActivity.kt

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -640,10 +640,18 @@ class MainActivity : NativeActivity(), LuaInterface,
640640
}
641641
}
642642

643+
override fun isWifiEnabled(): Boolean {
644+
return wifiEnabled()
645+
}
646+
643647
override fun openWifiSettings() {
644648
openWifi()
645649
}
646650

651+
override fun setWifiEnabled(enable: Boolean): Boolean {
652+
return setWifiRadio(enable)
653+
}
654+
647655
override fun performHapticFeedback(constant: Int, force: Int) {
648656
val rootView = view ?: window.decorView.findViewById<View>(android.R.id.content)
649657
hapticFeedback(constant, force > 0, rootView)

app/src/main/java/org/koreader/launcher/extensions/ActivityExtensions.kt

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import android.content.pm.PackageManager
99
import android.graphics.Point
1010
import android.graphics.Rect
1111
import android.net.ConnectivityManager
12+
import android.net.wifi.WifiManager
1213
import android.net.NetworkCapabilities
1314
import android.os.Build
1415
import android.os.Environment
@@ -191,6 +192,25 @@ fun Activity.openWifi() {
191192
startActivityCompat(this, openWifiIntent)
192193
}
193194

195+
fun Activity.wifiEnabled(): Boolean {
196+
val wifi = applicationContext.getSystemService(Context.WIFI_SERVICE) as? WifiManager ?: return false
197+
return wifi.isWifiEnabled
198+
}
199+
200+
@Suppress("DEPRECATION")
201+
fun Activity.setWifiRadio(enable: Boolean): Boolean {
202+
val wifi = applicationContext.getSystemService(Context.WIFI_SERVICE) as? WifiManager ?: return false
203+
if (wifi.setWifiEnabled(enable)) return true
204+
// WifiManager.setWifiEnabled() is blocked on many devices (restricted by OEM or Android 10+).
205+
// Fall back to root shell command.
206+
val cmd = if (enable) "svc wifi enable" else "svc wifi disable"
207+
return try {
208+
Runtime.getRuntime().exec(arrayOf("su", "-c", cmd)).waitFor() == 0
209+
} catch (e: Exception) {
210+
false
211+
}
212+
}
213+
194214
fun Activity.pruneCacheDir() {
195215
try {
196216
getExternalFilesDir(null)?.let {

assets/android.lua

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2478,6 +2478,27 @@ local function run(android_app_state)
24782478
end)
24792479
end
24802480

2481+
android.isWifiEnabled = function()
2482+
return JNI:context(android.app.activity.vm, function(jni)
2483+
return jni:callBooleanMethod(
2484+
android.app.activity.clazz,
2485+
"isWifiEnabled",
2486+
"()Z"
2487+
)
2488+
end)
2489+
end
2490+
2491+
android.setWifiEnabled = function(enable)
2492+
return JNI:context(android.app.activity.vm, function(jni)
2493+
return jni:callBooleanMethod(
2494+
android.app.activity.clazz,
2495+
"setWifiEnabled",
2496+
"(Z)Z",
2497+
ffi.new("bool", enable)
2498+
)
2499+
end)
2500+
end
2501+
24812502
android.download = function(url, name)
24822503
return JNI:context(android.app.activity.vm, function(jni)
24832504
local uri_string = jni.env[0].NewStringUTF(jni.env, url)

0 commit comments

Comments
 (0)