Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions app/src/main/java/com/sameerasw/essentials/EssentialsApp.kt
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,16 @@ import com.sameerasw.essentials.services.ScreenOffReceiver
import com.sameerasw.essentials.utils.ShizukuUtils

class EssentialsApp : Application() {
companion object {
lateinit var context: Context
private set
}

private val screenOffReceiver = ScreenOffReceiver()

override fun onCreate() {
super.onCreate()
context = applicationContext
ShizukuUtils.initialize()
com.sameerasw.essentials.utils.LogManager.init(this)
val intentFilter = IntentFilter(Intent.ACTION_SCREEN_OFF)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,7 @@ class FeatureSettingsActivity : FragmentActivity() {
"Snooze system notifications" -> !isNotificationListenerEnabled
"Screen locked security" -> !isAccessibilityEnabled || !isWriteSecureSettingsEnabled || !viewModel.isDeviceAdminEnabled.value
"App lock" -> !isAccessibilityEnabled
"Freeze" -> !viewModel.isShizukuAvailable.value || !viewModel.isShizukuPermissionGranted.value
"Freeze" -> !com.sameerasw.essentials.utils.ShellUtils.hasPermission(context)
"Location reached" -> !viewModel.isLocationPermissionGranted.value || !viewModel.isBackgroundLocationPermissionGranted.value
else -> false
}
Expand Down Expand Up @@ -376,17 +376,32 @@ class FeatureSettingsActivity : FragmentActivity() {
isGranted = isAccessibilityEnabled
)
)
"Freeze" -> listOf(
PermissionItem(
iconRes = R.drawable.rounded_mode_cool_24,
title = R.string.perm_shizuku_title,
description = R.string.perm_shizuku_desc,
dependentFeatures = PermissionRegistry.getFeatures("SHIZUKU"),
actionLabel = R.string.perm_action_grant,
action = { viewModel.requestShizukuPermission() },
isGranted = viewModel.isShizukuPermissionGranted.value
"Freeze" -> {
val isRootEnabled = com.sameerasw.essentials.utils.ShellUtils.isRootEnabled(context)
listOf(
if (isRootEnabled) {
PermissionItem(
iconRes = R.drawable.rounded_numbers_24,
title = R.string.perm_root_title,
description = R.string.perm_root_desc,
dependentFeatures = PermissionRegistry.getFeatures("ROOT"),
actionLabel = R.string.perm_action_grant,
action = { viewModel.check(context) },
isGranted = viewModel.isRootPermissionGranted.value
)
} else {
PermissionItem(
iconRes = R.drawable.rounded_mode_cool_24,
title = R.string.perm_shizuku_title,
description = R.string.perm_shizuku_desc,
dependentFeatures = PermissionRegistry.getFeatures("SHIZUKU"),
actionLabel = R.string.perm_action_grant,
action = { viewModel.requestShizukuPermission() },
isGranted = viewModel.isShizukuPermissionGranted.value
)
}
)
)
}
"Location reached" -> listOf(
PermissionItem(
iconRes = R.drawable.rounded_navigation_24,
Expand Down
24 changes: 23 additions & 1 deletion app/src/main/java/com/sameerasw/essentials/SettingsActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ import androidx.compose.foundation.background
import androidx.compose.foundation.combinedClickable
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.ui.draw.clip
import androidx.compose.ui.res.stringResource
import com.sameerasw.essentials.domain.registry.PermissionRegistry
import com.sameerasw.essentials.ui.components.sheets.InstructionsBottomSheet
import java.text.SimpleDateFormat
Expand Down Expand Up @@ -189,6 +190,9 @@ fun SettingsContent(viewModel: MainViewModel, modifier: Modifier = Modifier) {
val isAutoUpdateEnabled by viewModel.isAutoUpdateEnabled
val isUpdateNotificationEnabled by viewModel.isUpdateNotificationEnabled
val isPreReleaseCheckEnabled by viewModel.isPreReleaseCheckEnabled
val isRootEnabled by viewModel.isRootEnabled
val isRootAvailable by viewModel.isRootAvailable
val isRootPermissionGranted by viewModel.isRootPermissionGranted
val isDeveloperModeEnabled by viewModel.isDeveloperModeEnabled
var showInstructionsSheet by remember { mutableStateOf(false) }

Expand Down Expand Up @@ -267,6 +271,13 @@ fun SettingsContent(viewModel: MainViewModel, modifier: Modifier = Modifier) {
HapticUtil.saveAppHapticsEnabled(context, isChecked)
}
)
IconToggleItem(
iconRes = R.drawable.rounded_numbers_24,
title = stringResource(R.string.setting_use_root_title),
description = stringResource(R.string.setting_use_root_desc),
isChecked = viewModel.isRootEnabled.value,
onCheckedChange = { viewModel.setRootEnabled(it, context) }
)
}

Text(
Expand Down Expand Up @@ -346,7 +357,18 @@ fun SettingsContent(viewModel: MainViewModel, modifier: Modifier = Modifier) {
},
)

if (isShizukuAvailable) {
if (isRootEnabled) {
PermissionCard(
iconRes = R.drawable.rounded_numbers_24,
title = stringResource(R.string.perm_root_title),
dependentFeatures = PermissionRegistry.getFeatures("ROOT"),
actionLabel = if (isRootPermissionGranted) "Granted" else "Grant Access",
isGranted = isRootPermissionGranted,
onActionClick = {
viewModel.check(context)
}
)
} else if (isShizukuAvailable) {
PermissionCard(
iconRes = R.drawable.rounded_adb_24,
title = "Shizuku",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ class ShortcutHandlerActivity : ComponentActivity() {
CoroutineScope(Dispatchers.IO).launch {
val isFrozen = FreezeManager.isAppFrozen(this@ShortcutHandlerActivity, packageName)
if (isFrozen) {
FreezeManager.unfreezeApp(packageName)
FreezeManager.unfreezeApp(this@ShortcutHandlerActivity, packageName)
// Small delay to ensure system registers the change
delay(500) // Slightly longer delay to show the nice loader if frozen
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ class SettingsRepository(private val context: Context) {
const val KEY_DEVELOPER_MODE_ENABLED = "developer_mode_enabled"
const val KEY_HAPTIC_FEEDBACK_TYPE = "haptic_feedback_type"
const val KEY_DEFAULT_TAB = "default_tab"
const val KEY_USE_ROOT = "use_root"
}

// Observe changes
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import android.content.Context
import com.sameerasw.essentials.R
import com.sameerasw.essentials.domain.model.Feature
import com.sameerasw.essentials.domain.model.SearchSetting
import com.sameerasw.essentials.utils.ShellUtils
import com.sameerasw.essentials.viewmodels.MainViewModel

object FeatureRegistry {
Expand Down Expand Up @@ -90,12 +91,12 @@ object FeatureRegistry {
iconRes = R.drawable.rounded_navigation_24,
category = R.string.cat_tools,
description = R.string.feat_maps_power_saving_desc,
permissionKeys = listOf("SHIZUKU", "NOTIFICATION_LISTENER"),
permissionKeys = if (ShellUtils.isRootEnabled(com.sameerasw.essentials.EssentialsApp.context)) listOf("ROOT", "NOTIFICATION_LISTENER") else listOf("SHIZUKU", "NOTIFICATION_LISTENER"),
hasMoreSettings = false
) {
override fun isEnabled(viewModel: MainViewModel) = viewModel.isMapsPowerSavingEnabled.value
override fun isToggleEnabled(viewModel: MainViewModel, context: Context) =
viewModel.isShizukuAvailable.value && viewModel.isShizukuPermissionGranted.value && viewModel.isNotificationListenerEnabled.value
com.sameerasw.essentials.utils.ShellUtils.hasPermission(context) && viewModel.isNotificationListenerEnabled.value
override fun onToggle(viewModel: MainViewModel, context: Context, enabled: Boolean) = viewModel.setMapsPowerSavingEnabled(enabled, context)
override fun onClick(context: Context, viewModel: MainViewModel) {}
},
Expand Down Expand Up @@ -323,7 +324,7 @@ object FeatureRegistry {
iconRes = R.drawable.rounded_switch_access_3_24,
category = R.string.cat_system,
description = R.string.feat_button_remap_desc,
permissionKeys = listOf("ACCESSIBILITY"),
permissionKeys = if (ShellUtils.isRootEnabled(com.sameerasw.essentials.EssentialsApp.context)) listOf("ACCESSIBILITY", "ROOT") else listOf("ACCESSIBILITY", "SHIZUKU"),
showToggle = false,
searchableSettings = listOf(
SearchSetting(
Expand Down Expand Up @@ -434,7 +435,7 @@ object FeatureRegistry {
iconRes = R.drawable.rounded_mode_cool_24,
category = R.string.cat_tools,
description = R.string.feat_freeze_desc,
permissionKeys = listOf("SHIZUKU"),
permissionKeys = if (ShellUtils.isRootEnabled(com.sameerasw.essentials.EssentialsApp.context)) listOf("ROOT") else listOf("SHIZUKU"),
searchableSettings = listOf(
SearchSetting(
R.string.search_freeze_pick_title,
Expand Down Expand Up @@ -466,7 +467,7 @@ object FeatureRegistry {
) {
override fun isEnabled(viewModel: MainViewModel) = true
override fun isToggleEnabled(viewModel: MainViewModel, context: Context) =
viewModel.isShizukuAvailable.value && viewModel.isShizukuPermissionGranted.value
com.sameerasw.essentials.utils.ShellUtils.hasPermission(context)
override fun onToggle(viewModel: MainViewModel, context: Context, enabled: Boolean) {}
}
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,13 @@ fun initPermissionRegistry() {
PermissionRegistry.register("WRITE_SECURE_SETTINGS", R.string.feat_screen_locked_security_title)

// Shizuku permission
PermissionRegistry.register("SHIZUKU", R.string.feat_maps_power_saving_title)
PermissionRegistry.register("SHIZUKU", R.string.feat_freeze_title)
PermissionRegistry.register("SHIZUKU", R.string.feat_maps_power_saving_title)

// Root permission
PermissionRegistry.register("ROOT", R.string.feat_maps_power_saving_title)
PermissionRegistry.register("ROOT", R.string.feat_freeze_title)
PermissionRegistry.register("ROOT", R.string.feat_button_remap_title)

// Notification listener permission
PermissionRegistry.register("NOTIFICATION_LISTENER", R.string.feat_maps_power_saving_title)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,10 @@ class InputEventReader(private val devicePath: String) {
private val buffer = ByteArray(INPUT_EVENT_SIZE)

fun open(): Boolean = try {
process = ShizukuProcessHelper.newProcess(arrayOf("cat", devicePath))
process = com.sameerasw.essentials.utils.ShellUtils.newProcess(
com.sameerasw.essentials.EssentialsApp.context,
arrayOf("cat", devicePath)
)
inputStream = process?.inputStream
inputStream != null
} catch (e: Exception) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,8 +71,8 @@ class InputEventListenerService : Service() {

private fun startListening() {
scope?.launch {
if (shizukuHelper.getStatus() != ShizukuStatus.READY) {
Log.e("InputEventListener", "Shizuku not ready")
if (!com.sameerasw.essentials.utils.ShellUtils.hasPermission(this@InputEventListenerService)) {
Log.e("InputEventListener", "Shell permission not granted")
return@launch
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,12 @@ import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import com.sameerasw.essentials.domain.MapsState
import com.sameerasw.essentials.utils.ShizukuUtils
import com.sameerasw.essentials.utils.ShellUtils

class ScreenOffReceiver : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
if (intent.action == Intent.ACTION_SCREEN_OFF && MapsState.isEnabled && MapsState.hasNavigationNotification) {
ShizukuUtils.runCommand("am start -n com.google.android.apps.maps/com.google.android.apps.gmm.features.minmode.MinModeActivity")
ShellUtils.runCommand(context, "am start -n com.google.android.apps.maps/com.google.android.apps.gmm.features.minmode.MinModeActivity")
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ class ButtonRemapHandler(
// Typically AOD check is: Display.STATE_DOZE or STATE_DOZE_SUSPEND
val isAod = isAodShowing()

val shizukuReady = ShizukuUtils.isShizukuAvailable() && ShizukuUtils.hasPermission()
val shellReady = com.sameerasw.essentials.utils.ShellUtils.isAvailable(service) && com.sameerasw.essentials.utils.ShellUtils.hasPermission(service)
val devicePathDetected = !prefs.getString("shizuku_detected_device_path", null).isNullOrEmpty()

// If using Shizuku and screen off, verify if we should INTERCEPT or let Shizuku handle it?
Expand All @@ -66,7 +66,9 @@ class ButtonRemapHandler(
// NO, the return true means "CONSUME". So if Shizuku is handling it, we consume it here to prevent default volume action?
// Let's stick to the original logic flow.

if (isButtonRemapUseShizuku && isButtonRemapEnabled && shizukuReady && devicePathDetected && !isScreenInteractive && !isAod) {
val useShell = isButtonRemapUseShizuku || com.sameerasw.essentials.utils.ShellUtils.isRootEnabled(service)

if (useShell && isButtonRemapEnabled && shellReady && devicePathDetected && !isScreenInteractive && !isAod) {
val isTorchControl = flashlightHandler.isTorchOn && (isAdjustEnabled || isGlobalEnabled) && Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU

val suffix = "_off"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ class MonoAudioTileService : BaseTileService() {
override fun hasFeaturePermission(): Boolean {
// Private secure settings can only be modified by ADB, system apps, or
// apps with a target sdk of Android 5.1 and lower.
return ShizukuUtils.hasPermission() && ShizukuUtils.isShizukuAvailable()
return com.sameerasw.essentials.utils.ShellUtils.hasPermission(this) && com.sameerasw.essentials.utils.ShellUtils.isAvailable(this)
}

override fun getTileIcon(): Icon {
Expand All @@ -30,7 +30,7 @@ class MonoAudioTileService : BaseTileService() {

override fun onTileClick() {
val newState = if (isMonoAudioEnabled()) 0 else 1
ShizukuUtils.runCommand("settings put system master_mono $newState")
com.sameerasw.essentials.utils.ShellUtils.runCommand(this, "settings put system master_mono $newState")
}

private fun isMonoAudioEnabled(): Boolean {
Expand Down
Loading