Skip to content

Commit

Permalink
Fix exact alarm permission on Android 14 (#298)
Browse files Browse the repository at this point in the history
  • Loading branch information
cyb3rko committed Jun 24, 2023
1 parent 8649679 commit 12c21da
Show file tree
Hide file tree
Showing 2 changed files with 59 additions and 25 deletions.
Original file line number Diff line number Diff line change
@@ -1,12 +1,17 @@
package com.github.gotify.init

import android.Manifest
import android.app.AlarmManager
import android.app.NotificationManager
import android.content.Context
import android.content.Intent
import android.net.Uri
import android.os.Build
import android.os.Bundle
import androidx.activity.result.contract.ActivityResultContracts.StartActivityForResult
import androidx.annotation.RequiresApi
import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.ContextCompat
import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen
import androidx.preference.PreferenceManager
import com.github.gotify.NotificationSupport
Expand Down Expand Up @@ -34,6 +39,12 @@ internal class InitializationActivity : AppCompatActivity() {
private lateinit var settings: Settings
private var splashScreenActive = true

@RequiresApi(Build.VERSION_CODES.S)
private val activityResultLauncher =
registerForActivityResult(StartActivityForResult()) {
requestAlarmPermissionOrAuthenticate()
}

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
Log.init(this)
Expand All @@ -54,14 +65,30 @@ internal class InitializationActivity : AppCompatActivity() {
installSplashScreen().setKeepOnScreenCondition { splashScreenActive }

if (settings.tokenExists()) {
runWithNeededPermissions {
tryAuthenticate()
runWithPostNotificationsPermission {
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.TIRAMISU) {
// Android 14 and above
requestAlarmPermissionOrAuthenticate()
} else {
// Android 13 and below
tryAuthenticate()
}
}
} else {
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() {
splashScreenActive = false
startActivity(Intent(this, LoginActivity::class.java))
Expand Down Expand Up @@ -109,6 +136,22 @@ internal class InitializationActivity : AppCompatActivity() {
.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) {
Log.i("Authenticated as ${user.name}")

Expand Down Expand Up @@ -146,40 +189,30 @@ internal class InitializationActivity : AppCompatActivity() {
.enqueue(Callback.callInUI(this, callback, errorCallback))
}

private fun runWithNeededPermissions(action: () -> Unit) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
private fun runWithPostNotificationsPermission(action: () -> Unit) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
// Android 13 and above
val quickPermissionsOption = QuickPermissionsOptions(
handleRationale = true,
handlePermanentlyDenied = true,
rationaleMethod = { req -> processPermissionRationale(req) },
permissionsDeniedMethod = { req -> processPermissionRationale(req) },
permanentDeniedMethod = { req -> processPermissionsPermanentDenied(req) }
)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
// Android 13 and above
runWithPermissions(
Manifest.permission.SCHEDULE_EXACT_ALARM,
Manifest.permission.POST_NOTIFICATIONS,
options = quickPermissionsOption,
callback = action
)
} else {
// Android 12 and Android 12L
runWithPermissions(
Manifest.permission.SCHEDULE_EXACT_ALARM,
options = quickPermissionsOption,
callback = action
)
}
runWithPermissions(
Manifest.permission.POST_NOTIFICATIONS,
options = quickPermissionsOption,
callback = action
)
} else {
// Android 11 and below
// Android 12 and below
action()
}
}

private fun processPermissionRationale(req: QuickPermissionsRequest) {
MaterialAlertDialogBuilder(this)
.setMessage(getString(R.string.permissions_denied_temp))
.setMessage(getString(R.string.permissions_notification_denied_temp))
.setPositiveButton(getString(R.string.permissions_dialog_grant)) { _, _ ->
req.proceed()
}
Expand All @@ -189,7 +222,7 @@ internal class InitializationActivity : AppCompatActivity() {

private fun processPermissionsPermanentDenied(req: QuickPermissionsRequest) {
MaterialAlertDialogBuilder(this)
.setMessage(getString(R.string.permissions_denied_permanent))
.setMessage(getString(R.string.permissions_notification_denied_permanent))
.setPositiveButton(getString(R.string.permissions_dialog_grant)) { _, _ ->
req.openAppSettings()
}
Expand Down
5 changes: 3 additions & 2 deletions app/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,9 @@
<string name="login">Login</string>
<string name="check_url">Check URL</string>
<string name="permissions_dialog_grant">Grant</string>
<string name="permissions_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_temp">Gotify requires permission to display push notifications.</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="refresh_all">Refresh all</string>
<string name="logout_confirm">Do you really want to logout?</string>
Expand Down

0 comments on commit 12c21da

Please sign in to comment.