This commit is contained in:
sim 2024-11-18 12:40:53 +00:00
parent fb7b7d108d
commit 1bef3ee29e
26 changed files with 89 additions and 103 deletions

4
.editorconfig Normal file
View File

@ -0,0 +1,4 @@
[*.{kt,kts}]
ktlint_code_style = android_studio
ktlint_function_naming_ignore_when_annotated_with=Composable
max_line_length = 140

View File

@ -2,6 +2,7 @@ plugins {
alias(libs.plugins.android.application)
alias(libs.plugins.kotlin.android)
alias(libs.plugins.compose.compiler)
alias(libs.plugins.ktlint)
}
android {

View File

@ -4,8 +4,8 @@ import android.content.ContentValues
import android.content.Context
import android.database.sqlite.SQLiteDatabase
import android.database.sqlite.SQLiteOpenHelper
import org.unifiedpush.distributor.nextpush.services.RegistrationCountCache
import java.util.concurrent.atomic.AtomicReference
import org.unifiedpush.distributor.nextpush.services.RegistrationCountCache
class Database(val context: Context) :
SQLiteOpenHelper(context, DB_NAME, null, DB_VERSION) {

View File

@ -1,6 +1,5 @@
package org.unifiedpush.distributor.nextpush
import android.util.Log
import kotlin.coroutines.coroutineContext
import kotlinx.coroutines.ensureActive
import kotlinx.coroutines.flow.MutableSharedFlow

View File

@ -1,10 +1,10 @@
package org.unifiedpush.distributor.nextpush
import android.content.Context
import java.util.UUID
import org.unifiedpush.distributor.nextpush.Database.Companion.getDb
import org.unifiedpush.distributor.nextpush.api.Api
import org.unifiedpush.distributor.nextpush.utils.FromPushNotification
import java.util.UUID
object LocalNotification {
fun createChannel(context: Context, title: String, block: () -> Unit) {

View File

@ -19,7 +19,7 @@ class WakeLock(context: Context) {
*/
fun acquire() {
Log.d(TAG, "Acquiring WakeLock.")
wakeLock.acquire(10_000L /*10 secs*/)
wakeLock.acquire(10_000L) // 10 secs
}
/**

View File

@ -1,3 +1,5 @@
@file:Suppress("ktlint:standard:no-wildcard-imports")
package org.unifiedpush.distributor.nextpush.account
import android.app.Activity
@ -5,11 +7,11 @@ import android.content.Context
import android.content.Intent
import android.util.Log
import android.widget.Toast
import okhttp3.* // ktlint-disable no-wildcard-imports
import org.unifiedpush.distributor.nextpush.activities.StartActivity
import org.unifiedpush.distributor.nextpush.api.provider.ApiProvider.Companion.mApiEndpoint
import java.io.IOException
import java.util.concurrent.TimeUnit
import okhttp3.*
import org.unifiedpush.distributor.nextpush.activities.StartActivity
import org.unifiedpush.distributor.nextpush.api.provider.ApiProvider.Companion.API_PATH
class DirectAccount(context: Context) : Account<OkHttpClient> {
@ -30,7 +32,7 @@ class DirectAccount(context: Context) : Account<OkHttpClient> {
val request = try {
Request.Builder()
.url("${url}$mApiEndpoint")
.url("${url}$API_PATH")
.build()
} catch (e: IllegalArgumentException) {
Toast.makeText(activity, "Expected URL scheme 'http' or 'https'", Toast.LENGTH_SHORT).show()
@ -54,13 +56,7 @@ class DirectAccount(context: Context) : Account<OkHttpClient> {
})
}
override fun onActivityResult(
activity: Activity,
requestCode: Int,
resultCode: Int,
data: Intent?,
block: (success: Boolean) -> Unit
) {
override fun onActivityResult(activity: Activity, requestCode: Int, resultCode: Int, data: Intent?, block: (success: Boolean) -> Unit) {
block(connected)
}

View File

@ -1,3 +1,5 @@
@file:Suppress("ktlint:standard:no-wildcard-imports")
package org.unifiedpush.distributor.nextpush.account
import android.app.Activity
@ -12,7 +14,7 @@ import android.util.Log
import android.widget.TextView
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import com.nextcloud.android.sso.AccountImporter
import com.nextcloud.android.sso.exceptions.* // ktlint-disable no-wildcard-imports
import com.nextcloud.android.sso.exceptions.*
import com.nextcloud.android.sso.helper.SingleAccountHelper
import com.nextcloud.android.sso.model.SingleSignOnAccount
import com.nextcloud.android.sso.ui.UiExceptionManager
@ -51,13 +53,7 @@ class SSOAccount(val context: Context) : Account<SingleSignOnAccount> {
}
}
override fun onActivityResult(
activity: Activity,
requestCode: Int,
resultCode: Int,
data: Intent?,
block: (success: Boolean) -> Unit
) {
override fun onActivityResult(activity: Activity, requestCode: Int, resultCode: Int, data: Intent?, block: (success: Boolean) -> Unit) {
try {
AccountImporter.onActivityResult(
requestCode,

View File

@ -8,7 +8,6 @@ import android.util.Log
import org.unifiedpush.distributor.nextpush.distributor.EXTRA_PI
class LinkActivity : Activity() {
private val TAG = LinkActivity::class.simpleName
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
intent?.data?.run {
@ -22,4 +21,8 @@ class LinkActivity : Activity() {
} ?: setResult(RESULT_CANCELED)
finish()
}
companion object {
private const val TAG = "LinkActivity"
}
}

View File

@ -83,12 +83,7 @@ fun AppBarUi(viewModel: ViewModel) {
}
@Composable
fun Dropdown(
expanded: Boolean,
actionHandler: (AppAction) -> Unit,
onDismiss: () -> Unit,
onNewChannel: () -> Unit
) {
fun Dropdown(expanded: Boolean, actionHandler: (AppAction) -> Unit, onDismiss: () -> Unit, onNewChannel: () -> Unit) {
DropdownMenu(
expanded = expanded,
onDismissRequest = onDismiss

View File

@ -76,11 +76,7 @@ fun SelectToDeleteBarUi(count: Int = 1, onBack: () -> Unit = {}, onDelete: () ->
@Preview
@Composable
fun UnregisterConfirmationDialog(
count: Int = 1,
onDismissRequest: () -> Unit = {},
onConfirmation: () -> Unit = {}
) {
fun UnregisterConfirmationDialog(count: Int = 1, onDismissRequest: () -> Unit = {}, onConfirmation: () -> Unit = {}) {
AlertDialog(
title = {
Text(stringResource(R.string.dialog_unregistering_title))

View File

@ -1,3 +1,5 @@
@file:Suppress("ktlint:standard:no-wildcard-imports")
package org.unifiedpush.distributor.nextpush.api
import android.content.Context
@ -6,6 +8,8 @@ import android.util.Log
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
import io.reactivex.rxjava3.observers.DisposableObserver
import io.reactivex.rxjava3.schedulers.Schedulers
import java.util.concurrent.TimeUnit
import java.util.concurrent.atomic.AtomicReference
import okhttp3.OkHttpClient
import okhttp3.Request
import okhttp3.sse.EventSource
@ -13,12 +17,10 @@ import okhttp3.sse.EventSources
import org.unifiedpush.distributor.nextpush.AppStore
import org.unifiedpush.distributor.nextpush.account.AccountFactory.getAccount
import org.unifiedpush.distributor.nextpush.account.AccountType
import org.unifiedpush.distributor.nextpush.api.provider.* // ktlint-disable no-wildcard-imports
import org.unifiedpush.distributor.nextpush.api.provider.ApiProvider.Companion.mApiEndpoint
import org.unifiedpush.distributor.nextpush.api.provider.*
import org.unifiedpush.distributor.nextpush.api.provider.ApiProvider.Companion.API_PATH
import org.unifiedpush.distributor.nextpush.api.response.ApiResponse
import org.unifiedpush.distributor.nextpush.utils.NoServerAppNotification
import java.util.concurrent.TimeUnit
import java.util.concurrent.atomic.AtomicReference
class Api(context: Context) {
@ -88,7 +90,7 @@ class Api(context: Context) {
.readTimeout(0, TimeUnit.SECONDS)
.retryOnConnectionFailure(false)
.build()
val url = "$baseUrl${mApiEndpoint}device/$deviceId"
val url = "$baseUrl${API_PATH}device/$deviceId"
val request = Request.Builder().url(url)
.get()
@ -145,11 +147,7 @@ class Api(context: Context) {
}
}
fun apiCreateApp(
appName: String,
vapid: String?,
block: (String?) -> Unit
) {
fun apiCreateApp(appName: String, vapid: String?, block: (String?) -> Unit) {
tryWithDeviceId { deviceId ->
// The unity of connector token must already be checked here
val parameters = mutableMapOf(

View File

@ -4,6 +4,12 @@ import android.content.Context
import android.util.Base64
import android.util.Log
import com.google.gson.Gson
import java.lang.Exception
import java.util.Calendar
import java.util.Timer
import java.util.TimerTask
import java.util.concurrent.atomic.AtomicReference
import kotlin.concurrent.schedule
import okhttp3.Response
import okhttp3.sse.EventSource
import okhttp3.sse.EventSourceListener
@ -22,12 +28,6 @@ import org.unifiedpush.distributor.nextpush.utils.NoStartNotification
import org.unifiedpush.distributor.nextpush.utils.TAG
import org.unifiedpush.distributor.nextpush.utils.containsTokenElseAdd
import org.unifiedpush.distributor.nextpush.utils.removeToken
import java.lang.Exception
import java.util.Calendar
import java.util.Timer
import java.util.TimerTask
import java.util.concurrent.atomic.AtomicReference
import kotlin.concurrent.schedule
class SSEListener(val context: Context) : EventSourceListener() {
@ -184,7 +184,7 @@ class SSEListener(val context: Context) : EventSourceListener() {
!AppCompanion.bufferedResponseChecked.get() &&
!AppCompanion.booting.getAndSet(false)
) {
Timer().schedule(45_000L /* 45secs */) {
Timer().schedule(45_000L) { // 45 secs
if (FailureHandler.newFail(context, eventSource)) {
StartService.stopService()
NoStartNotification(context).showSingle()

View File

@ -3,7 +3,7 @@ package org.unifiedpush.distributor.nextpush.api.provider
import android.content.Context
import org.unifiedpush.distributor.nextpush.account.AccountFactory
import org.unifiedpush.distributor.nextpush.account.DirectAccount
import org.unifiedpush.distributor.nextpush.api.provider.ApiProvider.Companion.mApiEndpoint
import org.unifiedpush.distributor.nextpush.api.provider.ApiProvider.Companion.API_PATH
import retrofit2.Retrofit
import retrofit2.adapter.rxjava3.RxJava3CallAdapterFactory
import retrofit2.converter.gson.GsonConverterFactory
@ -23,7 +23,7 @@ class ApiDirectFactory(val context: Context) : ApiProviderFactory {
.client(client)
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJava3CallAdapterFactory.create())
.baseUrl("$url$mApiEndpoint").build()
.baseUrl("$url$API_PATH").build()
.create(ApiProvider::class.java).let {
block(it) {}
}

View File

@ -10,22 +10,18 @@ import retrofit2.http.Path
interface ApiProvider {
@PUT("device/")
fun createDevice(
@Body subscribeMap: Map<String, String>
): Observable<ApiResponse>?
fun createDevice(@Body subscribeMap: Map<String, String>): Observable<ApiResponse>?
@DELETE("device/{deviceId}")
fun deleteDevice(@Path("deviceId") deviceId: String): Observable<ApiResponse>?
@PUT("app/")
fun createApp(
@Body authorizeMap: Map<String, String>
): Observable<ApiResponse>?
fun createApp(@Body authorizeMap: Map<String, String>): Observable<ApiResponse>?
@DELETE("app/{token}")
fun deleteApp(@Path("token") token: String): Observable<ApiResponse>?
companion object {
const val mApiEndpoint = "/index.php/apps/uppush/"
const val API_PATH = "/index.php/apps/uppush/"
}
}

View File

@ -9,9 +9,6 @@ import org.unifiedpush.distributor.nextpush.account.SSOAccount
import retrofit2.NextcloudRetrofitApiBuilder
class ApiSSOFactory(val context: Context) : ApiProviderFactory {
private val TAG = ApiSSOFactory::class.java.simpleName
override fun getProviderAndExecute(block: (ApiProvider, then: () -> Unit) -> Unit) {
var nextcloudAPI: NextcloudAPI? = null
val account = AccountFactory.getAccount(context) ?: run {
@ -24,7 +21,7 @@ class ApiSSOFactory(val context: Context) : ApiProviderFactory {
override fun onConnected() {
Log.d(TAG, "Api connected.")
nextcloudAPI?.let { nextcloudAPI ->
NextcloudRetrofitApiBuilder(nextcloudAPI, ApiProvider.mApiEndpoint)
NextcloudRetrofitApiBuilder(nextcloudAPI, ApiProvider.API_PATH)
.create(ApiProvider::class.java).let {
block(it) {
nextcloudAPI.close()
@ -44,4 +41,8 @@ class ApiSSOFactory(val context: Context) : ApiProviderFactory {
ssoApiCallback
)
}
companion object {
private const val TAG = "ApiSSOFactory"
}
}

View File

@ -8,7 +8,7 @@ import org.unifiedpush.distributor.nextpush.Database.Companion.getDb
import org.unifiedpush.distributor.nextpush.LocalNotification
import org.unifiedpush.distributor.nextpush.account.AccountFactory.getAccount
import org.unifiedpush.distributor.nextpush.api.Api
import org.unifiedpush.distributor.nextpush.api.provider.ApiProvider.Companion.mApiEndpoint
import org.unifiedpush.distributor.nextpush.api.provider.ApiProvider.Companion.API_PATH
import org.unifiedpush.distributor.nextpush.utils.TAG
/**
@ -49,12 +49,7 @@ object Distributor {
context.sendBroadcast(broadcastIntent)
}
fun sendRegistrationFailed(
context: Context,
application: String,
connectorToken: String,
reason: FailedReason
) {
fun sendRegistrationFailed(context: Context, application: String, connectorToken: String, reason: FailedReason) {
application.ifBlank {
return
}
@ -87,7 +82,7 @@ object Distributor {
fun getEndpoint(context: Context, connectorToken: String): String {
val db = getDb(context)
val appToken = db.getAppToken(connectorToken)
return "${getAccount(context)?.url}${mApiEndpoint}push/$appToken"
return "${getAccount(context)?.url}${API_PATH}push/$appToken"
}
/**

View File

@ -8,12 +8,16 @@ import android.content.Intent
import android.content.ServiceConnection
import android.os.IBinder
import android.util.Log
import kotlinx.coroutines.Runnable
import java.util.concurrent.Executors
import java.util.concurrent.ScheduledFuture
import java.util.concurrent.TimeUnit
import kotlinx.coroutines.Runnable
class RaiseAppToForeground(private val context: Context, private val app: String, private val onUnbound: () -> Unit) : ServiceConnection, Runnable {
class RaiseAppToForeground(
private val context: Context,
private val app: String,
private val onUnbound: () -> Unit
) : ServiceConnection, Runnable {
/**
* Is the service bound ? This is a per service connection
@ -51,10 +55,10 @@ class RaiseAppToForeground(private val context: Context, private val app: String
if (bound) {
Log.w(TAG, "This service connection is already bound to $app. Aborting.")
/**
* Close current scheduledFuture. We interrupt if it is running, so [run] won't
* Close current scheduledFuture. We interrupt if it is running (mayInterruptIfRunning = true), so [run] won't
* unbind this new connection after we release the lock.
*/
scheduledFuture?.cancel(/* mayInterruptIfRunning = */ true)
scheduledFuture?.cancel(true)
/** Call [run] (unbind) in 5 seconds */
scheduledFuture = unbindExecutor.schedule(this, 5L, TimeUnit.SECONDS)
return true

View File

@ -1,3 +1,5 @@
@file:Suppress("ktlint:standard:no-wildcard-imports")
package org.unifiedpush.distributor.nextpush.receivers
import android.app.PendingIntent
@ -8,12 +10,13 @@ import android.os.Build
import android.util.Log
import android.widget.Toast
import androidx.annotation.RequiresApi
import java.lang.Exception
import org.unifiedpush.distributor.nextpush.AppCompanion
import org.unifiedpush.distributor.nextpush.Database.Companion.getDb
import org.unifiedpush.distributor.nextpush.WakeLock
import org.unifiedpush.distributor.nextpush.account.AccountFactory
import org.unifiedpush.distributor.nextpush.activities.UiAction
import org.unifiedpush.distributor.nextpush.distributor.* // ktlint-disable no-wildcard-imports
import org.unifiedpush.distributor.nextpush.distributor.*
import org.unifiedpush.distributor.nextpush.distributor.Distributor.checkRegistration
import org.unifiedpush.distributor.nextpush.distributor.Distributor.createApp
import org.unifiedpush.distributor.nextpush.distributor.Distributor.deleteApp
@ -24,7 +27,6 @@ import org.unifiedpush.distributor.nextpush.utils.appInfoForMetadata
import org.unifiedpush.distributor.nextpush.utils.containsTokenElseAdd
import org.unifiedpush.distributor.nextpush.utils.getApplicationName
import org.unifiedpush.distributor.nextpush.utils.removeToken
import java.lang.Exception
/**
* THIS SERVICE IS USED BY OTHER APPS TO REGISTER
@ -196,7 +198,7 @@ class RegisterBroadcastReceiver : BroadcastReceiver() {
connectorToken: String,
application: String,
vapid: String?,
newRegistration: Boolean = true,
newRegistration: Boolean = true
) {
val appName = context.getApplicationName(application) ?: application
when {

View File

@ -2,13 +2,13 @@ package org.unifiedpush.distributor.nextpush.services
import android.content.Context
import android.util.Log
import java.util.concurrent.atomic.AtomicInteger
import java.util.concurrent.atomic.AtomicReference
import okhttp3.sse.EventSource
import org.unifiedpush.distributor.nextpush.AppCompanion
import org.unifiedpush.distributor.nextpush.utils.DisconnectedNotification
import org.unifiedpush.distributor.nextpush.utils.NoPingNotification
import org.unifiedpush.distributor.nextpush.utils.TAG
import java.util.concurrent.atomic.AtomicInteger
import java.util.concurrent.atomic.AtomicReference
object FailureHandler {
@ -108,7 +108,11 @@ object FailureHandler {
*/
fun hasFailed(orNeverStart: Boolean = true): Boolean {
// nFails > 0 to be sure it is not actually restarting
return if (orNeverStart) { eventSource.get() == null } else { false } || nFails.get() > 0
return if (orNeverStart) {
eventSource.get() == null
} else {
false
} || nFails.get() > 0
}
fun getDebugInfo(): String {

View File

@ -6,11 +6,11 @@ import android.net.ConnectivityManager
import android.net.Network
import android.net.NetworkCapabilities
import android.util.Log
import org.unifiedpush.distributor.nextpush.AppCompanion
import org.unifiedpush.distributor.nextpush.utils.TAG
import java.lang.Exception
import java.util.concurrent.atomic.AtomicBoolean
import java.util.concurrent.atomic.AtomicReference
import org.unifiedpush.distributor.nextpush.AppCompanion
import org.unifiedpush.distributor.nextpush.utils.TAG
class RestartNetworkCallback(val context: Context) : ConnectivityManager.NetworkCallback() {
private val connectivityManager: AtomicReference<ConnectivityManager?> = AtomicReference(null)
@ -22,10 +22,7 @@ class RestartNetworkCallback(val context: Context) : ConnectivityManager.Network
}
}
override fun onCapabilitiesChanged(
network: Network,
networkCapabilities: NetworkCapabilities
) {
override fun onCapabilitiesChanged(network: Network, networkCapabilities: NetworkCapabilities) {
if (networkCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)) {
if (!AppCompanion.hasInternet.getAndSet(true)) {
Log.d(TAG, "Network Capabilities changed")

View File

@ -1,13 +1,15 @@
@file:Suppress("ktlint:standard:no-wildcard-imports")
package org.unifiedpush.distributor.nextpush.services
import android.content.Context
import android.util.Log
import androidx.work.* // ktlint-disable no-wildcard-imports
import androidx.work.*
import java.util.Calendar
import java.util.concurrent.TimeUnit
import org.unifiedpush.distributor.nextpush.AppCompanion
import org.unifiedpush.distributor.nextpush.account.AccountFactory.getAccount
import org.unifiedpush.distributor.nextpush.utils.TAG
import java.util.Calendar
import java.util.concurrent.TimeUnit
private const val UNIQUE_PERIODIC_WORK_TAG = "nextpush::RestartWorker::unique_periodic"
private const val UNIQUE_ONETIME_WORK_TAG = "nextpush::RestartWorker::unique_onetime"

View File

@ -6,6 +6,7 @@ import android.content.Intent
import android.os.Build
import android.os.IBinder
import android.util.Log
import java.util.concurrent.atomic.AtomicReference
import org.unifiedpush.distributor.nextpush.AppCompanion
import org.unifiedpush.distributor.nextpush.WakeLock
import org.unifiedpush.distributor.nextpush.account.AccountFactory.getAccount
@ -13,7 +14,6 @@ import org.unifiedpush.distributor.nextpush.api.Api
import org.unifiedpush.distributor.nextpush.utils.ForegroundNotification
import org.unifiedpush.distributor.nextpush.utils.NOTIFICATION_ID_FOREGROUND
import org.unifiedpush.distributor.nextpush.utils.TAG
import java.util.concurrent.atomic.AtomicReference
class StartService : Service() {

View File

@ -1,9 +1,9 @@
package org.unifiedpush.distributor.nextpush.utils
import java.text.SimpleDateFormat
import org.unifiedpush.distributor.nextpush.AppCompanion
import org.unifiedpush.distributor.nextpush.services.FailureHandler
import org.unifiedpush.distributor.nextpush.services.StartService
import java.text.SimpleDateFormat
fun getDebugInfo(): String {
val date = AppCompanion.lastEventDate?.let {

View File

@ -12,11 +12,11 @@ import android.net.Uri
import android.os.Build
import androidx.core.app.ActivityCompat
import androidx.core.app.NotificationManagerCompat
import java.util.concurrent.atomic.AtomicBoolean
import java.util.concurrent.atomic.AtomicInteger
import org.unifiedpush.distributor.nextpush.R
import org.unifiedpush.distributor.nextpush.activities.MainActivity
import org.unifiedpush.distributor.nextpush.services.RegistrationCountCache
import java.util.concurrent.atomic.AtomicBoolean
import java.util.concurrent.atomic.AtomicInteger
const val NOTIFICATION_ID_FOREGROUND = 51115
private const val NOTIFICATION_ID_WARNING = 51215
@ -62,10 +62,7 @@ open class AppNotification(
}
}
internal fun createNotification(
intent: PendingIntent?,
bigText: Boolean = false
): Notification {
internal fun createNotification(intent: PendingIntent?, bigText: Boolean = false): Notification {
val builder: Notification.Builder =
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
Notification.Builder(

View File

@ -22,7 +22,7 @@ fun MutableList<String>.removeToken(connectorToken: String) {
}
private fun delayRemove(list: MutableList<String>, token: String) {
Timer().schedule(1_000L /* 1sec */) {
Timer().schedule(1_000L) { // 1 sec
list.removeToken(token)
}
}