diff --git a/assets/text/faq/faq03-no-point-logged.md b/assets/text/faq/faq03-no-point-logged.md index e0d9eb68d..c703fc3ff 100644 --- a/assets/text/faq/faq03-no-point-logged.md +++ b/assets/text/faq/faq03-no-point-logged.md @@ -5,6 +5,10 @@ Sometimes your specified time interval will have passed, but no point was logged * On Android 6+ (Marshmallow), a new feature called *[doze mode](http://lifehacker.com/how-android-doze-works-and-how-to-tweak-it-to-save-you-1785921957)* was introduced, which severely restricts activity on the device after certain periods of inactivity. Be sure to grant the app permission to run in the background by disabling battery optimization. If you aren't sure, or if you've denied this permission you can [disable battery optimization for GPSLogger manually](https://android.stackexchange.com/a/129075/14996) which does not bypass doze mode but occasionally provides logging windows in which to work. It will not make a great difference though, doze mode is quite aggressive. +* Background permission or battery un-optimization wasn't granted to the app, and this can prevent the periodic alarm scheduling the app needs to get a new point. + +* This can also happen if the app isn't used for a long time, the OS starts to remove permissions from the app. + * Many vendors are also known to introduce their own _additional_ poorly written but aggressive battery optimization mechanisms. App developers don't have a way of detecting or working around these, and unfortunately the apps receive all the blame. You can see some partial workarounds on the [Don't Kill My App site](https://dontkillmyapp.com/?app=GPSLogger) * The GPS system will have attempted to find its location and given up after a while. This in turn means that Android OS will not have given a location to GPSLogger diff --git a/gpslogger/build.gradle b/gpslogger/build.gradle index 6a92746f5..fcce2f9f6 100644 --- a/gpslogger/build.gradle +++ b/gpslogger/build.gradle @@ -37,16 +37,16 @@ repositories { } android { - compileSdkVersion 34 + compileSdk 35 defaultConfig { applicationId "com.mendhak.gpslogger" - minSdkVersion 16 - //noinspection ExpiredTargetSdkVersion - targetSdkVersion 30 + minSdkVersion 21 + + targetSdkVersion 35 compileSdk 34 - versionCode 131 - versionName "131-rc2" + versionCode 132 + versionName "132-test1" // Used by AppAuth-Android manifestPlaceholders = [ @@ -121,8 +121,8 @@ android { dependencies { // implementation 'androidx.legacy:legacy-support-v4:1.0.0' - implementation "androidx.activity:activity:1.8.2" - implementation "androidx.fragment:fragment:1.6.2" + implementation "androidx.activity:activity:1.9.2" + implementation "androidx.fragment:fragment:1.8.3" implementation "androidx.preference:preference:1.2.1" implementation "androidx.constraintlayout:constraintlayout:2.1.4" @@ -136,16 +136,12 @@ dependencies { //Debug Logging - implementation('org.slf4j:slf4j-api:1.7.30') - implementation('com.github.tony19:logback-android-classic:1.1.1-2'){ - exclude group: 'com.google.android', module: 'android' - } - - implementation('com.github.tony19:logback-android-core:1.1.1-2') + implementation 'org.slf4j:slf4j-api:2.0.7' + implementation 'com.github.tony19:logback-android:3.0.0' //Android lollipop/material features including the Toolbar - implementation 'androidx.appcompat:appcompat:1.6.1' + implementation 'androidx.appcompat:appcompat:1.7.0' //Cardviews @@ -164,7 +160,7 @@ dependencies { implementation 'com.github.dmytrodanylyk.android-process-button:library:1.0.4' //Android's WorkManager - implementation 'androidx.work:work-runtime:2.9.0' + implementation 'androidx.work:work-runtime:2.9.1' // We need to use Gson to help with WorkManager limitations implementation 'com.google.code.gson:gson:2.10.1' @@ -212,11 +208,11 @@ dependencies { implementation('org.apache.commons:commons-csv:1.9.0') //Libraries required for unit testing - testImplementation 'junit:junit:4.12' + testImplementation 'junit:junit:4.13.2' testImplementation 'org.mockito:mockito-core:3.10.0' testImplementation 'org.json:json:20180813' - testImplementation 'androidx.test:runner:1.5.2' - testImplementation 'androidx.test:rules:1.5.0' + testImplementation 'androidx.test:runner:1.6.2' + testImplementation 'androidx.test:rules:1.6.1' } diff --git a/gpslogger/src/main/AndroidManifest.xml b/gpslogger/src/main/AndroidManifest.xml index 775d9bfe5..2302b22b2 100644 --- a/gpslogger/src/main/AndroidManifest.xml +++ b/gpslogger/src/main/AndroidManifest.xml @@ -74,7 +74,8 @@ android:resource="@xml/shortcuts" /> - + @@ -94,7 +95,9 @@ + android:parentActivityName=".GpsMainActivity" + android:exported="true" + > @@ -105,7 +108,9 @@ android:name=".Faqtivity" android:label="@string/faq_screen_title" android:launchMode="singleTask" - android:parentActivityName=".GpsMainActivity" > + android:parentActivityName=".GpsMainActivity" + android:exported="true" + > @@ -114,6 +119,7 @@ @@ -143,6 +150,7 @@ @@ -150,6 +158,7 @@ @@ -159,6 +168,7 @@ @@ -168,13 +178,15 @@ - + - + @@ -185,6 +197,7 @@ - + diff --git a/gpslogger/src/main/java/com/mendhak/gpslogger/GpsLoggingService.java b/gpslogger/src/main/java/com/mendhak/gpslogger/GpsLoggingService.java index 5e4550464..5d4513cab 100644 --- a/gpslogger/src/main/java/com/mendhak/gpslogger/GpsLoggingService.java +++ b/gpslogger/src/main/java/com/mendhak/gpslogger/GpsLoggingService.java @@ -25,10 +25,14 @@ import android.content.Intent; import android.content.pm.ServiceInfo; import android.graphics.BitmapFactory; +import android.location.GnssStatus; import android.location.Location; import android.location.LocationManager; import android.os.*; + +import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import androidx.core.app.AlarmManagerCompat; import androidx.core.app.NotificationCompat; import androidx.core.app.TaskStackBuilder; import android.text.Html; @@ -70,6 +74,7 @@ public class GpsLoggingService extends Service { private LocationManager passiveLocationManager; private LocationManager towerLocationManager; private GeneralLocationListener gpsLocationListener; + private GnssStatus.Callback gnssStatusCallback; private GeneralLocationListener towerLocationListener; private GeneralLocationListener passiveLocationListener; private NmeaLocationListener nmeaLocationListener; @@ -166,7 +171,7 @@ public void onLowMemory() { LOG.error("Android is low on memory!"); Intent i = new Intent(this, GpsLoggingService.class); i.putExtra(IntentConstants.GET_NEXT_POINT, true); - PendingIntent pi = PendingIntent.getService(this, 0, i, 0); + PendingIntent pi = PendingIntent.getService(this, 0, i, PendingIntent.FLAG_IMMUTABLE); nextPointAlarmManager.cancel(pi); nextPointAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, SystemClock.elapsedRealtime() + 300000, pi); super.onLowMemory(); @@ -319,7 +324,11 @@ public void setupAutoSendTimers() { alarmIntent = new Intent(this, AlarmReceiver.class); cancelAlarm(); - PendingIntent sender = PendingIntent.getBroadcast(this, 0, alarmIntent, PendingIntent.FLAG_UPDATE_CURRENT); + int flags = PendingIntent.FLAG_UPDATE_CURRENT; + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { + flags |= PendingIntent.FLAG_MUTABLE; + } + PendingIntent sender = PendingIntent.getBroadcast(this, 0, alarmIntent, flags); AlarmManager am = (AlarmManager) getSystemService(ALARM_SERVICE); if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { am.setExactAndAllowWhileIdle(AlarmManager.ELAPSED_REALTIME_WAKEUP, triggerTime, sender); @@ -351,7 +360,8 @@ public void logOnce() { private void cancelAlarm() { if (alarmIntent != null) { AlarmManager am = (AlarmManager) getSystemService(ALARM_SERVICE); - PendingIntent sender = PendingIntent.getBroadcast(this, 0, alarmIntent, PendingIntent.FLAG_UPDATE_CURRENT); + PendingIntent sender = PendingIntent.getBroadcast(this, 0, alarmIntent, + PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_MUTABLE); am.cancel(sender); } } @@ -497,11 +507,11 @@ private Notification getNotification() { Intent stopLoggingIntent = new Intent(this, GpsLoggingService.class); stopLoggingIntent.setAction("NotificationButton_STOP"); stopLoggingIntent.putExtra(IntentConstants.IMMEDIATE_STOP, true); - PendingIntent piStop = PendingIntent.getService(this, 0, stopLoggingIntent, 0); + PendingIntent piStop = PendingIntent.getService(this, 0, stopLoggingIntent, PendingIntent.FLAG_IMMUTABLE); Intent annotateIntent = new Intent(this, NotificationAnnotationActivity.class); annotateIntent.setAction("com.mendhak.gpslogger.NOTIFICATION_BUTTON"); - PendingIntent piAnnotate = PendingIntent.getActivity(this,0, annotateIntent,0); + PendingIntent piAnnotate = PendingIntent.getActivity(this,0, annotateIntent, PendingIntent.FLAG_IMMUTABLE); // What happens when the notification item is clicked Intent contentIntent = new Intent(this, GpsMainActivity.class); @@ -509,7 +519,11 @@ private Notification getNotification() { TaskStackBuilder stackBuilder = TaskStackBuilder.create(this); stackBuilder.addNextIntent(contentIntent); - PendingIntent pending = stackBuilder.getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT); + int flags = PendingIntent.FLAG_UPDATE_CURRENT; + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { + flags |= PendingIntent.FLAG_IMMUTABLE; + } + PendingIntent pending = stackBuilder.getPendingIntent(0, flags); CharSequence contentTitle = getString(R.string.gpslogger_still_running); CharSequence contentText = getString(R.string.app_name); @@ -581,6 +595,7 @@ private void startPassiveManager() { } } + /** * Starts the location manager. There are two location managers - GPS and * Cell Tower. This code determines which manager to request updates from @@ -607,6 +622,32 @@ private void startGpsManager() { towerLocationListener = new GeneralLocationListener(this, "CELL"); } + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { + gnssStatusCallback = new GnssStatus.Callback() { + @Override + public void onStarted() { + super.onStarted(); + } + + @Override + public void onStopped() { + super.onStopped(); + } + + @Override + public void onFirstFix(int ttffMillis) { + super.onFirstFix(ttffMillis); + LOG.info("Time to first fix: {}ms", ttffMillis); + } + + @Override + public void onSatelliteStatusChanged(@NonNull GnssStatus status) { + super.onSatelliteStatusChanged(status); + setSatelliteInfo(status.getSatelliteCount()); + gpsLocationListener.satellitesUsedInFix = status.getSatelliteCount(); + } + }; + } gpsLocationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE); @@ -618,7 +659,13 @@ private void startGpsManager() { LOG.info("Requesting GPS location updates"); // gps satellite based gpsLocationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 1000, 0, gpsLocationListener); - gpsLocationManager.addGpsStatusListener(gpsLocationListener); + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { + gpsLocationManager.registerGnssStatusCallback(gnssStatusCallback); + } + else { + gpsLocationManager.addGpsStatusListener(gpsLocationListener); + } if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { if (nmeaLocationListener == null){ @@ -715,6 +762,12 @@ private void stopGpsManager() { if (gpsLocationListener != null) { LOG.debug("Removing gpsLocationManager updates"); gpsLocationManager.removeUpdates(gpsLocationListener); + } + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N && gnssStatusCallback != null) { + gpsLocationManager.unregisterGnssStatusCallback(gnssStatusCallback); + } + else { gpsLocationManager.removeGpsStatusListener(gpsLocationListener); } @@ -1035,26 +1088,26 @@ protected void stopManagerAndResetAlarm() { private void stopAlarm() { Intent i = new Intent(this, GpsLoggingService.class); i.putExtra(IntentConstants.GET_NEXT_POINT, true); - PendingIntent pi = PendingIntent.getService(this, 0, i, 0); + PendingIntent pi = PendingIntent.getService(this, 0, i, PendingIntent.FLAG_MUTABLE); nextPointAlarmManager.cancel(pi); } private void setAlarmForNextPoint() { - LOG.debug("Set alarm for " + preferenceHelper.getMinimumLoggingInterval() + " seconds"); - Intent i = new Intent(this, GpsLoggingService.class); i.putExtra(IntentConstants.GET_NEXT_POINT, true); - PendingIntent pi = PendingIntent.getService(this, 0, i, 0); + PendingIntent pi = PendingIntent.getService(this, 0, i, PendingIntent.FLAG_MUTABLE); nextPointAlarmManager.cancel(pi); - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { - nextPointAlarmManager.setExactAndAllowWhileIdle(AlarmManager.ELAPSED_REALTIME_WAKEUP, - SystemClock.elapsedRealtime() + preferenceHelper.getMinimumLoggingInterval() * 1000, pi); + + if(AlarmManagerCompat.canScheduleExactAlarms(nextPointAlarmManager)){ + LOG.debug("Setting exact alarm for {}s", preferenceHelper.getMinimumLoggingInterval()); + AlarmManagerCompat.setExactAndAllowWhileIdle(nextPointAlarmManager, AlarmManager.ELAPSED_REALTIME_WAKEUP, + SystemClock.elapsedRealtime() + preferenceHelper.getMinimumLoggingInterval() * 1000L, pi); } else { - nextPointAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, - SystemClock.elapsedRealtime() + preferenceHelper.getMinimumLoggingInterval() * 1000, pi); + LOG.debug("Setting inexact alarm for {}s (exact alarm disallowed/not available)", preferenceHelper.getMinimumLoggingInterval()); + AlarmManagerCompat.setAndAllowWhileIdle(nextPointAlarmManager, AlarmManager.ELAPSED_REALTIME_WAKEUP, + SystemClock.elapsedRealtime() + preferenceHelper.getMinimumLoggingInterval() * 1000L, pi); } - } diff --git a/gpslogger/src/main/java/com/mendhak/gpslogger/GpsMainActivity.java b/gpslogger/src/main/java/com/mendhak/gpslogger/GpsMainActivity.java index ad8a1a574..c362d5b4e 100644 --- a/gpslogger/src/main/java/com/mendhak/gpslogger/GpsMainActivity.java +++ b/gpslogger/src/main/java/com/mendhak/gpslogger/GpsMainActivity.java @@ -65,6 +65,7 @@ import androidx.appcompat.view.menu.ActionMenuItemView; import androidx.appcompat.widget.ActionMenuView; import androidx.appcompat.widget.Toolbar; +import androidx.core.app.ActivityCompat; import androidx.core.app.NotificationManagerCompat; import androidx.core.content.ContextCompat; import androidx.core.content.FileProvider; @@ -267,19 +268,7 @@ public boolean onResult(@NonNull String dialogTag, int which, @NonNull Bundle ex return true; case BUTTON_POSITIVE: LOG.debug("Beginning request for multiple permissions"); - ArrayList permissions = new ArrayList(); - permissions.add(Manifest.permission.ACCESS_COARSE_LOCATION); - permissions.add(Manifest.permission.ACCESS_FINE_LOCATION); - permissions.add(Manifest.permission.READ_EXTERNAL_STORAGE); - permissions.add(Manifest.permission.WRITE_EXTERNAL_STORAGE); - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { - permissions.add(Manifest.permission.POST_NOTIFICATIONS); - } - - if (Build.VERSION.SDK_INT == Build.VERSION_CODES.Q) { - // Only on Android 10 (Q), the permission dialog can include an 'Allow all the time' - permissions.add(Manifest.permission.ACCESS_BACKGROUND_LOCATION); - } + ArrayList permissions = new ArrayList(Systems.getListOfNecessaryPermissions(true)); basicPermissionsLauncher.launch(permissions.toArray(new String[0])); return true; } diff --git a/gpslogger/src/main/java/com/mendhak/gpslogger/MainPreferenceActivity.java b/gpslogger/src/main/java/com/mendhak/gpslogger/MainPreferenceActivity.java index c41b5e0b1..498137e7b 100644 --- a/gpslogger/src/main/java/com/mendhak/gpslogger/MainPreferenceActivity.java +++ b/gpslogger/src/main/java/com/mendhak/gpslogger/MainPreferenceActivity.java @@ -22,9 +22,13 @@ import android.os.Bundle; import androidx.appcompat.app.AppCompatActivity; import androidx.appcompat.widget.Toolbar; +import androidx.core.graphics.Insets; +import androidx.core.view.ViewCompat; +import androidx.core.view.WindowInsetsCompat; import androidx.preference.PreferenceFragmentCompat; import android.view.MenuItem; +import android.view.ViewGroup; import com.mendhak.gpslogger.common.PreferenceHelper; import com.mendhak.gpslogger.common.Systems; import com.mendhak.gpslogger.common.slf4j.Logs; @@ -47,6 +51,25 @@ protected void onCreate(Bundle savedInstanceState) { Systems.setLocale(PreferenceHelper.getInstance().getUserSpecifiedLocale(),getBaseContext(),getResources()); setContentView(R.layout.activity_preferences); + ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.toolbar), (v, windowInsets) -> { + Insets insets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars() | WindowInsetsCompat.Type.displayCutout()); + + // Apply the insets as a margin to the view so it doesn't overlap with status bar + ViewGroup.MarginLayoutParams mlp = (ViewGroup.MarginLayoutParams) v.getLayoutParams(); + mlp.leftMargin = insets.left; + mlp.bottomMargin = insets.bottom; + mlp.rightMargin = insets.right; + mlp.topMargin = insets.top; + v.setLayoutParams(mlp); + + // Alternatively set the padding on the view itself. +// v.setPadding(insets.left, 0, insets.right, insets.bottom); + + // Return CONSUMED if you don't want want the window insets to keep passing + // down to descendant views. + return WindowInsetsCompat.CONSUMED; + }); + Toolbar toolbar = (Toolbar)findViewById(R.id.toolbar); setSupportActionBar(toolbar); if(getSupportActionBar() != null){ diff --git a/gpslogger/src/main/java/com/mendhak/gpslogger/common/RejectionHandler.java b/gpslogger/src/main/java/com/mendhak/gpslogger/common/RejectionHandler.java index fced27d62..f772f0529 100644 --- a/gpslogger/src/main/java/com/mendhak/gpslogger/common/RejectionHandler.java +++ b/gpslogger/src/main/java/com/mendhak/gpslogger/common/RejectionHandler.java @@ -30,9 +30,14 @@ public class RejectionHandler implements RejectedExecutionHandler { private static final Logger LOG = Logs.of(RejectionHandler.class); + private final String tag; + public RejectionHandler(String tag){ + this.tag = tag; + } + @Override public void rejectedExecution(Runnable runnable, ThreadPoolExecutor threadPoolExecutor) { - LOG.warn(SessionLogcatAppender.MARKER_INTERNAL, "Could not queue task, some points may not be logged."); + LOG.warn(SessionLogcatAppender.MARKER_INTERNAL, "Could not queue task for {}, some points may not be logged.", tag); } } diff --git a/gpslogger/src/main/java/com/mendhak/gpslogger/common/Systems.java b/gpslogger/src/main/java/com/mendhak/gpslogger/common/Systems.java index 9bbb42f0b..13bb9b48e 100644 --- a/gpslogger/src/main/java/com/mendhak/gpslogger/common/Systems.java +++ b/gpslogger/src/main/java/com/mendhak/gpslogger/common/Systems.java @@ -66,6 +66,7 @@ import java.security.cert.CertificateException; import java.security.cert.CertificateFactory; import java.security.cert.X509Certificate; +import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Locale; @@ -83,7 +84,16 @@ public static String getAndroidId() { } public static BatteryInfo getBatteryInfo(Context context){ - Intent batteryIntent = context.registerReceiver(null, new IntentFilter(Intent.ACTION_BATTERY_CHANGED)); + Intent batteryIntent = null; + if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) { + batteryIntent = ContextCompat.registerReceiver(context, null, new IntentFilter(Intent.ACTION_BATTERY_CHANGED), + ContextCompat.RECEIVER_EXPORTED); + } + else { + batteryIntent = context.registerReceiver(null, new IntentFilter(Intent.ACTION_BATTERY_CHANGED)); + } + + int level = batteryIntent != null ? batteryIntent.getIntExtra(BatteryManager.EXTRA_LEVEL, -1) : 0; int scale = batteryIntent != null ? batteryIntent.getIntExtra(BatteryManager.EXTRA_SCALE, -1) : 0; @@ -205,21 +215,61 @@ public static void setLocale(String userSpecifiedLocale, Context baseContext, Re } } + /** + * Returns a list of the necessary permissions for the app. + * Permissions are also filtered by the SDK version + * @param forInteractivePermissionWorkflow - Whether this is a permission workflow, in which case 'access_background_location' doesn't usually get returned + */ + public static List getListOfNecessaryPermissions(boolean forInteractivePermissionWorkflow){ + List permissions = new ArrayList(); + permissions.add(Manifest.permission.ACCESS_COARSE_LOCATION); + permissions.add(Manifest.permission.ACCESS_FINE_LOCATION); + + // In API 33, this storage permission has no effect. + // https://developer.android.com/reference/android/Manifest.permission#READ_EXTERNAL_STORAGE + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU){ + permissions.add(Manifest.permission.READ_EXTERNAL_STORAGE); + permissions.add(Manifest.permission.WRITE_EXTERNAL_STORAGE); + } + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU){ + permissions.add(Manifest.permission.POST_NOTIFICATIONS); + } + + + if(forInteractivePermissionWorkflow){ + // Only on Android 10 (Q), the permission dialog can include an 'Allow all the time' + if(Build.VERSION.SDK_INT == Build.VERSION_CODES.Q){ + permissions.add(Manifest.permission.ACCESS_BACKGROUND_LOCATION); + } + } + else { + // Only return when checking if a permission was granted or not, not for interactive workflow. + // Including this along with coarse/fine location permissions will get denied immediately. + // Instead you are expected to request coarse/fine location permissions first, then this *separately*. + if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { + permissions.add(Manifest.permission.ACCESS_BACKGROUND_LOCATION); + } + } + + + return permissions; + } + /** * Whether the user has allowed the permissions absolutely required to run the app. * Currently this is location and file storage. */ public static boolean hasUserGrantedAllNecessaryPermissions(Context context){ - boolean granted = hasUserGrantedPermission(Manifest.permission.ACCESS_COARSE_LOCATION, context) - && hasUserGrantedPermission(Manifest.permission.ACCESS_FINE_LOCATION, context) - && hasUserGrantedPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE, context) - && hasUserGrantedPermission(Manifest.permission.READ_EXTERNAL_STORAGE, context); - if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q){ - granted = granted && hasUserGrantedPermission(Manifest.permission.ACCESS_BACKGROUND_LOCATION, context); + List permissions = getListOfNecessaryPermissions(false); + for(String permission : permissions){ + if(!hasUserGrantedPermission(permission, context)){ + return false; + } } - return granted; + return true; } static boolean hasUserGrantedPermission(String permissionName, Context context){ @@ -301,7 +351,11 @@ public static void showErrorNotification(Context context, String message){ LOG.debug("Showing fatal notification"); Intent contentIntent = new Intent(context, GpsMainActivity.class); - PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, contentIntent, PendingIntent.FLAG_UPDATE_CURRENT); + int flags = PendingIntent.FLAG_UPDATE_CURRENT; + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { + flags |= PendingIntent.FLAG_IMMUTABLE; + } + PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, contentIntent, flags); NotificationCompat.Builder nfc = new NotificationCompat.Builder(context.getApplicationContext(), NotificationChannelNames.GPSLOGGER_ERRORS) .setSmallIcon(android.R.drawable.stat_sys_warning) diff --git a/gpslogger/src/main/java/com/mendhak/gpslogger/common/slf4j/SessionLogcatAppender.java b/gpslogger/src/main/java/com/mendhak/gpslogger/common/slf4j/SessionLogcatAppender.java index 10152dd0b..fbab8162a 100644 --- a/gpslogger/src/main/java/com/mendhak/gpslogger/common/slf4j/SessionLogcatAppender.java +++ b/gpslogger/src/main/java/com/mendhak/gpslogger/common/slf4j/SessionLogcatAppender.java @@ -52,7 +52,7 @@ protected void append(ILoggingEvent eventObject) { if(eventObject.getLevel().toInt() < Level.INFO.toInt()){ return; } //Prevents certain entries from appearing in device logcat - if(eventObject.getMarker() == MARKER_INTERNAL){ return; } + if(eventObject.getMarkers() != null && eventObject.getMarkers().contains(MARKER_INTERNAL)){ return; } Statuses.add(eventObject); } diff --git a/gpslogger/src/main/java/com/mendhak/gpslogger/loggers/Files.java b/gpslogger/src/main/java/com/mendhak/gpslogger/loggers/Files.java index 5581027fe..ae2937d33 100644 --- a/gpslogger/src/main/java/com/mendhak/gpslogger/loggers/Files.java +++ b/gpslogger/src/main/java/com/mendhak/gpslogger/loggers/Files.java @@ -99,13 +99,6 @@ public static String getMimeTypeFromFileName(String fileName) { } - public static void addToMediaDatabase(File file, String mimeType){ - - MediaScannerConnection.scanFile(AppSettings.getInstance(), - new String[]{file.getPath()}, - new String[]{mimeType}, - null); - } public static File[] fromFolder(File folder) { return fromFolder(folder, null); @@ -193,8 +186,6 @@ public static File createTestFile() throws IOException { initialOutput.write("This is a test file".getBytes()); initialOutput.flush(); initialOutput.close(); - - Files.addToMediaDatabase(testFile, "text/xml"); } return testFile; diff --git a/gpslogger/src/main/java/com/mendhak/gpslogger/loggers/csv/CSVFileLogger.java b/gpslogger/src/main/java/com/mendhak/gpslogger/loggers/csv/CSVFileLogger.java index 5d83ca92d..8d8084094 100644 --- a/gpslogger/src/main/java/com/mendhak/gpslogger/loggers/csv/CSVFileLogger.java +++ b/gpslogger/src/main/java/com/mendhak/gpslogger/loggers/csv/CSVFileLogger.java @@ -165,8 +165,6 @@ public void annotate(String description, Location loc) throws Exception { ); } out.close(); - - Files.addToMediaDatabase(file, "text/csv"); } /** diff --git a/gpslogger/src/main/java/com/mendhak/gpslogger/loggers/geojson/GeoJSONLogger.java b/gpslogger/src/main/java/com/mendhak/gpslogger/loggers/geojson/GeoJSONLogger.java index 977ceaeed..47e2287da 100644 --- a/gpslogger/src/main/java/com/mendhak/gpslogger/loggers/geojson/GeoJSONLogger.java +++ b/gpslogger/src/main/java/com/mendhak/gpslogger/loggers/geojson/GeoJSONLogger.java @@ -19,13 +19,14 @@ public class GeoJSONLogger implements FileLogger { final static Object lock = new Object(); - private final static ThreadPoolExecutor EXECUTOR = new ThreadPoolExecutor(1, 1, 60, TimeUnit.SECONDS, new LinkedBlockingQueue(10), new RejectionHandler()); private final File file; - protected final String name; + protected static final String name = "GeoJSON"; + private final static ThreadPoolExecutor EXECUTOR = new ThreadPoolExecutor(1, 1, 60, + TimeUnit.SECONDS, new LinkedBlockingQueue(10), new RejectionHandler(name)); + public GeoJSONLogger(File file, boolean addNewTrackSegment) { this.file = file; - name = "GeoJSON"; } @Override diff --git a/gpslogger/src/main/java/com/mendhak/gpslogger/loggers/gpx/Gpx10FileLogger.java b/gpslogger/src/main/java/com/mendhak/gpslogger/loggers/gpx/Gpx10FileLogger.java index 36af142d3..43d264915 100644 --- a/gpslogger/src/main/java/com/mendhak/gpslogger/loggers/gpx/Gpx10FileLogger.java +++ b/gpslogger/src/main/java/com/mendhak/gpslogger/loggers/gpx/Gpx10FileLogger.java @@ -44,11 +44,12 @@ public class Gpx10FileLogger implements FileLogger { protected final static Object lock = new Object(); - private final static ThreadPoolExecutor EXECUTOR = new ThreadPoolExecutor(1, 1, 60, TimeUnit.SECONDS, - new LinkedBlockingQueue(10), new RejectionHandler()); + private File gpxFile = null; private final boolean addNewTrackSegment; - protected final String name = "GPX"; + protected static final String name = "GPX"; + private final static ThreadPoolExecutor EXECUTOR = new ThreadPoolExecutor(1, 1, 60, TimeUnit.SECONDS, + new LinkedBlockingQueue(10), new RejectionHandler(name)); public Gpx10FileLogger(File gpxFile, boolean addNewTrackSegment) { this.gpxFile = gpxFile; @@ -241,7 +242,6 @@ public void run() { raf.seek(startPosition); raf.write(trackPoint.getBytes()); raf.close(); - Files.addToMediaDatabase(gpxFile, "text/plain"); LOG.debug("Finished writing to GPX10 file"); } catch (Exception e) { diff --git a/gpslogger/src/main/java/com/mendhak/gpslogger/loggers/kml/Kml22FileLogger.java b/gpslogger/src/main/java/com/mendhak/gpslogger/loggers/kml/Kml22FileLogger.java index b9952a83c..c9aa645de 100644 --- a/gpslogger/src/main/java/com/mendhak/gpslogger/loggers/kml/Kml22FileLogger.java +++ b/gpslogger/src/main/java/com/mendhak/gpslogger/loggers/kml/Kml22FileLogger.java @@ -41,11 +41,11 @@ public class Kml22FileLogger implements FileLogger { protected final static Object lock = new Object(); - private final static ThreadPoolExecutor EXECUTOR = new ThreadPoolExecutor(1, 1, 60, TimeUnit.SECONDS, - new LinkedBlockingQueue(10), new RejectionHandler()); private final boolean addNewTrackSegment; private final File kmlFile; - protected final String name = "KML"; + protected static final String name = "KML"; + private final static ThreadPoolExecutor EXECUTOR = new ThreadPoolExecutor(1, 1, 60, TimeUnit.SECONDS, + new LinkedBlockingQueue(10), new RejectionHandler(name)); public Kml22FileLogger(File kmlFile, boolean addNewTrackSegment) { @@ -221,7 +221,6 @@ public void run() { raf.seek(kmlFile.length() - 42); raf.write(coords.toString().getBytes()); raf.close(); - Files.addToMediaDatabase(kmlFile, "text/xml"); LOG.debug("Finished writing to KML22 File"); } diff --git a/gpslogger/src/main/java/com/mendhak/gpslogger/loggers/nmea/NmeaFileLogger.java b/gpslogger/src/main/java/com/mendhak/gpslogger/loggers/nmea/NmeaFileLogger.java index 5653fcfcd..1dcbf5480 100644 --- a/gpslogger/src/main/java/com/mendhak/gpslogger/loggers/nmea/NmeaFileLogger.java +++ b/gpslogger/src/main/java/com/mendhak/gpslogger/loggers/nmea/NmeaFileLogger.java @@ -44,8 +44,9 @@ public class NmeaFileLogger { protected final static Object lock = new Object(); private static final Logger LOG = Logs.of(NmeaFileLogger.class); String fileName; + protected static final String name = "NMEA"; private final static ThreadPoolExecutor EXECUTOR = new ThreadPoolExecutor(1, 1, 60, TimeUnit.SECONDS, - new LinkedBlockingQueue(10), new RejectionHandler()); + new LinkedBlockingQueue(30), new RejectionHandler(name)); private PreferenceHelper preferenceHelper = PreferenceHelper.getInstance(); private Session session = Session.getInstance(); @@ -98,7 +99,6 @@ public void run() { writer.write(nmeaSentence); writer.newLine(); writer.close(); - Files.addToMediaDatabase(gpxFile, "text/plain"); } catch (IOException e) { LOG.error("Error writing NMEA sentence", e); diff --git a/gpslogger/src/main/java/com/mendhak/gpslogger/ui/fragments/display/GpsLogViewFragment.java b/gpslogger/src/main/java/com/mendhak/gpslogger/ui/fragments/display/GpsLogViewFragment.java index 7772a424f..04ae3850c 100644 --- a/gpslogger/src/main/java/com/mendhak/gpslogger/ui/fragments/display/GpsLogViewFragment.java +++ b/gpslogger/src/main/java/com/mendhak/gpslogger/ui/fragments/display/GpsLogViewFragment.java @@ -128,21 +128,21 @@ void showLogcatMessages(){ StringBuilder sb = new StringBuilder(); for(ILoggingEvent message : SessionLogcatAppender.Statuses){ - if(message.getMarker() == SessionLogcatAppender.MARKER_LOCATION){ - sb.append(getFormattedMessage(message.getMessage(), R.color.accentColorComplementary, message.getTimeStamp(), true)); + if(message.getMarkers() != null && message.getMarkers().contains(SessionLogcatAppender.MARKER_LOCATION)){ + sb.append(getFormattedMessage(message.getFormattedMessage(), R.color.accentColorComplementary, message.getTimeStamp(), true)); } else if(!chkLocationsOnly.isChecked()){ if(message.getLevel() == Level.ERROR) { - sb.append(getFormattedMessage(message.getMessage(), R.color.errorColor, message.getTimeStamp(), false)); + sb.append(getFormattedMessage(message.getFormattedMessage(), R.color.errorColor, message.getTimeStamp(), false)); } else if(message.getLevel() == Level.WARN){ - sb.append(getFormattedMessage(message.getMessage(), R.color.warningColor, message.getTimeStamp(), false)); + sb.append(getFormattedMessage(message.getFormattedMessage(), R.color.warningColor, message.getTimeStamp(), false)); } else { - sb.append(getFormattedMessage(message.getMessage(), R.color.secondaryColorText, message.getTimeStamp(), false)); + sb.append(getFormattedMessage(message.getFormattedMessage(), R.color.secondaryColorText, message.getTimeStamp(), false)); } } diff --git a/gpslogger/src/main/java/com/mendhak/gpslogger/ui/fragments/settings/GoogleDriveSettingsFragment.java b/gpslogger/src/main/java/com/mendhak/gpslogger/ui/fragments/settings/GoogleDriveSettingsFragment.java index d15707d3c..a927c86c4 100644 --- a/gpslogger/src/main/java/com/mendhak/gpslogger/ui/fragments/settings/GoogleDriveSettingsFragment.java +++ b/gpslogger/src/main/java/com/mendhak/gpslogger/ui/fragments/settings/GoogleDriveSettingsFragment.java @@ -178,7 +178,7 @@ public boolean onPreferenceClick(Preference preference) { AuthorizationRequest authRequest = requestBuilder.build(); Intent authIntent = authorizationService.getAuthorizationRequestIntent(authRequest); googleDriveAuthenticationWorkflow.launch(new IntentSenderRequest.Builder( - PendingIntent.getActivity(getActivity(), 0, authIntent, 0)) + PendingIntent.getActivity(getActivity(), 0, authIntent, PendingIntent.FLAG_IMMUTABLE)) .setFillInIntent(authIntent) .build()); diff --git a/gpslogger/src/main/java/com/mendhak/gpslogger/ui/fragments/settings/OSMAuthorizationFragment.java b/gpslogger/src/main/java/com/mendhak/gpslogger/ui/fragments/settings/OSMAuthorizationFragment.java index 7b2b28960..a93a08da7 100644 --- a/gpslogger/src/main/java/com/mendhak/gpslogger/ui/fragments/settings/OSMAuthorizationFragment.java +++ b/gpslogger/src/main/java/com/mendhak/gpslogger/ui/fragments/settings/OSMAuthorizationFragment.java @@ -204,7 +204,7 @@ public boolean onPreferenceClick(Preference preference) { AuthorizationRequest authRequest = requestBuilder.build(); Intent authIntent = authorizationService.getAuthorizationRequestIntent(authRequest); openStreetMapAuthenticationWorkflow.launch(new IntentSenderRequest.Builder( - PendingIntent.getActivity(getActivity(), 53, authIntent, 0)) + PendingIntent.getActivity(getActivity(), 53, authIntent, PendingIntent.FLAG_IMMUTABLE)) .setFillInIntent(authIntent) .build()); diff --git a/gpslogger/src/main/res/layout/toolbar.xml b/gpslogger/src/main/res/layout/toolbar.xml index b1619ad7e..e07c69e87 100644 --- a/gpslogger/src/main/res/layout/toolbar.xml +++ b/gpslogger/src/main/res/layout/toolbar.xml @@ -4,10 +4,9 @@ xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:id="@+id/toolbar" - android:layout_height="55dp" + android:layout_height="wrap_content" android:layout_width="match_parent" android:minHeight="?attr/actionBarSize" android:background="?attr/colorPrimary" - android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar" - app:contentInsetStart="72dp"> + android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"> \ No newline at end of file