You've already forked KsuWebUIStandalone
mirror of
https://github.com/5ec1cff/KsuWebUIStandalone.git
synced 2025-09-06 06:37:11 +00:00
use global FileSystemManager
This commit is contained in:
@@ -1,11 +1,22 @@
|
|||||||
package io.github.a13e300.ksuwebui
|
package io.github.a13e300.ksuwebui
|
||||||
|
|
||||||
import android.app.Application
|
import android.app.Application
|
||||||
|
import android.os.Handler
|
||||||
|
import android.os.Looper
|
||||||
import com.topjohnwu.superuser.Shell
|
import com.topjohnwu.superuser.Shell
|
||||||
|
import java.util.concurrent.Executors
|
||||||
|
|
||||||
class App : Application() {
|
class App : Application() {
|
||||||
|
companion object {
|
||||||
|
lateinit var instance: App
|
||||||
|
private set
|
||||||
|
val executor by lazy { Executors.newCachedThreadPool() }
|
||||||
|
val handler = Handler(Looper.getMainLooper())
|
||||||
|
}
|
||||||
|
|
||||||
override fun onCreate() {
|
override fun onCreate() {
|
||||||
super.onCreate()
|
super.onCreate()
|
||||||
|
instance = this
|
||||||
Shell.setDefaultBuilder(Shell.Builder.create().setFlags(Shell.FLAG_MOUNT_MASTER))
|
Shell.setDefaultBuilder(Shell.Builder.create().setFlags(Shell.FLAG_MOUNT_MASTER))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,12 +1,88 @@
|
|||||||
package io.github.a13e300.ksuwebui
|
package io.github.a13e300.ksuwebui
|
||||||
|
|
||||||
|
import android.content.ComponentName
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
|
import android.content.ServiceConnection
|
||||||
import android.os.IBinder
|
import android.os.IBinder
|
||||||
|
import androidx.annotation.MainThread
|
||||||
|
import com.topjohnwu.superuser.Shell
|
||||||
import com.topjohnwu.superuser.ipc.RootService
|
import com.topjohnwu.superuser.ipc.RootService
|
||||||
import com.topjohnwu.superuser.nio.FileSystemManager
|
import com.topjohnwu.superuser.nio.FileSystemManager
|
||||||
|
import java.util.concurrent.CopyOnWriteArraySet
|
||||||
|
|
||||||
class FileSystemService : RootService() {
|
class FileSystemService : RootService() {
|
||||||
override fun onBind(intent: Intent): IBinder {
|
override fun onBind(intent: Intent): IBinder {
|
||||||
return FileSystemManager.getService()
|
return FileSystemManager.getService()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface Listener {
|
||||||
|
fun onServiceAvailable(fs: FileSystemManager)
|
||||||
|
fun onLaunchFailed()
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private sealed class Status {
|
||||||
|
data object Uninitialized : Status()
|
||||||
|
data object CheckRoot : Status()
|
||||||
|
data class ServiceAvailable(val fs: FileSystemManager) : Status()
|
||||||
|
}
|
||||||
|
|
||||||
|
private var status: Status = Status.Uninitialized
|
||||||
|
private val connection = object : ServiceConnection {
|
||||||
|
override fun onServiceConnected(p0: ComponentName, p1: IBinder) {
|
||||||
|
val fs = FileSystemManager.getRemote(p1)
|
||||||
|
status = Status.ServiceAvailable(fs)
|
||||||
|
pendingListeners.forEach { l ->
|
||||||
|
l.onServiceAvailable(fs)
|
||||||
|
pendingListeners.remove(l)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onServiceDisconnected(p0: ComponentName) {
|
||||||
|
status = Status.Uninitialized
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
private val pendingListeners = CopyOnWriteArraySet<Listener>()
|
||||||
|
|
||||||
|
@MainThread
|
||||||
|
fun start(listener: Listener) {
|
||||||
|
(status as? Status.ServiceAvailable)?.let {
|
||||||
|
listener.onServiceAvailable(it.fs)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
pendingListeners.add(listener)
|
||||||
|
if (status == Status.Uninitialized) {
|
||||||
|
checkRoot()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun checkRoot() {
|
||||||
|
status = Status.CheckRoot
|
||||||
|
App.executor.submit {
|
||||||
|
val isRoot = Shell.Builder.create().setFlags(Shell.FLAG_MOUNT_MASTER).build().use {
|
||||||
|
it.isRoot
|
||||||
|
}
|
||||||
|
App.handler.post {
|
||||||
|
if (isRoot) {
|
||||||
|
launchService()
|
||||||
|
} else {
|
||||||
|
status = Status.Uninitialized
|
||||||
|
pendingListeners.forEach { l ->
|
||||||
|
l.onLaunchFailed()
|
||||||
|
pendingListeners.remove(l)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun launchService() {
|
||||||
|
bind(Intent(App.instance, FileSystemService::class.java), connection)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun removeListener(listener: Listener) {
|
||||||
|
pendingListeners.remove(listener)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,13 +1,10 @@
|
|||||||
package io.github.a13e300.ksuwebui
|
package io.github.a13e300.ksuwebui
|
||||||
|
|
||||||
import android.annotation.SuppressLint
|
import android.annotation.SuppressLint
|
||||||
import android.content.ComponentName
|
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.content.ServiceConnection
|
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.os.IBinder
|
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.Menu
|
import android.view.Menu
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
@@ -18,17 +15,12 @@ import androidx.core.view.WindowInsetsCompat
|
|||||||
import androidx.core.view.isVisible
|
import androidx.core.view.isVisible
|
||||||
import androidx.core.view.updatePadding
|
import androidx.core.view.updatePadding
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import com.topjohnwu.superuser.Shell
|
|
||||||
import com.topjohnwu.superuser.ipc.RootService
|
|
||||||
import com.topjohnwu.superuser.nio.FileSystemManager
|
import com.topjohnwu.superuser.nio.FileSystemManager
|
||||||
import io.github.a13e300.ksuwebui.databinding.ActivityMainBinding
|
import io.github.a13e300.ksuwebui.databinding.ActivityMainBinding
|
||||||
import io.github.a13e300.ksuwebui.databinding.ItemModuleBinding
|
import io.github.a13e300.ksuwebui.databinding.ItemModuleBinding
|
||||||
import kotlin.concurrent.thread
|
|
||||||
|
|
||||||
@SuppressLint("NotifyDataSetChanged")
|
@SuppressLint("NotifyDataSetChanged")
|
||||||
class MainActivity : AppCompatActivity() {
|
class MainActivity : AppCompatActivity(), FileSystemService.Listener {
|
||||||
private var connection: ServiceConnection? = null
|
|
||||||
private var rootFilesystem: FileSystemManager? = null
|
|
||||||
private lateinit var binding: ActivityMainBinding
|
private lateinit var binding: ActivityMainBinding
|
||||||
private var moduleList = emptyList<Module>()
|
private var moduleList = emptyList<Module>()
|
||||||
private lateinit var adapter: Adapter
|
private lateinit var adapter: Adapter
|
||||||
@@ -101,13 +93,11 @@ class MainActivity : AppCompatActivity() {
|
|||||||
adapter.notifyDataSetChanged()
|
adapter.notifyDataSetChanged()
|
||||||
binding.info.setText(R.string.loading)
|
binding.info.setText(R.string.loading)
|
||||||
binding.info.isVisible = true
|
binding.info.isVisible = true
|
||||||
fetchModuleList()
|
FileSystemService.start(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun fetchModuleList() {
|
override fun onServiceAvailable(fs: FileSystemManager) {
|
||||||
thread {
|
App.executor.submit {
|
||||||
if (!maybeStartRootService()) return@thread
|
|
||||||
val fs = rootFilesystem!!
|
|
||||||
val mods = mutableListOf<Module>()
|
val mods = mutableListOf<Module>()
|
||||||
val showDisabled = prefs.getBoolean("show_disabled", false)
|
val showDisabled = prefs.getBoolean("show_disabled", false)
|
||||||
fs.getFile("/data/adb/modules").listFiles()!!.forEach { f ->
|
fs.getFile("/data/adb/modules").listFiles()!!.forEach { f ->
|
||||||
@@ -147,6 +137,14 @@ class MainActivity : AppCompatActivity() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun onLaunchFailed() {
|
||||||
|
moduleList = emptyList()
|
||||||
|
adapter.notifyDataSetChanged()
|
||||||
|
binding.info.setText(R.string.please_grant_root)
|
||||||
|
binding.info.isVisible = true
|
||||||
|
binding.swipeRefresh.isRefreshing = false
|
||||||
|
}
|
||||||
|
|
||||||
data class Module(val name: String, val id: String, val desc: String, val author: String, val version: String)
|
data class Module(val name: String, val id: String, val desc: String, val author: String, val version: String)
|
||||||
|
|
||||||
class ViewHolder(val binding: ItemModuleBinding) : RecyclerView.ViewHolder(binding.root)
|
class ViewHolder(val binding: ItemModuleBinding) : RecyclerView.ViewHolder(binding.root)
|
||||||
@@ -183,45 +181,8 @@ class MainActivity : AppCompatActivity() {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun maybeStartRootService(): Boolean {
|
|
||||||
if (connection == null) {
|
|
||||||
val isRoot = Shell.Builder.create().setFlags(Shell.FLAG_MOUNT_MASTER).build().use {
|
|
||||||
it.isRoot
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!isRoot) {
|
|
||||||
runOnUiThread {
|
|
||||||
moduleList = emptyList()
|
|
||||||
adapter.notifyDataSetChanged()
|
|
||||||
binding.info.setText(R.string.please_grant_root)
|
|
||||||
binding.info.isVisible = true
|
|
||||||
binding.swipeRefresh.isRefreshing = false
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
connection = object : ServiceConnection {
|
|
||||||
override fun onServiceConnected(p0: ComponentName, p1: IBinder) {
|
|
||||||
rootFilesystem = FileSystemManager.getRemote(p1)
|
|
||||||
fetchModuleList()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onServiceDisconnected(p0: ComponentName) {
|
|
||||||
rootFilesystem = null
|
|
||||||
connection = null
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
runOnUiThread {
|
|
||||||
RootService.bind(Intent(this, FileSystemService::class.java), connection!!)
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onDestroy() {
|
override fun onDestroy() {
|
||||||
super.onDestroy()
|
super.onDestroy()
|
||||||
connection?.let { RootService.unbind(it) }
|
FileSystemService.removeListener(this)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,9 +8,7 @@ import androidx.annotation.NonNull;
|
|||||||
import androidx.annotation.WorkerThread;
|
import androidx.annotation.WorkerThread;
|
||||||
import androidx.webkit.WebViewAssetLoader;
|
import androidx.webkit.WebViewAssetLoader;
|
||||||
|
|
||||||
import com.topjohnwu.superuser.Shell;
|
import com.topjohnwu.superuser.nio.FileSystemManager;
|
||||||
import com.topjohnwu.superuser.io.SuFile;
|
|
||||||
import com.topjohnwu.superuser.io.SuFileInputStream;
|
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
@@ -37,8 +35,8 @@ import java.util.zip.GZIPInputStream;
|
|||||||
* .build();
|
* .build();
|
||||||
* </pre>
|
* </pre>
|
||||||
*/
|
*/
|
||||||
public final class SuFilePathHandler implements WebViewAssetLoader.PathHandler {
|
public final class RemoteFsPathHandler implements WebViewAssetLoader.PathHandler {
|
||||||
private static final String TAG = "SuFilePathHandler";
|
private static final String TAG = "FsServicePathHandler";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Default value to be used as MIME type if guessing MIME type failed.
|
* Default value to be used as MIME type if guessing MIME type failed.
|
||||||
@@ -57,7 +55,7 @@ public final class SuFilePathHandler implements WebViewAssetLoader.PathHandler {
|
|||||||
@NonNull
|
@NonNull
|
||||||
private final File mDirectory;
|
private final File mDirectory;
|
||||||
|
|
||||||
private final Shell mShell;
|
private final FileSystemManager mFs;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates PathHandler for app's internal storage.
|
* Creates PathHandler for app's internal storage.
|
||||||
@@ -81,14 +79,14 @@ public final class SuFilePathHandler implements WebViewAssetLoader.PathHandler {
|
|||||||
* which files can be loaded.
|
* which files can be loaded.
|
||||||
* @throws IllegalArgumentException if the directory is not allowed.
|
* @throws IllegalArgumentException if the directory is not allowed.
|
||||||
*/
|
*/
|
||||||
public SuFilePathHandler(@NonNull Context context, @NonNull File directory, Shell rootShell) {
|
public RemoteFsPathHandler(@NonNull Context context, @NonNull File directory, FileSystemManager fs) {
|
||||||
try {
|
try {
|
||||||
mDirectory = new File(getCanonicalDirPath(directory));
|
mDirectory = new File(getCanonicalDirPath(directory));
|
||||||
if (!isAllowedInternalStorageDir(context)) {
|
if (!isAllowedInternalStorageDir(context)) {
|
||||||
throw new IllegalArgumentException("The given directory \"" + directory
|
throw new IllegalArgumentException("The given directory \"" + directory
|
||||||
+ "\" doesn't exist under an allowed app internal storage directory");
|
+ "\" doesn't exist under an allowed app internal storage directory");
|
||||||
}
|
}
|
||||||
mShell = rootShell;
|
mFs = fs;
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
throw new IllegalArgumentException(
|
throw new IllegalArgumentException(
|
||||||
"Failed to resolve the canonical path for the given directory: "
|
"Failed to resolve the canonical path for the given directory: "
|
||||||
@@ -133,7 +131,7 @@ public final class SuFilePathHandler implements WebViewAssetLoader.PathHandler {
|
|||||||
try {
|
try {
|
||||||
File file = getCanonicalFileIfChild(mDirectory, path);
|
File file = getCanonicalFileIfChild(mDirectory, path);
|
||||||
if (file != null) {
|
if (file != null) {
|
||||||
InputStream is = openFile(file, mShell);
|
InputStream is = openFile(file, mFs);
|
||||||
String mimeType = guessMimeType(path);
|
String mimeType = guessMimeType(path);
|
||||||
return new WebResourceResponse(mimeType, null, is);
|
return new WebResourceResponse(mimeType, null, is);
|
||||||
} else {
|
} else {
|
||||||
@@ -169,11 +167,8 @@ public final class SuFilePathHandler implements WebViewAssetLoader.PathHandler {
|
|||||||
return path.endsWith(".svgz") ? new GZIPInputStream(stream) : stream;
|
return path.endsWith(".svgz") ? new GZIPInputStream(stream) : stream;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static InputStream openFile(@NonNull File file, @NonNull Shell shell) throws IOException {
|
public static InputStream openFile(@NonNull File file, @NonNull FileSystemManager fs) throws IOException {
|
||||||
SuFile suFile = new SuFile(file.getAbsolutePath());
|
return handleSvgzStream(file.getPath(), fs.getFile(file.getAbsolutePath()).newInputStream());
|
||||||
suFile.setShell(shell);
|
|
||||||
InputStream fis = SuFileInputStream.open(suFile);
|
|
||||||
return handleSvgzStream(file.getPath(), fis);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -9,20 +9,22 @@ import android.webkit.WebResourceRequest
|
|||||||
import android.webkit.WebResourceResponse
|
import android.webkit.WebResourceResponse
|
||||||
import android.webkit.WebView
|
import android.webkit.WebView
|
||||||
import android.webkit.WebViewClient
|
import android.webkit.WebViewClient
|
||||||
|
import android.widget.Toast
|
||||||
import androidx.activity.ComponentActivity
|
import androidx.activity.ComponentActivity
|
||||||
import androidx.activity.enableEdgeToEdge
|
import androidx.activity.enableEdgeToEdge
|
||||||
import androidx.core.view.ViewCompat
|
import androidx.core.view.ViewCompat
|
||||||
import androidx.core.view.WindowInsetsCompat
|
import androidx.core.view.WindowInsetsCompat
|
||||||
import androidx.core.view.updateLayoutParams
|
import androidx.core.view.updateLayoutParams
|
||||||
import androidx.webkit.WebViewAssetLoader
|
import androidx.webkit.WebViewAssetLoader
|
||||||
import com.topjohnwu.superuser.Shell
|
import com.topjohnwu.superuser.nio.FileSystemManager
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
|
||||||
@SuppressLint("SetJavaScriptEnabled")
|
@SuppressLint("SetJavaScriptEnabled")
|
||||||
class WebUIActivity : ComponentActivity() {
|
class WebUIActivity : ComponentActivity(), FileSystemService.Listener {
|
||||||
private lateinit var webviewInterface: WebViewInterface
|
private lateinit var webviewInterface: WebViewInterface
|
||||||
|
|
||||||
private var rootShell: Shell? = null
|
private lateinit var webView: WebView
|
||||||
|
private lateinit var moduleDir: String
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
// Enable edge to edge
|
// Enable edge to edge
|
||||||
@@ -33,8 +35,12 @@ class WebUIActivity : ComponentActivity() {
|
|||||||
|
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
|
|
||||||
val moduleId = intent.getStringExtra("id")!!
|
val moduleId = intent.getStringExtra("id")
|
||||||
val name = intent.getStringExtra("name")!!
|
if (moduleId == null) {
|
||||||
|
finish()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
val name = intent.getStringExtra("name") ?: moduleId
|
||||||
if (name.isNotEmpty()) {
|
if (name.isNotEmpty()) {
|
||||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU) {
|
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU) {
|
||||||
@Suppress("DEPRECATION")
|
@Suppress("DEPRECATION")
|
||||||
@@ -48,27 +54,9 @@ class WebUIActivity : ComponentActivity() {
|
|||||||
val prefs = getSharedPreferences("settings", MODE_PRIVATE)
|
val prefs = getSharedPreferences("settings", MODE_PRIVATE)
|
||||||
WebView.setWebContentsDebuggingEnabled(prefs.getBoolean("enable_web_debugging", BuildConfig.DEBUG))
|
WebView.setWebContentsDebuggingEnabled(prefs.getBoolean("enable_web_debugging", BuildConfig.DEBUG))
|
||||||
|
|
||||||
val moduleDir = "/data/adb/modules/${moduleId}"
|
moduleDir = "/data/adb/modules/$moduleId"
|
||||||
val webRoot = File("${moduleDir}/webroot")
|
|
||||||
val rootShell = createRootShell(true).also { this.rootShell = it }
|
|
||||||
val webViewAssetLoader = WebViewAssetLoader.Builder()
|
|
||||||
.setDomain("mui.kernelsu.org")
|
|
||||||
.addPathHandler(
|
|
||||||
"/",
|
|
||||||
SuFilePathHandler(this, webRoot, rootShell)
|
|
||||||
)
|
|
||||||
.build()
|
|
||||||
|
|
||||||
val webViewClient = object : WebViewClient() {
|
webView = WebView(this).apply {
|
||||||
override fun shouldInterceptRequest(
|
|
||||||
view: WebView,
|
|
||||||
request: WebResourceRequest
|
|
||||||
): WebResourceResponse? {
|
|
||||||
return webViewAssetLoader.shouldInterceptRequest(request.url)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
val webView = WebView(this).apply {
|
|
||||||
ViewCompat.setOnApplyWindowInsetsListener(this) { view, insets ->
|
ViewCompat.setOnApplyWindowInsetsListener(this) { view, insets ->
|
||||||
val inset = insets.getInsets(WindowInsetsCompat.Type.systemBars())
|
val inset = insets.getInsets(WindowInsetsCompat.Type.systemBars())
|
||||||
view.updateLayoutParams<MarginLayoutParams> {
|
view.updateLayoutParams<MarginLayoutParams> {
|
||||||
@@ -83,16 +71,51 @@ class WebUIActivity : ComponentActivity() {
|
|||||||
settings.domStorageEnabled = true
|
settings.domStorageEnabled = true
|
||||||
settings.allowFileAccess = false
|
settings.allowFileAccess = false
|
||||||
webviewInterface = WebViewInterface(this@WebUIActivity, this, moduleDir)
|
webviewInterface = WebViewInterface(this@WebUIActivity, this, moduleDir)
|
||||||
|
}
|
||||||
|
|
||||||
|
setContentView(webView)
|
||||||
|
FileSystemService.start(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun setupWebview(fs: FileSystemManager) {
|
||||||
|
val webRoot = File("$moduleDir/webroot")
|
||||||
|
val webViewAssetLoader = WebViewAssetLoader.Builder()
|
||||||
|
.setDomain("mui.kernelsu.org")
|
||||||
|
.addPathHandler(
|
||||||
|
"/",
|
||||||
|
RemoteFsPathHandler(
|
||||||
|
this,
|
||||||
|
webRoot,
|
||||||
|
fs
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.build()
|
||||||
|
val webViewClient = object : WebViewClient() {
|
||||||
|
override fun shouldInterceptRequest(
|
||||||
|
view: WebView,
|
||||||
|
request: WebResourceRequest
|
||||||
|
): WebResourceResponse? {
|
||||||
|
return webViewAssetLoader.shouldInterceptRequest(request.url)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
webView.apply {
|
||||||
addJavascriptInterface(webviewInterface, "ksu")
|
addJavascriptInterface(webviewInterface, "ksu")
|
||||||
setWebViewClient(webViewClient)
|
setWebViewClient(webViewClient)
|
||||||
loadUrl("https://mui.kernelsu.org/index.html")
|
loadUrl("https://mui.kernelsu.org/index.html")
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
setContentView(webView)
|
override fun onServiceAvailable(fs: FileSystemManager) {
|
||||||
|
setupWebview(fs)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onLaunchFailed() {
|
||||||
|
Toast.makeText(this, R.string.please_grant_root, Toast.LENGTH_SHORT).show()
|
||||||
|
finish()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onDestroy() {
|
override fun onDestroy() {
|
||||||
super.onDestroy()
|
super.onDestroy()
|
||||||
runCatching { rootShell?.close() }
|
FileSystemService.removeListener(this)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user