141 lines
5.3 KiB
Kotlin
141 lines
5.3 KiB
Kotlin
package jp.juggler.subwaytooter.push
|
|
|
|
import android.app.PendingIntent
|
|
import android.content.Context
|
|
import android.content.Intent
|
|
import androidx.work.*
|
|
import jp.juggler.subwaytooter.ActMain
|
|
import jp.juggler.subwaytooter.notification.NotificationChannels
|
|
import jp.juggler.util.coroutine.AppDispatchers
|
|
import jp.juggler.util.data.notEmpty
|
|
import jp.juggler.util.log.LogCategory
|
|
import kotlinx.coroutines.withContext
|
|
import java.util.concurrent.atomic.AtomicLong
|
|
|
|
class PushWorker(appContext: Context, workerParams: WorkerParameters) :
|
|
CoroutineWorker(appContext, workerParams) {
|
|
|
|
companion object {
|
|
private val log = LogCategory("PushWorker")
|
|
|
|
private val ncPushWorker = NotificationChannels.PushWorker
|
|
|
|
const val KEY_ACTION = "action"
|
|
const val KEY_ENDPOINT = "endpoint"
|
|
const val KEY_MESSAGE_ID = "messageId"
|
|
const val KEY_KEEP_ALIVE_MODE = "keepAliveMode"
|
|
|
|
const val ACTION_UP_ENDPOINT = "upEndpoint"
|
|
const val ACTION_MESSAGE = "message"
|
|
const val ACTION_REGISTER_ENDPOINT = "endpointRegister"
|
|
|
|
val timeStartUpEndpoint = AtomicLong(0L)
|
|
val timeEndUpEndpoint = AtomicLong(0L)
|
|
val timeStartRegisterEndpoint = AtomicLong(0L)
|
|
val timeEndRegisterEndpoint = AtomicLong(0L)
|
|
|
|
fun enqueueUpEndpoint(context: Context, endpoint: String) {
|
|
workDataOf(
|
|
KEY_ACTION to ACTION_UP_ENDPOINT,
|
|
KEY_ENDPOINT to endpoint,
|
|
).launchPushWorker(context)
|
|
}
|
|
|
|
fun enqueueRegisterEndpoint(context: Context, keepAliveMode: Boolean = false) {
|
|
workDataOf(
|
|
KEY_ACTION to ACTION_REGISTER_ENDPOINT,
|
|
KEY_KEEP_ALIVE_MODE to keepAliveMode,
|
|
).launchPushWorker(context)
|
|
}
|
|
|
|
fun enqueuePushMessage(context: Context, messageId: Long) {
|
|
workDataOf(
|
|
KEY_ACTION to ACTION_MESSAGE,
|
|
KEY_MESSAGE_ID to messageId,
|
|
).launchPushWorker(context)
|
|
}
|
|
|
|
fun Data.launchPushWorker(context: Context) {
|
|
// EXPEDITED だと制約の種類が限られる
|
|
// すぐ起動してほしいので制約は少なめにする
|
|
val constraints = Constraints.Builder()
|
|
.setRequiredNetworkType(NetworkType.UNMETERED)
|
|
.build()
|
|
|
|
val request = OneTimeWorkRequestBuilder<PushWorker>().apply {
|
|
setExpedited(OutOfQuotaPolicy.RUN_AS_NON_EXPEDITED_WORK_REQUEST)
|
|
setConstraints(constraints)
|
|
setInputData(this@launchPushWorker)
|
|
}
|
|
WorkManager.getInstance(context).enqueue(request.build())
|
|
log.i("enqueued!")
|
|
}
|
|
}
|
|
|
|
override suspend fun doWork(): Result = try {
|
|
createForegroundInfo()?.let { setForegroundAsync(it) }
|
|
withContext(AppDispatchers.IO) {
|
|
val pushRepo = applicationContext.pushRepo
|
|
when (val action = inputData.getString(KEY_ACTION)) {
|
|
ACTION_UP_ENDPOINT -> {
|
|
timeStartUpEndpoint.set(System.currentTimeMillis())
|
|
try {
|
|
val endpoint = inputData.getString(KEY_ENDPOINT)
|
|
?.notEmpty() ?: error("missing endpoint.")
|
|
pushRepo.newUpEndpoint(endpoint)
|
|
} finally {
|
|
timeEndUpEndpoint.set(System.currentTimeMillis())
|
|
}
|
|
}
|
|
ACTION_REGISTER_ENDPOINT -> {
|
|
timeStartRegisterEndpoint.set(System.currentTimeMillis())
|
|
try {
|
|
val keepAliveMode = inputData.getBoolean(KEY_KEEP_ALIVE_MODE, false)
|
|
pushRepo.registerEndpoint(keepAliveMode)
|
|
} finally {
|
|
timeEndRegisterEndpoint.set(System.currentTimeMillis())
|
|
}
|
|
}
|
|
ACTION_MESSAGE -> {
|
|
val messageId = inputData.getLong(KEY_MESSAGE_ID, 0L)
|
|
.takeIf { it != 0L } ?: error("missing message id.")
|
|
pushRepo.updateMessage(messageId)
|
|
}
|
|
else -> error("invalid action $action")
|
|
}
|
|
}
|
|
Result.success()
|
|
} catch (ex: Throwable) {
|
|
log.e(ex, "doWork failed.")
|
|
Result.failure()
|
|
}
|
|
|
|
/**
|
|
* 時々OSに呼ばれる
|
|
* Android 11 moto g31 で発生
|
|
*/
|
|
override suspend fun getForegroundInfo(): ForegroundInfo {
|
|
return createForegroundInfo(force = true)!!
|
|
}
|
|
|
|
private fun createForegroundInfo(force: Boolean = false): ForegroundInfo? {
|
|
val context = applicationContext
|
|
|
|
// 通知タップ時のPendingIntent
|
|
val iTap = Intent(context, ActMain::class.java).apply {
|
|
addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
|
}
|
|
val piTap = PendingIntent.getActivity(
|
|
context,
|
|
ncPushWorker.pircTap,
|
|
iTap,
|
|
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
|
|
)
|
|
return ncPushWorker.createForegroundInfo(
|
|
context,
|
|
piTap = piTap,
|
|
force = force,
|
|
)
|
|
}
|
|
}
|