Skip to content
Snippets Groups Projects
UpdateChecking.kt 3.31 KiB
Newer Older
package org.futo.inputmethod.updates

import android.app.job.JobInfo
import android.app.job.JobScheduler
import android.content.ComponentName
import android.content.Context
import android.os.Build
import android.util.Log
import androidx.datastore.preferences.core.edit
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import kotlinx.serialization.encodeToString
import kotlinx.serialization.json.Json
import okhttp3.OkHttpClient
import okhttp3.Request
import okhttp3.internal.closeQuietly
import org.futo.inputmethod.latin.uix.dataStore
import org.futo.inputmethod.latin.uix.getSetting
import java.lang.Exception

const val UPDATE_URL = "https://voiceinput.futo.org/SuperSecretKeyboard/keyboard_version"

suspend fun checkForUpdate(): UpdateResult? {
    return withContext(Dispatchers.IO) {
        val httpClient = OkHttpClient()

        val request = Request.Builder().method("GET", null).url(UPDATE_URL).build()

        try {
            val response = httpClient.newCall(request).execute()

            val body = response.body

            val result = if (body != null) {
                val data = body.string().lines()
                body.closeQuietly()

                val latestVersion = data[0].toInt()
                val latestVersionUrl = data[1]
                val latestVersionString = data[2]
                if(latestVersionUrl.startsWith("https://voiceinput.futo.org/") || latestVersionUrl.startsWith("https://keyboard.futo.org/")){
                    UpdateResult(
                        nextVersion = latestVersion,
                        apkUrl = latestVersionUrl,
                        nextVersionString = latestVersionString
                    )
                } else {
                    null
                }
            } else {
                null
            }

            response.closeQuietly()

            result
        } catch (e: Exception) {
            null
        }
    }
}

suspend fun checkForUpdateAndSaveToPreferences(context: Context): Boolean {
    val updateResult = checkForUpdate()
    if(updateResult != null) {
        withContext(Dispatchers.IO) {
            context.dataStore.edit {
                it[LAST_UPDATE_CHECK_RESULT] = Json.encodeToString(updateResult)
            }
        }
        return true
    }

    return false
}

suspend fun retrieveSavedLastUpdateCheckResult(context: Context): UpdateResult? {
    return UpdateResult.fromString(context.getSetting(LAST_UPDATE_CHECK_RESULT, ""))
}

const val JOB_ID: Int = 15782788
fun scheduleUpdateCheckingJob(context: Context) {
    val jobScheduler = context.getSystemService(Context.JOB_SCHEDULER_SERVICE) as JobScheduler

    if(jobScheduler.getPendingJob(JOB_ID) != null) {
        Log.i("UpdateChecking", "Job already scheduled, no need to do anything")
        return
    }

    var jobInfoBuilder = JobInfo.Builder(JOB_ID, ComponentName(context, UpdateCheckingService::class.java))
        .setPeriodic(1000 * 60 * 60 * 24 * 2) // every two days
        .setRequiredNetworkType(JobInfo.NETWORK_TYPE_UNMETERED) // on unmetered Wi-Fi
        .setPersisted(true) // persist after reboots

    // Update checking has minimum priority
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
        jobInfoBuilder = jobInfoBuilder.setPriority(JobInfo.PRIORITY_MIN)
    }

    jobScheduler.schedule(jobInfoBuilder.build())
}