diff --git a/CHANGELOG.md b/CHANGELOG.md index 946f579d..e38a9426 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # Changelog for DP3T-SDK Android +## version 1.0.3 (24.7.2020) + +- upgraded to play-services-nearby-18.0.3-eap (adds a service for Google to restart our application after force stop starting v1.5) +- add success and error callback to senFakeInfectedRequest +- add response body to StatusCodeException + ## version 1.0.2 (17.7.2020) - fix logic for when a sync is considered successfull in HistoryDatabase (only if no errors) diff --git a/calibration-app/app/src/main/java/org/dpppt/android/calibration/controls/ControlsFragment.java b/calibration-app/app/src/main/java/org/dpppt/android/calibration/controls/ControlsFragment.java index 16864999..41261b64 100644 --- a/calibration-app/app/src/main/java/org/dpppt/android/calibration/controls/ControlsFragment.java +++ b/calibration-app/app/src/main/java/org/dpppt/android/calibration/controls/ControlsFragment.java @@ -344,7 +344,7 @@ private void updateSdkStatus() { Button buttonReportFake = view.findViewById(R.id.home_button_report_fake); buttonReportFake.setOnClickListener( v -> { - DP3T.sendFakeInfectedRequest(getContext(), null); + DP3T.sendFakeInfectedRequest(getContext(), null, null, null); }); EditText deanonymizationDeviceId = view.findViewById(R.id.deanonymization_device_id); @@ -427,4 +427,5 @@ private void setUploadDbLoadingViewVisible(boolean visible) { view.findViewById(R.id.home_button_upload_db).setVisibility(visible ? View.INVISIBLE : View.VISIBLE); } } + } diff --git a/calibration-app/app/src/main/java/org/dpppt/android/calibration/handshakes/BackendCalibrationReportRepository.java b/calibration-app/app/src/main/java/org/dpppt/android/calibration/handshakes/BackendCalibrationReportRepository.java index 505d3104..94111344 100644 --- a/calibration-app/app/src/main/java/org/dpppt/android/calibration/handshakes/BackendCalibrationReportRepository.java +++ b/calibration-app/app/src/main/java/org/dpppt/android/calibration/handshakes/BackendCalibrationReportRepository.java @@ -10,7 +10,6 @@ package org.dpppt.android.calibration.handshakes; import android.content.Context; -import androidx.annotation.NonNull; import org.dpppt.android.calibration.MainApplication; import org.dpppt.android.sdk.backend.ResponseCallback; @@ -18,6 +17,7 @@ import org.dpppt.android.sdk.internal.backend.StatusCodeException; import org.dpppt.android.sdk.internal.backend.models.GaenRequest; +import androidx.annotation.NonNull; import retrofit2.Call; import retrofit2.Callback; import retrofit2.Response; @@ -46,7 +46,7 @@ public void onResponse(@NonNull Call call, @NonNull Response respons if (response.isSuccessful()) { responseCallback.onSuccess(null); } else { - onFailure(call, new StatusCodeException(response.raw())); + onFailure(call, new StatusCodeException(response.raw(), response.errorBody())); } } diff --git a/calibration-app/app/src/main/java/org/dpppt/android/calibration/handshakes/BackendUserBucketRepository.java b/calibration-app/app/src/main/java/org/dpppt/android/calibration/handshakes/BackendUserBucketRepository.java index ccb6916c..f77b20a3 100644 --- a/calibration-app/app/src/main/java/org/dpppt/android/calibration/handshakes/BackendUserBucketRepository.java +++ b/calibration-app/app/src/main/java/org/dpppt/android/calibration/handshakes/BackendUserBucketRepository.java @@ -10,9 +10,6 @@ package org.dpppt.android.calibration.handshakes; import android.content.Context; -import androidx.annotation.NonNull; - -import java.io.IOException; import org.dpppt.android.calibration.MainApplication; import org.dpppt.android.sdk.backend.SignatureException; @@ -20,6 +17,9 @@ import org.dpppt.android.sdk.internal.backend.ServerTimeOffsetException; import org.dpppt.android.sdk.internal.backend.StatusCodeException; +import java.io.IOException; + +import androidx.annotation.NonNull; import okhttp3.ResponseBody; import retrofit2.Response; import retrofit2.Retrofit; @@ -47,7 +47,7 @@ public ResponseBody getGaenExposees(long batchReleaseTime) if (response.isSuccessful() && response.body() != null) { return response.body(); } else { - throw new StatusCodeException(response.raw()); + throw new StatusCodeException(response.raw(), response.errorBody()); } } diff --git a/calibration-app/app/src/main/java/org/dpppt/android/calibration/parameters/ParametersFragment.java b/calibration-app/app/src/main/java/org/dpppt/android/calibration/parameters/ParametersFragment.java index ccde80e4..9c3f6cec 100644 --- a/calibration-app/app/src/main/java/org/dpppt/android/calibration/parameters/ParametersFragment.java +++ b/calibration-app/app/src/main/java/org/dpppt/android/calibration/parameters/ParametersFragment.java @@ -60,7 +60,7 @@ public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceStat attenuationBucket1Seeekbar = view.findViewById(R.id.parameter_seekbar_attenuation_bucket1); attenuationBucket1Text = view.findViewById(R.id.parameter_seekbar_attenuation_bucket1_value); - attenuationBucket1Seeekbar.setMax(255); + attenuationBucket1Seeekbar.setMax(254); attenuationBucket1Seeekbar.setProgress(appConfigManager.getAttenuationThresholdLow()); attenuationBucket1Seeekbar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() { @Override @@ -99,6 +99,8 @@ public void onStopTrackingTouch(SeekBar seekBar) { } attenuationBucket2Seeekbar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() { @Override public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { + int min = 1; + if (progress < min) progress = min; setBucket2Value(progress); } @@ -133,16 +135,18 @@ public void onStopTrackingTouch(SeekBar seekBar) { } BuildConfig.BUILD_TYPE); } - private void setBucket1Value(int value) { - appConfigManager.setAttenuationThresholdLow(value); - attenuationBucket1Text.setText(Integer.toString(value)); - attenuationBucket2Seeekbar.setProgress(Math.max(attenuationBucket2Seeekbar.getProgress(), value + 1)); + private void setBucket1Value(int thresholdLow) { + int thresholdMedium = Math.max(attenuationBucket2Seeekbar.getProgress(), thresholdLow + 1); + appConfigManager.setAttenuationThresholds(thresholdLow, thresholdMedium); + attenuationBucket1Text.setText(Integer.toString(thresholdLow)); + attenuationBucket2Seeekbar.setProgress(thresholdMedium); } - private void setBucket2Value(int value) { - appConfigManager.setAttenuationThresholdMedium(value); - attenuationBucket2Text.setText(Integer.toString(value)); - attenuationBucket1Seeekbar.setProgress(Math.min(attenuationBucket1Seeekbar.getProgress(), value - 1)); + private void setBucket2Value(int thresholdMedium) { + int thresholdLow = Math.min(attenuationBucket1Seeekbar.getProgress(), thresholdMedium - 1); + appConfigManager.setAttenuationThresholds(thresholdLow, thresholdMedium); + attenuationBucket2Text.setText(Integer.toString(thresholdMedium)); + attenuationBucket1Seeekbar.setProgress(thresholdLow); } diff --git a/dp3t-sdk/sdk/build.gradle b/dp3t-sdk/sdk/build.gradle index 326f3684..0c1739f4 100644 --- a/dp3t-sdk/sdk/build.gradle +++ b/dp3t-sdk/sdk/build.gradle @@ -21,8 +21,8 @@ android { defaultConfig { minSdkVersion 23 targetSdkVersion 29 - versionCode 102 - versionName "1.0.2" + versionCode 103 + versionName "1.0.3" testInstrumentationRunnerArgument 'androidx.benchmark.suppressErrors', 'EMULATOR,LOW-BATTERY,ACTIVITY-MISSING,DEBUGGABLE,UNLOCKED,UNSUSTAINED-ACTIVITY-MISSING' testInstrumentationRunner "androidx.benchmark.junit4.AndroidBenchmarkRunner" diff --git a/dp3t-sdk/sdk/libs/play-services-nearby-18.0.2-eap-v1.3.1.aar b/dp3t-sdk/sdk/libs/play-services-nearby-18.0.2-eap-v1.3.1.aar deleted file mode 100644 index a80a47fd..00000000 Binary files a/dp3t-sdk/sdk/libs/play-services-nearby-18.0.2-eap-v1.3.1.aar and /dev/null differ diff --git a/dp3t-sdk/sdk/libs/play-services-nearby-18.0.3-eap.aar b/dp3t-sdk/sdk/libs/play-services-nearby-18.0.3-eap.aar new file mode 100644 index 00000000..e962ff05 Binary files /dev/null and b/dp3t-sdk/sdk/libs/play-services-nearby-18.0.3-eap.aar differ diff --git a/dp3t-sdk/sdk/src/androidTest/java/org/dpppt/android/sdk/internal/nearby/TestGoogleExposureClient.java b/dp3t-sdk/sdk/src/androidTest/java/org/dpppt/android/sdk/internal/nearby/TestGoogleExposureClient.java index b7bf340b..66cedbc5 100644 --- a/dp3t-sdk/sdk/src/androidTest/java/org/dpppt/android/sdk/internal/nearby/TestGoogleExposureClient.java +++ b/dp3t-sdk/sdk/src/androidTest/java/org/dpppt/android/sdk/internal/nearby/TestGoogleExposureClient.java @@ -22,11 +22,7 @@ import com.google.android.gms.common.api.Api; import com.google.android.gms.common.api.internal.ApiKey; -import com.google.android.gms.nearby.exposurenotification.ExposureConfiguration; -import com.google.android.gms.nearby.exposurenotification.ExposureInformation; -import com.google.android.gms.nearby.exposurenotification.ExposureNotificationClient; -import com.google.android.gms.nearby.exposurenotification.ExposureSummary; -import com.google.android.gms.nearby.exposurenotification.TemporaryExposureKey; +import com.google.android.gms.nearby.exposurenotification.*; import com.google.android.gms.tasks.Task; import org.dpppt.android.sdk.internal.util.Json; @@ -85,6 +81,11 @@ public Task provideDiagnosisKeys(List list, ExposureConfiguration ex return new DummyTask<>(null); } + @Override + public Task> getExposureWindows(String s) { + return new DummyTask<>(new ArrayList<>()); + } + @Override public Task getExposureSummary(String s) { return new DummyTask<>(new ExposureSummary.ExposureSummaryBuilder().build()); diff --git a/dp3t-sdk/sdk/src/main/java/org/dpppt/android/sdk/DP3T.java b/dp3t-sdk/sdk/src/main/java/org/dpppt/android/sdk/DP3T.java index 086541f4..c52ca9e2 100644 --- a/dp3t-sdk/sdk/src/main/java/org/dpppt/android/sdk/DP3T.java +++ b/dp3t-sdk/sdk/src/main/java/org/dpppt/android/sdk/DP3T.java @@ -40,8 +40,8 @@ import org.dpppt.android.sdk.internal.nearby.GoogleExposureClient; import org.dpppt.android.sdk.internal.storage.ErrorNotificationStorage; import org.dpppt.android.sdk.internal.storage.ExposureDayStorage; -import org.dpppt.android.sdk.internal.storage.models.PendingKey; import org.dpppt.android.sdk.internal.storage.PendingKeyUploadStorage; +import org.dpppt.android.sdk.internal.storage.models.PendingKey; import org.dpppt.android.sdk.models.ApplicationInfo; import org.dpppt.android.sdk.models.DayDate; import org.dpppt.android.sdk.models.ExposeeAuthMethod; @@ -85,12 +85,12 @@ public static void init(Context context, ApplicationInfo applicationInfo, Public googleExposureClient .setParams(appConfigManager.getAttenuationThresholdLow(), appConfigManager.getAttenuationThresholdMedium()); - executeInit(context.getApplicationContext()); + executeInit(context.getApplicationContext(), appConfigManager); initialized = true; } - private static void executeInit(Context context) { + private static void executeInit(Context context, AppConfigManager appConfigManager) { if (initialized) { return; } @@ -114,6 +114,11 @@ private static void executeInit(Context context) { GaenStateHelper.invalidateGaenAvailability(context); GaenStateHelper.invalidateGaenEnabled(context); + + if (appConfigManager.isTracingEnabled()) { + SyncWorker.startSyncWorker(context); + BroadcastHelper.sendUpdateAndErrorBroadcast(context); + } } public static boolean isInitialized() { @@ -288,7 +293,8 @@ private static void reportFailedIAmInfected(Throwable e) { pendingIAmInfectedRequest = null; } - public static void sendFakeInfectedRequest(Context context, ExposeeAuthMethod exposeeAuthMethod) { + public static void sendFakeInfectedRequest(Context context, ExposeeAuthMethod exposeeAuthMethod, Runnable successCallback, + Runnable errorCallback) { checkInit(); int delayedKeyDate = DateUtil.getCurrentRollingStartNumber(); @@ -311,6 +317,7 @@ public void onSuccess(String authToken) { historyDatabase.addEntry(new HistoryEntry(HistoryEntryType.FAKE_REQUEST, null, true, System.currentTimeMillis())); } + if (successCallback != null) successCallback.run(); } @Override @@ -323,6 +330,7 @@ public void onError(Throwable throwable) { historyDatabase.addEntry(new HistoryEntry(HistoryEntryType.FAKE_REQUEST, status, false, System.currentTimeMillis())); } + if (errorCallback != null) errorCallback.run(); } }); } catch (IllegalStateException e) { @@ -332,6 +340,7 @@ public void onError(Throwable throwable) { historyDatabase.addEntry(new HistoryEntry(HistoryEntryType.FAKE_REQUEST, "SYST", false, System.currentTimeMillis())); } + if (errorCallback != null) errorCallback.run(); } } @@ -398,8 +407,7 @@ public static void setMatchingParameters(Context context, int attenuationThresho checkInit(); AppConfigManager appConfigManager = AppConfigManager.getInstance(context); - appConfigManager.setAttenuationThresholdLow(attenuationThresholdLow); - appConfigManager.setAttenuationThresholdMedium(attenuationThresholdMedium); + appConfigManager.setAttenuationThresholds(attenuationThresholdLow, attenuationThresholdMedium); appConfigManager.setAttenuationFactorLow(attenuationFactorLow); appConfigManager.setAttenuationFactorMedium(attenuationFactorMedium); appConfigManager.setMinDurationForExposure(minDurationForExposure); diff --git a/dp3t-sdk/sdk/src/main/java/org/dpppt/android/sdk/internal/AppConfigManager.java b/dp3t-sdk/sdk/src/main/java/org/dpppt/android/sdk/internal/AppConfigManager.java index c85b35cd..86fa06d4 100644 --- a/dp3t-sdk/sdk/src/main/java/org/dpppt/android/sdk/internal/AppConfigManager.java +++ b/dp3t-sdk/sdk/src/main/java/org/dpppt/android/sdk/internal/AppConfigManager.java @@ -15,6 +15,7 @@ import java.text.ParseException; import java.util.HashMap; import java.util.Map; +import java.lang.IllegalArgumentException; import org.dpppt.android.sdk.internal.backend.BackendReportRepository; import org.dpppt.android.sdk.internal.nearby.GoogleExposureClient; @@ -148,18 +149,17 @@ public int getAttenuationThresholdLow() { return sharedPrefs.getInt(PREF_ATTENUATION_THRESHOLD_LOW, DEFAULT_ATTENUATION_THRESHOLD_LOW); } - public void setAttenuationThresholdLow(int threshold) { - sharedPrefs.edit().putInt(PREF_ATTENUATION_THRESHOLD_LOW, threshold).apply(); - googleExposureClient.setParams(threshold, getAttenuationThresholdMedium()); - } - public int getAttenuationThresholdMedium() { return sharedPrefs.getInt(PREF_ATTENUATION_THRESHOLD_MEDIUM, DEFAULT_ATTENUATION_THRESHOLD_MEDIUM); } - public void setAttenuationThresholdMedium(int threshold) { - sharedPrefs.edit().putInt(PREF_ATTENUATION_THRESHOLD_MEDIUM, threshold).apply(); - googleExposureClient.setParams(getAttenuationThresholdLow(), threshold); + public void setAttenuationThresholds(int thresholdLow, int thresholdMedium) { + if (thresholdLow >= thresholdMedium) { + throw new IllegalArgumentException("Illegal Arguments: thresholdLow must be smaller than thresholdMedium"); + } + sharedPrefs.edit().putInt(PREF_ATTENUATION_THRESHOLD_LOW, thresholdLow).apply(); + sharedPrefs.edit().putInt(PREF_ATTENUATION_THRESHOLD_MEDIUM, thresholdMedium).apply(); + googleExposureClient.setParams(thresholdLow, thresholdMedium); } public float getAttenuationFactorLow() { diff --git a/dp3t-sdk/sdk/src/main/java/org/dpppt/android/sdk/internal/backend/BackendBucketRepository.java b/dp3t-sdk/sdk/src/main/java/org/dpppt/android/sdk/internal/backend/BackendBucketRepository.java index 663870cd..8517816c 100644 --- a/dp3t-sdk/sdk/src/main/java/org/dpppt/android/sdk/internal/backend/BackendBucketRepository.java +++ b/dp3t-sdk/sdk/src/main/java/org/dpppt/android/sdk/internal/backend/BackendBucketRepository.java @@ -10,15 +10,15 @@ package org.dpppt.android.sdk.internal.backend; import android.content.Context; -import androidx.annotation.NonNull; - -import java.io.IOException; -import java.security.PublicKey; import org.dpppt.android.sdk.backend.SignatureException; import org.dpppt.android.sdk.backend.SignatureVerificationInterceptor; import org.dpppt.android.sdk.models.DayDate; +import java.io.IOException; +import java.security.PublicKey; + +import androidx.annotation.NonNull; import okhttp3.OkHttpClient; import okhttp3.ResponseBody; import retrofit2.Response; @@ -51,7 +51,7 @@ public Response getGaenExposees(DayDate keyDate, Long lastLoadedTi if (response.isSuccessful()) { return response; } else { - throw new StatusCodeException(response.raw()); + throw new StatusCodeException(response.raw(), response.errorBody()); } } diff --git a/dp3t-sdk/sdk/src/main/java/org/dpppt/android/sdk/internal/backend/BackendReportRepository.java b/dp3t-sdk/sdk/src/main/java/org/dpppt/android/sdk/internal/backend/BackendReportRepository.java index 2b48b471..949ba58e 100644 --- a/dp3t-sdk/sdk/src/main/java/org/dpppt/android/sdk/internal/backend/BackendReportRepository.java +++ b/dp3t-sdk/sdk/src/main/java/org/dpppt/android/sdk/internal/backend/BackendReportRepository.java @@ -52,7 +52,7 @@ public void onResponse(@NonNull Call call, @NonNull Response respons if (response.isSuccessful()) { responseCallback.onSuccess(response.headers().get("Authorization")); } else { - onFailure(call, new StatusCodeException(response.raw())); + onFailure(call, new StatusCodeException(response.raw(), response.errorBody())); } } @@ -66,7 +66,7 @@ public void onFailure(@NonNull Call call, @NonNull Throwable throwable) { public void addPendingGaenKey(GaenKey gaenKey, String token) throws IOException, StatusCodeException { Response response = reportService.addPendingGaenKey(new GaenSecondDay(gaenKey), token).execute(); if (!response.isSuccessful()) { - throw new StatusCodeException(response.raw()); + throw new StatusCodeException(response.raw(), response.errorBody()); } } diff --git a/dp3t-sdk/sdk/src/main/java/org/dpppt/android/sdk/internal/backend/StatusCodeException.java b/dp3t-sdk/sdk/src/main/java/org/dpppt/android/sdk/internal/backend/StatusCodeException.java index 6463ea10..0e79c272 100644 --- a/dp3t-sdk/sdk/src/main/java/org/dpppt/android/sdk/internal/backend/StatusCodeException.java +++ b/dp3t-sdk/sdk/src/main/java/org/dpppt/android/sdk/internal/backend/StatusCodeException.java @@ -9,27 +9,52 @@ */ package org.dpppt.android.sdk.internal.backend; +import java.io.IOException; + import androidx.annotation.NonNull; import androidx.annotation.Nullable; import okhttp3.Response; +import okhttp3.ResponseBody; public class StatusCodeException extends Exception { private Response response; + private String body; - public StatusCodeException(@NonNull Response response) { + public StatusCodeException(@NonNull Response response, @Nullable ResponseBody errorBody) { this.response = response; + this.body = readBody(errorBody); } @Nullable @Override public String getMessage() { - return "Code: " + response.code() + " Message: " + response.message(); + StringBuilder sb = new StringBuilder() + .append("Code: ") + .append(response.code()) + .append(" Message: ") + .append(response.message()); + if (body != null) { + sb.append(" Body: ").append(body); + } + return sb.toString(); + } + + @Nullable + public String getBody() { + return body; } public int getCode() { return response.code(); } + private static String readBody(ResponseBody body) { + try { + return body == null ? null : body.string(); + } catch (IOException error) { + return null; + } + } }