Skip to content

Commit

Permalink
Merge pull request #236 from DP-3T/develop
Browse files Browse the repository at this point in the history
Version 2.1.0
  • Loading branch information
simonroesch authored Mar 11, 2021
2 parents feaf563 + b375ef2 commit 648079e
Show file tree
Hide file tree
Showing 37 changed files with 984 additions and 1,305 deletions.
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
# Changelog for DP3T-SDK Android

## version 2.1.0 (11.03.2021)

- Removed logic for next-day-upload for the TEK of the reporting day. With this change, you must **make sure that Google configured EN for your country/app to always release the last TEK directly with a shortened rolling period**.
- Refactored Workers to Kotlin CoroutineWorkers for better handling of blocking EN API calls
- Added DP3TKotlin class with suspend function to send fake infected request
- Added flag to enable **federation gateway** sync: by default flag is not set, can be configured to be explicitly true or false
- SignatureException is now a subclass of IOException

## version 2.0.2 (22.01.2021)

Expand Down
2 changes: 1 addition & 1 deletion calibration-app/app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ dependencies {
implementation 'androidx.appcompat:appcompat:1.1.0'
implementation 'androidx.core:core:1.2.0'
implementation 'androidx.fragment:fragment:1.2.4'
implementation 'androidx.work:work-runtime:2.3.4'
implementation 'androidx.work:work-runtime:2.5.0'

implementation 'com.squareup.retrofit2:retrofit:2.8.1'
implementation 'com.squareup.retrofit2:converter-gson:2.8.1'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -271,7 +271,7 @@ private void updateSdkStatus() {
boolean isRunning = status.isTracingEnabled();
buttonStartStopTracing.setSelected(isRunning);
buttonStartStopTracing.setText(getString(isRunning ? R.string.button_tracing_stop
: R.string.button_tracing_start));
: R.string.button_tracing_start));
buttonStartStopTracing.setOnClickListener(v -> {
if (isRunning) {
DP3T.stop(v.getContext());
Expand Down Expand Up @@ -308,7 +308,9 @@ private void updateSdkStatus() {
Button buttonReportFake = view.findViewById(R.id.home_button_report_fake);
buttonReportFake.setOnClickListener(
v -> {
DP3T.sendFakeInfectedRequest(getContext(), null, null, null);
DP3T.sendFakeInfectedRequest(getContext(), null,
() -> Toast.makeText(context, "Fake request sent successfully!", Toast.LENGTH_LONG).show(),
() -> Toast.makeText(context, "Sending fake request failed!", Toast.LENGTH_LONG).show());
});
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -189,26 +189,26 @@ public static void executeAndUploadMatching(Context context, Experiment experime
HashMap<String, ExposureResult> resultMap = new HashMap<>();
List<ExposureWindow> oldExposureWindows = null;
try {
oldExposureWindows = googleExposureClient.getExposureWindows();
oldExposureWindows = googleExposureClient.getExposureWindowsBlocking();
} catch (Exception e) {
e.printStackTrace();
}
for (Experiment.Device device : experiment.devices) {
try {
ArrayList<File> fileList = new ArrayList<>();
fileList.add(device.file);
googleExposureClient.provideDiagnosisKeys(fileList);
googleExposureClient.provideDiagnosisKeysBlocking(fileList);
String token = experiment.name + "_" + device.name + "_" + new DayDate().formatAsString();
//noinspection deprecation
googleExposureClient.provideDiagnosisKeys(fileList,
googleExposureClient.provideDiagnosisKeysBlocking(fileList,
new ExposureConfiguration.ExposureConfigurationBuilder()
.setDurationAtAttenuationThresholds(
appConfigManager.getAttenuationThresholdLow(),
appConfigManager.getAttenuationThresholdMedium())
.build(),
token);
Thread.sleep(2000);
List<ExposureWindow> newExposureWindows = googleExposureClient.getExposureWindows();
List<ExposureWindow> newExposureWindows = googleExposureClient.getExposureWindowsBlocking();
Iterator<ExposureWindow> iterator = newExposureWindows.iterator();
while (iterator.hasNext()) {
if (oldExposureWindows.contains(iterator.next())) {
Expand All @@ -217,10 +217,10 @@ public static void executeAndUploadMatching(Context context, Experiment experime
}
oldExposureWindows.addAll(newExposureWindows);
ExposureResult result = new ExposureResult();
result.deviceCalibrationConfidence = googleExposureClient.getCalibrationConfidence();
result.deviceCalibrationConfidence = googleExposureClient.getCalibrationConfidenceBlocking();
result.exposureWindows = newExposureWindows;
//noinspection deprecation
result.exposureSummary = googleExposureClient.getExposureSummary(token);
result.exposureSummary = googleExposureClient.getExposureSummaryBlocking(token);
resultMap.put(device.getName(), result);
} catch (Exception e) {
e.printStackTrace();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ private void uploadKeys() {
ProgressDialog progressDialog = new ProgressDialog(getContext());
progressDialog.show();
GaenRequest exposeeListRequest =
new GaenRequest(temporaryExposureKeys, DateUtil.getCurrentRollingStartNumber());
new GaenRequest(temporaryExposureKeys, DateUtil.getCurrentRollingStartNumber(), null);
new BackendCalibrationReportRepository(requireContext())
.addGaenExposee(exposeeListRequest, name,
new ResponseCallback<Void>() {
Expand Down
4 changes: 4 additions & 0 deletions calibration-app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,16 @@
// Top-level build file where you can add configuration options common to all sub-projects/modules.

buildscript {
ext {
kotlinVersion = '1.4.31'
}
repositories {
google()
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:4.1.0'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlinVersion"
classpath 'com.jfrog.bintray.gradle:gradle-bintray-plugin:1.8.5'
}
}
Expand Down
4 changes: 4 additions & 0 deletions dp3t-sdk/build.gradle
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
// Top-level build file where you can add configuration options common to all sub-projects/modules.

buildscript {
ext {
kotlinVersion = '1.4.31'
}
repositories {
google()
maven {
Expand All @@ -10,6 +13,7 @@ buildscript {
}
dependencies {
classpath 'com.android.tools.build:gradle:4.0.1'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlinVersion"
classpath 'com.jfrog.bintray.gradle:gradle-bintray-plugin:1.8.5'
classpath 'com.google.protobuf:protobuf-gradle-plugin:0.8.12'
}
Expand Down
16 changes: 10 additions & 6 deletions dp3t-sdk/sdk/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,10 @@

plugins {
id 'com.android.library'
id 'kotlin-android'
id 'maven-publish'
id 'com.jfrog.bintray'
id "org.sonarqube" version "2.8"
id 'org.sonarqube' version '2.8'
}

android {
Expand All @@ -21,8 +22,8 @@ android {
defaultConfig {
minSdkVersion 23
targetSdkVersion 30
versionCode 202
versionName "2.0.2"
versionCode 210
versionName "2.1.0"
testInstrumentationRunnerArgument 'androidx.benchmark.suppressErrors', 'EMULATOR,LOW-BATTERY,ACTIVITY-MISSING,DEBUGGABLE,UNLOCKED,UNSUSTAINED-ACTIVITY-MISSING'
testInstrumentationRunner "androidx.benchmark.junit4.AndroidBenchmarkRunner"

Expand Down Expand Up @@ -124,9 +125,11 @@ dependencies {
compileOnly fileTree(dir: 'libs', include: ['*.jar', '*.aar'])
androidTestImplementation fileTree(dir: 'libs', include: ['*.jar', '*.aar'])

implementation 'androidx.core:core:1.3.2'
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlinVersion"

implementation 'androidx.core:core-ktx:1.3.2'
implementation 'androidx.security:security-crypto:1.0.0-rc03'
implementation 'androidx.work:work-runtime:2.5.0-beta02'
implementation 'androidx.work:work-runtime-ktx:2.5.0'

implementation 'com.squareup.retrofit2:retrofit:2.9.0'
implementation 'com.squareup.retrofit2:converter-gson:2.9.0'
Expand All @@ -140,12 +143,13 @@ dependencies {

implementation 'com.google.android.gms:play-services-tasks:17.2.0'
implementation 'com.google.android.gms:play-services-base:17.5.0'
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-play-services:1.4.1'

testImplementation 'junit:junit:4.13.1'

androidTestImplementation 'androidx.benchmark:benchmark-junit4:1.0.0'
androidTestImplementation 'androidx.test.ext:junit:1.1.2'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'
androidTestImplementation 'com.squareup.okhttp3:mockwebserver:3.14.7'
androidTestImplementation 'androidx.work:work-testing:2.4.0'
androidTestImplementation 'androidx.work:work-testing:2.5.0'
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
public class JwtsTest {

@Test(expected = SignatureException.class)
public void verifyExpired() throws NoSuchAlgorithmException, InvalidKeySpecException {
public void verifyExpired() throws NoSuchAlgorithmException, InvalidKeySpecException, SignatureException {
String jws = "eyJhbGciOiJFUzI1NiJ9.eyJjb250ZW50LWhhc2giOiJsTzd3TDBkOFl5MFBSaU" +
"w5NGhUa2txMkRXNUxXVjlPNi9zRWNZVDJHZ2t3PSIsImhhc2gtYWxnIjoic2hhLTI1Ni" +
"IsImlzcyI6ImRwM3QiLCJpYXQiOjE1ODgwODk2MDAsImV4cCI6MTU4OTkwNDAwMCwiYm" +
Expand All @@ -44,7 +44,7 @@ public void verifyExpired() throws NoSuchAlgorithmException, InvalidKeySpecExcep
}

@Test(expected = SignatureException.class)
public void verifyInvalidSignature() throws NoSuchAlgorithmException, InvalidKeySpecException {
public void verifyInvalidSignature() throws NoSuchAlgorithmException, InvalidKeySpecException, SignatureException {
String jws = "eyJhbGciOiJFUzI1NiJ9.eyJjb250ZW50LWhhc2giOiJsTzd3TDBkOFl5MFBSaU" +
"w5NGhUa2txMkRXNUxXVjlPNi9zRWNZVDJHZ2t3PSIsImhhc2gtYWxnIjoic2hhLTI1Ni" +
"IsImlzcyI6ImRwM3QiLCJpYXQiOjE1ODgwODk2MDAsImV4cCI6MTU4OTkwNDAwMCwiYm" +
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.platform.app.InstrumentationRegistry;
import androidx.work.Configuration;
import androidx.work.WorkInfo;
import androidx.work.WorkManager;
import androidx.work.impl.utils.SynchronousExecutor;
import androidx.work.testing.WorkManagerTestInitHelper;

Expand All @@ -22,6 +24,7 @@
import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.TimeZone;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.atomic.AtomicLong;

import com.google.android.gms.nearby.exposurenotification.ExposureWindow;
Expand All @@ -34,6 +37,7 @@
import org.dpppt.android.sdk.internal.backend.ProxyConfig;
import org.dpppt.android.sdk.internal.logger.LogLevel;
import org.dpppt.android.sdk.internal.logger.Logger;
import org.dpppt.android.sdk.internal.nearby.ExposureWindowMatchingWorker;
import org.dpppt.android.sdk.internal.nearby.GaenStateHelper;
import org.dpppt.android.sdk.internal.nearby.GoogleExposureClient;
import org.dpppt.android.sdk.internal.nearby.TestGoogleExposureClient;
Expand Down Expand Up @@ -118,7 +122,7 @@ public MockResponse dispatch(RecordedRequest request) {

for (int i = 0; i < 21 + 24; i++) {
try {
new SyncWorker.SyncImpl(context, time.get()).doSync();
new SyncWorker.SyncImpl(context, time.get()).doSyncBlocking();
} catch (Exception e) {
e.printStackTrace();
}
Expand Down Expand Up @@ -146,7 +150,7 @@ public MockResponse dispatch(RecordedRequest request) {
});

for (int i = 0; i < 480; i++) {
new SyncWorker.SyncImpl(context, time.get()).doSync();
new SyncWorker.SyncImpl(context, time.get()).doSyncBlocking();
time.set(time.get() + 1 * 60 * 60 * 1000l);
}

Expand All @@ -171,19 +175,19 @@ public MockResponse dispatch(RecordedRequest request) {
});

//8am
new SyncWorker.SyncImpl(context, time.get()).doSync();
new SyncWorker.SyncImpl(context, time.get()).doSyncBlocking();

//3am +1
time.set(time.get() + 19 * 60 * 60 * 1000l);
new SyncWorker.SyncImpl(context, time.get()).doSync();
new SyncWorker.SyncImpl(context, time.get()).doSyncBlocking();

//7am +1
time.set(time.get() + 4 * 60 * 60 * 1000l);
new SyncWorker.SyncImpl(context, time.get()).doSync();
new SyncWorker.SyncImpl(context, time.get()).doSyncBlocking();

//7pm +1
time.set(time.get() + 12 * 60 * 60 * 1000l);
new SyncWorker.SyncImpl(context, time.get()).doSync();
new SyncWorker.SyncImpl(context, time.get()).doSyncBlocking();

assertEquals(4, testGoogleExposureClient.getProvideDiagnosisKeysCounter());
}
Expand All @@ -198,12 +202,12 @@ public MockResponse dispatch(RecordedRequest request) {
}
});

new SyncWorker.SyncImpl(context, time.get()).doSync();
new SyncWorker.SyncImpl(context, time.get()).doSyncBlocking();
assertEquals(0, testGoogleExposureClient.getProvideDiagnosisKeysCounter());
}

@Test
public void testExposure() {
public void testExposure() throws ExecutionException, InterruptedException {
TestGoogleExposureClient.ExposureTestParameters params = new TestGoogleExposureClient.ExposureTestParameters();
params.exposureWindows = new ArrayList<>();
ArrayList<ScanInstance> scanInstances = new ArrayList<>();
Expand All @@ -227,7 +231,7 @@ public void testExposure() {
}

@Test
public void testExposureNotLongEnough() {
public void testExposureNotLongEnough() throws ExecutionException, InterruptedException {
TestGoogleExposureClient.ExposureTestParameters params = new TestGoogleExposureClient.ExposureTestParameters();
params.exposureWindows = new ArrayList<>();
ArrayList<ScanInstance> scanInstances = new ArrayList<>();
Expand Down Expand Up @@ -258,7 +262,7 @@ public void testExposureNotLongEnough() {
}

@Test
public void testExposureTooLongAgo() {
public void testExposureTooLongAgo() throws ExecutionException, InterruptedException {
TestGoogleExposureClient.ExposureTestParameters params = new TestGoogleExposureClient.ExposureTestParameters();
params.exposureWindows = new ArrayList<>();
ArrayList<ScanInstance> scanInstances = new ArrayList<>();
Expand All @@ -282,7 +286,7 @@ public void testExposureTooLongAgo() {
}

@Test
public void testExposureTooLongAgoWithChangedPeriod() {
public void testExposureTooLongAgoWithChangedPeriod() throws ExecutionException, InterruptedException {

DP3T.setNumberOfDaysToConsiderForExposure(context, 12);

Expand All @@ -309,7 +313,7 @@ public void testExposureTooLongAgoWithChangedPeriod() {
}

@Test
public void testExposureLongAgoWithChangedPeriod() {
public void testExposureLongAgoWithChangedPeriod() throws ExecutionException, InterruptedException {

DP3T.setNumberOfDaysToConsiderForExposure(context, 14);

Expand All @@ -335,7 +339,8 @@ public void testExposureLongAgoWithChangedPeriod() {
assertEquals(InfectionStatus.EXPOSED, status.getInfectionStatus());
}

private void testExposure(TestGoogleExposureClient.ExposureTestParameters params) {
private void testExposure(TestGoogleExposureClient.ExposureTestParameters params)
throws ExecutionException, InterruptedException {
AtomicLong time = new AtomicLong(yesterdayAt8am());
server.setDispatcher(new Dispatcher() {
@Override
Expand All @@ -349,10 +354,12 @@ public MockResponse dispatch(RecordedRequest request) {
});

try {
new SyncWorker.SyncImpl(context, time.get()).doSync();
new SyncWorker.SyncImpl(context, time.get()).doSyncBlocking();
} catch (Exception e) {
e.printStackTrace();
}

waitForAllRunningWorkersToStop();
}

private long yesterdayAt3am() {
Expand Down Expand Up @@ -382,4 +389,26 @@ private long yesterdayAt8pm() {
return cal.getTimeInMillis();
}


private void waitForAllRunningWorkersToStop() throws ExecutionException, InterruptedException {
boolean hasRunningWork;
do {
hasRunningWork = false;
for (WorkInfo workInfo : WorkManager.getInstance(context).getWorkInfosByTag(SyncWorker.WORK_TAG).get()) {
if (workInfo.getState() == WorkInfo.State.RUNNING) {
hasRunningWork = true;
}
}
for (WorkInfo workInfo : WorkManager.getInstance(context).getWorkInfosByTag(ExposureWindowMatchingWorker.WORK_TAG)
.get()) {
if (workInfo.getState() == WorkInfo.State.RUNNING) {
hasRunningWork = true;
}
}
if (hasRunningWork) {
Thread.sleep(500);
}
} while (hasRunningWork);
}

}
Loading

0 comments on commit 648079e

Please sign in to comment.