Skip to content

Commit 52ba201

Browse files
committed
feat: Action Log for batch & app detail, rollback for battery only, compact About page
1 parent 4ca661f commit 52ba201

File tree

5 files changed

+339
-502
lines changed

5 files changed

+339
-502
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -129,4 +129,4 @@ GPL-3.0 License - see [LICENSE](LICENSE)
129129
## Acknowledgments
130130

131131
- [libsu](https://github.com/topjohnwu/libsu) - Root shell library
132-
- [Shizuku](https://github.com/RikkaApps/Shizuku) - Elevated API access
132+
- [Shizuku](https://github.com/RikkaApps/Shizuku) - Elevated API access

app/src/main/java/com/appcontrolx/ui/AboutFragment.kt

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,9 @@ import androidx.fragment.app.Fragment
1212
import androidx.lifecycle.lifecycleScope
1313
import com.appcontrolx.R
1414
import com.appcontrolx.databinding.FragmentAboutBinding
15+
import com.appcontrolx.executor.RootExecutor
16+
import com.appcontrolx.model.ExecutionMode
17+
import com.appcontrolx.rollback.RollbackManager
1518
import com.appcontrolx.service.PermissionBridge
1619
import android.util.Log
1720
import dagger.hilt.android.AndroidEntryPoint
@@ -68,7 +71,7 @@ class AboutFragment : Fragment() {
6871
val b = binding ?: return
6972

7073
lifecycleScope.launch {
71-
val (userApps, systemApps) = withContext(Dispatchers.IO) {
74+
val (userApps, systemApps, actionsCount) = withContext(Dispatchers.IO) {
7275
val pm = requireContext().packageManager
7376
val packages = pm.getInstalledPackages(0)
7477

@@ -83,14 +86,19 @@ class AboutFragment : Fragment() {
8386
}
8487
}
8588

86-
Pair(user, system)
89+
// Get action count from RollbackManager
90+
val mode = PermissionBridge(requireContext()).detectMode()
91+
val actions = if (mode is ExecutionMode.Root) {
92+
val executor = RootExecutor()
93+
RollbackManager(requireContext(), executor).getLogCount()
94+
} else 0
95+
96+
Triple(user, system, actions)
8797
}
8898

8999
b.tvUserAppsCount.text = userApps.toString()
90100
b.tvSystemAppsCount.text = systemApps.toString()
91-
92-
// Actions count from prefs (placeholder for now)
93-
b.tvActionsCount.text = "0"
101+
b.tvActionsCount.text = actionsCount.toString()
94102
}
95103
}
96104

app/src/main/java/com/appcontrolx/ui/AppDetailBottomSheet.kt

Lines changed: 49 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ import com.appcontrolx.executor.CommandExecutor
1616
import com.appcontrolx.executor.RootExecutor
1717
import com.appcontrolx.model.AppInfo
1818
import com.appcontrolx.model.ExecutionMode
19+
import com.appcontrolx.rollback.ActionLog
20+
import com.appcontrolx.rollback.RollbackManager
1921
import com.appcontrolx.service.BackgroundStatus
2022
import com.appcontrolx.service.BatteryPolicyManager
2123
import com.appcontrolx.service.PermissionBridge
@@ -38,6 +40,7 @@ class AppDetailBottomSheet : BottomSheetDialogFragment() {
3840
private var appInfo: AppInfo? = null
3941
private var executor: CommandExecutor? = null
4042
private var policyManager: BatteryPolicyManager? = null
43+
private var rollbackManager: RollbackManager? = null
4144
private var executionMode: ExecutionMode = ExecutionMode.None
4245
private var currentBgStatus: BackgroundStatus = BackgroundStatus.DEFAULT
4346

@@ -87,6 +90,7 @@ class AppDetailBottomSheet : BottomSheetDialogFragment() {
8790
if (executionMode is ExecutionMode.Root) {
8891
executor = RootExecutor()
8992
policyManager = BatteryPolicyManager(executor!!)
93+
rollbackManager = RollbackManager(requireContext(), executor!!)
9094
}
9195
}
9296

@@ -222,54 +226,55 @@ class AppDetailBottomSheet : BottomSheetDialogFragment() {
222226

223227
binding.btnForceStop.setOnClickListener {
224228
if (isCritical) { showProtectedWarning(); return@setOnClickListener }
225-
executeActionWithLoading(getString(R.string.action_force_stop)) {
229+
executeActionWithLoading(getString(R.string.action_force_stop), {
226230
policyManager?.forceStop(appInfo!!.packageName)
227-
}
231+
}, "FORCE_STOP")
228232
}
229233

230234
binding.btnToggleEnable.setOnClickListener {
231235
if (isForceStopOnly || isCritical) { showProtectedWarning(); return@setOnClickListener }
232236
val app = appInfo ?: return@setOnClickListener
233237
val actionName = if (app.isEnabled) getString(R.string.action_freeze) else getString(R.string.action_unfreeze)
234-
executeActionWithLoading(actionName) {
238+
val logAction = if (app.isEnabled) "FREEZE" else "UNFREEZE"
239+
executeActionWithLoading(actionName, {
235240
if (app.isEnabled) policyManager?.freezeApp(app.packageName)
236241
else policyManager?.unfreezeApp(app.packageName)
237-
}
242+
}, logAction)
238243
}
239244

240245
binding.btnRestrictBg.setOnClickListener {
241246
if (isForceStopOnly || isCritical) { showProtectedWarning(); return@setOnClickListener }
242-
executeBackgroundAction(getString(R.string.action_restrict_bg)) {
247+
executeBackgroundAction(getString(R.string.action_restrict_bg), "RESTRICT_BACKGROUND") {
243248
policyManager?.restrictBackground(appInfo!!.packageName)
244249
}
245250
}
246251

247252
binding.btnAllowBg.setOnClickListener {
248253
if (isForceStopOnly || isCritical) { showProtectedWarning(); return@setOnClickListener }
249-
executeBackgroundAction(getString(R.string.action_allow_bg)) {
254+
executeBackgroundAction(getString(R.string.action_allow_bg), "ALLOW_BACKGROUND") {
250255
policyManager?.allowBackground(appInfo!!.packageName)
251256
}
252257
}
253258

254259
binding.btnClearCache.setOnClickListener {
255260
if (isCritical) { showProtectedWarning(); return@setOnClickListener }
256-
executeActionWithLoading(getString(R.string.action_clear_cache)) {
261+
executeActionWithLoading(getString(R.string.action_clear_cache), {
257262
executor?.execute("pm clear --cache-only ${appInfo!!.packageName}")?.map { }
258-
}
263+
}, "CLEAR_CACHE")
259264
}
260265

261266
binding.btnClearData.setOnClickListener {
262267
if (isCritical) { showProtectedWarning(); return@setOnClickListener }
263-
executeActionWithLoading(getString(R.string.action_clear_data)) {
268+
executeActionWithLoading(getString(R.string.action_clear_data), {
264269
executor?.execute("pm clear ${appInfo!!.packageName}")?.map { }
265-
}
270+
}, "CLEAR_DATA")
266271
}
267272

268273
binding.btnUninstall.setOnClickListener {
269274
if (isForceStopOnly || isCritical) { showProtectedWarning(); return@setOnClickListener }
270-
executeActionWithLoading(getString(R.string.action_uninstall)) {
275+
executeActionWithLoading(getString(R.string.action_uninstall), {
271276
policyManager?.uninstallApp(appInfo!!.packageName)
272-
}
277+
}, "UNINSTALL")
273278
}
274279

275280
binding.btnLaunchApp.setOnClickListener { launchApp() }
@@ -294,7 +299,7 @@ class AppDetailBottomSheet : BottomSheetDialogFragment() {
294299
Toast.makeText(context, R.string.error_protected_app, Toast.LENGTH_SHORT).show()
295300
}
296301

297-
private fun executeActionWithLoading(actionName: String, action: suspend () -> Result<Unit>?) {
302+
private fun executeActionWithLoading(actionName: String, action: suspend () -> Result<Unit>?, logActionName: String? = null) {
298303
if (policyManager == null) {
299304
Toast.makeText(context, R.string.error_mode_required_message, Toast.LENGTH_SHORT).show()
300305
return
@@ -308,7 +313,21 @@ class AppDetailBottomSheet : BottomSheetDialogFragment() {
308313
lifecycleScope.launch {
309314
try {
310315
val result = withContext(Dispatchers.IO) { action() }
311-
if (result?.isSuccess == true) {
316+
val success = result?.isSuccess == true
317+
318+
// Log action
319+
if (logActionName != null && appInfo != null) {
320+
withContext(Dispatchers.IO) {
321+
rollbackManager?.logAction(ActionLog(
322+
action = logActionName,
323+
packages = listOf(appInfo!!.packageName),
324+
success = success,
325+
message = if (success) null else "Failed"
326+
))
327+
}
328+
}
329+
330+
if (success) {
312331
binding.tvActionStatus.text = getString(R.string.action_completed, actionName)
313332
binding.tvActionStatus.setTextColor(resources.getColor(R.color.status_positive, null))
314333
onActionCompleted?.invoke()
@@ -331,7 +350,7 @@ class AppDetailBottomSheet : BottomSheetDialogFragment() {
331350
}
332351
}
333352

334-
private fun executeBackgroundAction(actionName: String, action: suspend () -> Result<Unit>?) {
353+
private fun executeBackgroundAction(actionName: String, logActionName: String, action: suspend () -> Result<Unit>?) {
335354
if (policyManager == null) {
336355
Toast.makeText(context, R.string.error_mode_required_message, Toast.LENGTH_SHORT).show()
337356
return
@@ -345,7 +364,21 @@ class AppDetailBottomSheet : BottomSheetDialogFragment() {
345364
lifecycleScope.launch {
346365
try {
347366
val result = withContext(Dispatchers.IO) { action() }
348-
if (result?.isSuccess == true) {
367+
val success = result?.isSuccess == true
368+
369+
// Log action
370+
if (appInfo != null) {
371+
withContext(Dispatchers.IO) {
372+
rollbackManager?.logAction(ActionLog(
373+
action = logActionName,
374+
packages = listOf(appInfo!!.packageName),
375+
success = success,
376+
message = if (success) null else "Failed"
377+
))
378+
}
379+
}
380+
381+
if (success) {
349382
// Refresh background status
350383
val packageName = appInfo?.packageName ?: return@launch
351384
currentBgStatus = withContext(Dispatchers.IO) {

app/src/main/java/com/appcontrolx/ui/adapter/ActionLogAdapter.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,8 +55,8 @@ class ActionLogAdapter(
5555
binding.tvStatus.setTextColor(context.getColor(R.color.status_negative))
5656
}
5757

58-
// Rollback button - only show for reversible actions
59-
val canRollback = log.action in listOf("FREEZE", "UNFREEZE", "RESTRICT_BACKGROUND", "ALLOW_BACKGROUND")
58+
// Rollback button - only show for RESTRICT_BACKGROUND and FREEZE
59+
val canRollback = log.action in listOf("RESTRICT_BACKGROUND", "FREEZE")
6060
binding.btnRollback.visibility = if (canRollback) View.VISIBLE else View.GONE
6161
binding.btnRollback.setOnClickListener {
6262
onRollbackClick(log)

0 commit comments

Comments
 (0)