Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Abort ACS operations early (with explanation) if ROM is not supported #1553

Merged
merged 5 commits into from
Jan 22, 2025
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
Original file line number Diff line number Diff line change
Expand Up @@ -31,13 +31,15 @@ import eu.darken.sdmse.appcleaner.core.automation.specs.vivo.VivoSpecs
import eu.darken.sdmse.automation.core.AutomationHost
import eu.darken.sdmse.automation.core.AutomationModule
import eu.darken.sdmse.automation.core.AutomationTask
import eu.darken.sdmse.automation.core.errors.AutomationCompatibilityException
import eu.darken.sdmse.automation.core.errors.ScreenUnavailableException
import eu.darken.sdmse.automation.core.errors.UserCancelledAutomationException
import eu.darken.sdmse.automation.core.finishAutomation
import eu.darken.sdmse.automation.core.specs.AutomationExplorer
import eu.darken.sdmse.automation.core.specs.AutomationSpec
import eu.darken.sdmse.common.ca.CaString
import eu.darken.sdmse.common.ca.toCaString
import eu.darken.sdmse.common.debug.logging.Logging.Priority.ERROR
import eu.darken.sdmse.common.debug.logging.Logging.Priority.INFO
import eu.darken.sdmse.common.debug.logging.Logging.Priority.VERBOSE
import eu.darken.sdmse.common.debug.logging.Logging.Priority.WARN
Expand Down Expand Up @@ -128,6 +130,8 @@ class ClearCacheModule @AssistedInject constructor(

var cancelledByUser = false
val currentUserHandle = userManager2.currentUser().handle
var timeoutCount = 0

for (target in task.targets) {
if (target.userHandle != currentUserHandle) {
throw UnsupportedOperationException("ACS based deletion is not support for other users ($target)")
Expand All @@ -149,13 +153,15 @@ class ClearCacheModule @AssistedInject constructor(
log(TAG, INFO) { "Successfully cleared cache for for $target" }
task.onSuccess(target)
successful.add(target)
increaseProgress()
} catch (e: ScreenUnavailableException) {
log(TAG, WARN) { "Cancelled because screen become unavailable: ${e.asLog()}" }
// TODO We don't have to abort here, but this is not a normal state and should show an error?
throw e
} catch (e: TimeoutCancellationException) {
log(TAG, WARN) { "Timeout while processing $installed" }
failed.add(target)
if (timeoutCount > 2 && successful.isEmpty()) break else timeoutCount++
} catch (e: CancellationException) {
log(TAG, WARN) { "We were cancelled: ${e.asLog()}" }
updateProgressPrimary(eu.darken.sdmse.common.R.string.general_cancel_action)
Expand All @@ -171,8 +177,6 @@ class ClearCacheModule @AssistedInject constructor(
} catch (e: Exception) {
log(TAG, WARN) { "Failure for $target: ${e.asLog()}" }
failed.add(target)
} finally {
increaseProgress()
}
}

Expand All @@ -182,6 +186,11 @@ class ClearCacheModule @AssistedInject constructor(
deviceDetective = deviceDetective,
)

if (timeoutCount != 0 && successful.isEmpty()) {
log(TAG, ERROR) { "Continued timeout errors, no successes so far, possible compatbility issue?" }
throw AutomationCompatibilityException()
}

return ClearCacheTask.Result(
successful = successful,
failed = failed,
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ class StepProcessor @AssistedInject constructor(
progressPub.value = update(progressPub.value)
}

suspend fun process(step: Step): Unit = withTimeout(20 * 1000) {
suspend fun process(step: Step): Unit = withTimeout(step.timeout) {
log(TAG) { "crawl(): $step" }
updateProgressPrimary(step.label)
var attempts = 0
Expand Down Expand Up @@ -236,7 +236,8 @@ class StepProcessor @AssistedInject constructor(
val nodeTest: (suspend (node: AccessibilityNodeInfo) -> Boolean)? = null,
val nodeRecovery: (suspend (node: AccessibilityNodeInfo) -> Boolean)? = null,
val nodeMapping: (suspend (node: AccessibilityNodeInfo) -> AccessibilityNodeInfo)? = null,
val action: (suspend (node: AccessibilityNodeInfo, retryCount: Int) -> Boolean)? = null
val action: (suspend (node: AccessibilityNodeInfo, retryCount: Int) -> Boolean)? = null,
val timeout: Long = 15 * 1000,
) {
override fun toString(): String = "Spec(source=$source, description=$descriptionInternal)"
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package eu.darken.sdmse.automation.core.errors

import eu.darken.sdmse.R
import eu.darken.sdmse.common.ca.toCaString
import eu.darken.sdmse.common.error.HasLocalizedError
import eu.darken.sdmse.common.error.LocalizedError

open class AutomationCompatibilityException(
override val message: String = "SD Maid couldn’t figure out the screen layout. If this keeps happening, your language or setup might not be fully supported. Check for updates or reach out to me so I can fix it."
) : AutomationException(), HasLocalizedError {

override fun getLocalizedError(): LocalizedError = LocalizedError(
throwable = this,
label = R.string.automation_error_no_consent_title.toCaString(),
description = R.string.automation_error_compatibility_body.toCaString(),
)

}
9 changes: 9 additions & 0 deletions app/src/main/java/eu/darken/sdmse/main/ui/MainActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,10 @@ import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen
import dagger.hilt.android.AndroidEntryPoint
import eu.darken.sdmse.R
import eu.darken.sdmse.common.debug.Bugs
import eu.darken.sdmse.common.debug.logging.Logging.Priority.VERBOSE
import eu.darken.sdmse.common.debug.logging.log
import eu.darken.sdmse.common.debug.recorder.core.RecorderModule
import eu.darken.sdmse.common.error.asErrorDialogBuilder
import eu.darken.sdmse.common.navigation.findNavController
import eu.darken.sdmse.common.theming.Theming
import eu.darken.sdmse.common.uix.Activity2
Expand Down Expand Up @@ -56,11 +59,17 @@ class MainActivity : Activity2() {
navController.addOnDestinationChangedListener { _, destination, bundle ->
Bugs.leaveBreadCrumb("Navigated to $destination with args $bundle")
}

vm.errorEvents.observe2 {
log(tag, VERBOSE) { "Error event: $it" }
it.asErrorDialogBuilder(this).show()
}
}

override fun onResume() {
super.onResume()
vm.checkUpgrades()
vm.checkErrors()
}

override fun onSaveInstanceState(outState: Bundle) {
Expand Down
31 changes: 30 additions & 1 deletion app/src/main/java/eu/darken/sdmse/main/ui/MainViewModel.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,24 @@ package eu.darken.sdmse.main.ui

import androidx.lifecycle.SavedStateHandle
import dagger.hilt.android.lifecycle.HiltViewModel
import eu.darken.sdmse.automation.core.errors.AutomationException
import eu.darken.sdmse.common.BuildConfigWrap
import eu.darken.sdmse.common.SingleLiveEvent
import eu.darken.sdmse.common.coroutine.DispatcherProvider
import eu.darken.sdmse.common.debug.logging.Logging.Priority.VERBOSE
import eu.darken.sdmse.common.debug.logging.log
import eu.darken.sdmse.common.debug.logging.logTag
import eu.darken.sdmse.common.uix.ViewModel2
import eu.darken.sdmse.common.upgrade.UpgradeRepo
import eu.darken.sdmse.main.core.SDMTool
import eu.darken.sdmse.main.core.taskmanager.TaskManager
import eu.darken.sdmse.main.core.taskmanager.getLatestTask
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.onEach
import java.time.Duration
import java.time.Instant
import javax.inject.Inject


Expand All @@ -21,14 +28,16 @@ class MainViewModel @Inject constructor(
dispatcherProvider: DispatcherProvider,
@Suppress("unused") private val handle: SavedStateHandle,
private val upgradeRepo: UpgradeRepo,
taskManager: TaskManager,
private val taskManager: TaskManager,
) : ViewModel2(dispatcherProvider = dispatcherProvider) {

private val stateFlow = MutableStateFlow(State())
val state = stateFlow
.onEach { log(VERBOSE) { "New state: $it" } }
.asLiveData2()

val errorEvents = SingleLiveEvent<Throwable>()

private val readyStateInternal = MutableStateFlow(true)
val readyState = readyStateInternal.asLiveData2()

Expand All @@ -45,6 +54,26 @@ class MainViewModel @Inject constructor(
upgradeRepo.refresh()
}

private var handledErrors: Set<String>
get() = handle["handledErrors"] ?: emptySet()
set(value) {
handle["handledErrors"] = value
}

fun checkErrors() = launch {
log(TAG) { "checkErrors()" }
val state = taskManager.state.first()

state.getLatestTask(SDMTool.Type.APPCLEANER)
?.takeIf { !handledErrors.contains(it.id) }
?.takeIf { Duration.between(it.completedAt!!, Instant.now()) < Duration.ofSeconds(10) }
?.let { task ->
val error = task.error as? AutomationException ?: return@let
handledErrors = handledErrors + task.id
errorEvents.postValue(error)
}
}

data class State(
val ready: Boolean = false
)
Expand Down
1 change: 1 addition & 0 deletions app/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -649,6 +649,7 @@
<string name="automation_error_not_running_body">Accessibility service is not running. Try rebooting the device.</string>
<string name="automation_error_screen_unavailable_title">Screen unavailable</string>
<string name="automation_error_screen_unavailable_body">The operation was aborted because the screen became unavailable (e.g. display off or lockscreen active).</string>
<string name="automation_error_compatibility_body">SD Maid couldn’t figure out the screen layout. If this keeps happening, your language or setup might not be fully supported. Check for updates or reach out to me so I can fix it.</string>

<string name="history_label">History</string>
<string name="history_description">A chronological list of recent actions and affected data.</string>
Expand Down
Loading