233 lines
8.3 KiB
Kotlin
233 lines
8.3 KiB
Kotlin
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
|
|
import com.github.gotify.R
|
|
import com.github.gotify.Settings
|
|
import com.github.gotify.api.ApiException
|
|
import com.github.gotify.api.Callback
|
|
import com.github.gotify.api.Callback.SuccessCallback
|
|
import com.github.gotify.api.ClientFactory
|
|
import com.github.gotify.client.model.User
|
|
import com.github.gotify.client.model.VersionInfo
|
|
import com.github.gotify.log.Log
|
|
import com.github.gotify.log.UncaughtExceptionHandler
|
|
import com.github.gotify.login.LoginActivity
|
|
import com.github.gotify.messages.MessagesActivity
|
|
import com.github.gotify.service.WebSocketService
|
|
import com.github.gotify.settings.ThemeHelper
|
|
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
|
import com.livinglifetechway.quickpermissionskotlin.runWithPermissions
|
|
import com.livinglifetechway.quickpermissionskotlin.util.QuickPermissionsOptions
|
|
import com.livinglifetechway.quickpermissionskotlin.util.QuickPermissionsRequest
|
|
|
|
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)
|
|
val theme = PreferenceManager.getDefaultSharedPreferences(this)
|
|
.getString(getString(R.string.setting_key_theme), getString(R.string.theme_default))!!
|
|
ThemeHelper.setTheme(this, theme)
|
|
|
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
|
NotificationSupport.createForegroundChannel(
|
|
this,
|
|
(this.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager)
|
|
)
|
|
}
|
|
UncaughtExceptionHandler.registerCurrentThread()
|
|
settings = Settings(this)
|
|
Log.i("Entering ${javaClass.simpleName}")
|
|
|
|
installSplashScreen().setKeepOnScreenCondition { splashScreenActive }
|
|
|
|
if (settings.tokenExists()) {
|
|
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))
|
|
finish()
|
|
}
|
|
|
|
private fun tryAuthenticate() {
|
|
ClientFactory.userApiWithToken(settings)
|
|
.currentUser()
|
|
.enqueue(
|
|
Callback.callInUI(
|
|
this,
|
|
onSuccess = Callback.SuccessBody { user -> authenticated(user) },
|
|
onError = { exception -> failed(exception) }
|
|
)
|
|
)
|
|
}
|
|
|
|
private fun failed(exception: ApiException) {
|
|
splashScreenActive = false
|
|
setContentView(R.layout.splash)
|
|
when (exception.code) {
|
|
0 -> {
|
|
dialog(getString(R.string.not_available, settings.url))
|
|
return
|
|
}
|
|
401 -> {
|
|
dialog(getString(R.string.auth_failed))
|
|
return
|
|
}
|
|
}
|
|
|
|
var response = exception.body
|
|
response = response.take(200)
|
|
dialog(getString(R.string.other_error, settings.url, exception.code, response))
|
|
}
|
|
|
|
private fun dialog(message: String) {
|
|
MaterialAlertDialogBuilder(this)
|
|
.setTitle(R.string.oops)
|
|
.setMessage(message)
|
|
.setPositiveButton(R.string.retry) { _, _ -> tryAuthenticate() }
|
|
.setNegativeButton(R.string.logout) { _, _ -> showLogin() }
|
|
.setCancelable(false)
|
|
.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}")
|
|
|
|
settings.setUser(user.name, user.isAdmin)
|
|
requestVersion {
|
|
splashScreenActive = false
|
|
startActivity(Intent(this, MessagesActivity::class.java))
|
|
finish()
|
|
}
|
|
|
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
|
startForegroundService(Intent(this, WebSocketService::class.java))
|
|
} else {
|
|
startService(Intent(this, WebSocketService::class.java))
|
|
}
|
|
}
|
|
|
|
private fun requestVersion(runnable: Runnable) {
|
|
requestVersion(
|
|
callback = Callback.SuccessBody { version: VersionInfo ->
|
|
Log.i("Server version: ${version.version}@${version.buildDate}")
|
|
settings.serverVersion = version.version
|
|
runnable.run()
|
|
},
|
|
errorCallback = { runnable.run() }
|
|
)
|
|
}
|
|
|
|
private fun requestVersion(
|
|
callback: SuccessCallback<VersionInfo>,
|
|
errorCallback: Callback.ErrorCallback
|
|
) {
|
|
ClientFactory.versionApi(settings.url, settings.sslSettings())
|
|
.version
|
|
.enqueue(Callback.callInUI(this, callback, errorCallback))
|
|
}
|
|
|
|
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) }
|
|
)
|
|
runWithPermissions(
|
|
Manifest.permission.POST_NOTIFICATIONS,
|
|
options = quickPermissionsOption,
|
|
callback = action
|
|
)
|
|
} else {
|
|
// Android 12 and below
|
|
action()
|
|
}
|
|
}
|
|
|
|
private fun processPermissionRationale(req: QuickPermissionsRequest) {
|
|
MaterialAlertDialogBuilder(this)
|
|
.setMessage(getString(R.string.permissions_notification_denied_temp))
|
|
.setPositiveButton(getString(R.string.permissions_dialog_grant)) { _, _ ->
|
|
req.proceed()
|
|
}
|
|
.setCancelable(false)
|
|
.show()
|
|
}
|
|
|
|
private fun processPermissionsPermanentDenied(req: QuickPermissionsRequest) {
|
|
MaterialAlertDialogBuilder(this)
|
|
.setMessage(getString(R.string.permissions_notification_denied_permanent))
|
|
.setPositiveButton(getString(R.string.permissions_dialog_grant)) { _, _ ->
|
|
req.openAppSettings()
|
|
}
|
|
.setCancelable(false)
|
|
.show()
|
|
}
|
|
}
|