You've already forked KernelSU-Next
mirror of
https://github.com/KernelSU-Next/KernelSU-Next.git
synced 2025-08-27 23:46:34 +00:00
manager: removed deprecated webuix and allow superuser and module management capabilities even with su compat disabled
This commit is contained in:
@@ -34,6 +34,7 @@ android {
|
|||||||
}
|
}
|
||||||
|
|
||||||
buildFeatures {
|
buildFeatures {
|
||||||
|
aidl = true
|
||||||
buildConfig = true
|
buildConfig = true
|
||||||
compose = true
|
compose = true
|
||||||
prefab = true
|
prefab = true
|
||||||
|
|||||||
@@ -0,0 +1,9 @@
|
|||||||
|
// IKsuInterface.aidl
|
||||||
|
package com.rifsxd.ksunext;
|
||||||
|
|
||||||
|
import android.content.pm.PackageInfo;
|
||||||
|
import rikka.parcelablelist.ParcelableListSlice;
|
||||||
|
|
||||||
|
interface IKsuInterface {
|
||||||
|
ParcelableListSlice<PackageInfo> getPackages(int flags);
|
||||||
|
}
|
||||||
@@ -4,7 +4,6 @@ import android.app.Application
|
|||||||
import android.system.Os
|
import android.system.Os
|
||||||
import coil.Coil
|
import coil.Coil
|
||||||
import coil.ImageLoader
|
import coil.ImageLoader
|
||||||
import com.dergoogler.mmrl.platform.Platform
|
|
||||||
import me.zhanghai.android.appiconloader.coil.AppIconFetcher
|
import me.zhanghai.android.appiconloader.coil.AppIconFetcher
|
||||||
import me.zhanghai.android.appiconloader.coil.AppIconKeyer
|
import me.zhanghai.android.appiconloader.coil.AppIconKeyer
|
||||||
import okhttp3.Cache
|
import okhttp3.Cache
|
||||||
@@ -22,8 +21,6 @@ class KernelSUApplication : Application() {
|
|||||||
super.onCreate()
|
super.onCreate()
|
||||||
ksuApp = this
|
ksuApp = this
|
||||||
|
|
||||||
Platform.setHiddenApiExemptions()
|
|
||||||
|
|
||||||
val context = this
|
val context = this
|
||||||
val iconSize = resources.getDimensionPixelSize(android.R.dimen.app_icon_size)
|
val iconSize = resources.getDimensionPixelSize(android.R.dimen.app_icon_size)
|
||||||
Coil.setImageLoader(
|
Coil.setImageLoader(
|
||||||
|
|||||||
77
manager/app/src/main/java/com/rifsxd/ksunext/KsuService.java
Normal file
77
manager/app/src/main/java/com/rifsxd/ksunext/KsuService.java
Normal file
@@ -0,0 +1,77 @@
|
|||||||
|
package com.rifsxd.ksunext.ui;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.content.pm.PackageInfo;
|
||||||
|
import android.content.pm.PackageManager;
|
||||||
|
import android.os.IBinder;
|
||||||
|
import android.os.UserHandle;
|
||||||
|
import android.os.UserManager;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
|
||||||
|
import com.topjohnwu.superuser.ipc.RootService;
|
||||||
|
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import com.rifsxd.ksunext.IKsuInterface;
|
||||||
|
import rikka.parcelablelist.ParcelableListSlice;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author weishu
|
||||||
|
* @date 2023/4/18.
|
||||||
|
*/
|
||||||
|
|
||||||
|
public class KsuService extends RootService {
|
||||||
|
|
||||||
|
private static final String TAG = "KsuService";
|
||||||
|
|
||||||
|
class Stub extends IKsuInterface.Stub {
|
||||||
|
@Override
|
||||||
|
public ParcelableListSlice<PackageInfo> getPackages(int flags) {
|
||||||
|
List<PackageInfo> list = getInstalledPackagesAll(flags);
|
||||||
|
Log.i(TAG, "getPackages: " + list.size());
|
||||||
|
return new ParcelableListSlice<>(list);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public IBinder onBind(@NonNull Intent intent) {
|
||||||
|
return new Stub();
|
||||||
|
}
|
||||||
|
|
||||||
|
List<Integer> getUserIds() {
|
||||||
|
List<Integer> result = new ArrayList<>();
|
||||||
|
UserManager um = (UserManager) getSystemService(Context.USER_SERVICE);
|
||||||
|
List<UserHandle> userProfiles = um.getUserProfiles();
|
||||||
|
for (UserHandle userProfile : userProfiles) {
|
||||||
|
int userId = userProfile.hashCode();
|
||||||
|
result.add(userProfile.hashCode());
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
ArrayList<PackageInfo> getInstalledPackagesAll(int flags) {
|
||||||
|
ArrayList<PackageInfo> packages = new ArrayList<>();
|
||||||
|
for (Integer userId : getUserIds()) {
|
||||||
|
Log.i(TAG, "getInstalledPackagesAll: " + userId);
|
||||||
|
packages.addAll(getInstalledPackagesAsUser(flags, userId));
|
||||||
|
}
|
||||||
|
return packages;
|
||||||
|
}
|
||||||
|
|
||||||
|
List<PackageInfo> getInstalledPackagesAsUser(int flags, int userId) {
|
||||||
|
try {
|
||||||
|
PackageManager pm = getPackageManager();
|
||||||
|
Method getInstalledPackagesAsUser = pm.getClass().getDeclaredMethod("getInstalledPackagesAsUser", int.class, int.class);
|
||||||
|
return (List<PackageInfo>) getInstalledPackagesAsUser.invoke(pm, flags, userId);
|
||||||
|
} catch (Throwable e) {
|
||||||
|
Log.e(TAG, "err", e);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new ArrayList<>();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -64,7 +64,7 @@ import com.rifsxd.ksunext.ui.util.install
|
|||||||
import com.rifsxd.ksunext.ui.util.isSuCompatDisabled
|
import com.rifsxd.ksunext.ui.util.isSuCompatDisabled
|
||||||
import com.rifsxd.ksunext.ui.screen.FlashIt
|
import com.rifsxd.ksunext.ui.screen.FlashIt
|
||||||
import com.rifsxd.ksunext.ui.viewmodel.ModuleViewModel
|
import com.rifsxd.ksunext.ui.viewmodel.ModuleViewModel
|
||||||
import com.rifsxd.ksunext.ui.webui.initPlatform
|
import com.rifsxd.ksunext.ui.viewmodel.SuperUserViewModel
|
||||||
|
|
||||||
class MainActivity : ComponentActivity() {
|
class MainActivity : ComponentActivity() {
|
||||||
|
|
||||||
@@ -115,6 +115,7 @@ class MainActivity : ComponentActivity() {
|
|||||||
val amoledMode = prefs.getBoolean("enable_amoled", false)
|
val amoledMode = prefs.getBoolean("enable_amoled", false)
|
||||||
|
|
||||||
val moduleViewModel: ModuleViewModel = viewModel()
|
val moduleViewModel: ModuleViewModel = viewModel()
|
||||||
|
val superUserViewModel: SuperUserViewModel = viewModel()
|
||||||
val moduleUpdateCount = moduleViewModel.moduleList.count {
|
val moduleUpdateCount = moduleViewModel.moduleList.count {
|
||||||
moduleViewModel.checkUpdate(it).first.isNotEmpty()
|
moduleViewModel.checkUpdate(it).first.isNotEmpty()
|
||||||
}
|
}
|
||||||
@@ -139,17 +140,22 @@ class MainActivity : ComponentActivity() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
LaunchedEffect(Unit) {
|
||||||
|
if (superUserViewModel.appList.isEmpty()) {
|
||||||
|
superUserViewModel.fetchAppList()
|
||||||
|
}
|
||||||
|
|
||||||
|
if (moduleViewModel.moduleList.isEmpty()) {
|
||||||
|
moduleViewModel.fetchModuleList()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
val showBottomBar = when (currentDestination?.route) {
|
val showBottomBar = when (currentDestination?.route) {
|
||||||
FlashScreenDestination.route -> false // Hide for FlashScreenDestination
|
FlashScreenDestination.route -> false // Hide for FlashScreenDestination
|
||||||
ExecuteModuleActionScreenDestination.route -> false // Hide for ExecuteModuleActionScreen
|
ExecuteModuleActionScreenDestination.route -> false // Hide for ExecuteModuleActionScreen
|
||||||
else -> true
|
else -> true
|
||||||
}
|
}
|
||||||
|
|
||||||
// pre-init platform to faster start WebUI X activities
|
|
||||||
LaunchedEffect(Unit) {
|
|
||||||
initPlatform()
|
|
||||||
}
|
|
||||||
|
|
||||||
Scaffold(
|
Scaffold(
|
||||||
bottomBar = {
|
bottomBar = {
|
||||||
AnimatedVisibility(
|
AnimatedVisibility(
|
||||||
@@ -199,17 +205,6 @@ private fun BottomBar(navController: NavHostController, moduleUpdateCount: Int)
|
|||||||
)
|
)
|
||||||
) {
|
) {
|
||||||
BottomBarDestination.entries
|
BottomBarDestination.entries
|
||||||
.filter {
|
|
||||||
// Hide SuperUser and Module when su compat is disabled
|
|
||||||
if (suCompatDisabled) {
|
|
||||||
if (suSFS == "Supported" && susSUMode == "2") {
|
|
||||||
true
|
|
||||||
} else {
|
|
||||||
// hide SuperUser and Module
|
|
||||||
it != BottomBarDestination.SuperUser && it != BottomBarDestination.Module
|
|
||||||
}
|
|
||||||
} else true
|
|
||||||
}
|
|
||||||
.forEach { destination ->
|
.forEach { destination ->
|
||||||
if (!fullFeatured && destination.rootRequired) return@forEach
|
if (!fullFeatured && destination.rootRequired) return@forEach
|
||||||
val isCurrentDestOnBackStack by navController.isRouteOnBackStackAsState(destination.direction)
|
val isCurrentDestOnBackStack by navController.isRouteOnBackStackAsState(destination.direction)
|
||||||
|
|||||||
@@ -36,7 +36,6 @@ import androidx.compose.ui.platform.LocalContext
|
|||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
import androidx.compose.ui.tooling.preview.Preview
|
import androidx.compose.ui.tooling.preview.Preview
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import com.dergoogler.mmrl.platform.Platform
|
|
||||||
import com.ramcosta.composedestinations.annotation.Destination
|
import com.ramcosta.composedestinations.annotation.Destination
|
||||||
import com.ramcosta.composedestinations.annotation.RootGraph
|
import com.ramcosta.composedestinations.annotation.RootGraph
|
||||||
import com.ramcosta.composedestinations.navigation.DestinationsNavigator
|
import com.ramcosta.composedestinations.navigation.DestinationsNavigator
|
||||||
@@ -102,25 +101,6 @@ fun DeveloperScreen(navigator: DestinationsNavigator) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var useWebUIX by rememberSaveable {
|
|
||||||
mutableStateOf(
|
|
||||||
prefs.getBoolean("use_webuix", true)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
if (ksuVersion != null) {
|
|
||||||
SwitchItem(
|
|
||||||
beta = false,
|
|
||||||
enabled = Platform.isAlive && developerOptionsEnabled,
|
|
||||||
icon = Icons.Filled.WebAsset,
|
|
||||||
title = stringResource(id = R.string.use_webuix),
|
|
||||||
summary = stringResource(id = R.string.use_webuix_summary),
|
|
||||||
checked = useWebUIX
|
|
||||||
) {
|
|
||||||
prefs.edit().putBoolean("use_webuix", it).apply()
|
|
||||||
useWebUIX = it
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var enableWebDebugging by rememberSaveable {
|
var enableWebDebugging by rememberSaveable {
|
||||||
mutableStateOf(
|
mutableStateOf(
|
||||||
prefs.getBoolean("enable_web_debugging", false)
|
prefs.getBoolean("enable_web_debugging", false)
|
||||||
@@ -138,25 +118,6 @@ fun DeveloperScreen(navigator: DestinationsNavigator) {
|
|||||||
enableWebDebugging = it
|
enableWebDebugging = it
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var useWebUIXEruda by rememberSaveable {
|
|
||||||
mutableStateOf(
|
|
||||||
prefs.getBoolean("use_webuix_eruda", false)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
if (ksuVersion != null) {
|
|
||||||
SwitchItem(
|
|
||||||
beta = false,
|
|
||||||
enabled = Platform.isAlive && useWebUIX && enableWebDebugging,
|
|
||||||
icon = Icons.Filled.FormatListNumbered,
|
|
||||||
title = stringResource(id = R.string.use_webuix_eruda),
|
|
||||||
summary = stringResource(id = R.string.use_webuix_eruda_summary),
|
|
||||||
checked = useWebUIXEruda
|
|
||||||
) {
|
|
||||||
prefs.edit().putBoolean("use_webuix_eruda", it).apply()
|
|
||||||
useWebUIXEruda = it
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -54,8 +54,6 @@ import com.rifsxd.ksunext.R
|
|||||||
import com.rifsxd.ksunext.ui.component.rememberConfirmDialog
|
import com.rifsxd.ksunext.ui.component.rememberConfirmDialog
|
||||||
import com.rifsxd.ksunext.ui.util.*
|
import com.rifsxd.ksunext.ui.util.*
|
||||||
import com.rifsxd.ksunext.ui.util.module.LatestVersionInfo
|
import com.rifsxd.ksunext.ui.util.module.LatestVersionInfo
|
||||||
import com.rifsxd.ksunext.ui.viewmodel.ModuleViewModel
|
|
||||||
import com.rifsxd.ksunext.ui.viewmodel.SuperUserViewModel
|
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
@OptIn(ExperimentalMaterial3Api::class)
|
@OptIn(ExperimentalMaterial3Api::class)
|
||||||
@@ -96,20 +94,6 @@ fun HomeScreen(navigator: DestinationsNavigator) {
|
|||||||
val lkmMode = ksuVersion?.let {
|
val lkmMode = ksuVersion?.let {
|
||||||
if (it >= Natives.MINIMAL_SUPPORTED_KERNEL_LKM && kernelVersion.isGKI()) Natives.isLkmMode else null
|
if (it >= Natives.MINIMAL_SUPPORTED_KERNEL_LKM && kernelVersion.isGKI()) Natives.isLkmMode else null
|
||||||
}
|
}
|
||||||
|
|
||||||
val superUserViewModel: SuperUserViewModel = viewModel()
|
|
||||||
|
|
||||||
val moduleViewModel: ModuleViewModel = viewModel()
|
|
||||||
|
|
||||||
LaunchedEffect(Unit) {
|
|
||||||
if (superUserViewModel.appList.isEmpty()) {
|
|
||||||
superUserViewModel.fetchAppList()
|
|
||||||
}
|
|
||||||
|
|
||||||
if (moduleViewModel.moduleList.isEmpty()) {
|
|
||||||
moduleViewModel.fetchModuleList()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
StatusCard(kernelVersion, ksuVersion, lkmMode) {
|
StatusCard(kernelVersion, ksuVersion, lkmMode) {
|
||||||
navigator.navigate(InstallScreenDestination)
|
navigator.navigate(InstallScreenDestination)
|
||||||
|
|||||||
@@ -95,7 +95,6 @@ import androidx.compose.ui.unit.Dp
|
|||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.core.net.toUri
|
import androidx.core.net.toUri
|
||||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||||
import com.dergoogler.mmrl.platform.Platform
|
|
||||||
import com.ramcosta.composedestinations.annotation.Destination
|
import com.ramcosta.composedestinations.annotation.Destination
|
||||||
import com.ramcosta.composedestinations.annotation.RootGraph
|
import com.ramcosta.composedestinations.annotation.RootGraph
|
||||||
import com.ramcosta.composedestinations.generated.destinations.ExecuteModuleActionScreenDestination
|
import com.ramcosta.composedestinations.generated.destinations.ExecuteModuleActionScreenDestination
|
||||||
@@ -126,7 +125,6 @@ import com.rifsxd.ksunext.ui.util.restoreModule
|
|||||||
import com.rifsxd.ksunext.ui.util.zygiskRequired
|
import com.rifsxd.ksunext.ui.util.zygiskRequired
|
||||||
import com.rifsxd.ksunext.ui.viewmodel.ModuleViewModel
|
import com.rifsxd.ksunext.ui.viewmodel.ModuleViewModel
|
||||||
import com.rifsxd.ksunext.ui.webui.WebUIActivity
|
import com.rifsxd.ksunext.ui.webui.WebUIActivity
|
||||||
import com.rifsxd.ksunext.ui.webui.WebUIXActivity
|
|
||||||
import com.dergoogler.mmrl.ui.component.LabelItem
|
import com.dergoogler.mmrl.ui.component.LabelItem
|
||||||
import com.topjohnwu.superuser.io.SuFile
|
import com.topjohnwu.superuser.io.SuFile
|
||||||
|
|
||||||
@@ -363,22 +361,11 @@ fun ModuleScreen(navigator: DestinationsNavigator) {
|
|||||||
},
|
},
|
||||||
onClickModule = { id, name, hasWebUi ->
|
onClickModule = { id, name, hasWebUi ->
|
||||||
if (hasWebUi) {
|
if (hasWebUi) {
|
||||||
val wxEngine = Intent(context, WebUIXActivity::class.java)
|
|
||||||
.setData("kernelsu://webuix/$id".toUri())
|
|
||||||
.putExtra("id", id)
|
|
||||||
.putExtra("name", name)
|
|
||||||
|
|
||||||
val ksuEngine = Intent(context, WebUIActivity::class.java)
|
|
||||||
.setData("kernelsu://webui/$id".toUri())
|
|
||||||
.putExtra("id", id)
|
|
||||||
.putExtra("name", name)
|
|
||||||
|
|
||||||
webUILauncher.launch(
|
webUILauncher.launch(
|
||||||
if (prefs.getBoolean("use_webuix", true) && Platform.isAlive) {
|
Intent(context, WebUIActivity::class.java)
|
||||||
wxEngine
|
.setData(Uri.parse("kernelsu://webui/$id"))
|
||||||
} else {
|
.putExtra("id", id)
|
||||||
ksuEngine
|
.putExtra("name", name)
|
||||||
}
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -54,7 +54,6 @@ import androidx.compose.ui.text.style.TextAlign
|
|||||||
import androidx.compose.ui.tooling.preview.Preview
|
import androidx.compose.ui.tooling.preview.Preview
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.core.content.FileProvider
|
import androidx.core.content.FileProvider
|
||||||
import com.dergoogler.mmrl.platform.Platform
|
|
||||||
import com.maxkeppeker.sheets.core.models.base.Header
|
import com.maxkeppeker.sheets.core.models.base.Header
|
||||||
import com.maxkeppeker.sheets.core.models.base.IconSource
|
import com.maxkeppeker.sheets.core.models.base.IconSource
|
||||||
import com.maxkeppeker.sheets.core.models.base.rememberUseCaseState
|
import com.maxkeppeker.sheets.core.models.base.rememberUseCaseState
|
||||||
|
|||||||
@@ -25,7 +25,6 @@ import androidx.compose.ui.unit.sp
|
|||||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||||
import coil.compose.AsyncImage
|
import coil.compose.AsyncImage
|
||||||
import coil.request.ImageRequest
|
import coil.request.ImageRequest
|
||||||
import com.dergoogler.mmrl.platform.Platform
|
|
||||||
import com.dergoogler.mmrl.ui.component.LabelItem
|
import com.dergoogler.mmrl.ui.component.LabelItem
|
||||||
import com.dergoogler.mmrl.ui.component.LabelItemDefaults
|
import com.dergoogler.mmrl.ui.component.LabelItemDefaults
|
||||||
import com.ramcosta.composedestinations.annotation.Destination
|
import com.ramcosta.composedestinations.annotation.Destination
|
||||||
|
|||||||
@@ -9,8 +9,6 @@ import androidx.compose.runtime.mutableStateOf
|
|||||||
import androidx.compose.runtime.setValue
|
import androidx.compose.runtime.setValue
|
||||||
import androidx.lifecycle.ViewModel
|
import androidx.lifecycle.ViewModel
|
||||||
import androidx.lifecycle.viewModelScope
|
import androidx.lifecycle.viewModelScope
|
||||||
import com.dergoogler.mmrl.platform.Platform
|
|
||||||
import com.dergoogler.mmrl.platform.TIMEOUT_MILLIS
|
|
||||||
import kotlinx.coroutines.delay
|
import kotlinx.coroutines.delay
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
@@ -111,21 +109,9 @@ class ModuleViewModel : ViewModel() {
|
|||||||
|
|
||||||
viewModelScope.launch {
|
viewModelScope.launch {
|
||||||
|
|
||||||
withContext(Dispatchers.Main) {
|
isRefreshing = true
|
||||||
isRefreshing = true
|
|
||||||
}
|
|
||||||
|
|
||||||
withContext(Dispatchers.IO) {
|
withContext(Dispatchers.IO) {
|
||||||
withTimeoutOrNull(TIMEOUT_MILLIS) {
|
|
||||||
while (!Platform.isAlive) {
|
|
||||||
delay(500)
|
|
||||||
}
|
|
||||||
} ?: run {
|
|
||||||
isRefreshing = false
|
|
||||||
Log.e(TAG, "Platform is not alive, aborting fetchModuleList")
|
|
||||||
return@withContext
|
|
||||||
}
|
|
||||||
|
|
||||||
val start = SystemClock.elapsedRealtime()
|
val start = SystemClock.elapsedRealtime()
|
||||||
val oldModuleList = modules
|
val oldModuleList = modules
|
||||||
|
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import android.content.Intent
|
|||||||
import android.content.ServiceConnection
|
import android.content.ServiceConnection
|
||||||
import android.content.pm.ApplicationInfo
|
import android.content.pm.ApplicationInfo
|
||||||
import android.content.pm.PackageInfo
|
import android.content.pm.PackageInfo
|
||||||
|
import android.os.IBinder
|
||||||
import android.os.Parcelable
|
import android.os.Parcelable
|
||||||
import android.os.SystemClock
|
import android.os.SystemClock
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
@@ -15,15 +16,16 @@ import androidx.compose.runtime.getValue
|
|||||||
import androidx.compose.runtime.mutableStateOf
|
import androidx.compose.runtime.mutableStateOf
|
||||||
import androidx.compose.runtime.setValue
|
import androidx.compose.runtime.setValue
|
||||||
import androidx.lifecycle.ViewModel
|
import androidx.lifecycle.ViewModel
|
||||||
import com.dergoogler.mmrl.platform.Platform
|
import com.topjohnwu.superuser.Shell
|
||||||
import com.dergoogler.mmrl.platform.TIMEOUT_MILLIS
|
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
import kotlinx.parcelize.Parcelize
|
import kotlinx.parcelize.Parcelize
|
||||||
|
import com.rifsxd.ksunext.IKsuInterface
|
||||||
import com.rifsxd.ksunext.Natives
|
import com.rifsxd.ksunext.Natives
|
||||||
import com.rifsxd.ksunext.ksuApp
|
import com.rifsxd.ksunext.ksuApp
|
||||||
|
import com.rifsxd.ksunext.ui.KsuService
|
||||||
import com.rifsxd.ksunext.ui.util.HanziToPinyin
|
import com.rifsxd.ksunext.ui.util.HanziToPinyin
|
||||||
import com.rifsxd.ksunext.ui.webui.getInstalledPackagesAll
|
import com.rifsxd.ksunext.ui.util.KsuCli
|
||||||
import kotlinx.coroutines.delay
|
import kotlinx.coroutines.delay
|
||||||
import kotlinx.coroutines.withTimeoutOrNull
|
import kotlinx.coroutines.withTimeoutOrNull
|
||||||
import java.text.Collator
|
import java.text.Collator
|
||||||
@@ -33,7 +35,6 @@ import kotlin.coroutines.suspendCoroutine
|
|||||||
import androidx.core.content.edit
|
import androidx.core.content.edit
|
||||||
|
|
||||||
class SuperUserViewModel : ViewModel() {
|
class SuperUserViewModel : ViewModel() {
|
||||||
val isPlatformAlive get() = Platform.isAlive
|
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private const val TAG = "SuperUserViewModel"
|
private const val TAG = "SuperUserViewModel"
|
||||||
@@ -117,24 +118,56 @@ class SuperUserViewModel : ViewModel() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private suspend inline fun connectKsuService(
|
||||||
|
crossinline onDisconnect: () -> Unit = {}
|
||||||
|
): Pair<IBinder, ServiceConnection> = suspendCoroutine {
|
||||||
|
val connection = object : ServiceConnection {
|
||||||
|
override fun onServiceDisconnected(name: ComponentName?) {
|
||||||
|
onDisconnect()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onServiceConnected(name: ComponentName?, binder: IBinder?) {
|
||||||
|
it.resume(binder as IBinder to this)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val intent = Intent(ksuApp, KsuService::class.java)
|
||||||
|
|
||||||
|
val task = KsuService.bindOrTask(
|
||||||
|
intent,
|
||||||
|
Shell.EXECUTOR,
|
||||||
|
connection,
|
||||||
|
)
|
||||||
|
val shell = KsuCli.SHELL
|
||||||
|
task?.let { it1 -> shell.execTask(it1) }
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun stopKsuService() {
|
||||||
|
val intent = Intent(ksuApp, KsuService::class.java)
|
||||||
|
KsuService.stop(intent)
|
||||||
|
}
|
||||||
|
|
||||||
suspend fun fetchAppList() {
|
suspend fun fetchAppList() {
|
||||||
|
|
||||||
isRefreshing = true
|
isRefreshing = true
|
||||||
|
|
||||||
withContext(Dispatchers.IO) {
|
val result = connectKsuService {
|
||||||
withTimeoutOrNull(TIMEOUT_MILLIS) {
|
Log.w(TAG, "KsuService disconnected")
|
||||||
while (!isPlatformAlive) {
|
}
|
||||||
delay(500)
|
|
||||||
}
|
|
||||||
} ?: return@withContext // Exit early if timeout
|
|
||||||
|
|
||||||
|
withContext(Dispatchers.IO) {
|
||||||
val pm = ksuApp.packageManager
|
val pm = ksuApp.packageManager
|
||||||
val start = SystemClock.elapsedRealtime()
|
val start = SystemClock.elapsedRealtime()
|
||||||
|
|
||||||
val packages = Platform.getInstalledPackagesAll {
|
val binder = result.first
|
||||||
Log.e(TAG, "getInstalledPackagesAll:", it)
|
val allPackages = IKsuInterface.Stub.asInterface(binder).getPackages(0)
|
||||||
Toast.makeText(ksuApp, "Something went wrong, check logs", Toast.LENGTH_SHORT).show()
|
|
||||||
|
withContext(Dispatchers.Main) {
|
||||||
|
stopKsuService()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val packages = allPackages.list
|
||||||
|
|
||||||
apps = packages.map {
|
apps = packages.map {
|
||||||
val appInfo = it.applicationInfo
|
val appInfo = it.applicationInfo
|
||||||
val uid = appInfo!!.uid
|
val uid = appInfo!!.uid
|
||||||
@@ -145,7 +178,6 @@ class SuperUserViewModel : ViewModel() {
|
|||||||
profile = profile,
|
profile = profile,
|
||||||
)
|
)
|
||||||
}.filter { it.packageName != ksuApp.packageName }
|
}.filter { it.packageName != ksuApp.packageName }
|
||||||
profileOverrides = emptyMap()
|
|
||||||
Log.i(TAG, "load cost: ${SystemClock.elapsedRealtime() - start}")
|
Log.i(TAG, "load cost: ${SystemClock.elapsedRealtime() - start}")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,73 +0,0 @@
|
|||||||
package com.rifsxd.ksunext.ui.webui
|
|
||||||
|
|
||||||
import android.content.ServiceConnection
|
|
||||||
import android.content.pm.PackageInfo
|
|
||||||
import android.util.Log
|
|
||||||
import com.dergoogler.mmrl.platform.Platform
|
|
||||||
import com.dergoogler.mmrl.platform.hiddenApi.HiddenPackageManager
|
|
||||||
import com.dergoogler.mmrl.platform.hiddenApi.HiddenUserManager
|
|
||||||
import com.dergoogler.mmrl.platform.model.IProvider
|
|
||||||
import com.dergoogler.mmrl.platform.model.PlatformIntent
|
|
||||||
import com.rifsxd.ksunext.Natives
|
|
||||||
import com.rifsxd.ksunext.ksuApp
|
|
||||||
import com.topjohnwu.superuser.ipc.RootService
|
|
||||||
import kotlinx.coroutines.Dispatchers
|
|
||||||
import kotlinx.coroutines.delay
|
|
||||||
import kotlinx.coroutines.withContext
|
|
||||||
|
|
||||||
class KsuLibSuProvider : IProvider {
|
|
||||||
override val name = "KsuLibSu"
|
|
||||||
|
|
||||||
override fun isAvailable() = true
|
|
||||||
|
|
||||||
override suspend fun isAuthorized() = Natives.becomeManager(ksuApp.packageName)
|
|
||||||
|
|
||||||
private val serviceIntent
|
|
||||||
get() = PlatformIntent(
|
|
||||||
ksuApp,
|
|
||||||
Platform.KsuNext,
|
|
||||||
SuService::class.java
|
|
||||||
)
|
|
||||||
|
|
||||||
override fun bind(connection: ServiceConnection) {
|
|
||||||
RootService.bind(serviceIntent.intent, connection)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun unbind(connection: ServiceConnection) {
|
|
||||||
RootService.stop(serviceIntent.intent)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
suspend fun initPlatform() = withContext(Dispatchers.IO) {
|
|
||||||
try {
|
|
||||||
val active = Platform.init {
|
|
||||||
this.context = ksuApp
|
|
||||||
this.platform = Platform.KsuNext
|
|
||||||
this.provider = from(KsuLibSuProvider())
|
|
||||||
}
|
|
||||||
|
|
||||||
while (!active) {
|
|
||||||
delay(1000)
|
|
||||||
}
|
|
||||||
|
|
||||||
return@withContext active
|
|
||||||
} catch (e: Exception) {
|
|
||||||
Log.e("KsuLibSu", "Failed to initialize platform", e)
|
|
||||||
return@withContext false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun Platform.Companion.getInstalledPackagesAll(catch: (Exception) -> Unit = {}): List<PackageInfo> =
|
|
||||||
try {
|
|
||||||
val packages = mutableListOf<PackageInfo>()
|
|
||||||
val userInfos = userManager.getUsers()
|
|
||||||
|
|
||||||
for (userInfo in userInfos) {
|
|
||||||
packages.addAll(packageManager.getInstalledPackages(0, userInfo.id))
|
|
||||||
}
|
|
||||||
|
|
||||||
packages
|
|
||||||
} catch (e: Exception) {
|
|
||||||
catch(e)
|
|
||||||
packageManager.getInstalledPackages(0, userManager.myUserId)
|
|
||||||
}
|
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
package com.rifsxd.ksunext.ui.webui
|
|
||||||
|
|
||||||
import android.content.Intent
|
|
||||||
import android.os.IBinder
|
|
||||||
import com.dergoogler.mmrl.platform.model.PlatformIntent.Companion.getPlatform
|
|
||||||
import com.dergoogler.mmrl.platform.service.ServiceManager
|
|
||||||
import com.topjohnwu.superuser.ipc.RootService
|
|
||||||
|
|
||||||
class SuService : RootService() {
|
|
||||||
override fun onBind(intent: Intent): IBinder {
|
|
||||||
val mode = intent.getPlatform()
|
|
||||||
return ServiceManager(mode)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -15,8 +15,6 @@ 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.dergoogler.mmrl.platform.model.ModId
|
|
||||||
import com.dergoogler.mmrl.webui.interfaces.WXOptions
|
|
||||||
import com.topjohnwu.superuser.Shell
|
import com.topjohnwu.superuser.Shell
|
||||||
import com.rifsxd.ksunext.ui.util.createRootShell
|
import com.rifsxd.ksunext.ui.util.createRootShell
|
||||||
import java.io.File
|
import java.io.File
|
||||||
@@ -41,10 +39,9 @@ class WebUIActivity : ComponentActivity() {
|
|||||||
val name = intent.getStringExtra("name")!!
|
val name = intent.getStringExtra("name")!!
|
||||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU) {
|
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU) {
|
||||||
@Suppress("DEPRECATION")
|
@Suppress("DEPRECATION")
|
||||||
setTaskDescription(ActivityManager.TaskDescription("KernelSU Next - $name"))
|
setTaskDescription(ActivityManager.TaskDescription("KSUNEXT - $name"))
|
||||||
} else {
|
} else {
|
||||||
val taskDescription =
|
val taskDescription = ActivityManager.TaskDescription.Builder().setLabel("KSUNEXT - $name").build()
|
||||||
ActivityManager.TaskDescription.Builder().setLabel("KernelSU Next - $name").build()
|
|
||||||
setTaskDescription(taskDescription)
|
setTaskDescription(taskDescription)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -65,7 +62,7 @@ class WebUIActivity : ComponentActivity() {
|
|||||||
val webViewClient = object : WebViewClient() {
|
val webViewClient = object : WebViewClient() {
|
||||||
override fun shouldInterceptRequest(
|
override fun shouldInterceptRequest(
|
||||||
view: WebView,
|
view: WebView,
|
||||||
request: WebResourceRequest,
|
request: WebResourceRequest
|
||||||
): WebResourceResponse? {
|
): WebResourceResponse? {
|
||||||
return webViewAssetLoader.shouldInterceptRequest(request.url)
|
return webViewAssetLoader.shouldInterceptRequest(request.url)
|
||||||
}
|
}
|
||||||
@@ -85,9 +82,7 @@ class WebUIActivity : ComponentActivity() {
|
|||||||
settings.javaScriptEnabled = true
|
settings.javaScriptEnabled = true
|
||||||
settings.domStorageEnabled = true
|
settings.domStorageEnabled = true
|
||||||
settings.allowFileAccess = false
|
settings.allowFileAccess = false
|
||||||
webviewInterface = WebViewInterface(
|
webviewInterface = WebViewInterface(this@WebUIActivity, this, moduleDir)
|
||||||
WXOptions(this@WebUIActivity, this, ModId(moduleId))
|
|
||||||
)
|
|
||||||
addJavascriptInterface(webviewInterface, "ksu")
|
addJavascriptInterface(webviewInterface, "ksu")
|
||||||
setWebViewClient(webViewClient)
|
setWebViewClient(webViewClient)
|
||||||
loadUrl("https://mui.kernelsu.org/index.html")
|
loadUrl("https://mui.kernelsu.org/index.html")
|
||||||
|
|||||||
@@ -1,113 +0,0 @@
|
|||||||
package com.rifsxd.ksunext.ui.webui
|
|
||||||
|
|
||||||
import android.app.ActivityManager
|
|
||||||
import android.os.Build
|
|
||||||
import android.os.Bundle
|
|
||||||
import android.webkit.WebView
|
|
||||||
import androidx.activity.ComponentActivity
|
|
||||||
import androidx.activity.compose.setContent
|
|
||||||
import androidx.activity.enableEdgeToEdge
|
|
||||||
import androidx.compose.foundation.isSystemInDarkTheme
|
|
||||||
import androidx.compose.runtime.LaunchedEffect
|
|
||||||
import androidx.compose.runtime.getValue
|
|
||||||
import androidx.compose.runtime.mutableStateOf
|
|
||||||
import androidx.compose.runtime.remember
|
|
||||||
import androidx.compose.runtime.setValue
|
|
||||||
import androidx.lifecycle.lifecycleScope
|
|
||||||
import com.dergoogler.mmrl.platform.Platform
|
|
||||||
import com.dergoogler.mmrl.platform.model.ModId
|
|
||||||
import com.dergoogler.mmrl.ui.component.Loading
|
|
||||||
import com.dergoogler.mmrl.webui.screen.WebUIScreen
|
|
||||||
import com.dergoogler.mmrl.webui.util.rememberWebUIOptions
|
|
||||||
import com.rifsxd.ksunext.BuildConfig
|
|
||||||
import com.rifsxd.ksunext.ui.theme.KernelSUTheme
|
|
||||||
import kotlinx.coroutines.delay
|
|
||||||
import kotlinx.coroutines.launch
|
|
||||||
|
|
||||||
class WebUIXActivity : ComponentActivity() {
|
|
||||||
private lateinit var webView: WebView
|
|
||||||
|
|
||||||
private val userAgent
|
|
||||||
get(): String {
|
|
||||||
val ksuVersion = BuildConfig.VERSION_CODE
|
|
||||||
|
|
||||||
val platform = Platform.get("Unknown") {
|
|
||||||
platform.name
|
|
||||||
}
|
|
||||||
|
|
||||||
val platformVersion = Platform.get(-1) {
|
|
||||||
moduleManager.versionCode
|
|
||||||
}
|
|
||||||
|
|
||||||
val osVersion = Build.VERSION.RELEASE
|
|
||||||
val deviceModel = Build.MODEL
|
|
||||||
|
|
||||||
return "KernelSU Next/$ksuVersion (Linux; Android $osVersion; $deviceModel; $platform/$platformVersion)"
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
|
||||||
super.onCreate(savedInstanceState)
|
|
||||||
enableEdgeToEdge()
|
|
||||||
|
|
||||||
webView = WebView(this)
|
|
||||||
|
|
||||||
lifecycleScope.launch {
|
|
||||||
initPlatform()
|
|
||||||
}
|
|
||||||
|
|
||||||
val moduleId = intent.getStringExtra("id")!!
|
|
||||||
val name = intent.getStringExtra("name")!!
|
|
||||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU) {
|
|
||||||
@Suppress("DEPRECATION")
|
|
||||||
setTaskDescription(ActivityManager.TaskDescription("KernelSU Next - $name"))
|
|
||||||
} else {
|
|
||||||
val taskDescription =
|
|
||||||
ActivityManager.TaskDescription.Builder().setLabel("KernelSU Next - $name").build()
|
|
||||||
setTaskDescription(taskDescription)
|
|
||||||
}
|
|
||||||
|
|
||||||
val prefs = getSharedPreferences("settings", MODE_PRIVATE)
|
|
||||||
|
|
||||||
setContent {
|
|
||||||
KernelSUTheme {
|
|
||||||
var isLoading by remember { mutableStateOf(true) }
|
|
||||||
|
|
||||||
LaunchedEffect(Platform.isAlive) {
|
|
||||||
while (!Platform.isAlive) {
|
|
||||||
delay(1000)
|
|
||||||
}
|
|
||||||
|
|
||||||
isLoading = false
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isLoading) {
|
|
||||||
Loading()
|
|
||||||
|
|
||||||
return@KernelSUTheme
|
|
||||||
}
|
|
||||||
|
|
||||||
val webDebugging = prefs.getBoolean("enable_web_debugging", false)
|
|
||||||
val erudaInject = prefs.getBoolean("use_webuix_eruda", false)
|
|
||||||
val dark = isSystemInDarkTheme()
|
|
||||||
|
|
||||||
val options = rememberWebUIOptions(
|
|
||||||
modId = ModId(moduleId),
|
|
||||||
debug = webDebugging,
|
|
||||||
appVersionCode = BuildConfig.VERSION_CODE,
|
|
||||||
isDarkMode = dark,
|
|
||||||
enableEruda = erudaInject,
|
|
||||||
cls = WebUIXActivity::class.java,
|
|
||||||
userAgentString = userAgent
|
|
||||||
)
|
|
||||||
|
|
||||||
WebUIScreen(
|
|
||||||
webView = webView,
|
|
||||||
options = options,
|
|
||||||
interfaces = listOf(
|
|
||||||
WebViewInterface.factory()
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,17 +1,16 @@
|
|||||||
package com.rifsxd.ksunext.ui.webui
|
package com.rifsxd.ksunext.ui.webui
|
||||||
|
|
||||||
import android.app.Activity
|
import android.app.Activity
|
||||||
|
import android.content.Context
|
||||||
import android.os.Handler
|
import android.os.Handler
|
||||||
import android.os.Looper
|
import android.os.Looper
|
||||||
import android.text.TextUtils
|
import android.text.TextUtils
|
||||||
import android.view.Window
|
import android.view.Window
|
||||||
import android.webkit.JavascriptInterface
|
import android.webkit.JavascriptInterface
|
||||||
|
import android.webkit.WebView
|
||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
import androidx.core.view.WindowInsetsCompat
|
import androidx.core.view.WindowInsetsCompat
|
||||||
import androidx.core.view.WindowInsetsControllerCompat
|
import androidx.core.view.WindowInsetsControllerCompat
|
||||||
import com.dergoogler.mmrl.webui.interfaces.WXInterface
|
|
||||||
import com.dergoogler.mmrl.webui.interfaces.WXOptions
|
|
||||||
import com.dergoogler.mmrl.webui.model.JavaScriptInterface
|
|
||||||
import com.topjohnwu.superuser.CallbackList
|
import com.topjohnwu.superuser.CallbackList
|
||||||
import com.topjohnwu.superuser.ShellUtils
|
import com.topjohnwu.superuser.ShellUtils
|
||||||
import com.topjohnwu.superuser.internal.UiThreadHandler
|
import com.topjohnwu.superuser.internal.UiThreadHandler
|
||||||
@@ -24,15 +23,10 @@ import java.io.File
|
|||||||
import java.util.concurrent.CompletableFuture
|
import java.util.concurrent.CompletableFuture
|
||||||
|
|
||||||
class WebViewInterface(
|
class WebViewInterface(
|
||||||
wxOptions: WXOptions,
|
val context: Context,
|
||||||
) : WXInterface(wxOptions) {
|
private val webView: WebView,
|
||||||
override var name: String = "ksu"
|
private val modDir: String
|
||||||
|
) {
|
||||||
companion object {
|
|
||||||
fun factory() = JavaScriptInterface(WebViewInterface::class.java)
|
|
||||||
}
|
|
||||||
|
|
||||||
private val modDir get() = "/data/adb/modules/${modId.id}"
|
|
||||||
|
|
||||||
@JavascriptInterface
|
@JavascriptInterface
|
||||||
fun exec(cmd: String): String {
|
fun exec(cmd: String): String {
|
||||||
@@ -65,7 +59,7 @@ class WebViewInterface(
|
|||||||
fun exec(
|
fun exec(
|
||||||
cmd: String,
|
cmd: String,
|
||||||
options: String?,
|
options: String?,
|
||||||
callbackFunc: String,
|
callbackFunc: String
|
||||||
) {
|
) {
|
||||||
val finalCommand = StringBuilder()
|
val finalCommand = StringBuilder()
|
||||||
processOptions(finalCommand, options)
|
processOptions(finalCommand, options)
|
||||||
@@ -174,9 +168,9 @@ class WebViewInterface(
|
|||||||
if (context is Activity) {
|
if (context is Activity) {
|
||||||
Handler(Looper.getMainLooper()).post {
|
Handler(Looper.getMainLooper()).post {
|
||||||
if (enable) {
|
if (enable) {
|
||||||
hideSystemUI(activity.window)
|
hideSystemUI(context.window)
|
||||||
} else {
|
} else {
|
||||||
showSystemUI(activity.window)
|
showSystemUI(context.window)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -185,7 +179,7 @@ class WebViewInterface(
|
|||||||
@JavascriptInterface
|
@JavascriptInterface
|
||||||
fun moduleInfo(): String {
|
fun moduleInfo(): String {
|
||||||
val moduleInfos = JSONArray(listModules())
|
val moduleInfos = JSONArray(listModules())
|
||||||
val currentModuleInfo = JSONObject()
|
var currentModuleInfo = JSONObject()
|
||||||
currentModuleInfo.put("moduleDir", modDir)
|
currentModuleInfo.put("moduleDir", modDir)
|
||||||
val moduleId = File(modDir).getName()
|
val moduleId = File(modDir).getName()
|
||||||
for (i in 0 until moduleInfos.length()) {
|
for (i in 0 until moduleInfos.length()) {
|
||||||
@@ -195,7 +189,7 @@ class WebViewInterface(
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
val keys = currentInfo.keys()
|
var keys = currentInfo.keys()
|
||||||
for (key in keys) {
|
for (key in keys) {
|
||||||
currentModuleInfo.put(key, currentInfo.get(key))
|
currentModuleInfo.put(key, currentInfo.get(key))
|
||||||
}
|
}
|
||||||
@@ -208,12 +202,8 @@ class WebViewInterface(
|
|||||||
fun hideSystemUI(window: Window) =
|
fun hideSystemUI(window: Window) =
|
||||||
WindowInsetsControllerCompat(window, window.decorView).let { controller ->
|
WindowInsetsControllerCompat(window, window.decorView).let { controller ->
|
||||||
controller.hide(WindowInsetsCompat.Type.systemBars())
|
controller.hide(WindowInsetsCompat.Type.systemBars())
|
||||||
controller.systemBarsBehavior =
|
controller.systemBarsBehavior = WindowInsetsControllerCompat.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE
|
||||||
WindowInsetsControllerCompat.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun showSystemUI(window: Window) =
|
fun showSystemUI(window: Window) =
|
||||||
WindowInsetsControllerCompat(
|
WindowInsetsControllerCompat(window, window.decorView).show(WindowInsetsCompat.Type.systemBars())
|
||||||
window,
|
|
||||||
window.decorView
|
|
||||||
).show(WindowInsetsCompat.Type.systemBars())
|
|
||||||
Reference in New Issue
Block a user