From f44ff3ae696cd88843cfead936078aae9eb47c8e Mon Sep 17 00:00:00 2001 From: vanous Date: Sun, 27 Feb 2022 18:43:53 +0100 Subject: [PATCH] AutoExporter changes for better operation and troubleshooting. - Add more info about AutoExport into DataManagement activity - Fix scheduleAlarm name - Run AutoExporter in another thread - Start AutoExporter on app startup if not running yet from AutoStartReceiver - Save and show time of scheduled and last executed AutoExport --- .../gadgetbridge/GBApplication.java | 22 ++++++ .../activities/DataManagementActivity.java | 64 +++++++++++++++--- .../activities/SettingsActivity.java | 6 +- .../database/PeriodicExporter.java | 67 ++++++++++++++----- .../externalevents/AutoStartReceiver.java | 2 +- .../res/layout/activity_data_management.xml | 26 ++++++- app/src/main/res/values/strings.xml | 6 ++ 7 files changed, 158 insertions(+), 35 deletions(-) diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/GBApplication.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/GBApplication.java index d035cb2e2..2425b7ec7 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/GBApplication.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/GBApplication.java @@ -62,6 +62,7 @@ import nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSett import nodomain.freeyourgadget.gadgetbridge.database.DBHandler; import nodomain.freeyourgadget.gadgetbridge.database.DBHelper; import nodomain.freeyourgadget.gadgetbridge.database.DBOpenHelper; +import nodomain.freeyourgadget.gadgetbridge.database.PeriodicExporter; import nodomain.freeyourgadget.gadgetbridge.devices.DeviceManager; import nodomain.freeyourgadget.gadgetbridge.entities.DaoMaster; import nodomain.freeyourgadget.gadgetbridge.entities.DaoSession; @@ -145,6 +146,9 @@ public class GBApplication extends Application { private BluetoothStateChangeReceiver bluetoothStateChangeReceiver; private OpenTracksContentObserver openTracksObserver; + + private long lastAutoExportTimestamp = 0; + private long autoExportScheduledTimestamp = 0; public static void quit() { GB.log("Quitting Gadgetbridge...", GB.INFO, null); @@ -213,6 +217,8 @@ public class GBApplication extends Application { loadAppsPebbleBlackList(); loadCalendarsBlackList(); + PeriodicExporter.enablePeriodicExport(context); + if (isRunningMarshmallowOrLater()) { notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE); if (isRunningOreoOrLater()) { @@ -1101,4 +1107,20 @@ public class GBApplication extends Application { public OpenTracksContentObserver getOpenTracksObserver() { return openTracksObserver; } + + public long getLastAutoExportTimestamp() { + return lastAutoExportTimestamp; + } + + public void setLastAutoExportTimestamp(long lastAutoExportTimestamp) { + this.lastAutoExportTimestamp = lastAutoExportTimestamp; + } + + public long getAutoExportScheduledTimestamp() { + return autoExportScheduledTimestamp; + } + + public void setAutoExportScheduledTimestamp(long autoExportScheduledTimestamp) { + this.autoExportScheduledTimestamp = autoExportScheduledTimestamp; + } } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/DataManagementActivity.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/DataManagementActivity.java index 145a9f7c4..2b526cce8 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/DataManagementActivity.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/DataManagementActivity.java @@ -42,6 +42,7 @@ import org.slf4j.LoggerFactory; import java.io.File; import java.io.IOException; +import java.util.Date; import java.util.List; import nodomain.freeyourgadget.gadgetbridge.GBApplication; @@ -51,6 +52,7 @@ import nodomain.freeyourgadget.gadgetbridge.database.DBHelper; import nodomain.freeyourgadget.gadgetbridge.database.PeriodicExporter; import nodomain.freeyourgadget.gadgetbridge.entities.Device; import nodomain.freeyourgadget.gadgetbridge.util.AndroidUtils; +import nodomain.freeyourgadget.gadgetbridge.util.DateTimeUtils; import nodomain.freeyourgadget.gadgetbridge.util.FileUtils; import nodomain.freeyourgadget.gadgetbridge.util.GB; import nodomain.freeyourgadget.gadgetbridge.util.GBPrefs; @@ -145,7 +147,7 @@ public class DataManagementActivity extends AbstractGBActivity { cleanExportDirectory(); } }); - + GBApplication gbApp = GBApplication.app(); Prefs prefs = GBApplication.getPrefs(); boolean autoExportEnabled = prefs.getBoolean(GBPrefs.AUTO_EXPORT_ENABLED, false); int autoExportInterval = prefs.getInt(GBPrefs.AUTO_EXPORT_INTERVAL, 0); @@ -153,16 +155,42 @@ public class DataManagementActivity extends AbstractGBActivity { //String autoExportLocation = prefs.getString(GBPrefs.AUTO_EXPORT_LOCATION, ""); int testExportVisibility = (autoExportInterval > 0 && autoExportEnabled) ? View.VISIBLE : View.GONE; - + boolean isExportEnabled = autoExportInterval > 0 && autoExportEnabled; TextView autoExportLocation_label = findViewById(R.id.autoExportLocation_label); autoExportLocation_label.setVisibility(testExportVisibility); - TextView autoExportLocation_intro = findViewById(R.id.autoExportLocation_intro); - autoExportLocation_intro.setVisibility(testExportVisibility); - TextView autoExportLocation_path = findViewById(R.id.autoExportLocation_path); autoExportLocation_path.setVisibility(testExportVisibility); - autoExportLocation_path.setText(getAutoExportLocationSummary()); + autoExportLocation_path.setText(getAutoExportLocationUserString() + " (" + getAutoExportLocationPreferenceString() + ")" ); + + TextView autoExportEnabled_label = findViewById(R.id.autoExportEnabled); + if (isExportEnabled) { + autoExportEnabled_label.setText(getString(R.string.activity_db_management_autoexport_enabled_yes)); + } else { + autoExportEnabled_label.setText(getString(R.string.activity_db_management_autoexport_enabled_no)); + } + + TextView autoExportScheduled = findViewById(R.id.autoExportScheduled); + autoExportScheduled.setVisibility(testExportVisibility); + long setAutoExportScheduledTimestamp = gbApp.getAutoExportScheduledTimestamp(); + if (setAutoExportScheduledTimestamp > 0) { + autoExportScheduled.setText(getString(R.string.activity_db_management_autoexport_scheduled_yes, + DateTimeUtils.formatDateTime(new Date(setAutoExportScheduledTimestamp)))); + } else { + autoExportScheduled.setText(getResources().getString(R.string.activity_db_management_autoexport_scheduled_no)); + } + + TextView autoExport_lastTime_label = findViewById(R.id.autoExport_lastTime_label); + long lastAutoExportTimestamp = gbApp.getLastAutoExportTimestamp(); + + autoExport_lastTime_label.setVisibility(View.GONE); + autoExport_lastTime_label.setText(getString(R.string.autoExport_lastTime_label, + DateTimeUtils.formatDateTime(new Date(lastAutoExportTimestamp)))); + + if (lastAutoExportTimestamp > 0) { + autoExport_lastTime_label.setVisibility(testExportVisibility); + autoExport_lastTime_label.setVisibility(testExportVisibility); + } final Context context = getApplicationContext(); Button testExportDBButton = findViewById(R.id.testExportDBButton); @@ -180,18 +208,25 @@ public class DataManagementActivity extends AbstractGBActivity { sharedPrefs = PreferenceManager.getDefaultSharedPreferences(this); } - - - //would rather re-use method of SettingsActivity... but lifecycle... - private String getAutoExportLocationSummary() { + private String getAutoExportLocationPreferenceString() { String autoExportLocation = GBApplication.getPrefs().getString(GBPrefs.AUTO_EXPORT_LOCATION, null); if (autoExportLocation == null) { return ""; } + return autoExportLocation; + } + + private String getAutoExportLocationUri() { + String autoExportLocation = getAutoExportLocationPreferenceString(); + if (autoExportLocation == null) { + return ""; + } Uri uri = Uri.parse(autoExportLocation); try { + return AndroidUtils.getFilePath(getApplicationContext(), uri); } catch (IllegalArgumentException e) { + LOG.error("getFilePath did not work, trying to resolve content provider path"); try { Cursor cursor = getContentResolver().query( uri, @@ -208,6 +243,13 @@ public class DataManagementActivity extends AbstractGBActivity { return ""; } + private String getAutoExportLocationUserString() { + String location = getAutoExportLocationUri(); + if (location == "") { + return getString(R.string.activity_db_management_autoexport_location); + } + return location; + } private boolean hasOldActivityDatabase() { return new DBHelper(this).existsDB("ActivityDatabase"); @@ -403,7 +445,7 @@ public class DataManagementActivity extends AbstractGBActivity { public void onClick(DialogInterface dialog, int which) { try { File externalFilesDir = FileUtils.getExternalFilesDir(); - String autoexportFile = getAutoExportLocationSummary(); + String autoexportFile = getAutoExportLocationUri(); for (File file : externalFilesDir.listFiles()) { if (file.isFile() && (!FileUtils.getExtension(file.toString()).toLowerCase().equals("gpx")) && //keep GPX files diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/SettingsActivity.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/SettingsActivity.java index 695b06746..5970cc691 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/SettingsActivity.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/SettingsActivity.java @@ -313,7 +313,7 @@ public class SettingsActivity extends AbstractSettingsActivity { Integer.valueOf((String) autoExportInterval)); preference.setSummary(summary); boolean auto_export_enabled = GBApplication.getPrefs().getBoolean(GBPrefs.AUTO_EXPORT_ENABLED, false); - PeriodicExporter.sheduleAlarm(getApplicationContext(), Integer.valueOf((String) autoExportInterval), auto_export_enabled); + PeriodicExporter.scheduleAlarm(getApplicationContext(), Integer.valueOf((String) autoExportInterval), auto_export_enabled); return true; } }); @@ -327,7 +327,7 @@ public class SettingsActivity extends AbstractSettingsActivity { @Override public boolean onPreferenceChange(Preference preference, Object autoExportEnabled) { int autoExportInterval = GBApplication.getPrefs().getInt(GBPrefs.AUTO_EXPORT_INTERVAL, 0); - PeriodicExporter.sheduleAlarm(getApplicationContext(), autoExportInterval, (boolean) autoExportEnabled); + PeriodicExporter.scheduleAlarm(getApplicationContext(), autoExportInterval, (boolean) autoExportEnabled); return true; } }); @@ -492,7 +492,7 @@ public class SettingsActivity extends AbstractSettingsActivity { .getPrefs().getBoolean(GBPrefs.AUTO_EXPORT_ENABLED, false); int autoExportPeriod = GBApplication .getPrefs().getInt(GBPrefs.AUTO_EXPORT_INTERVAL, 0); - PeriodicExporter.sheduleAlarm(getApplicationContext(), autoExportPeriod, autoExportEnabled); + PeriodicExporter.scheduleAlarm(getApplicationContext(), autoExportPeriod, autoExportEnabled); } } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/database/PeriodicExporter.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/database/PeriodicExporter.java index 2fe98665e..e3d5e3568 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/database/PeriodicExporter.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/database/PeriodicExporter.java @@ -44,24 +44,30 @@ public class PeriodicExporter extends BroadcastReceiver { public static void enablePeriodicExport(Context context) { Prefs prefs = GBApplication.getPrefs(); + GBApplication gbApp = GBApplication.app(); + long autoExportScheduled = gbApp.getAutoExportScheduledTimestamp(); boolean autoExportEnabled = prefs.getBoolean(GBPrefs.AUTO_EXPORT_ENABLED, false); Integer autoExportInterval = prefs.getInt(GBPrefs.AUTO_EXPORT_INTERVAL, 0); - sheduleAlarm(context, autoExportInterval, autoExportEnabled); + scheduleAlarm(context, autoExportInterval, autoExportEnabled && autoExportScheduled == 0); } - public static void sheduleAlarm(Context context, Integer autoExportInterval, boolean autoExportEnabled) { + public static void scheduleAlarm(Context context, Integer autoExportInterval, boolean autoExportEnabled) { Intent i = new Intent(context, PeriodicExporter.class); - PendingIntent pi = PendingIntent.getBroadcast(context, 0 , i, 0); + PendingIntent pi = PendingIntent.getBroadcast(context, 0, i, 0); AlarmManager am = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE); am.cancel(pi); if (!autoExportEnabled) { + LOG.info("Not scheduling periodic export, either already scheduled or not enabled"); return; } int exportPeriod = autoExportInterval * 60 * 60 * 1000; if (exportPeriod == 0) { + LOG.info("Not scheduling periodic export, interval set to 0"); return; } - LOG.info("Enabling periodic export"); + LOG.info("Scheduling periodic export"); + GBApplication gbApp = GBApplication.app(); + gbApp.setAutoExportScheduledTimestamp(System.currentTimeMillis() + exportPeriod); am.setInexactRepeating( AlarmManager.ELAPSED_REALTIME, SystemClock.elapsedRealtime() + exportPeriod, @@ -72,21 +78,46 @@ public class PeriodicExporter extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { - LOG.info("Exporting DB"); - try (DBHandler dbHandler = GBApplication.acquireDB()) { - DBHelper helper = new DBHelper(context); - String dst = GBApplication.getPrefs().getString(GBPrefs.AUTO_EXPORT_LOCATION, null); - if (dst == null) { - LOG.info("Unable to export DB, export location not set"); - return; + LOG.info("Received command to export DB"); + createRefreshTask("Export database", context).execute(); + } + + protected RefreshTask createRefreshTask(String task, Context context) { + return new RefreshTask(task, context); + } + + public class RefreshTask extends DBAccess { + Context localContext; + + public RefreshTask(String task, Context context) { + super(task, context); + localContext = context; + } + + @Override + protected void doInBackground(DBHandler handler) { + LOG.info("Exporting DB in a background thread"); + try (DBHandler dbHandler = GBApplication.acquireDB()) { + DBHelper helper = new DBHelper(localContext); + String dst = GBApplication.getPrefs().getString(GBPrefs.AUTO_EXPORT_LOCATION, null); + if (dst == null) { + LOG.info("Unable to export DB, export location not set"); + return; + } + Uri dstUri = Uri.parse(dst); + try (OutputStream out = localContext.getContentResolver().openOutputStream(dstUri)) { + helper.exportDB(dbHandler, out); + GBApplication gbApp = GBApplication.app(); + gbApp.setLastAutoExportTimestamp(System.currentTimeMillis()); + } + } catch (Exception ex) { + GB.updateExportFailedNotification(localContext.getString(R.string.notif_export_failed_title), localContext); + LOG.info("Exception while exporting DB: ", ex); } - Uri dstUri = Uri.parse(dst); - try (OutputStream out = context.getContentResolver().openOutputStream(dstUri)) { - helper.exportDB(dbHandler, out); - } - } catch (Exception ex) { - GB.updateExportFailedNotification(context.getString(R.string.notif_export_failed_title), context); - LOG.info("Exception while exporting DB: ", ex); + } + + @Override + protected void onPostExecute(Object o) { } } } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/AutoStartReceiver.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/AutoStartReceiver.java index 208b90b0f..f5e916486 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/AutoStartReceiver.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/AutoStartReceiver.java @@ -38,7 +38,7 @@ public class AutoStartReceiver extends BroadcastReceiver { } else { GBApplication.deviceService().start(); } - + Log.i(TAG, "Going to enable periodic exporter"); PeriodicExporter.enablePeriodicExport(context); } } diff --git a/app/src/main/res/layout/activity_data_management.xml b/app/src/main/res/layout/activity_data_management.xml index d72cb5216..0c2489d00 100644 --- a/app/src/main/res/layout/activity_data_management.xml +++ b/app/src/main/res/layout/activity_data_management.xml @@ -100,7 +100,7 @@ android:text="@string/activity_db_management_clean_export_directory_label" /> + + + + + + + Old Activity database deletion failed. Overwrite Database autoexport location has been set to: + Last AutoExport: %1$s + AutoExport is enabled. + AutoExport is not enabled. + AutoExport has (originally) been scheduled for %1$s + AutoExport has not been not scheduled. AutoExport + Location could not be understood. Likely an issue of newer Android permission system. Most likely, autoexport is not working now. Export Data Import Data Run AutoExport Now