From 183da9410b44079bdd0301a372c1f176a566274b Mon Sep 17 00:00:00 2001 From: Armin Date: Tue, 6 Apr 2021 10:55:17 +0200 Subject: [PATCH 1/9] [CY-5526] Migrate away from jCenter (#8) * [CY-5526] Migrate away from jCenter * Upgrade Kotlin 1.4.21 -> 1.4.32 * Upgrade Android Gradle Plugin 4.1.1 -> 4.1.3 * Upgrade Cyface Utils, -Energy Settings, -Camera Service * Upgrade Android Annotation 1.0.0 -> 1.2.0 * Upgrade Robolectric 4.3.1 -> 4.5.1 --- build.gradle | 20 +++++++++++--------- camera_service | 2 +- energy_settings | 2 +- 3 files changed, 13 insertions(+), 11 deletions(-) diff --git a/build.gradle b/build.gradle index c72b3172..29cfdab2 100644 --- a/build.gradle +++ b/build.gradle @@ -26,15 +26,16 @@ */ buildscript { - ext.kotlin_version = "1.4.21" + ext.kotlin_version = "1.4.32" ext.java_version = JavaVersion.VERSION_1_8 repositories { google() - jcenter() + mavenCentral() + gradlePluginPortal() } dependencies { - classpath 'com.android.tools.build:gradle:4.1.1' + classpath 'com.android.tools.build:gradle:4.1.3' // Required for versioning Google play services. classpath "com.google.android.gms:strict-version-matcher-plugin:1.2.2" classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" @@ -54,9 +55,9 @@ ext { */ cyfaceBackendVersion = "6.2.0" // Also update submodule commit ref - cyfaceUtilsVersion = "2.0.1" // Maven dependency - cyfaceEnergySettingsVersion = "3.0.0" // Also update submodule commit ref - cyfaceCameraServiceVersion = "3.0.0" // Also update submodule commit ref + cyfaceUtilsVersion = "2.0.2" // Maven dependency + cyfaceEnergySettingsVersion = "3.0.1" // Also update submodule commit ref + cyfaceCameraServiceVersion = "3.0.1" // Also update submodule commit ref minSdkVersion = 21 targetSdkVersion = 30 @@ -64,7 +65,7 @@ ext { buildToolsVersion = '30.0.3' multidexVersion = "2.0.1" - androidxAnnotationVersion = "1.0.0" + androidxAnnotationVersion = "1.2.0" androidxAppCompatVersion = "1.2.0" androidPreferencesVersion = "1.1.1" localbroadcastmanagerVersion = "1.0.0" @@ -78,7 +79,7 @@ ext { mockitoVersion = "3.3.3" hamcrestVersion = "1.3" rulesVersion = "1.3.0" - robolectricVersion = "4.3.1" + robolectricVersion = "4.5.1" androidxTestCoreVersion = "1.1.0" runnerVersion = "1.3.0" uiAutomatorVersion = "2.2.0" @@ -109,7 +110,8 @@ allprojects { repositories { google() - jcenter() + mavenCentral() + gradlePluginPortal() // Required by submodules: camera_service, energy_settings, measuring-client, backend maven { url "https://maven.pkg.github.com/cyface-de/android-utils" diff --git a/camera_service b/camera_service index 1e39c5b8..18ebf37f 160000 --- a/camera_service +++ b/camera_service @@ -1 +1 @@ -Subproject commit 1e39c5b82d2582da087e3d872cbfc5b741d3976e +Subproject commit 18ebf37f7cdbc960766bee83bb837626dadfca48 diff --git a/energy_settings b/energy_settings index d22b3f37..7d47f795 160000 --- a/energy_settings +++ b/energy_settings @@ -1 +1 @@ -Subproject commit d22b3f3746de7092cd4a30dd6fa26f9dd51016b8 +Subproject commit 7d47f79598409c9beef05ae6db97640464ab38c3 From e1c80dd4d1b4d08b06073e1eb69dbfab3fd42450 Mon Sep 17 00:00:00 2001 From: Armin Date: Tue, 6 Apr 2021 13:47:37 +0200 Subject: [PATCH 2/9] [CY-5489] Update contact details on policy page (#9) --- measuring-client/src/main/res/values-de/strings.xml | 8 ++++---- measuring-client/src/main/res/values-it/strings.xml | 8 ++++---- measuring-client/src/main/res/values/strings.xml | 8 ++++---- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/measuring-client/src/main/res/values-de/strings.xml b/measuring-client/src/main/res/values-de/strings.xml index e6a64ab8..c2057dc9 100644 --- a/measuring-client/src/main/res/values-de/strings.xml +++ b/measuring-client/src/main/res/values-de/strings.xml @@ -122,7 +122,7 @@ Herausgeber Cyface GmbH - \nBehringstraße 46 + \nFröbelstr. 49 \n01159 Dresden\n \nVertreten durch: @@ -131,7 +131,7 @@ \nDirk Ackner\n \nE-Mail: mail@cyface.de - \nTelefon: 0351 481 877 30\n + \nTelefon: +49 351 658 6363 9\n \nAmtsgericht Dresden \nHRB: 36726 @@ -169,10 +169,10 @@ \n\nDer Verantwortliche im Sinne der Datenschutz-Grundverordnung und anderer nationaler Datenschutzgesetze der Mitgliedsstaaten sowie sonstiger datenschutzrechtlicher Bestimmungen ist die: \n\nCyface GmbH - \nBehringstraße 46 + \nFröbelstr. 49 \n01159 Dresden \nDeutschland - \nTel.: 0351 48187730 + \nTel.: +49 351 658 6363 9 \nE-Mail: mail@cyface.de \nWebsite: https://cyface.de diff --git a/measuring-client/src/main/res/values-it/strings.xml b/measuring-client/src/main/res/values-it/strings.xml index e3470597..4df0692e 100644 --- a/measuring-client/src/main/res/values-it/strings.xml +++ b/measuring-client/src/main/res/values-it/strings.xml @@ -122,7 +122,7 @@ Editore Cyface GmbH - \nBehringstraße 46 + \nFröbelstr. 49 \n01159 Dresden \nGermany\n @@ -132,7 +132,7 @@ \nDirk Ackner\n \nEmail: mail@cyface.de - \nPhone: +49 351 481 877 30\n + \nTelefon: +49 351 658 6363 9\n \nAmtsgericht Dresden \nHRB: 36726 @@ -169,10 +169,10 @@ \n\nL\'entità responsabile ai sensi del regolamento generale sulla protezione dei dati e di altre leggi nazionali in materia di protezione dei dati degli Stati membri, nonché di altre disposizioni in materia di protezione dei dati è la seguente: \n\nCyface GmbH - \nBehringstraße 46 + \nFröbelstr. 49 \n01159 Dresden \nGermania - \nTelefono: 0351 48187730 + \nTelefono: +49 351 658 6363 9 \nE-Mail: mail@cyface.de \nSito web: https://cyface.de diff --git a/measuring-client/src/main/res/values/strings.xml b/measuring-client/src/main/res/values/strings.xml index ccd58def..7bef8046 100644 --- a/measuring-client/src/main/res/values/strings.xml +++ b/measuring-client/src/main/res/values/strings.xml @@ -126,7 +126,7 @@ Publisher Cyface GmbH - \nBehringstraße 46 + \nFröbelstr. 49 \n01159 Dresden \nGermany\n @@ -136,7 +136,7 @@ \nDirk Ackner\n \nEmail: mail@cyface.de - \nPhone: +49 351 481 877 30\n + \nTelefon: +49 351 658 6363 9\n \nAmtsgericht Dresden \nHRB: 36726 @@ -173,10 +173,10 @@ \n\nThe entity responsible within the meaning of the General Data Protection Regulation and other national data protection laws of the member states as well as other data protection provisions is the: \n\nCyface GmbH - \nBehringstraße 46 + \nFröbelstr. 49 \n01159 Dresden \nGermany - \nPhone: 0351 48187730 + \nPhone: +49 351 658 6363 9 \nE-mail: mail@cyface.de \nWebsite: https://cyface.de From aeabb8b1d26f15f8d7dbabbd45205954152bbe5e Mon Sep 17 00:00:00 2001 From: Armin Date: Fri, 10 Sep 2021 13:53:49 +0200 Subject: [PATCH 3/9] [CY-5664] Fix IAE: view not attached (#11) --- .../app/ui/button/DataCapturingButton.java | 22 ++++++++++++------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/measuring-client/src/main/java/de/cyface/app/ui/button/DataCapturingButton.java b/measuring-client/src/main/java/de/cyface/app/ui/button/DataCapturingButton.java index 55b2c2b3..0499f1b4 100644 --- a/measuring-client/src/main/java/de/cyface/app/ui/button/DataCapturingButton.java +++ b/measuring-client/src/main/java/de/cyface/app/ui/button/DataCapturingButton.java @@ -172,6 +172,7 @@ public class DataCapturingButton * {@code True} if the user opted-in to error reporting. */ private boolean isReportingEnabled; + private ProgressDialog calibrationProgressDialog; public DataCapturingButton(@NonNull final MainFragment mainFragment) { this.listener = new HashSet<>(); @@ -574,7 +575,7 @@ private void startCapturing() { // We use a handler to run the UI Code on the main thread as it is supposed to be runOnUiThread(() -> { - final ProgressDialog calibrationProgressDialog = createAndShowCalibrationDialog(); + calibrationProgressDialog = createAndShowCalibrationDialog(); scheduleProgressDialogDismissal(calibrationProgressDialog, calibrationDialogListener); }); @@ -780,14 +781,18 @@ public void shutDownFinished(final long l) { */ private void scheduleProgressDialogDismissal(final ProgressDialog progressDialog, final Collection calibrationDialogListener) { - new Handler().postDelayed(() -> { - if (progressDialog != null) { - progressDialog.dismiss(); - for (CalibrationDialogListener calibrationDialogListener1 : calibrationDialogListener) { - calibrationDialogListener1.onCalibrationDialogFinished(); - } + new Handler().postDelayed(() -> dismissCalibrationDialog(progressDialog, calibrationDialogListener), + CALIBRATION_DIALOG_TIMEOUT); + } + + private void dismissCalibrationDialog(final ProgressDialog progressDialog, + final Collection calibrationDialogListener) { + if (progressDialog != null) { + progressDialog.dismiss(); + for (CalibrationDialogListener calibrationDialogListener1 : calibrationDialogListener) { + calibrationDialogListener1.onCalibrationDialogFinished(); } - }, CALIBRATION_DIALOG_TIMEOUT); + } } /** @@ -831,6 +836,7 @@ public List loadCurrentMeasurementsEvents() throws CursorIsNullException, public void onDestroyView() { button.setOnClickListener(null); disconnect(dataCapturingService, cameraService); + dismissCalibrationDialog(calibrationProgressDialog, calibrationDialogListener); } /** From 4ddaf1f46188dfe7db2e6bc4e213d4cd13f8f6e6 Mon Sep 17 00:00:00 2001 From: Armin Date: Wed, 5 Jan 2022 16:28:54 +0100 Subject: [PATCH 4/9] [DAT-859] Switch to new transfer protocol v3 (#12) * Add dependencies required by proto from SDK * Inject debug setup properties via local.properties file * [DAT-746] Use java 11 * [DAT-725] Upgrade build.gradle dependencies * Enable desugaring to support Java 11 * Upgrade cyface-utils to 3.0.1 * Upgade gradle to 7 * Use apache Valiadate * [DAT-757] Handle paused deprecated measurement * [DAT-747] Fix sync progress * Upgrade dependencies * [DAT-746] Fix lint errors * Cleanup * Fix error: app isnt installed * Add gradle.properties.template * Remove Apache Validate * Read credentials from gradle.properties * Upgrade dependencies and Gradle to 7 * Add maven repo for android-publish to settings.gradle * Add support for DEPRECATED status * Fix build * Upgrade Cyface SDK, -camera service and energy settings * Fix build after dependency upgrades * [CY-5744] Fix no error shown on 401 error * Remove backend dependency and add Serialization dependency 1.0.2 * Upgrade Cyface Utils and Energy Settings * Upgrade Cyface Android Backend to 7.0.0 * Upgrade dependencies (Kotlin, Gradle Plugin, Annotation, Robolectr.) * Upgrade Android Google map and location play services * Undo fix to show UNAUTHORIZED toasts when app is in background --- .gitignore | 3 + README.adoc | 13 +-- backend | 2 +- bluetooth-le/build.gradle | 6 ++ build.gradle | 77 +++++++++--------- camera_service | 2 +- energy_settings | 2 +- gradle.properties | 5 -- gradle.properties.template | 27 ++++++ gradle/wrapper/gradle-wrapper.jar | Bin 55616 -> 59536 bytes gradle/wrapper/gradle-wrapper.properties | 3 +- gradlew | 33 ++++---- gradlew.bat | 25 ++---- measuring-client/build.gradle | 53 ++++++------ .../cyface/app/CapturingNotificationTest.java | 3 + measuring-client/src/main/AndroidManifest.xml | 10 ++- .../java/de/cyface/app/MeasuringClient.java | 1 + .../java/de/cyface/app/ui/MainFragment.java | 6 +- .../src/main/java/de/cyface/app/ui/Map.java | 16 ++-- .../app/ui/button/DataCapturingButton.java | 12 +-- .../app/ui/button/SynchronizationButton.java | 1 + .../app/ui/nav/controller/ExportTask.java | 12 +-- .../MeasurementDeleteController.java | 2 +- .../app/ui/nav/controller/NavDrawer.java | 2 +- .../app/ui/nav/view/CursorMeasureAdapter.java | 13 +-- .../nav/view/MeasurementOverviewFragment.java | 77 +++++++++--------- .../ui/notification/CameraEventHandler.java | 8 +- .../DataCapturingEventHandler.java | 7 +- .../ic_logo_only_c.xml | 0 .../src/main/res/values-v21/styles.xml | 29 ------- .../src/main/res/values/styles.xml | 9 +- .../de/cyface/app/ui/LoginActivityTest.java | 4 +- settings.gradle | 30 ++++++- 33 files changed, 267 insertions(+), 226 deletions(-) delete mode 100644 gradle.properties create mode 100644 gradle.properties.template rename measuring-client/src/main/res/{drawable-anydpi-v21 => drawable-anydpi}/ic_logo_only_c.xml (100%) delete mode 100644 measuring-client/src/main/res/values-v21/styles.xml diff --git a/.gitignore b/.gitignore index 52397ec2..0375e8a6 100644 --- a/.gitignore +++ b/.gitignore @@ -16,3 +16,6 @@ local.properties # keystore file, when copied into this project for manual (test) deployment of "release" variant /release-upload-key.jks + +# Only version gradle.properties.template +/gradle.properties diff --git a/README.adoc b/README.adoc index ba6a6811..fa00c131 100644 --- a/README.adoc +++ b/README.adoc @@ -28,11 +28,11 @@ To download the Cyface libraries (SDK, Energy Settings, Camera Service): [arabic] * You need a Github account with read-access to these Github repositories * Create a https://github.com/settings/tokens[personal access token on Github] with "write:packages" permissions -* Create or adjust a `local.properties` file in the project root containing: +* Copy `gradle.properties.template` to `gradle.properties` and adjust: + .... -github.user=YOUR_USERNAME -github.token=YOUR_ACCESS_TOKEN +githubUser=YOUR_USERNAME +githubToken=YOUR_ACCESS_TOKEN .... * Build the app `./gradlew build` @@ -44,7 +44,8 @@ The credentials are usually injected by the CI: ==== Sentry -Create a file `sentry.properties` with the following credentials: +Create a file `sentry.properties` with the following credentials, +the `auth.token` can be found on `Sentry > Settings > Account > API > Auth Tokens`. .... defaults.project=android-app @@ -54,14 +55,14 @@ auth.token=SECRET_TOKEN ==== Google Maps -Add the following to your `local.properties` file: +Add the following to your `gradle.properties` file: .... google.maps_api_key=SECRET_KEY .... ==== Cyface Guest Credentials -Add the following to your `local.properties` file: +Add the following to your `gradle.properties` file: .... cyface.guest_password=GUEST_PASSWORD .... diff --git a/backend b/backend index 78760756..168204ef 160000 --- a/backend +++ b/backend @@ -1 +1 @@ -Subproject commit 787607565f0d2c905d44ed704de7a8d99eb0119f +Subproject commit 168204efeb669bd30d4923a81660cc2626cb31d9 diff --git a/bluetooth-le/build.gradle b/bluetooth-le/build.gradle index ff38b712..4ef265ad 100644 --- a/bluetooth-le/build.gradle +++ b/bluetooth-le/build.gradle @@ -37,6 +37,12 @@ android { testInstrumentationRunner rootProject.ext.testInstrumentationRunner } + // Enabling desugaring to support Java 8 and Java 11 features + compileOptions { + sourceCompatibility rootProject.ext.sourceCompatibility + targetCompatibility rootProject.ext.targetCompatibility + } + lintOptions { abortOnError false } diff --git a/build.gradle b/build.gradle index 29cfdab2..a210ee79 100644 --- a/build.gradle +++ b/build.gradle @@ -1,5 +1,5 @@ /* - * Copyright 2017 Cyface GmbH + * Copyright 2017-2021 Cyface GmbH * * This file is part of the Cyface App for Android. * @@ -26,8 +26,9 @@ */ buildscript { - ext.kotlin_version = "1.4.32" - ext.java_version = JavaVersion.VERSION_1_8 + ext.gradle_version = "7.0.4" + ext.kotlin_version = "1.6.10" + ext.matcher_version = "1.2.2" repositories { google() @@ -35,17 +36,17 @@ buildscript { gradlePluginPortal() } dependencies { - classpath 'com.android.tools.build:gradle:4.1.3' + classpath "com.android.tools.build:gradle:$gradle_version" // Required for versioning Google play services. - classpath "com.google.android.gms:strict-version-matcher-plugin:1.2.2" + classpath "com.google.android.gms:strict-version-matcher-plugin:$matcher_version" classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" } } ext { - // This app + // This app's version applicationId = "de.cyface.app" - versionName = "0.0.0" // Version shown to the user. Only increase this on the release branch. + versionName = "0.0.0" // Version shown to the user versionCode = 1 // Automatically incremented by CI. Required for Play Store releases /* @@ -54,60 +55,62 @@ ext { * prevents you from the creation of an incompatible fork and enables us to work standalone on the submodules. */ - cyfaceBackendVersion = "6.2.0" // Also update submodule commit ref - cyfaceUtilsVersion = "2.0.2" // Maven dependency - cyfaceEnergySettingsVersion = "3.0.1" // Also update submodule commit ref - cyfaceCameraServiceVersion = "3.0.1" // Also update submodule commit ref + // Cyface dependencies + cyfaceAndroidBackendVersion = "7.0.0" // Also update submodule commit ref + cyfaceUtilsVersion = "3.2.2" // Maven dependency + cyfaceEnergySettingsVersion = "3.1.1" // Also update submodule commit ref + cyfaceCameraServiceVersion = "4.0.0" // Also update submodule commit ref + cyfaceSerializationVersion = "1.0.2" // Keep im sync with version in submodule `backend` + // Android SDK versions minSdkVersion = 21 targetSdkVersion = 30 compileSdkVersion = 30 buildToolsVersion = '30.0.3' + // Android dependencies multidexVersion = "2.0.1" - androidxAnnotationVersion = "1.2.0" - androidxAppCompatVersion = "1.2.0" + androidxAnnotationVersion = "1.3.0" + androidxAppCompatVersion = "1.3.1" // 1.4.0 leads to an error in `gradle verifyReleaseResources` androidPreferencesVersion = "1.1.1" localbroadcastmanagerVersion = "1.0.0" exifinterfaceVersion = "1.3.2" // Required by Camera Service submodule - kotlinCoreVersion = "1.3.2" + // Other dependencies + kotlinCoreVersion = "1.6.0" // 1.7.0 leads to an error in `gradle verifyReleaseResources` materialDialogsVersion = "3.1.1" + googleApiClientVersion = '1.31.5' // transmission protocol - // testing - junitVersion = "1.1.2" + // Testing + junitVersion = "1.1.3" mockitoVersion = "3.3.3" hamcrestVersion = "1.3" - rulesVersion = "1.3.0" - robolectricVersion = "4.5.1" + rulesVersion = "1.4.0" + robolectricVersion = "4.6.1" androidxTestCoreVersion = "1.1.0" - runnerVersion = "1.3.0" + runnerVersion = "1.4.0" uiAutomatorVersion = "2.2.0" constrantLayoutVersion = "1.3.2" - - sourceCompatibility = JavaVersion.VERSION_1_8 - targetCompatibility = JavaVersion.VERSION_1_8 - testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" - // android-frontend dependencies - sentryAndroidVersion = "3.1.1" - sentryAndroidGradlePluginVersion = "1.7.36" - mapPlayServicesVersion = "17.0.0" - locationPlayServicesVersion = "17.1.0" - materialVersion = "1.3.0-rc01" // Beta because we need version >= 1.2.0 for the slider + // Java version + sourceCompatibility = JavaVersion.VERSION_11 + targetCompatibility = JavaVersion.VERSION_11 + kotlinTargetJavaVersion = "11" + + // Android-frontend + sentryAndroidVersion = "5.0.1" + sentryAndroidGradlePluginVersion = "2.0.1" + mapPlayServicesVersion = "18.0.1" + locationPlayServicesVersion = "19.0.0" + materialVersion = "1.4.0" circelProgressVersion = "1.1.0" // Version > 1.1.0 (1.2.1) is currently not available - androidxRecyclerViewVersion = "1.1.0" - + androidxRecyclerViewVersion = "1.2.1" } // Attention: Overwrites also the repositories used to retrieve the transitive dependencies in the submodules allprojects { - // Load credentials - def properties = new Properties() - properties.load(new FileInputStream("local.properties")) - repositories { google() mavenCentral() @@ -116,8 +119,8 @@ allprojects { maven { url "https://maven.pkg.github.com/cyface-de/android-utils" credentials { - username = properties.getProperty("github.user") - password = properties.getProperty("github.token") + username = project.findProperty("githubUser") + password = project.findProperty("githubToken") } } } diff --git a/camera_service b/camera_service index 18ebf37f..1c2a1be0 160000 --- a/camera_service +++ b/camera_service @@ -1 +1 @@ -Subproject commit 18ebf37f7cdbc960766bee83bb837626dadfca48 +Subproject commit 1c2a1be09b6a8d658f1bb60600c05d057e740659 diff --git a/energy_settings b/energy_settings index 7d47f795..76baedeb 160000 --- a/energy_settings +++ b/energy_settings @@ -1 +1 @@ -Subproject commit 7d47f79598409c9beef05ae6db97640464ab38c3 +Subproject commit 76baedeb50edde4efb965de8645dba894eff8d1d diff --git a/gradle.properties b/gradle.properties deleted file mode 100644 index 590298c7..00000000 --- a/gradle.properties +++ /dev/null @@ -1,5 +0,0 @@ -org.gradle.jvmargs=-Xmx2049M -android.builder.sdkDownload=true -android.useAndroidX=true -android.enableJetifier=true - diff --git a/gradle.properties.template b/gradle.properties.template new file mode 100644 index 00000000..94af1436 --- /dev/null +++ b/gradle.properties.template @@ -0,0 +1,27 @@ +org.gradle.jvmargs=-Xmx2049M +android.builder.sdkDownload=true +android.useAndroidX=true +android.enableJetifier=true + +githubUser= +githubToken= + +cyface.guest_password= + +google.maps_api_key= + +cyface.demo_api= +cyface.demo_user= +cyface.demo_password= + +cyface.local_api= +cyface.local_user= +cyface.local_password= + +cyface.emulator_api= +cyface.emulator_user= +cyface.emulator_password= + +cyface.staging_api= +cyface.staging_user= +cyface.staging_password= \ No newline at end of file diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index 5c2d1cf016b3885f6930543d57b744ea8c220a1a..7454180f2ae8848c63b8b4dea2cb829da983f2fa 100644 GIT binary patch delta 26482 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 delta 22605 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 diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 2d527632..ffed3a25 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,5 @@ -#Tue Jan 19 12:39:03 CET 2021 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-7.2-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-6.8-all.zip diff --git a/gradlew b/gradlew index 83f2acfd..744e882e 100755 --- a/gradlew +++ b/gradlew @@ -72,7 +72,7 @@ case "`uname`" in Darwin* ) darwin=true ;; - MINGW* ) + MSYS* | MINGW* ) msys=true ;; NONSTOP* ) @@ -82,6 +82,7 @@ esac CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + # Determine the Java command to use to start the JVM. if [ -n "$JAVA_HOME" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then @@ -129,6 +130,7 @@ fi if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then APP_HOME=`cygpath --path --mixed "$APP_HOME"` CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + JAVACMD=`cygpath --unix "$JAVACMD"` # We build the pattern for arguments to be converted via cygpath @@ -154,19 +156,19 @@ if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then else eval `echo args$i`="\"$arg\"" fi - i=$((i+1)) + i=`expr $i + 1` done case $i in - (0) set -- ;; - (1) set -- "$args0" ;; - (2) set -- "$args0" "$args1" ;; - (3) set -- "$args0" "$args1" "$args2" ;; - (4) set -- "$args0" "$args1" "$args2" "$args3" ;; - (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; - (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; - (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; - (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; - (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + 0) set -- ;; + 1) set -- "$args0" ;; + 2) set -- "$args0" "$args1" ;; + 3) set -- "$args0" "$args1" "$args2" ;; + 4) set -- "$args0" "$args1" "$args2" "$args3" ;; + 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; esac fi @@ -175,14 +177,9 @@ save () { for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done echo " " } -APP_ARGS=$(save "$@") +APP_ARGS=`save "$@"` # Collect all arguments for the java command, following the shell quoting and substitution rules eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" -# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong -if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then - cd "$(dirname "$0")" -fi - exec "$JAVACMD" "$@" diff --git a/gradlew.bat b/gradlew.bat index 24467a14..ac1b06f9 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -29,6 +29,9 @@ if "%DIRNAME%" == "" set DIRNAME=. set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" @@ -37,7 +40,7 @@ if defined JAVA_HOME goto findJavaFromJavaHome set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 -if "%ERRORLEVEL%" == "0" goto init +if "%ERRORLEVEL%" == "0" goto execute echo. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. @@ -51,7 +54,7 @@ goto fail set JAVA_HOME=%JAVA_HOME:"=% set JAVA_EXE=%JAVA_HOME%/bin/java.exe -if exist "%JAVA_EXE%" goto init +if exist "%JAVA_EXE%" goto execute echo. echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% @@ -61,28 +64,14 @@ echo location of your Java installation. goto fail -:init -@rem Get command-line arguments, handling Windows variants - -if not "%OS%" == "Windows_NT" goto win9xME_args - -:win9xME_args -@rem Slurp the command line arguments. -set CMD_LINE_ARGS= -set _SKIP=2 - -:win9xME_args_slurp -if "x%~1" == "x" goto execute - -set CMD_LINE_ARGS=%* - :execute @rem Setup the command line set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + @rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* :end @rem End local scope for the variables with windows NT shell diff --git a/measuring-client/build.gradle b/measuring-client/build.gradle index 50d2a29f..09315751 100644 --- a/measuring-client/build.gradle +++ b/measuring-client/build.gradle @@ -44,10 +44,6 @@ android { compileSdkVersion rootProject.ext.compileSdkVersion buildToolsVersion rootProject.ext.buildToolsVersion - // Load credentials - def properties = new Properties() - file("../local.properties").withInputStream { properties.load(it) } - defaultConfig { minSdkVersion rootProject.ext.minSdkVersion targetSdkVersion rootProject.ext.targetSdkVersion @@ -74,7 +70,7 @@ android { missingDimensionStrategy 'mode', 'full' // Load Google Maps API key - manifestPlaceholders = [ googleMapsApiKey:"${properties.getProperty('google.maps_api_key')}"] + manifestPlaceholders = [ googleMapsApiKey:"${project.findProperty('google.maps_api_key')}"] } buildTypes { @@ -84,17 +80,29 @@ android { // Select one of the APIs below, depending on your needs - // Mock-api, only supports mock-login (used by UI test on CI) - buildConfigField "String", "cyfaceServer", '"https://demo.cyface.de/api/v2"' - manifestPlaceholders = [usesCleartextTraffic:"false"] // for local collector testing - buildConfigField "String", "guestLogin", '"MOCKED"' - buildConfigField "String", "guestPassword", '"MOCKED"' + // Phone - to local collector - ! only if iptables allow connection from outside + //buildConfigField "String", "cyfaceServer", "\"${project.findProperty('cyface.local_api')}\"" + //buildConfigField "String", "guestLogin", "\"${project.findProperty('cyface.local_user')}\"" + //buildConfigField "String", "guestPassword", "\"${project.findProperty('cyface.local_password')}\"" + //manifestPlaceholders = [usesCleartextTraffic:"true"] - // Local mock-api via emulator (see ./mock-api) - can be easily modified for testing - //buildConfigField "String", "cyfaceServer", '"http://10.0.2.2:8080/api/v2"' + // EMULATOR - to local collector + //buildConfigField "String", "cyfaceServer", "\"${project.findProperty('cyface.emulator_api')}\"" //manifestPlaceholders = [usesCleartextTraffic:"true"] // for local collector testing - //buildConfigField "String", "guestLogin", '"guest"' - //buildConfigField "String", "guestPassword", '"secret"' + //buildConfigField "String", "guestLogin", "\"${project.findProperty('cyface.emulator_user')}\"" + //buildConfigField "String", "guestPassword", "\"${project.findProperty('cyface.emulator_password')}\"" + + // Staging + buildConfigField "String", "cyfaceServer", "\"${project.findProperty('cyface.staging_api')}\"" + buildConfigField "String", "guestLogin", "\"${project.findProperty('cyface.staging_user')}\"" + buildConfigField "String", "guestPassword", "\"${project.findProperty('cyface.staging_password')}\"" + manifestPlaceholders = [usesCleartextTraffic:"false"] + + // MOCK-API - only supports login - used by UI test on CI + //buildConfigField "String", "cyfaceServer", "\"${project.findProperty('cyface.demo_api')}\"" + //manifestPlaceholders = [usesCleartextTraffic:"false"] // for local collector testing + //buildConfigField "String", "guestLogin", "\"${project.findProperty('cyface.demo_user')}\"" + //buildConfigField "String", "guestPassword", "\"${project.findProperty('cyface.demo_password')}\"" } release { // mapping.xml file required to decode stack traces, but it's included in the bundle @@ -105,7 +113,7 @@ android { // signingConfig is set by the CI buildConfigField "String", "cyfaceServer", '"https://s2.cyface.de/api/v2"' buildConfigField "String", "guestLogin", '"guest"' - buildConfigField "String", "guestPassword", "\"${properties.getProperty('cyface.guest_password')}\"" + buildConfigField "String", "guestPassword", "\"${project.findProperty('cyface.guest_password')}\"" manifestPlaceholders = [usesCleartextTraffic:"false"] } } @@ -130,8 +138,12 @@ android { pickFirst 'META-INF/ASL2.0' pickFirst 'META-INF/LICENSE' pickFirst 'META-INF/NOTICE' + + // To resolve the conflict warning after adding google-api-client dependency + exclude 'META-INF/DEPENDENCIES' } + // Enabling desugaring to support Java 8 and Java 11 features compileOptions { sourceCompatibility rootProject.ext.sourceCompatibility targetCompatibility rootProject.ext.targetCompatibility @@ -140,27 +152,22 @@ android { // Exception tracking sentry { - // Disables or enables the automatic configuration of ProGuard - // for Sentry. This injects a default config for ProGuard so - // you don't need to do it manually. - autoProguardConfig true - // Enables or disables the automatic upload of mapping files // during a build. If you disable this, you'll need to manually // upload the mapping files with sentry-cli when you do a release. - autoUpload true + autoUpload = true // Disables or enables the automatic configuration of Native Symbols // for Sentry. This executes sentry-cli automatically so // you don't need to do it manually. // Default is disabled. - uploadNativeSymbols false + uploadNativeSymbols = false // Does or doesn't include the source code of native code for Sentry. // This executes sentry-cli with the --include-sources param. automatically so // you don't need to do it manually. // Default is disabled. - includeNativeSources false + includeNativeSources = false } dependencies { diff --git a/measuring-client/src/androidTest/java/de/cyface/app/CapturingNotificationTest.java b/measuring-client/src/androidTest/java/de/cyface/app/CapturingNotificationTest.java index 86e7cc8a..967257da 100644 --- a/measuring-client/src/androidTest/java/de/cyface/app/CapturingNotificationTest.java +++ b/measuring-client/src/androidTest/java/de/cyface/app/CapturingNotificationTest.java @@ -134,7 +134,9 @@ public void test() { // Act: Open Notification Area device.openNotification(); + //noinspection SpellCheckingInspection device.wait(Until.hasObject(By.pkg("com.android.systemui")), DEFAULT_TIMEOUT); + //noinspection SpellCheckingInspection final BySelector navigationScroller = By.res("com.android.systemui:id/notification_stack_scroller"); final UiObject2 notificationArea = device.findObject(navigationScroller); @@ -205,6 +207,7 @@ private void allowPermissionsIfNeeded(final UiDevice device) { // On Android 10+ the location permission screen changed. // We now request "Allow app to access location only while in foreground" + //noinspection SpellCheckingInspection final BySelector allowButtonSelector = Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q ? By.res("com.android.permissioncontroller:id/permission_allow_foreground_only_button") : By.res("com.android.packageinstaller:id/permission_allow_button"); diff --git a/measuring-client/src/main/AndroidManifest.xml b/measuring-client/src/main/AndroidManifest.xml index 3d3d726c..2468f5a2 100644 --- a/measuring-client/src/main/AndroidManifest.xml +++ b/measuring-client/src/main/AndroidManifest.xml @@ -42,14 +42,16 @@ tools:ignore="ScopedStorage" /> + + + tools:ignore="GoogleAppIndexingWarning,UnusedAttribute" + android:usesCleartextTraffic="${usesCleartextTraffic}"> @@ -67,7 +69,9 @@ android:required="false" /> - + + diff --git a/measuring-client/src/main/java/de/cyface/app/MeasuringClient.java b/measuring-client/src/main/java/de/cyface/app/MeasuringClient.java index f70a2900..e5b81f47 100644 --- a/measuring-client/src/main/java/de/cyface/app/MeasuringClient.java +++ b/measuring-client/src/main/java/de/cyface/app/MeasuringClient.java @@ -63,6 +63,7 @@ public class MeasuringClient extends MultiDexApplication { */ private final ErrorHandler.ErrorListener errorListener = (errorCode, errorMessage) -> { // All other errors are shown by the LoginActivity + // Without this check "unauthorized" toast appears even when the app is in background if (errorCode != UNAUTHORIZED) { Toast.makeText(MeasuringClient.this, errorMessage, Toast.LENGTH_LONG).show(); } diff --git a/measuring-client/src/main/java/de/cyface/app/ui/MainFragment.java b/measuring-client/src/main/java/de/cyface/app/ui/MainFragment.java index 97854f93..a097d8a8 100644 --- a/measuring-client/src/main/java/de/cyface/app/ui/MainFragment.java +++ b/measuring-client/src/main/java/de/cyface/app/ui/MainFragment.java @@ -70,12 +70,12 @@ import de.cyface.camera_service.CameraService; import de.cyface.datacapturing.CyfaceDataCapturingService; import de.cyface.datacapturing.exception.SetupException; -import de.cyface.persistence.NoSuchMeasurementException; +import de.cyface.persistence.exception.NoSuchMeasurementException; import de.cyface.persistence.model.Event; import de.cyface.persistence.model.Modality; import de.cyface.persistence.model.Track; import de.cyface.synchronization.ConnectionStatusListener; -import de.cyface.synchronization.SynchronisationException; +import de.cyface.synchronization.exception.SynchronisationException; import de.cyface.synchronization.WiFiSurveyor; import de.cyface.utils.CursorIsNullException; import de.cyface.utils.Validate; @@ -372,7 +372,7 @@ public void onActivityResult(int requestCode, int resultCode, Intent data) { private void selectModalityTab() { final TabLayout tabLayout = fragmentRoot.findViewById(R.id.tab_layout); final String modality = preferences.getString(PREFERENCES_MODALITY_KEY, null); - Validate.notNull("Modality should already be set but isn't.", modality); + Validate.notNull(modality, "Modality should already be set but isn't."); // Select the Modality tab final TabLayout.Tab tab; diff --git a/measuring-client/src/main/java/de/cyface/app/ui/Map.java b/measuring-client/src/main/java/de/cyface/app/ui/Map.java index 9b64ba95..3e8245e4 100644 --- a/measuring-client/src/main/java/de/cyface/app/ui/Map.java +++ b/measuring-client/src/main/java/de/cyface/app/ui/Map.java @@ -63,7 +63,7 @@ import de.cyface.app.ui.nav.view.CursorMeasureAdapter; import de.cyface.app.utils.Constants; import de.cyface.persistence.model.Event; -import de.cyface.persistence.model.GeoLocation; +import de.cyface.persistence.model.ParcelableGeoLocation; import de.cyface.persistence.model.Modality; import de.cyface.persistence.model.Track; import de.cyface.utils.Validate; @@ -176,10 +176,10 @@ public void renderMeasurement(@NonNull final List tracks, @NonNull final int positions = 0; // Iterate through the sub tracks and their points - final List allLocations = new ArrayList<>(); + final List allLocations = new ArrayList<>(); for (final Track track : tracks) { final PolylineOptions subTrack = new PolylineOptions(); - for (final GeoLocation location : track.getGeoLocations()) { + for (final ParcelableGeoLocation location : track.getGeoLocations()) { allLocations.add(location); final LatLng position = new LatLng(location.getLat(), location.getLon()); subTrack.add(position); @@ -207,12 +207,12 @@ public void renderMeasurement(@NonNull final List tracks, @NonNull final } } - private void renderEvents(@NonNull final List allLocations, @NonNull final List events) { + private void renderEvents(@NonNull final List allLocations, @NonNull final List events) { // Iterate through the events and select GeoLocations for each event to be rendered on the map - final Iterator locationIterator = allLocations.iterator(); - GeoLocation previousLocation = null; - GeoLocation nextLocation = null; + final Iterator locationIterator = allLocations.iterator(); + ParcelableGeoLocation previousLocation = null; + ParcelableGeoLocation nextLocation = null; for (final Event event : events) { MarkerOptions markerOptions = null; final String markerTitle = applicationContext.getString(R.string.modality_type) + ": " @@ -226,7 +226,7 @@ private void renderEvents(@NonNull final List allLocations, @NonNul } else { // Iterate until Event's nextLocation is reached while (locationIterator.hasNext()) { - final GeoLocation location = locationIterator.next(); + final ParcelableGeoLocation location = locationIterator.next(); if (location.getTimestamp() < event.getTimestamp()) { previousLocation = location; continue; diff --git a/measuring-client/src/main/java/de/cyface/app/ui/button/DataCapturingButton.java b/measuring-client/src/main/java/de/cyface/app/ui/button/DataCapturingButton.java index 0499f1b4..725d6393 100644 --- a/measuring-client/src/main/java/de/cyface/app/ui/button/DataCapturingButton.java +++ b/measuring-client/src/main/java/de/cyface/app/ui/button/DataCapturingButton.java @@ -93,10 +93,10 @@ import de.cyface.datacapturing.ui.Reason; import de.cyface.persistence.DefaultLocationCleaningStrategy; import de.cyface.persistence.DefaultPersistenceBehaviour; -import de.cyface.persistence.NoSuchMeasurementException; +import de.cyface.persistence.exception.NoSuchMeasurementException; import de.cyface.persistence.PersistenceLayer; import de.cyface.persistence.model.Event; -import de.cyface.persistence.model.GeoLocation; +import de.cyface.persistence.model.ParcelableGeoLocation; import de.cyface.persistence.model.Measurement; import de.cyface.persistence.model.MeasurementStatus; import de.cyface.persistence.model.Modality; @@ -264,7 +264,7 @@ private void setButtonStatus(@NonNull final ImageButton button, @NonNull final M *

* When a new Capturing is started, the {@code TextView} will only show the {@link Measurement#getIdentifier()} * of the open {@link Measurement}. The {@link Measurement#getDistance()} is automatically updated as soon as the - * first {@link GeoLocation}s are captured. This way the user can see if the capturing actually works. + * first {@link ParcelableGeoLocation}s are captured. This way the user can see if the capturing actually works. * * @param status the state of the {@code DataCapturingButton} */ @@ -899,7 +899,7 @@ public void onFixLost() { } @Override - public void onNewGeoLocationAcquired(GeoLocation geoLocation) { + public void onNewGeoLocationAcquired(ParcelableGeoLocation geoLocation) { Log.d(TAG, "onNewGeoLocationAcquired"); final Measurement measurement; try { @@ -948,8 +948,8 @@ public void onNewGeoLocationAcquired(GeoLocation geoLocation) { } } - private void addLocationToCachedTrack(@NonNull final GeoLocation location) { - Validate.notNull("onNewGeoLocation - cached track is null", currentMeasurementsTracks); + private void addLocationToCachedTrack(@NonNull final ParcelableGeoLocation location) { + Validate.notNull(currentMeasurementsTracks, "onNewGeoLocation - cached track is null"); if (!location.isValid()) { Log.d(TAG, "updateCachedTrack: ignoring invalid point"); diff --git a/measuring-client/src/main/java/de/cyface/app/ui/button/SynchronizationButton.java b/measuring-client/src/main/java/de/cyface/app/ui/button/SynchronizationButton.java index 8132e511..d1c5ac35 100644 --- a/measuring-client/src/main/java/de/cyface/app/ui/button/SynchronizationButton.java +++ b/measuring-client/src/main/java/de/cyface/app/ui/button/SynchronizationButton.java @@ -121,6 +121,7 @@ private void setActivated() { private void setDeactivated() { button.setVisibility(View.VISIBLE); progressView.setVisibility(View.INVISIBLE); + progressView.setProgress(0); // Or else last progress is shown upon restart isActivated = false; } diff --git a/measuring-client/src/main/java/de/cyface/app/ui/nav/controller/ExportTask.java b/measuring-client/src/main/java/de/cyface/app/ui/nav/controller/ExportTask.java index 87e09f68..2fa5d317 100644 --- a/measuring-client/src/main/java/de/cyface/app/ui/nav/controller/ExportTask.java +++ b/measuring-client/src/main/java/de/cyface/app/ui/nav/controller/ExportTask.java @@ -52,13 +52,13 @@ import de.cyface.app.R; import de.cyface.persistence.DefaultFileAccess; -import de.cyface.persistence.serialization.Point3dFile; +import de.cyface.persistence.serialization.Point3DFile; import de.cyface.utils.Validate; /** * Async task which exports the measurement data without the image data. * - * FIXME: AsyncTasks all run on the same thread this is only for short running operations!! + * TODO: AsyncTasks all run on the same thread this is only for short running operations!! * this will block e.g. authRequest and delete- async tasks! * see min 3:45 for alternatives: * https://www.youtube.com/watch?v=jtlRNNhane0&list=PLWz5rJ2EKKc9CBxr3BVjPTPoDPLdPIFCE&index=4 @@ -71,7 +71,7 @@ */ public class ExportTask extends AsyncTask { - private WeakReference contextReference; + private final WeakReference contextReference; private final String targetPathTimestamp; public ExportTask(@NonNull final Context context) { @@ -90,9 +90,9 @@ protected Long doInBackground(final Void... params) { // Export sensor data final DefaultFileAccess fileAccess = new DefaultFileAccess(); - final File accelerations = fileAccess.getFolderPath(context, Point3dFile.ACCELERATIONS_FOLDER_NAME); - final File rotations = fileAccess.getFolderPath(context, Point3dFile.ROTATIONS_FOLDER_NAME); - final File directions = fileAccess.getFolderPath(context, Point3dFile.DIRECTIONS_FOLDER_NAME); + final File accelerations = fileAccess.getFolderPath(context, Point3DFile.ACCELERATIONS_FOLDER_NAME); + final File rotations = fileAccess.getFolderPath(context, Point3DFile.ROTATIONS_FOLDER_NAME); + final File directions = fileAccess.getFolderPath(context, Point3DFile.DIRECTIONS_FOLDER_NAME); long bytesTransferred = 0L; final UUID exportIdentifier = UUID.randomUUID(); try { diff --git a/measuring-client/src/main/java/de/cyface/app/ui/nav/controller/MeasurementDeleteController.java b/measuring-client/src/main/java/de/cyface/app/ui/nav/controller/MeasurementDeleteController.java index 958377fc..11cdb967 100644 --- a/measuring-client/src/main/java/de/cyface/app/ui/nav/controller/MeasurementDeleteController.java +++ b/measuring-client/src/main/java/de/cyface/app/ui/nav/controller/MeasurementDeleteController.java @@ -46,7 +46,7 @@ import de.cyface.app.R; import de.cyface.persistence.DefaultPersistenceBehaviour; -import de.cyface.persistence.NoSuchMeasurementException; +import de.cyface.persistence.exception.NoSuchMeasurementException; import de.cyface.persistence.PersistenceLayer; import de.cyface.persistence.model.Measurement; import de.cyface.utils.CursorIsNullException; diff --git a/measuring-client/src/main/java/de/cyface/app/ui/nav/controller/NavDrawer.java b/measuring-client/src/main/java/de/cyface/app/ui/nav/controller/NavDrawer.java index 2b89bd51..41b77b04 100644 --- a/measuring-client/src/main/java/de/cyface/app/ui/nav/controller/NavDrawer.java +++ b/measuring-client/src/main/java/de/cyface/app/ui/nav/controller/NavDrawer.java @@ -53,7 +53,7 @@ import de.cyface.app.ui.MainActivity; import de.cyface.app.ui.MainFragment; import de.cyface.datacapturing.CyfaceDataCapturingService; -import de.cyface.synchronization.SynchronisationException; +import de.cyface.synchronization.exception.SynchronisationException; import de.cyface.synchronization.WiFiSurveyor; /** diff --git a/measuring-client/src/main/java/de/cyface/app/ui/nav/view/CursorMeasureAdapter.java b/measuring-client/src/main/java/de/cyface/app/ui/nav/view/CursorMeasureAdapter.java index 76d7a9de..f772b4e9 100644 --- a/measuring-client/src/main/java/de/cyface/app/ui/nav/view/CursorMeasureAdapter.java +++ b/measuring-client/src/main/java/de/cyface/app/ui/nav/view/CursorMeasureAdapter.java @@ -1,5 +1,5 @@ /* - * Copyright 2017 Cyface GmbH + * Copyright 2017-2021 Cyface GmbH * * This file is part of the Cyface App for Android. * @@ -50,7 +50,7 @@ * * @author Klemens Muthmann * @author Armin Schnabel - * @version 3.0.0 + * @version 3.0.1 * @since 1.0.0 */ public class CursorMeasureAdapter extends CursorAdapter { @@ -111,8 +111,9 @@ private void mapCursorToView(final Cursor cursor, final View view) { final MeasurementStatus status = MeasurementStatus .valueOf(cursor.getString(cursor.getColumnIndex(MeasurementTable.COLUMN_STATUS))); if (status == MeasurementStatus.OPEN || status == MeasurementStatus.PAUSED - || status == MeasurementStatus.SYNCED) { - label += " - " + status.toString().toLowerCase(); + || status == MeasurementStatus.SYNCED || status == MeasurementStatus.SKIPPED + || status == MeasurementStatus.DEPRECATED) { + label += " - " + status.toString().toLowerCase(Locale.ENGLISH); } // Checkable itemView.setEnabled(true); @@ -133,7 +134,7 @@ public static String getTranslation(@Nullable final WeakReference conte @NonNull final Modality modality) { if (contextWeakReference == null) { Log.w(TAG, "WeakReference is null, displaying database identifier instead of translation for modality."); - return modality.getDatabaseIdentifier().toLowerCase(); + return modality.getDatabaseIdentifier().toLowerCase(Locale.ENGLISH); } final Context context = contextWeakReference.get(); @@ -151,7 +152,7 @@ public static String getTranslation(@Nullable final WeakReference conte case MOTORBIKE: return context.getString(R.string.modality_motorbike); case UNKNOWN: - return modality.getDatabaseIdentifier().toLowerCase(); + return modality.getDatabaseIdentifier().toLowerCase(Locale.ENGLISH); default: throw new IllegalArgumentException("Unknown modality type: " + modality); } diff --git a/measuring-client/src/main/java/de/cyface/app/ui/nav/view/MeasurementOverviewFragment.java b/measuring-client/src/main/java/de/cyface/app/ui/nav/view/MeasurementOverviewFragment.java index 103b66ec..2c13e0e0 100644 --- a/measuring-client/src/main/java/de/cyface/app/ui/nav/view/MeasurementOverviewFragment.java +++ b/measuring-client/src/main/java/de/cyface/app/ui/nav/view/MeasurementOverviewFragment.java @@ -1,5 +1,5 @@ /* - * Copyright 2017 Cyface GmbH + * Copyright 2017-2021 Cyface GmbH * * This file is part of the Cyface App for Android. * @@ -70,7 +70,7 @@ import de.cyface.persistence.DefaultPersistenceBehaviour; import de.cyface.persistence.PersistenceLayer; import de.cyface.persistence.model.Event; -import de.cyface.persistence.model.GeoLocation; +import de.cyface.persistence.model.ParcelableGeoLocation; import de.cyface.persistence.model.Measurement; import de.cyface.persistence.model.Modality; import de.cyface.persistence.model.Track; @@ -82,7 +82,7 @@ * * @author Armin Schnabel * @author Klemens Muthmann - * @version 4.5.4 + * @version 4.5.5 * @since 1.0.0 */ public class MeasurementOverviewFragment extends Fragment { @@ -109,7 +109,7 @@ public class MeasurementOverviewFragment extends Fragment { */ private boolean isEventsListShown = false; /** - * The {@link PersistenceLayer} required to retrieve the {@link Measurement} date from the {@link GeoLocation}s + * The {@link PersistenceLayer} required to retrieve the {@link Measurement} date from the {@link ParcelableGeoLocation}s */ private PersistenceLayer persistenceLayer; /** @@ -254,40 +254,39 @@ public void onCreateOptionsMenu(@NonNull final Menu menu, final MenuInflater inf public boolean onOptionsItemSelected(final MenuItem item) { final FragmentActivity fragmentActivity = getActivity(); Validate.notNull(fragmentActivity); - switch (item.getItemId()) { - case R.id.export_menu_item: - // Permission requirements: https://developer.android.com/training/data-storage - final boolean requiresWritePermission = Build.VERSION.SDK_INT < Build.VERSION_CODES.Q; - final boolean missingPermissions = ContextCompat.checkSelfPermission(fragmentActivity, - Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED - || ContextCompat.checkSelfPermission(fragmentActivity, - Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED; - if (requiresWritePermission && missingPermissions) { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { - requestPermissions( - new String[] {Manifest.permission.WRITE_EXTERNAL_STORAGE, - Manifest.permission.READ_EXTERNAL_STORAGE}, - Constants.PERMISSION_REQUEST_EXTERNAL_STORAGE_FOR_EXPORT); - } else { - Toast.makeText(fragmentActivity, fragmentActivity.getString(R.string.export_data_no_permission), - Toast.LENGTH_LONG).show(); - } + if (item.getItemId() == R.id.export_menu_item) { + // Permission requirements: https://developer.android.com/training/data-storage + final boolean requiresWritePermission = Build.VERSION.SDK_INT < Build.VERSION_CODES.Q; + final boolean missingPermissions = ContextCompat.checkSelfPermission(fragmentActivity, + Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED + || ContextCompat.checkSelfPermission(fragmentActivity, + Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED; + if (requiresWritePermission && missingPermissions) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + requestPermissions( + new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE, + Manifest.permission.READ_EXTERNAL_STORAGE}, + Constants.PERMISSION_REQUEST_EXTERNAL_STORAGE_FOR_EXPORT); } else { - new ExportTask(fragmentActivity).execute(); - } - return true; - case R.id.select_all_item: - selectAllItems(); - return true; - case R.id.delete_measurement_item: - if (isEventsListShown) { - deleteSelectedEvents(fragmentActivity, eventDataList.getListView()); - } else { - deleteSelectedMeasurements(fragmentActivity, measurementDataList.getListView()); + Toast.makeText(fragmentActivity, fragmentActivity.getString(R.string.export_data_no_permission), + Toast.LENGTH_LONG).show(); } - return true; - default: - return super.onOptionsItemSelected(item); + } else { + new ExportTask(fragmentActivity).execute(); + } + return true; + } else if (item.getItemId() == R.id.select_all_item) { + selectAllItems(); + return true; + } else if (item.getItemId() == R.id.delete_measurement_item) { + if (isEventsListShown) { + deleteSelectedEvents(fragmentActivity, eventDataList.getListView()); + } else { + deleteSelectedMeasurements(fragmentActivity, measurementDataList.getListView()); + } + return true; + } else { + return super.onOptionsItemSelected(item); } } @@ -451,7 +450,7 @@ public void onActivityResult(int requestCode, int resultCode, Intent data) { markerLocation.setLongitude(markerPosition.longitude); // Load GeoLocations - final List geoLocations = new ArrayList<>(); + final List geoLocations = new ArrayList<>(); try { List tracks = persistenceLayer.loadTracks(measurementId, new DefaultLocationCleaningStrategy()); for (final Track track : tracks) { @@ -463,8 +462,8 @@ public void onActivityResult(int requestCode, int resultCode, Intent data) { // Search for the nearest GeoLocation Double minDistance = null; - GeoLocation nearestGeoLocation = null; - for (final GeoLocation geoLocation : geoLocations) { + ParcelableGeoLocation nearestGeoLocation = null; + for (final ParcelableGeoLocation geoLocation : geoLocations) { final Location location = new Location("geoLocation"); location.setLatitude(geoLocation.getLat()); location.setLongitude(geoLocation.getLon()); diff --git a/measuring-client/src/main/java/de/cyface/app/ui/notification/CameraEventHandler.java b/measuring-client/src/main/java/de/cyface/app/ui/notification/CameraEventHandler.java index edfba339..4aa37317 100644 --- a/measuring-client/src/main/java/de/cyface/app/ui/notification/CameraEventHandler.java +++ b/measuring-client/src/main/java/de/cyface/app/ui/notification/CameraEventHandler.java @@ -1,5 +1,5 @@ /* - * Copyright 2017 Cyface GmbH + * Copyright 2017-2021 Cyface GmbH * * This file is part of the Cyface App for Android. * @@ -100,7 +100,7 @@ private static void createNotificationChannelIfNotExists(final @NonNull Context } final NotificationManager manager = (NotificationManager)context.getSystemService(Context.NOTIFICATION_SERVICE); - Validate.notNull("Manager for service notifications not available.", manager); + Validate.notNull(manager, "Manager for service notifications not available."); if (manager.getNotificationChannel(channelId) == null) { final NotificationChannel channel = new NotificationChannel(channelId, channelName, importance); @@ -181,7 +181,7 @@ private void showSpaceWarningNotification(final Context context) { context.getString(R.string.notification_channel_description_warning), NotificationManager.IMPORTANCE_HIGH, true, Color.RED, true); } - // FIXME: see if we not create two of those warnings (DCS and CS) + // TODO: see if we not create two of those warnings (DCS and CS) final NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(context, NOTIFICATION_CHANNEL_ID_WARNING).setContentIntent(onClickPendingIntent) .setSmallIcon(R.drawable.ic_logo_only_c) @@ -299,7 +299,7 @@ private void showPictureCapturingDecreasedNotification(final Context context) { @NonNull public Notification buildCapturingNotification(@NonNull final BackgroundService context, final boolean isVideoModeRequested) { - Validate.notNull("No context provided!", context); + Validate.notNull(context, "No context provided!"); final String channelId = NOTIFICATION_CHANNEL_ID_RUNNING; // Open Activity when the notification is clicked diff --git a/measuring-client/src/main/java/de/cyface/app/ui/notification/DataCapturingEventHandler.java b/measuring-client/src/main/java/de/cyface/app/ui/notification/DataCapturingEventHandler.java index 94e82549..3c042e7f 100644 --- a/measuring-client/src/main/java/de/cyface/app/ui/notification/DataCapturingEventHandler.java +++ b/measuring-client/src/main/java/de/cyface/app/ui/notification/DataCapturingEventHandler.java @@ -38,6 +38,7 @@ import androidx.annotation.NonNull; import androidx.core.app.NotificationCompat; + import de.cyface.app.R; import de.cyface.app.ui.MainActivity; import de.cyface.datacapturing.EventHandlingStrategy; @@ -58,7 +59,7 @@ public class DataCapturingEventHandler implements EventHandlingStrategy { /** * The Parcelable creator as required by the Android Parcelable specification. */ - public static final Creator CREATOR = new Creator() { + public static final Creator CREATOR = new Creator<>() { @Override public DataCapturingEventHandler createFromParcel(final Parcel in) { return new DataCapturingEventHandler(in); @@ -98,7 +99,7 @@ private static void createNotificationChannelIfNotExists(final @NonNull Context } final NotificationManager manager = (NotificationManager)context.getSystemService(Context.NOTIFICATION_SERVICE); - Validate.notNull("Manager for service notifications not available.", manager); + Validate.notNull(manager, "Manager for service notifications not available."); if (manager.getNotificationChannel(channelId) == null) { final NotificationChannel channel = new NotificationChannel(channelId, channelName, importance); @@ -164,7 +165,7 @@ private void showSpaceWarningNotification(final Context context) { @Override @NonNull public Notification buildCapturingNotification(@NonNull final DataCapturingBackgroundService context) { - Validate.notNull("No context provided!", context); + Validate.notNull(context, "No context provided!"); final String channelId = NOTIFICATION_CHANNEL_ID_RUNNING; // Open Activity when the notification is clicked diff --git a/measuring-client/src/main/res/drawable-anydpi-v21/ic_logo_only_c.xml b/measuring-client/src/main/res/drawable-anydpi/ic_logo_only_c.xml similarity index 100% rename from measuring-client/src/main/res/drawable-anydpi-v21/ic_logo_only_c.xml rename to measuring-client/src/main/res/drawable-anydpi/ic_logo_only_c.xml diff --git a/measuring-client/src/main/res/values-v21/styles.xml b/measuring-client/src/main/res/values-v21/styles.xml deleted file mode 100644 index 8501aa51..00000000 --- a/measuring-client/src/main/res/values-v21/styles.xml +++ /dev/null @@ -1,29 +0,0 @@ - - - - - - - -