Fix exact alarm permission on Android 14 (#298)

This commit is contained in:
Niko Diamadis
2023-06-24 11:25:13 +02:00
committed by GitHub
parent 864967927a
commit 12c21da7b7
2 changed files with 59 additions and 25 deletions

View File

@@ -1,12 +1,17 @@
package com.github.gotify.init package com.github.gotify.init
import android.Manifest import android.Manifest
import android.app.AlarmManager
import android.app.NotificationManager import android.app.NotificationManager
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import android.net.Uri
import android.os.Build import android.os.Build
import android.os.Bundle import android.os.Bundle
import androidx.activity.result.contract.ActivityResultContracts.StartActivityForResult
import androidx.annotation.RequiresApi
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.ContextCompat
import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen
import androidx.preference.PreferenceManager import androidx.preference.PreferenceManager
import com.github.gotify.NotificationSupport import com.github.gotify.NotificationSupport
@@ -34,6 +39,12 @@ internal class InitializationActivity : AppCompatActivity() {
private lateinit var settings: Settings private lateinit var settings: Settings
private var splashScreenActive = true private var splashScreenActive = true
@RequiresApi(Build.VERSION_CODES.S)
private val activityResultLauncher =
registerForActivityResult(StartActivityForResult()) {
requestAlarmPermissionOrAuthenticate()
}
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
Log.init(this) Log.init(this)
@@ -54,14 +65,30 @@ internal class InitializationActivity : AppCompatActivity() {
installSplashScreen().setKeepOnScreenCondition { splashScreenActive } installSplashScreen().setKeepOnScreenCondition { splashScreenActive }
if (settings.tokenExists()) { if (settings.tokenExists()) {
runWithNeededPermissions { runWithPostNotificationsPermission {
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.TIRAMISU) {
// Android 14 and above
requestAlarmPermissionOrAuthenticate()
} else {
// Android 13 and below
tryAuthenticate() tryAuthenticate()
} }
}
} else { } else {
showLogin() showLogin()
} }
} }
@RequiresApi(Build.VERSION_CODES.S)
private fun requestAlarmPermissionOrAuthenticate() {
val manager = ContextCompat.getSystemService(this, AlarmManager::class.java)
if (manager?.canScheduleExactAlarms() == true) {
tryAuthenticate()
} else {
alarmDialog()
}
}
private fun showLogin() { private fun showLogin() {
splashScreenActive = false splashScreenActive = false
startActivity(Intent(this, LoginActivity::class.java)) startActivity(Intent(this, LoginActivity::class.java))
@@ -109,6 +136,22 @@ internal class InitializationActivity : AppCompatActivity() {
.show() .show()
} }
@RequiresApi(Build.VERSION_CODES.S)
private fun alarmDialog() {
MaterialAlertDialogBuilder(this)
.setMessage(getString(R.string.permissions_alarm_prompt))
.setPositiveButton(getString(R.string.permissions_dialog_grant)) { _, _ ->
Intent(
android.provider.Settings.ACTION_REQUEST_SCHEDULE_EXACT_ALARM,
Uri.parse("package:$packageName")
).apply {
activityResultLauncher.launch(this)
}
}
.setCancelable(false)
.show()
}
private fun authenticated(user: User) { private fun authenticated(user: User) {
Log.i("Authenticated as ${user.name}") Log.i("Authenticated as ${user.name}")
@@ -146,8 +189,9 @@ internal class InitializationActivity : AppCompatActivity() {
.enqueue(Callback.callInUI(this, callback, errorCallback)) .enqueue(Callback.callInUI(this, callback, errorCallback))
} }
private fun runWithNeededPermissions(action: () -> Unit) { private fun runWithPostNotificationsPermission(action: () -> Unit) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
// Android 13 and above
val quickPermissionsOption = QuickPermissionsOptions( val quickPermissionsOption = QuickPermissionsOptions(
handleRationale = true, handleRationale = true,
handlePermanentlyDenied = true, handlePermanentlyDenied = true,
@@ -155,31 +199,20 @@ internal class InitializationActivity : AppCompatActivity() {
permissionsDeniedMethod = { req -> processPermissionRationale(req) }, permissionsDeniedMethod = { req -> processPermissionRationale(req) },
permanentDeniedMethod = { req -> processPermissionsPermanentDenied(req) } permanentDeniedMethod = { req -> processPermissionsPermanentDenied(req) }
) )
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
// Android 13 and above
runWithPermissions( runWithPermissions(
Manifest.permission.SCHEDULE_EXACT_ALARM,
Manifest.permission.POST_NOTIFICATIONS, Manifest.permission.POST_NOTIFICATIONS,
options = quickPermissionsOption, options = quickPermissionsOption,
callback = action callback = action
) )
} else { } else {
// Android 12 and Android 12L // Android 12 and below
runWithPermissions(
Manifest.permission.SCHEDULE_EXACT_ALARM,
options = quickPermissionsOption,
callback = action
)
}
} else {
// Android 11 and below
action() action()
} }
} }
private fun processPermissionRationale(req: QuickPermissionsRequest) { private fun processPermissionRationale(req: QuickPermissionsRequest) {
MaterialAlertDialogBuilder(this) MaterialAlertDialogBuilder(this)
.setMessage(getString(R.string.permissions_denied_temp)) .setMessage(getString(R.string.permissions_notification_denied_temp))
.setPositiveButton(getString(R.string.permissions_dialog_grant)) { _, _ -> .setPositiveButton(getString(R.string.permissions_dialog_grant)) { _, _ ->
req.proceed() req.proceed()
} }
@@ -189,7 +222,7 @@ internal class InitializationActivity : AppCompatActivity() {
private fun processPermissionsPermanentDenied(req: QuickPermissionsRequest) { private fun processPermissionsPermanentDenied(req: QuickPermissionsRequest) {
MaterialAlertDialogBuilder(this) MaterialAlertDialogBuilder(this)
.setMessage(getString(R.string.permissions_denied_permanent)) .setMessage(getString(R.string.permissions_notification_denied_permanent))
.setPositiveButton(getString(R.string.permissions_dialog_grant)) { _, _ -> .setPositiveButton(getString(R.string.permissions_dialog_grant)) { _, _ ->
req.openAppSettings() req.openAppSettings()
} }

View File

@@ -46,8 +46,9 @@
<string name="login">Login</string> <string name="login">Login</string>
<string name="check_url">Check URL</string> <string name="check_url">Check URL</string>
<string name="permissions_dialog_grant">Grant</string> <string name="permissions_dialog_grant">Grant</string>
<string name="permissions_denied_temp">Gotify requires permission to display push notifications.</string> <string name="permissions_notification_denied_temp">Gotify requires permission to display push notifications.</string>
<string name="permissions_denied_permanent">Gotify requires permission to display push notifications. Please grant the required permission in the settings.</string> <string name="permissions_notification_denied_permanent">Gotify requires permission to display push notifications. Please grant the required permission in the settings.</string>
<string name="permissions_alarm_prompt">Gotify requires permission to schedule reconnecting after connection is lost.</string>
<string name="gotify_logo">Gotify logo</string> <string name="gotify_logo">Gotify logo</string>
<string name="refresh_all">Refresh all</string> <string name="refresh_all">Refresh all</string>
<string name="logout_confirm">Do you really want to logout?</string> <string name="logout_confirm">Do you really want to logout?</string>