Merge branch 'master' of codeberg.org:Freeyourgadget/Gadgetbridge into combined

This commit is contained in:
Daniel Dakhno 2022-03-09 10:58:59 +01:00
commit d9a5a8c815
12 changed files with 211 additions and 67 deletions

View File

@ -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;
}
}

View File

@ -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

View File

@ -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);
}
}

View File

@ -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) {
}
}
}

View File

@ -579,39 +579,46 @@ public class HybridHRWatchfaceDesignerActivity extends AbstractGBActivity implem
if (widget != null) {
posY.setText(Integer.toString(widget.getPosY()));
}
// Configure position preset buttons
Button btnTop = layout.findViewById(R.id.watchface_widget_preset_top);
btnTop.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
posX.setText("120");
posY.setText("58");
class WidgetPosition{
final int posX, posY, buttonResource, hintStringResource;
public WidgetPosition(int posX, int posY, int buttonResource, int hintStringResource) {
this.posX = posX;
this.posY = posY;
this.buttonResource = buttonResource;
this.hintStringResource = hintStringResource;
}
});
Button btnBottom = layout.findViewById(R.id.watchface_widget_preset_bottom);
btnBottom.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
posX.setText("120");
posY.setText("182");
}
WidgetPosition[] positions = new WidgetPosition[]{
new WidgetPosition(120, 58, R.id.watchface_widget_preset_top, R.string.watchface_dialog_widget_preset_top),
new WidgetPosition(182, 120, R.id.watchface_widget_preset_right, R.string.watchface_dialog_widget_preset_right),
new WidgetPosition(120, 182, R.id.watchface_widget_preset_bottom, R.string.watchface_dialog_widget_preset_bottom),
new WidgetPosition(58, 120, R.id.watchface_widget_preset_left, R.string.watchface_dialog_widget_preset_left),
};
for(final WidgetPosition position : positions){
Button btn = layout.findViewById(position.buttonResource);
btn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
posX.setText(String.valueOf(position.posX));
posY.setText(String.valueOf(position.posY));
}
});
}
if(widget == null){
int currentIndex = widgets.size();
if(currentIndex < 4){
WidgetPosition newPosition = positions[currentIndex];
posX.setText(String.valueOf(newPosition.posX));
posY.setText(String.valueOf(newPosition.posY));
GB.toast(getString(R.string.watchface_dialog_pre_setting_position, getString(newPosition.hintStringResource)), Toast.LENGTH_SHORT, GB.INFO);
}
});
Button btnLeft = layout.findViewById(R.id.watchface_widget_preset_left);
btnLeft.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
posX.setText("58");
posY.setText("120");
}
});
Button btnRight = layout.findViewById(R.id.watchface_widget_preset_right);
btnRight.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
posX.setText("182");
posY.setText("120");
}
});
}
// Set widget size
final LinearLayout sizeLayout = layout.findViewById(R.id.watchface_widget_size_layout);
sizeLayout.setVisibility(View.GONE);

View File

@ -38,7 +38,7 @@ public class AutoStartReceiver extends BroadcastReceiver {
} else {
GBApplication.deviceService().start();
}
Log.i(TAG, "Going to enable periodic exporter");
PeriodicExporter.enablePeriodicExport(context);
}
}

View File

@ -194,6 +194,9 @@ public class BangleJSDeviceSupport extends AbstractBTLEDeviceSupport {
batteryInfo.level = b;
batteryInfo.state = BatteryState.BATTERY_NORMAL;
}
if (json.has("chg") && json.getInt("chg") == 1) {
batteryInfo.state = BatteryState.BATTERY_CHARGING;
}
if (json.has("volt"))
batteryInfo.voltage = (float) json.getDouble("volt");
handleGBDeviceEvent(batteryInfo);
@ -367,9 +370,10 @@ public class BangleJSDeviceSupport extends AbstractBTLEDeviceSupport {
jsonalarms.put(jsonalarm);
Calendar calendar = AlarmUtils.toCalendar(alarm);
// TODO: getRepetition to ensure it only happens on correct day?
jsonalarm.put("h", alarm.getHour());
jsonalarm.put("m", alarm.getMinute());
jsonalarm.put("rep", alarm.getRepetition());
}
uartTxJSON("onSetAlarms", o);
} catch (JSONException e) {

View File

@ -100,7 +100,7 @@
android:text="@string/activity_db_management_clean_export_directory_label" />
<TextView
android:id="@+id/autoExportLocation_label"
android:id="@+id/autoExportTitleLabel"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
@ -109,7 +109,29 @@
android:textColor="@color/accent" />
<TextView
android:id="@+id/autoExportLocation_intro"
android:id="@+id/autoExportEnabled"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text=""
android:textAppearance="?android:attr/textAppearanceSmall" />
<TextView
android:id="@+id/autoExportScheduled"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/activity_db_management_autoexport_scheduled_no"
android:textAppearance="?android:attr/textAppearanceSmall" />
<TextView
android:id="@+id/autoExport_lastTime_label"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/autoExport_lastTime_label"
android:textAppearance="?android:attr/textAppearanceSmall" />
<TextView
android:id="@+id/autoExportLocation_label"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/activity_db_management_autoexport_explanation"

View File

@ -1589,6 +1589,7 @@
<string name="sony_anc_optimize_confirmation_description">Verwende den Kopfhörer wie gewohnt. Wenn sich die Tragebedingungen oder der Luftdruck ändern, führe den Optimierer erneut aus.</string>
<string name="devicetype_amazfit_pop">Amazfit Pop</string>
<string name="devicetype_amazfit_pop_pro">Amazfit Pop Pro</string>
<string name="watchface_dialog_pre_setting_position">Setze position auf %s</string>
<string name="watchface_setting_light_up_on_notification">Bei neuen Benachrichtigungen aufleuchten</string>
<string name="info_connected_count">%d Geräte verbunden</string>

View File

@ -760,7 +760,13 @@
<string name="dbmanagementactivity_old_activity_db_deletion_failed">Old Activity database deletion failed.</string>
<string name="dbmanagementactivity_overwrite">Overwrite</string>
<string name="activity_db_management_autoexport_explanation">Database autoexport location has been set to:</string>
<string name="autoExport_lastTime_label">Last AutoExport: %1$s</string>
<string name="activity_db_management_autoexport_enabled_yes">AutoExport is enabled.</string>
<string name="activity_db_management_autoexport_enabled_no">AutoExport is not enabled.</string>
<string name="activity_db_management_autoexport_scheduled_yes">AutoExport has (originally) been scheduled for %1$s</string>
<string name="activity_db_management_autoexport_scheduled_no">AutoExport has not been not scheduled.</string>
<string name="activity_db_management_autoexport_label">AutoExport</string>
<string name="activity_db_management_autoexport_location">Location could not be understood. Likely an issue of newer Android permission system. Most likely, autoexport is not working now.</string>
<string name="activity_DB_ExportButton">Export Data</string>
<string name="activity_DB_import_button">Import Data</string>
<string name="activity_DB_test_export_button">Run AutoExport Now</string>
@ -1521,6 +1527,7 @@
<string name="watchface_dialog_widget_width">Width:</string>
<string name="pref_title_opentracks_packagename">OpenTracks package name</string>
<string name="pref_summary_opentracks_packagename">Used for starting/stopping GPS track recording in external fitness app.</string>
<string name="watchface_dialog_pre_setting_position">pre-setting position to %s</string>
<string name="watchface_setting_light_up_on_notification">Light up on new notification</string>
<string name="info_no_devices_connected">no devices connected</string>

View File

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="ic_launcher_background">#000000</color>
</resources>

View File

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="ic_launcher_background">#ff3d00</color>
</resources>