11package com.github.gotify.init
22
33import android.Manifest
4+ import android.app.AlarmManager
45import android.app.NotificationManager
56import android.content.Context
67import android.content.Intent
8+ import android.net.Uri
79import android.os.Build
810import android.os.Bundle
11+ import androidx.activity.result.contract.ActivityResultContracts.StartActivityForResult
12+ import androidx.annotation.RequiresApi
913import androidx.appcompat.app.AppCompatActivity
14+ import androidx.core.content.ContextCompat
1015import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen
1116import androidx.preference.PreferenceManager
1217import com.github.gotify.NotificationSupport
@@ -34,6 +39,12 @@ internal class InitializationActivity : AppCompatActivity() {
3439 private lateinit var settings: Settings
3540 private var splashScreenActive = true
3641
42+ @RequiresApi(Build .VERSION_CODES .S )
43+ private val activityResultLauncher =
44+ registerForActivityResult(StartActivityForResult ()) {
45+ requestAlarmPermissionOrAuthenticate()
46+ }
47+
3748 override fun onCreate (savedInstanceState : Bundle ? ) {
3849 super .onCreate(savedInstanceState)
3950 Log .init (this )
@@ -54,14 +65,30 @@ internal class InitializationActivity : AppCompatActivity() {
5465 installSplashScreen().setKeepOnScreenCondition { splashScreenActive }
5566
5667 if (settings.tokenExists()) {
57- runWithNeededPermissions {
58- tryAuthenticate()
68+ runWithPostNotificationsPermission {
69+ if (Build .VERSION .SDK_INT > Build .VERSION_CODES .TIRAMISU ) {
70+ // Android 14 and above
71+ requestAlarmPermissionOrAuthenticate()
72+ } else {
73+ // Android 13 and below
74+ tryAuthenticate()
75+ }
5976 }
6077 } else {
6178 showLogin()
6279 }
6380 }
6481
82+ @RequiresApi(Build .VERSION_CODES .S )
83+ private fun requestAlarmPermissionOrAuthenticate () {
84+ val manager = ContextCompat .getSystemService(this , AlarmManager ::class .java)
85+ if (manager?.canScheduleExactAlarms() == true ) {
86+ tryAuthenticate()
87+ } else {
88+ alarmDialog()
89+ }
90+ }
91+
6592 private fun showLogin () {
6693 splashScreenActive = false
6794 startActivity(Intent (this , LoginActivity ::class .java))
@@ -109,6 +136,22 @@ internal class InitializationActivity : AppCompatActivity() {
109136 .show()
110137 }
111138
139+ @RequiresApi(Build .VERSION_CODES .S )
140+ private fun alarmDialog () {
141+ MaterialAlertDialogBuilder (this )
142+ .setMessage(getString(R .string.permissions_alarm_prompt))
143+ .setPositiveButton(getString(R .string.permissions_dialog_grant)) { _, _ ->
144+ Intent (
145+ android.provider.Settings .ACTION_REQUEST_SCHEDULE_EXACT_ALARM ,
146+ Uri .parse(" package:$packageName " )
147+ ).apply {
148+ activityResultLauncher.launch(this )
149+ }
150+ }
151+ .setCancelable(false )
152+ .show()
153+ }
154+
112155 private fun authenticated (user : User ) {
113156 Log .i(" Authenticated as ${user.name} " )
114157
@@ -146,40 +189,30 @@ internal class InitializationActivity : AppCompatActivity() {
146189 .enqueue(Callback .callInUI(this , callback, errorCallback))
147190 }
148191
149- private fun runWithNeededPermissions (action : () -> Unit ) {
150- if (Build .VERSION .SDK_INT >= Build .VERSION_CODES .S ) {
192+ private fun runWithPostNotificationsPermission (action : () -> Unit ) {
193+ if (Build .VERSION .SDK_INT >= Build .VERSION_CODES .TIRAMISU ) {
194+ // Android 13 and above
151195 val quickPermissionsOption = QuickPermissionsOptions (
152196 handleRationale = true ,
153197 handlePermanentlyDenied = true ,
154198 rationaleMethod = { req -> processPermissionRationale(req) },
155199 permissionsDeniedMethod = { req -> processPermissionRationale(req) },
156200 permanentDeniedMethod = { req -> processPermissionsPermanentDenied(req) }
157201 )
158- if (Build .VERSION .SDK_INT >= Build .VERSION_CODES .TIRAMISU ) {
159- // Android 13 and above
160- runWithPermissions(
161- Manifest .permission.SCHEDULE_EXACT_ALARM ,
162- Manifest .permission.POST_NOTIFICATIONS ,
163- options = quickPermissionsOption,
164- callback = action
165- )
166- } else {
167- // Android 12 and Android 12L
168- runWithPermissions(
169- Manifest .permission.SCHEDULE_EXACT_ALARM ,
170- options = quickPermissionsOption,
171- callback = action
172- )
173- }
202+ runWithPermissions(
203+ Manifest .permission.POST_NOTIFICATIONS ,
204+ options = quickPermissionsOption,
205+ callback = action
206+ )
174207 } else {
175- // Android 11 and below
208+ // Android 12 and below
176209 action()
177210 }
178211 }
179212
180213 private fun processPermissionRationale (req : QuickPermissionsRequest ) {
181214 MaterialAlertDialogBuilder (this )
182- .setMessage(getString(R .string.permissions_denied_temp ))
215+ .setMessage(getString(R .string.permissions_notification_denied_temp ))
183216 .setPositiveButton(getString(R .string.permissions_dialog_grant)) { _, _ ->
184217 req.proceed()
185218 }
@@ -189,7 +222,7 @@ internal class InitializationActivity : AppCompatActivity() {
189222
190223 private fun processPermissionsPermanentDenied (req : QuickPermissionsRequest ) {
191224 MaterialAlertDialogBuilder (this )
192- .setMessage(getString(R .string.permissions_denied_permanent ))
225+ .setMessage(getString(R .string.permissions_notification_denied_permanent ))
193226 .setPositiveButton(getString(R .string.permissions_dialog_grant)) { _, _ ->
194227 req.openAppSettings()
195228 }
0 commit comments