diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/garmin/GarminCoordinator.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/garmin/GarminCoordinator.java index 25307b0647..8281e8190f 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/garmin/GarminCoordinator.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/garmin/GarminCoordinator.java @@ -266,6 +266,7 @@ public abstract class GarminCoordinator extends AbstractBLEDeviceCoordinator { developer.add(R.xml.devicesettings_import_activity_files); developer.add(R.xml.devicesettings_keep_activity_data_on_device); developer.add(R.xml.devicesettings_fetch_unknown_files); + developer.add(R.xml.devicesettings_install_unsupported_files); developer.add(R.xml.devicesettings_new_sync_protocol); developer.add(R.xml.devicesettings_garmin_mlr); diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/garmin/GarminFitFileInstallHandler.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/garmin/GarminFitFileInstallHandler.java index 455cbabe48..fd34a83fd7 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/garmin/GarminFitFileInstallHandler.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/garmin/GarminFitFileInstallHandler.java @@ -28,8 +28,8 @@ import org.slf4j.LoggerFactory; import java.io.BufferedInputStream; import java.io.IOException; import java.io.InputStream; -import java.util.Optional; +import nodomain.freeyourgadget.gadgetbridge.GBApplication; import nodomain.freeyourgadget.gadgetbridge.R; import nodomain.freeyourgadget.gadgetbridge.activities.install.FwAppInstallerActivity; import nodomain.freeyourgadget.gadgetbridge.activities.install.InstallActivity; @@ -52,6 +52,7 @@ public class GarminFitFileInstallHandler implements InstallHandler { protected final Context mContext; private byte[] rawBytes; + private String filename; private FitFile fitFile; private FileType.FILETYPE fileType; private FitParseException fitParseException; @@ -62,6 +63,7 @@ public class GarminFitFileInstallHandler implements InstallHandler { final UriHelper uriHelper; try { uriHelper = UriHelper.get(uri, context); + filename = uriHelper.getFileName(); } catch (final IOException e) { LOG.error("Failed to get uri", e); return; @@ -162,66 +164,61 @@ public class GarminFitFileInstallHandler implements InstallHandler { } private boolean parseFitFile(final InstallActivity installActivity, final GarminCoordinator coordinator, final GBDevice device) { + final boolean installUnsupportedFiles = GBApplication.getDevicePrefs(device).installUnsupportedFiles(); + final String name; - final int kindName; + final String kindName; + final boolean supported; switch (fileType) { case COURSES: - if (!coordinator.supports(device, GarminCapability.COURSE_DOWNLOAD)) { - LOG.warn("Device does not support course download"); - return false; - } - final Optional fitCourseOpt = fitFile.getRecords().stream() + kindName = mContext.getString(R.string.kind_gpx_route); + supported = coordinator.supports(device, GarminCapability.COURSE_DOWNLOAD); + name = fitFile.getRecords().stream() .filter(r -> r instanceof FitCourse) .map(r -> (FitCourse) r) - .findFirst(); - - if (!fitCourseOpt.isPresent()) { - LOG.error("Fit file has no course record"); - return false; - } - final FitCourse fitCourse = fitCourseOpt.get(); - - name = String.valueOf(fitCourse.getName()); - kindName = R.string.kind_gpx_route; - + .findFirst() + .map(FitCourse::getName) + .orElse(filename); break; case WORKOUTS: - if (!coordinator.supports(device, GarminCapability.WORKOUT_DOWNLOAD)) { - LOG.warn("Device does not support workout download"); - return false; - } - final Optional fitWorkoutOpt = fitFile.getRecords().stream() + kindName = mContext.getString(R.string.menuitem_workout); + supported = coordinator.supports(device, GarminCapability.WORKOUT_DOWNLOAD); + name = fitFile.getRecords().stream() .filter(r -> r instanceof FitWorkout) .map(r -> (FitWorkout) r) - .findFirst(); - - if (!fitWorkoutOpt.isPresent()) { - LOG.error("Fit file has no workout record"); - return false; - } - final FitWorkout fitWorkout = fitWorkoutOpt.get(); - - name = String.valueOf(fitWorkout.getName()); - kindName = R.string.menuitem_workout; - + .findFirst() + .map(FitWorkout::getName) + .orElse(filename); break; default: LOG.warn("Unsupported fit file type: {}", fileType); + kindName = mContext.getString(R.string.menuitem_unknown_app, fileType.name()); + supported = false; + name = filename; + } + + if (!supported) { + LOG.warn("Device does not support install of {}", fileType); + if (!installUnsupportedFiles) { return false; + } } final GenericItem fwItem = new GenericItem(mContext.getString( R.string.installhandler_firmware_name, mContext.getString(coordinator.getDeviceNameResource()), - mContext.getString(kindName), + kindName, name )); fwItem.setIcon(coordinator.getDefaultIconResource()); final StringBuilder builder = new StringBuilder(); - final String kindNameString = mContext.getString(kindName); - builder.append(mContext.getString(R.string.fw_upgrade_notice, kindNameString)); + builder.append(mContext.getString(R.string.fw_upgrade_notice, kindName)); + if (!supported) { + builder.append("\n\n"); + builder.append(mContext.getString(R.string.install_unsupported_files_warning)); + } installActivity.setInfoText(builder.toString()); installActivity.setInstallItem(fwItem); diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/garmin/GarminGpxRouteInstallHandler.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/garmin/GarminGpxRouteInstallHandler.java index 0a0f856d96..6677d4ac40 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/garmin/GarminGpxRouteInstallHandler.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/garmin/GarminGpxRouteInstallHandler.java @@ -24,6 +24,7 @@ import android.net.Uri; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import nodomain.freeyourgadget.gadgetbridge.GBApplication; import nodomain.freeyourgadget.gadgetbridge.devices.DeviceCoordinator; import nodomain.freeyourgadget.gadgetbridge.devices.GpxRouteInstallHandler; import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice; @@ -36,12 +37,13 @@ public class GarminGpxRouteInstallHandler extends GpxRouteInstallHandler { } @Override - protected boolean isCompatible(GBDevice device) { + protected boolean isCompatible(final GBDevice device) { final DeviceCoordinator coordinator = device.getDeviceCoordinator(); if (!(coordinator instanceof GarminCoordinator garminCoordinator)) { LOG.warn("Coordinator is not a GarminCoordinator: {}", coordinator.getClass()); return false; } - return garminCoordinator.supports(device, COURSE_DOWNLOAD); + final boolean installUnsupportedFiles = GBApplication.getDevicePrefs(device).installUnsupportedFiles(); + return garminCoordinator.supports(device, COURSE_DOWNLOAD) || installUnsupportedFiles; } } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/garmin/GarminPrgFileInstallHandler.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/garmin/GarminPrgFileInstallHandler.java index e54cb920af..6b6dacc137 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/garmin/GarminPrgFileInstallHandler.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/garmin/GarminPrgFileInstallHandler.java @@ -25,6 +25,7 @@ import androidx.annotation.NonNull; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import nodomain.freeyourgadget.gadgetbridge.GBApplication; import nodomain.freeyourgadget.gadgetbridge.R; import nodomain.freeyourgadget.gadgetbridge.activities.install.FwAppInstallerActivity; import nodomain.freeyourgadget.gadgetbridge.activities.install.InstallActivity; @@ -76,7 +77,9 @@ public class GarminPrgFileInstallHandler implements InstallHandler { } // FIXME this might not be the correct capability - if (!garminCoordinator.supports(device, GarminCapability.CONNECTIQ_APP_MANAGEMENT)) { + final boolean supported = garminCoordinator.supports(device, GarminCapability.CONNECTIQ_APP_MANAGEMENT); + final boolean installUnsupportedFiles = GBApplication.getDevicePrefs(device).installUnsupportedFiles(); + if (!supported && !installUnsupportedFiles) { installActivity.setInfoText(mContext.getString(R.string.fwapp_install_device_not_supported)); installActivity.setInstallEnabled(false); installActivity.setCloseEnabled(true); @@ -92,7 +95,14 @@ public class GarminPrgFileInstallHandler implements InstallHandler { )); fwItem.setIcon(coordinator.getDefaultIconResource()); - installActivity.setInfoText(mContext.getString(R.string.fw_upgrade_notice, "PRG")); + final StringBuilder builder = new StringBuilder(); + builder.append(mContext.getString(R.string.fw_upgrade_notice, "PRG")); + if (!supported) { + builder.append("\n\n"); + builder.append(mContext.getString(R.string.install_unsupported_files_warning)); + } + + installActivity.setInfoText(builder.toString()); installActivity.setInstallItem(fwItem); if (!device.isInitialized()) { diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/preferences/DevicePrefs.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/preferences/DevicePrefs.java index ba4e61db5e..fa6fb98f3b 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/preferences/DevicePrefs.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/preferences/DevicePrefs.java @@ -124,6 +124,10 @@ public class DevicePrefs extends Prefs { return getBoolean(PREF_ALLOW_HIGH_MTU, true); } + public boolean installUnsupportedFiles() { + return getBoolean("install_unsupported_files", false); + } + public boolean getConnectionPriorityLowPower() { return getBoolean(PREF_CONNECTION_PRIORITY_LOW_POWER, false); } diff --git a/app/src/main/res/drawable/ic_arrow_upload_progress.xml b/app/src/main/res/drawable/ic_arrow_upload_progress.xml new file mode 100644 index 0000000000..c4bd5bc7cb --- /dev/null +++ b/app/src/main/res/drawable/ic_arrow_upload_progress.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index a0be88dc92..39f0d2247d 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -3937,6 +3937,9 @@ Manually import activity files from the phone storage Fetch unknown files Fetch unknown activity files from the watch. They will not be processed, but will be saved in the phone. + Install unsupported files + Allow upload of unsupported files to the device. + This file is not supported by the device, and might cause issues.\n\nYou are DISCOURAGED from installing it! Swipe down to fetch new data from connected devices. Refresh on swipe Cannot upload watchface, too many watchfaces installed diff --git a/app/src/main/res/xml/devicesettings_install_unsupported_files.xml b/app/src/main/res/xml/devicesettings_install_unsupported_files.xml new file mode 100644 index 0000000000..405164f813 --- /dev/null +++ b/app/src/main/res/xml/devicesettings_install_unsupported_files.xml @@ -0,0 +1,10 @@ + + + +