diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 000000000..af1010185 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,5 @@ +build +.idea +.gradle +local.properties +Dockerfile.build \ No newline at end of file diff --git a/.github/workflows/android_ci.yml b/.github/workflows/android_ci.yml index 8172e79ce..1618bea5f 100644 --- a/.github/workflows/android_ci.yml +++ b/.github/workflows/android_ci.yml @@ -13,10 +13,10 @@ jobs: steps: - uses: actions/checkout@v2 - - name: set up JDK 8 + - name: set up JDK 11 uses: actions/setup-java@v2 with: - java-version: '8' + java-version: '11' distribution: 'adopt' cache: gradle diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index c78b5514d..4a6033fc0 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -13,10 +13,10 @@ jobs: steps: - uses: actions/checkout@v2 - - name: set up JDK 8 + - name: set up JDK 11 uses: actions/setup-java@v2 with: - java-version: '8' + java-version: '11' distribution: 'adopt' cache: gradle diff --git a/.gitignore b/.gitignore index f8fa5ea36..1c92576ad 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,5 @@ build/ *.iml local.properties */release/ +gradle-release.properties +lcs-keystore \ No newline at end of file diff --git a/Dockerfile.build b/Dockerfile.build new file mode 100644 index 000000000..49c3935c3 --- /dev/null +++ b/Dockerfile.build @@ -0,0 +1,31 @@ +FROM mingc/android-build-box:1.24.0 + +ARG ORG_GRADLE_PROJECT_MAPBOX_DOWNLOADS_TOKEN + +RUN mkdir /app +WORKDIR /app + +# rm the NDK because it breaks the build +RUN rm -rf /opt/android-sdk/ndk/current +RUN rm -rf /opt/android-sdk/ndk/23.1.7779620 + +COPY ./gradle /app/gradle +COPY ./gradlew /app +COPY ./gradle.properties /app +COPY ./settings.gradle /app +COPY ./build.gradle /app + +# add a step that downloads the latest gradle wrapper before the actual build +#RUN ./gradlew help + +COPY . /app + + +RUN ./gradlew build + +# build the image with: +# docker build --build-arg ORG_GRADLE_PROJECT_MAPBOX_DOWNLOADS_TOKEN= -t envirocar-app-build:latest -f Dockerfile.build . +# +# to copy the final APK from the image to the host path /tmp/envirocar: +# docker run --rm -v /tmp/envirocar:/mnt/out envirocar-app-build:latest cp /app/org.envirocar.app/build/outputs/apk/debug/org.envirocar.app-debug.apk /mnt/out + diff --git a/Dockerfile.release b/Dockerfile.release new file mode 100644 index 000000000..995c22145 --- /dev/null +++ b/Dockerfile.release @@ -0,0 +1,41 @@ +FROM mingc/android-build-box:1.24.0 + +ARG ORG_GRADLE_PROJECT_RELEASE_STORE_FILE +ARG ORG_GRADLE_PROJECT_RELEASE_STORE_PASSWORD +ARG ORG_GRADLE_PROJECT_RELEASE_KEY_ALIAS +ARG ORG_GRADLE_PROJECT_RELEASE_KEY_PASSWORD +ARG ORG_GRADLE_PROJECT_MAPBOX_DOWNLOADS_TOKEN + +RUN mkdir /app +WORKDIR /app + +# rm the NDK because it breaks the build +RUN rm -rf /opt/android-sdk/ndk/current +RUN rm -rf /opt/android-sdk/ndk/23.1.7779620 + +COPY ./gradle /app/gradle +COPY ./gradlew /app +COPY ./gradle.properties /app +COPY ./settings.gradle /app +COPY ./build.gradle /app +COPY ./lcs-keystore /app/lcs-keystore + +# add a step that downloads the latest gradle wrapper before the actual build +#RUN ./gradlew help + +COPY . /app +# use the following as --build-arg variables: +# ORG_GRADLE_PROJECT_RELEASE_STORE_FILE=/app/lcs-keystore +# ORG_GRADLE_PROJECT_RELEASE_STORE_PASSWORD= +# ORG_GRADLE_PROJECT_RELEASE_KEY_ALIAS= +# ORG_GRADLE_PROJECT_RELEASE_KEY_PASSWORD= + + +RUN ./gradlew assembleRelease + +# build the image with: +# docker build --build-arg ORG_GRADLE_PROJECT_RELEASE_STORE_FILE=/app/lcs-keystore --build-arg ORG_GRADLE_PROJECT_RELEASE_STORE_PASSWORD= --build-arg ORG_GRADLE_PROJECT_RELEASE_KEY_ALIAS= --build-arg ORG_GRADLE_PROJECT_RELEASE_KEY_PASSWORD= --build-arg ORG_GRADLE_PROJECT_MAPBOX_DOWNLOADS_TOKEN= -t envirocar-app-release:latest -f Dockerfile.release . +# +# to copy the final APK from the image to the host path /tmp/envirocar: +# docker run --rm -v /tmp/envirocar:/mnt/out envirocar-app-release:latest cp /app/org.envirocar.app/build/outputs/apk/release/org.envirocar.app-release.apk /mnt/out + diff --git a/android-obd-simulator/AndroidManifest.xml b/android-obd-simulator/AndroidManifest.xml index baa2f79c2..3ef444f3c 100644 --- a/android-obd-simulator/AndroidManifest.xml +++ b/android-obd-simulator/AndroidManifest.xml @@ -27,7 +27,8 @@ android:icon="@drawable/app_icon" > + android:configChanges="orientation|keyboardHidden" + android:exported="true"> diff --git a/build.gradle b/build.gradle index 15f8a7dcb..139b96c24 100644 --- a/build.gradle +++ b/build.gradle @@ -2,7 +2,6 @@ buildscript { repositories { mavenLocal() mavenCentral() - jcenter() maven { url "https://jitpack.io" } maven { url "https://plugins.gradle.org/m2/" } google() @@ -10,15 +9,14 @@ buildscript { } dependencies { - classpath 'com.android.tools.build:gradle:3.6.3' - classpath 'com.github.dcendents:android-maven-gradle-plugin:2.1' + classpath 'com.android.tools.build:gradle:7.0.3' } } plugins { - id "com.github.dcendents.android-maven" version "2.1" - id "com.github.hierynomus.license" version "0.15.0" + id 'maven-publish' + id "com.github.hierynomus.license" version "0.16.1" } allprojects { @@ -38,19 +36,31 @@ allprojects { mavenLocal() maven { url "https://jitpack.io" } mavenCentral() - jcenter() google() + maven { + url 'https://api.mapbox.com/downloads/v2/releases/maven' + authentication { + basic(BasicAuthentication) + } + credentials { + // Do not change the username below. + // This should always be `mapbox` (not your username). + username = "mapbox" + // Use the secret token you stored in gradle.properties as the password + password = project.properties['MAPBOX_DOWNLOADS_TOKEN'] ?: "" + } + } } } ext { androidPlugin = 'com.android.tools.build:gradle:3.1.2' minSdkVersion = 21 - compileSdkVersion = 30 - targetSdkVersion = 30 + compileSdkVersion = 31 + targetSdkVersion = 31 buildToolsVersion = '30.0.2' - versionCode = 50 - versionName = "2.0.0" + versionCode = 51 + versionName = "2.1.0" ndkVersion = "21.4.7075529" javaCompileVersion = JavaVersion.VERSION_1_8 diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 393a3b99d..10fca2d74 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.4-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-7.0.2-all.zip diff --git a/org.envirocar.algorithm/build.gradle b/org.envirocar.algorithm/build.gradle index 66b0c71b3..71ca0e230 100644 --- a/org.envirocar.algorithm/build.gradle +++ b/org.envirocar.algorithm/build.gradle @@ -12,8 +12,6 @@ android { defaultConfig { minSdkVersion rootProject.ext.minSdkVersion targetSdkVersion rootProject.ext.targetSdkVersion - versionCode rootProject.ext.versionCode - versionName rootProject.ext.versionName } buildTypes { diff --git a/org.envirocar.app/AndroidManifest.xml b/org.envirocar.app/AndroidManifest.xml index 65979f233..a67fbfcf6 100644 --- a/org.envirocar.app/AndroidManifest.xml +++ b/org.envirocar.app/AndroidManifest.xml @@ -3,8 +3,9 @@ xmlns:tools="http://schemas.android.com/tools" package="org.envirocar.app" android:installLocation="internalOnly" - android:versionCode="50" - android:versionName="2.0.0"> + android:versionCode="51" + android:versionName="2.1.0" + > @@ -85,7 +86,8 @@ android:label="@string/app_name" android:launchMode="singleTop" android:screenOrientation="portrait" - android:theme="@style/Theme.Cario"> + android:theme="@style/Theme.Cario" + android:exported="true"> @@ -116,13 +118,17 @@ - + - + diff --git a/org.envirocar.app/build.gradle b/org.envirocar.app/build.gradle index 9f7cab298..86d253830 100644 --- a/org.envirocar.app/build.gradle +++ b/org.envirocar.app/build.gradle @@ -51,9 +51,9 @@ dependencies { implementation rootProject.ext.rxBindingCore implementation rootProject.ext.rxBindingAppCompat - // MapBox SDK - implementation(rootProject.ext.mapbox) { - transitive = true + //MapBox SDK + implementation (rootProject.ext.mapbox){ + exclude group: 'group_name', module: 'module_name' } // Test @@ -103,11 +103,21 @@ android { buildToolsVersion rootProject.ext.buildToolsVersion ndkVersion rootProject.ext.ndkVersion + signingConfigs { + release { + storeFile file(project.properties['RELEASE_STORE_FILE'] ?: "/tmp/tmp.key") + storePassword project.properties['RELEASE_STORE_PASSWORD'] ?: "" + keyAlias project.properties['RELEASE_KEY_ALIAS'] ?: "" + keyPassword project.properties['RELEASE_KEY_PASSWORD'] ?: "" + } + } + buildTypes { release { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' zipAlignEnabled true + signingConfig signingConfigs.release } } diff --git a/org.envirocar.app/res/layout/activity_recording_screen.xml b/org.envirocar.app/res/layout/activity_recording_screen.xml index 08db5a0aa..1150ac49f 100644 --- a/org.envirocar.app/res/layout/activity_recording_screen.xml +++ b/org.envirocar.app/res/layout/activity_recording_screen.xml @@ -76,7 +76,7 @@ android:gravity="center" android:orientation="vertical"> - - - - - - - - - - - - - - - - - - - - - - - - Dieser Username ist bereits vergeben. Diese Adresse ist bereits in Benutzung. - Keine Verbindung zum Server möglich. + Sie müssen die neueste Version der Allgemeinen Nutzungsbedingungen akzeptieren. Logge aus... Lösche alle lokal gespeicherten Kopien von hochgeladenen Fahrten. diff --git a/org.envirocar.app/res/values-de/strings_activity_settings.xml b/org.envirocar.app/res/values-de/strings_activity_settings.xml index 80c45bc0c..16ae56be9 100644 --- a/org.envirocar.app/res/values-de/strings_activity_settings.xml +++ b/org.envirocar.app/res/values-de/strings_activity_settings.xml @@ -35,7 +35,7 @@ Automatisches Hochladen Ermöglicht das automatische Hochladen von aufgenommenen Fahrten nach Beendigung der Aufnahme. Es wird lediglich direkt im Anschluss versucht den Track hochzuladen. Wenn der Upload fehlschlägt (z.B. keine Internetverbindung), muss der Track manuell hochgeladen werden. - Bildschrim bleibt aktiv + Bildschirm bleibt aktiv Bildschirm bleibt bei Aufzeichnung einer Fahrt aktiv. Imperiale Maßeinheiten (Meilen) für die Anzeige nutzen Start und Ziel verschleiern @@ -90,4 +90,15 @@ Automatische GPS Aufzeichnung Aktiviert die automatische Aufzeichnung von GPS-basierten Fahrten basierend auf Mechanismen der Aktivitätserkennung.\n\nHinweis: Diese Androidfunktion läuft bei einigen Smartphonemodellen nicht zuverlässig. + + Messkampagne + Ausgewähltes Messprofil + Wähle ein Messprofil, das kontrolliert, welche PIDs während Deiner Fahrt erfasst werden. + + + + Standard + DVFO Kampagne + + diff --git a/org.envirocar.app/res/values/strings.xml b/org.envirocar.app/res/values/strings.xml index 57ac641d1..b2cecf4bf 100644 --- a/org.envirocar.app/res/values/strings.xml +++ b/org.envirocar.app/res/values/strings.xml @@ -152,6 +152,8 @@ pref_display_always_active pref_automatic_upload prefkey_gps_mode_ar + prefkey_campaign_profile + @@ -181,4 +183,21 @@ Attribut Selection + + + + + DEFAULT_COMMAND_PROFILE + DVFO_COMMAND_PROFILE + + + @string/item_campaign_profile_default + @string/item_campaign_profile_dvfo + + + + + + public_access_token + diff --git a/org.envirocar.app/res/values/strings_activity_login.xml b/org.envirocar.app/res/values/strings_activity_login.xml index 2728abc7a..22d378391 100644 --- a/org.envirocar.app/res/values/strings_activity_login.xml +++ b/org.envirocar.app/res/values/strings_activity_login.xml @@ -36,6 +36,7 @@ This username is already in use. This email is already in use. Unable to communicate with the server. + You must accept the latest Terms of Use version. Signing out... Deleting all local data and copies of uploaded tracks. diff --git a/org.envirocar.app/res/values/strings_activity_settings.xml b/org.envirocar.app/res/values/strings_activity_settings.xml index 9e0d4cce7..b358d99a2 100644 --- a/org.envirocar.app/res/values/strings_activity_settings.xml +++ b/org.envirocar.app/res/values/strings_activity_settings.xml @@ -89,4 +89,15 @@ Automatic Recording (GPS) Activates automatic recording of GPS-based trips based on activity detection mechanisms.\n\nNote: This Android function does not work reliably on some smartphone models. + + + Measurement Campaign + Selected measurement profile + Select a measurement profile that controls which PIDs will be recorded during your ride. + + + Default + DVFO Campaign + + diff --git a/org.envirocar.app/res/xml/settings.xml b/org.envirocar.app/res/xml/settings.xml index c80f08fc0..ddd2b0c17 100644 --- a/org.envirocar.app/res/xml/settings.xml +++ b/org.envirocar.app/res/xml/settings.xml @@ -117,4 +117,17 @@ app:iconSpaceReserved="false" /> + + + + \ No newline at end of file diff --git a/org.envirocar.app/src/org/envirocar/app/exception/LoginException.java b/org.envirocar.app/src/org/envirocar/app/exception/LoginException.java index 47722f7bc..30fa37b6e 100644 --- a/org.envirocar.app/src/org/envirocar/app/exception/LoginException.java +++ b/org.envirocar.app/src/org/envirocar/app/exception/LoginException.java @@ -26,7 +26,8 @@ public class LoginException extends Exception { public enum ErrorType { MAIL_NOT_CONFIREMED, UNABLE_TO_COMMUNICATE_WITH_SERVER, - USERNAME_OR_PASSWORD_INCORRECT + USERNAME_OR_PASSWORD_INCORRECT, + TERMS_NOT_ACCEPTED } private final ErrorType type; diff --git a/org.envirocar.app/src/org/envirocar/app/handler/ApplicationSettings.java b/org.envirocar.app/src/org/envirocar/app/handler/ApplicationSettings.java index cec93d483..d1bd112d4 100644 --- a/org.envirocar.app/src/org/envirocar/app/handler/ApplicationSettings.java +++ b/org.envirocar.app/src/org/envirocar/app/handler/ApplicationSettings.java @@ -21,9 +21,10 @@ import android.bluetooth.BluetoothDevice; import android.content.Context; import android.content.SharedPreferences; -import android.preference.PreferenceManager; import android.util.Pair; +import androidx.preference.PreferenceManager; + import com.f2prateek.rx.preferences2.RxSharedPreferences; import com.google.common.base.Preconditions; @@ -51,6 +52,7 @@ public class ApplicationSettings { public static final int DEFAULT_TRACK_TRIM_DURATION = 110; public static final boolean DEFAULT_DEBUG_LOGGING = false; public static final int DEFAULT_SAMPLING_RATE = 5; + public static final String DEFAULT_CAMPAIGN_PROFILE = "DEFAULT_COMANND_PROFILE"; // // General Settings // public static final String PREF_AUTOMATIC_UPLOAD_OF_TRACKS = "pref_automatic_upload_tracks"; @@ -245,6 +247,12 @@ public static SharedPreferences getSharedPreferences(Context context) { return PreferenceManager.getDefaultSharedPreferences(context); } + public static Observable getCampaignProfileObservable(Context context){ + return getRxSharedPreferences(context) + .getString(s(context, R.string.prefkey_campaign_profile), DEFAULT_CAMPAIGN_PROFILE) + .asObservable(); + } + private static final String s(Context context, int id){ return context.getString(id); } diff --git a/org.envirocar.app/src/org/envirocar/app/handler/InterpolationMeasurementProvider.java b/org.envirocar.app/src/org/envirocar/app/handler/InterpolationMeasurementProvider.java index 68f22ab83..3259d2c13 100644 --- a/org.envirocar.app/src/org/envirocar/app/handler/InterpolationMeasurementProvider.java +++ b/org.envirocar.app/src/org/envirocar/app/handler/InterpolationMeasurementProvider.java @@ -23,6 +23,7 @@ import com.squareup.otto.Subscribe; import org.envirocar.algorithm.AbstractMeasurementProvider; +import org.envirocar.app.handler.algorithm.DataResponseAlgorithm; import org.envirocar.core.entity.Measurement; import org.envirocar.core.entity.MeasurementImpl; import org.envirocar.core.events.gps.GpsDOP; @@ -156,7 +157,15 @@ private void appendToMeasurement(Measurement.PropertyKey pk, List algorithms = DataResponseAlgorithm.fromPropertyType(pk); + if(algorithms != null){ + for(DataResponseAlgorithm a : algorithms) { + Double value = a.calculate(dataResponses); + m.setProperty(a.getPropertyKey(pk), value); + LOG.debug(String.format("Calculated %s from %s %s values: %s", + a.getPropertyKey(pk).name(), dataResponses.size(), pk.name(), value)); + } + } } private Double first(List dataResponses) { diff --git a/org.envirocar.app/src/org/envirocar/app/handler/algorithm/AbstractAccelerationAlgorithm.java b/org.envirocar.app/src/org/envirocar/app/handler/algorithm/AbstractAccelerationAlgorithm.java new file mode 100644 index 000000000..3f6f8575e --- /dev/null +++ b/org.envirocar.app/src/org/envirocar/app/handler/algorithm/AbstractAccelerationAlgorithm.java @@ -0,0 +1,25 @@ +package org.envirocar.app.handler.algorithm; + +public class AbstractAccelerationAlgorithm { + + private static final double CONV_FACTOR = 3.6; + + /** + * Calculates the acceleration in m/s² from two speed values v1 and v2 at time t1 and t2. + * + * @param start Speed at time t1 + * @param end Speed at time t2 + * @param startTime Time t1 + * @param endTime Time t2 + * @return Acceleration in m/s² + */ + public Double calculateAcceleration(Number start, Number end, long startTime, long endTime) { + if (start == null || end == null) { + return null; + } + + double dV = (end.doubleValue() - start.doubleValue()); + double dT = (endTime - startTime); + return ((dV / CONV_FACTOR) / (dT / 1000)); + } +} diff --git a/org.envirocar.app/src/org/envirocar/app/handler/algorithm/DataResponseAlgorithm.java b/org.envirocar.app/src/org/envirocar/app/handler/algorithm/DataResponseAlgorithm.java new file mode 100644 index 000000000..d9692273f --- /dev/null +++ b/org.envirocar.app/src/org/envirocar/app/handler/algorithm/DataResponseAlgorithm.java @@ -0,0 +1,28 @@ +package org.envirocar.app.handler.algorithm; + +import org.envirocar.core.entity.Measurement; +import org.envirocar.obd.events.PropertyKeyEvent; + +import java.util.Arrays; +import java.util.List; + +public interface DataResponseAlgorithm { + + Double calculate(List pke); + + Measurement.PropertyKey getPropertyKey(Measurement.PropertyKey pk); + + static List fromPropertyType(Measurement.PropertyKey pk) { + switch (pk) { + case SPEED: + case GPS_SPEED: + return Arrays.asList( + new MinAccelerationAlgorithm(), + new MaxAccelerationAlgorithm() + ); + + default: + return null; + } + } +} diff --git a/org.envirocar.app/src/org/envirocar/app/handler/algorithm/MaxAccelerationAlgorithm.java b/org.envirocar.app/src/org/envirocar/app/handler/algorithm/MaxAccelerationAlgorithm.java new file mode 100644 index 000000000..fd8dcf0bf --- /dev/null +++ b/org.envirocar.app/src/org/envirocar/app/handler/algorithm/MaxAccelerationAlgorithm.java @@ -0,0 +1,38 @@ +package org.envirocar.app.handler.algorithm; + +import org.envirocar.core.entity.Measurement; +import org.envirocar.obd.events.PropertyKeyEvent; + +import java.util.List; + +public class MaxAccelerationAlgorithm extends AbstractAccelerationAlgorithm implements DataResponseAlgorithm { + + @Override + public Double calculate(List pkes) { + if(pkes.size() < 2) { + return null; + } + double maxAcc = calculateAcceleration(pkes.get(0).getValue(), pkes.get(1).getValue(), + pkes.get(0).getTimestamp(), pkes.get(1).getTimestamp()); + + for(int i = 1; i < pkes.size() - 1; i++) { + Double acc = calculateAcceleration(pkes.get(i).getValue(), pkes.get(i + 1).getValue(), + pkes.get(i).getTimestamp(), pkes.get(i + 1).getTimestamp()); + if(acc != null && acc > maxAcc){ + maxAcc = acc; + } + } + + return maxAcc; + } + + @Override + public Measurement.PropertyKey getPropertyKey(Measurement.PropertyKey pk) { + switch (pk) { + case GPS_SPEED: + return Measurement.PropertyKey.MAX_GPS_ACCELERATION; + default: + return Measurement.PropertyKey.MAX_ACCELERATION; + } + } +} diff --git a/org.envirocar.app/src/org/envirocar/app/handler/algorithm/MinAccelerationAlgorithm.java b/org.envirocar.app/src/org/envirocar/app/handler/algorithm/MinAccelerationAlgorithm.java new file mode 100644 index 000000000..e87221cc0 --- /dev/null +++ b/org.envirocar.app/src/org/envirocar/app/handler/algorithm/MinAccelerationAlgorithm.java @@ -0,0 +1,39 @@ +package org.envirocar.app.handler.algorithm; + +import org.envirocar.core.entity.Measurement; +import org.envirocar.obd.events.PropertyKeyEvent; + +import java.util.Arrays; +import java.util.List; + +public class MinAccelerationAlgorithm extends AbstractAccelerationAlgorithm implements DataResponseAlgorithm{ + + @Override + public Double calculate(List pkes) { + if(pkes.size() < 2) { + return null; + } + double minAcc = calculateAcceleration(pkes.get(0).getValue(), pkes.get(1).getValue(), + pkes.get(0).getTimestamp(), pkes.get(1).getTimestamp()); + + for(int i = 1; i < pkes.size() - 1; i++) { + Double acc = calculateAcceleration(pkes.get(i).getValue(), pkes.get(i + 1).getValue(), + pkes.get(i).getTimestamp(), pkes.get(i + 1).getTimestamp()); + if(acc != null && acc < minAcc){ + minAcc = acc; + } + } + + return minAcc; + } + + @Override + public Measurement.PropertyKey getPropertyKey(Measurement.PropertyKey pk) { + switch (pk) { + case GPS_SPEED: + return Measurement.PropertyKey.MIN_GPS_ACCELERATION; + default: + return Measurement.PropertyKey.MIN_ACCELERATION; + } + } +} diff --git a/org.envirocar.app/src/org/envirocar/app/handler/preferences/UserPreferenceHandler.java b/org.envirocar.app/src/org/envirocar/app/handler/preferences/UserPreferenceHandler.java index e25a316d4..64bf472ff 100644 --- a/org.envirocar.app/src/org/envirocar/app/handler/preferences/UserPreferenceHandler.java +++ b/org.envirocar.app/src/org/envirocar/app/handler/preferences/UserPreferenceHandler.java @@ -32,6 +32,7 @@ import org.envirocar.core.entity.UserImpl; import org.envirocar.core.events.NewUserSettingsEvent; import org.envirocar.core.exception.MailNotConfirmedException; +import org.envirocar.core.exception.NotConnectedException; import org.envirocar.core.exception.UnauthorizedException; import org.envirocar.core.injection.InjectApplicationScope; import org.envirocar.core.logging.Logger; @@ -177,6 +178,15 @@ public Completable logIn(String user, String token, boolean withEvent) { // UnauthorizedException can be either due to Incorrect password, Incorrect Username or both. // Hence, set error to both password and username emitter.onError(new LoginException(e.getMessage(), LoginException.ErrorType.USERNAME_OR_PASSWORD_INCORRECT)); + } catch (NotConnectedException e) { + LOG.warn(e.getMessage(), e); + // UnauthorizedException can be either due to Incorrect password, Incorrect Username or both. + // Hence, set error to both password and username + if (e.getMessage().contains("Legal reasons response")) { + emitter.onError(new LoginException(e.getMessage(), LoginException.ErrorType.TERMS_NOT_ACCEPTED)); + } else { + emitter.onError(e); + } } catch (Exception e) { LOG.warn(e.getMessage(), e); emitter.onError(e); diff --git a/org.envirocar.app/src/org/envirocar/app/recording/provider/LocationProvider.java b/org.envirocar.app/src/org/envirocar/app/recording/provider/LocationProvider.java index 9cdf7c114..e417aaee2 100644 --- a/org.envirocar.app/src/org/envirocar/app/recording/provider/LocationProvider.java +++ b/org.envirocar.app/src/org/envirocar/app/recording/provider/LocationProvider.java @@ -18,6 +18,7 @@ */ package org.envirocar.app.recording.provider; +import android.annotation.SuppressLint; import android.content.Context; import android.location.GpsStatus; import android.location.Location; @@ -190,13 +191,13 @@ public LocationProvider(@InjectApplicationScope Context context, Bus bus) { } + @SuppressLint("MissingPermission") @SuppressWarnings({"ResourceType"}) public Completable startLocating() { LOGGER.info("startLocating()"); return Completable.create(emitter -> { if (!PermissionUtils.hasLocationPermission(mContext)) emitter.onError(new PermissionException("User has not activated Location permission")); - mLocationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, mLocationListener); try { diff --git a/org.envirocar.app/src/org/envirocar/app/recording/strategy/OBDRecordingStrategy.java b/org.envirocar.app/src/org/envirocar/app/recording/strategy/OBDRecordingStrategy.java index 3399430bb..170fa9a20 100644 --- a/org.envirocar.app/src/org/envirocar/app/recording/strategy/OBDRecordingStrategy.java +++ b/org.envirocar.app/src/org/envirocar/app/recording/strategy/OBDRecordingStrategy.java @@ -28,6 +28,7 @@ import com.squareup.otto.Subscribe; import org.envirocar.algorithm.MeasurementProvider; +import org.envirocar.app.R; import org.envirocar.app.handler.ApplicationSettings; import org.envirocar.app.handler.BluetoothHandler; import org.envirocar.app.handler.preferences.CarPreferenceHandler; @@ -52,6 +53,8 @@ import org.envirocar.obd.OBDController; import org.envirocar.obd.OBDSchedulers; import org.envirocar.obd.bluetooth.BluetoothSocketWrapper; +import org.envirocar.obd.commands.CampagneCommandProfile; +import org.envirocar.obd.commands.CycleCommandProfile; import org.envirocar.obd.events.SpeedUpdateEvent; import org.envirocar.obd.exception.AllAdaptersFailedException; @@ -97,6 +100,7 @@ public class OBDRecordingStrategy implements RecordingStrategy { private boolean isRecording = false; private boolean isTrackFinished = false; private Track track = null; + private CycleCommandProfile cycleCommandProfile; /** * Constructor. @@ -121,6 +125,7 @@ public OBDRecordingStrategy( this.consumptionAlgorithm = ConsumptionAlgorithm.fromFuelType(car.getFuelType()); this.mafAlgorithm = new CalculatedMAFWithStaticVolumetricEfficiency(car); this.energyConsumptionAlgorithm = new LoadBasedEnergyConsumptionAlgorithm(car.getFuelType()); + this.cycleCommandProfile = new CycleCommandProfile.Default(); } @OnLifecycleEvent(Lifecycle.Event.ON_DESTROY) @@ -154,6 +159,11 @@ public void startRecording(Service service, RecordingListener listener) { .observeOn(Schedulers.newThread()) .doOnDispose(() -> LOG.info("Location Provider has been disposed!")) .subscribe(() -> LOG.info("Completed"), LOG::error)); + + // subscribe for preference changes + disposables.add(ApplicationSettings.getCampaignProfileObservable(context) + .doOnNext(campaign -> this.cycleCommandProfile = getCycleCommandProfile(campaign)) + .subscribe()); } @Override @@ -233,8 +243,7 @@ private ObservableTransformer ve LOG.info(String.format("OBDConnectionService.onDeviceConntected(%s)", socket.getRemoteDeviceName())); try { - - OBDController controller = new OBDController(socket, new ConnectionListener() { + OBDController controller = new OBDController(socket, this.cycleCommandProfile, new ConnectionListener() { int reconnectCount = 0; @Override @@ -371,6 +380,14 @@ private void stopOBDConnectionRecognizer() { } } + private CycleCommandProfile getCycleCommandProfile(String campaign) { + if (campaign.equals(this.context.getString(R.string.item_campaign_profile_dvfo))) { + return new CampagneCommandProfile(); + } else { + return new CycleCommandProfile.Default(); + } + } + private final class OBDConnectionRecognizer { private static final long OBD_INTERVAL = 1000 * 10; // 10 seconds; private static final long GPS_INTERVAL = 1000 * 60 * 2; // 2 minutes; @@ -384,16 +401,18 @@ private final class OBDConnectionRecognizer { private Disposable mGPSCheckerSubscription; private final Runnable gpsConnectionCloser = () -> { - if (!isRunning) + if (!isRunning) { return; + } LOG.warn("CONNECTION CLOSED due to no GPS values"); stopRecording(); }; private final Runnable obdConnectionCloser = () -> { - if (!isRunning) + if (!isRunning) { return; + } LOG.warn("CONNECTION CLOSED due to no OBD values"); stopRecording(); @@ -434,10 +453,12 @@ public void onReceiveSpeedUpdateEvent(SpeedUpdateEvent event) { public void shutDown() { LOG.info("shutDown() OBDConnectionRecognizer"); this.isRunning = false; - if (mOBDCheckerSubscription != null) + if (mOBDCheckerSubscription != null) { mOBDCheckerSubscription.dispose(); - if (mGPSCheckerSubscription != null) + } + if (mGPSCheckerSubscription != null) { mGPSCheckerSubscription.dispose(); + } } } } diff --git a/org.envirocar.app/src/org/envirocar/app/views/carselection/CarSelectionActivity.java b/org.envirocar.app/src/org/envirocar/app/views/carselection/CarSelectionActivity.java index be71920f3..cab99c09f 100644 --- a/org.envirocar.app/src/org/envirocar/app/views/carselection/CarSelectionActivity.java +++ b/org.envirocar.app/src/org/envirocar/app/views/carselection/CarSelectionActivity.java @@ -19,6 +19,7 @@ package org.envirocar.app.views.carselection; import android.content.Context; +import android.content.DialogInterface; import android.os.Bundle; import com.google.android.material.dialog.MaterialAlertDialogBuilder; @@ -32,6 +33,7 @@ import android.widget.ArrayAdapter; import android.widget.ImageView; import android.widget.ListView; +import android.widget.RadioButton; import android.widget.TextView; import org.envirocar.app.BaseApplicationComponent; @@ -240,7 +242,7 @@ public void onSelectCar(Car car) { } @Override - public void onDeleteCar(Car car) { + public void onDeleteCar(Car car, RadioButton mSelectedButton) { LOG.info(String.format("onDeleteCar(%s %s %s %s)", car.getManufacturer(), car.getModel(), "" + car.getConstructionYear(), @@ -262,9 +264,11 @@ public void onDeleteCar(Car car) { showBackgroundImage(); } } + if (mSelectedButton != null) { + mSelectedButton.setChecked(false); + } // then remove it from the list and show a snackbar. mCarListAdapter.removeCarItem(car);// Nothing to do on cancel - }) .setNegativeButton(R.string.cancel,null) .show(); @@ -312,6 +316,7 @@ public void onNext(List cars) { } mCarListAdapter.notifyDataSetInvalidated(); } + }); } diff --git a/org.envirocar.app/src/org/envirocar/app/views/carselection/CarSelectionListAdapter.java b/org.envirocar.app/src/org/envirocar/app/views/carselection/CarSelectionListAdapter.java index ffbab5c30..90f7b8403 100644 --- a/org.envirocar.app/src/org/envirocar/app/views/carselection/CarSelectionListAdapter.java +++ b/org.envirocar.app/src/org/envirocar/app/views/carselection/CarSelectionListAdapter.java @@ -62,7 +62,7 @@ public interface OnCarListActionCallback { * * @param car the selected car. */ - void onDeleteCar(Car car); + void onDeleteCar(Car car, RadioButton mSelectedButton); } /** @@ -156,16 +156,8 @@ public View getView(int position, View convertView, ViewGroup parent) { .itemsCallback((materialDialog, view, i, charSequence) -> { switch (i) { case 0: - // Uncheck the the previously checked radio button and update the - // references accordingly. - if (car.equals(mSelectedCar)) { - mSelectedCar = null; - mSelectedButton.setChecked(false); - mSelectedButton = null; - } - // Call the callback - mCallback.onDeleteCar(car); + mCallback.onDeleteCar(car, mSelectedButton); break; case 1: if(car.equals(mSelectedCar)) diff --git a/org.envirocar.app/src/org/envirocar/app/views/login/SigninActivity.java b/org.envirocar.app/src/org/envirocar/app/views/login/SigninActivity.java index e66518db7..2a93f0613 100644 --- a/org.envirocar.app/src/org/envirocar/app/views/login/SigninActivity.java +++ b/org.envirocar.app/src/org/envirocar/app/views/login/SigninActivity.java @@ -242,6 +242,9 @@ public void onError(Throwable e) { case UNABLE_TO_COMMUNICATE_WITH_SERVER: passwordEditText.setError(getString(R.string.error_host_not_found), errorPassword); break; + case TERMS_NOT_ACCEPTED: + passwordEditText.setError(getString(R.string.error_terms_not_acceppted), errorPassword); + break; default: passwordEditText.setError(getString(R.string.logbook_invalid_input), errorPassword); break; diff --git a/org.envirocar.app/src/org/envirocar/app/views/obdselection/OBDSelectionFragment.java b/org.envirocar.app/src/org/envirocar/app/views/obdselection/OBDSelectionFragment.java index 1ba9d2ce7..4d7b439da 100644 --- a/org.envirocar.app/src/org/envirocar/app/views/obdselection/OBDSelectionFragment.java +++ b/org.envirocar.app/src/org/envirocar/app/views/obdselection/OBDSelectionFragment.java @@ -20,12 +20,8 @@ import android.Manifest; import android.bluetooth.BluetoothDevice; -import android.content.Context; -import android.content.Intent; -import android.location.LocationManager; import android.os.Bundle; import android.os.CountDownTimer; -import android.provider.Settings; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; @@ -42,10 +38,10 @@ import com.google.android.material.dialog.MaterialAlertDialogBuilder; import com.squareup.otto.Subscribe; +import org.envirocar.app.BaseApplicationComponent; import org.envirocar.app.R; import org.envirocar.app.handler.BluetoothHandler; import org.envirocar.app.injection.BaseInjectorFragment; -import org.envirocar.app.BaseApplicationComponent; import org.envirocar.core.events.bluetooth.BluetoothPairingChangedEvent; import org.envirocar.core.events.bluetooth.BluetoothStateChangedEvent; import org.envirocar.core.logging.Logger; @@ -66,8 +62,6 @@ import pub.devrel.easypermissions.EasyPermissions; import pub.devrel.easypermissions.PermissionRequest; -import static android.location.LocationManager.GPS_PROVIDER; - /** * TODO JavaDoc @@ -149,7 +143,7 @@ public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle @Override public void onViewCreated(@NonNull @NotNull View view, @Nullable @org.jetbrains.annotations.Nullable Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); - requestLocationPermissions(); + checkAndRequestPermissions(); } @Override @@ -172,7 +166,7 @@ public void onBluetoothStateChangedEvent(BluetoothStateChangedEvent event) { @OnClick(R.id.activity_obd_selection_layout_rescan_bluetooth) protected void rediscover() { mBluetoothHandler.stopBluetoothDeviceDiscovery(); - requestLocationPermissions(); + checkAndRequestPermissions(); } /** @@ -194,7 +188,7 @@ private void updateContentView() { } } - private final int REQUEST_LOCATION_PERMISSION = 1; + private final int BLUETOOTH_PERMISSIONS = 1; @Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { @@ -203,16 +197,31 @@ public void onRequestPermissionsResult(int requestCode, @NonNull String[] permis EasyPermissions.onRequestPermissionsResult(requestCode,permissions,grantResults,this); } - public void requestLocationPermissions() { - String[] perms = {Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.ACCESS_COARSE_LOCATION}; + public void checkAndRequestPermissions() { + String[] perms; + if (android.os.Build.VERSION.SDK_INT >= 31) { + perms = new String[]{ + Manifest.permission.ACCESS_FINE_LOCATION, + Manifest.permission.ACCESS_COARSE_LOCATION, + Manifest.permission.BLUETOOTH_CONNECT, + Manifest.permission.BLUETOOTH_SCAN + }; + } + else{ + perms = new String[]{ + Manifest.permission.ACCESS_FINE_LOCATION, + Manifest.permission.ACCESS_COARSE_LOCATION + }; + } + if (EasyPermissions.hasPermissions(getContext(), perms)){ - // if location permissions are granted, Check GPS. - requestGps(); + // if all permissions are granted, start bluetooth discovery. + startBluetoothDiscovery(); } else{ // Dialog requesting the user for location permission. EasyPermissions.requestPermissions( - new PermissionRequest.Builder(this, REQUEST_LOCATION_PERMISSION, perms) + new PermissionRequest.Builder(this, BLUETOOTH_PERMISSIONS, perms) .setRationale(R.string.location_permission_to_discover_newdevices) .setPositiveButtonText(R.string.grant_permissions) .setNegativeButtonText(R.string.cancel) @@ -223,9 +232,9 @@ public void requestLocationPermissions() { @Override public void onPermissionsGranted(int requestCode, @NonNull @NotNull List perms) { - // if location permissions are granted, Check GPS. - if (requestCode == REQUEST_LOCATION_PERMISSION) { - requestGps(); + // if location permissions are granted, start Bluetooth discovery. + if (requestCode == BLUETOOTH_PERMISSIONS) { + startBluetoothDiscovery(); showSnackbar(getString(R.string.location_permission_granted)); } } @@ -233,62 +242,15 @@ public void onPermissionsGranted(int requestCode, @NonNull @NotNull List @Override public void onPermissionsDenied(int requestCode, @NonNull @NotNull List perms) { // if permissions are not granted, show toast. - if (requestCode == REQUEST_LOCATION_PERMISSION) { + if (requestCode == BLUETOOTH_PERMISSIONS) { showSnackbar(getString(R.string.location_permission_denied)); } } - public void requestGps() { - final LocationManager manager = (LocationManager) this.getContext().getSystemService(Context.LOCATION_SERVICE); - // Check whether the GPS is turned or not - if (manager.isProviderEnabled(GPS_PROVIDER)) { - // if the GPS is also enabled, start discovery - if(isResumed) - startBluetoothDiscovery(); - } else { - // Request to turn GPS on - buildAlertMessageNoGps(); - } - } - - private void buildAlertMessageNoGps(){ - final LocationManager manager = (LocationManager) this.getContext(). - getSystemService(Context.LOCATION_SERVICE); - - new MaterialAlertDialogBuilder(getActivity(),R.style.MaterialDialog) - .setTitle(R.string.GPS_turnon_title) - .setMessage(R.string.GPS_turnon_message) - .setIcon(R.drawable.ic_location_off_white_24dp) - .setPositiveButton(R.string.GPS_turnon_yes, (dialog, which) -> { - Intent intent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS); - startActivity(intent); - - // Check if location permissions are granted and Start discovery - // only after the GPS is also turned on. - checkGpsAfterDialog(); - }) - .setNegativeButton(getString(R.string.GPS_turnon_no), (dialog, id) -> { - dialog.cancel(); - showSnackbar(getString(R.string.GPS_request_denied)); - }) - .show(); - } - @Override public void onResume() { super.onResume(); isResumed = true; - checkGpsAfterDialog(); - } - - public void checkGpsAfterDialog(){ - String[] perms = {Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.ACCESS_COARSE_LOCATION}; - final LocationManager manager = (LocationManager) this.getContext().getSystemService(Context.LOCATION_SERVICE); - - // Check whether the GPS is turned or not - if (EasyPermissions.hasPermissions(getContext(), perms) && manager.isProviderEnabled(GPS_PROVIDER) && !pairingIsRunning) { - startBluetoothDiscovery(); - } } /** diff --git a/org.envirocar.app/tests/unit/java/org/envirocar/app/handler/algorithm/MaxAccelerationAlgorithmTest.java b/org.envirocar.app/tests/unit/java/org/envirocar/app/handler/algorithm/MaxAccelerationAlgorithmTest.java new file mode 100644 index 000000000..919f9b7da --- /dev/null +++ b/org.envirocar.app/tests/unit/java/org/envirocar/app/handler/algorithm/MaxAccelerationAlgorithmTest.java @@ -0,0 +1,42 @@ +package org.envirocar.app.handler.algorithm; + +import org.envirocar.core.entity.Measurement; +import org.envirocar.obd.events.PropertyKeyEvent; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +import java.util.Arrays; +import java.util.List; + +public class MaxAccelerationAlgorithmTest { + + private MaxAccelerationAlgorithm algorithm; + + @Before + public void setup(){ + algorithm = new MaxAccelerationAlgorithm(); + } + + @Test + public void testCalculateForLessThenTwoValues(){ + PropertyKeyEvent m1 = new PropertyKeyEvent(Measurement.PropertyKey.SPEED, 16.0, 1000); + List pkes = Arrays.asList(m1); + + Assert.assertNull(algorithm.calculate(pkes)); + } + + @Test + public void test(){ + PropertyKeyEvent m1 = new PropertyKeyEvent(Measurement.PropertyKey.SPEED, 16.0, 1000); + PropertyKeyEvent m2 = new PropertyKeyEvent(Measurement.PropertyKey.SPEED, 45.0, 1300); + PropertyKeyEvent m3 = new PropertyKeyEvent(Measurement.PropertyKey.SPEED, 61.2, 1900); + PropertyKeyEvent m4 = new PropertyKeyEvent(Measurement.PropertyKey.SPEED, 126.0, 2300); + PropertyKeyEvent m5 = new PropertyKeyEvent(Measurement.PropertyKey.SPEED, null, 2900); + + List pkes = Arrays.asList(m1, m2, m3, m4, m5); + + Assert.assertEquals(45., algorithm.calculate(pkes).doubleValue(),0.0001); + } + +} diff --git a/org.envirocar.app/tests/unit/java/org/envirocar/app/handler/algorithm/MinAccelerationAlgorithmTest.java b/org.envirocar.app/tests/unit/java/org/envirocar/app/handler/algorithm/MinAccelerationAlgorithmTest.java new file mode 100644 index 000000000..7a3c28348 --- /dev/null +++ b/org.envirocar.app/tests/unit/java/org/envirocar/app/handler/algorithm/MinAccelerationAlgorithmTest.java @@ -0,0 +1,42 @@ +package org.envirocar.app.handler.algorithm; + +import org.envirocar.core.entity.Measurement; +import org.envirocar.obd.events.PropertyKeyEvent; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +import java.util.Arrays; +import java.util.List; + +public class MinAccelerationAlgorithmTest { + + private MinAccelerationAlgorithm algorithm; + + @Before + public void setup(){ + algorithm = new MinAccelerationAlgorithm(); + } + + @Test + public void testCalculateForLessThenTwoValues(){ + PropertyKeyEvent m1 = new PropertyKeyEvent(Measurement.PropertyKey.SPEED, 16.0, 1000); + List pkes = Arrays.asList(m1); + + Assert.assertNull(algorithm.calculate(pkes)); + } + + @Test + public void test(){ + PropertyKeyEvent m1 = new PropertyKeyEvent(Measurement.PropertyKey.SPEED, 16.0, 1000); + PropertyKeyEvent m2 = new PropertyKeyEvent(Measurement.PropertyKey.SPEED, 45.0, 1300); + PropertyKeyEvent m3 = new PropertyKeyEvent(Measurement.PropertyKey.SPEED, 61.2, 1900); + PropertyKeyEvent m4 = new PropertyKeyEvent(Measurement.PropertyKey.SPEED, 126.0, 2300); + PropertyKeyEvent m5 = new PropertyKeyEvent(Measurement.PropertyKey.SPEED, null, 2900); + + List pkes = Arrays.asList(m1, m2, m3, m4, m5); + + Assert.assertEquals(7.5, algorithm.calculate(pkes).doubleValue(),0.0001); + } + +} diff --git a/org.envirocar.core/build.gradle b/org.envirocar.core/build.gradle index c3075c3dd..9805a3f19 100644 --- a/org.envirocar.core/build.gradle +++ b/org.envirocar.core/build.gradle @@ -12,8 +12,6 @@ android { defaultConfig { minSdkVersion rootProject.ext.minSdkVersion targetSdkVersion rootProject.ext.targetSdkVersion - versionCode rootProject.ext.versionCode - versionName rootProject.ext.versionName } } diff --git a/org.envirocar.core/src/main/java/org/envirocar/core/entity/Measurement.java b/org.envirocar.core/src/main/java/org/envirocar/core/entity/Measurement.java index fe90aff5b..c5d048d85 100644 --- a/org.envirocar.core/src/main/java/org/envirocar/core/entity/Measurement.java +++ b/org.envirocar.core/src/main/java/org/envirocar/core/entity/Measurement.java @@ -335,8 +335,53 @@ public int getStringResource() { public String toString() { return "Short-Term Fuel Trim 1"; } + }, + MIN_ACCELERATION { + @Override + public int getStringResource() { + return R.string.property_key_min_acceleration; + } + + @Override + public String toString() { + return "Minimum Acceleration"; + } + }, + MAX_ACCELERATION { + @Override + public int getStringResource() { + return R.string.property_key_max_acceleration; + } + + @Override + public String toString() { + return "Maximum Acceleration"; + } + }, + MIN_GPS_ACCELERATION { + @Override + public int getStringResource() { + return R.string.property_key_min_gps_acceleration; + } + + @Override + public String toString() { + return "Minimum GPS Acceleration"; + } + }, + MAX_GPS_ACCELERATION { + @Override + public int getStringResource() { + return R.string.property_key_max_gps_acceleration; + } + + @Override + public String toString() { + return "Maximum GPS Acceleration"; + } }; + @Override public int getUnitResource() { return -1; diff --git a/org.envirocar.core/src/main/java/org/envirocar/core/utils/PermissionUtils.java b/org.envirocar.core/src/main/java/org/envirocar/core/utils/PermissionUtils.java index 9ee04f09c..a47df94a6 100644 --- a/org.envirocar.core/src/main/java/org/envirocar/core/utils/PermissionUtils.java +++ b/org.envirocar.core/src/main/java/org/envirocar/core/utils/PermissionUtils.java @@ -34,10 +34,12 @@ public class PermissionUtils { public static final int LOCATION_PERMISSION_REQUEST_CODE = 89; - + public static boolean hasLocationPermission(Context Context) { return ActivityCompat.checkSelfPermission(Context, Manifest.permission.ACCESS_FINE_LOCATION) - == PackageManager.PERMISSION_GRANTED; + == PackageManager.PERMISSION_GRANTED && + ActivityCompat.checkSelfPermission(Context, Manifest.permission.ACCESS_COARSE_LOCATION) + == PackageManager.PERMISSION_GRANTED; } public static Completable requestLocationPermissionIfRequired(Activity activity) { diff --git a/org.envirocar.core/src/main/res/values-de/strings_property_keys.xml b/org.envirocar.core/src/main/res/values-de/strings_property_keys.xml index ec9ec767c..e28bc1aa9 100644 --- a/org.envirocar.core/src/main/res/values-de/strings_property_keys.xml +++ b/org.envirocar.core/src/main/res/values-de/strings_property_keys.xml @@ -49,5 +49,9 @@ Fuel System Status Code Long-Term Fuel Trim 1 Short-Term Fuel Trim 1 + Minimale Beschleunigung + Maximale Beschleunigung + Minimale GPS Beschleunigung + Maximale GPS Beschleunigung diff --git a/org.envirocar.core/src/main/res/values/strings_property_keys.xml b/org.envirocar.core/src/main/res/values/strings_property_keys.xml index aa9cc7170..c24d01163 100644 --- a/org.envirocar.core/src/main/res/values/strings_property_keys.xml +++ b/org.envirocar.core/src/main/res/values/strings_property_keys.xml @@ -49,5 +49,9 @@ Fuel System Status Code Long-Term Fuel Trim 1 Short-Term Fuel Trim 1 + Minimum Acceleration + Maximum Acceleration + Minimum GPS Acceleration + Maximum GPS Acceleration diff --git a/org.envirocar.obd/build.gradle b/org.envirocar.obd/build.gradle index 7c09479a5..99b3093fb 100644 --- a/org.envirocar.obd/build.gradle +++ b/org.envirocar.obd/build.gradle @@ -12,8 +12,6 @@ android { defaultConfig { minSdkVersion rootProject.ext.minSdkVersion targetSdkVersion rootProject.ext.targetSdkVersion - versionCode rootProject.ext.versionCode - versionName rootProject.ext.versionName } buildTypes { diff --git a/org.envirocar.obd/src/main/java/org/envirocar/obd/OBDController.java b/org.envirocar.obd/src/main/java/org/envirocar/obd/OBDController.java index 9783516c4..40485eaaf 100644 --- a/org.envirocar.obd/src/main/java/org/envirocar/obd/OBDController.java +++ b/org.envirocar.obd/src/main/java/org/envirocar/obd/OBDController.java @@ -31,6 +31,7 @@ import org.envirocar.obd.adapter.UniCarScanAdapter; import org.envirocar.obd.adapter.async.DriveDeckSportAdapter; import org.envirocar.obd.bluetooth.BluetoothSocketWrapper; +import org.envirocar.obd.commands.CycleCommandProfile; import org.envirocar.obd.commands.PID; import org.envirocar.obd.commands.PIDUtil; import org.envirocar.obd.commands.response.DataResponse; @@ -39,8 +40,6 @@ import org.envirocar.obd.events.SpeedUpdateEvent; import org.envirocar.obd.exception.AllAdaptersFailedException; import org.envirocar.obd.exception.EngineNotRunningException; -import org.reactivestreams.Subscriber; -import org.reactivestreams.Subscription; import java.io.IOException; import java.io.InputStream; @@ -49,7 +48,6 @@ import java.util.Queue; import java.util.concurrent.TimeUnit; -import io.reactivex.Observer; import io.reactivex.Scheduler; import io.reactivex.disposables.Disposable; import io.reactivex.observers.DisposableObserver; @@ -80,6 +78,7 @@ public class OBDController { private boolean userRequestedStop = false; private Bus eventBus; private Scheduler.Worker eventBusWorker; + private CycleCommandProfile commandProfile; /** * Default Constructor. @@ -93,9 +92,18 @@ public OBDController(BluetoothSocketWrapper bluetoothSocketWrapper, ConnectionLi this(bluetoothSocketWrapper.getInputStream(), bluetoothSocketWrapper.getOutputStream(), bluetoothSocketWrapper.getRemoteDeviceName(), + new CycleCommandProfile.Default(), cl, bus); } + public OBDController(BluetoothSocketWrapper bluetoothSocketWrapper, CycleCommandProfile cmp, + ConnectionListener cl, Bus bus) throws IOException { + this(bluetoothSocketWrapper.getInputStream(), + bluetoothSocketWrapper.getOutputStream(), + bluetoothSocketWrapper.getRemoteDeviceName(), + cmp, cl, bus); + } + /** * Init the OBD control layer with the streams and listeners to be used. * @@ -103,12 +111,13 @@ public OBDController(BluetoothSocketWrapper bluetoothSocketWrapper, ConnectionLi * @param out the outputStream of the connection * @param cl the connection listener which receives connection state changes */ - public OBDController(InputStream in, OutputStream out, - String deviceName, ConnectionListener cl, Bus bus) { + public OBDController(InputStream in, OutputStream out, String deviceName, + CycleCommandProfile cmp, ConnectionListener cl, Bus bus) { this.inputStream = Preconditions.checkNotNull(in); this.outputStream = Preconditions.checkNotNull(out); this.connectionListener = Preconditions.checkNotNull(cl); this.deviceName = Preconditions.checkNotNull(deviceName); + this.commandProfile = cmp; setupAdapterCandidates(); startPreferredAdapter(); @@ -124,11 +133,11 @@ public OBDController(InputStream in, OutputStream out, */ private void setupAdapterCandidates() { adapterCandidates.clear(); - adapterCandidates.offer(new ELM327Adapter()); - adapterCandidates.offer(new UniCarScanAdapter()); - adapterCandidates.offer(new OBDLinkAdapter()); - adapterCandidates.offer(new CarTrendAdapter()); - adapterCandidates.offer(new AposW3Adapter()); + adapterCandidates.offer(new ELM327Adapter(this.commandProfile)); + adapterCandidates.offer(new UniCarScanAdapter(this.commandProfile)); + adapterCandidates.offer(new OBDLinkAdapter(this.commandProfile)); + adapterCandidates.offer(new CarTrendAdapter(this.commandProfile)); + adapterCandidates.offer(new AposW3Adapter(this.commandProfile)); adapterCandidates.offer(new DriveDeckSportAdapter()); } diff --git a/org.envirocar.obd/src/main/java/org/envirocar/obd/adapter/AposW3Adapter.java b/org.envirocar.obd/src/main/java/org/envirocar/obd/adapter/AposW3Adapter.java index fecc6919d..0b92b1820 100644 --- a/org.envirocar.obd/src/main/java/org/envirocar/obd/adapter/AposW3Adapter.java +++ b/org.envirocar.obd/src/main/java/org/envirocar/obd/adapter/AposW3Adapter.java @@ -18,6 +18,7 @@ */ package org.envirocar.obd.adapter; +import org.envirocar.obd.commands.CycleCommandProfile; import org.envirocar.obd.commands.request.BasicCommand; import org.envirocar.obd.commands.request.elm.ConfigurationCommand; import org.envirocar.obd.commands.request.elm.DelayedConfigurationCommand; @@ -32,6 +33,10 @@ */ public class AposW3Adapter extends ELM327Adapter { + public AposW3Adapter(CycleCommandProfile cmp) { + super(cmp); + } + @Override protected Queue createInitCommands() { Queue result = new ArrayDeque<>(); diff --git a/org.envirocar.obd/src/main/java/org/envirocar/obd/adapter/CarTrendAdapter.java b/org.envirocar.obd/src/main/java/org/envirocar/obd/adapter/CarTrendAdapter.java index 4881251e6..c82d15a89 100644 --- a/org.envirocar.obd/src/main/java/org/envirocar/obd/adapter/CarTrendAdapter.java +++ b/org.envirocar.obd/src/main/java/org/envirocar/obd/adapter/CarTrendAdapter.java @@ -21,6 +21,7 @@ import android.util.Base64; import org.envirocar.core.logging.Logger; +import org.envirocar.obd.commands.CycleCommandProfile; import org.envirocar.obd.commands.request.BasicCommand; import org.envirocar.obd.commands.request.PIDCommand; import org.envirocar.obd.exception.AdapterFailedException; @@ -50,6 +51,10 @@ public class CarTrendAdapter extends SyncAdapter { private int initialCount; private ByteArrayOutputStream initialPhaseResponseLog = new ByteArrayOutputStream(); + public CarTrendAdapter(CycleCommandProfile cmp) { + super(cmp); + } + @Override protected BasicCommand pollNextInitializationCommand() { if (this.initializeRing == null) { diff --git a/org.envirocar.obd/src/main/java/org/envirocar/obd/adapter/ELM327Adapter.java b/org.envirocar.obd/src/main/java/org/envirocar/obd/adapter/ELM327Adapter.java index bfb5277fe..967951c72 100644 --- a/org.envirocar.obd/src/main/java/org/envirocar/obd/adapter/ELM327Adapter.java +++ b/org.envirocar.obd/src/main/java/org/envirocar/obd/adapter/ELM327Adapter.java @@ -21,6 +21,7 @@ import android.util.Base64; import org.envirocar.core.logging.Logger; +import org.envirocar.obd.commands.CycleCommandProfile; import org.envirocar.obd.commands.request.BasicCommand; import org.envirocar.obd.commands.request.PIDCommand; import org.envirocar.obd.commands.request.elm.ConfigurationCommand; @@ -47,6 +48,10 @@ public class ELM327Adapter extends SyncAdapter { protected int succesfulCount; protected boolean certifiedConnection; + public ELM327Adapter(CycleCommandProfile cmp) { + super(cmp); + } + @Override protected BasicCommand pollNextInitializationCommand() { diff --git a/org.envirocar.obd/src/main/java/org/envirocar/obd/adapter/OBDLinkAdapter.java b/org.envirocar.obd/src/main/java/org/envirocar/obd/adapter/OBDLinkAdapter.java index 0cd16ecd9..d8271a724 100644 --- a/org.envirocar.obd/src/main/java/org/envirocar/obd/adapter/OBDLinkAdapter.java +++ b/org.envirocar.obd/src/main/java/org/envirocar/obd/adapter/OBDLinkAdapter.java @@ -21,6 +21,7 @@ import android.util.Base64; import org.envirocar.core.logging.Logger; +import org.envirocar.obd.commands.CycleCommandProfile; import org.envirocar.obd.commands.request.BasicCommand; import org.envirocar.obd.commands.request.elm.ConfigurationCommand; import org.envirocar.obd.commands.request.elm.Timeout; @@ -35,6 +36,10 @@ public class OBDLinkAdapter extends ELM327Adapter{ private static final Logger LOG = Logger.getLogger(OBDLinkAdapter.class); + public OBDLinkAdapter(CycleCommandProfile cmp) { + super(cmp); + } + @Override protected Queue createInitCommands() { Queue result = new ArrayDeque<>(); diff --git a/org.envirocar.obd/src/main/java/org/envirocar/obd/adapter/SyncAdapter.java b/org.envirocar.obd/src/main/java/org/envirocar/obd/adapter/SyncAdapter.java index e17d80adf..d02aaa616 100644 --- a/org.envirocar.obd/src/main/java/org/envirocar/obd/adapter/SyncAdapter.java +++ b/org.envirocar.obd/src/main/java/org/envirocar/obd/adapter/SyncAdapter.java @@ -21,6 +21,8 @@ import android.util.Base64; import org.envirocar.core.logging.Logger; +import org.envirocar.obd.commands.CampagneCommandProfile; +import org.envirocar.obd.commands.CycleCommandProfile; import org.envirocar.obd.commands.PID; import org.envirocar.obd.commands.PIDSupported; import org.envirocar.obd.commands.PIDUtil; @@ -80,6 +82,11 @@ public abstract class SyncAdapter implements OBDAdapter { new PIDSupported("40"), new PIDSupported("80"))); + private CycleCommandProfile commandProfile; + + public SyncAdapter (CycleCommandProfile cmp) { + this.commandProfile = cmp; + } @Override public Observable initialize(InputStream is, OutputStream os) { @@ -204,6 +211,9 @@ public Observable observe() { if (response != null) { LOGGER.debug("isDisposed? " + subscriber.isDisposed()); + LOGGER.debug(String.format("Received data response: {%s=%s}", + response.getPid(), + response.getValue())); subscriber.onNext(response); } } catch (IOException e) { @@ -276,7 +286,7 @@ protected List defaultCycleCommands() { if (requestCommands == null) { requestCommands = new ArrayList<>(); - for (PID p : PID.values()) { + for (PID p : commandProfile.provideCommands()) { addIfSupported(p); } diff --git a/org.envirocar.obd/src/main/java/org/envirocar/obd/adapter/UniCarScanAdapter.java b/org.envirocar.obd/src/main/java/org/envirocar/obd/adapter/UniCarScanAdapter.java index bf5ed5f13..b06ff5303 100644 --- a/org.envirocar.obd/src/main/java/org/envirocar/obd/adapter/UniCarScanAdapter.java +++ b/org.envirocar.obd/src/main/java/org/envirocar/obd/adapter/UniCarScanAdapter.java @@ -18,7 +18,13 @@ */ package org.envirocar.obd.adapter; +import org.envirocar.obd.commands.CycleCommandProfile; + public class UniCarScanAdapter extends OBDLinkAdapter{ + public UniCarScanAdapter(CycleCommandProfile cmp) { + super(cmp); + } + @Override public boolean supportsDevice(String deviceName) { return deviceName.contains("UniCarScan"); diff --git a/org.envirocar.obd/src/main/java/org/envirocar/obd/commands/CampagneCommandProfile.java b/org.envirocar.obd/src/main/java/org/envirocar/obd/commands/CampagneCommandProfile.java new file mode 100644 index 000000000..c466f0d73 --- /dev/null +++ b/org.envirocar.obd/src/main/java/org/envirocar/obd/commands/CampagneCommandProfile.java @@ -0,0 +1,42 @@ +/** + * Copyright (C) 2013 - 2021 the enviroCar community + * + * This file is part of the enviroCar app. + * + * The enviroCar app is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License as published + * by the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The enviroCar app is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General + * Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with the enviroCar app. If not, see http://www.gnu.org/licenses/. + */ +package org.envirocar.obd.commands; + +import java.util.ArrayList; +import java.util.List; + +public class CampagneCommandProfile implements CycleCommandProfile { + + private List result = new ArrayList(); + + public CampagneCommandProfile() { + result.add(PID.SPEED); + result.add(PID.FUEL_PRESSURE); + result.add(PID.INTAKE_MAP); + result.add(PID.SPEED); + result.add(PID.RPM); + result.add(PID.INTAKE_AIR_TEMP); + result.add(PID.MAF); + } + + public List provideCommands() { + return result; + }; + +} \ No newline at end of file diff --git a/org.envirocar.obd/src/main/java/org/envirocar/obd/commands/CycleCommandProfile.java b/org.envirocar.obd/src/main/java/org/envirocar/obd/commands/CycleCommandProfile.java new file mode 100644 index 000000000..052d93c09 --- /dev/null +++ b/org.envirocar.obd/src/main/java/org/envirocar/obd/commands/CycleCommandProfile.java @@ -0,0 +1,35 @@ +/** + * Copyright (C) 2013 - 2021 the enviroCar community + * + * This file is part of the enviroCar app. + * + * The enviroCar app is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License as published + * by the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The enviroCar app is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General + * Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with the enviroCar app. If not, see http://www.gnu.org/licenses/. + */ +package org.envirocar.obd.commands; + +import java.util.Arrays; +import java.util.List; + +public interface CycleCommandProfile { + + default List provideCommands() { + return Arrays.asList(PID.values()); + }; + + + public static class Default implements CycleCommandProfile { + + } + +} \ No newline at end of file diff --git a/org.envirocar.obd/src/main/java/org/envirocar/obd/commands/PID.java b/org.envirocar.obd/src/main/java/org/envirocar/obd/commands/PID.java index 0696d21e6..a05d830e5 100644 --- a/org.envirocar.obd/src/main/java/org/envirocar/obd/commands/PID.java +++ b/org.envirocar.obd/src/main/java/org/envirocar/obd/commands/PID.java @@ -20,12 +20,12 @@ public enum PID implements PIDEnumInstance { -// FUEL_SYSTEM_STATUS { -// @Override -// public String getHexadecimalRepresentation() { -// return "03"; -// } -// }, + FUEL_SYSTEM_STATUS { + @Override + public String getHexadecimalRepresentation() { + return "03"; + } + }, CALCULATED_ENGINE_LOAD { @Override public String getHexadecimalRepresentation() { diff --git a/org.envirocar.remote/build.gradle b/org.envirocar.remote/build.gradle index f8b6435af..b44957108 100644 --- a/org.envirocar.remote/build.gradle +++ b/org.envirocar.remote/build.gradle @@ -12,8 +12,6 @@ android { defaultConfig { minSdkVersion rootProject.ext.minSdkVersion targetSdkVersion rootProject.ext.targetSdkVersion - versionCode rootProject.ext.versionCode - versionName rootProject.ext.versionName } buildTypes { diff --git a/org.envirocar.remote/src/main/java/org/envirocar/remote/dao/BaseRemoteDAO.java b/org.envirocar.remote/src/main/java/org/envirocar/remote/dao/BaseRemoteDAO.java index c99f1821a..2e17db73c 100644 --- a/org.envirocar.remote/src/main/java/org/envirocar/remote/dao/BaseRemoteDAO.java +++ b/org.envirocar.remote/src/main/java/org/envirocar/remote/dao/BaseRemoteDAO.java @@ -82,7 +82,7 @@ protected Response executeCall(Call call) throws IOException, // assert the responsecode if it was not an success. if (!response.isSuccessful()) { ResponseBody body = response.errorBody(); - EnvirocarServiceUtils.assertStatusCode(response.code(), response.message(), body.string()); + EnvirocarServiceUtils.assertStatusCode(response.code(), response.message(), body.string(), call.request().url().toString()); } return response; diff --git a/org.envirocar.remote/src/main/java/org/envirocar/remote/serde/TrackSerde.java b/org.envirocar.remote/src/main/java/org/envirocar/remote/serde/TrackSerde.java index b637716c5..16231bf64 100644 --- a/org.envirocar.remote/src/main/java/org/envirocar/remote/serde/TrackSerde.java +++ b/org.envirocar.remote/src/main/java/org/envirocar/remote/serde/TrackSerde.java @@ -77,6 +77,10 @@ import static org.envirocar.core.entity.Measurement.PropertyKey.LAMBDA_VOLTAGE_ER; import static org.envirocar.core.entity.Measurement.PropertyKey.LONG_TERM_TRIM_1; import static org.envirocar.core.entity.Measurement.PropertyKey.MAF; +import static org.envirocar.core.entity.Measurement.PropertyKey.MAX_ACCELERATION; +import static org.envirocar.core.entity.Measurement.PropertyKey.MAX_GPS_ACCELERATION; +import static org.envirocar.core.entity.Measurement.PropertyKey.MIN_ACCELERATION; +import static org.envirocar.core.entity.Measurement.PropertyKey.MIN_GPS_ACCELERATION; import static org.envirocar.core.entity.Measurement.PropertyKey.RPM; import static org.envirocar.core.entity.Measurement.PropertyKey.SHORT_TERM_TRIM_1; import static org.envirocar.core.entity.Measurement.PropertyKey.SPEED; @@ -119,6 +123,10 @@ public class TrackSerde extends AbstractJsonSerde implements JsonSerializer response) throws public static final void assertStatusCode(int httpStatusCode, String error, String body) throws UnauthorizedException, NotConnectedException, ResourceConflictException { + assertStatusCode(httpStatusCode, error, body, null); + } + + public static final void assertStatusCode(int httpStatusCode, String error, String body, String requestUrl) throws + UnauthorizedException, NotConnectedException, ResourceConflictException { LOG.info("Assert Status code " + httpStatusCode + " " + error); + + if (requestUrl != null) { + LOG.info("Requested URL: " + requestUrl); + } + if (httpStatusCode >= HTTP_MULTIPLE_CHOICES) { LOG.info(body); if (httpStatusCode == HTTP_UNAUTHORIZED || httpStatusCode == HTTP_FORBIDDEN) { diff --git a/org.envirocar.storage/build.gradle b/org.envirocar.storage/build.gradle index c2728eb8e..832b85ec0 100644 --- a/org.envirocar.storage/build.gradle +++ b/org.envirocar.storage/build.gradle @@ -12,8 +12,6 @@ android { defaultConfig { minSdkVersion rootProject.ext.minSdkVersion targetSdkVersion rootProject.ext.targetSdkVersion - versionCode rootProject.ext.versionCode - versionName rootProject.ext.versionName } }