aboutsummaryrefslogtreecommitdiff
path: root/app/src/main/kotlin/com/pitchedapps/frost/services/UpdateService.kt
blob: 0a528a0fe6e15dd48e6b0c597ce7eccb12b140f7 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
package com.pitchedapps.frost.services

import android.app.job.JobParameters
import android.app.job.JobService
import android.content.Context
import android.support.v4.app.NotificationManagerCompat
import ca.allanwang.kau.kotlin.firstOrNull
import ca.allanwang.kau.utils.string
import com.fasterxml.jackson.databind.JsonNode
import com.fasterxml.jackson.databind.ObjectMapper
import com.pitchedapps.frost.BuildConfig
import com.pitchedapps.frost.R
import com.pitchedapps.frost.facebook.requests.httpClient
import com.pitchedapps.frost.utils.L
import com.pitchedapps.frost.utils.Prefs
import com.pitchedapps.frost.utils.ReleasePrefs
import com.pitchedapps.frost.utils.frostEvent
import okhttp3.Request
import org.jetbrains.anko.doAsync
import org.joda.time.DateTime
import java.util.concurrent.Future

/**
 * Created by Allan Wang on 07/04/18.
 */
data class FrostRelease(val versionName: String,
                        val timestamp: Long,
                        val apk: FrostApkRelease? = null,
                        val category: String = "")

data class FrostApkRelease(val size: Long,
                           val name: String,
                           val url: String,
                           val timestamp: Long,
                           val downloadCount: Long = -1)

object UpdateManager {
    internal fun getLatestGithubRelease(): FrostRelease? {
        try {
            val data = getGithubReleaseJsonV3() ?: return null
            return parseGithubReleaseV3(data)
        } catch (e: Exception) {
            L.e(e) {
                "Failed to get github release"
            }
            return null
        }
    }

    private fun JsonNode.asMillis(): Long = DateTime(asText()).millis

    private fun getGithubReleaseJsonV3(): JsonNode? {
        val mapper = ObjectMapper()
        val response = httpClient.newCall(Request.Builder()
                .url("https://api.github.com/repos/AllanWang/Frost-for-Facebook/releases/latest")
                .get().build()).execute().body()?.string() ?: return null
        return mapper.readTree(response)
    }

    private fun parseGithubReleaseV3(data: JsonNode): FrostRelease? {
        val versionName = data.get("tag_name").asText()
        if (versionName.isEmpty()) return null
        val release = FrostRelease(
                versionName = versionName,
                timestamp = data.get("created_at").asMillis(),
                category = "Github")
        val assets = data.get("assets")
        if (!assets.isArray) return release
        val apkRelease = assets.elements().firstOrNull {
            it.get("content_type").asText().contains("android")
        } ?: return release
        val apk = FrostApkRelease(size = apkRelease.get("size").asLong(),
                name = apkRelease.get("name").asText(),
                url = apkRelease.get("browser_download_url").asText(),
                timestamp = apkRelease.get("updated_at").asMillis(),
                downloadCount = apkRelease.get("download_count").asLong())
        return release.copy(apk = apk)
    }
}

class UpdateService : JobService() {

    private var future: Future<Unit>? = null

    private val startTime = System.currentTimeMillis()

    override fun onStopJob(params: JobParameters?): Boolean {
        val time = System.currentTimeMillis() - startTime
        L.d { "Update service has finished abruptly in $time ms" }
        frostEvent("UpdateTime",
                "Type" to "Service force stop",
                "Duration" to time)
        future?.cancel(true)
        future = null
        return false
    }

    fun finish(params: JobParameters?) {
        val time = System.currentTimeMillis() - startTime
        L.i { "Update service has finished in $time ms" }
        frostEvent("UpdateTime",
                "Type" to "Service",
                "Duration" to time)
        jobFinished(params, false)
        future?.cancel(true)
        future = null
    }

    override fun onStartJob(params: JobParameters?): Boolean {
//        L.i { "Fetching update" }
//        future = doAsync {
//            fetch()
//            finish(params)
//        }
//        return true
        return false
    }

    private fun fetch() {
        val release = UpdateManager.getLatestGithubRelease() ?: return
        val timestamp = release.apk?.timestamp ?: return
        if (ReleasePrefs.lastTimeStamp >= timestamp) return
        ReleasePrefs.lastTimeStamp = timestamp
        if (BuildConfig.VERSION_NAME.contains(release.apk.name)) return
        updateNotification(release)
    }

    private fun updateNotification(release: FrostRelease) {
        val notifBuilder = frostNotification(NOTIF_CHANNEL_UPDATES)
                .setFrostAlert(true, Prefs.notificationRingtone)
                .setContentTitle(string(R.string.frost_name))
                .setContentText(string(R.string.update_notif_message))
        NotificationManagerCompat.from(this).notify(release.versionName.hashCode(), notifBuilder.build())
    }

}

const val UPDATE_PERIODIC_JOB = 7

fun Context.scheduleUpdater(enable: Boolean): Boolean =
        scheduleJob<UpdateService>(UPDATE_PERIODIC_JOB, if (enable) 1440 else -1)

const val UPDATE_JOB_NOW = 6

fun Context.fetchUpdates(): Boolean =
        fetchJob<UpdateService>(UPDATE_JOB_NOW)