@@ -16,6 +16,8 @@ import com.appcontrolx.executor.CommandExecutor
1616import com.appcontrolx.executor.RootExecutor
1717import com.appcontrolx.model.AppInfo
1818import com.appcontrolx.model.ExecutionMode
19+ import com.appcontrolx.rollback.ActionLog
20+ import com.appcontrolx.rollback.RollbackManager
1921import com.appcontrolx.service.BackgroundStatus
2022import com.appcontrolx.service.BatteryPolicyManager
2123import 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 ) {
0 commit comments