feat(setup/permissions): display over other apps

This commit is contained in:
rhunk
2023-10-14 15:07:01 +02:00
parent b92589fa07
commit 2b0e4ad09a
3 changed files with 89 additions and 61 deletions

View File

@ -6,5 +6,5 @@
-keep class org.jf.dexlib2.** { *; } -keep class org.jf.dexlib2.** { *; }
-keep class org.mozilla.javascript.** { *; } -keep class org.mozilla.javascript.** { *; }
-keep class androidx.compose.material.icons.** { *; } -keep class androidx.compose.material.icons.** { *; }
-keep class androidx.navigation.compose.** { *; } -keep class androidx.navigation.** { *; }
-keep class me.rhunk.snapenhance.** { *; } -keep class me.rhunk.snapenhance.** { *; }

View File

@ -17,7 +17,11 @@ import androidx.compose.material3.Button
import androidx.compose.material3.Icon import androidx.compose.material3.Icon
import androidx.compose.material3.OutlinedCard import androidx.compose.material3.OutlinedCard
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.runtime.* import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.mutableStateMapOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
@ -25,6 +29,12 @@ import kotlinx.coroutines.launch
import me.rhunk.snapenhance.ui.setup.screens.SetupScreen import me.rhunk.snapenhance.ui.setup.screens.SetupScreen
import me.rhunk.snapenhance.ui.util.ActivityLauncherHelper import me.rhunk.snapenhance.ui.util.ActivityLauncherHelper
data class PermissionData(
val translationKey: String,
val isPermissionGranted: () -> Boolean,
val requestPermission: (PermissionData) -> Unit,
)
class PermissionsScreen : SetupScreen() { class PermissionsScreen : SetupScreen() {
private lateinit var activityLauncherHelper: ActivityLauncherHelper private lateinit var activityLauncherHelper: ActivityLauncherHelper
@ -53,27 +63,73 @@ class PermissionsScreen : SetupScreen() {
@SuppressLint("BatteryLife") @SuppressLint("BatteryLife")
@Composable @Composable
override fun Content() { override fun Content() {
var notificationPermissionGranted by remember { mutableStateOf(true) }
var isBatteryOptimisationIgnored by remember { mutableStateOf(false) }
val coroutineScope = rememberCoroutineScope() val coroutineScope = rememberCoroutineScope()
val grantedPermissions = remember {
if (isBatteryOptimisationIgnored && notificationPermissionGranted) { mutableStateMapOf<String, Boolean>()
allowNext(true) }
} else { val permissions = remember {
allowNext(false) listOf(
PermissionData(
translationKey = "notification_access",
isPermissionGranted = {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
context.androidContext.checkSelfPermission(Manifest.permission.POST_NOTIFICATIONS) == PackageManager.PERMISSION_GRANTED
} else {
true
}
},
requestPermission = { perm ->
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
activityLauncherHelper.requestPermission(Manifest.permission.POST_NOTIFICATIONS) { resultCode, _ ->
coroutineScope.launch {
grantedPermissions[perm.translationKey] = resultCode == ComponentActivity.RESULT_OK
}
}
}
}
),
PermissionData(
translationKey = "battery_optimization",
isPermissionGranted = {
val powerManager =
context.androidContext.getSystemService(Context.POWER_SERVICE) as PowerManager
powerManager.isIgnoringBatteryOptimizations(context.androidContext.packageName)
},
requestPermission = { perm ->
activityLauncherHelper.launch(Intent().apply {
action = Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS
data = Uri.parse("package:${context.androidContext.packageName}")
}) { resultCode, _ ->
coroutineScope.launch {
grantedPermissions[perm.translationKey] = resultCode == 0
}
}
}
),
PermissionData(
translationKey = "display_over_other_apps",
isPermissionGranted = {
Settings.canDrawOverlays(context.androidContext)
},
requestPermission = { perm ->
activityLauncherHelper.launch(Intent().apply {
action = Settings.ACTION_MANAGE_OVERLAY_PERMISSION
data = Uri.parse("package:${context.androidContext.packageName}")
}) { resultCode, _ ->
coroutineScope.launch {
grantedPermissions[perm.translationKey] = resultCode == 0
}
}
}
)
)
} }
allowNext(permissions.all { perm -> grantedPermissions[perm.translationKey] == true })
LaunchedEffect(Unit) { LaunchedEffect(Unit) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { permissions.forEach { perm ->
notificationPermissionGranted = grantedPermissions[perm.translationKey] = perm.isPermissionGranted()
context.androidContext.checkSelfPermission(Manifest.permission.POST_NOTIFICATIONS) == PackageManager.PERMISSION_GRANTED
}
val powerManager =
context.androidContext.getSystemService(Context.POWER_SERVICE) as PowerManager
isBatteryOptimisationIgnored =
powerManager.isIgnoringBatteryOptimizations(context.androidContext.packageName)
if (isBatteryOptimisationIgnored && notificationPermissionGranted) {
goNext()
} }
} }
@ -88,52 +144,23 @@ class PermissionsScreen : SetupScreen() {
modifier = Modifier modifier = Modifier
.padding(all = 16.dp), .padding(all = 16.dp),
) { ) {
Row( permissions.forEach { perm ->
verticalAlignment = Alignment.CenterVertically, Row(
) { verticalAlignment = Alignment.CenterVertically,
DialogText( ) {
text = context.translation["setup.permissions.notification_access"], DialogText(
modifier = Modifier.weight(1f) text = context.translation["setup.permissions.${perm.translationKey}"],
) modifier = Modifier.weight(1f)
if (notificationPermissionGranted) { )
GrantedIcon() if (grantedPermissions[perm.translationKey] == true) {
} else { GrantedIcon()
RequestButton { } else {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { RequestButton {
activityLauncherHelper.requestPermission(Manifest.permission.POST_NOTIFICATIONS) { resultCode, _ -> perm.requestPermission(perm)
coroutineScope.launch {
notificationPermissionGranted =
resultCode == ComponentActivity.RESULT_OK
}
}
} }
} }
} }
} }
Row(
verticalAlignment = Alignment.CenterVertically,
) {
DialogText(
text = context.translation["setup.permissions.battery_optimization"],
modifier = Modifier.weight(1f)
)
if (isBatteryOptimisationIgnored) {
GrantedIcon()
} else {
RequestButton {
activityLauncherHelper.launch(Intent().apply {
action = Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS
data = Uri.parse("package:${context.androidContext.packageName}")
}) { resultCode, _ ->
coroutineScope.launch {
isBatteryOptimisationIgnored = resultCode == 0
}
}
}
}
}
} }
} }
} }

View File

@ -16,6 +16,7 @@
"dialog": "To continue you need to fit the following requirements:", "dialog": "To continue you need to fit the following requirements:",
"notification_access": "Notification Access", "notification_access": "Notification Access",
"battery_optimization": "Battery Optimization", "battery_optimization": "Battery Optimization",
"display_over_other_apps": "Display Over Other Apps",
"request_button": "Request" "request_button": "Request"
} }
}, },