Commit 1c503db0 authored by stopcovid@lunabee.com's avatar stopcovid@lunabee.com
Browse files

Update to 3.1.8

- Fix atomicFile
- Add analytics
parent 59eb56d7
......@@ -24,7 +24,6 @@ import okhttp3.Request
import retrofit2.HttpException
import retrofit2.Response
import java.io.File
import java.io.FileOutputStream
import java.net.HttpURLConnection
@Suppress("BlockingMethodInNonBlockingContext")
......@@ -37,8 +36,9 @@ suspend fun String.saveTo(context: Context, file: File): Boolean {
}.build()
val response = okHttpClient.newCall(request).execute()
if (response.isSuccessful && response.body != null && response.networkResponse?.code != HttpURLConnection.HTTP_NOT_MODIFIED) {
response.body!!.byteStream().use { input ->
val body = response.body
if (response.isSuccessful && body != null && response.networkResponse?.code != HttpURLConnection.HTTP_NOT_MODIFIED) {
body.byteStream().use { input ->
file.outputStream().use { output ->
input.copyTo(output, 4 * 1024)
}
......@@ -47,13 +47,13 @@ suspend fun String.saveTo(context: Context, file: File): Boolean {
} else if (response.networkResponse?.code == HttpURLConnection.HTTP_NOT_MODIFIED) {
true
} else {
throw HttpException(Response.error<Any>(response.body!!, response))
throw HttpException(Response.error<Any>(body!!, response))
}
}
}
@Suppress("BlockingMethodInNonBlockingContext")
suspend fun String.saveTo(context: Context, atomicFile: AtomicFile): FileOutputStream? {
suspend fun String.saveTo(context: Context, atomicFile: AtomicFile, validData: suspend (data: ByteArray) -> Boolean): Boolean {
return withContext(Dispatchers.IO) {
val cacheConfig = CacheConfig(File(context.cacheDir, "http_cache"), 30 * 1024 * 1024)
val okHttpClient = OkHttpClient.getDefaultOKHttpClient(context, this@saveTo, ConfigConstant.SERVER_CERTIFICATE_SHA256, cacheConfig)
......@@ -62,16 +62,29 @@ suspend fun String.saveTo(context: Context, atomicFile: AtomicFile): FileOutputS
}.build()
val response = okHttpClient.newCall(request).execute()
if (response.isSuccessful && response.body != null && response.networkResponse?.code != HttpURLConnection.HTTP_NOT_MODIFIED) {
val fileOutputStream = atomicFile.startWrite()
response.body!!.byteStream().use { input ->
input.copyTo(fileOutputStream, 4 * 1024)
val body = response.body
if (response.isSuccessful && body != null && response.networkResponse?.code != HttpURLConnection.HTTP_NOT_MODIFIED) {
body.use {
val bodyBytes = body.bytes()
val isValid = validData(bodyBytes)
if (isValid) {
val fileOutputStream = atomicFile.startWrite()
try {
bodyBytes.inputStream().use { input ->
input.copyTo(fileOutputStream, 4 * 1024)
}
atomicFile.finishWrite(fileOutputStream)
} catch (e: Exception) {
atomicFile.failWrite(fileOutputStream)
throw e
}
}
}
fileOutputStream
true
} else if (response.networkResponse?.code == HttpURLConnection.HTTP_NOT_MODIFIED) {
null
false
} else {
throw HttpException(Response.error<Any>(response.body!!, response))
throw HttpException(Response.error<Any>(body!!, response))
}
}
}
......
......@@ -38,8 +38,8 @@ android {
applicationId "fr.gouv.android.stopcovid"
minSdkVersion 21
targetSdkVersion 30
versionCode 260
versionName "3.1.7"
versionCode 262
versionName "3.1.8"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
......
......@@ -99,6 +99,7 @@ import java.io.File
import java.util.Calendar
import java.util.Date
import java.util.concurrent.TimeUnit
import kotlin.math.roundToInt
import kotlin.random.Random
import kotlin.time.ExperimentalTime
import kotlin.time.hours
......@@ -306,7 +307,8 @@ class StopCovid : Application(), LifecycleObserver, RobertApplication, Isolation
override fun notifyAtRiskLevelChange() {
RisksLevelManager.getCurrentLevel(robertManager.atRiskStatus?.riskLevel)?.let { riskLevel ->
AnalyticsManager.reportHealthEvent(this, HealthEventName.eh2, null)
AnalyticsManager.reportHealthEvent(this, HealthEventName.eh2, riskLevel.riskLevel.roundToInt().toString())
AnalyticsManager.reportAppEvent(this, AppEventName.e2)
val inputData = Data.Builder()
.putString(AtRiskNotificationWorker.INPUT_DATA_TITLE_KEY, riskLevel.labels.notifTitle)
.putString(AtRiskNotificationWorker.INPUT_DATA_MESSAGE_KEY, riskLevel.labels.notifBody)
......
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*
* Authors
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* Created by Lunabee Studio / Date - 2021/10/6 - for the TOUS-ANTI-COVID project
*/
package com.lunabeestudio.stopcovid.extension
import androidx.core.util.AtomicFile
import java.io.File
// TODO dirty hack to access new data of AtomicFile
val AtomicFile.newFile: File
get() = File(baseFile.path + ".new")
\ No newline at end of file
......@@ -30,7 +30,6 @@ import com.lunabeestudio.stopcovid.extension.currentVaccinationReferenceLatitude
import com.lunabeestudio.stopcovid.extension.currentVaccinationReferenceLongitude
import com.lunabeestudio.stopcovid.extension.hasChosenPostalCode
import com.lunabeestudio.stopcovid.extension.location
import com.lunabeestudio.stopcovid.extension.newFile
import com.lunabeestudio.stopcovid.extension.zipGeolocVersion
import com.lunabeestudio.stopcovid.model.PostalCodeDetails
import com.lunabeestudio.stopcovid.model.VaccinationCenter
......@@ -39,7 +38,6 @@ import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import timber.log.Timber
import java.io.File
import java.io.FileOutputStream
import java.lang.reflect.Type
import kotlin.math.abs
......@@ -85,10 +83,11 @@ object VaccinationCenterManager {
}
private suspend fun initializeCurrentDepartmentIfNeeded(context: Context, sharedPreferences: SharedPreferences) {
if ((
sharedPreferences.currentVaccinationReferenceDepartmentCode == null
|| sharedPreferences.zipGeolocVersion < ZIP_GEOLOC_VERSION
)
if (
(
sharedPreferences.currentVaccinationReferenceDepartmentCode == null
|| sharedPreferences.zipGeolocVersion < ZIP_GEOLOC_VERSION
)
&& sharedPreferences.chosenPostalCode != null
) {
postalCodeDidUpdate(context, sharedPreferences, sharedPreferences.chosenPostalCode)
......@@ -215,7 +214,6 @@ object VaccinationCenterManager {
@SuppressLint("BinaryOperationInTimber")
private suspend fun fetchLast(context: Context, sharedPreferences: SharedPreferences): Boolean {
val atomicLastUpdateFile = AtomicFile(localLastUpdateFile(context, sharedPreferences))
var lastUpdateFileOutPutStream: FileOutputStream? = null
return try {
val previousVaccinationCenterLastUpdate = if (atomicLastUpdateFile.baseFile.exists()) {
......@@ -226,13 +224,13 @@ object VaccinationCenterManager {
} else {
null
}
lastUpdateFileOutPutStream = "${url}${sharedPreferences.currentVaccinationReferenceDepartmentCode}/$lastUpdateFileName".saveTo(
return "$url${sharedPreferences.currentVaccinationReferenceDepartmentCode}/$lastUpdateFileName".saveTo(
context,
atomicLastUpdateFile,
)
if (lastUpdateFileOutPutStream != null) {
) { data ->
val vaccinationCenterLastUpdate = gson.fromJson(
atomicLastUpdateFile.newFile.readText(),
data.decodeToString(),
VaccinationCenterLastUpdate::class.java
)
......@@ -241,54 +239,31 @@ object VaccinationCenterManager {
"Downloaded Sha1 (${vaccinationCenterLastUpdate.sha1}) is different than our file " +
"Sha1 (${previousVaccinationCenterLastUpdate?.sha1}). Let's fetch the new file"
)
val fetched = fetchLastCenters(context, sharedPreferences)
if (!fetched) {
atomicLastUpdateFile.failWrite(lastUpdateFileOutPutStream)
} else {
atomicLastUpdateFile.finishWrite(lastUpdateFileOutPutStream)
}
fetched
fetchLastCenters(context, sharedPreferences)
} else {
Timber.d("Previous Sha1 is the same. No need to fetch new centers.")
atomicLastUpdateFile.failWrite(lastUpdateFileOutPutStream)
false
}
} else {
// No update etag is still valid
false
}
} catch (e: Exception) {
Timber.e(e, "Fetching fail for $lastUpdateFileName")
atomicLastUpdateFile.failWrite(lastUpdateFileOutPutStream)
false
}
}
private suspend fun fetchLastCenters(context: Context, sharedPreferences: SharedPreferences): Boolean {
val atomicCentersFile = AtomicFile(localCentersFile(context, sharedPreferences))
var centersFileOutPutStream: FileOutputStream? = null
return try {
centersFileOutPutStream = "${url}${sharedPreferences.currentVaccinationReferenceDepartmentCode}/$centersFileName".saveTo(
"${url}${sharedPreferences.currentVaccinationReferenceDepartmentCode}/$centersFileName".saveTo(
context,
atomicCentersFile,
)
if (centersFileOutPutStream != null) {
val list = gson.fromJson<List<VaccinationCenter?>>(atomicCentersFile.newFile.readText(), vaccinationCentersType)
if (list.any { it == null }) {
atomicCentersFile.failWrite(centersFileOutPutStream)
false
} else {
atomicCentersFile.finishWrite(centersFileOutPutStream)
true
}
} else {
// No update etag is still valid
false
) { data ->
val list = gson.fromJson<List<VaccinationCenter?>>(data.decodeToString(), vaccinationCentersType)
list.all { it != null }
}
} catch (e: Exception) {
Timber.e(e, "Fetching fail for $centersFileName")
atomicCentersFile.failWrite(centersFileOutPutStream)
false
}
}
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment