From 5a8d00ce6b052dc1408184eb1bd646760c0c54f3 Mon Sep 17 00:00:00 2001 From: bitscuit Date: Sat, 6 Mar 2021 14:45:16 +0100 Subject: [PATCH] Initial code upload --- .gitignore | 15 + .idea/.name | 1 + .idea/codeStyles/Project.xml | 116 +++++ .idea/jarRepositories.xml | 25 + .idea/misc.xml | 9 + .idea/runConfigurations.xml | 12 + app/.gitignore | 1 + app/build.gradle | 36 ++ app/proguard-rules.pro | 21 + .../gpslogger/ExampleInstrumentedTest.java | 26 ++ app/src/main/AndroidManifest.xml | 25 + .../be/bitscuit/gpslogger/LocationEvent.java | 38 ++ .../gpslogger/LocationEventListener.java | 5 + .../be/bitscuit/gpslogger/LoggerService.java | 146 ++++++ .../be/bitscuit/gpslogger/MainActivity.java | 426 ++++++++++++++++++ .../main/java/be/bitscuit/gpslogger/Util.java | 14 + .../drawable-v24/ic_launcher_foreground.xml | 30 ++ .../res/drawable/ic_launcher_background.xml | 170 +++++++ app/src/main/res/drawable/location_on.png | Bin 0 -> 843 bytes app/src/main/res/layout/activity_main.xml | 45 ++ .../res/mipmap-anydpi-v26/ic_launcher.xml | 5 + .../mipmap-anydpi-v26/ic_launcher_round.xml | 5 + app/src/main/res/mipmap-hdpi/ic_launcher.png | Bin 0 -> 3593 bytes .../res/mipmap-hdpi/ic_launcher_round.png | Bin 0 -> 5339 bytes app/src/main/res/mipmap-mdpi/ic_launcher.png | Bin 0 -> 2636 bytes .../res/mipmap-mdpi/ic_launcher_round.png | Bin 0 -> 3388 bytes app/src/main/res/mipmap-xhdpi/ic_launcher.png | Bin 0 -> 4926 bytes .../res/mipmap-xhdpi/ic_launcher_round.png | Bin 0 -> 7472 bytes .../main/res/mipmap-xxhdpi/ic_launcher.png | Bin 0 -> 7909 bytes .../res/mipmap-xxhdpi/ic_launcher_round.png | Bin 0 -> 11873 bytes .../main/res/mipmap-xxxhdpi/ic_launcher.png | Bin 0 -> 10652 bytes .../res/mipmap-xxxhdpi/ic_launcher_round.png | Bin 0 -> 16570 bytes app/src/main/res/values/colors.xml | 6 + app/src/main/res/values/strings.xml | 3 + app/src/main/res/values/styles.xml | 10 + .../bitscuit/gpslogger/ExampleUnitTest.java | 17 + build.gradle | 24 + gradle.properties | 19 + gradle/wrapper/gradle-wrapper.properties | 6 + gradlew | 172 +++++++ gradlew.bat | 84 ++++ settings.gradle | 2 + 42 files changed, 1514 insertions(+) create mode 100644 .idea/.name create mode 100644 .idea/codeStyles/Project.xml create mode 100644 .idea/jarRepositories.xml create mode 100644 .idea/misc.xml create mode 100644 .idea/runConfigurations.xml create mode 100644 app/.gitignore create mode 100644 app/build.gradle create mode 100644 app/proguard-rules.pro create mode 100644 app/src/androidTest/java/be/bitscuit/gpslogger/ExampleInstrumentedTest.java create mode 100644 app/src/main/AndroidManifest.xml create mode 100644 app/src/main/java/be/bitscuit/gpslogger/LocationEvent.java create mode 100644 app/src/main/java/be/bitscuit/gpslogger/LocationEventListener.java create mode 100644 app/src/main/java/be/bitscuit/gpslogger/LoggerService.java create mode 100644 app/src/main/java/be/bitscuit/gpslogger/MainActivity.java create mode 100644 app/src/main/java/be/bitscuit/gpslogger/Util.java create mode 100644 app/src/main/res/drawable-v24/ic_launcher_foreground.xml create mode 100644 app/src/main/res/drawable/ic_launcher_background.xml create mode 100644 app/src/main/res/drawable/location_on.png create mode 100644 app/src/main/res/layout/activity_main.xml create mode 100644 app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml create mode 100644 app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml create mode 100644 app/src/main/res/mipmap-hdpi/ic_launcher.png create mode 100644 app/src/main/res/mipmap-hdpi/ic_launcher_round.png create mode 100644 app/src/main/res/mipmap-mdpi/ic_launcher.png create mode 100644 app/src/main/res/mipmap-mdpi/ic_launcher_round.png create mode 100644 app/src/main/res/mipmap-xhdpi/ic_launcher.png create mode 100644 app/src/main/res/mipmap-xhdpi/ic_launcher_round.png create mode 100644 app/src/main/res/mipmap-xxhdpi/ic_launcher.png create mode 100644 app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png create mode 100644 app/src/main/res/mipmap-xxxhdpi/ic_launcher.png create mode 100644 app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png create mode 100644 app/src/main/res/values/colors.xml create mode 100644 app/src/main/res/values/strings.xml create mode 100644 app/src/main/res/values/styles.xml create mode 100644 app/src/test/java/be/bitscuit/gpslogger/ExampleUnitTest.java create mode 100644 build.gradle create mode 100644 gradle.properties create mode 100644 gradle/wrapper/gradle-wrapper.properties create mode 100755 gradlew create mode 100644 gradlew.bat create mode 100644 settings.gradle diff --git a/.gitignore b/.gitignore index ddbbaa3..64f1954 100644 --- a/.gitignore +++ b/.gitignore @@ -113,3 +113,18 @@ lint/tmp/ # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml hs_err_pid* +# -------> Android Studio generated rules +*.iml +.gradle +/local.properties +/.idea/caches +/.idea/libraries +/.idea/modules.xml +/.idea/workspace.xml +/.idea/navEditor.xml +/.idea/assetWizardSettings.xml +.DS_Store +/build +/captures +.externalNativeBuild +.cxx diff --git a/.idea/.name b/.idea/.name new file mode 100644 index 0000000..cc68f60 --- /dev/null +++ b/.idea/.name @@ -0,0 +1 @@ +GPS Logger \ No newline at end of file diff --git a/.idea/codeStyles/Project.xml b/.idea/codeStyles/Project.xml new file mode 100644 index 0000000..681f41a --- /dev/null +++ b/.idea/codeStyles/Project.xml @@ -0,0 +1,116 @@ + + + + + + + +
+ + + + xmlns:android + + ^$ + + + +
+
+ + + + xmlns:.* + + ^$ + + + BY_NAME + +
+
+ + + + .*:id + + http://schemas.android.com/apk/res/android + + + +
+
+ + + + .*:name + + http://schemas.android.com/apk/res/android + + + +
+
+ + + + name + + ^$ + + + +
+
+ + + + style + + ^$ + + + +
+
+ + + + .* + + ^$ + + + BY_NAME + +
+
+ + + + .* + + http://schemas.android.com/apk/res/android + + + ANDROID_ATTRIBUTE_ORDER + +
+
+ + + + .* + + .* + + + BY_NAME + +
+
+
+
+
+
\ No newline at end of file diff --git a/.idea/jarRepositories.xml b/.idea/jarRepositories.xml new file mode 100644 index 0000000..a5f05cd --- /dev/null +++ b/.idea/jarRepositories.xml @@ -0,0 +1,25 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..37a7509 --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,9 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/runConfigurations.xml b/.idea/runConfigurations.xml new file mode 100644 index 0000000..7f68460 --- /dev/null +++ b/.idea/runConfigurations.xml @@ -0,0 +1,12 @@ + + + + + + \ No newline at end of file diff --git a/app/.gitignore b/app/.gitignore new file mode 100644 index 0000000..42afabf --- /dev/null +++ b/app/.gitignore @@ -0,0 +1 @@ +/build \ No newline at end of file diff --git a/app/build.gradle b/app/build.gradle new file mode 100644 index 0000000..49d2b52 --- /dev/null +++ b/app/build.gradle @@ -0,0 +1,36 @@ +apply plugin: 'com.android.application' + +android { + compileSdkVersion 29 + buildToolsVersion "29.0.3" + + defaultConfig { + applicationId "be.bitscuit.gpslogger" + minSdkVersion 16 + targetSdkVersion 29 + versionCode 1 + versionName "1.0" + + testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" + } + + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' + } + } +} + +dependencies { + implementation fileTree(dir: "libs", include: ["*.jar"]) + implementation 'androidx.appcompat:appcompat:1.1.0' + implementation 'androidx.constraintlayout:constraintlayout:1.1.3' + testImplementation 'junit:junit:4.12' + androidTestImplementation 'androidx.test.ext:junit:1.1.1' + androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0' + + implementation 'com.google.android.gms:play-services-location:17.0.0' + implementation 'com.codebutchery.android:gpx_lib:1.0.3' + +} \ No newline at end of file diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro new file mode 100644 index 0000000..481bb43 --- /dev/null +++ b/app/proguard-rules.pro @@ -0,0 +1,21 @@ +# Add project specific ProGuard rules here. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile \ No newline at end of file diff --git a/app/src/androidTest/java/be/bitscuit/gpslogger/ExampleInstrumentedTest.java b/app/src/androidTest/java/be/bitscuit/gpslogger/ExampleInstrumentedTest.java new file mode 100644 index 0000000..7e94115 --- /dev/null +++ b/app/src/androidTest/java/be/bitscuit/gpslogger/ExampleInstrumentedTest.java @@ -0,0 +1,26 @@ +package be.bitscuit.gpslogger; + +import android.content.Context; + +import androidx.test.platform.app.InstrumentationRegistry; +import androidx.test.ext.junit.runners.AndroidJUnit4; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import static org.junit.Assert.*; + +/** + * Instrumented test, which will execute on an Android device. + * + * @see Testing documentation + */ +@RunWith(AndroidJUnit4.class) +public class ExampleInstrumentedTest { + @Test + public void useAppContext() { + // Context of the app under test. + Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext(); + assertEquals("be.bitscuit.gpslogger", appContext.getPackageName()); + } +} \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml new file mode 100644 index 0000000..b8d2149 --- /dev/null +++ b/app/src/main/AndroidManifest.xml @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/java/be/bitscuit/gpslogger/LocationEvent.java b/app/src/main/java/be/bitscuit/gpslogger/LocationEvent.java new file mode 100644 index 0000000..1a9b97c --- /dev/null +++ b/app/src/main/java/be/bitscuit/gpslogger/LocationEvent.java @@ -0,0 +1,38 @@ +package be.bitscuit.gpslogger; + +public class LocationEvent { + + private double latitude; + private double longitude; + private double elevation; + private double velocity; + private long time; + + public LocationEvent(double latitude, double longitude, double elevation, double velocity, long time){ + this.latitude = latitude; + this.longitude = longitude; + this.elevation = elevation; + this.velocity = velocity; + this.time = time; + } + + public double getLatitude() { + return latitude; + } + + public double getLongitude() { + return longitude; + } + + public double getElevation() { + return elevation; + } + + public double getVelocity() { + return velocity; + } + + public long getTime() { + return time; + } +} diff --git a/app/src/main/java/be/bitscuit/gpslogger/LocationEventListener.java b/app/src/main/java/be/bitscuit/gpslogger/LocationEventListener.java new file mode 100644 index 0000000..52e77f7 --- /dev/null +++ b/app/src/main/java/be/bitscuit/gpslogger/LocationEventListener.java @@ -0,0 +1,5 @@ +package be.bitscuit.gpslogger; + +public interface LocationEventListener { + void onLocationEvent(LocationEvent locationEvent); +} diff --git a/app/src/main/java/be/bitscuit/gpslogger/LoggerService.java b/app/src/main/java/be/bitscuit/gpslogger/LoggerService.java new file mode 100644 index 0000000..a1136b0 --- /dev/null +++ b/app/src/main/java/be/bitscuit/gpslogger/LoggerService.java @@ -0,0 +1,146 @@ +package be.bitscuit.gpslogger; + +import android.app.Notification; +import android.app.PendingIntent; +import android.app.Service; +import android.content.Intent; +import android.location.Location; +import android.os.Binder; +import android.os.IBinder; +import android.os.Looper; + +import androidx.annotation.Nullable; + +import com.google.android.gms.location.FusedLocationProviderClient; +import com.google.android.gms.location.LocationAvailability; +import com.google.android.gms.location.LocationCallback; +import com.google.android.gms.location.LocationRequest; +import com.google.android.gms.location.LocationResult; +import com.google.android.gms.location.LocationServices; + +import java.util.ArrayList; + +public class LoggerService extends Service { + + //Binder vars + private IBinder binder = new LoggerBinder(); + private LocationEventListener eventListener; + + //Location vars + private FusedLocationProviderClient fusedLocationClient; + private ArrayList locationEvents; + + @Override + public void onCreate() { + super.onCreate(); + } + + @Override + public int onStartCommand(Intent intent, int flags, int startId) { + + //Make foreground + Notification notification = + new Notification.Builder(this) + .setContentTitle("Logging GPS location data!") + .setContentText("GPS Logger is running...") + .setSmallIcon(R.drawable.location_on) + .build(); + + startForeground(100, notification); + + //Init vars + locationEvents = new ArrayList<>(); + + //Request location updates + fusedLocationClient = LocationServices.getFusedLocationProviderClient(this); + + LocationRequest locationRequest = LocationRequest.create(); + locationRequest.setInterval(3000); + locationRequest.setFastestInterval(1000); + locationRequest.setSmallestDisplacement(1);//1 meter displacement between 2 locations + locationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY); + + try { + fusedLocationClient.requestLocationUpdates(locationRequest, locationCallback, Looper.getMainLooper()); + }catch (SecurityException e){} + + + //Make sticky + return START_STICKY; + } + + @Nullable + @Override + public IBinder onBind(Intent intent) { + return binder; + } + + @Override + public boolean onUnbind(Intent intent) { + + //Reset eventListener + eventListener = null; + + return super.onUnbind(intent); + } + + @Override + public void onDestroy() { + + //Remove location updates + fusedLocationClient.removeLocationUpdates(locationCallback); + + super.onDestroy(); + } + + + + + private LocationCallback locationCallback = new LocationCallback(){ + @Override + public void onLocationResult(LocationResult locationResult) { + //When got location update + if(locationResult == null) return; + + //Analyse locations + for(Location location : locationResult.getLocations()) { + LocationEvent locationEvent = new LocationEvent( + location.getLatitude(), + location.getLongitude(), + location.getAltitude(), + location.getSpeed(), + location.getTime() + ); + + //Add LocationEvent to array + locationEvents.add(locationEvent); + + //Call listener if set + try { + eventListener.onLocationEvent(locationEvent); + }catch (Exception e){} + } + } + }; + + + + //Methods Binder can access to communicate with this Service + public void setLocationEventListener(LocationEventListener eventListener){ + this.eventListener = eventListener; + } + + public ArrayList getLocationEvents(){ + return locationEvents; + } + + + + //Binder class + public class LoggerBinder extends Binder { + public LoggerService getService(){ + return LoggerService.this; + } + } + +} diff --git a/app/src/main/java/be/bitscuit/gpslogger/MainActivity.java b/app/src/main/java/be/bitscuit/gpslogger/MainActivity.java new file mode 100644 index 0000000..a7da15c --- /dev/null +++ b/app/src/main/java/be/bitscuit/gpslogger/MainActivity.java @@ -0,0 +1,426 @@ +package be.bitscuit.gpslogger; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.appcompat.app.AppCompatActivity; +import androidx.core.content.ContextCompat; + +import android.Manifest; +import android.app.Activity; +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.ServiceConnection; +import android.content.pm.PackageManager; +import android.net.Uri; +import android.os.Build; +import android.os.Bundle; +import android.os.IBinder; +import android.view.View; +import android.widget.Button; +import android.widget.TextView; +import android.widget.Toast; + +import com.codebutchery.androidgpx.data.GPXDocument; +import com.codebutchery.androidgpx.data.GPXRoute; +import com.codebutchery.androidgpx.data.GPXSegment; +import com.codebutchery.androidgpx.data.GPXTrack; +import com.codebutchery.androidgpx.data.GPXTrackPoint; +import com.codebutchery.androidgpx.data.GPXWayPoint; +import com.codebutchery.androidgpx.print.GPXFilePrinter; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.PrintStream; +import java.net.URI; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; + +public class MainActivity extends AppCompatActivity implements LocationEventListener, GPXFilePrinter.GPXFilePrinterListener { + + //Static vars + private static final int STATE_IDLE = 0; + private static final int STATE_PERMISSION = 1; + private static final int STATE_LOGGING = 2; + private static final int STATE_RESULT = 3; + + private static final int REQUEST_CODE_PERMISSION = 100; + private static final int REQUEST_CODE_SAVE = 101; + + + //View vars + private TextView textInfo; + private Button buttonExport, buttonStartStop; + + //State vars + private int state = STATE_IDLE; + + //Location vars + private ArrayList locationEvents; + + + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_main); + + //Init views + textInfo = findViewById(R.id.main_text_info); + buttonExport = findViewById(R.id.main_button_left); + buttonStartStop = findViewById(R.id.main_button_right); + + //Add listeners + buttonExport.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + clickedButtonExport(); + } + }); + buttonStartStop.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + clickedButtonStartStop(); + } + }); + + //Set text + buttonExport.setText("Export"); + buttonExport.setEnabled(false); + buttonStartStop.setText("Start"); + updateInfoText(); + + + //Init other vars + locationEvents = new ArrayList<>(); + } + + + //Button handlers + private void clickedButtonExport(){ + //Make sure right state + if(state != STATE_RESULT) return; + + //Check if enough data + if(locationEvents.size() < 1){ + Toast.makeText(this, "Not enough locations!", Toast.LENGTH_SHORT).show(); + return; + } + + //Ask where to save file + Intent intent = new Intent(Intent.ACTION_CREATE_DOCUMENT); + intent.addCategory(Intent.CATEGORY_OPENABLE); + intent.setType("application/gpx"); + intent.putExtra(Intent.EXTRA_TITLE, "GPS_Logger_export.gpx"); + startActivityForResult(intent, REQUEST_CODE_SAVE); + + System.out.println("end buttonExport"); + } + + private void clickedButtonStartStop(){ + //Check state + switch (state){ + case STATE_IDLE: + case STATE_PERMISSION: + //Update state and UI + state = STATE_PERMISSION; + updateInfoText(); + + //Check permissions (only on Android 6+) + if(Build.VERSION.SDK_INT >= 23 + && ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_DENIED){ + //Ask for permission + requestPermissions(new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, REQUEST_CODE_PERMISSION); + break; + } + + //Reset/init location storage + locationEvents = new ArrayList<>(); + + //Start LoggingService + Intent intentStart = new Intent(this, LoggerService.class); + startService(intentStart); + Intent intentBind = new Intent(this, LoggerService.class); + bindService(intentBind, loggerConnection, Context.BIND_AUTO_CREATE); + + //Update UI + state = STATE_LOGGING; + updateInfoText(); + buttonStartStop.setText("Stop"); + + break; + + case STATE_LOGGING: + //Get LocationEvents + locationEvents = loggerService.getLocationEvents(); + + //Stop Service + unbindService(loggerConnection); + loggerServiceBound = false; + Intent intent = new Intent(this, LoggerService.class); + stopService(intent); + + //Update UI + state = STATE_RESULT; + updateInfoText(); + buttonStartStop.setText("Reset"); + buttonExport.setEnabled(true); + + break; + + case STATE_RESULT: + //TODO: add nice dialog for confirmation + + //Reset everything + locationEvents = new ArrayList<>(); + + //Update UI + state = STATE_IDLE; + updateInfoText(); + buttonStartStop.setText("Start"); + buttonExport.setEnabled(false); + + break; + } + } + + + //UI stuff + private void updateInfoText(){ + System.out.println("Updating text"); + String text = ""; + + //State + text += "Status: "; + switch (state){ + case STATE_IDLE: text += "IDLE"; break; + case STATE_PERMISSION: text += "PERMISSION"; break; + case STATE_LOGGING: text += "LOGGING"; break; + case STATE_RESULT: text += "RESULT"; break; + } + text += "\n"; + + //Extra (state-specific) + switch (state){ + case STATE_IDLE: + text += "Press START to begin logging!"; + break; + case STATE_PERMISSION: + text += "Please grant the permissions."; + break; + case STATE_LOGGING: + text += "Press STOP to end logging.\n\n"; + + //Adding location info + text += "Logged "+locationEvents.size()+" location"+(locationEvents.size()==1?"":"s")+".\n"; + try { + text += "Last location (" + locationEvents.get(locationEvents.size() - 1).getLatitude() + + ", " + locationEvents.get(locationEvents.size() - 1).getLongitude() + ") received at " + + Util.formatMillis(locationEvents.get(locationEvents.size() - 1).getTime(), "HH:mm:ss") + "\n"; + }catch (Exception e){} + + break; + case STATE_RESULT: + text += "Press EXPORT to save the data.\n" + + "Press RESET to reset the log.\n\n"; + + //Adding location info + text += "Logged "+locationEvents.size()+" location"+(locationEvents.size()==1?"":"s")+".\n"; + try { + text += "Last location (" + locationEvents.get(locationEvents.size() - 1).getLatitude() + + ", " + locationEvents.get(locationEvents.size() - 1).getLongitude() + ") received at " + + Util.formatMillis(locationEvents.get(locationEvents.size() - 1).getTime(), "HH:mm:ss") + "\n\n"; + }catch (Exception e){} + try { + int millis = (int) (locationEvents.get(locationEvents.size()-1).getTime()-locationEvents.get(0).getTime()); + int h = millis/3600000; + int m = (millis%3600000)/60000; + int s = ((millis%3600000)%60000)/1000; + text += "Total time: "+h+"h "+m+"m "+s+"s\n"; + }catch (Exception e){} + //TODO: add more metrics + + break; + } + + //Set text + final String textCopy = text; + runOnUiThread(new Runnable() { + @Override + public void run() { + textInfo.setText(textCopy); + } + }); + } + + + //Permission stuff + @Override + public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { + + System.out.println("onPermissionResult"); + + if(requestCode == REQUEST_CODE_PERMISSION){ + if(grantResults.length >= 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED){ + //When granted permission -> start logging + clickedButtonStartStop(); + }else{ + //When didn't grant permission + Toast.makeText(this, "Unable to start logging!", Toast.LENGTH_LONG).show(); + } + } + + } + + + //Service stuff + private LoggerService loggerService; + private boolean loggerServiceBound = false; + private ServiceConnection loggerConnection = new ServiceConnection() { + @Override + public void onServiceConnected(ComponentName componentName, IBinder iBinder) { + System.out.println("Connecting to service..."); + //When connected with Service + LoggerService.LoggerBinder loggerBinder = (LoggerService.LoggerBinder) iBinder; + loggerService = loggerBinder.getService(); + loggerServiceBound = true; + + //Add locationEvent listener + loggerService.setLocationEventListener(MainActivity.this); + + //Get LocationEvents up till now + locationEvents = loggerService.getLocationEvents(); + } + + @Override + public void onServiceDisconnected(ComponentName componentName) { + loggerServiceBound = false; + } + }; + + + @Override + public void onLocationEvent(LocationEvent locationEvent) { + //Add locationEvent to list + locationEvents.add(locationEvent); + + //Output to console + System.out.println("New location!\n" + + "Lat: " + locationEvent.getLatitude() + "\n" + + "Long: " + locationEvent.getLongitude() + "\n" + + "Alt: " + locationEvent.getElevation() + "\n" + + "Vel: " + locationEvent.getVelocity() + "\n" + + "Time: " + locationEvent.getTime() + "\n"); + + //Update UI + updateInfoText(); + } + + + @Override + protected void onResume() { + super.onResume(); + + System.out.println("onResume"); + + //Bind to service if logging + if(state == STATE_LOGGING){ + System.out.println("Reconnecting to service"); + Intent intent = new Intent(this, LoggerService.class); + bindService(intent, loggerConnection, Context.BIND_AUTO_CREATE); + } + } + + @Override + protected void onStop() { + super.onStop(); + + System.out.println("onStop"); + + //Unbind from service if logging + if(state == STATE_LOGGING) { + unbindService(loggerConnection); + loggerServiceBound = false; + } + } + + + + //Export GPX stuff + private void exportAsGPX(PrintStream printStream){ + //Export locationEvents using GPX library + GPXSegment segment = new GPXSegment(); + System.out.println("Segment created"); + + for(int i=0; i trackList = new ArrayList<>(); + trackList.add(track); + GPXDocument document = new GPXDocument(new ArrayList(), trackList, new ArrayList()); + + System.out.println("doc ok"); + + //Write to file + document.toGPX(printStream); + System.out.println("ok"); + } + + @Override + protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) { + super.onActivityResult(requestCode, resultCode, data); + + System.out.println("onActivityResult"); + + //Save file + if(requestCode == REQUEST_CODE_SAVE && resultCode == Activity.RESULT_OK){ + //Export to file + try{ + System.out.println("in try"); + Uri uri = data.getData(); + System.out.println("got uri"); + exportAsGPX(new PrintStream(getContentResolver().openOutputStream(uri))); + System.out.println("export done"); + Toast.makeText(this, "Successfully exported data!", Toast.LENGTH_LONG).show(); + }catch (Exception e){ + System.out.println("Excpetion!\n" + e.getMessage()); + e.printStackTrace(); + Toast.makeText(this, "Error during export:\n"+e.getMessage(), Toast.LENGTH_LONG).show(); + } + } + + } + + @Override + public void onGPXPrintStarted() { + + } + + @Override + public void onGPXPrintCompleted() { + Toast.makeText(this, "Successfully exported data to file!", Toast.LENGTH_SHORT).show(); + } + + @Override + public void onGPXPrintError(String message) { + Toast.makeText(this, "Error during export:\n"+message, Toast.LENGTH_LONG).show(); + } +} \ No newline at end of file diff --git a/app/src/main/java/be/bitscuit/gpslogger/Util.java b/app/src/main/java/be/bitscuit/gpslogger/Util.java new file mode 100644 index 0000000..6fe9c29 --- /dev/null +++ b/app/src/main/java/be/bitscuit/gpslogger/Util.java @@ -0,0 +1,14 @@ +package be.bitscuit.gpslogger; + +import java.text.SimpleDateFormat; +import java.util.Date; + +public class Util { + + public static String formatMillis(long millis, String format){ + SimpleDateFormat sdf = new SimpleDateFormat(format); + Date date = new Date(millis); + return sdf.format(date); + } + +} diff --git a/app/src/main/res/drawable-v24/ic_launcher_foreground.xml b/app/src/main/res/drawable-v24/ic_launcher_foreground.xml new file mode 100644 index 0000000..2b068d1 --- /dev/null +++ b/app/src/main/res/drawable-v24/ic_launcher_foreground.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_launcher_background.xml b/app/src/main/res/drawable/ic_launcher_background.xml new file mode 100644 index 0000000..07d5da9 --- /dev/null +++ b/app/src/main/res/drawable/ic_launcher_background.xml @@ -0,0 +1,170 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/drawable/location_on.png b/app/src/main/res/drawable/location_on.png new file mode 100644 index 0000000000000000000000000000000000000000..e1a9c703c5e46cbfa4a7e85427b857657d91264b GIT binary patch literal 843 zcmV-R1GM~!P)-UlT;LYBIL9$Y z7-9p9F};L0*vF;monwflNZ*DR*u|alZm@}7r01}STeEkCwMc)%FSzvMjWLKW!@l{N zU^}`7FL9zd4$Syep8?AXal@c zrwImaC_OjoHIAC$SM^(q8sQc0)$a_ayG9O}&(8rVJxW}vL66|S?jhLHUkWZtlFfd`EQ=^bELWbZ)Ph}S?J+x+N7;i z02XlL-(BEEq}jnT9z1u8#YnS + + + + +