You've already forked KsuWebUIStandalone
mirror of
https://github.com/5ec1cff/KsuWebUIStandalone.git
synced 2025-09-06 06:37:11 +00:00
main ui
This commit is contained in:
@@ -0,0 +1,12 @@
|
||||
package io.github.a13e300.ksuwebui
|
||||
|
||||
import android.content.Intent
|
||||
import android.os.IBinder
|
||||
import com.topjohnwu.superuser.ipc.RootService
|
||||
import com.topjohnwu.superuser.nio.FileSystemManager
|
||||
|
||||
class FileSystemService : RootService() {
|
||||
override fun onBind(intent: Intent): IBinder {
|
||||
return FileSystemManager.getService()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,187 @@
|
||||
package io.github.a13e300.ksuwebui
|
||||
|
||||
import android.content.ComponentName
|
||||
import android.content.Intent
|
||||
import android.content.ServiceConnection
|
||||
import android.net.Uri
|
||||
import android.os.Bundle
|
||||
import android.os.IBinder
|
||||
import android.view.LayoutInflater
|
||||
import android.view.Menu
|
||||
import android.view.ViewGroup
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.topjohnwu.superuser.Shell
|
||||
import com.topjohnwu.superuser.internal.MainShell
|
||||
import com.topjohnwu.superuser.ipc.RootService
|
||||
import com.topjohnwu.superuser.nio.FileSystemManager
|
||||
import io.github.a13e300.ksuwebui.databinding.ActivityMainBinding
|
||||
import io.github.a13e300.ksuwebui.databinding.ItemModuleBinding
|
||||
import kotlin.concurrent.thread
|
||||
|
||||
class MainActivity : AppCompatActivity() {
|
||||
private var connection: ServiceConnection? = null
|
||||
private var rootFilesystem: FileSystemManager? = null
|
||||
private lateinit var binding: ActivityMainBinding
|
||||
private var moduleList = emptyList<Module>()
|
||||
private lateinit var adapter: Adapter
|
||||
private val prefs by lazy { getSharedPreferences("settings", MODE_PRIVATE) }
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
binding = ActivityMainBinding.inflate(layoutInflater)
|
||||
adapter = Adapter()
|
||||
binding.list.adapter = adapter
|
||||
setContentView(binding.root)
|
||||
setSupportActionBar(binding.toolbar)
|
||||
binding.swipeRefresh.setOnRefreshListener {
|
||||
refresh()
|
||||
}
|
||||
binding.swipeRefresh.isRefreshing = true
|
||||
refresh()
|
||||
}
|
||||
|
||||
override fun onCreateOptionsMenu(menu: Menu?): Boolean {
|
||||
menuInflater.inflate(R.menu.main_menu, menu)
|
||||
menu!!.findItem(R.id.enable_webview_debugging).apply {
|
||||
isChecked = prefs.getBoolean("enable_web_debugging", BuildConfig.DEBUG)
|
||||
setOnMenuItemClickListener {
|
||||
val newValue = !it.isChecked
|
||||
prefs.edit().putBoolean("enable_web_debugging", newValue).apply()
|
||||
it.isChecked = newValue
|
||||
true
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
private fun refresh() {
|
||||
moduleList = emptyList()
|
||||
adapter.notifyDataSetChanged()
|
||||
binding.info.setText(R.string.loading)
|
||||
binding.info.isVisible = true
|
||||
fetchModuleList()
|
||||
}
|
||||
|
||||
private fun fetchModuleList() {
|
||||
thread {
|
||||
if (!maybeStartRootService()) return@thread
|
||||
val fs = rootFilesystem!!
|
||||
val mods = mutableListOf<Module>()
|
||||
fs.getFile("/data/adb/modules").listFiles()!!.forEach { f ->
|
||||
if (!f.isDirectory) return@forEach
|
||||
if (!fs.getFile(f, "webroot").isDirectory) return@forEach
|
||||
if (fs.getFile(f, "disable").exists()) return@forEach
|
||||
var name = f.name
|
||||
val id = f.name
|
||||
var author = "?"
|
||||
var version = "?"
|
||||
var desc = ""
|
||||
fs.getFile(f, "module.prop").newInputStream().bufferedReader().use {
|
||||
it.lines().forEach { l ->
|
||||
val ls = l.split("=", limit = 2)
|
||||
if (ls.size == 2) {
|
||||
if (ls[0] == "name") name = ls[1]
|
||||
else if (ls[0] == "description") desc = ls[1]
|
||||
else if (ls[0] == "author") author = ls[1]
|
||||
else if (ls[0] == "version") version = ls[1]
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
mods.add(Module(name, id, desc, author, version))
|
||||
}
|
||||
runOnUiThread {
|
||||
moduleList = mods
|
||||
adapter.notifyDataSetChanged()
|
||||
binding.swipeRefresh.isRefreshing = false
|
||||
if (mods.isEmpty()) {
|
||||
binding.info.setText(R.string.no_modules)
|
||||
binding.info.isVisible = true
|
||||
} else {
|
||||
binding.info.isVisible = false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
|
||||
inner class Adapter : RecyclerView.Adapter<ViewHolder>() {
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
|
||||
return ViewHolder(
|
||||
ItemModuleBinding.inflate(
|
||||
LayoutInflater.from(parent.context), parent, false
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
override fun getItemCount(): Int = moduleList.size
|
||||
|
||||
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
|
||||
val item = moduleList[position]
|
||||
val id = item.id
|
||||
val name = item.name
|
||||
holder.binding.name.text = name
|
||||
holder.binding.author.text = "Author: ${item.author}"
|
||||
holder.binding.version.text = "Version: ${item.version}"
|
||||
holder.binding.desc.text = item.desc
|
||||
holder.binding.root.setOnClickListener {
|
||||
startActivity(
|
||||
Intent(this@MainActivity, WebUIActivity::class.java)
|
||||
.setData(Uri.parse("ksuwebui://webui/$id"))
|
||||
.putExtra("id", id)
|
||||
.putExtra("name", name)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
}
|
||||
Shell.setDefaultBuilder(Shell.Builder.create().setFlags(Shell.FLAG_MOUNT_MASTER))
|
||||
runOnUiThread {
|
||||
RootService.bind(Intent(this, FileSystemService::class.java), connection!!)
|
||||
}
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
super.onDestroy()
|
||||
connection?.let { RootService.unbind(it) }
|
||||
}
|
||||
}
|
||||
@@ -16,23 +16,9 @@ inline fun <T> withNewRootShell(
|
||||
fun createRootShell(globalMnt: Boolean = false): Shell {
|
||||
Shell.enableVerboseLogging = BuildConfig.DEBUG
|
||||
val builder = Shell.Builder.create()
|
||||
return try {
|
||||
if (globalMnt) {
|
||||
builder.build("su", "-g")
|
||||
return if (globalMnt) {
|
||||
builder.build("su", "-mm")
|
||||
} else {
|
||||
builder.build("su")
|
||||
}
|
||||
} catch (e: Throwable) {
|
||||
Log.w(TAG, "ksu failed: ", e)
|
||||
try {
|
||||
if (globalMnt) {
|
||||
builder.build("su")
|
||||
} else {
|
||||
builder.build("su", "-mm")
|
||||
}
|
||||
} catch (e: Throwable) {
|
||||
Log.e(TAG, "su failed: ", e)
|
||||
builder.build("sh")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user