Commit 59eb56d7 authored by stopcovid@lunabee.com's avatar stopcovid@lunabee.com
Browse files

Update to 3.1.7

- Use Etag for better cache handling
- Widget figures
- Covid+ duration from config
parent 00f9b8f5
......@@ -10,7 +10,6 @@
apply plugin: 'com.android.library'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'
apply plugin: 'kotlin-kapt'
apply plugin: 'com.google.protobuf'
......@@ -41,8 +40,6 @@ android {
}
}
kotlinOptions.jvmTarget = JavaVersion.VERSION_1_8.toString()
lintOptions {
disable "GradleDependency"
}
......@@ -65,4 +62,4 @@ dependencies {
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:_'
implementation project(path: ':domain')
}
\ No newline at end of file
}
......@@ -25,9 +25,11 @@ fun TimestampedEvent.toProto(): ProtoStorage.TimestampedEventProto {
fun List<TimestampedEvent>.toProto(): ProtoStorage.TimestampedEventProtoList {
val builder = ProtoStorage.TimestampedEventProtoList.newBuilder().apply {
this.addAllTimestampedEventProtoList(map {
it.toProto()
})
this.addAllTimestampedEventProtoList(
map {
it.toProto()
}
)
}
return builder.build()
}
......
......@@ -31,7 +31,8 @@ import com.lunabeestudio.analytics.model.HealthEventName
import com.lunabeestudio.analytics.model.HealthInfos
import com.lunabeestudio.analytics.model.TimestampedEvent
import com.lunabeestudio.analytics.network.AnalyticsServerManager
import com.lunabeestudio.analytics.network.model.SendAnalyticsRQ
import com.lunabeestudio.analytics.network.model.SendAppAnalyticsRQ
import com.lunabeestudio.analytics.network.model.SendHealthAnalyticsRQ
import com.lunabeestudio.analytics.proto.ProtoStorage
import com.lunabeestudio.analytics.proxy.AnalyticsInfosProvider
import com.lunabeestudio.analytics.proxy.AnalyticsRobertManager
......@@ -155,7 +156,7 @@ object AnalyticsManager : LifecycleObserver {
val appInfos = getAppInfos(context, analyticsInfosProvider, receivedHelloMessagesCount)
val appEvents = getAppEvents(context)
val appErrors = getErrors(context.filesDir)
val sendAnalyticsRQ = SendAnalyticsRQ(
val sendAnalyticsRQ = SendAppAnalyticsRQ(
installationUuid = getSharedPrefs(context).installationUUID ?: UUID.randomUUID().toString(),
infos = appInfos,
events = appEvents.toAPI(),
......@@ -194,7 +195,7 @@ object AnalyticsManager : LifecycleObserver {
) {
val healthInfos = getHealthInfos(context, robertManager, analyticsInfosProvider)
val healthEvents = getHealthEvents(context)
val sendAnalyticsRQ = SendAnalyticsRQ(
val sendAnalyticsRQ = SendHealthAnalyticsRQ(
installationUuid = UUID.randomUUID().toString(),
infos = healthInfos,
events = healthEvents.toAPI(),
......@@ -292,7 +293,7 @@ object AnalyticsManager : LifecycleObserver {
if (getSharedPrefs(context).isOptIn) {
if (desc?.contains("No address associated with hostname") != true) {
CoroutineScope(Dispatchers.IO).launch {
val name = "ERR-${wsName.toUpperCase(Locale.getDefault())}-${wsVersion.toUpperCase(Locale.getDefault())}-$errorCode"
val name = "ERR-${wsName.uppercase(Locale.getDefault())}-${wsVersion.uppercase(Locale.getDefault())}-$errorCode"
val timestampedEventList = getErrors(filesDir).toMutableList()
timestampedEventList += TimestampedEvent(name, dateFormat.format(Date()), desc ?: "")
val file = File(File(filesDir, FOLDER_NAME), FILE_NAME_APP_ERRORS)
......
......@@ -10,7 +10,8 @@
package com.lunabeestudio.analytics.network
import com.lunabeestudio.analytics.network.model.SendAnalyticsRQ
import com.lunabeestudio.analytics.network.model.SendAppAnalyticsRQ
import com.lunabeestudio.analytics.network.model.SendHealthAnalyticsRQ
import okhttp3.ResponseBody
import retrofit2.Response
import retrofit2.http.Body
......@@ -22,9 +23,15 @@ import retrofit2.http.Query
internal interface AnalyticsApi {
@POST("api/{apiVersion}/analytics")
suspend fun sendAnalytics(
suspend fun sendAppAnalytics(
@Path("apiVersion") apiVersion: String,
@Body body: SendAnalyticsRQ,
@Body body: SendAppAnalyticsRQ,
): Response<ResponseBody>
@POST("api/{apiVersion}/analytics")
suspend fun sendHealthAnalytics(
@Path("apiVersion") apiVersion: String,
@Body body: SendHealthAnalyticsRQ,
): Response<ResponseBody>
@DELETE("api/{apiVersion}/analytics")
......
......@@ -16,6 +16,8 @@ import com.lunabeestudio.analytics.BuildConfig
import com.lunabeestudio.analytics.manager.AnalyticsManager
import com.lunabeestudio.analytics.model.AnalyticsResult
import com.lunabeestudio.analytics.network.model.SendAnalyticsRQ
import com.lunabeestudio.analytics.network.model.SendAppAnalyticsRQ
import com.lunabeestudio.analytics.network.model.SendHealthAnalyticsRQ
import okhttp3.CertificatePinner
import okhttp3.ConnectionSpec
import okhttp3.HttpUrl.Companion.toHttpUrl
......@@ -38,34 +40,36 @@ internal object AnalyticsServerManager {
return Retrofit.Builder()
.baseUrl(baseUrl)
.addConverterFactory(MoshiConverterFactory.create())
.client(OkHttpClient.Builder().apply {
if (!BuildConfig.DEBUG) {
val requireTls12 = ConnectionSpec.Builder(ConnectionSpec.RESTRICTED_TLS)
.tlsVersions(TlsVersion.TLS_1_2)
.build()
connectionSpecs(listOf(requireTls12))
}
if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.N) {
certificatePinner(
CertificatePinner.Builder()
.add(
baseUrl.toHttpUrl().host,
certificateSha256
)
.client(
OkHttpClient.Builder().apply {
if (!BuildConfig.DEBUG) {
val requireTls12 = ConnectionSpec.Builder(ConnectionSpec.RESTRICTED_TLS)
.tlsVersions(TlsVersion.TLS_1_2)
.build()
)
val certificates: HandshakeCertificates = HandshakeCertificates.Builder()
.addTrustedCertificate(certificateFromString(context, "analytics_api_tousanticovid_gouv_fr"))
.build()
sslSocketFactory(certificates.sslSocketFactory(), certificates.trustManager)
}
addInterceptor(getDefaultHeaderInterceptor(token))
addInterceptor(getLogInterceptor())
callTimeout(30L, TimeUnit.SECONDS)
connectTimeout(30L, TimeUnit.SECONDS)
readTimeout(30L, TimeUnit.SECONDS)
writeTimeout(30L, TimeUnit.SECONDS)
}.build())
connectionSpecs(listOf(requireTls12))
}
if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.N) {
certificatePinner(
CertificatePinner.Builder()
.add(
baseUrl.toHttpUrl().host,
certificateSha256
)
.build()
)
val certificates: HandshakeCertificates = HandshakeCertificates.Builder()
.addTrustedCertificate(certificateFromString(context, "analytics_api_tousanticovid_gouv_fr"))
.build()
sslSocketFactory(certificates.sslSocketFactory(), certificates.trustManager)
}
addInterceptor(getDefaultHeaderInterceptor(token))
addInterceptor(getLogInterceptor())
callTimeout(30L, TimeUnit.SECONDS)
connectTimeout(30L, TimeUnit.SECONDS)
readTimeout(30L, TimeUnit.SECONDS)
writeTimeout(30L, TimeUnit.SECONDS)
}.build()
)
.build()
.create(AnalyticsApi::class.java)
}
......@@ -80,7 +84,16 @@ internal object AnalyticsServerManager {
sendAnalyticsRQ: SendAnalyticsRQ
): AnalyticsResult {
return try {
val result = getRetrofit(context, baseUrl, certificateSha256, token).sendAnalytics(apiVersion, sendAnalyticsRQ)
val result = when (sendAnalyticsRQ) {
is SendAppAnalyticsRQ -> getRetrofit(context, baseUrl, certificateSha256, token).sendAppAnalytics(
apiVersion,
sendAnalyticsRQ
)
is SendHealthAnalyticsRQ -> getRetrofit(context, baseUrl, certificateSha256, token).sendHealthAnalytics(
apiVersion,
sendAnalyticsRQ
)
}
if (result.isSuccessful) {
AnalyticsResult.Success()
} else {
......@@ -145,4 +158,4 @@ internal object AnalyticsServerManager {
private fun getLogInterceptor(): HttpLoggingInterceptor = HttpLoggingInterceptor { message -> Timber.v(message) }.apply {
level = HttpLoggingInterceptor.Level.BODY
}
}
\ No newline at end of file
}
......@@ -10,12 +10,28 @@
package com.lunabeestudio.analytics.network.model
import com.lunabeestudio.analytics.model.AppInfos
import com.lunabeestudio.analytics.model.HealthInfos
import com.lunabeestudio.analytics.model.Infos
import com.lunabeestudio.analytics.model.TimestampedEvent
class SendAnalyticsRQ(
sealed class SendAnalyticsRQ(
val installationUuid: String,
val infos: Infos,
val events: List<TimestampedEventRQ>,
val errors: List<TimestampedEventRQ>
)
\ No newline at end of file
val errors: List<TimestampedEventRQ>,
) {
abstract val infos: Infos
}
class SendAppAnalyticsRQ(
installationUuid: String,
override val infos: AppInfos,
events: List<TimestampedEventRQ>,
errors: List<TimestampedEventRQ>
) : SendAnalyticsRQ(installationUuid, events, errors)
class SendHealthAnalyticsRQ(
installationUuid: String,
override val infos: HealthInfos,
events: List<TimestampedEventRQ>,
errors: List<TimestampedEventRQ>
) : SendAnalyticsRQ(installationUuid, events, errors)
\ No newline at end of file
......@@ -10,9 +10,6 @@
package com.lunabeestudio.analytics.network.model
import com.lunabeestudio.analytics.model.Infos
import com.lunabeestudio.analytics.model.TimestampedEvent
class TimestampedEventRQ(
var name: String,
var timestamp: String,
......
......@@ -9,7 +9,6 @@
*/
apply plugin: 'com.android.library'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'
android {
compileSdkVersion 30
......@@ -22,11 +21,6 @@ android {
buildConfigField 'String', 'BLE_VERSION', '"2.2.0"'
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8.toString()
targetCompatibility JavaVersion.VERSION_1_8.toString()
}
kotlinOptions {
freeCompilerArgs += [
"-Xuse-experimental=kotlinx.coroutines.ExperimentalCoroutinesApi"
......
......@@ -63,7 +63,6 @@ enum class ProximityNotificationEventId(val category: Category) {
BLE_PROXIMITY_NOTIFICATION_FACTORY(PROXIMITY_NOTIFICATION);
enum class Category {
/**
* BLE advertising error
......@@ -85,6 +84,4 @@ enum class ProximityNotificationEventId(val category: Category) {
*/
PROXIMITY_NOTIFICATION
}
}
\ No newline at end of file
......@@ -37,8 +37,11 @@ import kotlin.coroutines.CoroutineContext
/**
* ProximityNotification foreground service.
*/
abstract class ProximityNotificationService : Service(),
ProximityNotificationCallback, ProximityPayloadProvider, ProximityPayloadIdProvider,
abstract class ProximityNotificationService :
Service(),
ProximityNotificationCallback,
ProximityPayloadProvider,
ProximityPayloadIdProvider,
ProximityNotificationLogger.Listener,
CoroutineScope {
......@@ -212,7 +215,6 @@ abstract class ProximityNotificationService : Service(),
ProximityNotificationEventId.PROXIMITY_NOTIFICATION_RESTART,
"Restart Proximity Notification - success"
)
} catch (t: Throwable) {
ProximityNotificationLogger.error(
ProximityNotificationEventId.PROXIMITY_NOTIFICATION_RESTART,
......@@ -226,18 +228,17 @@ abstract class ProximityNotificationService : Service(),
cause = "Restart failed (throwable = $t)"
)
)
} finally {
restartInProgress.set(false)
}
}
private fun registerBluetoothBroadcastReceiver() {
bluetoothRestartInProgress.set(false)
bluetoothStateBroadcastReceiver = BluetoothStateBroadcastReceiver(
onBluetoothDisabled = { onBluetoothDisabled() },
onBluetoothEnabled = { onBluetoothEnabled() })
onBluetoothEnabled = { onBluetoothEnabled() }
)
.also {
applicationContext.registerReceiver(
it,
......@@ -343,7 +344,6 @@ abstract class ProximityNotificationService : Service(),
)
return true
} catch (t: Throwable) {
ProximityNotificationLogger.error(
ProximityNotificationEventId.PROXIMITY_NOTIFICATION_RESTART_BLUETOOTH,
......@@ -352,7 +352,6 @@ abstract class ProximityNotificationService : Service(),
)
return false
} finally {
withContext(NonCancellable) {
......@@ -363,7 +362,6 @@ abstract class ProximityNotificationService : Service(),
registerBluetoothBroadcastReceiver()
bluetoothRestartInProgress.set(false)
}
}
}
......@@ -406,7 +404,4 @@ abstract class ProximityNotificationService : Service(),
* @return Notification used to display foreground service
*/
abstract fun buildForegroundServiceNotification(): Notification
}
......@@ -37,6 +37,4 @@ data class ProximityPayload(val data: ByteArray) {
override fun hashCode(): Int {
return data.contentHashCode()
}
}
\ No newline at end of file
......@@ -29,7 +29,4 @@ interface ProximityPayloadIdProvider {
* @return [ProximityPayloadId] extracted or null if not found
*/
suspend fun fromProximityPayload(proximityPayload: ProximityPayload): ProximityPayloadId?
}
......@@ -39,7 +39,4 @@ internal class ProximityPayloadIdProviderWithCache(
return proximityPayloadId
}
}
......@@ -34,7 +34,6 @@ data class BlePayload(
private const val SIZE = PROXIMITY_PAYLOAD_SIZE + VERSION_SIZE + TX_POWER_LEVEL_SIZE
fun from(data: ByteArray): BlePayload {
require(data.size >= SIZE) { "Expecting a byte array of $SIZE bytes. Got ${data.size}." }
......
......@@ -107,7 +107,3 @@ internal abstract class BleProximityNotification(
calibratedRssi = calibratedRssi
)
}
......@@ -101,7 +101,8 @@ internal class BleProximityNotificationWithAdvertiser(
)
)
}
})
}
)
}
private suspend fun startGattServer() {
......@@ -187,25 +188,26 @@ internal class BleProximityNotificationWithAdvertiser(
}
private suspend fun doStartScanner() = withContext(coroutineContextProvider.main) {
bleScanner.start(callback = object : BleScanner.Callback {
override fun onResult(results: List<BleScannedDevice>) {
checkAndHandleScanResults(results)
}
bleScanner.start(
callback = object : BleScanner.Callback {
override fun onResult(results: List<BleScannedDevice>) {
checkAndHandleScanResults(results)
}
override fun onError(errorCode: Int) {
bleScanner.stop()
override fun onError(errorCode: Int) {
bleScanner.stop()
notifyErrorAsync(
ProximityNotificationError(
ProximityNotificationError.Type.BLE_SCANNER,
errorCode
notifyErrorAsync(
ProximityNotificationError(
ProximityNotificationError.Type.BLE_SCANNER,
errorCode
)
)
)
}
}
})
)
}
override suspend fun handleScanResults(results: List<BleScannedDevice>) {
withContext(coroutineContextProvider.default) {
results.forEach { scannedDevice ->
......@@ -223,7 +225,6 @@ internal class BleProximityNotificationWithAdvertiser(
}
}
private suspend fun stopAdvertiser() = withContext(coroutineContextProvider.main) {
bleAdvertiser.stop()
}
......@@ -235,8 +236,4 @@ internal class BleProximityNotificationWithAdvertiser(
private suspend fun stopScanner() = withContext(coroutineContextProvider.main) {
bleScanner.stop()
}
}
......@@ -49,7 +49,6 @@ import kotlin.coroutines.resume
import kotlin.coroutines.resumeWithException
import kotlin.math.roundToInt
private data class BleScannerException(
val errorCode: Int? = null,
override val cause: Throwable? = null
......@@ -158,7 +157,6 @@ internal class BleProximityNotificationWithoutAdvertiser(
deviceStatsProvider = { deviceStatsRepository?.get(it) },
payloadIdProvider = proximityPayloadIdProvider
)
}
override suspend fun start() {
......@@ -221,7 +219,6 @@ internal class BleProximityNotificationWithoutAdvertiser(
cause = "Advertise job failed (throwable = $t)"
)
)
} finally {
withContext(NonCancellable) {
......@@ -390,7 +387,6 @@ internal class BleProximityNotificationWithoutAdvertiser(
rxCompensationGain = settings.rxCompensationGain
)
/**
* Scan for devices having service UUID.
*/
......@@ -448,7 +444,6 @@ internal class BleProximityNotificationWithoutAdvertiser(
}
afterFirstScanAction(results)
} catch (_: CancellationException) {
null
} catch (t: Throwable) {
......@@ -466,14 +461,12 @@ internal class BleProximityNotificationWithoutAdvertiser(
)
)
}
} finally {
withContext(coroutineContextProvider.main + NonCancellable) {
bleScanner.stop()
}
}
}
}
/**
......@@ -579,5 +572,4 @@ internal class BleDeviceStatsRepository(maxCacheSize: Int, cacheTimeout: Long) {
val deviceStats = deviceStatsCache[deviceId] ?: BleDeviceStats()
deviceStatsCache.put(deviceId, updater(deviceStats))
}
}
......@@ -21,4 +21,3 @@ internal data class BleRecord(
val txPowerLevel: Int
get() = payload.txPowerLevel
}
......@@ -65,5 +65,4 @@ internal class BleRecordProviderForScanWithoutPayload(
lastPayloadByDeviceAddress.takeIf(cleanUpPredicate)?.cleanUp()
lastScanByDeviceAddress.takeIf(cleanUpPredicate)?.cleanUp()
}
}
\ No newline at end of file
......@@ -134,4 +134,3 @@ private data class DeviceScansById(
val timestamp: Long by lazy { mostRecentScan.timestamp.time }
val timestampBracket: Long by lazy { timestamp / 200 }
}
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