Skip to content

Commit c1aeb59

Browse files
Various improvements
- Introduced permissions dialog that can be shown by App - Introduce central ExecutorService instance - Add German translation - Improve the mess that was ENFImpl, PPCP and TracingService - Correctly follow the foreground service lifecycle rules
1 parent db152ca commit c1aeb59

28 files changed

+693
-334
lines changed
+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
distributionBase=GRADLE_USER_HOME
22
distributionPath=wrapper/dists
3-
distributionUrl=https\://services.gradle.org/distributions/gradle-6.7-all.zip
3+
distributionUrl=https\://services.gradle.org/distributions/gradle-6.8-all.zip
44
zipStoreBase=GRADLE_USER_HOME
55
zipStorePath=wrapper/dists

sdk/build.gradle

+20-6
Original file line numberDiff line numberDiff line change
@@ -20,14 +20,16 @@ plugins {
2020
apply plugin: 'kotlin-android'
2121
apply plugin: 'org.jetbrains.kotlin.kapt'
2222

23+
version = "0.3.0"
24+
2325
android {
2426
compileSdkVersion 29
2527

2628
defaultConfig {
2729
minSdkVersion 23
2830
targetSdkVersion 29
2931
versionCode 26
30-
versionName "0.2.6"
32+
versionName project.version
3133
testInstrumentationRunnerArgument 'androidx.benchmark.suppressErrors', 'EMULATOR,LOW-BATTERY,ACTIVITY-MISSING,DEBUGGABLE,UNLOCKED,UNSUSTAINED-ACTIVITY-MISSING'
3234
testInstrumentationRunner "androidx.benchmark.junit4.AndroidBenchmarkRunner"
3335

@@ -50,6 +52,10 @@ android {
5052
sourceCompatibility = 1.8
5153
targetCompatibility = 1.8
5254
}
55+
56+
buildFeatures {
57+
viewBinding = true
58+
}
5359
}
5460

5561
protobuf {
@@ -99,12 +105,18 @@ afterEvaluate {
99105
publishing {
100106
publications {
101107
release(MavenPublication) {
102-
from components.release
108+
def component
109+
if (System.getenv('ARTIFACT')) {
110+
component = components.release
111+
} else {
112+
component = components.debug
113+
}
114+
from component
103115
artifact androidSourcesJar
104116

105-
groupId = System.getenv('GROUP')
106-
artifactId = System.getenv('ARTIFACT')
107-
version = System.getenv('VERSION')
117+
groupId = System.getenv('GROUP') ?: 'com.github.CoraLibre'
118+
artifactId = System.getenv('ARTIFACT') ?: 'CoraLibre-android-sdk'
119+
version = System.getenv('VERSION') ?: "${project.version}-SNAPSHOT"
108120
}
109121
}
110122
}
@@ -161,5 +173,7 @@ dependencies {
161173
implementation "androidx.room:room-runtime:$room_version"
162174
kapt "androidx.room:room-compiler:$room_version"
163175

164-
176+
// UI
177+
implementation "androidx.fragment:fragment-ktx:1.2.5"
178+
implementation "androidx.recyclerview:recyclerview:1.1.0"
165179
}

sdk/src/androidTest/AndroidManifest.xml

+15-15
Original file line numberDiff line numberDiff line change
@@ -9,24 +9,24 @@
99
-->
1010

1111
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
12-
xmlns:tools="http://schemas.android.com/tools"
13-
package="org.coralibre.android.sdk.internal">
12+
xmlns:tools="http://schemas.android.com/tools"
13+
package="org.coralibre.android.sdk.internal">
1414

15-
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
16-
<uses-permission android:name="android.permission.INTERNET" />
17-
<uses-permission android:name="android.permission.BLUETOOTH" />
18-
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
19-
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
15+
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
16+
<uses-permission android:name="android.permission.INTERNET" />
17+
<uses-permission android:name="android.permission.BLUETOOTH" />
18+
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
19+
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
2020

21-
<application
22-
android:debuggable="false"
23-
tools:ignore="HardcodedDebugMode"
24-
tools:replace="android:debuggable">
21+
<application
22+
android:debuggable="false"
23+
tools:ignore="HardcodedDebugMode"
24+
tools:replace="android:debuggable">
2525

26-
<service
27-
android:name="org.coralibre.android.sdk.internal.TracingService"
28-
android:foregroundServiceType="location" />
26+
<service
27+
android:name="org.coralibre.android.sdk.internal.TracingService"
28+
android:foregroundServiceType="location|connectedDevice|dataSync" />
2929

30-
</application>
30+
</application>
3131

3232
</manifest>

sdk/src/androidTest/java/org/coralibre/android/sdk/internal/database/DatabaseTests.kt

+36-50
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,6 @@ package org.coralibre.android.sdk.internal.database
33
import androidx.test.ext.junit.runners.AndroidJUnit4
44
import androidx.test.platform.app.InstrumentationRegistry
55
import org.coralibre.android.sdk.DatatypesTestUtil
6-
import org.coralibre.android.sdk.internal.database.DatabaseAccess.getDefaultDatabaseInstance
7-
import org.coralibre.android.sdk.internal.database.DatabaseAccess.init
86
import org.coralibre.android.sdk.internal.datatypes.AssociatedEncryptedMetadata
97
import org.coralibre.android.sdk.internal.datatypes.CapturedData
108
import org.coralibre.android.sdk.internal.datatypes.DiagnosisKey
@@ -14,21 +12,27 @@ import org.coralibre.android.sdk.internal.datatypes.RollingProximityIdentifier
1412
import org.coralibre.android.sdk.internal.datatypes.util.ENIntervalUtil.createFromUnixTimestamp
1513
import org.coralibre.android.sdk.internal.datatypes.util.ENIntervalUtil.currentInterval
1614
import org.coralibre.android.sdk.internal.datatypes.util.ENIntervalUtil.getMidnight
17-
import org.junit.AfterClass
15+
import org.junit.After
1816
import org.junit.Assert.assertArrayEquals
1917
import org.junit.Assert.assertEquals
2018
import org.junit.Before
21-
import org.junit.BeforeClass
2219
import org.junit.Test
2320
import org.junit.runner.RunWith
2421
import java.util.LinkedList
2522
import java.util.Random
2623

2724
@RunWith(AndroidJUnit4::class)
2825
class DatabaseTests {
26+
private lateinit var database: Database
27+
2928
@Before
30-
fun clearData() {
31-
getDefaultDatabaseInstance().clearAllData()
29+
fun initializeDatabase() {
30+
database = PersistentDatabase(InstrumentationRegistry.getInstrumentation().context, true)
31+
}
32+
33+
@After
34+
fun closeDatabase() {
35+
database.close()
3236
}
3337

3438
@Test
@@ -39,11 +43,11 @@ class DatabaseTests {
3943
random.nextBytes(dumTekBytes)
4044
val dumInterval = ENInterval(getMidnight(2000L))
4145
val dumTek = InternalTemporaryExposureKey(dumInterval, dumTekBytes)
42-
getDefaultDatabaseInstance().addGeneratedTEK(dumTek)
46+
database.addGeneratedTEK(dumTek)
4347

4448
// Query:
45-
val resultTeks = getDefaultDatabaseInstance().allOwnTEKs
46-
val resultTekForInterval = getDefaultDatabaseInstance().getOwnTEK(dumInterval)
49+
val resultTeks = database.getAllOwnTEKs()
50+
val resultTekForInterval = database.getOwnTEK(dumInterval)
4751

4852
// Compare:
4953
var numResultTeks = 0
@@ -79,10 +83,10 @@ class DatabaseTests {
7983
),
8084
AssociatedEncryptedMetadata(dumAem)
8185
)
82-
getDefaultDatabaseInstance().addCapturedPayload(dumData)
86+
database.addCapturedPayload(dumData)
8387

8488
// Query:
85-
val resultIntervals = getDefaultDatabaseInstance().allCollectedPayload
89+
val resultIntervals = database.getAllCollectedPayload()
8690

8791
// Compare:
8892
var numResultIntervals = 0
@@ -118,12 +122,12 @@ class DatabaseTests {
118122
val tekRemoveBytes = ByteArray(16)
119123
random.nextBytes(tekRemoveBytes)
120124
val tekRemove = InternalTemporaryExposureKey(intervalRemove, tekRemoveBytes)
121-
getDefaultDatabaseInstance().addGeneratedTEK(tekRemove)
125+
database.addGeneratedTEK(tekRemove)
122126
}
123127
val tekKeepBytes = ByteArray(16)
124128
random.nextBytes(tekKeepBytes)
125129
val tekKeep = InternalTemporaryExposureKey(intervalKeep, tekKeepBytes)
126-
getDefaultDatabaseInstance().addGeneratedTEK(tekKeep)
130+
database.addGeneratedTEK(tekKeep)
127131
run {
128132
val rpiRemove = ByteArray(16)
129133
random.nextBytes(rpiRemove)
@@ -139,7 +143,7 @@ class DatabaseTests {
139143
RollingProximityIdentifier(rpiRemove, createFromUnixTimestamp(timestampRemove)),
140144
AssociatedEncryptedMetadata(aemRemove)
141145
)
142-
getDefaultDatabaseInstance().addCapturedPayload(dataRemove)
146+
database.addCapturedPayload(dataRemove)
143147
}
144148
val rpiKeep = ByteArray(16)
145149
random.nextBytes(rpiKeep)
@@ -155,14 +159,14 @@ class DatabaseTests {
155159
RollingProximityIdentifier(rpiKeep, intervalKeep),
156160
AssociatedEncryptedMetadata(aemKeep)
157161
)
158-
getDefaultDatabaseInstance().addCapturedPayload(dataKeep)
162+
database.addCapturedPayload(dataKeep)
159163

160164
// Truncate:
161-
getDefaultDatabaseInstance().truncateLast14Days()
165+
database.truncateLast14Days()
162166

163167
// Query:
164-
val resultTeks = getDefaultDatabaseInstance().allOwnTEKs
165-
val resultIntervals = getDefaultDatabaseInstance().allCollectedPayload
168+
val resultTeks = database.getAllOwnTEKs()
169+
val resultIntervals = database.getAllCollectedPayload()
166170

167171
// Compare:
168172
var numResultTeks = 0
@@ -190,77 +194,59 @@ class DatabaseTests {
190194

191195
@Test
192196
fun testAddDiagnosisKeys() {
193-
val db = getDefaultDatabaseInstance()
194197
val diagKeys = LinkedList<DiagnosisKey>()
195198
diagKeys.add(DatatypesTestUtil.createDummyDiagnosisKey())
196199
val token0 = "token0"
197-
db.addDiagnosisKeys(token0, diagKeys)
200+
database.addDiagnosisKeys(token0, diagKeys)
198201
diagKeys.add(DatatypesTestUtil.createDummyDiagnosisKey())
199202
diagKeys.add(DatatypesTestUtil.createDummyDiagnosisKey())
200203
val token1 = "token1"
201-
db.addDiagnosisKeys(token1, diagKeys)
204+
database.addDiagnosisKeys(token1, diagKeys)
202205

203206
// First verify that insertion with different tokens works:
204207
run {
205-
val result0 = db.getDiagnosisKeys(token0)
208+
val result0 = database.getDiagnosisKeys(token0)
206209
assertEquals(1, result0.size.toLong())
207-
val result1 = db.getDiagnosisKeys(token1)
210+
val result1 = database.getDiagnosisKeys(token1)
208211
assertEquals(3, result1.size.toLong())
209212
}
210213

211214
// Now add additional keys for an existing token:
212-
db.addDiagnosisKeys(token1, diagKeys)
215+
database.addDiagnosisKeys(token1, diagKeys)
213216
run {
214-
val result0 = db.getDiagnosisKeys(token0)
217+
val result0 = database.getDiagnosisKeys(token0)
215218
assertEquals(1, result0.size.toLong())
216-
val result1 = db.getDiagnosisKeys(token1)
219+
val result1 = database.getDiagnosisKeys(token1)
217220
assertEquals(6, result1.size.toLong())
218221
}
219222
}
220223

221224
@Test
222225
fun testDeleteToken() {
223-
val db = getDefaultDatabaseInstance()
224226
val diagKeys = LinkedList<DiagnosisKey>()
225227
diagKeys.add(DatatypesTestUtil.createDummyDiagnosisKey())
226228
val token0 = "token0"
227-
db.addDiagnosisKeys(token0, diagKeys)
229+
database.addDiagnosisKeys(token0, diagKeys)
228230
diagKeys.add(DatatypesTestUtil.createDummyDiagnosisKey())
229231
diagKeys.add(DatatypesTestUtil.createDummyDiagnosisKey())
230232
val token1 = "token1"
231-
db.addDiagnosisKeys(token1, diagKeys)
233+
database.addDiagnosisKeys(token1, diagKeys)
232234

233235
// Verify insertion worked as expected:
234236
run {
235-
val result0 = db.getDiagnosisKeys(token0)
237+
val result0 = database.getDiagnosisKeys(token0)
236238
assertEquals(1, result0.size.toLong())
237-
val result1 = db.getDiagnosisKeys(token1)
239+
val result1 = database.getDiagnosisKeys(token1)
238240
assertEquals(3, result1.size.toLong())
239241
}
240242

241243
// Now delete token1 and check again:
242-
db.deleteTokenWithData(token1)
244+
database.deleteTokenWithData(token1)
243245
run {
244-
val result0 = db.getDiagnosisKeys(token0)
246+
val result0 = database.getDiagnosisKeys(token0)
245247
assertEquals(1, result0.size.toLong())
246-
val result1 = db.getDiagnosisKeys(token1)
248+
val result1 = database.getDiagnosisKeys(token1)
247249
assertEquals(0, result1.size.toLong())
248250
}
249251
}
250-
251-
companion object {
252-
@BeforeClass
253-
@JvmStatic
254-
fun initGlobal() {
255-
init(InstrumentationRegistry.getInstrumentation().context)
256-
}
257-
258-
@AfterClass
259-
@JvmStatic
260-
fun deInit() {
261-
// If this call is not performed, tests from other classes where the database's init is
262-
// called might not run, since db reinitialization would throw an exception:
263-
DatabaseAccess.deInit()
264-
}
265-
}
266252
}

sdk/src/main/AndroidManifest.xml

+1-2
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@
1919
<uses-permission android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS" />
2020
<uses-permission android:name="android.permission.WAKE_LOCK" />
2121
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
22-
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
2322

2423
<uses-feature
2524
android:name="android.hardware.bluetooth"
@@ -36,7 +35,7 @@
3635
<service
3736
android:name="org.coralibre.android.sdk.internal.TracingService"
3837
android:enabled="true"
39-
android:foregroundServiceType="location" />
38+
android:foregroundServiceType="location|connectedDevice|dataSync" />
4039

4140
<receiver
4241
android:name="org.coralibre.android.sdk.internal.TracingServiceBroadcastReceiver"

sdk/src/main/java/org/coralibre/android/sdk/PPCP.kt

+8-3
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,14 @@ package org.coralibre.android.sdk
1212
import android.content.Context
1313
import android.content.Intent
1414
import android.content.IntentFilter
15+
import android.util.Log
1516
import androidx.core.content.ContextCompat
1617
import org.coralibre.android.sdk.internal.AppConfigManager
1718
import org.coralibre.android.sdk.internal.BroadcastHelper
1819
import org.coralibre.android.sdk.internal.TracingService
1920
import org.coralibre.android.sdk.internal.database.DatabaseAccess
2021

22+
@Deprecated("Use CoraLibre instead")
2123
object PPCP {
2224
private const val TAG = "PPCP Interface"
2325
const val UPDATE_INTENT_ACTION = "org.coralibre.android.sdk.UPDATE_ACTION"
@@ -26,6 +28,7 @@ object PPCP {
2628
@JvmStatic
2729
@Synchronized
2830
fun init(context: Context) {
31+
Log.e(TAG, "Deprecated method has been called", Exception())
2932
if (isInitialized) {
3033
return
3134
}
@@ -60,8 +63,6 @@ object PPCP {
6063
appConfigManager.isReceivingEnabled = receive
6164
val intent = Intent(context, TracingService::class.java)
6265
.setAction(TracingService.ACTION_START)
63-
.putExtra(TracingService.EXTRA_ADVERTISE, advertise)
64-
.putExtra(TracingService.EXTRA_RECEIVE, receive)
6566
ContextCompat.startForegroundService(context, intent)
6667
BroadcastHelper.sendUpdateBroadcast(context)
6768
}
@@ -87,10 +88,14 @@ object PPCP {
8788

8889
@JvmStatic
8990
val updateIntentFilter: IntentFilter
90-
get() = IntentFilter(UPDATE_INTENT_ACTION)
91+
get() {
92+
Log.e(TAG, "Deprecated method has been called", Exception())
93+
return IntentFilter(UPDATE_INTENT_ACTION)
94+
}
9195

9296
@JvmStatic
9397
fun clearData(context: Context, onDeleteListener: Runnable?) {
98+
Log.e(TAG, "Deprecated method has been called", Exception())
9499
checkInit()
95100
val appConfigManager = AppConfigManager.getInstance(context)
96101
check(!(appConfigManager.isAdvertisingEnabled || appConfigManager.isReceivingEnabled)) { "Tracking must be stopped for clearing the local data" }

0 commit comments

Comments
 (0)